zammy 1.2.1 → 1.3.2

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 (36) hide show
  1. package/README.md +322 -239
  2. package/assets/zammy.gif +0 -0
  3. package/dist/chunk-LLLEINP6.js +1229 -0
  4. package/dist/index.js +1886 -489
  5. package/dist/plugins.d.ts +168 -0
  6. package/dist/plugins.js +47 -0
  7. package/package.json +20 -2
  8. package/packages/plugins/docker/README.md +141 -0
  9. package/packages/plugins/docker/dist/index.d.ts +4 -0
  10. package/packages/plugins/docker/dist/index.d.ts.map +1 -0
  11. package/packages/plugins/docker/dist/index.js +402 -0
  12. package/packages/plugins/docker/dist/index.js.map +1 -0
  13. package/packages/plugins/docker/package.json +32 -0
  14. package/packages/plugins/docker/zammy-plugin.json +16 -0
  15. package/packages/plugins/faker/README.md +65 -0
  16. package/packages/plugins/faker/dist/index.d.ts +4 -0
  17. package/packages/plugins/faker/dist/index.d.ts.map +1 -0
  18. package/packages/plugins/faker/dist/index.js +349 -0
  19. package/packages/plugins/faker/dist/index.js.map +1 -0
  20. package/packages/plugins/faker/package.json +32 -0
  21. package/packages/plugins/faker/zammy-plugin.json +14 -0
  22. package/packages/plugins/network/README.md +126 -0
  23. package/packages/plugins/network/dist/index.d.ts +4 -0
  24. package/packages/plugins/network/dist/index.d.ts.map +1 -0
  25. package/packages/plugins/network/dist/index.js +405 -0
  26. package/packages/plugins/network/dist/index.js.map +1 -0
  27. package/packages/plugins/network/package.json +32 -0
  28. package/packages/plugins/network/zammy-plugin.json +17 -0
  29. package/packages/plugins/port/README.md +74 -0
  30. package/packages/plugins/port/dist/index.d.ts +4 -0
  31. package/packages/plugins/port/dist/index.d.ts.map +1 -0
  32. package/packages/plugins/port/dist/index.js +331 -0
  33. package/packages/plugins/port/dist/index.js.map +1 -0
  34. package/packages/plugins/port/package.json +32 -0
  35. package/packages/plugins/port/zammy-plugin.json +16 -0
  36. package/packages/plugins/tsconfig.base.json +17 -0
package/dist/index.js CHANGED
@@ -1,235 +1,42 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ box,
4
+ bubble,
5
+ categoryIcons,
6
+ checkConflicts,
7
+ detectSourceType,
8
+ discoverPlugins,
9
+ formatPermissions,
10
+ getAllCommands,
11
+ getCommand,
12
+ getDiscoveredPlugins,
13
+ getPluginCommands,
14
+ initPluginLoader,
15
+ installFromGit,
16
+ installFromGithub,
17
+ installFromLocal,
18
+ installFromNpm,
19
+ isPluginLoaded,
20
+ loadPlugin,
21
+ progressBar,
22
+ registerCommand,
23
+ registerPluginCommand,
24
+ removePlugin,
25
+ spinnerFrames,
26
+ symbols,
27
+ theme,
28
+ unloadPlugin
29
+ } from "./chunk-LLLEINP6.js";
2
30
 
3
31
  // src/index.ts
4
32
  import * as readline from "readline";
5
33
 
6
34
  // src/ui/banner.ts
7
35
  import figlet from "figlet";
8
- import chalk3 from "chalk";
9
-
10
- // src/ui/colors.ts
11
- import chalk from "chalk";
12
- var palette = {
13
- rose: "#FF6B6B",
14
- coral: "#FF8E72",
15
- peach: "#FFEAA7",
16
- mint: "#96CEB4",
17
- teal: "#4ECDC4",
18
- sky: "#45B7D1",
19
- lavender: "#DDA0DD",
20
- purple: "#9B59B6",
21
- gold: "#FFD700",
22
- silver: "#C0C0C0"
23
- };
24
- var theme = {
25
- primary: chalk.hex(palette.teal),
26
- secondary: chalk.hex(palette.lavender),
27
- success: chalk.hex("#2ECC71"),
28
- warning: chalk.hex("#F39C12"),
29
- error: chalk.hex("#E74C3C"),
30
- dim: chalk.hex("#6C7A89"),
31
- highlight: chalk.bold.white,
32
- command: chalk.bold.hex(palette.teal),
33
- prompt: chalk.bold.hex(palette.lavender),
34
- accent: chalk.hex(palette.rose),
35
- info: chalk.hex(palette.sky),
36
- muted: chalk.dim.hex("#95A5A6"),
37
- gold: chalk.hex(palette.gold),
38
- rose: chalk.hex(palette.rose),
39
- mint: chalk.hex(palette.mint),
40
- peach: chalk.hex(palette.peach),
41
- // Gradient text effects
42
- gradient: (text) => {
43
- const colors = [palette.rose, palette.coral, palette.peach, palette.mint, palette.teal];
44
- return text.split("").map(
45
- (char, i) => chalk.hex(colors[i % colors.length])(char)
46
- ).join("");
47
- },
48
- rainbow: (text) => {
49
- const colors = ["#FF6B6B", "#FF8E72", "#FFEAA7", "#96CEB4", "#4ECDC4", "#45B7D1", "#DDA0DD"];
50
- return text.split("").map(
51
- (char, i) => chalk.hex(colors[i % colors.length])(char)
52
- ).join("");
53
- },
54
- ocean: (text) => {
55
- const colors = ["#0077B6", "#00B4D8", "#48CAE4", "#90E0EF", "#CAF0F8"];
56
- return text.split("").map(
57
- (char, i) => chalk.hex(colors[i % colors.length])(char)
58
- ).join("");
59
- },
60
- sunset: (text) => {
61
- const colors = ["#FF6B6B", "#FF8E53", "#FFA07A", "#FFB347", "#FFD700"];
62
- return text.split("").map(
63
- (char, i) => chalk.hex(colors[i % colors.length])(char)
64
- ).join("");
65
- },
66
- // Bold variants
67
- b: {
68
- primary: chalk.bold.hex(palette.teal),
69
- secondary: chalk.bold.hex(palette.lavender),
70
- success: chalk.bold.hex("#2ECC71"),
71
- warning: chalk.bold.hex("#F39C12"),
72
- error: chalk.bold.hex("#E74C3C")
73
- }
74
- };
75
- var symbols = {
76
- // Basic UI
77
- arrow: "\u276F",
78
- // ❯
79
- check: "\u2714",
80
- // ✔
81
- cross: "\u2718",
82
- // ✘
83
- info: "\u2139",
84
- // ℹ
85
- warning: "\u26A0",
86
- // ⚠
87
- bullet: "\u2022",
88
- // •
89
- // Decorative
90
- star: "\u2605",
91
- // ★
92
- heart: "\u2665",
93
- // ♥
94
- diamond: "\u2666",
95
- // ♦
96
- sparkle: "\u2728",
97
- // ✨
98
- lightning: "\u26A1",
99
- // ⚡
100
- // Emoji icons
101
- fire: "\u{1F525}",
102
- // 🔥
103
- rocket: "\u{1F680}",
104
- // 🚀
105
- dice: "\u{1F3B2}",
106
- // 🎲
107
- coin: "\u{1FA99}",
108
- // 🪙
109
- lock: "\u{1F512}",
110
- // 🔒
111
- clock: "\u{1F552}",
112
- // 🕒
113
- chart: "\u{1F4CA}",
114
- // 📊
115
- note: "\u{1F4DD}",
116
- // 📝
117
- scroll: "\u{1F4DC}",
118
- // 📜
119
- clipboard: "\u{1F4CB}",
120
- // 📋
121
- palette: "\u{1F3A8}",
122
- // 🎨
123
- tomato: "\u{1F345}",
124
- // 🍅
125
- coffee: "\u2615",
126
- // ☕
127
- bell: "\u{1F514}",
128
- // 🔔
129
- gear: "\u2699",
130
- // ⚙
131
- folder: "\u{1F4C1}",
132
- // 📁
133
- terminal: "\u{1F4BB}",
134
- // 💻
135
- key: "\u{1F511}",
136
- // 🔑
137
- link: "\u{1F517}",
138
- // 🔗
139
- hourglass: "\u23F3"
140
- // ⏳
141
- };
142
- var boxChars = {
143
- rounded: { tl: "\u256D", tr: "\u256E", bl: "\u2570", br: "\u256F", h: "\u2500", v: "\u2502" },
144
- sharp: { tl: "\u250C", tr: "\u2510", bl: "\u2514", br: "\u2518", h: "\u2500", v: "\u2502" },
145
- double: { tl: "\u2554", tr: "\u2557", bl: "\u255A", br: "\u255D", h: "\u2550", v: "\u2551" },
146
- heavy: { tl: "\u250F", tr: "\u2513", bl: "\u2517", br: "\u251B", h: "\u2501", v: "\u2503" }
147
- };
148
- var box = {
149
- topLeft: "\u256D",
150
- // ╭
151
- topRight: "\u256E",
152
- // ╮
153
- bottomLeft: "\u2570",
154
- // ╰
155
- bottomRight: "\u256F",
156
- // ╯
157
- horizontal: "\u2500",
158
- // ─
159
- vertical: "\u2502",
160
- // │
161
- draw: (content, width = 50, style = "rounded") => {
162
- const chars = boxChars[style];
163
- const lines = [];
164
- const innerWidth = width - 2;
165
- lines.push(theme.dim(`${chars.tl}${chars.h.repeat(innerWidth)}${chars.tr}`));
166
- content.forEach((line) => {
167
- const stripped = line.replace(/\x1B\[[0-9;]*m/g, "");
168
- const padding = innerWidth - stripped.length;
169
- lines.push(theme.dim(chars.v) + line + " ".repeat(Math.max(0, padding)) + theme.dim(chars.v));
170
- });
171
- lines.push(theme.dim(`${chars.bl}${chars.h.repeat(innerWidth)}${chars.br}`));
172
- return lines.join("\n");
173
- },
174
- // Simple title box
175
- title: (title, width = 50) => {
176
- const chars = boxChars.rounded;
177
- const innerWidth = width - 2;
178
- const titleLen = title.replace(/\x1B\[[0-9;]*m/g, "").length;
179
- const leftPad = Math.floor((innerWidth - titleLen - 2) / 2);
180
- const rightPad = innerWidth - titleLen - 2 - leftPad;
181
- return theme.dim(`${chars.tl}${chars.h.repeat(leftPad)} `) + title + theme.dim(` ${chars.h.repeat(rightPad)}${chars.tr}`);
182
- }
183
- };
184
- var bubble = {
185
- say: (text, width = 50) => {
186
- const lines = [];
187
- const innerWidth = width - 4;
188
- const words = text.split(" ");
189
- let currentLine = "";
190
- const wrappedLines = [];
191
- for (const word of words) {
192
- if ((currentLine + " " + word).trim().length <= innerWidth) {
193
- currentLine = (currentLine + " " + word).trim();
194
- } else {
195
- if (currentLine) wrappedLines.push(currentLine);
196
- currentLine = word;
197
- }
198
- }
199
- if (currentLine) wrappedLines.push(currentLine);
200
- lines.push(theme.dim(" \u256D" + "\u2500".repeat(innerWidth + 2) + "\u256E"));
201
- for (const line of wrappedLines) {
202
- const padding = innerWidth - line.length;
203
- lines.push(theme.dim(" \u2502 ") + line + " ".repeat(padding) + theme.dim(" \u2502"));
204
- }
205
- lines.push(theme.dim(" \u2570" + "\u2500".repeat(innerWidth + 2) + "\u256F"));
206
- lines.push(theme.dim(" \u2572"));
207
- lines.push(theme.dim(" \u2572"));
208
- return lines.join("\n");
209
- },
210
- think: (text, width = 50) => {
211
- const lines = [];
212
- const innerWidth = width - 4;
213
- lines.push(theme.dim(" \u256D" + "\u2500".repeat(innerWidth + 2) + "\u256E"));
214
- const padding = innerWidth - text.length;
215
- lines.push(theme.dim(" \u2502 ") + text + " ".repeat(Math.max(0, padding)) + theme.dim(" \u2502"));
216
- lines.push(theme.dim(" \u2570" + "\u2500".repeat(innerWidth + 2) + "\u256F"));
217
- lines.push(theme.dim(" \u25CB"));
218
- lines.push(theme.dim(" \u25CB"));
219
- return lines.join("\n");
220
- }
221
- };
222
- var categoryIcons = {
223
- "Utilities": "\u{1F527}",
224
- "Fun": "\u{1F3AE}",
225
- "Creative": "\u{1F3A8}",
226
- "Dev": "\u{1F4BB}",
227
- "Info": "\u{1F4E1}"
228
- };
229
- var spinnerFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
36
+ import chalk2 from "chalk";
230
37
 
231
38
  // src/ui/slime-animated.ts
232
- import chalk2 from "chalk";
39
+ import chalk from "chalk";
233
40
  var C = {
234
41
  P1: "#4A235A",
235
42
  // Darkest edge
@@ -256,15 +63,15 @@ var C = {
256
63
  RD: "#E74C3C"
257
64
  // Red (angry)
258
65
  };
259
- var b = (hex) => chalk2.bgHex(hex)(" ");
260
- var dot = chalk2.hex(C.WH)("\xB7");
261
- var star = chalk2.hex(C.WH)("\u2726");
262
- var heart = chalk2.hex(C.PK)("\u2665");
263
- var z = chalk2.hex(C.CY)("z");
264
- var Z = chalk2.hex(C.CY)("Z");
265
- var eye = chalk2.bgHex(C.BK).hex(C.WH)(" \xB7");
266
- var shine = chalk2.bgHex(C.P3).hex(C.WH)(" \xB7");
267
- var shine2 = chalk2.bgHex(C.P4).hex(C.WH)("\xB7 ");
66
+ var b = (hex) => chalk.bgHex(hex)(" ");
67
+ var dot = chalk.hex(C.WH)("\xB7");
68
+ var star = chalk.hex(C.WH)("\u2726");
69
+ var heart = chalk.hex(C.PK)("\u2665");
70
+ var z = chalk.hex(C.CY)("z");
71
+ var Z = chalk.hex(C.CY)("Z");
72
+ var eye = chalk.bgHex(C.BK).hex(C.WH)(" \xB7");
73
+ var shine = chalk.bgHex(C.P3).hex(C.WH)(" \xB7");
74
+ var shine2 = chalk.bgHex(C.P4).hex(C.WH)("\xB7 ");
268
75
  var slimeFrames = {
269
76
  happy: () => {
270
77
  const { P1, P2, P3, P4, P5, BK, PK } = C;
@@ -281,7 +88,7 @@ var slimeFrames = {
281
88
  },
282
89
  excited: () => {
283
90
  const { P1, P2, P3, P4, P5, BK, PK, YL } = C;
284
- const starEye = chalk2.bgHex(YL).hex(C.WH)("\u2605 ");
91
+ const starEye = chalk.bgHex(YL).hex(C.WH)("\u2605 ");
285
92
  return [
286
93
  ` ${star} ${dot} ${star} ${dot} ${star}`,
287
94
  ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
@@ -295,7 +102,7 @@ var slimeFrames = {
295
102
  },
296
103
  love: () => {
297
104
  const { P1, P2, P3, P4, P5, BK, PK } = C;
298
- const heartEye = chalk2.bgHex(PK).hex(C.WH)("\u2665 ");
105
+ const heartEye = chalk.bgHex(PK).hex(C.WH)("\u2665 ");
299
106
  return [
300
107
  ` ${heart} ${heart}`,
301
108
  ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
@@ -309,7 +116,7 @@ var slimeFrames = {
309
116
  },
310
117
  sleepy: () => {
311
118
  const { P1, P2, P3, P4, P5, BK } = C;
312
- const closedEye = chalk2.bgHex(P3).hex(BK)("\u2500\u2500");
119
+ const closedEye = chalk.bgHex(P3).hex(BK)("\u2500\u2500");
313
120
  return [
314
121
  ` ${z} ${z} ${Z}`,
315
122
  ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
@@ -323,10 +130,10 @@ var slimeFrames = {
323
130
  },
324
131
  thinking: () => {
325
132
  const { P1, P2, P3, P4, P5, BK, YL } = C;
326
- const thinkEye = chalk2.bgHex(C.BK).hex(C.WH)(" \xB7");
327
- const lookUpEye = chalk2.bgHex(C.BK).hex(C.WH)("\xB7 ");
133
+ const thinkEye = chalk.bgHex(C.BK).hex(C.WH)(" \xB7");
134
+ const lookUpEye = chalk.bgHex(C.BK).hex(C.WH)("\xB7 ");
328
135
  return [
329
- ` ${chalk2.hex(YL)("?")}`,
136
+ ` ${chalk.hex(YL)("?")}`,
330
137
  ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
331
138
  ` ${b(P5)}${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}${b(P5)}`,
332
139
  ` ${b(P4)}${b(P3)}${thinkEye}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${lookUpEye}${b(P3)}${b(P4)}`,
@@ -338,9 +145,9 @@ var slimeFrames = {
338
145
  },
339
146
  surprised: () => {
340
147
  const { P1, P2, P3, P4, P5, BK, YL } = C;
341
- const bigEye = chalk2.bgHex(BK).hex(C.WH)("\u25C9 ");
148
+ const bigEye = chalk.bgHex(BK).hex(C.WH)("\u25C9 ");
342
149
  return [
343
- ` ${chalk2.hex(YL)("!!")}`,
150
+ ` ${chalk.hex(YL)("!!")}`,
344
151
  ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
345
152
  ` ${b(P5)}${b(P4)}${b(P3)}${shine2}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}${b(P5)}`,
346
153
  ` ${b(P4)}${b(P3)}${bigEye}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${bigEye}${b(P3)}${b(P4)}`,
@@ -352,8 +159,8 @@ var slimeFrames = {
352
159
  },
353
160
  sad: () => {
354
161
  const { P1, P2, P3, P4, P5, BK, BL } = C;
355
- const sadEye = chalk2.bgHex(BK).hex(C.WH)(" \xB7");
356
- const tear = chalk2.bgHex(BL)(" ");
162
+ const sadEye = chalk.bgHex(BK).hex(C.WH)(" \xB7");
163
+ const tear = chalk.bgHex(BL)(" ");
357
164
  return [
358
165
  ` ${dot} ${dot} ${dot}`,
359
166
  ` ${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}`,
@@ -367,7 +174,7 @@ var slimeFrames = {
367
174
  },
368
175
  wink: () => {
369
176
  const { P1, P2, P3, P4, P5, BK, PK } = C;
370
- const winkEye = chalk2.bgHex(P3).hex(BK)("> ");
177
+ const winkEye = chalk.bgHex(P3).hex(BK)("> ");
371
178
  return [
372
179
  ` ${star} ${dot}`,
373
180
  ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
@@ -381,10 +188,10 @@ var slimeFrames = {
381
188
  },
382
189
  angry: () => {
383
190
  const { P1, P2, P3, P4, BK, RD } = C;
384
- const angryEye = chalk2.bgHex(BK).hex(RD)("> ");
385
- const angryEye2 = chalk2.bgHex(BK).hex(RD)(" <");
191
+ const angryEye = chalk.bgHex(BK).hex(RD)("> ");
192
+ const angryEye2 = chalk.bgHex(BK).hex(RD)(" <");
386
193
  return [
387
- ` ${chalk2.hex(RD)("# @!")}`,
194
+ ` ${chalk.hex(RD)("# @!")}`,
388
195
  ` ${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}`,
389
196
  ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
390
197
  ` ${b(P4)}${b(P3)}${angryEye}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${angryEye2}${b(P3)}${b(P4)}`,
@@ -430,15 +237,15 @@ function getStartupMood() {
430
237
  return "happy";
431
238
  }
432
239
  var miniSlime = {
433
- happy: chalk2.hex(C.P3)("(") + chalk2.hex(C.BK)("\u25D5") + chalk2.hex(C.P3)("\u1D17") + chalk2.hex(C.BK)("\u25D5") + chalk2.hex(C.P3)(")"),
434
- excited: chalk2.hex(C.P3)("(") + chalk2.hex(C.YL)("\u2605") + chalk2.hex(C.P3)("\u1D17") + chalk2.hex(C.YL)("\u2605") + chalk2.hex(C.P3)(")"),
435
- love: chalk2.hex(C.P3)("(") + chalk2.hex(C.PK)("\u2665") + chalk2.hex(C.P3)("\u1D17") + chalk2.hex(C.PK)("\u2665") + chalk2.hex(C.P3)(")"),
436
- sleepy: chalk2.hex(C.P3)("(") + chalk2.hex(C.BK)("\u2013") + chalk2.hex(C.P3)("\u03C9") + chalk2.hex(C.BK)("\u2013") + chalk2.hex(C.P3)(") zZ"),
437
- sad: chalk2.hex(C.P3)("(") + chalk2.hex(C.BK)("\u25D5") + chalk2.hex(C.P3)("\uFE35") + chalk2.hex(C.BK)("\u25D5") + chalk2.hex(C.P3)(")"),
438
- surprised: chalk2.hex(C.P3)("(") + chalk2.hex(C.BK)("\u25CE") + chalk2.hex(C.P3)("\u25CB") + chalk2.hex(C.BK)("\u25CE") + chalk2.hex(C.P3)(")!"),
439
- wink: chalk2.hex(C.P3)("(") + chalk2.hex(C.BK)("\u25D5") + chalk2.hex(C.P3)("\u1D17") + chalk2.hex(C.BK)(">") + chalk2.hex(C.P3)(")"),
440
- thinking: chalk2.hex(C.P3)("(") + chalk2.hex(C.BK)("\u25D5") + chalk2.hex(C.P3)("\uFF5E") + chalk2.hex(C.BK)("\u25D4") + chalk2.hex(C.P3)(")"),
441
- angry: chalk2.hex(C.P3)("(") + chalk2.hex(C.RD)(">") + chalk2.hex(C.P3)("_") + chalk2.hex(C.RD)("<") + chalk2.hex(C.P3)(")")
240
+ happy: chalk.hex(C.P3)("(") + chalk.hex(C.BK)("\u25D5") + chalk.hex(C.P3)("\u1D17") + chalk.hex(C.BK)("\u25D5") + chalk.hex(C.P3)(")"),
241
+ excited: chalk.hex(C.P3)("(") + chalk.hex(C.YL)("\u2605") + chalk.hex(C.P3)("\u1D17") + chalk.hex(C.YL)("\u2605") + chalk.hex(C.P3)(")"),
242
+ love: chalk.hex(C.P3)("(") + chalk.hex(C.PK)("\u2665") + chalk.hex(C.P3)("\u1D17") + chalk.hex(C.PK)("\u2665") + chalk.hex(C.P3)(")"),
243
+ sleepy: chalk.hex(C.P3)("(") + chalk.hex(C.BK)("\u2013") + chalk.hex(C.P3)("\u03C9") + chalk.hex(C.BK)("\u2013") + chalk.hex(C.P3)(") zZ"),
244
+ sad: chalk.hex(C.P3)("(") + chalk.hex(C.BK)("\u25D5") + chalk.hex(C.P3)("\uFE35") + chalk.hex(C.BK)("\u25D5") + chalk.hex(C.P3)(")"),
245
+ surprised: chalk.hex(C.P3)("(") + chalk.hex(C.BK)("\u25CE") + chalk.hex(C.P3)("\u25CB") + chalk.hex(C.BK)("\u25CE") + chalk.hex(C.P3)(")!"),
246
+ wink: chalk.hex(C.P3)("(") + chalk.hex(C.BK)("\u25D5") + chalk.hex(C.P3)("\u1D17") + chalk.hex(C.BK)(">") + chalk.hex(C.P3)(")"),
247
+ thinking: chalk.hex(C.P3)("(") + chalk.hex(C.BK)("\u25D5") + chalk.hex(C.P3)("\uFF5E") + chalk.hex(C.BK)("\u25D4") + chalk.hex(C.P3)(")"),
248
+ angry: chalk.hex(C.P3)("(") + chalk.hex(C.RD)(">") + chalk.hex(C.P3)("_") + chalk.hex(C.RD)("<") + chalk.hex(C.P3)(")")
442
249
  };
443
250
  var validMoods = Object.keys(slimeFrames);
444
251
  function react(mood, message) {
@@ -508,16 +315,16 @@ var C2 = {
508
315
  PK: "#E91E63"
509
316
  // Pink (tongue)
510
317
  };
511
- var b2 = (hex) => chalk3.bgHex(hex)(" ");
512
- var dot2 = chalk3.hex(C2.WH)("\xB7");
318
+ var b2 = (hex) => chalk2.bgHex(hex)(" ");
319
+ var dot2 = chalk2.hex(C2.WH)("\xB7");
513
320
  function getSlimeLines(isBlinking, _mood) {
514
321
  const { P1, P2, P3, P4, P5, WH, BK, PK } = C2;
515
- const openEye = chalk3.bgHex(BK).hex(WH)(" \xB7");
516
- const closedEye = chalk3.bgHex(P3).hex(BK)("\u2500\u2500");
322
+ const openEye = chalk2.bgHex(BK).hex(WH)(" \xB7");
323
+ const closedEye = chalk2.bgHex(P3).hex(BK)("\u2500\u2500");
517
324
  const eyeL = isBlinking ? closedEye : openEye;
518
325
  const eyeR = isBlinking ? closedEye : openEye;
519
- const shine3 = chalk3.bgHex(P3).hex(WH)(" \xB7");
520
- const shine22 = chalk3.bgHex(P4).hex(WH)("\xB7 ");
326
+ const shine3 = chalk2.bgHex(P3).hex(WH)(" \xB7");
327
+ const shine22 = chalk2.bgHex(P4).hex(WH)("\xB7 ");
521
328
  const miniBlob = `${b2(P3)}`;
522
329
  return [
523
330
  ` ${dot2} ${dot2}`,
@@ -534,7 +341,7 @@ var MIN_WIDTH_FOR_MASCOT2 = 90;
534
341
  var MIN_WIDTH_FOR_FULL_LOGO = 55;
535
342
  var MIN_WIDTH_FOR_COMPACT = 30;
536
343
  async function displayBanner(simple = false) {
537
- return new Promise((resolve3) => {
344
+ return new Promise((resolve5) => {
538
345
  const termWidth = process.stdout.columns || 80;
539
346
  figlet("ZAMMY", {
540
347
  font: "ANSI Shadow",
@@ -548,7 +355,7 @@ async function displayBanner(simple = false) {
548
355
  console.log(theme.secondary(` "${greeting}"`));
549
356
  console.log(theme.dim(" Type /help for commands"));
550
357
  console.log("");
551
- resolve3();
358
+ resolve5();
552
359
  return;
553
360
  }
554
361
  let figletLines = [];
@@ -581,7 +388,7 @@ async function displayBanner(simple = false) {
581
388
  console.log(theme.dim(` ${symbols.arrow} Type ${theme.primary("/")} to browse commands or ${theme.primary("/help")} for full list`));
582
389
  console.log(theme.dim(` ${symbols.arrow} Shell commands start with ${theme.primary("!")} (e.g., ${theme.primary("!ls")}, ${theme.primary("!git")})`));
583
390
  console.log("");
584
- resolve3();
391
+ resolve5();
585
392
  return;
586
393
  }
587
394
  const figletWidth = 50;
@@ -611,7 +418,7 @@ async function displayBanner(simple = false) {
611
418
  console.log(theme.dim(` ${symbols.arrow} Type ${theme.primary("/")} to browse commands or ${theme.primary("/help")} for full list`));
612
419
  console.log(theme.dim(` ${symbols.arrow} Shell commands start with ${theme.primary("!")} (e.g., ${theme.primary("!ls")}, ${theme.primary("!git")})`));
613
420
  console.log("");
614
- resolve3();
421
+ resolve5();
615
422
  });
616
423
  });
617
424
  }
@@ -621,35 +428,24 @@ function getPrompt() {
621
428
  return `${theme.b.primary("zammy")}${theme.dim(symbols.arrow)} `;
622
429
  }
623
430
 
624
- // src/commands/registry.ts
625
- var commands = /* @__PURE__ */ new Map();
626
- function registerCommand(command) {
627
- commands.set(command.name, command);
628
- }
629
- function getCommand(name) {
630
- return commands.get(name);
631
- }
632
- function getAllCommands() {
633
- return Array.from(commands.values());
634
- }
635
-
636
431
  // src/commands/utilities/help.ts
637
432
  var categories = {
638
433
  "Utilities": ["help", "exit", "calc", "password", "stats", "time", "countdown", "timer", "todo", "history"],
639
434
  "Fun": ["joke", "quote", "fortune", "dice", "flip", "pomodoro", "zammy"],
640
435
  "Creative": ["asciiart", "figlet", "lorem", "color"],
641
436
  "Dev": ["hash", "uuid", "encode"],
642
- "Info": ["weather"]
437
+ "Info": ["weather"],
438
+ "System": ["plugin"]
643
439
  };
644
440
  registerCommand({
645
441
  name: "help",
646
442
  description: "Show all available commands",
647
443
  usage: "/help [command]",
648
444
  async execute(args2) {
649
- const commands2 = getAllCommands();
445
+ const commands = getAllCommands();
650
446
  if (args2.length > 0) {
651
447
  const cmdName = args2[0].replace(/^\//, "");
652
- const cmd = commands2.find((c) => c.name === cmdName);
448
+ const cmd = commands.find((c) => c.name === cmdName);
653
449
  if (cmd) {
654
450
  console.log("");
655
451
  console.log(box.draw([
@@ -677,9 +473,9 @@ registerCommand({
677
473
  console.log(` ${symbols.rocket} ${theme.gradient("ZAMMY COMMANDS")} ${symbols.rocket}`);
678
474
  console.log(` ${theme.rainbow("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501")}`);
679
475
  console.log("");
680
- const maxNameLength = Math.max(...commands2.map((c) => c.name.length));
476
+ const maxNameLength = Math.max(...commands.map((c) => c.name.length));
681
477
  for (const [category, cmdNames] of Object.entries(categories)) {
682
- const categoryCommands = commands2.filter((c) => cmdNames.includes(c.name));
478
+ const categoryCommands = commands.filter((c) => cmdNames.includes(c.name));
683
479
  if (categoryCommands.length === 0) continue;
684
480
  const icon = categoryIcons[category] || symbols.folder;
685
481
  console.log(` ${icon} ${theme.b.secondary(category)}`);
@@ -692,8 +488,24 @@ registerCommand({
692
488
  }
693
489
  console.log("");
694
490
  }
491
+ const pluginCmds = getPluginCommands();
492
+ if (pluginCmds.length > 0) {
493
+ console.log(` ${symbols.gear} ${theme.b.secondary("Plugins")}`);
494
+ console.log(theme.dim(" " + "\u2500".repeat(46)));
495
+ for (const cmd of pluginCmds) {
496
+ const paddedName = cmd.name.padEnd(maxNameLength + 2);
497
+ const pluginBadge = cmd.pluginName ? theme.dim(`[${cmd.pluginName}]`) : "";
498
+ console.log(
499
+ ` ${theme.command("/" + paddedName)} ${theme.dim("\u2502")} ${theme.dim(cmd.description)} ${pluginBadge}`
500
+ );
501
+ }
502
+ console.log("");
503
+ }
695
504
  const categorizedNames = Object.values(categories).flat();
696
- const uncategorized = commands2.filter((c) => !categorizedNames.includes(c.name));
505
+ const pluginCmdNames = pluginCmds.map((c) => c.name);
506
+ const uncategorized = commands.filter(
507
+ (c) => !categorizedNames.includes(c.name) && !pluginCmdNames.includes(c.name) && c.source === "core"
508
+ );
697
509
  if (uncategorized.length > 0) {
698
510
  console.log(` ${symbols.folder} ${theme.b.secondary("Other")}`);
699
511
  console.log(theme.dim(" " + "\u2500".repeat(46)));
@@ -764,21 +576,126 @@ registerCommand({
764
576
  });
765
577
 
766
578
  // src/handlers/utilities/calc.ts
767
- function evaluate(expression) {
768
- const expr = expression.replace(/\s+/g, "");
769
- if (!/^[\d+\-*/().%^]+$/.test(expr)) {
579
+ function tokenize(expression) {
580
+ const tokens = [];
581
+ let i = 0;
582
+ while (i < expression.length) {
583
+ const char = expression[i];
584
+ if (/\s/.test(char)) {
585
+ i++;
586
+ continue;
587
+ }
588
+ if (/\d/.test(char) || char === "." && /\d/.test(expression[i + 1])) {
589
+ let numStr = "";
590
+ while (i < expression.length && (/\d/.test(expression[i]) || expression[i] === ".")) {
591
+ numStr += expression[i];
592
+ i++;
593
+ }
594
+ const value = parseFloat(numStr);
595
+ if (isNaN(value)) return null;
596
+ tokens.push({ type: "number", value });
597
+ continue;
598
+ }
599
+ if (["+", "-", "*", "/", "%", "^"].includes(char)) {
600
+ tokens.push({ type: "op", value: char });
601
+ i++;
602
+ continue;
603
+ }
604
+ if (char === "(" || char === ")") {
605
+ tokens.push({ type: "paren", value: char });
606
+ i++;
607
+ continue;
608
+ }
770
609
  return null;
771
610
  }
772
- try {
773
- const sanitized = expr.replace(/\^/g, "**");
774
- const result = new Function(`return (${sanitized})`)();
775
- if (typeof result !== "number" || !isFinite(result)) {
776
- return null;
777
- }
611
+ return tokens;
612
+ }
613
+ var Parser = class {
614
+ tokens;
615
+ pos = 0;
616
+ constructor(tokens) {
617
+ this.tokens = tokens;
618
+ }
619
+ parse() {
620
+ const result = this.expr();
621
+ if (this.pos !== this.tokens.length) return null;
778
622
  return result;
779
- } catch {
623
+ }
624
+ current() {
625
+ return this.tokens[this.pos];
626
+ }
627
+ consume() {
628
+ return this.tokens[this.pos++];
629
+ }
630
+ expr() {
631
+ let left = this.term();
632
+ if (left === null) return null;
633
+ while (this.current()?.type === "op" && ["+", "-"].includes(this.current().value)) {
634
+ const op = this.consume().value;
635
+ const right = this.term();
636
+ if (right === null) return null;
637
+ left = op === "+" ? left + right : left - right;
638
+ }
639
+ return left;
640
+ }
641
+ term() {
642
+ let left = this.power();
643
+ if (left === null) return null;
644
+ while (this.current()?.type === "op" && ["*", "/", "%"].includes(this.current().value)) {
645
+ const op = this.consume().value;
646
+ const right = this.power();
647
+ if (right === null) return null;
648
+ if ((op === "/" || op === "%") && right === 0) return null;
649
+ left = op === "*" ? left * right : op === "/" ? left / right : left % right;
650
+ }
651
+ return left;
652
+ }
653
+ power() {
654
+ const base = this.unary();
655
+ if (base === null) return null;
656
+ if (this.current()?.type === "op" && this.current().value === "^") {
657
+ this.consume();
658
+ const exp = this.power();
659
+ if (exp === null) return null;
660
+ return Math.pow(base, exp);
661
+ }
662
+ return base;
663
+ }
664
+ unary() {
665
+ if (this.current()?.type === "op" && this.current().value === "-") {
666
+ this.consume();
667
+ const val = this.factor();
668
+ if (val === null) return null;
669
+ return -val;
670
+ }
671
+ return this.factor();
672
+ }
673
+ factor() {
674
+ const token = this.current();
675
+ if (token?.type === "number") {
676
+ this.consume();
677
+ return token.value;
678
+ }
679
+ if (token?.type === "paren" && token.value === "(") {
680
+ this.consume();
681
+ const result = this.expr();
682
+ if (result === null) return null;
683
+ if (this.current()?.type !== "paren" || this.current().value !== ")") {
684
+ return null;
685
+ }
686
+ this.consume();
687
+ return result;
688
+ }
780
689
  return null;
781
690
  }
691
+ };
692
+ function evaluate(expression) {
693
+ const tokens = tokenize(expression);
694
+ if (!tokens || tokens.length === 0) return null;
695
+ const parser = new Parser(tokens);
696
+ const result = parser.parse();
697
+ if (result === null || !isFinite(result)) return null;
698
+ return result;
782
699
  }
783
700
  function formatNumber(num) {
784
701
  if (Math.abs(num) < 1e-4 || Math.abs(num) > 1e10) {
@@ -1142,15 +1059,16 @@ registerCommand({
1142
1059
  console.log("");
1143
1060
  let remaining = totalSeconds;
1144
1061
  let spinnerIndex = 0;
1145
- return new Promise((resolve3) => {
1062
+ return new Promise((resolve5) => {
1146
1063
  const interval = setInterval(() => {
1147
1064
  process.stdout.write("\r\x1B[K");
1148
1065
  if (remaining <= 0) {
1149
1066
  clearInterval(interval);
1067
+ process.removeListener("SIGINT", cleanup);
1150
1068
  console.log(` ${symbols.sparkle} ${theme.success("TIME'S UP!")} ${symbols.sparkle}`);
1151
1069
  console.log("");
1152
1070
  process.stdout.write("\x07");
1153
- resolve3();
1071
+ resolve5();
1154
1072
  return;
1155
1073
  }
1156
1074
  const spinner = spinnerFrames[spinnerIndex % spinnerFrames.length];
@@ -1162,6 +1080,14 @@ registerCommand({
1162
1080
  remaining--;
1163
1081
  spinnerIndex++;
1164
1082
  }, 1e3);
1083
+ const cleanup = () => {
1084
+ clearInterval(interval);
1085
+ process.stdout.write("\r\x1B[K");
1086
+ console.log(` ${symbols.cross} ${theme.secondary("Countdown cancelled")}`);
1087
+ console.log("");
1088
+ resolve5();
1089
+ };
1090
+ process.once("SIGINT", cleanup);
1165
1091
  process.stdout.write(` ${theme.secondary(spinnerFrames[0])} ${theme.primary(formatTime(remaining))} remaining...`);
1166
1092
  });
1167
1093
  }
@@ -1423,7 +1349,7 @@ registerCommand({
1423
1349
  let history = [];
1424
1350
  try {
1425
1351
  if (existsSync2(HISTORY_FILE)) {
1426
- const lines = readFileSync2(HISTORY_FILE, "utf8").split("\n").filter((l) => l);
1352
+ const lines = readFileSync2(HISTORY_FILE, "utf8").split(/\r?\n/).filter((l) => l);
1427
1353
  history = lines.map((line) => {
1428
1354
  const [time, ...rest] = line.split("|");
1429
1355
  return { time, cmd: rest.join("|") };
@@ -1468,58 +1394,368 @@ registerCommand({
1468
1394
  }
1469
1395
  });
1470
1396
 
1397
+ // src/handlers/utilities/env.ts
1398
+ function getAllEnvVars() {
1399
+ return Object.entries(process.env).filter(([, value]) => value !== void 0).map(([name, value]) => ({ name, value })).sort((a, b3) => a.name.localeCompare(b3.name));
1400
+ }
1401
+ function getEnvVar(name) {
1402
+ const exactMatch = process.env[name];
1403
+ if (exactMatch !== void 0) return exactMatch;
1404
+ const upperName = name.toUpperCase();
1405
+ for (const [key, value] of Object.entries(process.env)) {
1406
+ if (key.toUpperCase() === upperName) {
1407
+ return value;
1408
+ }
1409
+ }
1410
+ return void 0;
1411
+ }
1412
+ function searchEnvVars(query) {
1413
+ const lowerQuery = query.toLowerCase();
1414
+ return getAllEnvVars().filter(
1415
+ (env) => env.name.toLowerCase().includes(lowerQuery) || env.value.toLowerCase().includes(lowerQuery)
1416
+ );
1417
+ }
1418
+ function getPathEntries() {
1419
+ const pathVar = process.env.PATH || process.env.Path || "";
1420
+ const separator = process.platform === "win32" ? ";" : ":";
1421
+ return pathVar.split(separator).filter(Boolean);
1422
+ }
1423
+
1424
+ // src/commands/utilities/env.ts
1425
+ registerCommand({
1426
+ name: "env",
1427
+ description: "View environment variables",
1428
+ usage: "/env [name|search|path]",
1429
+ async execute(args2) {
1430
+ const action = args2[0];
1431
+ console.log("");
1432
+ if (!action) {
1433
+ const vars = getAllEnvVars();
1434
+ console.log(` ${symbols.sparkle} ${theme.gradient("ENVIRONMENT VARIABLES")} ${theme.dim(`(${vars.length})`)}`);
1435
+ console.log("");
1436
+ for (const env of vars.slice(0, 30)) {
1437
+ const displayValue = env.value.length > 50 ? env.value.slice(0, 47) + "..." : env.value;
1438
+ console.log(` ${theme.primary(env.name.padEnd(20))} ${theme.dim("=")} ${displayValue}`);
1439
+ }
1440
+ if (vars.length > 30) {
1441
+ console.log("");
1442
+ console.log(` ${theme.dim(`... and ${vars.length - 30} more. Use /env search <query> to filter.`)}`);
1443
+ }
1444
+ console.log("");
1445
+ return;
1446
+ }
1447
+ if (action.toLowerCase() === "path") {
1448
+ const paths = getPathEntries();
1449
+ console.log(` ${symbols.sparkle} ${theme.gradient("PATH ENTRIES")} ${theme.dim(`(${paths.length})`)}`);
1450
+ console.log("");
1451
+ paths.forEach((p, i) => {
1452
+ console.log(` ${theme.dim(`${(i + 1).toString().padStart(2)}.`)} ${theme.primary(p)}`);
1453
+ });
1454
+ console.log("");
1455
+ return;
1456
+ }
1457
+ if (action.toLowerCase() === "search" && args2[1]) {
1458
+ const query = args2.slice(1).join(" ");
1459
+ const results = searchEnvVars(query);
1460
+ console.log(` ${symbols.sparkle} ${theme.gradient(`SEARCH: "${query}"`)} ${theme.dim(`(${results.length} matches)`)}`);
1461
+ console.log("");
1462
+ if (results.length === 0) {
1463
+ console.log(` ${theme.dim("No matches found")}`);
1464
+ } else {
1465
+ for (const env of results) {
1466
+ const displayValue = env.value.length > 50 ? env.value.slice(0, 47) + "..." : env.value;
1467
+ console.log(` ${theme.primary(env.name.padEnd(20))} ${theme.dim("=")} ${displayValue}`);
1468
+ }
1469
+ }
1470
+ console.log("");
1471
+ return;
1472
+ }
1473
+ const value = getEnvVar(action);
1474
+ if (value !== void 0) {
1475
+ console.log(` ${theme.primary(action)} ${theme.dim("=")}`);
1476
+ console.log("");
1477
+ if (value.includes(process.platform === "win32" ? ";" : ":") && value.length > 100) {
1478
+ const separator = process.platform === "win32" ? ";" : ":";
1479
+ const parts = value.split(separator);
1480
+ parts.forEach((p, i) => {
1481
+ console.log(` ${theme.dim(`${(i + 1).toString().padStart(2)}.`)} ${p}`);
1482
+ });
1483
+ } else {
1484
+ console.log(` ${theme.success(value)}`);
1485
+ }
1486
+ } else {
1487
+ console.log(` ${symbols.cross} ${theme.error(`Environment variable not found: ${action}`)}`);
1488
+ }
1489
+ console.log("");
1490
+ }
1491
+ });
1492
+
1493
+ // src/handlers/utilities/size.ts
1494
+ import { statSync, readdirSync, existsSync as existsSync3 } from "fs";
1495
+ import { join as join3, basename } from "path";
1496
+ function formatBytes2(bytes) {
1497
+ if (bytes === 0) return "0 B";
1498
+ const units = ["B", "KB", "MB", "GB", "TB"];
1499
+ const i = Math.floor(Math.log(bytes) / Math.log(1024));
1500
+ const size = bytes / Math.pow(1024, i);
1501
+ return `${size.toFixed(i > 0 ? 1 : 0)} ${units[i]}`;
1502
+ }
1503
+ function getSize(path) {
1504
+ if (!existsSync3(path)) return null;
1505
+ try {
1506
+ const stats = statSync(path);
1507
+ if (stats.isFile()) {
1508
+ return {
1509
+ path,
1510
+ name: basename(path),
1511
+ size: stats.size,
1512
+ isDirectory: false
1513
+ };
1514
+ }
1515
+ if (stats.isDirectory()) {
1516
+ return getDirSize(path);
1517
+ }
1518
+ return null;
1519
+ } catch {
1520
+ return null;
1521
+ }
1522
+ }
1523
+ function getDirSize(dirPath) {
1524
+ const children = [];
1525
+ let totalSize = 0;
1526
+ try {
1527
+ const entries = readdirSync(dirPath, { withFileTypes: true });
1528
+ for (const entry of entries) {
1529
+ const entryPath = join3(dirPath, entry.name);
1530
+ try {
1531
+ if (entry.isFile()) {
1532
+ const stats = statSync(entryPath);
1533
+ totalSize += stats.size;
1534
+ children.push({
1535
+ path: entryPath,
1536
+ name: entry.name,
1537
+ size: stats.size,
1538
+ isDirectory: false
1539
+ });
1540
+ } else if (entry.isDirectory()) {
1541
+ if (["node_modules", ".git", "dist", "build", ".next", "coverage"].includes(entry.name)) {
1542
+ const subSize = getQuickDirSize(entryPath);
1543
+ totalSize += subSize;
1544
+ children.push({
1545
+ path: entryPath,
1546
+ name: entry.name,
1547
+ size: subSize,
1548
+ isDirectory: true
1549
+ });
1550
+ } else {
1551
+ const subInfo = getDirSize(entryPath);
1552
+ totalSize += subInfo.size;
1553
+ children.push(subInfo);
1554
+ }
1555
+ }
1556
+ } catch {
1557
+ }
1558
+ }
1559
+ } catch {
1560
+ }
1561
+ children.sort((a, b3) => b3.size - a.size);
1562
+ return {
1563
+ path: dirPath,
1564
+ name: basename(dirPath),
1565
+ size: totalSize,
1566
+ isDirectory: true,
1567
+ children
1568
+ };
1569
+ }
1570
+ function getQuickDirSize(dirPath) {
1571
+ let totalSize = 0;
1572
+ try {
1573
+ const entries = readdirSync(dirPath, { withFileTypes: true });
1574
+ for (const entry of entries) {
1575
+ const entryPath = join3(dirPath, entry.name);
1576
+ try {
1577
+ if (entry.isFile()) {
1578
+ totalSize += statSync(entryPath).size;
1579
+ } else if (entry.isDirectory()) {
1580
+ totalSize += getQuickDirSize(entryPath);
1581
+ }
1582
+ } catch {
1583
+ }
1584
+ }
1585
+ } catch {
1586
+ }
1587
+ return totalSize;
1588
+ }
1589
+ function findLargestFiles(dirPath, count = 10) {
1590
+ const allFiles = [];
1591
+ function collectFiles(dir) {
1592
+ try {
1593
+ const entries = readdirSync(dir, { withFileTypes: true });
1594
+ for (const entry of entries) {
1595
+ const entryPath = join3(dir, entry.name);
1596
+ try {
1597
+ if (entry.isFile()) {
1598
+ const stats = statSync(entryPath);
1599
+ allFiles.push({
1600
+ path: entryPath,
1601
+ name: entry.name,
1602
+ size: stats.size,
1603
+ isDirectory: false
1604
+ });
1605
+ } else if (entry.isDirectory()) {
1606
+ if (!["node_modules", ".git"].includes(entry.name)) {
1607
+ collectFiles(entryPath);
1608
+ }
1609
+ }
1610
+ } catch {
1611
+ }
1612
+ }
1613
+ } catch {
1614
+ }
1615
+ }
1616
+ collectFiles(dirPath);
1617
+ allFiles.sort((a, b3) => b3.size - a.size);
1618
+ return allFiles.slice(0, count);
1619
+ }
1620
+
1621
+ // src/commands/utilities/size.ts
1622
+ import { resolve } from "path";
1623
+ registerCommand({
1624
+ name: "size",
1625
+ description: "Analyze file/folder sizes",
1626
+ usage: "/size [path] [--top N]",
1627
+ async execute(args2) {
1628
+ const targetPath = args2[0] || ".";
1629
+ const absPath = resolve(targetPath);
1630
+ const topIndex = args2.indexOf("--top");
1631
+ const showTop = topIndex !== -1 ? parseInt(args2[topIndex + 1]) || 10 : 0;
1632
+ console.log("");
1633
+ if (showTop > 0) {
1634
+ console.log(` ${symbols.sparkle} ${theme.gradient("LARGEST FILES")}`);
1635
+ console.log(` ${theme.dim(`in ${absPath}`)}`);
1636
+ console.log("");
1637
+ const largestFiles = findLargestFiles(absPath, showTop);
1638
+ if (largestFiles.length === 0) {
1639
+ console.log(` ${theme.dim("No files found")}`);
1640
+ } else {
1641
+ const maxSize = largestFiles[0].size;
1642
+ for (let i = 0; i < largestFiles.length; i++) {
1643
+ const file = largestFiles[i];
1644
+ const percent = file.size / maxSize * 100;
1645
+ const bar = progressBar(percent, 20);
1646
+ const relativePath = file.path.replace(absPath, ".").replace(/\\/g, "/");
1647
+ console.log(
1648
+ ` ${theme.dim(`${(i + 1).toString().padStart(2)}.`)} ${bar} ${theme.primary(formatBytes2(file.size).padStart(10))} ${relativePath}`
1649
+ );
1650
+ }
1651
+ }
1652
+ console.log("");
1653
+ return;
1654
+ }
1655
+ const info = getSize(absPath);
1656
+ if (!info) {
1657
+ console.log(` ${symbols.cross} ${theme.error(`Path not found: ${absPath}`)}`);
1658
+ console.log("");
1659
+ return;
1660
+ }
1661
+ console.log(` ${symbols.sparkle} ${theme.gradient("SIZE ANALYSIS")}`);
1662
+ console.log(` ${theme.dim(absPath)}`);
1663
+ console.log("");
1664
+ if (!info.isDirectory) {
1665
+ console.log(` ${theme.primary(info.name)}: ${theme.success(formatBytes2(info.size))}`);
1666
+ } else {
1667
+ console.log(` ${theme.secondary("Total:")} ${theme.success(formatBytes2(info.size))}`);
1668
+ console.log("");
1669
+ if (info.children && info.children.length > 0) {
1670
+ const maxSize = info.children[0].size;
1671
+ const displayCount = Math.min(15, info.children.length);
1672
+ for (let i = 0; i < displayCount; i++) {
1673
+ const child = info.children[i];
1674
+ const percent = child.size / maxSize * 100;
1675
+ const bar = progressBar(percent, 15);
1676
+ const icon = child.isDirectory ? symbols.folder : symbols.bullet;
1677
+ console.log(
1678
+ ` ${bar} ${theme.primary(formatBytes2(child.size).padStart(10))} ${icon} ${child.name}`
1679
+ );
1680
+ }
1681
+ if (info.children.length > displayCount) {
1682
+ console.log("");
1683
+ console.log(` ${theme.dim(`... and ${info.children.length - displayCount} more items`)}`);
1684
+ }
1685
+ } else {
1686
+ console.log(` ${theme.dim("Directory is empty")}`);
1687
+ }
1688
+ }
1689
+ console.log("");
1690
+ console.log(` ${theme.dim("Tip: /size . --top 10 shows largest files")}`);
1691
+ console.log("");
1692
+ }
1693
+ });
1694
+
1471
1695
  // src/commands/fun/joke.ts
1472
1696
  var fallbackJokes = [
1473
1697
  { setup: "Why do programmers prefer dark mode?", punchline: "Because light attracts bugs!" },
1474
1698
  { setup: "Why do Java developers wear glasses?", punchline: "Because they can't C#!" },
1475
1699
  { setup: "A SQL query walks into a bar, walks up to two tables and asks...", punchline: "Can I join you?" },
1476
1700
  { setup: "Why did the developer go broke?", punchline: "Because he used up all his cache!" },
1477
- { setup: "How many programmers does it take to change a light bulb?", punchline: "None, that's a hardware problem!" }
1701
+ { setup: "How many programmers does it take to change a light bulb?", punchline: "None, that's a hardware problem!" },
1702
+ { setup: "Why do programmers hate nature?", punchline: "It has too many bugs!" },
1703
+ { setup: "What's a programmer's favorite hangout place?", punchline: "Foo Bar!" },
1704
+ { setup: "Why was the JavaScript developer sad?", punchline: "Because he didn't Node how to Express himself!" },
1705
+ { setup: "What do you call a computer that sings?", punchline: "A-Dell!" },
1706
+ { setup: "Why did the developer quit his job?", punchline: "Because he didn't get arrays (a raise)!" }
1478
1707
  ];
1708
+ async function fetchJoke() {
1709
+ try {
1710
+ const response = await fetch("https://v2.jokeapi.dev/joke/Programming?type=twopart&safe-mode", {
1711
+ signal: AbortSignal.timeout(3e3)
1712
+ });
1713
+ if (response.ok) {
1714
+ const data = await response.json();
1715
+ if (!data.error && data.setup && data.delivery) {
1716
+ return { setup: data.setup, punchline: data.delivery };
1717
+ }
1718
+ }
1719
+ } catch {
1720
+ }
1721
+ try {
1722
+ const response = await fetch("https://official-joke-api.appspot.com/jokes/programming/random", {
1723
+ signal: AbortSignal.timeout(3e3)
1724
+ });
1725
+ if (response.ok) {
1726
+ const data = await response.json();
1727
+ if (data && data[0]) {
1728
+ return { setup: data[0].setup, punchline: data[0].punchline };
1729
+ }
1730
+ }
1731
+ } catch {
1732
+ }
1733
+ return fallbackJokes[Math.floor(Math.random() * fallbackJokes.length)];
1734
+ }
1479
1735
  registerCommand({
1480
1736
  name: "joke",
1481
- description: "Get a random joke",
1737
+ description: "Get a random programming joke",
1482
1738
  usage: "/joke",
1483
1739
  async execute(_args) {
1484
1740
  console.log("");
1485
1741
  console.log(` ${symbols.dice} ${theme.sunset("Getting a joke...")}`);
1486
- try {
1487
- const response = await fetch("https://official-joke-api.appspot.com/random_joke", {
1488
- signal: AbortSignal.timeout(3e3)
1489
- });
1490
- let joke;
1491
- if (!response.ok) {
1492
- joke = fallbackJokes[Math.floor(Math.random() * fallbackJokes.length)];
1493
- } else {
1494
- joke = await response.json();
1495
- }
1496
- process.stdout.write("\x1B[1A\x1B[2K");
1497
- console.log("");
1498
- console.log(bubble.say(joke.setup, 55));
1499
- console.log(` ${symbols.sparkle}`);
1500
- await new Promise((resolve3) => setTimeout(resolve3, 1500));
1501
- console.log("");
1502
- console.log(` ${theme.gold(" \u2726")} ${theme.b.success(joke.punchline)} ${theme.gold("\u2726")}`);
1503
- console.log("");
1504
- console.log(` ${theme.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}`);
1505
- console.log(` ${symbols.dice} ${theme.dim("Run /joke again for another!")}`);
1506
- console.log("");
1507
- } catch (error) {
1508
- process.stdout.write("\x1B[1A\x1B[2K");
1509
- const joke = fallbackJokes[Math.floor(Math.random() * fallbackJokes.length)];
1510
- console.log("");
1511
- console.log(bubble.say(joke.setup, 55));
1512
- console.log(` ${symbols.sparkle}`);
1513
- await new Promise((resolve3) => setTimeout(resolve3, 1500));
1514
- console.log("");
1515
- console.log(` ${theme.gold(" \u2726")} ${theme.b.success(joke.punchline)} ${theme.gold("\u2726")}`);
1516
- console.log("");
1517
- }
1742
+ const joke = await fetchJoke();
1743
+ process.stdout.write("\x1B[1A\x1B[2K");
1744
+ console.log("");
1745
+ console.log(bubble.say(joke.setup, 55));
1746
+ console.log(` ${symbols.sparkle}`);
1747
+ await new Promise((resolve5) => setTimeout(resolve5, 1500));
1748
+ console.log("");
1749
+ console.log(` ${theme.gold(" \u2726")} ${theme.b.success(joke.punchline)} ${theme.gold("\u2726")}`);
1750
+ console.log("");
1751
+ console.log(` ${theme.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}`);
1752
+ console.log(` ${symbols.dice} ${theme.dim("Run /joke again for another!")}`);
1753
+ console.log("");
1518
1754
  }
1519
1755
  });
1520
1756
 
1521
1757
  // src/commands/fun/quote.ts
1522
- var quotes = [
1758
+ var fallbackQuotes = [
1523
1759
  { text: "The only way to do great work is to love what you do.", author: "Steve Jobs" },
1524
1760
  { text: "Code is like humor. When you have to explain it, it's bad.", author: "Cory House" },
1525
1761
  { text: "First, solve the problem. Then, write the code.", author: "John Johnson" },
@@ -1536,6 +1772,33 @@ var quotes = [
1536
1772
  { text: "There are only two hard things in Computer Science: cache invalidation and naming things.", author: "Phil Karlton" },
1537
1773
  { text: "The best time to plant a tree was 20 years ago. The second best time is now.", author: "Chinese Proverb" }
1538
1774
  ];
1775
+ async function fetchQuote() {
1776
+ try {
1777
+ const response = await fetch("https://zenquotes.io/api/random", {
1778
+ signal: AbortSignal.timeout(3e3)
1779
+ });
1780
+ if (response.ok) {
1781
+ const data = await response.json();
1782
+ if (data && data[0]) {
1783
+ return { text: data[0].q, author: data[0].a };
1784
+ }
1785
+ }
1786
+ } catch {
1787
+ }
1788
+ try {
1789
+ const response = await fetch("https://api.quotable.io/random", {
1790
+ signal: AbortSignal.timeout(3e3)
1791
+ });
1792
+ if (response.ok) {
1793
+ const data = await response.json();
1794
+ if (data && data.content) {
1795
+ return { text: data.content, author: data.author };
1796
+ }
1797
+ }
1798
+ } catch {
1799
+ }
1800
+ return fallbackQuotes[Math.floor(Math.random() * fallbackQuotes.length)];
1801
+ }
1539
1802
  function wrapText(text, maxWidth) {
1540
1803
  const words = text.split(" ");
1541
1804
  const lines = [];
@@ -1556,7 +1819,10 @@ registerCommand({
1556
1819
  description: "Get an inspirational quote",
1557
1820
  usage: "/quote",
1558
1821
  async execute(_args) {
1559
- const quote = quotes[Math.floor(Math.random() * quotes.length)];
1822
+ console.log("");
1823
+ console.log(` ${symbols.sparkle} ${theme.dim("Fetching wisdom...")}`);
1824
+ const quote = await fetchQuote();
1825
+ process.stdout.write("\x1B[1A\x1B[2K\x1B[1A\x1B[2K");
1560
1826
  const wrapped = wrapText(quote.text, 55);
1561
1827
  console.log("");
1562
1828
  console.log(` ${theme.dim("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E")}`);
@@ -1928,7 +2194,10 @@ registerCommand({
1928
2194
  console.log(theme.dim(" Use /pomodoro status to check progress"));
1929
2195
  console.log(theme.dim(" Use /pomodoro skip to skip to break"));
1930
2196
  console.log("");
1931
- if (state.interval) clearTimeout(state.interval);
2197
+ if (state.interval) {
2198
+ clearTimeout(state.interval);
2199
+ state.interval = null;
2200
+ }
1932
2201
  state.interval = setTimeout(() => {
1933
2202
  if (state.running) {
1934
2203
  console.log("\n");
@@ -1937,6 +2206,7 @@ registerCommand({
1937
2206
  console.log("\n");
1938
2207
  state.sessions++;
1939
2208
  state.running = false;
2209
+ state.interval = null;
1940
2210
  }
1941
2211
  }, DURATIONS.work);
1942
2212
  return;
@@ -1946,7 +2216,10 @@ registerCommand({
1946
2216
  console.log(theme.dim(" Pomodoro is not running"));
1947
2217
  return;
1948
2218
  }
1949
- if (state.interval) clearTimeout(state.interval);
2219
+ if (state.interval) {
2220
+ clearTimeout(state.interval);
2221
+ state.interval = null;
2222
+ }
1950
2223
  state.running = false;
1951
2224
  console.log("");
1952
2225
  console.log(` ${symbols.cross} ${theme.secondary("Pomodoro stopped")}`);
@@ -1959,7 +2232,10 @@ registerCommand({
1959
2232
  console.log(theme.dim(" Pomodoro is not running"));
1960
2233
  return;
1961
2234
  }
1962
- if (state.interval) clearTimeout(state.interval);
2235
+ if (state.interval) {
2236
+ clearTimeout(state.interval);
2237
+ state.interval = null;
2238
+ }
1963
2239
  if (state.mode === "work") {
1964
2240
  state.sessions++;
1965
2241
  state.mode = state.sessions % 4 === 0 ? "longbreak" : "break";
@@ -1982,6 +2258,7 @@ registerCommand({
1982
2258
  ${symbols.bell} ${state.mode === "work" ? "Focus session" : "Break"} complete!
1983
2259
  `);
1984
2260
  state.running = false;
2261
+ state.interval = null;
1985
2262
  }
1986
2263
  }, state.endTime - Date.now());
1987
2264
  return;
@@ -2106,8 +2383,8 @@ registerCommand({
2106
2383
 
2107
2384
  // src/commands/creative/asciiart.ts
2108
2385
  import Jimp from "jimp";
2109
- import { existsSync as existsSync3 } from "fs";
2110
- import { resolve } from "path";
2386
+ import { existsSync as existsSync4 } from "fs";
2387
+ import { resolve as resolve2 } from "path";
2111
2388
  var CHAR_RAMPS = {
2112
2389
  // Standard - 10 levels, balanced
2113
2390
  standard: " .:-=+*#%@",
@@ -2212,8 +2489,8 @@ registerCommand({
2212
2489
  i++;
2213
2490
  }
2214
2491
  }
2215
- const fullPath = resolve(process.cwd(), imagePath);
2216
- if (!existsSync3(fullPath)) {
2492
+ const fullPath = resolve2(process.cwd(), imagePath);
2493
+ if (!existsSync4(fullPath)) {
2217
2494
  console.log(theme.error(`File not found: ${imagePath}`));
2218
2495
  return;
2219
2496
  }
@@ -2494,7 +2771,7 @@ registerCommand({
2494
2771
  });
2495
2772
 
2496
2773
  // src/commands/creative/color.ts
2497
- import chalk4 from "chalk";
2774
+ import chalk3 from "chalk";
2498
2775
 
2499
2776
  // src/handlers/creative/color.ts
2500
2777
  function hexToRgb(hex) {
@@ -2643,7 +2920,7 @@ registerCommand({
2643
2920
  console.log("");
2644
2921
  console.log(` ${symbols.palette} ${theme.gradient("COLOR CONVERTER")} ${symbols.palette}`);
2645
2922
  console.log("");
2646
- const colorBlock = chalk4.bgHex(hex).hex(textColor);
2923
+ const colorBlock = chalk3.bgHex(hex).hex(textColor);
2647
2924
  console.log(` ${colorBlock(" ")}`);
2648
2925
  console.log(` ${colorBlock(" ")}`);
2649
2926
  console.log(` ${colorBlock(` ${hex.toUpperCase()} `.slice(0, 40))}`);
@@ -2658,14 +2935,14 @@ registerCommand({
2658
2935
  let shadesLine = " ";
2659
2936
  const shades = generateShades(rgb);
2660
2937
  for (const shade of shades) {
2661
- shadesLine += chalk4.bgRgb(shade.r, shade.g, shade.b)(" ");
2938
+ shadesLine += chalk3.bgRgb(shade.r, shade.g, shade.b)(" ");
2662
2939
  }
2663
2940
  console.log(shadesLine);
2664
2941
  console.log(` ${theme.dim("Tints:")}`);
2665
2942
  let tintsLine = " ";
2666
2943
  const tints = generateTints(rgb);
2667
2944
  for (const tint of tints) {
2668
- tintsLine += chalk4.bgRgb(tint.r, tint.g, tint.b)(" ");
2945
+ tintsLine += chalk3.bgRgb(tint.r, tint.g, tint.b)(" ");
2669
2946
  }
2670
2947
  console.log(tintsLine);
2671
2948
  console.log("");
@@ -2772,8 +3049,18 @@ var SUPPORTED_METHODS = ["base64", "url", "hex"];
2772
3049
  function isValidMethod(method) {
2773
3050
  return SUPPORTED_METHODS.includes(method.toLowerCase());
2774
3051
  }
3052
+ function isValidBase64(str) {
3053
+ if (!str || str.length === 0) return false;
3054
+ const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
3055
+ return base64Regex.test(str) && str.length % 4 === 0;
3056
+ }
3057
+ function isValidHex(str) {
3058
+ if (!str || str.length === 0) return false;
3059
+ return str.length % 2 === 0 && /^[0-9A-Fa-f]+$/.test(str);
3060
+ }
2775
3061
  function encodeText(text, method, direction) {
2776
3062
  let output;
3063
+ let error;
2777
3064
  if (direction === "encode") {
2778
3065
  switch (method) {
2779
3066
  case "base64":
@@ -2789,21 +3076,47 @@ function encodeText(text, method, direction) {
2789
3076
  } else {
2790
3077
  switch (method) {
2791
3078
  case "base64":
2792
- output = Buffer.from(text, "base64").toString("utf-8");
3079
+ try {
3080
+ if (!isValidBase64(text)) {
3081
+ output = "";
3082
+ error = "Invalid base64 input";
3083
+ } else {
3084
+ output = Buffer.from(text, "base64").toString("utf-8");
3085
+ }
3086
+ } catch (e) {
3087
+ output = "";
3088
+ error = "Failed to decode base64: invalid input";
3089
+ }
2793
3090
  break;
2794
3091
  case "url":
2795
- output = decodeURIComponent(text);
3092
+ try {
3093
+ output = decodeURIComponent(text);
3094
+ } catch (e) {
3095
+ output = "";
3096
+ error = "Failed to decode URL: malformed URI sequence";
3097
+ }
2796
3098
  break;
2797
3099
  case "hex":
2798
- output = Buffer.from(text, "hex").toString("utf-8");
2799
- break;
2800
- }
2801
- }
3100
+ try {
3101
+ if (!isValidHex(text)) {
3102
+ output = "";
3103
+ error = "Invalid hex input: must be even length and contain only 0-9, A-F";
3104
+ } else {
3105
+ output = Buffer.from(text, "hex").toString("utf-8");
3106
+ }
3107
+ } catch (e) {
3108
+ output = "";
3109
+ error = "Failed to decode hex: invalid input";
3110
+ }
3111
+ break;
3112
+ }
3113
+ }
2802
3114
  return {
2803
3115
  method: method.toUpperCase(),
2804
3116
  direction,
2805
3117
  input: text,
2806
- output
3118
+ output,
3119
+ ...error && { error }
2807
3120
  };
2808
3121
  }
2809
3122
 
@@ -2865,6 +3178,565 @@ registerCommand({
2865
3178
  }
2866
3179
  });
2867
3180
 
3181
+ // src/handlers/dev/json.ts
3182
+ function validateJson(input) {
3183
+ try {
3184
+ const data = JSON.parse(input);
3185
+ return { valid: true, data };
3186
+ } catch (error) {
3187
+ const message = error instanceof Error ? error.message : "Invalid JSON";
3188
+ return { valid: false, error: message };
3189
+ }
3190
+ }
3191
+ function formatJson(input, indent = 2) {
3192
+ try {
3193
+ const data = JSON.parse(input);
3194
+ const formatted = JSON.stringify(data, null, indent);
3195
+ return { valid: true, data, formatted };
3196
+ } catch (error) {
3197
+ const message = error instanceof Error ? error.message : "Invalid JSON";
3198
+ return { valid: false, error: message };
3199
+ }
3200
+ }
3201
+ function minifyJson(input) {
3202
+ try {
3203
+ const data = JSON.parse(input);
3204
+ const formatted = JSON.stringify(data);
3205
+ return { valid: true, data, formatted };
3206
+ } catch (error) {
3207
+ const message = error instanceof Error ? error.message : "Invalid JSON";
3208
+ return { valid: false, error: message };
3209
+ }
3210
+ }
3211
+ function queryJson(input, path) {
3212
+ try {
3213
+ const data = JSON.parse(input);
3214
+ const parts = path.replace(/^\$\.?/, "").split(".").filter(Boolean);
3215
+ let current = data;
3216
+ for (const part of parts) {
3217
+ const arrayMatch = part.match(/^(\w*)\[(\d+)\]$/);
3218
+ if (arrayMatch) {
3219
+ const [, key, index] = arrayMatch;
3220
+ if (key) {
3221
+ current = current[key];
3222
+ }
3223
+ if (Array.isArray(current)) {
3224
+ current = current[parseInt(index)];
3225
+ } else {
3226
+ return { valid: false, error: `Not an array at ${part}` };
3227
+ }
3228
+ } else {
3229
+ if (current && typeof current === "object") {
3230
+ current = current[part];
3231
+ } else {
3232
+ return { valid: false, error: `Cannot access ${part}` };
3233
+ }
3234
+ }
3235
+ }
3236
+ return { valid: true, data: current, formatted: JSON.stringify(current, null, 2) };
3237
+ } catch (error) {
3238
+ const message = error instanceof Error ? error.message : "Invalid JSON";
3239
+ return { valid: false, error: message };
3240
+ }
3241
+ }
3242
+ function getJsonStats(input) {
3243
+ try {
3244
+ let countKeys2 = function(obj, depth = 0) {
3245
+ if (typeof obj !== "object" || obj === null) {
3246
+ return { keys: 0, maxDepth: depth };
3247
+ }
3248
+ let keys = 0;
3249
+ let maxDepth = depth;
3250
+ if (Array.isArray(obj)) {
3251
+ for (const item of obj) {
3252
+ const result = countKeys2(item, depth + 1);
3253
+ keys += result.keys;
3254
+ maxDepth = Math.max(maxDepth, result.maxDepth);
3255
+ }
3256
+ } else {
3257
+ keys = Object.keys(obj).length;
3258
+ for (const value of Object.values(obj)) {
3259
+ const result = countKeys2(value, depth + 1);
3260
+ keys += result.keys;
3261
+ maxDepth = Math.max(maxDepth, result.maxDepth);
3262
+ }
3263
+ }
3264
+ return { keys, maxDepth };
3265
+ };
3266
+ var countKeys = countKeys2;
3267
+ const data = JSON.parse(input);
3268
+ const stats = countKeys2(data);
3269
+ const size = new Blob([input]).size;
3270
+ const sizeStr = size < 1024 ? `${size}B` : size < 1024 * 1024 ? `${(size / 1024).toFixed(1)}KB` : `${(size / 1024 / 1024).toFixed(1)}MB`;
3271
+ return { keys: stats.keys, depth: stats.maxDepth, size: sizeStr };
3272
+ } catch {
3273
+ return null;
3274
+ }
3275
+ }
3276
+
3277
+ // src/commands/dev/json.ts
3278
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
3279
+ registerCommand({
3280
+ name: "json",
3281
+ description: "JSON tools (validate, format, query)",
3282
+ usage: "/json <action> <input>\n\n Actions: validate, format, minify, query, stats",
3283
+ async execute(args2) {
3284
+ const action = args2[0]?.toLowerCase();
3285
+ const input = args2.slice(1).join(" ");
3286
+ if (!action) {
3287
+ console.log("");
3288
+ console.log(` ${symbols.sparkle} ${theme.gradient("JSON TOOLS")}`);
3289
+ console.log("");
3290
+ console.log(` ${theme.dim("Usage:")} /json <action> <input>`);
3291
+ console.log("");
3292
+ console.log(` ${theme.dim("Actions:")}`);
3293
+ console.log(` ${theme.primary("validate")} <json|@file> ${theme.dim("Check if JSON is valid")}`);
3294
+ console.log(` ${theme.primary("format")} <json|@file> ${theme.dim("Pretty-print JSON")}`);
3295
+ console.log(` ${theme.primary("minify")} <json|@file> ${theme.dim("Minify JSON")}`);
3296
+ console.log(` ${theme.primary("query")} <path> <json> ${theme.dim("Query with path (e.g., users[0].name)")}`);
3297
+ console.log(` ${theme.primary("stats")} <json|@file> ${theme.dim("Show JSON statistics")}`);
3298
+ console.log("");
3299
+ console.log(` ${theme.dim("Use @filename to read from file")}`);
3300
+ console.log("");
3301
+ return;
3302
+ }
3303
+ let jsonContent = input;
3304
+ if (input.startsWith("@")) {
3305
+ const filePath = input.slice(1);
3306
+ if (!existsSync5(filePath)) {
3307
+ console.log("");
3308
+ console.log(` ${symbols.cross} ${theme.error(`File not found: ${filePath}`)}`);
3309
+ console.log("");
3310
+ return;
3311
+ }
3312
+ jsonContent = readFileSync3(filePath, "utf-8");
3313
+ }
3314
+ console.log("");
3315
+ switch (action) {
3316
+ case "validate": {
3317
+ if (!jsonContent) {
3318
+ console.log(` ${symbols.warning} ${theme.warning("Usage:")} /json validate <json|@file>`);
3319
+ break;
3320
+ }
3321
+ const result = validateJson(jsonContent);
3322
+ if (result.valid) {
3323
+ console.log(` ${symbols.check} ${theme.success("Valid JSON")}`);
3324
+ } else {
3325
+ console.log(` ${symbols.cross} ${theme.error("Invalid JSON")}`);
3326
+ console.log(` ${theme.dim(result.error || "")}`);
3327
+ }
3328
+ break;
3329
+ }
3330
+ case "format":
3331
+ case "pretty": {
3332
+ if (!jsonContent) {
3333
+ console.log(` ${symbols.warning} ${theme.warning("Usage:")} /json format <json|@file>`);
3334
+ break;
3335
+ }
3336
+ const result = formatJson(jsonContent);
3337
+ if (result.valid && result.formatted) {
3338
+ console.log(` ${symbols.check} ${theme.success("Formatted JSON:")}`);
3339
+ console.log("");
3340
+ for (const line of result.formatted.split("\n")) {
3341
+ console.log(` ${theme.primary(line)}`);
3342
+ }
3343
+ } else {
3344
+ console.log(` ${symbols.cross} ${theme.error("Invalid JSON")}`);
3345
+ console.log(` ${theme.dim(result.error || "")}`);
3346
+ }
3347
+ break;
3348
+ }
3349
+ case "minify":
3350
+ case "min": {
3351
+ if (!jsonContent) {
3352
+ console.log(` ${symbols.warning} ${theme.warning("Usage:")} /json minify <json|@file>`);
3353
+ break;
3354
+ }
3355
+ const result = minifyJson(jsonContent);
3356
+ if (result.valid && result.formatted) {
3357
+ console.log(` ${symbols.check} ${theme.success("Minified:")}`);
3358
+ console.log("");
3359
+ console.log(` ${theme.primary(result.formatted)}`);
3360
+ } else {
3361
+ console.log(` ${symbols.cross} ${theme.error("Invalid JSON")}`);
3362
+ console.log(` ${theme.dim(result.error || "")}`);
3363
+ }
3364
+ break;
3365
+ }
3366
+ case "query":
3367
+ case "get": {
3368
+ const path = args2[1];
3369
+ const queryInput = args2.slice(2).join(" ");
3370
+ if (!path || !queryInput) {
3371
+ console.log(` ${symbols.warning} ${theme.warning("Usage:")} /json query <path> <json|@file>`);
3372
+ console.log("");
3373
+ console.log(` ${theme.dim("Examples:")}`);
3374
+ console.log(` /json query name '{"name": "John"}'`);
3375
+ console.log(` /json query users[0].email @data.json`);
3376
+ break;
3377
+ }
3378
+ let queryJsonContent = queryInput;
3379
+ if (queryInput.startsWith("@")) {
3380
+ const filePath = queryInput.slice(1);
3381
+ if (!existsSync5(filePath)) {
3382
+ console.log(` ${symbols.cross} ${theme.error(`File not found: ${filePath}`)}`);
3383
+ break;
3384
+ }
3385
+ queryJsonContent = readFileSync3(filePath, "utf-8");
3386
+ }
3387
+ const result = queryJson(queryJsonContent, path);
3388
+ if (result.valid) {
3389
+ console.log(` ${symbols.check} ${theme.success(`Result for "${path}":`)} `);
3390
+ console.log("");
3391
+ if (result.formatted) {
3392
+ for (const line of result.formatted.split("\n")) {
3393
+ console.log(` ${theme.primary(line)}`);
3394
+ }
3395
+ } else {
3396
+ console.log(` ${theme.dim("undefined")}`);
3397
+ }
3398
+ } else {
3399
+ console.log(` ${symbols.cross} ${theme.error(result.error || "Query failed")}`);
3400
+ }
3401
+ break;
3402
+ }
3403
+ case "stats":
3404
+ case "info": {
3405
+ if (!jsonContent) {
3406
+ console.log(` ${symbols.warning} ${theme.warning("Usage:")} /json stats <json|@file>`);
3407
+ break;
3408
+ }
3409
+ const stats = getJsonStats(jsonContent);
3410
+ if (stats) {
3411
+ console.log(` ${symbols.sparkle} ${theme.gradient("JSON STATS")}`);
3412
+ console.log("");
3413
+ console.log(` ${theme.dim("Total keys:")} ${theme.primary(stats.keys.toString())}`);
3414
+ console.log(` ${theme.dim("Max depth:")} ${theme.primary(stats.depth.toString())}`);
3415
+ console.log(` ${theme.dim("Size:")} ${theme.primary(stats.size)}`);
3416
+ } else {
3417
+ console.log(` ${symbols.cross} ${theme.error("Invalid JSON")}`);
3418
+ }
3419
+ break;
3420
+ }
3421
+ default:
3422
+ console.log(` ${symbols.cross} ${theme.error(`Unknown action: ${action}`)}`);
3423
+ console.log(` ${theme.dim("Run /json to see available actions")}`);
3424
+ }
3425
+ console.log("");
3426
+ }
3427
+ });
3428
+
3429
+ // src/handlers/dev/request.ts
3430
+ import https from "https";
3431
+ import http from "http";
3432
+ import { URL } from "url";
3433
+ async function makeRequest(urlStr, options = { method: "GET" }) {
3434
+ const startTime2 = Date.now();
3435
+ return new Promise((resolve5) => {
3436
+ const timeout = setTimeout(() => {
3437
+ resolve5({ success: false, error: "Request timed out" });
3438
+ }, options.timeout || 3e4);
3439
+ try {
3440
+ const url = new URL(urlStr.startsWith("http") ? urlStr : `https://${urlStr}`);
3441
+ const client = url.protocol === "https:" ? https : http;
3442
+ const reqOptions = {
3443
+ hostname: url.hostname,
3444
+ port: url.port || (url.protocol === "https:" ? 443 : 80),
3445
+ path: url.pathname + url.search,
3446
+ method: options.method.toUpperCase(),
3447
+ headers: {
3448
+ "User-Agent": "Zammy-CLI/1.0",
3449
+ ...options.headers
3450
+ }
3451
+ };
3452
+ const req = client.request(reqOptions, (res) => {
3453
+ let body = "";
3454
+ res.on("data", (chunk) => {
3455
+ body += chunk.toString();
3456
+ });
3457
+ res.on("end", () => {
3458
+ clearTimeout(timeout);
3459
+ resolve5({
3460
+ success: true,
3461
+ statusCode: res.statusCode,
3462
+ statusMessage: res.statusMessage,
3463
+ headers: res.headers,
3464
+ body,
3465
+ time: Date.now() - startTime2
3466
+ });
3467
+ });
3468
+ });
3469
+ req.on("error", (error) => {
3470
+ clearTimeout(timeout);
3471
+ resolve5({ success: false, error: error.message });
3472
+ });
3473
+ if (options.body) {
3474
+ req.write(options.body);
3475
+ }
3476
+ req.end();
3477
+ } catch (error) {
3478
+ clearTimeout(timeout);
3479
+ resolve5({ success: false, error: error instanceof Error ? error.message : "Request failed" });
3480
+ }
3481
+ });
3482
+ }
3483
+ function tryParseJson(body) {
3484
+ try {
3485
+ const parsed = JSON.parse(body);
3486
+ return { isJson: true, formatted: JSON.stringify(parsed, null, 2) };
3487
+ } catch {
3488
+ return { isJson: false };
3489
+ }
3490
+ }
3491
+
3492
+ // src/commands/dev/request.ts
3493
+ registerCommand({
3494
+ name: "request",
3495
+ description: "Make HTTP requests",
3496
+ usage: "/request <method> <url> [options]",
3497
+ async execute(args2) {
3498
+ if (args2.length < 1) {
3499
+ console.log("");
3500
+ console.log(` ${symbols.sparkle} ${theme.gradient("HTTP REQUEST")}`);
3501
+ console.log("");
3502
+ console.log(` ${theme.dim("Usage:")} /request <method> <url> [options]`);
3503
+ console.log("");
3504
+ console.log(` ${theme.dim("Methods:")} GET, POST, PUT, DELETE, PATCH, HEAD`);
3505
+ console.log("");
3506
+ console.log(` ${theme.dim("Examples:")}`);
3507
+ console.log(` /request GET https://api.github.com`);
3508
+ console.log(` /request POST https://httpbin.org/post --body '{"name":"test"}'`);
3509
+ console.log(` /request GET api.example.com/users`);
3510
+ console.log("");
3511
+ return;
3512
+ }
3513
+ let method = "GET";
3514
+ let url = args2[0];
3515
+ const methods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"];
3516
+ if (methods.includes(args2[0].toUpperCase())) {
3517
+ method = args2[0].toUpperCase();
3518
+ url = args2[1];
3519
+ }
3520
+ if (!url) {
3521
+ console.log("");
3522
+ console.log(` ${symbols.cross} ${theme.error("URL is required")}`);
3523
+ console.log("");
3524
+ return;
3525
+ }
3526
+ const headers = {};
3527
+ let body;
3528
+ for (let i = 2; i < args2.length; i++) {
3529
+ if (args2[i] === "--header" || args2[i] === "-H") {
3530
+ const header = args2[++i];
3531
+ if (header) {
3532
+ const [key, ...valueParts] = header.split(":");
3533
+ headers[key.trim()] = valueParts.join(":").trim();
3534
+ }
3535
+ } else if (args2[i] === "--body" || args2[i] === "-d") {
3536
+ body = args2[++i];
3537
+ }
3538
+ }
3539
+ console.log("");
3540
+ console.log(` ${theme.dim(`${method} ${url}...`)}`);
3541
+ const result = await makeRequest(url, { method, headers, body });
3542
+ process.stdout.write("\x1B[1A\x1B[2K");
3543
+ if (!result.success) {
3544
+ console.log(` ${symbols.cross} ${theme.error(result.error || "Request failed")}`);
3545
+ console.log("");
3546
+ return;
3547
+ }
3548
+ const statusColor = result.statusCode && result.statusCode >= 200 && result.statusCode < 300 ? theme.success : result.statusCode && result.statusCode >= 400 ? theme.error : theme.warning;
3549
+ console.log(` ${statusColor(`${result.statusCode} ${result.statusMessage}`)} ${theme.dim(`(${result.time}ms)`)}`);
3550
+ console.log("");
3551
+ if (result.headers) {
3552
+ const importantHeaders = ["content-type", "content-length", "server", "date"];
3553
+ console.log(` ${theme.dim("Headers:")}`);
3554
+ for (const key of importantHeaders) {
3555
+ if (result.headers[key]) {
3556
+ console.log(` ${theme.secondary(key)}: ${result.headers[key]}`);
3557
+ }
3558
+ }
3559
+ console.log("");
3560
+ }
3561
+ if (result.body && method !== "HEAD") {
3562
+ console.log(` ${theme.dim("Body:")}`);
3563
+ const jsonResult = tryParseJson(result.body);
3564
+ if (jsonResult.isJson && jsonResult.formatted) {
3565
+ const lines = jsonResult.formatted.split("\n");
3566
+ const displayLines = lines.slice(0, 30);
3567
+ for (const line of displayLines) {
3568
+ console.log(` ${theme.primary(line)}`);
3569
+ }
3570
+ if (lines.length > 30) {
3571
+ console.log(` ${theme.dim(`... and ${lines.length - 30} more lines`)}`);
3572
+ }
3573
+ } else {
3574
+ const lines = result.body.split("\n").slice(0, 20);
3575
+ for (const line of lines) {
3576
+ console.log(` ${line.slice(0, 100)}`);
3577
+ }
3578
+ if (result.body.split("\n").length > 20) {
3579
+ console.log(` ${theme.dim("... (truncated)")}`);
3580
+ }
3581
+ }
3582
+ }
3583
+ console.log("");
3584
+ }
3585
+ });
3586
+
3587
+ // src/handlers/dev/diff.ts
3588
+ import { readFileSync as readFileSync4, existsSync as existsSync6 } from "fs";
3589
+ function diffFiles(file1, file2) {
3590
+ if (!existsSync6(file1)) {
3591
+ return { success: false, lines: [], stats: { additions: 0, deletions: 0, unchanged: 0 }, error: `File not found: ${file1}` };
3592
+ }
3593
+ if (!existsSync6(file2)) {
3594
+ return { success: false, lines: [], stats: { additions: 0, deletions: 0, unchanged: 0 }, error: `File not found: ${file2}` };
3595
+ }
3596
+ try {
3597
+ const content1 = readFileSync4(file1, "utf-8");
3598
+ const content2 = readFileSync4(file2, "utf-8");
3599
+ return diffStrings(content1, content2);
3600
+ } catch (error) {
3601
+ return {
3602
+ success: false,
3603
+ lines: [],
3604
+ stats: { additions: 0, deletions: 0, unchanged: 0 },
3605
+ error: error instanceof Error ? error.message : "Failed to read files"
3606
+ };
3607
+ }
3608
+ }
3609
+ function diffStrings(str1, str2) {
3610
+ const lines1 = str1.split("\n");
3611
+ const lines2 = str2.split("\n");
3612
+ const lcs = computeLCS(lines1, lines2);
3613
+ const diff = buildDiff(lines1, lines2, lcs);
3614
+ let additions = 0;
3615
+ let deletions = 0;
3616
+ let unchanged = 0;
3617
+ for (const line of diff) {
3618
+ if (line.type === "add") additions++;
3619
+ else if (line.type === "remove") deletions++;
3620
+ else if (line.type === "same") unchanged++;
3621
+ }
3622
+ return {
3623
+ success: true,
3624
+ lines: diff,
3625
+ stats: { additions, deletions, unchanged }
3626
+ };
3627
+ }
3628
+ function computeLCS(lines1, lines2) {
3629
+ const m = lines1.length;
3630
+ const n = lines2.length;
3631
+ const dp = Array(m + 1).fill(null).map(() => Array(n + 1).fill(0));
3632
+ for (let i = 1; i <= m; i++) {
3633
+ for (let j = 1; j <= n; j++) {
3634
+ if (lines1[i - 1] === lines2[j - 1]) {
3635
+ dp[i][j] = dp[i - 1][j - 1] + 1;
3636
+ } else {
3637
+ dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
3638
+ }
3639
+ }
3640
+ }
3641
+ return dp;
3642
+ }
3643
+ function buildDiff(lines1, lines2, lcs) {
3644
+ const result = [];
3645
+ let i = lines1.length;
3646
+ let j = lines2.length;
3647
+ const temp = [];
3648
+ while (i > 0 || j > 0) {
3649
+ if (i > 0 && j > 0 && lines1[i - 1] === lines2[j - 1]) {
3650
+ temp.push({ type: "same", content: lines1[i - 1], lineNum1: i, lineNum2: j });
3651
+ i--;
3652
+ j--;
3653
+ } else if (j > 0 && (i === 0 || lcs[i][j - 1] >= lcs[i - 1][j])) {
3654
+ temp.push({ type: "add", content: lines2[j - 1], lineNum2: j });
3655
+ j--;
3656
+ } else if (i > 0) {
3657
+ temp.push({ type: "remove", content: lines1[i - 1], lineNum1: i });
3658
+ i--;
3659
+ }
3660
+ }
3661
+ return temp.reverse();
3662
+ }
3663
+ function formatDiffStats(stats) {
3664
+ const parts = [];
3665
+ if (stats.additions > 0) parts.push(`+${stats.additions}`);
3666
+ if (stats.deletions > 0) parts.push(`-${stats.deletions}`);
3667
+ if (stats.unchanged > 0) parts.push(`=${stats.unchanged}`);
3668
+ return parts.join(", ");
3669
+ }
3670
+
3671
+ // src/commands/dev/diff.ts
3672
+ import { basename as basename2 } from "path";
3673
+ registerCommand({
3674
+ name: "diff",
3675
+ description: "Compare two files",
3676
+ usage: "/diff <file1> <file2>",
3677
+ async execute(args2) {
3678
+ if (args2.length < 2) {
3679
+ console.log("");
3680
+ console.log(` ${symbols.sparkle} ${theme.gradient("FILE DIFF")}`);
3681
+ console.log("");
3682
+ console.log(` ${theme.dim("Usage:")} /diff <file1> <file2>`);
3683
+ console.log("");
3684
+ console.log(` ${theme.dim("Example:")}`);
3685
+ console.log(` /diff old.json new.json`);
3686
+ console.log(` /diff config.ts config.backup.ts`);
3687
+ console.log("");
3688
+ return;
3689
+ }
3690
+ const file1 = args2[0];
3691
+ const file2 = args2[1];
3692
+ console.log("");
3693
+ const result = diffFiles(file1, file2);
3694
+ if (!result.success) {
3695
+ console.log(` ${symbols.cross} ${theme.error(result.error || "Diff failed")}`);
3696
+ console.log("");
3697
+ return;
3698
+ }
3699
+ console.log(` ${symbols.sparkle} ${theme.gradient("DIFF")}: ${theme.primary(basename2(file1))} ${theme.dim("\u2192")} ${theme.primary(basename2(file2))}`);
3700
+ console.log(` ${theme.dim(formatDiffStats(result.stats))}`);
3701
+ console.log("");
3702
+ if (result.stats.additions === 0 && result.stats.deletions === 0) {
3703
+ console.log(` ${symbols.check} ${theme.success("Files are identical")}`);
3704
+ console.log("");
3705
+ return;
3706
+ }
3707
+ let contextLines = 3;
3708
+ let lastShownIndex = -contextLines - 1;
3709
+ const linesToShow = [];
3710
+ result.lines.forEach((line, i) => {
3711
+ if (line.type !== "same") {
3712
+ for (let j = Math.max(0, i - contextLines); j <= Math.min(result.lines.length - 1, i + contextLines); j++) {
3713
+ if (!linesToShow.includes(j)) {
3714
+ linesToShow.push(j);
3715
+ }
3716
+ }
3717
+ }
3718
+ });
3719
+ linesToShow.sort((a, b3) => a - b3);
3720
+ for (let i = 0; i < linesToShow.length; i++) {
3721
+ const lineIndex = linesToShow[i];
3722
+ const line = result.lines[lineIndex];
3723
+ if (i > 0 && linesToShow[i] - linesToShow[i - 1] > 1) {
3724
+ console.log(` ${theme.dim("...")}`);
3725
+ }
3726
+ const lineNum = line.lineNum1 || line.lineNum2 || "";
3727
+ const numStr = lineNum.toString().padStart(4);
3728
+ if (line.type === "add") {
3729
+ console.log(` ${theme.success("+")} ${theme.dim(numStr)} ${theme.success(line.content)}`);
3730
+ } else if (line.type === "remove") {
3731
+ console.log(` ${theme.error("-")} ${theme.dim(numStr)} ${theme.error(line.content)}`);
3732
+ } else {
3733
+ console.log(` ${theme.dim(" ")} ${theme.dim(numStr)} ${line.content}`);
3734
+ }
3735
+ }
3736
+ console.log("");
3737
+ }
3738
+ });
3739
+
2868
3740
  // src/commands/info/weather.ts
2869
3741
  registerCommand({
2870
3742
  name: "weather",
@@ -2903,12 +3775,536 @@ registerCommand({
2903
3775
  }
2904
3776
  });
2905
3777
 
3778
+ // src/commands/plugin/list.ts
3779
+ async function listPlugins() {
3780
+ await discoverPlugins();
3781
+ const plugins = getDiscoveredPlugins();
3782
+ console.log("");
3783
+ if (plugins.length === 0) {
3784
+ console.log(` ${symbols.info} ${theme.dim("No plugins installed")}`);
3785
+ console.log("");
3786
+ console.log(` ${theme.dim("Install a plugin with:")} ${theme.primary("/plugin install <source>")}`);
3787
+ console.log(` ${theme.dim("Create a new plugin with:")} ${theme.primary("/plugin create")}`);
3788
+ console.log("");
3789
+ return;
3790
+ }
3791
+ console.log(` ${symbols.folder} ${theme.gradient("INSTALLED PLUGINS")} ${theme.dim(`(${plugins.length})`)}`);
3792
+ console.log("");
3793
+ for (const plugin of plugins) {
3794
+ const loaded = isPluginLoaded(plugin.name);
3795
+ const status = loaded ? theme.success("active") : theme.dim("idle");
3796
+ const statusIcon = loaded ? symbols.check : symbols.bullet;
3797
+ console.log(` ${statusIcon} ${theme.primary(plugin.displayName || plugin.name)} ${theme.dim(`v${plugin.version}`)}`);
3798
+ if (plugin.description) {
3799
+ console.log(` ${theme.dim(plugin.description)}`);
3800
+ }
3801
+ console.log(` ${theme.dim("Commands:")} ${plugin.commands.map((c) => theme.accent("/" + c)).join(", ")}`);
3802
+ if (plugin.permissions) {
3803
+ const perms = [];
3804
+ if (plugin.permissions.shell) perms.push("shell");
3805
+ if (plugin.permissions.filesystem) perms.push("fs");
3806
+ if (plugin.permissions.network) perms.push("net");
3807
+ if (perms.length > 0) {
3808
+ console.log(` ${theme.dim("Permissions:")} ${theme.warning(perms.join(", "))}`);
3809
+ }
3810
+ }
3811
+ console.log("");
3812
+ }
3813
+ }
3814
+
3815
+ // src/ui/input.ts
3816
+ async function confirm(message, defaultNo = true, options = {}) {
3817
+ const stdin = options.stdin || process.stdin;
3818
+ const stdout = options.stdout || process.stdout;
3819
+ const suffix = defaultNo ? "[y/N]" : "[Y/n]";
3820
+ stdout.write(`${message} ${theme.dim(suffix)} `);
3821
+ return new Promise((resolve5) => {
3822
+ const isTTY2 = "isTTY" in stdin && stdin.isTTY;
3823
+ const wasRaw = "isRaw" in stdin ? stdin.isRaw : false;
3824
+ if (isTTY2 && stdin.setRawMode) {
3825
+ stdin.setRawMode(true);
3826
+ }
3827
+ stdin.resume();
3828
+ const onData = (data) => {
3829
+ const char = data.toString()[0]?.toLowerCase() || "";
3830
+ if (isTTY2 && stdin.setRawMode) {
3831
+ stdin.setRawMode(wasRaw || false);
3832
+ }
3833
+ stdin.removeListener("data", onData);
3834
+ stdin.pause();
3835
+ if (char === "y") {
3836
+ stdout.write("y\n");
3837
+ resolve5(true);
3838
+ } else if (char === "n") {
3839
+ stdout.write("n\n");
3840
+ resolve5(false);
3841
+ } else if (char === "\r" || char === "\n") {
3842
+ stdout.write(defaultNo ? "n\n" : "y\n");
3843
+ resolve5(!defaultNo);
3844
+ } else if (char === "") {
3845
+ stdout.write("\n");
3846
+ resolve5(false);
3847
+ } else {
3848
+ stdout.write("\n");
3849
+ resolve5(false);
3850
+ }
3851
+ };
3852
+ stdin.once("data", onData);
3853
+ });
3854
+ }
3855
+ async function prompt(message, defaultValue, options = {}) {
3856
+ const stdin = options.stdin || process.stdin;
3857
+ const stdout = options.stdout || process.stdout;
3858
+ const suffix = defaultValue ? ` ${theme.dim(`(${defaultValue})`)}` : "";
3859
+ stdout.write(` ${message}${suffix}: `);
3860
+ return new Promise((resolve5) => {
3861
+ let input = "";
3862
+ const isTTY2 = "isTTY" in stdin && stdin.isTTY;
3863
+ const wasRaw = "isRaw" in stdin ? stdin.isRaw : false;
3864
+ if (isTTY2 && stdin.setRawMode) {
3865
+ stdin.setRawMode(true);
3866
+ }
3867
+ stdin.resume();
3868
+ const onData = (data) => {
3869
+ const chars = data.toString();
3870
+ for (const char of chars) {
3871
+ if (char === "\r" || char === "\n") {
3872
+ if (isTTY2 && stdin.setRawMode) {
3873
+ stdin.setRawMode(wasRaw || false);
3874
+ }
3875
+ stdin.removeListener("data", onData);
3876
+ stdin.pause();
3877
+ stdout.write("\n");
3878
+ resolve5(input.trim() || defaultValue || "");
3879
+ return;
3880
+ } else if (char === "") {
3881
+ if (isTTY2 && stdin.setRawMode) {
3882
+ stdin.setRawMode(wasRaw || false);
3883
+ }
3884
+ stdin.removeListener("data", onData);
3885
+ stdin.pause();
3886
+ stdout.write("\n");
3887
+ resolve5(defaultValue || "");
3888
+ return;
3889
+ } else if (char === "\x7F" || char === "\b") {
3890
+ if (input.length > 0) {
3891
+ input = input.slice(0, -1);
3892
+ stdout.write("\b \b");
3893
+ }
3894
+ } else if (char >= " " && char <= "~") {
3895
+ input += char;
3896
+ stdout.write(char);
3897
+ }
3898
+ }
3899
+ };
3900
+ stdin.on("data", onData);
3901
+ });
3902
+ }
3903
+
3904
+ // src/commands/plugin/install.ts
3905
+ async function installPlugin(args2) {
3906
+ const source = args2[0];
3907
+ if (!source) {
3908
+ console.log(theme.error(` ${symbols.cross} No source specified`));
3909
+ console.log("");
3910
+ console.log(` ${theme.primary("Usage:")} /plugin install <source>`);
3911
+ console.log("");
3912
+ console.log(` ${theme.dim("Examples:")}`);
3913
+ console.log(` ${theme.dim("/plugin install ./my-plugin")}`);
3914
+ console.log(` ${theme.dim("/plugin install zammy-plugin-git")}`);
3915
+ console.log(` ${theme.dim("/plugin install github:user/repo")}`);
3916
+ console.log("");
3917
+ return;
3918
+ }
3919
+ console.log("");
3920
+ console.log(` ${symbols.rocket} ${theme.primary("Installing plugin...")}`);
3921
+ const sourceType = detectSourceType(source);
3922
+ if (sourceType === "unknown") {
3923
+ console.log(theme.error(` ${symbols.cross} Could not determine source type for: ${source}`));
3924
+ return;
3925
+ }
3926
+ console.log(theme.dim(` Source type: ${sourceType}`));
3927
+ let result;
3928
+ switch (sourceType) {
3929
+ case "local":
3930
+ result = await installFromLocal(source);
3931
+ break;
3932
+ case "npm":
3933
+ result = await installFromNpm(source);
3934
+ break;
3935
+ case "github":
3936
+ result = await installFromGithub(source);
3937
+ break;
3938
+ case "git":
3939
+ result = await installFromGit(source);
3940
+ break;
3941
+ default:
3942
+ result = { success: false, error: "Unknown source type" };
3943
+ }
3944
+ if (!result.success) {
3945
+ console.log(theme.error(` ${symbols.cross} Installation failed: ${result.error}`));
3946
+ return;
3947
+ }
3948
+ const manifest = result.manifest;
3949
+ const conflicts = checkConflicts(manifest);
3950
+ if (conflicts.hasConflicts) {
3951
+ console.log("");
3952
+ console.log(theme.warning(` ${symbols.warning} Command conflicts detected:`));
3953
+ for (const conflict of conflicts.conflicts) {
3954
+ console.log(` ${theme.dim("-")} ${conflict}`);
3955
+ }
3956
+ console.log("");
3957
+ const proceed = await confirm(` ${theme.warning("Continue anyway?")}`);
3958
+ if (!proceed) {
3959
+ console.log(theme.dim(" Installation cancelled"));
3960
+ return;
3961
+ }
3962
+ }
3963
+ const permissions = formatPermissions(manifest);
3964
+ if (permissions.length > 0) {
3965
+ console.log("");
3966
+ console.log(theme.warning(` ${symbols.warning} Plugin requests permissions:`));
3967
+ for (const perm of permissions) {
3968
+ console.log(` ${perm}`);
3969
+ }
3970
+ console.log("");
3971
+ }
3972
+ await discoverPlugins();
3973
+ for (const cmdName of manifest.commands) {
3974
+ if (getCommand(cmdName)) continue;
3975
+ const lazyExecute = async (args3) => {
3976
+ const loaded = await loadPlugin(manifest.name);
3977
+ if (!loaded) {
3978
+ console.log(theme.error(` ${symbols.cross} Failed to load plugin '${manifest.name}'`));
3979
+ return;
3980
+ }
3981
+ const realCommand = getCommand(cmdName);
3982
+ if (realCommand && realCommand.execute !== lazyExecute) {
3983
+ await realCommand.execute(args3);
3984
+ } else {
3985
+ console.log(theme.error(` ${symbols.cross} Plugin '${manifest.name}' did not register command '${cmdName}'`));
3986
+ }
3987
+ };
3988
+ registerPluginCommand(
3989
+ {
3990
+ name: cmdName,
3991
+ description: `[${manifest.displayName || manifest.name}] ${manifest.description || "Plugin command"}`,
3992
+ usage: `/${cmdName}`,
3993
+ execute: lazyExecute
3994
+ },
3995
+ manifest.name
3996
+ );
3997
+ }
3998
+ console.log("");
3999
+ console.log(` ${symbols.check} ${theme.success("Plugin installed successfully!")}`);
4000
+ console.log("");
4001
+ console.log(` ${theme.primary(manifest.displayName || manifest.name)} ${theme.dim(`v${manifest.version}`)}`);
4002
+ if (manifest.description) {
4003
+ console.log(` ${theme.dim(manifest.description)}`);
4004
+ }
4005
+ console.log("");
4006
+ console.log(` ${theme.dim("Commands added:")} ${manifest.commands.map((c) => theme.accent("/" + c)).join(", ")}`);
4007
+ console.log("");
4008
+ }
4009
+
4010
+ // src/commands/plugin/remove.ts
4011
+ async function removePluginCommand(args2) {
4012
+ const forceIndex = args2.findIndex((a) => a === "-y" || a === "--yes");
4013
+ const skipConfirm = forceIndex !== -1;
4014
+ if (skipConfirm) {
4015
+ args2.splice(forceIndex, 1);
4016
+ }
4017
+ const name = args2[0];
4018
+ if (!name) {
4019
+ console.log(theme.error(` ${symbols.cross} No plugin name specified`));
4020
+ console.log("");
4021
+ console.log(` ${theme.primary("Usage:")} /plugin remove <name>`);
4022
+ console.log("");
4023
+ await discoverPlugins();
4024
+ const plugins2 = getDiscoveredPlugins();
4025
+ if (plugins2.length > 0) {
4026
+ console.log(` ${theme.dim("Installed plugins:")}`);
4027
+ for (const p of plugins2) {
4028
+ console.log(` ${theme.accent(p.name)}`);
4029
+ }
4030
+ console.log("");
4031
+ }
4032
+ return;
4033
+ }
4034
+ await discoverPlugins();
4035
+ const plugins = getDiscoveredPlugins();
4036
+ const plugin = plugins.find((p) => p.name === name || p.displayName?.toLowerCase() === name.toLowerCase());
4037
+ if (!plugin) {
4038
+ console.log(theme.error(` ${symbols.cross} Plugin '${name}' not found`));
4039
+ console.log("");
4040
+ const similar = plugins.filter(
4041
+ (p) => p.name.includes(name) || name.includes(p.name) || p.displayName?.toLowerCase().includes(name.toLowerCase())
4042
+ );
4043
+ if (similar.length > 0) {
4044
+ console.log(` ${theme.dim("Did you mean:")}`);
4045
+ for (const p of similar) {
4046
+ console.log(` ${theme.accent(p.name)}`);
4047
+ }
4048
+ console.log("");
4049
+ }
4050
+ return;
4051
+ }
4052
+ console.log("");
4053
+ console.log(` ${theme.warning("About to remove:")}`);
4054
+ console.log(` ${theme.primary(plugin.displayName || plugin.name)} ${theme.dim(`v${plugin.version}`)}`);
4055
+ console.log(` ${theme.dim("Commands:")} ${plugin.commands.map((c) => "/" + c).join(", ")}`);
4056
+ console.log("");
4057
+ if (!skipConfirm) {
4058
+ const proceed = await confirm(` ${theme.warning("Remove this plugin?")}`);
4059
+ if (!proceed) {
4060
+ console.log(theme.dim(" Removal cancelled"));
4061
+ return;
4062
+ }
4063
+ }
4064
+ await unloadPlugin(plugin.name);
4065
+ const result = removePlugin(plugin.name);
4066
+ if (!result.success) {
4067
+ console.log(theme.error(` ${symbols.cross} Failed to remove: ${result.error}`));
4068
+ return;
4069
+ }
4070
+ await discoverPlugins();
4071
+ console.log("");
4072
+ console.log(` ${symbols.check} ${theme.success("Plugin removed successfully")}`);
4073
+ console.log("");
4074
+ }
4075
+
4076
+ // src/commands/plugin/create.ts
4077
+ import { existsSync as existsSync7, mkdirSync, writeFileSync as writeFileSync3 } from "fs";
4078
+ import { join as join4, resolve as resolve3 } from "path";
4079
+ function generateManifest(name, displayName, description, commandName) {
4080
+ return JSON.stringify({
4081
+ name,
4082
+ version: "1.0.0",
4083
+ displayName,
4084
+ description,
4085
+ main: "./dist/index.js",
4086
+ commands: [commandName],
4087
+ zammy: {
4088
+ minVersion: "1.3.0"
4089
+ },
4090
+ permissions: {}
4091
+ }, null, 2);
4092
+ }
4093
+ function generatePackageJson(name, description) {
4094
+ return JSON.stringify({
4095
+ name,
4096
+ version: "1.0.0",
4097
+ description,
4098
+ type: "module",
4099
+ main: "dist/index.js",
4100
+ types: "dist/index.d.ts",
4101
+ scripts: {
4102
+ build: "tsc",
4103
+ dev: "tsc --watch"
4104
+ },
4105
+ keywords: ["zammy-plugin", "zammy", "cli", "plugin"],
4106
+ peerDependencies: {
4107
+ zammy: "^1.3.0"
4108
+ },
4109
+ devDependencies: {
4110
+ zammy: "^1.3.0",
4111
+ typescript: "^5.3.0"
4112
+ }
4113
+ }, null, 2);
4114
+ }
4115
+ function generateTsConfig() {
4116
+ return JSON.stringify({
4117
+ compilerOptions: {
4118
+ target: "ES2022",
4119
+ module: "NodeNext",
4120
+ moduleResolution: "NodeNext",
4121
+ outDir: "./dist",
4122
+ rootDir: "./src",
4123
+ strict: true,
4124
+ esModuleInterop: true,
4125
+ skipLibCheck: true,
4126
+ declaration: true
4127
+ },
4128
+ include: ["src/**/*"]
4129
+ }, null, 2);
4130
+ }
4131
+ function generateEntryPoint(commandName, displayName) {
4132
+ return `// ${displayName} - A zammy plugin
4133
+
4134
+ import type { PluginAPI, ZammyPlugin } from 'zammy/plugins';
4135
+
4136
+ const plugin: ZammyPlugin = {
4137
+ activate(api: PluginAPI) {
4138
+ const { theme, symbols } = api.ui;
4139
+
4140
+ api.registerCommand({
4141
+ name: '${commandName}',
4142
+ description: 'My custom command',
4143
+ usage: '/${commandName} [args]',
4144
+ async execute(args: string[]) {
4145
+ console.log('');
4146
+ console.log(\` \${symbols.star} \${theme.gradient('${displayName.toUpperCase()}')}\`);
4147
+ console.log('');
4148
+ console.log(\` \${theme.success('Hello from ${displayName}!')}\`);
4149
+
4150
+ if (args.length > 0) {
4151
+ console.log(\` \${theme.dim('Arguments:')} \${args.join(' ')}\`);
4152
+ }
4153
+
4154
+ console.log('');
4155
+ },
4156
+ });
4157
+
4158
+ api.log.info('Plugin activated!');
4159
+ },
4160
+
4161
+ deactivate() {
4162
+ // Cleanup if needed
4163
+ },
4164
+ };
4165
+
4166
+ export default plugin;
4167
+ `;
4168
+ }
4169
+ function generateReadme(name, displayName, description, commandName) {
4170
+ return `# ${displayName}
4171
+
4172
+ ${description}
4173
+
4174
+ ## Installation
4175
+
4176
+ \`\`\`bash
4177
+ /plugin install ./${name}
4178
+ \`\`\`
4179
+
4180
+ ## Usage
4181
+
4182
+ \`\`\`bash
4183
+ /${commandName} [args]
4184
+ \`\`\`
4185
+
4186
+ ## Development
4187
+
4188
+ \`\`\`bash
4189
+ # Build the plugin
4190
+ npm run build
4191
+
4192
+ # Watch for changes
4193
+ npm run dev
4194
+ \`\`\`
4195
+
4196
+ ## License
4197
+
4198
+ MIT
4199
+ `;
4200
+ }
4201
+ async function createPlugin(args2) {
4202
+ console.log("");
4203
+ console.log(` ${symbols.sparkle} ${theme.gradient("CREATE NEW PLUGIN")}`);
4204
+ console.log("");
4205
+ let name = args2[0] || "";
4206
+ if (!name) {
4207
+ name = await prompt("Plugin name (e.g., my-plugin)", "zammy-plugin-example");
4208
+ }
4209
+ name = name.toLowerCase().replace(/\s+/g, "-");
4210
+ if (!name.startsWith("zammy-plugin-")) {
4211
+ }
4212
+ const displayName = await prompt("Display name", name.replace(/^zammy-plugin-/, "").replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()));
4213
+ const description = await prompt("Description", "A zammy plugin");
4214
+ const commandName = await prompt("Main command name", name.replace(/^zammy-plugin-/, "").replace(/-/g, ""));
4215
+ const targetDir = resolve3(process.cwd(), name);
4216
+ if (existsSync7(targetDir)) {
4217
+ console.log(theme.error(` ${symbols.cross} Directory already exists: ${name}`));
4218
+ return;
4219
+ }
4220
+ console.log("");
4221
+ console.log(theme.dim(` Creating plugin in ${targetDir}...`));
4222
+ try {
4223
+ mkdirSync(targetDir);
4224
+ mkdirSync(join4(targetDir, "src"));
4225
+ mkdirSync(join4(targetDir, "dist"));
4226
+ writeFileSync3(join4(targetDir, "zammy-plugin.json"), generateManifest(name, displayName, description, commandName));
4227
+ writeFileSync3(join4(targetDir, "package.json"), generatePackageJson(name, description));
4228
+ writeFileSync3(join4(targetDir, "tsconfig.json"), generateTsConfig());
4229
+ writeFileSync3(join4(targetDir, "src", "index.ts"), generateEntryPoint(commandName, displayName));
4230
+ writeFileSync3(join4(targetDir, "README.md"), generateReadme(name, displayName, description, commandName));
4231
+ console.log("");
4232
+ console.log(` ${symbols.check} ${theme.success("Plugin created successfully!")}`);
4233
+ console.log("");
4234
+ console.log(` ${theme.primary("Next steps:")}`);
4235
+ console.log(` ${theme.dim("1.")} cd ${name}`);
4236
+ console.log(` ${theme.dim("2.")} npm install`);
4237
+ console.log(` ${theme.dim("3.")} npm run build`);
4238
+ console.log(` ${theme.dim("4.")} /plugin install ./${name}`);
4239
+ console.log("");
4240
+ console.log(` ${theme.dim("Edit")} ${theme.accent("src/index.ts")} ${theme.dim("to customize your plugin")}`);
4241
+ console.log("");
4242
+ } catch (error) {
4243
+ const message = error instanceof Error ? error.message : String(error);
4244
+ console.log(theme.error(` ${symbols.cross} Failed to create plugin: ${message}`));
4245
+ }
4246
+ }
4247
+
4248
+ // src/commands/plugin/index.ts
4249
+ registerCommand({
4250
+ name: "plugin",
4251
+ description: "Manage zammy plugins",
4252
+ usage: "/plugin <list|install|remove|create> [args]",
4253
+ async execute(args2) {
4254
+ const subcommand = args2[0]?.toLowerCase();
4255
+ if (!subcommand || subcommand === "help") {
4256
+ console.log("");
4257
+ console.log(` ${symbols.gear} ${theme.gradient("PLUGIN MANAGER")}`);
4258
+ console.log("");
4259
+ console.log(` ${theme.primary("Usage:")} /plugin <command> [args]`);
4260
+ console.log("");
4261
+ console.log(` ${theme.primary("Commands:")}`);
4262
+ console.log(` ${theme.accent("list")} ${theme.dim("Show installed plugins")}`);
4263
+ console.log(` ${theme.accent("install")} <source> ${theme.dim("Install a plugin")}`);
4264
+ console.log(` ${theme.accent("remove")} <name> ${theme.dim("Remove a plugin")}`);
4265
+ console.log(` ${theme.accent("create")} [name] ${theme.dim("Create a new plugin")}`);
4266
+ console.log("");
4267
+ console.log(` ${theme.primary("Install sources:")}`);
4268
+ console.log(` ${theme.dim("./path/to/plugin")} ${theme.dim("Local directory")}`);
4269
+ console.log(` ${theme.dim("package-name")} ${theme.dim("npm package")}`);
4270
+ console.log(` ${theme.dim("github:user/repo")} ${theme.dim("GitHub repository")}`);
4271
+ console.log(` ${theme.dim("https://...git")} ${theme.dim("Git URL")}`);
4272
+ console.log("");
4273
+ return;
4274
+ }
4275
+ switch (subcommand) {
4276
+ case "list":
4277
+ case "ls":
4278
+ await listPlugins();
4279
+ break;
4280
+ case "install":
4281
+ case "i":
4282
+ case "add":
4283
+ await installPlugin(args2.slice(1));
4284
+ break;
4285
+ case "remove":
4286
+ case "rm":
4287
+ case "uninstall":
4288
+ await removePluginCommand(args2.slice(1));
4289
+ break;
4290
+ case "create":
4291
+ case "new":
4292
+ case "init":
4293
+ await createPlugin(args2.slice(1));
4294
+ break;
4295
+ default:
4296
+ console.log(theme.error(` ${symbols.cross} Unknown subcommand: ${subcommand}`));
4297
+ console.log(theme.dim(` Use '/plugin help' to see available commands`));
4298
+ }
4299
+ }
4300
+ });
4301
+
2906
4302
  // src/cli.ts
2907
4303
  import { exec, execSync, spawn } from "child_process";
2908
- import { existsSync as existsSync4, statSync, readFileSync as readFileSync3, readdirSync, writeFileSync as writeFileSync3, watchFile, unwatchFile } from "fs";
2909
- import { resolve as resolve2, extname, basename, join as join3 } from "path";
4304
+ import { existsSync as existsSync8, statSync as statSync2, readFileSync as readFileSync5, readdirSync as readdirSync2, writeFileSync as writeFileSync4, watchFile, unwatchFile } from "fs";
4305
+ import { resolve as resolve4, extname, basename as basename3, join as join5 } from "path";
2910
4306
  import { homedir as homedir3, platform as platform2, networkInterfaces } from "os";
2911
- import chalk5 from "chalk";
4307
+ import chalk4 from "chalk";
2912
4308
  var isWindows = platform2() === "win32";
2913
4309
  function translateCommand(cmd) {
2914
4310
  if (!isWindows) return cmd;
@@ -2965,19 +4361,19 @@ function handleCd(args2) {
2965
4361
  if (!targetPath || targetPath === "~") {
2966
4362
  targetPath = homedir3();
2967
4363
  } else if (targetPath.startsWith("~/")) {
2968
- targetPath = resolve2(homedir3(), targetPath.slice(2));
4364
+ targetPath = resolve4(homedir3(), targetPath.slice(2));
2969
4365
  } else if (targetPath === "-") {
2970
4366
  console.log(theme.dim(process.cwd()));
2971
4367
  return;
2972
4368
  } else {
2973
- targetPath = resolve2(process.cwd(), targetPath);
4369
+ targetPath = resolve4(process.cwd(), targetPath);
2974
4370
  }
2975
- if (!existsSync4(targetPath)) {
4371
+ if (!existsSync8(targetPath)) {
2976
4372
  console.log(`${miniSlime.sad} ${theme.error(`Directory not found: ${targetPath}`)}`);
2977
4373
  return;
2978
4374
  }
2979
4375
  try {
2980
- const stats = statSync(targetPath);
4376
+ const stats = statSync2(targetPath);
2981
4377
  if (!stats.isDirectory()) {
2982
4378
  console.log(`${miniSlime.sad} ${theme.error(`Not a directory: ${targetPath}`)}`);
2983
4379
  return;
@@ -2992,13 +4388,13 @@ function handlePwd() {
2992
4388
  console.log(theme.primary(process.cwd()));
2993
4389
  }
2994
4390
  function handleCat(args2) {
2995
- const filePath = resolve2(process.cwd(), args2.trim());
2996
- if (!existsSync4(filePath)) {
4391
+ const filePath = resolve4(process.cwd(), args2.trim());
4392
+ if (!existsSync8(filePath)) {
2997
4393
  console.log(`${miniSlime.sad} ${theme.error(`File not found: ${args2}`)}`);
2998
4394
  return;
2999
4395
  }
3000
4396
  try {
3001
- const content = readFileSync3(filePath, "utf-8");
4397
+ const content = readFileSync5(filePath, "utf-8");
3002
4398
  const ext = extname(filePath).toLowerCase();
3003
4399
  if ([".js", ".ts", ".jsx", ".tsx", ".json", ".css", ".html", ".py", ".go", ".rs"].includes(ext)) {
3004
4400
  console.log(highlightSyntax(content, ext));
@@ -3015,13 +4411,13 @@ function highlightSyntax(content, ext) {
3015
4411
  py: ["def", "class", "import", "from", "return", "if", "elif", "else", "for", "while", "try", "except", "with", "as", "True", "False", "None", "and", "or", "not", "in", "is", "lambda", "async", "await"]
3016
4412
  };
3017
4413
  const kw = ext === ".py" ? keywords.py : keywords.js;
3018
- return content.split("\n").map((line) => {
3019
- line = line.replace(/(["'`])(?:(?!\1)[^\\]|\\.)*?\1/g, (match) => chalk5.hex("#98C379")(match));
3020
- line = line.replace(/(\/\/.*$|#.*$)/g, (match) => chalk5.hex("#5C6370")(match));
3021
- line = line.replace(/\b(\d+\.?\d*)\b/g, (match) => chalk5.hex("#D19A66")(match));
4414
+ return content.split(/\r?\n/).map((line) => {
4415
+ line = line.replace(/(["'`])(?:(?!\1)[^\\]|\\.)*?\1/g, (match) => chalk4.hex("#98C379")(match));
4416
+ line = line.replace(/(\/\/.*$|#.*$)/g, (match) => chalk4.hex("#5C6370")(match));
4417
+ line = line.replace(/\b(\d+\.?\d*)\b/g, (match) => chalk4.hex("#D19A66")(match));
3022
4418
  kw.forEach((keyword) => {
3023
4419
  const regex = new RegExp(`\\b(${keyword})\\b`, "g");
3024
- line = line.replace(regex, chalk5.hex("#C678DD")(keyword));
4420
+ line = line.replace(regex, chalk4.hex("#C678DD")(keyword));
3025
4421
  });
3026
4422
  return line;
3027
4423
  }).join("\n");
@@ -3086,24 +4482,24 @@ var fileIcons = {
3086
4482
  "default": { icon: "\u{1F4C4}", color: "#6C7A89" }
3087
4483
  };
3088
4484
  function formatSize(bytes) {
3089
- if (bytes === 0) return chalk5.dim(" 0 B");
4485
+ if (bytes === 0) return chalk4.dim(" 0 B");
3090
4486
  const units = ["B", "KB", "MB", "GB", "TB"];
3091
4487
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
3092
4488
  const size = (bytes / Math.pow(1024, i)).toFixed(i > 0 ? 1 : 0);
3093
- return chalk5.hex("#98C379")(size.padStart(5) + " " + units[i].padEnd(2));
4489
+ return chalk4.hex("#98C379")(size.padStart(5) + " " + units[i].padEnd(2));
3094
4490
  }
3095
4491
  function handleLs(args2) {
3096
4492
  const parts = args2.trim().split(/\s+/).filter(Boolean);
3097
4493
  const showAll = parts.some((a) => a === "-a" || a === "-la" || a === "-al");
3098
4494
  const showLong = parts.some((a) => a === "-l" || a === "-la" || a === "-al");
3099
4495
  const pathArgs = parts.filter((a) => !a.startsWith("-"));
3100
- const targetPath = pathArgs.length > 0 ? resolve2(process.cwd(), pathArgs[0]) : process.cwd();
3101
- if (!existsSync4(targetPath)) {
4496
+ const targetPath = pathArgs.length > 0 ? resolve4(process.cwd(), pathArgs[0]) : process.cwd();
4497
+ if (!existsSync8(targetPath)) {
3102
4498
  console.log(theme.error(`Directory not found: ${targetPath}`));
3103
4499
  return;
3104
4500
  }
3105
4501
  try {
3106
- const entries = readdirSync(targetPath, { withFileTypes: true });
4502
+ const entries = readdirSync2(targetPath, { withFileTypes: true });
3107
4503
  const filtered = showAll ? entries : entries.filter((e) => !e.name.startsWith("."));
3108
4504
  console.log("");
3109
4505
  console.log(theme.dim(` ${targetPath}`));
@@ -3119,22 +4515,22 @@ function handleLs(args2) {
3119
4515
  return a.name.localeCompare(b3.name);
3120
4516
  });
3121
4517
  for (const entry of sorted) {
3122
- const fullPath = resolve2(targetPath, entry.name);
4518
+ const fullPath = resolve4(targetPath, entry.name);
3123
4519
  const isDir = entry.isDirectory();
3124
4520
  const ext = isDir ? "dir" : extname(entry.name).toLowerCase();
3125
4521
  const iconInfo = fileIcons[ext] || fileIcons["default"];
3126
4522
  let line = ` ${iconInfo.icon} `;
3127
4523
  if (showLong) {
3128
4524
  try {
3129
- const stats = statSync(fullPath);
3130
- const size = isDir ? chalk5.dim(" <DIR>") : formatSize(stats.size);
4525
+ const stats = statSync2(fullPath);
4526
+ const size = isDir ? chalk4.dim(" <DIR>") : formatSize(stats.size);
3131
4527
  const date = stats.mtime.toLocaleDateString("en-US", { month: "short", day: "2-digit", year: "numeric" });
3132
- line += chalk5.dim(date.padEnd(13)) + size + " ";
4528
+ line += chalk4.dim(date.padEnd(13)) + size + " ";
3133
4529
  } catch {
3134
- line += chalk5.dim(" ") + " ";
4530
+ line += chalk4.dim(" ") + " ";
3135
4531
  }
3136
4532
  }
3137
- const name = isDir ? chalk5.hex(iconInfo.color).bold(entry.name + "/") : chalk5.hex(iconInfo.color)(entry.name);
4533
+ const name = isDir ? chalk4.hex(iconInfo.color).bold(entry.name + "/") : chalk4.hex(iconInfo.color)(entry.name);
3138
4534
  line += name;
3139
4535
  console.log(line);
3140
4536
  }
@@ -3148,19 +4544,19 @@ function handleLs(args2) {
3148
4544
  function handleTree(args2, maxDepth = 3) {
3149
4545
  const parts = args2.trim().split(/\s+/).filter(Boolean);
3150
4546
  const pathArgs = parts.filter((a) => !a.startsWith("-"));
3151
- const targetPath = pathArgs.length > 0 ? resolve2(process.cwd(), pathArgs[0]) : process.cwd();
3152
- if (!existsSync4(targetPath)) {
4547
+ const targetPath = pathArgs.length > 0 ? resolve4(process.cwd(), pathArgs[0]) : process.cwd();
4548
+ if (!existsSync8(targetPath)) {
3153
4549
  console.log(theme.error(`Directory not found: ${targetPath}`));
3154
4550
  return;
3155
4551
  }
3156
4552
  console.log("");
3157
- console.log(theme.primary(` \u{1F4C1} ${basename(targetPath)}/`));
4553
+ console.log(theme.primary(` \u{1F4C1} ${basename3(targetPath)}/`));
3158
4554
  let dirCount = 0;
3159
4555
  let fileCount = 0;
3160
4556
  function printTree(dir, prefix, depth) {
3161
4557
  if (depth > maxDepth) return;
3162
4558
  try {
3163
- const entries = readdirSync(dir, { withFileTypes: true }).filter((e) => !e.name.startsWith(".") && !["node_modules", ".git", "dist", "build"].includes(e.name)).sort((a, b3) => {
4559
+ const entries = readdirSync2(dir, { withFileTypes: true }).filter((e) => !e.name.startsWith(".") && !["node_modules", ".git", "dist", "build"].includes(e.name)).sort((a, b3) => {
3164
4560
  if (a.isDirectory() && !b3.isDirectory()) return -1;
3165
4561
  if (!a.isDirectory() && b3.isDirectory()) return 1;
3166
4562
  return a.name.localeCompare(b3.name);
@@ -3172,11 +4568,11 @@ function handleTree(args2, maxDepth = 3) {
3172
4568
  const iconInfo = fileIcons[ext] || fileIcons["default"];
3173
4569
  if (entry.isDirectory()) {
3174
4570
  dirCount++;
3175
- console.log(theme.dim(prefix + connector) + iconInfo.icon + " " + chalk5.hex(iconInfo.color).bold(entry.name + "/"));
3176
- printTree(resolve2(dir, entry.name), prefix + (isLast ? " " : "\u2502 "), depth + 1);
4571
+ console.log(theme.dim(prefix + connector) + iconInfo.icon + " " + chalk4.hex(iconInfo.color).bold(entry.name + "/"));
4572
+ printTree(resolve4(dir, entry.name), prefix + (isLast ? " " : "\u2502 "), depth + 1);
3177
4573
  } else {
3178
4574
  fileCount++;
3179
- console.log(theme.dim(prefix + connector) + iconInfo.icon + " " + chalk5.hex(iconInfo.color)(entry.name));
4575
+ console.log(theme.dim(prefix + connector) + iconInfo.icon + " " + chalk4.hex(iconInfo.color)(entry.name));
3180
4576
  }
3181
4577
  });
3182
4578
  } catch {
@@ -3187,18 +4583,18 @@ function handleTree(args2, maxDepth = 3) {
3187
4583
  console.log(theme.dim(` ${dirCount} directories, ${fileCount} files`));
3188
4584
  console.log("");
3189
4585
  }
3190
- var bookmarksFile = join3(homedir3(), ".zammy-bookmarks.json");
4586
+ var bookmarksFile = join5(homedir3(), ".zammy-bookmarks.json");
3191
4587
  function loadBookmarks() {
3192
4588
  try {
3193
- if (existsSync4(bookmarksFile)) {
3194
- return JSON.parse(readFileSync3(bookmarksFile, "utf-8"));
4589
+ if (existsSync8(bookmarksFile)) {
4590
+ return JSON.parse(readFileSync5(bookmarksFile, "utf-8"));
3195
4591
  }
3196
4592
  } catch {
3197
4593
  }
3198
4594
  return {};
3199
4595
  }
3200
4596
  function saveBookmarks(bookmarks) {
3201
- writeFileSync3(bookmarksFile, JSON.stringify(bookmarks, null, 2));
4597
+ writeFileSync4(bookmarksFile, JSON.stringify(bookmarks, null, 2));
3202
4598
  }
3203
4599
  function handleBookmark(args2) {
3204
4600
  const parts = args2.trim().split(/\s+/);
@@ -3254,7 +4650,7 @@ function handleBookmark(args2) {
3254
4650
  console.log(theme.primary(" \u{1F4CD} Directory Bookmarks"));
3255
4651
  console.log("");
3256
4652
  for (const key of keys.sort()) {
3257
- const exists = existsSync4(bookmarks[key]);
4653
+ const exists = existsSync8(bookmarks[key]);
3258
4654
  const status = exists ? theme.success(symbols.check) : theme.error(symbols.cross);
3259
4655
  console.log(` ${status} ${theme.primary(key.padEnd(15))} ${theme.dim("\u2192")} ${bookmarks[key]}`);
3260
4656
  }
@@ -3271,10 +4667,10 @@ function handleFind(args2) {
3271
4667
  function searchDir(dir, depth = 0) {
3272
4668
  if (depth > 5 || results.length >= maxResults) return;
3273
4669
  try {
3274
- const entries = readdirSync(dir, { withFileTypes: true });
4670
+ const entries = readdirSync2(dir, { withFileTypes: true });
3275
4671
  for (const entry of entries) {
3276
4672
  if (entry.name.startsWith(".") || ["node_modules", ".git", "dist", "build"].includes(entry.name)) continue;
3277
- const fullPath = resolve2(dir, entry.name);
4673
+ const fullPath = resolve4(dir, entry.name);
3278
4674
  const matchPattern = pattern.replace(/\*/g, ".*").replace(/\?/g, ".");
3279
4675
  const regex = new RegExp(matchPattern, "i");
3280
4676
  if (regex.test(entry.name)) {
@@ -3298,9 +4694,9 @@ function handleFind(args2) {
3298
4694
  const relativePath = result.path.replace(searchPath, ".").replace(/\\/g, "/");
3299
4695
  const ext = result.isDir ? "dir" : extname(result.path).toLowerCase();
3300
4696
  const iconInfo = fileIcons[ext] || fileIcons["default"];
3301
- const fileName = basename(result.path);
4697
+ const fileName = basename3(result.path);
3302
4698
  const dirPath = relativePath.slice(0, -fileName.length);
3303
- console.log(` ${iconInfo.icon} ${theme.dim(dirPath)}${chalk5.hex(iconInfo.color)(fileName)}${result.isDir ? "/" : ""}`);
4699
+ console.log(` ${iconInfo.icon} ${theme.dim(dirPath)}${chalk4.hex(iconInfo.color)(fileName)}${result.isDir ? "/" : ""}`);
3304
4700
  }
3305
4701
  if (results.length >= maxResults) {
3306
4702
  console.log("");
@@ -3310,8 +4706,8 @@ function handleFind(args2) {
3310
4706
  console.log("");
3311
4707
  }
3312
4708
  function handleDu(args2) {
3313
- const targetPath = args2.trim() ? resolve2(process.cwd(), args2.trim()) : process.cwd();
3314
- if (!existsSync4(targetPath)) {
4709
+ const targetPath = args2.trim() ? resolve4(process.cwd(), args2.trim()) : process.cwd();
4710
+ if (!existsSync8(targetPath)) {
3315
4711
  console.log(theme.error(` Path not found: ${targetPath}`));
3316
4712
  return;
3317
4713
  }
@@ -3319,10 +4715,10 @@ function handleDu(args2) {
3319
4715
  console.log("");
3320
4716
  console.log(theme.dim(" Calculating sizes..."));
3321
4717
  try {
3322
- const entries = readdirSync(targetPath, { withFileTypes: true });
4718
+ const entries = readdirSync2(targetPath, { withFileTypes: true });
3323
4719
  for (const entry of entries) {
3324
4720
  if (entry.name.startsWith(".")) continue;
3325
- const fullPath = resolve2(targetPath, entry.name);
4721
+ const fullPath = resolve4(targetPath, entry.name);
3326
4722
  let size = 0;
3327
4723
  let skipped = false;
3328
4724
  try {
@@ -3331,10 +4727,10 @@ function handleDu(args2) {
3331
4727
  skipped = true;
3332
4728
  size = 0;
3333
4729
  } else {
3334
- size = getDirSize(fullPath);
4730
+ size = getDirSize2(fullPath);
3335
4731
  }
3336
4732
  } else {
3337
- size = statSync(fullPath).size;
4733
+ size = statSync2(fullPath).size;
3338
4734
  }
3339
4735
  items.push({ name: entry.name, size, isDir: entry.isDirectory(), skipped });
3340
4736
  } catch {
@@ -3348,7 +4744,7 @@ function handleDu(args2) {
3348
4744
  items.sort((a, b3) => b3.size - a.size);
3349
4745
  const totalSize = items.reduce((sum, item) => sum + item.size, 0);
3350
4746
  console.log("");
3351
- console.log(theme.primary(` \u{1F4CA} Disk Usage: ${basename(targetPath)}`));
4747
+ console.log(theme.primary(` \u{1F4CA} Disk Usage: ${basename3(targetPath)}`));
3352
4748
  console.log(theme.dim(` Total: ${formatSizeSimple(totalSize)}`));
3353
4749
  console.log("");
3354
4750
  const maxItems = 15;
@@ -3362,10 +4758,10 @@ function handleDu(args2) {
3362
4758
  const percent = totalSize > 0 ? item.size / totalSize * 100 : 0;
3363
4759
  const barWidth = 20;
3364
4760
  const filled = Math.round(percent / 100 * barWidth);
3365
- const bar = chalk5.hex("#4ECDC4")("\u2588".repeat(filled)) + chalk5.dim("\u2591".repeat(barWidth - filled));
4761
+ const bar = chalk4.hex("#4ECDC4")("\u2588".repeat(filled)) + chalk4.dim("\u2591".repeat(barWidth - filled));
3366
4762
  const icon = item.isDir ? "\u{1F4C1}" : "\u{1F4C4}";
3367
4763
  const name = item.name.length > 25 ? item.name.slice(0, 22) + "..." : item.name.padEnd(25);
3368
- console.log(` ${icon} ${name} ${bar} ${formatSizeSimple(item.size).padStart(8)} ${chalk5.dim(`${percent.toFixed(1)}%`)}`);
4764
+ console.log(` ${icon} ${name} ${bar} ${formatSizeSimple(item.size).padStart(8)} ${chalk4.dim(`${percent.toFixed(1)}%`)}`);
3369
4765
  }
3370
4766
  if (items.length > maxItems) {
3371
4767
  console.log(theme.dim(` ... and ${items.length - maxItems} more items`));
@@ -3377,19 +4773,19 @@ function handleDu(args2) {
3377
4773
  console.log("");
3378
4774
  }
3379
4775
  var skipDirs = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", ".nuxt", "coverage", ".cache", "__pycache__", "venv", ".venv"]);
3380
- function getDirSize(dir, depth = 0, maxDepth = 4) {
4776
+ function getDirSize2(dir, depth = 0, maxDepth = 4) {
3381
4777
  if (depth > maxDepth) return 0;
3382
4778
  let size = 0;
3383
4779
  try {
3384
- const entries = readdirSync(dir, { withFileTypes: true });
4780
+ const entries = readdirSync2(dir, { withFileTypes: true });
3385
4781
  for (const entry of entries) {
3386
4782
  if (skipDirs.has(entry.name)) continue;
3387
- const fullPath = resolve2(dir, entry.name);
4783
+ const fullPath = resolve4(dir, entry.name);
3388
4784
  if (entry.isDirectory()) {
3389
- size += getDirSize(fullPath, depth + 1, maxDepth);
4785
+ size += getDirSize2(fullPath, depth + 1, maxDepth);
3390
4786
  } else {
3391
4787
  try {
3392
- size += statSync(fullPath).size;
4788
+ size += statSync2(fullPath).size;
3393
4789
  } catch {
3394
4790
  }
3395
4791
  }
@@ -3419,7 +4815,7 @@ function handleGit(args2) {
3419
4815
  case "status":
3420
4816
  case "s": {
3421
4817
  const branch = execSync("git branch --show-current", { encoding: "utf-8", timeout: 5e3 }).trim();
3422
- console.log(` ${symbols.rocket} ${theme.primary("Branch:")} ${chalk5.hex("#98C379")(branch)}`);
4818
+ console.log(` ${symbols.rocket} ${theme.primary("Branch:")} ${chalk4.hex("#98C379")(branch)}`);
3423
4819
  console.log("");
3424
4820
  const status = execSync("git status --porcelain", { encoding: "utf-8", timeout: 5e3 });
3425
4821
  if (!status.trim()) {
@@ -3444,12 +4840,12 @@ function handleGit(args2) {
3444
4840
  }
3445
4841
  if (staged.length > 0) {
3446
4842
  console.log(theme.success(" Staged changes:"));
3447
- staged.forEach((f) => console.log(` ${symbols.check} ${chalk5.hex("#98C379")(f)}`));
4843
+ staged.forEach((f) => console.log(` ${symbols.check} ${chalk4.hex("#98C379")(f)}`));
3448
4844
  console.log("");
3449
4845
  }
3450
4846
  if (modified.length > 0) {
3451
4847
  console.log(theme.warning(" Modified:"));
3452
- modified.forEach((f) => console.log(` ${symbols.bullet} ${chalk5.hex("#E5C07B")(f)}`));
4848
+ modified.forEach((f) => console.log(` ${symbols.bullet} ${chalk4.hex("#E5C07B")(f)}`));
3453
4849
  console.log("");
3454
4850
  }
3455
4851
  if (untracked.length > 0) {
@@ -3463,7 +4859,7 @@ function handleGit(args2) {
3463
4859
  console.log(theme.dim(" Recent commits:"));
3464
4860
  log.split("\n").forEach((line) => {
3465
4861
  const [hash, ...msg] = line.split(" ");
3466
- console.log(` ${chalk5.hex("#61AFEF")(hash)} ${theme.dim(msg.join(" "))}`);
4862
+ console.log(` ${chalk4.hex("#61AFEF")(hash)} ${theme.dim(msg.join(" "))}`);
3467
4863
  });
3468
4864
  }
3469
4865
  break;
@@ -3475,7 +4871,7 @@ function handleGit(args2) {
3475
4871
  console.log("");
3476
4872
  log.split("\n").forEach((line) => {
3477
4873
  const [hash, ...msg] = line.split(" ");
3478
- console.log(` ${chalk5.hex("#61AFEF")(hash)} ${msg.join(" ")}`);
4874
+ console.log(` ${chalk4.hex("#61AFEF")(hash)} ${msg.join(" ")}`);
3479
4875
  });
3480
4876
  break;
3481
4877
  }
@@ -3486,7 +4882,7 @@ function handleGit(args2) {
3486
4882
  console.log("");
3487
4883
  branches.split("\n").forEach((line) => {
3488
4884
  if (line.startsWith("*")) {
3489
- console.log(` ${chalk5.hex("#98C379")(line)}`);
4885
+ console.log(` ${chalk4.hex("#98C379")(line)}`);
3490
4886
  } else {
3491
4887
  console.log(` ${theme.dim(line)}`);
3492
4888
  }
@@ -3559,8 +4955,8 @@ function handleClipboard(args2) {
3559
4955
  }
3560
4956
  }
3561
4957
  } else if (action === "file" && parts[1]) {
3562
- const filePath = resolve2(process.cwd(), parts[1]);
3563
- if (existsSync4(filePath)) {
4958
+ const filePath = resolve4(process.cwd(), parts[1]);
4959
+ if (existsSync8(filePath)) {
3564
4960
  try {
3565
4961
  const copyCmd = getClipboardCopyCmd();
3566
4962
  if (isWindows) {
@@ -3592,14 +4988,14 @@ function handleClipboard(args2) {
3592
4988
  console.log("");
3593
4989
  }
3594
4990
  function handlePretty(args2) {
3595
- const filePath = resolve2(process.cwd(), args2.trim());
3596
- if (!existsSync4(filePath)) {
4991
+ const filePath = resolve4(process.cwd(), args2.trim());
4992
+ if (!existsSync8(filePath)) {
3597
4993
  console.log(theme.error(` File not found: ${args2}`));
3598
4994
  return;
3599
4995
  }
3600
4996
  console.log("");
3601
4997
  try {
3602
- const content = readFileSync3(filePath, "utf-8");
4998
+ const content = readFileSync5(filePath, "utf-8");
3603
4999
  const ext = extname(filePath).toLowerCase();
3604
5000
  if (ext === ".json") {
3605
5001
  const parsed = JSON.parse(content);
@@ -3615,7 +5011,7 @@ function handlePretty(args2) {
3615
5011
  console.log("");
3616
5012
  }
3617
5013
  function highlightJson(json) {
3618
- return json.replace(/"([^"]+)":/g, (_, key) => chalk5.hex("#E06C75")(`"${key}"`) + ":").replace(/: "([^"]*)"/g, (_, val) => ": " + chalk5.hex("#98C379")(`"${val}"`)).replace(/: (\d+)/g, (_, num) => ": " + chalk5.hex("#D19A66")(num)).replace(/: (true|false)/g, (_, bool) => ": " + chalk5.hex("#56B6C2")(bool)).replace(/: (null)/g, (_, n) => ": " + chalk5.hex("#C678DD")(n));
5014
+ return json.replace(/"([^"]+)":/g, (_, key) => chalk4.hex("#E06C75")(`"${key}"`) + ":").replace(/: "([^"]*)"/g, (_, val) => ": " + chalk4.hex("#98C379")(`"${val}"`)).replace(/: (\d+)/g, (_, num) => ": " + chalk4.hex("#D19A66")(num)).replace(/: (true|false)/g, (_, bool) => ": " + chalk4.hex("#56B6C2")(bool)).replace(/: (null)/g, (_, n) => ": " + chalk4.hex("#C678DD")(n));
3619
5015
  }
3620
5016
  var activeWatcher = null;
3621
5017
  function handleWatch(args2) {
@@ -3646,14 +5042,14 @@ function handleWatch(args2) {
3646
5042
  console.log("");
3647
5043
  return;
3648
5044
  }
3649
- const filePath = resolve2(process.cwd(), action);
3650
- if (!existsSync4(filePath)) {
5045
+ const filePath = resolve4(process.cwd(), action);
5046
+ if (!existsSync8(filePath)) {
3651
5047
  console.log(theme.error(` File not found: ${action}`));
3652
5048
  console.log("");
3653
5049
  return;
3654
5050
  }
3655
5051
  try {
3656
- const stats = statSync(filePath);
5052
+ const stats = statSync2(filePath);
3657
5053
  if (stats.isDirectory()) {
3658
5054
  console.log(theme.error(` Cannot watch a directory: ${action}`));
3659
5055
  console.log(theme.dim(" Please specify a file path"));
@@ -3669,13 +5065,13 @@ function handleWatch(args2) {
3669
5065
  unwatchFile(activeWatcher);
3670
5066
  }
3671
5067
  activeWatcher = filePath;
3672
- let lastSize = statSync(filePath).size;
5068
+ let lastSize = statSync2(filePath).size;
3673
5069
  console.log(` ${symbols.info} ${theme.primary("Watching:")} ${filePath}`);
3674
5070
  console.log(theme.dim(' (Type "!watch stop" to stop watching)'));
3675
5071
  console.log("");
3676
5072
  try {
3677
- const content = readFileSync3(filePath, "utf-8");
3678
- const lines = content.split("\n").slice(-10);
5073
+ const content = readFileSync5(filePath, "utf-8");
5074
+ const lines = content.split(/\r?\n/).slice(-10);
3679
5075
  lines.forEach((line) => console.log(theme.dim(line)));
3680
5076
  } catch {
3681
5077
  console.log(theme.dim(" (Unable to read initial content)"));
@@ -3683,12 +5079,12 @@ function handleWatch(args2) {
3683
5079
  watchFile(filePath, { interval: 500 }, (curr, prev) => {
3684
5080
  if (curr.size > lastSize) {
3685
5081
  try {
3686
- const newContent = readFileSync3(filePath, "utf-8");
3687
- const allLines = newContent.split("\n");
5082
+ const newContent = readFileSync5(filePath, "utf-8");
5083
+ const allLines = newContent.split(/\r?\n/);
3688
5084
  const oldLines = Math.floor(prev.size / 50);
3689
5085
  const newLines = allLines.slice(-Math.max(1, allLines.length - oldLines));
3690
5086
  newLines.forEach((line) => {
3691
- if (line.trim()) console.log(chalk5.hex("#98C379")(line));
5087
+ if (line.trim()) console.log(chalk4.hex("#98C379")(line));
3692
5088
  });
3693
5089
  } catch {
3694
5090
  }
@@ -3701,7 +5097,7 @@ function handleServe(args2) {
3701
5097
  console.log("");
3702
5098
  console.log(` ${symbols.rocket} ${theme.primary("Starting HTTP server...")}`);
3703
5099
  console.log(` ${theme.dim("Serving:")} ${process.cwd()}`);
3704
- console.log(` ${theme.dim("URL:")} ${chalk5.hex("#61AFEF")(`http://localhost:${port}`)}`);
5100
+ console.log(` ${theme.dim("URL:")} ${chalk4.hex("#61AFEF")(`http://localhost:${port}`)}`);
3705
5101
  console.log("");
3706
5102
  console.log(theme.dim(" Press Ctrl+C to stop"));
3707
5103
  console.log("");
@@ -3732,7 +5128,7 @@ function handlePs() {
3732
5128
  const name = parts[0].slice(0, 28).padEnd(30);
3733
5129
  const pid = parts[1].padStart(8);
3734
5130
  const mem = parts[4];
3735
- console.log(` ${name}${pid} ${chalk5.hex("#98C379")(mem)}`);
5131
+ console.log(` ${name}${pid} ${chalk4.hex("#98C379")(mem)}`);
3736
5132
  }
3737
5133
  });
3738
5134
  } else {
@@ -3759,7 +5155,7 @@ function handleEnv(args2) {
3759
5155
  filtered.slice(0, maxShow).forEach((key) => {
3760
5156
  const value = env[key] || "";
3761
5157
  const displayValue = value.length > 50 ? value.slice(0, 47) + "..." : value;
3762
- console.log(` ${chalk5.hex("#E06C75")(key.padEnd(25))} ${theme.dim("=")} ${displayValue}`);
5158
+ console.log(` ${chalk4.hex("#E06C75")(key.padEnd(25))} ${theme.dim("=")} ${displayValue}`);
3763
5159
  });
3764
5160
  if (filtered.length > maxShow) {
3765
5161
  console.log(theme.dim(` ... and ${filtered.length - maxShow} more`));
@@ -3788,7 +5184,7 @@ function handleIp() {
3788
5184
  if (localIps.length === 0) {
3789
5185
  console.log(` ${theme.dim("(No network interfaces found)")}`);
3790
5186
  } else {
3791
- localIps.forEach((ip) => console.log(` ${chalk5.hex("#98C379")(ip)}`));
5187
+ localIps.forEach((ip) => console.log(` ${chalk4.hex("#98C379")(ip)}`));
3792
5188
  }
3793
5189
  console.log("");
3794
5190
  console.log(theme.dim(" Public IP:"));
@@ -3803,7 +5199,7 @@ function handleIp() {
3803
5199
  throw new Error("curl not available");
3804
5200
  }
3805
5201
  }
3806
- console.log(` ${chalk5.hex("#61AFEF")(result)}`);
5202
+ console.log(` ${chalk4.hex("#61AFEF")(result)}`);
3807
5203
  } catch {
3808
5204
  console.log(` ${theme.dim("(Could not fetch - requires curl or internet)")}`);
3809
5205
  }
@@ -3820,21 +5216,21 @@ function handleEpoch(args2) {
3820
5216
  if (!input || input === "now") {
3821
5217
  const now = /* @__PURE__ */ new Date();
3822
5218
  console.log(` ${theme.dim("Current Time:")}`);
3823
- console.log(` ${chalk5.hex("#98C379")(now.toISOString())}`);
3824
- console.log(` ${chalk5.hex("#61AFEF")(Math.floor(now.getTime() / 1e3).toString())} ${theme.dim("(Unix seconds)")}`);
3825
- console.log(` ${chalk5.hex("#E5C07B")(now.getTime().toString())} ${theme.dim("(Unix milliseconds)")}`);
5219
+ console.log(` ${chalk4.hex("#98C379")(now.toISOString())}`);
5220
+ console.log(` ${chalk4.hex("#61AFEF")(Math.floor(now.getTime() / 1e3).toString())} ${theme.dim("(Unix seconds)")}`);
5221
+ console.log(` ${chalk4.hex("#E5C07B")(now.getTime().toString())} ${theme.dim("(Unix milliseconds)")}`);
3826
5222
  } else if (/^\d{10,13}$/.test(input)) {
3827
5223
  const ms = input.length === 10 ? parseInt(input) * 1e3 : parseInt(input);
3828
5224
  const date = new Date(ms);
3829
- console.log(` ${theme.dim("Epoch:")} ${chalk5.hex("#E5C07B")(input)}`);
3830
- console.log(` ${theme.dim("Date:")} ${chalk5.hex("#98C379")(date.toISOString())}`);
3831
- console.log(` ${chalk5.hex("#98C379")(date.toLocaleString())}`);
5225
+ console.log(` ${theme.dim("Epoch:")} ${chalk4.hex("#E5C07B")(input)}`);
5226
+ console.log(` ${theme.dim("Date:")} ${chalk4.hex("#98C379")(date.toISOString())}`);
5227
+ console.log(` ${chalk4.hex("#98C379")(date.toLocaleString())}`);
3832
5228
  } else {
3833
5229
  const date = new Date(input);
3834
5230
  if (!isNaN(date.getTime())) {
3835
- console.log(` ${theme.dim("Date:")} ${chalk5.hex("#98C379")(input)}`);
3836
- console.log(` ${theme.dim("Unix:")} ${chalk5.hex("#61AFEF")(Math.floor(date.getTime() / 1e3).toString())} ${theme.dim("(seconds)")}`);
3837
- console.log(` ${chalk5.hex("#E5C07B")(date.getTime().toString())} ${theme.dim("(milliseconds)")}`);
5231
+ console.log(` ${theme.dim("Date:")} ${chalk4.hex("#98C379")(input)}`);
5232
+ console.log(` ${theme.dim("Unix:")} ${chalk4.hex("#61AFEF")(Math.floor(date.getTime() / 1e3).toString())} ${theme.dim("(seconds)")}`);
5233
+ console.log(` ${chalk4.hex("#E5C07B")(date.getTime().toString())} ${theme.dim("(milliseconds)")}`);
3838
5234
  } else {
3839
5235
  console.log(theme.error(` Cannot parse: ${input}`));
3840
5236
  console.log(theme.dim(' Examples: epoch now, epoch 1703788800, epoch "2024-01-01"'));
@@ -3858,7 +5254,7 @@ async function handleHttp(args2) {
3858
5254
  return;
3859
5255
  }
3860
5256
  const fullUrl = url.startsWith("http") ? url : `https://${url}`;
3861
- console.log(` ${symbols.rocket} ${theme.dim(method)} ${chalk5.hex("#61AFEF")(fullUrl)}`);
5257
+ console.log(` ${symbols.rocket} ${theme.dim(method)} ${chalk4.hex("#61AFEF")(fullUrl)}`);
3862
5258
  console.log("");
3863
5259
  try {
3864
5260
  let result;
@@ -3908,22 +5304,22 @@ function handleDiff(args2) {
3908
5304
  console.log("");
3909
5305
  return;
3910
5306
  }
3911
- const path1 = resolve2(process.cwd(), file1);
3912
- const path2 = resolve2(process.cwd(), file2);
3913
- if (!existsSync4(path1)) {
5307
+ const path1 = resolve4(process.cwd(), file1);
5308
+ const path2 = resolve4(process.cwd(), file2);
5309
+ if (!existsSync8(path1)) {
3914
5310
  console.log(theme.error(` File not found: ${file1}`));
3915
5311
  console.log("");
3916
5312
  return;
3917
5313
  }
3918
- if (!existsSync4(path2)) {
5314
+ if (!existsSync8(path2)) {
3919
5315
  console.log(theme.error(` File not found: ${file2}`));
3920
5316
  console.log("");
3921
5317
  return;
3922
5318
  }
3923
5319
  try {
3924
- const content1 = readFileSync3(path1, "utf-8").split("\n");
3925
- const content2 = readFileSync3(path2, "utf-8").split("\n");
3926
- console.log(theme.primary(` Comparing: ${basename(file1)} \u2194 ${basename(file2)}`));
5320
+ const content1 = readFileSync5(path1, "utf-8").split(/\r?\n/);
5321
+ const content2 = readFileSync5(path2, "utf-8").split(/\r?\n/);
5322
+ console.log(theme.primary(` Comparing: ${basename3(file1)} \u2194 ${basename3(file2)}`));
3927
5323
  console.log("");
3928
5324
  const maxLines = Math.max(content1.length, content2.length);
3929
5325
  let differences = 0;
@@ -3932,8 +5328,8 @@ function handleDiff(args2) {
3932
5328
  const line2 = content2[i] || "";
3933
5329
  if (line1 !== line2) {
3934
5330
  differences++;
3935
- console.log(chalk5.hex("#E06C75")(` - ${(i + 1).toString().padStart(4)}: ${line1.slice(0, 70)}`));
3936
- console.log(chalk5.hex("#98C379")(` + ${(i + 1).toString().padStart(4)}: ${line2.slice(0, 70)}`));
5331
+ console.log(chalk4.hex("#E06C75")(` - ${(i + 1).toString().padStart(4)}: ${line1.slice(0, 70)}`));
5332
+ console.log(chalk4.hex("#98C379")(` + ${(i + 1).toString().padStart(4)}: ${line2.slice(0, 70)}`));
3937
5333
  console.log("");
3938
5334
  }
3939
5335
  }
@@ -3950,18 +5346,18 @@ function handleDiff(args2) {
3950
5346
  }
3951
5347
  console.log("");
3952
5348
  }
3953
- var aliasesFile = join3(homedir3(), ".zammy-aliases.json");
5349
+ var aliasesFile = join5(homedir3(), ".zammy-aliases.json");
3954
5350
  function loadAliases() {
3955
5351
  try {
3956
- if (existsSync4(aliasesFile)) {
3957
- return JSON.parse(readFileSync3(aliasesFile, "utf-8"));
5352
+ if (existsSync8(aliasesFile)) {
5353
+ return JSON.parse(readFileSync5(aliasesFile, "utf-8"));
3958
5354
  }
3959
5355
  } catch {
3960
5356
  }
3961
5357
  return {};
3962
5358
  }
3963
5359
  function saveAliases(aliases) {
3964
- writeFileSync3(aliasesFile, JSON.stringify(aliases, null, 2));
5360
+ writeFileSync4(aliasesFile, JSON.stringify(aliases, null, 2));
3965
5361
  }
3966
5362
  function handleAlias(args2) {
3967
5363
  const parts = args2.trim().split(/\s+/);
@@ -4065,8 +5461,8 @@ function handleGrep(args2) {
4065
5461
  function searchFile(filePath) {
4066
5462
  if (results.length >= maxResults) return;
4067
5463
  try {
4068
- const content = readFileSync3(filePath, "utf-8");
4069
- const lines = content.split("\n");
5464
+ const content = readFileSync5(filePath, "utf-8");
5465
+ const lines = content.split(/\r?\n/);
4070
5466
  lines.forEach((line, index) => {
4071
5467
  if (results.length >= maxResults) return;
4072
5468
  if (regex.test(line)) {
@@ -4083,11 +5479,11 @@ function handleGrep(args2) {
4083
5479
  function searchDir(dir, depth = 0) {
4084
5480
  if (depth > 4 || results.length >= maxResults) return;
4085
5481
  try {
4086
- const entries = readdirSync(dir, { withFileTypes: true });
5482
+ const entries = readdirSync2(dir, { withFileTypes: true });
4087
5483
  for (const entry of entries) {
4088
5484
  if (results.length >= maxResults) break;
4089
5485
  if (entry.name.startsWith(".") || ["node_modules", ".git", "dist", "build"].includes(entry.name)) continue;
4090
- const fullPath = resolve2(dir, entry.name);
5486
+ const fullPath = resolve4(dir, entry.name);
4091
5487
  if (entry.isDirectory()) {
4092
5488
  searchDir(fullPath, depth + 1);
4093
5489
  } else {
@@ -4110,9 +5506,9 @@ function handleGrep(args2) {
4110
5506
  for (const result of results) {
4111
5507
  const highlightedContent = result.content.replace(
4112
5508
  regex,
4113
- (match) => chalk5.hex("#FF6B6B").bold(match)
5509
+ (match) => chalk4.hex("#FF6B6B").bold(match)
4114
5510
  );
4115
- console.log(` ${theme.dim(result.file)}:${chalk5.hex("#61AFEF")(result.line)}`);
5511
+ console.log(` ${theme.dim(result.file)}:${chalk4.hex("#61AFEF")(result.line)}`);
4116
5512
  console.log(` ${highlightedContent}`);
4117
5513
  console.log("");
4118
5514
  }
@@ -4123,30 +5519,30 @@ function handleGrep(args2) {
4123
5519
  console.log("");
4124
5520
  }
4125
5521
  function handleWc(args2) {
4126
- const filePath = resolve2(process.cwd(), args2.trim());
5522
+ const filePath = resolve4(process.cwd(), args2.trim());
4127
5523
  console.log("");
4128
5524
  if (!args2.trim()) {
4129
5525
  console.log(theme.error(" Usage: wc <file>"));
4130
5526
  console.log("");
4131
5527
  return;
4132
5528
  }
4133
- if (!existsSync4(filePath)) {
5529
+ if (!existsSync8(filePath)) {
4134
5530
  console.log(theme.error(` File not found: ${args2}`));
4135
5531
  console.log("");
4136
5532
  return;
4137
5533
  }
4138
5534
  try {
4139
- const content = readFileSync3(filePath, "utf-8");
4140
- const lines = content.split("\n").length;
5535
+ const content = readFileSync5(filePath, "utf-8");
5536
+ const lines = content.split(/\r?\n/).length;
4141
5537
  const words = content.split(/\s+/).filter((w) => w.length > 0).length;
4142
5538
  const chars = content.length;
4143
5539
  const bytes = Buffer.byteLength(content, "utf-8");
4144
- console.log(theme.primary(` \u{1F4CA} ${basename(args2)}`));
5540
+ console.log(theme.primary(` \u{1F4CA} ${basename3(args2)}`));
4145
5541
  console.log("");
4146
- console.log(` ${chalk5.hex("#61AFEF")(lines.toLocaleString().padStart(8))} ${theme.dim("lines")}`);
4147
- console.log(` ${chalk5.hex("#98C379")(words.toLocaleString().padStart(8))} ${theme.dim("words")}`);
4148
- console.log(` ${chalk5.hex("#E5C07B")(chars.toLocaleString().padStart(8))} ${theme.dim("characters")}`);
4149
- console.log(` ${chalk5.hex("#C678DD")(bytes.toLocaleString().padStart(8))} ${theme.dim("bytes")}`);
5542
+ console.log(` ${chalk4.hex("#61AFEF")(lines.toLocaleString().padStart(8))} ${theme.dim("lines")}`);
5543
+ console.log(` ${chalk4.hex("#98C379")(words.toLocaleString().padStart(8))} ${theme.dim("words")}`);
5544
+ console.log(` ${chalk4.hex("#E5C07B")(chars.toLocaleString().padStart(8))} ${theme.dim("characters")}`);
5545
+ console.log(` ${chalk4.hex("#C678DD")(bytes.toLocaleString().padStart(8))} ${theme.dim("bytes")}`);
4150
5546
  } catch {
4151
5547
  console.log(theme.error(" Failed to read file"));
4152
5548
  }
@@ -4166,19 +5562,19 @@ function handleHead(args2) {
4166
5562
  console.log("");
4167
5563
  return;
4168
5564
  }
4169
- const fullPath = resolve2(process.cwd(), filePath);
4170
- if (!existsSync4(fullPath)) {
5565
+ const fullPath = resolve4(process.cwd(), filePath);
5566
+ if (!existsSync8(fullPath)) {
4171
5567
  console.log(theme.error(` File not found: ${filePath}`));
4172
5568
  console.log("");
4173
5569
  return;
4174
5570
  }
4175
5571
  try {
4176
- const content = readFileSync3(fullPath, "utf-8");
4177
- const fileLines = content.split("\n").slice(0, lines);
4178
- console.log(theme.dim(` First ${lines} lines of ${basename(filePath)}:`));
5572
+ const content = readFileSync5(fullPath, "utf-8");
5573
+ const fileLines = content.split(/\r?\n/).slice(0, lines);
5574
+ console.log(theme.dim(` First ${lines} lines of ${basename3(filePath)}:`));
4179
5575
  console.log("");
4180
5576
  fileLines.forEach((line, i) => {
4181
- console.log(` ${chalk5.dim((i + 1).toString().padStart(4))} ${line}`);
5577
+ console.log(` ${chalk4.dim((i + 1).toString().padStart(4))} ${line}`);
4182
5578
  });
4183
5579
  } catch {
4184
5580
  console.log(theme.error(" Failed to read file"));
@@ -4380,19 +5776,19 @@ async function parseAndExecute(input) {
4380
5776
  }
4381
5777
 
4382
5778
  // src/index.ts
4383
- import { readdirSync as readdirSync2, readFileSync as readFileSync4 } from "fs";
5779
+ import { readdirSync as readdirSync3, readFileSync as readFileSync6 } from "fs";
4384
5780
  import { fileURLToPath } from "url";
4385
- import { dirname, join as join4 } from "path";
4386
- import chalk6 from "chalk";
5781
+ import { dirname, join as join6 } from "path";
5782
+ import chalk5 from "chalk";
4387
5783
  var SLIME_COLOR = "#9B59B6";
4388
5784
  var EYE_COLOR = "#1A1A2E";
4389
5785
  var MIN_WIDTH_FOR_IDLE = 40;
4390
5786
  var MIN_WIDTH_FOR_MENU = 50;
4391
5787
  var miniSlimeFrames = [
4392
5788
  // Open eyes
4393
- chalk6.hex(SLIME_COLOR)("(") + chalk6.hex(EYE_COLOR)("\u25CF") + chalk6.hex(SLIME_COLOR)("\u1D17") + chalk6.hex(EYE_COLOR)("\u25CF") + chalk6.hex(SLIME_COLOR)(")"),
5789
+ chalk5.hex(SLIME_COLOR)("(") + chalk5.hex(EYE_COLOR)("\u25CF") + chalk5.hex(SLIME_COLOR)("\u1D17") + chalk5.hex(EYE_COLOR)("\u25CF") + chalk5.hex(SLIME_COLOR)(")"),
4394
5790
  // Blink (closed eyes)
4395
- chalk6.hex(SLIME_COLOR)("(") + chalk6.hex(EYE_COLOR)("\u2500") + chalk6.hex(SLIME_COLOR)("\u1D17") + chalk6.hex(EYE_COLOR)("\u2500") + chalk6.hex(SLIME_COLOR)(")")
5791
+ chalk5.hex(SLIME_COLOR)("(") + chalk5.hex(EYE_COLOR)("\u2500") + chalk5.hex(SLIME_COLOR)("\u1D17") + chalk5.hex(EYE_COLOR)("\u2500") + chalk5.hex(SLIME_COLOR)(")")
4396
5792
  ];
4397
5793
  var idleAnimationInterval = null;
4398
5794
  var isUserTyping = false;
@@ -4469,8 +5865,8 @@ if (args.includes("--version") || args.includes("-v")) {
4469
5865
  try {
4470
5866
  const __filename = fileURLToPath(import.meta.url);
4471
5867
  const __dirname = dirname(__filename);
4472
- const pkgPath = join4(__dirname, "..", "package.json");
4473
- const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
5868
+ const pkgPath = join6(__dirname, "..", "package.json");
5869
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf-8"));
4474
5870
  console.log(`zammy v${pkg.version}`);
4475
5871
  } catch {
4476
5872
  console.log("zammy v1.0.0");
@@ -4551,9 +5947,9 @@ var SHELL_COMMANDS = [
4551
5947
  { name: "mv", description: "Move files" }
4552
5948
  ];
4553
5949
  function getFilteredCommands(filter) {
4554
- const commands2 = getAllCommands().map((c) => ({ name: c.name, description: c.description }));
4555
- if (!filter) return commands2;
4556
- return commands2.filter((c) => c.name.toLowerCase().startsWith(filter.toLowerCase()));
5950
+ const commands = getAllCommands().map((c) => ({ name: c.name, description: c.description }));
5951
+ if (!filter) return commands;
5952
+ return commands.filter((c) => c.name.toLowerCase().startsWith(filter.toLowerCase()));
4557
5953
  }
4558
5954
  function getFilteredShellCommands(filter) {
4559
5955
  if (!filter) return SHELL_COMMANDS;
@@ -4684,14 +6080,14 @@ function navigateMenu(direction, currentLine) {
4684
6080
  renderMenu(currentLine);
4685
6081
  }
4686
6082
  function completer(line) {
4687
- const commands2 = getAllCommands().map((c) => "/" + c.name);
6083
+ const commands = getAllCommands().map((c) => "/" + c.name);
4688
6084
  if (line.startsWith("/")) {
4689
6085
  const input = line.toLowerCase();
4690
6086
  if (input.startsWith("/asciiart ")) {
4691
6087
  const afterCommand = line.slice("/asciiart ".length);
4692
6088
  const searchTerm = afterCommand.startsWith("@") ? afterCommand.slice(1) : afterCommand;
4693
6089
  try {
4694
- const files = readdirSync2(process.cwd());
6090
+ const files = readdirSync3(process.cwd());
4695
6091
  const imageFiles = files.filter((f) => {
4696
6092
  const ext = f.toLowerCase().slice(f.lastIndexOf("."));
4697
6093
  return IMAGE_EXTENSIONS.includes(ext);
@@ -4705,7 +6101,7 @@ function completer(line) {
4705
6101
  return [[], line];
4706
6102
  }
4707
6103
  }
4708
- const matches = commands2.filter((c) => c.toLowerCase().startsWith(input));
6104
+ const matches = commands.filter((c) => c.toLowerCase().startsWith(input));
4709
6105
  return [matches.length ? matches : [], line];
4710
6106
  }
4711
6107
  if (line.startsWith("!")) {
@@ -4721,6 +6117,7 @@ async function main() {
4721
6117
  console.log(theme.dim("For full features, run in a proper terminal or use: zammy --simple\n"));
4722
6118
  }
4723
6119
  await displayBanner(isSimpleMode);
6120
+ await initPluginLoader();
4724
6121
  const rl = readline.createInterface({
4725
6122
  input: process.stdin,
4726
6123
  output: process.stdout,