vibecheck-score 0.1.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/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +217 -0
- package/dist/index.js.map +1 -0
- package/dist/output/confirm.d.ts +3 -0
- package/dist/output/confirm.d.ts.map +1 -0
- package/dist/output/confirm.js +37 -0
- package/dist/output/confirm.js.map +1 -0
- package/dist/output/narrative.d.ts +3 -0
- package/dist/output/narrative.d.ts.map +1 -0
- package/dist/output/narrative.js +94 -0
- package/dist/output/narrative.js.map +1 -0
- package/dist/output/terminal.d.ts +4 -0
- package/dist/output/terminal.d.ts.map +1 -0
- package/dist/output/terminal.js +95 -0
- package/dist/output/terminal.js.map +1 -0
- package/dist/scanners/agents.d.ts +7 -0
- package/dist/scanners/agents.d.ts.map +1 -0
- package/dist/scanners/agents.js +95 -0
- package/dist/scanners/agents.js.map +1 -0
- package/dist/scanners/deploy.d.ts +7 -0
- package/dist/scanners/deploy.d.ts.map +1 -0
- package/dist/scanners/deploy.js +139 -0
- package/dist/scanners/deploy.js.map +1 -0
- package/dist/scanners/environment.d.ts +7 -0
- package/dist/scanners/environment.d.ts.map +1 -0
- package/dist/scanners/environment.js +110 -0
- package/dist/scanners/environment.js.map +1 -0
- package/dist/scanners/index.d.ts +7 -0
- package/dist/scanners/index.d.ts.map +1 -0
- package/dist/scanners/index.js +23 -0
- package/dist/scanners/index.js.map +1 -0
- package/dist/scanners/mcp.d.ts +7 -0
- package/dist/scanners/mcp.d.ts.map +1 -0
- package/dist/scanners/mcp.js +138 -0
- package/dist/scanners/mcp.js.map +1 -0
- package/dist/scanners/memory.d.ts +7 -0
- package/dist/scanners/memory.d.ts.map +1 -0
- package/dist/scanners/memory.js +131 -0
- package/dist/scanners/memory.js.map +1 -0
- package/dist/scanners/orchestration.d.ts +7 -0
- package/dist/scanners/orchestration.d.ts.map +1 -0
- package/dist/scanners/orchestration.js +99 -0
- package/dist/scanners/orchestration.js.map +1 -0
- package/dist/scanners/repositories.d.ts +7 -0
- package/dist/scanners/repositories.d.ts.map +1 -0
- package/dist/scanners/repositories.js +301 -0
- package/dist/scanners/repositories.js.map +1 -0
- package/dist/scanners/security.d.ts +7 -0
- package/dist/scanners/security.d.ts.map +1 -0
- package/dist/scanners/security.js +113 -0
- package/dist/scanners/security.js.map +1 -0
- package/dist/scanners/social.d.ts +7 -0
- package/dist/scanners/social.d.ts.map +1 -0
- package/dist/scanners/social.js +68 -0
- package/dist/scanners/social.js.map +1 -0
- package/dist/scanners/universal-file.d.ts +10 -0
- package/dist/scanners/universal-file.d.ts.map +1 -0
- package/dist/scanners/universal-file.js +526 -0
- package/dist/scanners/universal-file.js.map +1 -0
- package/dist/scanners/utils.d.ts +6 -0
- package/dist/scanners/utils.d.ts.map +1 -0
- package/dist/scanners/utils.js +51 -0
- package/dist/scanners/utils.js.map +1 -0
- package/dist/scanners/workspace.d.ts +3 -0
- package/dist/scanners/workspace.d.ts.map +1 -0
- package/dist/scanners/workspace.js +59 -0
- package/dist/scanners/workspace.js.map +1 -0
- package/dist/scoring/engine.d.ts +11 -0
- package/dist/scoring/engine.d.ts.map +1 -0
- package/dist/scoring/engine.js +85 -0
- package/dist/scoring/engine.js.map +1 -0
- package/dist/scoring/tiers.d.ts +11 -0
- package/dist/scoring/tiers.d.ts.map +1 -0
- package/dist/scoring/tiers.js +20 -0
- package/dist/scoring/tiers.js.map +1 -0
- package/dist/taxonomy/classifier.d.ts +9 -0
- package/dist/taxonomy/classifier.d.ts.map +1 -0
- package/dist/taxonomy/classifier.js +44 -0
- package/dist/taxonomy/classifier.js.map +1 -0
- package/dist/taxonomy/registry.json +189 -0
- package/dist/types.d.ts +109 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +58 -0
- package/dist/types.js.map +1 -0
- package/package.json +44 -0
- package/src/taxonomy/registry.json +189 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from "node:util";
|
|
3
|
+
import { platform, homedir } from "node:os";
|
|
4
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
import { randomUUID } from "node:crypto";
|
|
8
|
+
import { computeScore } from "./scoring/engine.js";
|
|
9
|
+
import { runAllScanners } from "./scanners/index.js";
|
|
10
|
+
import { EnvironmentScanner } from "./scanners/environment.js";
|
|
11
|
+
import { McpScanner } from "./scanners/mcp.js";
|
|
12
|
+
import { AgentsScanner } from "./scanners/agents.js";
|
|
13
|
+
import { OrchestrationScanner } from "./scanners/orchestration.js";
|
|
14
|
+
import { RepositoriesScanner } from "./scanners/repositories.js";
|
|
15
|
+
import { MemoryScanner } from "./scanners/memory.js";
|
|
16
|
+
import { SecurityScanner } from "./scanners/security.js";
|
|
17
|
+
import { DeployScanner } from "./scanners/deploy.js";
|
|
18
|
+
import { SocialScanner } from "./scanners/social.js";
|
|
19
|
+
import { UniversalFileScanner, getSupersededIds } from "./scanners/universal-file.js";
|
|
20
|
+
import { renderResults, createSpinner } from "./output/terminal.js";
|
|
21
|
+
function getVersion() {
|
|
22
|
+
try {
|
|
23
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
const pkgPath = join(__dirname, "..", "package.json");
|
|
25
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
26
|
+
return pkg.version ?? "0.1.0";
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return "0.1.0";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const HANDLE_RE = /^[a-z0-9_-]{3,39}$/;
|
|
33
|
+
function printHelp() {
|
|
34
|
+
console.log(`
|
|
35
|
+
vibecheck — scan your AI coding setup
|
|
36
|
+
|
|
37
|
+
Usage:
|
|
38
|
+
vibecheck [options]
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
--help Show this help message
|
|
42
|
+
--json Output raw ProbeResult as JSON
|
|
43
|
+
--merge <file> Merge detections from another scan (JSON file)
|
|
44
|
+
--deep Scan home directory for global AI config (crontab, launchd)
|
|
45
|
+
--submit Submit results to vibecheck.dev
|
|
46
|
+
--handle <id> Your handle (3-39 chars, lowercase, hyphens, underscores)
|
|
47
|
+
--url <url> Override submit URL (default: https://vibecheck.dev)
|
|
48
|
+
--yes Skip submit confirmation prompt
|
|
49
|
+
`);
|
|
50
|
+
}
|
|
51
|
+
async function main() {
|
|
52
|
+
const { values } = parseArgs({
|
|
53
|
+
options: {
|
|
54
|
+
help: { type: "boolean", default: false },
|
|
55
|
+
json: { type: "boolean", default: false },
|
|
56
|
+
deep: { type: "boolean", default: false },
|
|
57
|
+
merge: { type: "string" },
|
|
58
|
+
submit: { type: "boolean", default: false },
|
|
59
|
+
handle: { type: "string" },
|
|
60
|
+
url: { type: "string" },
|
|
61
|
+
yes: { type: "boolean", default: false },
|
|
62
|
+
},
|
|
63
|
+
strict: true,
|
|
64
|
+
});
|
|
65
|
+
if (values.help) {
|
|
66
|
+
printHelp();
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
69
|
+
const isJson = values.json ?? false;
|
|
70
|
+
const isDeep = values.deep ?? false;
|
|
71
|
+
const scanners = [
|
|
72
|
+
new EnvironmentScanner(),
|
|
73
|
+
new McpScanner(),
|
|
74
|
+
new AgentsScanner(),
|
|
75
|
+
new OrchestrationScanner(),
|
|
76
|
+
new RepositoriesScanner(),
|
|
77
|
+
new MemoryScanner(),
|
|
78
|
+
new SecurityScanner(),
|
|
79
|
+
new DeployScanner(),
|
|
80
|
+
new SocialScanner(),
|
|
81
|
+
new UniversalFileScanner(isDeep), // must be last — supersedes v2 for shared artifacts
|
|
82
|
+
];
|
|
83
|
+
const spinner = isJson ? null : createSpinner("Scanning your AI setup...");
|
|
84
|
+
spinner?.start();
|
|
85
|
+
const scanResults = await runAllScanners(scanners);
|
|
86
|
+
spinner?.stop();
|
|
87
|
+
// Flatten and deduplicate detections by id
|
|
88
|
+
// UFS runs last — collect its detections to know which v2 IDs to suppress
|
|
89
|
+
const supersededV2Ids = getSupersededIds();
|
|
90
|
+
const ufsResult = scanResults.find((r) => r.scanner === "universal-file");
|
|
91
|
+
const ufsDetectionIds = new Set(ufsResult?.detections.map((d) => d.id) ?? []);
|
|
92
|
+
// Build set of v2 IDs that UFS actually covered (supersedes + UFS emitted something)
|
|
93
|
+
const suppressedV2Ids = new Set();
|
|
94
|
+
for (const v2Id of supersededV2Ids) {
|
|
95
|
+
// Check if any UFS detection declares it supersedes this v2 ID
|
|
96
|
+
const hasUfsReplacement = ufsResult?.detections.some((d) => d.id.startsWith("ufs:"));
|
|
97
|
+
if (hasUfsReplacement)
|
|
98
|
+
suppressedV2Ids.add(v2Id);
|
|
99
|
+
}
|
|
100
|
+
const seen = new Set();
|
|
101
|
+
const detections = [];
|
|
102
|
+
for (const result of scanResults) {
|
|
103
|
+
for (const d of result.detections) {
|
|
104
|
+
if (seen.has(d.id))
|
|
105
|
+
continue;
|
|
106
|
+
// Skip v2 detections when UFS supersedes them
|
|
107
|
+
if (result.scanner !== "universal-file" && suppressedV2Ids.has(d.id))
|
|
108
|
+
continue;
|
|
109
|
+
seen.add(d.id);
|
|
110
|
+
detections.push(d);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// --merge: fold in detections from an external scan
|
|
114
|
+
if (values.merge) {
|
|
115
|
+
try {
|
|
116
|
+
const external = JSON.parse(readFileSync(values.merge, "utf-8"));
|
|
117
|
+
for (const d of external.detections) {
|
|
118
|
+
if (!seen.has(d.id)) {
|
|
119
|
+
seen.add(d.id);
|
|
120
|
+
detections.push(d);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
console.error(`\x1b[31m Failed to read --merge file: ${values.merge}\x1b[0m`);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const score = computeScore(detections);
|
|
130
|
+
const version = getVersion();
|
|
131
|
+
const result = {
|
|
132
|
+
version,
|
|
133
|
+
timestamp: new Date().toISOString(),
|
|
134
|
+
platform: platform(),
|
|
135
|
+
scanResults,
|
|
136
|
+
detections,
|
|
137
|
+
score,
|
|
138
|
+
};
|
|
139
|
+
if (isJson) {
|
|
140
|
+
console.log(JSON.stringify(result, null, 2));
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
renderResults(score, detections);
|
|
144
|
+
// Hint about --merge when autonomy is empty and no merge was used
|
|
145
|
+
const autonomyScore = score.categories.find((c) => c.category === "autonomy");
|
|
146
|
+
if (autonomyScore?.score === 0 && !values.merge) {
|
|
147
|
+
console.log(" \x1b[2m💡 Run agents on a separate machine? Export with --json there,");
|
|
148
|
+
console.log(" then pass it here with --merge <file> to combine scores.\x1b[0m\n");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// --submit flow
|
|
152
|
+
if (values.submit) {
|
|
153
|
+
const handle = values.handle;
|
|
154
|
+
if (!handle || !HANDLE_RE.test(handle)) {
|
|
155
|
+
console.error("\x1b[31m --handle is required for --submit (3-39 chars, lowercase alphanumeric/hyphens/underscores)\x1b[0m");
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
// Token management: ~/.vibecheck/token
|
|
159
|
+
const tokenDir = join(homedir(), ".vibecheck");
|
|
160
|
+
const tokenPath = join(tokenDir, "token");
|
|
161
|
+
let submissionToken;
|
|
162
|
+
if (existsSync(tokenPath)) {
|
|
163
|
+
submissionToken = readFileSync(tokenPath, "utf-8").trim();
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
submissionToken = randomUUID();
|
|
167
|
+
mkdirSync(tokenDir, { recursive: true });
|
|
168
|
+
writeFileSync(tokenPath, submissionToken, { mode: 0o600 });
|
|
169
|
+
}
|
|
170
|
+
// Confirmation unless --yes
|
|
171
|
+
if (!values.yes && !isJson) {
|
|
172
|
+
const rl = await import("node:readline/promises").then((m) => m.createInterface({ input: process.stdin, output: process.stdout }));
|
|
173
|
+
const answer = await rl.question(`\n Submit results as \x1b[1m${handle}\x1b[0m to vibecheck.dev? [Y/n] `);
|
|
174
|
+
rl.close();
|
|
175
|
+
if (answer.trim().toLowerCase() === "n") {
|
|
176
|
+
console.log(" Submission skipped.");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const submitUrl = values.url ?? "https://vibecheck.dev";
|
|
181
|
+
try {
|
|
182
|
+
const res = await fetch(`${submitUrl}/api/submit`, {
|
|
183
|
+
method: "POST",
|
|
184
|
+
headers: { "Content-Type": "application/json" },
|
|
185
|
+
body: JSON.stringify({ handle, probeResult: result, submissionToken }),
|
|
186
|
+
});
|
|
187
|
+
if (res.ok) {
|
|
188
|
+
const body = (await res.json());
|
|
189
|
+
const url = body.url;
|
|
190
|
+
const inner = ` \x1b[32m✓\x1b[0m Published! Share your score:`;
|
|
191
|
+
const urlLine = ` ${url}`;
|
|
192
|
+
const width = Math.max(inner.length - 9, urlLine.length) + 4; // -9 for ANSI codes
|
|
193
|
+
const border = "─".repeat(width);
|
|
194
|
+
console.log(`\n \x1b[32m┌${border}┐\x1b[0m`);
|
|
195
|
+
console.log(` \x1b[32m│\x1b[0m ${inner.padEnd(width - 2)} \x1b[32m│\x1b[0m`);
|
|
196
|
+
console.log(` \x1b[32m│\x1b[0m ${urlLine.padEnd(width - 2)} \x1b[32m│\x1b[0m`);
|
|
197
|
+
console.log(` \x1b[32m└${border}┘\x1b[0m\n`);
|
|
198
|
+
}
|
|
199
|
+
else if (res.status === 403) {
|
|
200
|
+
console.error("\n \x1b[31m✗ This handle is owned by a different machine.\x1b[0m");
|
|
201
|
+
console.error(" If this is your handle, restore ~/.vibecheck/token from the original machine.\n");
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const body = (await res.json().catch(() => ({})));
|
|
205
|
+
console.error(`\n \x1b[31m✗ Submit failed: ${body.error ?? res.statusText}\x1b[0m\n`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
console.error(`\n \x1b[33m⚠ Could not reach ${submitUrl} — results saved locally only.\x1b[0m\n`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
main().catch((err) => {
|
|
214
|
+
console.error("Fatal error:", err);
|
|
215
|
+
process.exit(1);
|
|
216
|
+
});
|
|
217
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm.d.ts","sourceRoot":"","sources":["../../src/output/confirm.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,SAAS,EAAE,GACtB,OAAO,CAAC,SAAS,EAAE,CAAC,CAoDtB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { stdin, stdout } from "node:process";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
export async function confirmDetections(detections) {
|
|
5
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
6
|
+
try {
|
|
7
|
+
console.log(chalk.bold("\n Detected items:"));
|
|
8
|
+
for (let i = 0; i < detections.length; i++) {
|
|
9
|
+
const d = detections[i];
|
|
10
|
+
const innovation = d.taxonomyMatch === null ? chalk.yellow(" *") : "";
|
|
11
|
+
console.log(` ${chalk.dim(`${i + 1}.`)} ${d.name}${innovation} ${chalk.dim(`(${d.source})`)}`);
|
|
12
|
+
}
|
|
13
|
+
console.log();
|
|
14
|
+
const answer = await rl.question(chalk.bold(" Confirm detections? [Y/n/edit] "));
|
|
15
|
+
const normalized = answer.trim().toLowerCase();
|
|
16
|
+
if (normalized === "n" || normalized === "no") {
|
|
17
|
+
console.log(chalk.dim(" Scan cancelled."));
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
if (normalized === "edit" || normalized === "e") {
|
|
21
|
+
const removeStr = await rl.question(chalk.dim(" Enter numbers to remove (comma-separated): "));
|
|
22
|
+
const toRemove = new Set(removeStr
|
|
23
|
+
.split(",")
|
|
24
|
+
.map((s) => parseInt(s.trim(), 10) - 1)
|
|
25
|
+
.filter((n) => !isNaN(n) && n >= 0 && n < detections.length));
|
|
26
|
+
const filtered = detections.filter((_, i) => !toRemove.has(i));
|
|
27
|
+
console.log(chalk.dim(` Removed ${toRemove.size} item(s). ${filtered.length} remaining.`));
|
|
28
|
+
return filtered;
|
|
29
|
+
}
|
|
30
|
+
// Y or empty = confirm all
|
|
31
|
+
return detections;
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
rl.close();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=confirm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm.js","sourceRoot":"","sources":["../../src/output/confirm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,UAAuB;IAEvB,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAE7D,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC;QAC/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YACxB,MAAM,UAAU,GAAG,CAAC,CAAC,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,OAAO,CAAC,GAAG,CACT,KAAK,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,UAAU,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CACnF,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAC9B,KAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAChD,CAAC;QAEF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAE/C,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YAC9C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;YAC5C,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,UAAU,KAAK,MAAM,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;YAChD,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,QAAQ,CACjC,KAAK,CAAC,GAAG,CACP,+CAA+C,CAChD,CACF,CAAC;YACF,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,SAAS;iBACN,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;iBACtC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAC/D,CAAC;YAEF,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAChC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAC3B,CAAC;YACF,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,aAAa,QAAQ,CAAC,IAAI,aAAa,QAAQ,CAAC,MAAM,aAAa,CAAC,CAC/E,CAAC;YACF,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,2BAA2B;QAC3B,OAAO,UAAU,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narrative.d.ts","sourceRoot":"","sources":["../../src/output/narrative.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAoB,MAAM,aAAa,CAAC;AAmE5E,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,SAAS,EAAE,GACtB,MAAM,CA8CR"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// TODO: extract to @vibecheck/core — duplicated from packages/web/src/lib/narrative-templates.ts
|
|
2
|
+
// Types and scoring are already duplicated between probe and web.
|
|
3
|
+
// When a third consumer appears, extract the shared package.
|
|
4
|
+
import { CATEGORY_LABELS } from "../types.js";
|
|
5
|
+
const DIMENSION_COMMENTARY = {
|
|
6
|
+
intelligence: {
|
|
7
|
+
low: "Single model, default config. The foundation is there — just needs breadth.",
|
|
8
|
+
mid: "Solid model strategy. You're making deliberate choices about which AI handles what.",
|
|
9
|
+
high: "Multi-model mastery with routing logic. You treat models like a portfolio, not a monogamy.",
|
|
10
|
+
},
|
|
11
|
+
tooling: {
|
|
12
|
+
low: "Light on tools. There's a whole ecosystem of MCP servers waiting to supercharge your setup.",
|
|
13
|
+
mid: "Good tool coverage. Your MCP servers extend the AI's reach meaningfully.",
|
|
14
|
+
high: "Deep tool ecosystem. Custom MCP servers, comprehensive coverage — you're a producer, not just a consumer.",
|
|
15
|
+
},
|
|
16
|
+
continuity: {
|
|
17
|
+
low: "No memory system. Your AI starts fresh every session — a brilliant goldfish.",
|
|
18
|
+
mid: "You've solved basic continuity. The AI remembers what matters across sessions.",
|
|
19
|
+
high: "Multi-layer memory architecture. Daily logs, curated long-term, active work tracking — this is institutional memory.",
|
|
20
|
+
},
|
|
21
|
+
autonomy: {
|
|
22
|
+
low: "Purely reactive. The AI waits for your every command.",
|
|
23
|
+
mid: "Your agents have some independence. Subagents and scheduled tasks are in play.",
|
|
24
|
+
high: "Full agent workforce. Proactive work loops, specialized roles, agents that find their own tasks.",
|
|
25
|
+
},
|
|
26
|
+
ship: {
|
|
27
|
+
low: "Manual deploy or basic push-to-deploy. The pipeline needs work.",
|
|
28
|
+
mid: "CI/CD with tests and automated deploy. Professional-grade shipping.",
|
|
29
|
+
high: "AI-integrated pipeline. Agent-opened PRs, merge queues, quality gates — a shipping machine.",
|
|
30
|
+
},
|
|
31
|
+
security: {
|
|
32
|
+
low: "Security gaps visible. Secrets management and agent permissions need attention.",
|
|
33
|
+
mid: "Good hygiene. Gitignored secrets, environment variables, some permission scoping.",
|
|
34
|
+
high: "Comprehensive security model. Canary tokens, permission governance, prompt injection defense.",
|
|
35
|
+
},
|
|
36
|
+
ops: {
|
|
37
|
+
low: "Minimal operational infrastructure. Documentation and project management are informal.",
|
|
38
|
+
mid: "Task tracking and good docs. The operational backbone is solid.",
|
|
39
|
+
high: "AI-integrated operations. Maintenance agents, monitoring, automated documentation.",
|
|
40
|
+
},
|
|
41
|
+
social: {
|
|
42
|
+
low: "Solo setup. No community integration or multi-channel presence.",
|
|
43
|
+
mid: "Some community engagement. Communication channels or shared configs.",
|
|
44
|
+
high: "Full social integration. Published tools, multi-channel AI presence, community builder.",
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
const IMPROVEMENT_HINTS = {
|
|
48
|
+
ship: "Add a GitHub Actions workflow or deploy config to level up.",
|
|
49
|
+
tooling: "Try connecting an MCP server — filesystem or GitHub are great starters.",
|
|
50
|
+
continuity: "Add a CLAUDE.md to your project root so the AI remembers your conventions.",
|
|
51
|
+
security: "Make sure .env is in your .gitignore and review agent permissions.",
|
|
52
|
+
ops: "Add build/dev/lint scripts to package.json for a quick ops boost.",
|
|
53
|
+
};
|
|
54
|
+
function commentaryForScore(cat, score) {
|
|
55
|
+
const c = DIMENSION_COMMENTARY[cat];
|
|
56
|
+
if (score >= 60)
|
|
57
|
+
return c.high;
|
|
58
|
+
if (score >= 30)
|
|
59
|
+
return c.mid;
|
|
60
|
+
return c.low;
|
|
61
|
+
}
|
|
62
|
+
export function generateNarrative(score, detections) {
|
|
63
|
+
const sorted = [...score.categories].sort((a, b) => b.score - a.score);
|
|
64
|
+
const strongest = sorted[0];
|
|
65
|
+
// Find weakest category with score < 50 (last in sorted = lowest score)
|
|
66
|
+
const weakCandidates = sorted.filter((c) => c.score < 50);
|
|
67
|
+
const weakest = weakCandidates.length > 0
|
|
68
|
+
? weakCandidates[weakCandidates.length - 1]
|
|
69
|
+
: undefined;
|
|
70
|
+
const sentences = [];
|
|
71
|
+
// Strongest category commentary
|
|
72
|
+
sentences.push(commentaryForScore(strongest.category, strongest.score));
|
|
73
|
+
// Weakest category suggestion (with guardrail)
|
|
74
|
+
if (weakest && weakest.category !== strongest.category) {
|
|
75
|
+
const hint = IMPROVEMENT_HINTS[weakest.category];
|
|
76
|
+
if (hint && weakest.score < 30) {
|
|
77
|
+
sentences.push(hint);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
sentences.push(`${CATEGORY_LABELS[weakest.category]} is your biggest growth area.`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// MCP count mention
|
|
84
|
+
const mcpCount = detections.filter((d) => d.id.startsWith("mcp-")).length;
|
|
85
|
+
if (mcpCount > 3) {
|
|
86
|
+
sentences.push(`${mcpCount} MCP servers connected — that's serious tool integration.`);
|
|
87
|
+
}
|
|
88
|
+
// Pioneer mention
|
|
89
|
+
if (score.pioneer.isPioneer) {
|
|
90
|
+
sentences.push("Pioneer badge earned — you're building what the taxonomy hasn't seen yet.");
|
|
91
|
+
}
|
|
92
|
+
return sentences.join(" ");
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=narrative.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narrative.js","sourceRoot":"","sources":["../../src/output/narrative.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,kEAAkE;AAClE,6DAA6D;AAG7D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,oBAAoB,GAGtB;IACF,YAAY,EAAE;QACZ,GAAG,EAAE,6EAA6E;QAClF,GAAG,EAAE,qFAAqF;QAC1F,IAAI,EAAE,4FAA4F;KACnG;IACD,OAAO,EAAE;QACP,GAAG,EAAE,6FAA6F;QAClG,GAAG,EAAE,0EAA0E;QAC/E,IAAI,EAAE,2GAA2G;KAClH;IACD,UAAU,EAAE;QACV,GAAG,EAAE,8EAA8E;QACnF,GAAG,EAAE,gFAAgF;QACrF,IAAI,EAAE,sHAAsH;KAC7H;IACD,QAAQ,EAAE;QACR,GAAG,EAAE,uDAAuD;QAC5D,GAAG,EAAE,gFAAgF;QACrF,IAAI,EAAE,kGAAkG;KACzG;IACD,IAAI,EAAE;QACJ,GAAG,EAAE,iEAAiE;QACtE,GAAG,EAAE,qEAAqE;QAC1E,IAAI,EAAE,6FAA6F;KACpG;IACD,QAAQ,EAAE;QACR,GAAG,EAAE,iFAAiF;QACtF,GAAG,EAAE,mFAAmF;QACxF,IAAI,EAAE,+FAA+F;KACtG;IACD,GAAG,EAAE;QACH,GAAG,EAAE,wFAAwF;QAC7F,GAAG,EAAE,iEAAiE;QACtE,IAAI,EAAE,oFAAoF;KAC3F;IACD,MAAM,EAAE;QACN,GAAG,EAAE,iEAAiE;QACtE,GAAG,EAAE,sEAAsE;QAC3E,IAAI,EAAE,yFAAyF;KAChG;CACF,CAAC;AAEF,MAAM,iBAAiB,GAA8C;IACnE,IAAI,EAAE,6DAA6D;IACnE,OAAO,EAAE,yEAAyE;IAClF,UAAU,EAAE,4EAA4E;IACxF,QAAQ,EAAE,oEAAoE;IAC9E,GAAG,EAAE,mEAAmE;CACzE,CAAC;AAEF,SAAS,kBAAkB,CACzB,GAAqB,EACrB,KAAa;IAEb,MAAM,CAAC,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,CAAC,CAAC,IAAI,CAAC;IAC/B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,CAAC,CAAC,GAAG,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,CAAC;AACf,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,KAAkB,EAClB,UAAuB;IAEvB,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CACvC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAC5B,CAAC;IACF,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC5B,wEAAwE;IACxE,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,GAAG,CAAC;QACvC,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC;QAC3C,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,gCAAgC;IAChC,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAExE,+CAA+C;IAC/C,IAAI,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,QAAQ,EAAE,CAAC;QACvD,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjD,IAAI,IAAI,IAAI,OAAO,CAAC,KAAK,GAAG,EAAE,EAAE,CAAC;YAC/B,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,IAAI,CACZ,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,+BAA+B,CACpE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACvC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CACxB,CAAC,MAAM,CAAC;IACT,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACjB,SAAS,CAAC,IAAI,CACZ,GAAG,QAAQ,2DAA2D,CACvE,CAAC;IACJ,CAAC;IAED,kBAAkB;IAClB,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QAC5B,SAAS,CAAC,IAAI,CACZ,2EAA2E,CAC5E,CAAC;IACJ,CAAC;IAED,OAAO,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/output/terminal.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EAGV,MAAM,aAAa,CAAC;AAqBrB,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,qBAEzC;AAED,wBAAgB,aAAa,CAC3B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,SAAS,EAAE,GACtB,IAAI,CAyGN"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import { CATEGORY_EMOJI, CATEGORY_LABELS, TAXONOMY_CATEGORIES } from "../types.js";
|
|
4
|
+
import { getNextTier } from "../scoring/tiers.js";
|
|
5
|
+
import { generateNarrative } from "./narrative.js";
|
|
6
|
+
function scoreColor(score) {
|
|
7
|
+
if (score >= 50)
|
|
8
|
+
return chalk.green;
|
|
9
|
+
if (score >= 25)
|
|
10
|
+
return chalk.yellow;
|
|
11
|
+
return chalk.red;
|
|
12
|
+
}
|
|
13
|
+
function tierBadge(tier) {
|
|
14
|
+
const badges = {
|
|
15
|
+
basic: chalk.gray("[basic]"),
|
|
16
|
+
intermediate: chalk.cyan("[inter]"),
|
|
17
|
+
advanced: chalk.magenta("[adv]"),
|
|
18
|
+
elite: chalk.yellow("[elite]"),
|
|
19
|
+
};
|
|
20
|
+
return badges[tier] ?? chalk.gray(`[${tier}]`);
|
|
21
|
+
}
|
|
22
|
+
export function createSpinner(text) {
|
|
23
|
+
return ora({ text, spinner: "dots" });
|
|
24
|
+
}
|
|
25
|
+
export function renderResults(score, detections) {
|
|
26
|
+
console.log();
|
|
27
|
+
// Header
|
|
28
|
+
const levelStr = chalk.bold.white(`Level ${score.level}`);
|
|
29
|
+
const tierStr = chalk.bold.cyan(score.tier.title);
|
|
30
|
+
const typeStr = chalk.dim(`[${score.typeCode.code}]`);
|
|
31
|
+
console.log(` ${levelStr} ${tierStr} ${typeStr}`);
|
|
32
|
+
console.log(` ${chalk.dim(score.tier.tagline)}`);
|
|
33
|
+
console.log();
|
|
34
|
+
// Narrative summary
|
|
35
|
+
const narrative = generateNarrative(score, detections);
|
|
36
|
+
console.log(` ${chalk.italic(narrative)}`);
|
|
37
|
+
console.log();
|
|
38
|
+
// Category bar chart
|
|
39
|
+
const catMap = new Map(score.categories.map((c) => [c.category, c]));
|
|
40
|
+
for (const cat of TAXONOMY_CATEGORIES) {
|
|
41
|
+
const cs = catMap.get(cat);
|
|
42
|
+
const label = CATEGORY_LABELS[cat].padEnd(12);
|
|
43
|
+
const filled = Math.round(cs.score / 10);
|
|
44
|
+
const empty = 10 - filled;
|
|
45
|
+
const bar = scoreColor(cs.score)("█".repeat(filled)) + chalk.dim("░".repeat(empty));
|
|
46
|
+
const scoreStr = scoreColor(cs.score)(String(cs.score).padStart(3));
|
|
47
|
+
console.log(` ${label} ${bar} ${scoreStr}`);
|
|
48
|
+
}
|
|
49
|
+
console.log();
|
|
50
|
+
// Detection list grouped by category
|
|
51
|
+
console.log(chalk.bold(" Detections"));
|
|
52
|
+
console.log(chalk.dim(" " + "-".repeat(52)));
|
|
53
|
+
for (const cat of TAXONOMY_CATEGORIES) {
|
|
54
|
+
const catDetections = detections.filter((d) => d.category === cat);
|
|
55
|
+
if (catDetections.length === 0)
|
|
56
|
+
continue;
|
|
57
|
+
console.log(` ${CATEGORY_EMOJI[cat]} ${chalk.bold(CATEGORY_LABELS[cat])}`);
|
|
58
|
+
for (const d of catDetections) {
|
|
59
|
+
const badge = tierBadge(d.tier);
|
|
60
|
+
const innovation = d.taxonomyMatch === null ? chalk.yellow(" *") : "";
|
|
61
|
+
const conf = d.confidence === "low" ? chalk.dim(" (low)") : "";
|
|
62
|
+
console.log(` ${badge} ${d.name}${innovation}${conf}`);
|
|
63
|
+
console.log(` ${chalk.dim(d.source)}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
console.log();
|
|
67
|
+
// Pioneer badge
|
|
68
|
+
if (score.pioneer.isPioneer) {
|
|
69
|
+
console.log(chalk.yellow.bold(" ★ Pioneer Badge"));
|
|
70
|
+
console.log(chalk.yellow(` ${score.pioneer.innovations.length} innovation(s) detected`));
|
|
71
|
+
for (const inn of score.pioneer.innovations) {
|
|
72
|
+
console.log(chalk.yellow(` → ${inn.name} (${inn.source})`));
|
|
73
|
+
}
|
|
74
|
+
console.log();
|
|
75
|
+
}
|
|
76
|
+
// Improvement hints
|
|
77
|
+
const weakest = [...score.categories]
|
|
78
|
+
.filter((c) => c.score < 50)
|
|
79
|
+
.sort((a, b) => a.score - b.score)
|
|
80
|
+
.slice(0, 3);
|
|
81
|
+
if (weakest.length > 0) {
|
|
82
|
+
console.log(chalk.bold(" Growth areas"));
|
|
83
|
+
for (const w of weakest) {
|
|
84
|
+
console.log(` ${chalk.dim("→")} ${CATEGORY_LABELS[w.category]}: ${w.score}/100`);
|
|
85
|
+
}
|
|
86
|
+
console.log();
|
|
87
|
+
}
|
|
88
|
+
// Next tier hint
|
|
89
|
+
const next = getNextTier(score.tier.title);
|
|
90
|
+
if (next) {
|
|
91
|
+
console.log(chalk.dim(` Next tier: ${next.title} (level ${next.minLevel}+)`));
|
|
92
|
+
console.log();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=terminal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/output/terminal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/scanners/agents.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAS1C,qBAAa,aAAc,YAAW,OAAO;IAC3C,IAAI,SAAY;IAEV,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;CA6FlC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { classify } from "../taxonomy/classifier.js";
|
|
3
|
+
import { fileExists, readJsonIfExists } from "./utils.js";
|
|
4
|
+
export class AgentsScanner {
|
|
5
|
+
name = "agents";
|
|
6
|
+
async scan() {
|
|
7
|
+
const start = performance.now();
|
|
8
|
+
const findings = [];
|
|
9
|
+
// Check .claude/agents/ directory for subagents
|
|
10
|
+
try {
|
|
11
|
+
const agents = await readdir(".claude/agents");
|
|
12
|
+
if (agents.length > 0) {
|
|
13
|
+
findings.push({
|
|
14
|
+
id: "subagents",
|
|
15
|
+
source: ".claude/agents/",
|
|
16
|
+
confidence: "high",
|
|
17
|
+
details: { count: agents.length },
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// directory doesn't exist
|
|
23
|
+
}
|
|
24
|
+
// Check for AGENTS.md, SOUL.md, EVOLVE.md — CWD first, then home dir
|
|
25
|
+
const specialFiles = [
|
|
26
|
+
{ file: "AGENTS.md", id: "agents-md" },
|
|
27
|
+
{ file: "SOUL.md", id: "soul-md" },
|
|
28
|
+
{ file: "EVOLVE.md", id: "evolve-md" },
|
|
29
|
+
];
|
|
30
|
+
for (const { file, id } of specialFiles) {
|
|
31
|
+
if (await fileExists(file)) {
|
|
32
|
+
findings.push({
|
|
33
|
+
id,
|
|
34
|
+
source: file,
|
|
35
|
+
confidence: "high",
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
else if (await fileExists(`~/${file}`)) {
|
|
39
|
+
findings.push({
|
|
40
|
+
id,
|
|
41
|
+
source: `~/${file}`,
|
|
42
|
+
confidence: "medium",
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Check hooks in settings
|
|
47
|
+
const settings = await readJsonIfExists(".claude/settings.json");
|
|
48
|
+
if (settings?.hooks && Object.keys(settings.hooks).length > 0) {
|
|
49
|
+
findings.push({
|
|
50
|
+
id: "hooks",
|
|
51
|
+
source: ".claude/settings.json",
|
|
52
|
+
confidence: "high",
|
|
53
|
+
details: {
|
|
54
|
+
hookCount: Object.keys(settings.hooks).length,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// Check .claude/skills/ directory
|
|
59
|
+
try {
|
|
60
|
+
const skills = await readdir(".claude/skills");
|
|
61
|
+
if (skills.length > 0) {
|
|
62
|
+
findings.push({
|
|
63
|
+
id: "claude-skills",
|
|
64
|
+
source: ".claude/skills/",
|
|
65
|
+
confidence: "high",
|
|
66
|
+
details: { count: skills.length },
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// directory doesn't exist
|
|
72
|
+
}
|
|
73
|
+
// Check .claude/commands/ directory
|
|
74
|
+
try {
|
|
75
|
+
const commands = await readdir(".claude/commands");
|
|
76
|
+
if (commands.length > 0) {
|
|
77
|
+
findings.push({
|
|
78
|
+
id: "claude-commands",
|
|
79
|
+
source: ".claude/commands/",
|
|
80
|
+
confidence: "high",
|
|
81
|
+
details: { count: commands.length },
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// directory doesn't exist
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
scanner: this.name,
|
|
90
|
+
detections: classify(findings),
|
|
91
|
+
duration: Math.round(performance.now() - start),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/scanners/agents.ts"],"names":[],"mappings":"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"}
|