diffsplain 0.2.0 → 0.3.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.
@@ -79,6 +79,7 @@ const cacheRoot = cacheOption
79
79
  : resolve(projectRoot, '.cache/git');
80
80
  const remoteMode = Boolean(prOption || branchOption);
81
81
  const watching = has('--watch');
82
+ const ignoreSummaryWatch = has('--ignore-summary-watch');
82
83
 
83
84
  if (prOption && branchOption) fail('--pr and --branch cannot be used together');
84
85
  if (prOption && (baseOption || headOption)) fail('--pr cannot be used with --base or --head');
@@ -706,7 +707,25 @@ function resolveTarget() {
706
707
  return resolveLocalTarget();
707
708
  }
708
709
 
709
- function filePatch(file, target) {
710
+ function trackedPatches(files, target) {
711
+ const raw = target.runGit([
712
+ 'diff',
713
+ '--no-ext-diff',
714
+ '--no-textconv',
715
+ '--binary',
716
+ '--find-renames',
717
+ ...target.range,
718
+ ]);
719
+ const patches = raw
720
+ .split(/(?=^diff --git )/m)
721
+ .filter((patch) => patch.startsWith('diff --git '));
722
+ if (patches.length !== files.length) return undefined;
723
+ return new Map(
724
+ files.map((file, index) => [file.path, patches[index]]),
725
+ );
726
+ }
727
+
728
+ function filePatch(file, target, patches) {
710
729
  if (file.untracked) {
711
730
  return runRepoWithDiffExit([
712
731
  'diff',
@@ -719,6 +738,8 @@ function filePatch(file, target) {
719
738
  file.path,
720
739
  ]);
721
740
  }
741
+ const combined = patches?.get(file.path);
742
+ if (combined !== undefined) return combined;
722
743
  const pathspec = file.oldPath ? [file.oldPath, file.path] : [file.path];
723
744
  return target.runGit([
724
745
  'diff',
@@ -766,7 +787,7 @@ function build() {
766
787
  const target = resolveTarget();
767
788
  const remoteRepository = githubRepository(target.remote?.url);
768
789
  const summaryDoc = readJson(summariesPath, {}) || {};
769
- const nameStatus = parseNameStatus(
790
+ const allTrackedFiles = parseNameStatus(
770
791
  target.runGit([
771
792
  'diff',
772
793
  '--no-ext-diff',
@@ -776,7 +797,10 @@ function build() {
776
797
  '--find-renames',
777
798
  ...target.range,
778
799
  ]),
779
- ).filter((file) => !excludedPaths.has(file.path));
800
+ );
801
+ const nameStatus = allTrackedFiles.filter(
802
+ (file) => !excludedPaths.has(file.path),
803
+ );
780
804
  const numstat = parseNumstat(
781
805
  target.runGit([
782
806
  'diff',
@@ -788,6 +812,7 @@ function build() {
788
812
  ...target.range,
789
813
  ]),
790
814
  );
815
+ const patches = trackedPatches(allTrackedFiles, target);
791
816
 
792
817
  if (target.kind === 'worktree' || target.kind === 'checkout') {
793
818
  const trackedPaths = new Set(nameStatus.map((file) => file.path));
@@ -815,7 +840,7 @@ function build() {
815
840
  deletions: 0,
816
841
  isBinary: false,
817
842
  };
818
- const patch = filePatch(file, target);
843
+ const patch = filePatch(file, target, patches);
819
844
  const binary =
820
845
  stat.isBinary ||
821
846
  patch.includes('Binary files ') ||
@@ -954,9 +979,11 @@ function build() {
954
979
 
955
980
  function fingerprint() {
956
981
  let summariesTime = '';
957
- try {
958
- summariesTime = String(statSync(summariesPath).mtimeMs);
959
- } catch {}
982
+ if (!ignoreSummaryWatch) {
983
+ try {
984
+ summariesTime = String(statSync(summariesPath).mtimeMs);
985
+ } catch {}
986
+ }
960
987
  if (remoteMode) return summariesTime;
961
988
  if (baseOption && headOption) {
962
989
  return [
@@ -16,6 +16,7 @@ const valueOptions = new Set([
16
16
  '--model',
17
17
  '--reasoning',
18
18
  '--batch-size',
19
+ '--jobs',
19
20
  '--port',
20
21
  ]);
21
22
  const flagOptions = new Set([
@@ -52,7 +53,8 @@ Options:
52
53
  --no-agent Do not write agent notes
53
54
  --model NAME Model for agent notes
54
55
  --reasoning LEVEL Agent reasoning effort when supported
55
- --batch-size COUNT Files per agent pass (default: 4)
56
+ --batch-size COUNT Maximum files per agent pass (default: 12)
57
+ --jobs COUNT Agent passes to run at once (default: 3)
56
58
  --force Regenerate all agent notes
57
59
  --remote NAME|URL Git remote (default: origin)
58
60
  --port NUMBER Local page port (default: 2299)
@@ -259,6 +261,7 @@ export function parseCliArgs(
259
261
  '--model',
260
262
  '--reasoning',
261
263
  '--batch-size',
264
+ '--jobs',
262
265
  ]) {
263
266
  const value = options.get(name);
264
267
  if (value) {
@@ -287,6 +290,13 @@ export function parseCliArgs(
287
290
  ) {
288
291
  fail('--batch-size must be a number from 1 to 50');
289
292
  }
293
+ const jobs = options.get('--jobs');
294
+ if (
295
+ jobs &&
296
+ (!/^[1-9]\d*$/.test(jobs) || Number(jobs) > 8)
297
+ ) {
298
+ fail('--jobs must be a number from 1 to 8');
299
+ }
290
300
 
291
301
  const portValue = options.get('--port') || '2299';
292
302
  if (!/^\d+$/.test(portValue) || Number(portValue) > 65_535) {
@@ -141,6 +141,7 @@ export function agentCommand({
141
141
  '--ignore-user-config',
142
142
  '--color',
143
143
  'never',
144
+ '--skip-git-repo-check',
144
145
  '-C',
145
146
  workingDirectory,
146
147
  '--output-schema',