@npm-safe/core-dsh 1.0.5

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 (86) hide show
  1. package/LICENSE +204 -0
  2. package/dist/index.d.ts +513 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +711 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/llm/anthropic.d.ts +47 -0
  7. package/dist/llm/anthropic.d.ts.map +1 -0
  8. package/dist/llm/anthropic.js +161 -0
  9. package/dist/llm/anthropic.js.map +1 -0
  10. package/dist/llm/gemini.d.ts +47 -0
  11. package/dist/llm/gemini.d.ts.map +1 -0
  12. package/dist/llm/gemini.js +165 -0
  13. package/dist/llm/gemini.js.map +1 -0
  14. package/dist/llm/llm-config.d.ts +97 -0
  15. package/dist/llm/llm-config.d.ts.map +1 -0
  16. package/dist/llm/llm-config.js +188 -0
  17. package/dist/llm/llm-config.js.map +1 -0
  18. package/dist/llm/parse.d.ts +95 -0
  19. package/dist/llm/parse.d.ts.map +1 -0
  20. package/dist/llm/parse.js +158 -0
  21. package/dist/llm/parse.js.map +1 -0
  22. package/dist/llm/provider.d.ts +122 -0
  23. package/dist/llm/provider.d.ts.map +1 -0
  24. package/dist/llm/provider.js +206 -0
  25. package/dist/llm/provider.js.map +1 -0
  26. package/dist/registry/client.d.ts +164 -0
  27. package/dist/registry/client.d.ts.map +1 -0
  28. package/dist/registry/client.js +378 -0
  29. package/dist/registry/client.js.map +1 -0
  30. package/dist/registry/types.d.ts +226 -0
  31. package/dist/registry/types.d.ts.map +1 -0
  32. package/dist/registry/types.js +32 -0
  33. package/dist/registry/types.js.map +1 -0
  34. package/dist/registry/validator.d.ts +87 -0
  35. package/dist/registry/validator.d.ts.map +1 -0
  36. package/dist/registry/validator.js +214 -0
  37. package/dist/registry/validator.js.map +1 -0
  38. package/dist/scanner/ci-scan.d.ts +82 -0
  39. package/dist/scanner/ci-scan.d.ts.map +1 -0
  40. package/dist/scanner/ci-scan.js +130 -0
  41. package/dist/scanner/ci-scan.js.map +1 -0
  42. package/dist/scanner/rule-config.d.ts +61 -0
  43. package/dist/scanner/rule-config.d.ts.map +1 -0
  44. package/dist/scanner/rule-config.js +103 -0
  45. package/dist/scanner/rule-config.js.map +1 -0
  46. package/dist/scanner/rule-loader.d.ts +28 -0
  47. package/dist/scanner/rule-loader.d.ts.map +1 -0
  48. package/dist/scanner/rule-loader.js +67 -0
  49. package/dist/scanner/rule-loader.js.map +1 -0
  50. package/dist/scanner/static-rules.d.ts +88 -0
  51. package/dist/scanner/static-rules.d.ts.map +1 -0
  52. package/dist/scanner/static-rules.js +723 -0
  53. package/dist/scanner/static-rules.js.map +1 -0
  54. package/dist/scanner/types.d.ts +177 -0
  55. package/dist/scanner/types.d.ts.map +1 -0
  56. package/dist/scanner/types.js +53 -0
  57. package/dist/scanner/types.js.map +1 -0
  58. package/dist/scheduler/rate-limiter.d.ts +74 -0
  59. package/dist/scheduler/rate-limiter.d.ts.map +1 -0
  60. package/dist/scheduler/rate-limiter.js +182 -0
  61. package/dist/scheduler/rate-limiter.js.map +1 -0
  62. package/dist/scheduler/refresh-scheduler.d.ts +201 -0
  63. package/dist/scheduler/refresh-scheduler.d.ts.map +1 -0
  64. package/dist/scheduler/refresh-scheduler.js +295 -0
  65. package/dist/scheduler/refresh-scheduler.js.map +1 -0
  66. package/dist/store/cache-manager.d.ts +166 -0
  67. package/dist/store/cache-manager.d.ts.map +1 -0
  68. package/dist/store/cache-manager.js +356 -0
  69. package/dist/store/cache-manager.js.map +1 -0
  70. package/dist/store/database.d.ts +81 -0
  71. package/dist/store/database.d.ts.map +1 -0
  72. package/dist/store/database.js +182 -0
  73. package/dist/store/database.js.map +1 -0
  74. package/dist/store/schema.d.ts +42 -0
  75. package/dist/store/schema.d.ts.map +1 -0
  76. package/dist/store/schema.js +126 -0
  77. package/dist/store/schema.js.map +1 -0
  78. package/dist/translator/provider.d.ts +152 -0
  79. package/dist/translator/provider.d.ts.map +1 -0
  80. package/dist/translator/provider.js +159 -0
  81. package/dist/translator/provider.js.map +1 -0
  82. package/dist/translator/types.d.ts +83 -0
  83. package/dist/translator/types.d.ts.map +1 -0
  84. package/dist/translator/types.js +58 -0
  85. package/dist/translator/types.js.map +1 -0
  86. package/package.json +42 -0
@@ -0,0 +1,188 @@
1
+ /**
2
+ * LLM provider configuration persistence and runtime resolution.
3
+ *
4
+ * {@link LlmConfigManager} reads/writes the `~/.npm-safe/llm.json` file. The
5
+ * configuration is optional: when no API key is configured and no supported
6
+ * environment variable is present, LLM scanning is silently disabled and the
7
+ * rest of the engine keeps working normally.
8
+ *
9
+ * API keys are stored in plain text at the configured path. The file is created
10
+ * with `0o600` permissions when possible (best effort on Windows).
11
+ */
12
+ import fs from 'node:fs';
13
+ import os from 'node:os';
14
+ import path from 'node:path';
15
+ import { createLlmProvider, LlmProviderType } from './provider.js';
16
+ const DEFAULT_TIMEOUT_MS = 30_000;
17
+ const DEFAULT_MAX_INPUT_CHARS = 12_000;
18
+ const DEFAULT_MAX_TOKENS = 4096;
19
+ const ENV_KEY_MAP = {
20
+ [LlmProviderType.OpenAi]: 'OPENAI_API_KEY',
21
+ [LlmProviderType.Gemini]: 'GEMINI_API_KEY',
22
+ [LlmProviderType.Anthropic]: 'ANTHROPIC_API_KEY',
23
+ };
24
+ const ENV_BASE_URL_MAP = {
25
+ [LlmProviderType.OpenAi]: 'OPENAI_BASE_URL',
26
+ [LlmProviderType.Gemini]: 'GEMINI_BASE_URL',
27
+ [LlmProviderType.Anthropic]: 'ANTHROPIC_BASE_URL',
28
+ };
29
+ const ENV_MODEL_MAP = {
30
+ [LlmProviderType.OpenAi]: 'OPENAI_MODEL',
31
+ [LlmProviderType.Gemini]: 'GEMINI_MODEL',
32
+ [LlmProviderType.Anthropic]: 'ANTHROPIC_MODEL',
33
+ };
34
+ /** Returns the default path for the LLM configuration file. */
35
+ export function getDefaultLlmConfigPath() {
36
+ return path.join(os.homedir(), '.npm-safe', 'llm.json');
37
+ }
38
+ /** Masks an API key for display: keeps the first 4 and last 4 characters. */
39
+ function maskApiKey(key) {
40
+ if (!key)
41
+ return undefined;
42
+ if (key.length <= 8)
43
+ return '*'.repeat(key.length);
44
+ return `${key.slice(0, 4)}${'*'.repeat(key.length - 8)}${key.slice(-4)}`;
45
+ }
46
+ /**
47
+ * Loads, mutates, and persists LLM provider configuration.
48
+ *
49
+ * Thread-safe per instance; concurrent instances may race on the file, which is
50
+ * acceptable for a single-user desktop tool.
51
+ */
52
+ export class LlmConfigManager {
53
+ filePath;
54
+ config;
55
+ constructor(filePath) {
56
+ this.filePath = filePath ?? getDefaultLlmConfigPath();
57
+ this.config = this.load();
58
+ }
59
+ /** Load (or initialize) the config file. */
60
+ load() {
61
+ try {
62
+ const raw = fs.readFileSync(this.filePath, 'utf8');
63
+ const parsed = JSON.parse(raw);
64
+ return this.normalize(parsed);
65
+ }
66
+ catch {
67
+ return this.normalize({});
68
+ }
69
+ }
70
+ /** Persist the current configuration to disk. */
71
+ save() {
72
+ try {
73
+ fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
74
+ fs.writeFileSync(this.filePath, JSON.stringify(this.config, null, 2));
75
+ try {
76
+ fs.chmodSync(this.filePath, 0o600);
77
+ }
78
+ catch {
79
+ // Ignore platforms/filesystems where chmod is unsupported.
80
+ }
81
+ }
82
+ catch {
83
+ // Best-effort persistence; in-memory config remains valid.
84
+ }
85
+ }
86
+ /** Normalize a partial config into a full config with defaults. */
87
+ normalize(input) {
88
+ const provider = input.provider && Object.values(LlmProviderType).includes(input.provider)
89
+ ? input.provider
90
+ : LlmProviderType.OpenAi;
91
+ return {
92
+ enabled: input.enabled ?? false,
93
+ provider,
94
+ apiKey: input.apiKey,
95
+ baseUrl: input.baseUrl,
96
+ model: input.model,
97
+ timeoutMs: input.timeoutMs ?? DEFAULT_TIMEOUT_MS,
98
+ maxInputChars: input.maxInputChars ?? DEFAULT_MAX_INPUT_CHARS,
99
+ maxTokens: input.maxTokens ?? DEFAULT_MAX_TOKENS,
100
+ };
101
+ }
102
+ /** Returns the current persisted config, including the raw API key. */
103
+ getConfig() {
104
+ return this.config;
105
+ }
106
+ /** Returns a masked status view suitable for display. */
107
+ getStatus() {
108
+ const resolved = this.resolveApiKey();
109
+ return {
110
+ enabled: this.config.enabled,
111
+ provider: this.config.provider,
112
+ configured: !!resolved,
113
+ model: this.resolveModel(),
114
+ baseUrl: this.resolveBaseUrl(),
115
+ apiKey: maskApiKey(resolved),
116
+ maxTokens: this.config.maxTokens,
117
+ maxInputChars: this.config.maxInputChars,
118
+ };
119
+ }
120
+ /** Update the persisted config. */
121
+ setConfig(update) {
122
+ const nextApiKey = update.apiKey !== undefined ? update.apiKey : this.config.apiKey;
123
+ const next = {
124
+ enabled: update.enabled ?? this.config.enabled,
125
+ provider: update.provider && Object.values(LlmProviderType).includes(update.provider)
126
+ ? update.provider
127
+ : this.config.provider,
128
+ apiKey: nextApiKey,
129
+ baseUrl: update.baseUrl !== undefined ? update.baseUrl : this.config.baseUrl,
130
+ model: update.model !== undefined ? update.model : this.config.model,
131
+ timeoutMs: update.timeoutMs ?? this.config.timeoutMs,
132
+ maxInputChars: update.maxInputChars ?? this.config.maxInputChars,
133
+ maxTokens: update.maxTokens ?? this.config.maxTokens,
134
+ };
135
+ this.config = next;
136
+ this.save();
137
+ }
138
+ /**
139
+ * Resolve the effective API key, preferring the persisted config and falling
140
+ * back to a provider-specific environment variable.
141
+ */
142
+ resolveApiKey() {
143
+ if (this.config.apiKey && this.config.apiKey.trim().length > 0) {
144
+ return this.config.apiKey.trim();
145
+ }
146
+ const envKey = ENV_KEY_MAP[this.config.provider];
147
+ return process.env[envKey]?.trim() || undefined;
148
+ }
149
+ /** Resolve the effective base URL. */
150
+ resolveBaseUrl() {
151
+ return this.config.baseUrl?.trim() || process.env[ENV_BASE_URL_MAP[this.config.provider]]?.trim() || undefined;
152
+ }
153
+ /** Resolve the effective model. */
154
+ resolveModel() {
155
+ return this.config.model?.trim() || process.env[ENV_MODEL_MAP[this.config.provider]]?.trim() || undefined;
156
+ }
157
+ /**
158
+ * Create a configured {@link LlmScanProvider} if LLM scanning is enabled and
159
+ * an API key is available; otherwise return `undefined`.
160
+ */
161
+ createProvider() {
162
+ const apiKey = this.resolveApiKey();
163
+ if (!this.config.enabled || !apiKey)
164
+ return undefined;
165
+ const options = {
166
+ provider: this.config.provider,
167
+ apiKey,
168
+ baseUrl: this.resolveBaseUrl(),
169
+ model: this.resolveModel(),
170
+ timeoutMs: this.config.timeoutMs,
171
+ maxInputChars: this.config.maxInputChars,
172
+ maxTokens: this.config.maxTokens,
173
+ };
174
+ return createLlmProvider(options);
175
+ }
176
+ /**
177
+ * Test whether the current configuration can connect to the provider.
178
+ *
179
+ * Returns `false` when the provider is not configured or disabled.
180
+ */
181
+ async testConnection() {
182
+ const provider = this.createProvider();
183
+ if (!provider)
184
+ return false;
185
+ return provider.testConnection();
186
+ }
187
+ }
188
+ //# sourceMappingURL=llm-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-config.js","sourceRoot":"","sources":["../../src/llm/llm-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Shared parse/validation helpers for LLM scan providers.
3
+ *
4
+ * This module extracts the JSON-parsing, finding-validation, and report-
5
+ * assembly helpers that are common to every OpenAI-compatible LLM provider
6
+ * (OpenAI, Gemini, Anthropic, …) so each provider can reuse them instead of
7
+ * duplicating logic.
8
+ */
9
+ import { FindingCategory, Severity, type LlmScanReport, type ScanFinding } from "../scanner/types.js";
10
+ /**
11
+ * Error thrown when an LLM provider request or response is invalid.
12
+ */
13
+ export declare class LlmProviderError extends Error {
14
+ readonly statusCode?: number | undefined;
15
+ constructor(message: string, statusCode?: number | undefined);
16
+ }
17
+ /**
18
+ * System prompt instructing the model to act as an npm package security
19
+ * analyst and return a JSON object with a fixed shape.
20
+ */
21
+ export declare const SYSTEM_PROMPT = "You are an npm package security analyst. Analyze the supplied package metadata and README for semantic risks that static rules may miss. Return only a JSON object with this exact shape:\n{\"summary\":\"string\",\"functionalMatch\":true,\"suspiciousScore\":0,\"findings\":[{\"ruleId\":\"llm-...\",\"ruleName\":\"string\",\"severity\":\"low|medium|high|critical\",\"message\":\"string\",\"recommendation\":\"string\",\"category\":\"informational|known-malicious|suspicious-dependency|sensitive-exposure|code-obfuscation|binary-download|install-script|typosquatting|homograph-attack|registry-mismatch\"}]}\nsuspiciousScore is 0-100, where higher means more suspicious. Do not invent evidence that is not present in the input. Use an empty findings array when no concern is found.";
22
+ /**
23
+ * Parse a raw LLM response string into a JSON object.
24
+ *
25
+ * Strips ```json fences, parses the content, and rejects non-object values
26
+ * (arrays, primitives, or invalid JSON) by throwing {@link LlmProviderError}.
27
+ *
28
+ * @param content - Raw text returned by the LLM.
29
+ * @returns The parsed JSON object.
30
+ * @throws {LlmProviderError} When the content is not a valid JSON object.
31
+ */
32
+ export declare function parseJsonObject(content: string): Record<string, unknown>;
33
+ /**
34
+ * Parse an unknown value into a list of validated scan findings.
35
+ *
36
+ * Non-array inputs yield an empty array. Items that are not objects or that
37
+ * lack a `message` field are dropped. Each surviving item is mapped to a
38
+ * {@link ScanFinding} with normalized severity and category.
39
+ *
40
+ * @param value - The `findings` field of a parsed LLM response.
41
+ * @returns A readonly array of validated findings.
42
+ */
43
+ export declare function parseFindings(value: unknown): readonly ScanFinding[];
44
+ /**
45
+ * Coerce an unknown value into a {@link Severity}, defaulting to Medium.
46
+ *
47
+ * @param value - The `severity` field of a finding.
48
+ * @returns The validated severity, or `Severity.Medium` if invalid.
49
+ */
50
+ export declare function readSeverity(value: unknown): Severity;
51
+ /**
52
+ * Coerce an unknown value into a {@link FindingCategory}, defaulting to
53
+ * Informational.
54
+ *
55
+ * @param value - The `category` field of a finding.
56
+ * @returns The validated category, or `FindingCategory.Informational` if invalid.
57
+ */
58
+ export declare function readCategory(value: unknown): FindingCategory;
59
+ /**
60
+ * Return the value if it is a string, otherwise `undefined`.
61
+ *
62
+ * @param value - An arbitrary unknown value.
63
+ * @returns The string value, or `undefined`.
64
+ */
65
+ export declare function readOptionalString(value: unknown): string | undefined;
66
+ /**
67
+ * Return the value if it is a boolean, otherwise `undefined`.
68
+ *
69
+ * @param value - An arbitrary unknown value.
70
+ * @returns The boolean value, or `undefined`.
71
+ */
72
+ export declare function readOptionalBoolean(value: unknown): boolean | undefined;
73
+ /**
74
+ * Return the value if it is a finite number, otherwise `undefined`.
75
+ *
76
+ * @param value - An arbitrary unknown value.
77
+ * @returns The finite number, or `undefined`.
78
+ */
79
+ export declare function readOptionalNumber(value: unknown): number | undefined;
80
+ /**
81
+ * Clamp a numeric score to the 0-100 range, rounding to the nearest integer.
82
+ *
83
+ * @param value - The raw numeric score.
84
+ * @returns The clamped integer score between 0 and 100.
85
+ */
86
+ export declare function clampScore(value: number): number;
87
+ /**
88
+ * Assemble the final {@link LlmScanReport} from a parsed LLM JSON object.
89
+ *
90
+ * @param parsed - The JSON object returned by {@link parseJsonObject}.
91
+ * @param scannedAt - ISO 8601 timestamp marking when the scan ran.
92
+ * @returns A populated LLM scan report with `enabled: true`.
93
+ */
94
+ export declare function buildReport(parsed: Record<string, unknown>, scannedAt: string): LlmScanReport;
95
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/llm/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,eAAe,EACf,QAAQ,EACR,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;aACI,UAAU,CAAC,EAAE,MAAM;gBAApD,OAAO,EAAE,MAAM,EAAkB,UAAU,CAAC,EAAE,MAAM,YAAA;CAIjE;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,6wBAEmJ,CAAC;AAE9K;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAaxE;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,WAAW,EAAE,CAgBpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAKrD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAI5D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAErE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAErE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,SAAS,EAAE,MAAM,GAChB,aAAa,CASf"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Shared parse/validation helpers for LLM scan providers.
3
+ *
4
+ * This module extracts the JSON-parsing, finding-validation, and report-
5
+ * assembly helpers that are common to every OpenAI-compatible LLM provider
6
+ * (OpenAI, Gemini, Anthropic, …) so each provider can reuse them instead of
7
+ * duplicating logic.
8
+ */
9
+ import { FindingCategory, Severity, } from "../scanner/types.js";
10
+ /**
11
+ * Error thrown when an LLM provider request or response is invalid.
12
+ */
13
+ export class LlmProviderError extends Error {
14
+ statusCode;
15
+ constructor(message, statusCode) {
16
+ super(message);
17
+ this.statusCode = statusCode;
18
+ this.name = "LlmProviderError";
19
+ }
20
+ }
21
+ /**
22
+ * System prompt instructing the model to act as an npm package security
23
+ * analyst and return a JSON object with a fixed shape.
24
+ */
25
+ export const SYSTEM_PROMPT = `You are an npm package security analyst. Analyze the supplied package metadata and README for semantic risks that static rules may miss. Return only a JSON object with this exact shape:
26
+ {"summary":"string","functionalMatch":true,"suspiciousScore":0,"findings":[{"ruleId":"llm-...","ruleName":"string","severity":"low|medium|high|critical","message":"string","recommendation":"string","category":"informational|known-malicious|suspicious-dependency|sensitive-exposure|code-obfuscation|binary-download|install-script|typosquatting|homograph-attack|registry-mismatch"}]}
27
+ suspiciousScore is 0-100, where higher means more suspicious. Do not invent evidence that is not present in the input. Use an empty findings array when no concern is found.`;
28
+ /**
29
+ * Parse a raw LLM response string into a JSON object.
30
+ *
31
+ * Strips ```json fences, parses the content, and rejects non-object values
32
+ * (arrays, primitives, or invalid JSON) by throwing {@link LlmProviderError}.
33
+ *
34
+ * @param content - Raw text returned by the LLM.
35
+ * @returns The parsed JSON object.
36
+ * @throws {LlmProviderError} When the content is not a valid JSON object.
37
+ */
38
+ export function parseJsonObject(content) {
39
+ const normalized = content.trim().replace(/^```json\s*/i, "").replace(/```$/, "").trim();
40
+ try {
41
+ const parsed = JSON.parse(normalized);
42
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
43
+ throw new Error("expected a JSON object");
44
+ }
45
+ return parsed;
46
+ }
47
+ catch (error) {
48
+ throw new LlmProviderError(`LLM returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`);
49
+ }
50
+ }
51
+ /**
52
+ * Parse an unknown value into a list of validated scan findings.
53
+ *
54
+ * Non-array inputs yield an empty array. Items that are not objects or that
55
+ * lack a `message` field are dropped. Each surviving item is mapped to a
56
+ * {@link ScanFinding} with normalized severity and category.
57
+ *
58
+ * @param value - The `findings` field of a parsed LLM response.
59
+ * @returns A readonly array of validated findings.
60
+ */
61
+ export function parseFindings(value) {
62
+ if (!Array.isArray(value))
63
+ return [];
64
+ return value.flatMap((item, index) => {
65
+ if (!item || typeof item !== "object")
66
+ return [];
67
+ const finding = item;
68
+ const message = readOptionalString(finding.message);
69
+ if (!message)
70
+ return [];
71
+ return [{
72
+ ruleId: readOptionalString(finding.ruleId) ?? `llm-finding-${index + 1}`,
73
+ ruleName: readOptionalString(finding.ruleName) ?? "LLM security finding",
74
+ severity: readSeverity(finding.severity),
75
+ message,
76
+ recommendation: readOptionalString(finding.recommendation),
77
+ category: readCategory(finding.category),
78
+ }];
79
+ });
80
+ }
81
+ /**
82
+ * Coerce an unknown value into a {@link Severity}, defaulting to Medium.
83
+ *
84
+ * @param value - The `severity` field of a finding.
85
+ * @returns The validated severity, or `Severity.Medium` if invalid.
86
+ */
87
+ export function readSeverity(value) {
88
+ return value === Severity.Critical || value === Severity.High ||
89
+ value === Severity.Medium || value === Severity.Low
90
+ ? value
91
+ : Severity.Medium;
92
+ }
93
+ /**
94
+ * Coerce an unknown value into a {@link FindingCategory}, defaulting to
95
+ * Informational.
96
+ *
97
+ * @param value - The `category` field of a finding.
98
+ * @returns The validated category, or `FindingCategory.Informational` if invalid.
99
+ */
100
+ export function readCategory(value) {
101
+ return Object.values(FindingCategory).includes(value)
102
+ ? value
103
+ : FindingCategory.Informational;
104
+ }
105
+ /**
106
+ * Return the value if it is a string, otherwise `undefined`.
107
+ *
108
+ * @param value - An arbitrary unknown value.
109
+ * @returns The string value, or `undefined`.
110
+ */
111
+ export function readOptionalString(value) {
112
+ return typeof value === "string" ? value : undefined;
113
+ }
114
+ /**
115
+ * Return the value if it is a boolean, otherwise `undefined`.
116
+ *
117
+ * @param value - An arbitrary unknown value.
118
+ * @returns The boolean value, or `undefined`.
119
+ */
120
+ export function readOptionalBoolean(value) {
121
+ return typeof value === "boolean" ? value : undefined;
122
+ }
123
+ /**
124
+ * Return the value if it is a finite number, otherwise `undefined`.
125
+ *
126
+ * @param value - An arbitrary unknown value.
127
+ * @returns The finite number, or `undefined`.
128
+ */
129
+ export function readOptionalNumber(value) {
130
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
131
+ }
132
+ /**
133
+ * Clamp a numeric score to the 0-100 range, rounding to the nearest integer.
134
+ *
135
+ * @param value - The raw numeric score.
136
+ * @returns The clamped integer score between 0 and 100.
137
+ */
138
+ export function clampScore(value) {
139
+ return Math.max(0, Math.min(100, Math.round(value)));
140
+ }
141
+ /**
142
+ * Assemble the final {@link LlmScanReport} from a parsed LLM JSON object.
143
+ *
144
+ * @param parsed - The JSON object returned by {@link parseJsonObject}.
145
+ * @param scannedAt - ISO 8601 timestamp marking when the scan ran.
146
+ * @returns A populated LLM scan report with `enabled: true`.
147
+ */
148
+ export function buildReport(parsed, scannedAt) {
149
+ return {
150
+ enabled: true,
151
+ summary: readOptionalString(parsed.summary),
152
+ functionalMatch: readOptionalBoolean(parsed.functionalMatch),
153
+ suspiciousScore: clampScore(readOptionalNumber(parsed.suspiciousScore) ?? 0),
154
+ findings: parseFindings(parsed.findings),
155
+ scannedAt,
156
+ };
157
+ }
158
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/llm/parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Multi-provider LLM scan core.
3
+ *
4
+ * This module hosts the unified {@link LlmProviderOptions} interface, the
5
+ * {@link LlmProviderType} enum, and the {@link createLlmProvider} factory
6
+ * that dispatches to a concrete provider implementation. The OpenAI-
7
+ * compatible provider ({@link OpenAICompatibleLlmProvider}) lives here as
8
+ * the reference implementation; Gemini and Anthropic providers live in
9
+ * sibling modules and are wired up through the factory.
10
+ *
11
+ * Shared parsing/validation helpers and the {@link LlmProviderError} class
12
+ * are imported from {@link ./parse.js} so every provider reuses the same
13
+ * logic instead of duplicating it.
14
+ */
15
+ import type { LlmScanReport } from "../scanner/types.js";
16
+ export { LlmProviderError } from "./parse.js";
17
+ export { GeminiLlmProvider } from "./gemini.js";
18
+ export { AnthropicLlmProvider } from "./anthropic.js";
19
+ /**
20
+ * Input passed to an LLM scan provider.
21
+ */
22
+ export interface LlmScanInput {
23
+ readonly packageName: string;
24
+ readonly version: string;
25
+ readonly description: string;
26
+ readonly readme: string;
27
+ readonly packageJson?: Record<string, unknown>;
28
+ /**
29
+ * Optional external abort signal. When supplied, the provider combines it
30
+ * with its own timeout controller via `AbortSignal.any` so an abort during
31
+ * an in-flight scan settles the promise promptly with an `AbortError`
32
+ * `DOMException` (cooperative cancellation).
33
+ */
34
+ readonly signal?: AbortSignal;
35
+ }
36
+ /**
37
+ * Contract every LLM scan provider implements.
38
+ */
39
+ export interface LlmScanProvider {
40
+ scan(input: LlmScanInput): Promise<LlmScanReport>;
41
+ testConnection(): Promise<boolean>;
42
+ }
43
+ /**
44
+ * Supported LLM provider backends.
45
+ */
46
+ export declare enum LlmProviderType {
47
+ OpenAi = "openai",
48
+ Gemini = "gemini",
49
+ Anthropic = "anthropic"
50
+ }
51
+ /**
52
+ * Unified options accepted by {@link createLlmProvider} and every concrete
53
+ * provider constructor. Fields not relevant to a given backend are ignored
54
+ * by that backend.
55
+ */
56
+ export interface LlmProviderOptions {
57
+ /** Backend to instantiate. @default {@link LlmProviderType.OpenAi} */
58
+ readonly provider?: LlmProviderType;
59
+ /** API key. Falls back to a backend-specific env var when omitted. */
60
+ readonly apiKey?: string;
61
+ /** Base URL of the LLM API endpoint. */
62
+ readonly baseUrl?: string;
63
+ /** Model identifier to use for completions. */
64
+ readonly model?: string;
65
+ /** Request timeout in milliseconds. @default 30000 */
66
+ readonly timeoutMs?: number;
67
+ /** Maximum README characters to send to the model. @default 12000 */
68
+ readonly maxInputChars?: number;
69
+ /** Maximum response tokens. @default 4096 */
70
+ readonly maxTokens?: number;
71
+ }
72
+ /**
73
+ * Deprecated alias for {@link LlmProviderOptions}.
74
+ * @deprecated Use {@link LlmProviderOptions} instead.
75
+ */
76
+ export type OpenAICompatibleLlmOptions = LlmProviderOptions;
77
+ /**
78
+ * Construct an {@link LlmScanProvider} for the backend selected via
79
+ * {@link LlmProviderOptions.provider}. Defaults to the OpenAI-compatible
80
+ * provider.
81
+ *
82
+ * @param options - Provider configuration. When omitted, an OpenAI-
83
+ * compatible provider is constructed with environment-derived defaults.
84
+ * @returns A concrete {@link LlmScanProvider} instance.
85
+ */
86
+ export declare function createLlmProvider(options?: LlmProviderOptions): LlmScanProvider;
87
+ /**
88
+ * OpenAI-compatible chat completions LLM scan provider.
89
+ *
90
+ * Talks to any endpoint that implements the `/chat/completions` surface
91
+ * (OpenAI, Azure OpenAI, local LM Studio / Ollama OpenAI shims, etc.).
92
+ */
93
+ export declare class OpenAICompatibleLlmProvider implements LlmScanProvider {
94
+ private readonly apiKey?;
95
+ private readonly baseUrl;
96
+ private readonly model;
97
+ private readonly timeoutMs;
98
+ private readonly maxInputChars;
99
+ private readonly maxTokens;
100
+ /**
101
+ * @param options - Provider configuration. Env-var fallbacks:
102
+ * `apiKey` defaults to `process.env.OPENAI_API_KEY`.
103
+ */
104
+ constructor(options?: LlmProviderOptions);
105
+ /** @inheritdoc */
106
+ scan(input: LlmScanInput): Promise<LlmScanReport>;
107
+ /** @inheritdoc */
108
+ testConnection(): Promise<boolean>;
109
+ /**
110
+ * Issue a POST to `/chat/completions` with timeout and error normalization.
111
+ *
112
+ * @param body - The JSON request body.
113
+ * @param signal - Optional external abort signal combined with the owned
114
+ * timeout controller via `AbortSignal.any`. An external abort propagates
115
+ * as `DOMException('The operation was aborted.', 'AbortError')`.
116
+ * @returns The `choices[0].message.content` string from the response.
117
+ * @throws {LlmProviderError} On network, timeout, HTTP, or shape errors.
118
+ * @throws {DOMException} With name `AbortError` when `signal` is aborted.
119
+ */
120
+ private request;
121
+ }
122
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/llm/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAazD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/C;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAClD,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,oBAAY,eAAe;IACzB,MAAM,WAAW;IACjB,MAAM,WAAW;IACjB,SAAS,cAAc;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;IACpC,sEAAsE;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,wCAAwC;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,6CAA6C;IAC7C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,MAAM,0BAA0B,GAAG,kBAAkB,CAAC;AAQ5D;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,eAAe,CAS/E;AAED;;;;;GAKG;AACH,qBAAa,2BAA4B,YAAW,eAAe;IACjE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC;;;OAGG;gBACS,OAAO,GAAE,kBAAuB;IAS5C,kBAAkB;IACZ,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAoCvD,kBAAkB;IACZ,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAUxC;;;;;;;;;;OAUG;YACW,OAAO;CAoDtB"}