@jannael/glinter 1.2.8 → 1.3.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 +104 -104
- package/dist/index.js +251 -124
- package/package.json +14 -18
package/README.md
CHANGED
|
@@ -1,104 +1,104 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<br>
|
|
3
|
-
<br>
|
|
4
|
-
<a href="https://glinter.jannael.com" target="_blank" rel="noopener noreferrer">
|
|
5
|
-
<picture>
|
|
6
|
-
<img alt="Glinter" src="https://github.com/Jannael/glinter/raw/main/apps/web/public/og.png">
|
|
7
|
-
</picture>
|
|
8
|
-
</a>
|
|
9
|
-
</p>
|
|
10
|
-
|
|
11
|
-
Glinter is a high-performance, transparent Git wrapper built with **Bun**.
|
|
12
|
-
|
|
13
|
-
[Tutorial](https://youtu.be/LQWp6flYeyI)
|
|
14
|
-
|
|
15
|
-
[Commands](https://glinter.jannael.com/#commands)
|
|
16
|
-
|
|
17
|
-
[Aliases](https://glinter.jannael.com/alias)
|
|
18
|
-
|
|
19
|
-
[Quick start](https://glinter.jannael.com/#quick-start)
|
|
20
|
-
|
|
21
|
-
## Preview
|
|
22
|
-
|
|
23
|
-
### Badge
|
|
24
|
-
|
|
25
|
-
| Preview | Copy |
|
|
26
|
-
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
27
|
-
| [](https://glinter.jannael.com) | `[](https://glinter.jannael.com)` |
|
|
28
|
-
|
|
29
|
-
<video src="https://github.com/user-attachments/assets/63b401a0-e1e1-453c-9e38-c36cd14e200f" controls="false" autoplay="true" loop="true" muted="true" style="max-width: 100%;">
|
|
30
|
-
Your browser does not support the video tag.
|
|
31
|
-
</video>
|
|
32
|
-
|
|
33
|
-
### Screenshots
|
|
34
|
-
|
|
35
|
-
| `g add` | `g commit` |
|
|
36
|
-
| ------------------------------------ | --------------------------------------- |
|
|
37
|
-
|  |  |
|
|
38
|
-
|
|
39
|
-
## Security
|
|
40
|
-
|
|
41
|
-
Security is a top priority for this project.
|
|
42
|
-
|
|
43
|
-
This project uses Bun as its runtime and package manager. You don't need to worry about package vulnerabilities — the `bunfig.toml` configuration includes `minimumReleaseAge = 259200` (3 days), which prevents newly published packages from being installed automatically. This protects against supply chain attacks that have become increasingly common in the npm ecosystem.
|
|
44
|
-
|
|
45
|
-
## Features
|
|
46
|
-
|
|
47
|
-
- **Abbreviation**: You can use `g` instead of `git`.
|
|
48
|
-
|
|
49
|
-
- **Safe by Default**: Automatically filters and prevents accidental staging of sensitive files: `.env` and `node_modules`.
|
|
50
|
-
|
|
51
|
-
- **Transparent Wrapper**: For every other command (like `commit`, `push`, `log`, or `status`), Glinter acts as a direct tunnel to Git. It preserves all original colors, formatting, and interactive features of the native Git CLI.
|
|
52
|
-
|
|
53
|
-
## Test environment
|
|
54
|
-
|
|
55
|
-
- for windows i used my own laptop (windows 11) so if you have a problem please create an issue
|
|
56
|
-
|
|
57
|
-
- for linux i used WSL (windows subsystem linux) with a kali-linux vm so if you have a problem please create an issue
|
|
58
|
-
|
|
59
|
-
## How it works
|
|
60
|
-
|
|
61
|
-
Glinter is designed to be as "natural" as possible, meaning it shouldn't feel like a wrapper at all.
|
|
62
|
-
|
|
63
|
-
### 1. The Transparent Proxy
|
|
64
|
-
|
|
65
|
-
In `src/index.ts`, Glinter uses `Bun.spawn` with `stdio: 'inherit'`. This is a low-level operation that connects the standard input, output, and error streams of the Git process directly to your terminal.
|
|
66
|
-
|
|
67
|
-
- **Result**: Git "knows" it's in a real terminal, so it correctly detects colors and allows for interactive prompts (like credential entry).
|
|
68
|
-
|
|
69
|
-
### 2. Reliable Status Parsing
|
|
70
|
-
|
|
71
|
-
For the interactive `add` feature, Glinter runs `git status --porcelain`.
|
|
72
|
-
|
|
73
|
-
- **Why?**: Standard `git status` output is designed for humans and can change based on your Git version or system language. `--porcelain` is a machine-readable format that is consistent across all environments, making the file detection 100% reliable.
|
|
74
|
-
|
|
75
|
-
### 3. Interactive Selection
|
|
76
|
-
|
|
77
|
-
Using the `@clack/prompts` library, Glinter transforms the raw status data into a selectable list.
|
|
78
|
-
|
|
79
|
-
- The selection logic uses Bun's high-speed shell to execute the final `git add` command, correctly escaping filenames to handle spaces and special characters.
|
|
80
|
-
|
|
81
|
-
## Installation
|
|
82
|
-
|
|
83
|
-
To use Glinter as your primary Git interface (e.g., using the command `g`):
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
npm install -g @jannael/glinter
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### For Development
|
|
90
|
-
|
|
91
|
-
1. **Clone the repo**
|
|
92
|
-
2. **Install dependencies**: `bun install`
|
|
93
|
-
3. **Link the binary**: `bun link`
|
|
94
|
-
|
|
95
|
-
now you can simply run:
|
|
96
|
-
|
|
97
|
-
```bash
|
|
98
|
-
g add # Opens the interactive selector
|
|
99
|
-
g commit # Opens commit type + message prompt
|
|
100
|
-
g add <file> # Runs standard git add <file>
|
|
101
|
-
g commit -m "" # Runs standard git commit -m ""
|
|
102
|
-
g status # Runs standard git status
|
|
103
|
-
g push # Runs standard git push
|
|
104
|
-
```
|
|
1
|
+
<p align="center">
|
|
2
|
+
<br>
|
|
3
|
+
<br>
|
|
4
|
+
<a href="https://glinter.jannael.com" target="_blank" rel="noopener noreferrer">
|
|
5
|
+
<picture>
|
|
6
|
+
<img alt="Glinter" src="https://github.com/Jannael/glinter/raw/main/apps/web/public/og.png">
|
|
7
|
+
</picture>
|
|
8
|
+
</a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
Glinter is a high-performance, transparent Git wrapper built with **Bun**.
|
|
12
|
+
|
|
13
|
+
[Tutorial](https://youtu.be/LQWp6flYeyI)
|
|
14
|
+
|
|
15
|
+
[Commands](https://glinter.jannael.com/#commands)
|
|
16
|
+
|
|
17
|
+
[Aliases](https://glinter.jannael.com/alias)
|
|
18
|
+
|
|
19
|
+
[Quick start](https://glinter.jannael.com/#quick-start)
|
|
20
|
+
|
|
21
|
+
## Preview
|
|
22
|
+
|
|
23
|
+
### Badge
|
|
24
|
+
|
|
25
|
+
| Preview | Copy |
|
|
26
|
+
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
27
|
+
| [](https://glinter.jannael.com) | `[](https://glinter.jannael.com)` |
|
|
28
|
+
|
|
29
|
+
<video src="https://github.com/user-attachments/assets/63b401a0-e1e1-453c-9e38-c36cd14e200f" controls="false" autoplay="true" loop="true" muted="true" style="max-width: 100%;">
|
|
30
|
+
Your browser does not support the video tag.
|
|
31
|
+
</video>
|
|
32
|
+
|
|
33
|
+
### Screenshots
|
|
34
|
+
|
|
35
|
+
| `g add` | `g commit` |
|
|
36
|
+
| ------------------------------------ | --------------------------------------- |
|
|
37
|
+
|  |  |
|
|
38
|
+
|
|
39
|
+
## Security
|
|
40
|
+
|
|
41
|
+
Security is a top priority for this project.
|
|
42
|
+
|
|
43
|
+
This project uses Bun as its runtime and package manager. You don't need to worry about package vulnerabilities — the `bunfig.toml` configuration includes `minimumReleaseAge = 259200` (3 days), which prevents newly published packages from being installed automatically. This protects against supply chain attacks that have become increasingly common in the npm ecosystem.
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- **Abbreviation**: You can use `g` instead of `git`.
|
|
48
|
+
|
|
49
|
+
- **Safe by Default**: Automatically filters and prevents accidental staging of sensitive files: `.env` and `node_modules`.
|
|
50
|
+
|
|
51
|
+
- **Transparent Wrapper**: For every other command (like `commit`, `push`, `log`, or `status`), Glinter acts as a direct tunnel to Git. It preserves all original colors, formatting, and interactive features of the native Git CLI.
|
|
52
|
+
|
|
53
|
+
## Test environment
|
|
54
|
+
|
|
55
|
+
- for windows i used my own laptop (windows 11) so if you have a problem please create an issue
|
|
56
|
+
|
|
57
|
+
- for linux i used WSL (windows subsystem linux) with a kali-linux vm so if you have a problem please create an issue
|
|
58
|
+
|
|
59
|
+
## How it works
|
|
60
|
+
|
|
61
|
+
Glinter is designed to be as "natural" as possible, meaning it shouldn't feel like a wrapper at all.
|
|
62
|
+
|
|
63
|
+
### 1. The Transparent Proxy
|
|
64
|
+
|
|
65
|
+
In `src/index.ts`, Glinter uses `Bun.spawn` with `stdio: 'inherit'`. This is a low-level operation that connects the standard input, output, and error streams of the Git process directly to your terminal.
|
|
66
|
+
|
|
67
|
+
- **Result**: Git "knows" it's in a real terminal, so it correctly detects colors and allows for interactive prompts (like credential entry).
|
|
68
|
+
|
|
69
|
+
### 2. Reliable Status Parsing
|
|
70
|
+
|
|
71
|
+
For the interactive `add` feature, Glinter runs `git status --porcelain`.
|
|
72
|
+
|
|
73
|
+
- **Why?**: Standard `git status` output is designed for humans and can change based on your Git version or system language. `--porcelain` is a machine-readable format that is consistent across all environments, making the file detection 100% reliable.
|
|
74
|
+
|
|
75
|
+
### 3. Interactive Selection
|
|
76
|
+
|
|
77
|
+
Using the `@clack/prompts` library, Glinter transforms the raw status data into a selectable list.
|
|
78
|
+
|
|
79
|
+
- The selection logic uses Bun's high-speed shell to execute the final `git add` command, correctly escaping filenames to handle spaces and special characters.
|
|
80
|
+
|
|
81
|
+
## Installation
|
|
82
|
+
|
|
83
|
+
To use Glinter as your primary Git interface (e.g., using the command `g`):
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm install -g @jannael/glinter
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### For Development
|
|
90
|
+
|
|
91
|
+
1. **Clone the repo**
|
|
92
|
+
2. **Install dependencies**: `bun install`
|
|
93
|
+
3. **Link the binary**: `bun link`
|
|
94
|
+
|
|
95
|
+
now you can simply run:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
g add # Opens the interactive selector
|
|
99
|
+
g commit # Opens commit type + message prompt
|
|
100
|
+
g add <file> # Runs standard git add <file>
|
|
101
|
+
g commit -m "" # Runs standard git commit -m ""
|
|
102
|
+
g status # Runs standard git status
|
|
103
|
+
g push # Runs standard git push
|
|
104
|
+
```
|
package/dist/index.js
CHANGED
|
@@ -116,6 +116,11 @@ var AVAILABLE_COMMANDS = [
|
|
|
116
116
|
name: "setup",
|
|
117
117
|
command: "g setup",
|
|
118
118
|
description: "Setup alias for git and glinter"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: "reset-hard",
|
|
122
|
+
command: "g reset-hard",
|
|
123
|
+
description: "Interactive reset hard"
|
|
119
124
|
}
|
|
120
125
|
];
|
|
121
126
|
|
|
@@ -1188,8 +1193,8 @@ var u$1 = class u extends V {
|
|
|
1188
1193
|
var o$1 = /* @__PURE__ */ new Set(["up", "down", "left", "right"]);
|
|
1189
1194
|
|
|
1190
1195
|
class h extends V {
|
|
1191
|
-
#
|
|
1192
|
-
#
|
|
1196
|
+
#t = false;
|
|
1197
|
+
#s;
|
|
1193
1198
|
focused = "editor";
|
|
1194
1199
|
get userInputWithCursor() {
|
|
1195
1200
|
if (this.state === "submit")
|
|
@@ -1197,10 +1202,10 @@ class h extends V {
|
|
|
1197
1202
|
const t2 = this.userInput;
|
|
1198
1203
|
if (this.cursor >= t2.length)
|
|
1199
1204
|
return `${t2}\u2588`;
|
|
1200
|
-
const s = t2.slice(0, this.cursor), r2 = t2[this.cursor],
|
|
1205
|
+
const s = t2.slice(0, this.cursor), r2 = t2[this.cursor], i = t2.slice(this.cursor + 1);
|
|
1201
1206
|
return r2 === `
|
|
1202
1207
|
` ? `${s}\u2588
|
|
1203
|
-
${
|
|
1208
|
+
${i}` : `${s}${styleText("inverse", r2)}${i}`;
|
|
1204
1209
|
}
|
|
1205
1210
|
get cursor() {
|
|
1206
1211
|
return this._cursor;
|
|
@@ -1230,37 +1235,41 @@ ${e}` : `${s}${styleText("inverse", r2)}${e}`;
|
|
|
1230
1235
|
}
|
|
1231
1236
|
}
|
|
1232
1237
|
_shouldSubmit(t2, s) {
|
|
1233
|
-
if (this.#
|
|
1238
|
+
if (this.#s)
|
|
1234
1239
|
return this.focused === "submit" ? true : (this.#r(`
|
|
1235
1240
|
`), this._cursor++, false);
|
|
1236
|
-
const r2 = this.#
|
|
1237
|
-
return this.#
|
|
1241
|
+
const r2 = this.#t;
|
|
1242
|
+
return this.#t = true, r2 && this.cursor === this.userInput.length ? (this.userInput[this.cursor - 1] === `
|
|
1238
1243
|
` && (this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--), true) : (this.#r(`
|
|
1239
1244
|
`), this._cursor++, false);
|
|
1240
1245
|
}
|
|
1241
1246
|
constructor(t2) {
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1247
|
+
const s = t2.initialUserInput ?? t2.initialValue;
|
|
1248
|
+
super({
|
|
1249
|
+
...t2,
|
|
1250
|
+
initialUserInput: s
|
|
1251
|
+
}, false), s !== undefined && (this._cursor = s.length), this.#s = t2.showSubmit ?? false, this.on("key", (r2, i) => {
|
|
1252
|
+
if (i?.name && o$1.has(i.name)) {
|
|
1253
|
+
this.#t = false, this.#i(i.name);
|
|
1245
1254
|
return;
|
|
1246
1255
|
}
|
|
1247
|
-
if (
|
|
1256
|
+
if (r2 === "\t" && this.#s) {
|
|
1248
1257
|
this.focused = this.focused === "editor" ? "submit" : "editor";
|
|
1249
1258
|
return;
|
|
1250
1259
|
}
|
|
1251
|
-
if (
|
|
1252
|
-
if (this.#
|
|
1260
|
+
if (i?.name !== "return") {
|
|
1261
|
+
if (this.#t = false, i?.name === "backspace" && this.cursor > 0) {
|
|
1253
1262
|
this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--;
|
|
1254
1263
|
return;
|
|
1255
1264
|
}
|
|
1256
|
-
if (
|
|
1265
|
+
if (i?.name === "delete" && this.cursor < this.userInput.length) {
|
|
1257
1266
|
this._setUserInput(this.userInput.slice(0, this.cursor) + this.userInput.slice(this.cursor + 1));
|
|
1258
1267
|
return;
|
|
1259
1268
|
}
|
|
1260
|
-
|
|
1269
|
+
r2 && (this.#s && this.focused === "submit" && (this.focused = "editor"), this.#r(r2 ?? ""), this._cursor++);
|
|
1261
1270
|
}
|
|
1262
|
-
}), this.on("userInput", (
|
|
1263
|
-
this._setValue(
|
|
1271
|
+
}), this.on("userInput", (r2) => {
|
|
1272
|
+
this._setValue(r2);
|
|
1264
1273
|
}), this.on("finalize", () => {
|
|
1265
1274
|
this.value || (this.value = t2.defaultValue), this.value === undefined && (this.value = "");
|
|
1266
1275
|
});
|
|
@@ -1377,7 +1386,7 @@ function isUnicodeSupported() {
|
|
|
1377
1386
|
}
|
|
1378
1387
|
var unicode = isUnicodeSupported();
|
|
1379
1388
|
var isCI = () => process.env.CI === "true";
|
|
1380
|
-
var unicodeOr = (
|
|
1389
|
+
var unicodeOr = (o2, e) => unicode ? o2 : e;
|
|
1381
1390
|
var S_STEP_ACTIVE = unicodeOr("\u25C6", "*");
|
|
1382
1391
|
var S_STEP_CANCEL = unicodeOr("\u25A0", "x");
|
|
1383
1392
|
var S_STEP_ERROR = unicodeOr("\u25B2", "x");
|
|
@@ -1403,8 +1412,8 @@ var S_INFO = unicodeOr("\u25CF", "\u2022");
|
|
|
1403
1412
|
var S_SUCCESS = unicodeOr("\u25C6", "*");
|
|
1404
1413
|
var S_WARN = unicodeOr("\u25B2", "!");
|
|
1405
1414
|
var S_ERROR = unicodeOr("\u25A0", "x");
|
|
1406
|
-
var symbol = (
|
|
1407
|
-
switch (
|
|
1415
|
+
var symbol = (o2) => {
|
|
1416
|
+
switch (o2) {
|
|
1408
1417
|
case "initial":
|
|
1409
1418
|
case "active":
|
|
1410
1419
|
return styleText2("cyan", S_STEP_ACTIVE);
|
|
@@ -1416,8 +1425,8 @@ var symbol = (e) => {
|
|
|
1416
1425
|
return styleText2("green", S_STEP_SUBMIT);
|
|
1417
1426
|
}
|
|
1418
1427
|
};
|
|
1419
|
-
var symbolBar = (
|
|
1420
|
-
switch (
|
|
1428
|
+
var symbolBar = (o2) => {
|
|
1429
|
+
switch (o2) {
|
|
1421
1430
|
case "initial":
|
|
1422
1431
|
case "active":
|
|
1423
1432
|
return styleText2("cyan", S_BAR);
|
|
@@ -1429,6 +1438,10 @@ var symbolBar = (e) => {
|
|
|
1429
1438
|
return styleText2("green", S_BAR);
|
|
1430
1439
|
}
|
|
1431
1440
|
};
|
|
1441
|
+
function formatInstructionFooter(o2, e) {
|
|
1442
|
+
const r2 = [`${e ? `${styleText2("cyan", S_BAR)} ` : ""}${o2.join(" \u2022 ")}`];
|
|
1443
|
+
return e && r2.push(styleText2("cyan", S_BAR_END)), r2;
|
|
1444
|
+
}
|
|
1432
1445
|
var E$1 = (l2, o2, g2, c2, h2, O = false) => {
|
|
1433
1446
|
let r2 = o2, w = 0;
|
|
1434
1447
|
if (O)
|
|
@@ -1513,61 +1526,48 @@ ${g2}
|
|
|
1513
1526
|
}
|
|
1514
1527
|
}).prompt();
|
|
1515
1528
|
};
|
|
1516
|
-
var
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
const i = t2?.output ?? process.stdout, e = t2?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_START)} ` : "";
|
|
1524
|
-
i.write(`${e}${o2}
|
|
1525
|
-
`);
|
|
1526
|
-
};
|
|
1527
|
-
var outro = (o2 = "", t2) => {
|
|
1528
|
-
const i = t2?.output ?? process.stdout, e = t2?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR)}
|
|
1529
|
-
${styleText2("gray", S_BAR_END)} ` : "";
|
|
1530
|
-
i.write(`${e}${o2}
|
|
1531
|
-
|
|
1532
|
-
`);
|
|
1533
|
-
};
|
|
1534
|
-
var d = (n2, a3) => n2.split(`
|
|
1535
|
-
`).map((m2) => a3(m2)).join(`
|
|
1529
|
+
var MULTISELECT_INSTRUCTIONS = [
|
|
1530
|
+
`${styleText2("dim", "\u2191/\u2193")} to navigate`,
|
|
1531
|
+
`${styleText2("dim", "Space:")} select`,
|
|
1532
|
+
`${styleText2("dim", "Enter:")} confirm`
|
|
1533
|
+
];
|
|
1534
|
+
var m2 = (n2, o2) => n2.split(`
|
|
1535
|
+
`).map((d) => o2(d)).join(`
|
|
1536
1536
|
`);
|
|
1537
1537
|
var multiselect = (n2) => {
|
|
1538
|
-
const
|
|
1538
|
+
const o2 = (t2, a3) => {
|
|
1539
1539
|
const r2 = t2.label ?? String(t2.value);
|
|
1540
|
-
return
|
|
1541
|
-
},
|
|
1540
|
+
return a3 === "disabled" ? `${styleText2("gray", S_CHECKBOX_INACTIVE)} ${m2(r2, (l2) => styleText2(["strikethrough", "gray"], l2))}${t2.hint ? ` ${styleText2("dim", `(${t2.hint ?? "disabled"})`)}` : ""}` : a3 === "active" ? `${styleText2("cyan", S_CHECKBOX_ACTIVE)} ${r2}${t2.hint ? ` ${styleText2("dim", `(${t2.hint})`)}` : ""}` : a3 === "selected" ? `${styleText2("green", S_CHECKBOX_SELECTED)} ${m2(r2, (l2) => styleText2("dim", l2))}${t2.hint ? ` ${styleText2("dim", `(${t2.hint})`)}` : ""}` : a3 === "cancelled" ? `${m2(r2, (l2) => styleText2(["strikethrough", "dim"], l2))}` : a3 === "active-selected" ? `${styleText2("green", S_CHECKBOX_SELECTED)} ${r2}${t2.hint ? ` ${styleText2("dim", `(${t2.hint})`)}` : ""}` : a3 === "submitted" ? `${m2(r2, (l2) => styleText2("dim", l2))}` : `${styleText2("dim", S_CHECKBOX_INACTIVE)} ${m2(r2, (l2) => styleText2("dim", l2))}`;
|
|
1541
|
+
}, d = n2.required ?? true;
|
|
1542
1542
|
return new a$1({
|
|
1543
1543
|
options: n2.options,
|
|
1544
1544
|
signal: n2.signal,
|
|
1545
1545
|
input: n2.input,
|
|
1546
1546
|
output: n2.output,
|
|
1547
1547
|
initialValues: n2.initialValues,
|
|
1548
|
-
required:
|
|
1548
|
+
required: d,
|
|
1549
1549
|
cursorAt: n2.cursorAt,
|
|
1550
1550
|
validate(t2) {
|
|
1551
|
-
if (
|
|
1551
|
+
if (d && (t2 === undefined || t2.length === 0))
|
|
1552
1552
|
return `Please select at least one option.
|
|
1553
1553
|
${styleText2("reset", styleText2("dim", `Press ${styleText2(["gray", "bgWhite", "inverse"], " space ")} to select, ${styleText2("gray", styleText2("bgWhite", styleText2("inverse", " enter ")))} to submit`))}`;
|
|
1554
1554
|
},
|
|
1555
1555
|
render() {
|
|
1556
|
-
const t2 = n2.withGuide ?? settings.withGuide,
|
|
1557
|
-
` : ""}${
|
|
1558
|
-
`, l2 = this.value ?? [],
|
|
1556
|
+
const t2 = n2.withGuide ?? settings.withGuide, a3 = wrapTextWithPrefix(n2.output, n2.message, t2 ? `${symbolBar(this.state)} ` : "", `${symbol(this.state)} `), r2 = `${t2 ? `${styleText2("gray", S_BAR)}
|
|
1557
|
+
` : ""}${a3}
|
|
1558
|
+
`, l2 = this.value ?? [], p2 = (i, u3) => {
|
|
1559
1559
|
if (i.disabled)
|
|
1560
|
-
return
|
|
1560
|
+
return o2(i, "disabled");
|
|
1561
1561
|
const s = l2.includes(i.value);
|
|
1562
|
-
return u3 && s ?
|
|
1562
|
+
return u3 && s ? o2(i, "active-selected") : s ? o2(i, "selected") : o2(i, u3 ? "active" : "inactive");
|
|
1563
1563
|
};
|
|
1564
1564
|
switch (this.state) {
|
|
1565
1565
|
case "submit": {
|
|
1566
|
-
const i = this.options.filter(({ value: s }) => l2.includes(s)).map((s) =>
|
|
1566
|
+
const i = this.options.filter(({ value: s }) => l2.includes(s)).map((s) => o2(s, "submitted")).join(styleText2("dim", ", ")) || styleText2("dim", "none"), u3 = wrapTextWithPrefix(n2.output, i, t2 ? `${styleText2("gray", S_BAR)} ` : "");
|
|
1567
1567
|
return `${r2}${u3}`;
|
|
1568
1568
|
}
|
|
1569
1569
|
case "cancel": {
|
|
1570
|
-
const i = this.options.filter(({ value: s }) => l2.includes(s)).map((s) =>
|
|
1570
|
+
const i = this.options.filter(({ value: s }) => l2.includes(s)).map((s) => o2(s, "cancelled")).join(styleText2("dim", ", "));
|
|
1571
1571
|
if (i.trim() === "")
|
|
1572
1572
|
return `${r2}${styleText2("gray", S_BAR)}`;
|
|
1573
1573
|
const u3 = wrapTextWithPrefix(n2.output, i, t2 ? `${styleText2("gray", S_BAR)} ` : "");
|
|
@@ -1576,9 +1576,9 @@ ${styleText2("gray", S_BAR)}` : ""}`;
|
|
|
1576
1576
|
}
|
|
1577
1577
|
case "error": {
|
|
1578
1578
|
const i = t2 ? `${styleText2("yellow", S_BAR)} ` : "", u3 = this.error.split(`
|
|
1579
|
-
`).map((
|
|
1579
|
+
`).map(($, x) => x === 0 ? `${t2 ? `${styleText2("yellow", S_BAR_END)} ` : ""}${styleText2("yellow", $)}` : ` ${$}`).join(`
|
|
1580
1580
|
`), s = r2.split(`
|
|
1581
|
-
`).length,
|
|
1581
|
+
`).length, g2 = u3.split(`
|
|
1582
1582
|
`).length + 1;
|
|
1583
1583
|
return `${r2}${i}${limitOptions({
|
|
1584
1584
|
output: n2.output,
|
|
@@ -1586,8 +1586,8 @@ ${styleText2("gray", S_BAR)}` : ""}`;
|
|
|
1586
1586
|
cursor: this.cursor,
|
|
1587
1587
|
maxItems: n2.maxItems,
|
|
1588
1588
|
columnPadding: i.length,
|
|
1589
|
-
rowPadding: s +
|
|
1590
|
-
style:
|
|
1589
|
+
rowPadding: s + g2,
|
|
1590
|
+
style: p2
|
|
1591
1591
|
}).join(`
|
|
1592
1592
|
${i}`)}
|
|
1593
1593
|
${u3}
|
|
@@ -1595,24 +1595,43 @@ ${u3}
|
|
|
1595
1595
|
}
|
|
1596
1596
|
default: {
|
|
1597
1597
|
const i = t2 ? `${styleText2("cyan", S_BAR)} ` : "", u3 = r2.split(`
|
|
1598
|
-
`).length, s = t2
|
|
1598
|
+
`).length, s = formatInstructionFooter(MULTISELECT_INSTRUCTIONS, t2), g2 = s.join(`
|
|
1599
|
+
`), $ = s.length + 1;
|
|
1599
1600
|
return `${r2}${i}${limitOptions({
|
|
1600
1601
|
output: n2.output,
|
|
1601
1602
|
options: this.options,
|
|
1602
1603
|
cursor: this.cursor,
|
|
1603
1604
|
maxItems: n2.maxItems,
|
|
1604
1605
|
columnPadding: i.length,
|
|
1605
|
-
rowPadding: u3 +
|
|
1606
|
-
style:
|
|
1606
|
+
rowPadding: u3 + $,
|
|
1607
|
+
style: p2
|
|
1607
1608
|
}).join(`
|
|
1608
1609
|
${i}`)}
|
|
1609
|
-
${
|
|
1610
|
+
${g2}
|
|
1610
1611
|
`;
|
|
1611
1612
|
}
|
|
1612
1613
|
}
|
|
1613
1614
|
}
|
|
1614
1615
|
}).prompt();
|
|
1615
1616
|
};
|
|
1617
|
+
var cancel = (o2 = "", t2) => {
|
|
1618
|
+
const i = t2?.output ?? process.stdout, e = t2?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_END)} ` : "";
|
|
1619
|
+
i.write(`${e}${styleText2("red", o2)}
|
|
1620
|
+
|
|
1621
|
+
`);
|
|
1622
|
+
};
|
|
1623
|
+
var intro = (o2 = "", t2) => {
|
|
1624
|
+
const i = t2?.output ?? process.stdout, e = t2?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_START)} ` : "";
|
|
1625
|
+
i.write(`${e}${o2}
|
|
1626
|
+
`);
|
|
1627
|
+
};
|
|
1628
|
+
var outro = (o2 = "", t2) => {
|
|
1629
|
+
const i = t2?.output ?? process.stdout, e = t2?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR)}
|
|
1630
|
+
${styleText2("gray", S_BAR_END)} ` : "";
|
|
1631
|
+
i.write(`${e}${o2}
|
|
1632
|
+
|
|
1633
|
+
`);
|
|
1634
|
+
};
|
|
1616
1635
|
var W = (l2) => styleText2("magenta", l2);
|
|
1617
1636
|
var spinner = ({
|
|
1618
1637
|
indicator: l2 = "dots",
|
|
@@ -1622,18 +1641,18 @@ var spinner = ({
|
|
|
1622
1641
|
errorMessage: O,
|
|
1623
1642
|
frames: E = unicode ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"],
|
|
1624
1643
|
delay: F = unicode ? 80 : 120,
|
|
1625
|
-
signal:
|
|
1644
|
+
signal: m3,
|
|
1626
1645
|
...I
|
|
1627
1646
|
} = {}) => {
|
|
1628
1647
|
const u3 = isCI();
|
|
1629
|
-
let M2, T3,
|
|
1648
|
+
let M2, T3, d = false, S = false, s = "", p2, w = performance.now();
|
|
1630
1649
|
const x = getColumns(n2), k = I?.styleFrame ?? W, g2 = (e) => {
|
|
1631
1650
|
const r2 = e > 1 ? O ?? settings.messages.error : G ?? settings.messages.cancel;
|
|
1632
|
-
S = e === 1,
|
|
1651
|
+
S = e === 1, d && (a3(r2, e), S && typeof h2 == "function" && h2());
|
|
1633
1652
|
}, f2 = () => g2(2), i = () => g2(1), A = () => {
|
|
1634
|
-
process.on("uncaughtExceptionMonitor", f2), process.on("unhandledRejection", f2), process.on("SIGINT", i), process.on("SIGTERM", i), process.on("exit", g2),
|
|
1653
|
+
process.on("uncaughtExceptionMonitor", f2), process.on("unhandledRejection", f2), process.on("SIGINT", i), process.on("SIGTERM", i), process.on("exit", g2), m3 && m3.addEventListener("abort", i);
|
|
1635
1654
|
}, H = () => {
|
|
1636
|
-
process.removeListener("uncaughtExceptionMonitor", f2), process.removeListener("unhandledRejection", f2), process.removeListener("SIGINT", i), process.removeListener("SIGTERM", i), process.removeListener("exit", g2),
|
|
1655
|
+
process.removeListener("uncaughtExceptionMonitor", f2), process.removeListener("unhandledRejection", f2), process.removeListener("SIGINT", i), process.removeListener("SIGTERM", i), process.removeListener("exit", g2), m3 && m3.removeEventListener("abort", i);
|
|
1637
1656
|
}, y = () => {
|
|
1638
1657
|
if (p2 === undefined)
|
|
1639
1658
|
return;
|
|
@@ -1649,7 +1668,7 @@ var spinner = ({
|
|
|
1649
1668
|
const r2 = (performance.now() - e) / 1000, t2 = Math.floor(r2 / 60), o2 = Math.floor(r2 % 60);
|
|
1650
1669
|
return t2 > 0 ? `[${t2}m ${o2}s]` : `[${o2}s]`;
|
|
1651
1670
|
}, N = I.withGuide ?? settings.withGuide, P2 = (e = "") => {
|
|
1652
|
-
|
|
1671
|
+
d = true, M2 = block({ output: n2 }), s = C2(e), w = performance.now(), N && n2.write(`${styleText2("gray", S_BAR)}
|
|
1653
1672
|
`);
|
|
1654
1673
|
let r2 = 0, t2 = 0;
|
|
1655
1674
|
A(), T3 = setInterval(() => {
|
|
@@ -1673,9 +1692,9 @@ var spinner = ({
|
|
|
1673
1692
|
n2.write(j), r2 = r2 + 1 < E.length ? r2 + 1 : 0, t2 = t2 < 4 ? t2 + 0.125 : 0;
|
|
1674
1693
|
}, F);
|
|
1675
1694
|
}, a3 = (e = "", r2 = 0, t2 = false) => {
|
|
1676
|
-
if (!
|
|
1695
|
+
if (!d)
|
|
1677
1696
|
return;
|
|
1678
|
-
|
|
1697
|
+
d = false, clearInterval(T3), y();
|
|
1679
1698
|
const o2 = r2 === 0 ? styleText2("green", S_STEP_SUBMIT) : r2 === 1 ? styleText2("red", S_STEP_CANCEL) : styleText2("red", S_STEP_ERROR);
|
|
1680
1699
|
s = e ?? s, t2 || (l2 === "timer" ? n2.write(`${o2} ${s} ${_2(w)}
|
|
1681
1700
|
`) : n2.write(`${o2} ${s}
|
|
@@ -1700,20 +1719,24 @@ var u3 = {
|
|
|
1700
1719
|
heavy: unicodeOr("\u2501", "="),
|
|
1701
1720
|
block: unicodeOr("\u2588", "#")
|
|
1702
1721
|
};
|
|
1703
|
-
var
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
var
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1722
|
+
var SELECT_INSTRUCTIONS = [
|
|
1723
|
+
`${styleText2("dim", "\u2191/\u2193")} to navigate`,
|
|
1724
|
+
`${styleText2("dim", "Enter:")} confirm`
|
|
1725
|
+
];
|
|
1726
|
+
var c2 = (t2, a3) => t2.includes(`
|
|
1727
|
+
`) ? t2.split(`
|
|
1728
|
+
`).map((i) => a3(i)).join(`
|
|
1729
|
+
`) : a3(t2);
|
|
1730
|
+
var select = (t2) => {
|
|
1731
|
+
const a3 = (i, m3) => {
|
|
1732
|
+
const s = i.label ?? String(i.value);
|
|
1733
|
+
switch (m3) {
|
|
1711
1734
|
case "disabled":
|
|
1712
|
-
return `${styleText2("gray", S_RADIO_INACTIVE)} ${c2(s, (n2) => styleText2("gray", n2))}${
|
|
1735
|
+
return `${styleText2("gray", S_RADIO_INACTIVE)} ${c2(s, (n2) => styleText2("gray", n2))}${i.hint ? ` ${styleText2("dim", `(${i.hint ?? "disabled"})`)}` : ""}`;
|
|
1713
1736
|
case "selected":
|
|
1714
1737
|
return `${c2(s, (n2) => styleText2("dim", n2))}`;
|
|
1715
1738
|
case "active":
|
|
1716
|
-
return `${styleText2("green", S_RADIO_ACTIVE)} ${s}${
|
|
1739
|
+
return `${styleText2("green", S_RADIO_ACTIVE)} ${s}${i.hint ? ` ${styleText2("dim", `(${i.hint})`)}` : ""}`;
|
|
1717
1740
|
case "cancelled":
|
|
1718
1741
|
return `${c2(s, (n2) => styleText2(["strikethrough", "dim"], n2))}`;
|
|
1719
1742
|
default:
|
|
@@ -1721,39 +1744,40 @@ var select = (e) => {
|
|
|
1721
1744
|
}
|
|
1722
1745
|
};
|
|
1723
1746
|
return new a2({
|
|
1724
|
-
options:
|
|
1725
|
-
signal:
|
|
1726
|
-
input:
|
|
1727
|
-
output:
|
|
1728
|
-
initialValue:
|
|
1747
|
+
options: t2.options,
|
|
1748
|
+
signal: t2.signal,
|
|
1749
|
+
input: t2.input,
|
|
1750
|
+
output: t2.output,
|
|
1751
|
+
initialValue: t2.initialValue,
|
|
1729
1752
|
render() {
|
|
1730
|
-
const
|
|
1753
|
+
const i = t2.withGuide ?? settings.withGuide, m3 = `${symbol(this.state)} `, s = `${symbolBar(this.state)} `, n2 = wrapTextWithPrefix(t2.output, t2.message, s, m3), u4 = `${i ? `${styleText2("gray", S_BAR)}
|
|
1731
1754
|
` : ""}${n2}
|
|
1732
1755
|
`;
|
|
1733
1756
|
switch (this.state) {
|
|
1734
1757
|
case "submit": {
|
|
1735
|
-
const r2 =
|
|
1736
|
-
return `${u4}${
|
|
1758
|
+
const r2 = i ? `${styleText2("gray", S_BAR)} ` : "", o2 = wrapTextWithPrefix(t2.output, a3(this.options[this.cursor], "selected"), r2);
|
|
1759
|
+
return `${u4}${o2}`;
|
|
1737
1760
|
}
|
|
1738
1761
|
case "cancel": {
|
|
1739
|
-
const r2 =
|
|
1740
|
-
return `${u4}${
|
|
1762
|
+
const r2 = i ? `${styleText2("gray", S_BAR)} ` : "", o2 = wrapTextWithPrefix(t2.output, a3(this.options[this.cursor], "cancelled"), r2);
|
|
1763
|
+
return `${u4}${o2}${i ? `
|
|
1741
1764
|
${styleText2("gray", S_BAR)}` : ""}`;
|
|
1742
1765
|
}
|
|
1743
1766
|
default: {
|
|
1744
|
-
const r2 =
|
|
1745
|
-
`).length,
|
|
1767
|
+
const r2 = i ? `${styleText2("cyan", S_BAR)} ` : "", o2 = u4.split(`
|
|
1768
|
+
`).length, $ = formatInstructionFooter(SELECT_INSTRUCTIONS, i), h2 = $.join(`
|
|
1769
|
+
`), b2 = $.length + 1;
|
|
1746
1770
|
return `${u4}${r2}${limitOptions({
|
|
1747
|
-
output:
|
|
1771
|
+
output: t2.output,
|
|
1748
1772
|
cursor: this.cursor,
|
|
1749
1773
|
options: this.options,
|
|
1750
|
-
maxItems:
|
|
1774
|
+
maxItems: t2.maxItems,
|
|
1751
1775
|
columnPadding: r2.length,
|
|
1752
|
-
rowPadding:
|
|
1753
|
-
style: (p2,
|
|
1776
|
+
rowPadding: o2 + b2,
|
|
1777
|
+
style: (p2, x) => a3(p2, p2.disabled ? "disabled" : x ? "active" : "inactive")
|
|
1754
1778
|
}).join(`
|
|
1755
1779
|
${r2}`)}
|
|
1756
|
-
${
|
|
1780
|
+
${h2}
|
|
1757
1781
|
`;
|
|
1758
1782
|
}
|
|
1759
1783
|
}
|
|
@@ -1775,10 +1799,10 @@ var text = (t2) => new n({
|
|
|
1775
1799
|
`, c3 = t2.placeholder ? styleText2("inverse", t2.placeholder[0]) + styleText2("dim", t2.placeholder.slice(1)) : styleText2(["inverse", "hidden"], "_"), o2 = this.userInput ? this.userInputWithCursor : c3, a3 = this.value ?? "";
|
|
1776
1800
|
switch (this.state) {
|
|
1777
1801
|
case "error": {
|
|
1778
|
-
const n2 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r2 = i2 ? `${styleText2("yellow", S_BAR)} ` : "",
|
|
1802
|
+
const n2 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r2 = i2 ? `${styleText2("yellow", S_BAR)} ` : "", d = i2 ? styleText2("yellow", S_BAR_END) : "";
|
|
1779
1803
|
return `${s.trim()}
|
|
1780
1804
|
${r2}${o2}
|
|
1781
|
-
${
|
|
1805
|
+
${d}${n2}
|
|
1782
1806
|
`;
|
|
1783
1807
|
}
|
|
1784
1808
|
case "submit": {
|
|
@@ -1835,8 +1859,6 @@ class AddCommand {
|
|
|
1835
1859
|
const options = changes.map((c3) => ({ value: c3.value, label: c3.label }));
|
|
1836
1860
|
const selectedChanges = await MultiSelect({
|
|
1837
1861
|
message: `Select the changes you want to commit.
|
|
1838
|
-
` + BLUE({ text: "[space] to select" }) + `
|
|
1839
|
-
` + GREEN({ text: "[enter] to confirm" }) + `
|
|
1840
1862
|
` + MAGENTA({ text: "[a] to select all" }) + `
|
|
1841
1863
|
` + RED({ text: "[esc] to cancel" }) + `
|
|
1842
1864
|
`,
|
|
@@ -2036,7 +2058,9 @@ var ALIASES = [
|
|
|
2036
2058
|
{ name: "gstp", command: "stash pop", kind: "git" },
|
|
2037
2059
|
{ name: "gstl", command: "stash list", kind: "git" },
|
|
2038
2060
|
{ name: "gcl", command: "clean -fd", kind: "git" },
|
|
2039
|
-
{ name: "grh", command: "reset --hard", kind: "git" }
|
|
2061
|
+
{ name: "grh", command: "reset --hard", kind: "git" },
|
|
2062
|
+
{ name: "ggrh", command: "reset-hard", kind: "glinter" },
|
|
2063
|
+
{ name: "ggclean", command: "reset --hard && git clean -fd", kind: "git" }
|
|
2040
2064
|
];
|
|
2041
2065
|
|
|
2042
2066
|
// apps/cli/modules/alias/main.ts
|
|
@@ -2108,10 +2132,7 @@ var commitTypeOptions = [
|
|
|
2108
2132
|
];
|
|
2109
2133
|
|
|
2110
2134
|
// apps/cli/utils/input.ts
|
|
2111
|
-
async function Input({
|
|
2112
|
-
message,
|
|
2113
|
-
placeholder
|
|
2114
|
-
}) {
|
|
2135
|
+
async function Input({ message, placeholder }) {
|
|
2115
2136
|
const value = await text({
|
|
2116
2137
|
message,
|
|
2117
2138
|
placeholder,
|
|
@@ -2129,10 +2150,7 @@ async function Input({
|
|
|
2129
2150
|
}
|
|
2130
2151
|
|
|
2131
2152
|
// apps/cli/utils/select.ts
|
|
2132
|
-
async function Select({
|
|
2133
|
-
message,
|
|
2134
|
-
options
|
|
2135
|
-
}) {
|
|
2153
|
+
async function Select({ message, options }) {
|
|
2136
2154
|
const selected = await select({
|
|
2137
2155
|
message,
|
|
2138
2156
|
options
|
|
@@ -2190,6 +2208,123 @@ async function commitCommand() {
|
|
|
2190
2208
|
await commitCmd.execute();
|
|
2191
2209
|
}
|
|
2192
2210
|
|
|
2211
|
+
// apps/cli/modules/reset-hard/app/reset-hard-command.ts
|
|
2212
|
+
var PREV_PAGE = "< Previous page";
|
|
2213
|
+
var NEXT_PAGE = "Next page >";
|
|
2214
|
+
|
|
2215
|
+
class ResetHardCommand {
|
|
2216
|
+
resetHardRepository;
|
|
2217
|
+
constructor(resetHardRepository) {
|
|
2218
|
+
this.resetHardRepository = resetHardRepository;
|
|
2219
|
+
}
|
|
2220
|
+
async execute() {
|
|
2221
|
+
try {
|
|
2222
|
+
let page = 0;
|
|
2223
|
+
const pageSize = 10;
|
|
2224
|
+
while (true) {
|
|
2225
|
+
const { commits, hasMore } = await this.resetHardRepository.getCommits(page, pageSize);
|
|
2226
|
+
if (commits.length === 0) {
|
|
2227
|
+
console.log(`${WARNING({ text: "No commits found." })}`);
|
|
2228
|
+
return;
|
|
2229
|
+
}
|
|
2230
|
+
const options = [];
|
|
2231
|
+
if (page > 0) {
|
|
2232
|
+
options.push({ value: PREV_PAGE, label: PREV_PAGE });
|
|
2233
|
+
}
|
|
2234
|
+
for (const commit of commits) {
|
|
2235
|
+
options.push({
|
|
2236
|
+
value: commit.hash,
|
|
2237
|
+
label: `${YELLOW({ text: commit.shortHash })} ${commit.subject}`
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
if (hasMore) {
|
|
2241
|
+
options.push({ value: NEXT_PAGE, label: NEXT_PAGE });
|
|
2242
|
+
}
|
|
2243
|
+
const selected = await Select({
|
|
2244
|
+
message: "Select the commit you want to reset to.",
|
|
2245
|
+
options
|
|
2246
|
+
});
|
|
2247
|
+
if (selected === PREV_PAGE) {
|
|
2248
|
+
page -= 1;
|
|
2249
|
+
continue;
|
|
2250
|
+
}
|
|
2251
|
+
if (selected === NEXT_PAGE) {
|
|
2252
|
+
page += 1;
|
|
2253
|
+
continue;
|
|
2254
|
+
}
|
|
2255
|
+
await this.resetHardRepository.resetHard(selected);
|
|
2256
|
+
console.log(`${CHECK({ text: "Successfully reset to " + selected })}`);
|
|
2257
|
+
break;
|
|
2258
|
+
}
|
|
2259
|
+
} catch (error) {
|
|
2260
|
+
errorHandler(error);
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
// apps/cli/modules/reset-hard/infra/bun-reset-hard.repository.ts
|
|
2266
|
+
var {$: $2 } = globalThis.Bun;
|
|
2267
|
+
|
|
2268
|
+
// apps/cli/modules/reset-hard/domain/commit.ts
|
|
2269
|
+
class Commit {
|
|
2270
|
+
props;
|
|
2271
|
+
constructor(props) {
|
|
2272
|
+
this.props = props;
|
|
2273
|
+
}
|
|
2274
|
+
get hash() {
|
|
2275
|
+
return this.props.hash;
|
|
2276
|
+
}
|
|
2277
|
+
get shortHash() {
|
|
2278
|
+
return this.props.hash.slice(0, 7);
|
|
2279
|
+
}
|
|
2280
|
+
get subject() {
|
|
2281
|
+
return this.props.subject;
|
|
2282
|
+
}
|
|
2283
|
+
static fromGitLog(output) {
|
|
2284
|
+
if (!output.trim())
|
|
2285
|
+
return [];
|
|
2286
|
+
const lines = output.split(`
|
|
2287
|
+
`).filter((line) => line.trim() !== "");
|
|
2288
|
+
return lines.map((line) => {
|
|
2289
|
+
const hash = line.substring(0, 40);
|
|
2290
|
+
const subject = line.substring(41).trim();
|
|
2291
|
+
return new Commit({ hash, subject });
|
|
2292
|
+
});
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
// apps/cli/modules/reset-hard/infra/bun-reset-hard.repository.ts
|
|
2297
|
+
class BunResetHardRepository {
|
|
2298
|
+
async getCommits(page, pageSize) {
|
|
2299
|
+
try {
|
|
2300
|
+
const skip = page * pageSize;
|
|
2301
|
+
const output = await $2`git --no-pager log -n ${pageSize + 1} --skip=${skip} --format="%H %s"`.quiet().text();
|
|
2302
|
+
const allCommits = Commit.fromGitLog(output);
|
|
2303
|
+
const hasMore = allCommits.length > pageSize;
|
|
2304
|
+
const commits = hasMore ? allCommits.slice(0, pageSize) : allCommits;
|
|
2305
|
+
return { commits, hasMore };
|
|
2306
|
+
} catch {
|
|
2307
|
+
throw new ServerError("Git log failed", "Could not retrieve commits");
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
async resetHard(hash) {
|
|
2311
|
+
const proc = Bun.spawn(["git", "reset", "--hard", hash], {
|
|
2312
|
+
stdio: ["inherit", "inherit", "inherit"]
|
|
2313
|
+
});
|
|
2314
|
+
const exitCode = await proc.exited;
|
|
2315
|
+
if (exitCode !== 0) {
|
|
2316
|
+
throw new ServerError("Git reset failed", `Failed to reset to commit ${hash}`);
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
// apps/cli/modules/reset-hard/main.ts
|
|
2322
|
+
async function resetHardCommand() {
|
|
2323
|
+
const resetHardRepository = new BunResetHardRepository;
|
|
2324
|
+
const resetHardCmd = new ResetHardCommand(resetHardRepository);
|
|
2325
|
+
await resetHardCmd.execute();
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2193
2328
|
// apps/cli/modules/setup/app/setup-aliases.use-case.ts
|
|
2194
2329
|
class SetupAliasesUseCase {
|
|
2195
2330
|
aliasRepository;
|
|
@@ -2210,11 +2345,7 @@ class SetupAliasesUseCase {
|
|
|
2210
2345
|
}
|
|
2211
2346
|
|
|
2212
2347
|
// apps/cli/utils/confirm.ts
|
|
2213
|
-
async function Confirm({
|
|
2214
|
-
message,
|
|
2215
|
-
cancelMessage,
|
|
2216
|
-
exitOnCancel = true
|
|
2217
|
-
}) {
|
|
2348
|
+
async function Confirm({ message, cancelMessage, exitOnCancel = true }) {
|
|
2218
2349
|
const confirmed = await confirm({
|
|
2219
2350
|
message
|
|
2220
2351
|
});
|
|
@@ -2360,12 +2491,7 @@ ${functionLine}
|
|
|
2360
2491
|
return path2.join(this.getWindowsDocumentsPath(), "PowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
2361
2492
|
}
|
|
2362
2493
|
getWindowsDocumentsPath() {
|
|
2363
|
-
const proc = Bun.spawnSync([
|
|
2364
|
-
"powershell",
|
|
2365
|
-
"-NoProfile",
|
|
2366
|
-
"-Command",
|
|
2367
|
-
"[Environment]::GetFolderPath('MyDocuments')"
|
|
2368
|
-
], {
|
|
2494
|
+
const proc = Bun.spawnSync(["powershell", "-NoProfile", "-Command", "[Environment]::GetFolderPath('MyDocuments')"], {
|
|
2369
2495
|
stdout: "pipe",
|
|
2370
2496
|
stderr: "pipe"
|
|
2371
2497
|
});
|
|
@@ -2516,11 +2642,11 @@ class SwitchCommand {
|
|
|
2516
2642
|
}
|
|
2517
2643
|
|
|
2518
2644
|
// apps/cli/modules/switch/infra/bun-switch-repository.ts
|
|
2519
|
-
var {$: $
|
|
2645
|
+
var {$: $3 } = globalThis.Bun;
|
|
2520
2646
|
class BunSwitchRepository {
|
|
2521
2647
|
async getBranches() {
|
|
2522
2648
|
try {
|
|
2523
|
-
const output = await $
|
|
2649
|
+
const output = await $3`git branch -a`.quiet().text();
|
|
2524
2650
|
if (!output.trim()) {
|
|
2525
2651
|
return [];
|
|
2526
2652
|
}
|
|
@@ -2556,7 +2682,8 @@ var COMMANDS_FN = {
|
|
|
2556
2682
|
commit: commitCommand,
|
|
2557
2683
|
switch: switchCommand,
|
|
2558
2684
|
alias: aliasCommand,
|
|
2559
|
-
setup: setupCommand
|
|
2685
|
+
setup: setupCommand,
|
|
2686
|
+
"reset-hard": resetHardCommand
|
|
2560
2687
|
};
|
|
2561
2688
|
|
|
2562
2689
|
// apps/cli/index.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jannael/glinter",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "A high-performance, transparent Git wrapper with interactive staging",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -36,12 +36,12 @@
|
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "bun build ./apps/cli/index.ts --outfile=./dist/index.js --target=bun",
|
|
38
38
|
"prepublishOnly": "bun run build",
|
|
39
|
-
"test": "
|
|
40
|
-
"lint": "oxlint",
|
|
41
|
-
"lint:fix": "oxlint --fix",
|
|
42
|
-
"format": "prettier --write .",
|
|
43
|
-
"format:check": "prettier --check .",
|
|
39
|
+
"test": "bun test",
|
|
44
40
|
"type-check": "bunx tsc --noEmit",
|
|
41
|
+
"lint": "eslint .",
|
|
42
|
+
"lint:fix": "eslint --fix .",
|
|
43
|
+
"fmt": "prettier --write .",
|
|
44
|
+
"fmt:check": "prettier --check .",
|
|
45
45
|
"prepare": "husky"
|
|
46
46
|
},
|
|
47
47
|
"bin": {
|
|
@@ -51,27 +51,23 @@
|
|
|
51
51
|
"bun": ">=1.0.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
+
"@eslint/js": "10.0.1",
|
|
54
55
|
"@types/bun": "1.3.14",
|
|
56
|
+
"eslint": "10.5.0",
|
|
57
|
+
"eslint-plugin-astro": "2.0.0",
|
|
55
58
|
"husky": "9.1.7",
|
|
56
|
-
"
|
|
57
|
-
"prettier": "3.8.
|
|
59
|
+
"lint-staged": "17.0.8",
|
|
60
|
+
"prettier": "3.8.4",
|
|
58
61
|
"prettier-plugin-astro": "0.14.1",
|
|
59
62
|
"prettier-plugin-tailwindcss": "0.8.0",
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"wrangler": "4.98.0"
|
|
63
|
+
"typescript-eslint": "8.62.0",
|
|
64
|
+
"wrangler": "4.104.0"
|
|
63
65
|
},
|
|
64
66
|
"peerDependencies": {
|
|
65
67
|
"bun": "1.3.14",
|
|
66
68
|
"typescript": "6.0.3"
|
|
67
69
|
},
|
|
68
70
|
"dependencies": {
|
|
69
|
-
"@clack/prompts": "1.
|
|
70
|
-
},
|
|
71
|
-
"lint-staged": {
|
|
72
|
-
"*.{ts,tsx,js,jsx,astro}": [
|
|
73
|
-
"bun run lint:fix",
|
|
74
|
-
"bun run format"
|
|
75
|
-
]
|
|
71
|
+
"@clack/prompts": "1.6.0"
|
|
76
72
|
}
|
|
77
73
|
}
|