@agent-relay/dashboard-server 2.0.71 → 2.0.73

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.
Files changed (60) hide show
  1. package/dist/server.js +19 -2
  2. package/dist/server.js.map +1 -1
  3. package/out/404.html +1 -1
  4. package/out/_next/static/chunks/285-57ccd3043914acb2.js +1 -0
  5. package/out/about.html +1 -1
  6. package/out/about.txt +1 -1
  7. package/out/app/onboarding.html +1 -1
  8. package/out/app/onboarding.txt +1 -1
  9. package/out/app.html +1 -1
  10. package/out/app.txt +2 -2
  11. package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +1 -1
  12. package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
  13. package/out/blog/let-them-cook-multi-agent-orchestration.html +1 -1
  14. package/out/blog/let-them-cook-multi-agent-orchestration.txt +1 -1
  15. package/out/blog.html +1 -1
  16. package/out/blog.txt +1 -1
  17. package/out/careers.html +1 -1
  18. package/out/careers.txt +1 -1
  19. package/out/changelog.html +1 -1
  20. package/out/changelog.txt +1 -1
  21. package/out/cloud/link.html +1 -1
  22. package/out/cloud/link.txt +1 -1
  23. package/out/complete-profile.html +1 -1
  24. package/out/complete-profile.txt +1 -1
  25. package/out/connect-repos.html +1 -1
  26. package/out/connect-repos.txt +1 -1
  27. package/out/contact.html +1 -1
  28. package/out/contact.txt +1 -1
  29. package/out/docs.html +1 -1
  30. package/out/docs.txt +1 -1
  31. package/out/history.html +1 -1
  32. package/out/history.txt +1 -1
  33. package/out/index.html +1 -1
  34. package/out/index.txt +2 -2
  35. package/out/login.html +1 -1
  36. package/out/login.txt +1 -1
  37. package/out/metrics.html +1 -1
  38. package/out/metrics.txt +1 -1
  39. package/out/pricing.html +1 -1
  40. package/out/pricing.txt +1 -1
  41. package/out/privacy.html +1 -1
  42. package/out/privacy.txt +1 -1
  43. package/out/providers/setup/claude.html +1 -1
  44. package/out/providers/setup/claude.txt +1 -1
  45. package/out/providers/setup/codex.html +1 -1
  46. package/out/providers/setup/codex.txt +1 -1
  47. package/out/providers/setup/cursor.html +1 -1
  48. package/out/providers/setup/cursor.txt +1 -1
  49. package/out/providers.html +1 -1
  50. package/out/providers.txt +1 -1
  51. package/out/security.html +1 -1
  52. package/out/security.txt +1 -1
  53. package/out/signup.html +1 -1
  54. package/out/signup.txt +1 -1
  55. package/out/terms.html +1 -1
  56. package/out/terms.txt +1 -1
  57. package/package.json +1 -1
  58. package/out/_next/static/chunks/285-52fb0aee5b6b90a6.js +0 -1
  59. /package/out/_next/static/{4b3iV9SX2_ON0klS0h-1g → CVQXstfbl09Ow0ERYIWu4}/_buildManifest.js +0 -0
  60. /package/out/_next/static/{4b3iV9SX2_ON0klS0h-1g → CVQXstfbl09Ow0ERYIWu4}/_ssgManifest.js +0 -0
package/dist/server.js CHANGED
@@ -4815,10 +4815,22 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
4815
4815
  const repoName = fullName.split('/').pop();
4816
4816
  const workspaceDir = process.env.WORKSPACE_DIR || path.dirname(projectRoot || dataDir);
4817
4817
  const targetDir = path.join(workspaceDir, repoName);
4818
- // Idempotent: skip if already cloned
4819
- if (fs.existsSync(targetDir)) {
4818
+ // Prevent path traversal (e.g., repoName = ".." or ".")
4819
+ const resolvedTarget = path.resolve(targetDir);
4820
+ const resolvedWorkspace = path.resolve(workspaceDir);
4821
+ if (!resolvedTarget.startsWith(resolvedWorkspace + path.sep)) {
4822
+ return res.status(400).json({ success: false, error: 'Invalid path' });
4823
+ }
4824
+ // Idempotent: skip if already cloned (check for .git to avoid false positives
4825
+ // from empty directories left behind by previous failed clone attempts)
4826
+ if (fs.existsSync(path.join(targetDir, '.git'))) {
4820
4827
  return res.json({ success: true, message: 'Already cloned', path: targetDir });
4821
4828
  }
4829
+ // Clean up stale directory from a previous failed clone (no .git = incomplete)
4830
+ if (fs.existsSync(targetDir)) {
4831
+ console.log(`[api/repos/clone] Removing stale directory ${targetDir} (no .git found)`);
4832
+ fs.rmSync(targetDir, { recursive: true, force: true });
4833
+ }
4822
4834
  // Use plain HTTPS URL - git credential helper handles authentication.
4823
4835
  // The credential helper (git-credential-relay) fetches per-repo tokens from
4824
4836
  // the cloud API, which correctly resolves installation tokens for private repos.
@@ -4842,6 +4854,11 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
4842
4854
  catch (err) {
4843
4855
  const safeMessage = (err.message || 'Clone failed');
4844
4856
  console.error('[api/repos/clone] Clone failed:', safeMessage);
4857
+ // Clean up failed clone directory so future attempts aren't blocked
4858
+ try {
4859
+ fs.rmSync(targetDir, { recursive: true, force: true });
4860
+ }
4861
+ catch { /* ignore */ }
4845
4862
  res.status(500).json({ success: false, error: safeMessage });
4846
4863
  }
4847
4864
  });