@jvittechs/jai1-cli 0.1.60 → 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 +884 -34
- package/dist/cli.js.map +1 -1
- package/package.json +5 -1
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
|
|
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.
|
|
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",
|
|
@@ -4790,8 +4794,850 @@ function createTranslateCommand() {
|
|
|
4790
4794
|
return cmd;
|
|
4791
4795
|
}
|
|
4792
4796
|
|
|
4793
|
-
// src/commands/
|
|
4797
|
+
// src/commands/utils/index.ts
|
|
4798
|
+
import { Command as Command27 } from "commander";
|
|
4799
|
+
|
|
4800
|
+
// src/commands/utils/password.ts
|
|
4794
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";
|
|
4795
5641
|
import { confirm as confirm4 } from "@inquirer/prompts";
|
|
4796
5642
|
import { execSync } from "child_process";
|
|
4797
5643
|
var colors2 = {
|
|
@@ -4803,7 +5649,7 @@ var colors2 = {
|
|
|
4803
5649
|
bold: "\x1B[1m"
|
|
4804
5650
|
};
|
|
4805
5651
|
function createUpgradeCommand() {
|
|
4806
|
-
return new
|
|
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) => {
|
|
4807
5653
|
await handleUpgrade(options);
|
|
4808
5654
|
});
|
|
4809
5655
|
}
|
|
@@ -4951,11 +5797,11 @@ function getInstallCommand(packageManager2) {
|
|
|
4951
5797
|
}
|
|
4952
5798
|
|
|
4953
5799
|
// src/commands/clean.ts
|
|
4954
|
-
import { Command as
|
|
5800
|
+
import { Command as Command29 } from "commander";
|
|
4955
5801
|
import { confirm as confirm5, select as select2 } from "@inquirer/prompts";
|
|
4956
5802
|
import { join as join4 } from "path";
|
|
4957
5803
|
function createCleanCommand() {
|
|
4958
|
-
return new
|
|
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) => {
|
|
4959
5805
|
await handleClean(options);
|
|
4960
5806
|
});
|
|
4961
5807
|
}
|
|
@@ -5068,10 +5914,10 @@ async function cleanTarget(target, skipConfirm) {
|
|
|
5068
5914
|
}
|
|
5069
5915
|
|
|
5070
5916
|
// src/commands/redmine/check.ts
|
|
5071
|
-
import { Command as
|
|
5917
|
+
import { Command as Command30 } from "commander";
|
|
5072
5918
|
|
|
5073
5919
|
// src/services/redmine-config.service.ts
|
|
5074
|
-
import { readFile } from "fs/promises";
|
|
5920
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
5075
5921
|
import { resolve } from "path";
|
|
5076
5922
|
|
|
5077
5923
|
// src/types/redmine.types.ts
|
|
@@ -5130,7 +5976,7 @@ var RedmineConfigService = class {
|
|
|
5130
5976
|
*/
|
|
5131
5977
|
async load() {
|
|
5132
5978
|
try {
|
|
5133
|
-
const content = await
|
|
5979
|
+
const content = await readFile6(this.configPath, "utf-8");
|
|
5134
5980
|
const rawConfig = parse(content);
|
|
5135
5981
|
return RedmineConfigSchema.parse(rawConfig);
|
|
5136
5982
|
} catch (error) {
|
|
@@ -5375,7 +6221,7 @@ async function checkConnectivity(config) {
|
|
|
5375
6221
|
|
|
5376
6222
|
// src/commands/redmine/check.ts
|
|
5377
6223
|
function createRedmineCheckCommand() {
|
|
5378
|
-
const cmd = new
|
|
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) => {
|
|
5379
6225
|
await handleRedmineCheck(options);
|
|
5380
6226
|
});
|
|
5381
6227
|
return cmd;
|
|
@@ -5403,7 +6249,7 @@ async function handleRedmineCheck(options) {
|
|
|
5403
6249
|
}
|
|
5404
6250
|
|
|
5405
6251
|
// src/commands/redmine/sync-issue.ts
|
|
5406
|
-
import { Command as
|
|
6252
|
+
import { Command as Command31 } from "commander";
|
|
5407
6253
|
|
|
5408
6254
|
// src/sync-issue.ts
|
|
5409
6255
|
import { resolve as resolve2, relative } from "path";
|
|
@@ -5545,7 +6391,7 @@ function generateFilename(issueId, title, config, existingSlugs = /* @__PURE__ *
|
|
|
5545
6391
|
}
|
|
5546
6392
|
|
|
5547
6393
|
// src/file.util.ts
|
|
5548
|
-
import { readFile as
|
|
6394
|
+
import { readFile as readFile7, writeFile as writeFile2, mkdir } from "fs/promises";
|
|
5549
6395
|
import { dirname } from "path";
|
|
5550
6396
|
import matter3 from "gray-matter";
|
|
5551
6397
|
async function ensureDir(filePath) {
|
|
@@ -5554,7 +6400,7 @@ async function ensureDir(filePath) {
|
|
|
5554
6400
|
}
|
|
5555
6401
|
async function readMarkdownFile(filePath) {
|
|
5556
6402
|
try {
|
|
5557
|
-
const content = await
|
|
6403
|
+
const content = await readFile7(filePath, "utf-8");
|
|
5558
6404
|
return parseMarkdownContent(content);
|
|
5559
6405
|
} catch (error) {
|
|
5560
6406
|
if (error.code === "ENOENT") {
|
|
@@ -5632,7 +6478,7 @@ ${config.anchors.end}`;
|
|
|
5632
6478
|
async function writeMarkdownFile(filePath, data, config) {
|
|
5633
6479
|
await ensureDir(filePath);
|
|
5634
6480
|
const content = buildMarkdownContent(data, config);
|
|
5635
|
-
await
|
|
6481
|
+
await writeFile2(filePath, content, "utf-8");
|
|
5636
6482
|
}
|
|
5637
6483
|
function extractIssueIdFromFrontmatter(frontmatter) {
|
|
5638
6484
|
const id = frontmatter.id;
|
|
@@ -5779,7 +6625,7 @@ function extractIssueIdFromUrl(url) {
|
|
|
5779
6625
|
|
|
5780
6626
|
// src/commands/redmine/sync-issue.ts
|
|
5781
6627
|
function createSyncIssueCommand() {
|
|
5782
|
-
const cmd = new
|
|
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) => {
|
|
5783
6629
|
await handleSyncIssue(options);
|
|
5784
6630
|
});
|
|
5785
6631
|
return cmd;
|
|
@@ -5823,7 +6669,7 @@ async function handleSyncIssue(options) {
|
|
|
5823
6669
|
}
|
|
5824
6670
|
|
|
5825
6671
|
// src/commands/redmine/sync-project.ts
|
|
5826
|
-
import { Command as
|
|
6672
|
+
import { Command as Command32 } from "commander";
|
|
5827
6673
|
|
|
5828
6674
|
// src/sync-project.ts
|
|
5829
6675
|
async function syncProject(config, options = {}) {
|
|
@@ -5893,7 +6739,7 @@ async function syncProject(config, options = {}) {
|
|
|
5893
6739
|
|
|
5894
6740
|
// src/commands/redmine/sync-project.ts
|
|
5895
6741
|
function createSyncProjectCommand() {
|
|
5896
|
-
const cmd = new
|
|
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) => {
|
|
5897
6743
|
await handleSyncProject(options);
|
|
5898
6744
|
});
|
|
5899
6745
|
return cmd;
|
|
@@ -5948,12 +6794,12 @@ async function handleSyncProject(options) {
|
|
|
5948
6794
|
}
|
|
5949
6795
|
|
|
5950
6796
|
// src/commands/framework/info.ts
|
|
5951
|
-
import { Command as
|
|
6797
|
+
import { Command as Command33 } from "commander";
|
|
5952
6798
|
import { promises as fs8 } from "fs";
|
|
5953
6799
|
import { join as join5 } from "path";
|
|
5954
6800
|
import { homedir as homedir5 } from "os";
|
|
5955
6801
|
function createInfoCommand() {
|
|
5956
|
-
const cmd = new
|
|
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) => {
|
|
5957
6803
|
await handleInfo(options);
|
|
5958
6804
|
});
|
|
5959
6805
|
return cmd;
|
|
@@ -6009,7 +6855,7 @@ async function getProjectStatus2() {
|
|
|
6009
6855
|
}
|
|
6010
6856
|
|
|
6011
6857
|
// src/commands/self-update.ts
|
|
6012
|
-
import { Command as
|
|
6858
|
+
import { Command as Command34 } from "commander";
|
|
6013
6859
|
import { confirm as confirm6 } from "@inquirer/prompts";
|
|
6014
6860
|
import { execSync as execSync2 } from "child_process";
|
|
6015
6861
|
var colors3 = {
|
|
@@ -6021,7 +6867,7 @@ var colors3 = {
|
|
|
6021
6867
|
bold: "\x1B[1m"
|
|
6022
6868
|
};
|
|
6023
6869
|
function createSelfUpdateCommand() {
|
|
6024
|
-
return new
|
|
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) => {
|
|
6025
6871
|
await handleSelfUpdate(options);
|
|
6026
6872
|
});
|
|
6027
6873
|
}
|
|
@@ -6161,10 +7007,10 @@ function getInstallCommand2(packageManager2) {
|
|
|
6161
7007
|
}
|
|
6162
7008
|
|
|
6163
7009
|
// src/commands/clear-backups.ts
|
|
6164
|
-
import { Command as
|
|
7010
|
+
import { Command as Command35 } from "commander";
|
|
6165
7011
|
import { confirm as confirm7 } from "@inquirer/prompts";
|
|
6166
7012
|
function createClearBackupsCommand() {
|
|
6167
|
-
return new
|
|
7013
|
+
return new Command35("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
|
|
6168
7014
|
const service = new ComponentsService();
|
|
6169
7015
|
const backups = await service.listBackups(process.cwd());
|
|
6170
7016
|
if (backups.length === 0) {
|
|
@@ -6189,7 +7035,7 @@ function createClearBackupsCommand() {
|
|
|
6189
7035
|
}
|
|
6190
7036
|
|
|
6191
7037
|
// src/commands/vscode/index.ts
|
|
6192
|
-
import { Command as
|
|
7038
|
+
import { Command as Command36 } from "commander";
|
|
6193
7039
|
import { checkbox as checkbox3, confirm as confirm8, select as select3 } from "@inquirer/prompts";
|
|
6194
7040
|
import fs9 from "fs/promises";
|
|
6195
7041
|
import path5 from "path";
|
|
@@ -6329,7 +7175,7 @@ var PERFORMANCE_GROUPS2 = {
|
|
|
6329
7175
|
}
|
|
6330
7176
|
};
|
|
6331
7177
|
function createVSCodeCommand() {
|
|
6332
|
-
const vscodeCommand = new
|
|
7178
|
+
const vscodeCommand = new Command36("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
|
|
6333
7179
|
vscodeCommand.action(async () => {
|
|
6334
7180
|
await interactiveMode2();
|
|
6335
7181
|
});
|
|
@@ -6500,9 +7346,9 @@ async function resetSettings2(groupKeys) {
|
|
|
6500
7346
|
// src/commands/guide.ts
|
|
6501
7347
|
import React27 from "react";
|
|
6502
7348
|
import { render as render5 } from "ink";
|
|
6503
|
-
import { Command as
|
|
7349
|
+
import { Command as Command37 } from "commander";
|
|
6504
7350
|
function createGuideCommand() {
|
|
6505
|
-
const cmd = new
|
|
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) => {
|
|
6506
7352
|
const { waitUntilExit } = render5(
|
|
6507
7353
|
React27.createElement(GuideApp, {
|
|
6508
7354
|
initialTopic: options.topic,
|
|
@@ -6519,9 +7365,9 @@ function createGuideCommand() {
|
|
|
6519
7365
|
// src/commands/context.ts
|
|
6520
7366
|
import React28 from "react";
|
|
6521
7367
|
import { render as render6 } from "ink";
|
|
6522
|
-
import { Command as
|
|
7368
|
+
import { Command as Command38 } from "commander";
|
|
6523
7369
|
function createContextCommand() {
|
|
6524
|
-
const cmd = new
|
|
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) => {
|
|
6525
7371
|
let initialIDE;
|
|
6526
7372
|
if (options.ide) {
|
|
6527
7373
|
const validIDEs = ["cursor", "windsurf", "antigravity", "jai1"];
|
|
@@ -6598,10 +7444,10 @@ async function printStats2() {
|
|
|
6598
7444
|
}
|
|
6599
7445
|
|
|
6600
7446
|
// src/commands/migrate-ide.ts
|
|
6601
|
-
import { Command as
|
|
7447
|
+
import { Command as Command39 } from "commander";
|
|
6602
7448
|
import { checkbox as checkbox4, confirm as confirm9 } from "@inquirer/prompts";
|
|
6603
7449
|
function createMigrateIdeCommand() {
|
|
6604
|
-
const cmd = new
|
|
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) => {
|
|
6605
7451
|
await runMigrateIde(options);
|
|
6606
7452
|
});
|
|
6607
7453
|
return cmd;
|
|
@@ -6707,7 +7553,7 @@ async function runMigrateIde(options) {
|
|
|
6707
7553
|
}
|
|
6708
7554
|
|
|
6709
7555
|
// src/cli.ts
|
|
6710
|
-
var program = new
|
|
7556
|
+
var program = new Command40();
|
|
6711
7557
|
if (process.argv.includes("-v") || process.argv.includes("--version")) {
|
|
6712
7558
|
console.log(package_default.version);
|
|
6713
7559
|
if (!process.argv.includes("--skip-update-check")) {
|
|
@@ -6727,11 +7573,12 @@ program.addCommand(createLearnCommand());
|
|
|
6727
7573
|
program.addCommand(createChatCommand());
|
|
6728
7574
|
program.addCommand(createApiKeysCommand());
|
|
6729
7575
|
program.addCommand(createTranslateCommand());
|
|
7576
|
+
program.addCommand(createUtilsCommand());
|
|
6730
7577
|
program.addCommand(createUpgradeCommand());
|
|
6731
7578
|
program.addCommand(createCleanCommand());
|
|
6732
|
-
var redmineCommand = new
|
|
7579
|
+
var redmineCommand = new Command40("redmine").description("Redmine context sync commands");
|
|
6733
7580
|
redmineCommand.addCommand(createRedmineCheckCommand());
|
|
6734
|
-
var syncCommand = new
|
|
7581
|
+
var syncCommand = new Command40("sync").description("Sync Redmine issues to markdown files");
|
|
6735
7582
|
syncCommand.addCommand(createSyncIssueCommand());
|
|
6736
7583
|
syncCommand.addCommand(createSyncProjectCommand());
|
|
6737
7584
|
redmineCommand.addCommand(syncCommand);
|
|
@@ -6769,6 +7616,9 @@ program.on("command:*", (operands) => {
|
|
|
6769
7616
|
console.error(" api-keys Show OpenAI-compatible API credentials");
|
|
6770
7617
|
console.error(" translate Translate text, files, or folders using AI");
|
|
6771
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("");
|
|
6772
7622
|
console.error(" \u{1F527} Maintenance");
|
|
6773
7623
|
console.error(" upgrade Upgrade jai1-client to latest version");
|
|
6774
7624
|
console.error(" clean Clean up backups and cache");
|