@kb-labs/commit-core 2.116.14 → 2.118.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.
package/dist/index.d.ts CHANGED
@@ -2,5 +2,6 @@ export { A as ApplyOptions, G as GenerateOptions, a as GitStatusWithStaleness, L
2
2
  export { F as FileDiff, d as detectCommitStyle, f as formatFileSummary, g as getAllChangedFiles, a as getCurrentBranch, b as getFileDiff, c as getFileSummaries, e as getGitStatus, h as getRecentCommits, i as hasChanges, j as isProtectedBranch } from './recent-commits-BnietMgO.js';
3
3
  export { S as SYSTEM_PROMPT, b as buildPrompt, g as generateCommitPlan, a as generateHeuristicPlan, p as parseResponse } from './heuristics-AM06lXSo.js';
4
4
  export { applyCommitPlan, formatCommitMessage, pushCommits } from './applier/index.js';
5
+ export { checkPlanStaleness, groupFilesByRepo, validatePlanIntegrity } from './validator/index.js';
5
6
  export { clearPlan, getCommitStoragePath, getCurrentPlanPath, getCurrentStatusPath, hasPlan, initStorage, listHistory, loadPlan, loadStatus, savePlan, saveToHistory } from './storage/index.js';
6
7
  export { ApplyResult, CommitGroup, CommitPlan, ConventionalType, FileSummary, GitStatus, GitStatusSnapshot, PushResult, ReleaseHint } from '@kb-labs/commit-contracts';
package/dist/index.js CHANGED
@@ -2029,7 +2029,7 @@ async function generateCommitPlan(options) {
2029
2029
  const { cwd, onProgress } = options;
2030
2030
  const logger = useLogger();
2031
2031
  const analytics = useAnalytics();
2032
- const llm = useLLM();
2032
+ const llm = options.llmComplete ? useLLM() : void 0;
2033
2033
  const startTime = Date.now();
2034
2034
  const gitStatus = await getGitStatus(cwd);
2035
2035
  const allFiles = getAllChangedFiles(gitStatus);
@@ -2766,6 +2766,98 @@ function getErrorType(error) {
2766
2766
  const preview = error.message.substring(0, 50).replace(/\n/g, " ");
2767
2767
  return `error: ${preview}${error.message.length > 50 ? "..." : ""}`;
2768
2768
  }
2769
+ function groupFilesByRepo(cwd, files) {
2770
+ const filesByRepo = /* @__PURE__ */ new Map();
2771
+ for (const file of files) {
2772
+ const segments = file.split("/");
2773
+ const potentialRepoDir = segments[0];
2774
+ if (!potentialRepoDir) {
2775
+ const group = filesByRepo.get(cwd) ?? [];
2776
+ group.push({ relativePath: file, originalPath: file });
2777
+ filesByRepo.set(cwd, group);
2778
+ continue;
2779
+ }
2780
+ const potentialRepoPath = join(cwd, potentialRepoDir);
2781
+ const potentialGitDir = join(potentialRepoPath, ".git");
2782
+ const isNestedRepo = existsSync(potentialGitDir);
2783
+ if (isNestedRepo) {
2784
+ const relativePath = segments.slice(1).join("/");
2785
+ const group = filesByRepo.get(potentialRepoPath) ?? [];
2786
+ group.push({ relativePath, originalPath: file });
2787
+ filesByRepo.set(potentialRepoPath, group);
2788
+ } else {
2789
+ const group = filesByRepo.get(cwd) ?? [];
2790
+ group.push({ relativePath: file, originalPath: file });
2791
+ filesByRepo.set(cwd, group);
2792
+ }
2793
+ }
2794
+ return filesByRepo;
2795
+ }
2796
+ function validatePlanIntegrity(plan) {
2797
+ const errors = [];
2798
+ const seenInCommit = /* @__PURE__ */ new Map();
2799
+ for (const commit of plan.commits) {
2800
+ if (commit.files.length === 0) {
2801
+ errors.push(`Commit ${commit.id} has no files`);
2802
+ continue;
2803
+ }
2804
+ if (!commit.message.trim()) {
2805
+ errors.push(`Commit ${commit.id} has empty message`);
2806
+ continue;
2807
+ }
2808
+ for (const file of commit.files) {
2809
+ const firstCommit = seenInCommit.get(file);
2810
+ if (firstCommit) {
2811
+ errors.push(
2812
+ `File appears in multiple commits: ${file} (first: ${firstCommit}, duplicate: ${commit.id})`
2813
+ );
2814
+ } else {
2815
+ seenInCommit.set(file, commit.id);
2816
+ }
2817
+ }
2818
+ }
2819
+ return errors;
2820
+ }
2821
+ async function checkPlanStaleness(cwd, plan, scope) {
2822
+ const logger = useLogger();
2823
+ const planFiles = new Set(plan.commits.flatMap((c) => c.files));
2824
+ await logger.debug("checkPlanStaleness: start", {
2825
+ scope,
2826
+ cwd,
2827
+ planFiles: [...planFiles]
2828
+ });
2829
+ if (planFiles.size === 0) {
2830
+ return { isStale: false, reason: "" };
2831
+ }
2832
+ const filesByRepo = groupFilesByRepo(cwd, [...planFiles]);
2833
+ for (const [repoPath, fileInfos] of filesByRepo) {
2834
+ const currentStatus = await getGitStatus(repoPath);
2835
+ const currentFiles = new Set(getAllChangedFiles(currentStatus));
2836
+ await logger.debug("checkPlanStaleness: repo status", {
2837
+ repoPath,
2838
+ staged: currentStatus.staged,
2839
+ unstaged: currentStatus.unstaged,
2840
+ untracked: currentStatus.untracked,
2841
+ expected: fileInfos.map((f) => f.relativePath)
2842
+ });
2843
+ for (const { relativePath, originalPath } of fileInfos) {
2844
+ if (!currentFiles.has(relativePath)) {
2845
+ await logger.warn("checkPlanStaleness: file not in current changes", {
2846
+ scope,
2847
+ repoPath,
2848
+ originalPath,
2849
+ relativePath,
2850
+ currentFiles: [...currentFiles]
2851
+ });
2852
+ return {
2853
+ isStale: true,
2854
+ reason: `File no longer has changes: ${originalPath}. Regenerate plan or use --force.`
2855
+ };
2856
+ }
2857
+ }
2858
+ }
2859
+ return { isStale: false, reason: "" };
2860
+ }
2769
2861
  var GIT_HOOK_NAMES = [
2770
2862
  "pre-commit",
2771
2863
  "commit-msg",
@@ -2811,7 +2903,7 @@ async function applyCommitPlan(cwd, plan, options) {
2811
2903
  };
2812
2904
  }
2813
2905
  if (!options?.force) {
2814
- const staleness = await checkStaleness(cwd, plan, options?.scope);
2906
+ const staleness = await checkPlanStaleness(cwd, plan, options?.scope);
2815
2907
  if (staleness.isStale) {
2816
2908
  return {
2817
2909
  success: false,
@@ -2840,31 +2932,6 @@ async function applyCommitPlan(cwd, plan, options) {
2840
2932
  errors
2841
2933
  };
2842
2934
  }
2843
- function validatePlanIntegrity(plan) {
2844
- const errors = [];
2845
- const seenInCommit = /* @__PURE__ */ new Map();
2846
- for (const commit of plan.commits) {
2847
- if (commit.files.length === 0) {
2848
- errors.push(`Commit ${commit.id} has no files`);
2849
- continue;
2850
- }
2851
- if (!commit.message.trim()) {
2852
- errors.push(`Commit ${commit.id} has empty message`);
2853
- continue;
2854
- }
2855
- for (const file of commit.files) {
2856
- const firstCommit = seenInCommit.get(file);
2857
- if (firstCommit) {
2858
- errors.push(
2859
- `File appears in multiple commits: ${file} (first: ${firstCommit}, duplicate: ${commit.id})`
2860
- );
2861
- } else {
2862
- seenInCommit.set(file, commit.id);
2863
- }
2864
- }
2865
- }
2866
- return errors;
2867
- }
2868
2935
  async function applyCommit(cwd, commit) {
2869
2936
  const filesByRepo = groupFilesByRepo(cwd, commit.files);
2870
2937
  const repos = Array.from(filesByRepo.keys());
@@ -2918,33 +2985,6 @@ async function applyCommit(cwd, commit) {
2918
2985
  const result = await git.commit(message);
2919
2986
  return result.commit;
2920
2987
  }
2921
- function groupFilesByRepo(cwd, files) {
2922
- const filesByRepo = /* @__PURE__ */ new Map();
2923
- for (const file of files) {
2924
- const segments = file.split("/");
2925
- const potentialRepoDir = segments[0];
2926
- if (!potentialRepoDir) {
2927
- const group = filesByRepo.get(cwd) ?? [];
2928
- group.push({ relativePath: file, originalPath: file });
2929
- filesByRepo.set(cwd, group);
2930
- continue;
2931
- }
2932
- const potentialRepoPath = join(cwd, potentialRepoDir);
2933
- const potentialGitDir = join(potentialRepoPath, ".git");
2934
- const isNestedRepo = existsSync(potentialGitDir);
2935
- if (isNestedRepo) {
2936
- const relativePath = segments.slice(1).join("/");
2937
- const group = filesByRepo.get(potentialRepoPath) ?? [];
2938
- group.push({ relativePath, originalPath: file });
2939
- filesByRepo.set(potentialRepoPath, group);
2940
- } else {
2941
- const group = filesByRepo.get(cwd) ?? [];
2942
- group.push({ relativePath: file, originalPath: file });
2943
- filesByRepo.set(cwd, group);
2944
- }
2945
- }
2946
- return filesByRepo;
2947
- }
2948
2988
  var COMMIT_FOOTER = "\n\n\u{1F916} Generated by kb-labs-commit-plugin";
2949
2989
  function formatCommitMessage(commit, options) {
2950
2990
  const type = commit.type;
@@ -2962,46 +3002,6 @@ ${commit.body}`;
2962
3002
  }
2963
3003
  return message;
2964
3004
  }
2965
- async function checkStaleness(cwd, plan, scope) {
2966
- const logger = useLogger();
2967
- const planFiles = new Set(plan.commits.flatMap((c) => c.files));
2968
- await logger.debug("checkStaleness: start", {
2969
- scope,
2970
- cwd,
2971
- planFiles: [...planFiles]
2972
- });
2973
- if (planFiles.size === 0) {
2974
- return { isStale: false, reason: "" };
2975
- }
2976
- const filesByRepo = groupFilesByRepo(cwd, [...planFiles]);
2977
- for (const [repoPath, fileInfos] of filesByRepo) {
2978
- const currentStatus = await getGitStatus(repoPath);
2979
- const currentFiles = new Set(getAllChangedFiles(currentStatus));
2980
- await logger.debug("checkStaleness: repo status", {
2981
- repoPath,
2982
- staged: currentStatus.staged,
2983
- unstaged: currentStatus.unstaged,
2984
- untracked: currentStatus.untracked,
2985
- expected: fileInfos.map((f) => f.relativePath)
2986
- });
2987
- for (const { relativePath, originalPath } of fileInfos) {
2988
- if (!currentFiles.has(relativePath)) {
2989
- await logger.warn("checkStaleness: file not in current changes", {
2990
- scope,
2991
- repoPath,
2992
- originalPath,
2993
- relativePath,
2994
- currentFiles: [...currentFiles]
2995
- });
2996
- return {
2997
- isStale: true,
2998
- reason: `File no longer has changes: ${originalPath}. Regenerate plan or use --force.`
2999
- };
3000
- }
3001
- }
3002
- }
3003
- return { isStale: false, reason: "" };
3004
- }
3005
3005
  async function pushCommits(cwd, options) {
3006
3006
  const git = simpleGit(cwd);
3007
3007
  const remote = options?.remote || "origin";
@@ -3199,6 +3199,6 @@ async function initStorage(cwd, scope = "root") {
3199
3199
  }
3200
3200
  }
3201
3201
 
3202
- export { SYSTEM_PROMPT, applyCommitPlan, buildPrompt, clearPlan, detectCommitStyle, formatCommitMessage, formatFileSummary, generateCommitPlan, generateHeuristicPlan, getAllChangedFiles, getCommitStoragePath, getCurrentBranch, getCurrentPlanPath, getCurrentStatusPath, getFileDiff, getFileSummaries, getGitStatus, getRecentCommits, hasChanges, hasPlan, initStorage, isProtectedBranch, listHistory, loadPlan, loadStatus, parseResponse, pushCommits, savePlan, saveToHistory };
3202
+ export { SYSTEM_PROMPT, applyCommitPlan, buildPrompt, checkPlanStaleness, clearPlan, detectCommitStyle, formatCommitMessage, formatFileSummary, generateCommitPlan, generateHeuristicPlan, getAllChangedFiles, getCommitStoragePath, getCurrentBranch, getCurrentPlanPath, getCurrentStatusPath, getFileDiff, getFileSummaries, getGitStatus, getRecentCommits, groupFilesByRepo, hasChanges, hasPlan, initStorage, isProtectedBranch, listHistory, loadPlan, loadStatus, parseResponse, pushCommits, savePlan, saveToHistory, validatePlanIntegrity };
3203
3203
  //# sourceMappingURL=index.js.map
3204
3204
  //# sourceMappingURL=index.js.map