@ian2018cs/agenthub 0.1.78 → 0.1.79

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ian2018cs/agenthub",
3
- "version": "0.1.78",
3
+ "version": "0.1.79",
4
4
  "description": "A web-based UI for AI Agents",
5
5
  "type": "module",
6
6
  "main": "server/index.js",
@@ -347,6 +347,47 @@ async function ensureSharedGitRepo(repoUrl, branch) {
347
347
  return targetPath;
348
348
  }
349
349
 
350
+ /**
351
+ * Try to move an existing local git clone directly into the shared location,
352
+ * avoiding a fresh network clone. Only succeeds when:
353
+ * - localPath is a real directory (not a symlink) with a .git folder
354
+ * - The shared target path does not yet exist
355
+ * Returns the shared path on success, or null if promotion is not possible.
356
+ */
357
+ async function tryPromoteLocalRepoToShared(localPath, repoUrl, branch) {
358
+ const parsed = parseGitUrl(repoUrl);
359
+ if (!parsed) return null;
360
+
361
+ const publicPaths = getPublicPaths();
362
+ const targetPath = path.join(publicPaths.gitRepoDir, parsed.owner, parsed.repo, branch);
363
+
364
+ // Shared repo already exists — nothing to promote
365
+ try {
366
+ await fs.access(targetPath);
367
+ return null;
368
+ } catch {}
369
+
370
+ // Source must be a real git directory (not a symlink, must have .git)
371
+ try {
372
+ const stat = await fs.lstat(localPath);
373
+ if (!stat.isDirectory() || stat.isSymbolicLink()) return null;
374
+ await fs.access(path.join(localPath, '.git'));
375
+ } catch {
376
+ return null;
377
+ }
378
+
379
+ try {
380
+ await fs.mkdir(path.dirname(targetPath), { recursive: true });
381
+ await fs.rename(localPath, targetPath);
382
+ console.log(`[GitRepo] Promoted local repo to shared: ${localPath} → ${targetPath}`);
383
+ return targetPath;
384
+ } catch (e) {
385
+ // rename may fail on cross-device links — fall back to normal clone
386
+ console.warn(`[GitRepo] Could not promote local repo (will clone instead): ${e.message}`);
387
+ return null;
388
+ }
389
+ }
390
+
350
391
  /**
351
392
  * Create a symlink from a project subdirectory to a shared git repo.
352
393
  * Removes existing directory or symlink at the target location.
@@ -513,6 +554,7 @@ async function scanClaudeMdRefs(projectPath) {
513
554
  if (!ref) continue;
514
555
  if (/^https?:\/\/|^mailto:|^\/\//.test(ref)) continue; // skip absolute URLs
515
556
  if (path.isAbsolute(ref)) continue; // skip absolute paths
557
+ if (ref.endsWith('/')) continue; // skip directory references like [src/utils/]
516
558
  if (seen.has(ref)) continue;
517
559
  seen.add(ref);
518
560
 
@@ -1530,8 +1572,22 @@ router.post('/submissions/:id/approve', async (req, res) => {
1530
1572
  for (const gitRepo of yamlGitRepos) {
1531
1573
  if (!gitRepo.name || !gitRepo.repo) continue;
1532
1574
  try {
1533
- // Ensure shared git repo exists
1534
- const sharedPath = await ensureSharedGitRepo(gitRepo.repo, gitRepo.branch || 'main');
1575
+ // Try to promote the submitter's existing local clone to shared location first
1576
+ // (avoids a full network re-clone if the user already has the repo cloned)
1577
+ let sharedPath = null;
1578
+ if (submitterUuid) {
1579
+ const submitterProjectDir = path.join(getUserPaths(submitterUuid).projectsDir, submission.agent_name);
1580
+ const localRepoPath = path.join(submitterProjectDir, gitRepo.name);
1581
+ sharedPath = await tryPromoteLocalRepoToShared(localRepoPath, gitRepo.repo, gitRepo.branch || 'main');
1582
+ if (sharedPath) {
1583
+ console.log(`[AgentApprove] Promoted local repo "${gitRepo.name}" to shared (no re-clone needed)`);
1584
+ }
1585
+ }
1586
+
1587
+ // Fall back to normal clone/update if promotion was not possible
1588
+ if (!sharedPath) {
1589
+ sharedPath = await ensureSharedGitRepo(gitRepo.repo, gitRepo.branch || 'main');
1590
+ }
1535
1591
  console.log(`[AgentApprove] Ensured shared git repo "${gitRepo.name}" at ${sharedPath}`);
1536
1592
 
1537
1593
  // Replace submitter's original subdirectory with symlink to shared repo