@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.
Files changed (3) hide show
  1. package/README.md +93 -8
  2. package/dist/index.js +628 -50
  3. package/package.json +8 -7
package/README.md CHANGED
@@ -1,23 +1,106 @@
1
- # Glinter
2
-
3
- Glinter is a high-performance, transparent Git wrapper built with **Bun**. It enhances the standard `git add` workflow with a beautiful, interactive CLI interface while acting as a seamless pass-through for all other Git commands.
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/7c7cddef-d656-45e7-82e3-452cf669bbfc" controls="false" autoplay="true" loop="true" muted="true" style="max-width: 100%;">
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
- - **Interactive `add`**: When you run `g add`, it presents a color-coded list of your modified, new, and deleted files. You can multi-select exactly what you want to stage using a GUI-like interface in your terminal.
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
- - **Abbreviation**: You can use `g` instead of `git`.
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
+ | ![glinter add](./screenshots/ga.png) | ![glinter commit](./screenshots/gc.png) |
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
- // src/utils/colors.ts
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
- // src/error/error-instance.ts
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
- // src/error/error-handler.ts
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, D) => et2(h, G2, j2, D, $2);
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
- // src/utils/multiselect.ts
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
- // src/modules/add/app/add-command.ts
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 and" }) + `
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
- // src/modules/add/domain/change.ts
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
- // src/modules/add/app/get-changes.use-case.ts
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
- // src/modules/add/app/stage-changes.use-case.ts
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
- // src/modules/add/infra/bun-git.repository.ts
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
- // src/modules/add/main.ts
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
- // src/modules/switch/domain/branch.ts
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
- // src/modules/switch/app/get-branches.use-case.ts
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
- // src/modules/switch/app/switch-branch.use-case.ts
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
- // src/utils/select.ts
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
- // src/modules/switch/infra/bun-switch-repository.ts
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
- // src/modules/switch/main.ts
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
- // src/index.ts
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.1.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://github.com/jannael/glinter#readme",
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
- "dev": "bun run src/index.ts",
38
- "build": "bun build ./src/index.ts --outfile=./dist/index.js --target=bun",
39
- "prepublishOnly": "bun run build",
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
+ }