@cybedefend/vibedefend 1.1.1

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 (103) hide show
  1. package/LICENSE +77 -0
  2. package/README.md +120 -0
  3. package/bin/vibedefend.js +19 -0
  4. package/dist/auth/auth-store.js +170 -0
  5. package/dist/auth/auth-store.js.map +1 -0
  6. package/dist/auth/auth.js +125 -0
  7. package/dist/auth/auth.js.map +1 -0
  8. package/dist/auth/callback-server.js +216 -0
  9. package/dist/auth/callback-server.js.map +1 -0
  10. package/dist/auth/pkce.js +31 -0
  11. package/dist/auth/pkce.js.map +1 -0
  12. package/dist/auth/token-exchange.js +83 -0
  13. package/dist/auth/token-exchange.js.map +1 -0
  14. package/dist/clients/claude-code.js +170 -0
  15. package/dist/clients/claude-code.js.map +1 -0
  16. package/dist/clients/codex.js +378 -0
  17. package/dist/clients/codex.js.map +1 -0
  18. package/dist/clients/cursor-guards-rules.js +94 -0
  19. package/dist/clients/cursor-guards-rules.js.map +1 -0
  20. package/dist/clients/cursor.js +172 -0
  21. package/dist/clients/cursor.js.map +1 -0
  22. package/dist/clients/detect.js +86 -0
  23. package/dist/clients/detect.js.map +1 -0
  24. package/dist/clients/registry.js +41 -0
  25. package/dist/clients/registry.js.map +1 -0
  26. package/dist/clients/types.js +2 -0
  27. package/dist/clients/types.js.map +1 -0
  28. package/dist/clients/vscode.js +187 -0
  29. package/dist/clients/vscode.js.map +1 -0
  30. package/dist/clients/windsurf.js +151 -0
  31. package/dist/clients/windsurf.js.map +1 -0
  32. package/dist/config.js +32 -0
  33. package/dist/config.js.map +1 -0
  34. package/dist/custom-regions.js +112 -0
  35. package/dist/custom-regions.js.map +1 -0
  36. package/dist/diagnostics.js +122 -0
  37. package/dist/diagnostics.js.map +1 -0
  38. package/dist/doctor.js +125 -0
  39. package/dist/doctor.js.map +1 -0
  40. package/dist/guards-evaluator/bucketing.js +83 -0
  41. package/dist/guards-evaluator/bucketing.js.map +1 -0
  42. package/dist/guards-evaluator/evaluate.js +272 -0
  43. package/dist/guards-evaluator/evaluate.js.map +1 -0
  44. package/dist/guards-evaluator/glob.js +148 -0
  45. package/dist/guards-evaluator/glob.js.map +1 -0
  46. package/dist/guards-evaluator/index.js +9 -0
  47. package/dist/guards-evaluator/index.js.map +1 -0
  48. package/dist/guards-evaluator/preprocess.js +174 -0
  49. package/dist/guards-evaluator/preprocess.js.map +1 -0
  50. package/dist/guards-evaluator/redact.js +111 -0
  51. package/dist/guards-evaluator/redact.js.map +1 -0
  52. package/dist/guards-evaluator/regex.js +125 -0
  53. package/dist/guards-evaluator/regex.js.map +1 -0
  54. package/dist/guards-evaluator/types.js +2 -0
  55. package/dist/guards-evaluator/types.js.map +1 -0
  56. package/dist/guards-evaluator/validation.js +115 -0
  57. package/dist/guards-evaluator/validation.js.map +1 -0
  58. package/dist/hook-runner.js +6680 -0
  59. package/dist/hooks/install.js +169 -0
  60. package/dist/hooks/install.js.map +1 -0
  61. package/dist/hooks/runtime/api.js +167 -0
  62. package/dist/hooks/runtime/api.js.map +1 -0
  63. package/dist/hooks/runtime/config.js +60 -0
  64. package/dist/hooks/runtime/config.js.map +1 -0
  65. package/dist/hooks/runtime/emit.js +45 -0
  66. package/dist/hooks/runtime/emit.js.map +1 -0
  67. package/dist/hooks/runtime/fetch-rules.js +154 -0
  68. package/dist/hooks/runtime/fetch-rules.js.map +1 -0
  69. package/dist/hooks/runtime/guard-rules-cache.js +217 -0
  70. package/dist/hooks/runtime/guard-rules-cache.js.map +1 -0
  71. package/dist/hooks/runtime/guard-violations-buffer.js +105 -0
  72. package/dist/hooks/runtime/guard-violations-buffer.js.map +1 -0
  73. package/dist/hooks/runtime/pre-compact.js +41 -0
  74. package/dist/hooks/runtime/pre-compact.js.map +1 -0
  75. package/dist/hooks/runtime/resolve.js +206 -0
  76. package/dist/hooks/runtime/resolve.js.map +1 -0
  77. package/dist/hooks/runtime/session-review.js +198 -0
  78. package/dist/hooks/runtime/session-review.js.map +1 -0
  79. package/dist/hooks/runtime/session-start.js +101 -0
  80. package/dist/hooks/runtime/session-start.js.map +1 -0
  81. package/dist/hooks/runtime/sniff.js +112 -0
  82. package/dist/hooks/runtime/sniff.js.map +1 -0
  83. package/dist/hooks/runtime/types.js +22 -0
  84. package/dist/hooks/runtime/types.js.map +1 -0
  85. package/dist/hooks/runtime/user-prompt-submit.js +154 -0
  86. package/dist/hooks/runtime/user-prompt-submit.js.map +1 -0
  87. package/dist/index.js +129 -0
  88. package/dist/index.js.map +1 -0
  89. package/dist/install.js +183 -0
  90. package/dist/install.js.map +1 -0
  91. package/dist/login.js +335 -0
  92. package/dist/login.js.map +1 -0
  93. package/dist/prompts.js +134 -0
  94. package/dist/prompts.js.map +1 -0
  95. package/dist/self-update.js +177 -0
  96. package/dist/self-update.js.map +1 -0
  97. package/dist/status.js +58 -0
  98. package/dist/status.js.map +1 -0
  99. package/dist/utils.js +84 -0
  100. package/dist/utils.js.map +1 -0
  101. package/dist/version.js +23 -0
  102. package/dist/version.js.map +1 -0
  103. package/package.json +73 -0
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Loader for the optional `vibedefend.regions.json` file.
3
+ *
4
+ * The public CLI ships only the Production EU / US regions. Teams who
5
+ * need to install against non-production clusters (staging, localhost,
6
+ * a contributor's docker-compose stack) maintain a local JSON file with
7
+ * those endpoints — the file is gitignored on every machine where it
8
+ * lives, so internal URLs never leak to the public repo.
9
+ *
10
+ * Lookup order (first match wins):
11
+ * 1. `$CYBEDEFEND_REGIONS_FILE` — absolute or relative path
12
+ * 2. `./vibedefend.regions.json` — current working directory
13
+ * 3. `~/.cybedefend/regions.json` — user-wide
14
+ *
15
+ * The file is a JSON array of `RegionConfig` objects. Each entry needs
16
+ * the six string fields `id`, `label`, `description`, `mcpUrl`,
17
+ * `apiBase`, `mcpName`. `dev` is optional (defaults to `false`).
18
+ *
19
+ * The loader never throws — bad JSON or malformed entries log a warning
20
+ * and degrade to "no custom regions" so a broken file can't break the
21
+ * install picker.
22
+ */
23
+ import { existsSync, readFileSync } from 'node:fs';
24
+ import { join } from 'node:path';
25
+ import { home, log } from './utils.js';
26
+ const REQUIRED_STRING_FIELDS = [
27
+ 'id',
28
+ 'label',
29
+ 'description',
30
+ 'mcpUrl',
31
+ 'apiBase',
32
+ 'mcpName',
33
+ ];
34
+ /**
35
+ * Resolve the candidate paths in lookup order. Filters out empty/undefined
36
+ * env-var values so we don't accidentally try to read `process.cwd()` etc.
37
+ */
38
+ function candidatePaths() {
39
+ const envOverride = process.env.CYBEDEFEND_REGIONS_FILE;
40
+ const candidates = [
41
+ envOverride && envOverride.length > 0 ? envOverride : null,
42
+ join(process.cwd(), 'vibedefend.regions.json'),
43
+ home('.cybedefend', 'regions.json'),
44
+ ];
45
+ return candidates.filter((p) => typeof p === 'string');
46
+ }
47
+ /**
48
+ * Read + parse + validate a single regions file. Returns the valid
49
+ * entries; logs and skips any malformed ones. Returns `[]` (with a
50
+ * warning) when the whole file can't be read or parsed.
51
+ */
52
+ function parseRegionsFile(path) {
53
+ let raw;
54
+ try {
55
+ raw = readFileSync(path, 'utf8');
56
+ }
57
+ catch (e) {
58
+ log.warn(`Could not read custom regions file ${path}: ${e.message}`);
59
+ return [];
60
+ }
61
+ let parsed;
62
+ try {
63
+ parsed = JSON.parse(raw);
64
+ }
65
+ catch (e) {
66
+ log.warn(`Custom regions file ${path} is not valid JSON: ${e.message}`);
67
+ return [];
68
+ }
69
+ if (!Array.isArray(parsed)) {
70
+ log.warn(`Custom regions file ${path} must contain a JSON array of region objects.`);
71
+ return [];
72
+ }
73
+ const valid = [];
74
+ parsed.forEach((entry, i) => {
75
+ if (typeof entry !== 'object' || entry === null) {
76
+ log.warn(`Custom regions file ${path}: entry #${i} is not an object — skipped.`);
77
+ return;
78
+ }
79
+ const obj = entry;
80
+ const missing = REQUIRED_STRING_FIELDS.filter((f) => typeof obj[f] !== 'string' || obj[f].length === 0);
81
+ if (missing.length > 0) {
82
+ log.warn(`Custom regions file ${path}: entry #${i} missing or empty required field(s) [${missing.join(', ')}] — skipped.`);
83
+ return;
84
+ }
85
+ valid.push({
86
+ id: obj.id,
87
+ label: obj.label,
88
+ description: obj.description,
89
+ mcpUrl: obj.mcpUrl,
90
+ apiBase: obj.apiBase,
91
+ mcpName: obj.mcpName,
92
+ dev: typeof obj.dev === 'boolean' ? obj.dev : false,
93
+ });
94
+ });
95
+ if (valid.length > 0) {
96
+ log.hint(`Loaded ${valid.length} custom region(s) from ${path}`);
97
+ }
98
+ return valid;
99
+ }
100
+ /**
101
+ * Public entry point. Returns the parsed array from the FIRST file
102
+ * found, or `[]` if none of the candidate paths exist.
103
+ */
104
+ export function loadCustomRegions() {
105
+ for (const path of candidatePaths()) {
106
+ if (!existsSync(path))
107
+ continue;
108
+ return parseRegionsFile(path);
109
+ }
110
+ return [];
111
+ }
112
+ //# sourceMappingURL=custom-regions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-regions.js","sourceRoot":"","sources":["../src/custom-regions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Side-effect-free collector of the local VibeDefend install state.
3
+ * Consumed by `vibedefend status` (renders it) and `vibedefend doctor`
4
+ * (repairs from it). Never throws — every read degrades to an "absent"
5
+ * value on failure.
6
+ */
7
+ import { existsSync, readFileSync } from 'node:fs';
8
+ import { homedir } from 'node:os';
9
+ import { join } from 'node:path';
10
+ import { ALL_ADAPTERS } from './clients/registry.js';
11
+ import { pkg } from './version.js';
12
+ import { pingGateway } from './hooks/runtime/api.js';
13
+ import { resolveProjectId, resolveToken } from './hooks/runtime/resolve.js';
14
+ /** `~/.cybedefend`, overridable via CYBEDEFEND_HOME for tests. */
15
+ function cybeHome() {
16
+ return join(process.env.CYBEDEFEND_HOME ?? homedir(), '.cybedefend');
17
+ }
18
+ function readJsonSafe(path) {
19
+ try {
20
+ if (!existsSync(path))
21
+ return null;
22
+ return JSON.parse(readFileSync(path, 'utf8'));
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ /** Read a trimmed text file, or `null` if absent / empty / unreadable. */
29
+ function readTextSafe(path) {
30
+ try {
31
+ if (!existsSync(path))
32
+ return null;
33
+ return readFileSync(path, 'utf8').trim() || null;
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ export async function gatherInstallState(opts = {}) {
40
+ const dir = cybeHome();
41
+ const runtimeConfig = readJsonSafe(join(dir, 'runtime-config.json'));
42
+ const region = runtimeConfig?.region ?? null;
43
+ const versionStamped = readTextSafe(join(dir, 'version'));
44
+ const clients = ALL_ADAPTERS.map((a) => {
45
+ const detected = (() => {
46
+ try {
47
+ return a.detect().installed;
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ })();
53
+ const ins = region
54
+ ? (() => {
55
+ try {
56
+ return a.inspect(region);
57
+ }
58
+ catch {
59
+ return { hooksWired: false, mcpRegistered: false };
60
+ }
61
+ })()
62
+ : { hooksWired: false, mcpRegistered: false };
63
+ return {
64
+ id: a.id,
65
+ label: a.label,
66
+ detected,
67
+ hooksWired: ins.hooksWired,
68
+ mcpRegistered: ins.mcpRegistered,
69
+ };
70
+ });
71
+ // `resolveProjectId` never throws — it swallows malformed config JSON and
72
+ // returns `{ projectId: null }`. Wrapped defensively all the same.
73
+ let projectId = null;
74
+ try {
75
+ projectId = resolveProjectId().projectId;
76
+ }
77
+ catch {
78
+ projectId = null;
79
+ }
80
+ let live = null;
81
+ if (opts.live) {
82
+ let token = null;
83
+ try {
84
+ token = region ? resolveToken(region.mcpName) : null;
85
+ }
86
+ catch {
87
+ token = null;
88
+ }
89
+ if (!region) {
90
+ live = { status: 'skipped', reason: 'not installed' };
91
+ }
92
+ else if (!projectId) {
93
+ live = { status: 'skipped', reason: 'no projectId (.cybedefend/config.json)' };
94
+ }
95
+ else if (!token) {
96
+ live = { status: 'skipped', reason: 'no MCP token' };
97
+ }
98
+ else {
99
+ try {
100
+ live = await pingGateway({
101
+ apiBase: region.apiBase,
102
+ projectId,
103
+ token,
104
+ });
105
+ }
106
+ catch {
107
+ live = { status: 'error', detail: 'live check threw' };
108
+ }
109
+ }
110
+ }
111
+ return {
112
+ installed: runtimeConfig !== null,
113
+ region,
114
+ runnerPresent: existsSync(join(dir, 'hook-runner.js')),
115
+ versionStamped,
116
+ versionCurrent: pkg.version,
117
+ clients,
118
+ projectId,
119
+ live,
120
+ };
121
+ }
122
+ //# sourceMappingURL=diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"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"}
package/dist/doctor.js ADDED
@@ -0,0 +1,125 @@
1
+ /**
2
+ * `vibedefend doctor` — diagnose the install and repair what is fixable.
3
+ *
4
+ * Two halves:
5
+ * - `deriveRepairs(state)` — PURE. Maps an `InstallState` to a list of
6
+ * `Repair`s. A repair with a `fix` function is auto-fixable; one
7
+ * without is something only the user can resolve (e.g. "not installed").
8
+ * No I/O, never throws — fully unit-testable.
9
+ * - `runDoctor(opts)` — the command entry point. Gathers live state,
10
+ * derives repairs, prints them, confirms, and applies the fixes.
11
+ */
12
+ import kleur from 'kleur';
13
+ import { adapterFor } from './clients/registry.js';
14
+ import { gatherInstallState } from './diagnostics.js';
15
+ import { installHookRuntime } from './hooks/install.js';
16
+ import { loadRuntimeConfig } from './hooks/runtime/config.js';
17
+ import { HOOK_DEFAULTS } from './config.js';
18
+ import { log } from './utils.js';
19
+ import { pkg } from './version.js';
20
+ /**
21
+ * The hook tunables persisted in `runtime-config.json` and the install-time
22
+ * `HookConfig` share the exact same shape, so a loaded `RuntimeConfig.hooks`
23
+ * is a valid `HookConfig`. Fall back to `HOOK_DEFAULTS` when the config file
24
+ * is absent or corrupt.
25
+ */
26
+ function resolveHookConfig() {
27
+ const cfg = loadRuntimeConfig();
28
+ return cfg?.hooks ?? { ...HOOK_DEFAULTS };
29
+ }
30
+ /** Pure: derive the repair list from a gathered state. */
31
+ export function deriveRepairs(state) {
32
+ const repairs = [];
33
+ if (!state.installed || !state.region) {
34
+ repairs.push({
35
+ id: 'not-installed',
36
+ description: 'VibeDefend is not installed — run `vibedefend install`.',
37
+ });
38
+ return repairs;
39
+ }
40
+ const region = state.region;
41
+ if (!state.runnerPresent) {
42
+ repairs.push({
43
+ id: 'runner-missing',
44
+ description: 'Hook runner ~/.cybedefend/hook-runner.js is missing — re-render it.',
45
+ fix: () => {
46
+ installHookRuntime({
47
+ region,
48
+ hooks: resolveHookConfig(),
49
+ installedVersion: pkg.version,
50
+ });
51
+ },
52
+ });
53
+ }
54
+ for (const c of state.clients) {
55
+ if (c.detected && !c.hooksWired) {
56
+ repairs.push({
57
+ id: `hooks-${c.id}`,
58
+ description: `${c.label} is installed but our hooks are not wired — re-wire them.`,
59
+ fix: () => {
60
+ const hooks = resolveHookConfig();
61
+ adapterFor(c.id).writeSettings({
62
+ hookDir: '',
63
+ enableSessionReview: hooks.enableSessionReview,
64
+ region,
65
+ hooks,
66
+ });
67
+ },
68
+ });
69
+ }
70
+ if (c.detected && !c.mcpRegistered) {
71
+ repairs.push({
72
+ id: `mcp-${c.id}`,
73
+ description: `${c.label} is installed but the MCP server is not registered — register it.`,
74
+ fix: () => {
75
+ const adapter = adapterFor(c.id);
76
+ adapter.registerMcp?.({ region });
77
+ adapter.postRegister?.({ region });
78
+ },
79
+ });
80
+ }
81
+ }
82
+ return repairs;
83
+ }
84
+ export async function runDoctor(opts = {}) {
85
+ const state = await gatherInstallState({ live: true });
86
+ const repairs = deriveRepairs(state);
87
+ if (repairs.length === 0) {
88
+ log.ok('VibeDefend looks healthy — nothing to repair.');
89
+ return;
90
+ }
91
+ console.log(kleur.bold(`Found ${repairs.length} issue(s):`));
92
+ for (const r of repairs) {
93
+ const tag = r.fix ? kleur.yellow('fixable') : kleur.red('manual');
94
+ console.log(` [${tag}] ${r.description}`);
95
+ }
96
+ const fixable = repairs.filter((r) => r.fix);
97
+ if (opts.check || fixable.length === 0) {
98
+ if (repairs.some((r) => !r.fix))
99
+ process.exitCode = 1;
100
+ return;
101
+ }
102
+ if (!opts.yes) {
103
+ const { confirm } = await import('@inquirer/prompts');
104
+ const go = await confirm({
105
+ message: `Apply ${fixable.length} fix(es)?`,
106
+ default: true,
107
+ });
108
+ if (!go)
109
+ return;
110
+ }
111
+ for (const r of fixable) {
112
+ try {
113
+ log.step(r.description);
114
+ await r.fix();
115
+ log.ok('Fixed.');
116
+ }
117
+ catch (err) {
118
+ log.err(`Could not fix "${r.id}": ${err instanceof Error ? err.message : String(err)}`);
119
+ process.exitCode = 1;
120
+ }
121
+ }
122
+ if (repairs.some((r) => !r.fix))
123
+ process.exitCode = 1;
124
+ }
125
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Rule bucketing — group rules by the type of target they can match.
3
+ *
4
+ * Bucketing reduces the set of rules evaluated per request from N to a
5
+ * small constant, avoiding O(N) per-rule matcher dispatch at hot-path time.
6
+ */
7
+ /**
8
+ * Determine which bucket a target belongs to.
9
+ */
10
+ export function targetTypeBucket(target) {
11
+ switch (target.type) {
12
+ case 'file': return 'file';
13
+ case 'command': return 'command';
14
+ case 'env': return 'env';
15
+ case 'http': return 'http';
16
+ case 'git': return 'git';
17
+ default: {
18
+ // Throw a typed error the MCP tool can convert into a fail-closed deny.
19
+ const t = target.type ?? '(missing)';
20
+ throw new TypeError(`Invalid target.type: ${t}. Expected one of file|command|env|http|git.`);
21
+ }
22
+ }
23
+ }
24
+ /**
25
+ * Determine which buckets a rule belongs to, based on which matcher fields
26
+ * are populated.
27
+ *
28
+ * A single rule may live in multiple buckets when it mixes matcher types
29
+ * (rare, but valid for rules like process.proc_environ which has both
30
+ * filePathGlobs and command_regex).
31
+ */
32
+ export function ruleBuckets(rule) {
33
+ const buckets = [];
34
+ const hasFile = (rule.filePathGlobs && rule.filePathGlobs.length > 0) ||
35
+ (rule.filePathExcludes && rule.filePathExcludes.length > 0);
36
+ const hasCommand = !!rule.commandRegex ||
37
+ (rule.commandArgGlobs && rule.commandArgGlobs.length > 0);
38
+ const hasEnv = rule.envNameGlobs && rule.envNameGlobs.length > 0;
39
+ const hasHttp = (rule.httpHostGlobs && rule.httpHostGlobs.length > 0) ||
40
+ (rule.httpMethod && rule.httpMethod.length > 0) ||
41
+ (rule.httpPathGlobs && rule.httpPathGlobs.length > 0);
42
+ const hasGit = (rule.gitRemoteGlobs && rule.gitRemoteGlobs.length > 0) ||
43
+ (rule.gitBranchGlobs && rule.gitBranchGlobs.length > 0) ||
44
+ (rule.gitSubcommand && rule.gitSubcommand.length > 0);
45
+ if (hasFile)
46
+ buckets.push('file');
47
+ if (hasCommand)
48
+ buckets.push('command');
49
+ if (hasEnv)
50
+ buckets.push('env');
51
+ if (hasHttp)
52
+ buckets.push('http');
53
+ if (hasGit)
54
+ buckets.push('git');
55
+ return buckets;
56
+ }
57
+ /**
58
+ * Partition a flat rule list into per-bucket maps for O(1) lookup per request.
59
+ *
60
+ * Rules with no recognised matcher fields are excluded from all buckets and
61
+ * a console.warn is emitted — they would never fire.
62
+ */
63
+ export function bucketRules(rules) {
64
+ const result = {
65
+ file: [],
66
+ command: [],
67
+ env: [],
68
+ http: [],
69
+ git: [],
70
+ };
71
+ for (const rule of rules) {
72
+ const buckets = ruleBuckets(rule);
73
+ if (buckets.length === 0) {
74
+ console.warn(`[guards-evaluator] Rule "${rule.id}" has no matcher fields — it will never fire.`);
75
+ continue;
76
+ }
77
+ for (const bucket of buckets) {
78
+ result[bucket].push(rule);
79
+ }
80
+ }
81
+ return result;
82
+ }
83
+ //# sourceMappingURL=bucketing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bucketing.js","sourceRoot":"","sources":["../../src/guards-evaluator/bucketing.ts"],"names":[],"mappings":"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"}