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