sadrazam 0.1.0-alpha.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/LICENSE +21 -0
  3. package/README.md +343 -0
  4. package/dist/aiClient.d.ts +4 -0
  5. package/dist/aiClient.d.ts.map +1 -0
  6. package/dist/aiClient.js +152 -0
  7. package/dist/aiClient.js.map +1 -0
  8. package/dist/aiConfig.d.ts +19 -0
  9. package/dist/aiConfig.d.ts.map +1 -0
  10. package/dist/aiConfig.js +28 -0
  11. package/dist/aiConfig.js.map +1 -0
  12. package/dist/config.d.ts +26 -0
  13. package/dist/config.d.ts.map +1 -0
  14. package/dist/config.js +32 -0
  15. package/dist/config.js.map +1 -0
  16. package/dist/fileFinder.d.ts +2 -0
  17. package/dist/fileFinder.d.ts.map +1 -0
  18. package/dist/fileFinder.js +14 -0
  19. package/dist/fileFinder.js.map +1 -0
  20. package/dist/findings.d.ts +13 -0
  21. package/dist/findings.d.ts.map +1 -0
  22. package/dist/findings.js +52 -0
  23. package/dist/findings.js.map +1 -0
  24. package/dist/importParser.d.ts +6 -0
  25. package/dist/importParser.d.ts.map +1 -0
  26. package/dist/importParser.js +36 -0
  27. package/dist/importParser.js.map +1 -0
  28. package/dist/index.d.ts +3 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +185 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/packageReader.d.ts +14 -0
  33. package/dist/packageReader.d.ts.map +1 -0
  34. package/dist/packageReader.js +51 -0
  35. package/dist/packageReader.js.map +1 -0
  36. package/dist/reporters.d.ts +42 -0
  37. package/dist/reporters.d.ts.map +1 -0
  38. package/dist/reporters.js +138 -0
  39. package/dist/reporters.js.map +1 -0
  40. package/dist/scan.d.ts +25 -0
  41. package/dist/scan.d.ts.map +1 -0
  42. package/dist/scan.js +152 -0
  43. package/dist/scan.js.map +1 -0
  44. package/dist/scriptParser.d.ts +7 -0
  45. package/dist/scriptParser.d.ts.map +1 -0
  46. package/dist/scriptParser.js +117 -0
  47. package/dist/scriptParser.js.map +1 -0
  48. package/dist/sourceMapper.d.ts +2 -0
  49. package/dist/sourceMapper.d.ts.map +1 -0
  50. package/dist/sourceMapper.js +57 -0
  51. package/dist/sourceMapper.js.map +1 -0
  52. package/dist/workspaceFinder.d.ts +11 -0
  53. package/dist/workspaceFinder.d.ts.map +1 -0
  54. package/dist/workspaceFinder.js +62 -0
  55. package/dist/workspaceFinder.js.map +1 -0
  56. package/package.json +53 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,62 @@
1
+ # CHANGELOG
2
+
3
+ ## Unreleased
4
+
5
+ ### Added
6
+ - Repository contribution and release rules in `AGENTS.md`
7
+
8
+ ## v0.1.0-alpha.6
9
+
10
+ ### Changed
11
+ - Switched the npm package name from `vezir` to `sadrazam` for publish testing
12
+
13
+ ## v0.1.0-alpha.5
14
+
15
+ ### Changed
16
+ - Switched the npm package name from `mizan` to `vezir` for publish testing
17
+
18
+ ## v0.1.0-alpha.4
19
+
20
+ ### Changed
21
+ - Switched the npm package name from `kantar` to `mizan` for publish testing
22
+
23
+ ## v0.1.0-alpha.3
24
+
25
+ ### Changed
26
+ - Switched the npm package name from `sarraf` to `kantar` for publish testing
27
+
28
+ ## v0.1.0-alpha.2
29
+
30
+ ### Added
31
+ - GitHub Actions workflows for docs validation and tagged npm publishing
32
+ - Vitest-based test runner setup
33
+ - MIT license file and package publish metadata cleanup
34
+
35
+ ### Changed
36
+ - Limited published package contents to production artifacts and top-level docs
37
+ - Strengthened alpha release preparation flow for automated npm publishing
38
+
39
+ ### Fixed
40
+ - Removed accidental token-like content from the publish workflow before release
41
+
42
+ ## v0.1.0-alpha.1
43
+
44
+ ### Added
45
+ - Workspace-aware scanning and workspace filtering
46
+ - Text and JSON reporters
47
+ - Script parser support for `package.json` scripts
48
+ - Dependency trace output
49
+ - Source mapping from build output back to source files
50
+ - Config loading from `sarraf.json` and `package.json#sarraf`
51
+ - Ignore and allowlist controls for findings
52
+ - AI-powered dependency summaries for OpenAI, Anthropic, and Gemini
53
+ - Fixture tests and smoke test scenarios
54
+
55
+ ### Changed
56
+ - Improved CLI help output and quick-start documentation
57
+ - Hardened CommonJS and hybrid import parsing
58
+ - Added debug visibility for config source and active rule filters
59
+
60
+ ### Fixed
61
+ - AI failures no longer break the main dependency scan report
62
+ - Script-based package usage now reduces false positives for unused tooling packages
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bora Kilicoglu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,343 @@
1
+ <p align="center">
2
+ <img src="./assets/logo.svg" alt="Sarraf logo" width="200" />
3
+ </p>
4
+
5
+ Sarraf is a dependency analysis CLI for JavaScript and TypeScript projects with optional AI-powered insights.
6
+
7
+ Sarraf scans your dependencies like a jeweler inspects gold. It finds unused packages, flags dependency hygiene issues, and, when you provide an AI token, can explain findings and suggest cleanup actions directly in the CLI.
8
+
9
+ Current status:
10
+
11
+ - unused `dependencies` and `devDependencies`
12
+ - script-aware dependency detection
13
+ - workspace and monorepo-aware scanning
14
+ - text and JSON reporters
15
+ - package usage tracing
16
+ - source mapping from build output back to source files
17
+ - production and strict scan modes
18
+ - config file support via `sarraf.json` or `package.json#sarraf`
19
+ - ignore and allowlist controls for findings
20
+ - AI summaries via `openai`, `anthropic`, or `gemini`
21
+
22
+ ## Why Sarraf?
23
+
24
+ JavaScript projects accumulate packages over time. Some stop being used. Some belong in `devDependencies` but end up in `dependencies`. Some become outdated, deprecated, or risky.
25
+
26
+ Sarraf exists to answer a simple question:
27
+
28
+ Which packages in this project are actually needed, and which ones are adding weight or risk?
29
+
30
+ Sarraf's direction is:
31
+
32
+ - cover the core dependency analysis workflow teams expect from a modern dependency scanner
33
+ - add an optional AI layer for interpretation, prioritization, and remediation suggestions
34
+ - keep the base scanner useful even when no token is provided
35
+
36
+ ## What Sarraf Does
37
+
38
+ Sarraf analyzes a project by reading its manifest and source files, then comparing declared dependencies with actual usage.
39
+
40
+ Without AI:
41
+
42
+ - scans the project
43
+ - resolves imported packages
44
+ - reports unused or suspicious dependencies
45
+
46
+ With AI token provided:
47
+
48
+ - explains why a dependency looks unused or risky
49
+ - suggests whether it should be removed, moved, or reviewed
50
+ - helps turn raw analysis into actionable cleanup decisions
51
+
52
+ Current focus:
53
+
54
+ - read `package.json`
55
+ - scan `js`, `ts`, `jsx`, `tsx`, `mjs`, `cjs`, `mts`, `cts` files
56
+ - extract package usage from `import`, `export ... from`, `import = require`, `require`, and `require.resolve`
57
+ - include package usage referenced from `package.json` scripts
58
+ - report unused and suspicious dependency declarations
59
+
60
+ ## MVP Scope
61
+
62
+ The first version is intentionally narrow.
63
+
64
+ Included in v1:
65
+
66
+ - package manifest analysis
67
+ - source scan for dependency usage
68
+ - unused `dependencies` detection
69
+ - unused `devDependencies` detection
70
+ - script parser support
71
+ - workspace-aware scanning
72
+ - trace output for package usage
73
+ - source mapping for build output
74
+ - reporter support for `text` and `json`
75
+ - `production` and `strict` scan modes
76
+ - config support
77
+ - ignore and allowlist support
78
+ - optional AI summaries in the CLI when a valid token is configured
79
+
80
+ Planned after MVP:
81
+
82
+ - deeper wrong dependency placement detection
83
+ - deprecated package checks
84
+ - basic dependency risk score
85
+ - CI-friendly output and exit codes
86
+ - richer AI remediation suggestions
87
+
88
+ ## Install
89
+
90
+ Local development:
91
+
92
+ ```bash
93
+ npm install
94
+ ```
95
+
96
+ When published as an npm package:
97
+
98
+ ```bash
99
+ npm install -g sarraf
100
+ ```
101
+
102
+ or run it without a global install:
103
+
104
+ ```bash
105
+ npx sarraf .
106
+ ```
107
+
108
+ ## Quick Start
109
+
110
+ ```bash
111
+ npx sarraf .
112
+ npx sarraf . --reporter json
113
+ npx sarraf . --trace typescript
114
+ AI_PROVIDER=openai AI_TOKEN=your_token npx sarraf . --ai
115
+ ```
116
+
117
+ ## Usage
118
+
119
+ Common scenarios:
120
+
121
+ - scan a single package
122
+ - scan one workspace inside a monorepo
123
+ - export findings as JSON
124
+ - trace why a package is treated as used
125
+ - run in production or strict mode
126
+ - enrich the report with AI summaries
127
+
128
+ Scan the current project:
129
+
130
+ ```bash
131
+ npx sarraf .
132
+ ```
133
+
134
+ Scan a specific directory:
135
+
136
+ ```bash
137
+ npx sarraf ./packages/web
138
+ ```
139
+
140
+ Scan a single workspace in a monorepo:
141
+
142
+ ```bash
143
+ npx sarraf . --workspace packages/web
144
+ ```
145
+
146
+ Get JSON output:
147
+
148
+ ```bash
149
+ npx sarraf . --reporter json
150
+ ```
151
+
152
+ Trace why a package is considered used:
153
+
154
+ ```bash
155
+ npx sarraf . --trace typescript
156
+ ```
157
+
158
+ Production-only scan:
159
+
160
+ ```bash
161
+ npx sarraf . --production
162
+ ```
163
+
164
+ Strict mode:
165
+
166
+ ```bash
167
+ npx sarraf . --strict
168
+ ```
169
+
170
+ Ignore or allow specific findings from the CLI:
171
+
172
+ ```bash
173
+ npx sarraf . --ignore-packages react
174
+ npx sarraf . --allow-unused-dev-dependencies typescript
175
+ ```
176
+
177
+ For local development in this repository:
178
+
179
+ ```bash
180
+ npm run dev
181
+ npm run build
182
+ npm run typecheck
183
+ node dist/index.js .
184
+ ```
185
+
186
+ Useful local examples:
187
+
188
+ ```bash
189
+ node dist/index.js . --debug
190
+ node dist/index.js . --exclude unused-devDependencies
191
+ node dist/index.js . --reporter json --trace commander
192
+ node dist/index.js . --ignore-packages react --allow-unused-dev-dependencies typescript
193
+ ```
194
+
195
+ ## Config
196
+
197
+ Sarraf can load config from either:
198
+
199
+ - `sarraf.json`
200
+ - `package.json` under the `sarraf` key
201
+
202
+ Example `sarraf.json`:
203
+
204
+ ```json
205
+ {
206
+ "reporter": "json",
207
+ "production": false,
208
+ "strict": false,
209
+ "exclude": ["missing"],
210
+ "ignorePackages": ["react"],
211
+ "allowUnusedDependencies": [],
212
+ "allowUnusedDevDependencies": ["typescript"],
213
+ "allowMissingPackages": [],
214
+ "allowMisplacedDevDependencies": [],
215
+ "workspace": ["packages/web"],
216
+ "ai": {
217
+ "provider": "openai",
218
+ "model": "gpt-4.1"
219
+ }
220
+ }
221
+ ```
222
+
223
+ CLI flags take precedence over config values.
224
+
225
+ ## Exit Codes
226
+
227
+ Sarraf uses these exit codes:
228
+
229
+ - `0`: scan completed and no findings were reported
230
+ - `1`: execution error, invalid configuration, or unrecoverable runtime failure
231
+ - `2`: scan completed and findings were reported
232
+
233
+ ## Ignore And Allowlist
234
+
235
+ Use these when a finding is intentionally acceptable:
236
+
237
+ - `ignorePackages`
238
+ - `allowUnusedDependencies`
239
+ - `allowUnusedDevDependencies`
240
+ - `allowMissingPackages`
241
+ - `allowMisplacedDevDependencies`
242
+
243
+ ## AI Mode
244
+
245
+ Sarraf works in two modes:
246
+
247
+ - standard analysis mode with no token required
248
+ - AI-assisted mode when the user provides an API token
249
+
250
+ The base CLI remains useful without AI. AI is an upgrade layer, not a requirement.
251
+
252
+ Environment variables:
253
+
254
+ ```bash
255
+ AI_PROVIDER=openai
256
+ AI_TOKEN=your_token
257
+ AI_MODEL=gpt-4.1
258
+ ```
259
+
260
+ Current provider values:
261
+
262
+ - `openai`
263
+ - `anthropic`
264
+ - `gemini`
265
+
266
+ Examples:
267
+
268
+ ```bash
269
+ AI_PROVIDER=openai AI_TOKEN=your_token npx sarraf . --ai
270
+ AI_PROVIDER=anthropic AI_TOKEN=your_token npx sarraf . --ai
271
+ AI_PROVIDER=gemini AI_TOKEN=your_token npx sarraf . --ai
272
+ ```
273
+
274
+ CLI overrides:
275
+
276
+ ```bash
277
+ npx sarraf . --ai --provider openai --model gpt-4.1
278
+ ```
279
+
280
+ What AI currently does:
281
+
282
+ - summarizes findings
283
+ - prioritizes the most important cleanup actions
284
+ - turns raw scan output into a short remediation note
285
+
286
+ What AI does not yet do:
287
+
288
+ - automatic fixes
289
+ - package reputation or security scoring
290
+ - multi-step remediation planning
291
+ - guaranteed deterministic recommendations across providers
292
+
293
+ ## Testing
294
+
295
+ Local verification includes fixture-based tests for:
296
+
297
+ - config loading
298
+ - ignore and allowlist behavior
299
+ - AI response parsing
300
+ - AI auth error handling
301
+
302
+ Run:
303
+
304
+ ```bash
305
+ npm test
306
+ ```
307
+
308
+ Smoke scenarios:
309
+
310
+ ```bash
311
+ npm run smoke
312
+ ```
313
+
314
+ This runs repeatable checks for:
315
+
316
+ - single-package config-driven repo
317
+ - CommonJS repo
318
+ - monorepo with multiple workspaces
319
+
320
+ ## Known Limitations
321
+
322
+ - AI summaries depend on third-party provider behavior and network availability
323
+ - source mapping uses source maps first and path heuristics second
324
+ - misplaced dependency detection is intentionally conservative
325
+ - dependency analysis is strongest for standard JS/TS project layouts
326
+
327
+ ## Product Vision
328
+
329
+ Sarraf aims to become a practical dependency audit tool for everyday JavaScript teams.
330
+
331
+ Not a full software composition analysis platform.
332
+ Not a vulnerability database replacement.
333
+
334
+ The goal is simpler and more useful in daily work:
335
+
336
+ - show what is unused
337
+ - reveal what looks suspicious
338
+ - explain findings in plain language when AI is enabled
339
+ - make dependency decisions easier during development and in CI
340
+
341
+ ## One-Line Pitch
342
+
343
+ Sarraf is a CLI that finds unnecessary and risky npm packages, then goes further with optional AI-powered explanations and cleanup guidance.
@@ -0,0 +1,4 @@
1
+ import type { AiConfig } from "./aiConfig.js";
2
+ import type { ReportWorkspace } from "./reporters.js";
3
+ export declare function generateAiSummary(config: AiConfig, workspaces: ReportWorkspace[]): Promise<string>;
4
+ //# sourceMappingURL=aiClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiClient.d.ts","sourceRoot":"","sources":["../src/aiClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,QAAQ,EAChB,UAAU,EAAE,eAAe,EAAE,GAC5B,OAAO,CAAC,MAAM,CAAC,CAYjB"}
@@ -0,0 +1,152 @@
1
+ export async function generateAiSummary(config, workspaces) {
2
+ const prompt = buildPrompt(workspaces);
3
+ if (config.provider === "openai") {
4
+ return callOpenAI(config, prompt);
5
+ }
6
+ if (config.provider === "anthropic") {
7
+ return callAnthropic(config, prompt);
8
+ }
9
+ return callGemini(config, prompt);
10
+ }
11
+ function buildPrompt(workspaces) {
12
+ const payload = {
13
+ workspaces: workspaces.map(({ workspace, findings, result }) => ({
14
+ workspace: workspace.name,
15
+ relativeDir: workspace.relativeDir,
16
+ findings: findings.map((finding) => ({
17
+ type: finding.type,
18
+ items: finding.items,
19
+ })),
20
+ externalImports: result.externalImports,
21
+ traces: result.packageTraces,
22
+ })),
23
+ };
24
+ return [
25
+ "You are Sarraf AI, a dependency analysis assistant.",
26
+ "Summarize the most important dependency hygiene issues.",
27
+ "Keep the answer short, actionable, and grouped by priority.",
28
+ "If there are no findings, say that clearly.",
29
+ JSON.stringify(payload),
30
+ ].join("\n\n");
31
+ }
32
+ async function callOpenAI(config, prompt) {
33
+ const response = await requestJson("openai", "https://api.openai.com/v1/responses", {
34
+ method: "POST",
35
+ headers: {
36
+ Authorization: `Bearer ${config.token}`,
37
+ "Content-Type": "application/json",
38
+ },
39
+ body: JSON.stringify({
40
+ model: config.model ?? "gpt-4.1",
41
+ input: prompt,
42
+ }),
43
+ });
44
+ return parseOpenAIResponse(await parseJsonResponse(response));
45
+ }
46
+ async function callAnthropic(config, prompt) {
47
+ const response = await requestJson("anthropic", "https://api.anthropic.com/v1/messages", {
48
+ method: "POST",
49
+ headers: {
50
+ "x-api-key": config.token,
51
+ "anthropic-version": "2023-06-01",
52
+ "Content-Type": "application/json",
53
+ },
54
+ body: JSON.stringify({
55
+ model: config.model ?? "claude-sonnet-4-5",
56
+ max_tokens: 700,
57
+ messages: [
58
+ {
59
+ role: "user",
60
+ content: prompt,
61
+ },
62
+ ],
63
+ }),
64
+ });
65
+ return parseAnthropicResponse(await parseJsonResponse(response));
66
+ }
67
+ async function callGemini(config, prompt) {
68
+ const model = config.model ?? "gemini-2.5-flash";
69
+ const response = await requestJson("gemini", `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(model)}:generateContent`, {
70
+ method: "POST",
71
+ headers: {
72
+ "x-goog-api-key": config.token,
73
+ "Content-Type": "application/json",
74
+ },
75
+ body: JSON.stringify({
76
+ contents: [
77
+ {
78
+ parts: [{ text: prompt }],
79
+ },
80
+ ],
81
+ }),
82
+ });
83
+ return parseGeminiResponse(await parseJsonResponse(response));
84
+ }
85
+ async function parseJsonResponse(response) {
86
+ const payload = await response.json().catch(() => null);
87
+ if (!response.ok) {
88
+ throw new Error(describeHttpFailure(response.status, payload));
89
+ }
90
+ return payload;
91
+ }
92
+ async function requestJson(provider, url, init) {
93
+ try {
94
+ return await fetch(url, init);
95
+ }
96
+ catch (error) {
97
+ const message = error instanceof Error ? error.message : String(error);
98
+ throw new Error(`AI request to ${provider} failed before a response was received: ${message}`);
99
+ }
100
+ }
101
+ function parseOpenAIResponse(payload) {
102
+ const data = payload;
103
+ if (data.output_text?.trim()) {
104
+ return data.output_text.trim();
105
+ }
106
+ const fallback = data.output
107
+ ?.flatMap((item) => item.content ?? [])
108
+ .map((item) => item.text ?? "")
109
+ .join("\n")
110
+ .trim();
111
+ if (!fallback) {
112
+ throw new Error("OpenAI response did not contain text output.");
113
+ }
114
+ return fallback;
115
+ }
116
+ function parseAnthropicResponse(payload) {
117
+ const data = payload;
118
+ const text = data.content
119
+ ?.filter((item) => item.type === "text")
120
+ .map((item) => item.text ?? "")
121
+ .join("\n")
122
+ .trim();
123
+ if (!text) {
124
+ throw new Error("Anthropic response did not contain text output.");
125
+ }
126
+ return text;
127
+ }
128
+ function parseGeminiResponse(payload) {
129
+ const data = payload;
130
+ const text = data.candidates
131
+ ?.flatMap((candidate) => candidate.content?.parts ?? [])
132
+ .map((part) => part.text ?? "")
133
+ .join("\n")
134
+ .trim();
135
+ if (!text) {
136
+ throw new Error("Gemini response did not contain text output.");
137
+ }
138
+ return text;
139
+ }
140
+ function describeHttpFailure(status, payload) {
141
+ if (status === 401 || status === 403) {
142
+ return `AI authentication failed (${status}). Check AI_TOKEN and provider configuration.`;
143
+ }
144
+ if (status === 429) {
145
+ return `AI rate limit exceeded (${status}). Try again later or reduce request frequency.`;
146
+ }
147
+ if (status >= 500) {
148
+ return `AI provider error (${status}). Try again later.`;
149
+ }
150
+ return `AI request failed (${status}): ${JSON.stringify(payload)}`;
151
+ }
152
+ //# sourceMappingURL=aiClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiClient.js","sourceRoot":"","sources":["../src/aiClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export declare const SUPPORTED_AI_PROVIDERS: readonly ["openai", "anthropic", "gemini"];
2
+ export type AiProvider = (typeof SUPPORTED_AI_PROVIDERS)[number];
3
+ export interface AiConfig {
4
+ enabled: boolean;
5
+ provider: AiProvider;
6
+ token: string;
7
+ model?: string;
8
+ }
9
+ export interface AiOptionsInput {
10
+ ai?: boolean | undefined;
11
+ provider?: string | undefined;
12
+ model?: string | undefined;
13
+ configAi?: {
14
+ provider?: string;
15
+ model?: string;
16
+ } | undefined;
17
+ }
18
+ export declare function resolveAiConfig(options: AiOptionsInput): AiConfig | null;
19
+ //# sourceMappingURL=aiConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiConfig.d.ts","sourceRoot":"","sources":["../src/aiConfig.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,4CAA6C,CAAC;AAEjF,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,UAAU,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE;QACT,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,SAAS,CAAC;CACf;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,QAAQ,GAAG,IAAI,CAgCxE"}
@@ -0,0 +1,28 @@
1
+ export const SUPPORTED_AI_PROVIDERS = ["openai", "anthropic", "gemini"];
2
+ export function resolveAiConfig(options) {
3
+ if (!options.ai) {
4
+ return null;
5
+ }
6
+ const provider = (options.provider ??
7
+ options.configAi?.provider ??
8
+ process.env.AI_PROVIDER ??
9
+ "openai").trim();
10
+ const token = (process.env.AI_TOKEN ?? "").trim();
11
+ const model = (options.model ?? options.configAi?.model ?? process.env.AI_MODEL ?? "").trim();
12
+ if (!isAiProvider(provider)) {
13
+ throw new Error(`Unsupported AI provider "${provider}". Supported providers: ${SUPPORTED_AI_PROVIDERS.join(", ")}`);
14
+ }
15
+ if (!token) {
16
+ throw new Error("AI mode requires AI_TOKEN. Set AI_PROVIDER/AI_TOKEN in your environment or use --provider.");
17
+ }
18
+ return {
19
+ enabled: true,
20
+ provider,
21
+ token,
22
+ ...(model ? { model } : {}),
23
+ };
24
+ }
25
+ function isAiProvider(value) {
26
+ return SUPPORTED_AI_PROVIDERS.includes(value);
27
+ }
28
+ //# sourceMappingURL=aiConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiConfig.js","sourceRoot":"","sources":["../src/aiConfig.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAU,CAAC;AAqBjF,MAAM,UAAU,eAAe,CAAC,OAAuB;IACrD,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,CACf,OAAO,CAAC,QAAQ;QAChB,OAAO,CAAC,QAAQ,EAAE,QAAQ;QAC1B,OAAO,CAAC,GAAG,CAAC,WAAW;QACvB,QAAQ,CACT,CAAC,IAAI,EAAE,CAAC;IACT,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClD,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAE9F,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,4BAA4B,QAAQ,2BAA2B,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACnG,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,4FAA4F,CAC7F,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO,EAAE,IAAI;QACb,QAAQ;QACR,KAAK;QACL,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5B,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,sBAAsB,CAAC,QAAQ,CAAC,KAAmB,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { FindingType, ReporterType } from "./reporters.js";
2
+ export interface SarrafConfig {
3
+ reporter?: ReporterType;
4
+ include?: FindingType[];
5
+ exclude?: FindingType[];
6
+ workspace?: string[];
7
+ production?: boolean;
8
+ strict?: boolean;
9
+ debug?: boolean;
10
+ trace?: string;
11
+ ignorePackages?: string[];
12
+ allowUnusedDependencies?: string[];
13
+ allowUnusedDevDependencies?: string[];
14
+ allowMissingPackages?: string[];
15
+ allowMisplacedDevDependencies?: string[];
16
+ ai?: {
17
+ provider?: string;
18
+ model?: string;
19
+ };
20
+ }
21
+ export interface LoadedSarrafConfig {
22
+ config: SarrafConfig;
23
+ source: string;
24
+ }
25
+ export declare function loadSarrafConfig(startDir: string): Promise<LoadedSarrafConfig>;
26
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGhE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC;IACtC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,6BAA6B,CAAC,EAAE,MAAM,EAAE,CAAC;IACzC,EAAE,CAAC,EAAE;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAoBpF"}