@pseolint/core 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/adapters/index.d.ts +53 -0
- package/dist/ai/adapters/index.d.ts.map +1 -0
- package/dist/ai/adapters/index.js +158 -0
- package/dist/ai/adapters/index.js.map +1 -0
- package/dist/ai/cache.d.ts +11 -0
- package/dist/ai/cache.d.ts.map +1 -0
- package/dist/ai/cache.js +40 -0
- package/dist/ai/cache.js.map +1 -0
- package/dist/ai/cost.d.ts +3 -0
- package/dist/ai/cost.d.ts.map +1 -0
- package/dist/ai/cost.js +22 -0
- package/dist/ai/cost.js.map +1 -0
- package/dist/ai/feedback-prompt.d.ts +22 -0
- package/dist/ai/feedback-prompt.d.ts.map +1 -0
- package/dist/ai/feedback-prompt.js +39 -0
- package/dist/ai/feedback-prompt.js.map +1 -0
- package/dist/ai/prompt.d.ts +10 -0
- package/dist/ai/prompt.d.ts.map +1 -0
- package/dist/ai/prompt.js +51 -0
- package/dist/ai/prompt.js.map +1 -0
- package/dist/ai/triage.d.ts +22 -0
- package/dist/ai/triage.d.ts.map +1 -0
- package/dist/ai/triage.js +123 -0
- package/dist/ai/triage.js.map +1 -0
- package/dist/ai/types.d.ts +26 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +2 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/auditor.d.ts.map +1 -1
- package/dist/auditor.js +367 -83
- package/dist/auditor.js.map +1 -1
- package/dist/cache.d.ts +44 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +182 -0
- package/dist/cache.js.map +1 -0
- package/dist/data-source-loader.d.ts +14 -0
- package/dist/data-source-loader.d.ts.map +1 -0
- package/dist/data-source-loader.js +76 -0
- package/dist/data-source-loader.js.map +1 -0
- package/dist/enrich-findings.d.ts.map +1 -1
- package/dist/enrich-findings.js +4 -0
- package/dist/enrich-findings.js.map +1 -1
- package/dist/formatters/console.d.ts.map +1 -1
- package/dist/formatters/console.js +30 -0
- package/dist/formatters/console.js.map +1 -1
- package/dist/formatters/html.d.ts.map +1 -1
- package/dist/formatters/html.js +92 -70
- package/dist/formatters/html.js.map +1 -1
- package/dist/formatters/markdown.d.ts.map +1 -1
- package/dist/formatters/markdown.js +29 -0
- package/dist/formatters/markdown.js.map +1 -1
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/rule-references.d.ts.map +1 -1
- package/dist/rule-references.js +3 -0
- package/dist/rule-references.js.map +1 -1
- package/dist/rules/data/data-binding.d.ts +4 -0
- package/dist/rules/data/data-binding.d.ts.map +1 -0
- package/dist/rules/data/data-binding.js +107 -0
- package/dist/rules/data/data-binding.js.map +1 -0
- package/dist/rules/tech/robots-sitemap-presence.d.ts +2 -1
- package/dist/rules/tech/robots-sitemap-presence.d.ts.map +1 -1
- package/dist/rules/tech/robots-sitemap-presence.js +101 -0
- package/dist/rules/tech/robots-sitemap-presence.js.map +1 -1
- package/dist/rules/tech/sitemap-completeness.d.ts.map +1 -1
- package/dist/rules/tech/sitemap-completeness.js +15 -0
- package/dist/rules/tech/sitemap-completeness.js.map +1 -1
- package/dist/state.d.ts +35 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +64 -0
- package/dist/state.js.map +1 -0
- package/dist/stratified-sample.d.ts +3 -0
- package/dist/stratified-sample.d.ts.map +1 -0
- package/dist/stratified-sample.js +88 -0
- package/dist/stratified-sample.js.map +1 -0
- package/dist/telemetry/aggregator.d.ts +28 -0
- package/dist/telemetry/aggregator.d.ts.map +1 -0
- package/dist/telemetry/aggregator.js +33 -0
- package/dist/telemetry/aggregator.js.map +1 -0
- package/dist/telemetry/index.d.ts +5 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +5 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/reader.d.ts +12 -0
- package/dist/telemetry/reader.d.ts.map +1 -0
- package/dist/telemetry/reader.js +35 -0
- package/dist/telemetry/reader.js.map +1 -0
- package/dist/telemetry/types.d.ts +120 -0
- package/dist/telemetry/types.d.ts.map +1 -0
- package/dist/telemetry/types.js +70 -0
- package/dist/telemetry/types.js.map +1 -0
- package/dist/telemetry/writer.d.ts +12 -0
- package/dist/telemetry/writer.d.ts.map +1 -0
- package/dist/telemetry/writer.js +38 -0
- package/dist/telemetry/writer.js.map +1 -0
- package/dist/types.d.ts +92 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +26 -6
- package/dist/algorithms/entity-mask.test.d.ts +0 -2
- package/dist/algorithms/entity-mask.test.d.ts.map +0 -1
- package/dist/algorithms/entity-mask.test.js +0 -23
- package/dist/algorithms/entity-mask.test.js.map +0 -1
- package/dist/algorithms/simhash.test.d.ts +0 -2
- package/dist/algorithms/simhash.test.d.ts.map +0 -1
- package/dist/algorithms/simhash.test.js +0 -23
- package/dist/algorithms/simhash.test.js.map +0 -1
- package/dist/auditor.test.d.ts +0 -2
- package/dist/auditor.test.d.ts.map +0 -1
- package/dist/auditor.test.js +0 -134
- package/dist/auditor.test.js.map +0 -1
- package/dist/parser.test.d.ts +0 -2
- package/dist/parser.test.d.ts.map +0 -1
- package/dist/parser.test.js +0 -37
- package/dist/parser.test.js.map +0 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { LanguageModel } from "ai";
|
|
2
|
+
import type { AiOptions } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* How the provider factory is constructed from the imported SDK package.
|
|
5
|
+
* - `cloud-apikey` — `factory({ apiKey })` then `provider(modelId)`.
|
|
6
|
+
* - `ollama` — `factory({ baseURL })` then `provider(modelId)`.
|
|
7
|
+
*/
|
|
8
|
+
export type ProviderKind = "cloud-apikey" | "ollama";
|
|
9
|
+
interface ProviderEntry {
|
|
10
|
+
/** npm package name to dynamically import at runtime. */
|
|
11
|
+
pkg: string;
|
|
12
|
+
/** Named export from the package, e.g. `createAnthropic`. */
|
|
13
|
+
factoryName: string;
|
|
14
|
+
/** Env var that holds the API key. Optional — Ollama has none. */
|
|
15
|
+
envVar?: string;
|
|
16
|
+
/** Default model id when the user does not specify one. */
|
|
17
|
+
defaultModel: string;
|
|
18
|
+
kind: ProviderKind;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Registry of supported AI SDK providers.
|
|
22
|
+
*
|
|
23
|
+
* To add a provider: drop a new entry here and publish the corresponding
|
|
24
|
+
* `@ai-sdk/*` package as an optional peer dep in core's `package.json`.
|
|
25
|
+
* Users install only the providers they use.
|
|
26
|
+
*/
|
|
27
|
+
declare const PROVIDER_REGISTRY: Record<string, ProviderEntry>;
|
|
28
|
+
/** Known provider ids plus any user-supplied string (validated at runtime). */
|
|
29
|
+
export type ProviderId = keyof typeof PROVIDER_REGISTRY | (string & {});
|
|
30
|
+
export interface ResolvedModel {
|
|
31
|
+
model: LanguageModel;
|
|
32
|
+
providerId: string;
|
|
33
|
+
modelId: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Best-effort provider auto-detection.
|
|
37
|
+
*
|
|
38
|
+
* Resolution order:
|
|
39
|
+
* 1. First cloud provider (in `CLOUD_DETECT_ORDER`) with its env var set.
|
|
40
|
+
* 2. Ollama daemon responding at `<endpoint>/` → "ollama".
|
|
41
|
+
* 3. Otherwise `null`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function detectProvider(endpoint?: string): Promise<string | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Resolve an AI SDK `LanguageModel` for the requested (or auto-detected) provider.
|
|
46
|
+
*
|
|
47
|
+
* Provider SDKs are loaded lazily via dynamic `import(specifier)` so unused
|
|
48
|
+
* providers don't need to be installed. If the chosen provider's package is
|
|
49
|
+
* missing, the error message includes an install hint.
|
|
50
|
+
*/
|
|
51
|
+
export declare function createLanguageModel(config: AiOptions): Promise<ResolvedModel>;
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ai/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,QAAQ,CAAC;AAErD,UAAU,aAAa;IACrB,yDAAyD;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,YAAY,CAAC;CACpB;AAED;;;;;;GAMG;AACH,QAAA,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAwDpD,CAAC;AAEF,+EAA+E;AAC/E,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,iBAAiB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAExE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAgBD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgB9E;AAaD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,CAsDnF"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry of supported AI SDK providers.
|
|
3
|
+
*
|
|
4
|
+
* To add a provider: drop a new entry here and publish the corresponding
|
|
5
|
+
* `@ai-sdk/*` package as an optional peer dep in core's `package.json`.
|
|
6
|
+
* Users install only the providers they use.
|
|
7
|
+
*/
|
|
8
|
+
const PROVIDER_REGISTRY = {
|
|
9
|
+
anthropic: {
|
|
10
|
+
pkg: "@ai-sdk/anthropic",
|
|
11
|
+
factoryName: "createAnthropic",
|
|
12
|
+
envVar: "ANTHROPIC_API_KEY",
|
|
13
|
+
defaultModel: "claude-sonnet-4-6",
|
|
14
|
+
kind: "cloud-apikey",
|
|
15
|
+
},
|
|
16
|
+
openai: {
|
|
17
|
+
pkg: "@ai-sdk/openai",
|
|
18
|
+
factoryName: "createOpenAI",
|
|
19
|
+
envVar: "OPENAI_API_KEY",
|
|
20
|
+
defaultModel: "gpt-4o-mini",
|
|
21
|
+
kind: "cloud-apikey",
|
|
22
|
+
},
|
|
23
|
+
google: {
|
|
24
|
+
pkg: "@ai-sdk/google",
|
|
25
|
+
factoryName: "createGoogleGenerativeAI",
|
|
26
|
+
envVar: "GOOGLE_GENERATIVE_AI_API_KEY",
|
|
27
|
+
defaultModel: "gemini-2.5-flash",
|
|
28
|
+
kind: "cloud-apikey",
|
|
29
|
+
},
|
|
30
|
+
mistral: {
|
|
31
|
+
pkg: "@ai-sdk/mistral",
|
|
32
|
+
factoryName: "createMistral",
|
|
33
|
+
envVar: "MISTRAL_API_KEY",
|
|
34
|
+
defaultModel: "mistral-small-latest",
|
|
35
|
+
kind: "cloud-apikey",
|
|
36
|
+
},
|
|
37
|
+
groq: {
|
|
38
|
+
pkg: "@ai-sdk/groq",
|
|
39
|
+
factoryName: "createGroq",
|
|
40
|
+
envVar: "GROQ_API_KEY",
|
|
41
|
+
defaultModel: "llama-3.3-70b-versatile",
|
|
42
|
+
kind: "cloud-apikey",
|
|
43
|
+
},
|
|
44
|
+
xai: {
|
|
45
|
+
pkg: "@ai-sdk/xai",
|
|
46
|
+
factoryName: "createXai",
|
|
47
|
+
envVar: "XAI_API_KEY",
|
|
48
|
+
defaultModel: "grok-2",
|
|
49
|
+
kind: "cloud-apikey",
|
|
50
|
+
},
|
|
51
|
+
cohere: {
|
|
52
|
+
pkg: "@ai-sdk/cohere",
|
|
53
|
+
factoryName: "createCohere",
|
|
54
|
+
envVar: "COHERE_API_KEY",
|
|
55
|
+
defaultModel: "command-r-plus",
|
|
56
|
+
kind: "cloud-apikey",
|
|
57
|
+
},
|
|
58
|
+
ollama: {
|
|
59
|
+
pkg: "ollama-ai-provider-v2",
|
|
60
|
+
factoryName: "createOllama",
|
|
61
|
+
defaultModel: "llama3.1:8b",
|
|
62
|
+
kind: "ollama",
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
const OLLAMA_DETECT_TIMEOUT_MS = 500;
|
|
66
|
+
const DEFAULT_OLLAMA_ENDPOINT = "http://localhost:11434";
|
|
67
|
+
/** Cloud providers checked in priority order during auto-detection. */
|
|
68
|
+
const CLOUD_DETECT_ORDER = [
|
|
69
|
+
"anthropic",
|
|
70
|
+
"openai",
|
|
71
|
+
"google",
|
|
72
|
+
"mistral",
|
|
73
|
+
"groq",
|
|
74
|
+
"xai",
|
|
75
|
+
"cohere",
|
|
76
|
+
];
|
|
77
|
+
/**
|
|
78
|
+
* Best-effort provider auto-detection.
|
|
79
|
+
*
|
|
80
|
+
* Resolution order:
|
|
81
|
+
* 1. First cloud provider (in `CLOUD_DETECT_ORDER`) with its env var set.
|
|
82
|
+
* 2. Ollama daemon responding at `<endpoint>/` → "ollama".
|
|
83
|
+
* 3. Otherwise `null`.
|
|
84
|
+
*/
|
|
85
|
+
export async function detectProvider(endpoint) {
|
|
86
|
+
for (const id of CLOUD_DETECT_ORDER) {
|
|
87
|
+
const entry = PROVIDER_REGISTRY[id];
|
|
88
|
+
if (entry?.envVar && process.env[entry.envVar])
|
|
89
|
+
return id;
|
|
90
|
+
}
|
|
91
|
+
const url = (endpoint ?? DEFAULT_OLLAMA_ENDPOINT).replace(/\/+$/, "") + "/";
|
|
92
|
+
try {
|
|
93
|
+
const ctrl = new AbortController();
|
|
94
|
+
const timer = setTimeout(() => ctrl.abort(), OLLAMA_DETECT_TIMEOUT_MS);
|
|
95
|
+
const res = await fetch(url, { method: "HEAD", signal: ctrl.signal });
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
if (res.status >= 200 && res.status < 500)
|
|
98
|
+
return "ollama";
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function supportedProviderList() {
|
|
106
|
+
return Object.keys(PROVIDER_REGISTRY).join(", ");
|
|
107
|
+
}
|
|
108
|
+
function envVarList() {
|
|
109
|
+
return CLOUD_DETECT_ORDER
|
|
110
|
+
.map((id) => PROVIDER_REGISTRY[id]?.envVar)
|
|
111
|
+
.filter((v) => Boolean(v))
|
|
112
|
+
.join(", ");
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Resolve an AI SDK `LanguageModel` for the requested (or auto-detected) provider.
|
|
116
|
+
*
|
|
117
|
+
* Provider SDKs are loaded lazily via dynamic `import(specifier)` so unused
|
|
118
|
+
* providers don't need to be installed. If the chosen provider's package is
|
|
119
|
+
* missing, the error message includes an install hint.
|
|
120
|
+
*/
|
|
121
|
+
export async function createLanguageModel(config) {
|
|
122
|
+
const providerId = config.provider ?? (await detectProvider(config.endpoint));
|
|
123
|
+
if (!providerId) {
|
|
124
|
+
throw new Error(`No AI provider detected. Set an API key env var (${envVarList()}), run Ollama locally, or pass --ai-provider explicitly.`);
|
|
125
|
+
}
|
|
126
|
+
const entry = PROVIDER_REGISTRY[providerId];
|
|
127
|
+
if (!entry) {
|
|
128
|
+
throw new Error(`Unknown AI provider "${providerId}". Supported: ${supportedProviderList()}. To add a provider, submit a PR with an entry in PROVIDER_REGISTRY.`);
|
|
129
|
+
}
|
|
130
|
+
let pkgExports;
|
|
131
|
+
try {
|
|
132
|
+
// Variable specifier — prevents tsc from trying to resolve the module at build time.
|
|
133
|
+
const specifier = entry.pkg;
|
|
134
|
+
pkgExports = (await import(specifier));
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
const original = e instanceof Error ? e.message : String(e);
|
|
138
|
+
throw new Error(`Provider "${providerId}" requires "${entry.pkg}". Install it with: npm install ${entry.pkg}\nOriginal: ${original}`);
|
|
139
|
+
}
|
|
140
|
+
const factory = pkgExports[entry.factoryName];
|
|
141
|
+
if (typeof factory !== "function") {
|
|
142
|
+
throw new Error(`Provider "${providerId}": package "${entry.pkg}" does not export "${entry.factoryName}"`);
|
|
143
|
+
}
|
|
144
|
+
const modelId = config.model ?? entry.defaultModel;
|
|
145
|
+
if (entry.kind === "ollama") {
|
|
146
|
+
const baseURL = (config.endpoint ?? DEFAULT_OLLAMA_ENDPOINT).replace(/\/+$/, "") + "/api";
|
|
147
|
+
const ollama = factory({ baseURL });
|
|
148
|
+
return { model: ollama(modelId), providerId, modelId };
|
|
149
|
+
}
|
|
150
|
+
// cloud-apikey
|
|
151
|
+
const apiKey = config.apiKey ?? (entry.envVar ? process.env[entry.envVar] : undefined);
|
|
152
|
+
if (!apiKey) {
|
|
153
|
+
throw new Error(`Provider "${providerId}" needs an API key. Set ${entry.envVar} or pass --ai-key / ai.apiKey.`);
|
|
154
|
+
}
|
|
155
|
+
const provider = factory({ apiKey });
|
|
156
|
+
return { model: provider(modelId), providerId, modelId };
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ai/adapters/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TriageResult } from "./types.js";
|
|
2
|
+
interface KeyInput {
|
|
3
|
+
findingsHash: string;
|
|
4
|
+
model: string;
|
|
5
|
+
promptVersion: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function triageCacheKey(input: KeyInput): string;
|
|
8
|
+
export declare function readTriageCache(dir: string, key: string, ttlMs: number): Promise<TriageResult | null>;
|
|
9
|
+
export declare function writeTriageCache(dir: string, key: string, result: TriageResult): Promise<void>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/ai/cache.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,UAAU,QAAQ;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;CACvB;AAOD,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAItD;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAkB3G;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAOpG"}
|
package/dist/ai/cache.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
export function triageCacheKey(input) {
|
|
5
|
+
return createHash("sha256")
|
|
6
|
+
.update(`${input.findingsHash}|${input.model}|${input.promptVersion}`)
|
|
7
|
+
.digest("hex");
|
|
8
|
+
}
|
|
9
|
+
export async function readTriageCache(dir, key, ttlMs) {
|
|
10
|
+
const path = join(dir, `${key}.json`);
|
|
11
|
+
let raw;
|
|
12
|
+
try {
|
|
13
|
+
raw = await readFile(path, "utf8");
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
let entry;
|
|
19
|
+
try {
|
|
20
|
+
entry = JSON.parse(raw);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
if (typeof entry.cachedAt !== "string" || typeof entry.result !== "object")
|
|
26
|
+
return null;
|
|
27
|
+
const ageMs = Date.now() - new Date(entry.cachedAt).getTime();
|
|
28
|
+
if (Number.isNaN(ageMs) || ageMs > ttlMs)
|
|
29
|
+
return null;
|
|
30
|
+
return entry.result;
|
|
31
|
+
}
|
|
32
|
+
export async function writeTriageCache(dir, key, result) {
|
|
33
|
+
await mkdir(dir, { recursive: true });
|
|
34
|
+
const path = join(dir, `${key}.json`);
|
|
35
|
+
const tmp = `${path}.tmp`;
|
|
36
|
+
const entry = { cachedAt: new Date().toISOString(), result };
|
|
37
|
+
await writeFile(tmp, JSON.stringify(entry), "utf8");
|
|
38
|
+
await rename(tmp, path);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/ai/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAcjC,MAAM,UAAU,cAAc,CAAC,KAAe;IAC5C,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,GAAG,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;SACrE,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW,EAAE,GAAW,EAAE,KAAa;IAC3E,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;IACtC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,KAAkB,CAAC;IACvB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACxF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC;IAC9D,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,KAAK;QAAE,OAAO,IAAI,CAAC;IACtD,OAAO,KAAK,CAAC,MAAM,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAW,EAAE,GAAW,EAAE,MAAoB;IACnF,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,GAAG,IAAI,MAAM,CAAC;IAC1B,MAAM,KAAK,GAAgB,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,CAAC;IAC1E,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;IACpD,MAAM,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../../src/ai/cost.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAsB7C,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAKxG"}
|
package/dist/ai/cost.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Best-effort pricing table. Missing entries return `undefined` — callers
|
|
3
|
+
* must treat unknown cost as "not estimable" rather than zero. Ollama and
|
|
4
|
+
* other local providers intentionally return undefined.
|
|
5
|
+
*/
|
|
6
|
+
const PRICING = {
|
|
7
|
+
"anthropic:claude-sonnet-4-6": { inputPerM: 3.0, outputPerM: 15.0 },
|
|
8
|
+
"anthropic:claude-opus-4-7": { inputPerM: 15.0, outputPerM: 75.0 },
|
|
9
|
+
"anthropic:claude-haiku-4-5-20251001": { inputPerM: 0.8, outputPerM: 4.0 },
|
|
10
|
+
"openai:gpt-4o": { inputPerM: 2.5, outputPerM: 10.0 },
|
|
11
|
+
"openai:gpt-4o-mini": { inputPerM: 0.15, outputPerM: 0.6 },
|
|
12
|
+
"google:gemini-2.5-pro": { inputPerM: 1.25, outputPerM: 10.0 },
|
|
13
|
+
"google:gemini-2.5-flash": { inputPerM: 0.3, outputPerM: 2.5 },
|
|
14
|
+
};
|
|
15
|
+
export function estimateCostUsd(providerId, model, usage) {
|
|
16
|
+
const key = `${providerId}:${model}`;
|
|
17
|
+
const pricing = PRICING[key];
|
|
18
|
+
if (!pricing)
|
|
19
|
+
return undefined;
|
|
20
|
+
return (usage.input / 1_000_000) * pricing.inputPerM + (usage.output / 1_000_000) * pricing.outputPerM;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=cost.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost.js","sourceRoot":"","sources":["../../src/ai/cost.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,OAAO,GAAiC;IAC5C,6BAA6B,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE;IACnE,2BAA2B,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;IAClE,qCAAqC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;IAC1E,eAAe,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE;IACrD,oBAAoB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE;IAC1D,uBAAuB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;IAC9D,yBAAyB,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;CAC/D,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,UAAkB,EAAE,KAAa,EAAE,KAAiB;IAClF,MAAM,GAAG,GAAG,GAAG,UAAU,IAAI,KAAK,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;AACzG,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type FeedbackRating = "helpful" | "unhelpful" | "skipped";
|
|
2
|
+
export interface PromptOptions {
|
|
3
|
+
/** Maximum time to wait for user input in milliseconds. Default: 15000. */
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
/** Input stream (defaults to process.stdin). Must be a TTY. */
|
|
6
|
+
input?: NodeJS.ReadableStream;
|
|
7
|
+
/** Output stream (defaults to process.stderr). Must be a TTY. */
|
|
8
|
+
output?: NodeJS.WritableStream;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Prompts the user once for triage feedback (y/n/skip).
|
|
12
|
+
*
|
|
13
|
+
* Returns "skipped" immediately on non-TTY or if either stream is not a TTY.
|
|
14
|
+
* Waits up to timeoutMs for input; if no input is received, returns "skipped".
|
|
15
|
+
*
|
|
16
|
+
* Accepted responses (case-insensitive):
|
|
17
|
+
* - helpful: "y", "yes", "helpful"
|
|
18
|
+
* - unhelpful: "n", "no", "unhelpful"
|
|
19
|
+
* - anything else (including empty) returns "skipped".
|
|
20
|
+
*/
|
|
21
|
+
export declare function promptTriageFeedback(opts?: PromptOptions): Promise<FeedbackRating>;
|
|
22
|
+
//# sourceMappingURL=feedback-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback-prompt.d.ts","sourceRoot":"","sources":["../../src/ai/feedback-prompt.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAChC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,cAAc,CAAC,CAuBzB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import readline from "node:readline";
|
|
2
|
+
/**
|
|
3
|
+
* Prompts the user once for triage feedback (y/n/skip).
|
|
4
|
+
*
|
|
5
|
+
* Returns "skipped" immediately on non-TTY or if either stream is not a TTY.
|
|
6
|
+
* Waits up to timeoutMs for input; if no input is received, returns "skipped".
|
|
7
|
+
*
|
|
8
|
+
* Accepted responses (case-insensitive):
|
|
9
|
+
* - helpful: "y", "yes", "helpful"
|
|
10
|
+
* - unhelpful: "n", "no", "unhelpful"
|
|
11
|
+
* - anything else (including empty) returns "skipped".
|
|
12
|
+
*/
|
|
13
|
+
export async function promptTriageFeedback(opts = {}) {
|
|
14
|
+
const input = opts.input ?? process.stdin;
|
|
15
|
+
const output = opts.output ?? process.stderr;
|
|
16
|
+
const inIsTty = input.isTTY === true;
|
|
17
|
+
const outIsTty = output.isTTY === true;
|
|
18
|
+
if (!inIsTty || !outIsTty)
|
|
19
|
+
return "skipped";
|
|
20
|
+
const timeoutMs = opts.timeoutMs ?? 15000;
|
|
21
|
+
const rl = readline.createInterface({ input, output, terminal: true });
|
|
22
|
+
output.write("\nWas this triage helpful? [y/n/skip] ");
|
|
23
|
+
try {
|
|
24
|
+
const answer = await Promise.race([
|
|
25
|
+
new Promise((resolve) => rl.once("line", resolve)),
|
|
26
|
+
new Promise((resolve) => setTimeout(() => resolve(""), timeoutMs)),
|
|
27
|
+
]);
|
|
28
|
+
const t = answer.trim().toLowerCase();
|
|
29
|
+
if (t === "y" || t === "yes" || t === "helpful")
|
|
30
|
+
return "helpful";
|
|
31
|
+
if (t === "n" || t === "no" || t === "unhelpful")
|
|
32
|
+
return "unhelpful";
|
|
33
|
+
return "skipped";
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
rl.close();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=feedback-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback-prompt.js","sourceRoot":"","sources":["../../src/ai/feedback-prompt.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,eAAe,CAAC;AAarC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAsB,EAAE;IAExB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAC7C,MAAM,OAAO,GAAI,KAAwC,CAAC,KAAK,KAAK,IAAI,CAAC;IACzE,MAAM,QAAQ,GAAI,MAAyC,CAAC,KAAK,KAAK,IAAI,CAAC;IAC3E,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IAE5C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;IAC1C,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IACvE,MAAM,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAEvD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAS;YACxC,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC1D,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;SAC3E,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAClE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,WAAW;YAAE,OAAO,WAAW,CAAC;QACrE,OAAO,SAAS,CAAC;IACnB,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RuleResult } from "../types.js";
|
|
2
|
+
export declare const PROMPT_VERSION = "1.0.0";
|
|
3
|
+
export declare const MAX_FINDINGS_IN_PROMPT = 200;
|
|
4
|
+
export interface PromptRequest {
|
|
5
|
+
system: string;
|
|
6
|
+
user: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function assignFindingId(f: RuleResult): string;
|
|
9
|
+
export declare function buildPromptRequest(findings: RuleResult[], pageCount: number): PromptRequest;
|
|
10
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/ai/prompt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,aAAa,CAAC;AAExD,eAAO,MAAM,cAAc,UAAU,CAAC;AACtC,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAe1C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAMrD;AAmBD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa,CA8B3F"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
export const PROMPT_VERSION = "1.0.0";
|
|
3
|
+
export const MAX_FINDINGS_IN_PROMPT = 200;
|
|
4
|
+
const SEVERITY_ORDER = { info: 0, warning: 1, error: 2, critical: 3 };
|
|
5
|
+
const SYSTEM_PROMPT = `You are an SEO audit triage assistant. Given a list of pSEO linter findings, identify 1-5 underlying ROOT CAUSES driving the findings. Group findings by shared underlying problem, not by rule ID. Rank causes by likely SEO impact (highest first).
|
|
6
|
+
|
|
7
|
+
Rules:
|
|
8
|
+
- Emit rootCauses FIRST, then narrative — do not reverse this order.
|
|
9
|
+
- Keep each rootCause label <= 80 chars and phrase it as a problem statement.
|
|
10
|
+
- Keep each rationale to 1-2 sentences (about 30-40 words max).
|
|
11
|
+
- fixOrder starts at 1 for the highest-priority root cause.
|
|
12
|
+
- Use only finding ids that appear in the input for relatedFindingIds.
|
|
13
|
+
- narrative is a SHORT 1-2 sentence overall summary (about 30 words max).
|
|
14
|
+
- Be concise. This is a structured report, not prose.`;
|
|
15
|
+
export function assignFindingId(f) {
|
|
16
|
+
const hash = createHash("sha256")
|
|
17
|
+
.update((f.pageUrl ?? "") + "|" + f.message)
|
|
18
|
+
.digest("hex")
|
|
19
|
+
.slice(0, 8);
|
|
20
|
+
return `${f.ruleId}:${hash}`;
|
|
21
|
+
}
|
|
22
|
+
export function buildPromptRequest(findings, pageCount) {
|
|
23
|
+
const total = findings.length;
|
|
24
|
+
const sorted = [...findings].sort((a, b) => SEVERITY_ORDER[b.severity] - SEVERITY_ORDER[a.severity]);
|
|
25
|
+
const truncated = total > MAX_FINDINGS_IN_PROMPT;
|
|
26
|
+
const projected = sorted.slice(0, MAX_FINDINGS_IN_PROMPT).map((f) => ({
|
|
27
|
+
id: assignFindingId(f),
|
|
28
|
+
ruleId: f.ruleId,
|
|
29
|
+
severity: f.severity,
|
|
30
|
+
message: f.message,
|
|
31
|
+
pageUrl: f.pageUrl,
|
|
32
|
+
group: f.group,
|
|
33
|
+
}));
|
|
34
|
+
const payload = {
|
|
35
|
+
totalFindings: total,
|
|
36
|
+
pageCount,
|
|
37
|
+
truncated,
|
|
38
|
+
findings: projected,
|
|
39
|
+
};
|
|
40
|
+
if (truncated) {
|
|
41
|
+
const counts = {};
|
|
42
|
+
for (const f of findings)
|
|
43
|
+
counts[f.ruleId] = (counts[f.ruleId] ?? 0) + 1;
|
|
44
|
+
payload.findingCountByRule = counts;
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
system: SYSTEM_PROMPT,
|
|
48
|
+
user: JSON.stringify(payload),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/ai/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AACtC,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,MAAM,cAAc,GAA6B,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AAEhG,MAAM,aAAa,GAAG;;;;;;;;;sDASgC,CAAC;AAOvD,MAAM,UAAU,eAAe,CAAC,CAAa;IAC3C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC;SAC9B,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC;SAC3C,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACf,OAAO,GAAG,CAAC,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;AAC/B,CAAC;AAmBD,MAAM,UAAU,kBAAkB,CAAC,QAAsB,EAAE,SAAiB;IAC1E,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC9B,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrG,MAAM,SAAS,GAAG,KAAK,GAAG,sBAAsB,CAAC;IACjD,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAqB,EAAE,CAAC,CAAC;QACvF,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;QACtB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,KAAK,EAAE,CAAC,CAAC,KAAK;KACf,CAAC,CAAC,CAAC;IAEJ,MAAM,OAAO,GAAkB;QAC7B,aAAa,EAAE,KAAK;QACpB,SAAS;QACT,SAAS;QACT,QAAQ,EAAE,SAAS;KACpB,CAAC;IAEF,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,KAAK,MAAM,CAAC,IAAI,QAAQ;YAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACzE,OAAO,CAAC,kBAAkB,GAAG,MAAM,CAAC;IACtC,CAAC;IAED,OAAO;QACL,MAAM,EAAE,aAAa;QACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC9B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type LanguageModel } from "ai";
|
|
2
|
+
import type { RuleResult } from "../types.js";
|
|
3
|
+
import type { TriageResult } from "./types.js";
|
|
4
|
+
export interface TriageOptions {
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
model: LanguageModel;
|
|
7
|
+
providerId: string;
|
|
8
|
+
modelId: string;
|
|
9
|
+
maxInputTokens?: number;
|
|
10
|
+
maxOutputTokens?: number;
|
|
11
|
+
cache?: {
|
|
12
|
+
dir: string;
|
|
13
|
+
ttlMs: number;
|
|
14
|
+
} | false;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
}
|
|
17
|
+
export interface TriageOutcome {
|
|
18
|
+
result?: TriageResult;
|
|
19
|
+
skipReason?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function triageFindings(findings: RuleResult[], pageCount: number, options: TriageOptions): Promise<TriageOutcome>;
|
|
22
|
+
//# sourceMappingURL=triage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triage.d.ts","sourceRoot":"","sources":["../../src/ai/triage.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,IAAI,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA2B/C,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,KAAK,CAAC;IAC/C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAeD,wBAAsB,cAAc,CAClC,QAAQ,EAAE,UAAU,EAAE,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,aAAa,CAAC,CA+FxB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { generateObject } from "ai";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { PROMPT_VERSION, MAX_FINDINGS_IN_PROMPT, assignFindingId, buildPromptRequest, } from "./prompt.js";
|
|
5
|
+
import { readTriageCache, writeTriageCache, triageCacheKey } from "./cache.js";
|
|
6
|
+
import { estimateCostUsd } from "./cost.js";
|
|
7
|
+
const SEVERITIES = ["info", "warning", "error", "critical"];
|
|
8
|
+
const rootCauseSchema = z.object({
|
|
9
|
+
label: z.string().min(1).max(80).describe("Short problem statement, <= 80 chars."),
|
|
10
|
+
findingsCount: z.number().int().nonnegative().describe("How many of the input findings this root cause covers."),
|
|
11
|
+
affectedRuleIds: z.array(z.string()).describe("Rule IDs (e.g. spam/near-duplicate) whose findings share this root cause."),
|
|
12
|
+
severity: z.enum(SEVERITIES).describe("Overall severity of this root cause: info | warning | error | critical."),
|
|
13
|
+
fixOrder: z.number().int().min(1).describe("1-indexed order to fix this in. 1 = highest priority."),
|
|
14
|
+
rationale: z.string().min(1).describe("1-2 sentences: why this matters and how to fix it."),
|
|
15
|
+
relatedFindingIds: z.array(z.string()).describe("IDs (from the input `findings[].id`) of findings attributed to this root cause. Use only IDs that appear in the input."),
|
|
16
|
+
});
|
|
17
|
+
const triagePayloadSchema = z.object({
|
|
18
|
+
rootCauses: z.array(rootCauseSchema).min(1).max(5).describe("1 to 5 root causes, ranked by SEO impact (highest first)."),
|
|
19
|
+
narrative: z.string().min(1).describe("2-3 sentence overall summary of the audit state."),
|
|
20
|
+
});
|
|
21
|
+
const DEFAULT_MAX_INPUT_TOKENS = 60_000;
|
|
22
|
+
const DEFAULT_MAX_OUTPUT_TOKENS = 4_000;
|
|
23
|
+
function hashFindings(findings) {
|
|
24
|
+
const ids = findings.map(assignFindingId).sort();
|
|
25
|
+
return createHash("sha256").update(ids.join("|")).digest("hex");
|
|
26
|
+
}
|
|
27
|
+
/** Rough token estimate: ~4 chars per token. Used only for the pre-flight cap. */
|
|
28
|
+
function estimateTokens(text) {
|
|
29
|
+
return Math.ceil(text.length / 4);
|
|
30
|
+
}
|
|
31
|
+
export async function triageFindings(findings, pageCount, options) {
|
|
32
|
+
if (options.signal?.aborted) {
|
|
33
|
+
return { skipReason: "aborted before triage started" };
|
|
34
|
+
}
|
|
35
|
+
const req = buildPromptRequest(findings, pageCount);
|
|
36
|
+
const truncatedInput = findings.length > MAX_FINDINGS_IN_PROMPT;
|
|
37
|
+
const maxInputTokens = options.maxInputTokens ?? DEFAULT_MAX_INPUT_TOKENS;
|
|
38
|
+
const estimate = estimateTokens(req.system + req.user);
|
|
39
|
+
if (estimate > maxInputTokens) {
|
|
40
|
+
return { skipReason: `pre-flight token estimate ${estimate} exceeds cap ${maxInputTokens}` };
|
|
41
|
+
}
|
|
42
|
+
const validIds = new Set();
|
|
43
|
+
for (const f of findings)
|
|
44
|
+
validIds.add(assignFindingId(f));
|
|
45
|
+
const cacheKey = triageCacheKey({
|
|
46
|
+
findingsHash: hashFindings(findings),
|
|
47
|
+
model: options.modelId,
|
|
48
|
+
promptVersion: PROMPT_VERSION,
|
|
49
|
+
});
|
|
50
|
+
if (options.cache) {
|
|
51
|
+
try {
|
|
52
|
+
const cached = await readTriageCache(options.cache.dir, cacheKey, options.cache.ttlMs);
|
|
53
|
+
if (cached) {
|
|
54
|
+
return { result: { ...cached, cacheHit: true } };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// cache read errors are non-fatal — fall through to fresh call
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
let generated;
|
|
62
|
+
try {
|
|
63
|
+
generated = await generateObject({
|
|
64
|
+
model: options.model,
|
|
65
|
+
system: req.system,
|
|
66
|
+
prompt: req.user,
|
|
67
|
+
schema: triagePayloadSchema,
|
|
68
|
+
maxOutputTokens: options.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS,
|
|
69
|
+
abortSignal: options.signal,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
const err = e;
|
|
74
|
+
if (err?.name === "AbortError" || (err?.message && /abort/i.test(err.message))) {
|
|
75
|
+
return { skipReason: "aborted during LLM call" };
|
|
76
|
+
}
|
|
77
|
+
let detail = err?.message ?? String(e);
|
|
78
|
+
if (err && typeof err === "object" && "text" in err && typeof err.text === "string") {
|
|
79
|
+
detail += ` | raw=${err.text.slice(0, 400)}`;
|
|
80
|
+
}
|
|
81
|
+
if (err?.cause) {
|
|
82
|
+
try {
|
|
83
|
+
detail += ` | cause=${JSON.stringify(err.cause).slice(0, 400)}`;
|
|
84
|
+
}
|
|
85
|
+
catch { /* ignore */ }
|
|
86
|
+
}
|
|
87
|
+
return { skipReason: `LLM call failed: ${detail}` };
|
|
88
|
+
}
|
|
89
|
+
// Validate relatedFindingIds reference known findings (semantic check
|
|
90
|
+
// beyond the structural schema enforcement performed by generateObject).
|
|
91
|
+
for (const [i, c] of generated.object.rootCauses.entries()) {
|
|
92
|
+
for (const id of c.relatedFindingIds) {
|
|
93
|
+
if (!validIds.has(id)) {
|
|
94
|
+
return { skipReason: `LLM returned unknown finding id at rootCauses[${i}]: ${id}` };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const usage = {
|
|
99
|
+
input: generated.usage.inputTokens ?? 0,
|
|
100
|
+
output: generated.usage.outputTokens ?? 0,
|
|
101
|
+
};
|
|
102
|
+
const result = {
|
|
103
|
+
rootCauses: generated.object.rootCauses,
|
|
104
|
+
narrative: generated.object.narrative,
|
|
105
|
+
modelUsed: options.modelId,
|
|
106
|
+
providerId: options.providerId,
|
|
107
|
+
tokenUsage: usage,
|
|
108
|
+
estimatedCostUsd: estimateCostUsd(options.providerId, options.modelId, usage),
|
|
109
|
+
cacheHit: false,
|
|
110
|
+
promptVersion: PROMPT_VERSION,
|
|
111
|
+
truncatedInput,
|
|
112
|
+
};
|
|
113
|
+
if (options.cache) {
|
|
114
|
+
try {
|
|
115
|
+
await writeTriageCache(options.cache.dir, cacheKey, result);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// cache write errors are non-fatal
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return { result };
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=triage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triage.js","sourceRoot":"","sources":["../../src/ai/triage.ts"],"names":[],"mappings":"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"}
|