zammy 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +328 -214
  2. package/SECURITY.md +57 -0
  3. package/assets/zammy.gif +0 -0
  4. package/dist/index.js +3257 -450
  5. package/package.json +10 -3
  6. package/packages/plugins/docker/README.md +141 -0
  7. package/packages/plugins/docker/dist/index.d.ts +46 -0
  8. package/packages/plugins/docker/dist/index.d.ts.map +1 -0
  9. package/packages/plugins/docker/dist/index.js +402 -0
  10. package/packages/plugins/docker/dist/index.js.map +1 -0
  11. package/packages/plugins/docker/package.json +28 -0
  12. package/packages/plugins/docker/zammy-plugin.json +16 -0
  13. package/packages/plugins/faker/README.md +65 -0
  14. package/packages/plugins/faker/dist/index.d.ts +43 -0
  15. package/packages/plugins/faker/dist/index.d.ts.map +1 -0
  16. package/packages/plugins/faker/dist/index.js +349 -0
  17. package/packages/plugins/faker/dist/index.js.map +1 -0
  18. package/packages/plugins/faker/package.json +28 -0
  19. package/packages/plugins/faker/zammy-plugin.json +14 -0
  20. package/packages/plugins/network/README.md +126 -0
  21. package/packages/plugins/network/dist/index.d.ts +45 -0
  22. package/packages/plugins/network/dist/index.d.ts.map +1 -0
  23. package/packages/plugins/network/dist/index.js +406 -0
  24. package/packages/plugins/network/dist/index.js.map +1 -0
  25. package/packages/plugins/network/package.json +28 -0
  26. package/packages/plugins/network/zammy-plugin.json +17 -0
  27. package/packages/plugins/port/README.md +74 -0
  28. package/packages/plugins/port/dist/index.d.ts +47 -0
  29. package/packages/plugins/port/dist/index.d.ts.map +1 -0
  30. package/packages/plugins/port/dist/index.js +331 -0
  31. package/packages/plugins/port/dist/index.js.map +1 -0
  32. package/packages/plugins/port/package.json +28 -0
  33. package/packages/plugins/port/zammy-plugin.json +16 -0
package/dist/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import * as readline from "readline";
4
+ import * as readline4 from "readline";
5
5
 
6
6
  // src/ui/banner.ts
7
7
  import figlet from "figlet";
8
+ import chalk3 from "chalk";
8
9
 
9
10
  // src/ui/colors.ts
10
11
  import chalk from "chalk";
@@ -180,6 +181,15 @@ var box = {
180
181
  return theme.dim(`${chars.tl}${chars.h.repeat(leftPad)} `) + title + theme.dim(` ${chars.h.repeat(rightPad)}${chars.tr}`);
181
182
  }
182
183
  };
184
+ var progressBar = (percent, width = 30, showPercent = true) => {
185
+ const filled = Math.round(percent / 100 * width);
186
+ const empty = width - filled;
187
+ let color = theme.success;
188
+ if (percent > 70) color = theme.warning;
189
+ if (percent > 90) color = theme.error;
190
+ const bar = color("\u2588".repeat(filled)) + theme.dim("\u2591".repeat(empty));
191
+ return showPercent ? `${bar} ${percent.toFixed(0)}%` : bar;
192
+ };
183
193
  var bubble = {
184
194
  say: (text, width = 50) => {
185
195
  const lines = [];
@@ -227,34 +237,390 @@ var categoryIcons = {
227
237
  };
228
238
  var spinnerFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
229
239
 
240
+ // src/ui/slime-animated.ts
241
+ import chalk2 from "chalk";
242
+ var C = {
243
+ P1: "#4A235A",
244
+ // Darkest edge
245
+ P2: "#7D3C98",
246
+ // Dark purple
247
+ P3: "#9B59B6",
248
+ // Main purple
249
+ P4: "#BB8FCE",
250
+ // Light purple
251
+ P5: "#D7BDE2",
252
+ // Lightest highlight
253
+ WH: "#FFFFFF",
254
+ // White (sparkles, eye shine)
255
+ BK: "#1A1A2E",
256
+ // Black (eyes, mouth)
257
+ PK: "#E91E63",
258
+ // Pink (tongue)
259
+ YL: "#F1C40F",
260
+ // Yellow (stars)
261
+ BL: "#3498DB",
262
+ // Blue (tears)
263
+ CY: "#00CED1",
264
+ // Cyan (zzz)
265
+ RD: "#E74C3C"
266
+ // Red (angry)
267
+ };
268
+ var b = (hex) => chalk2.bgHex(hex)(" ");
269
+ var dot = chalk2.hex(C.WH)("\xB7");
270
+ var star = chalk2.hex(C.WH)("\u2726");
271
+ var heart = chalk2.hex(C.PK)("\u2665");
272
+ var z = chalk2.hex(C.CY)("z");
273
+ var Z = chalk2.hex(C.CY)("Z");
274
+ var eye = chalk2.bgHex(C.BK).hex(C.WH)(" \xB7");
275
+ var shine = chalk2.bgHex(C.P3).hex(C.WH)(" \xB7");
276
+ var shine2 = chalk2.bgHex(C.P4).hex(C.WH)("\xB7 ");
277
+ var slimeFrames = {
278
+ happy: () => {
279
+ const { P1, P2, P3, P4, P5, BK, PK } = C;
280
+ return [
281
+ ` ${dot} ${dot}`,
282
+ ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
283
+ ` ${b(P5)}${b(P4)}${b(P3)}${shine2}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}${b(P5)}`,
284
+ ` ${b(P4)}${b(P3)}${eye}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${eye}${b(P3)}${b(P4)}`,
285
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${shine}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
286
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(BK)}${b(PK)}${b(BK)}${b(P3)}${b(P3)}${b(P4)}`,
287
+ ` ${b(P2)}${b(P3)}${b(P3)}${b(P3)}${shine}${b(P3)}${b(P3)}${b(P2)}`,
288
+ ` ${b(P1)}${b(P2)}${b(P2)}${b(P2)}${b(P2)}${b(P1)}`
289
+ ];
290
+ },
291
+ excited: () => {
292
+ const { P1, P2, P3, P4, P5, BK, PK, YL } = C;
293
+ const starEye = chalk2.bgHex(YL).hex(C.WH)("\u2605 ");
294
+ return [
295
+ ` ${star} ${dot} ${star} ${dot} ${star}`,
296
+ ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
297
+ ` ${b(P5)}${b(P4)}${b(P3)}${shine2}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}${b(P5)}`,
298
+ ` ${b(P4)}${b(P3)}${starEye}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${starEye}${b(P3)}${b(P4)}`,
299
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${shine}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
300
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(BK)}${b(PK)}${b(BK)}${b(P3)}${b(P3)}${b(P4)}`,
301
+ ` ${b(P2)}${b(P3)}${b(P3)}${b(P3)}${shine}${b(P3)}${b(P3)}${b(P2)}`,
302
+ ` ${b(P1)}${b(P2)}${b(P2)}${b(P2)}${b(P2)}${b(P1)}`
303
+ ];
304
+ },
305
+ love: () => {
306
+ const { P1, P2, P3, P4, P5, BK, PK } = C;
307
+ const heartEye = chalk2.bgHex(PK).hex(C.WH)("\u2665 ");
308
+ return [
309
+ ` ${heart} ${heart}`,
310
+ ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
311
+ ` ${b(P5)}${b(P4)}${b(P3)}${shine2}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}${b(P5)}`,
312
+ ` ${b(P4)}${b(P3)}${heartEye}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${heartEye}${b(P3)}${b(P4)}`,
313
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${shine}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
314
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(BK)}${b(PK)}${b(BK)}${b(P3)}${b(P3)}${b(P4)}`,
315
+ ` ${b(P2)}${b(P3)}${b(P3)}${b(P3)}${shine}${b(P3)}${b(P3)}${b(P2)}`,
316
+ ` ${b(P1)}${b(P2)}${b(P2)}${b(P2)}${b(P2)}${b(P1)}`
317
+ ];
318
+ },
319
+ sleepy: () => {
320
+ const { P1, P2, P3, P4, P5, BK } = C;
321
+ const closedEye = chalk2.bgHex(P3).hex(BK)("\u2500\u2500");
322
+ return [
323
+ ` ${z} ${z} ${Z}`,
324
+ ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
325
+ ` ${b(P5)}${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}${b(P5)}`,
326
+ ` ${b(P4)}${b(P3)}${closedEye}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${closedEye}${b(P3)}${b(P4)}`,
327
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
328
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(BK)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
329
+ ` ${b(P2)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P2)}`,
330
+ ` ${b(P1)}${b(P2)}${b(P2)}${b(P2)}${b(P2)}${b(P1)}`
331
+ ];
332
+ },
333
+ thinking: () => {
334
+ const { P1, P2, P3, P4, P5, BK, YL } = C;
335
+ const thinkEye = chalk2.bgHex(C.BK).hex(C.WH)(" \xB7");
336
+ const lookUpEye = chalk2.bgHex(C.BK).hex(C.WH)("\xB7 ");
337
+ return [
338
+ ` ${chalk2.hex(YL)("?")}`,
339
+ ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
340
+ ` ${b(P5)}${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}${b(P5)}`,
341
+ ` ${b(P4)}${b(P3)}${thinkEye}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${lookUpEye}${b(P3)}${b(P4)}`,
342
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
343
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(BK)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
344
+ ` ${b(P2)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P2)}`,
345
+ ` ${b(P1)}${b(P2)}${b(P2)}${b(P2)}${b(P2)}${b(P1)}`
346
+ ];
347
+ },
348
+ surprised: () => {
349
+ const { P1, P2, P3, P4, P5, BK, YL } = C;
350
+ const bigEye = chalk2.bgHex(BK).hex(C.WH)("\u25C9 ");
351
+ return [
352
+ ` ${chalk2.hex(YL)("!!")}`,
353
+ ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
354
+ ` ${b(P5)}${b(P4)}${b(P3)}${shine2}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}${b(P5)}`,
355
+ ` ${b(P4)}${b(P3)}${bigEye}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${bigEye}${b(P3)}${b(P4)}`,
356
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${shine}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
357
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(BK)}${b(BK)}${b(BK)}${b(P3)}${b(P3)}${b(P4)}`,
358
+ ` ${b(P2)}${b(P3)}${b(P3)}${b(P3)}${shine}${b(P3)}${b(P3)}${b(P2)}`,
359
+ ` ${b(P1)}${b(P2)}${b(P2)}${b(P2)}${b(P2)}${b(P1)}`
360
+ ];
361
+ },
362
+ sad: () => {
363
+ const { P1, P2, P3, P4, P5, BK, BL } = C;
364
+ const sadEye = chalk2.bgHex(BK).hex(C.WH)(" \xB7");
365
+ const tear = chalk2.bgHex(BL)(" ");
366
+ return [
367
+ ` ${dot} ${dot} ${dot}`,
368
+ ` ${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}`,
369
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
370
+ ` ${b(P4)}${b(P3)}${sadEye}${tear}${b(P3)}${b(P3)}${tear}${sadEye}${b(P3)}${b(P4)}`,
371
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
372
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(BK)}${b(BK)}${b(BK)}${b(P3)}${b(P3)}${b(P4)}`,
373
+ ` ${b(P2)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P2)}`,
374
+ ` ${b(P1)}${b(P2)}${b(P2)}${b(P2)}${b(P2)}${b(P1)}`
375
+ ];
376
+ },
377
+ wink: () => {
378
+ const { P1, P2, P3, P4, P5, BK, PK } = C;
379
+ const winkEye = chalk2.bgHex(P3).hex(BK)("> ");
380
+ return [
381
+ ` ${star} ${dot}`,
382
+ ` ${b(P5)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P5)}`,
383
+ ` ${b(P5)}${b(P4)}${b(P3)}${shine2}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}${b(P5)}`,
384
+ ` ${b(P4)}${b(P3)}${eye}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${winkEye}${b(P3)}${b(P4)}`,
385
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${shine}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
386
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(BK)}${b(PK)}${b(BK)}${b(P3)}${b(P3)}${b(P4)}`,
387
+ ` ${b(P2)}${b(P3)}${b(P3)}${b(P3)}${shine}${b(P3)}${b(P3)}${b(P2)}`,
388
+ ` ${b(P1)}${b(P2)}${b(P2)}${b(P2)}${b(P2)}${b(P1)}`
389
+ ];
390
+ },
391
+ angry: () => {
392
+ const { P1, P2, P3, P4, BK, RD } = C;
393
+ const angryEye = chalk2.bgHex(BK).hex(RD)("> ");
394
+ const angryEye2 = chalk2.bgHex(BK).hex(RD)(" <");
395
+ return [
396
+ ` ${chalk2.hex(RD)("# @!")}`,
397
+ ` ${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}${b(P4)}`,
398
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
399
+ ` ${b(P4)}${b(P3)}${angryEye}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${angryEye2}${b(P3)}${b(P4)}`,
400
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P4)}`,
401
+ ` ${b(P4)}${b(P3)}${b(P3)}${b(P3)}${b(BK)}${b(BK)}${b(BK)}${b(P3)}${b(P3)}${b(P4)}`,
402
+ ` ${b(P2)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P3)}${b(P2)}`,
403
+ ` ${b(P1)}${b(P2)}${b(P2)}${b(P2)}${b(P2)}${b(P1)}`
404
+ ];
405
+ }
406
+ };
407
+ var greetings = [
408
+ "Hiii~! I'm Zammy!",
409
+ "Ready to get stuff done?",
410
+ "*bounces* What's the plan?",
411
+ "Type / to see commands!",
412
+ "*jiggles excitedly* Let's go!",
413
+ "*sparkles* Hi friend!"
414
+ ];
415
+ var lateNightGreetings = [
416
+ "*yawns* Burning the midnight oil?",
417
+ "zzZ... oh! You're still up?",
418
+ "*sleepy bounce* Late night coding?",
419
+ "The best code happens at 3am~"
420
+ ];
421
+ var morningGreetings = [
422
+ "*stretches* Good morning~!",
423
+ "Rise and shine!",
424
+ "*bounces awake* New day!",
425
+ "Morning! Coffee first?"
426
+ ];
427
+ function getGreeting() {
428
+ const hour = (/* @__PURE__ */ new Date()).getHours();
429
+ if (hour >= 0 && hour < 5) {
430
+ return lateNightGreetings[Math.floor(Math.random() * lateNightGreetings.length)];
431
+ } else if (hour >= 5 && hour < 12) {
432
+ return morningGreetings[Math.floor(Math.random() * morningGreetings.length)];
433
+ }
434
+ return greetings[Math.floor(Math.random() * greetings.length)];
435
+ }
436
+ function getStartupMood() {
437
+ const hour = (/* @__PURE__ */ new Date()).getHours();
438
+ if (hour >= 0 && hour < 5) return "sleepy";
439
+ return "happy";
440
+ }
441
+ var miniSlime = {
442
+ happy: chalk2.hex(C.P3)("(") + chalk2.hex(C.BK)("\u25D5") + chalk2.hex(C.P3)("\u1D17") + chalk2.hex(C.BK)("\u25D5") + chalk2.hex(C.P3)(")"),
443
+ excited: chalk2.hex(C.P3)("(") + chalk2.hex(C.YL)("\u2605") + chalk2.hex(C.P3)("\u1D17") + chalk2.hex(C.YL)("\u2605") + chalk2.hex(C.P3)(")"),
444
+ love: chalk2.hex(C.P3)("(") + chalk2.hex(C.PK)("\u2665") + chalk2.hex(C.P3)("\u1D17") + chalk2.hex(C.PK)("\u2665") + chalk2.hex(C.P3)(")"),
445
+ 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"),
446
+ sad: chalk2.hex(C.P3)("(") + chalk2.hex(C.BK)("\u25D5") + chalk2.hex(C.P3)("\uFE35") + chalk2.hex(C.BK)("\u25D5") + chalk2.hex(C.P3)(")"),
447
+ surprised: chalk2.hex(C.P3)("(") + chalk2.hex(C.BK)("\u25CE") + chalk2.hex(C.P3)("\u25CB") + chalk2.hex(C.BK)("\u25CE") + chalk2.hex(C.P3)(")!"),
448
+ wink: chalk2.hex(C.P3)("(") + chalk2.hex(C.BK)("\u25D5") + chalk2.hex(C.P3)("\u1D17") + chalk2.hex(C.BK)(">") + chalk2.hex(C.P3)(")"),
449
+ thinking: chalk2.hex(C.P3)("(") + chalk2.hex(C.BK)("\u25D5") + chalk2.hex(C.P3)("\uFF5E") + chalk2.hex(C.BK)("\u25D4") + chalk2.hex(C.P3)(")"),
450
+ angry: chalk2.hex(C.P3)("(") + chalk2.hex(C.RD)(">") + chalk2.hex(C.P3)("_") + chalk2.hex(C.RD)("<") + chalk2.hex(C.P3)(")")
451
+ };
452
+ var validMoods = Object.keys(slimeFrames);
453
+ function react(mood, message) {
454
+ const slime = miniSlime[mood] || miniSlime.happy;
455
+ if (message) {
456
+ console.log(` ${slime} ${message}`);
457
+ } else {
458
+ console.log(` ${slime}`);
459
+ }
460
+ }
461
+ var MIN_WIDTH_FOR_MASCOT = 50;
462
+ function showMascot(mood) {
463
+ const termWidth = process.stdout.columns || 80;
464
+ if (termWidth < MIN_WIDTH_FOR_MASCOT) {
465
+ react(mood);
466
+ return;
467
+ }
468
+ const frameFunc = slimeFrames[mood];
469
+ if (frameFunc) {
470
+ const art = frameFunc();
471
+ console.log("");
472
+ art.forEach((line) => console.log(" " + line));
473
+ console.log("");
474
+ }
475
+ }
476
+ function getMoodFromText(text) {
477
+ const lower = text.toLowerCase();
478
+ if (/\b(thanks|thank you|love|love you|thx|ty|<3|heart)\b/.test(lower)) {
479
+ return "love";
480
+ }
481
+ if (/\b(awesome|amazing|wow|cool|nice|great|perfect|yay|woohoo|!\s*$)\b/.test(lower)) {
482
+ return "excited";
483
+ }
484
+ if (/\b(tired|sleepy|zzz|night|late|exhausted)\b/.test(lower)) {
485
+ return "sleepy";
486
+ }
487
+ if (/\b(angry|mad|hate|stupid|wtf|damn|crap|sucks|ugh|argh|grr)\b|:\(/.test(lower)) {
488
+ return "angry";
489
+ }
490
+ if (/\b(sad|sorry|fail|broke|wrong)\b/.test(lower)) {
491
+ return "sad";
492
+ }
493
+ if (/\b(hmm|think|wonder|maybe|idk|not sure|confused|\?$)\b/.test(lower)) {
494
+ return "thinking";
495
+ }
496
+ return null;
497
+ }
498
+
230
499
  // src/ui/banner.ts
231
- async function displayBanner() {
232
- return new Promise((resolve3) => {
500
+ var C2 = {
501
+ // Purple gradient (light to dark)
502
+ P1: "#4A235A",
503
+ // Darkest edge
504
+ P2: "#7D3C98",
505
+ // Dark purple
506
+ P3: "#9B59B6",
507
+ // Main purple
508
+ P4: "#BB8FCE",
509
+ // Light purple
510
+ P5: "#D7BDE2",
511
+ // Lightest
512
+ // Accents
513
+ WH: "#FFFFFF",
514
+ // White (sparkles, eye highlight)
515
+ BK: "#1A1A2E",
516
+ // Black (eyes, mouth)
517
+ PK: "#E91E63"
518
+ // Pink (tongue)
519
+ };
520
+ var b2 = (hex) => chalk3.bgHex(hex)(" ");
521
+ var dot2 = chalk3.hex(C2.WH)("\xB7");
522
+ function getSlimeLines(isBlinking, _mood) {
523
+ const { P1, P2, P3, P4, P5, WH, BK, PK } = C2;
524
+ const openEye = chalk3.bgHex(BK).hex(WH)(" \xB7");
525
+ const closedEye = chalk3.bgHex(P3).hex(BK)("\u2500\u2500");
526
+ const eyeL = isBlinking ? closedEye : openEye;
527
+ const eyeR = isBlinking ? closedEye : openEye;
528
+ const shine3 = chalk3.bgHex(P3).hex(WH)(" \xB7");
529
+ const shine22 = chalk3.bgHex(P4).hex(WH)("\xB7 ");
530
+ const miniBlob = `${b2(P3)}`;
531
+ return [
532
+ ` ${dot2} ${dot2}`,
533
+ ` ${b2(P5)}${b2(P4)}${b2(P4)}${b2(P4)}${b2(P4)}${b2(P4)}${b2(P4)}${b2(P5)}`,
534
+ ` ${b2(P5)}${b2(P4)}${b2(P3)}${shine22}${b2(P3)}${b2(P3)}${b2(P3)}${b2(P3)}${b2(P4)}${b2(P5)}`,
535
+ ` ${b2(P4)}${b2(P3)}${eyeL}${b2(P3)}${b2(P3)}${b2(P3)}${b2(P3)}${eyeR}${b2(P3)}${b2(P4)}`,
536
+ ` ${b2(P4)}${b2(P3)}${b2(P3)}${b2(P3)}${shine3}${b2(P3)}${b2(P3)}${b2(P3)}${b2(P3)}${b2(P4)}`,
537
+ ` ${b2(P4)}${b2(P3)}${b2(P3)}${b2(P3)}${b2(BK)}${b2(PK)}${b2(BK)}${b2(P3)}${b2(P3)}${b2(P4)}`,
538
+ ` ${b2(P2)}${b2(P3)}${b2(P3)}${b2(P3)}${shine3}${b2(P3)}${b2(P3)}${b2(P2)}`,
539
+ ` ${b2(P1)}${b2(P2)}${b2(P2)}${b2(P2)}${b2(P2)}${b2(P1)} ${miniBlob}`
540
+ ];
541
+ }
542
+ var MIN_WIDTH_FOR_MASCOT2 = 90;
543
+ var MIN_WIDTH_FOR_FULL_LOGO = 55;
544
+ var MIN_WIDTH_FOR_COMPACT = 30;
545
+ async function displayBanner(simple = false) {
546
+ return new Promise((resolve6) => {
547
+ const termWidth = process.stdout.columns || 80;
233
548
  figlet("ZAMMY", {
234
549
  font: "ANSI Shadow",
235
550
  horizontalLayout: "default"
236
- }, (err, data) => {
551
+ }, async (err, data) => {
237
552
  console.log("");
238
- if (err || !data) {
239
- console.log(theme.gradient(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557"));
240
- console.log(theme.gradient(" \u255A\u2550\u2550\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D"));
241
- console.log(theme.gradient(" \u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2554\u255D "));
242
- console.log(theme.gradient(" \u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2554\u255D "));
243
- console.log(theme.gradient(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551 "));
244
- console.log(theme.gradient(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D "));
553
+ const greeting = getGreeting();
554
+ const mood = getStartupMood();
555
+ if (termWidth < MIN_WIDTH_FOR_COMPACT) {
556
+ console.log(theme.gradient(" ZAMMY"));
557
+ console.log(theme.secondary(` "${greeting}"`));
558
+ console.log(theme.dim(" Type /help for commands"));
559
+ console.log("");
560
+ resolve6();
561
+ return;
562
+ }
563
+ let figletLines = [];
564
+ if (err || !data || termWidth < MIN_WIDTH_FOR_FULL_LOGO) {
565
+ if (termWidth < MIN_WIDTH_FOR_FULL_LOGO) {
566
+ figletLines = [
567
+ "\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557",
568
+ "\u2551 Z A M M Y \u2551",
569
+ "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"
570
+ ];
571
+ } else {
572
+ figletLines = [
573
+ "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557",
574
+ "\u255A\u2550\u2550\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D",
575
+ " \u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2554\u255D ",
576
+ " \u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2554\u255D ",
577
+ "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551 ",
578
+ "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D "
579
+ ];
580
+ }
245
581
  } else {
246
- data.split("\n").forEach((line) => {
247
- console.log(theme.gradient(line));
248
- });
582
+ figletLines = data.split("\n").filter((line) => line.trim());
249
583
  }
584
+ const showMascot2 = !simple && termWidth >= MIN_WIDTH_FOR_MASCOT2;
585
+ if (!showMascot2) {
586
+ figletLines.forEach((line) => console.log(" " + theme.gradient(line)));
587
+ console.log("");
588
+ console.log(theme.secondary(` "${greeting}"`));
589
+ console.log("");
590
+ console.log(theme.dim(` ${symbols.arrow} Type ${theme.primary("/")} to browse commands or ${theme.primary("/help")} for full list`));
591
+ console.log(theme.dim(` ${symbols.arrow} Shell commands start with ${theme.primary("!")} (e.g., ${theme.primary("!ls")}, ${theme.primary("!git")})`));
592
+ console.log("");
593
+ resolve6();
594
+ return;
595
+ }
596
+ const figletWidth = 50;
597
+ const paddedFiglet = figletLines.map((line) => line.padEnd(figletWidth));
598
+ const blinkSequence = [false, false, false, true, false, false];
599
+ const frameTime = 180;
600
+ process.stdout.write("\x1B[?25l");
601
+ for (let frame = 0; frame < blinkSequence.length; frame++) {
602
+ const isBlinking = blinkSequence[frame];
603
+ const slimeLines = getSlimeLines(isBlinking, mood);
604
+ if (frame > 0) {
605
+ const totalLines = Math.max(paddedFiglet.length, slimeLines.length) + 1;
606
+ process.stdout.write(`\x1B[${totalLines}A`);
607
+ }
608
+ const maxLines = Math.max(paddedFiglet.length, slimeLines.length);
609
+ for (let i = 0; i < maxLines; i++) {
610
+ const figLine = paddedFiglet[i] || "".padEnd(figletWidth);
611
+ const slimeLine = slimeLines[i] || "";
612
+ console.log(" " + theme.gradient(figLine) + " " + slimeLine);
613
+ }
614
+ console.log("");
615
+ await new Promise((r) => setTimeout(r, frameTime));
616
+ }
617
+ process.stdout.write("\x1B[?25h");
618
+ console.log(theme.secondary(` "${greeting}"`));
250
619
  console.log("");
251
- console.log(` ${symbols.sparkle} ${theme.secondary("Your slice-of-life terminal companion")} ${symbols.sparkle}`);
252
- console.log("");
253
- console.log(theme.dim(` ${symbols.arrow} Type ${theme.primary("/")} to browse commands (use ${theme.primary("\u2191\u2193")} to navigate, ${theme.primary("Tab")} to select)`));
254
- console.log(theme.dim(` ${symbols.arrow} Type ${theme.primary("/help")} for full command list`));
255
- console.log(theme.dim(` ${symbols.arrow} Shell commands start with ${theme.primary("!")} (e.g., ${theme.primary("!ls")}, ${theme.primary("!cd")})`));
620
+ console.log(theme.dim(` ${symbols.arrow} Type ${theme.primary("/")} to browse commands or ${theme.primary("/help")} for full list`));
621
+ console.log(theme.dim(` ${symbols.arrow} Shell commands start with ${theme.primary("!")} (e.g., ${theme.primary("!ls")}, ${theme.primary("!git")})`));
256
622
  console.log("");
257
- resolve3();
623
+ resolve6();
258
624
  });
259
625
  });
260
626
  }
@@ -267,7 +633,17 @@ function getPrompt() {
267
633
  // src/commands/registry.ts
268
634
  var commands = /* @__PURE__ */ new Map();
269
635
  function registerCommand(command) {
270
- commands.set(command.name, command);
636
+ commands.set(command.name, { ...command, source: "core" });
637
+ }
638
+ function registerPluginCommand(command, pluginName) {
639
+ commands.set(command.name, { ...command, source: "plugin", pluginName });
640
+ }
641
+ function unregisterPluginCommands(pluginName) {
642
+ for (const [name, cmd] of commands.entries()) {
643
+ if (cmd.source === "plugin" && cmd.pluginName === pluginName) {
644
+ commands.delete(name);
645
+ }
646
+ }
271
647
  }
272
648
  function getCommand(name) {
273
649
  return commands.get(name);
@@ -275,14 +651,29 @@ function getCommand(name) {
275
651
  function getAllCommands() {
276
652
  return Array.from(commands.values());
277
653
  }
654
+ function getPluginCommands() {
655
+ return Array.from(commands.values()).filter((cmd) => cmd.source === "plugin");
656
+ }
657
+ function checkCommandConflict(name) {
658
+ const existing = commands.get(name);
659
+ if (!existing) {
660
+ return { exists: false };
661
+ }
662
+ return {
663
+ exists: true,
664
+ source: existing.source,
665
+ pluginName: existing.pluginName
666
+ };
667
+ }
278
668
 
279
669
  // src/commands/utilities/help.ts
280
670
  var categories = {
281
671
  "Utilities": ["help", "exit", "calc", "password", "stats", "time", "countdown", "timer", "todo", "history"],
282
- "Fun": ["joke", "quote", "fortune", "dice", "flip", "pomodoro"],
672
+ "Fun": ["joke", "quote", "fortune", "dice", "flip", "pomodoro", "zammy"],
283
673
  "Creative": ["asciiart", "figlet", "lorem", "color"],
284
674
  "Dev": ["hash", "uuid", "encode"],
285
- "Info": ["weather"]
675
+ "Info": ["weather"],
676
+ "System": ["plugin"]
286
677
  };
287
678
  registerCommand({
288
679
  name: "help",
@@ -335,8 +726,24 @@ registerCommand({
335
726
  }
336
727
  console.log("");
337
728
  }
729
+ const pluginCmds = getPluginCommands();
730
+ if (pluginCmds.length > 0) {
731
+ console.log(` ${symbols.gear} ${theme.b.secondary("Plugins")}`);
732
+ console.log(theme.dim(" " + "\u2500".repeat(46)));
733
+ for (const cmd of pluginCmds) {
734
+ const paddedName = cmd.name.padEnd(maxNameLength + 2);
735
+ const pluginBadge = cmd.pluginName ? theme.dim(`[${cmd.pluginName}]`) : "";
736
+ console.log(
737
+ ` ${theme.command("/" + paddedName)} ${theme.dim("\u2502")} ${theme.dim(cmd.description)} ${pluginBadge}`
738
+ );
739
+ }
740
+ console.log("");
741
+ }
338
742
  const categorizedNames = Object.values(categories).flat();
339
- const uncategorized = commands2.filter((c) => !categorizedNames.includes(c.name));
743
+ const pluginCmdNames = pluginCmds.map((c) => c.name);
744
+ const uncategorized = commands2.filter(
745
+ (c) => !categorizedNames.includes(c.name) && !pluginCmdNames.includes(c.name) && c.source === "core"
746
+ );
340
747
  if (uncategorized.length > 0) {
341
748
  console.log(` ${symbols.folder} ${theme.b.secondary("Other")}`);
342
749
  console.log(theme.dim(" " + "\u2500".repeat(46)));
@@ -785,7 +1192,7 @@ registerCommand({
785
1192
  console.log("");
786
1193
  let remaining = totalSeconds;
787
1194
  let spinnerIndex = 0;
788
- return new Promise((resolve3) => {
1195
+ return new Promise((resolve6) => {
789
1196
  const interval = setInterval(() => {
790
1197
  process.stdout.write("\r\x1B[K");
791
1198
  if (remaining <= 0) {
@@ -793,7 +1200,7 @@ registerCommand({
793
1200
  console.log(` ${symbols.sparkle} ${theme.success("TIME'S UP!")} ${symbols.sparkle}`);
794
1201
  console.log("");
795
1202
  process.stdout.write("\x07");
796
- resolve3();
1203
+ resolve6();
797
1204
  return;
798
1205
  }
799
1206
  const spinner = spinnerFrames[spinnerIndex % spinnerFrames.length];
@@ -1111,58 +1518,368 @@ registerCommand({
1111
1518
  }
1112
1519
  });
1113
1520
 
1521
+ // src/handlers/utilities/env.ts
1522
+ function getAllEnvVars() {
1523
+ return Object.entries(process.env).filter(([, value]) => value !== void 0).map(([name, value]) => ({ name, value })).sort((a, b3) => a.name.localeCompare(b3.name));
1524
+ }
1525
+ function getEnvVar(name) {
1526
+ const exactMatch = process.env[name];
1527
+ if (exactMatch !== void 0) return exactMatch;
1528
+ const upperName = name.toUpperCase();
1529
+ for (const [key, value] of Object.entries(process.env)) {
1530
+ if (key.toUpperCase() === upperName) {
1531
+ return value;
1532
+ }
1533
+ }
1534
+ return void 0;
1535
+ }
1536
+ function searchEnvVars(query) {
1537
+ const lowerQuery = query.toLowerCase();
1538
+ return getAllEnvVars().filter(
1539
+ (env) => env.name.toLowerCase().includes(lowerQuery) || env.value.toLowerCase().includes(lowerQuery)
1540
+ );
1541
+ }
1542
+ function getPathEntries() {
1543
+ const pathVar = process.env.PATH || process.env.Path || "";
1544
+ const separator = process.platform === "win32" ? ";" : ":";
1545
+ return pathVar.split(separator).filter(Boolean);
1546
+ }
1547
+
1548
+ // src/commands/utilities/env.ts
1549
+ registerCommand({
1550
+ name: "env",
1551
+ description: "View environment variables",
1552
+ usage: "/env [name|search|path]",
1553
+ async execute(args2) {
1554
+ const action = args2[0];
1555
+ console.log("");
1556
+ if (!action) {
1557
+ const vars = getAllEnvVars();
1558
+ console.log(` ${symbols.sparkle} ${theme.gradient("ENVIRONMENT VARIABLES")} ${theme.dim(`(${vars.length})`)}`);
1559
+ console.log("");
1560
+ for (const env of vars.slice(0, 30)) {
1561
+ const displayValue = env.value.length > 50 ? env.value.slice(0, 47) + "..." : env.value;
1562
+ console.log(` ${theme.primary(env.name.padEnd(20))} ${theme.dim("=")} ${displayValue}`);
1563
+ }
1564
+ if (vars.length > 30) {
1565
+ console.log("");
1566
+ console.log(` ${theme.dim(`... and ${vars.length - 30} more. Use /env search <query> to filter.`)}`);
1567
+ }
1568
+ console.log("");
1569
+ return;
1570
+ }
1571
+ if (action.toLowerCase() === "path") {
1572
+ const paths = getPathEntries();
1573
+ console.log(` ${symbols.sparkle} ${theme.gradient("PATH ENTRIES")} ${theme.dim(`(${paths.length})`)}`);
1574
+ console.log("");
1575
+ paths.forEach((p, i) => {
1576
+ console.log(` ${theme.dim(`${(i + 1).toString().padStart(2)}.`)} ${theme.primary(p)}`);
1577
+ });
1578
+ console.log("");
1579
+ return;
1580
+ }
1581
+ if (action.toLowerCase() === "search" && args2[1]) {
1582
+ const query = args2.slice(1).join(" ");
1583
+ const results = searchEnvVars(query);
1584
+ console.log(` ${symbols.sparkle} ${theme.gradient(`SEARCH: "${query}"`)} ${theme.dim(`(${results.length} matches)`)}`);
1585
+ console.log("");
1586
+ if (results.length === 0) {
1587
+ console.log(` ${theme.dim("No matches found")}`);
1588
+ } else {
1589
+ for (const env of results) {
1590
+ const displayValue = env.value.length > 50 ? env.value.slice(0, 47) + "..." : env.value;
1591
+ console.log(` ${theme.primary(env.name.padEnd(20))} ${theme.dim("=")} ${displayValue}`);
1592
+ }
1593
+ }
1594
+ console.log("");
1595
+ return;
1596
+ }
1597
+ const value = getEnvVar(action);
1598
+ if (value !== void 0) {
1599
+ console.log(` ${theme.primary(action)} ${theme.dim("=")}`);
1600
+ console.log("");
1601
+ if (value.includes(process.platform === "win32" ? ";" : ":") && value.length > 100) {
1602
+ const separator = process.platform === "win32" ? ";" : ":";
1603
+ const parts = value.split(separator);
1604
+ parts.forEach((p, i) => {
1605
+ console.log(` ${theme.dim(`${(i + 1).toString().padStart(2)}.`)} ${p}`);
1606
+ });
1607
+ } else {
1608
+ console.log(` ${theme.success(value)}`);
1609
+ }
1610
+ } else {
1611
+ console.log(` ${symbols.cross} ${theme.error(`Environment variable not found: ${action}`)}`);
1612
+ }
1613
+ console.log("");
1614
+ }
1615
+ });
1616
+
1617
+ // src/handlers/utilities/size.ts
1618
+ import { statSync, readdirSync, existsSync as existsSync3 } from "fs";
1619
+ import { join as join3, basename } from "path";
1620
+ function formatBytes2(bytes) {
1621
+ if (bytes === 0) return "0 B";
1622
+ const units = ["B", "KB", "MB", "GB", "TB"];
1623
+ const i = Math.floor(Math.log(bytes) / Math.log(1024));
1624
+ const size = bytes / Math.pow(1024, i);
1625
+ return `${size.toFixed(i > 0 ? 1 : 0)} ${units[i]}`;
1626
+ }
1627
+ function getSize(path) {
1628
+ if (!existsSync3(path)) return null;
1629
+ try {
1630
+ const stats = statSync(path);
1631
+ if (stats.isFile()) {
1632
+ return {
1633
+ path,
1634
+ name: basename(path),
1635
+ size: stats.size,
1636
+ isDirectory: false
1637
+ };
1638
+ }
1639
+ if (stats.isDirectory()) {
1640
+ return getDirSize(path);
1641
+ }
1642
+ return null;
1643
+ } catch {
1644
+ return null;
1645
+ }
1646
+ }
1647
+ function getDirSize(dirPath) {
1648
+ const children = [];
1649
+ let totalSize = 0;
1650
+ try {
1651
+ const entries = readdirSync(dirPath, { withFileTypes: true });
1652
+ for (const entry of entries) {
1653
+ const entryPath = join3(dirPath, entry.name);
1654
+ try {
1655
+ if (entry.isFile()) {
1656
+ const stats = statSync(entryPath);
1657
+ totalSize += stats.size;
1658
+ children.push({
1659
+ path: entryPath,
1660
+ name: entry.name,
1661
+ size: stats.size,
1662
+ isDirectory: false
1663
+ });
1664
+ } else if (entry.isDirectory()) {
1665
+ if (["node_modules", ".git", "dist", "build", ".next", "coverage"].includes(entry.name)) {
1666
+ const subSize = getQuickDirSize(entryPath);
1667
+ totalSize += subSize;
1668
+ children.push({
1669
+ path: entryPath,
1670
+ name: entry.name,
1671
+ size: subSize,
1672
+ isDirectory: true
1673
+ });
1674
+ } else {
1675
+ const subInfo = getDirSize(entryPath);
1676
+ totalSize += subInfo.size;
1677
+ children.push(subInfo);
1678
+ }
1679
+ }
1680
+ } catch {
1681
+ }
1682
+ }
1683
+ } catch {
1684
+ }
1685
+ children.sort((a, b3) => b3.size - a.size);
1686
+ return {
1687
+ path: dirPath,
1688
+ name: basename(dirPath),
1689
+ size: totalSize,
1690
+ isDirectory: true,
1691
+ children
1692
+ };
1693
+ }
1694
+ function getQuickDirSize(dirPath) {
1695
+ let totalSize = 0;
1696
+ try {
1697
+ const entries = readdirSync(dirPath, { withFileTypes: true });
1698
+ for (const entry of entries) {
1699
+ const entryPath = join3(dirPath, entry.name);
1700
+ try {
1701
+ if (entry.isFile()) {
1702
+ totalSize += statSync(entryPath).size;
1703
+ } else if (entry.isDirectory()) {
1704
+ totalSize += getQuickDirSize(entryPath);
1705
+ }
1706
+ } catch {
1707
+ }
1708
+ }
1709
+ } catch {
1710
+ }
1711
+ return totalSize;
1712
+ }
1713
+ function findLargestFiles(dirPath, count = 10) {
1714
+ const allFiles = [];
1715
+ function collectFiles(dir) {
1716
+ try {
1717
+ const entries = readdirSync(dir, { withFileTypes: true });
1718
+ for (const entry of entries) {
1719
+ const entryPath = join3(dir, entry.name);
1720
+ try {
1721
+ if (entry.isFile()) {
1722
+ const stats = statSync(entryPath);
1723
+ allFiles.push({
1724
+ path: entryPath,
1725
+ name: entry.name,
1726
+ size: stats.size,
1727
+ isDirectory: false
1728
+ });
1729
+ } else if (entry.isDirectory()) {
1730
+ if (!["node_modules", ".git"].includes(entry.name)) {
1731
+ collectFiles(entryPath);
1732
+ }
1733
+ }
1734
+ } catch {
1735
+ }
1736
+ }
1737
+ } catch {
1738
+ }
1739
+ }
1740
+ collectFiles(dirPath);
1741
+ allFiles.sort((a, b3) => b3.size - a.size);
1742
+ return allFiles.slice(0, count);
1743
+ }
1744
+
1745
+ // src/commands/utilities/size.ts
1746
+ import { resolve } from "path";
1747
+ registerCommand({
1748
+ name: "size",
1749
+ description: "Analyze file/folder sizes",
1750
+ usage: "/size [path] [--top N]",
1751
+ async execute(args2) {
1752
+ const targetPath = args2[0] || ".";
1753
+ const absPath = resolve(targetPath);
1754
+ const topIndex = args2.indexOf("--top");
1755
+ const showTop = topIndex !== -1 ? parseInt(args2[topIndex + 1]) || 10 : 0;
1756
+ console.log("");
1757
+ if (showTop > 0) {
1758
+ console.log(` ${symbols.sparkle} ${theme.gradient("LARGEST FILES")}`);
1759
+ console.log(` ${theme.dim(`in ${absPath}`)}`);
1760
+ console.log("");
1761
+ const largestFiles = findLargestFiles(absPath, showTop);
1762
+ if (largestFiles.length === 0) {
1763
+ console.log(` ${theme.dim("No files found")}`);
1764
+ } else {
1765
+ const maxSize = largestFiles[0].size;
1766
+ for (let i = 0; i < largestFiles.length; i++) {
1767
+ const file = largestFiles[i];
1768
+ const percent = file.size / maxSize * 100;
1769
+ const bar = progressBar(percent, 20);
1770
+ const relativePath = file.path.replace(absPath, ".").replace(/\\/g, "/");
1771
+ console.log(
1772
+ ` ${theme.dim(`${(i + 1).toString().padStart(2)}.`)} ${bar} ${theme.primary(formatBytes2(file.size).padStart(10))} ${relativePath}`
1773
+ );
1774
+ }
1775
+ }
1776
+ console.log("");
1777
+ return;
1778
+ }
1779
+ const info = getSize(absPath);
1780
+ if (!info) {
1781
+ console.log(` ${symbols.cross} ${theme.error(`Path not found: ${absPath}`)}`);
1782
+ console.log("");
1783
+ return;
1784
+ }
1785
+ console.log(` ${symbols.sparkle} ${theme.gradient("SIZE ANALYSIS")}`);
1786
+ console.log(` ${theme.dim(absPath)}`);
1787
+ console.log("");
1788
+ if (!info.isDirectory) {
1789
+ console.log(` ${theme.primary(info.name)}: ${theme.success(formatBytes2(info.size))}`);
1790
+ } else {
1791
+ console.log(` ${theme.secondary("Total:")} ${theme.success(formatBytes2(info.size))}`);
1792
+ console.log("");
1793
+ if (info.children && info.children.length > 0) {
1794
+ const maxSize = info.children[0].size;
1795
+ const displayCount = Math.min(15, info.children.length);
1796
+ for (let i = 0; i < displayCount; i++) {
1797
+ const child = info.children[i];
1798
+ const percent = child.size / maxSize * 100;
1799
+ const bar = progressBar(percent, 15);
1800
+ const icon = child.isDirectory ? symbols.folder : symbols.bullet;
1801
+ console.log(
1802
+ ` ${bar} ${theme.primary(formatBytes2(child.size).padStart(10))} ${icon} ${child.name}`
1803
+ );
1804
+ }
1805
+ if (info.children.length > displayCount) {
1806
+ console.log("");
1807
+ console.log(` ${theme.dim(`... and ${info.children.length - displayCount} more items`)}`);
1808
+ }
1809
+ } else {
1810
+ console.log(` ${theme.dim("Directory is empty")}`);
1811
+ }
1812
+ }
1813
+ console.log("");
1814
+ console.log(` ${theme.dim("Tip: /size . --top 10 shows largest files")}`);
1815
+ console.log("");
1816
+ }
1817
+ });
1818
+
1114
1819
  // src/commands/fun/joke.ts
1115
1820
  var fallbackJokes = [
1116
1821
  { setup: "Why do programmers prefer dark mode?", punchline: "Because light attracts bugs!" },
1117
1822
  { setup: "Why do Java developers wear glasses?", punchline: "Because they can't C#!" },
1118
1823
  { setup: "A SQL query walks into a bar, walks up to two tables and asks...", punchline: "Can I join you?" },
1119
1824
  { setup: "Why did the developer go broke?", punchline: "Because he used up all his cache!" },
1120
- { setup: "How many programmers does it take to change a light bulb?", punchline: "None, that's a hardware problem!" }
1825
+ { setup: "How many programmers does it take to change a light bulb?", punchline: "None, that's a hardware problem!" },
1826
+ { setup: "Why do programmers hate nature?", punchline: "It has too many bugs!" },
1827
+ { setup: "What's a programmer's favorite hangout place?", punchline: "Foo Bar!" },
1828
+ { setup: "Why was the JavaScript developer sad?", punchline: "Because he didn't Node how to Express himself!" },
1829
+ { setup: "What do you call a computer that sings?", punchline: "A-Dell!" },
1830
+ { setup: "Why did the developer quit his job?", punchline: "Because he didn't get arrays (a raise)!" }
1121
1831
  ];
1832
+ async function fetchJoke() {
1833
+ try {
1834
+ const response = await fetch("https://v2.jokeapi.dev/joke/Programming?type=twopart&safe-mode", {
1835
+ signal: AbortSignal.timeout(3e3)
1836
+ });
1837
+ if (response.ok) {
1838
+ const data = await response.json();
1839
+ if (!data.error && data.setup && data.delivery) {
1840
+ return { setup: data.setup, punchline: data.delivery };
1841
+ }
1842
+ }
1843
+ } catch {
1844
+ }
1845
+ try {
1846
+ const response = await fetch("https://official-joke-api.appspot.com/jokes/programming/random", {
1847
+ signal: AbortSignal.timeout(3e3)
1848
+ });
1849
+ if (response.ok) {
1850
+ const data = await response.json();
1851
+ if (data && data[0]) {
1852
+ return { setup: data[0].setup, punchline: data[0].punchline };
1853
+ }
1854
+ }
1855
+ } catch {
1856
+ }
1857
+ return fallbackJokes[Math.floor(Math.random() * fallbackJokes.length)];
1858
+ }
1122
1859
  registerCommand({
1123
1860
  name: "joke",
1124
- description: "Get a random joke",
1861
+ description: "Get a random programming joke",
1125
1862
  usage: "/joke",
1126
1863
  async execute(_args) {
1127
1864
  console.log("");
1128
1865
  console.log(` ${symbols.dice} ${theme.sunset("Getting a joke...")}`);
1129
- try {
1130
- const response = await fetch("https://official-joke-api.appspot.com/random_joke", {
1131
- signal: AbortSignal.timeout(3e3)
1132
- });
1133
- let joke;
1134
- if (!response.ok) {
1135
- joke = fallbackJokes[Math.floor(Math.random() * fallbackJokes.length)];
1136
- } else {
1137
- joke = await response.json();
1138
- }
1139
- process.stdout.write("\x1B[1A\x1B[2K");
1140
- console.log("");
1141
- console.log(bubble.say(joke.setup, 55));
1142
- console.log(` ${symbols.sparkle}`);
1143
- await new Promise((resolve3) => setTimeout(resolve3, 1500));
1144
- console.log("");
1145
- console.log(` ${theme.gold(" \u2726")} ${theme.b.success(joke.punchline)} ${theme.gold("\u2726")}`);
1146
- console.log("");
1147
- 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")}`);
1148
- console.log(` ${symbols.dice} ${theme.dim("Run /joke again for another!")}`);
1149
- console.log("");
1150
- } catch (error) {
1151
- process.stdout.write("\x1B[1A\x1B[2K");
1152
- const joke = fallbackJokes[Math.floor(Math.random() * fallbackJokes.length)];
1153
- console.log("");
1154
- console.log(bubble.say(joke.setup, 55));
1155
- console.log(` ${symbols.sparkle}`);
1156
- await new Promise((resolve3) => setTimeout(resolve3, 1500));
1157
- console.log("");
1158
- console.log(` ${theme.gold(" \u2726")} ${theme.b.success(joke.punchline)} ${theme.gold("\u2726")}`);
1159
- console.log("");
1160
- }
1866
+ const joke = await fetchJoke();
1867
+ process.stdout.write("\x1B[1A\x1B[2K");
1868
+ console.log("");
1869
+ console.log(bubble.say(joke.setup, 55));
1870
+ console.log(` ${symbols.sparkle}`);
1871
+ await new Promise((resolve6) => setTimeout(resolve6, 1500));
1872
+ console.log("");
1873
+ console.log(` ${theme.gold(" \u2726")} ${theme.b.success(joke.punchline)} ${theme.gold("\u2726")}`);
1874
+ console.log("");
1875
+ 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")}`);
1876
+ console.log(` ${symbols.dice} ${theme.dim("Run /joke again for another!")}`);
1877
+ console.log("");
1161
1878
  }
1162
1879
  });
1163
1880
 
1164
1881
  // src/commands/fun/quote.ts
1165
- var quotes = [
1882
+ var fallbackQuotes = [
1166
1883
  { text: "The only way to do great work is to love what you do.", author: "Steve Jobs" },
1167
1884
  { text: "Code is like humor. When you have to explain it, it's bad.", author: "Cory House" },
1168
1885
  { text: "First, solve the problem. Then, write the code.", author: "John Johnson" },
@@ -1179,6 +1896,33 @@ var quotes = [
1179
1896
  { text: "There are only two hard things in Computer Science: cache invalidation and naming things.", author: "Phil Karlton" },
1180
1897
  { text: "The best time to plant a tree was 20 years ago. The second best time is now.", author: "Chinese Proverb" }
1181
1898
  ];
1899
+ async function fetchQuote() {
1900
+ try {
1901
+ const response = await fetch("https://zenquotes.io/api/random", {
1902
+ signal: AbortSignal.timeout(3e3)
1903
+ });
1904
+ if (response.ok) {
1905
+ const data = await response.json();
1906
+ if (data && data[0]) {
1907
+ return { text: data[0].q, author: data[0].a };
1908
+ }
1909
+ }
1910
+ } catch {
1911
+ }
1912
+ try {
1913
+ const response = await fetch("https://api.quotable.io/random", {
1914
+ signal: AbortSignal.timeout(3e3)
1915
+ });
1916
+ if (response.ok) {
1917
+ const data = await response.json();
1918
+ if (data && data.content) {
1919
+ return { text: data.content, author: data.author };
1920
+ }
1921
+ }
1922
+ } catch {
1923
+ }
1924
+ return fallbackQuotes[Math.floor(Math.random() * fallbackQuotes.length)];
1925
+ }
1182
1926
  function wrapText(text, maxWidth) {
1183
1927
  const words = text.split(" ");
1184
1928
  const lines = [];
@@ -1199,7 +1943,10 @@ registerCommand({
1199
1943
  description: "Get an inspirational quote",
1200
1944
  usage: "/quote",
1201
1945
  async execute(_args) {
1202
- const quote = quotes[Math.floor(Math.random() * quotes.length)];
1946
+ console.log("");
1947
+ console.log(` ${symbols.sparkle} ${theme.dim("Fetching wisdom...")}`);
1948
+ const quote = await fetchQuote();
1949
+ process.stdout.write("\x1B[1A\x1B[2K\x1B[1A\x1B[2K");
1203
1950
  const wrapped = wrapText(quote.text, 55);
1204
1951
  console.log("");
1205
1952
  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")}`);
@@ -1405,7 +2152,7 @@ function rollDice(count = 1, sides = 6) {
1405
2152
  count: safeCount,
1406
2153
  sides: safeSides,
1407
2154
  rolls,
1408
- total: rolls.reduce((a, b) => a + b, 0),
2155
+ total: rolls.reduce((a, b3) => a + b3, 0),
1409
2156
  isStandardD6: safeSides === 6 && safeCount <= 3
1410
2157
  };
1411
2158
  }
@@ -1655,18 +2402,110 @@ registerCommand({
1655
2402
  }
1656
2403
  });
1657
2404
 
1658
- // src/commands/creative/asciiart.ts
1659
- import Jimp from "jimp";
1660
- import { existsSync as existsSync3 } from "fs";
1661
- import { resolve } from "path";
1662
- var CHAR_RAMPS = {
1663
- // Standard - 10 levels, balanced
1664
- standard: " .:-=+*#%@",
1665
- // Detailed - 16 levels, more gradation
1666
- detailed: " .'`^\",:;Il!i><~+_-?][}{1)(|/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$",
1667
- // Block characters - uses Unicode block elements for smoother look
1668
- blocks: " \u2591\u2592\u2593\u2588",
1669
- // Simple - 5 levels for cleaner output
2405
+ // src/commands/fun/zammy.ts
2406
+ var MIN_WIDTH_FOR_MASCOT3 = 50;
2407
+ var MIN_WIDTH_FOR_ASCII = 70;
2408
+ var asciiMascot = `
2409
+ **/***********,
2410
+ ****** **//////////****
2411
+ ***/**///////////////////////**
2412
+ ****///////////**////////////////(**
2413
+ ***////& &////////////% &////* ,////(**
2414
+ *//////&&&/////////////&&&//(/////((((((*
2415
+ **/////////&&&&&&&&&&&&////(//((/(((((((((/*
2416
+ **/////////&&&&&&/****&&//((* /(((((((((((((*
2417
+ ,*////* *///&&&*******&*/(((((((((((((((((((**
2418
+ **////////////*//(**(/(/((((((((((((((((/(((*
2419
+ **//////////////(((/(((((((((/ .*((((((((((**
2420
+ **////////(/((((/((((((((((((((((((((((((/*
2421
+ **(((///(((((//((((((((((((((((((((((#**
2422
+ **/((((((((((((((((/*(((((((((((((*
2423
+ ***((((((((((((((((((#(((((** */*///
2424
+ ***************** *(((( .*/
2425
+ `;
2426
+ registerCommand({
2427
+ name: "zammy",
2428
+ description: "Say hi to Zammy the slime!",
2429
+ usage: "/zammy [mood|ascii|moods]",
2430
+ async execute(args2) {
2431
+ const mood = args2[0] || "happy";
2432
+ const termWidth = process.stdout.columns || 80;
2433
+ if (mood === "ascii" || mood === "mascot") {
2434
+ console.log("");
2435
+ if (termWidth < MIN_WIDTH_FOR_ASCII) {
2436
+ console.log(` ${miniSlime.happy} Hi! I'm Zammy!`);
2437
+ console.log(` ${theme.dim("(widen your terminal to see my full form!)")}`);
2438
+ } else {
2439
+ console.log(theme.primary(asciiMascot));
2440
+ }
2441
+ console.log(` ${theme.secondary(`"${getGreeting()}"`)}`);
2442
+ console.log("");
2443
+ return;
2444
+ }
2445
+ if (mood === "moods" || mood === "all") {
2446
+ console.log("");
2447
+ console.log(` ${symbols.sparkle} ${theme.primary("Zammy's moods:")} ${symbols.sparkle}`);
2448
+ console.log("");
2449
+ if (termWidth < MIN_WIDTH_FOR_MASCOT3) {
2450
+ for (const m of validMoods) {
2451
+ const mini = miniSlime[m];
2452
+ if (mini) {
2453
+ console.log(` ${mini} ${theme.dim(m)}`);
2454
+ }
2455
+ }
2456
+ console.log("");
2457
+ console.log(` ${theme.dim("(widen your terminal to see full mood sprites!)")}`);
2458
+ } else {
2459
+ for (const m of validMoods) {
2460
+ const frameFunc2 = slimeFrames[m];
2461
+ if (frameFunc2) {
2462
+ console.log(theme.secondary(` \u2500\u2500\u2500 ${m.toUpperCase()} \u2500\u2500\u2500`));
2463
+ const art = frameFunc2();
2464
+ art.forEach((line) => console.log(" " + line));
2465
+ console.log("");
2466
+ }
2467
+ }
2468
+ }
2469
+ return;
2470
+ }
2471
+ if (!validMoods.includes(mood)) {
2472
+ console.log("");
2473
+ console.log(` ${miniSlime.surprised} ${theme.warning("I don't know that mood!")}`);
2474
+ console.log(` ${theme.dim(`Try: ${validMoods.join(", ")}, ascii`)}`);
2475
+ console.log(` ${theme.dim(`Or: /zammy moods`)}`);
2476
+ console.log("");
2477
+ return;
2478
+ }
2479
+ const frameFunc = slimeFrames[mood];
2480
+ const greeting = getGreeting();
2481
+ console.log("");
2482
+ if (termWidth < MIN_WIDTH_FOR_MASCOT3) {
2483
+ const mini = miniSlime[mood] || miniSlime.happy;
2484
+ console.log(` ${mini}`);
2485
+ } else if (frameFunc) {
2486
+ const art = frameFunc();
2487
+ art.forEach((line) => console.log(" " + line));
2488
+ }
2489
+ console.log("");
2490
+ console.log(` ${theme.secondary(`"${greeting}"`)}`);
2491
+ console.log("");
2492
+ console.log(` ${theme.dim("I'm Zammy, your CLI buddy! Type /help to see what I can do~")}`);
2493
+ console.log("");
2494
+ }
2495
+ });
2496
+
2497
+ // src/commands/creative/asciiart.ts
2498
+ import Jimp from "jimp";
2499
+ import { existsSync as existsSync4 } from "fs";
2500
+ import { resolve as resolve2 } from "path";
2501
+ var CHAR_RAMPS = {
2502
+ // Standard - 10 levels, balanced
2503
+ standard: " .:-=+*#%@",
2504
+ // Detailed - 16 levels, more gradation
2505
+ detailed: " .'`^\",:;Il!i><~+_-?][}{1)(|/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$",
2506
+ // Block characters - uses Unicode block elements for smoother look
2507
+ blocks: " \u2591\u2592\u2593\u2588",
2508
+ // Simple - 5 levels for cleaner output
1670
2509
  simple: " .:\u2591\u2588",
1671
2510
  // Extended - Maximum depth with 70 characters
1672
2511
  extended: "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
@@ -1682,8 +2521,8 @@ var SOBEL_Y = [
1682
2521
  [1, 2, 1]
1683
2522
  ];
1684
2523
  function getAsciiChar(brightness, ramp, inverted) {
1685
- const b = Math.max(0, Math.min(255, brightness));
1686
- const index = Math.floor(b / 255 * (ramp.length - 1));
2524
+ const b3 = Math.max(0, Math.min(255, brightness));
2525
+ const index = Math.floor(b3 / 255 * (ramp.length - 1));
1687
2526
  return inverted ? ramp[ramp.length - 1 - index] : ramp[index];
1688
2527
  }
1689
2528
  async function applyEdgeEnhancement(image, strength) {
@@ -1763,8 +2602,8 @@ registerCommand({
1763
2602
  i++;
1764
2603
  }
1765
2604
  }
1766
- const fullPath = resolve(process.cwd(), imagePath);
1767
- if (!existsSync3(fullPath)) {
2605
+ const fullPath = resolve2(process.cwd(), imagePath);
2606
+ if (!existsSync4(fullPath)) {
1768
2607
  console.log(theme.error(`File not found: ${imagePath}`));
1769
2608
  return;
1770
2609
  }
@@ -2045,7 +2884,7 @@ registerCommand({
2045
2884
  });
2046
2885
 
2047
2886
  // src/commands/creative/color.ts
2048
- import chalk2 from "chalk";
2887
+ import chalk4 from "chalk";
2049
2888
 
2050
2889
  // src/handlers/creative/color.ts
2051
2890
  function hexToRgb(hex) {
@@ -2056,14 +2895,14 @@ function hexToRgb(hex) {
2056
2895
  b: parseInt(result[3], 16)
2057
2896
  } : null;
2058
2897
  }
2059
- function rgbToHex(r, g, b) {
2060
- return "#" + [r, g, b].map((x) => x.toString(16).padStart(2, "0")).join("");
2898
+ function rgbToHex(r, g, b3) {
2899
+ return "#" + [r, g, b3].map((x) => x.toString(16).padStart(2, "0")).join("");
2061
2900
  }
2062
- function rgbToHsl(r, g, b) {
2901
+ function rgbToHsl(r, g, b3) {
2063
2902
  r /= 255;
2064
2903
  g /= 255;
2065
- b /= 255;
2066
- const max = Math.max(r, g, b), min = Math.min(r, g, b);
2904
+ b3 /= 255;
2905
+ const max = Math.max(r, g, b3), min = Math.min(r, g, b3);
2067
2906
  let h = 0, s = 0;
2068
2907
  const l = (max + min) / 2;
2069
2908
  if (max !== min) {
@@ -2071,20 +2910,20 @@ function rgbToHsl(r, g, b) {
2071
2910
  s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
2072
2911
  switch (max) {
2073
2912
  case r:
2074
- h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
2913
+ h = ((g - b3) / d + (g < b3 ? 6 : 0)) / 6;
2075
2914
  break;
2076
2915
  case g:
2077
- h = ((b - r) / d + 2) / 6;
2916
+ h = ((b3 - r) / d + 2) / 6;
2078
2917
  break;
2079
- case b:
2918
+ case b3:
2080
2919
  h = ((r - g) / d + 4) / 6;
2081
2920
  break;
2082
2921
  }
2083
2922
  }
2084
2923
  return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) };
2085
2924
  }
2086
- function getLuminance(r, g, b) {
2087
- return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
2925
+ function getLuminance(r, g, b3) {
2926
+ return (0.299 * r + 0.587 * g + 0.114 * b3) / 255;
2088
2927
  }
2089
2928
  function randomColor() {
2090
2929
  return {
@@ -2094,12 +2933,12 @@ function randomColor() {
2094
2933
  };
2095
2934
  }
2096
2935
  function parseColor(input) {
2097
- let r, g, b;
2936
+ let r, g, b3;
2098
2937
  if (!input || input === "random") {
2099
2938
  const rgb = randomColor();
2100
2939
  r = rgb.r;
2101
2940
  g = rgb.g;
2102
- b = rgb.b;
2941
+ b3 = rgb.b;
2103
2942
  } else {
2104
2943
  const hexMatch = input.match(/^#?([a-f\d]{6}|[a-f\d]{3})$/i);
2105
2944
  if (hexMatch) {
@@ -2111,7 +2950,7 @@ function parseColor(input) {
2111
2950
  if (rgb) {
2112
2951
  r = rgb.r;
2113
2952
  g = rgb.g;
2114
- b = rgb.b;
2953
+ b3 = rgb.b;
2115
2954
  } else {
2116
2955
  return { error: "Invalid hex color" };
2117
2956
  }
@@ -2120,24 +2959,24 @@ function parseColor(input) {
2120
2959
  if (rgbMatch) {
2121
2960
  r = Math.min(255, parseInt(rgbMatch[1]));
2122
2961
  g = Math.min(255, parseInt(rgbMatch[2]));
2123
- b = Math.min(255, parseInt(rgbMatch[3]));
2962
+ b3 = Math.min(255, parseInt(rgbMatch[3]));
2124
2963
  } else {
2125
2964
  const nums = input.split(/[\s,]+/).map((n) => parseInt(n)).filter((n) => !isNaN(n));
2126
2965
  if (nums.length === 3) {
2127
2966
  r = Math.min(255, nums[0]);
2128
2967
  g = Math.min(255, nums[1]);
2129
- b = Math.min(255, nums[2]);
2968
+ b3 = Math.min(255, nums[2]);
2130
2969
  } else {
2131
2970
  return { error: "Could not parse color" };
2132
2971
  }
2133
2972
  }
2134
2973
  }
2135
2974
  }
2136
- const hex = rgbToHex(r, g, b);
2137
- const hsl = rgbToHsl(r, g, b);
2138
- const luminance = getLuminance(r, g, b);
2975
+ const hex = rgbToHex(r, g, b3);
2976
+ const hsl = rgbToHsl(r, g, b3);
2977
+ const luminance = getLuminance(r, g, b3);
2139
2978
  return {
2140
- rgb: { r, g, b },
2979
+ rgb: { r, g, b: b3 },
2141
2980
  hex,
2142
2981
  hsl,
2143
2982
  luminance,
@@ -2194,7 +3033,7 @@ registerCommand({
2194
3033
  console.log("");
2195
3034
  console.log(` ${symbols.palette} ${theme.gradient("COLOR CONVERTER")} ${symbols.palette}`);
2196
3035
  console.log("");
2197
- const colorBlock = chalk2.bgHex(hex).hex(textColor);
3036
+ const colorBlock = chalk4.bgHex(hex).hex(textColor);
2198
3037
  console.log(` ${colorBlock(" ")}`);
2199
3038
  console.log(` ${colorBlock(" ")}`);
2200
3039
  console.log(` ${colorBlock(` ${hex.toUpperCase()} `.slice(0, 40))}`);
@@ -2209,14 +3048,14 @@ registerCommand({
2209
3048
  let shadesLine = " ";
2210
3049
  const shades = generateShades(rgb);
2211
3050
  for (const shade of shades) {
2212
- shadesLine += chalk2.bgRgb(shade.r, shade.g, shade.b)(" ");
3051
+ shadesLine += chalk4.bgRgb(shade.r, shade.g, shade.b)(" ");
2213
3052
  }
2214
3053
  console.log(shadesLine);
2215
3054
  console.log(` ${theme.dim("Tints:")}`);
2216
3055
  let tintsLine = " ";
2217
3056
  const tints = generateTints(rgb);
2218
3057
  for (const tint of tints) {
2219
- tintsLine += chalk2.bgRgb(tint.r, tint.g, tint.b)(" ");
3058
+ tintsLine += chalk4.bgRgb(tint.r, tint.g, tint.b)(" ");
2220
3059
  }
2221
3060
  console.log(tintsLine);
2222
3061
  console.log("");
@@ -2280,189 +3119,2016 @@ registerCommand({
2280
3119
  ], 70));
2281
3120
  console.log("");
2282
3121
  }
2283
- });
3122
+ });
3123
+
3124
+ // src/handlers/dev/uuid.ts
3125
+ import { randomUUID } from "crypto";
3126
+ function generateUuids(count = 1) {
3127
+ const safeCount = Math.min(Math.max(1, count), 10);
3128
+ const uuids = [];
3129
+ for (let i = 0; i < safeCount; i++) {
3130
+ uuids.push(randomUUID());
3131
+ }
3132
+ return {
3133
+ uuids,
3134
+ count: safeCount
3135
+ };
3136
+ }
3137
+
3138
+ // src/commands/dev/uuid.ts
3139
+ registerCommand({
3140
+ name: "uuid",
3141
+ description: "Generate UUID(s)",
3142
+ usage: "/uuid [count]",
3143
+ async execute(args2) {
3144
+ const count = parseInt(args2[0]) || 1;
3145
+ const result = generateUuids(count);
3146
+ console.log("");
3147
+ console.log(` ${symbols.sparkle} ${theme.gradient("UUID GENERATOR")} ${symbols.sparkle}`);
3148
+ console.log("");
3149
+ result.uuids.forEach((uuid, i) => {
3150
+ console.log(` ${theme.dim(`${i + 1}.`)} ${theme.primary(uuid)}`);
3151
+ });
3152
+ console.log("");
3153
+ if (result.count === 1) {
3154
+ console.log(theme.dim(" Tip: /uuid 5 generates 5 UUIDs"));
3155
+ }
3156
+ console.log("");
3157
+ }
3158
+ });
3159
+
3160
+ // src/handlers/dev/encode.ts
3161
+ var SUPPORTED_METHODS = ["base64", "url", "hex"];
3162
+ function isValidMethod(method) {
3163
+ return SUPPORTED_METHODS.includes(method.toLowerCase());
3164
+ }
3165
+ function encodeText(text, method, direction) {
3166
+ let output;
3167
+ if (direction === "encode") {
3168
+ switch (method) {
3169
+ case "base64":
3170
+ output = Buffer.from(text).toString("base64");
3171
+ break;
3172
+ case "url":
3173
+ output = encodeURIComponent(text);
3174
+ break;
3175
+ case "hex":
3176
+ output = Buffer.from(text).toString("hex");
3177
+ break;
3178
+ }
3179
+ } else {
3180
+ switch (method) {
3181
+ case "base64":
3182
+ output = Buffer.from(text, "base64").toString("utf-8");
3183
+ break;
3184
+ case "url":
3185
+ output = decodeURIComponent(text);
3186
+ break;
3187
+ case "hex":
3188
+ output = Buffer.from(text, "hex").toString("utf-8");
3189
+ break;
3190
+ }
3191
+ }
3192
+ return {
3193
+ method: method.toUpperCase(),
3194
+ direction,
3195
+ input: text,
3196
+ output
3197
+ };
3198
+ }
3199
+
3200
+ // src/commands/dev/encode.ts
3201
+ registerCommand({
3202
+ name: "encode",
3203
+ description: "Encode/decode text (base64, url, hex)",
3204
+ usage: "/encode <method> <encode|decode> <text>",
3205
+ async execute(args2) {
3206
+ if (args2.length < 2) {
3207
+ console.log("");
3208
+ console.log(theme.error("Usage: /encode <method> <encode|decode> <text>"));
3209
+ console.log(theme.dim(` Methods: ${SUPPORTED_METHODS.join(", ")}`));
3210
+ console.log(theme.dim(" Example: /encode base64 encode hello"));
3211
+ console.log(theme.dim(" Example: /encode url decode hello%20world"));
3212
+ console.log("");
3213
+ return;
3214
+ }
3215
+ const method = args2[0].toLowerCase();
3216
+ const action = args2[1].toLowerCase();
3217
+ const text = args2.slice(2).join(" ");
3218
+ if (!isValidMethod(method)) {
3219
+ console.log(theme.error(`Unknown method: ${method}. Use ${SUPPORTED_METHODS.join(", ")}`));
3220
+ return;
3221
+ }
3222
+ if (action !== "encode" && action !== "decode") {
3223
+ console.log(theme.error(`Unknown action: ${action}. Use encode or decode`));
3224
+ return;
3225
+ }
3226
+ if (!text) {
3227
+ console.log(theme.error("Please provide text to encode/decode"));
3228
+ return;
3229
+ }
3230
+ try {
3231
+ const result = encodeText(text, method, action);
3232
+ console.log("");
3233
+ console.log(box.draw([
3234
+ "",
3235
+ ` ${symbols.sparkle} ${theme.gradient(result.method + " " + result.direction.toUpperCase())}`,
3236
+ "",
3237
+ ` ${theme.dim("Input:")}`,
3238
+ ` ${theme.secondary(result.input.length > 50 ? result.input.slice(0, 50) + "..." : result.input)}`,
3239
+ "",
3240
+ ` ${theme.dim("Output:")}`,
3241
+ ` ${theme.success(result.output.length > 50 ? result.output.slice(0, 50) + "..." : result.output)}`,
3242
+ "",
3243
+ ...result.output.length > 50 ? [` ${theme.dim("(Full output: " + result.output.length + " chars)")}`] : [],
3244
+ ""
3245
+ ], 60));
3246
+ console.log("");
3247
+ if (result.output.length > 50) {
3248
+ console.log(theme.dim(" Full result:"));
3249
+ console.log(` ${result.output}`);
3250
+ console.log("");
3251
+ }
3252
+ } catch (e) {
3253
+ console.log(theme.error(`Failed to ${action}: Invalid input for ${method}`));
3254
+ }
3255
+ }
3256
+ });
3257
+
3258
+ // src/handlers/dev/json.ts
3259
+ function validateJson(input) {
3260
+ try {
3261
+ const data = JSON.parse(input);
3262
+ return { valid: true, data };
3263
+ } catch (error) {
3264
+ const message = error instanceof Error ? error.message : "Invalid JSON";
3265
+ return { valid: false, error: message };
3266
+ }
3267
+ }
3268
+ function formatJson(input, indent = 2) {
3269
+ try {
3270
+ const data = JSON.parse(input);
3271
+ const formatted = JSON.stringify(data, null, indent);
3272
+ return { valid: true, data, formatted };
3273
+ } catch (error) {
3274
+ const message = error instanceof Error ? error.message : "Invalid JSON";
3275
+ return { valid: false, error: message };
3276
+ }
3277
+ }
3278
+ function minifyJson(input) {
3279
+ try {
3280
+ const data = JSON.parse(input);
3281
+ const formatted = JSON.stringify(data);
3282
+ return { valid: true, data, formatted };
3283
+ } catch (error) {
3284
+ const message = error instanceof Error ? error.message : "Invalid JSON";
3285
+ return { valid: false, error: message };
3286
+ }
3287
+ }
3288
+ function queryJson(input, path) {
3289
+ try {
3290
+ const data = JSON.parse(input);
3291
+ const parts = path.replace(/^\$\.?/, "").split(".").filter(Boolean);
3292
+ let current = data;
3293
+ for (const part of parts) {
3294
+ const arrayMatch = part.match(/^(\w*)\[(\d+)\]$/);
3295
+ if (arrayMatch) {
3296
+ const [, key, index] = arrayMatch;
3297
+ if (key) {
3298
+ current = current[key];
3299
+ }
3300
+ if (Array.isArray(current)) {
3301
+ current = current[parseInt(index)];
3302
+ } else {
3303
+ return { valid: false, error: `Not an array at ${part}` };
3304
+ }
3305
+ } else {
3306
+ if (current && typeof current === "object") {
3307
+ current = current[part];
3308
+ } else {
3309
+ return { valid: false, error: `Cannot access ${part}` };
3310
+ }
3311
+ }
3312
+ }
3313
+ return { valid: true, data: current, formatted: JSON.stringify(current, null, 2) };
3314
+ } catch (error) {
3315
+ const message = error instanceof Error ? error.message : "Invalid JSON";
3316
+ return { valid: false, error: message };
3317
+ }
3318
+ }
3319
+ function getJsonStats(input) {
3320
+ try {
3321
+ let countKeys2 = function(obj, depth = 0) {
3322
+ if (typeof obj !== "object" || obj === null) {
3323
+ return { keys: 0, maxDepth: depth };
3324
+ }
3325
+ let keys = 0;
3326
+ let maxDepth = depth;
3327
+ if (Array.isArray(obj)) {
3328
+ for (const item of obj) {
3329
+ const result = countKeys2(item, depth + 1);
3330
+ keys += result.keys;
3331
+ maxDepth = Math.max(maxDepth, result.maxDepth);
3332
+ }
3333
+ } else {
3334
+ keys = Object.keys(obj).length;
3335
+ for (const value of Object.values(obj)) {
3336
+ const result = countKeys2(value, depth + 1);
3337
+ keys += result.keys;
3338
+ maxDepth = Math.max(maxDepth, result.maxDepth);
3339
+ }
3340
+ }
3341
+ return { keys, maxDepth };
3342
+ };
3343
+ var countKeys = countKeys2;
3344
+ const data = JSON.parse(input);
3345
+ const stats = countKeys2(data);
3346
+ const size = new Blob([input]).size;
3347
+ const sizeStr = size < 1024 ? `${size}B` : size < 1024 * 1024 ? `${(size / 1024).toFixed(1)}KB` : `${(size / 1024 / 1024).toFixed(1)}MB`;
3348
+ return { keys: stats.keys, depth: stats.maxDepth, size: sizeStr };
3349
+ } catch {
3350
+ return null;
3351
+ }
3352
+ }
3353
+
3354
+ // src/commands/dev/json.ts
3355
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
3356
+ registerCommand({
3357
+ name: "json",
3358
+ description: "JSON tools (validate, format, query)",
3359
+ usage: "/json <action> <input>\n\n Actions: validate, format, minify, query, stats",
3360
+ async execute(args2) {
3361
+ const action = args2[0]?.toLowerCase();
3362
+ const input = args2.slice(1).join(" ");
3363
+ if (!action) {
3364
+ console.log("");
3365
+ console.log(` ${symbols.sparkle} ${theme.gradient("JSON TOOLS")}`);
3366
+ console.log("");
3367
+ console.log(` ${theme.dim("Usage:")} /json <action> <input>`);
3368
+ console.log("");
3369
+ console.log(` ${theme.dim("Actions:")}`);
3370
+ console.log(` ${theme.primary("validate")} <json|@file> ${theme.dim("Check if JSON is valid")}`);
3371
+ console.log(` ${theme.primary("format")} <json|@file> ${theme.dim("Pretty-print JSON")}`);
3372
+ console.log(` ${theme.primary("minify")} <json|@file> ${theme.dim("Minify JSON")}`);
3373
+ console.log(` ${theme.primary("query")} <path> <json> ${theme.dim("Query with path (e.g., users[0].name)")}`);
3374
+ console.log(` ${theme.primary("stats")} <json|@file> ${theme.dim("Show JSON statistics")}`);
3375
+ console.log("");
3376
+ console.log(` ${theme.dim("Use @filename to read from file")}`);
3377
+ console.log("");
3378
+ return;
3379
+ }
3380
+ let jsonContent = input;
3381
+ if (input.startsWith("@")) {
3382
+ const filePath = input.slice(1);
3383
+ if (!existsSync5(filePath)) {
3384
+ console.log("");
3385
+ console.log(` ${symbols.cross} ${theme.error(`File not found: ${filePath}`)}`);
3386
+ console.log("");
3387
+ return;
3388
+ }
3389
+ jsonContent = readFileSync3(filePath, "utf-8");
3390
+ }
3391
+ console.log("");
3392
+ switch (action) {
3393
+ case "validate": {
3394
+ if (!jsonContent) {
3395
+ console.log(` ${symbols.warning} ${theme.warning("Usage:")} /json validate <json|@file>`);
3396
+ break;
3397
+ }
3398
+ const result = validateJson(jsonContent);
3399
+ if (result.valid) {
3400
+ console.log(` ${symbols.check} ${theme.success("Valid JSON")}`);
3401
+ } else {
3402
+ console.log(` ${symbols.cross} ${theme.error("Invalid JSON")}`);
3403
+ console.log(` ${theme.dim(result.error || "")}`);
3404
+ }
3405
+ break;
3406
+ }
3407
+ case "format":
3408
+ case "pretty": {
3409
+ if (!jsonContent) {
3410
+ console.log(` ${symbols.warning} ${theme.warning("Usage:")} /json format <json|@file>`);
3411
+ break;
3412
+ }
3413
+ const result = formatJson(jsonContent);
3414
+ if (result.valid && result.formatted) {
3415
+ console.log(` ${symbols.check} ${theme.success("Formatted JSON:")}`);
3416
+ console.log("");
3417
+ for (const line of result.formatted.split("\n")) {
3418
+ console.log(` ${theme.primary(line)}`);
3419
+ }
3420
+ } else {
3421
+ console.log(` ${symbols.cross} ${theme.error("Invalid JSON")}`);
3422
+ console.log(` ${theme.dim(result.error || "")}`);
3423
+ }
3424
+ break;
3425
+ }
3426
+ case "minify":
3427
+ case "min": {
3428
+ if (!jsonContent) {
3429
+ console.log(` ${symbols.warning} ${theme.warning("Usage:")} /json minify <json|@file>`);
3430
+ break;
3431
+ }
3432
+ const result = minifyJson(jsonContent);
3433
+ if (result.valid && result.formatted) {
3434
+ console.log(` ${symbols.check} ${theme.success("Minified:")}`);
3435
+ console.log("");
3436
+ console.log(` ${theme.primary(result.formatted)}`);
3437
+ } else {
3438
+ console.log(` ${symbols.cross} ${theme.error("Invalid JSON")}`);
3439
+ console.log(` ${theme.dim(result.error || "")}`);
3440
+ }
3441
+ break;
3442
+ }
3443
+ case "query":
3444
+ case "get": {
3445
+ const path = args2[1];
3446
+ const queryInput = args2.slice(2).join(" ");
3447
+ if (!path || !queryInput) {
3448
+ console.log(` ${symbols.warning} ${theme.warning("Usage:")} /json query <path> <json|@file>`);
3449
+ console.log("");
3450
+ console.log(` ${theme.dim("Examples:")}`);
3451
+ console.log(` /json query name '{"name": "John"}'`);
3452
+ console.log(` /json query users[0].email @data.json`);
3453
+ break;
3454
+ }
3455
+ let queryJsonContent = queryInput;
3456
+ if (queryInput.startsWith("@")) {
3457
+ const filePath = queryInput.slice(1);
3458
+ if (!existsSync5(filePath)) {
3459
+ console.log(` ${symbols.cross} ${theme.error(`File not found: ${filePath}`)}`);
3460
+ break;
3461
+ }
3462
+ queryJsonContent = readFileSync3(filePath, "utf-8");
3463
+ }
3464
+ const result = queryJson(queryJsonContent, path);
3465
+ if (result.valid) {
3466
+ console.log(` ${symbols.check} ${theme.success(`Result for "${path}":`)} `);
3467
+ console.log("");
3468
+ if (result.formatted) {
3469
+ for (const line of result.formatted.split("\n")) {
3470
+ console.log(` ${theme.primary(line)}`);
3471
+ }
3472
+ } else {
3473
+ console.log(` ${theme.dim("undefined")}`);
3474
+ }
3475
+ } else {
3476
+ console.log(` ${symbols.cross} ${theme.error(result.error || "Query failed")}`);
3477
+ }
3478
+ break;
3479
+ }
3480
+ case "stats":
3481
+ case "info": {
3482
+ if (!jsonContent) {
3483
+ console.log(` ${symbols.warning} ${theme.warning("Usage:")} /json stats <json|@file>`);
3484
+ break;
3485
+ }
3486
+ const stats = getJsonStats(jsonContent);
3487
+ if (stats) {
3488
+ console.log(` ${symbols.sparkle} ${theme.gradient("JSON STATS")}`);
3489
+ console.log("");
3490
+ console.log(` ${theme.dim("Total keys:")} ${theme.primary(stats.keys.toString())}`);
3491
+ console.log(` ${theme.dim("Max depth:")} ${theme.primary(stats.depth.toString())}`);
3492
+ console.log(` ${theme.dim("Size:")} ${theme.primary(stats.size)}`);
3493
+ } else {
3494
+ console.log(` ${symbols.cross} ${theme.error("Invalid JSON")}`);
3495
+ }
3496
+ break;
3497
+ }
3498
+ default:
3499
+ console.log(` ${symbols.cross} ${theme.error(`Unknown action: ${action}`)}`);
3500
+ console.log(` ${theme.dim("Run /json to see available actions")}`);
3501
+ }
3502
+ console.log("");
3503
+ }
3504
+ });
3505
+
3506
+ // src/handlers/dev/request.ts
3507
+ import https from "https";
3508
+ import http from "http";
3509
+ import { URL } from "url";
3510
+ async function makeRequest(urlStr, options = { method: "GET" }) {
3511
+ const startTime2 = Date.now();
3512
+ return new Promise((resolve6) => {
3513
+ const timeout = setTimeout(() => {
3514
+ resolve6({ success: false, error: "Request timed out" });
3515
+ }, options.timeout || 3e4);
3516
+ try {
3517
+ const url = new URL(urlStr.startsWith("http") ? urlStr : `https://${urlStr}`);
3518
+ const client = url.protocol === "https:" ? https : http;
3519
+ const reqOptions = {
3520
+ hostname: url.hostname,
3521
+ port: url.port || (url.protocol === "https:" ? 443 : 80),
3522
+ path: url.pathname + url.search,
3523
+ method: options.method.toUpperCase(),
3524
+ headers: {
3525
+ "User-Agent": "Zammy-CLI/1.0",
3526
+ ...options.headers
3527
+ }
3528
+ };
3529
+ const req = client.request(reqOptions, (res) => {
3530
+ let body = "";
3531
+ res.on("data", (chunk) => {
3532
+ body += chunk.toString();
3533
+ });
3534
+ res.on("end", () => {
3535
+ clearTimeout(timeout);
3536
+ resolve6({
3537
+ success: true,
3538
+ statusCode: res.statusCode,
3539
+ statusMessage: res.statusMessage,
3540
+ headers: res.headers,
3541
+ body,
3542
+ time: Date.now() - startTime2
3543
+ });
3544
+ });
3545
+ });
3546
+ req.on("error", (error) => {
3547
+ clearTimeout(timeout);
3548
+ resolve6({ success: false, error: error.message });
3549
+ });
3550
+ if (options.body) {
3551
+ req.write(options.body);
3552
+ }
3553
+ req.end();
3554
+ } catch (error) {
3555
+ clearTimeout(timeout);
3556
+ resolve6({ success: false, error: error instanceof Error ? error.message : "Request failed" });
3557
+ }
3558
+ });
3559
+ }
3560
+ function tryParseJson(body) {
3561
+ try {
3562
+ const parsed = JSON.parse(body);
3563
+ return { isJson: true, formatted: JSON.stringify(parsed, null, 2) };
3564
+ } catch {
3565
+ return { isJson: false };
3566
+ }
3567
+ }
3568
+
3569
+ // src/commands/dev/request.ts
3570
+ registerCommand({
3571
+ name: "request",
3572
+ description: "Make HTTP requests",
3573
+ usage: "/request <method> <url> [options]",
3574
+ async execute(args2) {
3575
+ if (args2.length < 1) {
3576
+ console.log("");
3577
+ console.log(` ${symbols.sparkle} ${theme.gradient("HTTP REQUEST")}`);
3578
+ console.log("");
3579
+ console.log(` ${theme.dim("Usage:")} /request <method> <url> [options]`);
3580
+ console.log("");
3581
+ console.log(` ${theme.dim("Methods:")} GET, POST, PUT, DELETE, PATCH, HEAD`);
3582
+ console.log("");
3583
+ console.log(` ${theme.dim("Examples:")}`);
3584
+ console.log(` /request GET https://api.github.com`);
3585
+ console.log(` /request POST https://httpbin.org/post --body '{"name":"test"}'`);
3586
+ console.log(` /request GET api.example.com/users`);
3587
+ console.log("");
3588
+ return;
3589
+ }
3590
+ let method = "GET";
3591
+ let url = args2[0];
3592
+ const methods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"];
3593
+ if (methods.includes(args2[0].toUpperCase())) {
3594
+ method = args2[0].toUpperCase();
3595
+ url = args2[1];
3596
+ }
3597
+ if (!url) {
3598
+ console.log("");
3599
+ console.log(` ${symbols.cross} ${theme.error("URL is required")}`);
3600
+ console.log("");
3601
+ return;
3602
+ }
3603
+ const headers = {};
3604
+ let body;
3605
+ for (let i = 2; i < args2.length; i++) {
3606
+ if (args2[i] === "--header" || args2[i] === "-H") {
3607
+ const header = args2[++i];
3608
+ if (header) {
3609
+ const [key, ...valueParts] = header.split(":");
3610
+ headers[key.trim()] = valueParts.join(":").trim();
3611
+ }
3612
+ } else if (args2[i] === "--body" || args2[i] === "-d") {
3613
+ body = args2[++i];
3614
+ }
3615
+ }
3616
+ console.log("");
3617
+ console.log(` ${theme.dim(`${method} ${url}...`)}`);
3618
+ const result = await makeRequest(url, { method, headers, body });
3619
+ process.stdout.write("\x1B[1A\x1B[2K");
3620
+ if (!result.success) {
3621
+ console.log(` ${symbols.cross} ${theme.error(result.error || "Request failed")}`);
3622
+ console.log("");
3623
+ return;
3624
+ }
3625
+ const statusColor = result.statusCode && result.statusCode >= 200 && result.statusCode < 300 ? theme.success : result.statusCode && result.statusCode >= 400 ? theme.error : theme.warning;
3626
+ console.log(` ${statusColor(`${result.statusCode} ${result.statusMessage}`)} ${theme.dim(`(${result.time}ms)`)}`);
3627
+ console.log("");
3628
+ if (result.headers) {
3629
+ const importantHeaders = ["content-type", "content-length", "server", "date"];
3630
+ console.log(` ${theme.dim("Headers:")}`);
3631
+ for (const key of importantHeaders) {
3632
+ if (result.headers[key]) {
3633
+ console.log(` ${theme.secondary(key)}: ${result.headers[key]}`);
3634
+ }
3635
+ }
3636
+ console.log("");
3637
+ }
3638
+ if (result.body && method !== "HEAD") {
3639
+ console.log(` ${theme.dim("Body:")}`);
3640
+ const jsonResult = tryParseJson(result.body);
3641
+ if (jsonResult.isJson && jsonResult.formatted) {
3642
+ const lines = jsonResult.formatted.split("\n");
3643
+ const displayLines = lines.slice(0, 30);
3644
+ for (const line of displayLines) {
3645
+ console.log(` ${theme.primary(line)}`);
3646
+ }
3647
+ if (lines.length > 30) {
3648
+ console.log(` ${theme.dim(`... and ${lines.length - 30} more lines`)}`);
3649
+ }
3650
+ } else {
3651
+ const lines = result.body.split("\n").slice(0, 20);
3652
+ for (const line of lines) {
3653
+ console.log(` ${line.slice(0, 100)}`);
3654
+ }
3655
+ if (result.body.split("\n").length > 20) {
3656
+ console.log(` ${theme.dim("... (truncated)")}`);
3657
+ }
3658
+ }
3659
+ }
3660
+ console.log("");
3661
+ }
3662
+ });
3663
+
3664
+ // src/handlers/dev/diff.ts
3665
+ import { readFileSync as readFileSync4, existsSync as existsSync6 } from "fs";
3666
+ function diffFiles(file1, file2) {
3667
+ if (!existsSync6(file1)) {
3668
+ return { success: false, lines: [], stats: { additions: 0, deletions: 0, unchanged: 0 }, error: `File not found: ${file1}` };
3669
+ }
3670
+ if (!existsSync6(file2)) {
3671
+ return { success: false, lines: [], stats: { additions: 0, deletions: 0, unchanged: 0 }, error: `File not found: ${file2}` };
3672
+ }
3673
+ try {
3674
+ const content1 = readFileSync4(file1, "utf-8");
3675
+ const content2 = readFileSync4(file2, "utf-8");
3676
+ return diffStrings(content1, content2);
3677
+ } catch (error) {
3678
+ return {
3679
+ success: false,
3680
+ lines: [],
3681
+ stats: { additions: 0, deletions: 0, unchanged: 0 },
3682
+ error: error instanceof Error ? error.message : "Failed to read files"
3683
+ };
3684
+ }
3685
+ }
3686
+ function diffStrings(str1, str2) {
3687
+ const lines1 = str1.split("\n");
3688
+ const lines2 = str2.split("\n");
3689
+ const lcs = computeLCS(lines1, lines2);
3690
+ const diff = buildDiff(lines1, lines2, lcs);
3691
+ let additions = 0;
3692
+ let deletions = 0;
3693
+ let unchanged = 0;
3694
+ for (const line of diff) {
3695
+ if (line.type === "add") additions++;
3696
+ else if (line.type === "remove") deletions++;
3697
+ else if (line.type === "same") unchanged++;
3698
+ }
3699
+ return {
3700
+ success: true,
3701
+ lines: diff,
3702
+ stats: { additions, deletions, unchanged }
3703
+ };
3704
+ }
3705
+ function computeLCS(lines1, lines2) {
3706
+ const m = lines1.length;
3707
+ const n = lines2.length;
3708
+ const dp = Array(m + 1).fill(null).map(() => Array(n + 1).fill(0));
3709
+ for (let i = 1; i <= m; i++) {
3710
+ for (let j = 1; j <= n; j++) {
3711
+ if (lines1[i - 1] === lines2[j - 1]) {
3712
+ dp[i][j] = dp[i - 1][j - 1] + 1;
3713
+ } else {
3714
+ dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
3715
+ }
3716
+ }
3717
+ }
3718
+ return dp;
3719
+ }
3720
+ function buildDiff(lines1, lines2, lcs) {
3721
+ const result = [];
3722
+ let i = lines1.length;
3723
+ let j = lines2.length;
3724
+ const temp = [];
3725
+ while (i > 0 || j > 0) {
3726
+ if (i > 0 && j > 0 && lines1[i - 1] === lines2[j - 1]) {
3727
+ temp.push({ type: "same", content: lines1[i - 1], lineNum1: i, lineNum2: j });
3728
+ i--;
3729
+ j--;
3730
+ } else if (j > 0 && (i === 0 || lcs[i][j - 1] >= lcs[i - 1][j])) {
3731
+ temp.push({ type: "add", content: lines2[j - 1], lineNum2: j });
3732
+ j--;
3733
+ } else if (i > 0) {
3734
+ temp.push({ type: "remove", content: lines1[i - 1], lineNum1: i });
3735
+ i--;
3736
+ }
3737
+ }
3738
+ return temp.reverse();
3739
+ }
3740
+ function formatDiffStats(stats) {
3741
+ const parts = [];
3742
+ if (stats.additions > 0) parts.push(`+${stats.additions}`);
3743
+ if (stats.deletions > 0) parts.push(`-${stats.deletions}`);
3744
+ if (stats.unchanged > 0) parts.push(`=${stats.unchanged}`);
3745
+ return parts.join(", ");
3746
+ }
3747
+
3748
+ // src/commands/dev/diff.ts
3749
+ import { basename as basename2 } from "path";
3750
+ registerCommand({
3751
+ name: "diff",
3752
+ description: "Compare two files",
3753
+ usage: "/diff <file1> <file2>",
3754
+ async execute(args2) {
3755
+ if (args2.length < 2) {
3756
+ console.log("");
3757
+ console.log(` ${symbols.sparkle} ${theme.gradient("FILE DIFF")}`);
3758
+ console.log("");
3759
+ console.log(` ${theme.dim("Usage:")} /diff <file1> <file2>`);
3760
+ console.log("");
3761
+ console.log(` ${theme.dim("Example:")}`);
3762
+ console.log(` /diff old.json new.json`);
3763
+ console.log(` /diff config.ts config.backup.ts`);
3764
+ console.log("");
3765
+ return;
3766
+ }
3767
+ const file1 = args2[0];
3768
+ const file2 = args2[1];
3769
+ console.log("");
3770
+ const result = diffFiles(file1, file2);
3771
+ if (!result.success) {
3772
+ console.log(` ${symbols.cross} ${theme.error(result.error || "Diff failed")}`);
3773
+ console.log("");
3774
+ return;
3775
+ }
3776
+ console.log(` ${symbols.sparkle} ${theme.gradient("DIFF")}: ${theme.primary(basename2(file1))} ${theme.dim("\u2192")} ${theme.primary(basename2(file2))}`);
3777
+ console.log(` ${theme.dim(formatDiffStats(result.stats))}`);
3778
+ console.log("");
3779
+ if (result.stats.additions === 0 && result.stats.deletions === 0) {
3780
+ console.log(` ${symbols.check} ${theme.success("Files are identical")}`);
3781
+ console.log("");
3782
+ return;
3783
+ }
3784
+ let contextLines = 3;
3785
+ let lastShownIndex = -contextLines - 1;
3786
+ const linesToShow = [];
3787
+ result.lines.forEach((line, i) => {
3788
+ if (line.type !== "same") {
3789
+ for (let j = Math.max(0, i - contextLines); j <= Math.min(result.lines.length - 1, i + contextLines); j++) {
3790
+ if (!linesToShow.includes(j)) {
3791
+ linesToShow.push(j);
3792
+ }
3793
+ }
3794
+ }
3795
+ });
3796
+ linesToShow.sort((a, b3) => a - b3);
3797
+ for (let i = 0; i < linesToShow.length; i++) {
3798
+ const lineIndex = linesToShow[i];
3799
+ const line = result.lines[lineIndex];
3800
+ if (i > 0 && linesToShow[i] - linesToShow[i - 1] > 1) {
3801
+ console.log(` ${theme.dim("...")}`);
3802
+ }
3803
+ const lineNum = line.lineNum1 || line.lineNum2 || "";
3804
+ const numStr = lineNum.toString().padStart(4);
3805
+ if (line.type === "add") {
3806
+ console.log(` ${theme.success("+")} ${theme.dim(numStr)} ${theme.success(line.content)}`);
3807
+ } else if (line.type === "remove") {
3808
+ console.log(` ${theme.error("-")} ${theme.dim(numStr)} ${theme.error(line.content)}`);
3809
+ } else {
3810
+ console.log(` ${theme.dim(" ")} ${theme.dim(numStr)} ${line.content}`);
3811
+ }
3812
+ }
3813
+ console.log("");
3814
+ }
3815
+ });
3816
+
3817
+ // src/commands/info/weather.ts
3818
+ registerCommand({
3819
+ name: "weather",
3820
+ description: "Get current weather for a city",
3821
+ usage: "/weather <city>",
3822
+ async execute(args2) {
3823
+ const city = args2.join(" ") || "London";
3824
+ console.log(theme.dim(`Fetching weather for ${city}...`));
3825
+ try {
3826
+ const response = await fetch(`https://wttr.in/${encodeURIComponent(city)}?format=j1`);
3827
+ if (!response.ok) {
3828
+ console.log(theme.error(`Could not fetch weather for "${city}"`));
3829
+ return;
3830
+ }
3831
+ const data = await response.json();
3832
+ const current = data.current_condition[0];
3833
+ const location = data.nearest_area[0];
3834
+ const temp = current.temp_C;
3835
+ const feelsLike = current.FeelsLikeC;
3836
+ const desc = current.weatherDesc[0].value;
3837
+ const humidity = current.humidity;
3838
+ const wind = current.windspeedKmph;
3839
+ const cityName = location.areaName[0].value;
3840
+ const country = location.country[0].value;
3841
+ console.log("");
3842
+ console.log(theme.highlight(`${cityName}, ${country}`));
3843
+ console.log("");
3844
+ console.log(` ${theme.primary(desc)}`);
3845
+ console.log(` Temperature: ${theme.warning(temp + "\xB0C")} (feels like ${feelsLike}\xB0C)`);
3846
+ console.log(` Humidity: ${humidity}%`);
3847
+ console.log(` Wind: ${wind} km/h`);
3848
+ console.log("");
3849
+ } catch (error) {
3850
+ console.log(theme.error(`Error fetching weather: ${error}`));
3851
+ }
3852
+ }
3853
+ });
3854
+
3855
+ // src/plugins/loader.ts
3856
+ import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync7, mkdirSync as mkdirSync2 } from "fs";
3857
+ import { join as join6, dirname as dirname3 } from "path";
3858
+ import { homedir as homedir3 } from "os";
3859
+ import { pathToFileURL, fileURLToPath as fileURLToPath2 } from "url";
3860
+
3861
+ // src/plugins/api.ts
3862
+ import { execSync, spawn as nodeSpawn } from "child_process";
3863
+ import { join as join5 } from "path";
3864
+
3865
+ // src/plugins/storage.ts
3866
+ import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync } from "fs";
3867
+ import { join as join4 } from "path";
3868
+ function createPluginStorage(pluginName, dataDir) {
3869
+ const storagePath = join4(dataDir, "data.json");
3870
+ if (!existsSync7(dataDir)) {
3871
+ mkdirSync(dataDir, { recursive: true });
3872
+ }
3873
+ function loadData() {
3874
+ try {
3875
+ if (existsSync7(storagePath)) {
3876
+ const content = readFileSync5(storagePath, "utf-8");
3877
+ return JSON.parse(content);
3878
+ }
3879
+ } catch {
3880
+ }
3881
+ return {};
3882
+ }
3883
+ function saveData(data) {
3884
+ try {
3885
+ writeFileSync3(storagePath, JSON.stringify(data, null, 2), "utf-8");
3886
+ } catch (error) {
3887
+ console.error(`Failed to save plugin storage for ${pluginName}:`, error);
3888
+ }
3889
+ }
3890
+ return {
3891
+ get(key) {
3892
+ const data = loadData();
3893
+ return data[key];
3894
+ },
3895
+ set(key, value) {
3896
+ const data = loadData();
3897
+ data[key] = value;
3898
+ saveData(data);
3899
+ },
3900
+ delete(key) {
3901
+ const data = loadData();
3902
+ delete data[key];
3903
+ saveData(data);
3904
+ },
3905
+ clear() {
3906
+ saveData({});
3907
+ },
3908
+ getAll() {
3909
+ return loadData();
3910
+ }
3911
+ };
3912
+ }
3913
+
3914
+ // src/plugins/api.ts
3915
+ import { readFileSync as readFileSync6 } from "fs";
3916
+ import { fileURLToPath } from "url";
3917
+ import { dirname as dirname2 } from "path";
3918
+ function getZammyVersion() {
3919
+ try {
3920
+ const __filename = fileURLToPath(import.meta.url);
3921
+ const __dirname = dirname2(__filename);
3922
+ const pkgPath = join5(__dirname, "..", "..", "package.json");
3923
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf-8"));
3924
+ return pkg.version || "0.0.0";
3925
+ } catch {
3926
+ return "0.0.0";
3927
+ }
3928
+ }
3929
+ function createPluginUI() {
3930
+ return {
3931
+ theme: {
3932
+ primary: theme.primary,
3933
+ secondary: theme.secondary,
3934
+ accent: theme.accent,
3935
+ success: theme.success,
3936
+ warning: theme.warning,
3937
+ error: theme.error,
3938
+ info: theme.info,
3939
+ dim: theme.dim,
3940
+ gradient: theme.gradient
3941
+ },
3942
+ symbols: {
3943
+ check: symbols.check,
3944
+ cross: symbols.cross,
3945
+ star: symbols.star,
3946
+ arrow: symbols.arrow,
3947
+ bullet: symbols.bullet,
3948
+ folder: symbols.folder,
3949
+ file: "\u{1F4C4}",
3950
+ // 📄
3951
+ warning: symbols.warning,
3952
+ info: symbols.info,
3953
+ rocket: symbols.rocket,
3954
+ sparkles: symbols.sparkle
3955
+ },
3956
+ box: (content, options) => {
3957
+ const lines = content.split("\n");
3958
+ const width = Math.max(...lines.map((l) => l.replace(/\x1B\[[0-9;]*m/g, "").length)) + 4;
3959
+ return box.draw(lines, width);
3960
+ },
3961
+ progressBar: (current, total, width) => {
3962
+ const percent = Math.round(current / total * 100);
3963
+ return progressBar(percent, width || 30);
3964
+ }
3965
+ };
3966
+ }
3967
+ function createPluginLogger(pluginName) {
3968
+ const prefix = theme.dim(`[${pluginName}]`);
3969
+ return {
3970
+ info: (message) => console.log(`${prefix} ${theme.info(message)}`),
3971
+ warn: (message) => console.log(`${prefix} ${theme.warning(message)}`),
3972
+ error: (message) => console.log(`${prefix} ${theme.error(message)}`),
3973
+ debug: (message) => {
3974
+ if (process.env.ZAMMY_DEBUG) {
3975
+ console.log(`${prefix} ${theme.dim(message)}`);
3976
+ }
3977
+ }
3978
+ };
3979
+ }
3980
+ function createPluginShell(manifest) {
3981
+ if (!manifest.permissions?.shell) {
3982
+ return void 0;
3983
+ }
3984
+ return {
3985
+ exec: (command, options) => {
3986
+ try {
3987
+ return execSync(command, {
3988
+ encoding: "utf-8",
3989
+ timeout: options?.timeout || 3e4,
3990
+ stdio: ["pipe", "pipe", "pipe"]
3991
+ });
3992
+ } catch (error) {
3993
+ if (error && typeof error === "object" && "stdout" in error) {
3994
+ return error.stdout || "";
3995
+ }
3996
+ throw error;
3997
+ }
3998
+ },
3999
+ spawn: (command, args2) => {
4000
+ return new Promise((resolve6) => {
4001
+ const proc = nodeSpawn(command, args2 || [], {
4002
+ shell: true,
4003
+ stdio: ["pipe", "pipe", "pipe"]
4004
+ });
4005
+ let stdout = "";
4006
+ let stderr = "";
4007
+ proc.stdout?.on("data", (data) => {
4008
+ stdout += data.toString();
4009
+ });
4010
+ proc.stderr?.on("data", (data) => {
4011
+ stderr += data.toString();
4012
+ });
4013
+ proc.on("close", (code) => {
4014
+ resolve6({ stdout, stderr, code: code || 0 });
4015
+ });
4016
+ proc.on("error", () => {
4017
+ resolve6({ stdout, stderr, code: 1 });
4018
+ });
4019
+ });
4020
+ }
4021
+ };
4022
+ }
4023
+ function createPluginAPI(manifest, pluginPath) {
4024
+ const dataDir = pluginPath;
4025
+ const context = {
4026
+ pluginName: manifest.name,
4027
+ pluginVersion: manifest.version,
4028
+ zammyVersion: getZammyVersion(),
4029
+ dataDir,
4030
+ cwd: process.cwd()
4031
+ };
4032
+ return {
4033
+ registerCommand: (command) => {
4034
+ registerPluginCommand(command, manifest.name);
4035
+ },
4036
+ registerCommands: (commands2) => {
4037
+ for (const command of commands2) {
4038
+ registerPluginCommand(command, manifest.name);
4039
+ }
4040
+ },
4041
+ ui: createPluginUI(),
4042
+ storage: createPluginStorage(manifest.name, dataDir),
4043
+ log: createPluginLogger(manifest.name),
4044
+ context,
4045
+ shell: createPluginShell(manifest)
4046
+ };
4047
+ }
4048
+
4049
+ // src/plugins/loader.ts
4050
+ var PLUGINS_DIR = join6(homedir3(), ".zammy", "plugins");
4051
+ function getZammyVersion2() {
4052
+ try {
4053
+ const __filename = fileURLToPath2(import.meta.url);
4054
+ const __dirname = dirname3(__filename);
4055
+ const possiblePaths = [
4056
+ join6(__dirname, "package.json"),
4057
+ // Same dir (bundled: dist/)
4058
+ join6(__dirname, "..", "package.json"),
4059
+ // One up (bundled: project root)
4060
+ join6(__dirname, "..", "..", "package.json")
4061
+ // Two up (source: src/plugins/)
4062
+ ];
4063
+ for (const pkgPath of possiblePaths) {
4064
+ if (existsSync8(pkgPath)) {
4065
+ const pkg = JSON.parse(readFileSync7(pkgPath, "utf-8"));
4066
+ if (pkg.name === "zammy" && pkg.version) {
4067
+ return pkg.version;
4068
+ }
4069
+ }
4070
+ }
4071
+ return "0.0.0";
4072
+ } catch {
4073
+ return "0.0.0";
4074
+ }
4075
+ }
4076
+ function compareVersions(a, b3) {
4077
+ const partsA = a.split(".").map((n) => parseInt(n, 10) || 0);
4078
+ const partsB = b3.split(".").map((n) => parseInt(n, 10) || 0);
4079
+ for (let i = 0; i < 3; i++) {
4080
+ const numA = partsA[i] || 0;
4081
+ const numB = partsB[i] || 0;
4082
+ if (numA < numB) return -1;
4083
+ if (numA > numB) return 1;
4084
+ }
4085
+ return 0;
4086
+ }
4087
+ function checkVersionCompatibility(manifest, zammyVersion) {
4088
+ const minVersion = manifest.zammy?.minVersion;
4089
+ const maxVersion = manifest.zammy?.maxVersion;
4090
+ if (minVersion && compareVersions(zammyVersion, minVersion) < 0) {
4091
+ return {
4092
+ compatible: false,
4093
+ reason: `Requires Zammy v${minVersion}+, but you have v${zammyVersion}`
4094
+ };
4095
+ }
4096
+ if (maxVersion && compareVersions(zammyVersion, maxVersion) > 0) {
4097
+ return {
4098
+ compatible: false,
4099
+ reason: `Incompatible with Zammy v${zammyVersion} (max: v${maxVersion})`
4100
+ };
4101
+ }
4102
+ return { compatible: true };
4103
+ }
4104
+ var discoveredPlugins = /* @__PURE__ */ new Map();
4105
+ var loadedPlugins = /* @__PURE__ */ new Map();
4106
+ function ensurePluginsDir() {
4107
+ if (!existsSync8(PLUGINS_DIR)) {
4108
+ mkdirSync2(PLUGINS_DIR, { recursive: true });
4109
+ }
4110
+ }
4111
+ function getPluginsDir() {
4112
+ return PLUGINS_DIR;
4113
+ }
4114
+ async function discoverPlugins() {
4115
+ ensurePluginsDir();
4116
+ discoveredPlugins.clear();
4117
+ if (!existsSync8(PLUGINS_DIR)) {
4118
+ return [];
4119
+ }
4120
+ const zammyVersion = getZammyVersion2();
4121
+ const entries = readdirSync2(PLUGINS_DIR, { withFileTypes: true });
4122
+ const manifests = [];
4123
+ for (const entry of entries) {
4124
+ if (!entry.isDirectory()) continue;
4125
+ const pluginPath = join6(PLUGINS_DIR, entry.name);
4126
+ const manifestPath = join6(pluginPath, "zammy-plugin.json");
4127
+ if (!existsSync8(manifestPath)) continue;
4128
+ try {
4129
+ const manifestContent = readFileSync7(manifestPath, "utf-8");
4130
+ const manifest = JSON.parse(manifestContent);
4131
+ if (!manifest.name || !manifest.version || !manifest.main || !manifest.commands) {
4132
+ console.log(theme.warning(` ${symbols.warning} Invalid manifest for plugin in ${entry.name}`));
4133
+ continue;
4134
+ }
4135
+ const compatibility = checkVersionCompatibility(manifest, zammyVersion);
4136
+ if (!compatibility.compatible) {
4137
+ console.log(theme.warning(` ${symbols.warning} Plugin '${manifest.name}' skipped: ${compatibility.reason}`));
4138
+ continue;
4139
+ }
4140
+ discoveredPlugins.set(manifest.name, { manifest, path: pluginPath });
4141
+ manifests.push(manifest);
4142
+ } catch (error) {
4143
+ console.log(theme.warning(` ${symbols.warning} Failed to read manifest for ${entry.name}`));
4144
+ }
4145
+ }
4146
+ return manifests;
4147
+ }
4148
+ async function loadPlugin(name) {
4149
+ if (loadedPlugins.has(name)) {
4150
+ const existing = loadedPlugins.get(name);
4151
+ if (existing.state === "error") {
4152
+ return null;
4153
+ }
4154
+ return existing;
4155
+ }
4156
+ const discovered = discoveredPlugins.get(name);
4157
+ if (!discovered) {
4158
+ return null;
4159
+ }
4160
+ const { manifest, path: pluginPath } = discovered;
4161
+ try {
4162
+ const mainPath = join6(pluginPath, manifest.main);
4163
+ if (!existsSync8(mainPath)) {
4164
+ throw new Error(`Plugin entry point not found: ${mainPath}`);
4165
+ }
4166
+ const moduleUrl = pathToFileURL(mainPath).href;
4167
+ const module = await import(moduleUrl);
4168
+ const plugin = module.default;
4169
+ if (!plugin || typeof plugin.activate !== "function") {
4170
+ throw new Error("Plugin must export a default object with an activate function");
4171
+ }
4172
+ const api = createPluginAPI(manifest, pluginPath);
4173
+ try {
4174
+ await plugin.activate(api);
4175
+ } catch (activationError) {
4176
+ const msg = activationError instanceof Error ? activationError.message : String(activationError);
4177
+ throw new Error(`Plugin activation failed: ${msg}`);
4178
+ }
4179
+ const loaded = {
4180
+ manifest,
4181
+ instance: plugin,
4182
+ path: pluginPath,
4183
+ state: "active"
4184
+ };
4185
+ loadedPlugins.set(name, loaded);
4186
+ return loaded;
4187
+ } catch (error) {
4188
+ const errorMessage = error instanceof Error ? error.message : String(error);
4189
+ console.log(theme.error(` ${symbols.cross} Failed to load plugin '${name}': ${errorMessage}`));
4190
+ const failedPlugin = {
4191
+ manifest,
4192
+ instance: { activate: async () => {
4193
+ } },
4194
+ path: pluginPath,
4195
+ state: "error"
4196
+ };
4197
+ loadedPlugins.set(name, failedPlugin);
4198
+ return null;
4199
+ }
4200
+ }
4201
+ async function unloadPlugin(name) {
4202
+ const loaded = loadedPlugins.get(name);
4203
+ if (!loaded) {
4204
+ return false;
4205
+ }
4206
+ try {
4207
+ if (loaded.instance.deactivate) {
4208
+ await loaded.instance.deactivate();
4209
+ }
4210
+ unregisterPluginCommands(name);
4211
+ loadedPlugins.delete(name);
4212
+ return true;
4213
+ } catch (error) {
4214
+ const errorMessage = error instanceof Error ? error.message : String(error);
4215
+ console.log(theme.error(` ${symbols.cross} Failed to unload plugin '${name}': ${errorMessage}`));
4216
+ return false;
4217
+ }
4218
+ }
4219
+ function getDiscoveredPlugins() {
4220
+ return Array.from(discoveredPlugins.values()).map((p) => p.manifest);
4221
+ }
4222
+ function isPluginLoaded(name) {
4223
+ return loadedPlugins.has(name);
4224
+ }
4225
+ async function initPluginLoader() {
4226
+ const manifests = await discoverPlugins();
4227
+ for (const manifest of manifests) {
4228
+ for (const cmdName of manifest.commands) {
4229
+ const lazyExecute = async (args2) => {
4230
+ const loaded = await loadPlugin(manifest.name);
4231
+ if (!loaded) {
4232
+ console.log(theme.error(` ${symbols.cross} Failed to load plugin '${manifest.name}'`));
4233
+ console.log(theme.dim(` Try reinstalling: /plugin remove ${manifest.name} && /plugin install ${manifest.name}`));
4234
+ return;
4235
+ }
4236
+ const realCommand = getCommand(cmdName);
4237
+ if (realCommand && realCommand.execute !== lazyExecute) {
4238
+ await realCommand.execute(args2);
4239
+ } else {
4240
+ console.log(theme.error(` ${symbols.cross} Plugin '${manifest.name}' did not register command '${cmdName}'`));
4241
+ console.log(theme.dim(` The plugin may be misconfigured or corrupted.`));
4242
+ }
4243
+ };
4244
+ registerPluginCommand(
4245
+ {
4246
+ name: cmdName,
4247
+ description: `[${manifest.displayName || manifest.name}] Plugin command`,
4248
+ usage: `/${cmdName}`,
4249
+ execute: lazyExecute
4250
+ },
4251
+ manifest.name
4252
+ );
4253
+ }
4254
+ }
4255
+ }
4256
+
4257
+ // src/commands/plugin/list.ts
4258
+ async function listPlugins() {
4259
+ await discoverPlugins();
4260
+ const plugins = getDiscoveredPlugins();
4261
+ console.log("");
4262
+ if (plugins.length === 0) {
4263
+ console.log(` ${symbols.info} ${theme.dim("No plugins installed")}`);
4264
+ console.log("");
4265
+ console.log(` ${theme.dim("Install a plugin with:")} ${theme.primary("/plugin install <source>")}`);
4266
+ console.log(` ${theme.dim("Create a new plugin with:")} ${theme.primary("/plugin create")}`);
4267
+ console.log("");
4268
+ return;
4269
+ }
4270
+ console.log(` ${symbols.folder} ${theme.gradient("INSTALLED PLUGINS")} ${theme.dim(`(${plugins.length})`)}`);
4271
+ console.log("");
4272
+ for (const plugin of plugins) {
4273
+ const loaded = isPluginLoaded(plugin.name);
4274
+ const status = loaded ? theme.success("active") : theme.dim("idle");
4275
+ const statusIcon = loaded ? symbols.check : symbols.bullet;
4276
+ console.log(` ${statusIcon} ${theme.primary(plugin.displayName || plugin.name)} ${theme.dim(`v${plugin.version}`)}`);
4277
+ if (plugin.description) {
4278
+ console.log(` ${theme.dim(plugin.description)}`);
4279
+ }
4280
+ console.log(` ${theme.dim("Commands:")} ${plugin.commands.map((c) => theme.accent("/" + c)).join(", ")}`);
4281
+ if (plugin.permissions) {
4282
+ const perms = [];
4283
+ if (plugin.permissions.shell) perms.push("shell");
4284
+ if (plugin.permissions.filesystem) perms.push("fs");
4285
+ if (plugin.permissions.network) perms.push("net");
4286
+ if (perms.length > 0) {
4287
+ console.log(` ${theme.dim("Permissions:")} ${theme.warning(perms.join(", "))}`);
4288
+ }
4289
+ }
4290
+ console.log("");
4291
+ }
4292
+ }
4293
+
4294
+ // src/plugins/installer.ts
4295
+ import { existsSync as existsSync9, mkdirSync as mkdirSync3, cpSync, rmSync, readFileSync as readFileSync8, readdirSync as readdirSync3, createReadStream, createWriteStream } from "fs";
4296
+ import { join as join7, resolve as resolve3, dirname as dirname4 } from "path";
4297
+ import { execSync as execSync2 } from "child_process";
4298
+ import { tmpdir, platform as platform2 } from "os";
4299
+ import { createGunzip } from "zlib";
4300
+ import { pipeline } from "stream/promises";
4301
+ import { fileURLToPath as fileURLToPath3 } from "url";
4302
+ var isWindows = platform2() === "win32";
4303
+ function getZammyVersion3() {
4304
+ try {
4305
+ const __filename = fileURLToPath3(import.meta.url);
4306
+ const __dirname = dirname4(__filename);
4307
+ const possiblePaths = [
4308
+ join7(__dirname, "package.json"),
4309
+ join7(__dirname, "..", "package.json"),
4310
+ join7(__dirname, "..", "..", "package.json")
4311
+ ];
4312
+ for (const pkgPath of possiblePaths) {
4313
+ if (existsSync9(pkgPath)) {
4314
+ const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
4315
+ if (pkg.name === "zammy" && pkg.version) {
4316
+ return pkg.version;
4317
+ }
4318
+ }
4319
+ }
4320
+ return "0.0.0";
4321
+ } catch {
4322
+ return "0.0.0";
4323
+ }
4324
+ }
4325
+ function compareVersions2(a, b3) {
4326
+ const partsA = a.split(".").map((n) => parseInt(n, 10) || 0);
4327
+ const partsB = b3.split(".").map((n) => parseInt(n, 10) || 0);
4328
+ for (let i = 0; i < 3; i++) {
4329
+ const numA = partsA[i] || 0;
4330
+ const numB = partsB[i] || 0;
4331
+ if (numA < numB) return -1;
4332
+ if (numA > numB) return 1;
4333
+ }
4334
+ return 0;
4335
+ }
4336
+ function checkVersionCompatibility2(manifest) {
4337
+ const zammyVersion = getZammyVersion3();
4338
+ const minVersion = manifest.zammy?.minVersion;
4339
+ const maxVersion = manifest.zammy?.maxVersion;
4340
+ if (minVersion && compareVersions2(zammyVersion, minVersion) < 0) {
4341
+ return {
4342
+ compatible: false,
4343
+ reason: `Requires Zammy v${minVersion}+, but you have v${zammyVersion}`
4344
+ };
4345
+ }
4346
+ if (maxVersion && compareVersions2(zammyVersion, maxVersion) > 0) {
4347
+ return {
4348
+ compatible: false,
4349
+ reason: `Incompatible with Zammy v${zammyVersion} (max supported: v${maxVersion})`
4350
+ };
4351
+ }
4352
+ return { compatible: true };
4353
+ }
4354
+ async function extractTarGz(tarGzPath, destDir) {
4355
+ try {
4356
+ execSync2(`tar -xzf "${tarGzPath}" -C "${destDir}"`, {
4357
+ encoding: "utf-8",
4358
+ stdio: ["pipe", "pipe", "pipe"]
4359
+ });
4360
+ return;
4361
+ } catch {
4362
+ }
4363
+ const tarPath = tarGzPath.replace(/\.tgz$|\.tar\.gz$/, ".tar");
4364
+ await pipeline(
4365
+ createReadStream(tarGzPath),
4366
+ createGunzip(),
4367
+ createWriteStream(tarPath)
4368
+ );
4369
+ try {
4370
+ execSync2(`tar -xf "${tarPath}" -C "${destDir}"`, {
4371
+ encoding: "utf-8",
4372
+ stdio: ["pipe", "pipe", "pipe"]
4373
+ });
4374
+ rmSync(tarPath, { force: true });
4375
+ return;
4376
+ } catch {
4377
+ rmSync(tarPath, { force: true });
4378
+ }
4379
+ if (isWindows) {
4380
+ try {
4381
+ execSync2(`powershell -Command "tar -xf '${tarPath}' -C '${destDir}'"`, {
4382
+ encoding: "utf-8",
4383
+ stdio: ["pipe", "pipe", "pipe"]
4384
+ });
4385
+ return;
4386
+ } catch {
4387
+ throw new Error(
4388
+ "Unable to extract plugin archive. Please ensure tar is available.\nOn Windows 10+, tar should be built-in. Try running: tar --version"
4389
+ );
4390
+ }
4391
+ }
4392
+ throw new Error("Unable to extract plugin archive. Please ensure tar is installed.");
4393
+ }
4394
+ function validateManifest(manifest) {
4395
+ const errors = [];
4396
+ if (!manifest || typeof manifest !== "object") {
4397
+ return { valid: false, errors: ["Manifest must be an object"] };
4398
+ }
4399
+ const m = manifest;
4400
+ if (!m.name || typeof m.name !== "string") {
4401
+ errors.push('Missing or invalid "name" field');
4402
+ }
4403
+ if (!m.version || typeof m.version !== "string") {
4404
+ errors.push('Missing or invalid "version" field');
4405
+ }
4406
+ if (!m.main || typeof m.main !== "string") {
4407
+ errors.push('Missing or invalid "main" field');
4408
+ }
4409
+ if (!m.commands || !Array.isArray(m.commands) || m.commands.length === 0) {
4410
+ errors.push('Missing or invalid "commands" field (must be non-empty array)');
4411
+ }
4412
+ if (!m.zammy || typeof m.zammy !== "object") {
4413
+ errors.push('Missing or invalid "zammy" field');
4414
+ } else {
4415
+ const zammy = m.zammy;
4416
+ if (!zammy.minVersion || typeof zammy.minVersion !== "string") {
4417
+ errors.push('Missing or invalid "zammy.minVersion" field');
4418
+ }
4419
+ }
4420
+ return { valid: errors.length === 0, errors };
4421
+ }
4422
+ function checkConflicts(manifest) {
4423
+ const conflicts = [];
4424
+ for (const cmd of manifest.commands) {
4425
+ const conflict = checkCommandConflict(cmd);
4426
+ if (conflict.exists) {
4427
+ if (conflict.source === "core") {
4428
+ conflicts.push(`Command '/${cmd}' conflicts with core zammy command`);
4429
+ } else {
4430
+ conflicts.push(`Command '/${cmd}' conflicts with plugin '${conflict.pluginName}'`);
4431
+ }
4432
+ }
4433
+ }
4434
+ return { hasConflicts: conflicts.length > 0, conflicts };
4435
+ }
4436
+ function formatPermissions(manifest) {
4437
+ const perms = [];
4438
+ const p = manifest.permissions;
4439
+ if (!p) return perms;
4440
+ if (p.shell) {
4441
+ perms.push(`${symbols.warning} shell: Can run system commands`);
4442
+ }
4443
+ if (p.filesystem) {
4444
+ if (p.filesystem === true) {
4445
+ perms.push(`${symbols.warning} filesystem: Full file system access`);
4446
+ } else if (Array.isArray(p.filesystem)) {
4447
+ perms.push(`${symbols.info} filesystem: Access to ${p.filesystem.join(", ")}`);
4448
+ }
4449
+ }
4450
+ if (p.network) {
4451
+ if (p.network === true) {
4452
+ perms.push(`${symbols.warning} network: Full network access`);
4453
+ } else if (Array.isArray(p.network)) {
4454
+ perms.push(`${symbols.info} network: Access to ${p.network.join(", ")}`);
4455
+ }
4456
+ }
4457
+ return perms;
4458
+ }
4459
+ async function installFromLocal(sourcePath) {
4460
+ try {
4461
+ const absPath = resolve3(sourcePath);
4462
+ if (!existsSync9(absPath)) {
4463
+ return { success: false, error: `Path not found: ${absPath}` };
4464
+ }
4465
+ const manifestPath = join7(absPath, "zammy-plugin.json");
4466
+ if (!existsSync9(manifestPath)) {
4467
+ return { success: false, error: "No zammy-plugin.json found in source directory" };
4468
+ }
4469
+ const manifestContent = readFileSync8(manifestPath, "utf-8");
4470
+ let manifest;
4471
+ try {
4472
+ manifest = JSON.parse(manifestContent);
4473
+ } catch {
4474
+ return { success: false, error: "Invalid JSON in zammy-plugin.json" };
4475
+ }
4476
+ const validation = validateManifest(manifest);
4477
+ if (!validation.valid) {
4478
+ return { success: false, error: `Invalid manifest: ${validation.errors.join(", ")}` };
4479
+ }
4480
+ const versionCheck = checkVersionCompatibility2(manifest);
4481
+ if (!versionCheck.compatible) {
4482
+ return { success: false, error: versionCheck.reason };
4483
+ }
4484
+ const mainPath = join7(absPath, manifest.main);
4485
+ if (!existsSync9(mainPath)) {
4486
+ return { success: false, error: `Entry point not found: ${manifest.main}` };
4487
+ }
4488
+ ensurePluginsDir();
4489
+ const targetDir = join7(getPluginsDir(), manifest.name);
4490
+ if (existsSync9(targetDir)) {
4491
+ rmSync(targetDir, { recursive: true, force: true });
4492
+ }
4493
+ cpSync(absPath, targetDir, { recursive: true });
4494
+ return { success: true, manifest };
4495
+ } catch (error) {
4496
+ const message = error instanceof Error ? error.message : String(error);
4497
+ return { success: false, error: message };
4498
+ }
4499
+ }
4500
+ async function installFromNpm(packageName) {
4501
+ const tempDir = join7(tmpdir(), `zammy-plugin-${Date.now()}`);
4502
+ try {
4503
+ mkdirSync3(tempDir, { recursive: true });
4504
+ console.log(theme.dim(` Downloading ${packageName}...`));
4505
+ execSync2(`npm pack ${packageName} --pack-destination="${tempDir}"`, {
4506
+ encoding: "utf-8",
4507
+ stdio: ["pipe", "pipe", "pipe"],
4508
+ timeout: 6e4
4509
+ });
4510
+ const files = readdirSync3(tempDir);
4511
+ const tarball = files.find((f) => f.endsWith(".tgz"));
4512
+ if (!tarball) {
4513
+ return { success: false, error: "Failed to download package" };
4514
+ }
4515
+ const extractDir = join7(tempDir, "extract");
4516
+ mkdirSync3(extractDir);
4517
+ await extractTarGz(join7(tempDir, tarball), extractDir);
4518
+ const packageDir = join7(extractDir, "package");
4519
+ if (!existsSync9(packageDir)) {
4520
+ return { success: false, error: "Invalid package structure" };
4521
+ }
4522
+ return await installFromLocal(packageDir);
4523
+ } catch (error) {
4524
+ const message = error instanceof Error ? error.message : String(error);
4525
+ return { success: false, error: `npm install failed: ${message}` };
4526
+ } finally {
4527
+ try {
4528
+ rmSync(tempDir, { recursive: true, force: true });
4529
+ } catch {
4530
+ }
4531
+ }
4532
+ }
4533
+ async function installFromGithub(repo) {
4534
+ const tempDir = join7(tmpdir(), `zammy-plugin-${Date.now()}`);
4535
+ try {
4536
+ let repoPath = repo.replace(/^github:/, "");
4537
+ let branch = "main";
4538
+ if (repoPath.includes("#")) {
4539
+ [repoPath, branch] = repoPath.split("#");
4540
+ }
4541
+ mkdirSync3(tempDir, { recursive: true });
4542
+ console.log(theme.dim(` Cloning ${repoPath}...`));
4543
+ execSync2(`git clone --depth 1 --branch ${branch} https://github.com/${repoPath}.git "${tempDir}"`, {
4544
+ encoding: "utf-8",
4545
+ stdio: ["pipe", "pipe", "pipe"],
4546
+ timeout: 12e4
4547
+ });
4548
+ const pkgJsonPath = join7(tempDir, "package.json");
4549
+ if (existsSync9(pkgJsonPath)) {
4550
+ const pkgJson = JSON.parse(readFileSync8(pkgJsonPath, "utf-8"));
4551
+ if (pkgJson.scripts?.build) {
4552
+ console.log(theme.dim(` Installing dependencies...`));
4553
+ execSync2("npm install", { cwd: tempDir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 12e4 });
4554
+ console.log(theme.dim(` Building...`));
4555
+ execSync2("npm run build", { cwd: tempDir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 12e4 });
4556
+ }
4557
+ }
4558
+ return await installFromLocal(tempDir);
4559
+ } catch (error) {
4560
+ const message = error instanceof Error ? error.message : String(error);
4561
+ return { success: false, error: `GitHub install failed: ${message}` };
4562
+ } finally {
4563
+ try {
4564
+ rmSync(tempDir, { recursive: true, force: true });
4565
+ } catch {
4566
+ }
4567
+ }
4568
+ }
4569
+ async function installFromGit(url) {
4570
+ const tempDir = join7(tmpdir(), `zammy-plugin-${Date.now()}`);
4571
+ try {
4572
+ mkdirSync3(tempDir, { recursive: true });
4573
+ console.log(theme.dim(` Cloning from ${url}...`));
4574
+ execSync2(`git clone --depth 1 "${url}" "${tempDir}"`, {
4575
+ encoding: "utf-8",
4576
+ stdio: ["pipe", "pipe", "pipe"],
4577
+ timeout: 12e4
4578
+ });
4579
+ const pkgJsonPath = join7(tempDir, "package.json");
4580
+ if (existsSync9(pkgJsonPath)) {
4581
+ const pkgJson = JSON.parse(readFileSync8(pkgJsonPath, "utf-8"));
4582
+ if (pkgJson.scripts?.build) {
4583
+ console.log(theme.dim(` Installing dependencies...`));
4584
+ execSync2("npm install", { cwd: tempDir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 12e4 });
4585
+ console.log(theme.dim(` Building...`));
4586
+ execSync2("npm run build", { cwd: tempDir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 12e4 });
4587
+ }
4588
+ }
4589
+ return await installFromLocal(tempDir);
4590
+ } catch (error) {
4591
+ const message = error instanceof Error ? error.message : String(error);
4592
+ return { success: false, error: `Git install failed: ${message}` };
4593
+ } finally {
4594
+ try {
4595
+ rmSync(tempDir, { recursive: true, force: true });
4596
+ } catch {
4597
+ }
4598
+ }
4599
+ }
4600
+ function removePlugin(name) {
4601
+ try {
4602
+ const pluginDir = join7(getPluginsDir(), name);
4603
+ if (!existsSync9(pluginDir)) {
4604
+ return { success: false, error: `Plugin '${name}' not found` };
4605
+ }
4606
+ rmSync(pluginDir, { recursive: true, force: true });
4607
+ return { success: true };
4608
+ } catch (error) {
4609
+ const message = error instanceof Error ? error.message : String(error);
4610
+ return { success: false, error: message };
4611
+ }
4612
+ }
4613
+ function detectSourceType(source) {
4614
+ if (source.startsWith("./") || source.startsWith("/") || source.startsWith("..") || /^[A-Za-z]:/.test(source)) {
4615
+ return "local";
4616
+ }
4617
+ if (source.startsWith("github:")) {
4618
+ return "github";
4619
+ }
4620
+ if (source.includes("github.com")) {
4621
+ return "github";
4622
+ }
4623
+ if (source.endsWith(".git") || source.startsWith("git@") || source.startsWith("git://")) {
4624
+ return "git";
4625
+ }
4626
+ if (/^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(source)) {
4627
+ return "npm";
4628
+ }
4629
+ return "unknown";
4630
+ }
4631
+
4632
+ // src/commands/plugin/install.ts
4633
+ import * as readline from "readline";
4634
+ async function confirm(message) {
4635
+ const rl = readline.createInterface({
4636
+ input: process.stdin,
4637
+ output: process.stdout
4638
+ });
4639
+ return new Promise((resolve6) => {
4640
+ rl.question(`${message} [y/N] `, (answer) => {
4641
+ rl.close();
4642
+ resolve6(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
4643
+ });
4644
+ });
4645
+ }
4646
+ async function installPlugin(args2) {
4647
+ const source = args2[0];
4648
+ if (!source) {
4649
+ console.log(theme.error(` ${symbols.cross} No source specified`));
4650
+ console.log("");
4651
+ console.log(` ${theme.primary("Usage:")} /plugin install <source>`);
4652
+ console.log("");
4653
+ console.log(` ${theme.dim("Examples:")}`);
4654
+ console.log(` ${theme.dim("/plugin install ./my-plugin")}`);
4655
+ console.log(` ${theme.dim("/plugin install zammy-plugin-git")}`);
4656
+ console.log(` ${theme.dim("/plugin install github:user/repo")}`);
4657
+ console.log("");
4658
+ return;
4659
+ }
4660
+ console.log("");
4661
+ console.log(` ${symbols.rocket} ${theme.primary("Installing plugin...")}`);
4662
+ const sourceType = detectSourceType(source);
4663
+ if (sourceType === "unknown") {
4664
+ console.log(theme.error(` ${symbols.cross} Could not determine source type for: ${source}`));
4665
+ return;
4666
+ }
4667
+ console.log(theme.dim(` Source type: ${sourceType}`));
4668
+ let result;
4669
+ switch (sourceType) {
4670
+ case "local":
4671
+ result = await installFromLocal(source);
4672
+ break;
4673
+ case "npm":
4674
+ result = await installFromNpm(source);
4675
+ break;
4676
+ case "github":
4677
+ result = await installFromGithub(source);
4678
+ break;
4679
+ case "git":
4680
+ result = await installFromGit(source);
4681
+ break;
4682
+ default:
4683
+ result = { success: false, error: "Unknown source type" };
4684
+ }
4685
+ if (!result.success) {
4686
+ console.log(theme.error(` ${symbols.cross} Installation failed: ${result.error}`));
4687
+ return;
4688
+ }
4689
+ const manifest = result.manifest;
4690
+ const conflicts = checkConflicts(manifest);
4691
+ if (conflicts.hasConflicts) {
4692
+ console.log("");
4693
+ console.log(theme.warning(` ${symbols.warning} Command conflicts detected:`));
4694
+ for (const conflict of conflicts.conflicts) {
4695
+ console.log(` ${theme.dim("-")} ${conflict}`);
4696
+ }
4697
+ console.log("");
4698
+ const proceed = await confirm(` ${theme.warning("Continue anyway?")}`);
4699
+ if (!proceed) {
4700
+ console.log(theme.dim(" Installation cancelled"));
4701
+ return;
4702
+ }
4703
+ }
4704
+ const permissions = formatPermissions(manifest);
4705
+ if (permissions.length > 0) {
4706
+ console.log("");
4707
+ console.log(theme.warning(` ${symbols.warning} Plugin requests permissions:`));
4708
+ for (const perm of permissions) {
4709
+ console.log(` ${perm}`);
4710
+ }
4711
+ console.log("");
4712
+ }
4713
+ await discoverPlugins();
4714
+ for (const cmdName of manifest.commands) {
4715
+ if (getCommand(cmdName)) continue;
4716
+ const lazyExecute = async (args3) => {
4717
+ const loaded = await loadPlugin(manifest.name);
4718
+ if (!loaded) {
4719
+ console.log(theme.error(` ${symbols.cross} Failed to load plugin '${manifest.name}'`));
4720
+ return;
4721
+ }
4722
+ const realCommand = getCommand(cmdName);
4723
+ if (realCommand && realCommand.execute !== lazyExecute) {
4724
+ await realCommand.execute(args3);
4725
+ } else {
4726
+ console.log(theme.error(` ${symbols.cross} Plugin '${manifest.name}' did not register command '${cmdName}'`));
4727
+ }
4728
+ };
4729
+ registerPluginCommand(
4730
+ {
4731
+ name: cmdName,
4732
+ description: `[${manifest.displayName || manifest.name}] ${manifest.description || "Plugin command"}`,
4733
+ usage: `/${cmdName}`,
4734
+ execute: lazyExecute
4735
+ },
4736
+ manifest.name
4737
+ );
4738
+ }
4739
+ console.log("");
4740
+ console.log(` ${symbols.check} ${theme.success("Plugin installed successfully!")}`);
4741
+ console.log("");
4742
+ console.log(` ${theme.primary(manifest.displayName || manifest.name)} ${theme.dim(`v${manifest.version}`)}`);
4743
+ if (manifest.description) {
4744
+ console.log(` ${theme.dim(manifest.description)}`);
4745
+ }
4746
+ console.log("");
4747
+ console.log(` ${theme.dim("Commands added:")} ${manifest.commands.map((c) => theme.accent("/" + c)).join(", ")}`);
4748
+ console.log("");
4749
+ }
4750
+
4751
+ // src/commands/plugin/remove.ts
4752
+ import * as readline2 from "readline";
4753
+ async function confirm2(message) {
4754
+ const rl = readline2.createInterface({
4755
+ input: process.stdin,
4756
+ output: process.stdout
4757
+ });
4758
+ return new Promise((resolve6) => {
4759
+ rl.question(`${message} [y/N] `, (answer) => {
4760
+ rl.close();
4761
+ resolve6(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
4762
+ });
4763
+ });
4764
+ }
4765
+ async function removePluginCommand(args2) {
4766
+ const forceIndex = args2.findIndex((a) => a === "-y" || a === "--yes");
4767
+ const skipConfirm = forceIndex !== -1;
4768
+ if (skipConfirm) {
4769
+ args2.splice(forceIndex, 1);
4770
+ }
4771
+ const name = args2[0];
4772
+ if (!name) {
4773
+ console.log(theme.error(` ${symbols.cross} No plugin name specified`));
4774
+ console.log("");
4775
+ console.log(` ${theme.primary("Usage:")} /plugin remove <name>`);
4776
+ console.log("");
4777
+ await discoverPlugins();
4778
+ const plugins2 = getDiscoveredPlugins();
4779
+ if (plugins2.length > 0) {
4780
+ console.log(` ${theme.dim("Installed plugins:")}`);
4781
+ for (const p of plugins2) {
4782
+ console.log(` ${theme.accent(p.name)}`);
4783
+ }
4784
+ console.log("");
4785
+ }
4786
+ return;
4787
+ }
4788
+ await discoverPlugins();
4789
+ const plugins = getDiscoveredPlugins();
4790
+ const plugin = plugins.find((p) => p.name === name || p.displayName?.toLowerCase() === name.toLowerCase());
4791
+ if (!plugin) {
4792
+ console.log(theme.error(` ${symbols.cross} Plugin '${name}' not found`));
4793
+ console.log("");
4794
+ const similar = plugins.filter(
4795
+ (p) => p.name.includes(name) || name.includes(p.name) || p.displayName?.toLowerCase().includes(name.toLowerCase())
4796
+ );
4797
+ if (similar.length > 0) {
4798
+ console.log(` ${theme.dim("Did you mean:")}`);
4799
+ for (const p of similar) {
4800
+ console.log(` ${theme.accent(p.name)}`);
4801
+ }
4802
+ console.log("");
4803
+ }
4804
+ return;
4805
+ }
4806
+ console.log("");
4807
+ console.log(` ${theme.warning("About to remove:")}`);
4808
+ console.log(` ${theme.primary(plugin.displayName || plugin.name)} ${theme.dim(`v${plugin.version}`)}`);
4809
+ console.log(` ${theme.dim("Commands:")} ${plugin.commands.map((c) => "/" + c).join(", ")}`);
4810
+ console.log("");
4811
+ if (!skipConfirm) {
4812
+ const proceed = await confirm2(` ${theme.warning("Remove this plugin?")}`);
4813
+ if (!proceed) {
4814
+ console.log(theme.dim(" Removal cancelled"));
4815
+ return;
4816
+ }
4817
+ }
4818
+ await unloadPlugin(plugin.name);
4819
+ const result = removePlugin(plugin.name);
4820
+ if (!result.success) {
4821
+ console.log(theme.error(` ${symbols.cross} Failed to remove: ${result.error}`));
4822
+ return;
4823
+ }
4824
+ await discoverPlugins();
4825
+ console.log("");
4826
+ console.log(` ${symbols.check} ${theme.success("Plugin removed successfully")}`);
4827
+ console.log("");
4828
+ }
2284
4829
 
2285
- // src/handlers/dev/uuid.ts
2286
- import { randomUUID } from "crypto";
2287
- function generateUuids(count = 1) {
2288
- const safeCount = Math.min(Math.max(1, count), 10);
2289
- const uuids = [];
2290
- for (let i = 0; i < safeCount; i++) {
2291
- uuids.push(randomUUID());
2292
- }
2293
- return {
2294
- uuids,
2295
- count: safeCount
4830
+ // src/commands/plugin/create.ts
4831
+ import { existsSync as existsSync10, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
4832
+ import { join as join8, resolve as resolve4 } from "path";
4833
+ import * as readline3 from "readline";
4834
+ async function prompt(message, defaultValue) {
4835
+ const rl = readline3.createInterface({
4836
+ input: process.stdin,
4837
+ output: process.stdout
4838
+ });
4839
+ const suffix = defaultValue ? ` ${theme.dim(`(${defaultValue})`)}` : "";
4840
+ return new Promise((resolvePromise) => {
4841
+ rl.question(` ${message}${suffix}: `, (answer) => {
4842
+ rl.close();
4843
+ resolvePromise(answer.trim() || defaultValue || "");
4844
+ });
4845
+ });
4846
+ }
4847
+ function generateManifest(name, displayName, description, commandName) {
4848
+ return JSON.stringify({
4849
+ name,
4850
+ version: "1.0.0",
4851
+ displayName,
4852
+ description,
4853
+ main: "./dist/index.js",
4854
+ commands: [commandName],
4855
+ zammy: {
4856
+ minVersion: "1.3.0"
4857
+ },
4858
+ permissions: {}
4859
+ }, null, 2);
4860
+ }
4861
+ function generatePackageJson(name, description) {
4862
+ return JSON.stringify({
4863
+ name,
4864
+ version: "1.0.0",
4865
+ description,
4866
+ type: "module",
4867
+ main: "dist/index.js",
4868
+ scripts: {
4869
+ build: "tsc",
4870
+ dev: "tsc --watch"
4871
+ },
4872
+ keywords: ["zammy-plugin"],
4873
+ devDependencies: {
4874
+ typescript: "^5.3.0"
4875
+ }
4876
+ }, null, 2);
4877
+ }
4878
+ function generateTsConfig() {
4879
+ return JSON.stringify({
4880
+ compilerOptions: {
4881
+ target: "ES2022",
4882
+ module: "NodeNext",
4883
+ moduleResolution: "NodeNext",
4884
+ outDir: "./dist",
4885
+ rootDir: "./src",
4886
+ strict: true,
4887
+ esModuleInterop: true,
4888
+ skipLibCheck: true,
4889
+ declaration: true
4890
+ },
4891
+ include: ["src/**/*"]
4892
+ }, null, 2);
4893
+ }
4894
+ function generateEntryPoint(commandName, displayName) {
4895
+ return `// ${displayName} - A zammy plugin
4896
+
4897
+ // Plugin types (these match zammy's PluginAPI interface)
4898
+ interface Command {
4899
+ name: string;
4900
+ description: string;
4901
+ usage: string;
4902
+ execute: (args: string[]) => Promise<void>;
4903
+ }
4904
+
4905
+ interface PluginAPI {
4906
+ registerCommand(command: Command): void;
4907
+ ui: {
4908
+ theme: {
4909
+ primary: (text: string) => string;
4910
+ secondary: (text: string) => string;
4911
+ accent: (text: string) => string;
4912
+ success: (text: string) => string;
4913
+ warning: (text: string) => string;
4914
+ error: (text: string) => string;
4915
+ info: (text: string) => string;
4916
+ dim: (text: string) => string;
4917
+ gradient: (text: string) => string;
4918
+ };
4919
+ symbols: {
4920
+ check: string;
4921
+ cross: string;
4922
+ star: string;
4923
+ arrow: string;
4924
+ bullet: string;
4925
+ folder: string;
4926
+ file: string;
4927
+ warning: string;
4928
+ info: string;
4929
+ rocket: string;
4930
+ sparkles: string;
4931
+ };
4932
+ };
4933
+ storage: {
4934
+ get<T>(key: string): T | undefined;
4935
+ set<T>(key: string, value: T): void;
4936
+ delete(key: string): void;
4937
+ };
4938
+ log: {
4939
+ info(message: string): void;
4940
+ warn(message: string): void;
4941
+ error(message: string): void;
4942
+ };
4943
+ context: {
4944
+ pluginName: string;
4945
+ pluginVersion: string;
4946
+ zammyVersion: string;
4947
+ dataDir: string;
4948
+ cwd: string;
2296
4949
  };
2297
4950
  }
2298
4951
 
2299
- // src/commands/dev/uuid.ts
2300
- registerCommand({
2301
- name: "uuid",
2302
- description: "Generate UUID(s)",
2303
- usage: "/uuid [count]",
2304
- async execute(args2) {
2305
- const count = parseInt(args2[0]) || 1;
2306
- const result = generateUuids(count);
4952
+ interface ZammyPlugin {
4953
+ activate(api: PluginAPI): Promise<void> | void;
4954
+ deactivate?(): Promise<void> | void;
4955
+ }
4956
+
4957
+ const plugin: ZammyPlugin = {
4958
+ activate(api: PluginAPI) {
4959
+ const { theme, symbols } = api.ui;
4960
+
4961
+ api.registerCommand({
4962
+ name: '${commandName}',
4963
+ description: 'My custom command',
4964
+ usage: '/${commandName} [args]',
4965
+ async execute(args: string[]) {
4966
+ console.log('');
4967
+ console.log(\` \${symbols.star} \${theme.gradient('${displayName.toUpperCase()}')}\`);
4968
+ console.log('');
4969
+ console.log(\` \${theme.success('Hello from ${displayName}!')}\`);
4970
+
4971
+ if (args.length > 0) {
4972
+ console.log(\` \${theme.dim('Arguments:')} \${args.join(' ')}\`);
4973
+ }
4974
+
4975
+ console.log('');
4976
+ },
4977
+ });
4978
+
4979
+ api.log.info('Plugin activated!');
4980
+ },
4981
+
4982
+ deactivate() {
4983
+ // Cleanup if needed
4984
+ },
4985
+ };
4986
+
4987
+ export default plugin;
4988
+ `;
4989
+ }
4990
+ function generateReadme(name, displayName, description, commandName) {
4991
+ return `# ${displayName}
4992
+
4993
+ ${description}
4994
+
4995
+ ## Installation
4996
+
4997
+ \`\`\`bash
4998
+ /plugin install ./${name}
4999
+ \`\`\`
5000
+
5001
+ ## Usage
5002
+
5003
+ \`\`\`bash
5004
+ /${commandName} [args]
5005
+ \`\`\`
5006
+
5007
+ ## Development
5008
+
5009
+ \`\`\`bash
5010
+ # Build the plugin
5011
+ npm run build
5012
+
5013
+ # Watch for changes
5014
+ npm run dev
5015
+ \`\`\`
5016
+
5017
+ ## License
5018
+
5019
+ MIT
5020
+ `;
5021
+ }
5022
+ async function createPlugin(args2) {
5023
+ console.log("");
5024
+ console.log(` ${symbols.sparkle} ${theme.gradient("CREATE NEW PLUGIN")}`);
5025
+ console.log("");
5026
+ let name = args2[0] || "";
5027
+ if (!name) {
5028
+ name = await prompt("Plugin name (e.g., my-plugin)", "zammy-plugin-example");
5029
+ }
5030
+ name = name.toLowerCase().replace(/\s+/g, "-");
5031
+ if (!name.startsWith("zammy-plugin-")) {
5032
+ }
5033
+ const displayName = await prompt("Display name", name.replace(/^zammy-plugin-/, "").replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()));
5034
+ const description = await prompt("Description", "A zammy plugin");
5035
+ const commandName = await prompt("Main command name", name.replace(/^zammy-plugin-/, "").replace(/-/g, ""));
5036
+ const targetDir = resolve4(process.cwd(), name);
5037
+ if (existsSync10(targetDir)) {
5038
+ console.log(theme.error(` ${symbols.cross} Directory already exists: ${name}`));
5039
+ return;
5040
+ }
5041
+ console.log("");
5042
+ console.log(theme.dim(` Creating plugin in ${targetDir}...`));
5043
+ try {
5044
+ mkdirSync4(targetDir);
5045
+ mkdirSync4(join8(targetDir, "src"));
5046
+ mkdirSync4(join8(targetDir, "dist"));
5047
+ writeFileSync5(join8(targetDir, "zammy-plugin.json"), generateManifest(name, displayName, description, commandName));
5048
+ writeFileSync5(join8(targetDir, "package.json"), generatePackageJson(name, description));
5049
+ writeFileSync5(join8(targetDir, "tsconfig.json"), generateTsConfig());
5050
+ writeFileSync5(join8(targetDir, "src", "index.ts"), generateEntryPoint(commandName, displayName));
5051
+ writeFileSync5(join8(targetDir, "README.md"), generateReadme(name, displayName, description, commandName));
2307
5052
  console.log("");
2308
- console.log(` ${symbols.sparkle} ${theme.gradient("UUID GENERATOR")} ${symbols.sparkle}`);
5053
+ console.log(` ${symbols.check} ${theme.success("Plugin created successfully!")}`);
2309
5054
  console.log("");
2310
- result.uuids.forEach((uuid, i) => {
2311
- console.log(` ${theme.dim(`${i + 1}.`)} ${theme.primary(uuid)}`);
2312
- });
5055
+ console.log(` ${theme.primary("Next steps:")}`);
5056
+ console.log(` ${theme.dim("1.")} cd ${name}`);
5057
+ console.log(` ${theme.dim("2.")} npm install`);
5058
+ console.log(` ${theme.dim("3.")} npm run build`);
5059
+ console.log(` ${theme.dim("4.")} /plugin install ./${name}`);
2313
5060
  console.log("");
2314
- if (result.count === 1) {
2315
- console.log(theme.dim(" Tip: /uuid 5 generates 5 UUIDs"));
2316
- }
5061
+ console.log(` ${theme.dim("Edit")} ${theme.accent("src/index.ts")} ${theme.dim("to customize your plugin")}`);
2317
5062
  console.log("");
5063
+ } catch (error) {
5064
+ const message = error instanceof Error ? error.message : String(error);
5065
+ console.log(theme.error(` ${symbols.cross} Failed to create plugin: ${message}`));
2318
5066
  }
2319
- });
2320
-
2321
- // src/handlers/dev/encode.ts
2322
- var SUPPORTED_METHODS = ["base64", "url", "hex"];
2323
- function isValidMethod(method) {
2324
- return SUPPORTED_METHODS.includes(method.toLowerCase());
2325
- }
2326
- function encodeText(text, method, direction) {
2327
- let output;
2328
- if (direction === "encode") {
2329
- switch (method) {
2330
- case "base64":
2331
- output = Buffer.from(text).toString("base64");
2332
- break;
2333
- case "url":
2334
- output = encodeURIComponent(text);
2335
- break;
2336
- case "hex":
2337
- output = Buffer.from(text).toString("hex");
2338
- break;
2339
- }
2340
- } else {
2341
- switch (method) {
2342
- case "base64":
2343
- output = Buffer.from(text, "base64").toString("utf-8");
2344
- break;
2345
- case "url":
2346
- output = decodeURIComponent(text);
2347
- break;
2348
- case "hex":
2349
- output = Buffer.from(text, "hex").toString("utf-8");
2350
- break;
2351
- }
2352
- }
2353
- return {
2354
- method: method.toUpperCase(),
2355
- direction,
2356
- input: text,
2357
- output
2358
- };
2359
5067
  }
2360
5068
 
2361
- // src/commands/dev/encode.ts
5069
+ // src/commands/plugin/index.ts
2362
5070
  registerCommand({
2363
- name: "encode",
2364
- description: "Encode/decode text (base64, url, hex)",
2365
- usage: "/encode <method> <encode|decode> <text>",
5071
+ name: "plugin",
5072
+ description: "Manage zammy plugins",
5073
+ usage: "/plugin <list|install|remove|create> [args]",
2366
5074
  async execute(args2) {
2367
- if (args2.length < 2) {
5075
+ const subcommand = args2[0]?.toLowerCase();
5076
+ if (!subcommand || subcommand === "help") {
2368
5077
  console.log("");
2369
- console.log(theme.error("Usage: /encode <method> <encode|decode> <text>"));
2370
- console.log(theme.dim(` Methods: ${SUPPORTED_METHODS.join(", ")}`));
2371
- console.log(theme.dim(" Example: /encode base64 encode hello"));
2372
- console.log(theme.dim(" Example: /encode url decode hello%20world"));
2373
- console.log("");
2374
- return;
2375
- }
2376
- const method = args2[0].toLowerCase();
2377
- const action = args2[1].toLowerCase();
2378
- const text = args2.slice(2).join(" ");
2379
- if (!isValidMethod(method)) {
2380
- console.log(theme.error(`Unknown method: ${method}. Use ${SUPPORTED_METHODS.join(", ")}`));
2381
- return;
2382
- }
2383
- if (action !== "encode" && action !== "decode") {
2384
- console.log(theme.error(`Unknown action: ${action}. Use encode or decode`));
2385
- return;
2386
- }
2387
- if (!text) {
2388
- console.log(theme.error("Please provide text to encode/decode"));
2389
- return;
2390
- }
2391
- try {
2392
- const result = encodeText(text, method, action);
2393
- console.log("");
2394
- console.log(box.draw([
2395
- "",
2396
- ` ${symbols.sparkle} ${theme.gradient(result.method + " " + result.direction.toUpperCase())}`,
2397
- "",
2398
- ` ${theme.dim("Input:")}`,
2399
- ` ${theme.secondary(result.input.length > 50 ? result.input.slice(0, 50) + "..." : result.input)}`,
2400
- "",
2401
- ` ${theme.dim("Output:")}`,
2402
- ` ${theme.success(result.output.length > 50 ? result.output.slice(0, 50) + "..." : result.output)}`,
2403
- "",
2404
- ...result.output.length > 50 ? [` ${theme.dim("(Full output: " + result.output.length + " chars)")}`] : [],
2405
- ""
2406
- ], 60));
5078
+ console.log(` ${symbols.gear} ${theme.gradient("PLUGIN MANAGER")}`);
2407
5079
  console.log("");
2408
- if (result.output.length > 50) {
2409
- console.log(theme.dim(" Full result:"));
2410
- console.log(` ${result.output}`);
2411
- console.log("");
2412
- }
2413
- } catch (e) {
2414
- console.log(theme.error(`Failed to ${action}: Invalid input for ${method}`));
2415
- }
2416
- }
2417
- });
2418
-
2419
- // src/commands/info/weather.ts
2420
- registerCommand({
2421
- name: "weather",
2422
- description: "Get current weather for a city",
2423
- usage: "/weather <city>",
2424
- async execute(args2) {
2425
- const city = args2.join(" ") || "London";
2426
- console.log(theme.dim(`Fetching weather for ${city}...`));
2427
- try {
2428
- const response = await fetch(`https://wttr.in/${encodeURIComponent(city)}?format=j1`);
2429
- if (!response.ok) {
2430
- console.log(theme.error(`Could not fetch weather for "${city}"`));
2431
- return;
2432
- }
2433
- const data = await response.json();
2434
- const current = data.current_condition[0];
2435
- const location = data.nearest_area[0];
2436
- const temp = current.temp_C;
2437
- const feelsLike = current.FeelsLikeC;
2438
- const desc = current.weatherDesc[0].value;
2439
- const humidity = current.humidity;
2440
- const wind = current.windspeedKmph;
2441
- const cityName = location.areaName[0].value;
2442
- const country = location.country[0].value;
5080
+ console.log(` ${theme.primary("Usage:")} /plugin <command> [args]`);
2443
5081
  console.log("");
2444
- console.log(theme.highlight(`${cityName}, ${country}`));
5082
+ console.log(` ${theme.primary("Commands:")}`);
5083
+ console.log(` ${theme.accent("list")} ${theme.dim("Show installed plugins")}`);
5084
+ console.log(` ${theme.accent("install")} <source> ${theme.dim("Install a plugin")}`);
5085
+ console.log(` ${theme.accent("remove")} <name> ${theme.dim("Remove a plugin")}`);
5086
+ console.log(` ${theme.accent("create")} [name] ${theme.dim("Create a new plugin")}`);
2445
5087
  console.log("");
2446
- console.log(` ${theme.primary(desc)}`);
2447
- console.log(` Temperature: ${theme.warning(temp + "\xB0C")} (feels like ${feelsLike}\xB0C)`);
2448
- console.log(` Humidity: ${humidity}%`);
2449
- console.log(` Wind: ${wind} km/h`);
5088
+ console.log(` ${theme.primary("Install sources:")}`);
5089
+ console.log(` ${theme.dim("./path/to/plugin")} ${theme.dim("Local directory")}`);
5090
+ console.log(` ${theme.dim("package-name")} ${theme.dim("npm package")}`);
5091
+ console.log(` ${theme.dim("github:user/repo")} ${theme.dim("GitHub repository")}`);
5092
+ console.log(` ${theme.dim("https://...git")} ${theme.dim("Git URL")}`);
2450
5093
  console.log("");
2451
- } catch (error) {
2452
- console.log(theme.error(`Error fetching weather: ${error}`));
5094
+ return;
5095
+ }
5096
+ switch (subcommand) {
5097
+ case "list":
5098
+ case "ls":
5099
+ await listPlugins();
5100
+ break;
5101
+ case "install":
5102
+ case "i":
5103
+ case "add":
5104
+ await installPlugin(args2.slice(1));
5105
+ break;
5106
+ case "remove":
5107
+ case "rm":
5108
+ case "uninstall":
5109
+ await removePluginCommand(args2.slice(1));
5110
+ break;
5111
+ case "create":
5112
+ case "new":
5113
+ case "init":
5114
+ await createPlugin(args2.slice(1));
5115
+ break;
5116
+ default:
5117
+ console.log(theme.error(` ${symbols.cross} Unknown subcommand: ${subcommand}`));
5118
+ console.log(theme.dim(` Use '/plugin help' to see available commands`));
2453
5119
  }
2454
5120
  }
2455
5121
  });
2456
5122
 
2457
5123
  // src/cli.ts
2458
- import { exec, execSync, spawn } from "child_process";
2459
- import { existsSync as existsSync4, statSync, readFileSync as readFileSync3, readdirSync, writeFileSync as writeFileSync3, watchFile, unwatchFile } from "fs";
2460
- import { resolve as resolve2, extname, basename, join as join3 } from "path";
2461
- import { homedir as homedir3, platform as platform2, networkInterfaces } from "os";
2462
- import chalk3 from "chalk";
2463
- var isWindows = platform2() === "win32";
5124
+ import { exec, execSync as execSync3, spawn } from "child_process";
5125
+ import { existsSync as existsSync11, statSync as statSync2, readFileSync as readFileSync9, readdirSync as readdirSync4, writeFileSync as writeFileSync6, watchFile, unwatchFile } from "fs";
5126
+ import { resolve as resolve5, extname, basename as basename4, join as join9 } from "path";
5127
+ import { homedir as homedir5, platform as platform3, networkInterfaces } from "os";
5128
+ import chalk5 from "chalk";
5129
+ var isWindows2 = platform3() === "win32";
2464
5130
  function translateCommand(cmd) {
2465
- if (!isWindows) return cmd;
5131
+ if (!isWindows2) return cmd;
2466
5132
  const parts = cmd.trim().split(/\s+/);
2467
5133
  const command = parts[0].toLowerCase();
2468
5134
  const args2 = parts.slice(1);
@@ -2514,42 +5180,42 @@ function translateCommand(cmd) {
2514
5180
  function handleCd(args2) {
2515
5181
  let targetPath = args2.trim();
2516
5182
  if (!targetPath || targetPath === "~") {
2517
- targetPath = homedir3();
5183
+ targetPath = homedir5();
2518
5184
  } else if (targetPath.startsWith("~/")) {
2519
- targetPath = resolve2(homedir3(), targetPath.slice(2));
5185
+ targetPath = resolve5(homedir5(), targetPath.slice(2));
2520
5186
  } else if (targetPath === "-") {
2521
5187
  console.log(theme.dim(process.cwd()));
2522
5188
  return;
2523
5189
  } else {
2524
- targetPath = resolve2(process.cwd(), targetPath);
5190
+ targetPath = resolve5(process.cwd(), targetPath);
2525
5191
  }
2526
- if (!existsSync4(targetPath)) {
2527
- console.log(theme.error(`Directory not found: ${targetPath}`));
5192
+ if (!existsSync11(targetPath)) {
5193
+ console.log(`${miniSlime.sad} ${theme.error(`Directory not found: ${targetPath}`)}`);
2528
5194
  return;
2529
5195
  }
2530
5196
  try {
2531
- const stats = statSync(targetPath);
5197
+ const stats = statSync2(targetPath);
2532
5198
  if (!stats.isDirectory()) {
2533
- console.log(theme.error(`Not a directory: ${targetPath}`));
5199
+ console.log(`${miniSlime.sad} ${theme.error(`Not a directory: ${targetPath}`)}`);
2534
5200
  return;
2535
5201
  }
2536
5202
  process.chdir(targetPath);
2537
5203
  console.log(theme.dim(process.cwd()));
2538
5204
  } catch (error) {
2539
- console.log(theme.error(`Cannot access: ${targetPath}`));
5205
+ console.log(`${miniSlime.sad} ${theme.error(`Cannot access: ${targetPath}`)}`);
2540
5206
  }
2541
5207
  }
2542
5208
  function handlePwd() {
2543
5209
  console.log(theme.primary(process.cwd()));
2544
5210
  }
2545
5211
  function handleCat(args2) {
2546
- const filePath = resolve2(process.cwd(), args2.trim());
2547
- if (!existsSync4(filePath)) {
2548
- console.log(theme.error(`File not found: ${args2}`));
5212
+ const filePath = resolve5(process.cwd(), args2.trim());
5213
+ if (!existsSync11(filePath)) {
5214
+ console.log(`${miniSlime.sad} ${theme.error(`File not found: ${args2}`)}`);
2549
5215
  return;
2550
5216
  }
2551
5217
  try {
2552
- const content = readFileSync3(filePath, "utf-8");
5218
+ const content = readFileSync9(filePath, "utf-8");
2553
5219
  const ext = extname(filePath).toLowerCase();
2554
5220
  if ([".js", ".ts", ".jsx", ".tsx", ".json", ".css", ".html", ".py", ".go", ".rs"].includes(ext)) {
2555
5221
  console.log(highlightSyntax(content, ext));
@@ -2557,7 +5223,7 @@ function handleCat(args2) {
2557
5223
  console.log(content);
2558
5224
  }
2559
5225
  } catch (error) {
2560
- console.log(theme.error(`Cannot read file: ${args2}`));
5226
+ console.log(`${miniSlime.sad} ${theme.error(`Cannot read file: ${args2}`)}`);
2561
5227
  }
2562
5228
  }
2563
5229
  function highlightSyntax(content, ext) {
@@ -2567,12 +5233,12 @@ function highlightSyntax(content, ext) {
2567
5233
  };
2568
5234
  const kw = ext === ".py" ? keywords.py : keywords.js;
2569
5235
  return content.split("\n").map((line) => {
2570
- line = line.replace(/(["'`])(?:(?!\1)[^\\]|\\.)*?\1/g, (match) => chalk3.hex("#98C379")(match));
2571
- line = line.replace(/(\/\/.*$|#.*$)/g, (match) => chalk3.hex("#5C6370")(match));
2572
- line = line.replace(/\b(\d+\.?\d*)\b/g, (match) => chalk3.hex("#D19A66")(match));
5236
+ line = line.replace(/(["'`])(?:(?!\1)[^\\]|\\.)*?\1/g, (match) => chalk5.hex("#98C379")(match));
5237
+ line = line.replace(/(\/\/.*$|#.*$)/g, (match) => chalk5.hex("#5C6370")(match));
5238
+ line = line.replace(/\b(\d+\.?\d*)\b/g, (match) => chalk5.hex("#D19A66")(match));
2573
5239
  kw.forEach((keyword) => {
2574
5240
  const regex = new RegExp(`\\b(${keyword})\\b`, "g");
2575
- line = line.replace(regex, chalk3.hex("#C678DD")(keyword));
5241
+ line = line.replace(regex, chalk5.hex("#C678DD")(keyword));
2576
5242
  });
2577
5243
  return line;
2578
5244
  }).join("\n");
@@ -2637,24 +5303,24 @@ var fileIcons = {
2637
5303
  "default": { icon: "\u{1F4C4}", color: "#6C7A89" }
2638
5304
  };
2639
5305
  function formatSize(bytes) {
2640
- if (bytes === 0) return chalk3.dim(" 0 B");
5306
+ if (bytes === 0) return chalk5.dim(" 0 B");
2641
5307
  const units = ["B", "KB", "MB", "GB", "TB"];
2642
5308
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
2643
5309
  const size = (bytes / Math.pow(1024, i)).toFixed(i > 0 ? 1 : 0);
2644
- return chalk3.hex("#98C379")(size.padStart(5) + " " + units[i].padEnd(2));
5310
+ return chalk5.hex("#98C379")(size.padStart(5) + " " + units[i].padEnd(2));
2645
5311
  }
2646
5312
  function handleLs(args2) {
2647
5313
  const parts = args2.trim().split(/\s+/).filter(Boolean);
2648
5314
  const showAll = parts.some((a) => a === "-a" || a === "-la" || a === "-al");
2649
5315
  const showLong = parts.some((a) => a === "-l" || a === "-la" || a === "-al");
2650
5316
  const pathArgs = parts.filter((a) => !a.startsWith("-"));
2651
- const targetPath = pathArgs.length > 0 ? resolve2(process.cwd(), pathArgs[0]) : process.cwd();
2652
- if (!existsSync4(targetPath)) {
5317
+ const targetPath = pathArgs.length > 0 ? resolve5(process.cwd(), pathArgs[0]) : process.cwd();
5318
+ if (!existsSync11(targetPath)) {
2653
5319
  console.log(theme.error(`Directory not found: ${targetPath}`));
2654
5320
  return;
2655
5321
  }
2656
5322
  try {
2657
- const entries = readdirSync(targetPath, { withFileTypes: true });
5323
+ const entries = readdirSync4(targetPath, { withFileTypes: true });
2658
5324
  const filtered = showAll ? entries : entries.filter((e) => !e.name.startsWith("."));
2659
5325
  console.log("");
2660
5326
  console.log(theme.dim(` ${targetPath}`));
@@ -2664,28 +5330,28 @@ function handleLs(args2) {
2664
5330
  console.log("");
2665
5331
  return;
2666
5332
  }
2667
- const sorted = filtered.sort((a, b) => {
2668
- if (a.isDirectory() && !b.isDirectory()) return -1;
2669
- if (!a.isDirectory() && b.isDirectory()) return 1;
2670
- return a.name.localeCompare(b.name);
5333
+ const sorted = filtered.sort((a, b3) => {
5334
+ if (a.isDirectory() && !b3.isDirectory()) return -1;
5335
+ if (!a.isDirectory() && b3.isDirectory()) return 1;
5336
+ return a.name.localeCompare(b3.name);
2671
5337
  });
2672
5338
  for (const entry of sorted) {
2673
- const fullPath = resolve2(targetPath, entry.name);
5339
+ const fullPath = resolve5(targetPath, entry.name);
2674
5340
  const isDir = entry.isDirectory();
2675
5341
  const ext = isDir ? "dir" : extname(entry.name).toLowerCase();
2676
5342
  const iconInfo = fileIcons[ext] || fileIcons["default"];
2677
5343
  let line = ` ${iconInfo.icon} `;
2678
5344
  if (showLong) {
2679
5345
  try {
2680
- const stats = statSync(fullPath);
2681
- const size = isDir ? chalk3.dim(" <DIR>") : formatSize(stats.size);
5346
+ const stats = statSync2(fullPath);
5347
+ const size = isDir ? chalk5.dim(" <DIR>") : formatSize(stats.size);
2682
5348
  const date = stats.mtime.toLocaleDateString("en-US", { month: "short", day: "2-digit", year: "numeric" });
2683
- line += chalk3.dim(date.padEnd(13)) + size + " ";
5349
+ line += chalk5.dim(date.padEnd(13)) + size + " ";
2684
5350
  } catch {
2685
- line += chalk3.dim(" ") + " ";
5351
+ line += chalk5.dim(" ") + " ";
2686
5352
  }
2687
5353
  }
2688
- const name = isDir ? chalk3.hex(iconInfo.color).bold(entry.name + "/") : chalk3.hex(iconInfo.color)(entry.name);
5354
+ const name = isDir ? chalk5.hex(iconInfo.color).bold(entry.name + "/") : chalk5.hex(iconInfo.color)(entry.name);
2689
5355
  line += name;
2690
5356
  console.log(line);
2691
5357
  }
@@ -2699,22 +5365,22 @@ function handleLs(args2) {
2699
5365
  function handleTree(args2, maxDepth = 3) {
2700
5366
  const parts = args2.trim().split(/\s+/).filter(Boolean);
2701
5367
  const pathArgs = parts.filter((a) => !a.startsWith("-"));
2702
- const targetPath = pathArgs.length > 0 ? resolve2(process.cwd(), pathArgs[0]) : process.cwd();
2703
- if (!existsSync4(targetPath)) {
5368
+ const targetPath = pathArgs.length > 0 ? resolve5(process.cwd(), pathArgs[0]) : process.cwd();
5369
+ if (!existsSync11(targetPath)) {
2704
5370
  console.log(theme.error(`Directory not found: ${targetPath}`));
2705
5371
  return;
2706
5372
  }
2707
5373
  console.log("");
2708
- console.log(theme.primary(` \u{1F4C1} ${basename(targetPath)}/`));
5374
+ console.log(theme.primary(` \u{1F4C1} ${basename4(targetPath)}/`));
2709
5375
  let dirCount = 0;
2710
5376
  let fileCount = 0;
2711
5377
  function printTree(dir, prefix, depth) {
2712
5378
  if (depth > maxDepth) return;
2713
5379
  try {
2714
- const entries = readdirSync(dir, { withFileTypes: true }).filter((e) => !e.name.startsWith(".") && !["node_modules", ".git", "dist", "build"].includes(e.name)).sort((a, b) => {
2715
- if (a.isDirectory() && !b.isDirectory()) return -1;
2716
- if (!a.isDirectory() && b.isDirectory()) return 1;
2717
- return a.name.localeCompare(b.name);
5380
+ const entries = readdirSync4(dir, { withFileTypes: true }).filter((e) => !e.name.startsWith(".") && !["node_modules", ".git", "dist", "build"].includes(e.name)).sort((a, b3) => {
5381
+ if (a.isDirectory() && !b3.isDirectory()) return -1;
5382
+ if (!a.isDirectory() && b3.isDirectory()) return 1;
5383
+ return a.name.localeCompare(b3.name);
2718
5384
  });
2719
5385
  entries.forEach((entry, index) => {
2720
5386
  const isLast = index === entries.length - 1;
@@ -2723,11 +5389,11 @@ function handleTree(args2, maxDepth = 3) {
2723
5389
  const iconInfo = fileIcons[ext] || fileIcons["default"];
2724
5390
  if (entry.isDirectory()) {
2725
5391
  dirCount++;
2726
- console.log(theme.dim(prefix + connector) + iconInfo.icon + " " + chalk3.hex(iconInfo.color).bold(entry.name + "/"));
2727
- printTree(resolve2(dir, entry.name), prefix + (isLast ? " " : "\u2502 "), depth + 1);
5392
+ console.log(theme.dim(prefix + connector) + iconInfo.icon + " " + chalk5.hex(iconInfo.color).bold(entry.name + "/"));
5393
+ printTree(resolve5(dir, entry.name), prefix + (isLast ? " " : "\u2502 "), depth + 1);
2728
5394
  } else {
2729
5395
  fileCount++;
2730
- console.log(theme.dim(prefix + connector) + iconInfo.icon + " " + chalk3.hex(iconInfo.color)(entry.name));
5396
+ console.log(theme.dim(prefix + connector) + iconInfo.icon + " " + chalk5.hex(iconInfo.color)(entry.name));
2731
5397
  }
2732
5398
  });
2733
5399
  } catch {
@@ -2738,18 +5404,18 @@ function handleTree(args2, maxDepth = 3) {
2738
5404
  console.log(theme.dim(` ${dirCount} directories, ${fileCount} files`));
2739
5405
  console.log("");
2740
5406
  }
2741
- var bookmarksFile = join3(homedir3(), ".zammy-bookmarks.json");
5407
+ var bookmarksFile = join9(homedir5(), ".zammy-bookmarks.json");
2742
5408
  function loadBookmarks() {
2743
5409
  try {
2744
- if (existsSync4(bookmarksFile)) {
2745
- return JSON.parse(readFileSync3(bookmarksFile, "utf-8"));
5410
+ if (existsSync11(bookmarksFile)) {
5411
+ return JSON.parse(readFileSync9(bookmarksFile, "utf-8"));
2746
5412
  }
2747
5413
  } catch {
2748
5414
  }
2749
5415
  return {};
2750
5416
  }
2751
5417
  function saveBookmarks(bookmarks) {
2752
- writeFileSync3(bookmarksFile, JSON.stringify(bookmarks, null, 2));
5418
+ writeFileSync6(bookmarksFile, JSON.stringify(bookmarks, null, 2));
2753
5419
  }
2754
5420
  function handleBookmark(args2) {
2755
5421
  const parts = args2.trim().split(/\s+/);
@@ -2761,38 +5427,38 @@ function handleBookmark(args2) {
2761
5427
  case "save":
2762
5428
  case "add":
2763
5429
  if (!name) {
2764
- console.log(theme.error(" Usage: bookmark save <name>"));
5430
+ console.log(` ${miniSlime.thinking} ${theme.error("Usage: bookmark save <name>")}`);
2765
5431
  break;
2766
5432
  }
2767
5433
  bookmarks[name] = process.cwd();
2768
5434
  saveBookmarks(bookmarks);
2769
- console.log(` ${symbols.check} ${theme.success("Saved bookmark:")} ${theme.primary(name)} ${theme.dim("\u2192")} ${process.cwd()}`);
5435
+ console.log(` ${miniSlime.happy} ${theme.success("Saved bookmark:")} ${theme.primary(name)} ${theme.dim("\u2192")} ${process.cwd()}`);
2770
5436
  break;
2771
5437
  case "go":
2772
5438
  case "cd":
2773
5439
  if (!name || !bookmarks[name]) {
2774
- console.log(theme.error(` Bookmark not found: ${name}`));
5440
+ console.log(` ${miniSlime.sad} ${theme.error(`Bookmark not found: ${name}`)}`);
2775
5441
  console.log(theme.dim(' Use "bookmark list" to see all bookmarks'));
2776
5442
  break;
2777
5443
  }
2778
5444
  try {
2779
5445
  process.chdir(bookmarks[name]);
2780
- console.log(` ${symbols.check} ${theme.dim("Jumped to")} ${theme.primary(name)}`);
5446
+ console.log(` ${miniSlime.excited} ${theme.dim("Jumped to")} ${theme.primary(name)}`);
2781
5447
  console.log(` ${theme.dim(process.cwd())}`);
2782
5448
  } catch {
2783
- console.log(theme.error(` Cannot access: ${bookmarks[name]}`));
5449
+ console.log(` ${miniSlime.sad} ${theme.error(`Cannot access: ${bookmarks[name]}`)}`);
2784
5450
  }
2785
5451
  break;
2786
5452
  case "del":
2787
5453
  case "delete":
2788
5454
  case "rm":
2789
5455
  if (!name || !bookmarks[name]) {
2790
- console.log(theme.error(` Bookmark not found: ${name}`));
5456
+ console.log(` ${miniSlime.sad} ${theme.error(`Bookmark not found: ${name}`)}`);
2791
5457
  break;
2792
5458
  }
2793
5459
  delete bookmarks[name];
2794
5460
  saveBookmarks(bookmarks);
2795
- console.log(` ${symbols.check} ${theme.success("Deleted bookmark:")} ${theme.primary(name)}`);
5461
+ console.log(` ${miniSlime.happy} ${theme.success("Deleted bookmark:")} ${theme.primary(name)}`);
2796
5462
  break;
2797
5463
  case "list":
2798
5464
  case "ls":
@@ -2805,7 +5471,7 @@ function handleBookmark(args2) {
2805
5471
  console.log(theme.primary(" \u{1F4CD} Directory Bookmarks"));
2806
5472
  console.log("");
2807
5473
  for (const key of keys.sort()) {
2808
- const exists = existsSync4(bookmarks[key]);
5474
+ const exists = existsSync11(bookmarks[key]);
2809
5475
  const status = exists ? theme.success(symbols.check) : theme.error(symbols.cross);
2810
5476
  console.log(` ${status} ${theme.primary(key.padEnd(15))} ${theme.dim("\u2192")} ${bookmarks[key]}`);
2811
5477
  }
@@ -2822,10 +5488,10 @@ function handleFind(args2) {
2822
5488
  function searchDir(dir, depth = 0) {
2823
5489
  if (depth > 5 || results.length >= maxResults) return;
2824
5490
  try {
2825
- const entries = readdirSync(dir, { withFileTypes: true });
5491
+ const entries = readdirSync4(dir, { withFileTypes: true });
2826
5492
  for (const entry of entries) {
2827
5493
  if (entry.name.startsWith(".") || ["node_modules", ".git", "dist", "build"].includes(entry.name)) continue;
2828
- const fullPath = resolve2(dir, entry.name);
5494
+ const fullPath = resolve5(dir, entry.name);
2829
5495
  const matchPattern = pattern.replace(/\*/g, ".*").replace(/\?/g, ".");
2830
5496
  const regex = new RegExp(matchPattern, "i");
2831
5497
  if (regex.test(entry.name)) {
@@ -2849,9 +5515,9 @@ function handleFind(args2) {
2849
5515
  const relativePath = result.path.replace(searchPath, ".").replace(/\\/g, "/");
2850
5516
  const ext = result.isDir ? "dir" : extname(result.path).toLowerCase();
2851
5517
  const iconInfo = fileIcons[ext] || fileIcons["default"];
2852
- const fileName = basename(result.path);
5518
+ const fileName = basename4(result.path);
2853
5519
  const dirPath = relativePath.slice(0, -fileName.length);
2854
- console.log(` ${iconInfo.icon} ${theme.dim(dirPath)}${chalk3.hex(iconInfo.color)(fileName)}${result.isDir ? "/" : ""}`);
5520
+ console.log(` ${iconInfo.icon} ${theme.dim(dirPath)}${chalk5.hex(iconInfo.color)(fileName)}${result.isDir ? "/" : ""}`);
2855
5521
  }
2856
5522
  if (results.length >= maxResults) {
2857
5523
  console.log("");
@@ -2861,8 +5527,8 @@ function handleFind(args2) {
2861
5527
  console.log("");
2862
5528
  }
2863
5529
  function handleDu(args2) {
2864
- const targetPath = args2.trim() ? resolve2(process.cwd(), args2.trim()) : process.cwd();
2865
- if (!existsSync4(targetPath)) {
5530
+ const targetPath = args2.trim() ? resolve5(process.cwd(), args2.trim()) : process.cwd();
5531
+ if (!existsSync11(targetPath)) {
2866
5532
  console.log(theme.error(` Path not found: ${targetPath}`));
2867
5533
  return;
2868
5534
  }
@@ -2870,10 +5536,10 @@ function handleDu(args2) {
2870
5536
  console.log("");
2871
5537
  console.log(theme.dim(" Calculating sizes..."));
2872
5538
  try {
2873
- const entries = readdirSync(targetPath, { withFileTypes: true });
5539
+ const entries = readdirSync4(targetPath, { withFileTypes: true });
2874
5540
  for (const entry of entries) {
2875
5541
  if (entry.name.startsWith(".")) continue;
2876
- const fullPath = resolve2(targetPath, entry.name);
5542
+ const fullPath = resolve5(targetPath, entry.name);
2877
5543
  let size = 0;
2878
5544
  let skipped = false;
2879
5545
  try {
@@ -2882,10 +5548,10 @@ function handleDu(args2) {
2882
5548
  skipped = true;
2883
5549
  size = 0;
2884
5550
  } else {
2885
- size = getDirSize(fullPath);
5551
+ size = getDirSize2(fullPath);
2886
5552
  }
2887
5553
  } else {
2888
- size = statSync(fullPath).size;
5554
+ size = statSync2(fullPath).size;
2889
5555
  }
2890
5556
  items.push({ name: entry.name, size, isDir: entry.isDirectory(), skipped });
2891
5557
  } catch {
@@ -2896,10 +5562,10 @@ function handleDu(args2) {
2896
5562
  return;
2897
5563
  }
2898
5564
  process.stdout.write("\x1B[1A\x1B[2K");
2899
- items.sort((a, b) => b.size - a.size);
5565
+ items.sort((a, b3) => b3.size - a.size);
2900
5566
  const totalSize = items.reduce((sum, item) => sum + item.size, 0);
2901
5567
  console.log("");
2902
- console.log(theme.primary(` \u{1F4CA} Disk Usage: ${basename(targetPath)}`));
5568
+ console.log(theme.primary(` \u{1F4CA} Disk Usage: ${basename4(targetPath)}`));
2903
5569
  console.log(theme.dim(` Total: ${formatSizeSimple(totalSize)}`));
2904
5570
  console.log("");
2905
5571
  const maxItems = 15;
@@ -2913,10 +5579,10 @@ function handleDu(args2) {
2913
5579
  const percent = totalSize > 0 ? item.size / totalSize * 100 : 0;
2914
5580
  const barWidth = 20;
2915
5581
  const filled = Math.round(percent / 100 * barWidth);
2916
- const bar = chalk3.hex("#4ECDC4")("\u2588".repeat(filled)) + chalk3.dim("\u2591".repeat(barWidth - filled));
5582
+ const bar = chalk5.hex("#4ECDC4")("\u2588".repeat(filled)) + chalk5.dim("\u2591".repeat(barWidth - filled));
2917
5583
  const icon = item.isDir ? "\u{1F4C1}" : "\u{1F4C4}";
2918
5584
  const name = item.name.length > 25 ? item.name.slice(0, 22) + "..." : item.name.padEnd(25);
2919
- console.log(` ${icon} ${name} ${bar} ${formatSizeSimple(item.size).padStart(8)} ${chalk3.dim(`${percent.toFixed(1)}%`)}`);
5585
+ console.log(` ${icon} ${name} ${bar} ${formatSizeSimple(item.size).padStart(8)} ${chalk5.dim(`${percent.toFixed(1)}%`)}`);
2920
5586
  }
2921
5587
  if (items.length > maxItems) {
2922
5588
  console.log(theme.dim(` ... and ${items.length - maxItems} more items`));
@@ -2928,19 +5594,19 @@ function handleDu(args2) {
2928
5594
  console.log("");
2929
5595
  }
2930
5596
  var skipDirs = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", ".nuxt", "coverage", ".cache", "__pycache__", "venv", ".venv"]);
2931
- function getDirSize(dir, depth = 0, maxDepth = 4) {
5597
+ function getDirSize2(dir, depth = 0, maxDepth = 4) {
2932
5598
  if (depth > maxDepth) return 0;
2933
5599
  let size = 0;
2934
5600
  try {
2935
- const entries = readdirSync(dir, { withFileTypes: true });
5601
+ const entries = readdirSync4(dir, { withFileTypes: true });
2936
5602
  for (const entry of entries) {
2937
5603
  if (skipDirs.has(entry.name)) continue;
2938
- const fullPath = resolve2(dir, entry.name);
5604
+ const fullPath = resolve5(dir, entry.name);
2939
5605
  if (entry.isDirectory()) {
2940
- size += getDirSize(fullPath, depth + 1, maxDepth);
5606
+ size += getDirSize2(fullPath, depth + 1, maxDepth);
2941
5607
  } else {
2942
5608
  try {
2943
- size += statSync(fullPath).size;
5609
+ size += statSync2(fullPath).size;
2944
5610
  } catch {
2945
5611
  }
2946
5612
  }
@@ -2959,7 +5625,7 @@ function handleGit(args2) {
2959
5625
  const subcommand = args2.trim().split(/\s+/)[0] || "status";
2960
5626
  console.log("");
2961
5627
  try {
2962
- execSync("git rev-parse --is-inside-work-tree", { stdio: "pipe", timeout: 5e3 });
5628
+ execSync3("git rev-parse --is-inside-work-tree", { stdio: "pipe", timeout: 5e3 });
2963
5629
  } catch {
2964
5630
  console.log(theme.error(" Not a git repository"));
2965
5631
  console.log("");
@@ -2969,10 +5635,10 @@ function handleGit(args2) {
2969
5635
  switch (subcommand) {
2970
5636
  case "status":
2971
5637
  case "s": {
2972
- const branch = execSync("git branch --show-current", { encoding: "utf-8", timeout: 5e3 }).trim();
2973
- console.log(` ${symbols.rocket} ${theme.primary("Branch:")} ${chalk3.hex("#98C379")(branch)}`);
5638
+ const branch = execSync3("git branch --show-current", { encoding: "utf-8", timeout: 5e3 }).trim();
5639
+ console.log(` ${symbols.rocket} ${theme.primary("Branch:")} ${chalk5.hex("#98C379")(branch)}`);
2974
5640
  console.log("");
2975
- const status = execSync("git status --porcelain", { encoding: "utf-8", timeout: 5e3 });
5641
+ const status = execSync3("git status --porcelain", { encoding: "utf-8", timeout: 5e3 });
2976
5642
  if (!status.trim()) {
2977
5643
  console.log(` ${symbols.check} ${theme.success("Working tree clean")}`);
2978
5644
  } else {
@@ -2995,12 +5661,12 @@ function handleGit(args2) {
2995
5661
  }
2996
5662
  if (staged.length > 0) {
2997
5663
  console.log(theme.success(" Staged changes:"));
2998
- staged.forEach((f) => console.log(` ${symbols.check} ${chalk3.hex("#98C379")(f)}`));
5664
+ staged.forEach((f) => console.log(` ${symbols.check} ${chalk5.hex("#98C379")(f)}`));
2999
5665
  console.log("");
3000
5666
  }
3001
5667
  if (modified.length > 0) {
3002
5668
  console.log(theme.warning(" Modified:"));
3003
- modified.forEach((f) => console.log(` ${symbols.bullet} ${chalk3.hex("#E5C07B")(f)}`));
5669
+ modified.forEach((f) => console.log(` ${symbols.bullet} ${chalk5.hex("#E5C07B")(f)}`));
3004
5670
  console.log("");
3005
5671
  }
3006
5672
  if (untracked.length > 0) {
@@ -3009,35 +5675,35 @@ function handleGit(args2) {
3009
5675
  console.log("");
3010
5676
  }
3011
5677
  }
3012
- const log = execSync("git log --oneline -3", { encoding: "utf-8", timeout: 3e3 }).trim();
5678
+ const log = execSync3("git log --oneline -3", { encoding: "utf-8", timeout: 3e3 }).trim();
3013
5679
  if (log) {
3014
5680
  console.log(theme.dim(" Recent commits:"));
3015
5681
  log.split("\n").forEach((line) => {
3016
5682
  const [hash, ...msg] = line.split(" ");
3017
- console.log(` ${chalk3.hex("#61AFEF")(hash)} ${theme.dim(msg.join(" "))}`);
5683
+ console.log(` ${chalk5.hex("#61AFEF")(hash)} ${theme.dim(msg.join(" "))}`);
3018
5684
  });
3019
5685
  }
3020
5686
  break;
3021
5687
  }
3022
5688
  case "log":
3023
5689
  case "l": {
3024
- const log = execSync("git log --oneline -10", { encoding: "utf-8", timeout: 3e3 }).trim();
5690
+ const log = execSync3("git log --oneline -10", { encoding: "utf-8", timeout: 3e3 }).trim();
3025
5691
  console.log(theme.primary(" \u{1F4DC} Recent Commits"));
3026
5692
  console.log("");
3027
5693
  log.split("\n").forEach((line) => {
3028
5694
  const [hash, ...msg] = line.split(" ");
3029
- console.log(` ${chalk3.hex("#61AFEF")(hash)} ${msg.join(" ")}`);
5695
+ console.log(` ${chalk5.hex("#61AFEF")(hash)} ${msg.join(" ")}`);
3030
5696
  });
3031
5697
  break;
3032
5698
  }
3033
5699
  case "branch":
3034
5700
  case "b": {
3035
- const branches = execSync("git branch -a", { encoding: "utf-8", timeout: 3e3 }).trim();
5701
+ const branches = execSync3("git branch -a", { encoding: "utf-8", timeout: 3e3 }).trim();
3036
5702
  console.log(theme.primary(" \u{1F33F} Branches"));
3037
5703
  console.log("");
3038
5704
  branches.split("\n").forEach((line) => {
3039
5705
  if (line.startsWith("*")) {
3040
- console.log(` ${chalk3.hex("#98C379")(line)}`);
5706
+ console.log(` ${chalk5.hex("#98C379")(line)}`);
3041
5707
  } else {
3042
5708
  console.log(` ${theme.dim(line)}`);
3043
5709
  }
@@ -3045,7 +5711,7 @@ function handleGit(args2) {
3045
5711
  break;
3046
5712
  }
3047
5713
  default:
3048
- const result = execSync(`git ${args2}`, { encoding: "utf-8", timeout: 1e4 });
5714
+ const result = execSync3(`git ${args2}`, { encoding: "utf-8", timeout: 1e4 });
3049
5715
  console.log(result);
3050
5716
  }
3051
5717
  } catch (error) {
@@ -3054,23 +5720,23 @@ function handleGit(args2) {
3054
5720
  }
3055
5721
  console.log("");
3056
5722
  }
3057
- var isMac = platform2() === "darwin";
3058
- var isLinux = platform2() === "linux";
5723
+ var isMac = platform3() === "darwin";
5724
+ var isLinux = platform3() === "linux";
3059
5725
  function getClipboardCopyCmd() {
3060
- if (isWindows) return "clip";
5726
+ if (isWindows2) return "clip";
3061
5727
  if (isMac) return "pbcopy";
3062
5728
  try {
3063
- execSync("which xclip", { stdio: "pipe" });
5729
+ execSync3("which xclip", { stdio: "pipe" });
3064
5730
  return "xclip -selection clipboard";
3065
5731
  } catch {
3066
5732
  return "xsel --clipboard --input";
3067
5733
  }
3068
5734
  }
3069
5735
  function getClipboardPasteCmd() {
3070
- if (isWindows) return 'powershell -command "Get-Clipboard"';
5736
+ if (isWindows2) return 'powershell -command "Get-Clipboard"';
3071
5737
  if (isMac) return "pbpaste";
3072
5738
  try {
3073
- execSync("which xclip", { stdio: "pipe" });
5739
+ execSync3("which xclip", { stdio: "pipe" });
3074
5740
  return "xclip -selection clipboard -o";
3075
5741
  } catch {
3076
5742
  return "xsel --clipboard --output";
@@ -3084,10 +5750,10 @@ function handleClipboard(args2) {
3084
5750
  if (action === "copy" && content) {
3085
5751
  try {
3086
5752
  const copyCmd = getClipboardCopyCmd();
3087
- if (isWindows) {
3088
- execSync(`echo ${content} | ${copyCmd}`, { stdio: "pipe", timeout: 3e3 });
5753
+ if (isWindows2) {
5754
+ execSync3(`echo ${content} | ${copyCmd}`, { stdio: "pipe", timeout: 3e3 });
3089
5755
  } else {
3090
- execSync(`echo "${content}" | ${copyCmd}`, { stdio: "pipe", timeout: 3e3 });
5756
+ execSync3(`echo "${content}" | ${copyCmd}`, { stdio: "pipe", timeout: 3e3 });
3091
5757
  }
3092
5758
  console.log(` ${symbols.check} ${theme.success("Copied to clipboard")}`);
3093
5759
  } catch {
@@ -3099,7 +5765,7 @@ function handleClipboard(args2) {
3099
5765
  } else if (action === "paste") {
3100
5766
  try {
3101
5767
  const pasteCmd = getClipboardPasteCmd();
3102
- const result = execSync(pasteCmd, { encoding: "utf-8", timeout: 3e3 }).trim();
5768
+ const result = execSync3(pasteCmd, { encoding: "utf-8", timeout: 3e3 }).trim();
3103
5769
  console.log(` ${symbols.clipboard} ${theme.dim("Clipboard contents:")}`);
3104
5770
  console.log("");
3105
5771
  console.log(result);
@@ -3110,14 +5776,14 @@ function handleClipboard(args2) {
3110
5776
  }
3111
5777
  }
3112
5778
  } else if (action === "file" && parts[1]) {
3113
- const filePath = resolve2(process.cwd(), parts[1]);
3114
- if (existsSync4(filePath)) {
5779
+ const filePath = resolve5(process.cwd(), parts[1]);
5780
+ if (existsSync11(filePath)) {
3115
5781
  try {
3116
5782
  const copyCmd = getClipboardCopyCmd();
3117
- if (isWindows) {
3118
- execSync(`type "${filePath}" | ${copyCmd}`, { stdio: "pipe", timeout: 5e3 });
5783
+ if (isWindows2) {
5784
+ execSync3(`type "${filePath}" | ${copyCmd}`, { stdio: "pipe", timeout: 5e3 });
3119
5785
  } else {
3120
- execSync(`cat "${filePath}" | ${copyCmd}`, { stdio: "pipe", timeout: 5e3 });
5786
+ execSync3(`cat "${filePath}" | ${copyCmd}`, { stdio: "pipe", timeout: 5e3 });
3121
5787
  }
3122
5788
  console.log(` ${symbols.check} ${theme.success("File contents copied to clipboard")}`);
3123
5789
  } catch {
@@ -3143,14 +5809,14 @@ function handleClipboard(args2) {
3143
5809
  console.log("");
3144
5810
  }
3145
5811
  function handlePretty(args2) {
3146
- const filePath = resolve2(process.cwd(), args2.trim());
3147
- if (!existsSync4(filePath)) {
5812
+ const filePath = resolve5(process.cwd(), args2.trim());
5813
+ if (!existsSync11(filePath)) {
3148
5814
  console.log(theme.error(` File not found: ${args2}`));
3149
5815
  return;
3150
5816
  }
3151
5817
  console.log("");
3152
5818
  try {
3153
- const content = readFileSync3(filePath, "utf-8");
5819
+ const content = readFileSync9(filePath, "utf-8");
3154
5820
  const ext = extname(filePath).toLowerCase();
3155
5821
  if (ext === ".json") {
3156
5822
  const parsed = JSON.parse(content);
@@ -3166,7 +5832,7 @@ function handlePretty(args2) {
3166
5832
  console.log("");
3167
5833
  }
3168
5834
  function highlightJson(json) {
3169
- return json.replace(/"([^"]+)":/g, (_, key) => chalk3.hex("#E06C75")(`"${key}"`) + ":").replace(/: "([^"]*)"/g, (_, val) => ": " + chalk3.hex("#98C379")(`"${val}"`)).replace(/: (\d+)/g, (_, num) => ": " + chalk3.hex("#D19A66")(num)).replace(/: (true|false)/g, (_, bool) => ": " + chalk3.hex("#56B6C2")(bool)).replace(/: (null)/g, (_, n) => ": " + chalk3.hex("#C678DD")(n));
5835
+ 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));
3170
5836
  }
3171
5837
  var activeWatcher = null;
3172
5838
  function handleWatch(args2) {
@@ -3197,14 +5863,14 @@ function handleWatch(args2) {
3197
5863
  console.log("");
3198
5864
  return;
3199
5865
  }
3200
- const filePath = resolve2(process.cwd(), action);
3201
- if (!existsSync4(filePath)) {
5866
+ const filePath = resolve5(process.cwd(), action);
5867
+ if (!existsSync11(filePath)) {
3202
5868
  console.log(theme.error(` File not found: ${action}`));
3203
5869
  console.log("");
3204
5870
  return;
3205
5871
  }
3206
5872
  try {
3207
- const stats = statSync(filePath);
5873
+ const stats = statSync2(filePath);
3208
5874
  if (stats.isDirectory()) {
3209
5875
  console.log(theme.error(` Cannot watch a directory: ${action}`));
3210
5876
  console.log(theme.dim(" Please specify a file path"));
@@ -3220,12 +5886,12 @@ function handleWatch(args2) {
3220
5886
  unwatchFile(activeWatcher);
3221
5887
  }
3222
5888
  activeWatcher = filePath;
3223
- let lastSize = statSync(filePath).size;
5889
+ let lastSize = statSync2(filePath).size;
3224
5890
  console.log(` ${symbols.info} ${theme.primary("Watching:")} ${filePath}`);
3225
5891
  console.log(theme.dim(' (Type "!watch stop" to stop watching)'));
3226
5892
  console.log("");
3227
5893
  try {
3228
- const content = readFileSync3(filePath, "utf-8");
5894
+ const content = readFileSync9(filePath, "utf-8");
3229
5895
  const lines = content.split("\n").slice(-10);
3230
5896
  lines.forEach((line) => console.log(theme.dim(line)));
3231
5897
  } catch {
@@ -3234,12 +5900,12 @@ function handleWatch(args2) {
3234
5900
  watchFile(filePath, { interval: 500 }, (curr, prev) => {
3235
5901
  if (curr.size > lastSize) {
3236
5902
  try {
3237
- const newContent = readFileSync3(filePath, "utf-8");
5903
+ const newContent = readFileSync9(filePath, "utf-8");
3238
5904
  const allLines = newContent.split("\n");
3239
5905
  const oldLines = Math.floor(prev.size / 50);
3240
5906
  const newLines = allLines.slice(-Math.max(1, allLines.length - oldLines));
3241
5907
  newLines.forEach((line) => {
3242
- if (line.trim()) console.log(chalk3.hex("#98C379")(line));
5908
+ if (line.trim()) console.log(chalk5.hex("#98C379")(line));
3243
5909
  });
3244
5910
  } catch {
3245
5911
  }
@@ -3252,12 +5918,12 @@ function handleServe(args2) {
3252
5918
  console.log("");
3253
5919
  console.log(` ${symbols.rocket} ${theme.primary("Starting HTTP server...")}`);
3254
5920
  console.log(` ${theme.dim("Serving:")} ${process.cwd()}`);
3255
- console.log(` ${theme.dim("URL:")} ${chalk3.hex("#61AFEF")(`http://localhost:${port}`)}`);
5921
+ console.log(` ${theme.dim("URL:")} ${chalk5.hex("#61AFEF")(`http://localhost:${port}`)}`);
3256
5922
  console.log("");
3257
5923
  console.log(theme.dim(" Press Ctrl+C to stop"));
3258
5924
  console.log("");
3259
5925
  try {
3260
- const npx = isWindows ? "npx.cmd" : "npx";
5926
+ const npx = isWindows2 ? "npx.cmd" : "npx";
3261
5927
  spawn(npx, ["serve", "-p", String(port)], {
3262
5928
  cwd: process.cwd(),
3263
5929
  stdio: "inherit"
@@ -3272,8 +5938,8 @@ function handlePs() {
3272
5938
  console.log("");
3273
5939
  try {
3274
5940
  let result;
3275
- if (isWindows) {
3276
- result = execSync('tasklist /FO CSV /NH | findstr /V "System Idle"', { encoding: "utf-8", timeout: 5e3 });
5941
+ if (isWindows2) {
5942
+ result = execSync3('tasklist /FO CSV /NH | findstr /V "System Idle"', { encoding: "utf-8", timeout: 5e3 });
3277
5943
  const lines = result.trim().split("\n").slice(0, 15);
3278
5944
  console.log(theme.dim(" Name PID Memory"));
3279
5945
  console.log(theme.dim(" \u2500".repeat(25)));
@@ -3283,11 +5949,11 @@ function handlePs() {
3283
5949
  const name = parts[0].slice(0, 28).padEnd(30);
3284
5950
  const pid = parts[1].padStart(8);
3285
5951
  const mem = parts[4];
3286
- console.log(` ${name}${pid} ${chalk3.hex("#98C379")(mem)}`);
5952
+ console.log(` ${name}${pid} ${chalk5.hex("#98C379")(mem)}`);
3287
5953
  }
3288
5954
  });
3289
5955
  } else {
3290
- result = execSync("ps aux | head -15", { encoding: "utf-8", timeout: 5e3 });
5956
+ result = execSync3("ps aux | head -15", { encoding: "utf-8", timeout: 5e3 });
3291
5957
  console.log(result);
3292
5958
  }
3293
5959
  } catch {
@@ -3310,7 +5976,7 @@ function handleEnv(args2) {
3310
5976
  filtered.slice(0, maxShow).forEach((key) => {
3311
5977
  const value = env[key] || "";
3312
5978
  const displayValue = value.length > 50 ? value.slice(0, 47) + "..." : value;
3313
- console.log(` ${chalk3.hex("#E06C75")(key.padEnd(25))} ${theme.dim("=")} ${displayValue}`);
5979
+ console.log(` ${chalk5.hex("#E06C75")(key.padEnd(25))} ${theme.dim("=")} ${displayValue}`);
3314
5980
  });
3315
5981
  if (filtered.length > maxShow) {
3316
5982
  console.log(theme.dim(` ... and ${filtered.length - maxShow} more`));
@@ -3339,22 +6005,22 @@ function handleIp() {
3339
6005
  if (localIps.length === 0) {
3340
6006
  console.log(` ${theme.dim("(No network interfaces found)")}`);
3341
6007
  } else {
3342
- localIps.forEach((ip) => console.log(` ${chalk3.hex("#98C379")(ip)}`));
6008
+ localIps.forEach((ip) => console.log(` ${chalk5.hex("#98C379")(ip)}`));
3343
6009
  }
3344
6010
  console.log("");
3345
6011
  console.log(theme.dim(" Public IP:"));
3346
6012
  try {
3347
6013
  let result;
3348
6014
  try {
3349
- result = execSync("curl -s ifconfig.me", { encoding: "utf-8", timeout: 5e3 }).trim();
6015
+ result = execSync3("curl -s ifconfig.me", { encoding: "utf-8", timeout: 5e3 }).trim();
3350
6016
  } catch {
3351
- if (isWindows) {
3352
- result = execSync('powershell -command "(Invoke-WebRequest -Uri ifconfig.me -UseBasicParsing).Content"', { encoding: "utf-8", timeout: 5e3 }).trim();
6017
+ if (isWindows2) {
6018
+ result = execSync3('powershell -command "(Invoke-WebRequest -Uri ifconfig.me -UseBasicParsing).Content"', { encoding: "utf-8", timeout: 5e3 }).trim();
3353
6019
  } else {
3354
6020
  throw new Error("curl not available");
3355
6021
  }
3356
6022
  }
3357
- console.log(` ${chalk3.hex("#61AFEF")(result)}`);
6023
+ console.log(` ${chalk5.hex("#61AFEF")(result)}`);
3358
6024
  } catch {
3359
6025
  console.log(` ${theme.dim("(Could not fetch - requires curl or internet)")}`);
3360
6026
  }
@@ -3371,21 +6037,21 @@ function handleEpoch(args2) {
3371
6037
  if (!input || input === "now") {
3372
6038
  const now = /* @__PURE__ */ new Date();
3373
6039
  console.log(` ${theme.dim("Current Time:")}`);
3374
- console.log(` ${chalk3.hex("#98C379")(now.toISOString())}`);
3375
- console.log(` ${chalk3.hex("#61AFEF")(Math.floor(now.getTime() / 1e3).toString())} ${theme.dim("(Unix seconds)")}`);
3376
- console.log(` ${chalk3.hex("#E5C07B")(now.getTime().toString())} ${theme.dim("(Unix milliseconds)")}`);
6040
+ console.log(` ${chalk5.hex("#98C379")(now.toISOString())}`);
6041
+ console.log(` ${chalk5.hex("#61AFEF")(Math.floor(now.getTime() / 1e3).toString())} ${theme.dim("(Unix seconds)")}`);
6042
+ console.log(` ${chalk5.hex("#E5C07B")(now.getTime().toString())} ${theme.dim("(Unix milliseconds)")}`);
3377
6043
  } else if (/^\d{10,13}$/.test(input)) {
3378
6044
  const ms = input.length === 10 ? parseInt(input) * 1e3 : parseInt(input);
3379
6045
  const date = new Date(ms);
3380
- console.log(` ${theme.dim("Epoch:")} ${chalk3.hex("#E5C07B")(input)}`);
3381
- console.log(` ${theme.dim("Date:")} ${chalk3.hex("#98C379")(date.toISOString())}`);
3382
- console.log(` ${chalk3.hex("#98C379")(date.toLocaleString())}`);
6046
+ console.log(` ${theme.dim("Epoch:")} ${chalk5.hex("#E5C07B")(input)}`);
6047
+ console.log(` ${theme.dim("Date:")} ${chalk5.hex("#98C379")(date.toISOString())}`);
6048
+ console.log(` ${chalk5.hex("#98C379")(date.toLocaleString())}`);
3383
6049
  } else {
3384
6050
  const date = new Date(input);
3385
6051
  if (!isNaN(date.getTime())) {
3386
- console.log(` ${theme.dim("Date:")} ${chalk3.hex("#98C379")(input)}`);
3387
- console.log(` ${theme.dim("Unix:")} ${chalk3.hex("#61AFEF")(Math.floor(date.getTime() / 1e3).toString())} ${theme.dim("(seconds)")}`);
3388
- console.log(` ${chalk3.hex("#E5C07B")(date.getTime().toString())} ${theme.dim("(milliseconds)")}`);
6052
+ console.log(` ${theme.dim("Date:")} ${chalk5.hex("#98C379")(input)}`);
6053
+ console.log(` ${theme.dim("Unix:")} ${chalk5.hex("#61AFEF")(Math.floor(date.getTime() / 1e3).toString())} ${theme.dim("(seconds)")}`);
6054
+ console.log(` ${chalk5.hex("#E5C07B")(date.getTime().toString())} ${theme.dim("(milliseconds)")}`);
3389
6055
  } else {
3390
6056
  console.log(theme.error(` Cannot parse: ${input}`));
3391
6057
  console.log(theme.dim(' Examples: epoch now, epoch 1703788800, epoch "2024-01-01"'));
@@ -3409,19 +6075,19 @@ async function handleHttp(args2) {
3409
6075
  return;
3410
6076
  }
3411
6077
  const fullUrl = url.startsWith("http") ? url : `https://${url}`;
3412
- console.log(` ${symbols.rocket} ${theme.dim(method)} ${chalk3.hex("#61AFEF")(fullUrl)}`);
6078
+ console.log(` ${symbols.rocket} ${theme.dim(method)} ${chalk5.hex("#61AFEF")(fullUrl)}`);
3413
6079
  console.log("");
3414
6080
  try {
3415
6081
  let result;
3416
6082
  try {
3417
6083
  const curlCmd = method === "HEAD" ? `curl -sI "${fullUrl}"` : `curl -s -X ${method} "${fullUrl}"`;
3418
- result = execSync(curlCmd, { encoding: "utf-8", timeout: 1e4 });
6084
+ result = execSync3(curlCmd, { encoding: "utf-8", timeout: 1e4 });
3419
6085
  } catch {
3420
- if (isWindows) {
6086
+ if (isWindows2) {
3421
6087
  if (method === "HEAD") {
3422
- result = execSync(`powershell -command "(Invoke-WebRequest -Uri '${fullUrl}' -Method Head -UseBasicParsing).Headers | ConvertTo-Json"`, { encoding: "utf-8", timeout: 1e4 });
6088
+ result = execSync3(`powershell -command "(Invoke-WebRequest -Uri '${fullUrl}' -Method Head -UseBasicParsing).Headers | ConvertTo-Json"`, { encoding: "utf-8", timeout: 1e4 });
3423
6089
  } else {
3424
- result = execSync(`powershell -command "(Invoke-WebRequest -Uri '${fullUrl}' -Method ${method} -UseBasicParsing).Content"`, { encoding: "utf-8", timeout: 1e4 });
6090
+ result = execSync3(`powershell -command "(Invoke-WebRequest -Uri '${fullUrl}' -Method ${method} -UseBasicParsing).Content"`, { encoding: "utf-8", timeout: 1e4 });
3425
6091
  }
3426
6092
  } else {
3427
6093
  throw new Error("curl not available");
@@ -3459,22 +6125,22 @@ function handleDiff(args2) {
3459
6125
  console.log("");
3460
6126
  return;
3461
6127
  }
3462
- const path1 = resolve2(process.cwd(), file1);
3463
- const path2 = resolve2(process.cwd(), file2);
3464
- if (!existsSync4(path1)) {
6128
+ const path1 = resolve5(process.cwd(), file1);
6129
+ const path2 = resolve5(process.cwd(), file2);
6130
+ if (!existsSync11(path1)) {
3465
6131
  console.log(theme.error(` File not found: ${file1}`));
3466
6132
  console.log("");
3467
6133
  return;
3468
6134
  }
3469
- if (!existsSync4(path2)) {
6135
+ if (!existsSync11(path2)) {
3470
6136
  console.log(theme.error(` File not found: ${file2}`));
3471
6137
  console.log("");
3472
6138
  return;
3473
6139
  }
3474
6140
  try {
3475
- const content1 = readFileSync3(path1, "utf-8").split("\n");
3476
- const content2 = readFileSync3(path2, "utf-8").split("\n");
3477
- console.log(theme.primary(` Comparing: ${basename(file1)} \u2194 ${basename(file2)}`));
6141
+ const content1 = readFileSync9(path1, "utf-8").split("\n");
6142
+ const content2 = readFileSync9(path2, "utf-8").split("\n");
6143
+ console.log(theme.primary(` Comparing: ${basename4(file1)} \u2194 ${basename4(file2)}`));
3478
6144
  console.log("");
3479
6145
  const maxLines = Math.max(content1.length, content2.length);
3480
6146
  let differences = 0;
@@ -3483,8 +6149,8 @@ function handleDiff(args2) {
3483
6149
  const line2 = content2[i] || "";
3484
6150
  if (line1 !== line2) {
3485
6151
  differences++;
3486
- console.log(chalk3.hex("#E06C75")(` - ${(i + 1).toString().padStart(4)}: ${line1.slice(0, 70)}`));
3487
- console.log(chalk3.hex("#98C379")(` + ${(i + 1).toString().padStart(4)}: ${line2.slice(0, 70)}`));
6152
+ console.log(chalk5.hex("#E06C75")(` - ${(i + 1).toString().padStart(4)}: ${line1.slice(0, 70)}`));
6153
+ console.log(chalk5.hex("#98C379")(` + ${(i + 1).toString().padStart(4)}: ${line2.slice(0, 70)}`));
3488
6154
  console.log("");
3489
6155
  }
3490
6156
  }
@@ -3501,18 +6167,18 @@ function handleDiff(args2) {
3501
6167
  }
3502
6168
  console.log("");
3503
6169
  }
3504
- var aliasesFile = join3(homedir3(), ".zammy-aliases.json");
6170
+ var aliasesFile = join9(homedir5(), ".zammy-aliases.json");
3505
6171
  function loadAliases() {
3506
6172
  try {
3507
- if (existsSync4(aliasesFile)) {
3508
- return JSON.parse(readFileSync3(aliasesFile, "utf-8"));
6173
+ if (existsSync11(aliasesFile)) {
6174
+ return JSON.parse(readFileSync9(aliasesFile, "utf-8"));
3509
6175
  }
3510
6176
  } catch {
3511
6177
  }
3512
6178
  return {};
3513
6179
  }
3514
6180
  function saveAliases(aliases) {
3515
- writeFileSync3(aliasesFile, JSON.stringify(aliases, null, 2));
6181
+ writeFileSync6(aliasesFile, JSON.stringify(aliases, null, 2));
3516
6182
  }
3517
6183
  function handleAlias(args2) {
3518
6184
  const parts = args2.trim().split(/\s+/);
@@ -3542,7 +6208,7 @@ function handleAlias(args2) {
3542
6208
  console.log(theme.dim(` Running: ${aliases[name]}`));
3543
6209
  console.log("");
3544
6210
  try {
3545
- const result = execSync(aliases[name], { encoding: "utf-8", cwd: process.cwd(), timeout: 3e4 });
6211
+ const result = execSync3(aliases[name], { encoding: "utf-8", cwd: process.cwd(), timeout: 3e4 });
3546
6212
  console.log(result);
3547
6213
  } catch (error) {
3548
6214
  const err = error;
@@ -3574,7 +6240,7 @@ function handleNotify(args2) {
3574
6240
  const message = args2.trim() || "Notification from Zammy CLI";
3575
6241
  console.log("");
3576
6242
  try {
3577
- if (isWindows) {
6243
+ if (isWindows2) {
3578
6244
  const ps = `
3579
6245
  [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
3580
6246
  [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
@@ -3583,10 +6249,10 @@ function handleNotify(args2) {
3583
6249
  $notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("Zammy CLI")
3584
6250
  $notifier.Show([Windows.UI.Notifications.ToastNotification]::new($template))
3585
6251
  `;
3586
- execSync(`powershell -command "${ps.replace(/\n/g, " ")}"`, { stdio: "pipe", timeout: 5e3 });
6252
+ execSync3(`powershell -command "${ps.replace(/\n/g, " ")}"`, { stdio: "pipe", timeout: 5e3 });
3587
6253
  } else {
3588
- const cmd = platform2() === "darwin" ? `osascript -e 'display notification "${message}" with title "Zammy CLI"'` : `notify-send "Zammy CLI" "${message}"`;
3589
- execSync(cmd, { stdio: "pipe", timeout: 3e3 });
6254
+ const cmd = platform3() === "darwin" ? `osascript -e 'display notification "${message}" with title "Zammy CLI"'` : `notify-send "Zammy CLI" "${message}"`;
6255
+ execSync3(cmd, { stdio: "pipe", timeout: 3e3 });
3590
6256
  }
3591
6257
  console.log(` ${symbols.check} ${theme.success("Notification sent")}`);
3592
6258
  } catch {
@@ -3616,7 +6282,7 @@ function handleGrep(args2) {
3616
6282
  function searchFile(filePath) {
3617
6283
  if (results.length >= maxResults) return;
3618
6284
  try {
3619
- const content = readFileSync3(filePath, "utf-8");
6285
+ const content = readFileSync9(filePath, "utf-8");
3620
6286
  const lines = content.split("\n");
3621
6287
  lines.forEach((line, index) => {
3622
6288
  if (results.length >= maxResults) return;
@@ -3634,11 +6300,11 @@ function handleGrep(args2) {
3634
6300
  function searchDir(dir, depth = 0) {
3635
6301
  if (depth > 4 || results.length >= maxResults) return;
3636
6302
  try {
3637
- const entries = readdirSync(dir, { withFileTypes: true });
6303
+ const entries = readdirSync4(dir, { withFileTypes: true });
3638
6304
  for (const entry of entries) {
3639
6305
  if (results.length >= maxResults) break;
3640
6306
  if (entry.name.startsWith(".") || ["node_modules", ".git", "dist", "build"].includes(entry.name)) continue;
3641
- const fullPath = resolve2(dir, entry.name);
6307
+ const fullPath = resolve5(dir, entry.name);
3642
6308
  if (entry.isDirectory()) {
3643
6309
  searchDir(fullPath, depth + 1);
3644
6310
  } else {
@@ -3661,9 +6327,9 @@ function handleGrep(args2) {
3661
6327
  for (const result of results) {
3662
6328
  const highlightedContent = result.content.replace(
3663
6329
  regex,
3664
- (match) => chalk3.hex("#FF6B6B").bold(match)
6330
+ (match) => chalk5.hex("#FF6B6B").bold(match)
3665
6331
  );
3666
- console.log(` ${theme.dim(result.file)}:${chalk3.hex("#61AFEF")(result.line)}`);
6332
+ console.log(` ${theme.dim(result.file)}:${chalk5.hex("#61AFEF")(result.line)}`);
3667
6333
  console.log(` ${highlightedContent}`);
3668
6334
  console.log("");
3669
6335
  }
@@ -3674,30 +6340,30 @@ function handleGrep(args2) {
3674
6340
  console.log("");
3675
6341
  }
3676
6342
  function handleWc(args2) {
3677
- const filePath = resolve2(process.cwd(), args2.trim());
6343
+ const filePath = resolve5(process.cwd(), args2.trim());
3678
6344
  console.log("");
3679
6345
  if (!args2.trim()) {
3680
6346
  console.log(theme.error(" Usage: wc <file>"));
3681
6347
  console.log("");
3682
6348
  return;
3683
6349
  }
3684
- if (!existsSync4(filePath)) {
6350
+ if (!existsSync11(filePath)) {
3685
6351
  console.log(theme.error(` File not found: ${args2}`));
3686
6352
  console.log("");
3687
6353
  return;
3688
6354
  }
3689
6355
  try {
3690
- const content = readFileSync3(filePath, "utf-8");
6356
+ const content = readFileSync9(filePath, "utf-8");
3691
6357
  const lines = content.split("\n").length;
3692
6358
  const words = content.split(/\s+/).filter((w) => w.length > 0).length;
3693
6359
  const chars = content.length;
3694
6360
  const bytes = Buffer.byteLength(content, "utf-8");
3695
- console.log(theme.primary(` \u{1F4CA} ${basename(args2)}`));
6361
+ console.log(theme.primary(` \u{1F4CA} ${basename4(args2)}`));
3696
6362
  console.log("");
3697
- console.log(` ${chalk3.hex("#61AFEF")(lines.toLocaleString().padStart(8))} ${theme.dim("lines")}`);
3698
- console.log(` ${chalk3.hex("#98C379")(words.toLocaleString().padStart(8))} ${theme.dim("words")}`);
3699
- console.log(` ${chalk3.hex("#E5C07B")(chars.toLocaleString().padStart(8))} ${theme.dim("characters")}`);
3700
- console.log(` ${chalk3.hex("#C678DD")(bytes.toLocaleString().padStart(8))} ${theme.dim("bytes")}`);
6363
+ console.log(` ${chalk5.hex("#61AFEF")(lines.toLocaleString().padStart(8))} ${theme.dim("lines")}`);
6364
+ console.log(` ${chalk5.hex("#98C379")(words.toLocaleString().padStart(8))} ${theme.dim("words")}`);
6365
+ console.log(` ${chalk5.hex("#E5C07B")(chars.toLocaleString().padStart(8))} ${theme.dim("characters")}`);
6366
+ console.log(` ${chalk5.hex("#C678DD")(bytes.toLocaleString().padStart(8))} ${theme.dim("bytes")}`);
3701
6367
  } catch {
3702
6368
  console.log(theme.error(" Failed to read file"));
3703
6369
  }
@@ -3717,19 +6383,19 @@ function handleHead(args2) {
3717
6383
  console.log("");
3718
6384
  return;
3719
6385
  }
3720
- const fullPath = resolve2(process.cwd(), filePath);
3721
- if (!existsSync4(fullPath)) {
6386
+ const fullPath = resolve5(process.cwd(), filePath);
6387
+ if (!existsSync11(fullPath)) {
3722
6388
  console.log(theme.error(` File not found: ${filePath}`));
3723
6389
  console.log("");
3724
6390
  return;
3725
6391
  }
3726
6392
  try {
3727
- const content = readFileSync3(fullPath, "utf-8");
6393
+ const content = readFileSync9(fullPath, "utf-8");
3728
6394
  const fileLines = content.split("\n").slice(0, lines);
3729
- console.log(theme.dim(` First ${lines} lines of ${basename(filePath)}:`));
6395
+ console.log(theme.dim(` First ${lines} lines of ${basename4(filePath)}:`));
3730
6396
  console.log("");
3731
6397
  fileLines.forEach((line, i) => {
3732
- console.log(` ${chalk3.dim((i + 1).toString().padStart(4))} ${line}`);
6398
+ console.log(` ${chalk5.dim((i + 1).toString().padStart(4))} ${line}`);
3733
6399
  });
3734
6400
  } catch {
3735
6401
  console.log(theme.error(" Failed to read file"));
@@ -3761,8 +6427,9 @@ async function executeShellCommand(command) {
3761
6427
  return;
3762
6428
  }
3763
6429
  if (cmd === "clear" || cmd === "cls") {
3764
- console.clear();
3765
- await displayBanner();
6430
+ process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
6431
+ const isSimple = process.argv.includes("--simple") || !process.stdout.isTTY;
6432
+ await displayBanner(isSimple);
3766
6433
  return;
3767
6434
  }
3768
6435
  if (cmd === "bookmark" || cmd === "bm") {
@@ -3875,6 +6542,29 @@ async function parseAndExecute(input) {
3875
6542
  return;
3876
6543
  }
3877
6544
  if (!trimmed.startsWith("/")) {
6545
+ const detectedMood = getMoodFromText(trimmed);
6546
+ if (detectedMood) {
6547
+ console.log("");
6548
+ const responses = {
6549
+ love: ["Aww, you're sweet!", "Right back at ya!", "*happy wobble*"],
6550
+ excited: ["Yay! Let's gooo!", "Woohoo!", "*bounces excitedly*"],
6551
+ sleepy: ["*yawns* Same...", "Maybe take a break?", "zzZ..."],
6552
+ sad: ["Aww, it's okay!", "I'm here for you!", "*comforting wobble*"],
6553
+ angry: ["*hides nervously*", "Let's fix that!", "Deep breaths..."],
6554
+ thinking: ["Hmm indeed...", "Let me think too...", "*ponders*"]
6555
+ };
6556
+ const moodResponses = responses[detectedMood] || ["*wobbles*"];
6557
+ const response = moodResponses[Math.floor(Math.random() * moodResponses.length)];
6558
+ const isSimpleInput = trimmed.length < 20 && !/[{}\[\]();=<>]/.test(trimmed);
6559
+ if ((detectedMood === "love" || detectedMood === "excited") && isSimpleInput && Math.random() < 0.5) {
6560
+ showMascot(detectedMood);
6561
+ console.log(` ${theme.secondary(response)}`);
6562
+ } else {
6563
+ react(detectedMood, theme.secondary(response));
6564
+ }
6565
+ console.log("");
6566
+ return;
6567
+ }
3878
6568
  console.log("");
3879
6569
  console.log(` ${symbols.info} ${theme.dim("Commands start with")} ${theme.primary("/")} ${theme.dim("\u2022 Shell commands start with")} ${theme.primary("!")}`);
3880
6570
  console.log(` ${theme.dim(" Type")} ${theme.primary("/help")} ${theme.dim("for available commands")}`);
@@ -3894,24 +6584,110 @@ async function parseAndExecute(input) {
3894
6584
  }
3895
6585
  try {
3896
6586
  await command.execute(args2);
6587
+ if (Math.random() < 0.15) {
6588
+ const successMoods = ["happy", "excited", "wink"];
6589
+ const mood = successMoods[Math.floor(Math.random() * successMoods.length)];
6590
+ react(mood);
6591
+ }
3897
6592
  } catch (error) {
3898
6593
  console.log("");
3899
- console.log(` ${symbols.cross} ${theme.error("Error:")} ${theme.dim(String(error))}`);
6594
+ react("sad", theme.error(`Error: ${String(error)}`));
3900
6595
  console.log("");
3901
6596
  }
3902
6597
  }
3903
6598
 
3904
6599
  // src/index.ts
3905
- import { readdirSync as readdirSync2, readFileSync as readFileSync4 } from "fs";
3906
- import { fileURLToPath } from "url";
3907
- import { dirname, join as join4 } from "path";
6600
+ import { readdirSync as readdirSync5, readFileSync as readFileSync10 } from "fs";
6601
+ import { fileURLToPath as fileURLToPath4 } from "url";
6602
+ import { dirname as dirname5, join as join10 } from "path";
6603
+ import chalk6 from "chalk";
6604
+ var SLIME_COLOR = "#9B59B6";
6605
+ var EYE_COLOR = "#1A1A2E";
6606
+ var MIN_WIDTH_FOR_IDLE = 40;
6607
+ var MIN_WIDTH_FOR_MENU = 50;
6608
+ var miniSlimeFrames = [
6609
+ // Open eyes
6610
+ chalk6.hex(SLIME_COLOR)("(") + chalk6.hex(EYE_COLOR)("\u25CF") + chalk6.hex(SLIME_COLOR)("\u1D17") + chalk6.hex(EYE_COLOR)("\u25CF") + chalk6.hex(SLIME_COLOR)(")"),
6611
+ // Blink (closed eyes)
6612
+ chalk6.hex(SLIME_COLOR)("(") + chalk6.hex(EYE_COLOR)("\u2500") + chalk6.hex(SLIME_COLOR)("\u1D17") + chalk6.hex(EYE_COLOR)("\u2500") + chalk6.hex(SLIME_COLOR)(")")
6613
+ ];
6614
+ var idleAnimationInterval = null;
6615
+ var isUserTyping = false;
6616
+ var lastActivityTime = Date.now();
6617
+ var lastRenderedFrame = -1;
6618
+ var slimeVisible = false;
6619
+ var lastTermWidth = process.stdout.columns || 80;
6620
+ var IDLE_DELAY = 3e3;
6621
+ var FRAME_INTERVAL = 2e3;
6622
+ var animationSequence = [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0];
6623
+ var sequenceIndex = 0;
6624
+ function getAnimatedSlime() {
6625
+ const frameIndex = animationSequence[sequenceIndex % animationSequence.length];
6626
+ return { frame: miniSlimeFrames[frameIndex], index: frameIndex };
6627
+ }
6628
+ function updateIdleAnimation(rl) {
6629
+ const termWidth = process.stdout.columns || 80;
6630
+ if (isUserTyping || menu.visible || termWidth < MIN_WIDTH_FOR_IDLE) {
6631
+ if (slimeVisible) {
6632
+ clearIdleSlime(rl);
6633
+ }
6634
+ return;
6635
+ }
6636
+ const now = Date.now();
6637
+ if (now - lastActivityTime < IDLE_DELAY) return;
6638
+ const currentLine = rl.line || "";
6639
+ if (currentLine.length !== 0) return;
6640
+ sequenceIndex++;
6641
+ const { frame: slime, index: frameIndex } = getAnimatedSlime();
6642
+ if (frameIndex === lastRenderedFrame && slimeVisible) return;
6643
+ lastRenderedFrame = frameIndex;
6644
+ slimeVisible = true;
6645
+ const promptLen = getPromptLength();
6646
+ const slimePos = Math.max(promptLen + 3, termWidth - 12);
6647
+ process.stdout.write(
6648
+ `\x1B[?25l\x1B[${slimePos}G\x1B[K` + // Clear to end of line
6649
+ slime + // Draw slime
6650
+ `\x1B[${promptLen + 1}G\x1B[?25h`
6651
+ // Show cursor
6652
+ );
6653
+ }
6654
+ function startIdleAnimation(rl) {
6655
+ if (idleAnimationInterval) return;
6656
+ idleAnimationInterval = setInterval(() => {
6657
+ updateIdleAnimation(rl);
6658
+ }, FRAME_INTERVAL);
6659
+ }
6660
+ function stopIdleAnimation() {
6661
+ if (idleAnimationInterval) {
6662
+ clearInterval(idleAnimationInterval);
6663
+ idleAnimationInterval = null;
6664
+ }
6665
+ }
6666
+ function clearIdleSlime(rl) {
6667
+ if (!slimeVisible) return;
6668
+ slimeVisible = false;
6669
+ lastRenderedFrame = -1;
6670
+ const termWidth = process.stdout.columns || 80;
6671
+ const slimePos = termWidth - 12;
6672
+ const promptLen = getPromptLength();
6673
+ const currentLine = rl ? rl.line || "" : "";
6674
+ const cursorPos = promptLen + currentLine.length + 1;
6675
+ process.stdout.write(
6676
+ `\x1B[?25l\x1B[${slimePos}G\x1B[K\x1B[${cursorPos}G\x1B[?25h`
6677
+ // Show cursor
6678
+ );
6679
+ }
6680
+ function setIdle() {
6681
+ isUserTyping = false;
6682
+ lastActivityTime = Date.now();
6683
+ }
3908
6684
  var args = process.argv.slice(2);
3909
6685
  if (args.includes("--version") || args.includes("-v")) {
3910
6686
  try {
3911
- const __filename = fileURLToPath(import.meta.url);
3912
- const __dirname = dirname(__filename);
3913
- const pkgPath = join4(__dirname, "..", "package.json");
3914
- const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
6687
+ const __filename = fileURLToPath4(import.meta.url);
6688
+ const __dirname = dirname5(__filename);
6689
+ const pkgPath = join10(__dirname, "..", "package.json");
6690
+ const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
3915
6691
  console.log(`zammy v${pkg.version}`);
3916
6692
  } catch {
3917
6693
  console.log("zammy v1.0.0");
@@ -3920,14 +6696,15 @@ if (args.includes("--version") || args.includes("-v")) {
3920
6696
  }
3921
6697
  if (args.includes("--help") || args.includes("-h")) {
3922
6698
  console.log(`
3923
- zammy - Your slice-of-life terminal companion
6699
+ zammy - A feature-packed CLI with utilities, dev tools, and a bit of fun
3924
6700
 
3925
6701
  Usage: zammy [options]
3926
6702
 
3927
6703
  Options:
3928
6704
  -v, --version Show version number
3929
6705
  -h, --help Show this help message
3930
- --simple Force simple mode (no interactive features)
6706
+ --simple Force simple mode (no animations)
6707
+ --no-menu Disable interactive command menu
3931
6708
 
3932
6709
  Commands:
3933
6710
  Start zammy and type / to see all available commands
@@ -3942,6 +6719,7 @@ Examples:
3942
6719
  }
3943
6720
  var isTTY = process.stdin.isTTY && process.stdout.isTTY;
3944
6721
  var isSimpleMode = process.argv.includes("--simple") || !isTTY;
6722
+ var noMenu = process.argv.includes("--no-menu");
3945
6723
  var IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp"];
3946
6724
  var menu = {
3947
6725
  visible: false,
@@ -4060,6 +6838,11 @@ function hideMenu(currentLine = "") {
4060
6838
  menu.renderedLines = 0;
4061
6839
  }
4062
6840
  function showMenu(filter, prefix, currentLine) {
6841
+ const termWidth = process.stdout.columns || 80;
6842
+ if (termWidth < MIN_WIDTH_FOR_MENU) {
6843
+ if (menu.visible) hideMenu(currentLine);
6844
+ return;
6845
+ }
4063
6846
  const allItems = prefix === "/" ? getFilteredCommands(filter) : getFilteredShellCommands(filter);
4064
6847
  if (allItems.length === 0) {
4065
6848
  if (menu.visible) hideMenu(currentLine);
@@ -4125,7 +6908,7 @@ function completer(line) {
4125
6908
  const afterCommand = line.slice("/asciiart ".length);
4126
6909
  const searchTerm = afterCommand.startsWith("@") ? afterCommand.slice(1) : afterCommand;
4127
6910
  try {
4128
- const files = readdirSync2(process.cwd());
6911
+ const files = readdirSync5(process.cwd());
4129
6912
  const imageFiles = files.filter((f) => {
4130
6913
  const ext = f.toLowerCase().slice(f.lastIndexOf("."));
4131
6914
  return IMAGE_EXTENSIONS.includes(ext);
@@ -4154,8 +6937,9 @@ async function main() {
4154
6937
  console.log(theme.dim("Note: Running in simple mode (no TTY detected). Use Tab for autocomplete."));
4155
6938
  console.log(theme.dim("For full features, run in a proper terminal or use: zammy --simple\n"));
4156
6939
  }
4157
- await displayBanner();
4158
- const rl = readline.createInterface({
6940
+ await displayBanner(isSimpleMode);
6941
+ await initPluginLoader();
6942
+ const rl = readline4.createInterface({
4159
6943
  input: process.stdin,
4160
6944
  output: process.stdout,
4161
6945
  terminal: isTTY,
@@ -4163,8 +6947,29 @@ async function main() {
4163
6947
  });
4164
6948
  let prevLine = "";
4165
6949
  if (isTTY && !isSimpleMode) {
6950
+ startIdleAnimation(rl);
6951
+ }
6952
+ if (isTTY) {
6953
+ process.stdout.on("resize", () => {
6954
+ const currentLine = rl.line || "";
6955
+ const newWidth = process.stdout.columns || 80;
6956
+ if (menu.visible) {
6957
+ hideMenu(currentLine);
6958
+ }
6959
+ if (slimeVisible) {
6960
+ clearIdleSlime(rl);
6961
+ }
6962
+ process.stdout.write("\r" + getPrompt() + currentLine);
6963
+ lastTermWidth = newWidth;
6964
+ });
6965
+ }
6966
+ if (isTTY && !noMenu) {
4166
6967
  process.stdin.on("keypress", (_char, key) => {
4167
6968
  if (!key) return;
6969
+ if (!isSimpleMode) {
6970
+ isUserTyping = true;
6971
+ lastActivityTime = Date.now();
6972
+ }
4168
6973
  const currentLine = rl.line || "";
4169
6974
  if (menu.visible) {
4170
6975
  if (key.name === "up" || key.name === "down") {
@@ -4202,6 +7007,7 @@ async function main() {
4202
7007
  const line = rl.line || "";
4203
7008
  if (now - lastCtrlC < 500) {
4204
7009
  hideMenu(line);
7010
+ stopIdleAnimation();
4205
7011
  console.log("\n" + theme.secondary("Goodbye! See you next time.") + "\n");
4206
7012
  process.exit(0);
4207
7013
  } else {
@@ -4216,6 +7022,7 @@ async function main() {
4216
7022
  hideMenu(input);
4217
7023
  prevLine = "";
4218
7024
  await parseAndExecute(input);
7025
+ if (!isSimpleMode) setIdle();
4219
7026
  rl.prompt();
4220
7027
  });
4221
7028
  rl.prompt();