@kitlangton/ghui 0.3.2 → 0.4.0
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 +19 -4
- package/bin/ghui.js +91 -39
- package/package.json +11 -46
- package/.env.example +0 -6
- package/dist/index.js +0 -9419
package/README.md
CHANGED
|
@@ -8,13 +8,18 @@ Terminal UI for keeping up with your open GitHub pull requests across repositori
|
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
|
+
```bash
|
|
12
|
+
brew install kitlangton/tap/ghui
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or with npm:
|
|
16
|
+
|
|
11
17
|
```bash
|
|
12
18
|
npm install -g @kitlangton/ghui
|
|
13
19
|
```
|
|
14
20
|
|
|
15
21
|
Requirements:
|
|
16
22
|
|
|
17
|
-
- Bun runtime installed
|
|
18
23
|
- GitHub CLI installed and authenticated with `gh auth login`
|
|
19
24
|
|
|
20
25
|
Run it from anywhere:
|
|
@@ -67,10 +72,12 @@ You can also copy `.env.example` to `.env` and edit the values locally.
|
|
|
67
72
|
- `esc`: return from expanded details, leave diff/comment mode, or close modal
|
|
68
73
|
- `r`: refresh
|
|
69
74
|
- `d`: view stacked diff for all changed files
|
|
70
|
-
- `
|
|
71
|
-
- `up` / `down` / `pageup` / `pagedown`: move comment target while
|
|
75
|
+
- `shift-r`: review or approve the selected pull request
|
|
76
|
+
- `up` / `down` / `pageup` / `pagedown`: move comment target while viewing a diff
|
|
72
77
|
- `enter`: open a commented diff line, or start a comment on an uncommented line
|
|
73
|
-
- `
|
|
78
|
+
- `v`: start or clear a multi-line diff comment range
|
|
79
|
+
- `n` / `p`: jump between diff comment threads
|
|
80
|
+
- `f`: open the changed-files navigator while viewing a diff
|
|
74
81
|
- `left` / `right`: choose the deleted or added side while in split diff comment mode
|
|
75
82
|
- `[` / `]`: switch files while viewing or commenting on a diff
|
|
76
83
|
- `s`: toggle draft or ready-for-review state
|
|
@@ -81,3 +88,11 @@ You can also copy `.env.example` to `.env` and edit the values locally.
|
|
|
81
88
|
- `o`: open PR in browser
|
|
82
89
|
- `y`: copy PR metadata
|
|
83
90
|
- `q`: quit
|
|
91
|
+
|
|
92
|
+
Review submission:
|
|
93
|
+
|
|
94
|
+
- Press `shift-r` to open the review modal.
|
|
95
|
+
- Use `j` / `k` or `up` / `down` to choose Comment, Approve, or Request changes.
|
|
96
|
+
- Press `enter` to move to the optional summary area.
|
|
97
|
+
- Press `enter` again to submit, or `shift-enter` to insert a newline.
|
|
98
|
+
- Press `esc` from the summary to return to action selection; press `esc` from action selection to cancel.
|
package/bin/ghui.js
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import childProcess from "node:child_process"
|
|
4
|
+
import fs from "node:fs"
|
|
5
|
+
import os from "node:os"
|
|
6
|
+
import path from "node:path"
|
|
7
|
+
import { createRequire } from "node:module"
|
|
8
|
+
import { fileURLToPath } from "node:url"
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
11
|
+
const requireFromHere = createRequire(import.meta.url)
|
|
12
|
+
|
|
13
|
+
const packageJson = requireFromHere("../package.json")
|
|
14
|
+
|
|
15
|
+
const platformMap = {
|
|
16
|
+
darwin: "darwin",
|
|
17
|
+
linux: "linux",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const archMap = {
|
|
21
|
+
arm64: "arm64",
|
|
22
|
+
x64: "x64",
|
|
23
|
+
}
|
|
4
24
|
|
|
5
25
|
const help = `ghui ${packageJson.version}
|
|
6
26
|
|
|
@@ -14,58 +34,90 @@ Usage:
|
|
|
14
34
|
ghui -h, --help Show this help message
|
|
15
35
|
`
|
|
16
36
|
|
|
17
|
-
const args =
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const distances = Array.from({ length: a.length + 1 }, (_, i) => [i])
|
|
23
|
-
for (let j = 1; j <= b.length; j++) distances[0][j] = j
|
|
24
|
-
|
|
25
|
-
for (let i = 1; i <= a.length; i++) {
|
|
26
|
-
for (let j = 1; j <= b.length; j++) {
|
|
27
|
-
distances[i][j] = Math.min(
|
|
28
|
-
distances[i - 1][j] + 1,
|
|
29
|
-
distances[i][j - 1] + 1,
|
|
30
|
-
distances[i - 1][j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1),
|
|
31
|
-
)
|
|
32
|
-
}
|
|
37
|
+
const run = (target, args = process.argv.slice(2)) => {
|
|
38
|
+
const result = childProcess.spawnSync(target, args, { stdio: "inherit" })
|
|
39
|
+
if (result.error) {
|
|
40
|
+
console.error(result.error.message)
|
|
41
|
+
process.exit(1)
|
|
33
42
|
}
|
|
43
|
+
process.exit(typeof result.status === "number" ? result.status : 0)
|
|
44
|
+
}
|
|
34
45
|
|
|
35
|
-
|
|
46
|
+
if (process.env.GHUI_BIN_PATH) {
|
|
47
|
+
run(process.env.GHUI_BIN_PATH)
|
|
36
48
|
}
|
|
37
49
|
|
|
38
|
-
if (
|
|
50
|
+
if (process.argv[2] === "-h" || process.argv[2] === "--help" || process.argv[2] === "help") {
|
|
39
51
|
console.log(help)
|
|
40
52
|
process.exit(0)
|
|
41
53
|
}
|
|
42
54
|
|
|
43
|
-
if (
|
|
55
|
+
if (process.argv[2] === "-v" || process.argv[2] === "--version" || process.argv[2] === "version") {
|
|
44
56
|
console.log(packageJson.version)
|
|
45
57
|
process.exit(0)
|
|
46
58
|
}
|
|
47
59
|
|
|
48
|
-
if (
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
if (process.argv[2] === "upgrade") {
|
|
61
|
+
const result = childProcess.spawnSync("npm", ["install", "-g", `${packageJson.name}@latest`], { stdio: "inherit" })
|
|
62
|
+
if (result.error) {
|
|
63
|
+
console.error(result.error.message)
|
|
64
|
+
process.exit(1)
|
|
65
|
+
}
|
|
66
|
+
process.exit(typeof result.status === "number" ? result.status : 0)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const scriptPath = fs.realpathSync(__filename)
|
|
70
|
+
const scriptDir = path.dirname(scriptPath)
|
|
71
|
+
|
|
72
|
+
const platform = platformMap[os.platform()]
|
|
73
|
+
const arch = archMap[os.arch()]
|
|
74
|
+
|
|
75
|
+
const isMusl = () => {
|
|
76
|
+
if (os.platform() !== "linux") return false
|
|
77
|
+
try {
|
|
78
|
+
if (fs.existsSync("/etc/alpine-release")) return true
|
|
79
|
+
} catch {}
|
|
80
|
+
try {
|
|
81
|
+
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
|
|
82
|
+
return `${result.stdout ?? ""}${result.stderr ?? ""}`.toLowerCase().includes("musl")
|
|
83
|
+
} catch {
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
56
86
|
}
|
|
57
87
|
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
console.error(`Unknown command: ${command}`)
|
|
61
|
-
if (suggestion) console.error(`Did you mean: ghui ${suggestion}?`)
|
|
62
|
-
console.error("Run `ghui --help` for usage.")
|
|
88
|
+
if (!platform || !arch) {
|
|
89
|
+
console.error(`Unsupported platform for ${packageJson.name}: ${os.platform()}-${os.arch()}`)
|
|
63
90
|
process.exit(1)
|
|
64
91
|
}
|
|
65
92
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
93
|
+
if (platform === "linux" && isMusl()) {
|
|
94
|
+
console.error(`${packageJson.name} does not publish musl Linux binaries yet.`)
|
|
95
|
+
console.error("Use a glibc-based Linux distribution, Homebrew on Linux, or the source checkout with Bun.")
|
|
96
|
+
process.exit(1)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const packageName = `${packageJson.name}-${platform}-${arch}`
|
|
100
|
+
|
|
101
|
+
const resolveBinary = () => {
|
|
102
|
+
try {
|
|
103
|
+
const packageJsonPath = requireFromHere.resolve(`${packageName}/package.json`)
|
|
104
|
+
return path.join(path.dirname(packageJsonPath), "bin", "ghui")
|
|
105
|
+
} catch {
|
|
106
|
+
return null
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const binaryPath = resolveBinary()
|
|
111
|
+
|
|
112
|
+
if (!binaryPath || !fs.existsSync(binaryPath)) {
|
|
113
|
+
const sourceEntry = path.join(scriptDir, "..", "src", "standalone.ts")
|
|
114
|
+
if (fs.existsSync(sourceEntry)) {
|
|
115
|
+
run("bun", [sourceEntry, ...process.argv.slice(2)])
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
console.error(`Could not find the ${packageName} binary package for this platform.`)
|
|
119
|
+
console.error(`Try reinstalling ${packageJson.name}, or install ${packageName} manually.`)
|
|
120
|
+
process.exit(1)
|
|
71
121
|
}
|
|
122
|
+
|
|
123
|
+
run(binaryPath)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kitlangton/ghui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Terminal UI for GitHub pull requests",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,60 +16,25 @@
|
|
|
16
16
|
"github",
|
|
17
17
|
"pull-requests",
|
|
18
18
|
"terminal",
|
|
19
|
-
"tui"
|
|
20
|
-
"bun"
|
|
19
|
+
"tui"
|
|
21
20
|
],
|
|
21
|
+
"bin": {
|
|
22
|
+
"ghui": "bin/ghui.js"
|
|
23
|
+
},
|
|
22
24
|
"files": [
|
|
23
25
|
"bin",
|
|
24
|
-
"dist",
|
|
25
26
|
"README.md",
|
|
26
|
-
".env.example",
|
|
27
27
|
"LICENSE"
|
|
28
28
|
],
|
|
29
|
+
"optionalDependencies": {
|
|
30
|
+
"@kitlangton/ghui-darwin-arm64": "0.4.0",
|
|
31
|
+
"@kitlangton/ghui-darwin-x64": "0.4.0",
|
|
32
|
+
"@kitlangton/ghui-linux-arm64": "0.4.0",
|
|
33
|
+
"@kitlangton/ghui-linux-x64": "0.4.0"
|
|
34
|
+
},
|
|
29
35
|
"publishConfig": {
|
|
30
36
|
"access": "public",
|
|
31
37
|
"provenance": true,
|
|
32
38
|
"registry": "https://registry.npmjs.org/"
|
|
33
|
-
},
|
|
34
|
-
"bin": {
|
|
35
|
-
"ghui": "bin/ghui.js"
|
|
36
|
-
},
|
|
37
|
-
"scripts": {
|
|
38
|
-
"build:cli": "bun run dev/build-cli.ts",
|
|
39
|
-
"changeset": "npm exec --package @changesets/cli@2.31.0 -- changeset",
|
|
40
|
-
"changeset:status": "npm exec --package @changesets/cli@2.31.0 -- changeset status",
|
|
41
|
-
"changeset:version": "npm exec --package @changesets/cli@2.31.0 -- changeset version",
|
|
42
|
-
"dev": "GHUI_MOTEL_PORT=${GHUI_MOTEL_PORT:-27686} bun --watch bin/ghui.js",
|
|
43
|
-
"dev:logo": "bun --watch dev/loadingLogo.tsx",
|
|
44
|
-
"start": "bun run src/index.tsx",
|
|
45
|
-
"start:mock": "GHUI_MOCK_PR_COUNT=400 GHUI_MOCK_REPO_COUNT=4 bun run src/index.tsx",
|
|
46
|
-
"test": "bun test test",
|
|
47
|
-
"typecheck": "tsc --noEmit",
|
|
48
|
-
"lint": "oxlint --tsconfig tsconfig.json src/ test/",
|
|
49
|
-
"format": "oxfmt src/ test/ dev/",
|
|
50
|
-
"format:check": "oxfmt --check src/ test/ dev/",
|
|
51
|
-
"package:smoke": "bun run dev/package-smoke.ts",
|
|
52
|
-
"prepack": "bun run build:cli"
|
|
53
|
-
},
|
|
54
|
-
"workspaces": [
|
|
55
|
-
".",
|
|
56
|
-
"packages/*"
|
|
57
|
-
],
|
|
58
|
-
"dependencies": {
|
|
59
|
-
"@effect/atom-react": "4.0.0-beta.59",
|
|
60
|
-
"@opentui/core": "0.2.1",
|
|
61
|
-
"@opentui/react": "0.2.1",
|
|
62
|
-
"effect": "4.0.0-beta.59",
|
|
63
|
-
"react": "19.2.5",
|
|
64
|
-
"scheduler": "0.27.0"
|
|
65
|
-
},
|
|
66
|
-
"devDependencies": {
|
|
67
|
-
"@ghui/keymap": "workspace:*",
|
|
68
|
-
"@effect/language-service": "0.85.1",
|
|
69
|
-
"@types/bun": "1.3.12",
|
|
70
|
-
"@types/react": "19.2.14",
|
|
71
|
-
"oxfmt": "0.47.0",
|
|
72
|
-
"oxlint": "1.62.0",
|
|
73
|
-
"typescript": "6.0.2"
|
|
74
39
|
}
|
|
75
40
|
}
|