@cybedefend/vibedefend 1.4.7 → 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.
- package/README.md +77 -2
- package/dist/api/gateway-request.js +49 -0
- package/dist/api/gateway-request.js.map +1 -0
- package/dist/api/projects.js +67 -0
- package/dist/api/projects.js.map +1 -1
- package/dist/api/repository-link.js +157 -0
- package/dist/api/repository-link.js.map +1 -0
- package/dist/auth/auth-store.js +107 -25
- package/dist/auth/auth-store.js.map +1 -1
- package/dist/auth/auth.js +21 -0
- package/dist/auth/auth.js.map +1 -1
- package/dist/clients/cursor.js +5 -1
- package/dist/clients/cursor.js.map +1 -1
- package/dist/clients/vscode.js +38 -29
- package/dist/clients/vscode.js.map +1 -1
- package/dist/commands/mcp/allow.js +219 -0
- package/dist/commands/mcp/allow.js.map +1 -0
- package/dist/commands/mcp/connect.js +337 -0
- package/dist/commands/mcp/connect.js.map +1 -0
- package/dist/commands/mcp/index.js +170 -0
- package/dist/commands/mcp/index.js.map +1 -0
- package/dist/commands/mcp/proxy.js +264 -0
- package/dist/commands/mcp/proxy.js.map +1 -0
- package/dist/commands/mcp/scan.js +349 -0
- package/dist/commands/mcp/scan.js.map +1 -0
- package/dist/commands/mcp/sync.js +215 -0
- package/dist/commands/mcp/sync.js.map +1 -0
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/diagnostics.js +78 -12
- package/dist/diagnostics.js.map +1 -1
- package/dist/doctor.js +19 -0
- package/dist/doctor.js.map +1 -1
- package/dist/guards-evaluator/analysis-types.js +27 -0
- package/dist/guards-evaluator/analysis-types.js.map +1 -0
- package/dist/guards-evaluator/command-analysis.js +572 -0
- package/dist/guards-evaluator/command-analysis.js.map +1 -0
- package/dist/guards-evaluator/command-view.js +586 -0
- package/dist/guards-evaluator/command-view.js.map +1 -0
- package/dist/guards-evaluator/env.js +11 -0
- package/dist/guards-evaluator/env.js.map +1 -0
- package/dist/guards-evaluator/evaluate.js +91 -41
- package/dist/guards-evaluator/evaluate.js.map +1 -1
- package/dist/guards-evaluator/index.js +2 -1
- package/dist/guards-evaluator/index.js.map +1 -1
- package/dist/guards-evaluator/inline-code.js +259 -0
- package/dist/guards-evaluator/inline-code.js.map +1 -0
- package/dist/guards-evaluator/normalize.js +716 -0
- package/dist/guards-evaluator/normalize.js.map +1 -0
- package/dist/guards-evaluator/preprocess.js +13 -5
- package/dist/guards-evaluator/preprocess.js.map +1 -1
- package/dist/guards-evaluator/redact.js +19 -0
- package/dist/guards-evaluator/redact.js.map +1 -1
- package/dist/guards-evaluator/regex.js +25 -3
- package/dist/guards-evaluator/regex.js.map +1 -1
- package/dist/guards-evaluator/safe-commands.js +155 -0
- package/dist/guards-evaluator/safe-commands.js.map +1 -0
- package/dist/guards-evaluator/triage.js +315 -0
- package/dist/guards-evaluator/triage.js.map +1 -0
- package/dist/hook-runner.js +24873 -5068
- package/dist/hooks/install.js +38 -0
- package/dist/hooks/install.js.map +1 -1
- package/dist/hooks/runtime/config.js +38 -0
- package/dist/hooks/runtime/config.js.map +1 -1
- package/dist/hooks/runtime/emit.js +126 -53
- package/dist/hooks/runtime/emit.js.map +1 -1
- package/dist/hooks/runtime/fetch-rules.js +27 -7
- package/dist/hooks/runtime/fetch-rules.js.map +1 -1
- package/dist/hooks/runtime/gateway-http-error.js +34 -0
- package/dist/hooks/runtime/gateway-http-error.js.map +1 -0
- package/dist/hooks/runtime/guard-rules-cache.js +139 -17
- package/dist/hooks/runtime/guard-rules-cache.js.map +1 -1
- package/dist/hooks/runtime/guard-violations-buffer.js +321 -48
- package/dist/hooks/runtime/guard-violations-buffer.js.map +1 -1
- package/dist/hooks/runtime/judge-cache.js +6 -0
- package/dist/hooks/runtime/judge-cache.js.map +1 -1
- package/dist/hooks/runtime/judge-triage.js +193 -0
- package/dist/hooks/runtime/judge-triage.js.map +1 -0
- package/dist/hooks/runtime/judge.js +7 -1
- package/dist/hooks/runtime/judge.js.map +1 -1
- package/dist/hooks/runtime/pre-compact.js +21 -6
- package/dist/hooks/runtime/pre-compact.js.map +1 -1
- package/dist/hooks/runtime/resolve.js +108 -17
- package/dist/hooks/runtime/resolve.js.map +1 -1
- package/dist/hooks/runtime/retry-policy.js +57 -0
- package/dist/hooks/runtime/retry-policy.js.map +1 -0
- package/dist/hooks/runtime/review-sessions.js +74 -0
- package/dist/hooks/runtime/review-sessions.js.map +1 -0
- package/dist/hooks/runtime/script-resolve.js +695 -0
- package/dist/hooks/runtime/script-resolve.js.map +1 -0
- package/dist/hooks/runtime/session-activation.js +226 -0
- package/dist/hooks/runtime/session-activation.js.map +1 -0
- package/dist/hooks/runtime/session-review.js +174 -46
- package/dist/hooks/runtime/session-review.js.map +1 -1
- package/dist/hooks/runtime/session-start.js +35 -4
- package/dist/hooks/runtime/session-start.js.map +1 -1
- package/dist/hooks/runtime/session-writes.js +232 -0
- package/dist/hooks/runtime/session-writes.js.map +1 -0
- package/dist/hooks/runtime/sniff.js +26 -7
- package/dist/hooks/runtime/sniff.js.map +1 -1
- package/dist/hooks/runtime/target-resolve.js +336 -0
- package/dist/hooks/runtime/target-resolve.js.map +1 -0
- package/dist/hooks/runtime/unmapped-tools.js +93 -0
- package/dist/hooks/runtime/unmapped-tools.js.map +1 -0
- package/dist/hooks/runtime/usage-block.js +4 -0
- package/dist/hooks/runtime/usage-block.js.map +1 -1
- package/dist/hooks/runtime/user-prompt-submit.js +8 -2
- package/dist/hooks/runtime/user-prompt-submit.js.map +1 -1
- package/dist/hooks/runtime/wire-text.js +41 -0
- package/dist/hooks/runtime/wire-text.js.map +1 -0
- package/dist/hooks/runtime/work-dir.js +84 -0
- package/dist/hooks/runtime/work-dir.js.map +1 -0
- package/dist/index.js +45 -12
- package/dist/index.js.map +1 -1
- package/dist/install.js +174 -11
- package/dist/install.js.map +1 -1
- package/dist/link.js +74 -48
- package/dist/link.js.map +1 -1
- package/dist/login.js +99 -14
- package/dist/login.js.map +1 -1
- package/dist/mcp/auth/agent-sign-ins.js +174 -0
- package/dist/mcp/auth/agent-sign-ins.js.map +1 -0
- package/dist/mcp/auth/callback.js +200 -0
- package/dist/mcp/auth/callback.js.map +1 -0
- package/dist/mcp/auth/connect.js +392 -0
- package/dist/mcp/auth/connect.js.map +1 -0
- package/dist/mcp/auth/discovery.js +399 -0
- package/dist/mcp/auth/discovery.js.map +1 -0
- package/dist/mcp/auth/oauth.js +326 -0
- package/dist/mcp/auth/oauth.js.map +1 -0
- package/dist/mcp/auth/probe.js +128 -0
- package/dist/mcp/auth/probe.js.map +1 -0
- package/dist/mcp/auth/secrets.js +446 -0
- package/dist/mcp/auth/secrets.js.map +1 -0
- package/dist/mcp/auth/store.js +260 -0
- package/dist/mcp/auth/store.js.map +1 -0
- package/dist/mcp/auth/tokenSource.js +55 -0
- package/dist/mcp/auth/tokenSource.js.map +1 -0
- package/dist/mcp/config/atomicWrite.js +98 -0
- package/dist/mcp/config/atomicWrite.js.map +1 -0
- package/dist/mcp/config/clients.js +171 -0
- package/dist/mcp/config/clients.js.map +1 -0
- package/dist/mcp/config/cybedefend-servers.js +48 -0
- package/dist/mcp/config/cybedefend-servers.js.map +1 -0
- package/dist/mcp/config/discover.js +114 -0
- package/dist/mcp/config/discover.js.map +1 -0
- package/dist/mcp/config/hook.js +123 -0
- package/dist/mcp/config/hook.js.map +1 -0
- package/dist/mcp/config/index.js +11 -0
- package/dist/mcp/config/index.js.map +1 -0
- package/dist/mcp/config/install.js +132 -0
- package/dist/mcp/config/install.js.map +1 -0
- package/dist/mcp/config/installed.js +37 -0
- package/dist/mcp/config/installed.js.map +1 -0
- package/dist/mcp/config/jsonEdit.js +119 -0
- package/dist/mcp/config/jsonEdit.js.map +1 -0
- package/dist/mcp/config/lock.js +102 -0
- package/dist/mcp/config/lock.js.map +1 -0
- package/dist/mcp/config/proxyBinary.js +211 -0
- package/dist/mcp/config/proxyBinary.js.map +1 -0
- package/dist/mcp/config/rewrite.js +388 -0
- package/dist/mcp/config/rewrite.js.map +1 -0
- package/dist/mcp/config/types.js +34 -0
- package/dist/mcp/config/types.js.map +1 -0
- package/dist/mcp/proxy/audit.js +83 -0
- package/dist/mcp/proxy/audit.js.map +1 -0
- package/dist/mcp/proxy/authInterceptor.js +119 -0
- package/dist/mcp/proxy/authInterceptor.js.map +1 -0
- package/dist/mcp/proxy/expand.js +93 -0
- package/dist/mcp/proxy/expand.js.map +1 -0
- package/dist/mcp/proxy/inject.js +397 -0
- package/dist/mcp/proxy/inject.js.map +1 -0
- package/dist/mcp/proxy/intercept.js +37 -0
- package/dist/mcp/proxy/intercept.js.map +1 -0
- package/dist/mcp/proxy/jsonrpc.js +153 -0
- package/dist/mcp/proxy/jsonrpc.js.map +1 -0
- package/dist/mcp/proxy/log.js +109 -0
- package/dist/mcp/proxy/log.js.map +1 -0
- package/dist/mcp/proxy/paths.js +53 -0
- package/dist/mcp/proxy/paths.js.map +1 -0
- package/dist/mcp/proxy/proxy.js +510 -0
- package/dist/mcp/proxy/proxy.js.map +1 -0
- package/dist/mcp/proxy/spec.js +203 -0
- package/dist/mcp/proxy/spec.js.map +1 -0
- package/dist/mcp/proxy/sse.js +77 -0
- package/dist/mcp/proxy/sse.js.map +1 -0
- package/dist/mcp/proxy/upstream.js +2 -0
- package/dist/mcp/proxy/upstream.js.map +1 -0
- package/dist/mcp/proxy/upstreamHttp.js +499 -0
- package/dist/mcp/proxy/upstreamHttp.js.map +1 -0
- package/dist/mcp/proxy/upstreamStdio.js +188 -0
- package/dist/mcp/proxy/upstreamStdio.js.map +1 -0
- package/dist/mcp/proxy/upstreams.js +143 -0
- package/dist/mcp/proxy/upstreams.js.map +1 -0
- package/dist/mcp/proxy/verifyInterceptor.js +559 -0
- package/dist/mcp/proxy/verifyInterceptor.js.map +1 -0
- package/dist/mcp/proxy/windowsCommand.js +99 -0
- package/dist/mcp/proxy/windowsCommand.js.map +1 -0
- package/dist/mcp/scan/args.js +228 -0
- package/dist/mcp/scan/args.js.map +1 -0
- package/dist/mcp/scan/results.js +253 -0
- package/dist/mcp/scan/results.js.map +1 -0
- package/dist/mcp/scan/types.js +40 -0
- package/dist/mcp/scan/types.js.map +1 -0
- package/dist/mcp/verify/api.js +475 -0
- package/dist/mcp/verify/api.js.map +1 -0
- package/dist/mcp/verify/backend.js +143 -0
- package/dist/mcp/verify/backend.js.map +1 -0
- package/dist/mcp/verify/cache.js +182 -0
- package/dist/mcp/verify/cache.js.map +1 -0
- package/dist/mcp/verify/contract-errors.js +198 -0
- package/dist/mcp/verify/contract-errors.js.map +1 -0
- package/dist/mcp/verify/digest.js +91 -0
- package/dist/mcp/verify/digest.js.map +1 -0
- package/dist/mcp/verify/factory.js +56 -0
- package/dist/mcp/verify/factory.js.map +1 -0
- package/dist/mcp/verify/identity.js +173 -0
- package/dist/mcp/verify/identity.js.map +1 -0
- package/dist/mcp/verify/policy-store.js +63 -0
- package/dist/mcp/verify/policy-store.js.map +1 -0
- package/dist/mcp/verify/policy.js +158 -0
- package/dist/mcp/verify/policy.js.map +1 -0
- package/dist/mcp/verify/pool.js +27 -0
- package/dist/mcp/verify/pool.js.map +1 -0
- package/dist/mcp/verify/token-refresh.js +44 -0
- package/dist/mcp/verify/token-refresh.js.map +1 -0
- package/dist/mcp/verify/token.js +67 -0
- package/dist/mcp/verify/token.js.map +1 -0
- package/dist/mcp/verify/verifier.js +1009 -0
- package/dist/mcp/verify/verifier.js.map +1 -0
- package/dist/org-gate.js +1 -1
- package/dist/org-gate.js.map +1 -1
- package/dist/org.js +146 -0
- package/dist/org.js.map +1 -0
- package/dist/project-create.js +129 -0
- package/dist/project-create.js.map +1 -0
- package/dist/prompts.js +21 -0
- package/dist/prompts.js.map +1 -1
- package/dist/re2.wasm +0 -0
- package/dist/status.js +61 -0
- package/dist/status.js.map +1 -1
- package/dist/uninstall.js +49 -4
- package/dist/uninstall.js.map +1 -1
- package/dist/utils.js +62 -6
- package/dist/utils.js.map +1 -1
- package/package.json +10 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cybedefend-servers.js","sourceRoot":"","sources":["../../../src/mcp/config/cybedefend-servers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,SAAS,aAAa,CAAC,IAAY;IACjC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,iBAAiB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACpE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,IAAI,IAAI,OAAO,EAAE,EAAE,aAAa,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAc,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAEtD,CAAC;IACT,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;IAC7D,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/B,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE,CAAC;YACjC,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;gBAAE,IAAI,CAAC,IAAI,CAAE,MAA+B,CAAC,MAAM,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAiB,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC3F,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,MAAyB,OAAO,CAAC,GAAG;IAClF,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading every MCP server a user has configured, across clients.
|
|
3
|
+
*
|
|
4
|
+
* Nothing here writes. Discovery is used by `sync` (what changed?), by `scan`
|
|
5
|
+
* (what is out there?) and by `install` (what should be wrapped?), and all
|
|
6
|
+
* three want the same answer, so it is computed once and in one shape.
|
|
7
|
+
*
|
|
8
|
+
* It never throws. A client whose config is a JSON fragment mid-edit, or a
|
|
9
|
+
* file the user cannot read, is reported as a problem on that one file — the
|
|
10
|
+
* measured worst outcome of the previous generation was a single malformed
|
|
11
|
+
* server blinding the verification of the whole park.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
14
|
+
import { MCP_CLIENT_ADAPTERS, mcpAdapterFor } from './clients.js';
|
|
15
|
+
import { readJsonDocument } from './jsonEdit.js';
|
|
16
|
+
import { wrappedUpstreamName, } from './types.js';
|
|
17
|
+
export function discoverMcpConfigs(options = {}) {
|
|
18
|
+
const env = options.env ?? process.env;
|
|
19
|
+
const platform = options.platform ?? process.platform;
|
|
20
|
+
const readFileFn = options.readFileFn ?? ((path) => readFileSync(path, 'utf8'));
|
|
21
|
+
const existsFn = options.existsFn ?? existsSync;
|
|
22
|
+
const adapters = options.clients && options.clients.length > 0
|
|
23
|
+
? options.clients.map((id) => mcpAdapterFor(id))
|
|
24
|
+
: MCP_CLIENT_ADAPTERS;
|
|
25
|
+
const entries = [];
|
|
26
|
+
const problems = [];
|
|
27
|
+
const files = [];
|
|
28
|
+
for (const adapter of adapters) {
|
|
29
|
+
for (const location of adapter.locations(env, platform)) {
|
|
30
|
+
if (!existsFn(location.file))
|
|
31
|
+
continue;
|
|
32
|
+
let text;
|
|
33
|
+
try {
|
|
34
|
+
text = readFileFn(location.file);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
problems.push({ location, problem: 'unreadable' });
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const parsed = readJsonDocument(text);
|
|
41
|
+
if (!parsed.ok) {
|
|
42
|
+
problems.push({ location, problem: parsed.problem });
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
files.push(location);
|
|
46
|
+
entries.push(...entriesIn(adapter, location, parsed.document));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { entries, problems, files };
|
|
50
|
+
}
|
|
51
|
+
/** Every server in one document, from every map the client uses. */
|
|
52
|
+
export function entriesIn(adapter, location, document) {
|
|
53
|
+
const entries = [];
|
|
54
|
+
for (const map of adapter.serverMaps(document, location)) {
|
|
55
|
+
const servers = readPath(document.value, map.keys);
|
|
56
|
+
if (typeof servers !== 'object' || servers === null || Array.isArray(servers))
|
|
57
|
+
continue;
|
|
58
|
+
// A `projects.<path>.mcpServers` section lives in the user's own file, so
|
|
59
|
+
// it is discovered AND rewritten. `projectPath` is what tells the writer
|
|
60
|
+
// where to put the wrapped entry back.
|
|
61
|
+
const projectPath = map.keys[0] === 'projects' ? map.keys[1] : undefined;
|
|
62
|
+
const entryLocation = projectPath
|
|
63
|
+
? { ...location, scope: 'project-in-user-file', projectPath }
|
|
64
|
+
: location;
|
|
65
|
+
for (const [name, raw] of Object.entries(servers)) {
|
|
66
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
|
|
67
|
+
continue;
|
|
68
|
+
const typed = raw;
|
|
69
|
+
const upstreamName = wrappedUpstreamName(typed);
|
|
70
|
+
const parsed = adapter.parse(name, typed);
|
|
71
|
+
entries.push({
|
|
72
|
+
location: entryLocation,
|
|
73
|
+
name,
|
|
74
|
+
raw: typed,
|
|
75
|
+
kind: parsed.kind,
|
|
76
|
+
wrapped: upstreamName !== null,
|
|
77
|
+
wrappedName: upstreamName ?? undefined,
|
|
78
|
+
spec: parsed.spec,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return entries;
|
|
83
|
+
}
|
|
84
|
+
/** `readPath(doc, ['projects', '/a/b', 'mcpServers'])`. */
|
|
85
|
+
export function readPath(value, keys) {
|
|
86
|
+
let current = value;
|
|
87
|
+
for (const key of keys) {
|
|
88
|
+
if (typeof current !== 'object' || current === null || Array.isArray(current))
|
|
89
|
+
return undefined;
|
|
90
|
+
if (!Object.hasOwn(current, key))
|
|
91
|
+
return undefined;
|
|
92
|
+
current = Object.getOwnPropertyDescriptor(current, key)?.value;
|
|
93
|
+
}
|
|
94
|
+
return current;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Every entry the proxy could actually be put in front of.
|
|
98
|
+
*
|
|
99
|
+
* Excluded: entries already wrapped (nothing to do) and entries whose
|
|
100
|
+
* transport we could not read — wrapping one of those would replace a working
|
|
101
|
+
* server with a proxy that cannot reach it.
|
|
102
|
+
*
|
|
103
|
+
* ⚠️ NOT excluded any more: `projects.<path>.mcpServers`. Section 0 was
|
|
104
|
+
* amended on 2026-09-09 to "everything that lives in the user's home, never a
|
|
105
|
+
* versioned project file". Those sections live in the user's own
|
|
106
|
+
* `~/.claude.json`, and they are where `claude mcp add` writes by default —
|
|
107
|
+
* filtering them out meant the most common way of adding a server produced
|
|
108
|
+
* one that was never protected. A project's `.mcp.json` is still out of
|
|
109
|
+
* bounds, and it is excluded earlier: no adapter ever looks at one.
|
|
110
|
+
*/
|
|
111
|
+
export function wrappableEntries(entries) {
|
|
112
|
+
return entries.filter((entry) => !entry.wrapped && entry.kind !== 'unknown');
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=discover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/mcp/config/discover.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Claude Code `SessionStart` hook that keeps the park wrapped.
|
|
3
|
+
*
|
|
4
|
+
* A user who runs `claude mcp add` after installing VibeDefend has just added
|
|
5
|
+
* a server the proxy knows nothing about. The plan's answer is not to ask them
|
|
6
|
+
* to remember `vibedefend sync`: the hook runs it at the start of every
|
|
7
|
+
* session, quietly.
|
|
8
|
+
*
|
|
9
|
+
* What a `SessionStart` hook writes on stdout is APPENDED TO THE AGENT'S
|
|
10
|
+
* CONTEXT. That is why `sync --quiet` prints nothing at all when everything
|
|
11
|
+
* is in order: a line of reassurance on every session start is a line the
|
|
12
|
+
* model reads, pays for, and may act on. One sentence, in English, only when
|
|
13
|
+
* there is something to say.
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { clientConfigRoot } from '../proxy/paths.js';
|
|
18
|
+
import { writeFileAtomic } from './atomicWrite.js';
|
|
19
|
+
import { readJsonDocument, renderJson, DEFAULT_FORMAT } from './jsonEdit.js';
|
|
20
|
+
/** The command the hook runs. Matched to recognise our own entry again. */
|
|
21
|
+
export const SYNC_HOOK_COMMAND = 'vibedefend sync --quiet';
|
|
22
|
+
/** Under the home directory, or under `VIBEDEFEND_MCP_DIR` when it stands in for it. */
|
|
23
|
+
export function claudeCodeSettingsPath(env = process.env) {
|
|
24
|
+
return join(clientConfigRoot(env), '.claude', 'settings.json');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Adds the hook, or reports that it is already there.
|
|
28
|
+
*
|
|
29
|
+
* Idempotent by matching on the command rather than on deep equality: a user
|
|
30
|
+
* who added a `matcher` to our entry keeps it, and we do not add a second
|
|
31
|
+
* one beside it.
|
|
32
|
+
*/
|
|
33
|
+
export function installSyncHook(deps = {}) {
|
|
34
|
+
const env = deps.env ?? process.env;
|
|
35
|
+
const file = claudeCodeSettingsPath(env);
|
|
36
|
+
const readFileFn = deps.readFileFn ?? ((path) => readFileSync(path, 'utf8'));
|
|
37
|
+
const writeFileFn = deps.writeFileFn ?? defaultWrite;
|
|
38
|
+
const existsFn = deps.existsFn ?? existsSync;
|
|
39
|
+
let value = {};
|
|
40
|
+
let format = DEFAULT_FORMAT;
|
|
41
|
+
if (existsFn(file)) {
|
|
42
|
+
let text;
|
|
43
|
+
try {
|
|
44
|
+
text = readFileFn(file);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return { outcome: 'unreadable', file };
|
|
48
|
+
}
|
|
49
|
+
const parsed = readJsonDocument(text);
|
|
50
|
+
// Claude Code's settings file is the user's, and it may well have comments
|
|
51
|
+
// in it. Refusing is better than rewriting it without them.
|
|
52
|
+
if (!parsed.ok)
|
|
53
|
+
return { outcome: 'unreadable', file };
|
|
54
|
+
value = parsed.document.value;
|
|
55
|
+
format = parsed.document.format;
|
|
56
|
+
}
|
|
57
|
+
const hooks = asObject(value.hooks) ?? {};
|
|
58
|
+
const sessionStart = Array.isArray(hooks.SessionStart) ? [...hooks.SessionStart] : [];
|
|
59
|
+
if (sessionStart.some((entry) => mentionsSyncHook(entry))) {
|
|
60
|
+
return { outcome: 'already-installed', file };
|
|
61
|
+
}
|
|
62
|
+
sessionStart.push({ hooks: [{ type: 'command', command: SYNC_HOOK_COMMAND }] });
|
|
63
|
+
hooks.SessionStart = sessionStart;
|
|
64
|
+
value.hooks = hooks;
|
|
65
|
+
writeFileFn(file, renderJson(value, format));
|
|
66
|
+
return { outcome: 'installed', file };
|
|
67
|
+
}
|
|
68
|
+
/** Removes our entry, leaving every other hook alone. */
|
|
69
|
+
export function removeSyncHook(deps = {}) {
|
|
70
|
+
const env = deps.env ?? process.env;
|
|
71
|
+
const file = claudeCodeSettingsPath(env);
|
|
72
|
+
const readFileFn = deps.readFileFn ?? ((path) => readFileSync(path, 'utf8'));
|
|
73
|
+
const writeFileFn = deps.writeFileFn ?? defaultWrite;
|
|
74
|
+
const existsFn = deps.existsFn ?? existsSync;
|
|
75
|
+
if (!existsFn(file))
|
|
76
|
+
return { outcome: 'already-installed', file };
|
|
77
|
+
let text;
|
|
78
|
+
try {
|
|
79
|
+
text = readFileFn(file);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return { outcome: 'unreadable', file };
|
|
83
|
+
}
|
|
84
|
+
const parsed = readJsonDocument(text);
|
|
85
|
+
if (!parsed.ok)
|
|
86
|
+
return { outcome: 'unreadable', file };
|
|
87
|
+
const value = parsed.document.value;
|
|
88
|
+
const hooks = asObject(value.hooks);
|
|
89
|
+
if (!hooks || !Array.isArray(hooks.SessionStart))
|
|
90
|
+
return { outcome: 'already-installed', file };
|
|
91
|
+
const kept = hooks.SessionStart.filter((entry) => !mentionsSyncHook(entry));
|
|
92
|
+
if (kept.length === hooks.SessionStart.length)
|
|
93
|
+
return { outcome: 'already-installed', file };
|
|
94
|
+
// An empty array left behind is noise in a file the user reads.
|
|
95
|
+
if (kept.length === 0)
|
|
96
|
+
delete hooks.SessionStart;
|
|
97
|
+
else
|
|
98
|
+
hooks.SessionStart = kept;
|
|
99
|
+
if (Object.keys(hooks).length === 0)
|
|
100
|
+
delete value.hooks;
|
|
101
|
+
writeFileFn(file, renderJson(value, parsed.document.format));
|
|
102
|
+
return { outcome: 'installed', file };
|
|
103
|
+
}
|
|
104
|
+
/** Does this `SessionStart` entry run our sync? */
|
|
105
|
+
export function mentionsSyncHook(entry) {
|
|
106
|
+
const group = asObject(entry);
|
|
107
|
+
if (!group || !Array.isArray(group.hooks))
|
|
108
|
+
return false;
|
|
109
|
+
return group.hooks.some((hook) => {
|
|
110
|
+
const typed = asObject(hook);
|
|
111
|
+
const command = typed && typeof typed.command === 'string' ? typed.command : '';
|
|
112
|
+
return /\bvibedefend\b.*\bsync\b/.test(command);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function asObject(value) {
|
|
116
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
117
|
+
? value
|
|
118
|
+
: null;
|
|
119
|
+
}
|
|
120
|
+
function defaultWrite(path, content) {
|
|
121
|
+
writeFileAtomic(path, content, { mode: 0o644, directoryMode: 0o755 });
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../../../src/mcp/config/hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The client-config layer: discover what a user has, wrap it behind the
|
|
3
|
+
* proxy, and put it back.
|
|
4
|
+
*/
|
|
5
|
+
export * from './clients.js';
|
|
6
|
+
export * from './discover.js';
|
|
7
|
+
export * from './hook.js';
|
|
8
|
+
export * from './jsonEdit.js';
|
|
9
|
+
export * from './rewrite.js';
|
|
10
|
+
export * from './types.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/config/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { installedMarkerPath, isProxyInstalled, removeInstalledMarker, writeInstalledMarker, } from './installed.js';
|
|
2
|
+
import { checkProxyBinary, proxyBinaryKnowsMcp, } from './proxyBinary.js';
|
|
3
|
+
import { applySyncPlan, planSync, planUninstall } from './rewrite.js';
|
|
4
|
+
/** Why an install may not proceed, or `null` when it may. */
|
|
5
|
+
export function installRefusal(check, deps) {
|
|
6
|
+
if (!check.onPath)
|
|
7
|
+
return { reason: 'not-on-path', path: null };
|
|
8
|
+
if (!proxyBinaryKnowsMcp(check, { execFileFn: deps.execFileFn })) {
|
|
9
|
+
return { reason: 'no-mcp-subcommand', path: check.onPath };
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
export function installProxy(deps) {
|
|
14
|
+
const check = checkProxyBinary({ env: deps.env, argv1: deps.argv1, platform: deps.platform });
|
|
15
|
+
const refused = installRefusal(check, deps);
|
|
16
|
+
if (refused)
|
|
17
|
+
return { refused, check };
|
|
18
|
+
const plan = planSync({ env: deps.env, clients: deps.clients, platform: deps.platform });
|
|
19
|
+
const result = applySyncPlan(plan, {
|
|
20
|
+
env: deps.env,
|
|
21
|
+
dryRun: deps.dryRun,
|
|
22
|
+
backup: deps.backup,
|
|
23
|
+
now: deps.now,
|
|
24
|
+
});
|
|
25
|
+
if (!deps.dryRun) {
|
|
26
|
+
writeInstalledMarker({ env: deps.env, binary: check.running, now: deps.now });
|
|
27
|
+
}
|
|
28
|
+
return { check, plan, result };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Taking the proxy out needs no PATH check: restoring an original entry is
|
|
32
|
+
* right whatever the PATH holds. The marker goes with the last client — a
|
|
33
|
+
* partial `--client` uninstall leaves the others wrapped, and their proxies
|
|
34
|
+
* still need their permission to sync.
|
|
35
|
+
*/
|
|
36
|
+
export function uninstallProxy(deps) {
|
|
37
|
+
const plan = planUninstall({ env: deps.env, clients: deps.clients, platform: deps.platform });
|
|
38
|
+
const result = applySyncPlan(plan, {
|
|
39
|
+
env: deps.env,
|
|
40
|
+
dryRun: deps.dryRun,
|
|
41
|
+
backup: deps.backup,
|
|
42
|
+
now: deps.now,
|
|
43
|
+
});
|
|
44
|
+
if (!deps.dryRun && !(deps.clients && deps.clients.length > 0) && isProxyInstalled(deps.env)) {
|
|
45
|
+
removeInstalledMarker(deps.env);
|
|
46
|
+
}
|
|
47
|
+
return { plan, result };
|
|
48
|
+
}
|
|
49
|
+
const INSTALL_HINT = 'npm install -g @cybedefend/vibedefend';
|
|
50
|
+
/** The sentence a human gets. `command` is what they typed. */
|
|
51
|
+
export function installRefusalMessage(refusal, command = 'vibedefend sync') {
|
|
52
|
+
if (refusal.reason === 'not-on-path') {
|
|
53
|
+
return (`${command}: no \`vibedefend\` on the PATH. The proxy entries it writes ` +
|
|
54
|
+
'(`vibedefend mcp --name <server>`) would point at a command your MCP clients cannot find. ' +
|
|
55
|
+
`Install it with \`${INSTALL_HINT}\`, then run \`vibedefend sync\` again.`);
|
|
56
|
+
}
|
|
57
|
+
return (`${command}: the \`vibedefend\` on your PATH (${refusal.path}) does not know the \`mcp\` subcommand, ` +
|
|
58
|
+
'so the proxy entries it writes would not start. ' +
|
|
59
|
+
`Upgrade it with \`${INSTALL_HINT}@latest\`, then run \`vibedefend sync\` again.`);
|
|
60
|
+
}
|
|
61
|
+
/** The one sentence the `SessionStart` hook may add to the agent's context. */
|
|
62
|
+
export function installRefusalSentence(refusal) {
|
|
63
|
+
const cause = refusal.reason === 'not-on-path'
|
|
64
|
+
? 'there is no `vibedefend` on the PATH'
|
|
65
|
+
: `the \`vibedefend\` on the PATH (${refusal.path}) does not know \`mcp\``;
|
|
66
|
+
return `VibeDefend left the MCP servers unwrapped: ${cause}; run \`${INSTALL_HINT}@latest\` and then \`vibedefend sync\`.`;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The three facts a wrapped entry depends on, and that nothing in a client
|
|
70
|
+
* surfaces when one of them is false: every wrapped server just fails to
|
|
71
|
+
* start. The typical way to get there is nvm — each Node version has its own
|
|
72
|
+
* global install, and switching versions changes which `vibedefend` the PATH
|
|
73
|
+
* resolves to, possibly a release without `mcp`. This diagnoses; it never
|
|
74
|
+
* repairs.
|
|
75
|
+
*/
|
|
76
|
+
export function diagnoseProxyInstall(deps) {
|
|
77
|
+
const check = checkProxyBinary({ env: deps.env, argv1: deps.argv1, platform: deps.platform });
|
|
78
|
+
const knowsMcp = check.onPath ? proxyBinaryKnowsMcp(check, { execFileFn: deps.execFileFn }) : null;
|
|
79
|
+
return {
|
|
80
|
+
installed: isProxyInstalled(deps.env),
|
|
81
|
+
marker: installedMarkerPath(deps.env),
|
|
82
|
+
running: check.running,
|
|
83
|
+
onPath: check.onPath,
|
|
84
|
+
matches: check.matches,
|
|
85
|
+
knowsMcp,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** Three lines, one per fact, in the order a reader needs them. */
|
|
89
|
+
export function describeProxyInstall(diagnosis) {
|
|
90
|
+
const running = diagnosis.running ?? 'unknown';
|
|
91
|
+
const lines = [];
|
|
92
|
+
lines.push(diagnosis.installed
|
|
93
|
+
? { level: 'ok', text: `Proxy install: installed (marker at ${diagnosis.marker})` }
|
|
94
|
+
: {
|
|
95
|
+
level: 'warn',
|
|
96
|
+
text: 'Proxy install: not installed — wrapped entries are left alone until you run `vibedefend sync`',
|
|
97
|
+
});
|
|
98
|
+
if (!diagnosis.onPath) {
|
|
99
|
+
lines.push({
|
|
100
|
+
level: 'err',
|
|
101
|
+
text: `Running binary: ${running} — no \`vibedefend\` on the PATH, so a wrapped entry has nothing to start`,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
else if (diagnosis.matches) {
|
|
105
|
+
lines.push({
|
|
106
|
+
level: 'ok',
|
|
107
|
+
text: `Running binary: ${running} — is the \`vibedefend\` on the PATH (${diagnosis.onPath})`,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
lines.push({
|
|
112
|
+
level: 'warn',
|
|
113
|
+
text: `Running binary: ${running} — NOT the \`vibedefend\` on the PATH (${diagnosis.onPath}); wrapped entries start that one`,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
if (diagnosis.knowsMcp === null) {
|
|
117
|
+
lines.push({ level: 'warn', text: 'PATH vibedefend knows `mcp`: unknown (nothing on the PATH)' });
|
|
118
|
+
}
|
|
119
|
+
else if (diagnosis.knowsMcp) {
|
|
120
|
+
lines.push({ level: 'ok', text: 'PATH vibedefend knows `mcp`: yes' });
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
lines.push({
|
|
124
|
+
level: 'err',
|
|
125
|
+
text: 'PATH vibedefend knows `mcp`: no — every wrapped entry starts a release without the proxy. ' +
|
|
126
|
+
'Switched Node versions with nvm? Each version has its own global install; run ' +
|
|
127
|
+
'`npm install -g @cybedefend/vibedefend@latest` under the version in use, then `vibedefend sync`.',
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return lines;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/mcp/config/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `installed` marker.
|
|
3
|
+
*
|
|
4
|
+
* Written by an explicit install (`vibedefend install`, `vibedefend sync`),
|
|
5
|
+
* removed by `vibedefend unwrap`, and the first thing the proxy's
|
|
6
|
+
* background sync checks: with no marker, the proxy never writes into a
|
|
7
|
+
* client's config. A user who has not asked for the park to be wrapped does
|
|
8
|
+
* not get it wrapped because one proxy happened to start.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, unlinkSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { mcpHomeDir } from '../proxy/paths.js';
|
|
13
|
+
import { writeFileAtomic } from './atomicWrite.js';
|
|
14
|
+
export function installedMarkerPath(env = process.env) {
|
|
15
|
+
return join(mcpHomeDir(env), 'installed');
|
|
16
|
+
}
|
|
17
|
+
export function isProxyInstalled(env = process.env) {
|
|
18
|
+
return existsSync(installedMarkerPath(env));
|
|
19
|
+
}
|
|
20
|
+
export function writeInstalledMarker(deps) {
|
|
21
|
+
const now = deps.now ?? (() => new Date());
|
|
22
|
+
const content = `${JSON.stringify({ installedAt: now().toISOString(), binary: deps.binary }, null, 2)}\n`;
|
|
23
|
+
writeFileAtomic(installedMarkerPath(deps.env ?? process.env), content, {
|
|
24
|
+
mode: 0o600,
|
|
25
|
+
directoryMode: 0o700,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export function removeInstalledMarker(env = process.env) {
|
|
29
|
+
try {
|
|
30
|
+
unlinkSync(installedMarkerPath(env));
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error.code !== 'ENOENT')
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=installed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installed.js","sourceRoot":"","sources":["../../../src/mcp/config/installed.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,UAAU,mBAAmB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACtE,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACnE,OAAO,UAAU,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9C,CAAC;AASD,MAAM,UAAU,oBAAoB,CAAC,IAAyB;IAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IAC1G,eAAe,CAAC,mBAAmB,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE;QACrE,IAAI,EAAE,KAAK;QACX,aAAa,EAAE,KAAK;KACrB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACxE,IAAI,CAAC;QACH,UAAU,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAC;IACtE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editing a client's JSON config without rewriting the parts we did not come
|
|
3
|
+
* for.
|
|
4
|
+
*
|
|
5
|
+
* The Phase 5 acceptance criterion is that `install` followed by `uninstall`
|
|
6
|
+
* leaves the file byte for byte as it was. That rules out
|
|
7
|
+
* `JSON.stringify(value, null, 2)`: it would reindent a four-space file,
|
|
8
|
+
* strip a trailing newline, turn CRLF into LF, and rewrite every line of a
|
|
9
|
+
* document the user has been editing by hand for a year. A diff like that is
|
|
10
|
+
* unreviewable, and it is the kind of thing that makes people uninstall a
|
|
11
|
+
* tool.
|
|
12
|
+
*
|
|
13
|
+
* So the shape is measured on the way in and reproduced on the way out. Key
|
|
14
|
+
* ORDER comes for free: `JSON.parse` preserves insertion order for
|
|
15
|
+
* non-numeric keys, and so does `JSON.stringify`, so an untouched object
|
|
16
|
+
* round-trips unchanged.
|
|
17
|
+
*
|
|
18
|
+
* What is NOT preserved, and cannot be without a full CST: comments (JSONC,
|
|
19
|
+
* which VS Code accepts) and trailing commas. `readJsonDocument` reports
|
|
20
|
+
* whether it saw either, and the callers refuse to write such a file rather
|
|
21
|
+
* than silently dropping a comment the user wrote.
|
|
22
|
+
*/
|
|
23
|
+
export const DEFAULT_FORMAT = {
|
|
24
|
+
indent: ' ',
|
|
25
|
+
newline: '\n',
|
|
26
|
+
trailingNewline: true,
|
|
27
|
+
};
|
|
28
|
+
/** Measures the shape of an existing document. */
|
|
29
|
+
export function detectFormat(text) {
|
|
30
|
+
return {
|
|
31
|
+
indent: detectIndent(text),
|
|
32
|
+
newline: text.includes('\r\n') ? '\r\n' : '\n',
|
|
33
|
+
trailingNewline: /\n$/.test(text),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function detectIndent(text) {
|
|
37
|
+
// The first line that is more indented than its predecessor tells us the
|
|
38
|
+
// unit. A file with no nesting keeps the default, which it will never use.
|
|
39
|
+
for (const line of text.split(/\r?\n/)) {
|
|
40
|
+
const match = /^([ \t]+)\S/.exec(line);
|
|
41
|
+
if (match)
|
|
42
|
+
return match[1];
|
|
43
|
+
}
|
|
44
|
+
return DEFAULT_FORMAT.indent;
|
|
45
|
+
}
|
|
46
|
+
/** Renders a value in the measured shape. */
|
|
47
|
+
export function renderJson(value, format) {
|
|
48
|
+
const body = JSON.stringify(value, null, format.indent);
|
|
49
|
+
const withNewlines = format.newline === '\r\n' ? body.replace(/\n/g, '\r\n') : body;
|
|
50
|
+
return format.trailingNewline ? `${withNewlines}${format.newline}` : withNewlines;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Parses a config document, refusing the shapes we cannot write back.
|
|
54
|
+
*
|
|
55
|
+
* JSONC is refused rather than accepted-and-flattened. VS Code's `mcp.json`
|
|
56
|
+
* legitimately contains comments, and a user who wrote
|
|
57
|
+
* `// disabled for now, see JIRA-4021` above a server would find it gone
|
|
58
|
+
* after an install that never said it touched it.
|
|
59
|
+
*/
|
|
60
|
+
export function readJsonDocument(text) {
|
|
61
|
+
if (hasCommentsOrTrailingCommas(text))
|
|
62
|
+
return { ok: false, problem: 'jsonc' };
|
|
63
|
+
let parsed;
|
|
64
|
+
try {
|
|
65
|
+
parsed = JSON.parse(text);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return { ok: false, problem: 'unparseable' };
|
|
69
|
+
}
|
|
70
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
71
|
+
return { ok: false, problem: 'not-an-object' };
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
ok: true,
|
|
75
|
+
document: {
|
|
76
|
+
value: parsed,
|
|
77
|
+
format: detectFormat(text),
|
|
78
|
+
original: text,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Whether the text contains a comment or a trailing comma OUTSIDE a string.
|
|
84
|
+
*
|
|
85
|
+
* A scanner rather than a regular expression: `"url": "https://x/#anchor"`
|
|
86
|
+
* and `{"note": "a, b,}"}` are perfectly ordinary values, and a regex that
|
|
87
|
+
* did not track string state would refuse to touch half the real configs out
|
|
88
|
+
* there.
|
|
89
|
+
*/
|
|
90
|
+
export function hasCommentsOrTrailingCommas(text) {
|
|
91
|
+
let inString = false;
|
|
92
|
+
let escaped = false;
|
|
93
|
+
let lastMeaningful = '';
|
|
94
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
95
|
+
const char = text[index];
|
|
96
|
+
if (inString) {
|
|
97
|
+
if (escaped)
|
|
98
|
+
escaped = false;
|
|
99
|
+
else if (char === '\\')
|
|
100
|
+
escaped = true;
|
|
101
|
+
else if (char === '"')
|
|
102
|
+
inString = false;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (char === '"') {
|
|
106
|
+
inString = true;
|
|
107
|
+
lastMeaningful = '"';
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (char === '/' && (text[index + 1] === '/' || text[index + 1] === '*'))
|
|
111
|
+
return true;
|
|
112
|
+
if ((char === '}' || char === ']') && lastMeaningful === ',')
|
|
113
|
+
return true;
|
|
114
|
+
if (!/\s/.test(char))
|
|
115
|
+
lastMeaningful = char;
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=jsonEdit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonEdit.js","sourceRoot":"","sources":["../../../src/mcp/config/jsonEdit.ts"],"names":[],"mappings":"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"}
|