resulgit 1.0.5 → 1.0.6

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 (2) hide show
  1. package/package.json +1 -1
  2. package/resulgit.js +88 -79
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "resulgit",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "A powerful CLI tool for version control system operations - clone, commit, push, pull, merge, branch management, and more",
5
5
  "main": "resulgit.js",
6
6
  "bin": {
package/resulgit.js CHANGED
@@ -271,7 +271,7 @@ async function cmdClone(opts, cfg) {
271
271
  const server = getServer(opts, cfg)
272
272
  const token = getToken(opts, cfg)
273
273
  const repo = opts.repo
274
- const branch = opts.branch
274
+ const branch = opts.branch || 'main'
275
275
  let dest = opts.dest
276
276
  if (!repo || !branch) throw new Error('Missing --repo and --branch')
277
277
  const spinner = createSpinner('Initializing clone...', opts.json)
@@ -540,10 +540,10 @@ async function cmdDiff(opts) {
540
540
  const snap1 = await fetchSnapshotByCommit(server, meta.repoId, commit1, token)
541
541
  const snap2 = await fetchSnapshotByCommit(server, meta.repoId, commit2, token)
542
542
  const files = filePath ? [filePath] : Object.keys(new Set([...Object.keys(snap1.files), ...Object.keys(snap2.files)]))
543
-
543
+
544
544
  let added = 0, deleted = 0, modified = 0
545
545
  const stats = []
546
-
546
+
547
547
  for (const p of files) {
548
548
  const content1 = snap1.files[p] !== undefined ? String(snap1.files[p]) : null
549
549
  const content2 = snap2.files[p] !== undefined ? String(snap2.files[p]) : null
@@ -561,7 +561,7 @@ async function cmdDiff(opts) {
561
561
  const diff = Math.abs(lines2.length - lines1.length)
562
562
  if (showStat) stats.push({ path: p, added: lines2.length > lines1.length ? diff : 0, deleted: lines1.length > lines2.length ? diff : 0 })
563
563
  }
564
-
564
+
565
565
  if (!showStat) {
566
566
  if (opts.json === 'true') {
567
567
  print({ path: p, old: content1, new: content2 }, true)
@@ -585,7 +585,7 @@ async function cmdDiff(opts) {
585
585
  }
586
586
  }
587
587
  }
588
-
588
+
589
589
  if (showStat) {
590
590
  if (opts.json === 'true') {
591
591
  print({ added, deleted, modified, files: stats }, true)
@@ -607,7 +607,7 @@ async function cmdDiff(opts) {
607
607
  const parentSnap = parentId ? await fetchSnapshotByCommit(server, meta.repoId, parentId, token) : { files: {}, commitId: '' }
608
608
 
609
609
  const files = filePath ? [filePath] : Object.keys(new Set([...Object.keys(parentSnap.files), ...Object.keys(commitSnap.files)]))
610
-
610
+
611
611
  if (showStat) {
612
612
  let added = 0, deleted = 0, modified = 0
613
613
  const stats = []
@@ -640,7 +640,7 @@ async function cmdDiff(opts) {
640
640
  }
641
641
  return
642
642
  }
643
-
643
+
644
644
  for (const p of files) {
645
645
  const oldContent = parentSnap.files[p] !== undefined ? String(parentSnap.files[p]) : null
646
646
  const newContent = commitSnap.files[p] !== undefined ? String(commitSnap.files[p]) : null
@@ -726,7 +726,7 @@ async function cmdRm(opts) {
726
726
  const cfg = loadConfig()
727
727
  const server = getServer(opts, cfg) || meta.server
728
728
  const token = getToken(opts, cfg) || meta.token
729
-
729
+
730
730
  // Handle --cached flag (remove from index but keep file)
731
731
  if (opts.cached === 'true') {
732
732
  // Mark file for deletion in next commit but don't delete from filesystem
@@ -736,7 +736,7 @@ async function cmdRm(opts) {
736
736
  try {
737
737
  const s = await fs.promises.readFile(localPath, 'utf8')
738
738
  localMeta = JSON.parse(s)
739
- } catch {}
739
+ } catch { }
740
740
  if (!localMeta.removedFiles) localMeta.removedFiles = []
741
741
  if (!localMeta.removedFiles.includes(pathArg)) {
742
742
  localMeta.removedFiles.push(pathArg)
@@ -750,7 +750,7 @@ async function cmdRm(opts) {
750
750
  }
751
751
  return
752
752
  }
753
-
753
+
754
754
  const u = new URL(`/api/repositories/${meta.repoId}/files`, server)
755
755
  u.searchParams.set('branch', meta.branch)
756
756
  u.searchParams.set('path', pathArg)
@@ -776,7 +776,7 @@ async function cmdCommit(opts) {
776
776
  spinnerUpdate(spinner, 'Staging all changes...')
777
777
  await cmdAdd({ dir, all: 'true', json: opts.json })
778
778
  }
779
-
779
+
780
780
  // Handle --amend flag
781
781
  if (opts.amend === 'true') {
782
782
  spinnerUpdate(spinner, 'Amending last commit...')
@@ -823,7 +823,7 @@ async function cmdCommit(opts) {
823
823
  const local = await collectLocal(dir)
824
824
  const files = {}
825
825
  for (const [p, v] of Object.entries(local)) files[p] = v.content
826
-
826
+
827
827
  // Execute pre-commit hook
828
828
  spinnerUpdate(spinner, 'Running pre-commit hook...')
829
829
  try {
@@ -836,7 +836,7 @@ async function cmdCommit(opts) {
836
836
  if (err.message === 'pre-commit hook failed') throw err
837
837
  // Hook doesn't exist or other error, continue
838
838
  }
839
-
839
+
840
840
  localMeta.pendingCommit = { message, files, createdAt: Date.now() }
841
841
  // Clear conflicts if they were resolved
842
842
  if (localMeta.conflicts) {
@@ -844,12 +844,12 @@ async function cmdCommit(opts) {
844
844
  }
845
845
  await fs.promises.mkdir(metaDir, { recursive: true })
846
846
  await fs.promises.writeFile(localPath, JSON.stringify(localMeta, null, 2))
847
-
847
+
848
848
  // Execute post-commit hook
849
849
  try {
850
850
  await hooks.executeHook(dir, 'post-commit', { message, files: Object.keys(files) })
851
- } catch {}
852
-
851
+ } catch { }
852
+
853
853
  spinnerSuccess(spinner, `Staged changes for commit: "${message}"`)
854
854
  print({ pendingCommit: message }, opts.json === 'true')
855
855
  } catch (err) {
@@ -1395,7 +1395,7 @@ async function cmdPush(opts) {
1395
1395
  if (err.message === 'pre-push hook failed') throw err
1396
1396
  // Hook doesn't exist or other error, continue
1397
1397
  }
1398
-
1398
+
1399
1399
  const body = { message: localMeta.pendingCommit?.message || (opts.message || 'Push'), files: merged, branchName: remoteMeta.branch }
1400
1400
  spinnerUpdate(spinner, `Pushing to '${remoteMeta.branch}'...`)
1401
1401
  const url = new URL(`/api/repositories/${remoteMeta.repoId}/commits`, server).toString()
@@ -1404,12 +1404,12 @@ async function cmdPush(opts) {
1404
1404
  localMeta.baseFiles = merged
1405
1405
  localMeta.pendingCommit = null
1406
1406
  await fs.promises.writeFile(localPath, JSON.stringify(localMeta, null, 2))
1407
-
1407
+
1408
1408
  // Execute post-push hook
1409
1409
  try {
1410
1410
  await hooks.executeHook(dir, 'post-push', { branch: remoteMeta.branch, commitId: localMeta.baseCommitId })
1411
- } catch {}
1412
-
1411
+ } catch { }
1412
+
1413
1413
  spinnerSuccess(spinner, `Pushed to '${remoteMeta.branch}' (commit: ${(data.id || '').slice(0, 7)})`)
1414
1414
  print({ pushed: localMeta.baseCommitId }, opts.json === 'true')
1415
1415
  } catch (err) {
@@ -1758,7 +1758,7 @@ async function cmdBranch(sub, opts) {
1758
1758
  } catch { }
1759
1759
  process.stdout.write(color('Branches:\n', 'bold'))
1760
1760
  let list = (data.branches || []).map(b => ({ name: b.name, commitId: b.commitId || '', date: b.lastCommitDate || b.createdAt || '' }))
1761
-
1761
+
1762
1762
  // Handle --sort option
1763
1763
  if (opts.sort) {
1764
1764
  const sortBy = opts.sort.replace(/^-/, '') // Remove leading dash
@@ -1770,7 +1770,7 @@ async function cmdBranch(sub, opts) {
1770
1770
  })
1771
1771
  }
1772
1772
  }
1773
-
1773
+
1774
1774
  for (const b of list) {
1775
1775
  const isCur = b.name === current
1776
1776
  const mark = isCur ? color('*', 'green') : ' '
@@ -1838,7 +1838,7 @@ async function cmdSwitch(opts) {
1838
1838
  const cfg = loadConfig()
1839
1839
  const server = getServer(opts, cfg) || meta.server
1840
1840
  const token = getToken(opts, cfg) || meta.token
1841
-
1841
+
1842
1842
  // Handle -c flag (create and switch)
1843
1843
  if (create) {
1844
1844
  // Check if branch exists
@@ -1850,7 +1850,7 @@ async function cmdSwitch(opts) {
1850
1850
  await cmdBranch('create', { dir, name: branch, base: meta.branch, repo: meta.repoId, server, token })
1851
1851
  }
1852
1852
  }
1853
-
1853
+
1854
1854
  await pullToDir(meta.repoId, branch, dir, server, token)
1855
1855
  print({ repoId: meta.repoId, branch, dir }, opts.json === 'true')
1856
1856
  }
@@ -2301,8 +2301,10 @@ async function cmdInit(opts) {
2301
2301
  const cfg = loadConfig()
2302
2302
  const server = getServer(opts, cfg)
2303
2303
  const token = getToken(opts, cfg)
2304
- const repo = opts.repo || ''
2305
- const branch = opts.branch || 'main'
2304
+ // Repository name must be a non‑empty string; validate format
2305
+ const repo = opts.repo ? validation.validateRepoName(opts.repo) : ''
2306
+ // Branch name defaults to 'main' if not supplied
2307
+ const branch = opts.branch ? opts.branch : 'main'
2306
2308
  const metaDir = path.join(dir, '.vcs-next')
2307
2309
  const gitDir = path.join(dir, '.git')
2308
2310
  await fs.promises.mkdir(metaDir, { recursive: true })
@@ -2602,38 +2604,38 @@ async function cmdBlame(opts) {
2602
2604
  const dir = path.resolve(opts.dir || '.')
2603
2605
  const filePath = opts.path
2604
2606
  if (!filePath) throw new errors.ValidationError('Missing --path', 'path')
2605
-
2607
+
2606
2608
  const validPath = validation.validateFilePath(filePath)
2607
2609
  const meta = readRemoteMeta(dir)
2608
2610
  const cfg = loadConfig()
2609
2611
  const server = getServer(opts, cfg) || meta.server
2610
2612
  const token = getToken(opts, cfg) || meta.token
2611
-
2613
+
2612
2614
  const spinner = createSpinner(`Getting blame for ${validPath}...`, opts.json)
2613
-
2615
+
2614
2616
  try {
2615
2617
  // Get file content
2616
2618
  const local = await collectLocal(dir)
2617
2619
  if (!local[validPath]) {
2618
2620
  throw new errors.FileSystemError(`File not found: ${validPath}`, validPath, 'read')
2619
2621
  }
2620
-
2622
+
2621
2623
  // Get commits
2622
2624
  const commitsUrl = new URL(`/api/repositories/${meta.repoId}/commits`, server)
2623
2625
  commitsUrl.searchParams.set('branch', meta.branch)
2624
2626
  const commitsRes = await fetch(commitsUrl.toString(), {
2625
2627
  headers: token ? { Authorization: `Bearer ${token}` } : {}
2626
2628
  })
2627
-
2629
+
2628
2630
  if (!commitsRes.ok) {
2629
2631
  throw new errors.NetworkError('Failed to fetch commits', commitsRes.status, commitsUrl.toString())
2630
2632
  }
2631
-
2633
+
2632
2634
  const commits = await commitsRes.json()
2633
2635
  const blameData = parseBlame(local[validPath].content, commits, validPath)
2634
-
2636
+
2635
2637
  spinnerSuccess(spinner, `Blame for ${validPath}`)
2636
-
2638
+
2637
2639
  if (opts.json === 'true') {
2638
2640
  print(formatBlameJson(blameData), false)
2639
2641
  } else {
@@ -2651,17 +2653,17 @@ async function cmdLog(opts) {
2651
2653
  const cfg = loadConfig()
2652
2654
  const server = getServer(opts, cfg) || meta.server
2653
2655
  const token = getToken(opts, cfg) || meta.token
2654
-
2656
+
2655
2657
  const spinner = createSpinner('Fetching commit history...', opts.json)
2656
-
2658
+
2657
2659
  try {
2658
2660
  const url = new URL(`/api/repositories/${meta.repoId}/commits`, server)
2659
2661
  if (opts.branch) url.searchParams.set('branch', opts.branch)
2660
2662
  else url.searchParams.set('branch', meta.branch)
2661
-
2663
+
2662
2664
  const data = await request('GET', url.toString(), null, token)
2663
2665
  let commits = Array.isArray(data) ? data : []
2664
-
2666
+
2665
2667
  // Filter by file path if provided
2666
2668
  const filePath = opts.path
2667
2669
  if (filePath) {
@@ -2674,7 +2676,7 @@ async function cmdLog(opts) {
2674
2676
  }
2675
2677
  commits = filteredCommits
2676
2678
  }
2677
-
2679
+
2678
2680
  // Filter by content pattern (-G flag)
2679
2681
  const pattern = opts.G || opts.pattern
2680
2682
  if (pattern) {
@@ -2684,7 +2686,7 @@ async function cmdLog(opts) {
2684
2686
  const commitSnap = await fetchSnapshotByCommit(server, meta.repoId, commit.id || commit._id, token)
2685
2687
  const parentId = (Array.isArray(commit.parents) && commit.parents[0]) || ''
2686
2688
  const parentSnap = parentId ? await fetchSnapshotByCommit(server, meta.repoId, parentId, token) : { files: {} }
2687
-
2689
+
2688
2690
  // Check if pattern matches in any file changed in this commit
2689
2691
  const allPaths = new Set([...Object.keys(parentSnap.files), ...Object.keys(commitSnap.files)])
2690
2692
  let matches = false
@@ -2702,9 +2704,9 @@ async function cmdLog(opts) {
2702
2704
  }
2703
2705
  commits = filteredCommits
2704
2706
  }
2705
-
2707
+
2706
2708
  spinnerSuccess(spinner, `Found ${commits.length} commits`)
2707
-
2709
+
2708
2710
  if (opts.json === 'true') {
2709
2711
  print(commits, true)
2710
2712
  } else if (opts.oneline === 'true') {
@@ -2733,7 +2735,7 @@ async function cmdLog(opts) {
2733
2735
 
2734
2736
  async function cmdHook(sub, opts) {
2735
2737
  const dir = path.resolve(opts.dir || '.')
2736
-
2738
+
2737
2739
  if (sub === 'list') {
2738
2740
  const hooksList = await hooks.listHooks(dir)
2739
2741
  if (opts.json === 'true') {
@@ -2751,18 +2753,18 @@ async function cmdHook(sub, opts) {
2751
2753
  }
2752
2754
  return
2753
2755
  }
2754
-
2756
+
2755
2757
  if (sub === 'install') {
2756
2758
  const hookName = opts.name
2757
2759
  if (!hookName) throw new Error('Missing --name')
2758
-
2760
+
2759
2761
  let script = opts.script
2760
2762
  if (!script && opts.sample === 'true') {
2761
2763
  script = hooks.SAMPLE_HOOKS[hookName]
2762
2764
  if (!script) throw new Error(`No sample available for ${hookName}`)
2763
2765
  }
2764
2766
  if (!script) throw new Error('Missing --script or use --sample')
2765
-
2767
+
2766
2768
  const result = await hooks.installHook(dir, hookName, script)
2767
2769
  print(result, opts.json === 'true')
2768
2770
  if (opts.json !== 'true') {
@@ -2770,20 +2772,20 @@ async function cmdHook(sub, opts) {
2770
2772
  }
2771
2773
  return
2772
2774
  }
2773
-
2775
+
2774
2776
  if (sub === 'remove') {
2775
2777
  const hookName = opts.name
2776
2778
  if (!hookName) throw new Error('Missing --name')
2777
-
2779
+
2778
2780
  const result = await hooks.removeHook(dir, hookName)
2779
2781
  print(result, opts.json === 'true')
2780
2782
  return
2781
2783
  }
2782
-
2784
+
2783
2785
  if (sub === 'show') {
2784
2786
  const hookName = opts.name
2785
2787
  if (!hookName) throw new Error('Missing --name')
2786
-
2788
+
2787
2789
  const result = await hooks.readHook(dir, hookName)
2788
2790
  if (result.content) {
2789
2791
  process.stdout.write(result.content + '\n')
@@ -2792,7 +2794,7 @@ async function cmdHook(sub, opts) {
2792
2794
  }
2793
2795
  return
2794
2796
  }
2795
-
2797
+
2796
2798
  throw new Error('Unknown hook subcommand. Use: list, install, remove, show')
2797
2799
  }
2798
2800
 
@@ -2800,13 +2802,13 @@ async function cmdGrep(opts) {
2800
2802
  const dir = path.resolve(opts.dir || '.')
2801
2803
  const pattern = opts.pattern || opts.p || ''
2802
2804
  if (!pattern) throw new Error('Missing --pattern or -p')
2803
-
2805
+
2804
2806
  const meta = readRemoteMeta(dir)
2805
2807
  const local = await collectLocal(dir)
2806
2808
  const results = []
2807
-
2809
+
2808
2810
  const regex = new RegExp(pattern, opts.ignoreCase === 'true' ? 'i' : '')
2809
-
2811
+
2810
2812
  for (const [filePath, fileData] of Object.entries(local)) {
2811
2813
  const lines = fileData.content.split(/\r?\n/)
2812
2814
  for (let i = 0; i < lines.length; i++) {
@@ -2819,7 +2821,7 @@ async function cmdGrep(opts) {
2819
2821
  }
2820
2822
  }
2821
2823
  }
2822
-
2824
+
2823
2825
  if (opts.json === 'true') {
2824
2826
  print(results, true)
2825
2827
  } else {
@@ -2836,10 +2838,10 @@ async function cmdLsFiles(opts) {
2836
2838
  const cfg = loadConfig()
2837
2839
  const server = getServer(opts, cfg) || meta.server
2838
2840
  const token = getToken(opts, cfg) || meta.token
2839
-
2841
+
2840
2842
  const remote = await fetchRemoteFilesMap(server, meta.repoId, meta.branch, token)
2841
2843
  const files = Object.keys(remote.map)
2842
-
2844
+
2843
2845
  if (opts.json === 'true') {
2844
2846
  print(files.map(f => ({ path: f })), true)
2845
2847
  } else {
@@ -2853,13 +2855,13 @@ async function cmdReflog(opts) {
2853
2855
  const dir = path.resolve(opts.dir || '.')
2854
2856
  const metaDir = path.join(dir, '.vcs-next')
2855
2857
  const reflogPath = path.join(metaDir, 'reflog.json')
2856
-
2858
+
2857
2859
  let reflog = []
2858
2860
  try {
2859
2861
  const content = await fs.promises.readFile(reflogPath, 'utf8')
2860
2862
  reflog = JSON.parse(content)
2861
- } catch {}
2862
-
2863
+ } catch { }
2864
+
2863
2865
  if (opts.json === 'true') {
2864
2866
  print(reflog, true)
2865
2867
  } else {
@@ -2878,14 +2880,14 @@ async function cmdCatFile(opts) {
2878
2880
  const dir = path.resolve(opts.dir || '.')
2879
2881
  const type = opts.type || ''
2880
2882
  const object = opts.object || ''
2881
-
2883
+
2882
2884
  if (!type || !object) throw new Error('Missing --type and --object')
2883
-
2885
+
2884
2886
  const meta = readRemoteMeta(dir)
2885
2887
  const cfg = loadConfig()
2886
2888
  const server = getServer(opts, cfg) || meta.server
2887
2889
  const token = getToken(opts, cfg) || meta.token
2888
-
2890
+
2889
2891
  if (type === 'blob') {
2890
2892
  const snap = await fetchSnapshotByCommit(server, meta.repoId, object, token)
2891
2893
  const filePath = opts.path || ''
@@ -2912,12 +2914,12 @@ async function cmdCatFile(opts) {
2912
2914
  async function cmdRevParse(opts) {
2913
2915
  const dir = path.resolve(opts.dir || '.')
2914
2916
  const rev = opts.rev || 'HEAD'
2915
-
2917
+
2916
2918
  const meta = readRemoteMeta(dir)
2917
2919
  const cfg = loadConfig()
2918
2920
  const server = getServer(opts, cfg) || meta.server
2919
2921
  const token = getToken(opts, cfg) || meta.token
2920
-
2922
+
2921
2923
  if (rev === 'HEAD') {
2922
2924
  const info = await request('GET', new URL(`/api/repositories/${meta.repoId}/branches`, server).toString(), null, token)
2923
2925
  const found = (info.branches || []).find(b => b.name === meta.branch)
@@ -2938,20 +2940,20 @@ async function cmdRevParse(opts) {
2938
2940
  async function cmdDescribe(opts) {
2939
2941
  const dir = path.resolve(opts.dir || '.')
2940
2942
  const commitId = opts.commit || 'HEAD'
2941
-
2943
+
2942
2944
  const meta = readRemoteMeta(dir)
2943
2945
  const cfg = loadConfig()
2944
2946
  const server = getServer(opts, cfg) || meta.server
2945
2947
  const token = getToken(opts, cfg) || meta.token
2946
-
2948
+
2947
2949
  // Get tags
2948
2950
  const tagsUrl = new URL(`/api/repositories/${meta.repoId}/tags`, server)
2949
2951
  const tags = await request('GET', tagsUrl.toString(), null, token)
2950
2952
  const tagsList = Array.isArray(tags) ? tags : []
2951
-
2953
+
2952
2954
  // Find nearest tag (simplified - just find any tag)
2953
2955
  const nearestTag = tagsList[0]
2954
-
2956
+
2955
2957
  if (nearestTag) {
2956
2958
  const desc = `${nearestTag.name}-0-g${commitId.slice(0, 7)}`
2957
2959
  print(opts.json === 'true' ? { tag: nearestTag.name, commitId, describe: desc } : desc, opts.json === 'true')
@@ -2966,16 +2968,16 @@ async function cmdShortlog(opts) {
2966
2968
  const cfg = loadConfig()
2967
2969
  const server = getServer(opts, cfg) || meta.server
2968
2970
  const token = getToken(opts, cfg) || meta.token
2969
-
2971
+
2970
2972
  const url = new URL(`/api/repositories/${meta.repoId}/commits`, server)
2971
2973
  if (opts.branch) url.searchParams.set('branch', opts.branch)
2972
2974
  else url.searchParams.set('branch', meta.branch)
2973
-
2975
+
2974
2976
  const commits = await request('GET', url.toString(), null, token)
2975
2977
  const commitsList = Array.isArray(commits) ? commits : []
2976
-
2978
+
2977
2979
  const stats = generateCommitStats(commitsList)
2978
-
2980
+
2979
2981
  if (opts.json === 'true') {
2980
2982
  print(stats, true)
2981
2983
  } else {
@@ -3044,8 +3046,8 @@ function help() {
3044
3046
  ' >>>>>>> incoming (incoming changes)',
3045
3047
  ' Resolve conflicts manually, then commit and push. Push is blocked until conflicts are resolved.',
3046
3048
  ' pr list|create|merge [--dir <path>] [--title <t>] [--id <id>] [--source <branch>] [--target <branch>]',
3047
- ' clone <url> [--dest <dir>] | --repo <id> --branch <name> [--dest <dir>] [--server <url>] [--token <token>]',
3048
- ' init [--dir <path>] [--repo <id>] [--server <url>] [--branch <name>] [--token <tok>]',
3049
+ ' clone <url> [--dest <dir>] | --repo <name> --branch <name> [--dest <dir>] [--server <url>] [--token <token>]',
3050
+ ' init [--dir <path>] [--repo <name>] [--server <url>] [--branch <name>] [--token <tok>]',
3049
3051
  ' remote show|set-url|set-token [--dir <path>] [--server <url>] [--token <tok>]',
3050
3052
  ' config list|get|set [--key <k>] [--value <v>]',
3051
3053
  ' clean [--dir <path>] [--force]',
@@ -3078,13 +3080,20 @@ async function main() {
3078
3080
  return
3079
3081
  }
3080
3082
  if (cmd[0] === 'clone') {
3081
- if (!opts.url && cmd[1] && !cmd[1].startsWith('--')) opts.url = cmd[1]
3083
+ const arg = cmd[1];
3084
+ if (arg && !arg.startsWith('--')) {
3085
+ if (arg.includes('://')) {
3086
+ opts.url = arg;
3087
+ } else {
3088
+ opts.repo = arg;
3089
+ }
3090
+ }
3082
3091
  if (opts.url) {
3083
- await cmdCloneFromUrl(opts, cfg)
3092
+ await cmdCloneFromUrl(opts, cfg);
3084
3093
  } else {
3085
- await cmdClone(opts, cfg)
3094
+ await cmdClone(opts, cfg);
3086
3095
  }
3087
- return
3096
+ return;
3088
3097
  }
3089
3098
  if (cmd[0] === 'status') {
3090
3099
  await cmdStatus(opts)