bilt-toolkit 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 (116) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +168 -0
  3. package/bin/bilt.js +2 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +161 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/doctor.d.ts +13 -0
  9. package/dist/commands/doctor.d.ts.map +1 -0
  10. package/dist/commands/doctor.js +194 -0
  11. package/dist/commands/doctor.js.map +1 -0
  12. package/dist/commands/fix.d.ts +12 -0
  13. package/dist/commands/fix.d.ts.map +1 -0
  14. package/dist/commands/fix.js +273 -0
  15. package/dist/commands/fix.js.map +1 -0
  16. package/dist/commands/init.d.ts +11 -0
  17. package/dist/commands/init.d.ts.map +1 -0
  18. package/dist/commands/init.js +101 -0
  19. package/dist/commands/init.js.map +1 -0
  20. package/dist/commands/scan.d.ts +17 -0
  21. package/dist/commands/scan.d.ts.map +1 -0
  22. package/dist/commands/scan.js +267 -0
  23. package/dist/commands/scan.js.map +1 -0
  24. package/dist/commands/undo.d.ts +12 -0
  25. package/dist/commands/undo.d.ts.map +1 -0
  26. package/dist/commands/undo.js +90 -0
  27. package/dist/commands/undo.js.map +1 -0
  28. package/dist/commands/watch.d.ts +10 -0
  29. package/dist/commands/watch.d.ts.map +1 -0
  30. package/dist/commands/watch.js +68 -0
  31. package/dist/commands/watch.js.map +1 -0
  32. package/dist/config/config.d.ts +8 -0
  33. package/dist/config/config.d.ts.map +1 -0
  34. package/dist/config/config.js +75 -0
  35. package/dist/config/config.js.map +1 -0
  36. package/dist/core/fix/confirm.d.ts +21 -0
  37. package/dist/core/fix/confirm.d.ts.map +1 -0
  38. package/dist/core/fix/confirm.js +60 -0
  39. package/dist/core/fix/confirm.js.map +1 -0
  40. package/dist/core/fix/env-fix.d.ts +40 -0
  41. package/dist/core/fix/env-fix.d.ts.map +1 -0
  42. package/dist/core/fix/env-fix.js +186 -0
  43. package/dist/core/fix/env-fix.js.map +1 -0
  44. package/dist/core/fix/snapshot.d.ts +30 -0
  45. package/dist/core/fix/snapshot.d.ts.map +1 -0
  46. package/dist/core/fix/snapshot.js +186 -0
  47. package/dist/core/fix/snapshot.js.map +1 -0
  48. package/dist/core/rules/entropy.d.ts +29 -0
  49. package/dist/core/rules/entropy.d.ts.map +1 -0
  50. package/dist/core/rules/entropy.js +117 -0
  51. package/dist/core/rules/entropy.js.map +1 -0
  52. package/dist/core/rules/providers.d.ts +12 -0
  53. package/dist/core/rules/providers.d.ts.map +1 -0
  54. package/dist/core/rules/providers.js +184 -0
  55. package/dist/core/rules/providers.js.map +1 -0
  56. package/dist/core/rules/secret-rules.d.ts +3 -0
  57. package/dist/core/rules/secret-rules.d.ts.map +1 -0
  58. package/dist/core/rules/secret-rules.js +205 -0
  59. package/dist/core/rules/secret-rules.js.map +1 -0
  60. package/dist/core/scan/env.d.ts +47 -0
  61. package/dist/core/scan/env.d.ts.map +1 -0
  62. package/dist/core/scan/env.js +301 -0
  63. package/dist/core/scan/env.js.map +1 -0
  64. package/dist/core/scan/framework.d.ts +26 -0
  65. package/dist/core/scan/framework.d.ts.map +1 -0
  66. package/dist/core/scan/framework.js +254 -0
  67. package/dist/core/scan/framework.js.map +1 -0
  68. package/dist/core/scan/gitignore.d.ts +20 -0
  69. package/dist/core/scan/gitignore.d.ts.map +1 -0
  70. package/dist/core/scan/gitignore.js +217 -0
  71. package/dist/core/scan/gitignore.js.map +1 -0
  72. package/dist/core/scan/secrets.d.ts +27 -0
  73. package/dist/core/scan/secrets.d.ts.map +1 -0
  74. package/dist/core/scan/secrets.js +247 -0
  75. package/dist/core/scan/secrets.js.map +1 -0
  76. package/dist/core/score/health.d.ts +29 -0
  77. package/dist/core/score/health.d.ts.map +1 -0
  78. package/dist/core/score/health.js +73 -0
  79. package/dist/core/score/health.js.map +1 -0
  80. package/dist/core/watch/watcher.d.ts +29 -0
  81. package/dist/core/watch/watcher.d.ts.map +1 -0
  82. package/dist/core/watch/watcher.js +176 -0
  83. package/dist/core/watch/watcher.js.map +1 -0
  84. package/dist/index.d.ts +2 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +2 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/plugins/interface.d.ts +12 -0
  89. package/dist/plugins/interface.d.ts.map +1 -0
  90. package/dist/plugins/interface.js +91 -0
  91. package/dist/plugins/interface.js.map +1 -0
  92. package/dist/plugins/loader.d.ts +10 -0
  93. package/dist/plugins/loader.d.ts.map +1 -0
  94. package/dist/plugins/loader.js +104 -0
  95. package/dist/plugins/loader.js.map +1 -0
  96. package/dist/plugins/official/docker.d.ts +4 -0
  97. package/dist/plugins/official/docker.d.ts.map +1 -0
  98. package/dist/plugins/official/docker.js +111 -0
  99. package/dist/plugins/official/docker.js.map +1 -0
  100. package/dist/plugins/official/terraform.d.ts +4 -0
  101. package/dist/plugins/official/terraform.d.ts.map +1 -0
  102. package/dist/plugins/official/terraform.js +131 -0
  103. package/dist/plugins/official/terraform.js.map +1 -0
  104. package/dist/types/index.d.ts +158 -0
  105. package/dist/types/index.d.ts.map +1 -0
  106. package/dist/types/index.js +3 -0
  107. package/dist/types/index.js.map +1 -0
  108. package/dist/ui/format.d.ts +43 -0
  109. package/dist/ui/format.d.ts.map +1 -0
  110. package/dist/ui/format.js +207 -0
  111. package/dist/ui/format.js.map +1 -0
  112. package/dist/ui/reporter.d.ts +39 -0
  113. package/dist/ui/reporter.d.ts.map +1 -0
  114. package/dist/ui/reporter.js +254 -0
  115. package/dist/ui/reporter.js.map +1 -0
  116. package/package.json +65 -0
@@ -0,0 +1,267 @@
1
+ // ─── Scan Command ────────────────────────────────────────────────────────────
2
+ // Orchestrates all scanning passes and produces a unified ScanResult.
3
+ import path from "node:path";
4
+ import { promises as fs } from "node:fs";
5
+ import fg from "fast-glob";
6
+ import { loadConfig } from "../config/config.js";
7
+ import { parseEnvFile, findEnvFiles, diffEnvFiles, scanCodeForEnvRefs, findMissingEnvVars, findUnusedEnvVars, } from "../core/scan/env.js";
8
+ import { checkEnvFilesIgnoredWithGit } from "../core/scan/gitignore.js";
9
+ import { scanFileForSecrets, scanGitHistory } from "../core/scan/secrets.js";
10
+ import { detectFramework, checkClientExposedSecrets, } from "../core/scan/framework.js";
11
+ import { calculateHealthScore } from "../core/score/health.js";
12
+ import { loadPlugins } from "../plugins/loader.js";
13
+ import { createPluginContext } from "../plugins/interface.js";
14
+ import { SECRET_RULES } from "../core/rules/secret-rules.js";
15
+ import { reportScanStart, reportScanProgress, reportScanResults, } from "../ui/reporter.js";
16
+ /**
17
+ * Execute a full project scan, returning a ScanResult.
18
+ *
19
+ * 1. Load config
20
+ * 2. Find & parse .env files
21
+ * 3. Detect env mismatches (missing/unused vars)
22
+ * 4. Check .gitignore coverage
23
+ * 5. Scan working tree for secrets
24
+ * 6. Scan git history for secrets
25
+ * 7. Detect framework & client-exposed secrets
26
+ * 8. Run plugins
27
+ * 9. Calculate health score
28
+ * 10. Report results
29
+ */
30
+ export async function executeScan(projectDir, options = {}) {
31
+ const start = Date.now();
32
+ const rootDir = path.resolve(projectDir);
33
+ const config = await loadConfig(rootDir);
34
+ const findings = [];
35
+ // Start spinner unless quiet mode
36
+ const spinner = options.quiet ? null : reportScanStart(rootDir);
37
+ try {
38
+ // ── 1. Find & parse .env files ──────────────────────────────────────
39
+ if (spinner)
40
+ reportScanProgress(spinner, "Parsing .env files…");
41
+ const envFiles = await findEnvFiles(rootDir);
42
+ const parsedEnvFiles = [];
43
+ for (const envFile of envFiles) {
44
+ try {
45
+ const content = await fs.readFile(envFile, "utf-8");
46
+ const parsed = parseEnvFile(content, envFile);
47
+ parsedEnvFiles.push(parsed);
48
+ }
49
+ catch {
50
+ // Skip unreadable files
51
+ }
52
+ }
53
+ // ── 2. Env mismatch detection ───────────────────────────────────────
54
+ if (spinner)
55
+ reportScanProgress(spinner, "Checking env variable usage…");
56
+ // Find code files
57
+ const codeFiles = await fg(["**/*.ts", "**/*.js", "**/*.tsx", "**/*.jsx", "**/*.py", "**/*.rb"], {
58
+ cwd: rootDir,
59
+ ignore: config.ignore,
60
+ onlyFiles: true,
61
+ absolute: true,
62
+ });
63
+ // Scan code for env references and missing vars
64
+ const envRefs = new Set();
65
+ const primaryEnv = parsedEnvFiles[0];
66
+ const definedKeys = primaryEnv ? [...primaryEnv.entries.keys()] : [];
67
+ for (const codeFile of codeFiles) {
68
+ try {
69
+ const content = await fs.readFile(codeFile, "utf-8");
70
+ const refs = scanCodeForEnvRefs(content, codeFile);
71
+ for (const ref of refs)
72
+ envRefs.add(ref);
73
+ if (primaryEnv) {
74
+ const missingFindings = findMissingEnvVars(refs, definedKeys, path.relative(rootDir, codeFile));
75
+ findings.push(...missingFindings);
76
+ }
77
+ }
78
+ catch {
79
+ // Skip unreadable files
80
+ }
81
+ }
82
+ // Compare env files to find mismatches
83
+ if (parsedEnvFiles.length >= 2) {
84
+ const diffFindings = diffEnvFiles(parsedEnvFiles);
85
+ findings.push(...diffFindings);
86
+ }
87
+ // Find unused env vars
88
+ if (primaryEnv) {
89
+ const unusedFindings = findUnusedEnvVars([...envRefs], [...primaryEnv.entries.values()], path.relative(rootDir, primaryEnv.filePath));
90
+ findings.push(...unusedFindings);
91
+ }
92
+ // ── 3. Check .gitignore coverage ────────────────────────────────────
93
+ if (spinner)
94
+ reportScanProgress(spinner, "Checking .gitignore…");
95
+ let gitignoreContent = "";
96
+ try {
97
+ gitignoreContent = await fs.readFile(path.join(rootDir, ".gitignore"), "utf-8");
98
+ }
99
+ catch { }
100
+ const gitignoreFindings = await checkEnvFilesIgnoredWithGit(rootDir, envFiles);
101
+ findings.push(...gitignoreFindings);
102
+ // ── 4. Scan working tree for secrets ────────────────────────────────
103
+ if (spinner)
104
+ reportScanProgress(spinner, "Scanning for secrets…");
105
+ const scanTargets = await fg(["**/*"], {
106
+ cwd: rootDir,
107
+ ignore: config.ignore,
108
+ onlyFiles: true,
109
+ });
110
+ // Filter to text-like files only
111
+ const textExtensions = new Set([
112
+ ".ts",
113
+ ".js",
114
+ ".tsx",
115
+ ".jsx",
116
+ ".mjs",
117
+ ".cjs",
118
+ ".py",
119
+ ".rb",
120
+ ".go",
121
+ ".rs",
122
+ ".java",
123
+ ".kt",
124
+ ".json",
125
+ ".yaml",
126
+ ".yml",
127
+ ".toml",
128
+ ".xml",
129
+ ".env",
130
+ ".cfg",
131
+ ".conf",
132
+ ".ini",
133
+ ".properties",
134
+ ".sh",
135
+ ".bash",
136
+ ".zsh",
137
+ ".fish",
138
+ ".tf",
139
+ ".hcl",
140
+ ".dockerfile",
141
+ ".md",
142
+ ".txt",
143
+ ".csv",
144
+ ]);
145
+ let scannedFiles = 0;
146
+ for (const file of scanTargets) {
147
+ const ext = path.extname(file).toLowerCase();
148
+ const basename = path.basename(file).toLowerCase();
149
+ // Include dotfiles like .env, .env.local etc.
150
+ const isEnvFile = basename.startsWith(".env");
151
+ if (!isEnvFile && !textExtensions.has(ext) && ext !== "")
152
+ continue;
153
+ const fullPath = path.join(rootDir, file);
154
+ try {
155
+ const stat = await fs.stat(fullPath);
156
+ // Skip files > 1MB
157
+ if (stat.size > 1_048_576)
158
+ continue;
159
+ const content = await fs.readFile(fullPath, "utf-8");
160
+ const secretFindings = scanFileForSecrets(content, file, SECRET_RULES, config.entropyThreshold);
161
+ findings.push(...secretFindings);
162
+ scannedFiles++;
163
+ }
164
+ catch {
165
+ // Skip binary/unreadable files
166
+ }
167
+ }
168
+ // ── 5. Scan git history ─────────────────────────────────────────────
169
+ if (spinner)
170
+ reportScanProgress(spinner, "Scanning git history…");
171
+ try {
172
+ const depth = options.fullHistory ? undefined : config.historyDepth;
173
+ const historyFindings = await scanGitHistory(rootDir, SECRET_RULES, config.entropyThreshold, depth);
174
+ findings.push(...historyFindings);
175
+ }
176
+ catch {
177
+ // Not a git repo or git not available — skip
178
+ }
179
+ // ── 6. Detect framework & client-exposed secrets ────────────────────
180
+ if (spinner)
181
+ reportScanProgress(spinner, "Detecting framework…");
182
+ let framework;
183
+ try {
184
+ const detected = await detectFramework(rootDir);
185
+ framework = detected || undefined;
186
+ if (framework && parsedEnvFiles.length > 0) {
187
+ const exposedFindings = checkClientExposedSecrets(parsedEnvFiles, framework, SECRET_RULES, config.entropyThreshold);
188
+ findings.push(...exposedFindings);
189
+ }
190
+ }
191
+ catch {
192
+ // Framework detection failed — non-critical
193
+ }
194
+ // ── 7. Load and run plugins ─────────────────────────────────────────
195
+ if (spinner)
196
+ reportScanProgress(spinner, "Running plugins…");
197
+ try {
198
+ const plugins = await loadPlugins(config, rootDir);
199
+ if (plugins.length > 0) {
200
+ const pluginContext = await createPluginContext(rootDir, config);
201
+ for (const plugin of plugins) {
202
+ try {
203
+ const result = await plugin.check(pluginContext);
204
+ findings.push(...result.findings);
205
+ }
206
+ catch {
207
+ // Plugin error — skip silently
208
+ }
209
+ }
210
+ }
211
+ }
212
+ catch {
213
+ // Plugin loading failed — non-critical
214
+ }
215
+ // ── 8. Apply severity overrides ─────────────────────────────────────
216
+ for (const finding of findings) {
217
+ if (finding.ruleId) {
218
+ const override = config.severityOverrides[finding.ruleId];
219
+ if (override) {
220
+ finding.severity = override;
221
+ }
222
+ }
223
+ }
224
+ // ── 9. Filter by severity if requested ──────────────────────────────
225
+ let filteredFindings = findings;
226
+ if (options.severity) {
227
+ const severityOrder = {
228
+ critical: 0,
229
+ warning: 1,
230
+ info: 2,
231
+ };
232
+ const minLevel = severityOrder[options.severity];
233
+ filteredFindings = findings.filter((f) => severityOrder[f.severity] <= minLevel);
234
+ }
235
+ // ── 10. Calculate health score ──────────────────────────────────────
236
+ const { score, grade } = calculateHealthScore(filteredFindings);
237
+ const duration = Date.now() - start;
238
+ const result = {
239
+ findings: filteredFindings,
240
+ healthScore: score,
241
+ grade,
242
+ timestamp: new Date(),
243
+ scannedFiles,
244
+ framework,
245
+ duration,
246
+ };
247
+ // ── 11. Report ──────────────────────────────────────────────────────
248
+ if (spinner)
249
+ spinner.stop();
250
+ if (options.json) {
251
+ console.log(JSON.stringify(result, null, 2));
252
+ }
253
+ else if (!options.quiet) {
254
+ reportScanResults(result, {
255
+ fun: options.fun ?? config.funMode,
256
+ verbose: options.verbose,
257
+ });
258
+ }
259
+ return result;
260
+ }
261
+ catch (error) {
262
+ if (spinner)
263
+ spinner.fail("Scan failed");
264
+ throw error;
265
+ }
266
+ }
267
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Execute the `bilt undo` command.
3
+ *
4
+ * 1. List available snapshots
5
+ * 2. Get latest snapshot
6
+ * 3. Show preview of what will be restored
7
+ * 4. Require confirmation
8
+ * 5. Restore snapshot
9
+ * 6. Report success
10
+ */
11
+ export declare function executeUndo(projectDir: string): Promise<void>;
12
+ //# sourceMappingURL=undo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"undo.d.ts","sourceRoot":"","sources":["../../src/commands/undo.ts"],"names":[],"mappings":"AAeA;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuFnE"}
@@ -0,0 +1,90 @@
1
+ // ─── Undo Command ────────────────────────────────────────────────────────────
2
+ // Restore the latest snapshot to revert changes made by `bilt fix`.
3
+ import path from "node:path";
4
+ import chalk from "chalk";
5
+ import { getLatestSnapshot, listSnapshots, restoreSnapshot, } from "../core/fix/snapshot.js";
6
+ import { requireSimpleConfirmation } from "../core/fix/confirm.js";
7
+ import { reportUndoComplete } from "../ui/reporter.js";
8
+ import { formatDiff } from "../ui/format.js";
9
+ import { promises as fs } from "node:fs";
10
+ /**
11
+ * Execute the `bilt undo` command.
12
+ *
13
+ * 1. List available snapshots
14
+ * 2. Get latest snapshot
15
+ * 3. Show preview of what will be restored
16
+ * 4. Require confirmation
17
+ * 5. Restore snapshot
18
+ * 6. Report success
19
+ */
20
+ export async function executeUndo(projectDir) {
21
+ const rootDir = path.resolve(projectDir);
22
+ // ── List snapshots ──────────────────────────────────────────────────
23
+ const snapshots = await listSnapshots(rootDir);
24
+ if (snapshots.length === 0) {
25
+ console.log("");
26
+ console.log(chalk.yellow(" ⚠ No snapshots found. Nothing to undo."));
27
+ console.log(chalk.dim(" Snapshots are created automatically when `bilt fix` or `bilt init` makes changes."));
28
+ console.log("");
29
+ return;
30
+ }
31
+ // ── Get latest snapshot ─────────────────────────────────────────────
32
+ const snapshot = await getLatestSnapshot(rootDir);
33
+ if (!snapshot) {
34
+ console.log("");
35
+ console.log(chalk.yellow(" ⚠ Could not load the latest snapshot."));
36
+ console.log("");
37
+ return;
38
+ }
39
+ // ── Preview changes ─────────────────────────────────────────────────
40
+ console.log("");
41
+ console.log(chalk.bold(` ⏪ Snapshot: ${chalk.cyan(snapshot.id)}`));
42
+ console.log(chalk.dim(` ${snapshot.description}`));
43
+ console.log(chalk.dim(` Created: ${new Date(snapshot.timestamp).toLocaleString()}`));
44
+ console.log("");
45
+ console.log(chalk.bold(" Files to restore:"));
46
+ for (const file of snapshot.files) {
47
+ const fullPath = path.join(rootDir, file.path);
48
+ let currentContent = "";
49
+ try {
50
+ currentContent = await fs.readFile(fullPath, "utf-8");
51
+ }
52
+ catch {
53
+ currentContent = "";
54
+ }
55
+ const hasChanged = currentContent !== file.content;
56
+ if (hasChanged) {
57
+ console.log(chalk.yellow(` ↻ ${file.path}`));
58
+ // Show brief diff
59
+ const diff = formatDiff(currentContent, file.content);
60
+ const diffLines = diff.split("\n").slice(0, 8);
61
+ for (const line of diffLines) {
62
+ console.log(` ${line}`);
63
+ }
64
+ if (diff.split("\n").length > 8) {
65
+ console.log(chalk.dim(` … and more`));
66
+ }
67
+ }
68
+ else {
69
+ console.log(chalk.dim(` ✓ ${file.path} (unchanged)`));
70
+ }
71
+ }
72
+ console.log("");
73
+ // ── Confirm ─────────────────────────────────────────────────────────
74
+ const confirmed = await requireSimpleConfirmation({
75
+ id: "undo",
76
+ description: `Restore ${snapshot.files.length} file(s) from snapshot`,
77
+ type: "destructive",
78
+ findingId: "undo",
79
+ apply: async () => true,
80
+ });
81
+ if (!confirmed) {
82
+ console.log(chalk.dim(" Undo cancelled."));
83
+ console.log("");
84
+ return;
85
+ }
86
+ // ── Restore ─────────────────────────────────────────────────────────
87
+ await restoreSnapshot(snapshot.id, rootDir);
88
+ reportUndoComplete(snapshot);
89
+ }
90
+ //# sourceMappingURL=undo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"undo.js","sourceRoot":"","sources":["../../src/commands/undo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { WatchOptions } from "../types/index.js";
2
+ /**
3
+ * Execute the `bilt watch` command.
4
+ *
5
+ * 1. Start file watcher on the project directory
6
+ * 2. On file changes: scan for secrets and report findings
7
+ * 3. Handle SIGINT for graceful shutdown
8
+ */
9
+ export declare function executeWatch(projectDir: string, options?: WatchOptions): Promise<void>;
10
+ //# sourceMappingURL=watch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,mBAAmB,CAAC;AAKlE;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CA0Df"}
@@ -0,0 +1,68 @@
1
+ // ─── Watch Command ───────────────────────────────────────────────────────────
2
+ // Real-time file monitoring with instant secret & env scanning.
3
+ import path from "node:path";
4
+ import chalk from "chalk";
5
+ import { loadConfig } from "../config/config.js";
6
+ import { startWatcher, stopWatcher } from "../core/watch/watcher.js";
7
+ import { reportWatchEvent } from "../ui/reporter.js";
8
+ /**
9
+ * Execute the `bilt watch` command.
10
+ *
11
+ * 1. Start file watcher on the project directory
12
+ * 2. On file changes: scan for secrets and report findings
13
+ * 3. Handle SIGINT for graceful shutdown
14
+ */
15
+ export async function executeWatch(projectDir, options = {}) {
16
+ const rootDir = path.resolve(projectDir);
17
+ const config = await loadConfig(rootDir);
18
+ // ── Status banner ───────────────────────────────────────────────────
19
+ if (!options.quiet) {
20
+ console.log("");
21
+ console.log(chalk.cyan.bold(" 👁️ Bilt Watch Mode"));
22
+ console.log(chalk.dim(` Monitoring ${rootDir} for changes…`));
23
+ console.log(chalk.dim(" Press Ctrl+C to stop."));
24
+ console.log("");
25
+ }
26
+ // ── Start watcher ──────────────────────────────────────────────────
27
+ const watcher = startWatcher(rootDir, config, (event) => {
28
+ // Only report if there are findings or the file was deleted
29
+ if (event.findings.length > 0 || event.type === "unlink") {
30
+ // Map absolute path back to relative path for formatting
31
+ const relativePath = path.relative(rootDir, event.file);
32
+ const relativeFindings = event.findings.map((f) => ({
33
+ ...f,
34
+ file: path.relative(rootDir, f.file),
35
+ }));
36
+ reportWatchEvent({
37
+ ...event,
38
+ file: relativePath,
39
+ findings: relativeFindings,
40
+ });
41
+ }
42
+ });
43
+ // ── Graceful shutdown ──────────────────────────────────────────────
44
+ const cleanup = async () => {
45
+ if (!options.quiet) {
46
+ console.log("");
47
+ console.log(chalk.dim(" Stopping watcher…"));
48
+ }
49
+ await stopWatcher(watcher);
50
+ if (!options.quiet) {
51
+ console.log(chalk.green(" ✓ Watcher stopped."));
52
+ console.log("");
53
+ }
54
+ process.exit(0);
55
+ };
56
+ process.on("SIGINT", () => {
57
+ void cleanup();
58
+ });
59
+ process.on("SIGTERM", () => {
60
+ void cleanup();
61
+ });
62
+ // Keep the process running
63
+ await new Promise(() => {
64
+ // This promise intentionally never resolves — the process stays alive
65
+ // until SIGINT/SIGTERM.
66
+ });
67
+ }
68
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { BiltConfig } from "../types/index.js";
2
+ export declare const DEFAULT_CONFIG: BiltConfig;
3
+ /**
4
+ * Load and merge user configuration with defaults.
5
+ * If no config file exists, returns defaults (zero-config).
6
+ */
7
+ export declare function loadConfig(searchFrom?: string): Promise<BiltConfig>;
8
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD,eAAO,MAAM,cAAc,EAAE,UAsB5B,CAAC;AAoBF;;;GAGG;AACH,wBAAsB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA+BzE"}
@@ -0,0 +1,75 @@
1
+ import { cosmiconfig } from "cosmiconfig";
2
+ // ─── Default Configuration (Zero-Config) ────────────────────────────────────
3
+ export const DEFAULT_CONFIG = {
4
+ ignore: [
5
+ "node_modules/**",
6
+ ".git/**",
7
+ "dist/**",
8
+ "build/**",
9
+ "coverage/**",
10
+ ".bilt/**",
11
+ "*.min.js",
12
+ "*.min.css",
13
+ "*.map",
14
+ "*.lock",
15
+ "package-lock.json",
16
+ "yarn.lock",
17
+ "pnpm-lock.yaml",
18
+ ],
19
+ severityOverrides: {},
20
+ plugins: [],
21
+ entropyThreshold: 4.5,
22
+ historyDepth: 10,
23
+ customRules: [],
24
+ funMode: false,
25
+ };
26
+ // ─── Config Loader ───────────────────────────────────────────────────────────
27
+ const explorer = cosmiconfig("bilt", {
28
+ searchPlaces: [
29
+ ".biltrc",
30
+ ".biltrc.json",
31
+ ".biltrc.yaml",
32
+ ".biltrc.yml",
33
+ ".biltrc.js",
34
+ ".biltrc.cjs",
35
+ ".biltrc.mjs",
36
+ "bilt.config.js",
37
+ "bilt.config.cjs",
38
+ "bilt.config.mjs",
39
+ "bilt.config.ts",
40
+ ],
41
+ });
42
+ /**
43
+ * Load and merge user configuration with defaults.
44
+ * If no config file exists, returns defaults (zero-config).
45
+ */
46
+ export async function loadConfig(searchFrom) {
47
+ try {
48
+ const result = await explorer.search(searchFrom);
49
+ if (!result || result.isEmpty) {
50
+ return { ...DEFAULT_CONFIG };
51
+ }
52
+ const userConfig = result.config;
53
+ return {
54
+ ignore: userConfig.ignore
55
+ ? [...DEFAULT_CONFIG.ignore, ...userConfig.ignore]
56
+ : [...DEFAULT_CONFIG.ignore],
57
+ severityOverrides: {
58
+ ...DEFAULT_CONFIG.severityOverrides,
59
+ ...userConfig.severityOverrides,
60
+ },
61
+ plugins: userConfig.plugins ?? DEFAULT_CONFIG.plugins,
62
+ entropyThreshold: userConfig.entropyThreshold ?? DEFAULT_CONFIG.entropyThreshold,
63
+ historyDepth: userConfig.historyDepth ?? DEFAULT_CONFIG.historyDepth,
64
+ customRules: userConfig.customRules
65
+ ? [...DEFAULT_CONFIG.customRules, ...userConfig.customRules]
66
+ : [...DEFAULT_CONFIG.customRules],
67
+ funMode: userConfig.funMode ?? DEFAULT_CONFIG.funMode,
68
+ };
69
+ }
70
+ catch {
71
+ // If config loading fails, silently use defaults (zero-config philosophy)
72
+ return { ...DEFAULT_CONFIG };
73
+ }
74
+ }
75
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,+EAA+E;AAE/E,MAAM,CAAC,MAAM,cAAc,GAAe;IACxC,MAAM,EAAE;QACN,iBAAiB;QACjB,SAAS;QACT,SAAS;QACT,UAAU;QACV,aAAa;QACb,UAAU;QACV,UAAU;QACV,WAAW;QACX,OAAO;QACP,QAAQ;QACR,mBAAmB;QACnB,WAAW;QACX,gBAAgB;KACjB;IACD,iBAAiB,EAAE,EAAE;IACrB,OAAO,EAAE,EAAE;IACX,gBAAgB,EAAE,GAAG;IACrB,YAAY,EAAE,EAAE;IAChB,WAAW,EAAE,EAAE;IACf,OAAO,EAAE,KAAK;CACf,CAAC;AAEF,gFAAgF;AAEhF,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,EAAE;IACnC,YAAY,EAAE;QACZ,SAAS;QACT,cAAc;QACd,cAAc;QACd,aAAa;QACb,YAAY;QACZ,aAAa;QACb,aAAa;QACb,gBAAgB;QAChB,iBAAiB;QACjB,iBAAiB;QACjB,gBAAgB;KACjB;CACF,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAmB;IAClD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAEjD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;QAC/B,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,CAAC,MAA6B,CAAC;QAExD,OAAO;YACL,MAAM,EAAE,UAAU,CAAC,MAAM;gBACvB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC;gBAClD,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC;YAC9B,iBAAiB,EAAE;gBACjB,GAAG,cAAc,CAAC,iBAAiB;gBACnC,GAAG,UAAU,CAAC,iBAAiB;aAChC;YACD,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,cAAc,CAAC,OAAO;YACrD,gBAAgB,EACd,UAAU,CAAC,gBAAgB,IAAI,cAAc,CAAC,gBAAgB;YAChE,YAAY,EAAE,UAAU,CAAC,YAAY,IAAI,cAAc,CAAC,YAAY;YACpE,WAAW,EAAE,UAAU,CAAC,WAAW;gBACjC,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC;gBAC5D,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,WAAW,CAAC;YACnC,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,cAAc,CAAC,OAAO;SACtD,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { FixAction } from "../../types/index.js";
2
+ /**
3
+ * Prompt the user to type the filename to confirm an **irreversible** action.
4
+ *
5
+ * Used for actions like permanently deleting a file or rewriting git history
6
+ * where a simple y/n is not enough assurance.
7
+ *
8
+ * @param action The fix action being applied.
9
+ * @param fileName The filename the user must type to confirm.
10
+ * @returns `true` if the user typed the correct filename, `false` otherwise.
11
+ */
12
+ export declare function requireTypedConfirmation(action: FixAction, fileName: string): Promise<boolean>;
13
+ /**
14
+ * Prompt the user for a simple y/n confirmation for a **destructive**
15
+ * action.
16
+ *
17
+ * @param action The fix action being applied.
18
+ * @returns `true` if the user confirms, `false` otherwise.
19
+ */
20
+ export declare function requireSimpleConfirmation(action: FixAction): Promise<boolean>;
21
+ //# sourceMappingURL=confirm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm.d.ts","sourceRoot":"","sources":["../../../src/core/fix/confirm.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAOtD;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAkBlB;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,SAAS,GAChB,OAAO,CAAC,OAAO,CAAC,CAiBlB"}