@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 @@
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/clients/cursor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Shared detection utilities for client adapters.
3
+ *
4
+ * Each adapter calls `probeBinaryVersion()` with the name of its CLI
5
+ * (e.g. `cursor`, `code`, `windsurf`, `codex`) and gets back either a
6
+ * parsed semver string or `null` if not on PATH / version flag failed.
7
+ *
8
+ * Why so cautious: we run detection serially for every adapter at
9
+ * install time. A single hung probe (binary that prints to a pager,
10
+ * waits for input, etc.) would freeze the installer. We bound every
11
+ * spawn with a hard timeout and treat any non-zero exit as "not
12
+ * detected" rather than re-raising.
13
+ */
14
+ import { spawnSync } from 'node:child_process';
15
+ import { existsSync } from 'node:fs';
16
+ import { which } from '../utils.js';
17
+ const VERSION_PROBE_TIMEOUT_MS = 3000;
18
+ /**
19
+ * Run `<binary> <versionFlag>` and parse a semver-ish version from the
20
+ * first line of stdout. Returns `null` if the binary isn't on PATH,
21
+ * the spawn timed out, or no version could be extracted.
22
+ *
23
+ * `firstLineParser` lets each adapter tweak which line/regex it cares
24
+ * about — VS Code's `code --version` prints 3 lines (version, commit,
25
+ * arch); Cursor prints just the version; Codex prints "codex 0.1.0".
26
+ */
27
+ export function probeBinaryVersion(binary, args = ['--version'], firstLineParser = defaultParser) {
28
+ if (which(binary) === null)
29
+ return null;
30
+ const result = spawnSync(binary, args, {
31
+ encoding: 'utf8',
32
+ timeout: VERSION_PROBE_TIMEOUT_MS,
33
+ stdio: ['ignore', 'pipe', 'ignore'],
34
+ shell: false,
35
+ });
36
+ if (result.status !== 0 || !result.stdout)
37
+ return null;
38
+ return firstLineParser(result.stdout);
39
+ }
40
+ /**
41
+ * Default semver parser — pulls the first `X.Y.Z` substring out of the
42
+ * stdout. Handles common shapes:
43
+ * "0.1.0" → "0.1.0"
44
+ * "claude-code 0.1.0" → "0.1.0"
45
+ * "Cursor v1.7.3 (build ...)" → "1.7.3"
46
+ * "1.111.0\n<commit>\n<arch>" → "1.111.0"
47
+ */
48
+ function defaultParser(stdout) {
49
+ const match = /(\d+\.\d+\.\d+(?:-[a-z0-9.-]+)?)/i.exec(stdout);
50
+ return match ? match[1] : null;
51
+ }
52
+ /**
53
+ * Compare two semver-ish strings. Returns:
54
+ * < 0 if `a < b`
55
+ * = 0 if `a == b`
56
+ * > 0 if `a > b`
57
+ *
58
+ * Ignores pre-release suffixes (-rc.1 etc.) — we only care about the
59
+ * numeric (major.minor.patch) for the "is hooks supported?" gate, which
60
+ * was added in a specific minor version.
61
+ */
62
+ export function compareVersions(a, b) {
63
+ const pa = a.split('-')[0].split('.').map((n) => parseInt(n, 10) || 0);
64
+ const pb = b.split('-')[0].split('.').map((n) => parseInt(n, 10) || 0);
65
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
66
+ const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
67
+ if (diff !== 0)
68
+ return diff;
69
+ }
70
+ return 0;
71
+ }
72
+ /** True iff `version >= minVersion` under {@link compareVersions}. */
73
+ export function versionAtLeast(version, minVersion) {
74
+ return compareVersions(version, minVersion) >= 0;
75
+ }
76
+ /**
77
+ * Check whether a known config directory exists. Used as a secondary
78
+ * signal: e.g. Cursor on macOS may live as an `.app` bundle not on PATH,
79
+ * but its `~/.cursor/` directory is reliably present after first launch.
80
+ */
81
+ export function configDirExists(...parts) {
82
+ if (parts.length === 0)
83
+ return false;
84
+ return existsSync(parts.join('/'));
85
+ }
86
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/clients/detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAEtC;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAc,EACd,OAAiB,CAAC,WAAW,CAAC,EAC9B,kBAAqD,aAAa;IAElE,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAExC,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE;QACrC,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,wBAAwB;QACjC,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;QACnC,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACvD,OAAO,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,KAAK,GAAG,mCAAmC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/D,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,CAAS,EAAE,CAAS;IAClD,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACvE,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACvE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACzC,IAAI,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;IAC9B,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,UAAkB;IAChE,OAAO,eAAe,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAG,KAAe;IAChD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Client adapter registry. Single source of truth for "which clients
3
+ * does VibeDefend support?".
4
+ *
5
+ * Order matters — adapters appear in the multi-select prompt in this
6
+ * order. Claude Code first because it has the most mature hook surface
7
+ * and is the assumed default; the others follow alphabetically.
8
+ */
9
+ import { claudeCodeAdapter } from './claude-code.js';
10
+ import { codexAdapter } from './codex.js';
11
+ import { cursorAdapter } from './cursor.js';
12
+ import { vscodeAdapter } from './vscode.js';
13
+ import { windsurfAdapter } from './windsurf.js';
14
+ export const ALL_ADAPTERS = [
15
+ claudeCodeAdapter,
16
+ cursorAdapter,
17
+ vscodeAdapter,
18
+ windsurfAdapter,
19
+ codexAdapter,
20
+ ];
21
+ /** Look up an adapter by ID. Throws if not found (programming error). */
22
+ export function adapterFor(id) {
23
+ const adapter = ALL_ADAPTERS.find((a) => a.id === id);
24
+ if (!adapter) {
25
+ throw new Error(`No adapter registered for client id "${id}".`);
26
+ }
27
+ return adapter;
28
+ }
29
+ /**
30
+ * Run detection on every adapter, returning a structured list.
31
+ * Pure — no side effects. Used by the multi-select prompt to populate
32
+ * its initial state ("which clients are installed + support hooks?")
33
+ * and by tests.
34
+ */
35
+ export function detectAll() {
36
+ return ALL_ADAPTERS.map((adapter) => ({
37
+ adapter,
38
+ detection: adapter.detect(),
39
+ }));
40
+ }
41
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/clients/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAIhD,MAAM,CAAC,MAAM,YAAY,GAA6B;IACpD,iBAAiB;IACjB,aAAa;IACb,aAAa;IACb,eAAe;IACf,YAAY;CACJ,CAAC;AAEX,yEAAyE;AACzE,MAAM,UAAU,UAAU,CAAC,EAAY;IACrC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,wCAAwC,EAAE,IAAI,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS;IAIvB,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACpC,OAAO;QACP,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE;KAC5B,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/clients/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,187 @@
1
+ /**
2
+ * VS Code Copilot adapter.
3
+ *
4
+ * Wires our universal hook scripts into `~/.copilot/hooks/cybedefend.json`
5
+ * (per decision 2 = B: write a dedicated config rather than relying on the
6
+ * `~/.claude/settings.json` fallback). Format mirrors Claude Code's
7
+ * `{ "hooks": { "EventName": [...] } }` shape — VS Code Copilot reads
8
+ * both layouts.
9
+ *
10
+ * Caveats called out by the VS Code docs (and surfaced to the user via
11
+ * `reason`):
12
+ * - Hooks are **preview** as of v1.110; format may change.
13
+ * - VS Code IGNORES the `matcher` field — every PreToolUse hook fires
14
+ * on every tool call. Our universal hook script self-filters via the
15
+ * `case "$TOOL_NAME" in Edit|Write|MultiEdit|apply_patch)` early-exit
16
+ * so the runtime cost is sub-millisecond per ignored call.
17
+ *
18
+ * Min version: 1.110.0 (February 2026 — first release with hook support).
19
+ */
20
+ import { existsSync, mkdirSync, readFileSync } from 'node:fs';
21
+ import { dirname, join } from 'node:path';
22
+ import { platform } from 'node:os';
23
+ import { home, log, readJson, writeJson } from '../utils.js';
24
+ import { hookCommand, VIBEDEFEND_PATH_MARKER, isVibedefendOwnedHookCommand, } from '../hooks/install.js';
25
+ import { probeBinaryVersion, versionAtLeast } from './detect.js';
26
+ const COPILOT_HOOKS = home('.copilot', 'hooks', 'cybedefend.json');
27
+ const MIN_VERSION = '1.110.0';
28
+ /**
29
+ * Resolve the user-profile `mcp.json` path for the current platform.
30
+ *
31
+ * VS Code stores user-level MCP config in its user-data directory, which
32
+ * differs per OS (and per build flavor — Insiders / Code-OSS use different
33
+ * subfolders, but we only target stable `Code` for V1):
34
+ * - macOS: ~/Library/Application Support/Code/User/mcp.json
35
+ * - Linux: ~/.config/Code/User/mcp.json
36
+ * - Windows: %APPDATA%/Code/User/mcp.json
37
+ *
38
+ * Resolution honours `process.env.HOME` (set by tests for sandboxing).
39
+ */
40
+ function vscodeUserMcpPath() {
41
+ const p = platform();
42
+ if (p === 'darwin') {
43
+ return home('Library', 'Application Support', 'Code', 'User', 'mcp.json');
44
+ }
45
+ if (p === 'linux') {
46
+ return home('.config', 'Code', 'User', 'mcp.json');
47
+ }
48
+ if (p === 'win32') {
49
+ const appData = process.env.APPDATA || home('AppData', 'Roaming');
50
+ return join(appData, 'Code', 'User', 'mcp.json');
51
+ }
52
+ // Unknown OS — fall back under HOME so tests still work.
53
+ return home('.vscode', 'mcp.json');
54
+ }
55
+ function detect() {
56
+ const version = probeBinaryVersion('code') ?? undefined;
57
+ if (version === undefined) {
58
+ return {
59
+ installed: false,
60
+ supportsHooks: false,
61
+ reason: '`code` CLI not on PATH. Install VS Code and run "Shell Command: Install \'code\' command" from the Command Palette.',
62
+ };
63
+ }
64
+ if (!versionAtLeast(version, MIN_VERSION)) {
65
+ return {
66
+ installed: true,
67
+ version,
68
+ supportsHooks: false,
69
+ reason: `VS Code ${version} is below the minimum ${MIN_VERSION} required for Copilot hooks. Update VS Code.`,
70
+ };
71
+ }
72
+ return {
73
+ installed: true,
74
+ version,
75
+ supportsHooks: true,
76
+ // Don't bake "preview" warnings into reason when supportsHooks is true —
77
+ // the multi-select prompt prints reasons only when supportsHooks is false.
78
+ };
79
+ }
80
+ function supports(event) {
81
+ // VS Code Copilot mirrors Claude Code's event surface per the docs.
82
+ return ['fetch-rules', 'session-start', 'stop', 'pre-compact'].includes(event);
83
+ }
84
+ function dropOurs(entries) {
85
+ return entries.filter((e) => !(e.hooks ?? []).some((h) => isVibedefendOwnedHookCommand(h.command)));
86
+ }
87
+ function writeSettings(opts) {
88
+ // Ensure the parent directory exists — VS Code doesn't create
89
+ // ~/.copilot/hooks/ on first launch like ~/.claude/ does.
90
+ mkdirSync(dirname(COPILOT_HOOKS), { recursive: true });
91
+ const file = readJson(COPILOT_HOOKS, {});
92
+ file.hooks ??= {};
93
+ file.hooks.PreToolUse ??= [];
94
+ file.hooks.SessionStart ??= [];
95
+ file.hooks.Stop ??= [];
96
+ file.hooks.PreCompact ??= [];
97
+ file.hooks.PreToolUse = dropOurs(file.hooks.PreToolUse);
98
+ file.hooks.SessionStart = dropOurs(file.hooks.SessionStart);
99
+ file.hooks.Stop = dropOurs(file.hooks.Stop);
100
+ file.hooks.PreCompact = dropOurs(file.hooks.PreCompact);
101
+ // Matcher is set but VS Code ignores it (per docs). The Node runner
102
+ // self-filters via its INTERESTED_TOOLS set. We keep the matcher so
103
+ // a future VS Code release that respects it Just Works.
104
+ file.hooks.PreToolUse.push({
105
+ matcher: 'Edit|Write|MultiEdit',
106
+ hooks: [{ type: 'command', command: hookCommand('fetch-rules') }],
107
+ });
108
+ file.hooks.SessionStart.push({
109
+ hooks: [{ type: 'command', command: hookCommand('session-start') }],
110
+ });
111
+ if (opts.enableSessionReview) {
112
+ file.hooks.Stop.push({
113
+ matcher: 'Stop',
114
+ hooks: [{ type: 'command', command: hookCommand('session-review') }],
115
+ });
116
+ file.hooks.PreCompact.push({
117
+ hooks: [{ type: 'command', command: hookCommand('pre-compact') }],
118
+ });
119
+ }
120
+ writeJson(COPILOT_HOOKS, file);
121
+ log.ok(`VS Code Copilot hooks wired into ${COPILOT_HOOKS}`);
122
+ }
123
+ /**
124
+ * Register the CybeDefend MCP server in VS Code's user-level `mcp.json`.
125
+ *
126
+ * Schema (per code.visualstudio.com/docs/copilot/customization/mcp-servers):
127
+ * { "servers": { "<name>": { "type": "http", "url": "<url>" } } }
128
+ *
129
+ * Note the field name `servers` (NOT `mcpServers` — that's Cursor/Windsurf).
130
+ * VS Code also offers a `code --add-mcp '<json>'` CLI but writing the file
131
+ * directly is more reliable and avoids spawning a process that may take
132
+ * time to start up.
133
+ */
134
+ function registerMcp(opts) {
135
+ const path = vscodeUserMcpPath();
136
+ log.step(`Registering MCP "${opts.region.mcpName}" in VS Code Copilot`);
137
+ log.hint(`URL: ${opts.region.mcpUrl}`);
138
+ log.hint(`Config: ${path}`);
139
+ mkdirSync(dirname(path), { recursive: true });
140
+ const file = readJson(path, {});
141
+ file.servers ??= {};
142
+ file.servers[opts.region.mcpName] = {
143
+ type: 'http',
144
+ url: opts.region.mcpUrl,
145
+ };
146
+ writeJson(path, file);
147
+ log.ok(`MCP "${opts.region.mcpName}" registered in ${path}`);
148
+ return true;
149
+ }
150
+ /**
151
+ * Pure introspection — never throws. `hooksWired` from
152
+ * `~/.copilot/hooks/cybedefend.json`, `mcpRegistered` from the per-OS
153
+ * user-profile `mcp.json` (same path `registerMcp` writes to). Raw-text
154
+ * substring checks keep the never-throw guarantee.
155
+ */
156
+ function inspect(region) {
157
+ let hooksWired = false;
158
+ try {
159
+ if (existsSync(COPILOT_HOOKS)) {
160
+ hooksWired = readFileSync(COPILOT_HOOKS, 'utf8').includes(VIBEDEFEND_PATH_MARKER);
161
+ }
162
+ }
163
+ catch {
164
+ /* missing/unreadable → false */
165
+ }
166
+ let mcpRegistered = false;
167
+ try {
168
+ const mcpPath = vscodeUserMcpPath();
169
+ if (existsSync(mcpPath)) {
170
+ mcpRegistered = readFileSync(mcpPath, 'utf8').includes(region.mcpName);
171
+ }
172
+ }
173
+ catch {
174
+ /* → false */
175
+ }
176
+ return { hooksWired, mcpRegistered };
177
+ }
178
+ export const vscodeAdapter = {
179
+ id: 'vscode',
180
+ label: 'VS Code Copilot',
181
+ detect,
182
+ supports,
183
+ writeSettings,
184
+ registerMcp,
185
+ inspect,
186
+ };
187
+ //# sourceMappingURL=vscode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vscode.js","sourceRoot":"","sources":["../../src/clients/vscode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Windsurf Cascade adapter.
3
+ *
4
+ * Wires our universal hook scripts into `~/.codeium/windsurf/hooks.json`.
5
+ * Windsurf's 12 lifecycle events are listed in
6
+ * https://docs.windsurf.com/windsurf/cascade/hooks. We map our 4 logical
7
+ * moments to the closest Cascade events:
8
+ *
9
+ * ┌──────────────────┬─────────────────────────────────────────────┐
10
+ * │ Our event │ Windsurf event │
11
+ * ├──────────────────┼─────────────────────────────────────────────┤
12
+ * │ fetch-rules │ pre_write_code │
13
+ * │ session-start │ pre_user_prompt (no SessionStart in Cascade)│
14
+ * │ stop │ post_cascade_response │
15
+ * │ pre-compact │ (not supported — Cascade has no equivalent) │
16
+ * └──────────────────┴─────────────────────────────────────────────┘
17
+ *
18
+ * `pre_user_prompt` as a stand-in for SessionStart fires on EVERY user
19
+ * turn (not just the first). Our session-start hook is idempotent and
20
+ * cheap (a single GET to the proposals endpoint that returns "0 pending"
21
+ * after the inbox is empty) so the cost is acceptable. A future Cascade
22
+ * release exposing a true session-start event will let us swap this.
23
+ *
24
+ * No version min documented — Windsurf added hooks recently but the doc
25
+ * doesn't pin a number. We soft-warn the user to ensure they're on a
26
+ * current build.
27
+ */
28
+ import { existsSync, readFileSync } from 'node:fs';
29
+ import { join } from 'node:path';
30
+ import { home, log, readJson, writeJson } from '../utils.js';
31
+ import { WINDSURF_GUARDS_SNIPPET, appendGuardSnippetIdempotent, } from './cursor-guards-rules.js';
32
+ import { hookCommand, VIBEDEFEND_PATH_MARKER, isVibedefendOwnedHookCommand, } from '../hooks/install.js';
33
+ import { configDirExists, probeBinaryVersion, } from './detect.js';
34
+ const WINDSURF_HOOKS = home('.codeium', 'windsurf', 'hooks.json');
35
+ const WINDSURF_MCP = home('.codeium', 'windsurf', 'mcp_config.json');
36
+ function detect() {
37
+ // Windsurf binary names: `windsurf` (CLI shim) or check for the config dir.
38
+ const version = probeBinaryVersion('windsurf') ?? undefined;
39
+ const hasConfigDir = configDirExists(home('.codeium', 'windsurf'));
40
+ const installed = version !== undefined || hasConfigDir;
41
+ if (!installed) {
42
+ return {
43
+ installed: false,
44
+ supportsHooks: false,
45
+ reason: '`windsurf` CLI not on PATH and no ~/.codeium/windsurf/ directory.',
46
+ };
47
+ }
48
+ return {
49
+ installed: true,
50
+ version,
51
+ supportsHooks: true,
52
+ // No version gate — Cascade added hooks in a recent release but the
53
+ // doc doesn't pin a version. We assume a current install supports
54
+ // them; a too-old Windsurf will silently ignore the hook file.
55
+ };
56
+ }
57
+ function supports(event) {
58
+ // Cascade has no PreCompact equivalent. Skip it — the orchestrator
59
+ // surfaces this gap to the user in the multi-select prompt.
60
+ return event !== 'pre-compact';
61
+ }
62
+ function dropOurs(entries) {
63
+ return entries.filter((e) => !isVibedefendOwnedHookCommand(e.command));
64
+ }
65
+ function writeSettings(opts) {
66
+ const file = readJson(WINDSURF_HOOKS, {});
67
+ file.pre_write_code ??= [];
68
+ file.pre_user_prompt ??= [];
69
+ file.post_cascade_response ??= [];
70
+ file.pre_write_code = dropOurs(file.pre_write_code);
71
+ file.pre_user_prompt = dropOurs(file.pre_user_prompt);
72
+ file.post_cascade_response = dropOurs(file.post_cascade_response);
73
+ file.pre_write_code.push({ command: hookCommand('fetch-rules') });
74
+ file.pre_user_prompt.push({ command: hookCommand('session-start') });
75
+ // Action Guards: pre_write_code fires before every write — closest
76
+ // Cascade equivalent to PreToolUse. Also fires guard-check on
77
+ // pre_user_prompt so shell / HTTP commands typed by the user are
78
+ // gated as well.
79
+ file.pre_write_code.push({ command: hookCommand('guard-check') });
80
+ if (opts.enableSessionReview) {
81
+ file.post_cascade_response.push({
82
+ command: hookCommand('session-review'),
83
+ });
84
+ }
85
+ writeJson(WINDSURF_HOOKS, file);
86
+ log.ok(`Windsurf hooks wired into ${WINDSURF_HOOKS}`);
87
+ log.hint('Note: Cascade has no PreCompact event, so long-session gap analysis only fires at end-of-response (post_cascade_response).');
88
+ // Inject the soft-enforcement snippet into .windsurfrules in the project
89
+ // directory (process.cwd() at install time = repo root). Windsurf's
90
+ // Cascade pre_write_code hook fires on file writes but not on Read/Bash/
91
+ // WebFetch tool calls, so the snippet closes that gap by instructing the
92
+ // model to call cybe_guards_check before ANY sensitive action via MCP.
93
+ const windsurfRulesPath = join(process.cwd(), '.windsurfrules');
94
+ appendGuardSnippetIdempotent(windsurfRulesPath, WINDSURF_GUARDS_SNIPPET, '<see .cybedefend/config.json>');
95
+ log.ok(`.windsurfrules updated at ${windsurfRulesPath}`);
96
+ }
97
+ /**
98
+ * Register the CybeDefend MCP server in `~/.codeium/windsurf/mcp_config.json`.
99
+ *
100
+ * Windsurf's MCP config (per docs.windsurf.com/windsurf/cascade/mcp) uses
101
+ * `serverUrl` (camelCase, distinct from Cursor's `url`) for remote HTTP
102
+ * servers. Schema:
103
+ * { "mcpServers": { "<name>": { "serverUrl": "<url>" } } }
104
+ */
105
+ function registerMcp(opts) {
106
+ log.step(`Registering MCP "${opts.region.mcpName}" in Windsurf`);
107
+ log.hint(`URL: ${opts.region.mcpUrl}`);
108
+ const file = readJson(WINDSURF_MCP, {});
109
+ file.mcpServers ??= {};
110
+ file.mcpServers[opts.region.mcpName] = { serverUrl: opts.region.mcpUrl };
111
+ writeJson(WINDSURF_MCP, file);
112
+ log.ok(`MCP "${opts.region.mcpName}" registered in ${WINDSURF_MCP}`);
113
+ return true;
114
+ }
115
+ /**
116
+ * Pure introspection — never throws. `hooksWired` from
117
+ * `~/.codeium/windsurf/hooks.json`, `mcpRegistered` from
118
+ * `~/.codeium/windsurf/mcp_config.json`. Raw-text substring checks keep
119
+ * the never-throw guarantee.
120
+ */
121
+ function inspect(region) {
122
+ let hooksWired = false;
123
+ try {
124
+ if (existsSync(WINDSURF_HOOKS)) {
125
+ hooksWired = readFileSync(WINDSURF_HOOKS, 'utf8').includes(VIBEDEFEND_PATH_MARKER);
126
+ }
127
+ }
128
+ catch {
129
+ /* missing/unreadable → false */
130
+ }
131
+ let mcpRegistered = false;
132
+ try {
133
+ if (existsSync(WINDSURF_MCP)) {
134
+ mcpRegistered = readFileSync(WINDSURF_MCP, 'utf8').includes(region.mcpName);
135
+ }
136
+ }
137
+ catch {
138
+ /* → false */
139
+ }
140
+ return { hooksWired, mcpRegistered };
141
+ }
142
+ export const windsurfAdapter = {
143
+ id: 'windsurf',
144
+ label: 'Windsurf (Cascade)',
145
+ detect,
146
+ supports,
147
+ writeSettings,
148
+ registerMcp,
149
+ inspect,
150
+ };
151
+ //# sourceMappingURL=windsurf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windsurf.js","sourceRoot":"","sources":["../../src/clients/windsurf.ts"],"names":[],"mappings":"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"}
package/dist/config.js ADDED
@@ -0,0 +1,32 @@
1
+ export const REGIONS = [
2
+ {
3
+ id: 'eu',
4
+ label: 'Production — EU',
5
+ description: 'EU production cluster. Pick this if your team is GDPR-scoped or based in Europe.',
6
+ mcpUrl: 'https://mcp.cybedefend.com/mcp',
7
+ apiBase: 'https://api.cybedefend.com',
8
+ mcpName: 'cybedefend',
9
+ dev: false,
10
+ },
11
+ {
12
+ id: 'us',
13
+ label: 'Production — US',
14
+ description: 'US production cluster. Pick this if your team is based in North America.',
15
+ mcpUrl: 'https://mcp-us.cybedefend.com/mcp',
16
+ apiBase: 'https://api-us.cybedefend.com',
17
+ mcpName: 'cybedefend',
18
+ dev: false,
19
+ },
20
+ ];
21
+ /**
22
+ * Defaults the installer pre-fills for the hook config step. Tuned from the
23
+ * earlier debug sessions: threshold=3 hides typo-fix noise without missing
24
+ * meaningful work; auto-propose stays OFF because policy mutations need an
25
+ * explicit user "yes" in the chat by default.
26
+ */
27
+ export const HOOK_DEFAULTS = {
28
+ enableSessionReview: true,
29
+ reviewThreshold: 3,
30
+ autoProposeMode: false,
31
+ };
32
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAgCA,MAAM,CAAC,MAAM,OAAO,GAA4B;IAC9C;QACE,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,iBAAiB;QACxB,WAAW,EACT,kFAAkF;QACpF,MAAM,EAAE,gCAAgC;QACxC,OAAO,EAAE,4BAA4B;QACrC,OAAO,EAAE,YAAY;QACrB,GAAG,EAAE,KAAK;KACX;IACD;QACE,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,iBAAiB;QACxB,WAAW,EACT,0EAA0E;QAC5E,MAAM,EAAE,mCAAmC;QAC3C,OAAO,EAAE,+BAA+B;QACxC,OAAO,EAAE,YAAY;QACrB,GAAG,EAAE,KAAK;KACX;CACO,CAAC;AAEX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,mBAAmB,EAAE,IAAI;IACzB,eAAe,EAAE,CAAC;IAClB,eAAe,EAAE,KAAK;CACd,CAAC"}