@jannael/glinter 1.1.1 → 1.2.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 +93 -8
- package/dist/index.js +628 -50
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -1,23 +1,106 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
+
<br>
|
|
10
|
+
<br>
|
|
11
|
+
<br>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
Glinter is a high-performance, transparent Git wrapper built with **Bun**.
|
|
4
15
|
|
|
5
16
|
## Preview
|
|
6
17
|
|
|
7
|
-
<video src="https://github.com/user-attachments/assets/
|
|
18
|
+
<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%;">
|
|
8
19
|
Your browser does not support the video tag.
|
|
9
20
|
</video>
|
|
10
21
|
|
|
11
|
-
|
|
12
22
|
## Features
|
|
13
23
|
|
|
14
|
-
- **
|
|
24
|
+
- **Abbreviation**: You can use `g` instead of `git`.
|
|
25
|
+
|
|
26
|
+
- **Safe by Default**: Automatically filters and prevents accidental staging of sensitive files: `.env` and `node_modules`.
|
|
15
27
|
|
|
16
28
|
- **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.
|
|
17
29
|
|
|
18
|
-
- **Safe by Default**: Automatically filters and prevents accidental staging of sensitive files: `.env` and `node_modules`.
|
|
19
30
|
|
|
20
|
-
|
|
31
|
+
### Commands
|
|
32
|
+
|
|
33
|
+
| Command | Description |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `g add` | Opens an interactive file selector to stage changes, filtering out sensitive files like `.env` and `node_modules` |
|
|
36
|
+
| `g commit` | Opens an interactive prompt to select a commit type and write a commit message |
|
|
37
|
+
| `g switch` | Opens an interactive prompt to switch branches |
|
|
38
|
+
| `g setup` | sets up alias for git and glinter |
|
|
39
|
+
| `g alias` | shows all the aliases |
|
|
40
|
+
|
|
41
|
+
### Aliases
|
|
42
|
+
|
|
43
|
+
| Alias | Command | Description |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| gs | git status -sb | Status with short format and branch info |
|
|
46
|
+
| gl | git log --oneline --decorate --graph --all -n 20 | Recent commits graph |
|
|
47
|
+
| gll | git log --stat | Log with file change statistics |
|
|
48
|
+
| gd | git diff --word-diff=color | Word-level diff with colors |
|
|
49
|
+
| gds | git diff --staged --word-diff=color | Staged diff with colors |
|
|
50
|
+
| ga | glinter add | Interactive staging |
|
|
51
|
+
| gaa | git add -A | Add all changes |
|
|
52
|
+
| gc | glinter commit | Interactive commit |
|
|
53
|
+
| gcm | git commit -m | Direct commit message |
|
|
54
|
+
| gca | git commit --amend | Amend last commit |
|
|
55
|
+
| gcan | git commit --amend --no-edit | Amend without editing |
|
|
56
|
+
| gb | git branch | List branches |
|
|
57
|
+
| gba | git branch -a | List all branches |
|
|
58
|
+
| gco | glinter switch | Interactive branch switch |
|
|
59
|
+
| gcb | git checkout -b | Create and switch branch |
|
|
60
|
+
| gpl | git pull | Pull from remote |
|
|
61
|
+
| gplr | git pull --rebase | Pull with rebase |
|
|
62
|
+
| gp | git push | Push to remote |
|
|
63
|
+
| ggpush | git push origin HEAD | Push current branch |
|
|
64
|
+
| gpf | git push --force-with-lease | Force push with lease |
|
|
65
|
+
| gst | git stash | Stash changes |
|
|
66
|
+
| gstp | git stash pop | Pop stash |
|
|
67
|
+
| gstl | git stash list | List stashes |
|
|
68
|
+
| gcl | git clean -fd | Clean untracked files |
|
|
69
|
+
| grh | git reset --hard | Hard reset |
|
|
70
|
+
|
|
71
|
+
## Quick Start
|
|
72
|
+
|
|
73
|
+
1. **Install Glinter**:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm install -g @jannael/glinter
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
2. **Set up aliases** (optional, recommended):
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
g setup
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
3. **Start using Glinter**:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
g add # Interactive file staging
|
|
89
|
+
g commit # Interactive commit
|
|
90
|
+
g status # Standard git status
|
|
91
|
+
g push # Standard git push
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
### Screenshots
|
|
98
|
+
|
|
99
|
+
| `g add` | `g commit` |
|
|
100
|
+
|---|---|
|
|
101
|
+
|  |  |
|
|
102
|
+
|
|
103
|
+
|
|
21
104
|
|
|
22
105
|
## How it works
|
|
23
106
|
|
|
@@ -52,7 +135,9 @@ npm install -g @jannael/glinter
|
|
|
52
135
|
now you can simply run:
|
|
53
136
|
```bash
|
|
54
137
|
g add # Opens the interactive selector
|
|
138
|
+
g commit # Opens commit type + message prompt
|
|
55
139
|
g add <file> # Runs standard git add <file>
|
|
140
|
+
g commit -m "" # Runs standard git commit -m ""
|
|
56
141
|
g status # Runs standard git status
|
|
57
142
|
g push # Runs standard git push
|
|
58
143
|
```
|
package/dist/index.js
CHANGED
|
@@ -90,22 +90,7 @@ var require_src = __commonJS((exports, module) => {
|
|
|
90
90
|
module.exports = { cursor, scroll, erase, beep };
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
//
|
|
94
|
-
var RESET = "\x1B[0m";
|
|
95
|
-
var GREEN = ({ text }) => `\x1B[32m${text}${RESET}`;
|
|
96
|
-
var YELLOW = ({ text }) => `\x1B[33m${text}${RESET}`;
|
|
97
|
-
var RED = ({ text }) => `\x1B[31m${text}${RESET}`;
|
|
98
|
-
var MAGENTA = ({ text }) => `\x1B[35m${text}${RESET}`;
|
|
99
|
-
var BLUE = ({ text }) => `\x1B[34m${text}${RESET}`;
|
|
100
|
-
var BLACK = ({ text }) => `\x1B[30m${text}${RESET}`;
|
|
101
|
-
var BG_YELLOW = ({ text }) => `\x1B[43m${text}${RESET}`;
|
|
102
|
-
|
|
103
|
-
// src/utils/icons-terminal.ts
|
|
104
|
-
var X = ({ text }) => RED({ text: `\u2716 ${text}` });
|
|
105
|
-
var CHECK = ({ text }) => `${GREEN({ text: "\u2714" })} ${text}`;
|
|
106
|
-
var WARNING = ({ text }) => BG_YELLOW({ text: BLACK({ text: ` \u26A0 ${text}` }) });
|
|
107
|
-
|
|
108
|
-
// src/error/error-constructor.ts
|
|
93
|
+
// apps/cli/error/error-constructor.ts
|
|
109
94
|
function CreateError(name) {
|
|
110
95
|
const capitalize = (text) => text.charAt(0).toUpperCase() + text.slice(1);
|
|
111
96
|
return class extends Error {
|
|
@@ -118,14 +103,29 @@ function CreateError(name) {
|
|
|
118
103
|
};
|
|
119
104
|
}
|
|
120
105
|
|
|
121
|
-
//
|
|
106
|
+
// apps/cli/error/error-instance.ts
|
|
122
107
|
var NotFound = CreateError("NotFound");
|
|
123
108
|
var Forbidden = CreateError("Forbidden");
|
|
124
109
|
var Conflict = CreateError("Conflict");
|
|
125
110
|
var ServerError = CreateError("ServerError");
|
|
126
111
|
var BadRequest = CreateError("BadRequest");
|
|
127
112
|
|
|
128
|
-
//
|
|
113
|
+
// apps/cli/utils/colors.ts
|
|
114
|
+
var RESET = "\x1B[0m";
|
|
115
|
+
var GREEN = ({ text }) => `\x1B[32m${text}${RESET}`;
|
|
116
|
+
var YELLOW = ({ text }) => `\x1B[33m${text}${RESET}`;
|
|
117
|
+
var RED = ({ text }) => `\x1B[31m${text}${RESET}`;
|
|
118
|
+
var MAGENTA = ({ text }) => `\x1B[35m${text}${RESET}`;
|
|
119
|
+
var BLUE = ({ text }) => `\x1B[34m${text}${RESET}`;
|
|
120
|
+
var BLACK = ({ text }) => `\x1B[30m${text}${RESET}`;
|
|
121
|
+
var BG_YELLOW = ({ text }) => `\x1B[43m${text}${RESET}`;
|
|
122
|
+
|
|
123
|
+
// apps/cli/utils/icons-terminal.ts
|
|
124
|
+
var X = ({ text }) => RED({ text: `\u2716 ${text}` });
|
|
125
|
+
var CHECK = ({ text }) => `${GREEN({ text: "\u2714" })} ${text}`;
|
|
126
|
+
var WARNING = ({ text }) => BG_YELLOW({ text: BLACK({ text: ` \u26A0 ${text}` }) });
|
|
127
|
+
|
|
128
|
+
// apps/cli/error/error-handler.ts
|
|
129
129
|
function errorHandler(error) {
|
|
130
130
|
if (error instanceof ServerError) {
|
|
131
131
|
console.error(X({ text: error.message }));
|
|
@@ -147,6 +147,7 @@ function errorHandler(error) {
|
|
|
147
147
|
// node_modules/@clack/core/dist/index.mjs
|
|
148
148
|
import { styleText as y } from "util";
|
|
149
149
|
import { stdout as S, stdin as $ } from "process";
|
|
150
|
+
import * as _ from "readline";
|
|
150
151
|
import P from "readline";
|
|
151
152
|
|
|
152
153
|
// node_modules/fast-string-truncated-width/dist/utils.js
|
|
@@ -535,6 +536,7 @@ function wrapAnsi(string, columns, options) {
|
|
|
535
536
|
|
|
536
537
|
// node_modules/@clack/core/dist/index.mjs
|
|
537
538
|
var import_sisteransi = __toESM(require_src(), 1);
|
|
539
|
+
import { ReadStream as D } from "tty";
|
|
538
540
|
function d(r, t, e) {
|
|
539
541
|
if (!e.some((o) => !o.disabled))
|
|
540
542
|
return r;
|
|
@@ -571,6 +573,28 @@ function w(r, t) {
|
|
|
571
573
|
const e = r;
|
|
572
574
|
e.isTTY && e.setRawMode(t);
|
|
573
575
|
}
|
|
576
|
+
function z({ input: r = $, output: t = S, overwrite: e = true, hideCursor: s = true } = {}) {
|
|
577
|
+
const i = _.createInterface({ input: r, output: t, prompt: "", tabSize: 1 });
|
|
578
|
+
_.emitKeypressEvents(r, i), r instanceof D && r.isTTY && r.setRawMode(true);
|
|
579
|
+
const n = (o, { name: a, sequence: h }) => {
|
|
580
|
+
const l = String(o);
|
|
581
|
+
if (V([l, a, h], "cancel")) {
|
|
582
|
+
s && t.write(import_sisteransi.cursor.show), process.exit(0);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
if (!e)
|
|
586
|
+
return;
|
|
587
|
+
const f = a === "return" ? 0 : -1, v = a === "return" ? -1 : 0;
|
|
588
|
+
_.moveCursor(t, f, v, () => {
|
|
589
|
+
_.clearLine(t, 1, () => {
|
|
590
|
+
r.once("keypress", n);
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
};
|
|
594
|
+
return s && t.write(import_sisteransi.cursor.hide), r.once("keypress", n), () => {
|
|
595
|
+
r.off("keypress", n), s && t.write(import_sisteransi.cursor.show), r instanceof D && r.isTTY && !Y && r.setRawMode(false), i.terminal = false, i.close();
|
|
596
|
+
};
|
|
597
|
+
}
|
|
574
598
|
var O = (r) => ("columns" in r) && typeof r.columns == "number" ? r.columns : 80;
|
|
575
599
|
var A = (r) => ("rows" in r) && typeof r.rows == "number" ? r.rows : 20;
|
|
576
600
|
function R(r, t, e, s = e) {
|
|
@@ -785,6 +809,24 @@ var H = class extends p {
|
|
|
785
809
|
}
|
|
786
810
|
}
|
|
787
811
|
};
|
|
812
|
+
|
|
813
|
+
class Q extends p {
|
|
814
|
+
get cursor() {
|
|
815
|
+
return this.value ? 0 : 1;
|
|
816
|
+
}
|
|
817
|
+
get _value() {
|
|
818
|
+
return this.cursor === 0;
|
|
819
|
+
}
|
|
820
|
+
constructor(t) {
|
|
821
|
+
super(t, false), this.value = !!t.initialValue, this.on("userInput", () => {
|
|
822
|
+
this.value = this._value;
|
|
823
|
+
}), this.on("confirm", (e) => {
|
|
824
|
+
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = e, this.state = "submit", this.close();
|
|
825
|
+
}), this.on("cursor", () => {
|
|
826
|
+
this.value = !this.value;
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
}
|
|
788
830
|
var X2 = { Y: { type: "year", len: 4 }, M: { type: "month", len: 2 }, D: { type: "day", len: 2 } };
|
|
789
831
|
function L(r) {
|
|
790
832
|
return [...r].map((t) => X2[t]);
|
|
@@ -1089,6 +1131,27 @@ class nt extends p {
|
|
|
1089
1131
|
});
|
|
1090
1132
|
}
|
|
1091
1133
|
}
|
|
1134
|
+
class at extends p {
|
|
1135
|
+
get userInputWithCursor() {
|
|
1136
|
+
if (this.state === "submit")
|
|
1137
|
+
return this.userInput;
|
|
1138
|
+
const t = this.userInput;
|
|
1139
|
+
if (this.cursor >= t.length)
|
|
1140
|
+
return `${this.userInput}\u2588`;
|
|
1141
|
+
const e = t.slice(0, this.cursor), [s, ...i] = t.slice(this.cursor);
|
|
1142
|
+
return `${e}${y("inverse", s)}${i.join("")}`;
|
|
1143
|
+
}
|
|
1144
|
+
get cursor() {
|
|
1145
|
+
return this._cursor;
|
|
1146
|
+
}
|
|
1147
|
+
constructor(t) {
|
|
1148
|
+
super({ ...t, initialUserInput: t.initialUserInput ?? t.initialValue }), this.on("userInput", (e) => {
|
|
1149
|
+
this._setValue(e);
|
|
1150
|
+
}), this.on("finalize", () => {
|
|
1151
|
+
this.value || (this.value = t.defaultValue), this.value === undefined && (this.value = "");
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1092
1155
|
|
|
1093
1156
|
// node_modules/@clack/prompts/dist/index.mjs
|
|
1094
1157
|
import { styleText as t, stripVTControlCharacters as ne } from "util";
|
|
@@ -1098,6 +1161,7 @@ function Ze() {
|
|
|
1098
1161
|
return P2.platform !== "win32" ? P2.env.TERM !== "linux" : !!P2.env.CI || !!P2.env.WT_SESSION || !!P2.env.TERMINUS_SUBLIME || P2.env.ConEmuTask === "{cmd::Cmder}" || P2.env.TERM_PROGRAM === "Terminus-Sublime" || P2.env.TERM_PROGRAM === "vscode" || P2.env.TERM === "xterm-256color" || P2.env.TERM === "alacritty" || P2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
1099
1162
|
}
|
|
1100
1163
|
var ee = Ze();
|
|
1164
|
+
var ae = () => process.env.CI === "true";
|
|
1101
1165
|
var w2 = (e, i) => ee ? e : i;
|
|
1102
1166
|
var _e = w2("\u25C6", "*");
|
|
1103
1167
|
var oe = w2("\u25A0", "x");
|
|
@@ -1175,7 +1239,7 @@ var Y2 = ({ cursor: e, options: i, style: s, output: r = process.stdout, maxItem
|
|
|
1175
1239
|
}
|
|
1176
1240
|
if (f > $2) {
|
|
1177
1241
|
let b = 0, x = 0, G2 = f;
|
|
1178
|
-
const M2 = e - v, R2 = (j2,
|
|
1242
|
+
const M2 = e - v, R2 = (j2, D2) => et2(h, G2, j2, D2, $2);
|
|
1179
1243
|
m ? ({ lineCount: G2, removals: b } = R2(0, M2), G2 > $2 && ({ lineCount: G2, removals: x } = R2(M2 + 1, h.length))) : ({ lineCount: G2, removals: x } = R2(M2 + 1, h.length), G2 > $2 && ({ lineCount: G2, removals: b } = R2(0, M2))), b > 0 && (m = true, h.splice(0, b)), x > 0 && (g = true, h.splice(h.length - x, x));
|
|
1180
1244
|
}
|
|
1181
1245
|
const C2 = [];
|
|
@@ -1185,10 +1249,49 @@ var Y2 = ({ cursor: e, options: i, style: s, output: r = process.stdout, maxItem
|
|
|
1185
1249
|
C2.push(x);
|
|
1186
1250
|
return g && C2.push(l), C2;
|
|
1187
1251
|
};
|
|
1252
|
+
var ot2 = (e) => {
|
|
1253
|
+
const i = e.active ?? "Yes", s = e.inactive ?? "No";
|
|
1254
|
+
return new Q({ active: i, inactive: s, signal: e.signal, input: e.input, output: e.output, initialValue: e.initialValue ?? true, render() {
|
|
1255
|
+
const r = e.withGuide ?? u.withGuide, u2 = `${V2(this.state)} `, n = r ? `${t("gray", d2)} ` : "", o = R(e.output, e.message, n, u2), c2 = `${r ? `${t("gray", d2)}
|
|
1256
|
+
` : ""}${o}
|
|
1257
|
+
`, a = this.value ? i : s;
|
|
1258
|
+
switch (this.state) {
|
|
1259
|
+
case "submit": {
|
|
1260
|
+
const l = r ? `${t("gray", d2)} ` : "";
|
|
1261
|
+
return `${c2}${l}${t("dim", a)}`;
|
|
1262
|
+
}
|
|
1263
|
+
case "cancel": {
|
|
1264
|
+
const l = r ? `${t("gray", d2)} ` : "";
|
|
1265
|
+
return `${c2}${l}${t(["strikethrough", "dim"], a)}${r ? `
|
|
1266
|
+
${t("gray", d2)}` : ""}`;
|
|
1267
|
+
}
|
|
1268
|
+
default: {
|
|
1269
|
+
const l = r ? `${t("cyan", d2)} ` : "", $2 = r ? t("cyan", E2) : "";
|
|
1270
|
+
return `${c2}${l}${this.value ? `${t("green", z2)} ${i}` : `${t("dim", H2)} ${t("dim", i)}`}${e.vertical ? r ? `
|
|
1271
|
+
${t("cyan", d2)} ` : `
|
|
1272
|
+
` : ` ${t("dim", "/")} `}${this.value ? `${t("dim", H2)} ${t("dim", s)}` : `${t("green", z2)} ${s}`}
|
|
1273
|
+
${$2}
|
|
1274
|
+
`;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
} }).prompt();
|
|
1278
|
+
};
|
|
1188
1279
|
var pt = (e = "", i) => {
|
|
1189
1280
|
const s = i?.output ?? process.stdout, r = i?.withGuide ?? u.withGuide ? `${t("gray", E2)} ` : "";
|
|
1190
1281
|
s.write(`${r}${t("red", e)}
|
|
1191
1282
|
|
|
1283
|
+
`);
|
|
1284
|
+
};
|
|
1285
|
+
var mt = (e = "", i) => {
|
|
1286
|
+
const s = i?.output ?? process.stdout, r = i?.withGuide ?? u.withGuide ? `${t("gray", le)} ` : "";
|
|
1287
|
+
s.write(`${r}${e}
|
|
1288
|
+
`);
|
|
1289
|
+
};
|
|
1290
|
+
var gt = (e = "", i) => {
|
|
1291
|
+
const s = i?.output ?? process.stdout, r = i?.withGuide ?? u.withGuide ? `${t("gray", d2)}
|
|
1292
|
+
${t("gray", E2)} ` : "";
|
|
1293
|
+
s.write(`${r}${e}
|
|
1294
|
+
|
|
1192
1295
|
`);
|
|
1193
1296
|
};
|
|
1194
1297
|
var Q2 = (e, i) => e.split(`
|
|
@@ -1247,6 +1350,64 @@ ${r ? t("cyan", E2) : ""}
|
|
|
1247
1350
|
}
|
|
1248
1351
|
} }).prompt();
|
|
1249
1352
|
};
|
|
1353
|
+
var Ct = (e) => t("magenta", e);
|
|
1354
|
+
var fe = ({ indicator: e = "dots", onCancel: i, output: s = process.stdout, cancelMessage: r, errorMessage: u2, frames: n = ee ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], delay: o = ee ? 80 : 120, signal: c2, ...a } = {}) => {
|
|
1355
|
+
const l = ae();
|
|
1356
|
+
let $2, y2, p2 = false, m = false, g = "", S2, h = performance.now();
|
|
1357
|
+
const f = O(s), v = a?.styleFrame ?? Ct, T2 = (_2) => {
|
|
1358
|
+
const A2 = _2 > 1 ? u2 ?? u.messages.error : r ?? u.messages.cancel;
|
|
1359
|
+
m = _2 === 1, p2 && (W2(A2, _2), m && typeof i == "function" && i());
|
|
1360
|
+
}, C2 = () => T2(2), b = () => T2(1), x = () => {
|
|
1361
|
+
process.on("uncaughtExceptionMonitor", C2), process.on("unhandledRejection", C2), process.on("SIGINT", b), process.on("SIGTERM", b), process.on("exit", T2), c2 && c2.addEventListener("abort", b);
|
|
1362
|
+
}, G2 = () => {
|
|
1363
|
+
process.removeListener("uncaughtExceptionMonitor", C2), process.removeListener("unhandledRejection", C2), process.removeListener("SIGINT", b), process.removeListener("SIGTERM", b), process.removeListener("exit", T2), c2 && c2.removeEventListener("abort", b);
|
|
1364
|
+
}, M2 = () => {
|
|
1365
|
+
if (S2 === undefined)
|
|
1366
|
+
return;
|
|
1367
|
+
l && s.write(`
|
|
1368
|
+
`);
|
|
1369
|
+
const _2 = wrapAnsi(S2, f, { hard: true, trim: false }).split(`
|
|
1370
|
+
`);
|
|
1371
|
+
_2.length > 1 && s.write(import_sisteransi2.cursor.up(_2.length - 1)), s.write(import_sisteransi2.cursor.to(0)), s.write(import_sisteransi2.erase.down());
|
|
1372
|
+
}, R2 = (_2) => _2.replace(/\.+$/, ""), j2 = (_2) => {
|
|
1373
|
+
const A2 = (performance.now() - _2) / 1000, k2 = Math.floor(A2 / 60), L2 = Math.floor(A2 % 60);
|
|
1374
|
+
return k2 > 0 ? `[${k2}m ${L2}s]` : `[${L2}s]`;
|
|
1375
|
+
}, D2 = a.withGuide ?? u.withGuide, ie = (_2 = "") => {
|
|
1376
|
+
p2 = true, $2 = z({ output: s }), g = R2(_2), h = performance.now(), D2 && s.write(`${t("gray", d2)}
|
|
1377
|
+
`);
|
|
1378
|
+
let A2 = 0, k2 = 0;
|
|
1379
|
+
x(), y2 = setInterval(() => {
|
|
1380
|
+
if (l && g === S2)
|
|
1381
|
+
return;
|
|
1382
|
+
M2(), S2 = g;
|
|
1383
|
+
const L2 = v(n[A2]);
|
|
1384
|
+
let Z2;
|
|
1385
|
+
if (l)
|
|
1386
|
+
Z2 = `${L2} ${g}...`;
|
|
1387
|
+
else if (e === "timer")
|
|
1388
|
+
Z2 = `${L2} ${g} ${j2(h)}`;
|
|
1389
|
+
else {
|
|
1390
|
+
const Be = ".".repeat(Math.floor(k2)).slice(0, 3);
|
|
1391
|
+
Z2 = `${L2} ${g}${Be}`;
|
|
1392
|
+
}
|
|
1393
|
+
const Ne = wrapAnsi(Z2, f, { hard: true, trim: false });
|
|
1394
|
+
s.write(Ne), A2 = A2 + 1 < n.length ? A2 + 1 : 0, k2 = k2 < 4 ? k2 + 0.125 : 0;
|
|
1395
|
+
}, o);
|
|
1396
|
+
}, W2 = (_2 = "", A2 = 0, k2 = false) => {
|
|
1397
|
+
if (!p2)
|
|
1398
|
+
return;
|
|
1399
|
+
p2 = false, clearInterval(y2), M2();
|
|
1400
|
+
const L2 = A2 === 0 ? t("green", F2) : A2 === 1 ? t("red", oe) : t("red", ue);
|
|
1401
|
+
g = _2 ?? g, k2 || (e === "timer" ? s.write(`${L2} ${g} ${j2(h)}
|
|
1402
|
+
`) : s.write(`${L2} ${g}
|
|
1403
|
+
`)), G2(), $2();
|
|
1404
|
+
};
|
|
1405
|
+
return { start: ie, stop: (_2 = "") => W2(_2, 0), message: (_2 = "") => {
|
|
1406
|
+
g = R2(_2 ?? g);
|
|
1407
|
+
}, cancel: (_2 = "") => W2(_2, 1), error: (_2 = "") => W2(_2, 2), clear: () => W2("", 0, true), get isCancelled() {
|
|
1408
|
+
return m;
|
|
1409
|
+
} };
|
|
1410
|
+
};
|
|
1250
1411
|
var Ve = { light: w2("\u2500", "-"), heavy: w2("\u2501", "="), block: w2("\u2588", "#") };
|
|
1251
1412
|
var re = (e, i) => e.includes(`
|
|
1252
1413
|
`) ? e.split(`
|
|
@@ -1294,8 +1455,37 @@ ${a}
|
|
|
1294
1455
|
} }).prompt();
|
|
1295
1456
|
};
|
|
1296
1457
|
var je = `${t("gray", d2)} `;
|
|
1458
|
+
var Ot = (e) => new at({ validate: e.validate, placeholder: e.placeholder, defaultValue: e.defaultValue, initialValue: e.initialValue, output: e.output, signal: e.signal, input: e.input, render() {
|
|
1459
|
+
const i = e?.withGuide ?? u.withGuide, s = `${`${i ? `${t("gray", d2)}
|
|
1460
|
+
` : ""}${V2(this.state)} `}${e.message}
|
|
1461
|
+
`, r = e.placeholder ? t("inverse", e.placeholder[0]) + t("dim", e.placeholder.slice(1)) : t(["inverse", "hidden"], "_"), u2 = this.userInput ? this.userInputWithCursor : r, n = this.value ?? "";
|
|
1462
|
+
switch (this.state) {
|
|
1463
|
+
case "error": {
|
|
1464
|
+
const o = this.error ? ` ${t("yellow", this.error)}` : "", c2 = i ? `${t("yellow", d2)} ` : "", a = i ? t("yellow", E2) : "";
|
|
1465
|
+
return `${s.trim()}
|
|
1466
|
+
${c2}${u2}
|
|
1467
|
+
${a}${o}
|
|
1468
|
+
`;
|
|
1469
|
+
}
|
|
1470
|
+
case "submit": {
|
|
1471
|
+
const o = n ? ` ${t("dim", n)}` : "", c2 = i ? t("gray", d2) : "";
|
|
1472
|
+
return `${s}${c2}${o}`;
|
|
1473
|
+
}
|
|
1474
|
+
case "cancel": {
|
|
1475
|
+
const o = n ? ` ${t(["strikethrough", "dim"], n)}` : "", c2 = i ? t("gray", d2) : "";
|
|
1476
|
+
return `${s}${c2}${o}${n.trim() ? `
|
|
1477
|
+
${c2}` : ""}`;
|
|
1478
|
+
}
|
|
1479
|
+
default: {
|
|
1480
|
+
const o = i ? `${t("cyan", d2)} ` : "", c2 = i ? t("cyan", E2) : "";
|
|
1481
|
+
return `${s}${o}${u2}
|
|
1482
|
+
${c2}
|
|
1483
|
+
`;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
} }).prompt();
|
|
1297
1487
|
|
|
1298
|
-
//
|
|
1488
|
+
// apps/cli/utils/multiselect.ts
|
|
1299
1489
|
async function MultiSelect({
|
|
1300
1490
|
message,
|
|
1301
1491
|
options
|
|
@@ -1312,7 +1502,7 @@ async function MultiSelect({
|
|
|
1312
1502
|
return selected;
|
|
1313
1503
|
}
|
|
1314
1504
|
|
|
1315
|
-
//
|
|
1505
|
+
// apps/cli/modules/add/app/add-command.ts
|
|
1316
1506
|
class AddCommand {
|
|
1317
1507
|
getChangesUseCase;
|
|
1318
1508
|
stageChangesUseCase;
|
|
@@ -1332,7 +1522,7 @@ class AddCommand {
|
|
|
1332
1522
|
];
|
|
1333
1523
|
const selectedChanges = await MultiSelect({
|
|
1334
1524
|
message: `Select the changes you want to commit.
|
|
1335
|
-
` + BLUE({ text: "[space] to select
|
|
1525
|
+
` + BLUE({ text: "[space] to select" }) + `
|
|
1336
1526
|
` + GREEN({ text: "[enter] to confirm" }) + `
|
|
1337
1527
|
` + MAGENTA({ text: "[a] to select all" }) + `
|
|
1338
1528
|
` + RED({ text: "[esc] to cancel" }) + `
|
|
@@ -1360,7 +1550,7 @@ ${WARNING({ text: " WARNING " })}`);
|
|
|
1360
1550
|
}
|
|
1361
1551
|
}
|
|
1362
1552
|
|
|
1363
|
-
//
|
|
1553
|
+
// apps/cli/modules/add/domain/change.ts
|
|
1364
1554
|
class Change {
|
|
1365
1555
|
props;
|
|
1366
1556
|
constructor(props) {
|
|
@@ -1427,7 +1617,7 @@ class Change {
|
|
|
1427
1617
|
}
|
|
1428
1618
|
}
|
|
1429
1619
|
|
|
1430
|
-
//
|
|
1620
|
+
// apps/cli/modules/add/app/get-changes.use-case.ts
|
|
1431
1621
|
class GetChangesUseCase {
|
|
1432
1622
|
gitRepository;
|
|
1433
1623
|
constructor(gitRepository) {
|
|
@@ -1454,7 +1644,7 @@ class GetChangesUseCase {
|
|
|
1454
1644
|
}
|
|
1455
1645
|
}
|
|
1456
1646
|
|
|
1457
|
-
//
|
|
1647
|
+
// apps/cli/modules/add/app/stage-changes.use-case.ts
|
|
1458
1648
|
class StageChangesUseCase {
|
|
1459
1649
|
gitRepository;
|
|
1460
1650
|
constructor(gitRepository) {
|
|
@@ -1467,7 +1657,7 @@ class StageChangesUseCase {
|
|
|
1467
1657
|
}
|
|
1468
1658
|
}
|
|
1469
1659
|
|
|
1470
|
-
//
|
|
1660
|
+
// apps/cli/modules/add/infra/bun-git.repository.ts
|
|
1471
1661
|
var {$: $2 } = globalThis.Bun;
|
|
1472
1662
|
class BunGitRepository {
|
|
1473
1663
|
async getEntries() {
|
|
@@ -1494,7 +1684,7 @@ class BunGitRepository {
|
|
|
1494
1684
|
}
|
|
1495
1685
|
}
|
|
1496
1686
|
|
|
1497
|
-
//
|
|
1687
|
+
// apps/cli/modules/add/main.ts
|
|
1498
1688
|
async function addCommand() {
|
|
1499
1689
|
const gitRepository = new BunGitRepository;
|
|
1500
1690
|
const getChangesUseCase = new GetChangesUseCase(gitRepository);
|
|
@@ -1503,7 +1693,405 @@ async function addCommand() {
|
|
|
1503
1693
|
await addCommand2.execute();
|
|
1504
1694
|
}
|
|
1505
1695
|
|
|
1506
|
-
//
|
|
1696
|
+
// apps/cli/alias.ts
|
|
1697
|
+
var ALIASES = [
|
|
1698
|
+
{ name: "gs", command: "status -sb", kind: "git" },
|
|
1699
|
+
{
|
|
1700
|
+
name: "gl",
|
|
1701
|
+
command: "log --oneline --decorate --graph --all -n 20",
|
|
1702
|
+
kind: "git"
|
|
1703
|
+
},
|
|
1704
|
+
{ name: "gll", command: "log --stat", kind: "git" },
|
|
1705
|
+
{ name: "gd", command: "diff --word-diff=color", kind: "git" },
|
|
1706
|
+
{ name: "gds", command: "diff --staged --word-diff=color", kind: "git" },
|
|
1707
|
+
{ name: "ga", command: "add", kind: "glinter" },
|
|
1708
|
+
{ name: "gaa", command: "add -A", kind: "git" },
|
|
1709
|
+
{ name: "gc", command: "commit", kind: "glinter" },
|
|
1710
|
+
{ name: "gcm", command: "commit -m", kind: "git" },
|
|
1711
|
+
{ name: "gca", command: "commit --amend", kind: "git" },
|
|
1712
|
+
{ name: "gcan", command: "commit --amend --no-edit", kind: "git" },
|
|
1713
|
+
{ name: "gb", command: "branch", kind: "git" },
|
|
1714
|
+
{ name: "gba", command: "branch -a", kind: "git" },
|
|
1715
|
+
{ name: "gco", command: "switch", kind: "glinter" },
|
|
1716
|
+
{ name: "gcb", command: "checkout -b", kind: "git" },
|
|
1717
|
+
{ name: "gpl", command: "pull", kind: "git" },
|
|
1718
|
+
{ name: "gplr", command: "pull --rebase", kind: "git" },
|
|
1719
|
+
{ name: "gp", command: "push", kind: "git" },
|
|
1720
|
+
{ name: "ggpush", command: "push origin HEAD", kind: "git" },
|
|
1721
|
+
{ name: "gpf", command: "push --force-with-lease", kind: "git" },
|
|
1722
|
+
{ name: "gst", command: "stash", kind: "git" },
|
|
1723
|
+
{ name: "gstp", command: "stash pop", kind: "git" },
|
|
1724
|
+
{ name: "gstl", command: "stash list", kind: "git" },
|
|
1725
|
+
{ name: "gcl", command: "clean -fd", kind: "git" },
|
|
1726
|
+
{ name: "grh", command: "reset --hard", kind: "git" }
|
|
1727
|
+
];
|
|
1728
|
+
|
|
1729
|
+
// apps/cli/modules/alias/main.ts
|
|
1730
|
+
function resolveAlias(name, command) {
|
|
1731
|
+
return { name, value: command };
|
|
1732
|
+
}
|
|
1733
|
+
function printAliases({
|
|
1734
|
+
title = "The following aliases are configured by setup:"
|
|
1735
|
+
} = {}) {
|
|
1736
|
+
console.log(YELLOW({ text: `
|
|
1737
|
+
${title}
|
|
1738
|
+
` }));
|
|
1739
|
+
for (const alias of ALIASES) {
|
|
1740
|
+
const tag = alias.kind === "glinter" ? MAGENTA({ text: "[glinter]" }) : BLUE({ text: "[git] " });
|
|
1741
|
+
const { name, value } = resolveAlias(alias.name, alias.command);
|
|
1742
|
+
console.log(` ${tag} ${GREEN({ text: name.padEnd(8) })} \u2192 ${value}`);
|
|
1743
|
+
}
|
|
1744
|
+
console.log("");
|
|
1745
|
+
}
|
|
1746
|
+
async function aliasCommand() {
|
|
1747
|
+
printAliases();
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
// apps/cli/modules/commit/app/commit.use-case.ts
|
|
1751
|
+
class CommitUseCase {
|
|
1752
|
+
commitRepository;
|
|
1753
|
+
constructor(commitRepository) {
|
|
1754
|
+
this.commitRepository = commitRepository;
|
|
1755
|
+
}
|
|
1756
|
+
async execute({ message }) {
|
|
1757
|
+
await this.commitRepository.commit(message);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
// apps/cli/commit-options.ts
|
|
1762
|
+
var commitTypeOptions = [
|
|
1763
|
+
{
|
|
1764
|
+
value: "feat",
|
|
1765
|
+
label: `${GREEN({ text: "feat" })}: A new feature`
|
|
1766
|
+
},
|
|
1767
|
+
{
|
|
1768
|
+
value: "fix",
|
|
1769
|
+
label: `${GREEN({ text: "fix" })}: A bug fix`
|
|
1770
|
+
},
|
|
1771
|
+
{
|
|
1772
|
+
value: "chore",
|
|
1773
|
+
label: `${GREEN({ text: "chore" })}: Routine maintenance`
|
|
1774
|
+
},
|
|
1775
|
+
{
|
|
1776
|
+
value: "docs",
|
|
1777
|
+
label: `${GREEN({ text: "docs" })}: Documentation updates`
|
|
1778
|
+
},
|
|
1779
|
+
{
|
|
1780
|
+
value: "refactor",
|
|
1781
|
+
label: `${GREEN({ text: "refactor" })}: Code changes without behavior change`
|
|
1782
|
+
},
|
|
1783
|
+
{
|
|
1784
|
+
value: "test",
|
|
1785
|
+
label: `${GREEN({ text: "test" })}: Add or update tests`
|
|
1786
|
+
},
|
|
1787
|
+
{
|
|
1788
|
+
value: "perf",
|
|
1789
|
+
label: `${GREEN({ text: "perf" })}: Performance improvements`
|
|
1790
|
+
},
|
|
1791
|
+
{
|
|
1792
|
+
value: "style",
|
|
1793
|
+
label: `${GREEN({ text: "style" })}: Formatting or style-only changes`
|
|
1794
|
+
}
|
|
1795
|
+
];
|
|
1796
|
+
|
|
1797
|
+
// apps/cli/utils/input.ts
|
|
1798
|
+
async function Input({
|
|
1799
|
+
message,
|
|
1800
|
+
placeholder
|
|
1801
|
+
}) {
|
|
1802
|
+
const value = await Ot({
|
|
1803
|
+
message,
|
|
1804
|
+
placeholder,
|
|
1805
|
+
validate(input) {
|
|
1806
|
+
if (!input?.trim()) {
|
|
1807
|
+
return "Commit message is required.";
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
});
|
|
1811
|
+
if (q(value)) {
|
|
1812
|
+
pt("Operation cancelled.");
|
|
1813
|
+
process.exit(0);
|
|
1814
|
+
}
|
|
1815
|
+
return value.trim();
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
// apps/cli/utils/select.ts
|
|
1819
|
+
async function Select({
|
|
1820
|
+
message,
|
|
1821
|
+
options
|
|
1822
|
+
}) {
|
|
1823
|
+
const selected = await _t({
|
|
1824
|
+
message,
|
|
1825
|
+
options
|
|
1826
|
+
});
|
|
1827
|
+
if (q(selected)) {
|
|
1828
|
+
pt("Operation cancelled.");
|
|
1829
|
+
process.exit(0);
|
|
1830
|
+
}
|
|
1831
|
+
return selected;
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
// apps/cli/modules/commit/app/commit-command.ts
|
|
1835
|
+
class CommitCommand {
|
|
1836
|
+
commitUseCase;
|
|
1837
|
+
constructor(commitUseCase) {
|
|
1838
|
+
this.commitUseCase = commitUseCase;
|
|
1839
|
+
}
|
|
1840
|
+
async execute() {
|
|
1841
|
+
try {
|
|
1842
|
+
const commitType = await Select({
|
|
1843
|
+
message: "Select the commit type.",
|
|
1844
|
+
options: commitTypeOptions
|
|
1845
|
+
});
|
|
1846
|
+
const commitDescription = await Input({
|
|
1847
|
+
message: "Write your commit message.",
|
|
1848
|
+
placeholder: "e.g. add interactive commit flow"
|
|
1849
|
+
});
|
|
1850
|
+
await this.commitUseCase.execute({
|
|
1851
|
+
message: `${commitType}: ${commitDescription}`
|
|
1852
|
+
});
|
|
1853
|
+
} catch (error) {
|
|
1854
|
+
errorHandler(error);
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
// apps/cli/modules/commit/infra/bun-commit.repository.ts
|
|
1860
|
+
class BunCommitRepository {
|
|
1861
|
+
async commit(message) {
|
|
1862
|
+
const proc = Bun.spawn(["git", "commit", "-m", message], {
|
|
1863
|
+
stdio: ["inherit", "inherit", "inherit"]
|
|
1864
|
+
});
|
|
1865
|
+
const exitCode = await proc.exited;
|
|
1866
|
+
if (exitCode !== 0) {
|
|
1867
|
+
throw new ServerError("Git commit failed", "Could not create commit from interactive prompt");
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
// apps/cli/modules/commit/main.ts
|
|
1873
|
+
async function commitCommand() {
|
|
1874
|
+
const commitRepository = new BunCommitRepository;
|
|
1875
|
+
const commitUseCase = new CommitUseCase(commitRepository);
|
|
1876
|
+
const commitCommand2 = new CommitCommand(commitUseCase);
|
|
1877
|
+
await commitCommand2.execute();
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
// apps/cli/modules/setup/app/setup-aliases.use-case.ts
|
|
1881
|
+
class SetupAliasesUseCase {
|
|
1882
|
+
aliasRepository;
|
|
1883
|
+
constructor(aliasRepository) {
|
|
1884
|
+
this.aliasRepository = aliasRepository;
|
|
1885
|
+
}
|
|
1886
|
+
async execute() {
|
|
1887
|
+
for (const alias of ALIASES) {
|
|
1888
|
+
const { name, value } = this.resolveAlias(alias.name, alias.command, alias.kind);
|
|
1889
|
+
await this.aliasRepository.setAlias(name, value);
|
|
1890
|
+
}
|
|
1891
|
+
return { total: ALIASES.length };
|
|
1892
|
+
}
|
|
1893
|
+
resolveAlias(name, command, kind) {
|
|
1894
|
+
const aliasCommand2 = kind === "git" ? `git ${command}` : `g ${command}`;
|
|
1895
|
+
return { name, value: aliasCommand2 };
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
// apps/cli/utils/confirm.ts
|
|
1900
|
+
async function Confirm({
|
|
1901
|
+
message,
|
|
1902
|
+
cancelMessage,
|
|
1903
|
+
exitOnCancel = true
|
|
1904
|
+
}) {
|
|
1905
|
+
const confirmed = await ot2({
|
|
1906
|
+
message
|
|
1907
|
+
});
|
|
1908
|
+
if (q(confirmed)) {
|
|
1909
|
+
if (exitOnCancel) {
|
|
1910
|
+
pt(cancelMessage ?? "Operation cancelled.");
|
|
1911
|
+
process.exit(0);
|
|
1912
|
+
}
|
|
1913
|
+
return null;
|
|
1914
|
+
}
|
|
1915
|
+
return confirmed;
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
// apps/cli/utils/intro.ts
|
|
1919
|
+
function Intro(message) {
|
|
1920
|
+
mt(message);
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
// apps/cli/utils/outro.ts
|
|
1924
|
+
function Outro(message) {
|
|
1925
|
+
gt(message);
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
// apps/cli/utils/spinner.ts
|
|
1929
|
+
function Spinner() {
|
|
1930
|
+
return fe();
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
// apps/cli/modules/setup/app/setup-command.ts
|
|
1934
|
+
class SetupCommand {
|
|
1935
|
+
setupAliasesUseCase;
|
|
1936
|
+
constructor(setupAliasesUseCase) {
|
|
1937
|
+
this.setupAliasesUseCase = setupAliasesUseCase;
|
|
1938
|
+
}
|
|
1939
|
+
async execute() {
|
|
1940
|
+
try {
|
|
1941
|
+
Intro(MAGENTA({ text: " Glinter Setup " }));
|
|
1942
|
+
printAliases({ title: "The following aliases will be set globally:" });
|
|
1943
|
+
const confirmed = await Confirm({
|
|
1944
|
+
message: "Apply these aliases to your global git config?",
|
|
1945
|
+
exitOnCancel: false
|
|
1946
|
+
});
|
|
1947
|
+
if (!confirmed) {
|
|
1948
|
+
Outro("Setup cancelled.");
|
|
1949
|
+
return;
|
|
1950
|
+
}
|
|
1951
|
+
const spinner = Spinner();
|
|
1952
|
+
spinner.start("Writing aliases...");
|
|
1953
|
+
const { total } = await this.setupAliasesUseCase.execute();
|
|
1954
|
+
console.log("");
|
|
1955
|
+
spinner.stop(`${CHECK({ text: `${total} aliases configured successfully.` })}`);
|
|
1956
|
+
Outro(`${GREEN({ text: "GLINTER" })}, if you like the project, give a star on github: https://github.com/jannael/glinter`);
|
|
1957
|
+
console.log("");
|
|
1958
|
+
console.log(MAGENTA({ text: "To use the aliases, please restart your terminal." }));
|
|
1959
|
+
} catch (error) {
|
|
1960
|
+
errorHandler(error);
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
// apps/cli/modules/setup/infra/bun-alias-unix.ts
|
|
1966
|
+
import fs from "fs";
|
|
1967
|
+
import os from "os";
|
|
1968
|
+
import path from "path";
|
|
1969
|
+
|
|
1970
|
+
class BunAliasUnix {
|
|
1971
|
+
async setAlias(name, value) {
|
|
1972
|
+
const profilePath = this.getUnixProfilePath();
|
|
1973
|
+
fs.mkdirSync(path.dirname(profilePath), { recursive: true });
|
|
1974
|
+
const current = fs.existsSync(profilePath) ? fs.readFileSync(profilePath, "utf8") : "";
|
|
1975
|
+
const updated = this.upsertUnixProfileAlias(current, name, value);
|
|
1976
|
+
fs.writeFileSync(profilePath, updated);
|
|
1977
|
+
}
|
|
1978
|
+
upsertUnixProfileAlias(content, name, value) {
|
|
1979
|
+
const escapedName = this.escapeRegex(name);
|
|
1980
|
+
const escapedValue = this.escapeSingleQuotes(value);
|
|
1981
|
+
const aliasLine = `alias ${name}='${escapedValue}'`;
|
|
1982
|
+
const aliasRegex = new RegExp(`^alias ${escapedName}=.*\\r?\\n?`, "gm");
|
|
1983
|
+
const cleaned = content.replace(aliasRegex, "").trimEnd();
|
|
1984
|
+
const prefix = cleaned.length > 0 ? `${cleaned}
|
|
1985
|
+
` : "";
|
|
1986
|
+
return `${prefix}${aliasLine}
|
|
1987
|
+
`;
|
|
1988
|
+
}
|
|
1989
|
+
getUnixProfilePath() {
|
|
1990
|
+
const home = os.homedir();
|
|
1991
|
+
const shellName = path.basename(process.env.SHELL ?? "");
|
|
1992
|
+
const preferredProfile = shellName === "zsh" ? ".zshrc" : shellName === "bash" ? ".bashrc" : ".profile";
|
|
1993
|
+
const candidates = [preferredProfile, ".bashrc", ".zshrc", ".profile"];
|
|
1994
|
+
const uniqueCandidates = [...new Set(candidates)];
|
|
1995
|
+
for (const candidate of uniqueCandidates) {
|
|
1996
|
+
const candidatePath = path.join(home, candidate);
|
|
1997
|
+
if (fs.existsSync(candidatePath)) {
|
|
1998
|
+
return candidatePath;
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
return path.join(home, preferredProfile);
|
|
2002
|
+
}
|
|
2003
|
+
escapeRegex(value) {
|
|
2004
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2005
|
+
}
|
|
2006
|
+
escapeSingleQuotes(value) {
|
|
2007
|
+
return value.replace(/'/g, `'"'"'`);
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
// apps/cli/modules/setup/infra/bun-alias-windows.ts
|
|
2012
|
+
import fs2 from "fs";
|
|
2013
|
+
import os2 from "os";
|
|
2014
|
+
import path2 from "path";
|
|
2015
|
+
|
|
2016
|
+
class BunAliasWindows {
|
|
2017
|
+
async setAlias(name, value) {
|
|
2018
|
+
const psProfilePath = this.getWindowsProfilePath();
|
|
2019
|
+
fs2.mkdirSync(path2.dirname(psProfilePath), { recursive: true });
|
|
2020
|
+
const current = fs2.existsSync(psProfilePath) ? fs2.readFileSync(psProfilePath, "utf8") : "";
|
|
2021
|
+
const updated = this.upsertWindowsProfileFunction(current, name, value);
|
|
2022
|
+
fs2.writeFileSync(psProfilePath, updated);
|
|
2023
|
+
}
|
|
2024
|
+
upsertWindowsProfileFunction(content, name, value) {
|
|
2025
|
+
const escapedName = this.escapeRegex(name);
|
|
2026
|
+
const removeAliasLine = `if (Get-Alias -Name ${name} -ErrorAction SilentlyContinue) { Remove-Item Alias:${name} -Force }`;
|
|
2027
|
+
const functionLine = `function ${name} { ${value} @args }`;
|
|
2028
|
+
const removeAliasRegex = new RegExp(`^if \\(Get-Alias -Name ${escapedName} -ErrorAction SilentlyContinue\\) \\{ Remove-Item Alias:${escapedName} -Force \\}\\r?\\n?`, "gm");
|
|
2029
|
+
const functionRegex = new RegExp(`^function ${escapedName} \\{[^\\r\\n]*\\}\\r?\\n?`, "gm");
|
|
2030
|
+
const cleaned = content.replace(removeAliasRegex, "").replace(functionRegex, "").trimEnd();
|
|
2031
|
+
const prefix = cleaned.length > 0 ? `${cleaned}
|
|
2032
|
+
` : "";
|
|
2033
|
+
return `${prefix}${removeAliasLine}
|
|
2034
|
+
${functionLine}
|
|
2035
|
+
`;
|
|
2036
|
+
}
|
|
2037
|
+
escapeRegex(value) {
|
|
2038
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2039
|
+
}
|
|
2040
|
+
getWindowsProfilePath() {
|
|
2041
|
+
return path2.join(this.getWindowsDocumentsPath(), "PowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
2042
|
+
}
|
|
2043
|
+
getWindowsDocumentsPath() {
|
|
2044
|
+
const proc = Bun.spawnSync([
|
|
2045
|
+
"powershell",
|
|
2046
|
+
"-NoProfile",
|
|
2047
|
+
"-Command",
|
|
2048
|
+
"[Environment]::GetFolderPath('MyDocuments')"
|
|
2049
|
+
], {
|
|
2050
|
+
stdout: "pipe",
|
|
2051
|
+
stderr: "pipe"
|
|
2052
|
+
});
|
|
2053
|
+
if (proc.exitCode === 0) {
|
|
2054
|
+
const docsPath = new TextDecoder().decode(proc.stdout).trim();
|
|
2055
|
+
if (docsPath.length > 0) {
|
|
2056
|
+
return docsPath;
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
return path2.join(os2.homedir(), "Documents");
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
// apps/cli/modules/setup/infra/bun-alias.repository.ts
|
|
2064
|
+
class BunAliasRepository {
|
|
2065
|
+
getOS() {
|
|
2066
|
+
return process.platform === "win32" ? "windows" : "unix";
|
|
2067
|
+
}
|
|
2068
|
+
async setAlias(name, value) {
|
|
2069
|
+
try {
|
|
2070
|
+
const system = this.getOS();
|
|
2071
|
+
if (system === "windows") {
|
|
2072
|
+
const bunAliasWindows = new BunAliasWindows;
|
|
2073
|
+
await bunAliasWindows.setAlias(name, value);
|
|
2074
|
+
}
|
|
2075
|
+
if (system === "unix") {
|
|
2076
|
+
const bunAliasUnix = new BunAliasUnix;
|
|
2077
|
+
await bunAliasUnix.setAlias(name, value);
|
|
2078
|
+
}
|
|
2079
|
+
console.log(` ${MAGENTA({ text: name.padEnd(8) })} set ${GREEN({ text: "successfully".padStart(10) })}`);
|
|
2080
|
+
} catch {
|
|
2081
|
+
throw new ServerError("Unexpected execution error", `Failed to set alias: ${name}`);
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
// apps/cli/modules/setup/main.ts
|
|
2087
|
+
async function setupCommand() {
|
|
2088
|
+
const aliasRepository = new BunAliasRepository;
|
|
2089
|
+
const setupAliasesUseCase = new SetupAliasesUseCase(aliasRepository);
|
|
2090
|
+
const setupCommand2 = new SetupCommand(setupAliasesUseCase);
|
|
2091
|
+
await setupCommand2.execute();
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
// apps/cli/modules/switch/domain/branch.ts
|
|
1507
2095
|
class Branch {
|
|
1508
2096
|
props;
|
|
1509
2097
|
constructor(props) {
|
|
@@ -1539,7 +2127,7 @@ class Branch {
|
|
|
1539
2127
|
}
|
|
1540
2128
|
}
|
|
1541
2129
|
|
|
1542
|
-
//
|
|
2130
|
+
// apps/cli/modules/switch/app/get-branches.use-case.ts
|
|
1543
2131
|
class GetBranchesUseCase {
|
|
1544
2132
|
branchRepository;
|
|
1545
2133
|
constructor(branchRepository) {
|
|
@@ -1552,7 +2140,7 @@ class GetBranchesUseCase {
|
|
|
1552
2140
|
}
|
|
1553
2141
|
}
|
|
1554
2142
|
|
|
1555
|
-
//
|
|
2143
|
+
// apps/cli/modules/switch/app/switch-branch.use-case.ts
|
|
1556
2144
|
class SwitchBranch {
|
|
1557
2145
|
branchRepository;
|
|
1558
2146
|
constructor(branchRepository) {
|
|
@@ -1563,23 +2151,7 @@ class SwitchBranch {
|
|
|
1563
2151
|
}
|
|
1564
2152
|
}
|
|
1565
2153
|
|
|
1566
|
-
//
|
|
1567
|
-
async function Select({
|
|
1568
|
-
message,
|
|
1569
|
-
options
|
|
1570
|
-
}) {
|
|
1571
|
-
const selected = await _t({
|
|
1572
|
-
message,
|
|
1573
|
-
options
|
|
1574
|
-
});
|
|
1575
|
-
if (q(selected)) {
|
|
1576
|
-
pt("Operation cancelled.");
|
|
1577
|
-
process.exit(0);
|
|
1578
|
-
}
|
|
1579
|
-
return selected;
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
// src/modules/switch/app/switch-command.ts
|
|
2154
|
+
// apps/cli/modules/switch/app/switch-command.ts
|
|
1583
2155
|
class SwitchCommand {
|
|
1584
2156
|
getBranchesUseCase;
|
|
1585
2157
|
switchBranch;
|
|
@@ -1624,7 +2196,7 @@ class SwitchCommand {
|
|
|
1624
2196
|
}
|
|
1625
2197
|
}
|
|
1626
2198
|
|
|
1627
|
-
//
|
|
2199
|
+
// apps/cli/modules/switch/infra/bun-switch-repository.ts
|
|
1628
2200
|
var {$: $3 } = globalThis.Bun;
|
|
1629
2201
|
class BunSwitchRepository {
|
|
1630
2202
|
async getBranches() {
|
|
@@ -1650,7 +2222,7 @@ class BunSwitchRepository {
|
|
|
1650
2222
|
}
|
|
1651
2223
|
}
|
|
1652
2224
|
|
|
1653
|
-
//
|
|
2225
|
+
// apps/cli/modules/switch/main.ts
|
|
1654
2226
|
async function switchCommand() {
|
|
1655
2227
|
const switchRepo = new BunSwitchRepository;
|
|
1656
2228
|
const switchBranchUseCase = new SwitchBranch(switchRepo);
|
|
@@ -1659,12 +2231,18 @@ async function switchCommand() {
|
|
|
1659
2231
|
await switchCommand2.execute();
|
|
1660
2232
|
}
|
|
1661
2233
|
|
|
1662
|
-
//
|
|
2234
|
+
// apps/cli/index.ts
|
|
1663
2235
|
var args = Bun.argv.slice(2);
|
|
1664
2236
|
if (args[0] === "add" && !args[1])
|
|
1665
2237
|
await addCommand();
|
|
2238
|
+
else if (args[0] === "commit" && !args[1])
|
|
2239
|
+
await commitCommand();
|
|
1666
2240
|
else if (args[0] === "switch" && !args[1])
|
|
1667
2241
|
await switchCommand();
|
|
2242
|
+
else if (args[0] === "alias" && !args[1])
|
|
2243
|
+
await aliasCommand();
|
|
2244
|
+
else if (args[0] === "setup")
|
|
2245
|
+
await setupCommand();
|
|
1668
2246
|
else {
|
|
1669
2247
|
const proc = Bun.spawn(["git", ...args], {
|
|
1670
2248
|
stdio: ["inherit", "inherit", "inherit"]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jannael/glinter",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A high-performance, transparent Git wrapper with interactive staging",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"name": "Jannael",
|
|
14
14
|
"url": "https://github.com/jannael"
|
|
15
15
|
},
|
|
16
|
-
"homepage": "https://
|
|
16
|
+
"homepage": "https://glinter.jannael.com",
|
|
17
17
|
"bugs": {
|
|
18
18
|
"url": "https://github.com/jannael/glinter/issues"
|
|
19
19
|
},
|
|
@@ -34,12 +34,13 @@
|
|
|
34
34
|
".": "./dist/index.js"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
37
|
+
"build:cli": "bun build ./apps/cli/index.ts --outfile=./dist/index.js --target=bun",
|
|
38
|
+
"prepublishOnly": "bun run build:cli",
|
|
39
|
+
|
|
40
40
|
"test": "vitest",
|
|
41
41
|
"lint": "biome check",
|
|
42
|
-
"lint:fix": "biome format --write"
|
|
42
|
+
"lint:fix": "biome format --write",
|
|
43
|
+
"type-check": "bunx tsc --noEmit"
|
|
43
44
|
},
|
|
44
45
|
"bin": {
|
|
45
46
|
"g": "./dist/index.js"
|
|
@@ -59,4 +60,4 @@
|
|
|
59
60
|
"dependencies": {
|
|
60
61
|
"@clack/prompts": "1.2.0"
|
|
61
62
|
}
|
|
62
|
-
}
|
|
63
|
+
}
|