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.
Files changed (202) hide show
  1. package/CHANGELOG.md +308 -0
  2. package/LICENSE +21 -0
  3. package/README.md +550 -0
  4. package/bin/claude-crap.mjs +141 -0
  5. package/dist/adapters/bandit.d.ts +48 -0
  6. package/dist/adapters/bandit.d.ts.map +1 -0
  7. package/dist/adapters/bandit.js +145 -0
  8. package/dist/adapters/bandit.js.map +1 -0
  9. package/dist/adapters/common.d.ts +73 -0
  10. package/dist/adapters/common.d.ts.map +1 -0
  11. package/dist/adapters/common.js +78 -0
  12. package/dist/adapters/common.js.map +1 -0
  13. package/dist/adapters/eslint.d.ts +52 -0
  14. package/dist/adapters/eslint.d.ts.map +1 -0
  15. package/dist/adapters/eslint.js +142 -0
  16. package/dist/adapters/eslint.js.map +1 -0
  17. package/dist/adapters/index.d.ts +47 -0
  18. package/dist/adapters/index.d.ts.map +1 -0
  19. package/dist/adapters/index.js +64 -0
  20. package/dist/adapters/index.js.map +1 -0
  21. package/dist/adapters/semgrep.d.ts +30 -0
  22. package/dist/adapters/semgrep.d.ts.map +1 -0
  23. package/dist/adapters/semgrep.js +130 -0
  24. package/dist/adapters/semgrep.js.map +1 -0
  25. package/dist/adapters/stryker.d.ts +55 -0
  26. package/dist/adapters/stryker.d.ts.map +1 -0
  27. package/dist/adapters/stryker.js +165 -0
  28. package/dist/adapters/stryker.js.map +1 -0
  29. package/dist/ast/cyclomatic.d.ts +48 -0
  30. package/dist/ast/cyclomatic.d.ts.map +1 -0
  31. package/dist/ast/cyclomatic.js +106 -0
  32. package/dist/ast/cyclomatic.js.map +1 -0
  33. package/dist/ast/index.d.ts +26 -0
  34. package/dist/ast/index.d.ts.map +1 -0
  35. package/dist/ast/index.js +23 -0
  36. package/dist/ast/index.js.map +1 -0
  37. package/dist/ast/language-config.d.ts +70 -0
  38. package/dist/ast/language-config.d.ts.map +1 -0
  39. package/dist/ast/language-config.js +192 -0
  40. package/dist/ast/language-config.js.map +1 -0
  41. package/dist/ast/tree-sitter-engine.d.ts +133 -0
  42. package/dist/ast/tree-sitter-engine.d.ts.map +1 -0
  43. package/dist/ast/tree-sitter-engine.js +270 -0
  44. package/dist/ast/tree-sitter-engine.js.map +1 -0
  45. package/dist/config.d.ts +57 -0
  46. package/dist/config.d.ts.map +1 -0
  47. package/dist/config.js +78 -0
  48. package/dist/config.js.map +1 -0
  49. package/dist/crap-config.d.ts +97 -0
  50. package/dist/crap-config.d.ts.map +1 -0
  51. package/dist/crap-config.js +144 -0
  52. package/dist/crap-config.js.map +1 -0
  53. package/dist/dashboard/server.d.ts +65 -0
  54. package/dist/dashboard/server.d.ts.map +1 -0
  55. package/dist/dashboard/server.js +147 -0
  56. package/dist/dashboard/server.js.map +1 -0
  57. package/dist/index.d.ts +32 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +574 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/metrics/crap.d.ts +71 -0
  62. package/dist/metrics/crap.d.ts.map +1 -0
  63. package/dist/metrics/crap.js +67 -0
  64. package/dist/metrics/crap.js.map +1 -0
  65. package/dist/metrics/index.d.ts +31 -0
  66. package/dist/metrics/index.d.ts.map +1 -0
  67. package/dist/metrics/index.js +27 -0
  68. package/dist/metrics/index.js.map +1 -0
  69. package/dist/metrics/score.d.ts +143 -0
  70. package/dist/metrics/score.d.ts.map +1 -0
  71. package/dist/metrics/score.js +224 -0
  72. package/dist/metrics/score.js.map +1 -0
  73. package/dist/metrics/tdr.d.ts +106 -0
  74. package/dist/metrics/tdr.d.ts.map +1 -0
  75. package/dist/metrics/tdr.js +117 -0
  76. package/dist/metrics/tdr.js.map +1 -0
  77. package/dist/metrics/workspace-walker.d.ts +43 -0
  78. package/dist/metrics/workspace-walker.d.ts.map +1 -0
  79. package/dist/metrics/workspace-walker.js +137 -0
  80. package/dist/metrics/workspace-walker.js.map +1 -0
  81. package/dist/sarif/index.d.ts +21 -0
  82. package/dist/sarif/index.d.ts.map +1 -0
  83. package/dist/sarif/index.js +19 -0
  84. package/dist/sarif/index.js.map +1 -0
  85. package/dist/sarif/sarif-builder.d.ts +128 -0
  86. package/dist/sarif/sarif-builder.d.ts.map +1 -0
  87. package/dist/sarif/sarif-builder.js +79 -0
  88. package/dist/sarif/sarif-builder.js.map +1 -0
  89. package/dist/sarif/sarif-store.d.ts +205 -0
  90. package/dist/sarif/sarif-store.d.ts.map +1 -0
  91. package/dist/sarif/sarif-store.js +246 -0
  92. package/dist/sarif/sarif-store.js.map +1 -0
  93. package/dist/sarif/sarif-validator.d.ts +45 -0
  94. package/dist/sarif/sarif-validator.d.ts.map +1 -0
  95. package/dist/sarif/sarif-validator.js +138 -0
  96. package/dist/sarif/sarif-validator.js.map +1 -0
  97. package/dist/schemas/tool-schemas.d.ts +216 -0
  98. package/dist/schemas/tool-schemas.d.ts.map +1 -0
  99. package/dist/schemas/tool-schemas.js +208 -0
  100. package/dist/schemas/tool-schemas.js.map +1 -0
  101. package/dist/sdk.d.ts +45 -0
  102. package/dist/sdk.d.ts.map +1 -0
  103. package/dist/sdk.js +44 -0
  104. package/dist/sdk.js.map +1 -0
  105. package/dist/tools/index.d.ts +24 -0
  106. package/dist/tools/index.d.ts.map +1 -0
  107. package/dist/tools/index.js +23 -0
  108. package/dist/tools/index.js.map +1 -0
  109. package/dist/tools/test-harness.d.ts +75 -0
  110. package/dist/tools/test-harness.d.ts.map +1 -0
  111. package/dist/tools/test-harness.js +137 -0
  112. package/dist/tools/test-harness.js.map +1 -0
  113. package/dist/workspace-guard.d.ts +53 -0
  114. package/dist/workspace-guard.d.ts.map +1 -0
  115. package/dist/workspace-guard.js +61 -0
  116. package/dist/workspace-guard.js.map +1 -0
  117. package/package.json +133 -0
  118. package/plugin/.claude-plugin/plugin.json +29 -0
  119. package/plugin/.mcp.json +18 -0
  120. package/plugin/CLAUDE.md +143 -0
  121. package/plugin/bundle/dashboard/public/index.html +368 -0
  122. package/plugin/bundle/dashboard/public/vendor/vue.global.prod.js +9 -0
  123. package/plugin/bundle/mcp-server.mjs +8718 -0
  124. package/plugin/bundle/mcp-server.mjs.map +7 -0
  125. package/plugin/bundle/tdr-engine.mjs +50 -0
  126. package/plugin/bundle/tdr-engine.mjs.map +7 -0
  127. package/plugin/hooks/hooks.json +62 -0
  128. package/plugin/hooks/lib/crap-config.mjs +152 -0
  129. package/plugin/hooks/lib/gatekeeper-rules.mjs +257 -0
  130. package/plugin/hooks/lib/hook-io.mjs +151 -0
  131. package/plugin/hooks/lib/quality-gate.mjs +329 -0
  132. package/plugin/hooks/lib/test-harness.mjs +152 -0
  133. package/plugin/hooks/post-tool-use.mjs +245 -0
  134. package/plugin/hooks/pre-tool-use.mjs +290 -0
  135. package/plugin/hooks/session-start.mjs +109 -0
  136. package/plugin/hooks/stop-quality-gate.mjs +226 -0
  137. package/plugin/package.json +18 -0
  138. package/plugin/skills/adopt/SKILL.md +74 -0
  139. package/plugin/skills/analyze/SKILL.md +77 -0
  140. package/plugin/skills/check-test/SKILL.md +50 -0
  141. package/plugin/skills/score/SKILL.md +31 -0
  142. package/scripts/bug-report.mjs +328 -0
  143. package/scripts/build-fast.mjs +130 -0
  144. package/scripts/bundle-plugin.mjs +74 -0
  145. package/scripts/doctor.mjs +320 -0
  146. package/scripts/install.mjs +192 -0
  147. package/scripts/lib/cli-ui.mjs +122 -0
  148. package/scripts/postinstall.mjs +127 -0
  149. package/scripts/run-tests.mjs +95 -0
  150. package/scripts/status.mjs +110 -0
  151. package/scripts/uninstall.mjs +72 -0
  152. package/src/adapters/bandit.ts +191 -0
  153. package/src/adapters/common.ts +133 -0
  154. package/src/adapters/eslint.ts +187 -0
  155. package/src/adapters/index.ts +78 -0
  156. package/src/adapters/semgrep.ts +150 -0
  157. package/src/adapters/stryker.ts +218 -0
  158. package/src/ast/cyclomatic.ts +131 -0
  159. package/src/ast/index.ts +33 -0
  160. package/src/ast/language-config.ts +231 -0
  161. package/src/ast/tree-sitter-engine.ts +385 -0
  162. package/src/config.ts +109 -0
  163. package/src/crap-config.ts +196 -0
  164. package/src/dashboard/public/index.html +368 -0
  165. package/src/dashboard/public/vendor/vue.global.prod.js +9 -0
  166. package/src/dashboard/server.ts +205 -0
  167. package/src/index.ts +696 -0
  168. package/src/metrics/crap.ts +101 -0
  169. package/src/metrics/index.ts +51 -0
  170. package/src/metrics/score.ts +329 -0
  171. package/src/metrics/tdr.ts +155 -0
  172. package/src/metrics/workspace-walker.ts +146 -0
  173. package/src/sarif/index.ts +31 -0
  174. package/src/sarif/sarif-builder.ts +139 -0
  175. package/src/sarif/sarif-store.ts +347 -0
  176. package/src/sarif/sarif-validator.ts +145 -0
  177. package/src/schemas/tool-schemas.ts +225 -0
  178. package/src/sdk.ts +110 -0
  179. package/src/tests/adapters/bandit.test.ts +111 -0
  180. package/src/tests/adapters/dispatch.test.ts +100 -0
  181. package/src/tests/adapters/eslint.test.ts +138 -0
  182. package/src/tests/adapters/semgrep.test.ts +125 -0
  183. package/src/tests/adapters/stryker.test.ts +103 -0
  184. package/src/tests/crap-config.test.ts +228 -0
  185. package/src/tests/crap.test.ts +59 -0
  186. package/src/tests/cyclomatic.test.ts +87 -0
  187. package/src/tests/dashboard-http.test.ts +108 -0
  188. package/src/tests/dashboard-integrity.test.ts +128 -0
  189. package/src/tests/integration/mcp-server.integration.test.ts +352 -0
  190. package/src/tests/pre-tool-use-hook.test.ts +178 -0
  191. package/src/tests/sarif-store.test.ts +241 -0
  192. package/src/tests/sarif-validator.test.ts +164 -0
  193. package/src/tests/score.test.ts +260 -0
  194. package/src/tests/skills-frontmatter.test.ts +172 -0
  195. package/src/tests/stop-quality-gate-strictness.test.ts +243 -0
  196. package/src/tests/tdr.test.ts +86 -0
  197. package/src/tests/test-harness.test.ts +153 -0
  198. package/src/tests/workspace-guard.test.ts +111 -0
  199. package/src/tools/index.ts +24 -0
  200. package/src/tools/test-harness.ts +158 -0
  201. package/src/workspace-guard.ts +64 -0
  202. package/tsconfig.json +27 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crap-config.js","sourceRoot":"","sources":["../src/crap-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
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
+ import type { Logger } from "pino";
27
+ import type { CrapConfig } from "../config.js";
28
+ import { type WorkspaceStats } from "../metrics/score.js";
29
+ import type { SarifStore } from "../sarif/sarif-store.js";
30
+ /**
31
+ * Callback used by the dashboard to refresh workspace LOC stats on
32
+ * every score request. The MCP server provides this so the dashboard
33
+ * does not have to know how to walk the disk itself.
34
+ */
35
+ export type WorkspaceStatsProvider = () => Promise<WorkspaceStats>;
36
+ /**
37
+ * Inputs accepted by {@link startDashboard}.
38
+ */
39
+ export interface StartDashboardOptions {
40
+ /** Fully resolved server configuration. */
41
+ readonly config: CrapConfig;
42
+ /** Live SARIF store the dashboard reads findings from. */
43
+ readonly sarifStore: SarifStore;
44
+ /** Function that returns up-to-date LOC + file count for the workspace. */
45
+ readonly workspaceStatsProvider: WorkspaceStatsProvider;
46
+ /** Pino logger from the MCP server (writes to stderr). */
47
+ readonly logger: Logger;
48
+ }
49
+ /**
50
+ * Handle returned by {@link startDashboard}. Use `url` to build the
51
+ * link the user clicks; call `close()` during shutdown.
52
+ */
53
+ export interface DashboardHandle {
54
+ readonly url: string;
55
+ close(): Promise<void>;
56
+ }
57
+ /**
58
+ * Boot the Fastify dashboard server. Resolves with a {@link DashboardHandle}
59
+ * once the server is listening, or rejects when the bind fails (caller
60
+ * should treat that as a non-fatal degradation).
61
+ *
62
+ * @param options Configuration, store, and provider callback.
63
+ */
64
+ export declare function startDashboard(options: StartDashboardOptions): Promise<DashboardHandle>;
65
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/dashboard/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAQH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,2EAA2E;IAC3E,QAAQ,CAAC,sBAAsB,EAAE,sBAAsB,CAAC;IACxD,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAqD7F"}
@@ -0,0 +1,147 @@
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
+ import { promises as fs } from "node:fs";
27
+ import { dirname, resolve } from "node:path";
28
+ import { fileURLToPath } from "node:url";
29
+ import Fastify from "fastify";
30
+ import fastifyStatic from "@fastify/static";
31
+ import { computeProjectScore, } from "../metrics/score.js";
32
+ /**
33
+ * Boot the Fastify dashboard server. Resolves with a {@link DashboardHandle}
34
+ * once the server is listening, or rejects when the bind fails (caller
35
+ * should treat that as a non-fatal degradation).
36
+ *
37
+ * @param options Configuration, store, and provider callback.
38
+ */
39
+ export async function startDashboard(options) {
40
+ const { config, sarifStore, workspaceStatsProvider, logger } = options;
41
+ // Resolve the public/ directory. After `npm run build` the compiled
42
+ // server lives in `dist/dashboard/server.js`, but we keep the static
43
+ // SPA assets in `src/dashboard/public/` so we don't need a postbuild
44
+ // copy step. We probe both candidate locations in priority order.
45
+ const publicRoot = await resolvePublicRoot(logger);
46
+ const fastify = Fastify({
47
+ logger: false, // we route everything through pino-on-stderr ourselves
48
+ disableRequestLogging: true,
49
+ });
50
+ await fastify.register(fastifyStatic, {
51
+ root: publicRoot,
52
+ prefix: "/",
53
+ decorateReply: false,
54
+ });
55
+ // ------------------------------------------------------------------
56
+ // /api/health — liveness probe
57
+ // ------------------------------------------------------------------
58
+ fastify.get("/api/health", async () => ({ status: "ok", server: "claude-crap", version: "0.1.0" }));
59
+ // ------------------------------------------------------------------
60
+ // /api/score — live project score
61
+ // ------------------------------------------------------------------
62
+ fastify.get("/api/score", async () => {
63
+ const stats = await workspaceStatsProvider();
64
+ const score = await buildScore(config, sarifStore, stats, urlOf(fastify, config));
65
+ return score;
66
+ });
67
+ // ------------------------------------------------------------------
68
+ // /api/sarif — consolidated SARIF 2.1.0 document
69
+ // ------------------------------------------------------------------
70
+ fastify.get("/api/sarif", async () => sarifStore.toSarifDocument());
71
+ // ------------------------------------------------------------------
72
+ // / — static SPA fallback (Fastify-static handles index.html)
73
+ // ------------------------------------------------------------------
74
+ await fastify.listen({ port: config.dashboardPort, host: "127.0.0.1" });
75
+ const url = `http://127.0.0.1:${config.dashboardPort}`;
76
+ logger.info({ url, publicRoot }, "claude-crap dashboard listening");
77
+ return {
78
+ url,
79
+ async close() {
80
+ await fastify.close();
81
+ },
82
+ };
83
+ }
84
+ /**
85
+ * Probe the candidate public/ directories in priority order and return
86
+ * the first one that contains an `index.html`. Throws when none of the
87
+ * candidates exist — that points at a packaging mistake the developer
88
+ * should fix immediately.
89
+ *
90
+ * @param logger Pino instance for diagnostics.
91
+ */
92
+ async function resolvePublicRoot(logger) {
93
+ const here = dirname(fileURLToPath(import.meta.url));
94
+ const candidates = [
95
+ // 0. Bundled layout: plugin/bundle/mcp-server.mjs → ./dashboard/public
96
+ resolve(here, "dashboard", "public"),
97
+ // 1. Compiled layout: dist/dashboard/server.js → ./public next to it
98
+ // (only present if a build step copies the assets — not used
99
+ // today, but accepted so a future copy step does not break us).
100
+ resolve(here, "public"),
101
+ // 2. Source-relative layout: dist/dashboard/server.js → ../../src/dashboard/public
102
+ // This is the default — no copy step required because we resolve
103
+ // upward from `dist/` into `src/` at runtime.
104
+ resolve(here, "..", "..", "src", "dashboard", "public"),
105
+ ];
106
+ for (const candidate of candidates) {
107
+ try {
108
+ await fs.access(resolve(candidate, "index.html"));
109
+ return candidate;
110
+ }
111
+ catch {
112
+ // probe next
113
+ }
114
+ }
115
+ logger.error({ candidates }, "dashboard public/ directory not found");
116
+ throw new Error(`[claude-crap] dashboard: index.html not found in any of ${candidates.join(", ")}`);
117
+ }
118
+ /**
119
+ * Resolve the canonical dashboard URL using the live Fastify address
120
+ * info. Falls back to the configured port when the address info is
121
+ * not yet available (e.g. on the very first request during startup).
122
+ */
123
+ function urlOf(fastify, config) {
124
+ const addresses = fastify.addresses?.() ?? [];
125
+ const first = addresses[0];
126
+ if (first) {
127
+ const host = first.address === "::" || first.address === "0.0.0.0" ? "127.0.0.1" : first.address;
128
+ return `http://${host}:${first.port}`;
129
+ }
130
+ return `http://127.0.0.1:${config.dashboardPort}`;
131
+ }
132
+ /**
133
+ * Wrap {@link computeProjectScore} so the dashboard endpoint can call
134
+ * it with the live store and provide consistent location metadata.
135
+ */
136
+ async function buildScore(config, sarifStore, workspace, dashboardUrl) {
137
+ return computeProjectScore({
138
+ workspaceRoot: config.pluginRoot,
139
+ minutesPerLoc: config.minutesPerLoc,
140
+ tdrMaxRating: config.tdrMaxRating,
141
+ workspace,
142
+ sarifStore,
143
+ dashboardUrl,
144
+ sarifReportPath: sarifStore.consolidatedReportPath,
145
+ });
146
+ }
147
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/dashboard/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * claude-crap MCP server — entrypoint.
4
+ *
5
+ * Transport: stdio. The server is launched by `.mcp.json` with the
6
+ * arguments `--transport stdio` and it never opens sockets or listens
7
+ * on the network: all communication with Claude Code happens over
8
+ * stdin/stdout as JSON-RPC messages.
9
+ *
10
+ * What this file wires together:
11
+ *
12
+ * Tools:
13
+ * - compute_crap (CRAP index for one function)
14
+ * - compute_tdr (Technical Debt Ratio for a scope)
15
+ * - analyze_file_ast (tree-sitter AST metrics for a source file)
16
+ * - ingest_sarif (normalize + dedupe an external SARIF report)
17
+ * - ingest_scanner_output (route Semgrep/ESLint/Bandit/Stryker native output through an adapter and persist the normalized SARIF)
18
+ * - require_test_harness (check that a production source file has a matching test)
19
+ * - score_project (aggregate the workspace into Maintainability / Reliability / Security / Overall ratings)
20
+ *
21
+ * Resources:
22
+ * - sonar://metrics/current (live CRAP / TDR / rating snapshot)
23
+ * - sonar://reports/latest.sarif (last consolidated SARIF document)
24
+ *
25
+ * The handlers delegate to pure engines in `./metrics`, `./ast` and
26
+ * `./sarif`, so the index file stays focused on routing and
27
+ * cross-cutting concerns (configuration, logging, error boundaries).
28
+ *
29
+ * @module index
30
+ */
31
+ export {};
32
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG"}