safe-pkg 1.0.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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +304 -0
  3. package/dist/.DS_Store +0 -0
  4. package/dist/cli/index.d.ts +5 -0
  5. package/dist/cli/index.js +135 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/cli/parser.d.ts +5 -0
  8. package/dist/cli/parser.js +61 -0
  9. package/dist/cli/parser.js.map +1 -0
  10. package/dist/config/index.d.ts +1 -0
  11. package/dist/config/index.js +3 -0
  12. package/dist/config/index.js.map +1 -0
  13. package/dist/config/loadConfig.d.ts +5 -0
  14. package/dist/config/loadConfig.js +49 -0
  15. package/dist/config/loadConfig.js.map +1 -0
  16. package/dist/detector/detectPackageManager.d.ts +14 -0
  17. package/dist/detector/detectPackageManager.js +68 -0
  18. package/dist/detector/detectPackageManager.js.map +1 -0
  19. package/dist/detector/index.d.ts +1 -0
  20. package/dist/detector/index.js +3 -0
  21. package/dist/detector/index.js.map +1 -0
  22. package/dist/executor/index.d.ts +1 -0
  23. package/dist/executor/index.js +3 -0
  24. package/dist/executor/index.js.map +1 -0
  25. package/dist/executor/runCommand.d.ts +9 -0
  26. package/dist/executor/runCommand.js +61 -0
  27. package/dist/executor/runCommand.js.map +1 -0
  28. package/dist/index.d.ts +8 -0
  29. package/dist/index.js +11 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/scanner/aiAnalyzer.d.ts +6 -0
  32. package/dist/scanner/aiAnalyzer.js +92 -0
  33. package/dist/scanner/aiAnalyzer.js.map +1 -0
  34. package/dist/scanner/analyzePackage.d.ts +5 -0
  35. package/dist/scanner/analyzePackage.js +155 -0
  36. package/dist/scanner/analyzePackage.js.map +1 -0
  37. package/dist/scanner/auditAnalyzer.d.ts +11 -0
  38. package/dist/scanner/auditAnalyzer.js +113 -0
  39. package/dist/scanner/auditAnalyzer.js.map +1 -0
  40. package/dist/scanner/heuristicAnalyzer.d.ts +5 -0
  41. package/dist/scanner/heuristicAnalyzer.js +228 -0
  42. package/dist/scanner/heuristicAnalyzer.js.map +1 -0
  43. package/dist/scanner/index.d.ts +6 -0
  44. package/dist/scanner/index.js +8 -0
  45. package/dist/scanner/index.js.map +1 -0
  46. package/dist/scanner/metadataAnalyzer.d.ts +5 -0
  47. package/dist/scanner/metadataAnalyzer.js +136 -0
  48. package/dist/scanner/metadataAnalyzer.js.map +1 -0
  49. package/dist/scanner/scriptAnalyzer.d.ts +5 -0
  50. package/dist/scanner/scriptAnalyzer.js +187 -0
  51. package/dist/scanner/scriptAnalyzer.js.map +1 -0
  52. package/dist/scanner-project/batchAnalyze.d.ts +1 -0
  53. package/dist/scanner-project/batchAnalyze.js +4 -0
  54. package/dist/scanner-project/batchAnalyze.js.map +1 -0
  55. package/dist/scanner-project/index.d.ts +4 -0
  56. package/dist/scanner-project/index.js +6 -0
  57. package/dist/scanner-project/index.js.map +1 -0
  58. package/dist/scanner-project/readDependencies.d.ts +5 -0
  59. package/dist/scanner-project/readDependencies.js +28 -0
  60. package/dist/scanner-project/readDependencies.js.map +1 -0
  61. package/dist/scanner-project/scanNodeModules.d.ts +1 -0
  62. package/dist/scanner-project/scanNodeModules.js +4 -0
  63. package/dist/scanner-project/scanNodeModules.js.map +1 -0
  64. package/dist/scanner-project/scanProject.d.ts +5 -0
  65. package/dist/scanner-project/scanProject.js +69 -0
  66. package/dist/scanner-project/scanProject.js.map +1 -0
  67. package/dist/test.d.ts +6 -0
  68. package/dist/test.js +153 -0
  69. package/dist/test.js.map +1 -0
  70. package/dist/types.d.ts +133 -0
  71. package/dist/types.js +2 -0
  72. package/dist/types.js.map +1 -0
  73. package/dist/ui/index.d.ts +4 -0
  74. package/dist/ui/index.js +6 -0
  75. package/dist/ui/index.js.map +1 -0
  76. package/dist/ui/logger.d.ts +24 -0
  77. package/dist/ui/logger.js +39 -0
  78. package/dist/ui/logger.js.map +1 -0
  79. package/dist/ui/promptUser.d.ts +12 -0
  80. package/dist/ui/promptUser.js +50 -0
  81. package/dist/ui/promptUser.js.map +1 -0
  82. package/dist/ui/riskReporter.d.ts +5 -0
  83. package/dist/ui/riskReporter.js +157 -0
  84. package/dist/ui/riskReporter.js.map +1 -0
  85. package/dist/ui/scanReporter.d.ts +1 -0
  86. package/dist/ui/scanReporter.js +4 -0
  87. package/dist/ui/scanReporter.js.map +1 -0
  88. package/package.json +61 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Georges Fouejio
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,304 @@
1
+ # 🔒 safe-pkg
2
+
3
+ **Security-first package installer with multi-layer vulnerability analysis**
4
+
5
+ `safe-pkg` is a drop-in replacement for `npm install`, `yarn add`, and `pnpm add` that analyzes packages for security risks **before** installing them. It combines industry-standard vulnerability scanning with intelligent heuristics and optional AI enhancement to protect your projects from malicious packages.
6
+
7
+ ---
8
+
9
+ ## ✨ Features
10
+
11
+ - 🔍 **4-Layer Security Analysis**
12
+ - NPM Audit integration for known vulnerabilities
13
+ - Package metadata analysis (downloads, age, maintainers)
14
+ - Suspicious script detection (postinstall hooks, dangerous commands)
15
+ - Heuristic pattern matching (typosquatting, malware signatures)
16
+
17
+ - 🤖 **Optional AI Enhancement**
18
+ - Natural language security insights powered by Claude
19
+ - Contextual risk explanations
20
+ - Smart recommendations
21
+
22
+ - 🎨 **Beautiful Terminal UI**
23
+ - Color-coded risk levels (🟢 Safe / 🟡 Caution / 🔴 Dangerous)
24
+ - Detailed security reports
25
+ - Interactive confirmation prompts
26
+
27
+ - 📦 **Universal Package Manager Support**
28
+ - Auto-detects npm, yarn, or pnpm
29
+ - Seamlessly forwards commands to your package manager
30
+ - Works with existing workflows
31
+
32
+ - 📊 **Project Scanning**
33
+ - Analyze all existing dependencies at once
34
+ - Identify risky packages in your codebase
35
+ - Continuous security monitoring
36
+
37
+ ---
38
+
39
+ ## 🚀 Installation
40
+
41
+ ### Global Installation (Recommended)
42
+
43
+ ```bash
44
+ # Using npm
45
+ npm install -g safe-pkg
46
+
47
+ # Using pnpm
48
+ pnpm add -g safe-pkg
49
+
50
+ # Using yarn
51
+ yarn global add safe-pkg
52
+ ```
53
+
54
+ ### Local Development
55
+
56
+ ```bash
57
+ git clone https://github.com/joker7blue/safe-install.git
58
+ cd safe-install
59
+ pnpm install
60
+ pnpm build
61
+ pnpm link --global
62
+ ```
63
+
64
+ ---
65
+
66
+ ## 📖 Usage
67
+
68
+ ### Install Packages with Security Analysis
69
+
70
+ ```bash
71
+ # Analyze and install a single package
72
+ safe-pkg install express
73
+
74
+ # Install multiple packages
75
+ safe-pkg install react vue lodash
76
+
77
+ # Save to devDependencies
78
+ safe-pkg install -D typescript eslint
79
+
80
+ # Skip analysis (direct install)
81
+ safe-pkg install axios --skip-analysis
82
+ ```
83
+
84
+ ### Check a Package Without Installing
85
+
86
+ ```bash
87
+ # Analyze a package before deciding to install
88
+ safe-pkg check suspicious-package-name
89
+ ```
90
+
91
+ ### Scan Existing Project Dependencies
92
+
93
+ ```bash
94
+ # Scan production dependencies
95
+ safe-pkg scan
96
+
97
+ # Include devDependencies
98
+ safe-pkg scan --dev
99
+ ```
100
+
101
+ ### Help & Options
102
+
103
+ ```bash
104
+ safe-pkg --help
105
+ safe-pkg install --help
106
+ safe-pkg scan --help
107
+ ```
108
+
109
+ ---
110
+
111
+ ## 🔐 Security Layers Explained
112
+
113
+ ### 1. **NPM Audit** (40% weight)
114
+ - Checks for known CVEs and security advisories
115
+ - Identifies critical, high, moderate, and low severity vulnerabilities
116
+ - Uses official npm audit database
117
+
118
+ ### 2. **Metadata Analysis** (25% weight)
119
+ - Weekly download counts (flags packages with <100 downloads)
120
+ - Package age (warns about brand new or abandoned packages)
121
+ - Maintainer count (flags unmaintained packages)
122
+ - License verification
123
+
124
+ ### 3. **Script Detection** (25% weight)
125
+ - Scans package.json scripts for dangerous commands
126
+ - Detects postinstall/preinstall hooks
127
+ - Identifies network calls, file system modifications, eval usage
128
+ - Flags obfuscated code patterns
129
+
130
+ ### 4. **Heuristic Analysis** (10% weight)
131
+ - Typosquatting detection (Levenshtein distance from popular packages)
132
+ - Suspicious keywords ("hack", "crack", "free-premium")
133
+ - Name pattern analysis (excessive hyphens, random characters)
134
+ - Known malware signatures
135
+
136
+ ---
137
+
138
+ ## 🤖 AI Enhancement (Optional)
139
+
140
+ Enable AI-powered insights by setting your Anthropic API key:
141
+
142
+ ```bash
143
+ # Set environment variable
144
+ export ANTHROPIC_API_KEY="sk-ant-..."
145
+
146
+ # Or create a config file
147
+ echo '{"anthropicApiKey": "sk-ant-..."}' > ~/.safe-pkgrc
148
+ ```
149
+
150
+ The AI layer provides:
151
+ - Natural language security explanations
152
+ - Context-aware risk assessment
153
+ - Actionable recommendations
154
+ - Human-readable insights
155
+
156
+ ---
157
+
158
+ ## 📊 Example Output
159
+
160
+ ```bash
161
+ $ safe-pkg install tiny-package-that-doesnt-exist-12345
162
+
163
+ ℹ Using package manager: pnpm
164
+
165
+ 🔒 Security Analysis
166
+ ====================
167
+
168
+ ℹ Analyzing tiny-package-that-doesnt-exist-12345...
169
+
170
+ ================================================================================
171
+ 📦 tiny-package-that-doesnt-exist-12345 (unknown)
172
+ ================================================================================
173
+
174
+ Risk Score: 6/10
175
+ Risk Level: CAUTION
176
+
177
+ Recommendation:
178
+ ⚠️ PROCEED WITH CAUTION - Review security warnings carefully
179
+
180
+ Warnings: (4)
181
+ 🟡 MEDIUM - Low weekly downloads (0)
182
+ Source: metadata
183
+ 🟠 HIGH - Package has no maintainers
184
+ Source: metadata
185
+ 🟡 MEDIUM - Package has no license
186
+ Source: metadata
187
+ 🟡 MEDIUM - Pattern warnings: Excessive hyphens (5)
188
+ Source: heuristic
189
+
190
+ Analysis Details:
191
+ Audit: 0 vulnerabilities - Score: 0/10
192
+ Metadata: 0 weekly downloads, 0 days old - Score: 8/10
193
+ Maintainers: 0, License: No
194
+ Scripts: Clean - Score: 0/10
195
+ Heuristics: Clean - Score: 1/10
196
+ Patterns: Excessive hyphens (5)
197
+
198
+ ⚠️ Package "tiny-package-that-doesnt-exist-12345" has warnings (score: 6/10). Continue? › (y/N)
199
+ ```
200
+
201
+ ---
202
+
203
+ ## ⚙️ Configuration
204
+
205
+ Create a `.safe-pkgrc` file in your project root or home directory:
206
+
207
+ ```json
208
+ {
209
+ "anthropicApiKey": "sk-ant-...",
210
+ "riskThreshold": 7,
211
+ "autoConfirm": false
212
+ }
213
+ ```
214
+
215
+ **Options:**
216
+ - `anthropicApiKey` - Your Anthropic API key for AI insights
217
+ - `riskThreshold` - Minimum risk score to trigger warnings (default: 7)
218
+ - `autoConfirm` - Skip confirmation for safe packages (default: false)
219
+
220
+ ---
221
+
222
+ ## 🛠️ Development
223
+
224
+ ```bash
225
+ # Clone repository
226
+ git clone https://github.com/joker7blue/safe-install.git
227
+ cd safe-install
228
+
229
+ # Install dependencies
230
+ pnpm install
231
+
232
+ # Build TypeScript
233
+ pnpm build
234
+
235
+ # Run linter
236
+ pnpm check
237
+
238
+ # Run tests
239
+ pnpm test
240
+
241
+ # Link globally for testing
242
+ pnpm link --global
243
+ ```
244
+
245
+ ### Project Structure
246
+
247
+ ```
248
+ src/
249
+ ├── cli/ # Command-line interface
250
+ ├── config/ # Configuration loader
251
+ ├── detector/ # Package manager detection
252
+ ├── executor/ # Command execution
253
+ ├── scanner/ # Security analyzers
254
+ │ ├── auditAnalyzer.ts
255
+ │ ├── metadataAnalyzer.ts
256
+ │ ├── scriptAnalyzer.ts
257
+ │ ├── heuristicAnalyzer.ts
258
+ │ ├── aiAnalyzer.ts
259
+ │ └── analyzePackage.ts
260
+ ├── scanner-project/ # Project dependency scanning
261
+ ├── ui/ # Terminal UI components
262
+ └── types.ts # TypeScript definitions
263
+ ```
264
+
265
+ ---
266
+
267
+ ## 🤝 Contributing
268
+
269
+ Contributions are welcome! Please:
270
+
271
+ 1. Fork the repository
272
+ 2. Create a feature branch (`git checkout -b feat/amazing-feature`)
273
+ 3. Commit your changes (`git commit -m 'feat: add amazing feature'`)
274
+ 4. Push to the branch (`git push origin feat/amazing-feature`)
275
+ 5. Open a Pull Request
276
+
277
+ ---
278
+
279
+ ## 📝 License
280
+
281
+ MIT © Georges Fouejio
282
+
283
+ ---
284
+
285
+ ## 🙏 Acknowledgments
286
+
287
+ - Built with [TypeScript](https://www.typescriptlang.org/)
288
+ - Styled with [Chalk](https://github.com/chalk/chalk)
289
+ - CLI powered by [Commander.js](https://github.com/tj/commander.js)
290
+ - AI enhancement via [Anthropic Claude](https://www.anthropic.com/)
291
+
292
+ ---
293
+
294
+ ## 🔗 Links
295
+
296
+ - [GitHub Repository](https://github.com/joker7blue/safe-install)
297
+ - [Issue Tracker](https://github.com/joker7blue/safe-install/issues)
298
+ - [NPM Package](https://www.npmjs.com/package/safe-pkg) *(coming soon)*
299
+
300
+ ---
301
+
302
+ ## ⚠️ Disclaimer
303
+
304
+ While `safe-pkg` provides multiple layers of security analysis, no automated tool can guarantee 100% protection against all security threats. Always review package source code for critical applications and report suspicious packages to the npm security team.
package/dist/.DS_Store ADDED
Binary file
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Main CLI orchestrator
4
+ */
5
+ export declare function main(): Promise<void>;
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env node
2
+ import chalk from "chalk";
3
+ import { loadConfig } from "../config/loadConfig.js";
4
+ import { detectPackageManager } from "../detector/detectPackageManager.js";
5
+ import { runInstallCommand } from "../executor/runCommand.js";
6
+ import { scanProject } from "../scanner-project/scanProject.js";
7
+ import { analyzePackage } from "../scanner/analyzePackage.js";
8
+ import { logError, logHeader, logNewline, logStep, logSuccess, } from "../ui/logger.js";
9
+ import { askUserConfirmation } from "../ui/promptUser.js";
10
+ import { displayRiskReport } from "../ui/riskReporter.js";
11
+ import { parseArguments } from "./parser.js";
12
+ /**
13
+ * Main CLI orchestrator
14
+ */
15
+ export async function main() {
16
+ try {
17
+ // Parse command line arguments
18
+ const command = parseArguments(process.argv);
19
+ // Load configuration
20
+ const config = loadConfig();
21
+ // Handle different commands
22
+ if (command.action === "scan") {
23
+ await handleScanCommand(config, command.options);
24
+ }
25
+ else if (command.action === "check") {
26
+ await handleCheckCommand(command.packages[0] || "", config);
27
+ }
28
+ else if (command.action === "install") {
29
+ await handleInstallCommand(command.packages, config, command.options);
30
+ }
31
+ else {
32
+ logError("Unknown command");
33
+ process.exit(1);
34
+ }
35
+ }
36
+ catch (error) {
37
+ logError(`Fatal error: ${error instanceof Error ? error.message : String(error)}`);
38
+ process.exit(1);
39
+ }
40
+ }
41
+ /**
42
+ * Handle scan command - analyze existing project dependencies
43
+ */
44
+ async function handleScanCommand(config, options) {
45
+ logHeader("🔍 Scanning Project Dependencies");
46
+ logNewline();
47
+ const result = await scanProject(process.cwd(), config, Boolean(options.dev));
48
+ // Display summary
49
+ logNewline();
50
+ logHeader("Scan Results");
51
+ console.log(`Total packages: ${chalk.bold(result.totalPackages)}`);
52
+ console.log(`${chalk.green("✓")} Safe: ${chalk.green.bold(result.summary.safe)}`);
53
+ console.log(`${chalk.yellow("⚠")} Caution: ${chalk.yellow.bold(result.summary.caution)}`);
54
+ console.log(`${chalk.red("✖")} Dangerous: ${chalk.red.bold(result.summary.dangerous)}`);
55
+ // Show detailed reports for risky packages
56
+ const riskyPackages = result.reports.filter((r) => r.riskLevel !== "safe");
57
+ if (riskyPackages.length > 0) {
58
+ logNewline();
59
+ logHeader("⚠️ Packages Requiring Attention");
60
+ for (const report of riskyPackages) {
61
+ displayRiskReport(report);
62
+ }
63
+ }
64
+ else {
65
+ logNewline();
66
+ logSuccess("All packages are safe! ✨");
67
+ }
68
+ }
69
+ /**
70
+ * Handle check command - analyze a single package
71
+ */
72
+ async function handleCheckCommand(packageName, config) {
73
+ if (!packageName) {
74
+ logError("Package name required for check command");
75
+ process.exit(1);
76
+ }
77
+ logHeader(`🔍 Analyzing ${packageName}`);
78
+ logNewline();
79
+ const report = await analyzePackage(packageName, config);
80
+ displayRiskReport(report);
81
+ }
82
+ /**
83
+ * Handle install command - analyze and install packages
84
+ */
85
+ async function handleInstallCommand(packages, config, options) {
86
+ if (packages.length === 0) {
87
+ logError("No packages specified");
88
+ process.exit(1);
89
+ }
90
+ // Detect package manager
91
+ const packageManager = (await detectPackageManager(process.cwd())) || "npm";
92
+ logStep(`Using package manager: ${chalk.cyan(packageManager)}`);
93
+ logNewline();
94
+ // Skip analysis if requested
95
+ if (options.skipAnalysis) {
96
+ await runInstallCommand(packageManager, packages, options);
97
+ return;
98
+ }
99
+ // Analyze each package
100
+ logHeader("🔒 Security Analysis");
101
+ logNewline();
102
+ const packagesToInstall = [];
103
+ for (const packageName of packages) {
104
+ logStep(`Analyzing ${chalk.cyan(packageName)}...`);
105
+ const report = await analyzePackage(packageName, config);
106
+ displayRiskReport(report);
107
+ logNewline();
108
+ // Check if user approves
109
+ const shouldInstall = config.autoConfirm && report.riskLevel === "safe"
110
+ ? true
111
+ : await askUserConfirmation(packageName, report.riskLevel, report.riskScore);
112
+ if (shouldInstall) {
113
+ packagesToInstall.push(packageName);
114
+ }
115
+ else {
116
+ logError(`Skipping ${packageName}`);
117
+ }
118
+ logNewline();
119
+ }
120
+ // Install approved packages
121
+ if (packagesToInstall.length > 0) {
122
+ logHeader("📦 Installing Packages");
123
+ logNewline();
124
+ await runInstallCommand(packageManager, packagesToInstall, options);
125
+ }
126
+ else {
127
+ logError("No packages approved for installation");
128
+ process.exit(1);
129
+ }
130
+ }
131
+ // Run CLI if executed directly
132
+ if (import.meta.url === `file://${process.argv[1]}`) {
133
+ main();
134
+ }
135
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { CommandConfig } from "../types.js";
2
+ /**
3
+ * Parse CLI arguments and return structured command config
4
+ */
5
+ export declare function parseArguments(argv: string[]): CommandConfig;
@@ -0,0 +1,61 @@
1
+ import { Command } from "commander";
2
+ /**
3
+ * Parse CLI arguments and return structured command config
4
+ */
5
+ export function parseArguments(argv) {
6
+ const program = new Command();
7
+ let commandConfig = {
8
+ action: "help",
9
+ packages: [],
10
+ options: {},
11
+ };
12
+ program
13
+ .name("safe-pkg")
14
+ .description("Secure package installer with built-in security analysis")
15
+ .version("0.0.1");
16
+ // Install command (default action)
17
+ program
18
+ .command("install [packages...]", { isDefault: true })
19
+ .alias("i")
20
+ .alias("add")
21
+ .description("Install packages after security analysis")
22
+ .option("-D, --save-dev", "Save to devDependencies")
23
+ .option("-g, --global", "Install globally")
24
+ .option("--skip-analysis", "Skip security analysis")
25
+ .option("--auto-yes", "Automatically proceed with safe packages")
26
+ .action((packages, options) => {
27
+ commandConfig = {
28
+ action: "install",
29
+ packages,
30
+ options,
31
+ };
32
+ });
33
+ // Scan command
34
+ program
35
+ .command("scan")
36
+ .description("Scan existing project dependencies")
37
+ .option("--dev", "Include devDependencies")
38
+ .option("--json", "Output as JSON")
39
+ .action((options) => {
40
+ commandConfig = {
41
+ action: "scan",
42
+ packages: [],
43
+ options,
44
+ };
45
+ });
46
+ // Check command
47
+ program
48
+ .command("check <package>")
49
+ .description("Check a single package without installing")
50
+ .action((packageName) => {
51
+ commandConfig = {
52
+ action: "check",
53
+ packages: [packageName],
54
+ options: {},
55
+ };
56
+ });
57
+ // Parse argv
58
+ program.parse(argv);
59
+ return commandConfig;
60
+ }
61
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/cli/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAc;IAC5C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,IAAI,aAAa,GAAkB;QAClC,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE,EAAE;KACX,CAAC;IAEF,OAAO;SACL,IAAI,CAAC,UAAU,CAAC;SAChB,WAAW,CAAC,0DAA0D,CAAC;SACvE,OAAO,CAAC,OAAO,CAAC,CAAC;IAEnB,mCAAmC;IACnC,OAAO;SACL,OAAO,CAAC,uBAAuB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;SACrD,KAAK,CAAC,GAAG,CAAC;SACV,KAAK,CAAC,KAAK,CAAC;SACZ,WAAW,CAAC,0CAA0C,CAAC;SACvD,MAAM,CAAC,gBAAgB,EAAE,yBAAyB,CAAC;SACnD,MAAM,CAAC,cAAc,EAAE,kBAAkB,CAAC;SAC1C,MAAM,CAAC,iBAAiB,EAAE,wBAAwB,CAAC;SACnD,MAAM,CAAC,YAAY,EAAE,0CAA0C,CAAC;SAChE,MAAM,CAAC,CAAC,QAAkB,EAAE,OAAgC,EAAE,EAAE;QAChE,aAAa,GAAG;YACf,MAAM,EAAE,SAAS;YACjB,QAAQ;YACR,OAAO;SACP,CAAC;IACH,CAAC,CAAC,CAAC;IAEJ,eAAe;IACf,OAAO;SACL,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,oCAAoC,CAAC;SACjD,MAAM,CAAC,OAAO,EAAE,yBAAyB,CAAC;SAC1C,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,MAAM,CAAC,CAAC,OAAgC,EAAE,EAAE;QAC5C,aAAa,GAAG;YACf,MAAM,EAAE,MAAM;YACd,QAAQ,EAAE,EAAE;YACZ,OAAO;SACP,CAAC;IACH,CAAC,CAAC,CAAC;IAEJ,gBAAgB;IAChB,OAAO;SACL,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,2CAA2C,CAAC;SACxD,MAAM,CAAC,CAAC,WAAmB,EAAE,EAAE;QAC/B,aAAa,GAAG;YACf,MAAM,EAAE,OAAO;YACf,QAAQ,EAAE,CAAC,WAAW,CAAC;YACvB,OAAO,EAAE,EAAE;SACX,CAAC;IACH,CAAC,CAAC,CAAC;IAEJ,aAAa;IACb,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEpB,OAAO,aAAa,CAAC;AACtB,CAAC"}
@@ -0,0 +1 @@
1
+ export * from "./loadConfig.js";
@@ -0,0 +1,3 @@
1
+ // Config barrel exports
2
+ export * from "./loadConfig.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Config } from "../types.js";
2
+ /**
3
+ * Load configuration from environment variables or config file
4
+ */
5
+ export declare function loadConfig(): Config;
@@ -0,0 +1,49 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ /**
5
+ * Load configuration from environment variables or config file
6
+ */
7
+ export function loadConfig() {
8
+ // Default config
9
+ const config = {
10
+ riskThreshold: 7,
11
+ autoConfirm: false,
12
+ };
13
+ // Check for API key in environment variable
14
+ const envApiKey = process.env.ANTHROPIC_API_KEY;
15
+ if (envApiKey) {
16
+ config.anthropicApiKey = envApiKey;
17
+ }
18
+ // Try to load from config file if no env var
19
+ if (!config.anthropicApiKey) {
20
+ const configFromFile = loadConfigFile();
21
+ if (configFromFile.anthropicApiKey) {
22
+ config.anthropicApiKey = configFromFile.anthropicApiKey;
23
+ }
24
+ }
25
+ return config;
26
+ }
27
+ /**
28
+ * Load configuration from file (.safe-pkgrc or ~/.safe-pkgrc)
29
+ */
30
+ function loadConfigFile() {
31
+ const configPaths = [
32
+ join(process.cwd(), ".safe-pkgrc"),
33
+ join(homedir(), ".safe-pkgrc"),
34
+ ];
35
+ for (const configPath of configPaths) {
36
+ if (existsSync(configPath)) {
37
+ try {
38
+ const content = readFileSync(configPath, "utf-8");
39
+ const config = JSON.parse(content);
40
+ return config;
41
+ }
42
+ catch (error) {
43
+ // Invalid JSON or read error, skip to next file
44
+ }
45
+ }
46
+ }
47
+ return {};
48
+ }
49
+ //# sourceMappingURL=loadConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadConfig.js","sourceRoot":"","sources":["../../src/config/loadConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC;;GAEG;AACH,MAAM,UAAU,UAAU;IACzB,iBAAiB;IACjB,MAAM,MAAM,GAAW;QACtB,aAAa,EAAE,CAAC;QAChB,WAAW,EAAE,KAAK;KAClB,CAAC;IAEF,4CAA4C;IAC5C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAChD,IAAI,SAAS,EAAE,CAAC;QACf,MAAM,CAAC,eAAe,GAAG,SAAS,CAAC;IACpC,CAAC;IAED,6CAA6C;IAC7C,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;QAC7B,MAAM,cAAc,GAAG,cAAc,EAAE,CAAC;QACxC,IAAI,cAAc,CAAC,eAAe,EAAE,CAAC;YACpC,MAAM,CAAC,eAAe,GAAG,cAAc,CAAC,eAAe,CAAC;QACzD,CAAC;IACF,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;GAEG;AACH,SAAS,cAAc;IACtB,MAAM,WAAW,GAAG;QACnB,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,CAAC;QAClC,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC;KAC9B,CAAC;IAEF,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACtC,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACJ,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;gBAClD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACnC,OAAO,MAAyB,CAAC;YAClC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,gDAAgD;YACjD,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,EAAE,CAAC;AACX,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { PackageManager } from "../types.js";
2
+ /**
3
+ * Detect package manager from lock files in the given directory
4
+ * Priority: pnpm > yarn > npm
5
+ */
6
+ export declare function detectPackageManager(cwd?: string): Promise<PackageManager>;
7
+ /**
8
+ * Check if a specific package manager is available
9
+ */
10
+ export declare function isPackageManagerAvailable(manager: PackageManager): Promise<boolean>;
11
+ /**
12
+ * Get the version of a package manager
13
+ */
14
+ export declare function getPackageManagerVersion(manager: PackageManager): Promise<string | null>;