claude-crap 0.1.2
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/CHANGELOG.md +308 -0
- package/LICENSE +21 -0
- package/README.md +550 -0
- package/bin/claude-crap.mjs +141 -0
- package/dist/adapters/bandit.d.ts +48 -0
- package/dist/adapters/bandit.d.ts.map +1 -0
- package/dist/adapters/bandit.js +145 -0
- package/dist/adapters/bandit.js.map +1 -0
- package/dist/adapters/common.d.ts +73 -0
- package/dist/adapters/common.d.ts.map +1 -0
- package/dist/adapters/common.js +78 -0
- package/dist/adapters/common.js.map +1 -0
- package/dist/adapters/eslint.d.ts +52 -0
- package/dist/adapters/eslint.d.ts.map +1 -0
- package/dist/adapters/eslint.js +142 -0
- package/dist/adapters/eslint.js.map +1 -0
- package/dist/adapters/index.d.ts +47 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +64 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/semgrep.d.ts +30 -0
- package/dist/adapters/semgrep.d.ts.map +1 -0
- package/dist/adapters/semgrep.js +130 -0
- package/dist/adapters/semgrep.js.map +1 -0
- package/dist/adapters/stryker.d.ts +55 -0
- package/dist/adapters/stryker.d.ts.map +1 -0
- package/dist/adapters/stryker.js +165 -0
- package/dist/adapters/stryker.js.map +1 -0
- package/dist/ast/cyclomatic.d.ts +48 -0
- package/dist/ast/cyclomatic.d.ts.map +1 -0
- package/dist/ast/cyclomatic.js +106 -0
- package/dist/ast/cyclomatic.js.map +1 -0
- package/dist/ast/index.d.ts +26 -0
- package/dist/ast/index.d.ts.map +1 -0
- package/dist/ast/index.js +23 -0
- package/dist/ast/index.js.map +1 -0
- package/dist/ast/language-config.d.ts +70 -0
- package/dist/ast/language-config.d.ts.map +1 -0
- package/dist/ast/language-config.js +192 -0
- package/dist/ast/language-config.js.map +1 -0
- package/dist/ast/tree-sitter-engine.d.ts +133 -0
- package/dist/ast/tree-sitter-engine.d.ts.map +1 -0
- package/dist/ast/tree-sitter-engine.js +270 -0
- package/dist/ast/tree-sitter-engine.js.map +1 -0
- package/dist/config.d.ts +57 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +78 -0
- package/dist/config.js.map +1 -0
- package/dist/crap-config.d.ts +97 -0
- package/dist/crap-config.d.ts.map +1 -0
- package/dist/crap-config.js +144 -0
- package/dist/crap-config.js.map +1 -0
- package/dist/dashboard/server.d.ts +65 -0
- package/dist/dashboard/server.d.ts.map +1 -0
- package/dist/dashboard/server.js +147 -0
- package/dist/dashboard/server.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +574 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics/crap.d.ts +71 -0
- package/dist/metrics/crap.d.ts.map +1 -0
- package/dist/metrics/crap.js +67 -0
- package/dist/metrics/crap.js.map +1 -0
- package/dist/metrics/index.d.ts +31 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +27 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/score.d.ts +143 -0
- package/dist/metrics/score.d.ts.map +1 -0
- package/dist/metrics/score.js +224 -0
- package/dist/metrics/score.js.map +1 -0
- package/dist/metrics/tdr.d.ts +106 -0
- package/dist/metrics/tdr.d.ts.map +1 -0
- package/dist/metrics/tdr.js +117 -0
- package/dist/metrics/tdr.js.map +1 -0
- package/dist/metrics/workspace-walker.d.ts +43 -0
- package/dist/metrics/workspace-walker.d.ts.map +1 -0
- package/dist/metrics/workspace-walker.js +137 -0
- package/dist/metrics/workspace-walker.js.map +1 -0
- package/dist/sarif/index.d.ts +21 -0
- package/dist/sarif/index.d.ts.map +1 -0
- package/dist/sarif/index.js +19 -0
- package/dist/sarif/index.js.map +1 -0
- package/dist/sarif/sarif-builder.d.ts +128 -0
- package/dist/sarif/sarif-builder.d.ts.map +1 -0
- package/dist/sarif/sarif-builder.js +79 -0
- package/dist/sarif/sarif-builder.js.map +1 -0
- package/dist/sarif/sarif-store.d.ts +205 -0
- package/dist/sarif/sarif-store.d.ts.map +1 -0
- package/dist/sarif/sarif-store.js +246 -0
- package/dist/sarif/sarif-store.js.map +1 -0
- package/dist/sarif/sarif-validator.d.ts +45 -0
- package/dist/sarif/sarif-validator.d.ts.map +1 -0
- package/dist/sarif/sarif-validator.js +138 -0
- package/dist/sarif/sarif-validator.js.map +1 -0
- package/dist/schemas/tool-schemas.d.ts +216 -0
- package/dist/schemas/tool-schemas.d.ts.map +1 -0
- package/dist/schemas/tool-schemas.js +208 -0
- package/dist/schemas/tool-schemas.js.map +1 -0
- package/dist/sdk.d.ts +45 -0
- package/dist/sdk.d.ts.map +1 -0
- package/dist/sdk.js +44 -0
- package/dist/sdk.js.map +1 -0
- package/dist/tools/index.d.ts +24 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +23 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/test-harness.d.ts +75 -0
- package/dist/tools/test-harness.d.ts.map +1 -0
- package/dist/tools/test-harness.js +137 -0
- package/dist/tools/test-harness.js.map +1 -0
- package/dist/workspace-guard.d.ts +53 -0
- package/dist/workspace-guard.d.ts.map +1 -0
- package/dist/workspace-guard.js +61 -0
- package/dist/workspace-guard.js.map +1 -0
- package/package.json +133 -0
- package/plugin/.claude-plugin/plugin.json +29 -0
- package/plugin/.mcp.json +18 -0
- package/plugin/CLAUDE.md +143 -0
- package/plugin/bundle/dashboard/public/index.html +368 -0
- package/plugin/bundle/dashboard/public/vendor/vue.global.prod.js +9 -0
- package/plugin/bundle/mcp-server.mjs +8718 -0
- package/plugin/bundle/mcp-server.mjs.map +7 -0
- package/plugin/bundle/tdr-engine.mjs +50 -0
- package/plugin/bundle/tdr-engine.mjs.map +7 -0
- package/plugin/hooks/hooks.json +62 -0
- package/plugin/hooks/lib/crap-config.mjs +152 -0
- package/plugin/hooks/lib/gatekeeper-rules.mjs +257 -0
- package/plugin/hooks/lib/hook-io.mjs +151 -0
- package/plugin/hooks/lib/quality-gate.mjs +329 -0
- package/plugin/hooks/lib/test-harness.mjs +152 -0
- package/plugin/hooks/post-tool-use.mjs +245 -0
- package/plugin/hooks/pre-tool-use.mjs +290 -0
- package/plugin/hooks/session-start.mjs +109 -0
- package/plugin/hooks/stop-quality-gate.mjs +226 -0
- package/plugin/package.json +18 -0
- package/plugin/skills/adopt/SKILL.md +74 -0
- package/plugin/skills/analyze/SKILL.md +77 -0
- package/plugin/skills/check-test/SKILL.md +50 -0
- package/plugin/skills/score/SKILL.md +31 -0
- package/scripts/bug-report.mjs +328 -0
- package/scripts/build-fast.mjs +130 -0
- package/scripts/bundle-plugin.mjs +74 -0
- package/scripts/doctor.mjs +320 -0
- package/scripts/install.mjs +192 -0
- package/scripts/lib/cli-ui.mjs +122 -0
- package/scripts/postinstall.mjs +127 -0
- package/scripts/run-tests.mjs +95 -0
- package/scripts/status.mjs +110 -0
- package/scripts/uninstall.mjs +72 -0
- package/src/adapters/bandit.ts +191 -0
- package/src/adapters/common.ts +133 -0
- package/src/adapters/eslint.ts +187 -0
- package/src/adapters/index.ts +78 -0
- package/src/adapters/semgrep.ts +150 -0
- package/src/adapters/stryker.ts +218 -0
- package/src/ast/cyclomatic.ts +131 -0
- package/src/ast/index.ts +33 -0
- package/src/ast/language-config.ts +231 -0
- package/src/ast/tree-sitter-engine.ts +385 -0
- package/src/config.ts +109 -0
- package/src/crap-config.ts +196 -0
- package/src/dashboard/public/index.html +368 -0
- package/src/dashboard/public/vendor/vue.global.prod.js +9 -0
- package/src/dashboard/server.ts +205 -0
- package/src/index.ts +696 -0
- package/src/metrics/crap.ts +101 -0
- package/src/metrics/index.ts +51 -0
- package/src/metrics/score.ts +329 -0
- package/src/metrics/tdr.ts +155 -0
- package/src/metrics/workspace-walker.ts +146 -0
- package/src/sarif/index.ts +31 -0
- package/src/sarif/sarif-builder.ts +139 -0
- package/src/sarif/sarif-store.ts +347 -0
- package/src/sarif/sarif-validator.ts +145 -0
- package/src/schemas/tool-schemas.ts +225 -0
- package/src/sdk.ts +110 -0
- package/src/tests/adapters/bandit.test.ts +111 -0
- package/src/tests/adapters/dispatch.test.ts +100 -0
- package/src/tests/adapters/eslint.test.ts +138 -0
- package/src/tests/adapters/semgrep.test.ts +125 -0
- package/src/tests/adapters/stryker.test.ts +103 -0
- package/src/tests/crap-config.test.ts +228 -0
- package/src/tests/crap.test.ts +59 -0
- package/src/tests/cyclomatic.test.ts +87 -0
- package/src/tests/dashboard-http.test.ts +108 -0
- package/src/tests/dashboard-integrity.test.ts +128 -0
- package/src/tests/integration/mcp-server.integration.test.ts +352 -0
- package/src/tests/pre-tool-use-hook.test.ts +178 -0
- package/src/tests/sarif-store.test.ts +241 -0
- package/src/tests/sarif-validator.test.ts +164 -0
- package/src/tests/score.test.ts +260 -0
- package/src/tests/skills-frontmatter.test.ts +172 -0
- package/src/tests/stop-quality-gate-strictness.test.ts +243 -0
- package/src/tests/tdr.test.ts +86 -0
- package/src/tests/test-harness.test.ts +153 -0
- package/src/tests/workspace-guard.test.ts +111 -0
- package/src/tools/index.ts +24 -0
- package/src/tools/test-harness.ts +158 -0
- package/src/workspace-guard.ts +64 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Vue.js dashboard for claude-crap — Fastify HTTP server.
|
|
3
|
+
*
|
|
4
|
+
* The dashboard runs in the same Node.js process as the MCP server,
|
|
5
|
+
* but on a separate TCP port (default 5117). It exposes:
|
|
6
|
+
*
|
|
7
|
+
* GET / → static index.html (Vue 3 SPA from CDN)
|
|
8
|
+
* GET /api/score → live ProjectScore JSON from the score engine
|
|
9
|
+
* GET /api/sarif → consolidated SARIF 2.1.0 document
|
|
10
|
+
* GET /api/health → simple {status:"ok"} liveness probe
|
|
11
|
+
*
|
|
12
|
+
* The server binds to `127.0.0.1` only — never to `0.0.0.0` — so the
|
|
13
|
+
* dashboard cannot be reached from outside the developer's machine.
|
|
14
|
+
*
|
|
15
|
+
* If the configured port is already in use (or the bind otherwise
|
|
16
|
+
* fails), `startDashboard()` rejects gracefully and the caller falls
|
|
17
|
+
* back to "no dashboard". The MCP server will keep running.
|
|
18
|
+
*
|
|
19
|
+
* IMPORTANT: this module never writes to stdout. The MCP stdio
|
|
20
|
+
* transport reserves stdout for JSON-RPC framing, so all logs and
|
|
21
|
+
* errors here go through the same pino-on-stderr instance the rest of
|
|
22
|
+
* the server uses.
|
|
23
|
+
*
|
|
24
|
+
* @module dashboard/server
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { promises as fs } from "node:fs";
|
|
28
|
+
import { dirname, resolve } from "node:path";
|
|
29
|
+
import { fileURLToPath } from "node:url";
|
|
30
|
+
|
|
31
|
+
import Fastify, { type FastifyInstance } from "fastify";
|
|
32
|
+
import fastifyStatic from "@fastify/static";
|
|
33
|
+
import type { Logger } from "pino";
|
|
34
|
+
|
|
35
|
+
import type { CrapConfig } from "../config.js";
|
|
36
|
+
import {
|
|
37
|
+
computeProjectScore,
|
|
38
|
+
type ProjectScore,
|
|
39
|
+
type WorkspaceStats,
|
|
40
|
+
} from "../metrics/score.js";
|
|
41
|
+
import type { SarifStore } from "../sarif/sarif-store.js";
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Callback used by the dashboard to refresh workspace LOC stats on
|
|
45
|
+
* every score request. The MCP server provides this so the dashboard
|
|
46
|
+
* does not have to know how to walk the disk itself.
|
|
47
|
+
*/
|
|
48
|
+
export type WorkspaceStatsProvider = () => Promise<WorkspaceStats>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Inputs accepted by {@link startDashboard}.
|
|
52
|
+
*/
|
|
53
|
+
export interface StartDashboardOptions {
|
|
54
|
+
/** Fully resolved server configuration. */
|
|
55
|
+
readonly config: CrapConfig;
|
|
56
|
+
/** Live SARIF store the dashboard reads findings from. */
|
|
57
|
+
readonly sarifStore: SarifStore;
|
|
58
|
+
/** Function that returns up-to-date LOC + file count for the workspace. */
|
|
59
|
+
readonly workspaceStatsProvider: WorkspaceStatsProvider;
|
|
60
|
+
/** Pino logger from the MCP server (writes to stderr). */
|
|
61
|
+
readonly logger: Logger;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Handle returned by {@link startDashboard}. Use `url` to build the
|
|
66
|
+
* link the user clicks; call `close()` during shutdown.
|
|
67
|
+
*/
|
|
68
|
+
export interface DashboardHandle {
|
|
69
|
+
readonly url: string;
|
|
70
|
+
close(): Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Boot the Fastify dashboard server. Resolves with a {@link DashboardHandle}
|
|
75
|
+
* once the server is listening, or rejects when the bind fails (caller
|
|
76
|
+
* should treat that as a non-fatal degradation).
|
|
77
|
+
*
|
|
78
|
+
* @param options Configuration, store, and provider callback.
|
|
79
|
+
*/
|
|
80
|
+
export async function startDashboard(options: StartDashboardOptions): Promise<DashboardHandle> {
|
|
81
|
+
const { config, sarifStore, workspaceStatsProvider, logger } = options;
|
|
82
|
+
|
|
83
|
+
// Resolve the public/ directory. After `npm run build` the compiled
|
|
84
|
+
// server lives in `dist/dashboard/server.js`, but we keep the static
|
|
85
|
+
// SPA assets in `src/dashboard/public/` so we don't need a postbuild
|
|
86
|
+
// copy step. We probe both candidate locations in priority order.
|
|
87
|
+
const publicRoot = await resolvePublicRoot(logger);
|
|
88
|
+
|
|
89
|
+
const fastify: FastifyInstance = Fastify({
|
|
90
|
+
logger: false, // we route everything through pino-on-stderr ourselves
|
|
91
|
+
disableRequestLogging: true,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
await fastify.register(fastifyStatic, {
|
|
95
|
+
root: publicRoot,
|
|
96
|
+
prefix: "/",
|
|
97
|
+
decorateReply: false,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// ------------------------------------------------------------------
|
|
101
|
+
// /api/health — liveness probe
|
|
102
|
+
// ------------------------------------------------------------------
|
|
103
|
+
fastify.get("/api/health", async () => ({ status: "ok", server: "claude-crap", version: "0.1.0" }));
|
|
104
|
+
|
|
105
|
+
// ------------------------------------------------------------------
|
|
106
|
+
// /api/score — live project score
|
|
107
|
+
// ------------------------------------------------------------------
|
|
108
|
+
fastify.get("/api/score", async () => {
|
|
109
|
+
const stats = await workspaceStatsProvider();
|
|
110
|
+
const score = await buildScore(config, sarifStore, stats, urlOf(fastify, config));
|
|
111
|
+
return score;
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// ------------------------------------------------------------------
|
|
115
|
+
// /api/sarif — consolidated SARIF 2.1.0 document
|
|
116
|
+
// ------------------------------------------------------------------
|
|
117
|
+
fastify.get("/api/sarif", async () => sarifStore.toSarifDocument());
|
|
118
|
+
|
|
119
|
+
// ------------------------------------------------------------------
|
|
120
|
+
// / — static SPA fallback (Fastify-static handles index.html)
|
|
121
|
+
// ------------------------------------------------------------------
|
|
122
|
+
|
|
123
|
+
await fastify.listen({ port: config.dashboardPort, host: "127.0.0.1" });
|
|
124
|
+
const url = `http://127.0.0.1:${config.dashboardPort}`;
|
|
125
|
+
logger.info({ url, publicRoot }, "claude-crap dashboard listening");
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
url,
|
|
129
|
+
async close() {
|
|
130
|
+
await fastify.close();
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Probe the candidate public/ directories in priority order and return
|
|
137
|
+
* the first one that contains an `index.html`. Throws when none of the
|
|
138
|
+
* candidates exist — that points at a packaging mistake the developer
|
|
139
|
+
* should fix immediately.
|
|
140
|
+
*
|
|
141
|
+
* @param logger Pino instance for diagnostics.
|
|
142
|
+
*/
|
|
143
|
+
async function resolvePublicRoot(logger: Logger): Promise<string> {
|
|
144
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
145
|
+
const candidates = [
|
|
146
|
+
// 0. Bundled layout: plugin/bundle/mcp-server.mjs → ./dashboard/public
|
|
147
|
+
resolve(here, "dashboard", "public"),
|
|
148
|
+
// 1. Compiled layout: dist/dashboard/server.js → ./public next to it
|
|
149
|
+
// (only present if a build step copies the assets — not used
|
|
150
|
+
// today, but accepted so a future copy step does not break us).
|
|
151
|
+
resolve(here, "public"),
|
|
152
|
+
// 2. Source-relative layout: dist/dashboard/server.js → ../../src/dashboard/public
|
|
153
|
+
// This is the default — no copy step required because we resolve
|
|
154
|
+
// upward from `dist/` into `src/` at runtime.
|
|
155
|
+
resolve(here, "..", "..", "src", "dashboard", "public"),
|
|
156
|
+
];
|
|
157
|
+
for (const candidate of candidates) {
|
|
158
|
+
try {
|
|
159
|
+
await fs.access(resolve(candidate, "index.html"));
|
|
160
|
+
return candidate;
|
|
161
|
+
} catch {
|
|
162
|
+
// probe next
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
logger.error({ candidates }, "dashboard public/ directory not found");
|
|
166
|
+
throw new Error(
|
|
167
|
+
`[claude-crap] dashboard: index.html not found in any of ${candidates.join(", ")}`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Resolve the canonical dashboard URL using the live Fastify address
|
|
173
|
+
* info. Falls back to the configured port when the address info is
|
|
174
|
+
* not yet available (e.g. on the very first request during startup).
|
|
175
|
+
*/
|
|
176
|
+
function urlOf(fastify: FastifyInstance, config: CrapConfig): string {
|
|
177
|
+
const addresses = fastify.addresses?.() ?? [];
|
|
178
|
+
const first = addresses[0];
|
|
179
|
+
if (first) {
|
|
180
|
+
const host = first.address === "::" || first.address === "0.0.0.0" ? "127.0.0.1" : first.address;
|
|
181
|
+
return `http://${host}:${first.port}`;
|
|
182
|
+
}
|
|
183
|
+
return `http://127.0.0.1:${config.dashboardPort}`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Wrap {@link computeProjectScore} so the dashboard endpoint can call
|
|
188
|
+
* it with the live store and provide consistent location metadata.
|
|
189
|
+
*/
|
|
190
|
+
async function buildScore(
|
|
191
|
+
config: CrapConfig,
|
|
192
|
+
sarifStore: SarifStore,
|
|
193
|
+
workspace: WorkspaceStats,
|
|
194
|
+
dashboardUrl: string | null,
|
|
195
|
+
): Promise<ProjectScore> {
|
|
196
|
+
return computeProjectScore({
|
|
197
|
+
workspaceRoot: config.pluginRoot,
|
|
198
|
+
minutesPerLoc: config.minutesPerLoc,
|
|
199
|
+
tdrMaxRating: config.tdrMaxRating,
|
|
200
|
+
workspace,
|
|
201
|
+
sarifStore,
|
|
202
|
+
dashboardUrl,
|
|
203
|
+
sarifReportPath: sarifStore.consolidatedReportPath,
|
|
204
|
+
});
|
|
205
|
+
}
|