@jvittechs/jai1-cli 0.1.67 → 0.1.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -33,7 +33,7 @@ var NetworkError = class extends Jai1Error {
33
33
  // package.json
34
34
  var package_default = {
35
35
  name: "@jvittechs/jai1-cli",
36
- version: "0.1.67",
36
+ version: "0.1.68",
37
37
  description: "Unified CLI for Jai1 Framework Management and Redmine Context Sync",
38
38
  type: "module",
39
39
  bin: {
@@ -388,9 +388,9 @@ async function handleAuth(options) {
388
388
  output: process.stdout
389
389
  });
390
390
  const question = (prompt) => {
391
- return new Promise((resolve3) => {
391
+ return new Promise((resolve4) => {
392
392
  rl.question(prompt, (answer) => {
393
- resolve3(answer);
393
+ resolve4(answer);
394
394
  });
395
395
  });
396
396
  };
@@ -3534,7 +3534,7 @@ var AgenticGuideView = ({ onBack }) => {
3534
3534
  setMessages((prev) => [...prev, userMessage]);
3535
3535
  setInputValue("");
3536
3536
  setIsTyping(true);
3537
- await new Promise((resolve3) => setTimeout(resolve3, 800 + Math.random() * 700));
3537
+ await new Promise((resolve4) => setTimeout(resolve4, 800 + Math.random() * 700));
3538
3538
  const response = getMockResponse(text);
3539
3539
  const assistantMessage = {
3540
3540
  id: `assistant-${Date.now()}`,
@@ -5717,12 +5717,12 @@ Examples:
5717
5717
  }
5718
5718
 
5719
5719
  // src/commands/utils/interactive.ts
5720
- import React31 from "react";
5720
+ import React39 from "react";
5721
5721
  import { render as render5 } from "ink";
5722
5722
 
5723
5723
  // src/ui/utils/UtilsApp.tsx
5724
- import React30, { useState as useState17 } from "react";
5725
- import { Box as Box20, Text as Text21, useInput as useInput15, useApp as useApp5 } from "ink";
5724
+ import React38, { useState as useState25 } from "react";
5725
+ import { Box as Box28, Text as Text29, useInput as useInput23, useApp as useApp5 } from "ink";
5726
5726
 
5727
5727
  // src/ui/utils/views/PasswordView.tsx
5728
5728
  import React27, { useState as useState14 } from "react";
@@ -5981,6 +5981,966 @@ var HashView = () => {
5981
5981
  ), /* @__PURE__ */ React29.createElement(Box19, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 2 }, /* @__PURE__ */ React29.createElement(Text20, { dimColor: true }, "Tab: Next | \u2190/\u2192: Change algorithm | Enter: Generate | C: Copy | Esc: Back")));
5982
5982
  };
5983
5983
 
5984
+ // src/ui/utils/views/Base64View.tsx
5985
+ import React30, { useState as useState17 } from "react";
5986
+ import { Box as Box20, Text as Text21, useInput as useInput15 } from "ink";
5987
+ import TextInput7 from "ink-text-input";
5988
+ var Base64View = () => {
5989
+ const [input, setInput] = useState17("");
5990
+ const [mode, setMode] = useState17("encode");
5991
+ const [urlSafe, setUrlSafe] = useState17(false);
5992
+ const [result, setResult] = useState17("");
5993
+ const [error, setError] = useState17("");
5994
+ const [focusedField, setFocusedField] = useState17("input");
5995
+ const [copied, setCopied] = useState17(false);
5996
+ const service = new UtilsService();
5997
+ useInput15((input2, key) => {
5998
+ if (key.tab) {
5999
+ const fields = ["input", "mode", "urlsafe", "convert"];
6000
+ const currentIndex = fields.indexOf(focusedField);
6001
+ setFocusedField(fields[(currentIndex + 1) % fields.length]);
6002
+ } else if (key.return) {
6003
+ if (focusedField === "mode") {
6004
+ setMode(mode === "encode" ? "decode" : "encode");
6005
+ setResult("");
6006
+ setError("");
6007
+ } else if (focusedField === "urlsafe") {
6008
+ setUrlSafe(!urlSafe);
6009
+ } else if (focusedField === "convert") {
6010
+ handleConvert();
6011
+ }
6012
+ } else if (input2 === "c" && result) {
6013
+ handleCopy();
6014
+ }
6015
+ });
6016
+ const handleConvert = () => {
6017
+ if (!input) {
6018
+ setError("Input cannot be empty");
6019
+ return;
6020
+ }
6021
+ try {
6022
+ setError("");
6023
+ if (mode === "encode") {
6024
+ const encoded = service.base64Encode(input, urlSafe);
6025
+ setResult(encoded);
6026
+ } else {
6027
+ const decoded = service.base64Decode(input);
6028
+ setResult(decoded.toString("utf-8"));
6029
+ }
6030
+ setCopied(false);
6031
+ } catch (err) {
6032
+ setError(`Failed to ${mode}: ${err instanceof Error ? err.message : "Unknown error"}`);
6033
+ setResult("");
6034
+ }
6035
+ };
6036
+ const handleCopy = async () => {
6037
+ try {
6038
+ const { default: clipboardy } = await import("clipboardy");
6039
+ await clipboardy.write(result);
6040
+ setCopied(true);
6041
+ setTimeout(() => setCopied(false), 2e3);
6042
+ } catch (error2) {
6043
+ }
6044
+ };
6045
+ return /* @__PURE__ */ React30.createElement(Box20, { flexDirection: "column" }, /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React30.createElement(Text21, { bold: true, color: "cyan" }, "\u{1F4DD} Base64 Encoder/Decoder")), /* @__PURE__ */ React30.createElement(
6046
+ Box20,
6047
+ {
6048
+ flexDirection: "column",
6049
+ borderStyle: "single",
6050
+ borderColor: "gray",
6051
+ paddingX: 2,
6052
+ paddingY: 1,
6053
+ marginBottom: 1
6054
+ },
6055
+ /* @__PURE__ */ React30.createElement(Text21, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
6056
+ /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 0 }, /* @__PURE__ */ React30.createElement(Text21, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", "Input text:")), /* @__PURE__ */ React30.createElement(Box20, { marginLeft: 2, width: 60 }, focusedField === "input" ? /* @__PURE__ */ React30.createElement(TextInput7, { value: input, onChange: setInput, placeholder: "Enter text..." }) : /* @__PURE__ */ React30.createElement(Text21, { dimColor: !input }, input || "(empty)"))),
6057
+ /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React30.createElement(Box20, { width: 20 }, /* @__PURE__ */ React30.createElement(Text21, { color: focusedField === "mode" ? "green" : void 0 }, focusedField === "mode" ? "\u25B6 " : " ", "Mode:")), /* @__PURE__ */ React30.createElement(Text21, { bold: true, color: focusedField === "mode" ? "yellow" : void 0 }, mode === "encode" ? "ENCODE" : "DECODE"), focusedField === "mode" && /* @__PURE__ */ React30.createElement(Text21, { dimColor: true }, " (Enter to toggle)")),
6058
+ mode === "encode" && /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React30.createElement(Text21, { color: focusedField === "urlsafe" ? "green" : void 0 }, focusedField === "urlsafe" ? "\u25B6 " : " ", "[", urlSafe ? "\u2713" : " ", "] URL-Safe (+ \u2192 -, / \u2192 _)")),
6059
+ /* @__PURE__ */ React30.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React30.createElement(
6060
+ Text21,
6061
+ {
6062
+ bold: true,
6063
+ backgroundColor: focusedField === "convert" ? "green" : void 0,
6064
+ color: focusedField === "convert" ? "black" : "green"
6065
+ },
6066
+ focusedField === "convert" ? "\u25B6 " : " ",
6067
+ "[ ",
6068
+ mode === "encode" ? "Encode" : "Decode",
6069
+ " ]"
6070
+ ))
6071
+ ), error && /* @__PURE__ */ React30.createElement(
6072
+ Box20,
6073
+ {
6074
+ flexDirection: "column",
6075
+ borderStyle: "single",
6076
+ borderColor: "red",
6077
+ paddingX: 2,
6078
+ paddingY: 1,
6079
+ marginBottom: 1
6080
+ },
6081
+ /* @__PURE__ */ React30.createElement(Text21, { color: "red" }, "\u2717 Error: ", error)
6082
+ ), result && /* @__PURE__ */ React30.createElement(
6083
+ Box20,
6084
+ {
6085
+ flexDirection: "column",
6086
+ borderStyle: "single",
6087
+ borderColor: "green",
6088
+ paddingX: 2,
6089
+ paddingY: 1
6090
+ },
6091
+ /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React30.createElement(Text21, { bold: true, color: "green" }, "\u2713 Result:"), copied && /* @__PURE__ */ React30.createElement(Box20, { marginLeft: 2 }, /* @__PURE__ */ React30.createElement(Text21, { color: "green" }, "\u2713 Copied to clipboard!"))),
6092
+ /* @__PURE__ */ React30.createElement(Box20, { flexDirection: "column" }, /* @__PURE__ */ React30.createElement(Text21, { dimColor: true }, "Mode: ", mode.toUpperCase()), /* @__PURE__ */ React30.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React30.createElement(Text21, { wrap: "wrap" }, result)))
6093
+ ), /* @__PURE__ */ React30.createElement(Box20, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 2 }, /* @__PURE__ */ React30.createElement(Text21, { dimColor: true }, "Tab: Next | Enter: Toggle/Convert | C: Copy | Esc: Back")));
6094
+ };
6095
+
6096
+ // src/ui/utils/views/UrlView.tsx
6097
+ import React31, { useState as useState18 } from "react";
6098
+ import { Box as Box21, Text as Text22, useInput as useInput16 } from "ink";
6099
+ import TextInput8 from "ink-text-input";
6100
+ var UrlView = () => {
6101
+ const [input, setInput] = useState18("");
6102
+ const [mode, setMode] = useState18("encode");
6103
+ const [fullUrl, setFullUrl] = useState18(false);
6104
+ const [result, setResult] = useState18("");
6105
+ const [focusedField, setFocusedField] = useState18("input");
6106
+ const [copied, setCopied] = useState18(false);
6107
+ const service = new UtilsService();
6108
+ useInput16((input2, key) => {
6109
+ if (key.tab) {
6110
+ const fields = ["input", "mode", "full", "convert"];
6111
+ const currentIndex = fields.indexOf(focusedField);
6112
+ setFocusedField(fields[(currentIndex + 1) % fields.length]);
6113
+ } else if (key.return) {
6114
+ if (focusedField === "mode") {
6115
+ setMode(mode === "encode" ? "decode" : "encode");
6116
+ setResult("");
6117
+ } else if (focusedField === "full") {
6118
+ setFullUrl(!fullUrl);
6119
+ } else if (focusedField === "convert") {
6120
+ handleConvert();
6121
+ }
6122
+ } else if (input2 === "c" && result) {
6123
+ handleCopy();
6124
+ }
6125
+ });
6126
+ const handleConvert = () => {
6127
+ if (!input) return;
6128
+ if (mode === "encode") {
6129
+ const encoded = fullUrl ? service.urlEncode(input, true) : service.urlEncode(input, false);
6130
+ setResult(encoded);
6131
+ } else {
6132
+ const decoded = fullUrl ? service.urlDecode(input, true) : service.urlDecode(input, false);
6133
+ setResult(decoded);
6134
+ }
6135
+ setCopied(false);
6136
+ };
6137
+ const handleCopy = async () => {
6138
+ try {
6139
+ const { default: clipboardy } = await import("clipboardy");
6140
+ await clipboardy.write(result);
6141
+ setCopied(true);
6142
+ setTimeout(() => setCopied(false), 2e3);
6143
+ } catch (error) {
6144
+ }
6145
+ };
6146
+ return /* @__PURE__ */ React31.createElement(Box21, { flexDirection: "column" }, /* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1 }, /* @__PURE__ */ React31.createElement(Text22, { bold: true, color: "cyan" }, "\u{1F517} URL Encoder/Decoder")), /* @__PURE__ */ React31.createElement(
6147
+ Box21,
6148
+ {
6149
+ flexDirection: "column",
6150
+ borderStyle: "single",
6151
+ borderColor: "gray",
6152
+ paddingX: 2,
6153
+ paddingY: 1,
6154
+ marginBottom: 1
6155
+ },
6156
+ /* @__PURE__ */ React31.createElement(Text22, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
6157
+ /* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React31.createElement(Box21, { marginBottom: 0 }, /* @__PURE__ */ React31.createElement(Text22, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", "Input text:")), /* @__PURE__ */ React31.createElement(Box21, { marginLeft: 2, width: 60 }, focusedField === "input" ? /* @__PURE__ */ React31.createElement(TextInput8, { value: input, onChange: setInput, placeholder: "Enter text or URL..." }) : /* @__PURE__ */ React31.createElement(Text22, { dimColor: !input }, input || "(empty)"))),
6158
+ /* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1 }, /* @__PURE__ */ React31.createElement(Box21, { width: 20 }, /* @__PURE__ */ React31.createElement(Text22, { color: focusedField === "mode" ? "green" : void 0 }, focusedField === "mode" ? "\u25B6 " : " ", "Mode:")), /* @__PURE__ */ React31.createElement(Text22, { bold: true, color: focusedField === "mode" ? "yellow" : void 0 }, mode === "encode" ? "ENCODE" : "DECODE"), focusedField === "mode" && /* @__PURE__ */ React31.createElement(Text22, { dimColor: true }, " (Enter to toggle)")),
6159
+ /* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1 }, /* @__PURE__ */ React31.createElement(Text22, { color: focusedField === "full" ? "green" : void 0 }, focusedField === "full" ? "\u25B6 " : " ", "[", fullUrl ? "\u2713" : " ", "] Full URL (encode/decode entire URL)")),
6160
+ /* @__PURE__ */ React31.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(
6161
+ Text22,
6162
+ {
6163
+ bold: true,
6164
+ backgroundColor: focusedField === "convert" ? "green" : void 0,
6165
+ color: focusedField === "convert" ? "black" : "green"
6166
+ },
6167
+ focusedField === "convert" ? "\u25B6 " : " ",
6168
+ "[ ",
6169
+ mode === "encode" ? "Encode" : "Decode",
6170
+ " ]"
6171
+ ))
6172
+ ), result && /* @__PURE__ */ React31.createElement(
6173
+ Box21,
6174
+ {
6175
+ flexDirection: "column",
6176
+ borderStyle: "single",
6177
+ borderColor: "green",
6178
+ paddingX: 2,
6179
+ paddingY: 1
6180
+ },
6181
+ /* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1 }, /* @__PURE__ */ React31.createElement(Text22, { bold: true, color: "green" }, "\u2713 Result:"), copied && /* @__PURE__ */ React31.createElement(Box21, { marginLeft: 2 }, /* @__PURE__ */ React31.createElement(Text22, { color: "green" }, "\u2713 Copied to clipboard!"))),
6182
+ /* @__PURE__ */ React31.createElement(Box21, { flexDirection: "column" }, /* @__PURE__ */ React31.createElement(Text22, { dimColor: true }, "Mode: ", mode.toUpperCase(), " ", fullUrl ? "(Full URL)" : "(Component)"), /* @__PURE__ */ React31.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text22, { wrap: "wrap" }, result)))
6183
+ ), /* @__PURE__ */ React31.createElement(Box21, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 2 }, /* @__PURE__ */ React31.createElement(Text22, { dimColor: true }, "Tab: Next | Enter: Toggle/Convert | C: Copy | Esc: Back")));
6184
+ };
6185
+
6186
+ // src/ui/utils/views/UnixTimeView.tsx
6187
+ import React32, { useState as useState19 } from "react";
6188
+ import { Box as Box22, Text as Text23, useInput as useInput17 } from "ink";
6189
+ import TextInput9 from "ink-text-input";
6190
+ var UnixTimeView = () => {
6191
+ const [input, setInput] = useState19("");
6192
+ const [mode, setMode] = useState19("now");
6193
+ const [format, setFormat] = useState19("iso");
6194
+ const [useMs, setUseMs] = useState19(false);
6195
+ const [result, setResult] = useState19("");
6196
+ const [error, setError] = useState19("");
6197
+ const [focusedField, setFocusedField] = useState19("mode");
6198
+ const [copied, setCopied] = useState19(false);
6199
+ const service = new UtilsService();
6200
+ useInput17((input2, key) => {
6201
+ if (key.tab) {
6202
+ const fields = mode === "now" ? ["mode", "ms", "convert"] : mode === "to-human" ? ["mode", "input", "format", "convert"] : ["mode", "input", "convert"];
6203
+ const currentIndex = fields.indexOf(focusedField);
6204
+ setFocusedField(fields[(currentIndex + 1) % fields.length]);
6205
+ } else if (key.return) {
6206
+ if (focusedField === "mode") {
6207
+ const modes = ["now", "to-human", "to-unix"];
6208
+ const currentIndex = modes.indexOf(mode);
6209
+ setMode(modes[(currentIndex + 1) % modes.length]);
6210
+ setResult("");
6211
+ setError("");
6212
+ } else if (focusedField === "format") {
6213
+ const formats = ["iso", "local", "utc"];
6214
+ const currentIndex = formats.indexOf(format);
6215
+ setFormat(formats[(currentIndex + 1) % formats.length]);
6216
+ } else if (focusedField === "ms") {
6217
+ setUseMs(!useMs);
6218
+ } else if (focusedField === "convert") {
6219
+ handleConvert();
6220
+ }
6221
+ } else if (input2 === "c" && result) {
6222
+ handleCopy();
6223
+ }
6224
+ });
6225
+ const handleConvert = () => {
6226
+ try {
6227
+ setError("");
6228
+ if (mode === "now") {
6229
+ const timestamp = service.unixTimeCurrent(useMs);
6230
+ setResult(timestamp.toString());
6231
+ } else if (mode === "to-human") {
6232
+ if (!input) {
6233
+ setError("Please enter a timestamp");
6234
+ return;
6235
+ }
6236
+ const human = service.unixTimeToHuman(parseInt(input, 10), format);
6237
+ setResult(human);
6238
+ } else {
6239
+ if (!input) {
6240
+ setError("Please enter a date string");
6241
+ return;
6242
+ }
6243
+ const timestamp = service.unixTimeFromString(input);
6244
+ setResult(timestamp.toString());
6245
+ }
6246
+ setCopied(false);
6247
+ } catch (err) {
6248
+ setError(err instanceof Error ? err.message : "Conversion failed");
6249
+ setResult("");
6250
+ }
6251
+ };
6252
+ const handleCopy = async () => {
6253
+ try {
6254
+ const { default: clipboardy } = await import("clipboardy");
6255
+ await clipboardy.write(result);
6256
+ setCopied(true);
6257
+ setTimeout(() => setCopied(false), 2e3);
6258
+ } catch (error2) {
6259
+ }
6260
+ };
6261
+ return /* @__PURE__ */ React32.createElement(Box22, { flexDirection: "column" }, /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React32.createElement(Text23, { bold: true, color: "cyan" }, "\u{1F552} Unix Time Converter")), /* @__PURE__ */ React32.createElement(
6262
+ Box22,
6263
+ {
6264
+ flexDirection: "column",
6265
+ borderStyle: "single",
6266
+ borderColor: "gray",
6267
+ paddingX: 2,
6268
+ paddingY: 1,
6269
+ marginBottom: 1
6270
+ },
6271
+ /* @__PURE__ */ React32.createElement(Text23, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
6272
+ /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React32.createElement(Box22, { width: 20 }, /* @__PURE__ */ React32.createElement(Text23, { color: focusedField === "mode" ? "green" : void 0 }, focusedField === "mode" ? "\u25B6 " : " ", "Mode:")), /* @__PURE__ */ React32.createElement(Text23, { bold: true, color: focusedField === "mode" ? "yellow" : void 0 }, mode === "now" ? "CURRENT TIME" : mode === "to-human" ? "TIMESTAMP \u2192 HUMAN" : "HUMAN \u2192 TIMESTAMP"), focusedField === "mode" && /* @__PURE__ */ React32.createElement(Text23, { dimColor: true }, " (Enter to cycle)")),
6273
+ mode !== "now" && /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 0 }, /* @__PURE__ */ React32.createElement(Text23, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", mode === "to-human" ? "Timestamp:" : "Date string:")), /* @__PURE__ */ React32.createElement(Box22, { marginLeft: 2, width: 50 }, focusedField === "input" ? /* @__PURE__ */ React32.createElement(
6274
+ TextInput9,
6275
+ {
6276
+ value: input,
6277
+ onChange: setInput,
6278
+ placeholder: mode === "to-human" ? "1702550400" : "2024-01-15 10:30:00"
6279
+ }
6280
+ ) : /* @__PURE__ */ React32.createElement(Text23, { dimColor: !input }, input || "(empty)"))),
6281
+ mode === "to-human" && /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React32.createElement(Box22, { width: 20 }, /* @__PURE__ */ React32.createElement(Text23, { color: focusedField === "format" ? "green" : void 0 }, focusedField === "format" ? "\u25B6 " : " ", "Format:")), /* @__PURE__ */ React32.createElement(Text23, { bold: true, color: focusedField === "format" ? "yellow" : void 0 }, format.toUpperCase()), focusedField === "format" && /* @__PURE__ */ React32.createElement(Text23, { dimColor: true }, " (Enter to cycle)")),
6282
+ mode === "now" && /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React32.createElement(Text23, { color: focusedField === "ms" ? "green" : void 0 }, focusedField === "ms" ? "\u25B6 " : " ", "[", useMs ? "\u2713" : " ", "] Milliseconds")),
6283
+ /* @__PURE__ */ React32.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(
6284
+ Text23,
6285
+ {
6286
+ bold: true,
6287
+ backgroundColor: focusedField === "convert" ? "green" : void 0,
6288
+ color: focusedField === "convert" ? "black" : "green"
6289
+ },
6290
+ focusedField === "convert" ? "\u25B6 " : " ",
6291
+ "[ ",
6292
+ mode === "now" ? "Get Current" : "Convert",
6293
+ " ]"
6294
+ ))
6295
+ ), error && /* @__PURE__ */ React32.createElement(
6296
+ Box22,
6297
+ {
6298
+ flexDirection: "column",
6299
+ borderStyle: "single",
6300
+ borderColor: "red",
6301
+ paddingX: 2,
6302
+ paddingY: 1,
6303
+ marginBottom: 1
6304
+ },
6305
+ /* @__PURE__ */ React32.createElement(Text23, { color: "red" }, "\u2717 Error: ", error)
6306
+ ), result && /* @__PURE__ */ React32.createElement(
6307
+ Box22,
6308
+ {
6309
+ flexDirection: "column",
6310
+ borderStyle: "single",
6311
+ borderColor: "green",
6312
+ paddingX: 2,
6313
+ paddingY: 1
6314
+ },
6315
+ /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React32.createElement(Text23, { bold: true, color: "green" }, "\u2713 Result:"), copied && /* @__PURE__ */ React32.createElement(Box22, { marginLeft: 2 }, /* @__PURE__ */ React32.createElement(Text23, { color: "green" }, "\u2713 Copied to clipboard!"))),
6316
+ /* @__PURE__ */ React32.createElement(Box22, { flexDirection: "column" }, /* @__PURE__ */ React32.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text23, { wrap: "wrap" }, result)))
6317
+ ), /* @__PURE__ */ React32.createElement(Box22, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 2 }, /* @__PURE__ */ React32.createElement(Text23, { dimColor: true }, "Tab: Next | Enter: Toggle/Convert | C: Copy | Esc: Back")));
6318
+ };
6319
+
6320
+ // src/ui/utils/views/JwtView.tsx
6321
+ import React33, { useState as useState20 } from "react";
6322
+ import { Box as Box23, Text as Text24, useInput as useInput18 } from "ink";
6323
+ import TextInput10 from "ink-text-input";
6324
+ var JwtView = () => {
6325
+ const [mode, setMode] = useState20("decode");
6326
+ const [token, setToken] = useState20("");
6327
+ const [payload, setPayload] = useState20("");
6328
+ const [secret, setSecret] = useState20("");
6329
+ const [result, setResult] = useState20({});
6330
+ const [error, setError] = useState20("");
6331
+ const [focusedField, setFocusedField] = useState20("mode");
6332
+ const [copied, setCopied] = useState20(false);
6333
+ const service = new UtilsService();
6334
+ useInput18((input, key) => {
6335
+ if (key.tab) {
6336
+ const fields = mode === "decode" ? ["mode", "token", "process"] : ["mode", "payload", "secret", "process"];
6337
+ const currentIndex = fields.indexOf(focusedField);
6338
+ setFocusedField(fields[(currentIndex + 1) % fields.length]);
6339
+ } else if (key.return) {
6340
+ if (focusedField === "mode") {
6341
+ setMode(mode === "decode" ? "encode" : "decode");
6342
+ setResult({});
6343
+ setError("");
6344
+ } else if (focusedField === "process") {
6345
+ handleProcess();
6346
+ }
6347
+ } else if (input === "c" && result.token) {
6348
+ handleCopy();
6349
+ }
6350
+ });
6351
+ const handleProcess = () => {
6352
+ try {
6353
+ setError("");
6354
+ if (mode === "decode") {
6355
+ if (!token) {
6356
+ setError("Please enter a JWT token");
6357
+ return;
6358
+ }
6359
+ const decoded = service.jwtDecode(token);
6360
+ setResult(decoded);
6361
+ } else {
6362
+ if (!payload) {
6363
+ setError("Please enter payload JSON");
6364
+ return;
6365
+ }
6366
+ if (!secret) {
6367
+ setError("Please enter a secret key");
6368
+ return;
6369
+ }
6370
+ const payloadObj = JSON.parse(payload);
6371
+ const encoded = service.jwtEncode(payloadObj, secret);
6372
+ setResult({ token: encoded });
6373
+ }
6374
+ setCopied(false);
6375
+ } catch (err) {
6376
+ setError(err instanceof Error ? err.message : "Processing failed");
6377
+ setResult({});
6378
+ }
6379
+ };
6380
+ const handleCopy = async () => {
6381
+ try {
6382
+ const { default: clipboardy } = await import("clipboardy");
6383
+ await clipboardy.write(result.token || "");
6384
+ setCopied(true);
6385
+ setTimeout(() => setCopied(false), 2e3);
6386
+ } catch (error2) {
6387
+ }
6388
+ };
6389
+ return /* @__PURE__ */ React33.createElement(Box23, { flexDirection: "column" }, /* @__PURE__ */ React33.createElement(Box23, { marginBottom: 1 }, /* @__PURE__ */ React33.createElement(Text24, { bold: true, color: "cyan" }, "\u{1F511} JWT Decoder/Encoder")), /* @__PURE__ */ React33.createElement(
6390
+ Box23,
6391
+ {
6392
+ flexDirection: "column",
6393
+ borderStyle: "single",
6394
+ borderColor: "gray",
6395
+ paddingX: 2,
6396
+ paddingY: 1,
6397
+ marginBottom: 1
6398
+ },
6399
+ /* @__PURE__ */ React33.createElement(Text24, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
6400
+ /* @__PURE__ */ React33.createElement(Box23, { marginBottom: 1 }, /* @__PURE__ */ React33.createElement(Box23, { width: 20 }, /* @__PURE__ */ React33.createElement(Text24, { color: focusedField === "mode" ? "green" : void 0 }, focusedField === "mode" ? "\u25B6 " : " ", "Mode:")), /* @__PURE__ */ React33.createElement(Text24, { bold: true, color: focusedField === "mode" ? "yellow" : void 0 }, mode === "decode" ? "DECODE" : "ENCODE"), focusedField === "mode" && /* @__PURE__ */ React33.createElement(Text24, { dimColor: true }, " (Enter to toggle)")),
6401
+ mode === "decode" ? /* @__PURE__ */ React33.createElement(Box23, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React33.createElement(Box23, { marginBottom: 0 }, /* @__PURE__ */ React33.createElement(Text24, { color: focusedField === "token" ? "green" : void 0 }, focusedField === "token" ? "\u25B6 " : " ", "JWT Token:")), /* @__PURE__ */ React33.createElement(Box23, { marginLeft: 2, width: 60 }, focusedField === "token" ? /* @__PURE__ */ React33.createElement(
6402
+ TextInput10,
6403
+ {
6404
+ value: token,
6405
+ onChange: setToken,
6406
+ placeholder: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
6407
+ }
6408
+ ) : /* @__PURE__ */ React33.createElement(Text24, { dimColor: !token }, token || "(empty)"))) : /* @__PURE__ */ React33.createElement(React33.Fragment, null, /* @__PURE__ */ React33.createElement(Box23, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React33.createElement(Box23, { marginBottom: 0 }, /* @__PURE__ */ React33.createElement(Text24, { color: focusedField === "payload" ? "green" : void 0 }, focusedField === "payload" ? "\u25B6 " : " ", "Payload (JSON):")), /* @__PURE__ */ React33.createElement(Box23, { marginLeft: 2, width: 60 }, focusedField === "payload" ? /* @__PURE__ */ React33.createElement(
6409
+ TextInput10,
6410
+ {
6411
+ value: payload,
6412
+ onChange: setPayload,
6413
+ placeholder: '{"sub":"123","name":"John"}'
6414
+ }
6415
+ ) : /* @__PURE__ */ React33.createElement(Text24, { dimColor: !payload }, payload || "(empty)"))), /* @__PURE__ */ React33.createElement(Box23, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React33.createElement(Box23, { marginBottom: 0 }, /* @__PURE__ */ React33.createElement(Text24, { color: focusedField === "secret" ? "green" : void 0 }, focusedField === "secret" ? "\u25B6 " : " ", "Secret Key:")), /* @__PURE__ */ React33.createElement(Box23, { marginLeft: 2, width: 60 }, focusedField === "secret" ? /* @__PURE__ */ React33.createElement(
6416
+ TextInput10,
6417
+ {
6418
+ value: secret,
6419
+ onChange: setSecret,
6420
+ placeholder: "your-secret-key",
6421
+ mask: "*"
6422
+ }
6423
+ ) : /* @__PURE__ */ React33.createElement(Text24, { dimColor: !secret }, secret ? "*".repeat(secret.length) : "(empty)")))),
6424
+ /* @__PURE__ */ React33.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React33.createElement(
6425
+ Text24,
6426
+ {
6427
+ bold: true,
6428
+ backgroundColor: focusedField === "process" ? "green" : void 0,
6429
+ color: focusedField === "process" ? "black" : "green"
6430
+ },
6431
+ focusedField === "process" ? "\u25B6 " : " ",
6432
+ "[ ",
6433
+ mode === "decode" ? "Decode" : "Encode",
6434
+ " ]"
6435
+ ))
6436
+ ), error && /* @__PURE__ */ React33.createElement(
6437
+ Box23,
6438
+ {
6439
+ flexDirection: "column",
6440
+ borderStyle: "single",
6441
+ borderColor: "red",
6442
+ paddingX: 2,
6443
+ paddingY: 1,
6444
+ marginBottom: 1
6445
+ },
6446
+ /* @__PURE__ */ React33.createElement(Text24, { color: "red" }, "\u2717 Error: ", error)
6447
+ ), (result.header || result.token) && /* @__PURE__ */ React33.createElement(
6448
+ Box23,
6449
+ {
6450
+ flexDirection: "column",
6451
+ borderStyle: "single",
6452
+ borderColor: "green",
6453
+ paddingX: 2,
6454
+ paddingY: 1
6455
+ },
6456
+ /* @__PURE__ */ React33.createElement(Box23, { marginBottom: 1 }, /* @__PURE__ */ React33.createElement(Text24, { bold: true, color: "green" }, "\u2713 Result:"), copied && result.token && /* @__PURE__ */ React33.createElement(Box23, { marginLeft: 2 }, /* @__PURE__ */ React33.createElement(Text24, { color: "green" }, "\u2713 Copied to clipboard!"))),
6457
+ /* @__PURE__ */ React33.createElement(Box23, { flexDirection: "column" }, result.header && /* @__PURE__ */ React33.createElement(React33.Fragment, null, /* @__PURE__ */ React33.createElement(Text24, { bold: true, color: "yellow" }, "Header:"), /* @__PURE__ */ React33.createElement(Text24, null, JSON.stringify(result.header, null, 2)), /* @__PURE__ */ React33.createElement(Text24, null, " "), /* @__PURE__ */ React33.createElement(Text24, { bold: true, color: "yellow" }, "Payload:"), /* @__PURE__ */ React33.createElement(Text24, null, JSON.stringify(result.payload, null, 2)), /* @__PURE__ */ React33.createElement(Text24, null, " "), /* @__PURE__ */ React33.createElement(Text24, { bold: true, color: "yellow" }, "Signature:"), /* @__PURE__ */ React33.createElement(Text24, { dimColor: true }, result.signature)), result.token && /* @__PURE__ */ React33.createElement(React33.Fragment, null, /* @__PURE__ */ React33.createElement(Text24, { bold: true, color: "yellow" }, "Token:"), /* @__PURE__ */ React33.createElement(Text24, { wrap: "wrap" }, result.token)))
6458
+ ), /* @__PURE__ */ React33.createElement(Box23, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 2 }, /* @__PURE__ */ React33.createElement(Text24, { dimColor: true }, "Tab: Next | Enter: Toggle/", mode === "decode" ? "Decode" : "Encode", " | C: Copy | Esc: Back")));
6459
+ };
6460
+
6461
+ // src/ui/utils/views/CronView.tsx
6462
+ import React34, { useState as useState21 } from "react";
6463
+ import { Box as Box24, Text as Text25, useInput as useInput19 } from "ink";
6464
+ import TextInput11 from "ink-text-input";
6465
+ var CronView = () => {
6466
+ const [expression, setExpression] = useState21("");
6467
+ const [result, setResult] = useState21(null);
6468
+ const [error, setError] = useState21("");
6469
+ const [focusedField, setFocusedField] = useState21("expression");
6470
+ const [copied, setCopied] = useState21(false);
6471
+ const service = new UtilsService();
6472
+ useInput19((input, key) => {
6473
+ if (key.tab) {
6474
+ setFocusedField(focusedField === "expression" ? "parse" : "expression");
6475
+ } else if (key.return && focusedField === "parse") {
6476
+ handleParse();
6477
+ } else if (input === "c" && result) {
6478
+ handleCopy();
6479
+ }
6480
+ });
6481
+ const handleParse = () => {
6482
+ if (!expression) {
6483
+ setError("Please enter a cron expression");
6484
+ return;
6485
+ }
6486
+ try {
6487
+ setError("");
6488
+ const parsed = service.parseCron(expression);
6489
+ setResult(parsed);
6490
+ setCopied(false);
6491
+ } catch (err) {
6492
+ setError(err instanceof Error ? err.message : "Failed to parse cron expression");
6493
+ setResult(null);
6494
+ }
6495
+ };
6496
+ const handleCopy = async () => {
6497
+ if (!result) return;
6498
+ try {
6499
+ const { default: clipboardy } = await import("clipboardy");
6500
+ const copyText = `${result.description}
6501
+
6502
+ Next runs:
6503
+ ${result.nextRuns.join("\n")}`;
6504
+ await clipboardy.write(copyText);
6505
+ setCopied(true);
6506
+ setTimeout(() => setCopied(false), 2e3);
6507
+ } catch (error2) {
6508
+ }
6509
+ };
6510
+ return /* @__PURE__ */ React34.createElement(Box24, { flexDirection: "column" }, /* @__PURE__ */ React34.createElement(Box24, { marginBottom: 1 }, /* @__PURE__ */ React34.createElement(Text25, { bold: true, color: "cyan" }, "\u23F0 Cron Expression Parser")), /* @__PURE__ */ React34.createElement(
6511
+ Box24,
6512
+ {
6513
+ flexDirection: "column",
6514
+ borderStyle: "single",
6515
+ borderColor: "gray",
6516
+ paddingX: 2,
6517
+ paddingY: 1,
6518
+ marginBottom: 1
6519
+ },
6520
+ /* @__PURE__ */ React34.createElement(Text25, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
6521
+ /* @__PURE__ */ React34.createElement(Box24, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React34.createElement(Box24, { marginBottom: 0 }, /* @__PURE__ */ React34.createElement(Text25, { color: focusedField === "expression" ? "green" : void 0 }, focusedField === "expression" ? "\u25B6 " : " ", "Cron Expression:")), /* @__PURE__ */ React34.createElement(Box24, { marginLeft: 2, width: 50 }, focusedField === "expression" ? /* @__PURE__ */ React34.createElement(
6522
+ TextInput11,
6523
+ {
6524
+ value: expression,
6525
+ onChange: setExpression,
6526
+ placeholder: "0 5 * * * (5-field or 6-field)"
6527
+ }
6528
+ ) : /* @__PURE__ */ React34.createElement(Text25, { dimColor: !expression }, expression || "(empty)"))),
6529
+ /* @__PURE__ */ React34.createElement(Box24, { marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React34.createElement(Text25, { dimColor: true }, 'Examples: "0 5 * * *" (daily at 5am), "*/15 * * * *" (every 15 min)')),
6530
+ /* @__PURE__ */ React34.createElement(Box24, { marginTop: 1 }, /* @__PURE__ */ React34.createElement(
6531
+ Text25,
6532
+ {
6533
+ bold: true,
6534
+ backgroundColor: focusedField === "parse" ? "green" : void 0,
6535
+ color: focusedField === "parse" ? "black" : "green"
6536
+ },
6537
+ focusedField === "parse" ? "\u25B6 " : " ",
6538
+ "[ Parse Expression ]"
6539
+ ))
6540
+ ), error && /* @__PURE__ */ React34.createElement(
6541
+ Box24,
6542
+ {
6543
+ flexDirection: "column",
6544
+ borderStyle: "single",
6545
+ borderColor: "red",
6546
+ paddingX: 2,
6547
+ paddingY: 1,
6548
+ marginBottom: 1
6549
+ },
6550
+ /* @__PURE__ */ React34.createElement(Text25, { color: "red" }, "\u2717 Error: ", error)
6551
+ ), result && /* @__PURE__ */ React34.createElement(
6552
+ Box24,
6553
+ {
6554
+ flexDirection: "column",
6555
+ borderStyle: "single",
6556
+ borderColor: "green",
6557
+ paddingX: 2,
6558
+ paddingY: 1
6559
+ },
6560
+ /* @__PURE__ */ React34.createElement(Box24, { marginBottom: 1 }, /* @__PURE__ */ React34.createElement(Text25, { bold: true, color: "green" }, "\u2713 Result:"), copied && /* @__PURE__ */ React34.createElement(Box24, { marginLeft: 2 }, /* @__PURE__ */ React34.createElement(Text25, { color: "green" }, "\u2713 Copied to clipboard!"))),
6561
+ /* @__PURE__ */ React34.createElement(Box24, { flexDirection: "column" }, /* @__PURE__ */ React34.createElement(Text25, { bold: true, color: "yellow" }, "Expression:"), /* @__PURE__ */ React34.createElement(Text25, null, expression), /* @__PURE__ */ React34.createElement(Text25, null, " "), /* @__PURE__ */ React34.createElement(Text25, { bold: true, color: "yellow" }, "Meaning:"), /* @__PURE__ */ React34.createElement(Text25, null, result.description), /* @__PURE__ */ React34.createElement(Text25, null, " "), /* @__PURE__ */ React34.createElement(Text25, { bold: true, color: "yellow" }, "Next 5 executions:"), result.nextRuns.map((run, index) => /* @__PURE__ */ React34.createElement(Text25, { key: index }, " ", index + 1, ". ", run)))
6562
+ ), /* @__PURE__ */ React34.createElement(Box24, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 2 }, /* @__PURE__ */ React34.createElement(Text25, { dimColor: true }, "Tab: Next | Enter: Parse | C: Copy | Esc: Back")));
6563
+ };
6564
+
6565
+ // src/ui/utils/views/TimezoneView.tsx
6566
+ import React35, { useState as useState22 } from "react";
6567
+ import { Box as Box25, Text as Text26, useInput as useInput20 } from "ink";
6568
+ import TextInput12 from "ink-text-input";
6569
+ var TimezoneView = () => {
6570
+ const [time, setTime] = useState22("");
6571
+ const [fromTz, setFromTz] = useState22("UTC");
6572
+ const [toTz, setToTz] = useState22("America/New_York");
6573
+ const [result, setResult] = useState22("");
6574
+ const [error, setError] = useState22("");
6575
+ const [focusedField, setFocusedField] = useState22("time");
6576
+ const [copied, setCopied] = useState22(false);
6577
+ const service = new UtilsService();
6578
+ useInput20((input, key) => {
6579
+ if (key.tab) {
6580
+ const fields = ["time", "from", "to", "convert"];
6581
+ const currentIndex = fields.indexOf(focusedField);
6582
+ setFocusedField(fields[(currentIndex + 1) % fields.length]);
6583
+ } else if (key.return && focusedField === "convert") {
6584
+ handleConvert();
6585
+ } else if (input === "c" && result) {
6586
+ handleCopy();
6587
+ }
6588
+ });
6589
+ const handleConvert = () => {
6590
+ if (!time) {
6591
+ setError("Please enter a time");
6592
+ return;
6593
+ }
6594
+ if (!fromTz || !toTz) {
6595
+ setError("Please enter both timezones");
6596
+ return;
6597
+ }
6598
+ try {
6599
+ setError("");
6600
+ const converted = service.convertTimezone(time, fromTz, toTz);
6601
+ setResult(converted);
6602
+ setCopied(false);
6603
+ } catch (err) {
6604
+ setError(err instanceof Error ? err.message : "Conversion failed");
6605
+ setResult("");
6606
+ }
6607
+ };
6608
+ const handleCopy = async () => {
6609
+ try {
6610
+ const { default: clipboardy } = await import("clipboardy");
6611
+ await clipboardy.write(result);
6612
+ setCopied(true);
6613
+ setTimeout(() => setCopied(false), 2e3);
6614
+ } catch (error2) {
6615
+ }
6616
+ };
6617
+ return /* @__PURE__ */ React35.createElement(Box25, { flexDirection: "column" }, /* @__PURE__ */ React35.createElement(Box25, { marginBottom: 1 }, /* @__PURE__ */ React35.createElement(Text26, { bold: true, color: "cyan" }, "\u{1F30D} Timezone Converter")), /* @__PURE__ */ React35.createElement(
6618
+ Box25,
6619
+ {
6620
+ flexDirection: "column",
6621
+ borderStyle: "single",
6622
+ borderColor: "gray",
6623
+ paddingX: 2,
6624
+ paddingY: 1,
6625
+ marginBottom: 1
6626
+ },
6627
+ /* @__PURE__ */ React35.createElement(Text26, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
6628
+ /* @__PURE__ */ React35.createElement(Box25, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React35.createElement(Box25, { marginBottom: 0 }, /* @__PURE__ */ React35.createElement(Text26, { color: focusedField === "time" ? "green" : void 0 }, focusedField === "time" ? "\u25B6 " : " ", "Time:")), /* @__PURE__ */ React35.createElement(Box25, { marginLeft: 2, width: 50 }, focusedField === "time" ? /* @__PURE__ */ React35.createElement(
6629
+ TextInput12,
6630
+ {
6631
+ value: time,
6632
+ onChange: setTime,
6633
+ placeholder: "2024-01-15 10:00:00"
6634
+ }
6635
+ ) : /* @__PURE__ */ React35.createElement(Text26, { dimColor: !time }, time || "(empty)"))),
6636
+ /* @__PURE__ */ React35.createElement(Box25, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React35.createElement(Box25, { marginBottom: 0 }, /* @__PURE__ */ React35.createElement(Text26, { color: focusedField === "from" ? "green" : void 0 }, focusedField === "from" ? "\u25B6 " : " ", "From Timezone:")), /* @__PURE__ */ React35.createElement(Box25, { marginLeft: 2, width: 50 }, focusedField === "from" ? /* @__PURE__ */ React35.createElement(
6637
+ TextInput12,
6638
+ {
6639
+ value: fromTz,
6640
+ onChange: setFromTz,
6641
+ placeholder: "UTC or America/New_York"
6642
+ }
6643
+ ) : /* @__PURE__ */ React35.createElement(Text26, { dimColor: !fromTz }, fromTz || "(empty)"))),
6644
+ /* @__PURE__ */ React35.createElement(Box25, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React35.createElement(Box25, { marginBottom: 0 }, /* @__PURE__ */ React35.createElement(Text26, { color: focusedField === "to" ? "green" : void 0 }, focusedField === "to" ? "\u25B6 " : " ", "To Timezone:")), /* @__PURE__ */ React35.createElement(Box25, { marginLeft: 2, width: 50 }, focusedField === "to" ? /* @__PURE__ */ React35.createElement(
6645
+ TextInput12,
6646
+ {
6647
+ value: toTz,
6648
+ onChange: setToTz,
6649
+ placeholder: "Asia/Tokyo or Europe/London"
6650
+ }
6651
+ ) : /* @__PURE__ */ React35.createElement(Text26, { dimColor: !toTz }, toTz || "(empty)"))),
6652
+ /* @__PURE__ */ React35.createElement(Box25, { marginBottom: 1 }, /* @__PURE__ */ React35.createElement(Text26, { dimColor: true }, "Common: UTC, America/New_York, Europe/London, Asia/Tokyo")),
6653
+ /* @__PURE__ */ React35.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React35.createElement(
6654
+ Text26,
6655
+ {
6656
+ bold: true,
6657
+ backgroundColor: focusedField === "convert" ? "green" : void 0,
6658
+ color: focusedField === "convert" ? "black" : "green"
6659
+ },
6660
+ focusedField === "convert" ? "\u25B6 " : " ",
6661
+ "[ Convert ]"
6662
+ ))
6663
+ ), error && /* @__PURE__ */ React35.createElement(
6664
+ Box25,
6665
+ {
6666
+ flexDirection: "column",
6667
+ borderStyle: "single",
6668
+ borderColor: "red",
6669
+ paddingX: 2,
6670
+ paddingY: 1,
6671
+ marginBottom: 1
6672
+ },
6673
+ /* @__PURE__ */ React35.createElement(Text26, { color: "red" }, "\u2717 Error: ", error)
6674
+ ), result && /* @__PURE__ */ React35.createElement(
6675
+ Box25,
6676
+ {
6677
+ flexDirection: "column",
6678
+ borderStyle: "single",
6679
+ borderColor: "green",
6680
+ paddingX: 2,
6681
+ paddingY: 1
6682
+ },
6683
+ /* @__PURE__ */ React35.createElement(Box25, { marginBottom: 1 }, /* @__PURE__ */ React35.createElement(Text26, { bold: true, color: "green" }, "\u2713 Result:"), copied && /* @__PURE__ */ React35.createElement(Box25, { marginLeft: 2 }, /* @__PURE__ */ React35.createElement(Text26, { color: "green" }, "\u2713 Copied to clipboard!"))),
6684
+ /* @__PURE__ */ React35.createElement(Box25, { flexDirection: "column" }, /* @__PURE__ */ React35.createElement(Text26, { dimColor: true }, "From: ", fromTz), /* @__PURE__ */ React35.createElement(Text26, { dimColor: true }, "To: ", toTz), /* @__PURE__ */ React35.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React35.createElement(Text26, { wrap: "wrap" }, result)))
6685
+ ), /* @__PURE__ */ React35.createElement(Box25, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 2 }, /* @__PURE__ */ React35.createElement(Text26, { dimColor: true }, "Tab: Next | Enter: Convert | C: Copy | Esc: Back")));
6686
+ };
6687
+
6688
+ // src/ui/utils/views/HttpView.tsx
6689
+ import React36, { useState as useState23 } from "react";
6690
+ import { Box as Box26, Text as Text27, useInput as useInput21 } from "ink";
6691
+ import TextInput13 from "ink-text-input";
6692
+ var METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
6693
+ var HttpView = () => {
6694
+ const [url, setUrl] = useState23("");
6695
+ const [method, setMethod] = useState23("GET");
6696
+ const [headers, setHeaders] = useState23("");
6697
+ const [body, setBody] = useState23("");
6698
+ const [response, setResponse] = useState23(null);
6699
+ const [error, setError] = useState23("");
6700
+ const [loading, setLoading] = useState23(false);
6701
+ const [focusedField, setFocusedField] = useState23("url");
6702
+ const [copied, setCopied] = useState23(false);
6703
+ const service = new UtilsService();
6704
+ useInput21((input, key) => {
6705
+ if (loading) return;
6706
+ if (key.tab) {
6707
+ const fields = ["url", "method", "headers", "body", "send"];
6708
+ const currentIndex = fields.indexOf(focusedField);
6709
+ setFocusedField(fields[(currentIndex + 1) % fields.length]);
6710
+ } else if (key.leftArrow && focusedField === "method") {
6711
+ const currentIndex = METHODS.indexOf(method);
6712
+ setMethod(METHODS[currentIndex > 0 ? currentIndex - 1 : METHODS.length - 1]);
6713
+ } else if (key.rightArrow && focusedField === "method") {
6714
+ const currentIndex = METHODS.indexOf(method);
6715
+ setMethod(METHODS[(currentIndex + 1) % METHODS.length]);
6716
+ } else if (key.return && focusedField === "send") {
6717
+ handleSend();
6718
+ } else if (input === "c" && response) {
6719
+ handleCopy();
6720
+ }
6721
+ });
6722
+ const handleSend = async () => {
6723
+ if (!url) {
6724
+ setError("Please enter a URL");
6725
+ return;
6726
+ }
6727
+ try {
6728
+ setError("");
6729
+ setLoading(true);
6730
+ const headersObj = {};
6731
+ if (headers) {
6732
+ const headerLines = headers.split("\n");
6733
+ for (const line of headerLines) {
6734
+ const [key, ...valueParts] = line.split(":");
6735
+ if (key && valueParts.length > 0) {
6736
+ headersObj[key.trim()] = valueParts.join(":").trim();
6737
+ }
6738
+ }
6739
+ }
6740
+ const result = await service.httpRequest(url, {
6741
+ method,
6742
+ headers: headersObj,
6743
+ body: body || void 0
6744
+ });
6745
+ setResponse(result);
6746
+ setCopied(false);
6747
+ } catch (err) {
6748
+ setError(err instanceof Error ? err.message : "Request failed");
6749
+ setResponse(null);
6750
+ } finally {
6751
+ setLoading(false);
6752
+ }
6753
+ };
6754
+ const handleCopy = async () => {
6755
+ if (!response) return;
6756
+ try {
6757
+ const { default: clipboardy } = await import("clipboardy");
6758
+ const copyText = typeof response.body === "string" ? response.body : JSON.stringify(response.body, null, 2);
6759
+ await clipboardy.write(copyText);
6760
+ setCopied(true);
6761
+ setTimeout(() => setCopied(false), 2e3);
6762
+ } catch (error2) {
6763
+ }
6764
+ };
6765
+ return /* @__PURE__ */ React36.createElement(Box26, { flexDirection: "column" }, /* @__PURE__ */ React36.createElement(Box26, { marginBottom: 1 }, /* @__PURE__ */ React36.createElement(Text27, { bold: true, color: "cyan" }, "\u{1F310} HTTP Request")), /* @__PURE__ */ React36.createElement(
6766
+ Box26,
6767
+ {
6768
+ flexDirection: "column",
6769
+ borderStyle: "single",
6770
+ borderColor: "gray",
6771
+ paddingX: 2,
6772
+ paddingY: 1,
6773
+ marginBottom: 1
6774
+ },
6775
+ /* @__PURE__ */ React36.createElement(Text27, { bold: true, color: "yellow", marginBottom: 1 }, "Request:"),
6776
+ /* @__PURE__ */ React36.createElement(Box26, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React36.createElement(Box26, { marginBottom: 0 }, /* @__PURE__ */ React36.createElement(Text27, { color: focusedField === "url" ? "green" : void 0 }, focusedField === "url" ? "\u25B6 " : " ", "URL:")), /* @__PURE__ */ React36.createElement(Box26, { marginLeft: 2, width: 60 }, focusedField === "url" ? /* @__PURE__ */ React36.createElement(
6777
+ TextInput13,
6778
+ {
6779
+ value: url,
6780
+ onChange: setUrl,
6781
+ placeholder: "https://api.example.com/endpoint"
6782
+ }
6783
+ ) : /* @__PURE__ */ React36.createElement(Text27, { dimColor: !url }, url || "(empty)"))),
6784
+ /* @__PURE__ */ React36.createElement(Box26, { marginBottom: 1 }, /* @__PURE__ */ React36.createElement(Box26, { width: 20 }, /* @__PURE__ */ React36.createElement(Text27, { color: focusedField === "method" ? "green" : void 0 }, focusedField === "method" ? "\u25B6 " : " ", "Method:")), /* @__PURE__ */ React36.createElement(Text27, { bold: true, color: focusedField === "method" ? "yellow" : void 0 }, method), focusedField === "method" && /* @__PURE__ */ React36.createElement(Text27, { dimColor: true }, " (\u2190 \u2192 to change)")),
6785
+ /* @__PURE__ */ React36.createElement(Box26, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React36.createElement(Box26, { marginBottom: 0 }, /* @__PURE__ */ React36.createElement(Text27, { color: focusedField === "headers" ? "green" : void 0 }, focusedField === "headers" ? "\u25B6 " : " ", "Headers (one per line, Key: Value):")), /* @__PURE__ */ React36.createElement(Box26, { marginLeft: 2, width: 60 }, focusedField === "headers" ? /* @__PURE__ */ React36.createElement(
6786
+ TextInput13,
6787
+ {
6788
+ value: headers,
6789
+ onChange: setHeaders,
6790
+ placeholder: "Authorization: Bearer token"
6791
+ }
6792
+ ) : /* @__PURE__ */ React36.createElement(Text27, { dimColor: !headers }, headers || "(none)"))),
6793
+ (method === "POST" || method === "PUT" || method === "PATCH") && /* @__PURE__ */ React36.createElement(Box26, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React36.createElement(Box26, { marginBottom: 0 }, /* @__PURE__ */ React36.createElement(Text27, { color: focusedField === "body" ? "green" : void 0 }, focusedField === "body" ? "\u25B6 " : " ", "Body (JSON):")), /* @__PURE__ */ React36.createElement(Box26, { marginLeft: 2, width: 60 }, focusedField === "body" ? /* @__PURE__ */ React36.createElement(
6794
+ TextInput13,
6795
+ {
6796
+ value: body,
6797
+ onChange: setBody,
6798
+ placeholder: '{"key":"value"}'
6799
+ }
6800
+ ) : /* @__PURE__ */ React36.createElement(Text27, { dimColor: !body }, body || "(empty)"))),
6801
+ /* @__PURE__ */ React36.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React36.createElement(
6802
+ Text27,
6803
+ {
6804
+ bold: true,
6805
+ backgroundColor: focusedField === "send" ? "green" : void 0,
6806
+ color: focusedField === "send" ? "black" : "green"
6807
+ },
6808
+ focusedField === "send" ? "\u25B6 " : " ",
6809
+ "[ ",
6810
+ loading ? "Sending..." : "Send Request",
6811
+ " ]"
6812
+ ))
6813
+ ), error && /* @__PURE__ */ React36.createElement(
6814
+ Box26,
6815
+ {
6816
+ flexDirection: "column",
6817
+ borderStyle: "single",
6818
+ borderColor: "red",
6819
+ paddingX: 2,
6820
+ paddingY: 1,
6821
+ marginBottom: 1
6822
+ },
6823
+ /* @__PURE__ */ React36.createElement(Text27, { color: "red" }, "\u2717 Error: ", error)
6824
+ ), response && /* @__PURE__ */ React36.createElement(
6825
+ Box26,
6826
+ {
6827
+ flexDirection: "column",
6828
+ borderStyle: "single",
6829
+ borderColor: "green",
6830
+ paddingX: 2,
6831
+ paddingY: 1
6832
+ },
6833
+ /* @__PURE__ */ React36.createElement(Box26, { marginBottom: 1 }, /* @__PURE__ */ React36.createElement(Text27, { bold: true, color: "green" }, "\u2713 Response:"), copied && /* @__PURE__ */ React36.createElement(Box26, { marginLeft: 2 }, /* @__PURE__ */ React36.createElement(Text27, { color: "green" }, "\u2713 Copied body to clipboard!"))),
6834
+ /* @__PURE__ */ React36.createElement(Box26, { flexDirection: "column" }, /* @__PURE__ */ React36.createElement(Text27, null, "Status: ", /* @__PURE__ */ React36.createElement(Text27, { color: response.status < 400 ? "green" : "red" }, response.status)), /* @__PURE__ */ React36.createElement(Text27, null, "Time: ", response.time, "ms"), /* @__PURE__ */ React36.createElement(Text27, null, "Size: ", response.size), /* @__PURE__ */ React36.createElement(Text27, null, " "), /* @__PURE__ */ React36.createElement(Text27, { bold: true, color: "yellow" }, "Headers:"), Object.entries(response.headers).slice(0, 5).map(([key, value]) => /* @__PURE__ */ React36.createElement(Text27, { key, dimColor: true }, " ", key, ": ", value)), /* @__PURE__ */ React36.createElement(Text27, null, " "), /* @__PURE__ */ React36.createElement(Text27, { bold: true, color: "yellow" }, "Body:"), /* @__PURE__ */ React36.createElement(Text27, null, typeof response.body === "string" ? response.body.slice(0, 500) : JSON.stringify(response.body, null, 2).slice(0, 500)))
6835
+ ), /* @__PURE__ */ React36.createElement(Box26, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 2 }, /* @__PURE__ */ React36.createElement(Text27, { dimColor: true }, "Tab: Next | \u2190/\u2192: Change method | Enter: Send | C: Copy body | Esc: Back")));
6836
+ };
6837
+
6838
+ // src/ui/utils/views/MarkdownView.tsx
6839
+ import React37, { useState as useState24 } from "react";
6840
+ import { Box as Box27, Text as Text28, useInput as useInput22 } from "ink";
6841
+ import TextInput14 from "ink-text-input";
6842
+ import * as fs8 from "fs";
6843
+ import * as path5 from "path";
6844
+ var MarkdownView = () => {
6845
+ const [filePath, setFilePath] = useState24("");
6846
+ const [content, setContent] = useState24("");
6847
+ const [error, setError] = useState24("");
6848
+ const [focusedField, setFocusedField] = useState24("file");
6849
+ useInput22((input, key) => {
6850
+ if (key.tab) {
6851
+ setFocusedField(focusedField === "file" ? "preview" : "file");
6852
+ } else if (key.return && focusedField === "preview") {
6853
+ handlePreview();
6854
+ }
6855
+ });
6856
+ const handlePreview = async () => {
6857
+ if (!filePath) {
6858
+ setError("Please enter a file path");
6859
+ return;
6860
+ }
6861
+ try {
6862
+ setError("");
6863
+ const resolvedPath = path5.resolve(filePath);
6864
+ if (!fs8.existsSync(resolvedPath)) {
6865
+ setError(`File not found: ${resolvedPath}`);
6866
+ return;
6867
+ }
6868
+ let fileContent = fs8.readFileSync(resolvedPath, "utf-8");
6869
+ fileContent = fileContent.replace(/```mermaid\n([\s\S]*?)```/g, (match, code) => {
6870
+ return `
6871
+ \u{1F3A8} **Mermaid Diagram**
6872
+
6873
+ \`\`\`
6874
+ ${code.trim()}
6875
+ \`\`\`
6876
+
6877
+ \u{1F4A1} *Tip: Mermaid diagrams cannot be rendered in terminal. View in a Markdown viewer.*
6878
+ `;
6879
+ });
6880
+ const { marked: marked2 } = await import("marked");
6881
+ const { default: markedTerminal } = await import("marked-terminal");
6882
+ marked2.use(markedTerminal());
6883
+ const rendered = marked2(fileContent);
6884
+ setContent(rendered);
6885
+ } catch (err) {
6886
+ setError(err instanceof Error ? err.message : "Failed to preview file");
6887
+ setContent("");
6888
+ }
6889
+ };
6890
+ return /* @__PURE__ */ React37.createElement(Box27, { flexDirection: "column" }, /* @__PURE__ */ React37.createElement(Box27, { marginBottom: 1 }, /* @__PURE__ */ React37.createElement(Text28, { bold: true, color: "cyan" }, "\u{1F4C4} Markdown Preview")), /* @__PURE__ */ React37.createElement(
6891
+ Box27,
6892
+ {
6893
+ flexDirection: "column",
6894
+ borderStyle: "single",
6895
+ borderColor: "gray",
6896
+ paddingX: 2,
6897
+ paddingY: 1,
6898
+ marginBottom: 1
6899
+ },
6900
+ /* @__PURE__ */ React37.createElement(Text28, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
6901
+ /* @__PURE__ */ React37.createElement(Box27, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React37.createElement(Box27, { marginBottom: 0 }, /* @__PURE__ */ React37.createElement(Text28, { color: focusedField === "file" ? "green" : void 0 }, focusedField === "file" ? "\u25B6 " : " ", "File path:")), /* @__PURE__ */ React37.createElement(Box27, { marginLeft: 2, width: 60 }, focusedField === "file" ? /* @__PURE__ */ React37.createElement(
6902
+ TextInput14,
6903
+ {
6904
+ value: filePath,
6905
+ onChange: setFilePath,
6906
+ placeholder: "./README.md or /path/to/file.md"
6907
+ }
6908
+ ) : /* @__PURE__ */ React37.createElement(Text28, { dimColor: !filePath }, filePath || "(empty)"))),
6909
+ /* @__PURE__ */ React37.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React37.createElement(
6910
+ Text28,
6911
+ {
6912
+ bold: true,
6913
+ backgroundColor: focusedField === "preview" ? "green" : void 0,
6914
+ color: focusedField === "preview" ? "black" : "green"
6915
+ },
6916
+ focusedField === "preview" ? "\u25B6 " : " ",
6917
+ "[ Preview File ]"
6918
+ ))
6919
+ ), error && /* @__PURE__ */ React37.createElement(
6920
+ Box27,
6921
+ {
6922
+ flexDirection: "column",
6923
+ borderStyle: "single",
6924
+ borderColor: "red",
6925
+ paddingX: 2,
6926
+ paddingY: 1,
6927
+ marginBottom: 1
6928
+ },
6929
+ /* @__PURE__ */ React37.createElement(Text28, { color: "red" }, "\u2717 Error: ", error)
6930
+ ), content && /* @__PURE__ */ React37.createElement(
6931
+ Box27,
6932
+ {
6933
+ flexDirection: "column",
6934
+ borderStyle: "single",
6935
+ borderColor: "green",
6936
+ paddingX: 2,
6937
+ paddingY: 1
6938
+ },
6939
+ /* @__PURE__ */ React37.createElement(Box27, { marginBottom: 1 }, /* @__PURE__ */ React37.createElement(Text28, { bold: true, color: "green" }, "\u2713 Preview:")),
6940
+ /* @__PURE__ */ React37.createElement(Box27, { flexDirection: "column" }, /* @__PURE__ */ React37.createElement(Text28, null, content))
6941
+ ), /* @__PURE__ */ React37.createElement(Box27, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 2 }, /* @__PURE__ */ React37.createElement(Text28, { dimColor: true }, "Tab: Next | Enter: Preview | Esc: Back")));
6942
+ };
6943
+
5984
6944
  // src/ui/utils/UtilsApp.tsx
5985
6945
  var MENU_ITEMS2 = [
5986
6946
  { id: "password", icon: "\u{1F510}", label: "Password", description: "Generate secure passwords" },
@@ -5998,10 +6958,10 @@ var MENU_ITEMS2 = [
5998
6958
  { id: "markdown", icon: "\u{1F4C4}", label: "Markdown", description: "Preview markdown" }
5999
6959
  ];
6000
6960
  var UtilsApp = ({ onExit }) => {
6001
- const [selectedIndex, setSelectedIndex] = useState17(0);
6002
- const [activeView, setActiveView] = useState17(null);
6961
+ const [selectedIndex, setSelectedIndex] = useState25(0);
6962
+ const [activeView, setActiveView] = useState25(null);
6003
6963
  const { exit } = useApp5();
6004
- useInput15((input, key) => {
6964
+ useInput23((input, key) => {
6005
6965
  if (activeView) {
6006
6966
  if (key.escape) {
6007
6967
  setActiveView(null);
@@ -6019,8 +6979,8 @@ var UtilsApp = ({ onExit }) => {
6019
6979
  exit();
6020
6980
  }
6021
6981
  });
6022
- return /* @__PURE__ */ React30.createElement(Box20, { flexDirection: "column", width: "100%", height: "100%" }, /* @__PURE__ */ React30.createElement(
6023
- Box20,
6982
+ return /* @__PURE__ */ React38.createElement(Box28, { flexDirection: "column", width: "100%", height: "100%" }, /* @__PURE__ */ React38.createElement(
6983
+ Box28,
6024
6984
  {
6025
6985
  borderStyle: "single",
6026
6986
  borderColor: "cyan",
@@ -6028,10 +6988,10 @@ var UtilsApp = ({ onExit }) => {
6028
6988
  paddingY: 0,
6029
6989
  marginBottom: 1
6030
6990
  },
6031
- /* @__PURE__ */ React30.createElement(Text21, { bold: true, color: "cyan" }, "\u{1F6E0}\uFE0F Developer Utilities - Interactive Mode"),
6032
- /* @__PURE__ */ React30.createElement(Box20, { marginLeft: "auto" }, /* @__PURE__ */ React30.createElement(Text21, { dimColor: true }, "Press 'q' to quit"))
6033
- ), /* @__PURE__ */ React30.createElement(Box20, { flexGrow: 1 }, /* @__PURE__ */ React30.createElement(
6034
- Box20,
6991
+ /* @__PURE__ */ React38.createElement(Text29, { bold: true, color: "cyan" }, "\u{1F6E0}\uFE0F Developer Utilities - Interactive Mode"),
6992
+ /* @__PURE__ */ React38.createElement(Box28, { marginLeft: "auto" }, /* @__PURE__ */ React38.createElement(Text29, { dimColor: true }, "Press 'q' to quit"))
6993
+ ), /* @__PURE__ */ React38.createElement(Box28, { flexGrow: 1 }, /* @__PURE__ */ React38.createElement(
6994
+ Box28,
6035
6995
  {
6036
6996
  flexDirection: "column",
6037
6997
  width: 30,
@@ -6041,9 +7001,9 @@ var UtilsApp = ({ onExit }) => {
6041
7001
  paddingY: 1,
6042
7002
  marginRight: 1
6043
7003
  },
6044
- /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React30.createElement(Text21, { bold: true, color: "yellow" }, "Select Utility:")),
6045
- MENU_ITEMS2.map((item, index) => /* @__PURE__ */ React30.createElement(Box20, { key: item.id, marginBottom: 0 }, /* @__PURE__ */ React30.createElement(
6046
- Text21,
7004
+ /* @__PURE__ */ React38.createElement(Box28, { marginBottom: 1 }, /* @__PURE__ */ React38.createElement(Text29, { bold: true, color: "yellow" }, "Select Utility:")),
7005
+ MENU_ITEMS2.map((item, index) => /* @__PURE__ */ React38.createElement(Box28, { key: item.id, marginBottom: 0 }, /* @__PURE__ */ React38.createElement(
7006
+ Text29,
6047
7007
  {
6048
7008
  color: selectedIndex === index && !activeView ? "green" : void 0,
6049
7009
  bold: selectedIndex === index && !activeView,
@@ -6054,9 +7014,9 @@ var UtilsApp = ({ onExit }) => {
6054
7014
  " ",
6055
7015
  item.label
6056
7016
  ))),
6057
- /* @__PURE__ */ React30.createElement(Box20, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React30.createElement(Text21, { dimColor: true }, "\u2191/\u2193: Navigate", "\n", "Enter: Select", "\n", "Esc: Back/Quit"))
6058
- ), /* @__PURE__ */ React30.createElement(
6059
- Box20,
7017
+ /* @__PURE__ */ React38.createElement(Box28, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React38.createElement(Text29, { dimColor: true }, "\u2191/\u2193: Navigate", "\n", "Enter: Select", "\n", "Esc: Back/Quit"))
7018
+ ), /* @__PURE__ */ React38.createElement(
7019
+ Box28,
6060
7020
  {
6061
7021
  flexDirection: "column",
6062
7022
  flexGrow: 1,
@@ -6065,21 +7025,21 @@ var UtilsApp = ({ onExit }) => {
6065
7025
  paddingX: 2,
6066
7026
  paddingY: 1
6067
7027
  },
6068
- activeView ? /* @__PURE__ */ React30.createElement(ActiveUtilityView, { utilityType: activeView }) : /* @__PURE__ */ React30.createElement(WelcomeView, { selectedItem: MENU_ITEMS2[selectedIndex] })
6069
- )), /* @__PURE__ */ React30.createElement(
6070
- Box20,
7028
+ activeView ? /* @__PURE__ */ React38.createElement(ActiveUtilityView, { utilityType: activeView }) : /* @__PURE__ */ React38.createElement(WelcomeView, { selectedItem: MENU_ITEMS2[selectedIndex] })
7029
+ )), /* @__PURE__ */ React38.createElement(
7030
+ Box28,
6071
7031
  {
6072
7032
  borderStyle: "single",
6073
7033
  borderColor: "gray",
6074
7034
  paddingX: 2,
6075
7035
  marginTop: 1
6076
7036
  },
6077
- /* @__PURE__ */ React30.createElement(Text21, { dimColor: true }, "jai1-cli | Use arrow keys or j/k to navigate")
7037
+ /* @__PURE__ */ React38.createElement(Text29, { dimColor: true }, "jai1-cli | Use arrow keys or j/k to navigate")
6078
7038
  ));
6079
7039
  };
6080
7040
  var WelcomeView = ({ selectedItem }) => {
6081
- return /* @__PURE__ */ React30.createElement(Box20, { flexDirection: "column" }, /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React30.createElement(Text21, { bold: true, color: "cyan" }, "Welcome to Developer Utilities")), /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 2 }, /* @__PURE__ */ React30.createElement(Text21, null, "Select a utility from the left menu to get started.")), /* @__PURE__ */ React30.createElement(
6082
- Box20,
7041
+ return /* @__PURE__ */ React38.createElement(Box28, { flexDirection: "column" }, /* @__PURE__ */ React38.createElement(Box28, { marginBottom: 1 }, /* @__PURE__ */ React38.createElement(Text29, { bold: true, color: "cyan" }, "Welcome to Developer Utilities")), /* @__PURE__ */ React38.createElement(Box28, { marginBottom: 2 }, /* @__PURE__ */ React38.createElement(Text29, null, "Select a utility from the left menu to get started.")), /* @__PURE__ */ React38.createElement(
7042
+ Box28,
6083
7043
  {
6084
7044
  borderStyle: "single",
6085
7045
  borderColor: "yellow",
@@ -6087,40 +7047,57 @@ var WelcomeView = ({ selectedItem }) => {
6087
7047
  paddingY: 1,
6088
7048
  marginBottom: 2
6089
7049
  },
6090
- /* @__PURE__ */ React30.createElement(Box20, { flexDirection: "column" }, /* @__PURE__ */ React30.createElement(Text21, { bold: true, color: "yellow" }, selectedItem.icon, " ", selectedItem.label), /* @__PURE__ */ React30.createElement(Text21, { dimColor: true }, selectedItem.description))
6091
- ), /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React30.createElement(Text21, { bold: true }, "Quick Actions:")), /* @__PURE__ */ React30.createElement(Box20, { flexDirection: "column", marginLeft: 2 }, /* @__PURE__ */ React30.createElement(Text21, null, "\u2022 Press ", /* @__PURE__ */ React30.createElement(Text21, { color: "green" }, "Enter"), " to open selected utility"), /* @__PURE__ */ React30.createElement(Text21, null, "\u2022 Use ", /* @__PURE__ */ React30.createElement(Text21, { color: "green" }, "\u2191/\u2193"), " or ", /* @__PURE__ */ React30.createElement(Text21, { color: "green" }, "j/k"), " to navigate"), /* @__PURE__ */ React30.createElement(Text21, null, "\u2022 Press ", /* @__PURE__ */ React30.createElement(Text21, { color: "green" }, "Esc"), " to go back or quit"), /* @__PURE__ */ React30.createElement(Text21, null, "\u2022 Press ", /* @__PURE__ */ React30.createElement(Text21, { color: "green" }, "q"), " to quit anytime")), /* @__PURE__ */ React30.createElement(Box20, { marginTop: 2 }, /* @__PURE__ */ React30.createElement(Text21, { dimColor: true }, "\u{1F4A1} Tip: Each utility provides an interactive interface for easy usage.")));
7050
+ /* @__PURE__ */ React38.createElement(Box28, { flexDirection: "column" }, /* @__PURE__ */ React38.createElement(Text29, { bold: true, color: "yellow" }, selectedItem.icon, " ", selectedItem.label), /* @__PURE__ */ React38.createElement(Text29, { dimColor: true }, selectedItem.description))
7051
+ ), /* @__PURE__ */ React38.createElement(Box28, { marginBottom: 1 }, /* @__PURE__ */ React38.createElement(Text29, { bold: true }, "Quick Actions:")), /* @__PURE__ */ React38.createElement(Box28, { flexDirection: "column", marginLeft: 2 }, /* @__PURE__ */ React38.createElement(Text29, null, "\u2022 Press ", /* @__PURE__ */ React38.createElement(Text29, { color: "green" }, "Enter"), " to open selected utility"), /* @__PURE__ */ React38.createElement(Text29, null, "\u2022 Use ", /* @__PURE__ */ React38.createElement(Text29, { color: "green" }, "\u2191/\u2193"), " or ", /* @__PURE__ */ React38.createElement(Text29, { color: "green" }, "j/k"), " to navigate"), /* @__PURE__ */ React38.createElement(Text29, null, "\u2022 Press ", /* @__PURE__ */ React38.createElement(Text29, { color: "green" }, "Esc"), " to go back or quit"), /* @__PURE__ */ React38.createElement(Text29, null, "\u2022 Press ", /* @__PURE__ */ React38.createElement(Text29, { color: "green" }, "q"), " to quit anytime")), /* @__PURE__ */ React38.createElement(Box28, { marginTop: 2 }, /* @__PURE__ */ React38.createElement(Text29, { dimColor: true }, "\u{1F4A1} Tip: Each utility provides an interactive interface for easy usage.")));
6092
7052
  };
6093
7053
  var ActiveUtilityView = ({ utilityType }) => {
6094
7054
  switch (utilityType) {
6095
7055
  case "password":
6096
- return /* @__PURE__ */ React30.createElement(PasswordView, null);
7056
+ return /* @__PURE__ */ React38.createElement(PasswordView, null);
6097
7057
  case "uuid":
6098
- return /* @__PURE__ */ React30.createElement(UuidView, null);
7058
+ return /* @__PURE__ */ React38.createElement(UuidView, null);
6099
7059
  case "hash":
6100
- return /* @__PURE__ */ React30.createElement(HashView, null);
6101
- // Add more views as they are created
7060
+ return /* @__PURE__ */ React38.createElement(HashView, null);
7061
+ case "base64-encode":
7062
+ case "base64-decode":
7063
+ return /* @__PURE__ */ React38.createElement(Base64View, null);
7064
+ case "url-encode":
7065
+ case "url-decode":
7066
+ return /* @__PURE__ */ React38.createElement(UrlView, null);
7067
+ case "unix-time":
7068
+ return /* @__PURE__ */ React38.createElement(UnixTimeView, null);
7069
+ case "jwt":
7070
+ return /* @__PURE__ */ React38.createElement(JwtView, null);
7071
+ case "cron":
7072
+ return /* @__PURE__ */ React38.createElement(CronView, null);
7073
+ case "timezone":
7074
+ return /* @__PURE__ */ React38.createElement(TimezoneView, null);
7075
+ case "http":
7076
+ return /* @__PURE__ */ React38.createElement(HttpView, null);
7077
+ case "markdown":
7078
+ return /* @__PURE__ */ React38.createElement(MarkdownView, null);
6102
7079
  default:
6103
- return /* @__PURE__ */ React30.createElement(PlaceholderView, { utilityType });
7080
+ return /* @__PURE__ */ React38.createElement(PlaceholderView, { utilityType });
6104
7081
  }
6105
7082
  };
6106
7083
  var PlaceholderView = ({ utilityType }) => {
6107
7084
  const item = MENU_ITEMS2.find((m) => m.id === utilityType);
6108
- return /* @__PURE__ */ React30.createElement(Box20, { flexDirection: "column" }, /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React30.createElement(Text21, { bold: true, color: "cyan" }, item?.icon, " ", item?.label)), /* @__PURE__ */ React30.createElement(Box20, { borderStyle: "single", borderColor: "yellow", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React30.createElement(Text21, null, "\u{1F6A7} This utility view is under construction.", "\n", "\n", "For now, use the command-line version:", "\n", /* @__PURE__ */ React30.createElement(Text21, { color: "green" }, "$ jai1 utils ", utilityType, " --help"), "\n", "\n", "Press ", /* @__PURE__ */ React30.createElement(Text21, { color: "yellow" }, "Esc"), " to return to the menu.")));
7085
+ return /* @__PURE__ */ React38.createElement(Box28, { flexDirection: "column" }, /* @__PURE__ */ React38.createElement(Box28, { marginBottom: 1 }, /* @__PURE__ */ React38.createElement(Text29, { bold: true, color: "cyan" }, item?.icon, " ", item?.label)), /* @__PURE__ */ React38.createElement(Box28, { borderStyle: "single", borderColor: "yellow", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React38.createElement(Text29, null, "\u{1F6A7} This utility view is under construction.", "\n", "\n", "For now, use the command-line version:", "\n", /* @__PURE__ */ React38.createElement(Text29, { color: "green" }, "$ jai1 utils ", utilityType, " --help"), "\n", "\n", "Press ", /* @__PURE__ */ React38.createElement(Text29, { color: "yellow" }, "Esc"), " to return to the menu.")));
6109
7086
  };
6110
7087
 
6111
7088
  // src/commands/utils/interactive.ts
6112
7089
  async function runInteractiveMode() {
6113
- return new Promise((resolve3) => {
7090
+ return new Promise((resolve4) => {
6114
7091
  const { unmount, waitUntilExit } = render5(
6115
- React31.createElement(UtilsApp, {
7092
+ React39.createElement(UtilsApp, {
6116
7093
  onExit: () => {
6117
7094
  unmount();
6118
- resolve3();
7095
+ resolve4();
6119
7096
  }
6120
7097
  })
6121
7098
  );
6122
7099
  waitUntilExit().then(() => {
6123
- resolve3();
7100
+ resolve4();
6124
7101
  });
6125
7102
  });
6126
7103
  }
@@ -6443,7 +7420,7 @@ import { Command as Command30 } from "commander";
6443
7420
 
6444
7421
  // src/services/redmine-config.service.ts
6445
7422
  import { readFile as readFile6 } from "fs/promises";
6446
- import { resolve } from "path";
7423
+ import { resolve as resolve2 } from "path";
6447
7424
 
6448
7425
  // src/types/redmine.types.ts
6449
7426
  import { z } from "zod";
@@ -6494,7 +7471,7 @@ import { z as z2 } from "zod";
6494
7471
  var RedmineConfigService = class {
6495
7472
  configPath;
6496
7473
  constructor(configPath) {
6497
- this.configPath = configPath ?? resolve(process.cwd(), "redmine.config.yaml");
7474
+ this.configPath = configPath ?? resolve2(process.cwd(), "redmine.config.yaml");
6498
7475
  }
6499
7476
  /**
6500
7477
  * Load Redmine configuration from YAML file
@@ -6560,8 +7537,8 @@ var RedmineApiClient = class {
6560
7537
  this.retryConfig = config.defaults.retry;
6561
7538
  this.concurrencyLimit = pLimit2(config.defaults.concurrency);
6562
7539
  }
6563
- async request(path6, options = {}) {
6564
- const url = `${this.baseUrl}${path6}`;
7540
+ async request(path7, options = {}) {
7541
+ const url = `${this.baseUrl}${path7}`;
6565
7542
  const headers = {
6566
7543
  "X-Redmine-API-Key": this.apiAccessToken,
6567
7544
  "Content-Type": "application/json",
@@ -6622,8 +7599,8 @@ var RedmineApiClient = class {
6622
7599
  if (include && include.length > 0) {
6623
7600
  params.append("include", include.join(","));
6624
7601
  }
6625
- const path6 = `/issues/${issueId}.json${params.toString() ? `?${params.toString()}` : ""}`;
6626
- return this.request(path6);
7602
+ const path7 = `/issues/${issueId}.json${params.toString() ? `?${params.toString()}` : ""}`;
7603
+ return this.request(path7);
6627
7604
  }
6628
7605
  async getIssues(projectId, options = {}) {
6629
7606
  const params = new URLSearchParams();
@@ -6643,8 +7620,8 @@ var RedmineApiClient = class {
6643
7620
  if (options.updatedSince) {
6644
7621
  params.append("updated_on", `>=${options.updatedSince}`);
6645
7622
  }
6646
- const path6 = `/issues.json?${params.toString()}`;
6647
- return this.request(path6);
7623
+ const path7 = `/issues.json?${params.toString()}`;
7624
+ return this.request(path7);
6648
7625
  }
6649
7626
  async getAllIssues(projectId, options = {}) {
6650
7627
  const pageSize = options.pageSize || 100;
@@ -6777,7 +7754,7 @@ async function handleRedmineCheck(options) {
6777
7754
  import { Command as Command31 } from "commander";
6778
7755
 
6779
7756
  // src/sync-issue.ts
6780
- import { resolve as resolve2, relative } from "path";
7757
+ import { resolve as resolve3, relative } from "path";
6781
7758
 
6782
7759
  // src/mappers.ts
6783
7760
  function mapIssueToFrontmatter(issue) {
@@ -7037,7 +8014,7 @@ async function syncIssue(issueId, config, options = {}) {
7037
8014
  const response = await client.getIssue(issueId, include);
7038
8015
  const issue = response.issue;
7039
8016
  const filename = generateFilename(issue.id, issue.subject, config.filename);
7040
- const filePath = resolve2(outputDir, filename);
8017
+ const filePath = resolve3(outputDir, filename);
7041
8018
  const relativePath = relative(process.cwd(), filePath);
7042
8019
  const existingFile = await readMarkdownFile(filePath);
7043
8020
  const existingIssueId = extractIssueIdFromFrontmatter(existingFile.frontmatter);
@@ -7320,7 +8297,7 @@ async function handleSyncProject(options) {
7320
8297
 
7321
8298
  // src/commands/framework/info.ts
7322
8299
  import { Command as Command33 } from "commander";
7323
- import { promises as fs8 } from "fs";
8300
+ import { promises as fs9 } from "fs";
7324
8301
  import { join as join5 } from "path";
7325
8302
  import { homedir as homedir5 } from "os";
7326
8303
  function createInfoCommand() {
@@ -7372,7 +8349,7 @@ function maskKey3(key) {
7372
8349
  async function getProjectStatus2() {
7373
8350
  const projectJai1 = join5(process.cwd(), ".jai1");
7374
8351
  try {
7375
- await fs8.access(projectJai1);
8352
+ await fs9.access(projectJai1);
7376
8353
  return { exists: true, version: "Synced" };
7377
8354
  } catch {
7378
8355
  return { exists: false };
@@ -7562,9 +8539,9 @@ function createClearBackupsCommand() {
7562
8539
  // src/commands/vscode/index.ts
7563
8540
  import { Command as Command36 } from "commander";
7564
8541
  import { checkbox as checkbox3, confirm as confirm8, select as select3 } from "@inquirer/prompts";
7565
- import fs9 from "fs/promises";
7566
- import path5 from "path";
7567
- import { existsSync as existsSync2 } from "fs";
8542
+ import fs10 from "fs/promises";
8543
+ import path6 from "path";
8544
+ import { existsSync as existsSync3 } from "fs";
7568
8545
  var PERFORMANCE_GROUPS2 = {
7569
8546
  telemetry: {
7570
8547
  name: "Telemetry",
@@ -7783,8 +8760,8 @@ async function selectGroupsToApply2(action) {
7783
8760
  }
7784
8761
  }
7785
8762
  async function applyGroups2(groupKeys, action) {
7786
- const vscodeDir = path5.join(process.cwd(), ".vscode");
7787
- const settingsPath = path5.join(vscodeDir, "settings.json");
8763
+ const vscodeDir = path6.join(process.cwd(), ".vscode");
8764
+ const settingsPath = path6.join(vscodeDir, "settings.json");
7788
8765
  const invalidGroups = groupKeys.filter((key) => !PERFORMANCE_GROUPS2[key]);
7789
8766
  if (invalidGroups.length > 0) {
7790
8767
  console.log(`
@@ -7792,14 +8769,14 @@ async function applyGroups2(groupKeys, action) {
7792
8769
  console.log(' \u{1F4A1} Ch\u1EA1y "jai1 vscode list" \u0111\u1EC3 xem danh s\xE1ch nh\xF3m c\xF3 s\u1EB5n.');
7793
8770
  return;
7794
8771
  }
7795
- if (!existsSync2(vscodeDir)) {
7796
- await fs9.mkdir(vscodeDir, { recursive: true });
8772
+ if (!existsSync3(vscodeDir)) {
8773
+ await fs10.mkdir(vscodeDir, { recursive: true });
7797
8774
  console.log("\u{1F4C1} \u0110\xE3 t\u1EA1o th\u01B0 m\u1EE5c .vscode/");
7798
8775
  }
7799
8776
  let currentSettings = {};
7800
- if (existsSync2(settingsPath)) {
8777
+ if (existsSync3(settingsPath)) {
7801
8778
  try {
7802
- const content = await fs9.readFile(settingsPath, "utf-8");
8779
+ const content = await fs10.readFile(settingsPath, "utf-8");
7803
8780
  currentSettings = JSON.parse(content);
7804
8781
  console.log("\u{1F4C4} \u0110\xE3 \u0111\u1ECDc c\xE0i \u0111\u1EB7t hi\u1EC7n t\u1EA1i t\u1EEB settings.json");
7805
8782
  } catch {
@@ -7839,15 +8816,15 @@ async function applyGroups2(groupKeys, action) {
7839
8816
  }
7840
8817
  }
7841
8818
  }
7842
- await fs9.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
8819
+ await fs10.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
7843
8820
  console.log(`
7844
8821
  \u2705 \u0110\xE3 c\u1EADp nh\u1EADt c\xE0i \u0111\u1EB7t VSCode t\u1EA1i: ${settingsPath}`);
7845
8822
  console.log("\u{1F4A1} M\u1EB9o: Kh\u1EDFi \u0111\u1ED9ng l\u1EA1i VSCode \u0111\u1EC3 \xE1p d\u1EE5ng c\xE1c thay \u0111\u1ED5i.");
7846
8823
  }
7847
8824
  async function resetSettings2(groupKeys) {
7848
- const vscodeDir = path5.join(process.cwd(), ".vscode");
7849
- const settingsPath = path5.join(vscodeDir, "settings.json");
7850
- if (!existsSync2(settingsPath)) {
8825
+ const vscodeDir = path6.join(process.cwd(), ".vscode");
8826
+ const settingsPath = path6.join(vscodeDir, "settings.json");
8827
+ if (!existsSync3(settingsPath)) {
7851
8828
  console.log("\n\u26A0\uFE0F Kh\xF4ng t\xECm th\u1EA5y file settings.json");
7852
8829
  return;
7853
8830
  }
@@ -7860,7 +8837,7 @@ async function resetSettings2(groupKeys) {
7860
8837
  return;
7861
8838
  }
7862
8839
  if (groupKeys.length === 0) {
7863
- await fs9.unlink(settingsPath);
8840
+ await fs10.unlink(settingsPath);
7864
8841
  console.log("\n\u2705 \u0110\xE3 x\xF3a file settings.json");
7865
8842
  } else {
7866
8843
  await applyGroups2(groupKeys, "disable");
@@ -7869,13 +8846,13 @@ async function resetSettings2(groupKeys) {
7869
8846
  }
7870
8847
 
7871
8848
  // src/commands/guide.ts
7872
- import React32 from "react";
8849
+ import React40 from "react";
7873
8850
  import { render as render6 } from "ink";
7874
8851
  import { Command as Command37 } from "commander";
7875
8852
  function createGuideCommand() {
7876
8853
  const cmd = new Command37("guide").description("Interactive guide center for Agentic Coding").option("--topic <topic>", "Open specific topic (intro, rules, workflows, prompts, skills)").action(async (options) => {
7877
8854
  const { waitUntilExit } = render6(
7878
- React32.createElement(GuideApp, {
8855
+ React40.createElement(GuideApp, {
7879
8856
  initialTopic: options.topic,
7880
8857
  onExit: () => {
7881
8858
  process.exit(0);
@@ -7888,7 +8865,7 @@ function createGuideCommand() {
7888
8865
  }
7889
8866
 
7890
8867
  // src/commands/context.ts
7891
- import React33 from "react";
8868
+ import React41 from "react";
7892
8869
  import { render as render7 } from "ink";
7893
8870
  import { Command as Command38 } from "commander";
7894
8871
  function createContextCommand() {
@@ -7918,7 +8895,7 @@ function createContextCommand() {
7918
8895
  return;
7919
8896
  }
7920
8897
  const { waitUntilExit } = render7(
7921
- React33.createElement(ContextApp, {
8898
+ React41.createElement(ContextApp, {
7922
8899
  initialIDE,
7923
8900
  initialType,
7924
8901
  onExit: () => {