@jvittechs/jai1-cli 0.1.59 → 0.1.61

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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { Command as Command26 } from "commander";
4
+ import { Command as Command40 } from "commander";
5
5
 
6
6
  // src/errors/index.ts
7
7
  var Jai1Error = class extends Error {
@@ -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.59",
36
+ version: "0.1.61",
37
37
  description: "Unified CLI for Jai1 Framework Management and Redmine Context Sync",
38
38
  type: "module",
39
39
  bin: {
@@ -80,13 +80,17 @@ var package_default = {
80
80
  dependencies: {
81
81
  "@inquirer/prompts": "^8.0.2",
82
82
  "adm-zip": "^0.5.16",
83
+ bcryptjs: "^2.4.3",
83
84
  "cli-progress": "^3.12.0",
84
85
  clipboardy: "^4.0.0",
85
86
  commander: "^12.1.0",
87
+ cronstrue: "^2.50.0",
86
88
  "gray-matter": "^4.0.3",
87
89
  ink: "^5.0.1",
88
90
  "ink-spinner": "^5.0.0",
89
91
  "ink-text-input": "^6.0.0",
92
+ marked: "^12.0.0",
93
+ "marked-terminal": "^7.0.0",
90
94
  "p-limit": "^5.0.0",
91
95
  "p-queue": "^7.4.1",
92
96
  "p-retry": "^6.2.0",
@@ -191,8 +195,13 @@ var colors = {
191
195
  };
192
196
  var lastCheckTime = 0;
193
197
  var cachedLatestVersion = null;
198
+ var shouldCheckUpdates = true;
194
199
  var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
200
+ function disableUpdateCheck() {
201
+ shouldCheckUpdates = false;
202
+ }
195
203
  async function checkForClientUpdate() {
204
+ if (!shouldCheckUpdates) return;
196
205
  try {
197
206
  const now = Date.now();
198
207
  if (now - lastCheckTime < CHECK_INTERVAL_MS && cachedLatestVersion) {
@@ -4785,8 +4794,850 @@ function createTranslateCommand() {
4785
4794
  return cmd;
4786
4795
  }
4787
4796
 
4788
- // src/commands/upgrade.ts
4797
+ // src/commands/utils/index.ts
4798
+ import { Command as Command27 } from "commander";
4799
+
4800
+ // src/commands/utils/password.ts
4789
4801
  import { Command as Command14 } from "commander";
4802
+
4803
+ // src/services/utils.service.ts
4804
+ import crypto from "crypto";
4805
+ import bcrypt from "bcryptjs";
4806
+ import { readFile } from "fs/promises";
4807
+ var UtilsService = class {
4808
+ /**
4809
+ * Generate secure random password
4810
+ */
4811
+ generatePassword(options) {
4812
+ const {
4813
+ length,
4814
+ lowercase,
4815
+ uppercase,
4816
+ digits,
4817
+ symbols,
4818
+ symbolChars = "!@#$%^&*()_+-=[]{}|;:,.<>?"
4819
+ } = options;
4820
+ let charset = "";
4821
+ if (lowercase) charset += "abcdefghijklmnopqrstuvwxyz";
4822
+ if (uppercase) charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
4823
+ if (digits) charset += "0123456789";
4824
+ if (symbols) charset += symbolChars;
4825
+ if (charset.length === 0) {
4826
+ throw new Error("At least one character type must be enabled");
4827
+ }
4828
+ const randomBytes = crypto.randomBytes(length);
4829
+ let password = "";
4830
+ for (let i = 0; i < length; i++) {
4831
+ const randomIndex = randomBytes[i] % charset.length;
4832
+ password += charset[randomIndex];
4833
+ }
4834
+ return password;
4835
+ }
4836
+ /**
4837
+ * Generate UUID v4
4838
+ */
4839
+ generateUuid(options) {
4840
+ let uuid = crypto.randomUUID();
4841
+ if (options?.uppercase) {
4842
+ uuid = uuid.toUpperCase();
4843
+ }
4844
+ if (options?.noHyphens) {
4845
+ uuid = uuid.replace(/-/g, "");
4846
+ }
4847
+ return uuid;
4848
+ }
4849
+ /**
4850
+ * Hash text or file using specified algorithm
4851
+ */
4852
+ async hash(input, algorithm) {
4853
+ if (algorithm === "bcrypt") {
4854
+ throw new Error("Use hashBcrypt for bcrypt algorithm");
4855
+ }
4856
+ const hash = crypto.createHash(algorithm);
4857
+ hash.update(input);
4858
+ return hash.digest("hex");
4859
+ }
4860
+ /**
4861
+ * Hash file contents
4862
+ */
4863
+ async hashFile(filePath, algorithm) {
4864
+ const content = await readFile(filePath);
4865
+ return this.hash(content, algorithm);
4866
+ }
4867
+ /**
4868
+ * Hash using bcrypt
4869
+ */
4870
+ async hashBcrypt(input, rounds = 10) {
4871
+ return bcrypt.hash(input, rounds);
4872
+ }
4873
+ /**
4874
+ * Base64 encode
4875
+ */
4876
+ base64Encode(input, urlSafe = false) {
4877
+ const buffer = typeof input === "string" ? Buffer.from(input, "utf-8") : input;
4878
+ let encoded = buffer.toString("base64");
4879
+ if (urlSafe) {
4880
+ encoded = encoded.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
4881
+ }
4882
+ return encoded;
4883
+ }
4884
+ /**
4885
+ * Base64 decode
4886
+ */
4887
+ base64Decode(input) {
4888
+ let normalized = input.replace(/-/g, "+").replace(/_/g, "/");
4889
+ while (normalized.length % 4) {
4890
+ normalized += "=";
4891
+ }
4892
+ return Buffer.from(normalized, "base64");
4893
+ }
4894
+ /**
4895
+ * Make HTTP request with detailed output
4896
+ */
4897
+ async httpRequest(url, options) {
4898
+ const startTime = performance.now();
4899
+ const fetchOptions = {
4900
+ method: options.method,
4901
+ headers: options.headers,
4902
+ body: options.body,
4903
+ signal: options.timeout ? AbortSignal.timeout(options.timeout) : void 0,
4904
+ redirect: options.followRedirects === false ? "manual" : "follow"
4905
+ };
4906
+ const response = await fetch(url, fetchOptions);
4907
+ const body = await response.text();
4908
+ const endTime = performance.now();
4909
+ const headers = {};
4910
+ response.headers.forEach((value, key) => {
4911
+ headers[key] = value;
4912
+ });
4913
+ return {
4914
+ status: response.status,
4915
+ statusText: response.statusText,
4916
+ headers,
4917
+ body,
4918
+ timing: Math.round(endTime - startTime),
4919
+ size: Buffer.byteLength(body, "utf-8")
4920
+ };
4921
+ }
4922
+ /**
4923
+ * Decode JWT (no verification)
4924
+ */
4925
+ jwtDecode(token) {
4926
+ const parts = token.split(".");
4927
+ if (parts.length !== 3) {
4928
+ throw new Error("Invalid JWT format");
4929
+ }
4930
+ const [headerB64, payloadB64, signature] = parts;
4931
+ const header = JSON.parse(this.base64Decode(headerB64).toString("utf-8"));
4932
+ const payload = JSON.parse(this.base64Decode(payloadB64).toString("utf-8"));
4933
+ return { header, payload, signature };
4934
+ }
4935
+ /**
4936
+ * Encode JWT (HS256 only)
4937
+ */
4938
+ jwtEncode(payload, secret, header) {
4939
+ const defaultHeader = { alg: "HS256", typ: "JWT" };
4940
+ const finalHeader = { ...defaultHeader, ...header };
4941
+ const headerB64 = this.base64Encode(JSON.stringify(finalHeader), true);
4942
+ const payloadB64 = this.base64Encode(JSON.stringify(payload), true);
4943
+ const signatureInput = `${headerB64}.${payloadB64}`;
4944
+ const signature = crypto.createHmac("sha256", secret).update(signatureInput).digest("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
4945
+ return `${headerB64}.${payloadB64}.${signature}`;
4946
+ }
4947
+ /**
4948
+ * Convert unix timestamp to date
4949
+ */
4950
+ unixToDate(timestamp, milliseconds = false) {
4951
+ return new Date(milliseconds ? timestamp : timestamp * 1e3);
4952
+ }
4953
+ /**
4954
+ * Convert date to unix timestamp
4955
+ */
4956
+ dateToUnix(date, milliseconds = false) {
4957
+ const timestamp = date.getTime();
4958
+ return milliseconds ? timestamp : Math.floor(timestamp / 1e3);
4959
+ }
4960
+ /**
4961
+ * Convert time between timezones
4962
+ */
4963
+ convertTimezone(time, fromTimezone, toTimezone) {
4964
+ const date = typeof time === "string" ? new Date(time) : time;
4965
+ const formatter = new Intl.DateTimeFormat("en-US", {
4966
+ timeZone: toTimezone,
4967
+ year: "numeric",
4968
+ month: "2-digit",
4969
+ day: "2-digit",
4970
+ hour: "2-digit",
4971
+ minute: "2-digit",
4972
+ second: "2-digit",
4973
+ hour12: false
4974
+ });
4975
+ const parts = formatter.formatToParts(date);
4976
+ const dateParts = parts.reduce((acc, part) => {
4977
+ if (part.type !== "literal") {
4978
+ acc[part.type] = part.value;
4979
+ }
4980
+ return acc;
4981
+ }, {});
4982
+ const time24 = `${dateParts.year}-${dateParts.month}-${dateParts.day} ${dateParts.hour}:${dateParts.minute}:${dateParts.second}`;
4983
+ return {
4984
+ time: time24,
4985
+ iso: date.toISOString()
4986
+ };
4987
+ }
4988
+ /**
4989
+ * Get list of available timezones
4990
+ */
4991
+ getTimezones() {
4992
+ return [
4993
+ "UTC",
4994
+ "America/New_York",
4995
+ "America/Chicago",
4996
+ "America/Denver",
4997
+ "America/Los_Angeles",
4998
+ "America/Sao_Paulo",
4999
+ "Europe/London",
5000
+ "Europe/Paris",
5001
+ "Europe/Berlin",
5002
+ "Europe/Moscow",
5003
+ "Asia/Dubai",
5004
+ "Asia/Kolkata",
5005
+ "Asia/Bangkok",
5006
+ "Asia/Shanghai",
5007
+ "Asia/Tokyo",
5008
+ "Asia/Seoul",
5009
+ "Asia/Ho_Chi_Minh",
5010
+ "Australia/Sydney",
5011
+ "Pacific/Auckland"
5012
+ ];
5013
+ }
5014
+ /**
5015
+ * URL encode
5016
+ */
5017
+ urlEncode(input, full = false) {
5018
+ return full ? encodeURI(input) : encodeURIComponent(input);
5019
+ }
5020
+ /**
5021
+ * URL decode
5022
+ */
5023
+ urlDecode(input, full = false) {
5024
+ return full ? decodeURI(input) : decodeURIComponent(input);
5025
+ }
5026
+ /**
5027
+ * Format bytes to human-readable size
5028
+ */
5029
+ formatBytes(bytes) {
5030
+ if (bytes === 0) return "0 B";
5031
+ const k = 1024;
5032
+ const sizes = ["B", "KB", "MB", "GB"];
5033
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
5034
+ return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`;
5035
+ }
5036
+ };
5037
+
5038
+ // src/commands/utils/password.ts
5039
+ async function handlePasswordGeneration(options) {
5040
+ const service = new UtilsService();
5041
+ try {
5042
+ const passwords = [];
5043
+ for (let i = 0; i < options.count; i++) {
5044
+ const password = service.generatePassword({
5045
+ length: options.length,
5046
+ lowercase: options.lowercase,
5047
+ uppercase: options.uppercase,
5048
+ digits: options.digits,
5049
+ symbols: options.symbols,
5050
+ symbolChars: options.symbolChars
5051
+ });
5052
+ passwords.push(password);
5053
+ }
5054
+ console.log("\u{1F510} Generated Password(s):");
5055
+ console.log("\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\n");
5056
+ passwords.forEach((password, index) => {
5057
+ if (options.count > 1) {
5058
+ console.log(` ${index + 1}. ${password}`);
5059
+ } else {
5060
+ console.log(` ${password}`);
5061
+ }
5062
+ });
5063
+ console.log();
5064
+ } catch (error) {
5065
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5066
+ process.exit(1);
5067
+ }
5068
+ }
5069
+ function createPasswordCommand() {
5070
+ const cmd = new Command14("password").description("Generate secure random password").option("-l, --length <number>", "Password length", "16").option("--no-lowercase", "Exclude lowercase letters").option("--no-uppercase", "Exclude uppercase letters").option("--no-digits", "Exclude digits").option("--no-symbols", "Exclude symbols").option("--symbol-chars <chars>", "Custom symbol characters").option("-c, --count <number>", "Number of passwords to generate", "1").action(async (options) => {
5071
+ await handlePasswordGeneration({
5072
+ ...options,
5073
+ length: parseInt(options.length, 10),
5074
+ count: parseInt(options.count, 10)
5075
+ });
5076
+ });
5077
+ return cmd;
5078
+ }
5079
+
5080
+ // src/commands/utils/uuid.ts
5081
+ import { Command as Command15 } from "commander";
5082
+ async function handleUuidGeneration(options) {
5083
+ const service = new UtilsService();
5084
+ try {
5085
+ const uuids = [];
5086
+ for (let i = 0; i < options.count; i++) {
5087
+ const uuid = service.generateUuid({
5088
+ uppercase: options.uppercase,
5089
+ noHyphens: options.noHyphens
5090
+ });
5091
+ uuids.push(uuid);
5092
+ }
5093
+ console.log("\u{1F194} Generated UUID(s):");
5094
+ console.log("\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\n");
5095
+ uuids.forEach((uuid, index) => {
5096
+ if (options.count > 1) {
5097
+ console.log(` ${index + 1}. ${uuid}`);
5098
+ } else {
5099
+ console.log(` ${uuid}`);
5100
+ }
5101
+ });
5102
+ console.log();
5103
+ } catch (error) {
5104
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5105
+ process.exit(1);
5106
+ }
5107
+ }
5108
+ function createUuidCommand() {
5109
+ const cmd = new Command15("uuid").description("Generate UUID v4 identifier").option("-c, --count <number>", "Number of UUIDs to generate", "1").option("--uppercase", "Output in uppercase").option("--no-hyphens", "Remove hyphens from output").action(async (options) => {
5110
+ await handleUuidGeneration({
5111
+ ...options,
5112
+ count: parseInt(options.count, 10)
5113
+ });
5114
+ });
5115
+ return cmd;
5116
+ }
5117
+
5118
+ // src/commands/utils/hash.ts
5119
+ import { Command as Command16 } from "commander";
5120
+ async function handleHashGeneration(input, options) {
5121
+ const service = new UtilsService();
5122
+ try {
5123
+ let hash;
5124
+ if (options.file) {
5125
+ if (options.algorithm === "bcrypt") {
5126
+ console.error("\u274C bcrypt cannot be used with files (it requires string input)");
5127
+ process.exit(1);
5128
+ }
5129
+ hash = await service.hashFile(options.file, options.algorithm);
5130
+ } else {
5131
+ if (!input) {
5132
+ console.error("\u274C Please provide input text or use --file option");
5133
+ process.exit(1);
5134
+ }
5135
+ if (options.algorithm === "bcrypt") {
5136
+ hash = await service.hashBcrypt(input, options.rounds);
5137
+ } else {
5138
+ hash = await service.hash(input, options.algorithm);
5139
+ }
5140
+ }
5141
+ console.log("\u{1F512} Hash Result:");
5142
+ console.log("\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");
5143
+ console.log(` Algorithm: ${options.algorithm.toUpperCase()}`);
5144
+ if (options.file) {
5145
+ console.log(` File: ${options.file}`);
5146
+ }
5147
+ if (options.algorithm === "bcrypt") {
5148
+ console.log(` Rounds: ${options.rounds}`);
5149
+ }
5150
+ console.log();
5151
+ console.log(` ${hash}`);
5152
+ console.log();
5153
+ } catch (error) {
5154
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5155
+ process.exit(1);
5156
+ }
5157
+ }
5158
+ function createHashCommand() {
5159
+ const cmd = new Command16("hash").description("Generate hash (MD5, SHA, bcrypt)").argument("[input]", "Text to hash").option(
5160
+ "-a, --algorithm <algorithm>",
5161
+ "Hash algorithm (md5, sha1, sha256, sha512, bcrypt)",
5162
+ "sha256"
5163
+ ).option("-f, --file <path>", "Hash file contents instead of text").option("-r, --rounds <number>", "Bcrypt rounds (only for bcrypt)", "10").action(async (input, options) => {
5164
+ await handleHashGeneration(input, {
5165
+ ...options,
5166
+ rounds: parseInt(options.rounds, 10)
5167
+ });
5168
+ });
5169
+ return cmd;
5170
+ }
5171
+
5172
+ // src/commands/utils/base64-encode.ts
5173
+ import { Command as Command17 } from "commander";
5174
+ import { readFile as readFile2 } from "fs/promises";
5175
+ async function handleBase64Encode(input, options) {
5176
+ const service = new UtilsService();
5177
+ try {
5178
+ let encoded;
5179
+ if (options.file) {
5180
+ const content = await readFile2(options.file);
5181
+ encoded = service.base64Encode(content, options.urlSafe);
5182
+ } else {
5183
+ if (!input) {
5184
+ console.error("\u274C Please provide input text or use --file option");
5185
+ process.exit(1);
5186
+ }
5187
+ encoded = service.base64Encode(input, options.urlSafe);
5188
+ }
5189
+ console.log("\u{1F4DD} Base64 Encoded:");
5190
+ console.log("\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");
5191
+ if (options.file) {
5192
+ console.log(` File: ${options.file}`);
5193
+ }
5194
+ if (options.urlSafe) {
5195
+ console.log(` Format: URL-safe`);
5196
+ }
5197
+ console.log();
5198
+ console.log(` ${encoded}`);
5199
+ console.log();
5200
+ } catch (error) {
5201
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5202
+ process.exit(1);
5203
+ }
5204
+ }
5205
+ function createBase64EncodeCommand() {
5206
+ const cmd = new Command17("base64-encode").description("Encode text or file to Base64").argument("[input]", "Text to encode").option("-f, --file <path>", "Encode file contents").option("--url-safe", "Use URL-safe Base64 encoding").action(async (input, options) => {
5207
+ await handleBase64Encode(input, options);
5208
+ });
5209
+ return cmd;
5210
+ }
5211
+
5212
+ // src/commands/utils/base64-decode.ts
5213
+ import { Command as Command18 } from "commander";
5214
+ import { readFile as readFile3, writeFile } from "fs/promises";
5215
+ async function handleBase64Decode(input, options) {
5216
+ const service = new UtilsService();
5217
+ try {
5218
+ let encodedInput;
5219
+ if (options.file) {
5220
+ encodedInput = await readFile3(options.file, "utf-8");
5221
+ } else {
5222
+ if (!input) {
5223
+ console.error("\u274C Please provide Base64 input or use --file option");
5224
+ process.exit(1);
5225
+ }
5226
+ encodedInput = input;
5227
+ }
5228
+ const decoded = service.base64Decode(encodedInput.trim());
5229
+ if (options.output) {
5230
+ await writeFile(options.output, decoded);
5231
+ console.log("\u2705 Decoded and saved to:", options.output);
5232
+ } else {
5233
+ console.log("\u{1F4DD} Base64 Decoded:");
5234
+ console.log("\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");
5235
+ console.log();
5236
+ console.log(` ${decoded.toString("utf-8")}`);
5237
+ console.log();
5238
+ }
5239
+ } catch (error) {
5240
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5241
+ process.exit(1);
5242
+ }
5243
+ }
5244
+ function createBase64DecodeCommand() {
5245
+ const cmd = new Command18("base64-decode").description("Decode Base64 string").argument("[input]", "Base64 string to decode").option("-f, --file <path>", "Decode from file").option("-o, --output <path>", "Write decoded output to file").action(async (input, options) => {
5246
+ await handleBase64Decode(input, options);
5247
+ });
5248
+ return cmd;
5249
+ }
5250
+
5251
+ // src/commands/utils/http.ts
5252
+ import { Command as Command19 } from "commander";
5253
+ import { readFile as readFile4 } from "fs/promises";
5254
+ async function handleHttpRequest(url, options) {
5255
+ const service = new UtilsService();
5256
+ try {
5257
+ const headers = {};
5258
+ if (options.header) {
5259
+ options.header.forEach((header) => {
5260
+ const [key, ...valueParts] = header.split(":");
5261
+ if (key && valueParts.length > 0) {
5262
+ headers[key.trim()] = valueParts.join(":").trim();
5263
+ }
5264
+ });
5265
+ }
5266
+ let body;
5267
+ if (options.file) {
5268
+ body = await readFile4(options.file, "utf-8");
5269
+ } else if (options.data) {
5270
+ body = options.data;
5271
+ }
5272
+ const response = await service.httpRequest(url, {
5273
+ method: options.method.toUpperCase(),
5274
+ headers,
5275
+ body,
5276
+ timeout: options.timeout,
5277
+ followRedirects: !options.noFollow
5278
+ });
5279
+ if (!options.onlyBody) {
5280
+ console.log(`HTTP/${response.status >= 200 && response.status < 300 ? "1.1" : "1.0"} ${response.status} ${response.statusText}`);
5281
+ console.log("\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");
5282
+ console.log(`\u{1F4CA} Status: ${response.status} ${response.statusText}`);
5283
+ console.log(`\u23F1\uFE0F Time: ${response.timing}ms`);
5284
+ console.log(`\u{1F4E6} Size: ${service.formatBytes(response.size)}`);
5285
+ console.log();
5286
+ }
5287
+ if (!options.onlyBody && !options.onlyHeaders) {
5288
+ console.log("\u{1F4CB} Headers:");
5289
+ Object.entries(response.headers).forEach(([key, value]) => {
5290
+ console.log(` ${key}: ${value}`);
5291
+ });
5292
+ console.log();
5293
+ }
5294
+ if (options.onlyHeaders) {
5295
+ Object.entries(response.headers).forEach(([key, value]) => {
5296
+ console.log(`${key}: ${value}`);
5297
+ });
5298
+ return;
5299
+ }
5300
+ if (!options.onlyHeaders) {
5301
+ if (!options.onlyBody) {
5302
+ console.log("\u{1F4C4} Body:");
5303
+ }
5304
+ try {
5305
+ const json = JSON.parse(response.body);
5306
+ console.log(JSON.stringify(json, null, 2));
5307
+ } catch {
5308
+ console.log(response.body);
5309
+ }
5310
+ console.log();
5311
+ }
5312
+ } catch (error) {
5313
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5314
+ process.exit(1);
5315
+ }
5316
+ }
5317
+ function createHttpCommand() {
5318
+ const cmd = new Command19("http").description("Make HTTP request with formatted output").argument("<url>", "Target URL").option("-X, --method <method>", "HTTP method", "GET").option("-H, --header <header...>", "Request headers (repeatable)").option("-d, --data <data>", "Request body (JSON string)").option("--file <path>", "Read body from file").option("--timeout <ms>", "Request timeout in milliseconds", "30000").option("--no-follow", "Do not follow redirects").option("--only-headers", "Show only response headers").option("--only-body", "Show only response body").action(async (url, options) => {
5319
+ await handleHttpRequest(url, {
5320
+ ...options,
5321
+ timeout: parseInt(options.timeout, 10)
5322
+ });
5323
+ });
5324
+ return cmd;
5325
+ }
5326
+
5327
+ // src/commands/utils/jwt.ts
5328
+ import { Command as Command20 } from "commander";
5329
+ async function handleJwtDecode(token) {
5330
+ const service = new UtilsService();
5331
+ try {
5332
+ const { header, payload, signature } = service.jwtDecode(token);
5333
+ console.log("\u{1F513} JWT Decoded:");
5334
+ console.log("\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\n");
5335
+ console.log("\u{1F4CB} Header:");
5336
+ console.log(JSON.stringify(header, null, 2));
5337
+ console.log();
5338
+ console.log("\u{1F4C4} Payload:");
5339
+ console.log(JSON.stringify(payload, null, 2));
5340
+ console.log();
5341
+ console.log("\u{1F50F} Signature:");
5342
+ console.log(` ${signature}`);
5343
+ console.log();
5344
+ console.log("\u26A0\uFE0F Note: Token signature is not verified");
5345
+ console.log();
5346
+ } catch (error) {
5347
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5348
+ process.exit(1);
5349
+ }
5350
+ }
5351
+ async function handleJwtEncode(options) {
5352
+ const service = new UtilsService();
5353
+ try {
5354
+ const payload = JSON.parse(options.payload);
5355
+ const header = options.header ? JSON.parse(options.header) : void 0;
5356
+ const token = service.jwtEncode(payload, options.secret, header);
5357
+ console.log("\u{1F510} JWT Encoded:");
5358
+ console.log("\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\n");
5359
+ console.log(` ${token}`);
5360
+ console.log();
5361
+ } catch (error) {
5362
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5363
+ process.exit(1);
5364
+ }
5365
+ }
5366
+ function createJwtCommand() {
5367
+ const jwtCommand = new Command20("jwt").description("Decode and encode JWT tokens");
5368
+ jwtCommand.command("decode").description("Decode JWT token").argument("<token>", "JWT token to decode").action(async (token) => {
5369
+ await handleJwtDecode(token);
5370
+ });
5371
+ jwtCommand.command("encode").description("Encode JWT token (HS256)").requiredOption("-p, --payload <json>", "Payload as JSON string").requiredOption("-s, --secret <secret>", "Secret key for signing").option("-h, --header <json>", "Custom header as JSON string").action(async (options) => {
5372
+ await handleJwtEncode(options);
5373
+ });
5374
+ return jwtCommand;
5375
+ }
5376
+
5377
+ // src/commands/utils/unix-time.ts
5378
+ import { Command as Command21 } from "commander";
5379
+ async function handleUnixTime(input, options) {
5380
+ const service = new UtilsService();
5381
+ try {
5382
+ if (!input) {
5383
+ const now = /* @__PURE__ */ new Date();
5384
+ const timestamp = service.dateToUnix(now, options.ms);
5385
+ console.log("\u{1F552} Current Unix Timestamp:");
5386
+ console.log("\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");
5387
+ console.log(` ${timestamp}${options.ms ? " (milliseconds)" : ""}`);
5388
+ console.log();
5389
+ console.log(` ISO: ${now.toISOString()}`);
5390
+ console.log(` Local: ${now.toLocaleString()}`);
5391
+ console.log();
5392
+ } else if (/^\d+$/.test(input)) {
5393
+ const timestamp = parseInt(input, 10);
5394
+ const date = service.unixToDate(timestamp, options.ms);
5395
+ console.log("\u{1F552} Unix Timestamp to Date:");
5396
+ console.log("\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");
5397
+ console.log(` Input: ${timestamp}${options.ms ? " (ms)" : ""}`);
5398
+ console.log();
5399
+ if (options.format === "iso" || options.format === "utc") {
5400
+ console.log(` ${date.toISOString()}`);
5401
+ } else {
5402
+ console.log(` ${date.toLocaleString()}`);
5403
+ }
5404
+ console.log();
5405
+ } else {
5406
+ const date = new Date(input);
5407
+ if (isNaN(date.getTime())) {
5408
+ console.error("\u274C Invalid date format");
5409
+ process.exit(1);
5410
+ }
5411
+ const timestamp = service.dateToUnix(date, options.ms);
5412
+ console.log("\u{1F552} Date to Unix Timestamp:");
5413
+ console.log("\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");
5414
+ console.log(` Input: ${input}`);
5415
+ console.log(` Parsed: ${date.toISOString()}`);
5416
+ console.log();
5417
+ console.log(` ${timestamp}${options.ms ? " (ms)" : ""}`);
5418
+ console.log();
5419
+ }
5420
+ } catch (error) {
5421
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5422
+ process.exit(1);
5423
+ }
5424
+ }
5425
+ function createUnixTimeCommand() {
5426
+ const cmd = new Command21("unix-time").description("Convert unix timestamps to/from dates").argument("[input]", "Unix timestamp or date string").option("-f, --format <format>", "Output format (iso, local, utc)", "iso").option("--ms", "Use milliseconds instead of seconds").action(async (input, options) => {
5427
+ await handleUnixTime(input, options);
5428
+ });
5429
+ return cmd;
5430
+ }
5431
+
5432
+ // src/commands/utils/timezone.ts
5433
+ import { Command as Command22 } from "commander";
5434
+ async function handleTimezoneConversion(time, options) {
5435
+ const service = new UtilsService();
5436
+ try {
5437
+ if (options.list) {
5438
+ console.log("\u{1F30D} Available Timezones:");
5439
+ console.log("\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\n");
5440
+ const timezones = service.getTimezones();
5441
+ timezones.forEach((tz) => {
5442
+ console.log(` ${tz}`);
5443
+ });
5444
+ console.log();
5445
+ return;
5446
+ }
5447
+ if (!time) {
5448
+ console.error("\u274C Please provide time to convert or use --list to see available timezones");
5449
+ process.exit(1);
5450
+ }
5451
+ if (!options.from || !options.to) {
5452
+ console.error("\u274C Please provide both --from and --to timezones");
5453
+ process.exit(1);
5454
+ }
5455
+ const result = service.convertTimezone(time, options.from, options.to);
5456
+ console.log("\u{1F30D} Timezone Conversion:");
5457
+ console.log("\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");
5458
+ console.log(` From: ${options.from}`);
5459
+ console.log(` To: ${options.to}`);
5460
+ console.log();
5461
+ console.log(` ${result.time}`);
5462
+ console.log(` ISO: ${result.iso}`);
5463
+ console.log();
5464
+ } catch (error) {
5465
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5466
+ process.exit(1);
5467
+ }
5468
+ }
5469
+ function createTimezoneCommand() {
5470
+ const cmd = new Command22("timezone").description("Convert time between timezones").argument("[time]", 'Time to convert (e.g., "2024-01-15 10:00")').option("--from <timezone>", "Source timezone").option("--to <timezone>", "Target timezone").option("--list", "Show available timezones").action(async (time, options) => {
5471
+ await handleTimezoneConversion(time, options);
5472
+ });
5473
+ return cmd;
5474
+ }
5475
+
5476
+ // src/commands/utils/url-encode.ts
5477
+ import { Command as Command23 } from "commander";
5478
+ async function handleUrlEncode(input, options) {
5479
+ const service = new UtilsService();
5480
+ try {
5481
+ const encoded = service.urlEncode(input, options.full);
5482
+ console.log("\u{1F517} URL Encoded:");
5483
+ console.log("\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");
5484
+ if (options.full) {
5485
+ console.log(" Mode: Full URL (encodeURI)");
5486
+ } else {
5487
+ console.log(" Mode: Component (encodeURIComponent)");
5488
+ }
5489
+ console.log();
5490
+ console.log(` ${encoded}`);
5491
+ console.log();
5492
+ } catch (error) {
5493
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5494
+ process.exit(1);
5495
+ }
5496
+ }
5497
+ function createUrlEncodeCommand() {
5498
+ const cmd = new Command23("url-encode").description("Encode URL component or full URL").argument("<input>", "Text to encode").option("--full", "Encode full URL (use encodeURI instead of encodeURIComponent)").action(async (input, options) => {
5499
+ await handleUrlEncode(input, options);
5500
+ });
5501
+ return cmd;
5502
+ }
5503
+
5504
+ // src/commands/utils/url-decode.ts
5505
+ import { Command as Command24 } from "commander";
5506
+ async function handleUrlDecode(input, options) {
5507
+ const service = new UtilsService();
5508
+ try {
5509
+ const decoded = service.urlDecode(input, options.full);
5510
+ console.log("\u{1F517} URL Decoded:");
5511
+ console.log("\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");
5512
+ if (options.full) {
5513
+ console.log(" Mode: Full URL (decodeURI)");
5514
+ } else {
5515
+ console.log(" Mode: Component (decodeURIComponent)");
5516
+ }
5517
+ console.log();
5518
+ console.log(` ${decoded}`);
5519
+ console.log();
5520
+ } catch (error) {
5521
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5522
+ process.exit(1);
5523
+ }
5524
+ }
5525
+ function createUrlDecodeCommand() {
5526
+ const cmd = new Command24("url-decode").description("Decode URL-encoded string").argument("<input>", "Text to decode").option("--full", "Decode full URL (use decodeURI instead of decodeURIComponent)").action(async (input, options) => {
5527
+ await handleUrlDecode(input, options);
5528
+ });
5529
+ return cmd;
5530
+ }
5531
+
5532
+ // src/commands/utils/cron.ts
5533
+ import { Command as Command25 } from "commander";
5534
+ import cronstrue from "cronstrue";
5535
+ async function handleCronParse(expression) {
5536
+ try {
5537
+ const description = cronstrue.toString(expression);
5538
+ console.log("\u23F0 Cron Expression Parser:");
5539
+ console.log("\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");
5540
+ console.log(` Expression: ${expression}`);
5541
+ console.log(` Meaning: ${description}`);
5542
+ console.log();
5543
+ console.log("\u{1F4C5} Next 5 Executions:");
5544
+ const parts = expression.trim().split(/\s+/);
5545
+ if (parts.length < 5 || parts.length > 6) {
5546
+ console.log(" \u26A0\uFE0F Invalid cron expression format");
5547
+ return;
5548
+ }
5549
+ const now = /* @__PURE__ */ new Date();
5550
+ const executions = [];
5551
+ for (let i = 0; i < 5; i++) {
5552
+ const nextTime = new Date(now);
5553
+ nextTime.setDate(nextTime.getDate() + i);
5554
+ const [minute, hour] = parts.slice(parts.length === 6 ? 1 : 0, parts.length === 6 ? 3 : 2);
5555
+ if (minute !== "*" && !minute.includes("/") && !minute.includes("-")) {
5556
+ nextTime.setMinutes(parseInt(minute, 10));
5557
+ }
5558
+ if (hour !== "*" && !hour.includes("/") && !hour.includes("-")) {
5559
+ nextTime.setHours(parseInt(hour, 10));
5560
+ }
5561
+ executions.push(
5562
+ ` ${i + 1}. ${nextTime.toISOString().replace("T", " ").substring(0, 19)}`
5563
+ );
5564
+ }
5565
+ executions.forEach((exec) => console.log(exec));
5566
+ console.log();
5567
+ console.log("\u{1F4A1} Tip: This is an approximate calculation.");
5568
+ console.log(" For exact times, consider your system timezone.");
5569
+ console.log();
5570
+ } catch (error) {
5571
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5572
+ process.exit(1);
5573
+ }
5574
+ }
5575
+ function createCronCommand() {
5576
+ const cmd = new Command25("cron").description("Parse and explain cron expression").argument("<expression>", 'Cron expression (e.g., "0 5 * * *")').action(async (expression) => {
5577
+ await handleCronParse(expression);
5578
+ });
5579
+ return cmd;
5580
+ }
5581
+
5582
+ // src/commands/utils/markdown-preview.ts
5583
+ import { Command as Command26 } from "commander";
5584
+ import { readFile as readFile5 } from "fs/promises";
5585
+ import { marked } from "marked";
5586
+ import TerminalRenderer from "marked-terminal";
5587
+ async function handleMarkdownPreview(file, options) {
5588
+ try {
5589
+ const content = await readFile5(file, "utf-8");
5590
+ if (options.raw) {
5591
+ console.log("\u{1F4C4} Markdown File (Raw):");
5592
+ console.log("\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\n");
5593
+ console.log(content);
5594
+ console.log();
5595
+ } else {
5596
+ marked.setOptions({
5597
+ // @ts-ignore - marked-terminal types may not match perfectly
5598
+ renderer: new TerminalRenderer()
5599
+ });
5600
+ const rendered = marked(content);
5601
+ console.log("\u{1F4C4} Markdown Preview:");
5602
+ console.log("\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\n");
5603
+ console.log(rendered);
5604
+ }
5605
+ } catch (error) {
5606
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
5607
+ process.exit(1);
5608
+ }
5609
+ }
5610
+ function createMarkdownPreviewCommand() {
5611
+ const cmd = new Command26("markdown-preview").description("Preview markdown file in terminal").argument("<file>", "Markdown file path").option("--raw", "Show raw markdown instead of rendered").action(async (file, options) => {
5612
+ await handleMarkdownPreview(file, options);
5613
+ });
5614
+ return cmd;
5615
+ }
5616
+
5617
+ // src/commands/utils/index.ts
5618
+ function createUtilsCommand() {
5619
+ const utilsCommand = new Command27("utils").description("Developer utilities for common tasks");
5620
+ utilsCommand.addCommand(createPasswordCommand());
5621
+ utilsCommand.addCommand(createUuidCommand());
5622
+ utilsCommand.addCommand(createHashCommand());
5623
+ utilsCommand.addCommand(createBase64EncodeCommand());
5624
+ utilsCommand.addCommand(createBase64DecodeCommand());
5625
+ utilsCommand.addCommand(createHttpCommand());
5626
+ utilsCommand.addCommand(createJwtCommand());
5627
+ utilsCommand.addCommand(createUnixTimeCommand());
5628
+ utilsCommand.addCommand(createTimezoneCommand());
5629
+ utilsCommand.addCommand(createUrlEncodeCommand());
5630
+ utilsCommand.addCommand(createUrlDecodeCommand());
5631
+ utilsCommand.addCommand(createCronCommand());
5632
+ utilsCommand.addCommand(createMarkdownPreviewCommand());
5633
+ utilsCommand.action(() => {
5634
+ utilsCommand.help();
5635
+ });
5636
+ return utilsCommand;
5637
+ }
5638
+
5639
+ // src/commands/upgrade.ts
5640
+ import { Command as Command28 } from "commander";
4790
5641
  import { confirm as confirm4 } from "@inquirer/prompts";
4791
5642
  import { execSync } from "child_process";
4792
5643
  var colors2 = {
@@ -4798,7 +5649,7 @@ var colors2 = {
4798
5649
  bold: "\x1B[1m"
4799
5650
  };
4800
5651
  function createUpgradeCommand() {
4801
- return new Command14("upgrade").description("Upgrade jai1-client to the latest version").option("--check", "Only check for updates without installing").option("--force", "Force upgrade without confirmation").action(async (options) => {
5652
+ return new Command28("upgrade").description("Upgrade jai1-client to the latest version").option("--check", "Only check for updates without installing").option("--force", "Force upgrade without confirmation").action(async (options) => {
4802
5653
  await handleUpgrade(options);
4803
5654
  });
4804
5655
  }
@@ -4871,6 +5722,7 @@ ${colors2.green}\u2705 Successfully upgraded to version ${latestVersion}!${color
4871
5722
  to_version: latestVersion,
4872
5723
  package_manager: packageManager2
4873
5724
  });
5725
+ disableUpdateCheck();
4874
5726
  } catch (error) {
4875
5727
  console.error(`
4876
5728
  ${colors2.red}\u274C Upgrade failed!${colors2.reset}`);
@@ -4945,11 +5797,11 @@ function getInstallCommand(packageManager2) {
4945
5797
  }
4946
5798
 
4947
5799
  // src/commands/clean.ts
4948
- import { Command as Command15 } from "commander";
5800
+ import { Command as Command29 } from "commander";
4949
5801
  import { confirm as confirm5, select as select2 } from "@inquirer/prompts";
4950
5802
  import { join as join4 } from "path";
4951
5803
  function createCleanCommand() {
4952
- return new Command15("clean").description("Clean up backups, cache, and temporary files").option("-y, --yes", "Skip confirmation").option("--backups", "Clean only backup files").option("--all", "Clean all (backups + cache)").action(async (options) => {
5804
+ return new Command29("clean").description("Clean up backups, cache, and temporary files").option("-y, --yes", "Skip confirmation").option("--backups", "Clean only backup files").option("--all", "Clean all (backups + cache)").action(async (options) => {
4953
5805
  await handleClean(options);
4954
5806
  });
4955
5807
  }
@@ -5062,10 +5914,10 @@ async function cleanTarget(target, skipConfirm) {
5062
5914
  }
5063
5915
 
5064
5916
  // src/commands/redmine/check.ts
5065
- import { Command as Command16 } from "commander";
5917
+ import { Command as Command30 } from "commander";
5066
5918
 
5067
5919
  // src/services/redmine-config.service.ts
5068
- import { readFile } from "fs/promises";
5920
+ import { readFile as readFile6 } from "fs/promises";
5069
5921
  import { resolve } from "path";
5070
5922
 
5071
5923
  // src/types/redmine.types.ts
@@ -5124,7 +5976,7 @@ var RedmineConfigService = class {
5124
5976
  */
5125
5977
  async load() {
5126
5978
  try {
5127
- const content = await readFile(this.configPath, "utf-8");
5979
+ const content = await readFile6(this.configPath, "utf-8");
5128
5980
  const rawConfig = parse(content);
5129
5981
  return RedmineConfigSchema.parse(rawConfig);
5130
5982
  } catch (error) {
@@ -5369,7 +6221,7 @@ async function checkConnectivity(config) {
5369
6221
 
5370
6222
  // src/commands/redmine/check.ts
5371
6223
  function createRedmineCheckCommand() {
5372
- const cmd = new Command16("check").description("Check Redmine connectivity").option("-c, --config <path>", "Config file path", "redmine.config.yaml").option("--json", "Output as JSON").action(async (options) => {
6224
+ const cmd = new Command30("check").description("Check Redmine connectivity").option("-c, --config <path>", "Config file path", "redmine.config.yaml").option("--json", "Output as JSON").action(async (options) => {
5373
6225
  await handleRedmineCheck(options);
5374
6226
  });
5375
6227
  return cmd;
@@ -5397,7 +6249,7 @@ async function handleRedmineCheck(options) {
5397
6249
  }
5398
6250
 
5399
6251
  // src/commands/redmine/sync-issue.ts
5400
- import { Command as Command17 } from "commander";
6252
+ import { Command as Command31 } from "commander";
5401
6253
 
5402
6254
  // src/sync-issue.ts
5403
6255
  import { resolve as resolve2, relative } from "path";
@@ -5539,7 +6391,7 @@ function generateFilename(issueId, title, config, existingSlugs = /* @__PURE__ *
5539
6391
  }
5540
6392
 
5541
6393
  // src/file.util.ts
5542
- import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
6394
+ import { readFile as readFile7, writeFile as writeFile2, mkdir } from "fs/promises";
5543
6395
  import { dirname } from "path";
5544
6396
  import matter3 from "gray-matter";
5545
6397
  async function ensureDir(filePath) {
@@ -5548,7 +6400,7 @@ async function ensureDir(filePath) {
5548
6400
  }
5549
6401
  async function readMarkdownFile(filePath) {
5550
6402
  try {
5551
- const content = await readFile2(filePath, "utf-8");
6403
+ const content = await readFile7(filePath, "utf-8");
5552
6404
  return parseMarkdownContent(content);
5553
6405
  } catch (error) {
5554
6406
  if (error.code === "ENOENT") {
@@ -5626,7 +6478,7 @@ ${config.anchors.end}`;
5626
6478
  async function writeMarkdownFile(filePath, data, config) {
5627
6479
  await ensureDir(filePath);
5628
6480
  const content = buildMarkdownContent(data, config);
5629
- await writeFile(filePath, content, "utf-8");
6481
+ await writeFile2(filePath, content, "utf-8");
5630
6482
  }
5631
6483
  function extractIssueIdFromFrontmatter(frontmatter) {
5632
6484
  const id = frontmatter.id;
@@ -5773,7 +6625,7 @@ function extractIssueIdFromUrl(url) {
5773
6625
 
5774
6626
  // src/commands/redmine/sync-issue.ts
5775
6627
  function createSyncIssueCommand() {
5776
- const cmd = new Command17("issue").description("Sync a single issue").option("-i, --id <number>", "Issue ID").option("-u, --url <url>", "Issue URL").option("--dry-run", "Preview without making changes").option("-c, --config <path>", "Config file path").option("-o, --output-dir <path>", "Output directory").option("--json", "Output as JSON").action(async (options) => {
6628
+ const cmd = new Command31("issue").description("Sync a single issue").option("-i, --id <number>", "Issue ID").option("-u, --url <url>", "Issue URL").option("--dry-run", "Preview without making changes").option("-c, --config <path>", "Config file path").option("-o, --output-dir <path>", "Output directory").option("--json", "Output as JSON").action(async (options) => {
5777
6629
  await handleSyncIssue(options);
5778
6630
  });
5779
6631
  return cmd;
@@ -5817,7 +6669,7 @@ async function handleSyncIssue(options) {
5817
6669
  }
5818
6670
 
5819
6671
  // src/commands/redmine/sync-project.ts
5820
- import { Command as Command18 } from "commander";
6672
+ import { Command as Command32 } from "commander";
5821
6673
 
5822
6674
  // src/sync-project.ts
5823
6675
  async function syncProject(config, options = {}) {
@@ -5887,7 +6739,7 @@ async function syncProject(config, options = {}) {
5887
6739
 
5888
6740
  // src/commands/redmine/sync-project.ts
5889
6741
  function createSyncProjectCommand() {
5890
- const cmd = new Command18("project").description("Sync all issues in a project").option("-s, --status <status>", "Filter by status (default: *)", "*").option("--updated-since <date>", "Only sync issues updated since YYYY-MM-DD").option("--concurrency <number>", "Number of concurrent requests").option("--page-size <number>", "Page size for API requests").option("--dry-run", "Preview without making changes").option("-c, --config <path>", "Config file path").option("-o, --output-dir <path>", "Output directory").option("--json", "Output as JSON").action(async (options) => {
6742
+ const cmd = new Command32("project").description("Sync all issues in a project").option("-s, --status <status>", "Filter by status (default: *)", "*").option("--updated-since <date>", "Only sync issues updated since YYYY-MM-DD").option("--concurrency <number>", "Number of concurrent requests").option("--page-size <number>", "Page size for API requests").option("--dry-run", "Preview without making changes").option("-c, --config <path>", "Config file path").option("-o, --output-dir <path>", "Output directory").option("--json", "Output as JSON").action(async (options) => {
5891
6743
  await handleSyncProject(options);
5892
6744
  });
5893
6745
  return cmd;
@@ -5942,12 +6794,12 @@ async function handleSyncProject(options) {
5942
6794
  }
5943
6795
 
5944
6796
  // src/commands/framework/info.ts
5945
- import { Command as Command19 } from "commander";
6797
+ import { Command as Command33 } from "commander";
5946
6798
  import { promises as fs8 } from "fs";
5947
6799
  import { join as join5 } from "path";
5948
6800
  import { homedir as homedir5 } from "os";
5949
6801
  function createInfoCommand() {
5950
- const cmd = new Command19("info").description("Show jai1-client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
6802
+ const cmd = new Command33("info").description("Show jai1-client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
5951
6803
  await handleInfo(options);
5952
6804
  });
5953
6805
  return cmd;
@@ -6003,7 +6855,7 @@ async function getProjectStatus2() {
6003
6855
  }
6004
6856
 
6005
6857
  // src/commands/self-update.ts
6006
- import { Command as Command20 } from "commander";
6858
+ import { Command as Command34 } from "commander";
6007
6859
  import { confirm as confirm6 } from "@inquirer/prompts";
6008
6860
  import { execSync as execSync2 } from "child_process";
6009
6861
  var colors3 = {
@@ -6015,7 +6867,7 @@ var colors3 = {
6015
6867
  bold: "\x1B[1m"
6016
6868
  };
6017
6869
  function createSelfUpdateCommand() {
6018
- return new Command20("self-update").description("Update jai1-client to the latest version").option("--check", "Only check for updates without installing").option("--force", "Force update without confirmation").action(async (options) => {
6870
+ return new Command34("self-update").description("Update jai1-client to the latest version").option("--check", "Only check for updates without installing").option("--force", "Force update without confirmation").action(async (options) => {
6019
6871
  await handleSelfUpdate(options);
6020
6872
  });
6021
6873
  }
@@ -6088,6 +6940,7 @@ ${colors3.green}\u2705 Successfully updated to version ${latestVersion}!${colors
6088
6940
  to_version: latestVersion,
6089
6941
  package_manager: packageManager2
6090
6942
  });
6943
+ disableUpdateCheck();
6091
6944
  } catch (error) {
6092
6945
  console.error(`
6093
6946
  ${colors3.red}\u274C Update failed!${colors3.reset}`);
@@ -6154,10 +7007,10 @@ function getInstallCommand2(packageManager2) {
6154
7007
  }
6155
7008
 
6156
7009
  // src/commands/clear-backups.ts
6157
- import { Command as Command21 } from "commander";
7010
+ import { Command as Command35 } from "commander";
6158
7011
  import { confirm as confirm7 } from "@inquirer/prompts";
6159
7012
  function createClearBackupsCommand() {
6160
- return new Command21("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
7013
+ return new Command35("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
6161
7014
  const service = new ComponentsService();
6162
7015
  const backups = await service.listBackups(process.cwd());
6163
7016
  if (backups.length === 0) {
@@ -6182,7 +7035,7 @@ function createClearBackupsCommand() {
6182
7035
  }
6183
7036
 
6184
7037
  // src/commands/vscode/index.ts
6185
- import { Command as Command22 } from "commander";
7038
+ import { Command as Command36 } from "commander";
6186
7039
  import { checkbox as checkbox3, confirm as confirm8, select as select3 } from "@inquirer/prompts";
6187
7040
  import fs9 from "fs/promises";
6188
7041
  import path5 from "path";
@@ -6322,7 +7175,7 @@ var PERFORMANCE_GROUPS2 = {
6322
7175
  }
6323
7176
  };
6324
7177
  function createVSCodeCommand() {
6325
- const vscodeCommand = new Command22("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
7178
+ const vscodeCommand = new Command36("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
6326
7179
  vscodeCommand.action(async () => {
6327
7180
  await interactiveMode2();
6328
7181
  });
@@ -6493,9 +7346,9 @@ async function resetSettings2(groupKeys) {
6493
7346
  // src/commands/guide.ts
6494
7347
  import React27 from "react";
6495
7348
  import { render as render5 } from "ink";
6496
- import { Command as Command23 } from "commander";
7349
+ import { Command as Command37 } from "commander";
6497
7350
  function createGuideCommand() {
6498
- const cmd = new Command23("guide").description("Interactive guide center for Agentic Coding").option("--topic <topic>", "Open specific topic (intro, rules, workflows, prompts, skills)").action(async (options) => {
7351
+ 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) => {
6499
7352
  const { waitUntilExit } = render5(
6500
7353
  React27.createElement(GuideApp, {
6501
7354
  initialTopic: options.topic,
@@ -6512,9 +7365,9 @@ function createGuideCommand() {
6512
7365
  // src/commands/context.ts
6513
7366
  import React28 from "react";
6514
7367
  import { render as render6 } from "ink";
6515
- import { Command as Command24 } from "commander";
7368
+ import { Command as Command38 } from "commander";
6516
7369
  function createContextCommand() {
6517
- const cmd = new Command24("context").description("Kh\xE1m ph\xE1 v\xE0 qu\u1EA3n l\xFD context d\u1EF1 \xE1n cho c\xE1c IDE").option("--ide <ide>", "M\u1EDF tr\u1EF1c ti\u1EBFp IDE c\u1EE5 th\u1EC3 (cursor, windsurf, antigravity, jai1)").option("--type <type>", "Hi\u1EC3n th\u1ECB lo\u1EA1i context c\u1EE5 th\u1EC3 (rules, workflows, skills, agents, prompts)").option("--stats", "Hi\u1EC3n th\u1ECB th\u1ED1ng k\xEA context (non-interactive)").action(async (options) => {
7370
+ const cmd = new Command38("context").description("Kh\xE1m ph\xE1 v\xE0 qu\u1EA3n l\xFD context d\u1EF1 \xE1n cho c\xE1c IDE").option("--ide <ide>", "M\u1EDF tr\u1EF1c ti\u1EBFp IDE c\u1EE5 th\u1EC3 (cursor, windsurf, antigravity, jai1)").option("--type <type>", "Hi\u1EC3n th\u1ECB lo\u1EA1i context c\u1EE5 th\u1EC3 (rules, workflows, skills, agents, prompts)").option("--stats", "Hi\u1EC3n th\u1ECB th\u1ED1ng k\xEA context (non-interactive)").action(async (options) => {
6518
7371
  let initialIDE;
6519
7372
  if (options.ide) {
6520
7373
  const validIDEs = ["cursor", "windsurf", "antigravity", "jai1"];
@@ -6591,10 +7444,10 @@ async function printStats2() {
6591
7444
  }
6592
7445
 
6593
7446
  // src/commands/migrate-ide.ts
6594
- import { Command as Command25 } from "commander";
7447
+ import { Command as Command39 } from "commander";
6595
7448
  import { checkbox as checkbox4, confirm as confirm9 } from "@inquirer/prompts";
6596
7449
  function createMigrateIdeCommand() {
6597
- const cmd = new Command25("migrate-ide").description("Migrate .jai1 rules v\xE0 workflows sang IDEs (Cursor, Windsurf, Claude Code, etc.)").option("--ide <ides...>", "Target IDEs (cursor, windsurf, antigravity, claudecode, opencode)").option("--type <types...>", "Content types (rules, workflows, commands)").option("--dry-run", "Preview changes without writing files").action(async (options) => {
7450
+ const cmd = new Command39("migrate-ide").description("Migrate .jai1 rules v\xE0 workflows sang IDEs (Cursor, Windsurf, Claude Code, etc.)").option("--ide <ides...>", "Target IDEs (cursor, windsurf, antigravity, claudecode, opencode)").option("--type <types...>", "Content types (rules, workflows, commands)").option("--dry-run", "Preview changes without writing files").action(async (options) => {
6598
7451
  await runMigrateIde(options);
6599
7452
  });
6600
7453
  return cmd;
@@ -6700,7 +7553,7 @@ async function runMigrateIde(options) {
6700
7553
  }
6701
7554
 
6702
7555
  // src/cli.ts
6703
- var program = new Command26();
7556
+ var program = new Command40();
6704
7557
  if (process.argv.includes("-v") || process.argv.includes("--version")) {
6705
7558
  console.log(package_default.version);
6706
7559
  if (!process.argv.includes("--skip-update-check")) {
@@ -6720,11 +7573,12 @@ program.addCommand(createLearnCommand());
6720
7573
  program.addCommand(createChatCommand());
6721
7574
  program.addCommand(createApiKeysCommand());
6722
7575
  program.addCommand(createTranslateCommand());
7576
+ program.addCommand(createUtilsCommand());
6723
7577
  program.addCommand(createUpgradeCommand());
6724
7578
  program.addCommand(createCleanCommand());
6725
- var redmineCommand = new Command26("redmine").description("Redmine context sync commands");
7579
+ var redmineCommand = new Command40("redmine").description("Redmine context sync commands");
6726
7580
  redmineCommand.addCommand(createRedmineCheckCommand());
6727
- var syncCommand = new Command26("sync").description("Sync Redmine issues to markdown files");
7581
+ var syncCommand = new Command40("sync").description("Sync Redmine issues to markdown files");
6728
7582
  syncCommand.addCommand(createSyncIssueCommand());
6729
7583
  syncCommand.addCommand(createSyncProjectCommand());
6730
7584
  redmineCommand.addCommand(syncCommand);
@@ -6762,6 +7616,9 @@ program.on("command:*", (operands) => {
6762
7616
  console.error(" api-keys Show OpenAI-compatible API credentials");
6763
7617
  console.error(" translate Translate text, files, or folders using AI");
6764
7618
  console.error("");
7619
+ console.error(" \u{1F6E0}\uFE0F Developer Utilities");
7620
+ console.error(" utils Developer tools (password, uuid, hash, jwt, etc.)");
7621
+ console.error("");
6765
7622
  console.error(" \u{1F527} Maintenance");
6766
7623
  console.error(" upgrade Upgrade jai1-client to latest version");
6767
7624
  console.error(" clean Clean up backups and cache");