@kernlang/review 3.3.4 → 3.3.6
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/cache.js +1 -1
- package/dist/concept-rules/auth-drift.d.ts +29 -0
- package/dist/concept-rules/auth-drift.js +127 -0
- package/dist/concept-rules/auth-drift.js.map +1 -0
- package/dist/concept-rules/contract-drift.d.ts +21 -0
- package/dist/concept-rules/contract-drift.js +65 -0
- package/dist/concept-rules/contract-drift.js.map +1 -0
- package/dist/concept-rules/contract-method-drift.d.ts +22 -0
- package/dist/concept-rules/contract-method-drift.js +105 -0
- package/dist/concept-rules/contract-method-drift.js.map +1 -0
- package/dist/concept-rules/cross-stack-utils.d.ts +96 -0
- package/dist/concept-rules/cross-stack-utils.js +259 -0
- package/dist/concept-rules/cross-stack-utils.js.map +1 -0
- package/dist/concept-rules/duplicate-route.d.ts +20 -0
- package/dist/concept-rules/duplicate-route.js +112 -0
- package/dist/concept-rules/duplicate-route.js.map +1 -0
- package/dist/concept-rules/index.js +26 -1
- package/dist/concept-rules/index.js.map +1 -1
- package/dist/concept-rules/missing-response-model.d.ts +10 -0
- package/dist/concept-rules/missing-response-model.js +38 -0
- package/dist/concept-rules/missing-response-model.js.map +1 -0
- package/dist/concept-rules/orphan-route.d.ts +20 -0
- package/dist/concept-rules/orphan-route.js +96 -0
- package/dist/concept-rules/orphan-route.js.map +1 -0
- package/dist/concept-rules/sync-handler-does-io.d.ts +9 -0
- package/dist/concept-rules/sync-handler-does-io.js +56 -0
- package/dist/concept-rules/sync-handler-does-io.js.map +1 -0
- package/dist/concept-rules/tainted-across-wire.d.ts +33 -0
- package/dist/concept-rules/tainted-across-wire.js +95 -0
- package/dist/concept-rules/tainted-across-wire.js.map +1 -0
- package/dist/concept-rules/untyped-api-response.d.ts +30 -0
- package/dist/concept-rules/untyped-api-response.js +73 -0
- package/dist/concept-rules/untyped-api-response.js.map +1 -0
- package/dist/concept-rules/untyped-both-ends-response.d.ts +10 -0
- package/dist/concept-rules/untyped-both-ends-response.js +55 -0
- package/dist/concept-rules/untyped-both-ends-response.js.map +1 -0
- package/dist/external-tools.d.ts +17 -4
- package/dist/external-tools.js +12 -1
- package/dist/external-tools.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +115 -9
- package/dist/index.js.map +1 -1
- package/dist/llm-bridge.d.ts +38 -1
- package/dist/llm-bridge.js +172 -12
- package/dist/llm-bridge.js.map +1 -1
- package/dist/llm-review.js +29 -11
- package/dist/llm-review.js.map +1 -1
- package/dist/mappers/ts-concepts.js +650 -11
- package/dist/mappers/ts-concepts.js.map +1 -1
- package/dist/rules/index.js +17 -1
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/kern-source.js +37 -5
- package/dist/rules/kern-source.js.map +1 -1
- package/dist/rules/set-setter-collision.d.ts +21 -0
- package/dist/rules/set-setter-collision.js +74 -0
- package/dist/rules/set-setter-collision.js.map +1 -0
- package/dist/rules/suggest-kern-primitive.d.ts +30 -0
- package/dist/rules/suggest-kern-primitive.js +543 -0
- package/dist/rules/suggest-kern-primitive.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: sync-handler-does-io
|
|
3
|
+
*
|
|
4
|
+
* Fires when a route handler is explicitly synchronous and performs
|
|
5
|
+
* network/db/fs I/O in the same function container.
|
|
6
|
+
*/
|
|
7
|
+
import { createFingerprint } from '../types.js';
|
|
8
|
+
const BLOCKING_IO_SUBTYPES = new Set(['network', 'db', 'fs']);
|
|
9
|
+
export function syncHandlerDoesIo(ctx) {
|
|
10
|
+
const effectsByContainer = new Map();
|
|
11
|
+
for (const node of ctx.concepts.nodes) {
|
|
12
|
+
if (node.kind !== 'effect')
|
|
13
|
+
continue;
|
|
14
|
+
if (node.payload.kind !== 'effect')
|
|
15
|
+
continue;
|
|
16
|
+
if (!BLOCKING_IO_SUBTYPES.has(node.payload.subtype))
|
|
17
|
+
continue;
|
|
18
|
+
if (!node.containerId)
|
|
19
|
+
continue;
|
|
20
|
+
const existing = effectsByContainer.get(node.containerId) ?? [];
|
|
21
|
+
existing.push(node);
|
|
22
|
+
effectsByContainer.set(node.containerId, existing);
|
|
23
|
+
}
|
|
24
|
+
const findings = [];
|
|
25
|
+
for (const node of ctx.concepts.nodes) {
|
|
26
|
+
if (node.kind !== 'entrypoint')
|
|
27
|
+
continue;
|
|
28
|
+
if (node.payload.kind !== 'entrypoint')
|
|
29
|
+
continue;
|
|
30
|
+
if (node.payload.subtype !== 'route')
|
|
31
|
+
continue;
|
|
32
|
+
if (node.payload.isAsync !== false)
|
|
33
|
+
continue;
|
|
34
|
+
if (!node.containerId)
|
|
35
|
+
continue;
|
|
36
|
+
const effects = effectsByContainer.get(node.containerId);
|
|
37
|
+
if (!effects || effects.length === 0)
|
|
38
|
+
continue;
|
|
39
|
+
const firstEffect = effects[0];
|
|
40
|
+
if (firstEffect.payload.kind !== 'effect')
|
|
41
|
+
continue;
|
|
42
|
+
findings.push({
|
|
43
|
+
source: 'kern',
|
|
44
|
+
ruleId: 'sync-handler-does-io',
|
|
45
|
+
severity: 'warning',
|
|
46
|
+
category: 'bug',
|
|
47
|
+
message: `Sync route handler \`${node.payload.name}\` performs ${firstEffect.payload.subtype} I/O. Make the handler async and use non-blocking I/O, or move the blocking work out of the request path.`,
|
|
48
|
+
primarySpan: node.primarySpan,
|
|
49
|
+
relatedSpans: effects.map((effect) => effect.primarySpan),
|
|
50
|
+
fingerprint: createFingerprint('sync-handler-does-io', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
51
|
+
confidence: 0.9,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return findings;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=sync-handler-does-io.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-handler-does-io.js","sourceRoot":"","sources":["../../src/concept-rules/sync-handler-does-io.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAE9D,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACvD,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAyB,CAAC;IAE5D,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QACrC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QAC7C,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;YAAE,SAAS;QAC9D,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,SAAS;QAEhC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QAChE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY;YAAE,SAAS;QACzC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY;YAAE,SAAS;QACjD,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,OAAO;YAAE,SAAS;QAC/C,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,KAAK;YAAE,SAAS;QAC7C,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,SAAS;QAEhC,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QAEpD,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,sBAAsB;YAC9B,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,wBAAwB,IAAI,CAAC,OAAO,CAAC,IAAI,eAAe,WAAW,CAAC,OAAO,CAAC,OAAO,2GAA2G;YACvM,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC;YACzD,WAAW,EAAE,iBAAiB,CAAC,sBAAsB,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;YAC7G,UAAU,EAAE,GAAG;SAChB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: tainted-across-wire
|
|
3
|
+
*
|
|
4
|
+
* Cross-stack rule — fires when a frontend (TS) network call sends a
|
|
5
|
+
* dynamic (user-controlled) body to a server-side route in the reviewed
|
|
6
|
+
* project AND that route's handler has no validation guard in scope.
|
|
7
|
+
*
|
|
8
|
+
* This is rule #3 of the fullstack wedge. Pure server-side taint analysis
|
|
9
|
+
* (already in @kernlang/review's taint-crossfile module) finds sinks
|
|
10
|
+
* reachable from `req.body`, but it can't see the *client-side call site*
|
|
11
|
+
* that's feeding the unvalidated input. And pure client-side analysis
|
|
12
|
+
* doesn't know whether the server validates — so it either fires on every
|
|
13
|
+
* dynamic POST (noise) or on none (misses the moat).
|
|
14
|
+
*
|
|
15
|
+
* By correlating both sides via the concept graph we can fire precisely:
|
|
16
|
+
* "here's the fetch that sends user input to an endpoint whose handler
|
|
17
|
+
* doesn't parse it with zod/yup/joi/pydantic". The finding lands on the
|
|
18
|
+
* client-side call so the fix is visible where the developer is working.
|
|
19
|
+
*
|
|
20
|
+
* Preconditions to fire:
|
|
21
|
+
* 1. Graph mode (`ctx.allConcepts` populated).
|
|
22
|
+
* 2. Client concept has `bodyKind === 'dynamic'` — we know real data is
|
|
23
|
+
* crossing the wire, not a ping/HEAD/etc.
|
|
24
|
+
* 3. Client target path matches a server route in the graph.
|
|
25
|
+
* 4. That server route's container has NO `guard` concept with
|
|
26
|
+
* `subtype === 'validation'` (schema.parse / zod.parse / …).
|
|
27
|
+
*
|
|
28
|
+
* Silent on `bodyKind === undefined` (mapper couldn't classify) and on
|
|
29
|
+
* missing server matches (contract-drift owns that class).
|
|
30
|
+
*/
|
|
31
|
+
import type { ReviewFinding } from '../types.js';
|
|
32
|
+
import type { ConceptRuleContext } from './index.js';
|
|
33
|
+
export declare function taintedAcrossWire(ctx: ConceptRuleContext): ReviewFinding[];
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: tainted-across-wire
|
|
3
|
+
*
|
|
4
|
+
* Cross-stack rule — fires when a frontend (TS) network call sends a
|
|
5
|
+
* dynamic (user-controlled) body to a server-side route in the reviewed
|
|
6
|
+
* project AND that route's handler has no validation guard in scope.
|
|
7
|
+
*
|
|
8
|
+
* This is rule #3 of the fullstack wedge. Pure server-side taint analysis
|
|
9
|
+
* (already in @kernlang/review's taint-crossfile module) finds sinks
|
|
10
|
+
* reachable from `req.body`, but it can't see the *client-side call site*
|
|
11
|
+
* that's feeding the unvalidated input. And pure client-side analysis
|
|
12
|
+
* doesn't know whether the server validates — so it either fires on every
|
|
13
|
+
* dynamic POST (noise) or on none (misses the moat).
|
|
14
|
+
*
|
|
15
|
+
* By correlating both sides via the concept graph we can fire precisely:
|
|
16
|
+
* "here's the fetch that sends user input to an endpoint whose handler
|
|
17
|
+
* doesn't parse it with zod/yup/joi/pydantic". The finding lands on the
|
|
18
|
+
* client-side call so the fix is visible where the developer is working.
|
|
19
|
+
*
|
|
20
|
+
* Preconditions to fire:
|
|
21
|
+
* 1. Graph mode (`ctx.allConcepts` populated).
|
|
22
|
+
* 2. Client concept has `bodyKind === 'dynamic'` — we know real data is
|
|
23
|
+
* crossing the wire, not a ping/HEAD/etc.
|
|
24
|
+
* 3. Client target path matches a server route in the graph.
|
|
25
|
+
* 4. That server route's container has NO `guard` concept with
|
|
26
|
+
* `subtype === 'validation'` (schema.parse / zod.parse / …).
|
|
27
|
+
*
|
|
28
|
+
* Silent on `bodyKind === undefined` (mapper couldn't classify) and on
|
|
29
|
+
* missing server matches (contract-drift owns that class).
|
|
30
|
+
*/
|
|
31
|
+
import { createFingerprint } from '../types.js';
|
|
32
|
+
import { API_PATH_RE, CROSS_STACK_HEURISTIC_CONFIDENCE, collectRoutesAcrossGraph, findMatchingRoute, normalizeClientUrl, } from './cross-stack-utils.js';
|
|
33
|
+
export function taintedAcrossWire(ctx) {
|
|
34
|
+
if (!ctx.allConcepts || ctx.allConcepts.size === 0)
|
|
35
|
+
return [];
|
|
36
|
+
const serverRoutes = collectRoutesAcrossGraph(ctx.allConcepts);
|
|
37
|
+
if (serverRoutes.length === 0)
|
|
38
|
+
return [];
|
|
39
|
+
// Build the set of files that contain at least one validation guard.
|
|
40
|
+
// Container-level matching is too strict: zod/yup parsers typically live
|
|
41
|
+
// inside the route callback body (arrow function container) while the
|
|
42
|
+
// route entrypoint itself is emitted at the call-expression level (module
|
|
43
|
+
// container). File-level matching is coarser but safer — it silences the
|
|
44
|
+
// common case where a validator exists in the same server file as the
|
|
45
|
+
// route, which is a strong signal the handler is guarded. False negatives
|
|
46
|
+
// (a validation-less route in a file that validates *other* routes) cost
|
|
47
|
+
// us less than false positives on the pitch.
|
|
48
|
+
const validatedFiles = collectValidatedFiles(ctx.allConcepts);
|
|
49
|
+
const findings = [];
|
|
50
|
+
const localConcepts = ctx.allConcepts.get(ctx.filePath) ?? ctx.concepts;
|
|
51
|
+
for (const node of localConcepts.nodes) {
|
|
52
|
+
if (node.kind !== 'effect' || node.payload.kind !== 'effect' || node.payload.subtype !== 'network')
|
|
53
|
+
continue;
|
|
54
|
+
if (node.payload.bodyKind !== 'dynamic')
|
|
55
|
+
continue;
|
|
56
|
+
const target = node.payload.target;
|
|
57
|
+
if (typeof target !== 'string')
|
|
58
|
+
continue;
|
|
59
|
+
const normalized = normalizeClientUrl(target);
|
|
60
|
+
if (!normalized || !API_PATH_RE.test(normalized))
|
|
61
|
+
continue;
|
|
62
|
+
const matchedRoute = findMatchingRoute(normalized, serverRoutes);
|
|
63
|
+
if (!matchedRoute)
|
|
64
|
+
continue; // contract-drift owns the "wrong URL" class.
|
|
65
|
+
const routeFile = matchedRoute.node?.primarySpan.file;
|
|
66
|
+
if (routeFile && validatedFiles.has(routeFile))
|
|
67
|
+
continue;
|
|
68
|
+
findings.push({
|
|
69
|
+
source: 'kern',
|
|
70
|
+
ruleId: 'tainted-across-wire',
|
|
71
|
+
severity: 'warning',
|
|
72
|
+
category: 'pattern',
|
|
73
|
+
message: `Dynamic body sent to \`${target}\` but the matching server route has no validation guard (schema.parse / zod / yup / pydantic). Add a validator on the server before trusting the payload, or move validation to the client if this endpoint is internal-only.`,
|
|
74
|
+
primarySpan: node.primarySpan,
|
|
75
|
+
fingerprint: createFingerprint('tainted-across-wire', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
76
|
+
confidence: node.confidence * CROSS_STACK_HEURISTIC_CONFIDENCE,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return findings;
|
|
80
|
+
}
|
|
81
|
+
function collectValidatedFiles(allConcepts) {
|
|
82
|
+
const set = new Set();
|
|
83
|
+
for (const [file, conceptMap] of allConcepts) {
|
|
84
|
+
for (const node of conceptMap.nodes) {
|
|
85
|
+
if (node.kind !== 'guard' || node.payload.kind !== 'guard')
|
|
86
|
+
continue;
|
|
87
|
+
if (node.payload.subtype !== 'validation')
|
|
88
|
+
continue;
|
|
89
|
+
set.add(file);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return set;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=tainted-across-wire.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tainted-across-wire.js","sourceRoot":"","sources":["../../src/concept-rules/tainted-across-wire.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: untyped-api-response
|
|
3
|
+
*
|
|
4
|
+
* Cross-stack rule — fires when a frontend (TS) network call targets a
|
|
5
|
+
* server-side route in the reviewed project AND consumes the JSON body
|
|
6
|
+
* without a type annotation, `as T` cast, or `satisfies T` clause.
|
|
7
|
+
*
|
|
8
|
+
* This is rule #2 of the fullstack wedge (TS ↔ Python/Express). The server
|
|
9
|
+
* has a declared response shape (Pydantic `response_model=`, Express
|
|
10
|
+
* `Response<T>`, …) but the client is treating the payload as `any`, which
|
|
11
|
+
* means any breaking change in the response shape will silently rot the
|
|
12
|
+
* frontend at runtime. ESLint can catch "no-explicit-any" at the TS level
|
|
13
|
+
* but it can't tell you *which* fetch() is actually talking to a project
|
|
14
|
+
* endpoint — only the concept graph knows that.
|
|
15
|
+
*
|
|
16
|
+
* Preconditions to fire:
|
|
17
|
+
* 1. Graph mode (`ctx.allConcepts` populated).
|
|
18
|
+
* 2. Client concept has `responseAsserted === false` (mapper proved the
|
|
19
|
+
* .json() consumption is untyped).
|
|
20
|
+
* 3. The call's target path matches a server-side route in the graph —
|
|
21
|
+
* otherwise this is just a generic untyped-fetch case, which Biome
|
|
22
|
+
* already covers and we don't want to duplicate.
|
|
23
|
+
*
|
|
24
|
+
* Kept conservative: when the mapper returns `undefined` for
|
|
25
|
+
* responseAsserted (patterns it couldn't analyze) the rule stays silent.
|
|
26
|
+
* False positives here would poison the pitch.
|
|
27
|
+
*/
|
|
28
|
+
import type { ReviewFinding } from '../types.js';
|
|
29
|
+
import type { ConceptRuleContext } from './index.js';
|
|
30
|
+
export declare function untypedApiResponse(ctx: ConceptRuleContext): ReviewFinding[];
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: untyped-api-response
|
|
3
|
+
*
|
|
4
|
+
* Cross-stack rule — fires when a frontend (TS) network call targets a
|
|
5
|
+
* server-side route in the reviewed project AND consumes the JSON body
|
|
6
|
+
* without a type annotation, `as T` cast, or `satisfies T` clause.
|
|
7
|
+
*
|
|
8
|
+
* This is rule #2 of the fullstack wedge (TS ↔ Python/Express). The server
|
|
9
|
+
* has a declared response shape (Pydantic `response_model=`, Express
|
|
10
|
+
* `Response<T>`, …) but the client is treating the payload as `any`, which
|
|
11
|
+
* means any breaking change in the response shape will silently rot the
|
|
12
|
+
* frontend at runtime. ESLint can catch "no-explicit-any" at the TS level
|
|
13
|
+
* but it can't tell you *which* fetch() is actually talking to a project
|
|
14
|
+
* endpoint — only the concept graph knows that.
|
|
15
|
+
*
|
|
16
|
+
* Preconditions to fire:
|
|
17
|
+
* 1. Graph mode (`ctx.allConcepts` populated).
|
|
18
|
+
* 2. Client concept has `responseAsserted === false` (mapper proved the
|
|
19
|
+
* .json() consumption is untyped).
|
|
20
|
+
* 3. The call's target path matches a server-side route in the graph —
|
|
21
|
+
* otherwise this is just a generic untyped-fetch case, which Biome
|
|
22
|
+
* already covers and we don't want to duplicate.
|
|
23
|
+
*
|
|
24
|
+
* Kept conservative: when the mapper returns `undefined` for
|
|
25
|
+
* responseAsserted (patterns it couldn't analyze) the rule stays silent.
|
|
26
|
+
* False positives here would poison the pitch.
|
|
27
|
+
*/
|
|
28
|
+
import { createFingerprint } from '../types.js';
|
|
29
|
+
import { API_PATH_RE, CROSS_STACK_HEURISTIC_CONFIDENCE, collectRoutesAcrossGraph, findMatchingRoute, isFastApiRouteMissingResponseModel, normalizeClientUrl, } from './cross-stack-utils.js';
|
|
30
|
+
export function untypedApiResponse(ctx) {
|
|
31
|
+
if (!ctx.allConcepts || ctx.allConcepts.size === 0)
|
|
32
|
+
return [];
|
|
33
|
+
const serverRoutes = collectRoutesAcrossGraph(ctx.allConcepts);
|
|
34
|
+
if (serverRoutes.length === 0)
|
|
35
|
+
return [];
|
|
36
|
+
const findings = [];
|
|
37
|
+
// Only scan this file's concepts so we don't duplicate findings per call.
|
|
38
|
+
const localConcepts = ctx.allConcepts.get(ctx.filePath) ?? ctx.concepts;
|
|
39
|
+
for (const node of localConcepts.nodes) {
|
|
40
|
+
if (node.kind !== 'effect' || node.payload.kind !== 'effect' || node.payload.subtype !== 'network')
|
|
41
|
+
continue;
|
|
42
|
+
if (node.payload.responseAsserted !== false)
|
|
43
|
+
continue; // undefined stays silent
|
|
44
|
+
const target = node.payload.target;
|
|
45
|
+
if (typeof target !== 'string')
|
|
46
|
+
continue;
|
|
47
|
+
const normalized = normalizeClientUrl(target);
|
|
48
|
+
if (!normalized || !API_PATH_RE.test(normalized))
|
|
49
|
+
continue;
|
|
50
|
+
const matchedRoute = findMatchingRoute(normalized, serverRoutes);
|
|
51
|
+
if (!matchedRoute)
|
|
52
|
+
continue;
|
|
53
|
+
if (matchedRoute.node &&
|
|
54
|
+
isFastApiRouteMissingResponseModel(matchedRoute.node, ctx.allConcepts.get(matchedRoute.node.primarySpan.file))) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
findings.push({
|
|
58
|
+
source: 'kern',
|
|
59
|
+
ruleId: 'untyped-api-response',
|
|
60
|
+
severity: 'warning',
|
|
61
|
+
category: 'bug',
|
|
62
|
+
message: `Response from \`${target}\` is consumed without a type annotation. The server route defines a response shape — assign the awaited value to a typed variable or use \`as T\` / \`satisfies T\` so response-shape drift is caught at compile time instead of breaking at runtime.`,
|
|
63
|
+
primarySpan: node.primarySpan,
|
|
64
|
+
fingerprint: createFingerprint('untyped-api-response', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
65
|
+
// Same tier as contract-drift. Upgrade once the Python mapper surfaces
|
|
66
|
+
// `response_model=` and we can also cite the specific server type the
|
|
67
|
+
// frontend should be asserting against.
|
|
68
|
+
confidence: node.confidence * CROSS_STACK_HEURISTIC_CONFIDENCE,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return findings;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=untyped-api-response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"untyped-api-response.js","sourceRoot":"","sources":["../../src/concept-rules/untyped-api-response.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,WAAW,EACX,gCAAgC,EAChC,wBAAwB,EACxB,iBAAiB,EACjB,kCAAkC,EAClC,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAGhC,MAAM,UAAU,kBAAkB,CAAC,GAAuB;IACxD,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAE9D,MAAM,YAAY,GAAG,wBAAwB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC/D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEzC,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,0EAA0E;IAC1E,MAAM,aAAa,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC;IACxE,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,KAAK,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS;YAAE,SAAS;QAC7G,IAAI,IAAI,CAAC,OAAO,CAAC,gBAAgB,KAAK,KAAK;YAAE,SAAS,CAAC,yBAAyB;QAChF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;QACnC,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,SAAS;QACzC,MAAM,UAAU,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,CAAC,UAAU,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC;YAAE,SAAS;QAC3D,MAAM,YAAY,GAAG,iBAAiB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QACjE,IAAI,CAAC,YAAY;YAAE,SAAS;QAC5B,IACE,YAAY,CAAC,IAAI;YACjB,kCAAkC,CAAC,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,EAC9G,CAAC;YACD,SAAS;QACX,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,sBAAsB;YAC9B,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,mBAAmB,MAAM,wPAAwP;YAC1R,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,iBAAiB,CAAC,sBAAsB,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;YAC7G,uEAAuE;YACvE,sEAAsE;YACtE,wCAAwC;YACxC,UAAU,EAAE,IAAI,CAAC,UAAU,GAAG,gCAAgC;SAC/D,CAAC,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: untyped-both-ends-response
|
|
3
|
+
*
|
|
4
|
+
* Cross-stack linker for the response typing wedge. Fires when the client
|
|
5
|
+
* consumes a matching API response without a type assertion and the Python
|
|
6
|
+
* server route also has no `response_model=...`.
|
|
7
|
+
*/
|
|
8
|
+
import type { ReviewFinding } from '../types.js';
|
|
9
|
+
import type { ConceptRuleContext } from './index.js';
|
|
10
|
+
export declare function untypedBothEndsResponse(ctx: ConceptRuleContext): ReviewFinding[];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: untyped-both-ends-response
|
|
3
|
+
*
|
|
4
|
+
* Cross-stack linker for the response typing wedge. Fires when the client
|
|
5
|
+
* consumes a matching API response without a type assertion and the Python
|
|
6
|
+
* server route also has no `response_model=...`.
|
|
7
|
+
*/
|
|
8
|
+
import { createFingerprint } from '../types.js';
|
|
9
|
+
import { API_PATH_RE, CROSS_STACK_HEURISTIC_CONFIDENCE, collectRoutesAcrossGraph, findMatchingRoute, isFastApiRouteMissingResponseModel, normalizeClientUrl, } from './cross-stack-utils.js';
|
|
10
|
+
export function untypedBothEndsResponse(ctx) {
|
|
11
|
+
if (!ctx.allConcepts || ctx.allConcepts.size === 0)
|
|
12
|
+
return [];
|
|
13
|
+
const allConcepts = ctx.allConcepts;
|
|
14
|
+
const routesMissingModel = collectRoutesAcrossGraph(allConcepts).filter((route) => routeMissingResponseModel(route, allConcepts));
|
|
15
|
+
if (routesMissingModel.length === 0)
|
|
16
|
+
return [];
|
|
17
|
+
const findings = [];
|
|
18
|
+
const localConcepts = allConcepts.get(ctx.filePath) ?? ctx.concepts;
|
|
19
|
+
for (const node of localConcepts.nodes) {
|
|
20
|
+
if (node.language !== 'ts')
|
|
21
|
+
continue;
|
|
22
|
+
if (node.kind !== 'effect' || node.payload.kind !== 'effect' || node.payload.subtype !== 'network')
|
|
23
|
+
continue;
|
|
24
|
+
if (node.payload.responseAsserted !== false)
|
|
25
|
+
continue;
|
|
26
|
+
const target = node.payload.target;
|
|
27
|
+
if (typeof target !== 'string')
|
|
28
|
+
continue;
|
|
29
|
+
const normalized = normalizeClientUrl(target);
|
|
30
|
+
if (!normalized || !API_PATH_RE.test(normalized))
|
|
31
|
+
continue;
|
|
32
|
+
const matchedRoute = findMatchingRoute(normalized, routesMissingModel);
|
|
33
|
+
if (!matchedRoute?.node)
|
|
34
|
+
continue;
|
|
35
|
+
findings.push({
|
|
36
|
+
source: 'kern',
|
|
37
|
+
ruleId: 'untyped-both-ends-response',
|
|
38
|
+
severity: 'warning',
|
|
39
|
+
category: 'bug',
|
|
40
|
+
message: `Response for \`${target}\` is untyped on both ends: the client consumes it without a type assertion and the matching backend route has no response_model.`,
|
|
41
|
+
primarySpan: node.primarySpan,
|
|
42
|
+
relatedSpans: [matchedRoute.node.primarySpan],
|
|
43
|
+
fingerprint: createFingerprint('untyped-both-ends-response', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
44
|
+
confidence: Math.min(node.confidence, matchedRoute.node.confidence) * CROSS_STACK_HEURISTIC_CONFIDENCE,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return findings;
|
|
48
|
+
}
|
|
49
|
+
function routeMissingResponseModel(route, allConcepts) {
|
|
50
|
+
const node = route.node;
|
|
51
|
+
if (!node)
|
|
52
|
+
return false;
|
|
53
|
+
return isFastApiRouteMissingResponseModel(node, allConcepts.get(node.primarySpan.file));
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=untyped-both-ends-response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"untyped-both-ends-response.js","sourceRoot":"","sources":["../../src/concept-rules/untyped-both-ends-response.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,WAAW,EACX,gCAAgC,EAChC,wBAAwB,EACxB,iBAAiB,EACjB,kCAAkC,EAClC,kBAAkB,GAEnB,MAAM,wBAAwB,CAAC;AAGhC,MAAM,UAAU,uBAAuB,CAAC,GAAuB;IAC7D,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9D,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;IAEpC,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAChF,yBAAyB,CAAC,KAAK,EAAE,WAAW,CAAC,CAC9C,CAAC;IACF,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAE/C,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC;IAEpE,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,KAAK,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI;YAAE,SAAS;QACrC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS;YAAE,SAAS;QAC7G,IAAI,IAAI,CAAC,OAAO,CAAC,gBAAgB,KAAK,KAAK;YAAE,SAAS;QACtD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;QACnC,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,SAAS;QACzC,MAAM,UAAU,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,CAAC,UAAU,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC;YAAE,SAAS;QAC3D,MAAM,YAAY,GAAG,iBAAiB,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;QACvE,IAAI,CAAC,YAAY,EAAE,IAAI;YAAE,SAAS;QAElC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,4BAA4B;YACpC,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,kBAAkB,MAAM,mIAAmI;YACpK,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,YAAY,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC;YAC7C,WAAW,EAAE,iBAAiB,CAC5B,4BAA4B,EAC5B,IAAI,CAAC,WAAW,CAAC,SAAS,EAC1B,IAAI,CAAC,WAAW,CAAC,QAAQ,CAC1B;YACD,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,gCAAgC;SACvG,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,yBAAyB,CAAC,KAAkB,EAAE,WAA4C;IACjG,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACxB,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,OAAO,kCAAkC,CAAC,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1F,CAAC"}
|
package/dist/external-tools.d.ts
CHANGED
|
@@ -22,10 +22,23 @@ import type { InferResult, ReviewFinding } from './types.js';
|
|
|
22
22
|
export declare function runESLint(filePaths: string[], cwd: string, health?: ReviewHealthBuilder): Promise<ReviewFinding[]>;
|
|
23
23
|
export interface RunTSCDiagnosticsOptions {
|
|
24
24
|
/**
|
|
25
|
-
* When true, suppress
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* When true, suppress TS diagnostics that fire as kern-review infrastructure noise when we inject
|
|
26
|
+
* ad-hoc files into a Project that carries a host tsconfig. Suppressed codes fall into two classes:
|
|
27
|
+
*
|
|
28
|
+
* Project membership (in-memory Project vs host rootDir):
|
|
29
|
+
* - TS6059 — "File is not listed within the file list of project"
|
|
30
|
+
* - TS6307 — "File is not under 'rootDir'"
|
|
31
|
+
*
|
|
32
|
+
* Environmental (in-memory Project doesn't mirror host compilerOptions — moduleResolution, jsx, lib):
|
|
33
|
+
* - TS2792 — "Cannot find module X. Did you mean to set 'moduleResolution' to 'nodenext'?"
|
|
34
|
+
* - TS17004 — "Cannot use JSX unless the '--jsx' flag is provided"
|
|
35
|
+
* - TS2580 / TS2591 — "Cannot find name 'process'/'require'/'module'" (@types/node missing)
|
|
36
|
+
*
|
|
37
|
+
* The dev already sees the environmental class in their IDE / local `tsc --noEmit` when real.
|
|
38
|
+
* Set this only for the standard review path. The --lint path must leave it false so real
|
|
39
|
+
* tsconfig misconfigurations still surface as errors.
|
|
40
|
+
*
|
|
41
|
+
* The name is kept for backward compatibility; scope broadened deliberately.
|
|
29
42
|
*/
|
|
30
43
|
downgradeProjectLoadingErrors?: boolean;
|
|
31
44
|
}
|
package/dist/external-tools.js
CHANGED
|
@@ -151,8 +151,19 @@ export function runTSCDiagnostics(project, options = {}, health) {
|
|
|
151
151
|
// them as info still pollutes every barrel/re-export report in composite monorepos.
|
|
152
152
|
// ts6059 — "File is not listed within the file list of project"
|
|
153
153
|
// ts6307 — "File is not under 'rootDir'"
|
|
154
|
+
// The following codes are environmental: they reflect ts-morph's in-memory Project not
|
|
155
|
+
// perfectly mirroring the host's compilerOptions (moduleResolution, jsx, lib). The dev
|
|
156
|
+
// already sees them in their IDE / local `tsc --noEmit` if real; the review's value-add
|
|
157
|
+
// is KERN-relevant findings, not duplicating compiler output. A sweep of the agon repo
|
|
158
|
+
// (451 files) emitted 1869 of these as errors — pure noise drowning real findings.
|
|
159
|
+
// ts2792 — "Cannot find module X. Did you mean to set 'moduleResolution' to 'nodenext'?"
|
|
160
|
+
// ts17004 — "Cannot use JSX unless the '--jsx' flag is provided"
|
|
161
|
+
// ts2580 / ts2591 — "Cannot find name 'process'/'require'/'module'. Install @types/node?"
|
|
162
|
+
// (TS emits 2580 when the name resolves via global lib shims, 2591 when it doesn't —
|
|
163
|
+
// both point at the same user-side remedy, both are environmental from review's POV.)
|
|
154
164
|
const isLoadingNoise = code === 6059 || code === 6307;
|
|
155
|
-
|
|
165
|
+
const isEnvironmentalNoise = code === 2792 || code === 17004 || code === 2580 || code === 2591;
|
|
166
|
+
if ((isLoadingNoise || isEnvironmentalNoise) && options.downgradeProjectLoadingErrors) {
|
|
156
167
|
continue;
|
|
157
168
|
}
|
|
158
169
|
findings.push({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-tools.js","sourceRoot":"","sources":["../src/external-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAA4B,MAAM,oBAAoB,CAAC;AAE3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,GAAY;IACpC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClD,MAAM,IAAI,GAAI,GAA0B,CAAC,IAAI,CAAC;IAC9C,OAAO,IAAI,KAAK,kBAAkB,IAAI,IAAI,KAAK,sBAAsB,CAAC;AACxE,CAAC;AAED,4EAA4E;AAE5E;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,SAAmB,EACnB,GAAW,EACX,MAA4B;IAE5B,uFAAuF;IACvF,sFAAsF;IACtF,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IAClC,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,CAAC,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAQ,CAAC;QAC7D,MAAM,GAAG,YAAY,CAAC,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC;IAC/D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,gCAAgC,CAAC,CAAC;YACxE,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,uBAAuB,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/E,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU;YAAE,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;QACxF,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,4DAA4D,CAAC,CAAC;QACpG,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAElD,MAAM,QAAQ,GAAoB,EAAE,CAAC;QAErC,KAAK,MAAM,MAAM,IAAI,OAAgB,EAAE,CAAC;YACtC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,QAAiB,EAAE,CAAC;gBAC3C,MAAM,QAAQ,GACZ,GAAG,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;gBAEzE,MAAM,WAAW,GAAe;oBAC9B,IAAI,EAAE,MAAM,CAAC,QAAQ;oBACrB,SAAS,EAAE,GAAG,CAAC,IAAI;oBACnB,QAAQ,EAAE,GAAG,CAAC,MAAM;oBACpB,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,IAAI;oBAChC,MAAM,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,MAAM;iBACpC,CAAC;gBAEF,QAAQ,CAAC,IAAI,CAAC;oBACZ,MAAM,EAAE,QAAQ;oBAChB,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,gBAAgB;oBACtC,QAAQ;oBACR,QAAQ,EAAE,oBAAoB,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;oBAChD,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,WAAW;oBACX,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS;oBAChD,WAAW,EAAE,iBAAiB,CAAC,GAAG,CAAC,MAAM,IAAI,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC;iBAC7E,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wFAAwF;QACxF,sFAAsF;QACtF,4CAA4C;QAC5C,MAAM,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,+BAA+B,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;QACvF,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU;YAAE,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;QACxF,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAAC,MAAc;IAC1C,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,OAAO,CAAC;IAC/E,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAC1E,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9E,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,WAAW,CAAC;IAC/E,OAAO,SAAS,CAAC;AACnB,CAAC;
|
|
1
|
+
{"version":3,"file":"external-tools.js","sourceRoot":"","sources":["../src/external-tools.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export { resolveImportGraph } from './graph.js';
|
|
|
24
24
|
export { findTsConfig, inferFromFile, inferFromSource } from './inferrer.js';
|
|
25
25
|
export type { KernLintRule } from './kern-lint.js';
|
|
26
26
|
export { flattenIR, lintKernIR } from './kern-lint.js';
|
|
27
|
-
export type { LLMBridgeConfig, LLMReviewInput, ReviewInstructionOptions } from './llm-bridge.js';
|
|
27
|
+
export type { LLMBridgeConfig, LLMCallResult, LLMReviewInput, LLMReviewResult, LLMUsage, ReviewInstructionOptions, } from './llm-bridge.js';
|
|
28
28
|
export { buildReviewInstructions, isLLMAvailable, runLLMReview } from './llm-bridge.js';
|
|
29
29
|
export type { LLMGraphContext } from './llm-review.js';
|
|
30
30
|
export { buildLLMPrompt, exportKernIR, parseLLMResponse } from './llm-review.js';
|
|
@@ -81,6 +81,7 @@ export declare function resetFsProject(): void;
|
|
|
81
81
|
export declare function refreshFsProjectFromDisk(): number;
|
|
82
82
|
/** True when the file is codegen output — detected via common path patterns or a @generated header. */
|
|
83
83
|
export declare function isGeneratedFile(filePath: string, source?: string): boolean;
|
|
84
|
+
export declare function isReviewableFile(filePath: string): boolean;
|
|
84
85
|
/**
|
|
85
86
|
* Review a single file. Auto-detects language from extension.
|
|
86
87
|
* Uses a filesystem-backed ts-morph Project for type-aware analysis.
|