code-auditor-mcp 3.9.6 → 3.9.11

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 (127) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +220 -0
  3. package/README.md +18 -0
  4. package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
  5. package/dist/analyzers/reactAnalyzer.js +4 -1
  6. package/dist/analyzers/reactAnalyzer.js.map +1 -1
  7. package/dist/analyzers/ruleRegistry.d.ts +8 -0
  8. package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
  9. package/dist/analyzers/ruleRegistry.js +32 -10
  10. package/dist/analyzers/ruleRegistry.js.map +1 -1
  11. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
  12. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +23 -20
  13. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
  14. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts +1 -0
  15. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
  16. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +19 -5
  17. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
  18. package/dist/analyzers/universal/schema/codeAnalysis.d.ts +44 -2
  19. package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -1
  20. package/dist/analyzers/universal/schema/codeAnalysis.js +153 -8
  21. package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -1
  22. package/dist/analyzers/universal/schema/config.d.ts +8 -0
  23. package/dist/analyzers/universal/schema/config.d.ts.map +1 -1
  24. package/dist/analyzers/universal/schema/config.js +9 -0
  25. package/dist/analyzers/universal/schema/config.js.map +1 -1
  26. package/dist/analyzers/universal/schema/types.d.ts +5 -0
  27. package/dist/analyzers/universal/schema/types.d.ts.map +1 -1
  28. package/dist/auditRouter.d.ts.map +1 -1
  29. package/dist/auditRouter.js +6 -1
  30. package/dist/auditRouter.js.map +1 -1
  31. package/dist/auditRunner.d.ts.map +1 -1
  32. package/dist/auditRunner.js +62 -8
  33. package/dist/auditRunner.js.map +1 -1
  34. package/dist/cli.js +157 -13
  35. package/dist/cli.js.map +1 -1
  36. package/dist/codeIndexDB.d.ts.map +1 -1
  37. package/dist/codeIndexDB.js +29 -7
  38. package/dist/codeIndexDB.js.map +1 -1
  39. package/dist/config/defaults.d.ts +2 -0
  40. package/dist/config/defaults.d.ts.map +1 -1
  41. package/dist/config/defaults.js +15 -6
  42. package/dist/config/defaults.js.map +1 -1
  43. package/dist/config/effectiveConfig.d.ts +22 -1
  44. package/dist/config/effectiveConfig.d.ts.map +1 -1
  45. package/dist/config/effectiveConfig.js +69 -2
  46. package/dist/config/effectiveConfig.js.map +1 -1
  47. package/dist/config/lintConfigReader.d.ts +56 -0
  48. package/dist/config/lintConfigReader.d.ts.map +1 -0
  49. package/dist/config/lintConfigReader.js +263 -0
  50. package/dist/config/lintConfigReader.js.map +1 -0
  51. package/dist/constants.d.ts +9 -2
  52. package/dist/constants.d.ts.map +1 -1
  53. package/dist/constants.js +10 -6
  54. package/dist/constants.js.map +1 -1
  55. package/dist/dataPaths.d.ts +8 -0
  56. package/dist/dataPaths.d.ts.map +1 -1
  57. package/dist/dataPaths.js +21 -0
  58. package/dist/dataPaths.js.map +1 -1
  59. package/dist/dismissals.d.ts +59 -0
  60. package/dist/dismissals.d.ts.map +1 -0
  61. package/dist/dismissals.js +128 -0
  62. package/dist/dismissals.js.map +1 -0
  63. package/dist/enforcement/gate.d.ts.map +1 -1
  64. package/dist/enforcement/gate.js +5 -0
  65. package/dist/enforcement/gate.js.map +1 -1
  66. package/dist/hooks/codex.d.ts.map +1 -1
  67. package/dist/hooks/codex.js +18 -6
  68. package/dist/hooks/codex.js.map +1 -1
  69. package/dist/hooks/core.d.ts +12 -0
  70. package/dist/hooks/core.d.ts.map +1 -1
  71. package/dist/hooks/core.js +12 -3
  72. package/dist/hooks/core.js.map +1 -1
  73. package/dist/hooks/cursor.d.ts.map +1 -1
  74. package/dist/hooks/cursor.js +17 -10
  75. package/dist/hooks/cursor.js.map +1 -1
  76. package/dist/installConfig.d.ts +40 -0
  77. package/dist/installConfig.d.ts.map +1 -0
  78. package/dist/installConfig.js +84 -0
  79. package/dist/installConfig.js.map +1 -0
  80. package/dist/installer.d.ts.map +1 -1
  81. package/dist/installer.js +2 -15
  82. package/dist/installer.js.map +1 -1
  83. package/dist/languages/go/analyzer +0 -0
  84. package/dist/languages/go/analyzer-src/solid.go +14 -6
  85. package/dist/mcp.js +54 -0
  86. package/dist/mcp.js.map +1 -1
  87. package/dist/pipeline.d.ts.map +1 -1
  88. package/dist/pipeline.js +12 -1
  89. package/dist/pipeline.js.map +1 -1
  90. package/dist/pipelineAdapters.d.ts.map +1 -1
  91. package/dist/pipelineAdapters.js +87 -7
  92. package/dist/pipelineAdapters.js.map +1 -1
  93. package/dist/reporting/csvReportGenerator.d.ts.map +1 -1
  94. package/dist/reporting/csvReportGenerator.js +1 -0
  95. package/dist/reporting/csvReportGenerator.js.map +1 -1
  96. package/dist/reporting/htmlReportGenerator.d.ts.map +1 -1
  97. package/dist/reporting/htmlReportGenerator.js +5 -0
  98. package/dist/reporting/htmlReportGenerator.js.map +1 -1
  99. package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
  100. package/dist/reporting/jsonReportGenerator.js +6 -0
  101. package/dist/reporting/jsonReportGenerator.js.map +1 -1
  102. package/dist/reporting/sarifReportGenerator.d.ts.map +1 -1
  103. package/dist/reporting/sarifReportGenerator.js +3 -0
  104. package/dist/reporting/sarifReportGenerator.js.map +1 -1
  105. package/dist/services/auditJobService.d.ts.map +1 -1
  106. package/dist/services/auditJobService.js +4 -7
  107. package/dist/services/auditJobService.js.map +1 -1
  108. package/dist/structuralSignature.d.ts +41 -0
  109. package/dist/structuralSignature.d.ts.map +1 -0
  110. package/dist/structuralSignature.js +93 -0
  111. package/dist/structuralSignature.js.map +1 -0
  112. package/dist/telemetry.d.ts +80 -0
  113. package/dist/telemetry.d.ts.map +1 -0
  114. package/dist/telemetry.js +148 -0
  115. package/dist/telemetry.js.map +1 -0
  116. package/dist/types.d.ts +72 -1
  117. package/dist/types.d.ts.map +1 -1
  118. package/dist/types.js.map +1 -1
  119. package/dist/version.generated.d.ts +2 -0
  120. package/dist/version.generated.d.ts.map +1 -0
  121. package/dist/version.generated.js +7 -0
  122. package/dist/version.generated.js.map +1 -0
  123. package/package.json +3 -2
  124. package/plugin/.claude-plugin/plugin.json +1 -1
  125. package/plugin/scripts/hook-common.sh +37 -9
  126. package/plugin/skills/code-auditor/SKILL.md +24 -2
  127. package/server.json +2 -2
@@ -10,14 +10,11 @@
10
10
  * The database handle is passed in explicitly (matching `ledger.ts`); callers
11
11
  * resolve the per-project DB via `CodeIndexDB.getInstance(undefined, projectRoot)`.
12
12
  */
13
- import path from 'node:path';
14
- import { readFileSync } from 'node:fs';
15
- import { fileURLToPath } from 'node:url';
16
13
  import { createLedgerRun, detectRunInput, getLedgerRun, patchLedgerRun, } from '../ledger.js';
17
- // Package version — read once at module load (mirrors auditRunner.ts).
18
- const __svcDirname = path.dirname(fileURLToPath(import.meta.url));
19
- const _pkg = JSON.parse(readFileSync(path.join(__svcDirname, '..', '..', 'package.json'), 'utf-8'));
20
- const TOOL_VERSION = String(_pkg.version || '0.0.0');
14
+ // Package version — stamped into the build (see constants.ts), not read from
15
+ // package.json at runtime, so a stale binary reports the version it was built as.
16
+ import { PACKAGE_VERSION } from '../constants.js';
17
+ const TOOL_VERSION = PACKAGE_VERSION;
21
18
  function toAuditJobRecord(detail) {
22
19
  let progress;
23
20
  if (detail.progressJson) {
@@ -1 +1 @@
1
- {"version":3,"file":"auditJobService.js","sourceRoot":"","sources":["../../src/services/auditJobService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auditJobService.js","sourceRoot":"","sources":["../../src/services/auditJobService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Spec 57 — structural AST signature.
3
+ *
4
+ * The telemetry payload describes *the shape* of the code a finding points at,
5
+ * so the service can cluster "these are all for-loops with a `.save()` inside"
6
+ * without ever receiving source text. The only thing this module reads off a
7
+ * node is `type` — the tree-sitter grammar kind (`for_statement`,
8
+ * `call_expression`, `identifier`, `string`, …) — a fixed, finite vocabulary.
9
+ * It never reads `getNodeText`/`getNodeName`/`raw`, so identifiers, string
10
+ * literals, table names, paths, and comments can never enter a signature.
11
+ *
12
+ * Acceptance 6 (the shipping gate) hinges on exactly this: a finding on code
13
+ * containing a secret + a table name + a distinctive identifier must produce a
14
+ * signature containing none of the three. The `structuralSignature.spec.ts`
15
+ * guard test asserts that directly.
16
+ */
17
+ import type { AST, ASTNode } from './languages/types.js';
18
+ export interface SignatureOptions {
19
+ /** Stop descending past this depth (default 8). Keeps the shape coarse. */
20
+ maxDepth?: number;
21
+ /** Stop after this many node kinds (default 128). Bounds large subtrees. */
22
+ maxNodes?: number;
23
+ }
24
+ /**
25
+ * Canonical structural signature of a node's subtree: a parenthesized pre-order
26
+ * encoding of node kinds. Only `type` is read; content is never touched, so the
27
+ * output is safe to transmit.
28
+ *
29
+ * Example: `for_statement ( ) call_expression ( member_expression ( identifier property_identifier ) argument_list ( ) )`
30
+ */
31
+ export declare function structuralSignature(node: ASTNode, opts?: SignatureOptions): string;
32
+ /**
33
+ * Produce the structural signature for a finding at a 1-based source location.
34
+ * The located node is walked up to its function/class boundary before signing.
35
+ * Returns null when no node contains the location.
36
+ */
37
+ export declare function signatureForLocation(ast: AST, location: {
38
+ line: number;
39
+ column: number;
40
+ }, opts?: SignatureOptions): string | null;
41
+ //# sourceMappingURL=structuralSignature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structuralSignature.d.ts","sourceRoot":"","sources":["../src/structuralSignature.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAGzD,MAAM,WAAW,gBAAgB;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,GAAE,gBAAqB,GAAG,MAAM,CAsBtF;AAuDD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC1C,IAAI,GAAE,gBAAqB,GAC1B,MAAM,GAAG,IAAI,CAIf"}
@@ -0,0 +1,93 @@
1
+ import { isFunctionType, isClassType } from './languages/tree-sitter/converter.js';
2
+ /**
3
+ * Canonical structural signature of a node's subtree: a parenthesized pre-order
4
+ * encoding of node kinds. Only `type` is read; content is never touched, so the
5
+ * output is safe to transmit.
6
+ *
7
+ * Example: `for_statement ( ) call_expression ( member_expression ( identifier property_identifier ) argument_list ( ) )`
8
+ */
9
+ export function structuralSignature(node, opts = {}) {
10
+ const maxDepth = opts.maxDepth ?? 8;
11
+ const maxNodes = opts.maxNodes ?? 128;
12
+ const parts = [];
13
+ let count = 0;
14
+ const walk = (n, depth) => {
15
+ if (count >= maxNodes)
16
+ return false;
17
+ count += 1;
18
+ parts.push(n.type);
19
+ const kids = n.children ?? [];
20
+ if (depth >= maxDepth || kids.length === 0)
21
+ return true;
22
+ parts.push('(');
23
+ for (const child of kids) {
24
+ if (!walk(child, depth + 1))
25
+ break;
26
+ }
27
+ parts.push(')');
28
+ return true;
29
+ };
30
+ walk(node, 0);
31
+ return parts.join(' ');
32
+ }
33
+ /**
34
+ * The node whose shape represents the finding's code: the nearest enclosing
35
+ * function/class/method boundary, else the nearest top-level statement, else the
36
+ * located node itself. Climbing to the function boundary means the signature
37
+ * captures the finding's *context* (the whole for-loop, not just the `.save()`),
38
+ * while `maxNodes` keeps a giant function from producing a giant signature.
39
+ */
40
+ function findSignatureRoot(located) {
41
+ let funcOrClass = null;
42
+ let topLevel = null;
43
+ let cur = located;
44
+ while (cur) {
45
+ if (!funcOrClass && (isFunctionType(cur.type) || isClassType(cur.type))) {
46
+ funcOrClass = cur;
47
+ }
48
+ const parent = cur.parent;
49
+ if (parent && !parent.parent) {
50
+ // `parent` is the root — `cur` is a top-level statement/declaration.
51
+ if (!topLevel)
52
+ topLevel = cur;
53
+ }
54
+ cur = parent;
55
+ }
56
+ return funcOrClass ?? topLevel ?? located;
57
+ }
58
+ /**
59
+ * Locate the deepest node containing the given 1-based line/column.
60
+ * Returns null when the location is outside the tree.
61
+ */
62
+ function findDeepestNodeAt(root, location) {
63
+ let best = null;
64
+ let bestDepth = -1;
65
+ const walk = (node, depth) => {
66
+ const s = node.location.start;
67
+ const e = node.location.end;
68
+ const contains = (s.line < location.line || (s.line === location.line && s.column <= location.column)) &&
69
+ (e.line > location.line || (e.line === location.line && e.column >= location.column));
70
+ if (!contains)
71
+ return;
72
+ if (depth > bestDepth) {
73
+ best = node;
74
+ bestDepth = depth;
75
+ }
76
+ for (const child of node.children ?? [])
77
+ walk(child, depth + 1);
78
+ };
79
+ walk(root, 0);
80
+ return best;
81
+ }
82
+ /**
83
+ * Produce the structural signature for a finding at a 1-based source location.
84
+ * The located node is walked up to its function/class boundary before signing.
85
+ * Returns null when no node contains the location.
86
+ */
87
+ export function signatureForLocation(ast, location, opts = {}) {
88
+ const located = findDeepestNodeAt(ast.root, location);
89
+ if (!located)
90
+ return null;
91
+ return structuralSignature(findSignatureRoot(located), opts);
92
+ }
93
+ //# sourceMappingURL=structuralSignature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structuralSignature.js","sourceRoot":"","sources":["../src/structuralSignature.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import type { Severity } from './types.js';
2
+ /**
3
+ * The version of the telemetry *schema* — the payload shape itself — independent
4
+ * of the tool version. This is the cross-repo contract with the feedback service
5
+ * (`../services/src/index.ts`): both sides pin the same value, and a bump on one
6
+ * side without the other is caught by each repo's pinned-shape test. The `v`
7
+ * field below is the tool version, which changes every release while the schema
8
+ * stays put — it is *not* a schema version and must not be used as one.
9
+ */
10
+ export declare const TELEMETRY_SCHEMA_VERSION = 2;
11
+ /** The exact, minimal set of fields sent. Adding a field here is a security review. */
12
+ export interface TelemetryPayload {
13
+ /** Payload schema version (the shape contract across repos), not the tool version. */
14
+ schema: number;
15
+ /** Anonymous install ID (random, generated locally) — groups submissions by source. */
16
+ install_id: string;
17
+ /** Tool version (package.json). */
18
+ v: string;
19
+ /** Canonical rule ID of the dismissed finding. */
20
+ rule: string;
21
+ /** Urgency level — critical | severe | high. */
22
+ level: Severity;
23
+ /** Dismissal reason, verbatim (the product — it is the human's words). */
24
+ reason: string;
25
+ /** Structural AST signature (grammar kinds only; no identifiers/literals). */
26
+ signature: string;
27
+ /** Coarse language/framework hint (e.g. `typescript`, `react`, `go`). */
28
+ lang: string;
29
+ /** ISO-8601 timestamp of the send. */
30
+ ts: string;
31
+ }
32
+ /** Coarse language/framework hint from a file path — never a path, just a class. */
33
+ export declare function languageHint(filePath: string): string;
34
+ export interface TelemetryPayloadInput {
35
+ install_id: string;
36
+ toolVersion: string;
37
+ rule: string;
38
+ level: Severity;
39
+ reason: string;
40
+ signature: string;
41
+ lang: string;
42
+ }
43
+ /** Assemble the payload. Timestamp is stamped at build time. */
44
+ export declare function buildTelemetryPayload(input: TelemetryPayloadInput): TelemetryPayload;
45
+ /** Human-readable preview, printed before any send so the user can review it. */
46
+ export declare function formatTelemetryPreview(payload: TelemetryPayload): string;
47
+ export interface TelemetryConfig {
48
+ enabled: boolean;
49
+ /** Endpoint URL. Empty/absent → telemetry is a no-op (nothing to send to). */
50
+ endpoint: string;
51
+ }
52
+ /**
53
+ * Resolve opt-in from the user-level config (see `installConfig.ts`): OFF unless
54
+ * the user explicitly enabled it via the `telemetry` MCP tool. `opts.endpoint` is
55
+ * a caller override (e.g. the local-dev `--telemetry-endpoint` flag).
56
+ */
57
+ export declare function resolveTelemetryConfig(opts?: {
58
+ endpoint?: string;
59
+ dir?: string;
60
+ }): TelemetryConfig;
61
+ export interface TelemetrySendResult {
62
+ sent: boolean;
63
+ error?: string;
64
+ }
65
+ /**
66
+ * Send a payload to the feedback service. Best-effort: a missing endpoint, a
67
+ * network failure, a timeout, or a non-2xx response all resolve to
68
+ * `{ sent: false }` and never throw — telemetry can never block or fail a gate.
69
+ */
70
+ export declare function sendTelemetry(payload: TelemetryPayload, endpoint: string, opts?: {
71
+ timeoutMs?: number;
72
+ }): Promise<TelemetrySendResult>;
73
+ /**
74
+ * Compute the structural signature for a finding at a file location. Reads the
75
+ * file, parses it, and signs the shape at that location. Returns null when the
76
+ * file can't be read/parsed or no node contains the location. Requires
77
+ * `initParsers()` to have been called by the caller.
78
+ */
79
+ export declare function signatureForFinding(filePath: string, line: number, column: number): string | null;
80
+ //# sourceMappingURL=telemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,uFAAuF;AACvF,MAAM,WAAW,gBAAgB;IAC/B,sFAAsF;IACtF,MAAM,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,CAAC,EAAE,MAAM,CAAC;IACV,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,KAAK,EAAE,QAAQ,CAAC;IAChB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,EAAE,EAAE,MAAM,CAAC;CACZ;AAID,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgBrD;AAID,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,gEAAgE;AAChE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,gBAAgB,CAYpF;AAED,iFAAiF;AACjF,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAexE;AAID,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7C,eAAe,CAMjB;AAID,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAChC,OAAO,CAAC,mBAAmB,CAAC,CAuB9B;AAID;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CAYf"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Spec 57 — opt-in dismissals telemetry.
3
+ *
4
+ * When the user dismisses a finding and has opted in, a small anonymized payload
5
+ * is sent to the feedback service. The payload is *shape + decision*, never
6
+ * code. The only code-derived field is the structural signature (`structuralSignature`),
7
+ * which is built from grammar kinds alone — identifiers, string literals, table
8
+ * names, paths, and source text are structurally impossible to include.
9
+ *
10
+ * The rules that make this safe and invisible to the gate:
11
+ *
12
+ * - **opt-in** — nothing is sent unless the user opts in via the `telemetry` MCP
13
+ * tool, and the payload is *printed before sending* so the user can review it.
14
+ * - **offline never blocks** — `sendTelemetry` is best-effort: any network error
15
+ * resolves to `{ sent: false }`, never throws, never affects the exit code.
16
+ * - **no content** — the payload type has no field for a path, identifier,
17
+ * literal, or source snippet, so none can leak by accident (acceptance 4).
18
+ */
19
+ import { readFileSync, existsSync } from 'node:fs';
20
+ import path from 'node:path';
21
+ import { parseFile } from './languages/adapterBridge.js';
22
+ import { signatureForLocation } from './structuralSignature.js';
23
+ import { getTelemetryOptIn } from './installConfig.js';
24
+ // ── Payload ──────────────────────────────────────────────────────────────────
25
+ /**
26
+ * The version of the telemetry *schema* — the payload shape itself — independent
27
+ * of the tool version. This is the cross-repo contract with the feedback service
28
+ * (`../services/src/index.ts`): both sides pin the same value, and a bump on one
29
+ * side without the other is caught by each repo's pinned-shape test. The `v`
30
+ * field below is the tool version, which changes every release while the schema
31
+ * stays put — it is *not* a schema version and must not be used as one.
32
+ */
33
+ export const TELEMETRY_SCHEMA_VERSION = 2;
34
+ // ── Language hint ────────────────────────────────────────────────────────────
35
+ /** Coarse language/framework hint from a file path — never a path, just a class. */
36
+ export function languageHint(filePath) {
37
+ const ext = path.extname(filePath).toLowerCase();
38
+ switch (ext) {
39
+ case '.tsx':
40
+ return 'typescript-react';
41
+ case '.jsx':
42
+ return 'javascript-react';
43
+ case '.ts':
44
+ return 'typescript';
45
+ case '.js':
46
+ return 'javascript';
47
+ case '.go':
48
+ return 'go';
49
+ default:
50
+ return 'other';
51
+ }
52
+ }
53
+ /** Assemble the payload. Timestamp is stamped at build time. */
54
+ export function buildTelemetryPayload(input) {
55
+ return {
56
+ schema: TELEMETRY_SCHEMA_VERSION,
57
+ install_id: input.install_id,
58
+ v: input.toolVersion,
59
+ rule: input.rule,
60
+ level: input.level,
61
+ reason: input.reason,
62
+ signature: input.signature,
63
+ lang: input.lang,
64
+ ts: new Date().toISOString(),
65
+ };
66
+ }
67
+ /** Human-readable preview, printed before any send so the user can review it. */
68
+ export function formatTelemetryPreview(payload) {
69
+ return [
70
+ '',
71
+ '── Telemetry payload (preview — review before sending) ──',
72
+ ` schema: ${payload.schema}`,
73
+ ` install ID: ${payload.install_id}`,
74
+ ` tool version: ${payload.v}`,
75
+ ` rule: ${payload.rule}`,
76
+ ` urgency: ${payload.level}`,
77
+ ` reason: ${payload.reason}`,
78
+ ` signature: ${payload.signature}`,
79
+ ` language: ${payload.lang}`,
80
+ ' (no file paths, identifiers, literals, or source text are included)',
81
+ '',
82
+ ].join('\n');
83
+ }
84
+ /**
85
+ * Resolve opt-in from the user-level config (see `installConfig.ts`): OFF unless
86
+ * the user explicitly enabled it via the `telemetry` MCP tool. `opts.endpoint` is
87
+ * a caller override (e.g. the local-dev `--telemetry-endpoint` flag).
88
+ */
89
+ export function resolveTelemetryConfig(opts = {}) {
90
+ const optIn = getTelemetryOptIn(opts.dir);
91
+ return {
92
+ enabled: optIn.enabled,
93
+ endpoint: opts.endpoint ?? optIn.endpoint,
94
+ };
95
+ }
96
+ /**
97
+ * Send a payload to the feedback service. Best-effort: a missing endpoint, a
98
+ * network failure, a timeout, or a non-2xx response all resolve to
99
+ * `{ sent: false }` and never throw — telemetry can never block or fail a gate.
100
+ */
101
+ export async function sendTelemetry(payload, endpoint, opts = {}) {
102
+ if (!endpoint)
103
+ return { sent: false };
104
+ const timeoutMs = opts.timeoutMs ?? 2000;
105
+ const controller = new AbortController();
106
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
107
+ try {
108
+ const response = await fetch(endpoint, {
109
+ method: 'POST',
110
+ headers: { 'content-type': 'application/json' },
111
+ body: JSON.stringify(payload),
112
+ signal: controller.signal,
113
+ });
114
+ clearTimeout(timer);
115
+ if (!response.ok) {
116
+ return { sent: false, error: `HTTP ${response.status}` };
117
+ }
118
+ return { sent: true };
119
+ }
120
+ catch (error) {
121
+ clearTimeout(timer);
122
+ return { sent: false, error: error instanceof Error ? error.message : String(error) };
123
+ }
124
+ }
125
+ // ── Signature from a finding ─────────────────────────────────────────────────
126
+ /**
127
+ * Compute the structural signature for a finding at a file location. Reads the
128
+ * file, parses it, and signs the shape at that location. Returns null when the
129
+ * file can't be read/parsed or no node contains the location. Requires
130
+ * `initParsers()` to have been called by the caller.
131
+ */
132
+ export function signatureForFinding(filePath, line, column) {
133
+ try {
134
+ if (!existsSync(filePath))
135
+ return null;
136
+ const content = readFileSync(filePath, 'utf-8');
137
+ const ast = parseFile(filePath, content);
138
+ if (!ast)
139
+ return null;
140
+ const signature = signatureForLocation(ast, { line, column });
141
+ ast.dispose?.();
142
+ return signature;
143
+ }
144
+ catch {
145
+ return null;
146
+ }
147
+ }
148
+ //# sourceMappingURL=telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -114,6 +114,13 @@ export interface Violation {
114
114
  * `severityCap` soften-in-place mechanism.
115
115
  */
116
116
  gateExcluded?: boolean;
117
+ /**
118
+ * Spec 57 — true when a committed dismissal matches this finding's
119
+ * fingerprint. A dismissed finding never blocks the gate, but it is still
120
+ * counted in `summary.totalViolations` — dismissal never silently reduces the
121
+ * total; the reduced count is reported separately as `summary.dismissed`.
122
+ */
123
+ dismissed?: boolean;
117
124
  violationType?: string;
118
125
  symbol?: string;
119
126
  principle?: string;
@@ -148,6 +155,28 @@ export interface Violation {
148
155
  */
149
156
  resolution?: Resolution;
150
157
  }
158
+ /**
159
+ * A coverage diagnostic — a per-occurrence record that the analyzer could not
160
+ * *see* a region of the code, as distinct from a {@link Violation}, which says
161
+ * the code is wrong. Diagnostics are never blocking: the gate only ever reads
162
+ * violations. They are surfaced (counted, with file + line) in the report's
163
+ * coverage section and in the `metadata.diagnostics` channel alongside
164
+ * `zero-files` / `no-result` ("the tool couldn't do its job").
165
+ */
166
+ export interface CoverageDiagnostic {
167
+ /** Owning analyzer (e.g. `schema`, `dependency-graph`). */
168
+ analyzerName: string;
169
+ /** The diagnostic kind — currently `unresolved-query` or `unresolved-dynamic-import`. */
170
+ kind: 'unresolved-query' | 'unresolved-dynamic-import';
171
+ /** Human-readable explanation of what could not be resolved. */
172
+ message: string;
173
+ /** File the unresolved construct is in. */
174
+ file: string;
175
+ /** 1-based line of the unresolved construct. */
176
+ line: number;
177
+ /** Kind-specific detail (e.g. `{ identifier }` or `{ expression }`). */
178
+ details?: Record<string, unknown>;
179
+ }
151
180
  /**
152
181
  * Per-rule coverage classification — emitted on every audit.
153
182
  * @see buildCoverageReport() in pipeline.ts
@@ -209,6 +238,8 @@ export interface AnalyzerResult {
209
238
  file: string;
210
239
  error: string;
211
240
  }>;
241
+ /** Per-occurrence coverage diagnostics (non-blocking). */
242
+ diagnostics?: CoverageDiagnostic[];
212
243
  /** Number of files processed by the analyzer. */
213
244
  filesProcessed?: number;
214
245
  /** Arbitrary metrics bag — used by cross-domain, visualizations, etc. */
@@ -266,6 +297,9 @@ export interface VisitorResult {
266
297
  violations: Violation[];
267
298
  facts: Record<string, unknown>;
268
299
  indexFacts?: IndexFactsEntry[];
300
+ /** Per-occurrence coverage diagnostics (non-blocking). Collected into
301
+ * `metadata.diagnostics` by the pipeline. */
302
+ diagnostics?: CoverageDiagnostic[];
269
303
  }
270
304
  /** Return type from stage-3/4 reducer reduce(). */
271
305
  export interface ReducerResult {
@@ -283,6 +317,9 @@ export interface ReducerResult {
283
317
  * `context.readSource` do not need to report here.
284
318
  */
285
319
  consumedFiles?: string[];
320
+ /** Per-occurrence coverage diagnostics (non-blocking). Collected into
321
+ * `metadata.diagnostics` by the pipeline. */
322
+ diagnostics?: CoverageDiagnostic[];
286
323
  }
287
324
  /** Per-file visitor — runs on every AST in stage 2. */
288
325
  export interface Stage2Visitor {
@@ -470,6 +507,9 @@ export interface PipelineResult {
470
507
  analyzerName: string;
471
508
  kind: string;
472
509
  message: string;
510
+ file?: string;
511
+ line?: number;
512
+ details?: Record<string, unknown>;
473
513
  }>;
474
514
  coverage?: RuleCoverage[];
475
515
  /** Spec 29: Per-table provenance catalog from schema reducer */
@@ -576,6 +616,12 @@ export interface AuditSummary {
576
616
  type: string;
577
617
  count: number;
578
618
  }>;
619
+ /**
620
+ * Spec 57 — number of findings cleared by a committed dismissal. Reported
621
+ * alongside `totalViolations` ("43 findings, 3 dismissed"), never subtracted
622
+ * from it. Absent/0 when no dismissals apply.
623
+ */
624
+ dismissed?: number;
579
625
  }
580
626
  export interface AuditResult {
581
627
  timestamp: Date;
@@ -597,11 +643,15 @@ export interface AuditResult {
597
643
  provenanceResolutionMs?: number;
598
644
  /** Blast radius impact for changed functions (Spec 14 R6 — scoped audits only). */
599
645
  blastRadius?: BlastRadiusImpact;
600
- /** Zero-files or missing-result diagnostics (v3.4.8 — verify:dist gate hardening). */
646
+ /** Zero-files / missing-result diagnostics plus per-occurrence coverage
647
+ * diagnostics (unresolved SQL/specifier). Non-blocking — see CoverageDiagnostic. */
601
648
  diagnostics?: Array<{
602
649
  analyzerName: string;
603
650
  kind: string;
604
651
  message: string;
652
+ file?: string;
653
+ line?: number;
654
+ details?: Record<string, unknown>;
605
655
  }>;
606
656
  baseline?: {
607
657
  present: boolean;
@@ -647,6 +697,9 @@ export interface AuditResult {
647
697
  inputPresence?: InputPresence;
648
698
  /** Spec 44: per-file accounting (analyzed vs. dropped, with reasons). */
649
699
  fileAccounting?: FileAccountingSummary;
700
+ /** Spec 50 R2 — which config layer supplied each size threshold (default,
701
+ * project-config, project-lint-config, preset:<id>). */
702
+ thresholdSources?: ThresholdSource[];
650
703
  };
651
704
  }
652
705
  /** Thrown when an in-process audit is stopped via AbortSignal (parent cancel or soft budget). */
@@ -832,6 +885,24 @@ export interface AuditMetadata {
832
885
  defaultValue: unknown;
833
886
  effectiveValue: unknown;
834
887
  }>;
888
+ /** Spec 50 R2 — which config layer supplied each size threshold. */
889
+ thresholdSources?: ThresholdSource[];
890
+ }
891
+ /**
892
+ * Spec 50 R2 — a size threshold and the config layer that supplied its value.
893
+ * Surfaces in audit metadata and `print-config` so a threshold that came from
894
+ * the project's ESLint config (vs. a default or an explicit .codeauditor.json)
895
+ * is named, not archaeology.
896
+ */
897
+ export interface ThresholdSource {
898
+ /** Dot-notation key within the analyzer namespace, e.g. `solid.maxLinesPerMethod`. */
899
+ key: string;
900
+ /** The effective value the run used. */
901
+ value: unknown;
902
+ /** Where the value came from: `default`, `project-config`, `project-lint-config`, `preset:<id>`, `path-profile:<name>`. */
903
+ source: string;
904
+ /** The analyzer's runtime default (for the `[differs from default]` display). */
905
+ defaultValue: unknown;
835
906
  }
836
907
  export interface BaseAnalyzerOptions {
837
908
  verbose?: boolean;