agentlock-shared 0.2.0 → 0.3.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.
Files changed (169) hide show
  1. package/dist/__tests__/billing.test.d.ts +2 -0
  2. package/dist/__tests__/billing.test.d.ts.map +1 -0
  3. package/dist/__tests__/billing.test.js +31 -0
  4. package/dist/__tests__/billing.test.js.map +1 -0
  5. package/dist/__tests__/dns-pinning.test.d.ts +2 -0
  6. package/dist/__tests__/dns-pinning.test.d.ts.map +1 -0
  7. package/dist/__tests__/dns-pinning.test.js +33 -0
  8. package/dist/__tests__/dns-pinning.test.js.map +1 -0
  9. package/dist/__tests__/llm-classifier-cache-store.test.d.ts +2 -0
  10. package/dist/__tests__/llm-classifier-cache-store.test.d.ts.map +1 -0
  11. package/dist/__tests__/llm-classifier-cache-store.test.js +65 -0
  12. package/dist/__tests__/llm-classifier-cache-store.test.js.map +1 -0
  13. package/dist/__tests__/llm-classifier-cache.test.d.ts +2 -0
  14. package/dist/__tests__/llm-classifier-cache.test.d.ts.map +1 -0
  15. package/dist/__tests__/llm-classifier-cache.test.js +44 -0
  16. package/dist/__tests__/llm-classifier-cache.test.js.map +1 -0
  17. package/dist/__tests__/llm-classifier.test.d.ts +2 -0
  18. package/dist/__tests__/llm-classifier.test.d.ts.map +1 -0
  19. package/dist/__tests__/llm-classifier.test.js +167 -0
  20. package/dist/__tests__/llm-classifier.test.js.map +1 -0
  21. package/dist/__tests__/plans-classifier-limits.test.d.ts +2 -0
  22. package/dist/__tests__/plans-classifier-limits.test.d.ts.map +1 -0
  23. package/dist/__tests__/plans-classifier-limits.test.js +22 -0
  24. package/dist/__tests__/plans-classifier-limits.test.js.map +1 -0
  25. package/dist/__tests__/policy-category-floor.test.d.ts +2 -0
  26. package/dist/__tests__/policy-category-floor.test.d.ts.map +1 -0
  27. package/dist/__tests__/policy-category-floor.test.js +46 -0
  28. package/dist/__tests__/policy-category-floor.test.js.map +1 -0
  29. package/dist/__tests__/policy-claude-bash.test.d.ts +2 -0
  30. package/dist/__tests__/policy-claude-bash.test.d.ts.map +1 -0
  31. package/dist/__tests__/policy-claude-bash.test.js +401 -0
  32. package/dist/__tests__/policy-claude-bash.test.js.map +1 -0
  33. package/dist/__tests__/policy-llm-floor.test.d.ts +2 -0
  34. package/dist/__tests__/policy-llm-floor.test.d.ts.map +1 -0
  35. package/dist/__tests__/policy-llm-floor.test.js +107 -0
  36. package/dist/__tests__/policy-llm-floor.test.js.map +1 -0
  37. package/dist/__tests__/policy-ssh-e2e.test.d.ts +2 -0
  38. package/dist/__tests__/policy-ssh-e2e.test.d.ts.map +1 -0
  39. package/dist/__tests__/policy-ssh-e2e.test.js +89 -0
  40. package/dist/__tests__/policy-ssh-e2e.test.js.map +1 -0
  41. package/dist/__tests__/policy-ssh-sessions.test.d.ts +2 -0
  42. package/dist/__tests__/policy-ssh-sessions.test.d.ts.map +1 -0
  43. package/dist/__tests__/policy-ssh-sessions.test.js +139 -0
  44. package/dist/__tests__/policy-ssh-sessions.test.js.map +1 -0
  45. package/dist/__tests__/policy-ssh.test.d.ts +2 -0
  46. package/dist/__tests__/policy-ssh.test.d.ts.map +1 -0
  47. package/dist/__tests__/policy-ssh.test.js +180 -0
  48. package/dist/__tests__/policy-ssh.test.js.map +1 -0
  49. package/dist/__tests__/policy.test.js +400 -2
  50. package/dist/__tests__/policy.test.js.map +1 -1
  51. package/dist/__tests__/redact.test.js +76 -0
  52. package/dist/__tests__/redact.test.js.map +1 -1
  53. package/dist/__tests__/signing.test.js +89 -0
  54. package/dist/__tests__/signing.test.js.map +1 -1
  55. package/dist/__tests__/ssh-fingerprint.test.d.ts +2 -0
  56. package/dist/__tests__/ssh-fingerprint.test.d.ts.map +1 -0
  57. package/dist/__tests__/ssh-fingerprint.test.js +19 -0
  58. package/dist/__tests__/ssh-fingerprint.test.js.map +1 -0
  59. package/dist/__tests__/vpn-route.test.d.ts +2 -0
  60. package/dist/__tests__/vpn-route.test.d.ts.map +1 -0
  61. package/dist/__tests__/vpn-route.test.js +72 -0
  62. package/dist/__tests__/vpn-route.test.js.map +1 -0
  63. package/dist/__tests__/wireguard.test.d.ts +2 -0
  64. package/dist/__tests__/wireguard.test.d.ts.map +1 -0
  65. package/dist/__tests__/wireguard.test.js +114 -0
  66. package/dist/__tests__/wireguard.test.js.map +1 -0
  67. package/dist/billing.d.ts +12 -0
  68. package/dist/billing.d.ts.map +1 -0
  69. package/dist/billing.js +41 -0
  70. package/dist/billing.js.map +1 -0
  71. package/dist/crypto.d.ts +5 -0
  72. package/dist/crypto.d.ts.map +1 -1
  73. package/dist/crypto.js +80 -23
  74. package/dist/crypto.js.map +1 -1
  75. package/dist/dns-pinning.d.ts +28 -0
  76. package/dist/dns-pinning.d.ts.map +1 -0
  77. package/dist/dns-pinning.js +113 -0
  78. package/dist/dns-pinning.js.map +1 -0
  79. package/dist/index.d.ts +6 -0
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +9 -0
  82. package/dist/index.js.map +1 -1
  83. package/dist/llm-classifier-cache-store.d.ts +49 -0
  84. package/dist/llm-classifier-cache-store.d.ts.map +1 -0
  85. package/dist/llm-classifier-cache-store.js +63 -0
  86. package/dist/llm-classifier-cache-store.js.map +1 -0
  87. package/dist/llm-classifier-cache.d.ts +6 -0
  88. package/dist/llm-classifier-cache.d.ts.map +1 -0
  89. package/dist/llm-classifier-cache.js +52 -0
  90. package/dist/llm-classifier-cache.js.map +1 -0
  91. package/dist/llm-classifier.d.ts +29 -0
  92. package/dist/llm-classifier.d.ts.map +1 -0
  93. package/dist/llm-classifier.js +191 -0
  94. package/dist/llm-classifier.js.map +1 -0
  95. package/dist/observability.d.ts +36 -0
  96. package/dist/observability.d.ts.map +1 -0
  97. package/dist/observability.js +75 -0
  98. package/dist/observability.js.map +1 -0
  99. package/dist/plans.d.ts +17 -0
  100. package/dist/plans.d.ts.map +1 -1
  101. package/dist/plans.js +36 -14
  102. package/dist/plans.js.map +1 -1
  103. package/dist/policy.d.ts +173 -3
  104. package/dist/policy.d.ts.map +1 -1
  105. package/dist/policy.js +910 -42
  106. package/dist/policy.js.map +1 -1
  107. package/dist/redact.d.ts.map +1 -1
  108. package/dist/redact.js +83 -3
  109. package/dist/redact.js.map +1 -1
  110. package/dist/regex-safety.d.ts +21 -0
  111. package/dist/regex-safety.d.ts.map +1 -0
  112. package/dist/regex-safety.js +49 -0
  113. package/dist/regex-safety.js.map +1 -0
  114. package/dist/sanitize.d.ts +31 -0
  115. package/dist/sanitize.d.ts.map +1 -0
  116. package/dist/sanitize.js +54 -0
  117. package/dist/sanitize.js.map +1 -0
  118. package/dist/schemas.d.ts +202 -10
  119. package/dist/schemas.d.ts.map +1 -1
  120. package/dist/schemas.js +91 -1
  121. package/dist/schemas.js.map +1 -1
  122. package/dist/signing.d.ts +15 -0
  123. package/dist/signing.d.ts.map +1 -1
  124. package/dist/signing.js +53 -4
  125. package/dist/signing.js.map +1 -1
  126. package/dist/ssh-fingerprint.d.ts +10 -0
  127. package/dist/ssh-fingerprint.d.ts.map +1 -0
  128. package/dist/ssh-fingerprint.js +52 -0
  129. package/dist/ssh-fingerprint.js.map +1 -0
  130. package/dist/ssrf.d.ts +36 -0
  131. package/dist/ssrf.d.ts.map +1 -0
  132. package/dist/ssrf.js +140 -0
  133. package/dist/ssrf.js.map +1 -0
  134. package/dist/types.d.ts +130 -0
  135. package/dist/types.d.ts.map +1 -1
  136. package/dist/wireguard.d.ts +63 -0
  137. package/dist/wireguard.d.ts.map +1 -0
  138. package/dist/wireguard.js +226 -0
  139. package/dist/wireguard.js.map +1 -0
  140. package/package.json +42 -29
  141. package/.turbo/turbo-build.log +0 -4
  142. package/.turbo/turbo-test.log +0 -76
  143. package/dist/__tests__/content-crypto.test.d.ts +0 -2
  144. package/dist/__tests__/content-crypto.test.d.ts.map +0 -1
  145. package/dist/__tests__/content-crypto.test.js +0 -117
  146. package/dist/__tests__/content-crypto.test.js.map +0 -1
  147. package/dist/__tests__/signing.test (# Edit conflict 2026-04-01 z3etfmC #).js +0 -51
  148. package/dist/__tests__/signing.test.js (# Edit conflict 2026-04-01 4rndy9C #).map +0 -1
  149. package/dist/content-crypto.d.ts +0 -24
  150. package/dist/content-crypto.d.ts.map +0 -1
  151. package/dist/content-crypto.js +0 -58
  152. package/dist/content-crypto.js.map +0 -1
  153. package/src/__tests__/crypto.test.ts +0 -169
  154. package/src/__tests__/messaging.test.ts +0 -83
  155. package/src/__tests__/policy.test.ts +0 -222
  156. package/src/__tests__/redact.test.ts +0 -41
  157. package/src/__tests__/signing.test.ts +0 -55
  158. package/src/crypto.ts +0 -235
  159. package/src/index.ts +0 -8
  160. package/src/mcp-catalog.ts +0 -181
  161. package/src/plans.ts +0 -116
  162. package/src/policy.ts +0 -216
  163. package/src/redact.ts +0 -131
  164. package/src/schemas.ts +0 -121
  165. package/src/signing.ts +0 -120
  166. package/src/types.ts +0 -213
  167. package/test-gateway.mjs +0 -47
  168. package/tsconfig.json +0 -10
  169. package/vitest.config.ts +0 -8
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=billing.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/billing.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const billing_js_1 = require("../billing.js");
5
+ (0, vitest_1.describe)('stripe billing status helpers', () => {
6
+ (0, vitest_1.it)('treats active and trialing subscriptions as entitled', () => {
7
+ (0, vitest_1.expect)((0, billing_js_1.isEntitledStripeSubscriptionStatus)('active')).toBe(true);
8
+ (0, vitest_1.expect)((0, billing_js_1.isEntitledStripeSubscriptionStatus)('trialing')).toBe(true);
9
+ (0, vitest_1.expect)((0, billing_js_1.isEntitledStripeSubscriptionStatus)('past_due')).toBe(false);
10
+ });
11
+ (0, vitest_1.it)('keeps recoverable subscriptions attached to the existing customer flow', () => {
12
+ (0, vitest_1.expect)((0, billing_js_1.isRecoverableStripeSubscriptionStatus)('active')).toBe(true);
13
+ (0, vitest_1.expect)((0, billing_js_1.isRecoverableStripeSubscriptionStatus)('trialing')).toBe(true);
14
+ (0, vitest_1.expect)((0, billing_js_1.isRecoverableStripeSubscriptionStatus)('past_due')).toBe(true);
15
+ (0, vitest_1.expect)((0, billing_js_1.isRecoverableStripeSubscriptionStatus)('unpaid')).toBe(true);
16
+ (0, vitest_1.expect)((0, billing_js_1.isRecoverableStripeSubscriptionStatus)('incomplete')).toBe(true);
17
+ (0, vitest_1.expect)((0, billing_js_1.isRecoverableStripeSubscriptionStatus)('paused')).toBe(true);
18
+ (0, vitest_1.expect)((0, billing_js_1.isRecoverableStripeSubscriptionStatus)('incomplete_expired')).toBe(false);
19
+ });
20
+ (0, vitest_1.it)('only allows a fresh checkout for terminal subscriptions', () => {
21
+ (0, vitest_1.expect)((0, billing_js_1.isTerminalStripeSubscriptionStatus)('canceled')).toBe(true);
22
+ (0, vitest_1.expect)((0, billing_js_1.isTerminalStripeSubscriptionStatus)('incomplete_expired')).toBe(true);
23
+ (0, vitest_1.expect)((0, billing_js_1.isTerminalStripeSubscriptionStatus)('past_due')).toBe(false);
24
+ (0, vitest_1.expect)((0, billing_js_1.canStartNewCheckoutForStripeSubscriptionStatus)('canceled')).toBe(true);
25
+ (0, vitest_1.expect)((0, billing_js_1.canStartNewCheckoutForStripeSubscriptionStatus)('incomplete_expired')).toBe(true);
26
+ (0, vitest_1.expect)((0, billing_js_1.canStartNewCheckoutForStripeSubscriptionStatus)('active')).toBe(false);
27
+ (0, vitest_1.expect)((0, billing_js_1.canStartNewCheckoutForStripeSubscriptionStatus)('paused')).toBe(false);
28
+ (0, vitest_1.expect)((0, billing_js_1.canStartNewCheckoutForStripeSubscriptionStatus)('unknown_future_status')).toBe(false);
29
+ });
30
+ });
31
+ //# sourceMappingURL=billing.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing.test.js","sourceRoot":"","sources":["../../src/__tests__/billing.test.ts"],"names":[],"mappings":";;AAAA,mCAA8C;AAC9C,8CAKuB;AAEvB,IAAA,iBAAQ,EAAC,+BAA+B,EAAE,GAAG,EAAE;IAC7C,IAAA,WAAE,EAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,IAAA,eAAM,EAAC,IAAA,+CAAkC,EAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChE,IAAA,eAAM,EAAC,IAAA,+CAAkC,EAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,IAAA,eAAM,EAAC,IAAA,+CAAkC,EAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,IAAA,eAAM,EAAC,IAAA,kDAAqC,EAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnE,IAAA,eAAM,EAAC,IAAA,kDAAqC,EAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrE,IAAA,eAAM,EAAC,IAAA,kDAAqC,EAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrE,IAAA,eAAM,EAAC,IAAA,kDAAqC,EAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnE,IAAA,eAAM,EAAC,IAAA,kDAAqC,EAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvE,IAAA,eAAM,EAAC,IAAA,kDAAqC,EAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnE,IAAA,eAAM,EAAC,IAAA,kDAAqC,EAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,IAAA,eAAM,EAAC,IAAA,+CAAkC,EAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,IAAA,eAAM,EAAC,IAAA,+CAAkC,EAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5E,IAAA,eAAM,EAAC,IAAA,+CAAkC,EAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEnE,IAAA,eAAM,EAAC,IAAA,2DAA8C,EAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9E,IAAA,eAAM,EAAC,IAAA,2DAA8C,EAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxF,IAAA,eAAM,EAAC,IAAA,2DAA8C,EAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7E,IAAA,eAAM,EAAC,IAAA,2DAA8C,EAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7E,IAAA,eAAM,EAAC,IAAA,2DAA8C,EAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9F,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=dns-pinning.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dns-pinning.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/dns-pinning.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const dns_pinning_js_1 = require("../dns-pinning.js");
5
+ (0, vitest_1.describe)('createPinnedLookup', () => {
6
+ (0, vitest_1.it)('returns a literal IPv4 as-is via the resolver (no DNS round-trip)', async () => {
7
+ const lookup = (0, dns_pinning_js_1.createPinnedLookup)();
8
+ const ips = await lookup.resolver('203.0.113.7');
9
+ (0, vitest_1.expect)(ips).toEqual(['203.0.113.7']);
10
+ });
11
+ (0, vitest_1.it)('hands the connect path the same address the resolver validated (pin)', async () => {
12
+ // The SSRF check calls `.resolver(host)`; undici's connect calls the
13
+ // lookup itself. Both must agree on one address or the pin is voided.
14
+ const lookup = (0, dns_pinning_js_1.createPinnedLookup)();
15
+ const viaResolver = await lookup.resolver('198.51.100.42');
16
+ const viaLookup = await new Promise((resolve, reject) => {
17
+ lookup('198.51.100.42', { family: 4 }, (err, address) => (err ? reject(err) : resolve(address)));
18
+ });
19
+ (0, vitest_1.expect)(viaResolver).toEqual(['198.51.100.42']);
20
+ (0, vitest_1.expect)(viaLookup).toBe('198.51.100.42');
21
+ });
22
+ (0, vitest_1.it)('honors undici\'s { all: true } callback shape', async () => {
23
+ // Node >=20 / undici invoke the lookup with { all: true } and expect
24
+ // callback(null, [{ address, family }]). The 3-arg form silently breaks
25
+ // there and voids the pin, so this shape must be supported.
26
+ const lookup = (0, dns_pinning_js_1.createPinnedLookup)();
27
+ const result = await new Promise((resolve, reject) => {
28
+ lookup('192.0.2.10', { all: true }, ((err, addrs) => err ? reject(err) : resolve(addrs)));
29
+ });
30
+ (0, vitest_1.expect)(result).toEqual([{ address: '192.0.2.10', family: 4 }]);
31
+ });
32
+ });
33
+ //# sourceMappingURL=dns-pinning.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dns-pinning.test.js","sourceRoot":"","sources":["../../src/__tests__/dns-pinning.test.ts"],"names":[],"mappings":";;AAAA,mCAA8C;AAC9C,sDAAuD;AAEvD,IAAA,iBAAQ,EAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,IAAA,WAAE,EAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,MAAM,GAAG,IAAA,mCAAkB,GAAE,CAAC;QACpC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QACjD,IAAA,eAAM,EAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;QACpF,qEAAqE;QACrE,sEAAsE;QACtE,MAAM,MAAM,GAAG,IAAA,mCAAkB,GAAE,CAAC;QACpC,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;QAC3D,MAAM,SAAS,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC9D,MAAM,CACJ,eAAe,EACf,EAAE,MAAM,EAAE,CAAC,EAA4C,EACvD,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CACzD,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,IAAA,eAAM,EAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;QAC/C,IAAA,eAAM,EAAC,SAAS,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,qEAAqE;QACrE,wEAAwE;QACxE,4DAA4D;QAC5D,MAAM,MAAM,GAAG,IAAA,mCAAkB,GAAE,CAAC;QACpC,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAC9B,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAClB,MAAM,CACJ,YAAY,EACZ,EAAE,GAAG,EAAE,IAAI,EAA4C,EACvD,CAAC,CAAC,GAAiC,EAAE,KAAiD,EAAE,EAAE,CACxF,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAI3B,CACV,CAAC;QACJ,CAAC,CACF,CAAC;QACF,IAAA,eAAM,EAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=llm-classifier-cache-store.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-classifier-cache-store.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/llm-classifier-cache-store.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const llm_classifier_cache_store_js_1 = require("../llm-classifier-cache-store.js");
5
+ const SAMPLE = {
6
+ category: 'admin',
7
+ reason: 'tool name suggests privileged operation',
8
+ confidence: 0.95,
9
+ model: 'google/gemini-2.5-flash-lite',
10
+ };
11
+ (0, vitest_1.describe)('InMemoryCacheStore', () => {
12
+ let store;
13
+ (0, vitest_1.beforeEach)(() => {
14
+ store = new llm_classifier_cache_store_js_1.InMemoryCacheStore({ ttlMs: 1000 * 60 * 60 });
15
+ });
16
+ (0, vitest_1.it)('returns null on cache miss', async () => {
17
+ (0, vitest_1.expect)(await store.get('missing-key')).toBeNull();
18
+ });
19
+ (0, vitest_1.it)('returns stored classification marked as cached', async () => {
20
+ await store.set('k1', SAMPLE);
21
+ const got = await store.get('k1');
22
+ (0, vitest_1.expect)(got).not.toBeNull();
23
+ (0, vitest_1.expect)(got.category).toBe('admin');
24
+ (0, vitest_1.expect)(got.cached).toBe(true);
25
+ });
26
+ (0, vitest_1.it)('does not return expired entries', async () => {
27
+ const shortLived = new llm_classifier_cache_store_js_1.InMemoryCacheStore({ ttlMs: 5 });
28
+ await shortLived.set('k1', SAMPLE);
29
+ await new Promise((resolve) => setTimeout(resolve, 20));
30
+ (0, vitest_1.expect)(await shortLived.get('k1')).toBeNull();
31
+ });
32
+ (0, vitest_1.it)('overwrites existing entries', async () => {
33
+ await store.set('k1', SAMPLE);
34
+ await store.set('k1', { ...SAMPLE, category: 'financial', reason: 'updated' });
35
+ const got = await store.get('k1');
36
+ (0, vitest_1.expect)(got.category).toBe('financial');
37
+ });
38
+ (0, vitest_1.it)('does not throw on errors from get or set', async () => {
39
+ await (0, vitest_1.expect)(store.get('k1')).resolves.not.toThrow();
40
+ await (0, vitest_1.expect)(store.set('k1', SAMPLE)).resolves.not.toThrow();
41
+ });
42
+ });
43
+ (0, vitest_1.describe)('classifier cache store singleton', () => {
44
+ (0, vitest_1.beforeEach)(() => {
45
+ (0, llm_classifier_cache_store_js_1.resetClassifierCacheStoreForTest)();
46
+ });
47
+ (0, vitest_1.it)('returns a default InMemoryCacheStore if nothing was set', () => {
48
+ const store = (0, llm_classifier_cache_store_js_1.getClassifierCacheStore)();
49
+ (0, vitest_1.expect)(store).toBeInstanceOf(llm_classifier_cache_store_js_1.InMemoryCacheStore);
50
+ });
51
+ (0, vitest_1.it)('returns the store that was injected via setClassifierCacheStore', () => {
52
+ const custom = {
53
+ get: async () => null,
54
+ set: async () => { },
55
+ };
56
+ (0, llm_classifier_cache_store_js_1.setClassifierCacheStore)(custom);
57
+ (0, vitest_1.expect)((0, llm_classifier_cache_store_js_1.getClassifierCacheStore)()).toBe(custom);
58
+ });
59
+ (0, vitest_1.it)('resetClassifierCacheStoreForTest clears the injected store', () => {
60
+ (0, llm_classifier_cache_store_js_1.setClassifierCacheStore)({ get: async () => null, set: async () => { } });
61
+ (0, llm_classifier_cache_store_js_1.resetClassifierCacheStoreForTest)();
62
+ (0, vitest_1.expect)((0, llm_classifier_cache_store_js_1.getClassifierCacheStore)()).toBeInstanceOf(llm_classifier_cache_store_js_1.InMemoryCacheStore);
63
+ });
64
+ });
65
+ //# sourceMappingURL=llm-classifier-cache-store.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-classifier-cache-store.test.js","sourceRoot":"","sources":["../../src/__tests__/llm-classifier-cache-store.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=llm-classifier-cache.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-classifier-cache.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/llm-classifier-cache.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const llm_classifier_cache_js_1 = require("../llm-classifier-cache.js");
5
+ (0, vitest_1.describe)('llm-classifier-cache', () => {
6
+ (0, vitest_1.describe)('buildCacheKey', () => {
7
+ (0, vitest_1.it)('produces the same key for identical tool + payload shape', () => {
8
+ const k1 = (0, llm_classifier_cache_js_1.buildCacheKey)('notion.delete_page', { pageId: 'abc', permanent: true });
9
+ const k2 = (0, llm_classifier_cache_js_1.buildCacheKey)('notion.delete_page', { pageId: 'xyz', permanent: false });
10
+ (0, vitest_1.expect)(k1).toBe(k2);
11
+ });
12
+ (0, vitest_1.it)('produces the same key regardless of key ordering', () => {
13
+ const k1 = (0, llm_classifier_cache_js_1.buildCacheKey)('tool.name', { a: 1, b: 2, c: 3 });
14
+ const k2 = (0, llm_classifier_cache_js_1.buildCacheKey)('tool.name', { c: 3, a: 1, b: 2 });
15
+ (0, vitest_1.expect)(k1).toBe(k2);
16
+ });
17
+ (0, vitest_1.it)('produces different keys for different tool names', () => {
18
+ const k1 = (0, llm_classifier_cache_js_1.buildCacheKey)('notion.delete_page', { pageId: 'abc' });
19
+ const k2 = (0, llm_classifier_cache_js_1.buildCacheKey)('notion.archive_page', { pageId: 'abc' });
20
+ (0, vitest_1.expect)(k1).not.toBe(k2);
21
+ });
22
+ (0, vitest_1.it)('produces different keys for different payload shapes', () => {
23
+ const k1 = (0, llm_classifier_cache_js_1.buildCacheKey)('tool', { a: 1, b: 2 });
24
+ const k2 = (0, llm_classifier_cache_js_1.buildCacheKey)('tool', { a: 1, b: 2, c: 3 });
25
+ (0, vitest_1.expect)(k1).not.toBe(k2);
26
+ });
27
+ (0, vitest_1.it)('is case-insensitive on tool name (matches static floor behavior)', () => {
28
+ const k1 = (0, llm_classifier_cache_js_1.buildCacheKey)('Notion.Delete_Page', {});
29
+ const k2 = (0, llm_classifier_cache_js_1.buildCacheKey)('notion.delete_page', {});
30
+ (0, vitest_1.expect)(k1).toBe(k2);
31
+ });
32
+ (0, vitest_1.it)('strips values but preserves nested structure', () => {
33
+ const k1 = (0, llm_classifier_cache_js_1.buildCacheKey)('tool', { nested: { x: 1, y: 2 } });
34
+ const k2 = (0, llm_classifier_cache_js_1.buildCacheKey)('tool', { nested: { x: 999, y: 'different' } });
35
+ (0, vitest_1.expect)(k1).toBe(k2);
36
+ });
37
+ (0, vitest_1.it)('treats arrays by structure of first element', () => {
38
+ const k1 = (0, llm_classifier_cache_js_1.buildCacheKey)('tool', { items: [{ id: 1 }] });
39
+ const k2 = (0, llm_classifier_cache_js_1.buildCacheKey)('tool', { items: [{ id: 2 }, { id: 3 }] });
40
+ (0, vitest_1.expect)(k1).toBe(k2);
41
+ });
42
+ });
43
+ });
44
+ //# sourceMappingURL=llm-classifier-cache.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-classifier-cache.test.js","sourceRoot":"","sources":["../../src/__tests__/llm-classifier-cache.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=llm-classifier.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-classifier.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/llm-classifier.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const llm_classifier_js_1 = require("../llm-classifier.js");
5
+ const llm_classifier_cache_store_js_1 = require("../llm-classifier-cache-store.js");
6
+ function mockClassifier(result) {
7
+ return async () => {
8
+ if (result instanceof Error)
9
+ throw result;
10
+ return result;
11
+ };
12
+ }
13
+ (0, vitest_1.describe)('classifyWithLLM', () => {
14
+ (0, vitest_1.beforeEach)(() => {
15
+ (0, llm_classifier_cache_store_js_1.resetClassifierCacheStoreForTest)();
16
+ (0, llm_classifier_js_1.__setClassifierForTest)(null); // reset to default
17
+ });
18
+ (0, vitest_1.it)('returns null when no API key is configured (env var missing)', async () => {
19
+ const original = process.env.OPENROUTER_API_KEY;
20
+ delete process.env.OPENROUTER_API_KEY;
21
+ try {
22
+ const result = await (0, llm_classifier_js_1.classifyWithLLM)('unknown.tool', { foo: 'bar' });
23
+ (0, vitest_1.expect)(result).toBeNull();
24
+ }
25
+ finally {
26
+ if (original !== undefined)
27
+ process.env.OPENROUTER_API_KEY = original;
28
+ }
29
+ });
30
+ (0, vitest_1.it)('returns classification from injected classifier', async () => {
31
+ (0, llm_classifier_js_1.__setClassifierForTest)(mockClassifier({
32
+ category: 'write',
33
+ reason: 'Tool name suggests a mutation',
34
+ confidence: 0.88,
35
+ model: 'google/gemini-2.5-flash-lite',
36
+ }));
37
+ const result = await (0, llm_classifier_js_1.classifyWithLLM)('notion.update_page', { pageId: 'abc' });
38
+ (0, vitest_1.expect)(result).not.toBeNull();
39
+ (0, vitest_1.expect)(result?.category).toBe('write');
40
+ (0, vitest_1.expect)(result?.cached).toBe(false);
41
+ });
42
+ (0, vitest_1.it)('caches results — same shape hits, different shape misses', async () => {
43
+ const spy = vitest_1.vi.fn(mockClassifier({
44
+ category: 'admin',
45
+ reason: 'Delete user action',
46
+ confidence: 0.97,
47
+ model: 'google/gemini-2.5-flash-lite',
48
+ }));
49
+ (0, llm_classifier_js_1.__setClassifierForTest)(spy);
50
+ // Same shape — r2 is a cache hit
51
+ const r1 = await (0, llm_classifier_js_1.classifyWithLLM)('custom.delete_user', { userId: 'user-1' });
52
+ const r2 = await (0, llm_classifier_js_1.classifyWithLLM)('custom.delete_user', { userId: 'user-2' });
53
+ (0, vitest_1.expect)(r1?.cached).toBe(false);
54
+ (0, vitest_1.expect)(r2?.cached).toBe(true);
55
+ (0, vitest_1.expect)(r2?.category).toBe('admin');
56
+ (0, vitest_1.expect)(spy).toHaveBeenCalledTimes(1);
57
+ // Different shape — r3 is a cache MISS, spy called again
58
+ const r3 = await (0, llm_classifier_js_1.classifyWithLLM)('custom.delete_user', {
59
+ userId: 'user-3',
60
+ force: true,
61
+ });
62
+ (0, vitest_1.expect)(r3?.cached).toBe(false);
63
+ (0, vitest_1.expect)(spy).toHaveBeenCalledTimes(2);
64
+ });
65
+ (0, vitest_1.it)('returns null (graceful fallback) when classifier throws', async () => {
66
+ (0, llm_classifier_js_1.__setClassifierForTest)(mockClassifier(new Error('OpenRouter 503')));
67
+ const result = await (0, llm_classifier_js_1.classifyWithLLM)('unknown.tool', {});
68
+ (0, vitest_1.expect)(result).toBeNull();
69
+ });
70
+ (0, vitest_1.it)('returns null (graceful fallback) when classifier returns null', async () => {
71
+ (0, llm_classifier_js_1.__setClassifierForTest)(mockClassifier(null));
72
+ const result = await (0, llm_classifier_js_1.classifyWithLLM)('unknown.tool', {});
73
+ (0, vitest_1.expect)(result).toBeNull();
74
+ });
75
+ (0, vitest_1.it)('enforces a hard timeout (does not wait forever)', async () => {
76
+ (0, llm_classifier_js_1.__setClassifierForTest)(async () => {
77
+ await new Promise((r) => setTimeout(r, 5000));
78
+ return null;
79
+ });
80
+ const start = Date.now();
81
+ const result = await (0, llm_classifier_js_1.classifyWithLLM)('slow.tool', {}, { timeoutMs: 100 });
82
+ const elapsed = Date.now() - start;
83
+ (0, vitest_1.expect)(result).toBeNull();
84
+ (0, vitest_1.expect)(elapsed).toBeLessThan(200); // timeout was 100ms, give some wiggle room
85
+ });
86
+ (0, vitest_1.it)('does not leak errors — just returns null', async () => {
87
+ (0, llm_classifier_js_1.__setClassifierForTest)(async () => {
88
+ throw new Error('Unexpected error');
89
+ });
90
+ await (0, vitest_1.expect)((0, llm_classifier_js_1.classifyWithLLM)('tool', {})).resolves.toBeNull();
91
+ });
92
+ (0, vitest_1.it)('never downgrades — a "read" response is still returned as read', async () => {
93
+ // The caller (evaluatePolicy) applies max(declared, staticFloor, llmFloor).
94
+ // This test just confirms the classifier faithfully returns whatever the
95
+ // LLM said; downgrade protection is a policy-layer concern.
96
+ (0, llm_classifier_js_1.__setClassifierForTest)(mockClassifier({
97
+ category: 'read',
98
+ reason: 'Looks like a read-only lookup',
99
+ confidence: 0.6,
100
+ model: 'google/gemini-2.5-flash-lite',
101
+ }));
102
+ const result = await (0, llm_classifier_js_1.classifyWithLLM)('some.tool', {});
103
+ (0, vitest_1.expect)(result?.category).toBe('read');
104
+ });
105
+ (0, vitest_1.it)('shapeOnly strips raw values from payloads — no values leak to the LLM', async () => {
106
+ const { shapeOnly } = await import('../llm-classifier.js');
107
+ const result = shapeOnly({
108
+ apiKey: 'sk-live-SECRET-DO-NOT-LEAK',
109
+ email: 'user@example.com',
110
+ amount: 999.99,
111
+ nested: { card: '4242-4242-4242-4242', count: 7 },
112
+ tags: ['alpha', 'beta'],
113
+ });
114
+ const serialized = JSON.stringify(result);
115
+ // Raw values must not appear
116
+ (0, vitest_1.expect)(serialized).not.toContain('sk-live-SECRET-DO-NOT-LEAK');
117
+ (0, vitest_1.expect)(serialized).not.toContain('user@example.com');
118
+ (0, vitest_1.expect)(serialized).not.toContain('999.99');
119
+ (0, vitest_1.expect)(serialized).not.toContain('4242');
120
+ (0, vitest_1.expect)(serialized).not.toContain('alpha');
121
+ // Keys ARE preserved
122
+ (0, vitest_1.expect)(serialized).toContain('apiKey');
123
+ (0, vitest_1.expect)(serialized).toContain('email');
124
+ (0, vitest_1.expect)(serialized).toContain('nested');
125
+ // Type descriptors ARE present
126
+ (0, vitest_1.expect)(serialized).toContain('<string>');
127
+ (0, vitest_1.expect)(serialized).toContain('<number>');
128
+ });
129
+ });
130
+ // ---------------------------------------------------------------------------
131
+ // Opt-in integration test — calls the real OpenRouter API.
132
+ // Skipped unless INTEGRATION=1 is set (pnpm test:integration runs with it).
133
+ // ---------------------------------------------------------------------------
134
+ vitest_1.describe.skipIf(process.env.INTEGRATION !== '1')('classifyWithLLM — OpenRouter integration', () => {
135
+ (0, vitest_1.beforeEach)(() => {
136
+ (0, llm_classifier_cache_store_js_1.resetClassifierCacheStoreForTest)();
137
+ (0, llm_classifier_js_1.__setClassifierForTest)(null); // use the real classifier
138
+ });
139
+ (0, vitest_1.it)('classifies notion.delete_workspace_page as write or admin', async () => {
140
+ if (!process.env.OPENROUTER_API_KEY) {
141
+ throw new Error('OPENROUTER_API_KEY not set — cannot run integration test');
142
+ }
143
+ // 5s timeout (vs. the 800ms production default) because cold-start latency
144
+ // to OpenRouter can exceed 800ms on the first real call of a test run.
145
+ // This test validates classification correctness, not the timeout mechanism —
146
+ // that's covered by the mocked unit tests.
147
+ const result = await (0, llm_classifier_js_1.classifyWithLLM)('notion.delete_workspace_page', {
148
+ pageId: '<string>',
149
+ permanent: '<boolean>',
150
+ }, { timeoutMs: 5000 });
151
+ (0, vitest_1.expect)(result).not.toBeNull();
152
+ (0, vitest_1.expect)(['write', 'admin']).toContain(result?.category);
153
+ (0, vitest_1.expect)(result?.reason.length).toBeGreaterThan(0);
154
+ (0, vitest_1.expect)(result?.model).toContain('gemini');
155
+ }, 10_000);
156
+ (0, vitest_1.it)('classifies unknown.read_user_profile as read', async () => {
157
+ if (!process.env.OPENROUTER_API_KEY) {
158
+ throw new Error('OPENROUTER_API_KEY not set — cannot run integration test');
159
+ }
160
+ const result = await (0, llm_classifier_js_1.classifyWithLLM)('unknown.read_user_profile', {
161
+ userId: '<string>',
162
+ }, { timeoutMs: 5000 });
163
+ (0, vitest_1.expect)(result).not.toBeNull();
164
+ (0, vitest_1.expect)(result?.category).toBe('read');
165
+ }, 10_000);
166
+ });
167
+ //# sourceMappingURL=llm-classifier.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-classifier.test.js","sourceRoot":"","sources":["../../src/__tests__/llm-classifier.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plans-classifier-limits.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plans-classifier-limits.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/plans-classifier-limits.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const plans_js_1 = require("../plans.js");
5
+ (0, vitest_1.describe)('plans — classifier quota', () => {
6
+ (0, vitest_1.it)('free plan has 0 classifier calls per month', () => {
7
+ (0, vitest_1.expect)(plans_js_1.PLANS.free.classifierCallsPerMonth).toBe(0);
8
+ (0, vitest_1.expect)((0, plans_js_1.getPlanLimits)('free').classifierCallsPerMonth).toBe(0);
9
+ });
10
+ (0, vitest_1.it)('pro plan has 1000 classifier calls per month', () => {
11
+ (0, vitest_1.expect)(plans_js_1.PLANS.pro.classifierCallsPerMonth).toBe(1000);
12
+ (0, vitest_1.expect)((0, plans_js_1.getPlanLimits)('pro').classifierCallsPerMonth).toBe(1000);
13
+ });
14
+ (0, vitest_1.it)('team plan has 10000 classifier calls per month', () => {
15
+ (0, vitest_1.expect)(plans_js_1.PLANS.team.classifierCallsPerMonth).toBe(10000);
16
+ (0, vitest_1.expect)((0, plans_js_1.getPlanLimits)('team').classifierCallsPerMonth).toBe(10000);
17
+ });
18
+ (0, vitest_1.it)('getPlanLimits falls back to free quota for unknown plans', () => {
19
+ (0, vitest_1.expect)((0, plans_js_1.getPlanLimits)('mystery').classifierCallsPerMonth).toBe(0);
20
+ });
21
+ });
22
+ //# sourceMappingURL=plans-classifier-limits.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plans-classifier-limits.test.js","sourceRoot":"","sources":["../../src/__tests__/plans-classifier-limits.test.ts"],"names":[],"mappings":";;AAAA,mCAA8C;AAC9C,0CAAmD;AAEnD,IAAA,iBAAQ,EAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,IAAA,WAAE,EAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,IAAA,eAAM,EAAC,gBAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnD,IAAA,eAAM,EAAC,IAAA,wBAAa,EAAC,MAAM,CAAC,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,IAAA,eAAM,EAAC,gBAAK,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrD,IAAA,eAAM,EAAC,IAAA,wBAAa,EAAC,KAAK,CAAC,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,IAAA,eAAM,EAAC,gBAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvD,IAAA,eAAM,EAAC,IAAA,wBAAa,EAAC,MAAM,CAAC,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,IAAA,eAAM,EAAC,IAAA,wBAAa,EAAC,SAAS,CAAC,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=policy-category-floor.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-category-floor.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/policy-category-floor.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const policy_js_1 = require("../policy.js");
5
+ const baseAction = (overrides = {}) => ({
6
+ action_type: 'read',
7
+ tool: 'unknown.tool',
8
+ payload: {},
9
+ ...overrides,
10
+ });
11
+ // The static category floor is the only anti-downgrade layer (the LLM
12
+ // classifier and its upgrade-only llmFloor option were removed 2026-06-12).
13
+ (0, vitest_1.describe)('evaluatePolicy - static category floor', () => {
14
+ (0, vitest_1.it)('keeps a known read-floor tool at read', () => {
15
+ const action = baseAction({ tool: 'mcp.list_tools' });
16
+ const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES);
17
+ (0, vitest_1.expect)(result.effective_action_type).toBe('read');
18
+ });
19
+ (0, vitest_1.it)('floors unrecognised tools to write (fail-closed)', () => {
20
+ const action = baseAction({ action_type: 'read', tool: 'unknown.tool' });
21
+ const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES);
22
+ (0, vitest_1.expect)(result.effective_action_type).toBe('write');
23
+ (0, vitest_1.expect)(result.decision).toBe('REQUIRE_APPROVAL');
24
+ (0, vitest_1.expect)(result.reason).toContain('category floored');
25
+ });
26
+ (0, vitest_1.it)('floors a declared read on a financial tool to financial', () => {
27
+ const action = baseAction({ action_type: 'read', tool: 'stripe.charge' });
28
+ const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES);
29
+ (0, vitest_1.expect)(result.effective_action_type).toBe('financial');
30
+ (0, vitest_1.expect)(result.decision).toBe('REQUIRE_APPROVAL');
31
+ });
32
+ (0, vitest_1.it)('never downgrades a declared admin action', () => {
33
+ const action = baseAction({ action_type: 'admin', tool: 'unknown.tool' });
34
+ const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES);
35
+ (0, vitest_1.expect)(result.effective_action_type).toBe('admin');
36
+ (0, vitest_1.expect)(result.decision).toBe('BLOCK');
37
+ });
38
+ (0, vitest_1.it)('skipCategoryFloor bypasses the floor (owner opt-in escape hatch)', () => {
39
+ const action = baseAction({ action_type: 'read', tool: 'stripe.charge' });
40
+ const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES, {
41
+ skipCategoryFloor: true,
42
+ });
43
+ (0, vitest_1.expect)(result.effective_action_type).toBe('read');
44
+ });
45
+ });
46
+ //# sourceMappingURL=policy-category-floor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-category-floor.test.js","sourceRoot":"","sources":["../../src/__tests__/policy-category-floor.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=policy-claude-bash.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-claude-bash.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/policy-claude-bash.test.ts"],"names":[],"mappings":""}