@kb-labs/commit-core 2.118.2 → 2.119.0-canary.85d060ea6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/analyzer/index.d.ts
CHANGED
|
@@ -43,6 +43,14 @@ declare class SecretsDetectedError extends Error {
|
|
|
43
43
|
readonly secretMatches: SecretMatch[];
|
|
44
44
|
constructor(matches: SecretMatch[], message: string);
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Structural check for SecretsDetectedError, safe across subpath-export
|
|
48
|
+
* boundaries (`./analyzer` vs `./generator`). tsup bundles each entry
|
|
49
|
+
* independently, so `error instanceof SecretsDetectedError` fails when the
|
|
50
|
+
* throw site and the catch site pull the class from different subpaths —
|
|
51
|
+
* they end up with two distinct class objects despite identical source.
|
|
52
|
+
*/
|
|
53
|
+
declare function isSecretsDetectedError(error: unknown): error is SecretsDetectedError;
|
|
46
54
|
/**
|
|
47
55
|
* Detailed information about a detected secret
|
|
48
56
|
*/
|
|
@@ -87,4 +95,4 @@ declare function detectSecretsWithLocation(diffs: Map<string, string>): SecretMa
|
|
|
87
95
|
*/
|
|
88
96
|
declare function formatSecretsReport(matches: SecretMatch[]): string;
|
|
89
97
|
|
|
90
|
-
export { type PackageInfo, type ResolvedScope, type SecretMatch, SecretsDetectedError, containsSecrets, detectSecretFiles, detectSecretsInDiffs, detectSecretsWithLocation, formatSecretsReport, formatSecretsWarning, isSecretFile, matchesScope, resolveScope };
|
|
98
|
+
export { type PackageInfo, type ResolvedScope, type SecretMatch, SecretsDetectedError, containsSecrets, detectSecretFiles, detectSecretsInDiffs, detectSecretsWithLocation, formatSecretsReport, formatSecretsWarning, isSecretFile, isSecretsDetectedError, matchesScope, resolveScope };
|
package/dist/analyzer/index.js
CHANGED
|
@@ -396,6 +396,9 @@ var SecretsDetectedError = class _SecretsDetectedError extends Error {
|
|
|
396
396
|
}
|
|
397
397
|
}
|
|
398
398
|
};
|
|
399
|
+
function isSecretsDetectedError(error) {
|
|
400
|
+
return error instanceof Error && error.name === "SecretsDetectedError" && Array.isArray(error.secretMatches);
|
|
401
|
+
}
|
|
399
402
|
var SECRET_FILE_PATTERNS = [
|
|
400
403
|
// Environment files
|
|
401
404
|
".env",
|
|
@@ -580,6 +583,6 @@ function formatSecretsReport(matches) {
|
|
|
580
583
|
return lines.join("\n");
|
|
581
584
|
}
|
|
582
585
|
|
|
583
|
-
export { SecretsDetectedError, containsSecrets, detectCommitStyle, detectSecretFiles, detectSecretsInDiffs, detectSecretsWithLocation, formatFileSummary, formatSecretsReport, formatSecretsWarning, getAllChangedFiles, getCurrentBranch, getFileDiff, getFileDiffs, getFileSummaries, getGitStatus, getRecentCommits, hasChanges, isProtectedBranch, isSecretFile, matchesScope, resolveScope };
|
|
586
|
+
export { SecretsDetectedError, containsSecrets, detectCommitStyle, detectSecretFiles, detectSecretsInDiffs, detectSecretsWithLocation, formatFileSummary, formatSecretsReport, formatSecretsWarning, getAllChangedFiles, getCurrentBranch, getFileDiff, getFileDiffs, getFileSummaries, getGitStatus, getRecentCommits, hasChanges, isProtectedBranch, isSecretFile, isSecretsDetectedError, matchesScope, resolveScope };
|
|
584
587
|
//# sourceMappingURL=index.js.map
|
|
585
588
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/analyzer/git-status.ts","../../src/analyzer/file-summary.ts","../../src/analyzer/file-diff.ts","../../src/analyzer/recent-commits.ts","../../src/analyzer/scope-resolver.ts","../../src/analyzer/secrets-detector.ts"],"names":["simpleGit","group"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Git status analysis\n */\n\nimport { simpleGit, type SimpleGit, type StatusResult } from \"simple-git\";\nimport type { GitStatus } from \"@kb-labs/commit-contracts\";\n\n/**\n * Get current git status (staged, unstaged, untracked files).\n * cwd must already point to the resolved scope directory.\n */\nexport async function getGitStatus(cwd: string): Promise<GitStatus> {\n // --ignore-submodules=all: exclude submodule pointer drift in worktrees\n const git: SimpleGit = simpleGit(cwd);\n const status: StatusResult = await git.status(['--ignore-submodules=all']);\n\n return {\n staged: status.staged.filter((f) => !shouldIgnoreFile(f)),\n unstaged: [...status.modified, ...status.deleted]\n .filter((f) => !status.staged.includes(f))\n .filter((f) => !shouldIgnoreFile(f)),\n untracked: status.not_added.filter((f) => !shouldIgnoreFile(f)),\n };\n}\n\nconst IGNORED_SEGMENTS = new Set([\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \".next\",\n \".turbo\",\n \"coverage\",\n]);\n\n/**\n * Check if file should be ignored (node_modules, dist, etc.)\n * Uses exact path segment matching to avoid false positives like \"my-dist/file.ts\".\n */\nfunction shouldIgnoreFile(file: string): boolean {\n return file.split(\"/\").some((segment) => IGNORED_SEGMENTS.has(segment));\n}\n\n/**\n * Get all changed files (staged + unstaged + untracked)\n * Filters out node_modules and other build artifacts\n */\nexport function getAllChangedFiles(status: GitStatus): string[] {\n const allFiles = [\n ...new Set([...status.staged, ...status.unstaged, ...status.untracked]),\n ];\n return allFiles.filter((file) => !shouldIgnoreFile(file));\n}\n\n/**\n * Check if there are any changes\n */\nexport function hasChanges(status: GitStatus): boolean {\n return (\n status.staged.length > 0 ||\n status.unstaged.length > 0 ||\n status.untracked.length > 0\n );\n}\n\n/**\n * Get current branch name\n */\nexport async function getCurrentBranch(cwd: string): Promise<string> {\n const git: SimpleGit = simpleGit(cwd);\n const branch = await git.revparse([\"--abbrev-ref\", \"HEAD\"]);\n return branch.trim();\n}\n\n/**\n * Check if branch is protected (main/master)\n */\nexport function isProtectedBranch(branch: string): boolean {\n const protectedBranches = [\n \"main\",\n \"master\",\n \"develop\",\n \"release\",\n \"production\",\n ];\n return protectedBranches.includes(branch.toLowerCase());\n}\n","/**\n * File summary extraction\n */\n\n/* eslint-disable no-await-in-loop -- Sequential git operations required: must check status, read diffs, compute summaries one-by-one for each file */\n\nimport {\n simpleGit,\n type SimpleGit,\n type DiffResultTextFile,\n type DiffResultBinaryFile,\n} from \"simple-git\";\nimport type { FileSummary } from \"@kb-labs/commit-contracts\";\n\n/**\n * Type guard for text file diff result\n */\nfunction isTextFile(\n file: DiffResultTextFile | DiffResultBinaryFile,\n): file is DiffResultTextFile {\n return !file.binary;\n}\n\n/**\n * Check if file is truly new (doesn't exist in current HEAD commit)\n * Returns true if file doesn't exist in HEAD (the current committed state)\n * Returns false if file exists in HEAD (even if modified/deleted locally)\n * Supports nested git repositories\n */\nasync function isNewFile(cwd: string, filePath: string): Promise<boolean> {\n try {\n // Find the git repository for this file (walks up directory tree)\n const repo = await findGitRepo(cwd, filePath);\n\n if (!repo) {\n // No git repo found - treat as new file\n return true;\n }\n\n const git = simpleGit(repo.repoPath);\n\n // Check if file exists in HEAD (current commit), not in history\n // git ls-tree HEAD -- <file>\n // Returns tree entry if file exists in HEAD, empty if file is new\n // This correctly handles modified/unstaged files (they exist in HEAD = not new)\n const result = await git.raw([\"ls-tree\", \"HEAD\", \"--\", repo.relativePath]);\n\n // If no output, file doesn't exist in HEAD → truly new file\n // If has output, file exists in HEAD → not new (modified/unstaged)\n return result.trim().length === 0;\n } catch {\n // On error, assume it's new (safer to say \"new\" than claim it existed)\n return true;\n }\n}\n\n/**\n * Get file summaries with diff stats for given files\n * Supports nested git repositories by grouping files per repo\n */\n// eslint-disable-next-line sonarjs/cognitive-complexity -- File summary extraction: groups files by repo, handles nested git repos, computes diff stats, processes staged/unstaged/untracked files\nexport async function getFileSummaries(\n cwd: string,\n files: string[],\n): Promise<FileSummary[]> {\n if (files.length === 0) {\n return [];\n }\n\n const summaries: FileSummary[] = [];\n\n // Group files by repository (walks up directory tree to find .git)\n const filesByRepo = new Map<\n string,\n { repoPath: string; relativePath: string; originalPath: string }[]\n >();\n\n for (const file of files) {\n const repo = await findGitRepo(cwd, file);\n\n if (!repo) {\n // No git repo found - treat as file in cwd\n const group = filesByRepo.get(cwd) ?? [];\n group.push({ repoPath: cwd, relativePath: file, originalPath: file });\n filesByRepo.set(cwd, group);\n continue;\n }\n\n // Group by repository path\n const group = filesByRepo.get(repo.repoPath) ?? [];\n group.push({\n repoPath: repo.repoPath,\n relativePath: repo.relativePath,\n originalPath: file,\n });\n filesByRepo.set(repo.repoPath, group);\n }\n\n // Get diff summaries for each repo separately\n for (const [repoPath, fileInfos] of filesByRepo) {\n const git: SimpleGit = simpleGit(repoPath);\n const relativePaths = fileInfos.map((f) => f.relativePath);\n\n try {\n // Try staged diff first\n const stagedDiff = await git.diffSummary([\n \"--cached\",\n \"--\",\n ...relativePaths,\n ]);\n\n // Then try unstaged diff (working tree changes)\n const unstagedDiff = await git.diffSummary([\"--\", ...relativePaths]);\n\n // Combine results (prefer staged if file appears in both)\n const allDiffFiles = new Map<\n string,\n DiffResultTextFile | DiffResultBinaryFile\n >();\n for (const file of unstagedDiff.files) {\n allDiffFiles.set(file.file, file);\n }\n for (const file of stagedDiff.files) {\n // Staged takes priority\n allDiffFiles.set(file.file, file);\n }\n\n // Process diff results\n for (const file of allDiffFiles.values()) {\n // Find original path (with repo prefix)\n const fileInfo = fileInfos.find((f) => f.relativePath === file.file);\n if (!fileInfo) {\n continue;\n }\n\n // Check if file is truly new (using repoPath as cwd)\n const isNew = await isNewFile(repoPath, file.file);\n\n // Handle both text and binary files\n if (isTextFile(file)) {\n summaries.push({\n path: fileInfo.originalPath,\n status: mapDiffStatus(file.insertions, file.deletions),\n additions: file.insertions,\n deletions: file.deletions,\n binary: false,\n isNewFile: isNew,\n });\n } else {\n // Binary file\n summaries.push({\n path: fileInfo.originalPath,\n status: \"modified\",\n additions: 0,\n deletions: 0,\n binary: true,\n isNewFile: isNew,\n });\n }\n }\n\n // Add any missing files from this repo (untracked - not in git yet)\n const processedPaths = new Set(\n Array.from(allDiffFiles.values()).map((f) => f.file),\n );\n const missingInRepo = fileInfos.filter(\n (f) => !processedPaths.has(f.relativePath),\n );\n\n for (const fileInfo of missingInRepo) {\n // Untracked files are always new (never existed in git)\n summaries.push({\n path: fileInfo.originalPath,\n status: \"added\",\n additions: 0,\n deletions: 0,\n binary: false,\n isNewFile: true,\n });\n }\n } catch {\n // Fallback: create basic summaries for this repo's files\n for (const fileInfo of fileInfos) {\n summaries.push({\n path: fileInfo.originalPath,\n status: \"modified\",\n additions: 0,\n deletions: 0,\n binary: false,\n isNewFile: false, // Conservative assumption\n });\n }\n }\n }\n\n return summaries;\n}\n\n/**\n * Map insertions/deletions to status\n */\nfunction mapDiffStatus(\n insertions: number,\n deletions: number,\n): FileSummary[\"status\"] {\n // Simple heuristic: if only insertions, likely added; if only deletions, likely deleted\n if (deletions === 0 && insertions > 0) {\n return \"added\";\n }\n if (insertions === 0 && deletions > 0) {\n return \"deleted\";\n }\n return \"modified\";\n}\n\n/**\n * Get a short summary string for display\n */\nexport function formatFileSummary(summary: FileSummary): string {\n const stats = summary.binary\n ? \"binary\"\n : `+${summary.additions}/-${summary.deletions}`;\n return `${summary.path} (${summary.status}, ${stats})`;\n}\n\n/**\n * Get diff content for specific files\n * Used when LLM requests more context (Phase 2 escalation)\n * Supports nested git repositories (files with prefix like 'kb-labs-sdk/...')\n */\n// eslint-disable-next-line sonarjs/cognitive-complexity -- Diff extraction: groups files by nested repo, handles staged/unstaged diffs, processes binary files, merges results\nexport async function getFileDiffs(\n cwd: string,\n files: string[],\n): Promise<Map<string, string>> {\n if (files.length === 0) {\n return new Map();\n }\n\n const diffs = new Map<string, string>();\n\n // Group files by repository (walks up directory tree to find .git)\n const filesByRepo = new Map<\n string,\n { repoPath: string; relativePath: string; originalPath: string }[]\n >();\n\n for (const file of files) {\n const repo = await findGitRepo(cwd, file);\n\n if (!repo) {\n // No git repo found - treat as file in cwd\n const group = filesByRepo.get(cwd) ?? [];\n group.push({ repoPath: cwd, relativePath: file, originalPath: file });\n filesByRepo.set(cwd, group);\n continue;\n }\n\n // Group by repository path\n const group = filesByRepo.get(repo.repoPath) ?? [];\n group.push({\n repoPath: repo.repoPath,\n relativePath: repo.relativePath,\n originalPath: file,\n });\n filesByRepo.set(repo.repoPath, group);\n }\n\n // Get diffs for each repo\n for (const [repoPath, fileInfos] of filesByRepo) {\n const git: SimpleGit = simpleGit(repoPath);\n\n for (const { relativePath, originalPath } of fileInfos) {\n try {\n // Try staged diff first, then unstaged\n let diff = await git.diff([\"--cached\", \"--\", relativePath]);\n if (!diff) {\n diff = await git.diff([\"--\", relativePath]);\n }\n if (!diff) {\n // For untracked files, try to read content\n diff = await git.show([`:${relativePath}`]).catch(() => \"\");\n }\n if (diff) {\n diffs.set(originalPath, diff);\n }\n } catch {\n // Skip files that can't be diffed\n }\n }\n }\n\n return diffs;\n}\n\n/**\n * Helper to check if path exists asynchronously\n */\nasync function existsAsync(path: string): Promise<boolean> {\n try {\n const { existsSync } = await import(\"node:fs\");\n return existsSync(path);\n } catch {\n return false;\n }\n}\n\n/**\n * Find the git repository root for a given file path.\n * Walks up the directory tree to find the nearest .git directory.\n *\n * @param basePath - Base path to start searching from (e.g., /Users/user/project)\n * @param filePath - Relative file path (e.g., kb-labs-commit/packages/core/src/index.ts)\n * @returns Object with repoPath (absolute) and relativePath (relative to repo), or null if no repo found\n *\n * @example\n * // For nested repo:\n * findGitRepo('/Users/user/kb-labs', 'kb-labs-commit/packages/core/src/index.ts')\n * // Returns: { repoPath: '/Users/user/kb-labs/kb-labs-commit', relativePath: 'packages/core/src/index.ts' }\n *\n * // For file in root repo:\n * findGitRepo('/Users/user/kb-labs', 'src/index.ts')\n * // Returns: { repoPath: '/Users/user/kb-labs', relativePath: 'src/index.ts' }\n */\nasync function findGitRepo(\n basePath: string,\n filePath: string,\n): Promise<{ repoPath: string; relativePath: string } | null> {\n const segments = filePath.split(\"/\");\n\n // Try progressively shorter paths (walk up the tree)\n // For 'kb-labs-commit/packages/core/src/index.ts', try:\n // 1. basePath/kb-labs-commit/packages/core/src\n // 2. basePath/kb-labs-commit/packages/core\n // 3. basePath/kb-labs-commit/packages\n // 4. basePath/kb-labs-commit\n // 5. basePath (fallback to root)\n\n for (let i = segments.length - 1; i > 0; i--) {\n const potentialRepoSegments = segments.slice(0, i);\n const potentialRepoPath = `${basePath}/${potentialRepoSegments.join(\"/\")}`;\n const gitDir = `${potentialRepoPath}/.git`;\n\n if (await existsAsync(gitDir)) {\n // Found a .git directory - this is the repo root\n const relativePath = segments.slice(i).join(\"/\");\n return { repoPath: potentialRepoPath, relativePath };\n }\n }\n\n // No nested repo found, check if basePath itself is a git repo\n if (await existsAsync(`${basePath}/.git`)) {\n return { repoPath: basePath, relativePath: filePath };\n }\n\n // No git repo found at all\n return null;\n}\n","/**\n * File diff utilities\n */\n\nimport { simpleGit } from \"simple-git\";\n\nexport interface FileDiff {\n diff: string;\n additions: number;\n deletions: number;\n}\n\n/**\n * Get diff for a specific file\n */\nexport async function getFileDiff(\n cwd: string,\n filePath: string,\n): Promise<FileDiff> {\n const git = simpleGit(cwd);\n\n // Get diff for the specific file\n // git diff HEAD -- <file>\n const diffOutput = await git.diff([\"HEAD\", \"--\", filePath]);\n\n // Count additions and deletions\n const additions = (diffOutput.match(/^\\+(?!\\+)/gm) || []).length;\n const deletions = (diffOutput.match(/^-(?!-)/gm) || []).length;\n\n return {\n diff: diffOutput,\n additions,\n deletions,\n };\n}\n","/**\n * Recent commits analysis for style matching\n */\n\nimport { simpleGit, type SimpleGit } from \"simple-git\";\n\n/**\n * Get recent commit messages for style reference\n *\n * @param cwd - Working directory\n * @param count - Number of commits to retrieve (default: 10)\n * @returns Array of commit messages (subject line only)\n */\nexport async function getRecentCommits(\n cwd: string,\n count: number = 10,\n): Promise<string[]> {\n const git: SimpleGit = simpleGit(cwd);\n\n try {\n const log = await git.log({\n maxCount: count,\n format: {\n message: \"%s\", // Subject line only\n },\n });\n\n return log.all.map((commit) => commit.message);\n } catch {\n // Return empty array if no commits or error\n return [];\n }\n}\n\n/**\n * Detect the commit style from recent commits\n *\n * @returns Detected style hints\n */\nexport function detectCommitStyle(commits: string[]): {\n usesConventional: boolean;\n commonScopes: string[];\n avgLength: number;\n} {\n if (commits.length === 0) {\n return {\n usesConventional: false,\n commonScopes: [],\n avgLength: 50,\n };\n }\n\n // Check for conventional commit pattern: type(scope)?: message\n const conventionalPattern =\n /^(feat|fix|docs|style|refactor|test|chore|ci|perf|build)(\\([^)]+\\))?!?:/i;\n const conventionalMatches = commits.filter((c) =>\n conventionalPattern.test(c),\n );\n const usesConventional = conventionalMatches.length >= commits.length * 0.5;\n\n // Extract scopes\n const scopePattern = /^\\w+\\(([^)]+)\\)/;\n const scopes = commits\n .map((c) => {\n const match = c.match(scopePattern);\n return match ? match[1] : null;\n })\n .filter((s): s is string => s !== null);\n\n // Count scope frequency\n const scopeCounts = scopes.reduce<Record<string, number>>((acc, scope) => {\n acc[scope] = (acc[scope] || 0) + 1;\n return acc;\n }, {});\n\n // Get top 5 most common scopes\n const commonScopes = Object.entries(scopeCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 5)\n .map(([scope]) => scope);\n\n // Calculate average message length\n const avgLength = Math.round(\n commits.reduce((sum, c) => sum + c.length, 0) / commits.length,\n );\n\n return {\n usesConventional,\n commonScopes,\n avgLength,\n };\n}\n","/**\n * Scope resolver - converts package names to file path patterns\n * Supports:\n * 1. Exact package name: @kb-labs/core, my-package\n * 2. Wildcard pattern: @kb-labs/core-*, packages/*\n * 3. Path pattern: packages/core/src/**\n */\n\n/* eslint-disable no-await-in-loop -- Sequential file reads required for package.json discovery in nested directories */\n\nimport { readFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport globby from \"globby\";\n\nexport interface ResolvedScope {\n /** Original scope string */\n original: string;\n /** Type of scope */\n type: \"package-name\" | \"wildcard\" | \"path-pattern\";\n /** Resolved package paths (directories) */\n packagePaths: string[];\n /** Pattern to filter files (glob or regex) */\n filePattern?: string;\n}\n\nexport interface PackageInfo {\n name: string;\n path: string;\n}\n\n/**\n * Resolve scope to package paths and file pattern\n */\nexport async function resolveScope(\n cwd: string,\n scope: string,\n): Promise<ResolvedScope> {\n // Detect scope type\n const isExactPackageName =\n !scope.includes(\"*\") && (scope.startsWith(\"@\") || !scope.includes(\"/\"));\n const isWildcardPackageName =\n scope.includes(\"*\") && (scope.startsWith(\"@\") || !scope.includes(\"/\"));\n const _isPathPattern = scope.includes(\"/\") && !scope.startsWith(\"@\");\n\n if (isExactPackageName) {\n // Exact package name: @kb-labs/core\n const packages = await discoverPackages(cwd);\n const matched = packages.filter((pkg) => pkg.name === scope);\n\n return {\n original: scope,\n type: \"package-name\",\n packagePaths: matched.map((p) => p.path),\n filePattern:\n matched.length > 0 ? createGlobPattern(cwd, matched) : undefined,\n };\n }\n\n if (isWildcardPackageName) {\n // Wildcard package name: @kb-labs/core-*\n const packages = await discoverPackages(cwd);\n const regex = createPackageNameRegex(scope);\n const matched = packages.filter((pkg) => regex.test(pkg.name));\n\n return {\n original: scope,\n type: \"wildcard\",\n packagePaths: matched.map((p) => p.path),\n filePattern:\n matched.length > 0 ? createGlobPattern(cwd, matched) : undefined,\n };\n }\n\n // Path pattern: packages/core/** or src/**/*.ts\n // If the scope is a plain directory path (no glob chars), append /** to match all files inside\n const filePattern = !scope.includes(\"*\") && !scope.includes(\"?\")\n ? `${scope}/**`\n : scope;\n return {\n original: scope,\n type: \"path-pattern\",\n packagePaths: [],\n filePattern,\n };\n}\n\n/**\n * Check if a file matches the resolved scope\n */\nexport function matchesScope(\n filePath: string,\n resolvedScope: ResolvedScope,\n): boolean {\n // For package-based scopes, check if file is within any package path\n if (resolvedScope.packagePaths.length > 0) {\n return resolvedScope.packagePaths.some((pkgPath) => {\n // Normalize both paths for comparison\n const normalizedFile = filePath.replace(/\\\\/g, \"/\");\n const normalizedPkg = pkgPath.replace(/\\\\/g, \"/\");\n return (\n normalizedFile.startsWith(normalizedPkg + \"/\") ||\n normalizedFile === normalizedPkg\n );\n });\n }\n\n // For path patterns, use minimatch (caller should handle this)\n return true;\n}\n\n/**\n * Discover all packages in workspace\n */\nasync function discoverPackages(cwd: string): Promise<PackageInfo[]> {\n const packages: PackageInfo[] = [];\n\n // Find all package.json files\n const packageJsonPaths = await globby(\"**/package.json\", {\n cwd,\n absolute: true,\n onlyFiles: true,\n ignore: [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/.git/**\",\n \"**/.*/**\",\n ],\n });\n\n for (const packageJsonPath of packageJsonPaths) {\n try {\n const packagePath = join(packageJsonPath, \"..\");\n const content = await readFile(packageJsonPath, \"utf-8\");\n const packageJson = JSON.parse(content);\n\n // Skip packages without name\n if (!packageJson.name) {\n continue;\n }\n\n packages.push({\n name: packageJson.name,\n path: relative(cwd, packagePath) || \".\",\n });\n } catch {\n // Skip invalid package.json\n }\n }\n\n return packages;\n}\n\n/**\n * Create regex from wildcard package name pattern\n * @kb-labs/core-* -> /^@kb-labs\\/core-.*$/\n */\nfunction createPackageNameRegex(pattern: string): RegExp {\n const escaped = pattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\") // Escape special chars\n .replace(/\\*/g, \".*\"); // Convert * to .*\n return new RegExp(`^${escaped}$`);\n}\n\n/**\n * Create glob pattern from package paths\n */\nfunction createGlobPattern(cwd: string, packages: PackageInfo[]): string {\n if (packages.length === 1 && packages[0]) {\n return `${packages[0].path}/**`;\n }\n // Multiple packages: {pkg1,pkg2}/**\n const paths = packages.map((p) => p.path).join(\",\");\n return `{${paths}}/**`;\n}\n","/**\n * Secrets detection module\n * Detects files that likely contain secrets and should not be sent to LLM\n */\n\nimport { minimatch } from \"minimatch\";\n\n/**\n * Custom error class for secrets detection\n * This error should NEVER be caught and fallback to heuristics\n */\nexport class SecretsDetectedError extends Error {\n public readonly secretMatches: SecretMatch[];\n\n constructor(matches: SecretMatch[], message: string) {\n super(message);\n this.name = 'SecretsDetectedError';\n this.secretMatches = matches;\n\n // Maintain proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SecretsDetectedError);\n }\n }\n}\n\n/**\n * Detailed information about a detected secret\n */\nexport interface SecretMatch {\n file: string;\n line: number;\n column: number;\n pattern: string; // Which pattern matched\n patternName: string; // Human-readable pattern name\n snippet: string; // Code snippet (with context)\n matchedText: string; // The actual matched text (truncated if long)\n}\n\n/**\n * File patterns that likely contain secrets\n * Based on common secret file conventions\n */\nconst SECRET_FILE_PATTERNS = [\n // Environment files\n \".env\",\n \".env.*\",\n \"*.env\",\n \".envrc\",\n\n // NPM/Node\n \".npmrc\",\n \".yarnrc\",\n \".yarnrc.yml\",\n\n // SSH/GPG keys\n \"*.key\",\n \"*.pem\",\n \"*.p12\",\n \"*.pfx\",\n \"id_rsa\",\n \"id_dsa\",\n \"id_ecdsa\",\n \"id_ed25519\",\n \"*.pub\",\n\n // AWS\n \".aws/**\",\n \"credentials\",\n\n // Docker\n \".docker/config.json\",\n\n // Git credentials\n \".git-credentials\",\n \".netrc\",\n\n // Service account files\n \"*-service-account.json\",\n \"*-serviceaccount.json\",\n \"service-account*.json\",\n \"serviceaccount*.json\",\n\n // Kubernetes\n \"kubeconfig\",\n \"*.kubeconfig\",\n\n // Terraform\n \"*.tfvars\",\n \"terraform.tfstate\",\n \"terraform.tfstate.backup\",\n\n // Other common secrets\n \"secrets.yml\",\n \"secrets.yaml\",\n \"secret.yml\",\n \"secret.yaml\",\n \"passwords.txt\",\n \"password.txt\",\n];\n\n/**\n * Content patterns that indicate secrets (with human-readable names)\n */\nconst SECRET_CONTENT_PATTERNS: Array<{ pattern: RegExp; name: string }> = [\n // API keys/tokens\n { pattern: /api[_-]?key[s]?['\":\\s]*[a-zA-Z0-9_-]{20,}/i, name: 'API Key' },\n { pattern: /auth[_-]?token[s]?['\":\\s]*[a-zA-Z0-9_-]{20,}/i, name: 'Auth Token' },\n { pattern: /access[_-]?token[s]?['\":\\s]*[a-zA-Z0-9_-]{20,}/i, name: 'Access Token' },\n\n // AWS\n { pattern: /AKIA[0-9A-Z]{16}/, name: 'AWS Access Key ID' },\n { pattern: /aws[_-]?secret[_-]?access[_-]?key/i, name: 'AWS Secret Access Key' },\n\n // NPM\n { pattern: /\\/\\/registry\\.npmjs\\.org\\/:_authToken=/, name: 'NPM Auth Token' },\n { pattern: /npm_[A-Za-z0-9]{30,}/, name: 'NPM Token' },\n\n // GitHub\n { pattern: /gh[pousr]_[A-Za-z0-9_]{36,}/, name: 'GitHub Token' },\n\n // Slack\n { pattern: /xox[baprs]-[0-9]{10,13}-[0-9]{10,13}-[A-Za-z0-9]{24,}/, name: 'Slack Token' },\n\n // Private keys\n { pattern: /-----BEGIN (RSA|DSA|EC|OPENSSH|PGP) PRIVATE KEY-----/, name: 'Private Key' },\n\n // Passwords\n { pattern: /password['\":\\s]*['\"]/i, name: 'Password' },\n\n // Generic patterns\n { pattern: /secret['\":\\s]*['\"]/i, name: 'Secret' },\n];\n\n/**\n * Check if file path matches secret file patterns\n */\nexport function isSecretFile(filePath: string): boolean {\n // Normalize path separators\n const normalizedPath = filePath.replace(/\\\\/g, \"/\");\n\n return SECRET_FILE_PATTERNS.some((pattern) =>\n minimatch(normalizedPath, pattern, { matchBase: true }),\n );\n}\n\n/**\n * Check if file content contains secret patterns\n */\nexport function containsSecrets(content: string): boolean {\n return SECRET_CONTENT_PATTERNS.some(({ pattern }) => pattern.test(content));\n}\n\n/**\n * Scan files for potential secrets\n * Returns list of files that likely contain secrets\n */\nexport function detectSecretFiles(files: string[]): string[] {\n return files.filter(isSecretFile);\n}\n\n/**\n * Scan file diffs for secrets\n * Returns map of files that contain secrets\n */\nexport function detectSecretsInDiffs(\n diffs: Map<string, string>,\n): Map<string, string> {\n const secretDiffs = new Map<string, string>();\n\n for (const [file, diff] of diffs.entries()) {\n if (containsSecrets(diff)) {\n secretDiffs.set(file, diff);\n }\n }\n\n return secretDiffs;\n}\n\n/**\n * Create error message for detected secrets\n */\nexport function formatSecretsWarning(secretFiles: string[]): string {\n const count = secretFiles.length;\n const filesList = secretFiles.map((f) => ` - ${f}`).join(\"\\n\");\n\n return [\n `🚨 CRITICAL SECURITY ERROR: Detected ${count} file(s) with potential secrets:`,\n filesList,\n \"\",\n \"⛔️ COMMIT GENERATION ABORTED\",\n \"\",\n \"These files contain sensitive data (API keys, tokens, credentials)\",\n \"that MUST NOT be committed to git or sent to LLM.\",\n \"\",\n \"✅ Actions to fix:\",\n \" 1. Add these files to .gitignore\",\n \" 2. Remove secrets from the files (use environment variables instead)\",\n \" 3. If already committed, use git filter-branch or BFG to remove from history\",\n \"\",\n \"⚠️ If you already ran commit:generate before, the secrets may have been\",\n \"sent to OpenAI. Rotate your credentials immediately.\",\n ].join(\"\\n\");\n}\n\n/**\n * Detect secrets in file diffs with exact location information\n * Returns array of SecretMatch with file, line, column, pattern info\n */\nexport function detectSecretsWithLocation(\n diffs: Map<string, string>,\n): SecretMatch[] {\n const matches: SecretMatch[] = [];\n\n for (const [file, diff] of diffs.entries()) {\n const lines = diff.split('\\n');\n\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex] ?? '';\n\n for (const { pattern, name } of SECRET_CONTENT_PATTERNS) {\n // Reset regex lastIndex for global patterns\n pattern.lastIndex = 0;\n\n const match = pattern.exec(line);\n if (match) {\n const matchedText = match[0];\n const column = match.index;\n\n // Create snippet with context (20 chars before, full match, 20 chars after)\n const snippetStart = Math.max(0, column - 20);\n const snippetEnd = Math.min(line.length, column + matchedText.length + 20);\n const snippet = line.substring(snippetStart, snippetEnd);\n\n // Truncate matched text if very long (max 50 chars)\n const displayText = matchedText.length > 50\n ? matchedText.substring(0, 50) + '...'\n : matchedText;\n\n matches.push({\n file,\n line: lineIndex + 1, // 1-based line numbers\n column: column + 1, // 1-based column numbers\n pattern: pattern.source,\n patternName: name,\n snippet: snippet.trim(),\n matchedText: displayText,\n });\n }\n }\n }\n }\n\n return matches;\n}\n\n/**\n * Format detailed secrets report with locations\n */\nexport function formatSecretsReport(matches: SecretMatch[]): string {\n const count = matches.length;\n const fileCount = new Set(matches.map(m => m.file)).size;\n\n const lines = [\n `🚨 CRITICAL SECURITY ERROR: Detected ${count} potential secret(s) in ${fileCount} file(s)`,\n \"\",\n \"⛔️ COMMIT GENERATION BLOCKED\",\n \"\",\n ];\n\n // Group by file\n const byFile = new Map<string, SecretMatch[]>();\n for (const match of matches) {\n const existing = byFile.get(match.file) ?? [];\n existing.push(match);\n byFile.set(match.file, existing);\n }\n\n // Format each file's matches\n for (const [file, fileMatches] of byFile.entries()) {\n lines.push(`📄 ${file}:`);\n for (const match of fileMatches) {\n lines.push(` Line ${match.line}:${match.column} - ${match.patternName}`);\n lines.push(` Pattern: ${match.pattern.substring(0, 60)}${match.pattern.length > 60 ? '...' : ''}`);\n lines.push(` Matched: ${match.matchedText}`);\n lines.push(` Context: ...${match.snippet}...`);\n lines.push('');\n }\n }\n\n lines.push(\n \"🔒 These files contain sensitive data (API keys, tokens, credentials)\",\n \"that MUST NOT be committed to git or sent to LLM.\",\n \"\",\n \"✅ Actions to fix:\",\n \" 1. Review each match above - some may be false positives (e.g., examples in comments)\",\n \" 2. If real secrets: Add files to .gitignore and remove secrets (use env vars)\",\n \" 3. If false positives: Use --allow-secrets flag to proceed with confirmation\",\n \"\",\n \"⚠️ If secrets were already sent to LLM in previous runs, rotate credentials immediately!\",\n );\n\n return lines.join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/analyzer/git-status.ts","../../src/analyzer/file-summary.ts","../../src/analyzer/file-diff.ts","../../src/analyzer/recent-commits.ts","../../src/analyzer/scope-resolver.ts","../../src/analyzer/secrets-detector.ts"],"names":["simpleGit","group"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Git status analysis\n */\n\nimport { simpleGit, type SimpleGit, type StatusResult } from \"simple-git\";\nimport type { GitStatus } from \"@kb-labs/commit-contracts\";\n\n/**\n * Get current git status (staged, unstaged, untracked files).\n * cwd must already point to the resolved scope directory.\n */\nexport async function getGitStatus(cwd: string): Promise<GitStatus> {\n // --ignore-submodules=all: exclude submodule pointer drift in worktrees\n const git: SimpleGit = simpleGit(cwd);\n const status: StatusResult = await git.status(['--ignore-submodules=all']);\n\n return {\n staged: status.staged.filter((f) => !shouldIgnoreFile(f)),\n unstaged: [...status.modified, ...status.deleted]\n .filter((f) => !status.staged.includes(f))\n .filter((f) => !shouldIgnoreFile(f)),\n untracked: status.not_added.filter((f) => !shouldIgnoreFile(f)),\n };\n}\n\nconst IGNORED_SEGMENTS = new Set([\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \".next\",\n \".turbo\",\n \"coverage\",\n]);\n\n/**\n * Check if file should be ignored (node_modules, dist, etc.)\n * Uses exact path segment matching to avoid false positives like \"my-dist/file.ts\".\n */\nfunction shouldIgnoreFile(file: string): boolean {\n return file.split(\"/\").some((segment) => IGNORED_SEGMENTS.has(segment));\n}\n\n/**\n * Get all changed files (staged + unstaged + untracked)\n * Filters out node_modules and other build artifacts\n */\nexport function getAllChangedFiles(status: GitStatus): string[] {\n const allFiles = [\n ...new Set([...status.staged, ...status.unstaged, ...status.untracked]),\n ];\n return allFiles.filter((file) => !shouldIgnoreFile(file));\n}\n\n/**\n * Check if there are any changes\n */\nexport function hasChanges(status: GitStatus): boolean {\n return (\n status.staged.length > 0 ||\n status.unstaged.length > 0 ||\n status.untracked.length > 0\n );\n}\n\n/**\n * Get current branch name\n */\nexport async function getCurrentBranch(cwd: string): Promise<string> {\n const git: SimpleGit = simpleGit(cwd);\n const branch = await git.revparse([\"--abbrev-ref\", \"HEAD\"]);\n return branch.trim();\n}\n\n/**\n * Check if branch is protected (main/master)\n */\nexport function isProtectedBranch(branch: string): boolean {\n const protectedBranches = [\n \"main\",\n \"master\",\n \"develop\",\n \"release\",\n \"production\",\n ];\n return protectedBranches.includes(branch.toLowerCase());\n}\n","/**\n * File summary extraction\n */\n\n/* eslint-disable no-await-in-loop -- Sequential git operations required: must check status, read diffs, compute summaries one-by-one for each file */\n\nimport {\n simpleGit,\n type SimpleGit,\n type DiffResultTextFile,\n type DiffResultBinaryFile,\n} from \"simple-git\";\nimport type { FileSummary } from \"@kb-labs/commit-contracts\";\n\n/**\n * Type guard for text file diff result\n */\nfunction isTextFile(\n file: DiffResultTextFile | DiffResultBinaryFile,\n): file is DiffResultTextFile {\n return !file.binary;\n}\n\n/**\n * Check if file is truly new (doesn't exist in current HEAD commit)\n * Returns true if file doesn't exist in HEAD (the current committed state)\n * Returns false if file exists in HEAD (even if modified/deleted locally)\n * Supports nested git repositories\n */\nasync function isNewFile(cwd: string, filePath: string): Promise<boolean> {\n try {\n // Find the git repository for this file (walks up directory tree)\n const repo = await findGitRepo(cwd, filePath);\n\n if (!repo) {\n // No git repo found - treat as new file\n return true;\n }\n\n const git = simpleGit(repo.repoPath);\n\n // Check if file exists in HEAD (current commit), not in history\n // git ls-tree HEAD -- <file>\n // Returns tree entry if file exists in HEAD, empty if file is new\n // This correctly handles modified/unstaged files (they exist in HEAD = not new)\n const result = await git.raw([\"ls-tree\", \"HEAD\", \"--\", repo.relativePath]);\n\n // If no output, file doesn't exist in HEAD → truly new file\n // If has output, file exists in HEAD → not new (modified/unstaged)\n return result.trim().length === 0;\n } catch {\n // On error, assume it's new (safer to say \"new\" than claim it existed)\n return true;\n }\n}\n\n/**\n * Get file summaries with diff stats for given files\n * Supports nested git repositories by grouping files per repo\n */\n// eslint-disable-next-line sonarjs/cognitive-complexity -- File summary extraction: groups files by repo, handles nested git repos, computes diff stats, processes staged/unstaged/untracked files\nexport async function getFileSummaries(\n cwd: string,\n files: string[],\n): Promise<FileSummary[]> {\n if (files.length === 0) {\n return [];\n }\n\n const summaries: FileSummary[] = [];\n\n // Group files by repository (walks up directory tree to find .git)\n const filesByRepo = new Map<\n string,\n { repoPath: string; relativePath: string; originalPath: string }[]\n >();\n\n for (const file of files) {\n const repo = await findGitRepo(cwd, file);\n\n if (!repo) {\n // No git repo found - treat as file in cwd\n const group = filesByRepo.get(cwd) ?? [];\n group.push({ repoPath: cwd, relativePath: file, originalPath: file });\n filesByRepo.set(cwd, group);\n continue;\n }\n\n // Group by repository path\n const group = filesByRepo.get(repo.repoPath) ?? [];\n group.push({\n repoPath: repo.repoPath,\n relativePath: repo.relativePath,\n originalPath: file,\n });\n filesByRepo.set(repo.repoPath, group);\n }\n\n // Get diff summaries for each repo separately\n for (const [repoPath, fileInfos] of filesByRepo) {\n const git: SimpleGit = simpleGit(repoPath);\n const relativePaths = fileInfos.map((f) => f.relativePath);\n\n try {\n // Try staged diff first\n const stagedDiff = await git.diffSummary([\n \"--cached\",\n \"--\",\n ...relativePaths,\n ]);\n\n // Then try unstaged diff (working tree changes)\n const unstagedDiff = await git.diffSummary([\"--\", ...relativePaths]);\n\n // Combine results (prefer staged if file appears in both)\n const allDiffFiles = new Map<\n string,\n DiffResultTextFile | DiffResultBinaryFile\n >();\n for (const file of unstagedDiff.files) {\n allDiffFiles.set(file.file, file);\n }\n for (const file of stagedDiff.files) {\n // Staged takes priority\n allDiffFiles.set(file.file, file);\n }\n\n // Process diff results\n for (const file of allDiffFiles.values()) {\n // Find original path (with repo prefix)\n const fileInfo = fileInfos.find((f) => f.relativePath === file.file);\n if (!fileInfo) {\n continue;\n }\n\n // Check if file is truly new (using repoPath as cwd)\n const isNew = await isNewFile(repoPath, file.file);\n\n // Handle both text and binary files\n if (isTextFile(file)) {\n summaries.push({\n path: fileInfo.originalPath,\n status: mapDiffStatus(file.insertions, file.deletions),\n additions: file.insertions,\n deletions: file.deletions,\n binary: false,\n isNewFile: isNew,\n });\n } else {\n // Binary file\n summaries.push({\n path: fileInfo.originalPath,\n status: \"modified\",\n additions: 0,\n deletions: 0,\n binary: true,\n isNewFile: isNew,\n });\n }\n }\n\n // Add any missing files from this repo (untracked - not in git yet)\n const processedPaths = new Set(\n Array.from(allDiffFiles.values()).map((f) => f.file),\n );\n const missingInRepo = fileInfos.filter(\n (f) => !processedPaths.has(f.relativePath),\n );\n\n for (const fileInfo of missingInRepo) {\n // Untracked files are always new (never existed in git)\n summaries.push({\n path: fileInfo.originalPath,\n status: \"added\",\n additions: 0,\n deletions: 0,\n binary: false,\n isNewFile: true,\n });\n }\n } catch {\n // Fallback: create basic summaries for this repo's files\n for (const fileInfo of fileInfos) {\n summaries.push({\n path: fileInfo.originalPath,\n status: \"modified\",\n additions: 0,\n deletions: 0,\n binary: false,\n isNewFile: false, // Conservative assumption\n });\n }\n }\n }\n\n return summaries;\n}\n\n/**\n * Map insertions/deletions to status\n */\nfunction mapDiffStatus(\n insertions: number,\n deletions: number,\n): FileSummary[\"status\"] {\n // Simple heuristic: if only insertions, likely added; if only deletions, likely deleted\n if (deletions === 0 && insertions > 0) {\n return \"added\";\n }\n if (insertions === 0 && deletions > 0) {\n return \"deleted\";\n }\n return \"modified\";\n}\n\n/**\n * Get a short summary string for display\n */\nexport function formatFileSummary(summary: FileSummary): string {\n const stats = summary.binary\n ? \"binary\"\n : `+${summary.additions}/-${summary.deletions}`;\n return `${summary.path} (${summary.status}, ${stats})`;\n}\n\n/**\n * Get diff content for specific files\n * Used when LLM requests more context (Phase 2 escalation)\n * Supports nested git repositories (files with prefix like 'kb-labs-sdk/...')\n */\n// eslint-disable-next-line sonarjs/cognitive-complexity -- Diff extraction: groups files by nested repo, handles staged/unstaged diffs, processes binary files, merges results\nexport async function getFileDiffs(\n cwd: string,\n files: string[],\n): Promise<Map<string, string>> {\n if (files.length === 0) {\n return new Map();\n }\n\n const diffs = new Map<string, string>();\n\n // Group files by repository (walks up directory tree to find .git)\n const filesByRepo = new Map<\n string,\n { repoPath: string; relativePath: string; originalPath: string }[]\n >();\n\n for (const file of files) {\n const repo = await findGitRepo(cwd, file);\n\n if (!repo) {\n // No git repo found - treat as file in cwd\n const group = filesByRepo.get(cwd) ?? [];\n group.push({ repoPath: cwd, relativePath: file, originalPath: file });\n filesByRepo.set(cwd, group);\n continue;\n }\n\n // Group by repository path\n const group = filesByRepo.get(repo.repoPath) ?? [];\n group.push({\n repoPath: repo.repoPath,\n relativePath: repo.relativePath,\n originalPath: file,\n });\n filesByRepo.set(repo.repoPath, group);\n }\n\n // Get diffs for each repo\n for (const [repoPath, fileInfos] of filesByRepo) {\n const git: SimpleGit = simpleGit(repoPath);\n\n for (const { relativePath, originalPath } of fileInfos) {\n try {\n // Try staged diff first, then unstaged\n let diff = await git.diff([\"--cached\", \"--\", relativePath]);\n if (!diff) {\n diff = await git.diff([\"--\", relativePath]);\n }\n if (!diff) {\n // For untracked files, try to read content\n diff = await git.show([`:${relativePath}`]).catch(() => \"\");\n }\n if (diff) {\n diffs.set(originalPath, diff);\n }\n } catch {\n // Skip files that can't be diffed\n }\n }\n }\n\n return diffs;\n}\n\n/**\n * Helper to check if path exists asynchronously\n */\nasync function existsAsync(path: string): Promise<boolean> {\n try {\n const { existsSync } = await import(\"node:fs\");\n return existsSync(path);\n } catch {\n return false;\n }\n}\n\n/**\n * Find the git repository root for a given file path.\n * Walks up the directory tree to find the nearest .git directory.\n *\n * @param basePath - Base path to start searching from (e.g., /Users/user/project)\n * @param filePath - Relative file path (e.g., kb-labs-commit/packages/core/src/index.ts)\n * @returns Object with repoPath (absolute) and relativePath (relative to repo), or null if no repo found\n *\n * @example\n * // For nested repo:\n * findGitRepo('/Users/user/kb-labs', 'kb-labs-commit/packages/core/src/index.ts')\n * // Returns: { repoPath: '/Users/user/kb-labs/kb-labs-commit', relativePath: 'packages/core/src/index.ts' }\n *\n * // For file in root repo:\n * findGitRepo('/Users/user/kb-labs', 'src/index.ts')\n * // Returns: { repoPath: '/Users/user/kb-labs', relativePath: 'src/index.ts' }\n */\nasync function findGitRepo(\n basePath: string,\n filePath: string,\n): Promise<{ repoPath: string; relativePath: string } | null> {\n const segments = filePath.split(\"/\");\n\n // Try progressively shorter paths (walk up the tree)\n // For 'kb-labs-commit/packages/core/src/index.ts', try:\n // 1. basePath/kb-labs-commit/packages/core/src\n // 2. basePath/kb-labs-commit/packages/core\n // 3. basePath/kb-labs-commit/packages\n // 4. basePath/kb-labs-commit\n // 5. basePath (fallback to root)\n\n for (let i = segments.length - 1; i > 0; i--) {\n const potentialRepoSegments = segments.slice(0, i);\n const potentialRepoPath = `${basePath}/${potentialRepoSegments.join(\"/\")}`;\n const gitDir = `${potentialRepoPath}/.git`;\n\n if (await existsAsync(gitDir)) {\n // Found a .git directory - this is the repo root\n const relativePath = segments.slice(i).join(\"/\");\n return { repoPath: potentialRepoPath, relativePath };\n }\n }\n\n // No nested repo found, check if basePath itself is a git repo\n if (await existsAsync(`${basePath}/.git`)) {\n return { repoPath: basePath, relativePath: filePath };\n }\n\n // No git repo found at all\n return null;\n}\n","/**\n * File diff utilities\n */\n\nimport { simpleGit } from \"simple-git\";\n\nexport interface FileDiff {\n diff: string;\n additions: number;\n deletions: number;\n}\n\n/**\n * Get diff for a specific file\n */\nexport async function getFileDiff(\n cwd: string,\n filePath: string,\n): Promise<FileDiff> {\n const git = simpleGit(cwd);\n\n // Get diff for the specific file\n // git diff HEAD -- <file>\n const diffOutput = await git.diff([\"HEAD\", \"--\", filePath]);\n\n // Count additions and deletions\n const additions = (diffOutput.match(/^\\+(?!\\+)/gm) || []).length;\n const deletions = (diffOutput.match(/^-(?!-)/gm) || []).length;\n\n return {\n diff: diffOutput,\n additions,\n deletions,\n };\n}\n","/**\n * Recent commits analysis for style matching\n */\n\nimport { simpleGit, type SimpleGit } from \"simple-git\";\n\n/**\n * Get recent commit messages for style reference\n *\n * @param cwd - Working directory\n * @param count - Number of commits to retrieve (default: 10)\n * @returns Array of commit messages (subject line only)\n */\nexport async function getRecentCommits(\n cwd: string,\n count: number = 10,\n): Promise<string[]> {\n const git: SimpleGit = simpleGit(cwd);\n\n try {\n const log = await git.log({\n maxCount: count,\n format: {\n message: \"%s\", // Subject line only\n },\n });\n\n return log.all.map((commit) => commit.message);\n } catch {\n // Return empty array if no commits or error\n return [];\n }\n}\n\n/**\n * Detect the commit style from recent commits\n *\n * @returns Detected style hints\n */\nexport function detectCommitStyle(commits: string[]): {\n usesConventional: boolean;\n commonScopes: string[];\n avgLength: number;\n} {\n if (commits.length === 0) {\n return {\n usesConventional: false,\n commonScopes: [],\n avgLength: 50,\n };\n }\n\n // Check for conventional commit pattern: type(scope)?: message\n const conventionalPattern =\n /^(feat|fix|docs|style|refactor|test|chore|ci|perf|build)(\\([^)]+\\))?!?:/i;\n const conventionalMatches = commits.filter((c) =>\n conventionalPattern.test(c),\n );\n const usesConventional = conventionalMatches.length >= commits.length * 0.5;\n\n // Extract scopes\n const scopePattern = /^\\w+\\(([^)]+)\\)/;\n const scopes = commits\n .map((c) => {\n const match = c.match(scopePattern);\n return match ? match[1] : null;\n })\n .filter((s): s is string => s !== null);\n\n // Count scope frequency\n const scopeCounts = scopes.reduce<Record<string, number>>((acc, scope) => {\n acc[scope] = (acc[scope] || 0) + 1;\n return acc;\n }, {});\n\n // Get top 5 most common scopes\n const commonScopes = Object.entries(scopeCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 5)\n .map(([scope]) => scope);\n\n // Calculate average message length\n const avgLength = Math.round(\n commits.reduce((sum, c) => sum + c.length, 0) / commits.length,\n );\n\n return {\n usesConventional,\n commonScopes,\n avgLength,\n };\n}\n","/**\n * Scope resolver - converts package names to file path patterns\n * Supports:\n * 1. Exact package name: @kb-labs/core, my-package\n * 2. Wildcard pattern: @kb-labs/core-*, packages/*\n * 3. Path pattern: packages/core/src/**\n */\n\n/* eslint-disable no-await-in-loop -- Sequential file reads required for package.json discovery in nested directories */\n\nimport { readFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport globby from \"globby\";\n\nexport interface ResolvedScope {\n /** Original scope string */\n original: string;\n /** Type of scope */\n type: \"package-name\" | \"wildcard\" | \"path-pattern\";\n /** Resolved package paths (directories) */\n packagePaths: string[];\n /** Pattern to filter files (glob or regex) */\n filePattern?: string;\n}\n\nexport interface PackageInfo {\n name: string;\n path: string;\n}\n\n/**\n * Resolve scope to package paths and file pattern\n */\nexport async function resolveScope(\n cwd: string,\n scope: string,\n): Promise<ResolvedScope> {\n // Detect scope type\n const isExactPackageName =\n !scope.includes(\"*\") && (scope.startsWith(\"@\") || !scope.includes(\"/\"));\n const isWildcardPackageName =\n scope.includes(\"*\") && (scope.startsWith(\"@\") || !scope.includes(\"/\"));\n const _isPathPattern = scope.includes(\"/\") && !scope.startsWith(\"@\");\n\n if (isExactPackageName) {\n // Exact package name: @kb-labs/core\n const packages = await discoverPackages(cwd);\n const matched = packages.filter((pkg) => pkg.name === scope);\n\n return {\n original: scope,\n type: \"package-name\",\n packagePaths: matched.map((p) => p.path),\n filePattern:\n matched.length > 0 ? createGlobPattern(cwd, matched) : undefined,\n };\n }\n\n if (isWildcardPackageName) {\n // Wildcard package name: @kb-labs/core-*\n const packages = await discoverPackages(cwd);\n const regex = createPackageNameRegex(scope);\n const matched = packages.filter((pkg) => regex.test(pkg.name));\n\n return {\n original: scope,\n type: \"wildcard\",\n packagePaths: matched.map((p) => p.path),\n filePattern:\n matched.length > 0 ? createGlobPattern(cwd, matched) : undefined,\n };\n }\n\n // Path pattern: packages/core/** or src/**/*.ts\n // If the scope is a plain directory path (no glob chars), append /** to match all files inside\n const filePattern = !scope.includes(\"*\") && !scope.includes(\"?\")\n ? `${scope}/**`\n : scope;\n return {\n original: scope,\n type: \"path-pattern\",\n packagePaths: [],\n filePattern,\n };\n}\n\n/**\n * Check if a file matches the resolved scope\n */\nexport function matchesScope(\n filePath: string,\n resolvedScope: ResolvedScope,\n): boolean {\n // For package-based scopes, check if file is within any package path\n if (resolvedScope.packagePaths.length > 0) {\n return resolvedScope.packagePaths.some((pkgPath) => {\n // Normalize both paths for comparison\n const normalizedFile = filePath.replace(/\\\\/g, \"/\");\n const normalizedPkg = pkgPath.replace(/\\\\/g, \"/\");\n return (\n normalizedFile.startsWith(normalizedPkg + \"/\") ||\n normalizedFile === normalizedPkg\n );\n });\n }\n\n // For path patterns, use minimatch (caller should handle this)\n return true;\n}\n\n/**\n * Discover all packages in workspace\n */\nasync function discoverPackages(cwd: string): Promise<PackageInfo[]> {\n const packages: PackageInfo[] = [];\n\n // Find all package.json files\n const packageJsonPaths = await globby(\"**/package.json\", {\n cwd,\n absolute: true,\n onlyFiles: true,\n ignore: [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/.git/**\",\n \"**/.*/**\",\n ],\n });\n\n for (const packageJsonPath of packageJsonPaths) {\n try {\n const packagePath = join(packageJsonPath, \"..\");\n const content = await readFile(packageJsonPath, \"utf-8\");\n const packageJson = JSON.parse(content);\n\n // Skip packages without name\n if (!packageJson.name) {\n continue;\n }\n\n packages.push({\n name: packageJson.name,\n path: relative(cwd, packagePath) || \".\",\n });\n } catch {\n // Skip invalid package.json\n }\n }\n\n return packages;\n}\n\n/**\n * Create regex from wildcard package name pattern\n * @kb-labs/core-* -> /^@kb-labs\\/core-.*$/\n */\nfunction createPackageNameRegex(pattern: string): RegExp {\n const escaped = pattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\") // Escape special chars\n .replace(/\\*/g, \".*\"); // Convert * to .*\n return new RegExp(`^${escaped}$`);\n}\n\n/**\n * Create glob pattern from package paths\n */\nfunction createGlobPattern(cwd: string, packages: PackageInfo[]): string {\n if (packages.length === 1 && packages[0]) {\n return `${packages[0].path}/**`;\n }\n // Multiple packages: {pkg1,pkg2}/**\n const paths = packages.map((p) => p.path).join(\",\");\n return `{${paths}}/**`;\n}\n","/**\n * Secrets detection module\n * Detects files that likely contain secrets and should not be sent to LLM\n */\n\nimport { minimatch } from \"minimatch\";\n\n/**\n * Custom error class for secrets detection\n * This error should NEVER be caught and fallback to heuristics\n */\nexport class SecretsDetectedError extends Error {\n public readonly secretMatches: SecretMatch[];\n\n constructor(matches: SecretMatch[], message: string) {\n super(message);\n this.name = 'SecretsDetectedError';\n this.secretMatches = matches;\n\n // Maintain proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SecretsDetectedError);\n }\n }\n}\n\n/**\n * Structural check for SecretsDetectedError, safe across subpath-export\n * boundaries (`./analyzer` vs `./generator`). tsup bundles each entry\n * independently, so `error instanceof SecretsDetectedError` fails when the\n * throw site and the catch site pull the class from different subpaths —\n * they end up with two distinct class objects despite identical source.\n */\nexport function isSecretsDetectedError(error: unknown): error is SecretsDetectedError {\n return (\n error instanceof Error &&\n error.name === 'SecretsDetectedError' &&\n Array.isArray((error as SecretsDetectedError).secretMatches)\n );\n}\n\n/**\n * Detailed information about a detected secret\n */\nexport interface SecretMatch {\n file: string;\n line: number;\n column: number;\n pattern: string; // Which pattern matched\n patternName: string; // Human-readable pattern name\n snippet: string; // Code snippet (with context)\n matchedText: string; // The actual matched text (truncated if long)\n}\n\n/**\n * File patterns that likely contain secrets\n * Based on common secret file conventions\n */\nconst SECRET_FILE_PATTERNS = [\n // Environment files\n \".env\",\n \".env.*\",\n \"*.env\",\n \".envrc\",\n\n // NPM/Node\n \".npmrc\",\n \".yarnrc\",\n \".yarnrc.yml\",\n\n // SSH/GPG keys\n \"*.key\",\n \"*.pem\",\n \"*.p12\",\n \"*.pfx\",\n \"id_rsa\",\n \"id_dsa\",\n \"id_ecdsa\",\n \"id_ed25519\",\n \"*.pub\",\n\n // AWS\n \".aws/**\",\n \"credentials\",\n\n // Docker\n \".docker/config.json\",\n\n // Git credentials\n \".git-credentials\",\n \".netrc\",\n\n // Service account files\n \"*-service-account.json\",\n \"*-serviceaccount.json\",\n \"service-account*.json\",\n \"serviceaccount*.json\",\n\n // Kubernetes\n \"kubeconfig\",\n \"*.kubeconfig\",\n\n // Terraform\n \"*.tfvars\",\n \"terraform.tfstate\",\n \"terraform.tfstate.backup\",\n\n // Other common secrets\n \"secrets.yml\",\n \"secrets.yaml\",\n \"secret.yml\",\n \"secret.yaml\",\n \"passwords.txt\",\n \"password.txt\",\n];\n\n/**\n * Content patterns that indicate secrets (with human-readable names)\n */\nconst SECRET_CONTENT_PATTERNS: Array<{ pattern: RegExp; name: string }> = [\n // API keys/tokens\n { pattern: /api[_-]?key[s]?['\":\\s]*[a-zA-Z0-9_-]{20,}/i, name: 'API Key' },\n { pattern: /auth[_-]?token[s]?['\":\\s]*[a-zA-Z0-9_-]{20,}/i, name: 'Auth Token' },\n { pattern: /access[_-]?token[s]?['\":\\s]*[a-zA-Z0-9_-]{20,}/i, name: 'Access Token' },\n\n // AWS\n { pattern: /AKIA[0-9A-Z]{16}/, name: 'AWS Access Key ID' },\n { pattern: /aws[_-]?secret[_-]?access[_-]?key/i, name: 'AWS Secret Access Key' },\n\n // NPM\n { pattern: /\\/\\/registry\\.npmjs\\.org\\/:_authToken=/, name: 'NPM Auth Token' },\n { pattern: /npm_[A-Za-z0-9]{30,}/, name: 'NPM Token' },\n\n // GitHub\n { pattern: /gh[pousr]_[A-Za-z0-9_]{36,}/, name: 'GitHub Token' },\n\n // Slack\n { pattern: /xox[baprs]-[0-9]{10,13}-[0-9]{10,13}-[A-Za-z0-9]{24,}/, name: 'Slack Token' },\n\n // Private keys\n { pattern: /-----BEGIN (RSA|DSA|EC|OPENSSH|PGP) PRIVATE KEY-----/, name: 'Private Key' },\n\n // Passwords\n { pattern: /password['\":\\s]*['\"]/i, name: 'Password' },\n\n // Generic patterns\n { pattern: /secret['\":\\s]*['\"]/i, name: 'Secret' },\n];\n\n/**\n * Check if file path matches secret file patterns\n */\nexport function isSecretFile(filePath: string): boolean {\n // Normalize path separators\n const normalizedPath = filePath.replace(/\\\\/g, \"/\");\n\n return SECRET_FILE_PATTERNS.some((pattern) =>\n minimatch(normalizedPath, pattern, { matchBase: true }),\n );\n}\n\n/**\n * Check if file content contains secret patterns\n */\nexport function containsSecrets(content: string): boolean {\n return SECRET_CONTENT_PATTERNS.some(({ pattern }) => pattern.test(content));\n}\n\n/**\n * Scan files for potential secrets\n * Returns list of files that likely contain secrets\n */\nexport function detectSecretFiles(files: string[]): string[] {\n return files.filter(isSecretFile);\n}\n\n/**\n * Scan file diffs for secrets\n * Returns map of files that contain secrets\n */\nexport function detectSecretsInDiffs(\n diffs: Map<string, string>,\n): Map<string, string> {\n const secretDiffs = new Map<string, string>();\n\n for (const [file, diff] of diffs.entries()) {\n if (containsSecrets(diff)) {\n secretDiffs.set(file, diff);\n }\n }\n\n return secretDiffs;\n}\n\n/**\n * Create error message for detected secrets\n */\nexport function formatSecretsWarning(secretFiles: string[]): string {\n const count = secretFiles.length;\n const filesList = secretFiles.map((f) => ` - ${f}`).join(\"\\n\");\n\n return [\n `🚨 CRITICAL SECURITY ERROR: Detected ${count} file(s) with potential secrets:`,\n filesList,\n \"\",\n \"⛔️ COMMIT GENERATION ABORTED\",\n \"\",\n \"These files contain sensitive data (API keys, tokens, credentials)\",\n \"that MUST NOT be committed to git or sent to LLM.\",\n \"\",\n \"✅ Actions to fix:\",\n \" 1. Add these files to .gitignore\",\n \" 2. Remove secrets from the files (use environment variables instead)\",\n \" 3. If already committed, use git filter-branch or BFG to remove from history\",\n \"\",\n \"⚠️ If you already ran commit:generate before, the secrets may have been\",\n \"sent to OpenAI. Rotate your credentials immediately.\",\n ].join(\"\\n\");\n}\n\n/**\n * Detect secrets in file diffs with exact location information\n * Returns array of SecretMatch with file, line, column, pattern info\n */\nexport function detectSecretsWithLocation(\n diffs: Map<string, string>,\n): SecretMatch[] {\n const matches: SecretMatch[] = [];\n\n for (const [file, diff] of diffs.entries()) {\n const lines = diff.split('\\n');\n\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex] ?? '';\n\n for (const { pattern, name } of SECRET_CONTENT_PATTERNS) {\n // Reset regex lastIndex for global patterns\n pattern.lastIndex = 0;\n\n const match = pattern.exec(line);\n if (match) {\n const matchedText = match[0];\n const column = match.index;\n\n // Create snippet with context (20 chars before, full match, 20 chars after)\n const snippetStart = Math.max(0, column - 20);\n const snippetEnd = Math.min(line.length, column + matchedText.length + 20);\n const snippet = line.substring(snippetStart, snippetEnd);\n\n // Truncate matched text if very long (max 50 chars)\n const displayText = matchedText.length > 50\n ? matchedText.substring(0, 50) + '...'\n : matchedText;\n\n matches.push({\n file,\n line: lineIndex + 1, // 1-based line numbers\n column: column + 1, // 1-based column numbers\n pattern: pattern.source,\n patternName: name,\n snippet: snippet.trim(),\n matchedText: displayText,\n });\n }\n }\n }\n }\n\n return matches;\n}\n\n/**\n * Format detailed secrets report with locations\n */\nexport function formatSecretsReport(matches: SecretMatch[]): string {\n const count = matches.length;\n const fileCount = new Set(matches.map(m => m.file)).size;\n\n const lines = [\n `🚨 CRITICAL SECURITY ERROR: Detected ${count} potential secret(s) in ${fileCount} file(s)`,\n \"\",\n \"⛔️ COMMIT GENERATION BLOCKED\",\n \"\",\n ];\n\n // Group by file\n const byFile = new Map<string, SecretMatch[]>();\n for (const match of matches) {\n const existing = byFile.get(match.file) ?? [];\n existing.push(match);\n byFile.set(match.file, existing);\n }\n\n // Format each file's matches\n for (const [file, fileMatches] of byFile.entries()) {\n lines.push(`📄 ${file}:`);\n for (const match of fileMatches) {\n lines.push(` Line ${match.line}:${match.column} - ${match.patternName}`);\n lines.push(` Pattern: ${match.pattern.substring(0, 60)}${match.pattern.length > 60 ? '...' : ''}`);\n lines.push(` Matched: ${match.matchedText}`);\n lines.push(` Context: ...${match.snippet}...`);\n lines.push('');\n }\n }\n\n lines.push(\n \"🔒 These files contain sensitive data (API keys, tokens, credentials)\",\n \"that MUST NOT be committed to git or sent to LLM.\",\n \"\",\n \"✅ Actions to fix:\",\n \" 1. Review each match above - some may be false positives (e.g., examples in comments)\",\n \" 2. If real secrets: Add files to .gitignore and remove secrets (use env vars)\",\n \" 3. If false positives: Use --allow-secrets flag to proceed with confirmation\",\n \"\",\n \"⚠️ If secrets were already sent to LLM in previous runs, rotate credentials immediately!\",\n );\n\n return lines.join(\"\\n\");\n}\n"]}
|