gitpick 4.20.0-canary.0 → 4.20.0-canary.10

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 (3) hide show
  1. package/README.md +77 -2
  2. package/dist/index.mjs +13 -13
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -4,13 +4,15 @@
4
4
 
5
5
  **Clone exactly what you need aka straightforward project scaffolding!**
6
6
 
7
- šŸ“¦ `Zero dependencies` / `Un/packed (~25/10kb)` / `Faster and more features` yet drop-in replacement for `degit`
8
-
9
7
  [![Twitter](https://img.shields.io/twitter/follow/nrjdalal_dev?label=%40nrjdalal_dev)](https://twitter.com/nrjdalal_dev)
10
8
  [![npm](https://img.shields.io/npm/v/gitpick?color=red&logo=npm)](https://www.npmjs.com/package/gitpick)
11
9
  [![downloads](https://img.shields.io/npm/dt/gitpick?color=red&logo=npm)](https://www.npmjs.com/package/gitpick)
12
10
  [![stars](https://img.shields.io/github/stars/nrjdalal/gitpick?color=blue)](https://github.com/nrjdalal/gitpick)
13
11
 
12
+ **Now with Interactive Mode.** Browse any repo right in your terminal. See every file, pick what you want, skip what you don't. Just `gitpick owner/repo -i` and you're in. No more guessing paths.
13
+
14
+ šŸ“¦ `Zero dependencies` / `Un/packed (~37/14kb)` / `Faster and more features` yet drop-in replacement for `degit`
15
+
14
16
  > #### Just `copy-and-paste` any GitHub, GitLab or Bitbucket URL - no editing required (shorthands work too) - to clone individual files, folders, branches, commits, raw content or even entire repositories without the `.git` directory.
15
17
 
16
18
  Unlike other tools that force you to tweak URLs or follow strict formats to clone files, folders, branches or commits GitPick works seamlessly with any URL.
@@ -19,11 +21,30 @@ Unlike other tools that force you to tweak URLs or follow strict formats to clon
19
21
 
20
22
  ---
21
23
 
24
+ ### Table of Contents
25
+
26
+ - [Some Examples](#-some-examples)
27
+ - [Features](#-features)
28
+ - [Quick Usage](#-quick-usage)
29
+ - [Options](#-options)
30
+ - [Interactive Mode](#-interactive-mode)
31
+ - [Private Repos](#-private-repos)
32
+ - [Config File](#-config-file)
33
+ - [Install Globally](#-install-globally-optional)
34
+ - [Used By](#-used-by)
35
+ - [Related Projects](#-related-projects)
36
+ - [Contributing](#-contributing)
37
+
38
+ ---
39
+
22
40
  ## šŸ“– Some Examples
23
41
 
24
42
  ### See [Quick Usage](#-quick-usage) for to learn more.
25
43
 
26
44
  ```sh
45
+ # interactive mode - browse and pick files/folders
46
+ npx gitpick owner/repo -i
47
+ npx gitpick https://github.com/owner/repo -i
27
48
  # clone a repo without .git
28
49
  npx gitpick owner/repo
29
50
  npx gitpick https://github.com/owner/repo
@@ -54,6 +75,7 @@ npx gitpick https://bitbucket.org/owner/repo
54
75
  npx gitpick https://bitbucket.org/owner/repo/src/main/path/to/folder
55
76
  # dry run (preview without cloning)
56
77
  npx gitpick owner/repo --dry-run
78
+ npx gitpick owner/repo -i --dry-run
57
79
  ```
58
80
 
59
81
  ---
@@ -63,6 +85,7 @@ npx gitpick owner/repo --dry-run
63
85
  - šŸ” Clone individual files or folders from GitHub, GitLab and Bitbucket
64
86
  - 🧠 Use shorthands `TanStack/router` or full URL's `https://github.com/TanStack/router`
65
87
  - āš™ļø Auto-detects branches and target directory (if not specified) like `git clone`
88
+ - **šŸ”„ Interactive mode** - browse and cherry-pick files/folders with `-i` | `--interactive`
66
89
  - šŸ” Seamlessly works with both public and private repositories using a PAT
67
90
  - šŸ“¦ Can easily clone all submodules with `-r` | `--recursive`
68
91
  - šŸ”Ž Preview what would be cloned with `--dry-run` before cloning
@@ -109,6 +132,7 @@ npx gitpick https://bitbucket.org/owner/repo # Bitbucket
109
132
 
110
133
  ```
111
134
  -b, --branch Branch/SHA to clone
135
+ -i, --interactive Browse and pick files/folders interactively
112
136
  -n, --dry-run Show what would be cloned without cloning
113
137
  -o, --overwrite Skip overwrite prompt
114
138
  -r, --recursive Clone submodules
@@ -123,6 +147,57 @@ npx gitpick https://bitbucket.org/owner/repo # Bitbucket
123
147
 
124
148
  ---
125
149
 
150
+ ## šŸ”„ Interactive Mode
151
+
152
+ > **New in v5.0.** Browse any repository's file tree in your terminal and cherry-pick exactly the files and folders you want.
153
+
154
+ ```sh
155
+ npx gitpick owner/repo -i
156
+ npx gitpick owner/repo -i -b canary
157
+ npx gitpick https://github.com/owner/repo -i
158
+ npx gitpick https://gitlab.com/owner/repo -i
159
+ ```
160
+
161
+ **How it works:**
162
+
163
+ 1. GitPick fetches the repository
164
+ 2. An interactive file tree appears in your terminal
165
+ 3. Navigate with arrow keys, select with space, expand/collapse folders with enter
166
+ 4. Press `c` to confirm - only your selected files get copied
167
+
168
+ ```
169
+ nrjdalal/gitpick repository:main > gitpick
170
+
171
+ > ā— .
172
+ ā— ā”œā”€ā”€ ā–¾ bin/
173
+ ā— │ ā”œā”€ā”€ ā–ø external/
174
+ ā— │ ā”œā”€ā”€ ā–ø utils/
175
+ ā—‹ │ └── index.ts
176
+ ā—‹ ā”œā”€ā”€ ā–ø tests/
177
+ ā—‹ ā”œā”€ā”€ package.json
178
+ ā—‹ └── README.md
179
+
180
+ 2 folders 3 files • 12.4 KB
181
+
182
+ ↑↓:navigate enter:expand space:select c:confirm q:quit
183
+ ```
184
+
185
+ **Controls:**
186
+
187
+ | Key | Action |
188
+ | ----------------- | -------------------------- |
189
+ | `↑` `↓` / `j` `k` | Navigate up/down |
190
+ | `←` `→` / `h` `l` | Collapse/expand folder |
191
+ | `Enter` | Toggle expand/collapse |
192
+ | `Space` | Toggle selection |
193
+ | `.` (first row) | Select/deselect all |
194
+ | `c` | Confirm and clone selected |
195
+ | `q` / `Ctrl+C` | Quit without cloning |
196
+
197
+ Works with GitHub, GitLab, Bitbucket, public and private repos.
198
+
199
+ ---
200
+
126
201
  ## šŸ” Private Repos
127
202
 
128
203
  Use a personal access token with read-only contents permission. Works with GitHub, GitLab and Bitbucket:
package/dist/index.mjs CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import e from"node:fs";import t from"node:os";import n from"node:path";import{parseArgs as r,stripVTControlCharacters as i}from"node:util";import{spawn as a}from"node:child_process";import{once as o}from"node:events";import s from"node:fs/promises";import c from"node:process";import{fileURLToPath as l}from"node:url";import u from"node:tty";import d from"node:https";var f=class extends Error{constructor(...e){super(...e),this.name=`SubprocessError`,this.stdout=``,this.stderr=``}};const p=[`.exe`,`.com`],m={},h=e=>(...t)=>m[t.join(`\0`)]??=e(...t),g=h(async(...e)=>{try{return await s.access(e[0]),!0}catch{return!1}}),_=h(async(e,t,r)=>{let i=r.split(n.delimiter).filter(Boolean).map(e=>e.replace(/^"(.*)"$/,`$1`));try{await Promise.any([t,...i].flatMap(t=>p.map(r=>g(`${n.resolve(t,e)}${r}`))))}catch{return!1}return!0}),v=async(e,t)=>c.platform===`win32`&&!t.shell&&!p.some(t=>e.toLowerCase().endsWith(t))&&!await _(e,t.cwd??`.`,(c.env.PATH||c.env.Path)??``),y=e=>e.replaceAll(/([()\][%!^"`<>&|;, *?])/g,`^$1`),b=e=>y(y(`"${e.replaceAll(/(\\*)"/g,`$1$1\\"`).replace(/(\\*)$/,`$1$1`)}"`)),x=e=>/[^\w./-]/.test(e)?`'${e.replaceAll(`'`,`'\\''`)}'`:e;async function S(e,t=[],r={}){let{stdin:s,stdout:u,stderr:d,stdio:p,cwd:m=`.`,env:h,...g}=r,_=m instanceof URL?l(m):n.resolve(m),S=h?{...c.env,...h}:void 0,C=p??[s,u,d],w=[e,...t].map(e=>x(i(e))).join(` `);[`node`,`node.exe`].includes(e.toLowerCase())&&(e=c.execPath,t=[...c.execArgv.filter(e=>!e.startsWith(`--inspect`)),...t]);let T={...g,stdio:C,env:S,cwd:_};await v(e,T)&&(t=t.map(e=>b(e)),e=y(e),T={...T,shell:!0}),T.shell&&t.length>0&&(e=[e,...t].join(` `),t=[]);let E=a(e,t,T),D=``,O=``;E.stdout&&(E.stdout.setEncoding(`utf8`),E.stdout.on(`data`,e=>D+=e)),E.stderr&&(E.stderr.setEncoding(`utf8`),E.stderr.on(`data`,e=>O+=e)),E.once(`error`,()=>{});try{await o(E,`spawn`)}catch(e){throw Object.assign(new f(`Command failed: ${w}`,{cause:e}),{stdout:D,stderr:O})}await o(E,`close`);let k=e=>e.at(-1)===`
3
- `?e.slice(0,e.at(-2)===`\r`?-2:-1):e;if(E.exitCode&&E.exitCode>0)throw Object.assign(new f(`Command failed with exit code ${E.exitCode}: ${w}`),{stdout:k(D),stderr:k(O),exitCode:E.exitCode});if(E.signalCode)throw Object.assign(new f(`Command was terminated with ${E.signalCode}: ${w}`),{stdout:k(D),stderr:k(O)});return{stdout:k(D),stderr:k(O)}}const C=u?.WriteStream?.prototype?.hasColors?.()??!1,w=(e,t)=>{if(!C)return e=>e;let n=`\u001B[${e}m`,r=`\u001B[${t}m`;return e=>{let i=e+``,a=i.indexOf(r);if(a===-1)return n+i+r;let o=n,s=0,c=(t===22?r:``)+n;for(;a!==-1;)o+=i.slice(s,a)+c,s=a+r.length,a=i.indexOf(r,s);return o+=i.slice(s)+r,o}},T=w(1,22),E=w(2,22),D=w(31,39),O=w(32,39),k=w(33,39),A=w(36,39),ee=c.platform!==`win32`||!!c.env.WT_SESSION||c.env.TERM_PROGRAM===`vscode`,te=e=>!!(e.isTTY&&c.env.TERM!==`dumb`&&!(`CI`in c.env)),ne=O(ee?`āœ”`:`√`),j=ee?[`ā ‹`,`ā ™`,`ā ¹`,`ā ø`,`ā ¼`,`ā “`,`ā ¦`,`ā §`,`ā ‡`,`ā `]:[`-`,`\\`,`|`,`/`],M=(e={})=>{let t=-1,n,r=e.text??``,a=e.stream??c.stderr,o=te(a),s=0,l=0,u=!1,d=e=>a.write(e),f=()=>{if(!(!o||s===0)){a.cursorTo(0);for(let e=0;e<s;e++)e>0&&a.moveCursor(0,-1),a.clearLine(1);s=0}},p=e=>{let t=a.columns??80,n=i(e).split(`
4
- `),r=0;for(let e of n)r+=Math.max(1,Math.ceil(e.length/t));return r},m=()=>{if(!o)return;let e=Date.now();(t===-1||e-l>=80)&&(t=++t%j.length,l=e);let n=j[t],i=`${A(n)} ${r}`;f(),d(i),s=p(i)};return{start(e){return r=e,u=!0,o&&d(`\x1B[?25l`),m(),o&&(n=setInterval(m,80)),this},success(e){return u?(u=!1,n&&=(clearInterval(n),void 0),f(),o&&d(`\x1B[?25h`),d(`${ne} ${e??r}\n`),this):this}}},N=async(t,r,i)=>{let a=i??r,o=await e.promises.readdir(t,{withFileTypes:!0});await e.promises.mkdir(r,{recursive:!0});let s=[];for(let i of o){if(i.name===`.git`)continue;let o=n.join(t,i.name),c=n.join(r,i.name);if(i.isDirectory())s.push(...await N(o,c,a));else if(i.isSymbolicLink()){let t=await e.promises.readlink(o);await e.promises.symlink(t,c),s.push(n.relative(a,c))}else await e.promises.copyFile(o,c),s.push(n.relative(a,c))}return s},P=new Set;function F(){for(let t of P)try{e.rmSync(t,{recursive:!0,force:!0})}catch{}process.exit(1)}process.on(`SIGINT`,F),process.on(`SIGTERM`,F);const re=e=>e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`,I=async(r,i,a)=>{let o=i.tree||i.quiet,s=i.verbose&&!o;process.platform===`win32`&&await S(`git`,[`config`,`--global`,`core.longpaths`,`true`]);let c=`https://${r.token?r.token+`@`:r.token}${r.host}/${r.owner}/${r.repository}.git`,l=`https://${r.host}/${r.owner}/${r.repository}.git`,u=n.resolve(t.tmpdir(),`${r.repository}-${Date.now()}${Math.random().toString(16).slice(2,6)}`);P.add(u);let d=M(),f=performance.now();!i.watch&&!o&&d.start(`Picking ${r.type}${r.type===`repository`?` without .git`:` from repository`}...`);let p=`shallow`,m=performance.now();try{await S(`git`,[`clone`,c,u,`--branch`,r.branch,`--depth`,`1`,`--single-branch`,...i.recursive?[`--recursive`]:[]])}catch{p=`full`,await S(`git`,[`clone`,c,u,...i.recursive?[`--recursive`]:[]]),await S(`git`,[`checkout`,r.branch],{cwd:u})}let h=Number(((performance.now()-m)/1e3).toFixed(2)),g=n.resolve(u,r.path),_=await e.promises.stat(g),v=[],y=performance.now();_.isDirectory()?(await e.promises.mkdir(a,{recursive:!0}),v=await N(g,a)):(await e.promises.mkdir(n.dirname(a),{recursive:!0}),await e.promises.copyFile(g,a),v=[n.basename(a)]);let b=Number(((performance.now()-y)/1e3).toFixed(2)),x=Number(((performance.now()-f)/1e3).toFixed(2)),C=0;for(let t of v)try{let r=await e.promises.stat(n.join(a,t));C+=r.size}catch{let t=await e.promises.stat(a);C+=t.size;break}return o||(i.watch?console.log(`- Synced at `+new Date().toLocaleTimeString()):d.success(`Picked ${r.type}${r.type===`repository`?` without .git`:` from repository`} in ${x} seconds.`)),s&&(console.log(E(` clone: ${p} (depth=${p===`shallow`?`1`:`full`})`)),console.log(E(` from: ${l} @ ${A(r.branch)}`)),console.log(E(` to: ${a}`)),console.log(E(` files: ${v.length} (${re(C)})`)),console.log(E(` network: ${h}s`)),console.log(E(` copy: ${b}s`)),console.log(E(` total: ${x}s`))),await e.promises.rm(u,{recursive:!0,force:!0}),P.delete(u),{files:v,duration:x,networkTime:h,copyTime:b,totalSize:C,cloneStrategy:p}};function L(e,t){return new Promise((n,r)=>{let i=d.get(e,{headers:t,timeout:15e3},e=>{if(e.statusCode===301||e.statusCode===302){let i=e.headers.location;if(i)return e.resume(),L(i,t).then(n,r)}let i=``;e.on(`data`,e=>i+=e),e.on(`end`,()=>n({statusCode:e.statusCode||0,headers:e.headers,body:i}))});i.on(`error`,r),i.on(`timeout`,()=>{i.destroy(),r(Error(`Request timed out`))})})}async function ie(e,t,n,r){let i=`https://api.github.com/repos/${e}/${t}/git/trees/${n}?recursive=1`,a={Accept:`application/vnd.github.v3+json`,"User-Agent":`gitpick`};r&&(a.Authorization=`token ${r}`);let o=await L(i,a);if(o.statusCode===401||o.statusCode===403)throw Error(`GitHub API returned ${o.statusCode}. For private repos or rate limits, set GITHUB_TOKEN or pass a token in the URL.`);if(o.statusCode!==200)throw Error(`GitHub API returned ${o.statusCode}: ${o.body.slice(0,200)}`);return(JSON.parse(o.body).tree||[]).map(e=>({path:e.path,type:e.type===`blob`?`blob`:`tree`,size:e.size}))}async function ae(e,t,n,r){let i=encodeURIComponent(`${e}/${t}`),a=[],o=1;for(;;){let e=`https://gitlab.com/api/v4/projects/${i}/repository/tree?ref=${encodeURIComponent(n)}&recursive=true&per_page=100&page=${o}`,t={"User-Agent":`gitpick`};r&&(t[`PRIVATE-TOKEN`]=r);let s=await L(e,t);if(s.statusCode===401||s.statusCode===403)throw Error(`GitLab API returned ${s.statusCode}. For private repos, set GITLAB_TOKEN or pass a token in the URL.`);if(s.statusCode!==200)throw Error(`GitLab API returned ${s.statusCode}: ${s.body.slice(0,200)}`);let c=JSON.parse(s.body);for(let e of c)a.push({path:e.path,type:e.type===`blob`?`blob`:`tree`});let l=s.headers[`x-next-page`];if(!l||l===``||c.length===0)break;o=Number(l)}return a}async function oe(e,t,n,r){let i=[],a=`https://api.bitbucket.org/2.0/repositories/${e}/${t}/src/${encodeURIComponent(n)}/?pagelen=100&max_depth=100`;for(;a;){let e={"User-Agent":`gitpick`};r&&(e.Authorization=`Bearer ${r}`);let t=await L(a,e);if(t.statusCode===401||t.statusCode===403)throw Error(`Bitbucket API returned ${t.statusCode}. For private repos, set BITBUCKET_TOKEN or pass a token in the URL.`);if(t.statusCode!==200)throw Error(`Bitbucket API returned ${t.statusCode}: ${t.body.slice(0,200)}`);let n=JSON.parse(t.body);for(let e of n.values||[])i.push({path:e.path,type:e.type===`commit_directory`?`tree`:`blob`});a=n.next||null}return i}async function se(e){if(e.host===`github.com`)return ie(e.owner,e.repository,e.branch,e.token);if(e.host===`gitlab.com`)return ae(e.owner,e.repository,e.branch,e.token);if(e.host===`bitbucket.org`)return oe(e.owner,e.repository,e.branch,e.token);throw Error(`Interactive mode is not supported for host: ${e.host}`)}const R=e=>e.replace(/\x1B\[\d+(?:;\d+)*m/g,``);function ce(e){let t=[],n=new Map,r=[...e].sort((e,t)=>e.type===t.type?e.path.localeCompare(t.path,void 0,{sensitivity:`base`}):e.type===`tree`?-1:1);for(let e of r){let r=e.path.split(`/`),i={name:r[r.length-1],path:e.path,type:e.type,size:e.size||0,children:[],expanded:!1,selected:!1,depth:r.length-1};if(e.type===`tree`&&n.set(e.path,i),r.length===1)t.push(i);else{let e=r.slice(0,-1).join(`/`),a=n.get(e);if(a)a.children.push(i);else{let e=``,a=t;for(let t=0;t<r.length-1;t++){e=e?e+`/`+r[t]:r[t];let i=n.get(e);i||(i={name:r[t],path:e,type:`tree`,size:0,children:[],expanded:!1,selected:!1,depth:t},n.set(e,i),a.push(i)),a=i.children}a.push(i)}}}function i(e){e.sort((e,t)=>e.type===t.type?e.name.localeCompare(t.name,void 0,{sensitivity:`base`}):e.type===`tree`?-1:1);for(let t of e)t.children.length&&i(t.children)}return i(t),t}function z(e){let t=[];function n(e,r){for(let i=0;i<e.length;i++){let a=e[i],o=i===e.length-1,s=o?`└── `:`ā”œā”€ā”€ `;t.push({node:a,prefix:r,connector:s}),a.type===`tree`&&a.expanded&&n(a.children,r+(o?` `:`│ `))}}return n(e,``),t}function B(e,t){e.selected=t;for(let n of e.children)B(n,t)}function le(e){let t=[];function n(e){for(let r of e)r.selected?r.type===`tree`?r.children.length>0&&r.children.every(e=>e.selected)||r.children.length===0?t.push(r.path):n(r.children):t.push(r.path):r.type===`tree`&&n(r.children)}return n(e),t}function ue(e){let t=0,n=0,r=0;function i(e){for(let a of e)a.selected&&(a.type===`tree`?n++:(t++,r+=a.size)),a.children.length&&i(a.children)}return i(e),{files:t,folders:n,size:r}}const de=e=>e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`;function fe(e,t){return new Promise(n=>{let r=ce(e);if(!r.length){n([]);return}function i(e,t,n=0){for(let r of e)r.type===`tree`&&n<=t&&(r.expanded=!0,i(r.children,t,n+1))}e.length<=30?i(r,1/0):i(r,1);let a=0,o=0,s=process.stdout,c=process.stdin,l=c.isRaw;c.setRawMode(!0),c.resume(),s.write(`\x1B[?1049h\x1B[?25l`);function u(){c.setRawMode(l??!1),c.pause(),c.removeListener(`data`,p),s.write(`\x1B[?25h\x1B[?1049l`)}let d=()=>{s.write(`\x1B[?25h\x1B[?1049l`)};process.on(`exit`,d);function f(){let e=s.rows||24,n=s.columns||80,i=e-3-1-5,c=z(r);c.length+1;let l=a-1;l>=0?(l<o&&(o=l),l>=o+i&&(o=l-i+1)):o=0,o<0&&(o=0);let u=c.slice(o,o+i),{files:d,folders:f,size:p}=ue(r),m=`\x1B[H\x1B[2J`;m+=`\n ${t}\n\n`;let h=r.every(e=>e.selected),g=a===0,_=h?O(`[āœ”]`):E(`[ ]`),v=`${g?k(`>`):` `} ${_} ${E(`.`)}`;if(g){let e=Math.max(0,n-R(v).length);v=`\x1B[48;5;236m${v}${` `.repeat(e)}\x1B[49m`}m+=v+`
5
- `;for(let e=0;e<u.length;e++){let t=u[e],r=o+e+1===a,i=t.node.selected?O(`[āœ”]`):E(`[ ]`),s=t.node.type===`tree`?A(t.node.name+`/`):t.node.name,c=t.node.type===`tree`?t.node.expanded?E(`ā–¾ `):E(`ā–ø `):` `,l=`${r?k(`>`):` `} ${i} ${E(t.prefix)}${E(t.connector)}${c}${s}`;if(r){let e=Math.max(0,n-R(l).length);l=`\x1B[48;5;236m${l}${` `.repeat(e)}\x1B[49m`}m+=l+`
3
+ `?e.slice(0,e.at(-2)===`\r`?-2:-1):e;if(E.exitCode&&E.exitCode>0)throw Object.assign(new f(`Command failed with exit code ${E.exitCode}: ${w}`),{stdout:k(D),stderr:k(O),exitCode:E.exitCode});if(E.signalCode)throw Object.assign(new f(`Command was terminated with ${E.signalCode}: ${w}`),{stdout:k(D),stderr:k(O)});return{stdout:k(D),stderr:k(O)}}const C=u?.WriteStream?.prototype?.hasColors?.()??!1,w=(e,t)=>{if(!C)return e=>e;let n=`\u001B[${e}m`,r=`\u001B[${t}m`;return e=>{let i=e+``,a=i.indexOf(r);if(a===-1)return n+i+r;let o=n,s=0,c=(t===22?r:``)+n;for(;a!==-1;)o+=i.slice(s,a)+c,s=a+r.length,a=i.indexOf(r,s);return o+=i.slice(s)+r,o}},T=w(1,22),E=w(2,22),D=w(31,39),O=w(32,39),k=w(33,39),A=w(36,39),j=c.platform!==`win32`||!!c.env.WT_SESSION||c.env.TERM_PROGRAM===`vscode`,ee=e=>!!(e.isTTY&&c.env.TERM!==`dumb`&&!(`CI`in c.env)),te=O(j?`āœ”`:`√`),M=j?[`ā ‹`,`ā ™`,`ā ¹`,`ā ø`,`ā ¼`,`ā “`,`ā ¦`,`ā §`,`ā ‡`,`ā `]:[`-`,`\\`,`|`,`/`],N=(e={})=>{let t=-1,n,r=e.text??``,a=e.stream??c.stderr,o=ee(a),s=0,l=0,u=!1,d=e=>a.write(e),f=()=>{if(!(!o||s===0)){a.cursorTo(0);for(let e=0;e<s;e++)e>0&&a.moveCursor(0,-1),a.clearLine(1);s=0}},p=e=>{let t=a.columns??80,n=i(e).split(`
4
+ `),r=0;for(let e of n)r+=Math.max(1,Math.ceil(e.length/t));return r},m=()=>{if(!o)return;let e=Date.now();(t===-1||e-l>=80)&&(t=++t%M.length,l=e);let n=M[t],i=`${A(n)} ${r}`;f(),d(i),s=p(i)};return{start(e){return r=e,u=!0,o&&d(`\x1B[?25l`),m(),o&&(n=setInterval(m,80)),this},success(e){return u?(u=!1,n&&=(clearInterval(n),void 0),f(),o&&d(`\x1B[?25h`),d(`${te} ${e??r}\n`),this):this}}},P=async(t,r,i)=>{let a=i??r,o=await e.promises.readdir(t,{withFileTypes:!0});await e.promises.mkdir(r,{recursive:!0});let s=[];for(let i of o){if(i.name===`.git`)continue;let o=n.join(t,i.name),c=n.join(r,i.name);if(i.isDirectory())s.push(...await P(o,c,a));else if(i.isSymbolicLink()){let t=await e.promises.readlink(o);await e.promises.symlink(t,c),s.push(n.relative(a,c))}else await e.promises.copyFile(o,c),s.push(n.relative(a,c))}return s},F=new Set;function I(){for(let t of F)try{e.rmSync(t,{recursive:!0,force:!0})}catch{}process.exit(1)}process.on(`SIGINT`,I),process.on(`SIGTERM`,I);const ne=e=>e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`,L=async(r,i,a)=>{let o=i.tree||i.quiet,s=i.verbose&&!o;process.platform===`win32`&&await S(`git`,[`config`,`--global`,`core.longpaths`,`true`]);let c=`https://${r.token?r.token+`@`:r.token}${r.host}/${r.owner}/${r.repository}.git`,l=`https://${r.host}/${r.owner}/${r.repository}.git`,u=n.resolve(t.tmpdir(),`${r.repository}-${Date.now()}${Math.random().toString(16).slice(2,6)}`);F.add(u);let d=N(),f=performance.now();!i.watch&&!o&&d.start(`Picking ${r.type}${r.type===`repository`?` without .git`:` from repository`}...`);let p=`shallow`,m=performance.now();try{await S(`git`,[`clone`,c,u,`--branch`,r.branch,`--depth`,`1`,`--single-branch`,...i.recursive?[`--recursive`]:[]])}catch{p=`full`,await S(`git`,[`clone`,c,u,...i.recursive?[`--recursive`]:[]]),await S(`git`,[`checkout`,r.branch],{cwd:u})}let h=Number(((performance.now()-m)/1e3).toFixed(2)),g=n.resolve(u,r.path),_=await e.promises.stat(g),v=[],y=performance.now();_.isDirectory()?(await e.promises.mkdir(a,{recursive:!0}),v=await P(g,a)):(await e.promises.mkdir(n.dirname(a),{recursive:!0}),await e.promises.copyFile(g,a),v=[n.basename(a)]);let b=Number(((performance.now()-y)/1e3).toFixed(2)),x=Number(((performance.now()-f)/1e3).toFixed(2)),C=0;for(let t of v)try{let r=await e.promises.stat(n.join(a,t));C+=r.size}catch{let t=await e.promises.stat(a);C+=t.size;break}return o||(i.watch?console.log(`- Synced at `+new Date().toLocaleTimeString()):d.success(`Picked ${r.type}${r.type===`repository`?` without .git`:` from repository`} in ${x} seconds.`)),s&&(console.log(E(` clone: ${p} (depth=${p===`shallow`?`1`:`full`})`)),console.log(E(` from: ${l} @ ${A(r.branch)}`)),console.log(E(` to: ${a}`)),console.log(E(` files: ${v.length} (${ne(C)})`)),console.log(E(` network: ${h}s`)),console.log(E(` copy: ${b}s`)),console.log(E(` total: ${x}s`))),await e.promises.rm(u,{recursive:!0,force:!0}),F.delete(u),{files:v,duration:x,networkTime:h,copyTime:b,totalSize:C,cloneStrategy:p}},R=e=>e.replace(/\x1B\[\d+(?:;\d+)*m/g,``);function re(e){let t=[],n=new Map,r=[...e].sort((e,t)=>e.type===t.type?e.path.localeCompare(t.path,void 0,{sensitivity:`base`}):e.type===`tree`?-1:1);for(let e of r){let r=e.path.split(`/`),i={name:r[r.length-1],path:e.path,type:e.type,size:e.size||0,children:[],expanded:!1,selected:!1,depth:r.length-1};if(e.type===`tree`&&n.set(e.path,i),r.length===1)t.push(i);else{let e=r.slice(0,-1).join(`/`),a=n.get(e);if(a)a.children.push(i);else{let e=``,a=t;for(let t=0;t<r.length-1;t++){e=e?e+`/`+r[t]:r[t];let i=n.get(e);i||(i={name:r[t],path:e,type:`tree`,size:0,children:[],expanded:!1,selected:!1,depth:t},n.set(e,i),a.push(i)),a=i.children}a.push(i)}}}function i(e){e.sort((e,t)=>e.type===t.type?e.name.localeCompare(t.name,void 0,{sensitivity:`base`}):e.type===`tree`?-1:1);for(let t of e)t.children.length&&i(t.children)}return i(t),t}function ie(e){let t=[];function n(e,r){for(let i=0;i<e.length;i++){let a=e[i],o=i===e.length-1,s=o?`└── `:`ā”œā”€ā”€ `;t.push({node:a,prefix:r,connector:s}),a.type===`tree`&&a.expanded&&n(a.children,r+(o?` `:`│ `))}}return n(e,``),t}function z(e,t){e.selected=t;for(let n of e.children)z(n,t)}function ae(e){let t=[];function n(e){for(let r of e)r.selected?r.type===`tree`?r.children.length>0&&r.children.every(e=>e.selected)||r.children.length===0?t.push(r.path):n(r.children):t.push(r.path):r.type===`tree`&&n(r.children)}return n(e),t}function oe(e){let t=0,n=0,r=0;function i(e){for(let a of e)a.selected&&(a.type===`tree`?n++:(t++,r+=a.size)),a.children.length&&i(a.children)}return i(e),{files:t,folders:n,size:r}}const se=e=>e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`;function ce(e,t){return new Promise(n=>{let r=re(e);if(!r.length){n([]);return}function i(e,t,n=0){for(let r of e)r.type===`tree`&&n<=t&&(r.expanded=!0,i(r.children,t,n+1))}e.length<=30?i(r,1/0):i(r,1);let a=0,o=0,s=process.stdout,c=process.stdin,l=c.isRaw;c.setRawMode(!0),c.resume(),s.write(`\x1B[?1049h\x1B[?25l`);function u(){c.setRawMode(l??!1),c.pause(),c.removeListener(`data`,m),s.write(`\x1B[?25h\x1B[?1049l`)}let d=()=>{s.write(`\x1B[?25h\x1B[?1049l`)},f=()=>{u(),process.removeListener(`exit`,d),process.removeListener(`SIGINT`,f),n([]),process.exit(0)};process.on(`exit`,d),process.on(`SIGINT`,f);function p(){let e=s.rows||24,n=s.columns||80,i=Math.max(1,e-3-1-5),c=ie(r),l=a-1;l>=0?(l<o&&(o=l),l>=o+i&&(o=l-i+1)):o=0,o<0&&(o=0);let u=c.slice(o,o+i),{files:d,folders:f,size:p}=oe(r),m=`\x1B[H\x1B[2J`;m+=`\n ${t}\n\n`;let h=r.every(e=>e.selected),g=a===0,_=h?O(`ā—`):E(`ā—‹`),v=`${g?k(`>`):` `} ${_} ${E(`.`)}`;if(g){let e=Math.max(0,n-R(v).length);v=`\x1B[48;5;236m${v}${` `.repeat(e)}\x1B[49m`}m+=v+`
5
+ `;for(let e=0;e<u.length;e++){let t=u[e],r=o+e+1===a,i=t.node.selected?O(`ā—`):E(`ā—‹`),s=t.node.type===`tree`?A(t.node.name+`/`):t.node.name,c=t.node.type===`tree`?t.node.expanded?E(`ā–¾ `):E(`ā–ø `):` `,l=`${r?k(`>`):` `} ${i} ${E(t.prefix)}${E(t.connector)}${c}${s}`;if(r){let e=Math.max(0,n-R(l).length);l=`\x1B[48;5;236m${l}${` `.repeat(e)}\x1B[49m`}m+=l+`
6
6
  `}for(let e=u.length;e<i;e++)m+=`
7
7
  `;m+=`
8
- `;let y=[];f>0&&y.push(A(`${f} folder${f===1?``:`s`}`)),d>0&&y.push(`${d} file${d===1?``:`s`}`);let b=[];y.length>0&&b.push(y.join(` `)),b.length>0&&b.push(E(de(p)));let x=c.length>i?E(` • ${o+1}-${Math.min(o+i,c.length)}/${c.length}`):``,S=b.length>0?` ${b.join(E(` • `))}${x}`:E(` nothing selected`)+x;m+=S+`
8
+ `;let y=[];f>0&&y.push(A(`${f} folder${f===1?``:`s`}`)),d>0&&y.push(`${d} file${d===1?``:`s`}`);let b=[];y.length>0&&b.push(y.join(` `)),b.length>0&&b.push(E(se(p)));let x=c.length>i?E(` • ${o+1}-${Math.min(o+i,c.length)}/${c.length}`):``,S=b.length>0?` ${b.join(E(` • `))}${x}`:E(` nothing selected`)+x;m+=S+`
9
9
  `,m+=`
10
- `;let C=E(`↑↓:navigate enter:expand space:select c:confirm q:quit`);m+=` ${C}\n`,s.write(m)}function p(e){let t=z(r),i=t.length+1,o=e.toString();if(o===``||o===`q`||o===`Q`){u(),process.removeListener(`exit`,d),n([]);return}if(o===`c`||o===`C`){u(),process.removeListener(`exit`,d),n(le(r));return}if((o===`\x1B[A`||o===`k`)&&a>0&&a--,(o===`\x1B[B`||o===`j`)&&a<i-1&&a++,a===0&&(o===` `||o===`\r`)){let e=r.every(e=>e.selected);for(let t of r)B(t,!e)}if(o===` `&&a>0){let e=t[a-1];e&&B(e.node,!e.node.selected)}if(o===`\r`&&a>0){let e=t[a-1];e&&e.node.type===`tree`&&(e.node.expanded=!e.node.expanded)}if((o===`\x1B[C`||o===`l`)&&a>0){let e=t[a-1];e&&e.node.type===`tree`&&(e.node.expanded=!0)}if((o===`\x1B[D`||o===`h`)&&a>0){let e=t[a-1];e&&e.node.type===`tree`&&(e.node.expanded=!1)}f()}c.on(`data`,p),f()})}function V(e){if(typeof e==`number`||/^\d+$/.test(e))return typeof e==`number`?e:parseInt(e,10);let t=/(\d+)([hms])/g,n=0,r;for(;(r=t.exec(e))!==null;){let e=parseInt(r[1],10);switch(r[2]){case`h`:n+=e*36e5;break;case`m`:n+=e*6e4;break;case`s`:n+=e*1e3;break}}return n}const H=async e=>{let t=(await S(`git`,[`ls-remote`,e])).stdout,n=t.match(/(.+)\s+HEAD/)?.[1],r=t.match(RegExp(`${n}\\s+refs/heads/(.+)`))?.[1];if(!r)throw Error(`Could not determine default branch!`);return r},U=[{prefix:`git@github.com:`,host:`github.com`},{prefix:`https://github.com/`,host:`github.com`},{prefix:`https://raw.githubusercontent.com/`,host:`github.com`},{prefix:`git@gitlab.com:`,host:`gitlab.com`},{prefix:`https://gitlab.com/`,host:`gitlab.com`},{prefix:`git@bitbucket.org:`,host:`bitbucket.org`},{prefix:`https://bitbucket.org/`,host:`bitbucket.org`}];async function pe(e,{branch:t,target:n}){let r=e.match(/^https:\/\/([^@]+)@(github\.com|gitlab\.com|bitbucket\.org)/),i=``;if(r)i=r[1],e=e.replace(`${r[1]}@`,``);else{let t={"github.com":process.env.GITHUB_TOKEN||process.env.GH_TOKEN||``,"gitlab.com":process.env.GITLAB_TOKEN||``,"bitbucket.org":process.env.BITBUCKET_TOKEN||``};for(let{prefix:n,host:r}of U)if(e.startsWith(n)){i=t[r];break}!i&&!e.startsWith(`https://`)&&!e.startsWith(`git@`)&&(i=t[`github.com`])}let a=`github.com`;for(let{prefix:t,host:n}of U)if(e.startsWith(t)){a=n,e=e.replace(t,``);break}let o=e.split(`/`),s=o[0],c=o[1]?.endsWith(`.git`)?o[1].slice(0,-4):o[1],l=`https://${i&&i+`@`}${a}/${s}/${c}`,u,d,f;a===`github.com`?o[2]===`refs`&&[`heads`,`tags`].includes(o[3])?(u=`raw`,d=t||o[4],f=o.slice(5).join(`/`)):o[2]===`refs`&&o[3]===`remotes`?(u=`raw`,d=t||`${o[4]}/${o[5]}`,f=o.slice(6).join(`/`)):o[2]===`blob`?(u=`blob`,d=t||o[3],f=o.slice(4).join(`/`)):o[2]===`tree`?(u=`tree`,d=t||o[3],f=o.slice(4).join(`/`)):o[2]===`commit`?(u=`repository`,d=t||o[3],f=``):(u=`repository`,d=t||await H(l),f=``):a===`gitlab.com`?o[2]===`-`&&o[3]===`blob`?(u=`blob`,d=t||o[4],f=o.slice(5).join(`/`)):o[2]===`-`&&o[3]===`tree`?(u=`tree`,d=t||o[4],f=o.slice(5).join(`/`)):(u=`repository`,d=t||await H(l),f=``):o[2]===`src`?(u=`tree`,d=t||o[3],f=o.slice(4).join(`/`)):(u=`repository`,d=t||await H(l),f=``);let p=n||(u===`blob`?`.`:f.split(`/`).pop()||c);return{token:i,host:a,owner:s,repository:c,type:u,branch:d,path:f,target:p}}const W=n.join(t.homedir(),`.cache`,`gitpick`),G=n.join(W,`update-check.json`);function K(){try{return JSON.parse(e.readFileSync(G,`utf-8`))}catch{return null}}function me(t){try{e.mkdirSync(W,{recursive:!0}),e.writeFileSync(G,JSON.stringify(t))}catch{}}function he(){return new Promise(e=>{let t=d.get(`https://registry.npmjs.org/gitpick/latest`,{headers:{Accept:`application/json`},timeout:3e3},t=>{if(t.statusCode!==200)return t.resume(),e(null);let n=``;t.on(`data`,e=>n+=e),t.on(`end`,()=>{try{e(JSON.parse(n).version||null)}catch{e(null)}})});t.on(`error`,()=>e(null)),t.on(`timeout`,()=>{t.destroy(),e(null)})})}function ge(e,t){let n=e.split(`.`).map(Number),r=t.split(`.`).map(Number);for(let e=0;e<3;e++){if((n[e]||0)>(r[e]||0))return!0;if((n[e]||0)<(r[e]||0))return!1}return!1}function q(e,t){if(t)return;let n=K();n&&ge(n.latestVersion,e)&&console.log(E(`\n Update available: ${k(e)} → ${A(T(n.latestVersion))}\n Run ${A(`npm i -g gitpick`)} to update\n`))}function _e(){let e=K();e&&Date.now()-e.lastCheck<864e5||setTimeout(async()=>{let e=await he();e&&me({lastCheck:Date.now(),latestVersion:e})},0)}const J=Symbol(`singleComment`),ve=Symbol(`multiComment`),Y=(e,t,n)=>e.slice(t,n).replace(/[^ \t\r\n]/g,` `),ye=(e,t)=>{let n=t-1,r=0;for(;e[n]===`\\`;)--n,r+=1;return!!(r%2)};function be(e){if(typeof e!=`string`)throw TypeError(`Expected argument \`jsonString\` to be a \`string\`, got \`${typeof e}\``);let t=!1,n=!1,r=0,i=``,a=``,o=-1;for(let s=0;s<e.length;s++){let c=e[s],l=e[s+1];if(!n&&c===`"`&&(ye(e,s)||(t=!t)),!t)if(!n&&c+l===`//`)i+=e.slice(r,s),r=s,n=J,s++;else if(n===J&&c+l===`\r
11
- `){s++,n=!1,i+=Y(e,r,s),r=s;continue}else if(n===J&&c===`
12
- `)n=!1,i+=Y(e,r,s),r=s;else if(!n&&c+l===`/*`){i+=e.slice(r,s),r=s,n=ve,s++;continue}else if(n===ve&&c+l===`*/`){s++,n=!1,i+=Y(e,r,s+1),r=s+1;continue}else n||(o===-1?c===`,`&&(a+=i+e.slice(r,s),i=``,r=s,o=s):c===`}`||c===`]`?(i+=e.slice(r,s),a+=Y(i,0,1)+i.slice(1),i=``,r=s,o=-1):c!==` `&&c!==` `&&c!==`\r`&&c!==`
13
- `&&(i+=e.slice(r,s),r=s,o=-1))}let s=n===J?Y(e,r):e.slice(r);return a+i+s}const xe=[`.gitpick.json`,`.gitpick.jsonc`],Se=async()=>{let t;for(let r of xe){let i=n.resolve(r);if(e.existsSync(i)){t=i;break}}if(!t)return!1;let r=await e.promises.readFile(t,`utf-8`),i=JSON.parse(be(r));if(!Array.isArray(i)||!i.every(e=>typeof e==`string`))throw Error(`${n.basename(t)} must be an array of strings`);for(let e of i)await S(process.argv[0],[...process.argv.slice(1),...e.split(/\s+/),`-o`],{stdio:`inherit`});return!0};var Ce=`gitpick`,X=`4.20.0-canary.0`;const Z=(e,t)=>`\x1b]8;;${t}\x07${e}\x1b]8;;\x07`,we=`
10
+ `;let C=E(`↑↓:navigate enter:expand space:select c:confirm q:quit`);m+=` ${C}\n`,s.write(m)}function m(e){let t=ie(r),i=t.length+1,o=e.toString();if(o===``||o===`q`||o===`Q`){u(),process.removeListener(`exit`,d),process.removeListener(`SIGINT`,f),n([]);return}if(o===`c`||o===`C`){u(),process.removeListener(`exit`,d),process.removeListener(`SIGINT`,f),n(ae(r));return}if((o===`\x1B[A`||o===`k`)&&a>0&&a--,(o===`\x1B[B`||o===`j`)&&a<i-1&&a++,a===0&&(o===` `||o===`\r`)){let e=r.every(e=>e.selected);for(let t of r)z(t,!e)}if(o===` `&&a>0){let e=t[a-1];e&&z(e.node,!e.node.selected)}if(o===`\r`&&a>0){let e=t[a-1];e&&e.node.type===`tree`&&(e.node.expanded=!e.node.expanded)}if((o===`\x1B[C`||o===`l`)&&a>0){let e=t[a-1];e&&e.node.type===`tree`&&(e.node.expanded=!0)}if((o===`\x1B[D`||o===`h`)&&a>0){let e=t[a-1];e&&e.node.type===`tree`&&(e.node.expanded=!1)}p()}c.on(`data`,m),p()})}function B(e){if(typeof e==`number`||/^\d+$/.test(e))return typeof e==`number`?e:parseInt(e,10);let t=/(\d+)([hms])/g,n=0,r;for(;(r=t.exec(e))!==null;){let e=parseInt(r[1],10);switch(r[2]){case`h`:n+=e*36e5;break;case`m`:n+=e*6e4;break;case`s`:n+=e*1e3;break}}return n}const V=async e=>{let t=(await S(`git`,[`ls-remote`,e])).stdout,n=t.match(/(.+)\s+HEAD/)?.[1],r=t.match(RegExp(`${n}\\s+refs/heads/(.+)`))?.[1];if(!r)throw Error(`Could not determine default branch!`);return r},H=[{prefix:`git@github.com:`,host:`github.com`},{prefix:`https://github.com/`,host:`github.com`},{prefix:`https://raw.githubusercontent.com/`,host:`github.com`},{prefix:`git@gitlab.com:`,host:`gitlab.com`},{prefix:`https://gitlab.com/`,host:`gitlab.com`},{prefix:`git@bitbucket.org:`,host:`bitbucket.org`},{prefix:`https://bitbucket.org/`,host:`bitbucket.org`}];async function le(e,{branch:t,target:n}){let r=e.match(/^https:\/\/([^@]+)@(github\.com|gitlab\.com|bitbucket\.org)/),i=``;if(r)i=r[1],e=e.replace(`${r[1]}@`,``);else{let t={"github.com":process.env.GITHUB_TOKEN||process.env.GH_TOKEN||``,"gitlab.com":process.env.GITLAB_TOKEN||``,"bitbucket.org":process.env.BITBUCKET_TOKEN||``};for(let{prefix:n,host:r}of H)if(e.startsWith(n)){i=t[r];break}!i&&!e.startsWith(`https://`)&&!e.startsWith(`git@`)&&(i=t[`github.com`])}let a=`github.com`;for(let{prefix:t,host:n}of H)if(e.startsWith(t)){a=n,e=e.replace(t,``);break}let o=e.split(`/`),s=o[0],c=o[1]?.endsWith(`.git`)?o[1].slice(0,-4):o[1],l=`https://${i&&i+`@`}${a}/${s}/${c}`,u,d,f;a===`github.com`?o[2]===`refs`&&[`heads`,`tags`].includes(o[3])?(u=`raw`,d=t||o[4],f=o.slice(5).join(`/`)):o[2]===`refs`&&o[3]===`remotes`?(u=`raw`,d=t||`${o[4]}/${o[5]}`,f=o.slice(6).join(`/`)):o[2]===`blob`?(u=`blob`,d=t||o[3],f=o.slice(4).join(`/`)):o[2]===`tree`?(u=`tree`,d=t||o[3],f=o.slice(4).join(`/`)):o[2]===`commit`?(u=`repository`,d=t||o[3],f=``):(u=`repository`,d=t||await V(l),f=``):a===`gitlab.com`?o[2]===`-`&&o[3]===`blob`?(u=`blob`,d=t||o[4],f=o.slice(5).join(`/`)):o[2]===`-`&&o[3]===`tree`?(u=`tree`,d=t||o[4],f=o.slice(5).join(`/`)):(u=`repository`,d=t||await V(l),f=``):o[2]===`src`?(u=`tree`,d=t||o[3],f=o.slice(4).join(`/`)):(u=`repository`,d=t||await V(l),f=``);let p=n||(u===`blob`?`.`:f.split(`/`).pop()||c);return{token:i,host:a,owner:s,repository:c,type:u,branch:d,path:f,target:p}}const U=n.join(t.homedir(),`.cache`,`gitpick`),W=n.join(U,`update-check.json`);function G(){try{return JSON.parse(e.readFileSync(W,`utf-8`))}catch{return null}}function ue(t){try{e.mkdirSync(U,{recursive:!0}),e.writeFileSync(W,JSON.stringify(t))}catch{}}function de(){return new Promise(e=>{let t=d.get(`https://registry.npmjs.org/gitpick/latest`,{headers:{Accept:`application/json`},timeout:3e3},t=>{if(t.statusCode!==200)return t.resume(),e(null);let n=``;t.on(`data`,e=>n+=e),t.on(`end`,()=>{try{e(JSON.parse(n).version||null)}catch{e(null)}})});t.on(`error`,()=>e(null)),t.on(`timeout`,()=>{t.destroy(),e(null)})})}function fe(e,t){let n=e.split(`.`).map(Number),r=t.split(`.`).map(Number);for(let e=0;e<3;e++){if((n[e]||0)>(r[e]||0))return!0;if((n[e]||0)<(r[e]||0))return!1}return!1}function K(e,t){if(t)return;let n=G();n&&fe(n.latestVersion,e)&&console.log(E(`\n Update available: ${k(e)} → ${A(T(n.latestVersion))}\n Run ${A(`npm i -g gitpick`)} to update\n`))}function pe(){let e=G();e&&Date.now()-e.lastCheck<864e5||setTimeout(async()=>{let e=await de();e&&ue({lastCheck:Date.now(),latestVersion:e})},0)}const q=Symbol(`singleComment`),J=Symbol(`multiComment`),Y=(e,t,n)=>e.slice(t,n).replace(/[^ \t\r\n]/g,` `),me=(e,t)=>{let n=t-1,r=0;for(;e[n]===`\\`;)--n,r+=1;return!!(r%2)};function he(e){if(typeof e!=`string`)throw TypeError(`Expected argument \`jsonString\` to be a \`string\`, got \`${typeof e}\``);let t=!1,n=!1,r=0,i=``,a=``,o=-1;for(let s=0;s<e.length;s++){let c=e[s],l=e[s+1];if(!n&&c===`"`&&(me(e,s)||(t=!t)),!t)if(!n&&c+l===`//`)i+=e.slice(r,s),r=s,n=q,s++;else if(n===q&&c+l===`\r
11
+ `){s++,n=!1,i+=Y(e,r,s),r=s;continue}else if(n===q&&c===`
12
+ `)n=!1,i+=Y(e,r,s),r=s;else if(!n&&c+l===`/*`){i+=e.slice(r,s),r=s,n=J,s++;continue}else if(n===J&&c+l===`*/`){s++,n=!1,i+=Y(e,r,s+1),r=s+1;continue}else n||(o===-1?c===`,`&&(a+=i+e.slice(r,s),i=``,r=s,o=s):c===`}`||c===`]`?(i+=e.slice(r,s),a+=Y(i,0,1)+i.slice(1),i=``,r=s,o=-1):c!==` `&&c!==` `&&c!==`\r`&&c!==`
13
+ `&&(i+=e.slice(r,s),r=s,o=-1))}let s=n===q?Y(e,r):e.slice(r);return a+i+s}const ge=[`.gitpick.json`,`.gitpick.jsonc`],_e=async()=>{let t;for(let r of ge){let i=n.resolve(r);if(e.existsSync(i)){t=i;break}}if(!t)return!1;let r=await e.promises.readFile(t,`utf-8`),i=JSON.parse(he(r));if(!Array.isArray(i)||!i.every(e=>typeof e==`string`))throw Error(`${n.basename(t)} must be an array of strings`);for(let e of i)await S(process.argv[0],[...process.argv.slice(1),...e.split(/\s+/),`-o`],{stdio:`inherit`});return!0};var ve=`gitpick`,X=`4.20.0-canary.10`;const Z=(e,t)=>`\x1b]8;;${t}\x07${e}\x1b]8;;\x07`,ye=`
14
14
  With ${T(`${Z(`GitPick`,`https://github.com/nrjdalal/gitpick`)}`)} clone specific directories or files from GitHub, GitLab and Bitbucket!
15
15
 
16
16
  $ gitpick ${k(`<url>`)} ${O(`[target]`)} ${A(`[options]`)}
@@ -47,9 +47,9 @@ ${T(`Examples:`)}
47
47
  $ gitpick https://gitlab.com/owner/repo
48
48
  $ gitpick https://bitbucket.org/owner/repo
49
49
 
50
- šŸš€ More awesome tools at ${A(`https://github.com/nrjdalal`)}`,Q=e=>{let r=process.cwd(),i=t.homedir(),a=n.sep;return e===r?`.`:e.startsWith(r+a)?`./`+n.relative(r,e).replaceAll(a,`/`):e.startsWith(i+a)?`~/`+n.relative(i,e).replaceAll(a,`/`):e},$=async(t,r=``)=>{let i=(await e.promises.readdir(t,{withFileTypes:!0})).filter(e=>e.name!==`.git`).sort((e,t)=>e.name.localeCompare(t.name,void 0,{sensitivity:`base`}));for(let a=0;a<i.length;a++){let o=i[a],s=a===i.length-1,c=s?`└── `:`ā”œā”€ā”€ `,l=n.join(t,o.name);if(o.isSymbolicLink()){let t=await e.promises.readlink(l),n=!1;try{n=e.statSync(l).isDirectory()}catch{}process.stdout.write(`${r}${c}${k(o.name)} -> ${n?A(t):t}\n`)}else o.isDirectory()?(process.stdout.write(`${r}${c}${A(o.name)}\n`),await $(l,`${r}${s?` `:`│ `}`)):process.stdout.write(`${r}${c}${o.name}\n`)}},Te=e=>{try{return r(e)}catch(e){throw Error(`Error parsing arguments: ${e.message}`)}};(async()=>{_e();try{let{positionals:r,values:i}=Te({allowPositionals:!0,options:{branch:{type:`string`,short:`b`},"dry-run":{type:`boolean`,short:`n`},force:{type:`boolean`,short:`f`},help:{type:`boolean`,short:`h`},interactive:{type:`boolean`,short:`i`},quiet:{type:`boolean`,short:`q`},tree:{type:`boolean`},verbose:{type:`boolean`},overwrite:{type:`boolean`,short:`o`},recursive:{type:`boolean`,short:`r`},version:{type:`boolean`,short:`v`},watch:{type:`string`,short:`w`}}});r.length||(i.version&&(console.log(`\n${Ce}@${X}`),process.exit(0)),await Se()&&process.exit(0),console.log(we),process.exit(0)),r[0]===`clone`&&r.shift();let[a,o]=r,s={branch:i.branch,dryRun:i[`dry-run`],force:i.force,interactive:i.interactive,quiet:i.quiet,tree:i.tree,verbose:i.verbose,overwrite:i.overwrite,recursive:i.recursive,watch:i.watch},c=s.tree||s.quiet;c||console.log(`\nWith ${T(`${Z(`GitPick`,`https://github.com/nrjdalal/gitpick`)}`)} clone specific files, folders, branches,\ncommits and much more from GitHub, GitLab and Bitbucket!`);let l=await pe(a,{branch:s.branch,target:o});if(l.type===`blob`){let e=l.target.split(/[/\\]/).filter(e=>e!==``),t=e[e.length-1];t!==`.`&&t!==`..`&&t.includes(`.`)?e.pop():t=l.path.split(`/`).pop()||t,l.target=[...e,t].join(`/`)}c||console.info(`\n${O(`āœ”`)} ${l.owner}/${l.repository} ${A(l.type+`:`+l.branch)} ${l.type===`repository`?`> ${O(l.target)}`:`${l.path.length?k(l.path)+` >`:`>`} ${O(l.target)}`}`);let u=n.resolve(l.target);if(s.interactive){if(!process.stdout.isTTY)throw Error(`Interactive mode requires a TTY`);let r=M();r.start(`Fetching file tree from ${l.owner}/${l.repository}...`);let i=await se(l);r.success(`Fetched ${i.length} entries from ${l.owner}/${l.repository}`),i.length||(console.log(k(`
51
- Repository has no files.`)),process.exit(0));let a=await fe(i,`${l.owner}/${l.repository} ${A(`repository:`+l.branch)} > ${O(l.target)}`);a.length||(console.log(`
52
- No files selected.`),process.exit(0)),console.log(`\n${O(`āœ”`)} Picking ${a.length} selected path${a.length===1?``:`s`}...`);let o=n.resolve(t.tmpdir(),`gitpick-interactive-${Date.now()}${Math.random().toString(16).slice(2,6)}`),c=`https://${l.token?l.token+`@`:``}${l.host}/${l.owner}/${l.repository}.git`;try{await S(`git`,[`clone`,c,o,`--branch`,l.branch,`--depth`,`1`,`--single-branch`,...s.recursive?[`--recursive`]:[]])}catch{await S(`git`,[`clone`,c,o,...s.recursive?[`--recursive`]:[]]),await S(`git`,[`checkout`,l.branch],{cwd:o})}await e.promises.mkdir(u,{recursive:!0});let d=0;for(let t of a){let r=n.join(o,t),i=n.join(u,t),a=await e.promises.stat(r).catch(()=>null);if(a)if(a.isDirectory()){await e.promises.mkdir(i,{recursive:!0});let t=await N(r,i);d+=t.length}else await e.promises.mkdir(n.dirname(i),{recursive:!0}),await e.promises.copyFile(r,i),d++}await e.promises.rm(o,{recursive:!0,force:!0}),console.log(O(`āœ” Copied ${d} file${d===1?``:`s`} to ${Q(u)}`)),s.tree&&(process.stdout.write(`\n${T(A(Q(u)))}\n`),await $(u),process.stdout.write(`
53
- `)),q(X,!1),process.exit(0)}let d=async t=>{e.statSync(t).isDirectory()?(process.stdout.write(`${T(A(Q(u)))}\n`),await $(t)):(process.stdout.write(`${T(A(Q(n.dirname(u))))}\n`),process.stdout.write(`└── ${n.basename(u)}\n`)),process.stdout.write(`
54
- `)};if(s.dryRun){if(s.tree){let r=n.resolve(t.tmpdir(),`gitpick-dry-${Date.now()}${Math.random().toString(16).slice(2,6)}`);try{await I(l,s,r),await d(r)}finally{await e.promises.rm(r,{recursive:!0,force:!0})}}c||console.log(),q(X,c),process.exit(0)}if(s.overwrite=s.overwrite||s.force,s.watch&&(s.overwrite=!0),e.existsSync(u)&&!s.overwrite&&(l.type===`blob`&&(console.log(`${k(`\nWarning: The target file exists at ${O(l.target)}. Use ${A(`-f`)} or ${A(`-o`)} to overwrite.`)}`),process.exit(1)),(await e.promises.readdir(u)).length&&(console.log(`${k(`\nWarning: The target directory exists at ${O(l.target)} and is not empty. Use ${A(`-f`)} or ${A(`-o`)} to overwrite.`)}`),process.exit(1))),s.watch){c||console.log(`\nšŸ‘€ Watching every ${V(s.watch)/1e3+`s`}\n`),await I(l,s,u),s.tree&&await d(u);let e=V(s.watch);setInterval(async()=>{await I(l,s,u),s.tree&&await d(u)},e)}else await I(l,s,u),s.tree&&await d(u),q(X,c),process.exit(0)}catch(e){e instanceof Error?console.log(T(`\n${D(`Error: `)}`)+e.message):console.log(T(`${D(`
50
+ šŸš€ More awesome tools at ${A(`https://github.com/nrjdalal`)}`,Q=e=>{let r=process.cwd(),i=t.homedir(),a=n.sep;return e===r?`.`:e.startsWith(r+a)?`./`+n.relative(r,e).replaceAll(a,`/`):e.startsWith(i+a)?`~/`+n.relative(i,e).replaceAll(a,`/`):e},$=async(t,r=``)=>{let i=(await e.promises.readdir(t,{withFileTypes:!0})).filter(e=>e.name!==`.git`).sort((e,t)=>e.name.localeCompare(t.name,void 0,{sensitivity:`base`}));for(let a=0;a<i.length;a++){let o=i[a],s=a===i.length-1,c=s?`└── `:`ā”œā”€ā”€ `,l=n.join(t,o.name);if(o.isSymbolicLink()){let t=await e.promises.readlink(l),n=!1;try{n=e.statSync(l).isDirectory()}catch{}process.stdout.write(`${r}${c}${k(o.name)} -> ${n?A(t):t}\n`)}else o.isDirectory()?(process.stdout.write(`${r}${c}${A(o.name)}\n`),await $(l,`${r}${s?` `:`│ `}`)):process.stdout.write(`${r}${c}${o.name}\n`)}},be=e=>{try{return r(e)}catch(e){throw Error(`Error parsing arguments: ${e.message}`)}};(async()=>{pe();try{let{positionals:r,values:i}=be({allowPositionals:!0,options:{branch:{type:`string`,short:`b`},"dry-run":{type:`boolean`,short:`n`},force:{type:`boolean`,short:`f`},help:{type:`boolean`,short:`h`},interactive:{type:`boolean`,short:`i`},quiet:{type:`boolean`,short:`q`},tree:{type:`boolean`},verbose:{type:`boolean`},overwrite:{type:`boolean`,short:`o`},recursive:{type:`boolean`,short:`r`},version:{type:`boolean`,short:`v`},watch:{type:`string`,short:`w`}}});r.length||(i.version&&(console.log(`\n${ve}@${X}`),process.exit(0)),await _e()&&process.exit(0),console.log(ye),process.exit(0)),r[0]===`clone`&&r.shift();let[a,o]=r,s={branch:i.branch,dryRun:i[`dry-run`],force:i.force,interactive:i.interactive,quiet:i.quiet,tree:i.tree,verbose:i.verbose,overwrite:i.overwrite,recursive:i.recursive,watch:i.watch},c=s.tree||s.quiet;c||console.log(`\nWith ${T(`${Z(`GitPick`,`https://github.com/nrjdalal/gitpick`)}`)} clone specific files, folders, branches,\ncommits and much more from GitHub, GitLab and Bitbucket!`);let l=await le(a,{branch:s.branch,target:o});if(l.type===`blob`){let e=l.target.split(/[/\\]/).filter(e=>e!==``),t=e[e.length-1];t!==`.`&&t!==`..`&&t.includes(`.`)?e.pop():t=l.path.split(`/`).pop()||t,l.target=[...e,t].join(`/`)}c||console.info(`\n${O(`āœ”`)} ${l.owner}/${l.repository} ${A(l.type+`:`+l.branch)} ${l.type===`repository`?`> ${O(l.target)}`:`${l.path.length?k(l.path)+` >`:`>`} ${O(l.target)}`}`);let u=n.resolve(l.target);if(s.interactive){if(!process.stdout.isTTY)throw Error(`Interactive mode requires a TTY`);let r=n.resolve(t.tmpdir(),`gitpick-interactive-${Date.now()}${Math.random().toString(16).slice(2,6)}`),i=`https://${l.token?l.token+`@`:``}${l.host}/${l.owner}/${l.repository}.git`,a=N();a.start(`Fetching ${l.owner}/${l.repository}...`);try{await S(`git`,[`clone`,i,r,`--branch`,l.branch,`--depth`,`1`,`--single-branch`,...s.recursive?[`--recursive`]:[]])}catch{await S(`git`,[`clone`,i,r,...s.recursive?[`--recursive`]:[]]),await S(`git`,[`checkout`,l.branch],{cwd:r})}let o=[];async function c(t,r){let i=await e.promises.readdir(t,{withFileTypes:!0});for(let a of i){if(a.name===`.git`)continue;let i=r?`${r}/${a.name}`:a.name,s=n.join(t,a.name);if(a.isDirectory())o.push({path:i,type:`tree`}),await c(s,i);else{let t=await e.promises.stat(s);o.push({path:i,type:`blob`,size:t.size})}}}await c(r,``),a.success(`Fetched ${l.owner}/${l.repository} (${o.length} entries)`),o.length||(await e.promises.rm(r,{recursive:!0,force:!0}),console.log(k(`
51
+ Repository has no files.`)),process.exit(0));let d=await ce(o,`${l.owner}/${l.repository} ${A(`repository:`+l.branch)} > ${O(l.target)}`);if(d.length||(await e.promises.rm(r,{recursive:!0,force:!0}),console.log(`
52
+ No files selected.`),process.exit(0)),s.dryRun){console.log(`\n${O(`āœ”`)} Would pick ${d.length} path${d.length===1?``:`s`}:`);for(let e of d)console.log(` ${e}`);await e.promises.rm(r,{recursive:!0,force:!0}),console.log(),K(X,!1),process.exit(0)}console.log(`\n${O(`āœ”`)} Picking ${d.length} selected path${d.length===1?``:`s`}...`),e.existsSync(u)&&!s.overwrite&&(await e.promises.readdir(u)).length&&(await e.promises.rm(r,{recursive:!0,force:!0}),console.log(`${k(`\nWarning: The target directory exists at ${O(l.target)} and is not empty. Use ${A(`-f`)} or ${A(`-o`)} to overwrite.`)}`),process.exit(1)),await e.promises.mkdir(u,{recursive:!0});let f=0;for(let t of d){let i=n.join(r,t),a=n.join(u,t),o=await e.promises.stat(i).catch(()=>null);if(o)if(o.isDirectory()){await e.promises.mkdir(a,{recursive:!0});let t=await P(i,a);f+=t.length}else await e.promises.mkdir(n.dirname(a),{recursive:!0}),await e.promises.copyFile(i,a),f++}await e.promises.rm(r,{recursive:!0,force:!0}),console.log(O(`āœ” Copied ${f} file${f===1?``:`s`} to ${Q(u)}`)),s.tree&&(process.stdout.write(`\n${T(A(Q(u)))}\n`),await $(u),process.stdout.write(`
53
+ `)),K(X,!1),process.exit(0)}let d=async t=>{e.statSync(t).isDirectory()?(process.stdout.write(`${T(A(Q(u)))}\n`),await $(t)):(process.stdout.write(`${T(A(Q(n.dirname(u))))}\n`),process.stdout.write(`└── ${n.basename(u)}\n`)),process.stdout.write(`
54
+ `)};if(s.dryRun){if(s.tree){let r=n.resolve(t.tmpdir(),`gitpick-dry-${Date.now()}${Math.random().toString(16).slice(2,6)}`);try{await L(l,s,r),await d(r)}finally{await e.promises.rm(r,{recursive:!0,force:!0})}}c||console.log(),K(X,c),process.exit(0)}if(s.overwrite=s.overwrite||s.force,s.watch&&(s.overwrite=!0),e.existsSync(u)&&!s.overwrite&&(l.type===`blob`&&(console.log(`${k(`\nWarning: The target file exists at ${O(l.target)}. Use ${A(`-f`)} or ${A(`-o`)} to overwrite.`)}`),process.exit(1)),(await e.promises.readdir(u)).length&&(console.log(`${k(`\nWarning: The target directory exists at ${O(l.target)} and is not empty. Use ${A(`-f`)} or ${A(`-o`)} to overwrite.`)}`),process.exit(1))),s.watch){c||console.log(`\nšŸ‘€ Watching every ${B(s.watch)/1e3+`s`}\n`),await L(l,s,u),s.tree&&await d(u);let e=B(s.watch);setInterval(async()=>{await L(l,s,u),s.tree&&await d(u)},e)}else await L(l,s,u),s.tree&&await d(u),K(X,c),process.exit(0)}catch(e){e instanceof Error?console.log(T(`\n${D(`Error: `)}`)+e.message):console.log(T(`${D(`
55
55
  Unexpected Error: `)}`)+JSON.stringify(e,null,2)),process.exit(1)}})();export{};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitpick",
3
- "version": "4.20.0-canary.0",
3
+ "version": "4.20.0-canary.10",
4
4
  "description": "Clone exactly what you need aka straightforward project scaffolding!",
5
5
  "keywords": [
6
6
  "clone",