@involvex/gitlurk-desktop 0.1.5 → 0.1.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.
- package/README.md +4 -0
- package/dist/index.js +92 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -20,6 +20,10 @@ gitlurk gh run list # passthrough to GitHub CLI
|
|
|
20
20
|
gitlurk runs # shortcut for gh run list
|
|
21
21
|
gitlurk git config list --global
|
|
22
22
|
gitlurk install-desktop # download Windows installer from GitHub Releases
|
|
23
|
+
|
|
24
|
+
# PowerShell tab completion
|
|
25
|
+
gitlurk completions powershell | Out-String | Invoke-Expression
|
|
26
|
+
# or: gitlurk completions powershell >> $PROFILE
|
|
23
27
|
```
|
|
24
28
|
|
|
25
29
|
Requires [GitHub CLI](https://cli.github.com) for `gh` commands.
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,92 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawn as
|
|
3
|
-
`)[0]??null}catch{return null}}async function I(t=[],e){return
|
|
2
|
+
import{spawn as C}from"node:child_process";import{platform as pt}from"node:os";var x=null,ft="GitHub CLI (gh) not found. Install from https://cli.github.com";async function dt(){let t=pt()==="win32"?"where":"which";return new Promise((e)=>{let r=C(t,["gh"],{shell:!0}),o="";r.stdout.on("data",(n)=>{o+=n.toString()}),r.on("close",(n)=>{if(n!==0){e(null);return}let i=o.split(/\r?\n/).find((s)=>s.trim());e(i?.trim()??null)}),r.on("error",()=>e(null))})}async function d(){if(x)return x;let t=await dt();if(!t)throw Error(ft);return x=t,t}async function mt(t,e={}){let r=await d(),o=e.cwd??process.cwd();if(e.inheritStdio)return{stdout:"",stderr:"",exitCode:await c(t,o)};return new Promise((n,i)=>{let s=C(r,t,{cwd:o,shell:!1}),g="",a="";s.stdout.on("data",(l)=>{g+=l.toString()}),s.stderr.on("data",(l)=>{a+=l.toString()}),s.on("error",i),s.on("close",(l)=>{n({stdout:g,stderr:a,exitCode:l??1})})})}async function c(t,e=process.cwd()){let r=await d();return new Promise((o,n)=>{let i=C(r,t,{cwd:e,stdio:"inherit",shell:!1});i.on("error",n),i.on("close",(s)=>o(s??1))})}async function O(){try{let t=await mt(["--version"]);if(t.exitCode!==0)return null;return t.stdout.trim().split(`
|
|
3
|
+
`)[0]??null}catch{return null}}async function I(t=[],e){return c(["run","list",...t],e)}async function L(t=[],e){return c(["run","watch",...t],e)}async function T(t=[],e){return c(["repo","fork",...t],e)}async function A(t=[],e){return c(["repo","edit",...t],e)}async function _(t=[],e){return c(["release","create",...t],e)}async function U(t=[],e){return c(["alias",...t],e)}async function D(t=[],e){return c(["config",...t],e)}async function j(t=[],e){return c(["skill",...t],e)}import{spawn as H}from"node:child_process";import{existsSync as V,readFileSync as kt}from"node:fs";import{join as p,resolve as K}from"node:path";function F(t,e){let r=`gitlurk://openRepo/${t}`;return e?`${r}?branch=${encodeURIComponent(e)}`:r}import{existsSync as N,readFileSync as ht}from"node:fs";import{dirname as q,join as B}from"node:path";import{fileURLToPath as wt}from"node:url";function m(){let t=q(wt(import.meta.url));for(let e=0;e<12;e++){let r=B(t,"package.json");if(N(r))try{let n=JSON.parse(ht(r,"utf8")),i=B(t,"packages/app/package.json");if(n.workspaces&&N(i))return t}catch{}let o=q(t);if(o===t)break;t=o}return null}var f="gitlurk-desktop.exe";function xt(t){let e=p(t,".cargo/config.toml");if(!V(e))return null;try{return kt(e,"utf8").match(/^\s*target-dir\s*=\s*"([^"]+)"/m)?.[1]??null}catch{return null}}function W(t){let e=K(t);return[p(e,"release",f),p(e,"debug",f)]}function Ct(t){let e=[],r=process.env.GITLURK_DESKTOP_EXE??process.env.MYGIT_DESKTOP_EXE;if(r)e.push(r);let o=process.env.CARGO_TARGET_DIR;if(o)e.push(...W(o));if(t){let n=xt(t);if(n)e.push(...W(n));e.push(p(t,"packages/app/src-tauri/target/release",f),p(t,"packages/app/src-tauri/target/debug",f))}return e}function yt(t){for(let e of Ct(t))if(e&&V(e))return e;return null}function y(t){let e=m(),r=yt(e);if(r){console.log(`Launching ${r}`),console.log(` arg: ${t}`),H(r,[t],{detached:!0,stdio:"ignore",windowsHide:!1}).unref();return}if(!e)console.error("GitLurk Desktop executable not found and monorepo root could not be resolved.\nSet GITLURK_DESKTOP_EXE or CARGO_TARGET_DIR, or install with `gitlurk install-desktop`."),process.exit(1);console.log(`No ${f} found — launching via bun tauri from ${e}`),console.log(` arg: ${t}`),H("bun",["run","--filter","@gitlurk/app","tauri","dev","--release","--no-watch","--",t],{cwd:e,detached:!0,stdio:"ignore"}).unref()}function M(t){let e=K(t);y(`--open-local=${e}`)}function X(t){let e=t[0];if(!e||e===".")return M(e==="."?".":process.cwd()),!0;if(e==="open"&&t[1])return M(t[1]),!0;if(e==="clone"&&t[1])return y(`--clone=${t[1]}`),!0;if(e==="url"&&t[1])return y(F(t[1],t[2])),!0;return!1}var J=["powershell"];function bt(t){return t!==void 0&&J.includes(t)}function Pt(){console.log(`Usage:
|
|
4
|
+
gitlurk completions <shell>
|
|
5
|
+
|
|
6
|
+
Shells:
|
|
7
|
+
powershell
|
|
8
|
+
|
|
9
|
+
Install (PowerShell profile):
|
|
10
|
+
gitlurk completions powershell | Out-String | Invoke-Expression
|
|
11
|
+
|
|
12
|
+
Or persist:
|
|
13
|
+
gitlurk completions powershell >> $PROFILE
|
|
14
|
+
`)}function Et(){return`# gitlurk PowerShell completions
|
|
15
|
+
# Add to your profile: gitlurk completions powershell | Out-String | Invoke-Expression
|
|
16
|
+
|
|
17
|
+
Register-ArgumentCompleter -Native -CommandName gitlurk -ScriptBlock {
|
|
18
|
+
param($wordToComplete, $commandAst, $cursorPosition)
|
|
19
|
+
|
|
20
|
+
$elements = @($commandAst.CommandElements | ForEach-Object { $_.Extent.Text })
|
|
21
|
+
if ($elements.Count -eq 0 -or $elements[0] -ne 'gitlurk') { return }
|
|
22
|
+
|
|
23
|
+
$tokens = @($elements | Select-Object -Skip 1)
|
|
24
|
+
if ($wordToComplete -and $tokens.Count -gt 0 -and $tokens[-1] -eq $wordToComplete) {
|
|
25
|
+
$tokens = @($tokens | Select-Object -SkipLast 1)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function Emit([string[]]$Items) {
|
|
29
|
+
$Items |
|
|
30
|
+
Where-Object { $_ -like "$wordToComplete*" } |
|
|
31
|
+
ForEach-Object {
|
|
32
|
+
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if ($tokens.Count -eq 0) {
|
|
37
|
+
Emit @(
|
|
38
|
+
'open', 'clone', 'url', 'gh', 'runs', 'watch', 'fork', 'repo', 'release',
|
|
39
|
+
'alias', 'config', 'skill', 'git', 'install-desktop', 'completions', 'help',
|
|
40
|
+
'--help', '--version', '-h', '-V'
|
|
41
|
+
)
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
$cmd = $tokens[0]
|
|
46
|
+
|
|
47
|
+
switch -Regex ($cmd) {
|
|
48
|
+
'^(open|clone|url|watch|fork|alias|config|skill|install-desktop|help)$' {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
'^gh$' {
|
|
52
|
+
# Defer to file/path completion for gh passthrough args
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
'^runs$' {
|
|
56
|
+
Emit @('--limit', '--json', '--workflow')
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
'^repo$' {
|
|
60
|
+
if ($tokens.Count -eq 1) { Emit @('edit'); return }
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
'^release$' {
|
|
64
|
+
if ($tokens.Count -eq 1) { Emit @('create'); return }
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
'^git$' {
|
|
68
|
+
if ($tokens.Count -eq 1) { Emit @('config'); return }
|
|
69
|
+
if ($tokens.Count -eq 2 -and $tokens[1] -eq 'config') {
|
|
70
|
+
Emit @('list', 'get', 'set', 'edit')
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
if ($tokens.Count -ge 3 -and $tokens[1] -eq 'config') {
|
|
74
|
+
Emit @('--global', '--local', '--system')
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
'^completions$' {
|
|
80
|
+
if ($tokens.Count -eq 1) { Emit @('powershell'); return }
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
default { return }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
`}function z(t){let e=t[1];if(!e||e==="-h"||e==="--help"){Pt();return}if(!bt(e))console.error(`Unsupported shell: ${e}
|
|
87
|
+
Supported: ${J.join(", ")}`),process.exit(1);if(e==="powershell")process.stdout.write(Et())}function Y(t){return t==="completions"||t==="completion"}async function Q(){try{await d()}catch(t){console.error(t instanceof Error?t.message:String(t)),process.exit(1)}}async function Z(t){await Q();let e=t[0];if(e==="runs")process.exit(await I(t.slice(1)));if(e==="watch")process.exit(await L(t.slice(1)));if(e==="fork")process.exit(await T(t.slice(1)));if(e==="repo"&&t[1]==="edit")process.exit(await A(t.slice(2)));if(e==="release"&&t[1]==="create")process.exit(await _(t.slice(2)));if(e==="alias")process.exit(await U(t.slice(1)));if(e==="config")process.exit(await D(t.slice(1)));if(e==="skill")process.exit(await j(t.slice(1)))}async function tt(t){await Q(),process.exit(await c(t))}function et(t){if(!t)return!1;return t==="gh"||t==="runs"||t==="watch"||t==="fork"||t==="repo"||t==="release"||t==="alias"||t==="config"||t==="skill"}import{spawn as E}from"node:child_process";import Gt from"node:fs";import b from"node:path";import{platform as P}from"node:os";var h=null;function St(){let t=[b.join(process.cwd(),"resources","git","cmd","git.exe"),b.join(process.cwd(),"resources","git","bin","git.exe"),b.join(process.env.LOCALAPPDATA??"","GitLurk","git","cmd","git.exe")];for(let e of t)if(e&&Gt.existsSync(e))return e;return null}async function $t(){if(h)return h;let t=await Rt();if(t)return h=t,t;let e=St();if(e)return h=e,e;throw Error("Git not found. Install Git for Windows or bundle Portable Git in resources/git/")}async function Rt(){let t=P()==="win32"?"where":"which";return new Promise((e)=>{let r=E(t,["git"],{shell:!0}),o="";r.stdout.on("data",(n)=>{o+=n.toString()}),r.on("close",(n)=>{if(n!==0){e(null);return}let i=o.split(/\r?\n/).find((s)=>s.trim());e(i?.trim()??null)}),r.on("error",()=>e(null))})}async function w(t,e,r){let o=await $t();return new Promise((n,i)=>{let s=E(o,t,{cwd:e,env:{...process.env,GIT_TERMINAL_PROMPT:"0"}}),g="",a="";s.stdout.on("data",(l)=>{let u=l.toString();g+=u,r?.(u.trim())}),s.stderr.on("data",(l)=>{let u=l.toString();a+=u,r?.(u.trim())}),s.on("error",i),s.on("close",(l)=>{n({stdout:g,stderr:a,exitCode:l??1})})})}function k(t){return`--${t}`}function vt(t){let e=t.trim();if(!e)return null;let r=e.match(/^file:(.+?)\s+(.+)$/);if(r){let n=r[2]??"",i=n.indexOf("=");if(i===-1)return null;return{origin:r[1],key:n.slice(0,i),value:n.slice(i+1)}}let o=e.indexOf("=");if(o===-1)return null;return{key:e.slice(0,o),value:e.slice(o+1)}}async function rt(t){let e=t.cwd??process.cwd(),r=t.scope??"local",o=["config",k(r),"--list"];if(t.showOrigin??r==="local")o.push("--show-origin");let n=await w(o,e);if(n.exitCode!==0)throw Error(n.stderr||"Failed to list git config");return n.stdout.split(/\r?\n/).map(vt).filter((i)=>i!==null)}async function ot(t){let e=t.cwd??process.cwd(),r=t.scope??"local",o=await w(["config",k(r),t.key],e);if(o.exitCode!==0)return null;return o.stdout.trim()}async function nt(t){let e=t.cwd??process.cwd(),r=t.scope??"local",o=await w(["config",k(r),t.key,t.value],e);if(o.exitCode!==0)throw Error(o.stderr||"Failed to set git config")}async function Ot(t){let e=t.cwd??process.cwd(),r=await w(["config",k(t.scope),"--path"],e);if(r.exitCode!==0)return null;return r.stdout.trim()||null}async function it(t){let e=t.cwd??process.cwd(),r=t.scope??"global",o=await Ot({scope:r,cwd:e});if(!o)throw Error(`Could not resolve ${r} git config file path`);let i=(process.env.GIT_EDITOR??process.env.VISUAL??process.env.EDITOR??(P()==="win32"?"notepad":"vi")).split(/\s+/).filter(Boolean),s=i[0];if(!s)throw Error("No editor configured");await new Promise((g,a)=>{let l=E(s,[...i.slice(1),o],{cwd:e,stdio:"inherit",shell:P()==="win32"});l.on("error",a),l.on("close",(u)=>{if(u!==0){a(Error(`Editor exited with code ${u}`));return}g()})})}function It(t){let e="local",r=[];for(let o of t)if(o==="--global")e="global";else if(o==="--local")e="local";else if(o==="--system")e="system";else r.push(o);return{scope:e,remaining:r}}async function st(t){if(t[0]!=="git"||t[1]!=="config")return!1;let e=t[2],{scope:r,remaining:o}=It(t.slice(3)),n=process.cwd();if(e==="list"){let i=await rt({scope:r,cwd:n});for(let s of i)if(s.origin)console.log(`${s.origin} ${s.key}=${s.value}`);else console.log(`${s.key}=${s.value}`);return!0}if(e==="get"){let i=o[0];if(!i)console.error("Usage: gitlurk git config get <key> [--global|--local]"),process.exit(1);let s=await ot({key:i,scope:r,cwd:n});if(s===null)process.exit(1);return console.log(s),!0}if(e==="set"){let i=o[0],s=o[1];if(!i||s===void 0)console.error("Usage: gitlurk git config set <key> <value> [--global|--local]"),process.exit(1);return await nt({key:i,value:s,scope:r,cwd:n}),!0}if(e==="edit")return await it({scope:r,cwd:n}),!0;console.error("Unknown git config subcommand. Use list, get, set, or edit."),process.exit(1)}function lt(t){return t[0]==="git"&&t[1]==="config"}import{spawn as Lt}from"node:child_process";import{createWriteStream as Tt}from"node:fs";import{mkdir as At}from"node:fs/promises";import{homedir as _t,tmpdir as Ut}from"node:os";import{join as G}from"node:path";import{pipeline as Dt}from"node:stream/promises";import{Readable as jt}from"node:stream";var S="involvex/gitlurk",Ft=`https://api.github.com/repos/${S}/releases/latest`;function Nt(t){let e=t.find((r)=>r.name.toLowerCase().endsWith(".msi"));if(e)return e;return t.find((r)=>/setup\.exe$/i.test(r.name)||/-setup\.exe$/i.test(r.name))??null}async function ct(t,e){let r=await fetch(t,{headers:{"User-Agent":"gitlurk-desktop-cli"},redirect:"follow"});if(!r.ok||!r.body)throw Error(`Download failed: ${r.status} ${r.statusText}`);await Dt(jt.fromWeb(r.body),Tt(e))}function qt(t){if(console.log("Launching installer…"),process.platform==="win32"){Lt("cmd",["/c","start","",t],{detached:!0,stdio:"ignore"}).unref();return}console.log(`Installer downloaded to:
|
|
4
88
|
${t}
|
|
5
|
-
Open it manually on this platform.`)}async function
|
|
89
|
+
Open it manually on this platform.`)}async function at(){console.log(`Fetching latest release from ${S}…`);let t=await fetch(Ft,{headers:{"User-Agent":"gitlurk-desktop-cli",Accept:"application/vnd.github+json"}});if(!t.ok)throw Error(`Failed to fetch releases: ${t.status} ${t.statusText}`);let e=await t.json(),r=Nt(e.assets);if(!r)throw Error(`No MSI/setup.exe found in ${e.tag_name}. See https://github.com/${S}/releases`);let o=G(_t(),".gitlurk","downloads");await At(o,{recursive:!0});let n=G(o,r.name);console.log(`Downloading ${r.name} (${e.tag_name})…`);try{await ct(r.browser_download_url,n)}catch{n=G(Ut(),r.name),await ct(r.browser_download_url,n)}console.log(`Saved to ${n}`),qt(n)}function R(){console.log(`GitLurk CLI
|
|
6
90
|
|
|
7
91
|
Usage:
|
|
8
92
|
gitlurk [--help] [--version]
|
|
@@ -32,6 +116,10 @@ Git config:
|
|
|
32
116
|
Desktop installer:
|
|
33
117
|
gitlurk install-desktop Download & launch latest Windows installer
|
|
34
118
|
|
|
119
|
+
Completions:
|
|
120
|
+
gitlurk completions powershell
|
|
121
|
+
# Install: gitlurk completions powershell | Out-String | Invoke-Expression
|
|
122
|
+
|
|
35
123
|
Env:
|
|
36
124
|
GITLURK_DESKTOP_EXE Path to gitlurk-desktop.exe (optional)
|
|
37
125
|
CARGO_TARGET_DIR Cargo target dir; uses release/ then debug/
|
|
@@ -42,4 +130,4 @@ Install:
|
|
|
42
130
|
|
|
43
131
|
If no exe is found, falls back to:
|
|
44
132
|
bun run --filter @gitlurk/app tauri dev --release --no-watch -- <arg>
|
|
45
|
-
`)}import{existsSync as
|
|
133
|
+
`)}import{existsSync as Bt,readFileSync as Ht}from"node:fs";import{dirname as Wt,join as v}from"node:path";import{fileURLToPath as Mt}from"node:url";function ut(t){if(!Bt(t))return null;try{return JSON.parse(Ht(t,"utf8")).version??null}catch{return null}}function gt(){let t=m();if(t){let r=ut(v(t,"package.json"));if(r)return r}let e=Wt(Mt(import.meta.url));for(let r of[v(e,"..","package.json"),v(e,"..","..","package.json")]){let o=ut(r);if(o)return o}return"0.0.0"}function Vt(t){let e=[],r=!1,o=!1;for(let n of t)if(n==="-h"||n==="--help")r=!0;else if(n==="-V"||n==="--version")o=!0;else e.push(n);return{args:e,help:r,version:o}}async function Kt(){let t=process.argv.slice(2),e=t[0]==="--"?t.slice(1):t,{args:r,help:o,version:n}=Vt(e);if(n){console.log(`gitlurk ${gt()}`);let i=await O();if(i)console.log(i);return}if(o||r[0]==="help"){R();return}if(r[0]==="install-desktop"){try{await at()}catch(i){console.error(i instanceof Error?i.message:String(i)),process.exit(1)}return}if(Y(r[0])){z(r);return}if(lt(r)){await st(r);return}if(r[0]==="gh"){await tt(r.slice(1));return}if(et(r[0])){await Z(r);return}if(X(r))return;R(),process.exit(1)}Kt();
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@involvex/gitlurk-desktop",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "GitLurk Desktop CLI — open repos, wrap gh, manage git config",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"gitlurk": "
|
|
7
|
+
"gitlurk": "dist/index.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|