gitnexushub 0.7.1 → 0.7.2

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.
@@ -729,52 +729,104 @@ async function runKiroEditCapture(agentName) {
729
729
 
730
730
  const entries = readRegistry();
731
731
  const cwd = process.cwd();
732
- const entry = resolveCwdToRepo(cwd, entries);
733
- if (!entry) return;
734
-
735
- // Two parallel git invocations: tracked-file modifications via
736
- // `git diff --name-only HEAD` (catches modified + staged + deleted-
737
- // tracked), and untracked files via `git ls-files --others
738
- // --exclude-standard`. Both produce one absolute-relative path per
739
- // line, no status-code prefix far more robust than parsing
740
- // `git status --porcelain` (whose XY field varies across git
741
- // versions and edge cases).
742
- const collected = new Set();
743
- for (const args of [
744
- ['diff', '--name-only', 'HEAD'],
745
- ['ls-files', '--others', '--exclude-standard'],
746
- ]) {
747
- try {
748
- const r = spawnSync('git', args, { cwd, encoding: 'utf-8', timeout: 2000 });
749
- const out = (r.stdout || '').trim();
750
- if (!out) continue;
751
- for (const line of out.split('\n')) {
752
- const trimmed = line.trim();
753
- if (trimmed) collected.add(trimmed);
732
+
733
+ // Pick which repos to scan. Two cases:
734
+ //
735
+ // A. cwd is INSIDE a registered repo (e.g. Kiro opened directly
736
+ // on the project root, or any child path). Standard
737
+ // resolveCwdToRepo path scan that single repo.
738
+ //
739
+ // B. cwd is the PARENT of one or more registered repos (e.g.
740
+ // Kiro opened on `~/AkonLabs/` with multiple sub-repos
741
+ // inside). resolveCwdToRepo returns null in this case
742
+ // because the cwd↔localPath direction is reversed. Find all
743
+ // registered repos whose localPath is inside cwd and scan
744
+ // each. The single-repo case (A) takes precedence so we
745
+ // don't double-scan when both relations match.
746
+ let resolvedCwd;
747
+ try {
748
+ resolvedCwd = fs.realpathSync(path.resolve(cwd));
749
+ } catch {
750
+ resolvedCwd = path.resolve(cwd);
751
+ }
752
+ const isWin = process.platform === 'win32';
753
+ const normCwd = isWin ? resolvedCwd.toLowerCase() : resolvedCwd;
754
+ const sep = path.sep;
755
+
756
+ /** @type {Array<{ hubRepoId: string, localPath: string }>} */
757
+ const targets = [];
758
+ const inside = resolveCwdToRepo(cwd, entries);
759
+ if (inside) {
760
+ targets.push({ hubRepoId: inside.hubRepoId, localPath: inside.localPath });
761
+ } else {
762
+ for (const entry of entries) {
763
+ if (!entry || !entry.localPath || !entry.hubRepoId) continue;
764
+ let ep;
765
+ try {
766
+ ep = fs.realpathSync(path.resolve(entry.localPath));
767
+ } catch {
768
+ ep = path.resolve(entry.localPath);
769
+ }
770
+ const nep = isWin ? ep.toLowerCase() : ep;
771
+ if (nep === normCwd || nep.startsWith(normCwd + sep)) {
772
+ targets.push({ hubRepoId: entry.hubRepoId, localPath: ep });
754
773
  }
755
- } catch {
756
- // Best effort — proceed with whatever we got from prior args.
757
774
  }
758
775
  }
759
- if (collected.size === 0) return;
760
-
761
- // Cap at 20 files per fire so a big rewrite or a fresh branch
762
- // pull doesn't hammer the hub with hundreds of edit-observed
763
- // posts. The 20 cap is arbitrary but matches the per-call
764
- // ladybugdb worker pool's typical session length.
765
- let posted = 0;
766
- for (const filePath of collected) {
767
- if (posted >= 20) break;
768
- const absPath = path.isAbsolute(filePath) ? filePath : path.join(cwd, filePath);
769
- await httpPostJson(`${config.hubUrl}/api/activity/edit-observed`, authHeaders(config), {
770
- sessionId: null,
771
- repoId: entry.hubRepoId,
772
- filePath: absPath,
773
- line: null,
774
- tool: 'Write',
775
- agentName,
776
- });
777
- posted++;
776
+ if (targets.length === 0) return;
777
+
778
+ // Run git diff + ls-files inside each target repo. Cap at 5 repos
779
+ // per fire so a `~/code/` workspace with 50 sibling repos doesn't
780
+ // spawn 100 git processes on every postToolUse. The 20-file cap
781
+ // is applied per-repo.
782
+ let postedTotal = 0;
783
+ const MAX_REPOS = 5;
784
+ const MAX_FILES_PER_REPO = 20;
785
+ for (const target of targets.slice(0, MAX_REPOS)) {
786
+ const collected = new Set();
787
+ for (const args of [
788
+ ['diff', '--name-only', 'HEAD'],
789
+ ['ls-files', '--others', '--exclude-standard'],
790
+ ]) {
791
+ try {
792
+ const r = spawnSync('git', args, {
793
+ cwd: target.localPath,
794
+ encoding: 'utf-8',
795
+ timeout: 2000,
796
+ });
797
+ const out = (r.stdout || '').trim();
798
+ if (!out) continue;
799
+ for (const line of out.split('\n')) {
800
+ const trimmed = line.trim();
801
+ if (trimmed) collected.add(trimmed);
802
+ }
803
+ } catch {
804
+ // Best effort
805
+ }
806
+ }
807
+ if (collected.size === 0) continue;
808
+
809
+ let perRepo = 0;
810
+ for (const filePath of collected) {
811
+ if (perRepo >= MAX_FILES_PER_REPO) break;
812
+ const absPath = path.isAbsolute(filePath) ? filePath : path.join(target.localPath, filePath);
813
+ await httpPostJson(`${config.hubUrl}/api/activity/edit-observed`, authHeaders(config), {
814
+ sessionId: null,
815
+ repoId: target.hubRepoId,
816
+ filePath: absPath,
817
+ line: null,
818
+ tool: 'Write',
819
+ agentName,
820
+ });
821
+ perRepo++;
822
+ postedTotal++;
823
+ }
824
+ }
825
+
826
+ if (process.env.GITNEXUS_DEBUG) {
827
+ process.stderr.write(
828
+ `kiro-edit-capture: targets=${targets.length} posted=${postedTotal}\n`,
829
+ );
778
830
  }
779
831
  }
780
832
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexushub",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Connect your editor to GitNexus Hub — one command MCP setup + project context",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",