@cybedefend/vibedefend 1.5.0 → 1.6.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 (246) hide show
  1. package/README.md +67 -2
  2. package/dist/api/gateway-request.js +49 -0
  3. package/dist/api/gateway-request.js.map +1 -0
  4. package/dist/api/projects.js +67 -0
  5. package/dist/api/projects.js.map +1 -1
  6. package/dist/api/repository-link.js +157 -0
  7. package/dist/api/repository-link.js.map +1 -0
  8. package/dist/auth/auth-store.js +107 -25
  9. package/dist/auth/auth-store.js.map +1 -1
  10. package/dist/auth/auth.js +21 -0
  11. package/dist/auth/auth.js.map +1 -1
  12. package/dist/clients/cursor.js +5 -1
  13. package/dist/clients/cursor.js.map +1 -1
  14. package/dist/clients/vscode.js +38 -29
  15. package/dist/clients/vscode.js.map +1 -1
  16. package/dist/commands/mcp/allow.js +219 -0
  17. package/dist/commands/mcp/allow.js.map +1 -0
  18. package/dist/commands/mcp/connect.js +337 -0
  19. package/dist/commands/mcp/connect.js.map +1 -0
  20. package/dist/commands/mcp/index.js +170 -0
  21. package/dist/commands/mcp/index.js.map +1 -0
  22. package/dist/commands/mcp/proxy.js +264 -0
  23. package/dist/commands/mcp/proxy.js.map +1 -0
  24. package/dist/commands/mcp/scan.js +349 -0
  25. package/dist/commands/mcp/scan.js.map +1 -0
  26. package/dist/commands/mcp/sync.js +215 -0
  27. package/dist/commands/mcp/sync.js.map +1 -0
  28. package/dist/config.js +6 -0
  29. package/dist/config.js.map +1 -1
  30. package/dist/diagnostics.js +78 -12
  31. package/dist/diagnostics.js.map +1 -1
  32. package/dist/doctor.js +19 -0
  33. package/dist/doctor.js.map +1 -1
  34. package/dist/guards-evaluator/analysis-types.js +27 -0
  35. package/dist/guards-evaluator/analysis-types.js.map +1 -0
  36. package/dist/guards-evaluator/command-analysis.js +572 -0
  37. package/dist/guards-evaluator/command-analysis.js.map +1 -0
  38. package/dist/guards-evaluator/command-view.js +586 -0
  39. package/dist/guards-evaluator/command-view.js.map +1 -0
  40. package/dist/guards-evaluator/env.js +11 -0
  41. package/dist/guards-evaluator/env.js.map +1 -0
  42. package/dist/guards-evaluator/evaluate.js +91 -41
  43. package/dist/guards-evaluator/evaluate.js.map +1 -1
  44. package/dist/guards-evaluator/index.js +2 -1
  45. package/dist/guards-evaluator/index.js.map +1 -1
  46. package/dist/guards-evaluator/inline-code.js +259 -0
  47. package/dist/guards-evaluator/inline-code.js.map +1 -0
  48. package/dist/guards-evaluator/normalize.js +716 -0
  49. package/dist/guards-evaluator/normalize.js.map +1 -0
  50. package/dist/guards-evaluator/preprocess.js +13 -5
  51. package/dist/guards-evaluator/preprocess.js.map +1 -1
  52. package/dist/guards-evaluator/redact.js +19 -0
  53. package/dist/guards-evaluator/redact.js.map +1 -1
  54. package/dist/guards-evaluator/regex.js +25 -3
  55. package/dist/guards-evaluator/regex.js.map +1 -1
  56. package/dist/guards-evaluator/safe-commands.js +155 -0
  57. package/dist/guards-evaluator/safe-commands.js.map +1 -0
  58. package/dist/guards-evaluator/triage.js +315 -0
  59. package/dist/guards-evaluator/triage.js.map +1 -0
  60. package/dist/hook-runner.js +24679 -5079
  61. package/dist/hooks/install.js +38 -0
  62. package/dist/hooks/install.js.map +1 -1
  63. package/dist/hooks/runtime/config.js +38 -0
  64. package/dist/hooks/runtime/config.js.map +1 -1
  65. package/dist/hooks/runtime/emit.js +94 -61
  66. package/dist/hooks/runtime/emit.js.map +1 -1
  67. package/dist/hooks/runtime/fetch-rules.js +22 -7
  68. package/dist/hooks/runtime/fetch-rules.js.map +1 -1
  69. package/dist/hooks/runtime/gateway-http-error.js +34 -0
  70. package/dist/hooks/runtime/gateway-http-error.js.map +1 -0
  71. package/dist/hooks/runtime/guard-rules-cache.js +139 -17
  72. package/dist/hooks/runtime/guard-rules-cache.js.map +1 -1
  73. package/dist/hooks/runtime/guard-violations-buffer.js +321 -48
  74. package/dist/hooks/runtime/guard-violations-buffer.js.map +1 -1
  75. package/dist/hooks/runtime/judge-cache.js +6 -0
  76. package/dist/hooks/runtime/judge-cache.js.map +1 -1
  77. package/dist/hooks/runtime/judge-triage.js +193 -0
  78. package/dist/hooks/runtime/judge-triage.js.map +1 -0
  79. package/dist/hooks/runtime/judge.js +7 -1
  80. package/dist/hooks/runtime/judge.js.map +1 -1
  81. package/dist/hooks/runtime/pre-compact.js +12 -6
  82. package/dist/hooks/runtime/pre-compact.js.map +1 -1
  83. package/dist/hooks/runtime/resolve.js +90 -8
  84. package/dist/hooks/runtime/resolve.js.map +1 -1
  85. package/dist/hooks/runtime/retry-policy.js +57 -0
  86. package/dist/hooks/runtime/retry-policy.js.map +1 -0
  87. package/dist/hooks/runtime/review-sessions.js +74 -0
  88. package/dist/hooks/runtime/review-sessions.js.map +1 -0
  89. package/dist/hooks/runtime/script-resolve.js +695 -0
  90. package/dist/hooks/runtime/script-resolve.js.map +1 -0
  91. package/dist/hooks/runtime/session-activation.js +5 -1
  92. package/dist/hooks/runtime/session-activation.js.map +1 -1
  93. package/dist/hooks/runtime/session-review.js +163 -45
  94. package/dist/hooks/runtime/session-review.js.map +1 -1
  95. package/dist/hooks/runtime/session-start.js +2 -1
  96. package/dist/hooks/runtime/session-start.js.map +1 -1
  97. package/dist/hooks/runtime/session-writes.js +232 -0
  98. package/dist/hooks/runtime/session-writes.js.map +1 -0
  99. package/dist/hooks/runtime/sniff.js +26 -7
  100. package/dist/hooks/runtime/sniff.js.map +1 -1
  101. package/dist/hooks/runtime/target-resolve.js +336 -0
  102. package/dist/hooks/runtime/target-resolve.js.map +1 -0
  103. package/dist/hooks/runtime/unmapped-tools.js +93 -0
  104. package/dist/hooks/runtime/unmapped-tools.js.map +1 -0
  105. package/dist/hooks/runtime/usage-block.js +4 -0
  106. package/dist/hooks/runtime/usage-block.js.map +1 -1
  107. package/dist/hooks/runtime/user-prompt-submit.js +2 -1
  108. package/dist/hooks/runtime/user-prompt-submit.js.map +1 -1
  109. package/dist/hooks/runtime/wire-text.js +41 -0
  110. package/dist/hooks/runtime/wire-text.js.map +1 -0
  111. package/dist/hooks/runtime/work-dir.js +84 -0
  112. package/dist/hooks/runtime/work-dir.js.map +1 -0
  113. package/dist/index.js +45 -12
  114. package/dist/index.js.map +1 -1
  115. package/dist/install.js +174 -11
  116. package/dist/install.js.map +1 -1
  117. package/dist/link.js +74 -48
  118. package/dist/link.js.map +1 -1
  119. package/dist/login.js +77 -11
  120. package/dist/login.js.map +1 -1
  121. package/dist/mcp/auth/agent-sign-ins.js +174 -0
  122. package/dist/mcp/auth/agent-sign-ins.js.map +1 -0
  123. package/dist/mcp/auth/callback.js +200 -0
  124. package/dist/mcp/auth/callback.js.map +1 -0
  125. package/dist/mcp/auth/connect.js +392 -0
  126. package/dist/mcp/auth/connect.js.map +1 -0
  127. package/dist/mcp/auth/discovery.js +399 -0
  128. package/dist/mcp/auth/discovery.js.map +1 -0
  129. package/dist/mcp/auth/oauth.js +326 -0
  130. package/dist/mcp/auth/oauth.js.map +1 -0
  131. package/dist/mcp/auth/probe.js +128 -0
  132. package/dist/mcp/auth/probe.js.map +1 -0
  133. package/dist/mcp/auth/secrets.js +446 -0
  134. package/dist/mcp/auth/secrets.js.map +1 -0
  135. package/dist/mcp/auth/store.js +260 -0
  136. package/dist/mcp/auth/store.js.map +1 -0
  137. package/dist/mcp/auth/tokenSource.js +55 -0
  138. package/dist/mcp/auth/tokenSource.js.map +1 -0
  139. package/dist/mcp/config/atomicWrite.js +98 -0
  140. package/dist/mcp/config/atomicWrite.js.map +1 -0
  141. package/dist/mcp/config/clients.js +171 -0
  142. package/dist/mcp/config/clients.js.map +1 -0
  143. package/dist/mcp/config/cybedefend-servers.js +48 -0
  144. package/dist/mcp/config/cybedefend-servers.js.map +1 -0
  145. package/dist/mcp/config/discover.js +114 -0
  146. package/dist/mcp/config/discover.js.map +1 -0
  147. package/dist/mcp/config/hook.js +123 -0
  148. package/dist/mcp/config/hook.js.map +1 -0
  149. package/dist/mcp/config/index.js +11 -0
  150. package/dist/mcp/config/index.js.map +1 -0
  151. package/dist/mcp/config/install.js +132 -0
  152. package/dist/mcp/config/install.js.map +1 -0
  153. package/dist/mcp/config/installed.js +37 -0
  154. package/dist/mcp/config/installed.js.map +1 -0
  155. package/dist/mcp/config/jsonEdit.js +119 -0
  156. package/dist/mcp/config/jsonEdit.js.map +1 -0
  157. package/dist/mcp/config/lock.js +102 -0
  158. package/dist/mcp/config/lock.js.map +1 -0
  159. package/dist/mcp/config/proxyBinary.js +211 -0
  160. package/dist/mcp/config/proxyBinary.js.map +1 -0
  161. package/dist/mcp/config/rewrite.js +388 -0
  162. package/dist/mcp/config/rewrite.js.map +1 -0
  163. package/dist/mcp/config/types.js +34 -0
  164. package/dist/mcp/config/types.js.map +1 -0
  165. package/dist/mcp/proxy/audit.js +83 -0
  166. package/dist/mcp/proxy/audit.js.map +1 -0
  167. package/dist/mcp/proxy/authInterceptor.js +119 -0
  168. package/dist/mcp/proxy/authInterceptor.js.map +1 -0
  169. package/dist/mcp/proxy/expand.js +93 -0
  170. package/dist/mcp/proxy/expand.js.map +1 -0
  171. package/dist/mcp/proxy/inject.js +397 -0
  172. package/dist/mcp/proxy/inject.js.map +1 -0
  173. package/dist/mcp/proxy/intercept.js +37 -0
  174. package/dist/mcp/proxy/intercept.js.map +1 -0
  175. package/dist/mcp/proxy/jsonrpc.js +153 -0
  176. package/dist/mcp/proxy/jsonrpc.js.map +1 -0
  177. package/dist/mcp/proxy/log.js +109 -0
  178. package/dist/mcp/proxy/log.js.map +1 -0
  179. package/dist/mcp/proxy/paths.js +53 -0
  180. package/dist/mcp/proxy/paths.js.map +1 -0
  181. package/dist/mcp/proxy/proxy.js +510 -0
  182. package/dist/mcp/proxy/proxy.js.map +1 -0
  183. package/dist/mcp/proxy/spec.js +203 -0
  184. package/dist/mcp/proxy/spec.js.map +1 -0
  185. package/dist/mcp/proxy/sse.js +77 -0
  186. package/dist/mcp/proxy/sse.js.map +1 -0
  187. package/dist/mcp/proxy/upstream.js +2 -0
  188. package/dist/mcp/proxy/upstream.js.map +1 -0
  189. package/dist/mcp/proxy/upstreamHttp.js +499 -0
  190. package/dist/mcp/proxy/upstreamHttp.js.map +1 -0
  191. package/dist/mcp/proxy/upstreamStdio.js +188 -0
  192. package/dist/mcp/proxy/upstreamStdio.js.map +1 -0
  193. package/dist/mcp/proxy/upstreams.js +143 -0
  194. package/dist/mcp/proxy/upstreams.js.map +1 -0
  195. package/dist/mcp/proxy/verifyInterceptor.js +559 -0
  196. package/dist/mcp/proxy/verifyInterceptor.js.map +1 -0
  197. package/dist/mcp/proxy/windowsCommand.js +99 -0
  198. package/dist/mcp/proxy/windowsCommand.js.map +1 -0
  199. package/dist/mcp/scan/args.js +228 -0
  200. package/dist/mcp/scan/args.js.map +1 -0
  201. package/dist/mcp/scan/results.js +253 -0
  202. package/dist/mcp/scan/results.js.map +1 -0
  203. package/dist/mcp/scan/types.js +40 -0
  204. package/dist/mcp/scan/types.js.map +1 -0
  205. package/dist/mcp/verify/api.js +475 -0
  206. package/dist/mcp/verify/api.js.map +1 -0
  207. package/dist/mcp/verify/backend.js +143 -0
  208. package/dist/mcp/verify/backend.js.map +1 -0
  209. package/dist/mcp/verify/cache.js +182 -0
  210. package/dist/mcp/verify/cache.js.map +1 -0
  211. package/dist/mcp/verify/contract-errors.js +198 -0
  212. package/dist/mcp/verify/contract-errors.js.map +1 -0
  213. package/dist/mcp/verify/digest.js +91 -0
  214. package/dist/mcp/verify/digest.js.map +1 -0
  215. package/dist/mcp/verify/factory.js +56 -0
  216. package/dist/mcp/verify/factory.js.map +1 -0
  217. package/dist/mcp/verify/identity.js +173 -0
  218. package/dist/mcp/verify/identity.js.map +1 -0
  219. package/dist/mcp/verify/policy-store.js +63 -0
  220. package/dist/mcp/verify/policy-store.js.map +1 -0
  221. package/dist/mcp/verify/policy.js +158 -0
  222. package/dist/mcp/verify/policy.js.map +1 -0
  223. package/dist/mcp/verify/pool.js +27 -0
  224. package/dist/mcp/verify/pool.js.map +1 -0
  225. package/dist/mcp/verify/token-refresh.js +44 -0
  226. package/dist/mcp/verify/token-refresh.js.map +1 -0
  227. package/dist/mcp/verify/token.js +67 -0
  228. package/dist/mcp/verify/token.js.map +1 -0
  229. package/dist/mcp/verify/verifier.js +1009 -0
  230. package/dist/mcp/verify/verifier.js.map +1 -0
  231. package/dist/org-gate.js +1 -1
  232. package/dist/org-gate.js.map +1 -1
  233. package/dist/org.js +146 -0
  234. package/dist/org.js.map +1 -0
  235. package/dist/project-create.js +129 -0
  236. package/dist/project-create.js.map +1 -0
  237. package/dist/prompts.js +21 -0
  238. package/dist/prompts.js.map +1 -1
  239. package/dist/re2.wasm +0 -0
  240. package/dist/status.js +61 -0
  241. package/dist/status.js.map +1 -1
  242. package/dist/uninstall.js +49 -4
  243. package/dist/uninstall.js.map +1 -1
  244. package/dist/utils.js +62 -6
  245. package/dist/utils.js.map +1 -1
  246. package/package.json +10 -3
@@ -0,0 +1,102 @@
1
+ /**
2
+ * One sync at a time, across processes.
3
+ *
4
+ * The proxy runs one process per MCP server, and each of them wants to sync
5
+ * at startup. Five processes rewriting `~/.claude.json` at the same second is
6
+ * how a lost update happens: they all read the same document, they all write,
7
+ * and the last one wins — taking with it whatever the others (or the client
8
+ * itself) had just added.
9
+ *
10
+ * `open(…, 'wx')` is the whole mechanism: it creates the file or fails, in
11
+ * one syscall, on every platform we ship to. No dependency, no daemon.
12
+ *
13
+ * A lock is stolen once it is older than `STALE_AFTER_MS`. A proxy killed
14
+ * with SIGKILL leaves its lock behind, and a park that never syncs again
15
+ * because of a file nobody will ever delete is worse than the race the lock
16
+ * exists to prevent.
17
+ */
18
+ import { closeSync, mkdirSync, openSync, readFileSync, unlinkSync, writeSync } from 'node:fs';
19
+ import { dirname, join } from 'node:path';
20
+ import { mcpHomeDir } from '../proxy/paths.js';
21
+ export const STALE_AFTER_MS = 60_000;
22
+ export function syncLockPath(env = process.env) {
23
+ return join(mcpHomeDir(env), 'sync.lock');
24
+ }
25
+ /**
26
+ * Runs `body` while holding the lock, or returns `null` without running it.
27
+ *
28
+ * `null` is not a failure: it means another process is already doing exactly
29
+ * this work, and the right thing is to let it.
30
+ */
31
+ export async function withSyncLock(body, deps = {}) {
32
+ const path = syncLockPath(deps.env ?? process.env);
33
+ const now = deps.now ?? Date.now;
34
+ const staleAfter = deps.staleAfterMs ?? STALE_AFTER_MS;
35
+ if (!acquire(path, now(), staleAfter, now))
36
+ return null;
37
+ try {
38
+ return await body();
39
+ }
40
+ finally {
41
+ try {
42
+ unlinkSync(path);
43
+ }
44
+ catch {
45
+ /* someone stole it; they own the cleanup */
46
+ }
47
+ }
48
+ }
49
+ function acquire(path, stamp, staleAfter, now) {
50
+ try {
51
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
52
+ }
53
+ catch {
54
+ return false;
55
+ }
56
+ if (tryCreate(path, stamp))
57
+ return true;
58
+ // Held. Only steal it if whoever wrote it is long gone.
59
+ let age = Number.POSITIVE_INFINITY;
60
+ try {
61
+ const held = Number(JSON.parse(readFileSync(path, 'utf8')).at ?? 0);
62
+ age = now() - held;
63
+ }
64
+ catch {
65
+ // Unreadable lock file: treat it as stale rather than as a permanent
66
+ // block, which is what a truncated write would otherwise cause.
67
+ }
68
+ if (age < staleAfter)
69
+ return false;
70
+ try {
71
+ unlinkSync(path);
72
+ }
73
+ catch {
74
+ return false;
75
+ }
76
+ return tryCreate(path, stamp);
77
+ }
78
+ function tryCreate(path, stamp) {
79
+ let handle;
80
+ try {
81
+ handle = openSync(path, 'wx', 0o600);
82
+ }
83
+ catch {
84
+ return false;
85
+ }
86
+ try {
87
+ writeSync(handle, JSON.stringify({ pid: process.pid, at: stamp }));
88
+ }
89
+ catch {
90
+ /* the lock is held either way; the contents are only a diagnostic */
91
+ }
92
+ finally {
93
+ try {
94
+ closeSync(handle);
95
+ }
96
+ catch {
97
+ /* nothing to close */
98
+ }
99
+ }
100
+ return true;
101
+ }
102
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../../../src/mcp/config/lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Is the `vibedefend` that is running the one a client would spawn?
3
+ *
4
+ * A wrapped entry says `{"command":"vibedefend","args":["mcp","--name",…]}`
5
+ * and nothing more, so it works only if the `vibedefend` a client finds on
6
+ * the PATH is a release that has the `mcp` subcommand. Two things follow:
7
+ *
8
+ * - the proxy's background sync may rewrite a client config only when the
9
+ * proxy itself IS that binary — the entries it writes then point at the
10
+ * thing that is demonstrably running. `node dist/index.js` in a checkout
11
+ * is somebody else, and its entries would point at whatever older release
12
+ * the PATH holds: measured on 2026-09-08, three clients broken at once;
13
+ * - an explicit install may proceed from another binary, but only after
14
+ * asking the PATH's `vibedefend` whether it knows `mcp`.
15
+ *
16
+ * What "the binary on the PATH" delegates to is read from the shim itself:
17
+ * a symlink (npm on POSIX), a shell script (pnpm everywhere, npm's cmd-shim
18
+ * for POSIX callers on Windows) or a `.cmd` (npm on Windows) all name the
19
+ * JavaScript entry point they run, and that entry point is what
20
+ * `process.argv[1]` resolves to in the running process.
21
+ */
22
+ import { spawnSync } from 'node:child_process';
23
+ import { readFileSync, realpathSync, statSync } from 'node:fs';
24
+ import { dirname, isAbsolute, resolve, sep } from 'node:path';
25
+ const BINARY_NAME = 'vibedefend';
26
+ const DEFAULT_PATHEXT = '.COM;.EXE;.BAT;.CMD';
27
+ /** A shim is a few hundred bytes; anything bigger is a real program, not a pointer. */
28
+ const MAX_SHIM_BYTES = 64 * 1024;
29
+ const SCRIPT_SUFFIX = /\.(?:js|cjs|mjs)$/i;
30
+ /** The first `vibedefend` on the PATH, the way a client's `spawn` would find it. */
31
+ export function findProxyBinaryOnPath(deps = {}) {
32
+ const env = deps.env ?? process.env;
33
+ const platform = deps.platform ?? process.platform;
34
+ const existsFn = deps.existsFn ?? isFile;
35
+ const path = envValue(env, 'PATH');
36
+ if (!path)
37
+ return null;
38
+ const names = platform === 'win32'
39
+ ? (envValue(env, 'PATHEXT') ?? DEFAULT_PATHEXT)
40
+ .split(';')
41
+ .filter((ext) => ext.trim() !== '')
42
+ // The file system is case-insensitive there and PATHEXT is spelled
43
+ // in capitals; probing the lower-case name returns the path as npm
44
+ // wrote it.
45
+ .map((ext) => BINARY_NAME + ext.trim().toLowerCase())
46
+ : [BINARY_NAME];
47
+ for (const dir of path.split(platform === 'win32' ? ';' : ':')) {
48
+ if (dir.trim() === '')
49
+ continue;
50
+ for (const name of names) {
51
+ const candidate = resolve(dir, name);
52
+ if (existsFn(candidate))
53
+ return candidate;
54
+ }
55
+ }
56
+ return null;
57
+ }
58
+ /**
59
+ * The real paths a PATH entry ends up running.
60
+ *
61
+ * Always its own real path (a symlink resolves to the script; a script is
62
+ * itself). Then, when it is a small text file, every token in it that names a
63
+ * JavaScript file, with the placeholders the shim generators use for "the
64
+ * directory I am in" filled in. A token that still holds a variable after
65
+ * that is somebody else's and is ignored.
66
+ */
67
+ export function proxyBinaryDelegates(shim, deps = {}) {
68
+ const platform = deps.platform ?? process.platform;
69
+ const existsFn = deps.existsFn ?? isFile;
70
+ const readFileFn = deps.readFileFn ?? readShim;
71
+ const realpathFn = deps.realpathFn ?? realpathSync;
72
+ const out = new Set();
73
+ try {
74
+ out.add(realpathFn(shim));
75
+ }
76
+ catch {
77
+ /* dangling symlink: nothing to delegate to */
78
+ }
79
+ let text;
80
+ try {
81
+ text = readFileFn(shim);
82
+ }
83
+ catch {
84
+ return [...out];
85
+ }
86
+ const shimDir = dirname(shim);
87
+ for (const token of text.split(/["'\s]+/)) {
88
+ if (!SCRIPT_SUFFIX.test(token))
89
+ continue;
90
+ let candidate = token
91
+ .replace(/%~dp0/gi, shimDir)
92
+ .replace(/%dp0%/gi, shimDir)
93
+ .replace(/\$\{basedir\}|\$basedir/g, shimDir);
94
+ if (/[$%]/.test(candidate))
95
+ continue;
96
+ if (platform === 'win32')
97
+ candidate = candidate.replace(/\\/g, sep);
98
+ if (!isAbsolute(candidate))
99
+ candidate = resolve(shimDir, candidate);
100
+ if (!existsFn(candidate))
101
+ continue;
102
+ try {
103
+ out.add(realpathFn(candidate));
104
+ }
105
+ catch {
106
+ /* raced away; not a delegate */
107
+ }
108
+ }
109
+ return [...out];
110
+ }
111
+ export function checkProxyBinary(deps = {}) {
112
+ const env = deps.env ?? process.env;
113
+ const platform = deps.platform ?? process.platform;
114
+ const existsFn = deps.existsFn ?? isFile;
115
+ const realpathFn = deps.realpathFn ?? realpathSync;
116
+ let running = null;
117
+ const argv1 = deps.argv1 ?? process.argv[1];
118
+ if (argv1 && existsFn(argv1)) {
119
+ try {
120
+ running = realpathFn(argv1);
121
+ }
122
+ catch {
123
+ running = null;
124
+ }
125
+ }
126
+ const onPath = findProxyBinaryOnPath({ ...deps, env, platform });
127
+ const base = { running, onPath, platform, env };
128
+ if (!onPath)
129
+ return { ...base, delegates: [], matches: false, reason: 'not-on-path' };
130
+ const delegates = proxyBinaryDelegates(onPath, { ...deps, env, platform });
131
+ if (!running)
132
+ return { ...base, delegates, matches: false, reason: 'no-entry-point' };
133
+ const matches = delegates.includes(running);
134
+ return matches
135
+ ? { ...base, delegates, matches: true }
136
+ : { ...base, delegates, matches: false, reason: 'different-binary' };
137
+ }
138
+ /**
139
+ * The option every wrapped entry passes. A help text that describes it is a
140
+ * release that can serve the entry; one that does not is not, whatever its
141
+ * exit code says.
142
+ */
143
+ const WRAPPED_ENTRY_OPTION = /--name\b/;
144
+ /**
145
+ * Does the `vibedefend` on the PATH have the `mcp` subcommand?
146
+ *
147
+ * Trivially yes when it is the running binary. Otherwise the only honest
148
+ * answer comes from asking it — and the exit code of `mcp --help` proves
149
+ * nothing: measured on 1.4.2, commander prints the PROGRAM help and exits 0
150
+ * for an unknown command followed by `--help`. What proves it is the help
151
+ * describing `--name`, the option a wrapped entry runs with. A `.cmd` shim is
152
+ * not an executable and goes through the command interpreter.
153
+ */
154
+ export function proxyBinaryKnowsMcp(check, deps = {}) {
155
+ if (!check.onPath)
156
+ return false;
157
+ if (check.matches)
158
+ return true;
159
+ const execFileFn = deps.execFileFn ?? defaultExecFile;
160
+ try {
161
+ const result = check.platform === 'win32' && /\.(?:cmd|bat)$/i.test(check.onPath)
162
+ ? execFileFn(envValue(check.env, 'ComSpec') ?? 'cmd.exe', [
163
+ '/d',
164
+ '/s',
165
+ '/c',
166
+ `"${check.onPath}" mcp --help`,
167
+ ])
168
+ : execFileFn(check.onPath, ['mcp', '--help']);
169
+ return result.status === 0 && WRAPPED_ENTRY_OPTION.test(result.output ?? '');
170
+ }
171
+ catch {
172
+ return false;
173
+ }
174
+ }
175
+ /** Environment lookups are case-insensitive on Windows (`Path`, `ComSpec`), so be everywhere. */
176
+ function envValue(env, name) {
177
+ const direct = env[name];
178
+ if (direct !== undefined)
179
+ return direct;
180
+ const wanted = name.toLowerCase();
181
+ for (const [key, value] of Object.entries(env)) {
182
+ if (key.toLowerCase() === wanted)
183
+ return value;
184
+ }
185
+ return undefined;
186
+ }
187
+ function isFile(path) {
188
+ try {
189
+ return statSync(path).isFile();
190
+ }
191
+ catch {
192
+ return false;
193
+ }
194
+ }
195
+ function readShim(path) {
196
+ if (statSync(path).size > MAX_SHIM_BYTES)
197
+ throw new Error('not a shim');
198
+ return readFileSync(path, 'utf8');
199
+ }
200
+ function defaultExecFile(file, args) {
201
+ const result = spawnSync(file, args, {
202
+ encoding: 'utf8',
203
+ stdio: ['ignore', 'pipe', 'pipe'],
204
+ timeout: 15_000,
205
+ windowsHide: true,
206
+ });
207
+ if (result.error)
208
+ throw result.error;
209
+ return { status: result.status, output: `${result.stdout ?? ''}${result.stderr ?? ''}` };
210
+ }
211
+ //# sourceMappingURL=proxyBinary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxyBinary.js","sourceRoot":"","sources":["../../../src/mcp/config/proxyBinary.ts"],"names":[],"mappings":"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"}