@jvittechs/jai1-cli 0.1.60 → 0.1.62
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 +975 -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.62",
|
|
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,941 @@ 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").addHelpText("after", `
|
|
5071
|
+
Examples:
|
|
5072
|
+
$ jai1 utils password
|
|
5073
|
+
$ jai1 utils password --length 24
|
|
5074
|
+
$ jai1 utils password --no-symbols
|
|
5075
|
+
$ jai1 utils password --count 5
|
|
5076
|
+
$ jai1 utils password -l 32 --no-digits
|
|
5077
|
+
`).action(async (options) => {
|
|
5078
|
+
await handlePasswordGeneration({
|
|
5079
|
+
...options,
|
|
5080
|
+
length: parseInt(options.length, 10),
|
|
5081
|
+
count: parseInt(options.count, 10)
|
|
5082
|
+
});
|
|
5083
|
+
});
|
|
5084
|
+
return cmd;
|
|
5085
|
+
}
|
|
5086
|
+
|
|
5087
|
+
// src/commands/utils/uuid.ts
|
|
5088
|
+
import { Command as Command15 } from "commander";
|
|
5089
|
+
async function handleUuidGeneration(options) {
|
|
5090
|
+
const service = new UtilsService();
|
|
5091
|
+
try {
|
|
5092
|
+
const uuids = [];
|
|
5093
|
+
for (let i = 0; i < options.count; i++) {
|
|
5094
|
+
const uuid = service.generateUuid({
|
|
5095
|
+
uppercase: options.uppercase,
|
|
5096
|
+
noHyphens: options.noHyphens
|
|
5097
|
+
});
|
|
5098
|
+
uuids.push(uuid);
|
|
5099
|
+
}
|
|
5100
|
+
console.log("\u{1F194} Generated UUID(s):");
|
|
5101
|
+
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");
|
|
5102
|
+
uuids.forEach((uuid, index) => {
|
|
5103
|
+
if (options.count > 1) {
|
|
5104
|
+
console.log(` ${index + 1}. ${uuid}`);
|
|
5105
|
+
} else {
|
|
5106
|
+
console.log(` ${uuid}`);
|
|
5107
|
+
}
|
|
5108
|
+
});
|
|
5109
|
+
console.log();
|
|
5110
|
+
} catch (error) {
|
|
5111
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5112
|
+
process.exit(1);
|
|
5113
|
+
}
|
|
5114
|
+
}
|
|
5115
|
+
function createUuidCommand() {
|
|
5116
|
+
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").addHelpText("after", `
|
|
5117
|
+
Examples:
|
|
5118
|
+
$ jai1 utils uuid
|
|
5119
|
+
$ jai1 utils uuid --count 10
|
|
5120
|
+
$ jai1 utils uuid --uppercase
|
|
5121
|
+
$ jai1 utils uuid --no-hyphens
|
|
5122
|
+
$ jai1 utils uuid --uppercase --no-hyphens
|
|
5123
|
+
`).action(async (options) => {
|
|
5124
|
+
await handleUuidGeneration({
|
|
5125
|
+
...options,
|
|
5126
|
+
count: parseInt(options.count, 10)
|
|
5127
|
+
});
|
|
5128
|
+
});
|
|
5129
|
+
return cmd;
|
|
5130
|
+
}
|
|
5131
|
+
|
|
5132
|
+
// src/commands/utils/hash.ts
|
|
5133
|
+
import { Command as Command16 } from "commander";
|
|
5134
|
+
async function handleHashGeneration(input, options) {
|
|
5135
|
+
const service = new UtilsService();
|
|
5136
|
+
try {
|
|
5137
|
+
let hash;
|
|
5138
|
+
if (options.file) {
|
|
5139
|
+
if (options.algorithm === "bcrypt") {
|
|
5140
|
+
console.error("\u274C bcrypt cannot be used with files (it requires string input)");
|
|
5141
|
+
process.exit(1);
|
|
5142
|
+
}
|
|
5143
|
+
hash = await service.hashFile(options.file, options.algorithm);
|
|
5144
|
+
} else {
|
|
5145
|
+
if (!input) {
|
|
5146
|
+
console.error("\u274C Please provide input text or use --file option");
|
|
5147
|
+
process.exit(1);
|
|
5148
|
+
}
|
|
5149
|
+
if (options.algorithm === "bcrypt") {
|
|
5150
|
+
hash = await service.hashBcrypt(input, options.rounds);
|
|
5151
|
+
} else {
|
|
5152
|
+
hash = await service.hash(input, options.algorithm);
|
|
5153
|
+
}
|
|
5154
|
+
}
|
|
5155
|
+
console.log("\u{1F512} Hash Result:");
|
|
5156
|
+
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");
|
|
5157
|
+
console.log(` Algorithm: ${options.algorithm.toUpperCase()}`);
|
|
5158
|
+
if (options.file) {
|
|
5159
|
+
console.log(` File: ${options.file}`);
|
|
5160
|
+
}
|
|
5161
|
+
if (options.algorithm === "bcrypt") {
|
|
5162
|
+
console.log(` Rounds: ${options.rounds}`);
|
|
5163
|
+
}
|
|
5164
|
+
console.log();
|
|
5165
|
+
console.log(` ${hash}`);
|
|
5166
|
+
console.log();
|
|
5167
|
+
} catch (error) {
|
|
5168
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5169
|
+
process.exit(1);
|
|
5170
|
+
}
|
|
5171
|
+
}
|
|
5172
|
+
function createHashCommand() {
|
|
5173
|
+
const cmd = new Command16("hash").description("Generate hash (MD5, SHA, bcrypt)").argument("[input]", "Text to hash").option(
|
|
5174
|
+
"-a, --algorithm <algorithm>",
|
|
5175
|
+
"Hash algorithm (md5, sha1, sha256, sha512, bcrypt)",
|
|
5176
|
+
"sha256"
|
|
5177
|
+
).option("-f, --file <path>", "Hash file contents instead of text").option("-r, --rounds <number>", "Bcrypt rounds (only for bcrypt)", "10").addHelpText("after", `
|
|
5178
|
+
Examples:
|
|
5179
|
+
$ jai1 utils hash "hello world"
|
|
5180
|
+
$ jai1 utils hash "hello" --algorithm md5
|
|
5181
|
+
$ jai1 utils hash "password" --algorithm bcrypt
|
|
5182
|
+
$ jai1 utils hash "password" --algorithm bcrypt --rounds 12
|
|
5183
|
+
$ jai1 utils hash --file ./myfile.txt
|
|
5184
|
+
$ jai1 utils hash --file ./image.png --algorithm sha512
|
|
5185
|
+
`).action(async (input, options) => {
|
|
5186
|
+
await handleHashGeneration(input, {
|
|
5187
|
+
...options,
|
|
5188
|
+
rounds: parseInt(options.rounds, 10)
|
|
5189
|
+
});
|
|
5190
|
+
});
|
|
5191
|
+
return cmd;
|
|
5192
|
+
}
|
|
5193
|
+
|
|
5194
|
+
// src/commands/utils/base64-encode.ts
|
|
5195
|
+
import { Command as Command17 } from "commander";
|
|
5196
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
5197
|
+
async function handleBase64Encode(input, options) {
|
|
5198
|
+
const service = new UtilsService();
|
|
5199
|
+
try {
|
|
5200
|
+
let encoded;
|
|
5201
|
+
if (options.file) {
|
|
5202
|
+
const content = await readFile2(options.file);
|
|
5203
|
+
encoded = service.base64Encode(content, options.urlSafe);
|
|
5204
|
+
} else {
|
|
5205
|
+
if (!input) {
|
|
5206
|
+
console.error("\u274C Please provide input text or use --file option");
|
|
5207
|
+
process.exit(1);
|
|
5208
|
+
}
|
|
5209
|
+
encoded = service.base64Encode(input, options.urlSafe);
|
|
5210
|
+
}
|
|
5211
|
+
console.log("\u{1F4DD} Base64 Encoded:");
|
|
5212
|
+
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");
|
|
5213
|
+
if (options.file) {
|
|
5214
|
+
console.log(` File: ${options.file}`);
|
|
5215
|
+
}
|
|
5216
|
+
if (options.urlSafe) {
|
|
5217
|
+
console.log(` Format: URL-safe`);
|
|
5218
|
+
}
|
|
5219
|
+
console.log();
|
|
5220
|
+
console.log(` ${encoded}`);
|
|
5221
|
+
console.log();
|
|
5222
|
+
} catch (error) {
|
|
5223
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5224
|
+
process.exit(1);
|
|
5225
|
+
}
|
|
5226
|
+
}
|
|
5227
|
+
function createBase64EncodeCommand() {
|
|
5228
|
+
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").addHelpText("after", `
|
|
5229
|
+
Examples:
|
|
5230
|
+
$ jai1 utils base64-encode "hello world"
|
|
5231
|
+
$ jai1 utils base64-encode "hello world" --url-safe
|
|
5232
|
+
$ jai1 utils base64-encode --file ./document.txt
|
|
5233
|
+
$ jai1 utils base64-encode --file ./image.png
|
|
5234
|
+
`).action(async (input, options) => {
|
|
5235
|
+
await handleBase64Encode(input, options);
|
|
5236
|
+
});
|
|
5237
|
+
return cmd;
|
|
5238
|
+
}
|
|
5239
|
+
|
|
5240
|
+
// src/commands/utils/base64-decode.ts
|
|
5241
|
+
import { Command as Command18 } from "commander";
|
|
5242
|
+
import { readFile as readFile3, writeFile } from "fs/promises";
|
|
5243
|
+
async function handleBase64Decode(input, options) {
|
|
5244
|
+
const service = new UtilsService();
|
|
5245
|
+
try {
|
|
5246
|
+
let encodedInput;
|
|
5247
|
+
if (options.file) {
|
|
5248
|
+
encodedInput = await readFile3(options.file, "utf-8");
|
|
5249
|
+
} else {
|
|
5250
|
+
if (!input) {
|
|
5251
|
+
console.error("\u274C Please provide Base64 input or use --file option");
|
|
5252
|
+
process.exit(1);
|
|
5253
|
+
}
|
|
5254
|
+
encodedInput = input;
|
|
5255
|
+
}
|
|
5256
|
+
const decoded = service.base64Decode(encodedInput.trim());
|
|
5257
|
+
if (options.output) {
|
|
5258
|
+
await writeFile(options.output, decoded);
|
|
5259
|
+
console.log("\u2705 Decoded and saved to:", options.output);
|
|
5260
|
+
} else {
|
|
5261
|
+
console.log("\u{1F4DD} Base64 Decoded:");
|
|
5262
|
+
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");
|
|
5263
|
+
console.log();
|
|
5264
|
+
console.log(` ${decoded.toString("utf-8")}`);
|
|
5265
|
+
console.log();
|
|
5266
|
+
}
|
|
5267
|
+
} catch (error) {
|
|
5268
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5269
|
+
process.exit(1);
|
|
5270
|
+
}
|
|
5271
|
+
}
|
|
5272
|
+
function createBase64DecodeCommand() {
|
|
5273
|
+
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").addHelpText("after", `
|
|
5274
|
+
Examples:
|
|
5275
|
+
$ jai1 utils base64-decode "aGVsbG8gd29ybGQ="
|
|
5276
|
+
$ jai1 utils base64-decode --file ./encoded.txt
|
|
5277
|
+
$ jai1 utils base64-decode "aGVsbG8=" --output ./decoded.txt
|
|
5278
|
+
$ jai1 utils base64-decode --file ./encoded.txt --output ./image.png
|
|
5279
|
+
`).action(async (input, options) => {
|
|
5280
|
+
await handleBase64Decode(input, options);
|
|
5281
|
+
});
|
|
5282
|
+
return cmd;
|
|
5283
|
+
}
|
|
5284
|
+
|
|
5285
|
+
// src/commands/utils/http.ts
|
|
5286
|
+
import { Command as Command19 } from "commander";
|
|
5287
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
5288
|
+
async function handleHttpRequest(url, options) {
|
|
5289
|
+
const service = new UtilsService();
|
|
5290
|
+
try {
|
|
5291
|
+
const headers = {};
|
|
5292
|
+
if (options.header) {
|
|
5293
|
+
options.header.forEach((header) => {
|
|
5294
|
+
const [key, ...valueParts] = header.split(":");
|
|
5295
|
+
if (key && valueParts.length > 0) {
|
|
5296
|
+
headers[key.trim()] = valueParts.join(":").trim();
|
|
5297
|
+
}
|
|
5298
|
+
});
|
|
5299
|
+
}
|
|
5300
|
+
let body;
|
|
5301
|
+
if (options.file) {
|
|
5302
|
+
body = await readFile4(options.file, "utf-8");
|
|
5303
|
+
} else if (options.data) {
|
|
5304
|
+
body = options.data;
|
|
5305
|
+
}
|
|
5306
|
+
const response = await service.httpRequest(url, {
|
|
5307
|
+
method: options.method.toUpperCase(),
|
|
5308
|
+
headers,
|
|
5309
|
+
body,
|
|
5310
|
+
timeout: options.timeout,
|
|
5311
|
+
followRedirects: !options.noFollow
|
|
5312
|
+
});
|
|
5313
|
+
if (!options.onlyBody) {
|
|
5314
|
+
console.log(`HTTP/${response.status >= 200 && response.status < 300 ? "1.1" : "1.0"} ${response.status} ${response.statusText}`);
|
|
5315
|
+
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");
|
|
5316
|
+
console.log(`\u{1F4CA} Status: ${response.status} ${response.statusText}`);
|
|
5317
|
+
console.log(`\u23F1\uFE0F Time: ${response.timing}ms`);
|
|
5318
|
+
console.log(`\u{1F4E6} Size: ${service.formatBytes(response.size)}`);
|
|
5319
|
+
console.log();
|
|
5320
|
+
}
|
|
5321
|
+
if (!options.onlyBody && !options.onlyHeaders) {
|
|
5322
|
+
console.log("\u{1F4CB} Headers:");
|
|
5323
|
+
Object.entries(response.headers).forEach(([key, value]) => {
|
|
5324
|
+
console.log(` ${key}: ${value}`);
|
|
5325
|
+
});
|
|
5326
|
+
console.log();
|
|
5327
|
+
}
|
|
5328
|
+
if (options.onlyHeaders) {
|
|
5329
|
+
Object.entries(response.headers).forEach(([key, value]) => {
|
|
5330
|
+
console.log(`${key}: ${value}`);
|
|
5331
|
+
});
|
|
5332
|
+
return;
|
|
5333
|
+
}
|
|
5334
|
+
if (!options.onlyHeaders) {
|
|
5335
|
+
if (!options.onlyBody) {
|
|
5336
|
+
console.log("\u{1F4C4} Body:");
|
|
5337
|
+
}
|
|
5338
|
+
try {
|
|
5339
|
+
const json = JSON.parse(response.body);
|
|
5340
|
+
console.log(JSON.stringify(json, null, 2));
|
|
5341
|
+
} catch {
|
|
5342
|
+
console.log(response.body);
|
|
5343
|
+
}
|
|
5344
|
+
console.log();
|
|
5345
|
+
}
|
|
5346
|
+
} catch (error) {
|
|
5347
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5348
|
+
process.exit(1);
|
|
5349
|
+
}
|
|
5350
|
+
}
|
|
5351
|
+
function createHttpCommand() {
|
|
5352
|
+
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").addHelpText("after", `
|
|
5353
|
+
Examples:
|
|
5354
|
+
$ jai1 utils http https://api.example.com/users
|
|
5355
|
+
$ jai1 utils http https://api.example.com/users -X POST -d '{"name":"John"}'
|
|
5356
|
+
$ jai1 utils http https://api.example.com -H "Authorization: Bearer token123"
|
|
5357
|
+
$ jai1 utils http https://api.example.com -H "Content-Type: application/json" -H "Accept: application/json"
|
|
5358
|
+
$ jai1 utils http https://api.example.com --timeout 5000
|
|
5359
|
+
$ jai1 utils http https://api.example.com --only-body
|
|
5360
|
+
`).showHelpAfterError("(add --help for additional examples)").action(async (url, options) => {
|
|
5361
|
+
await handleHttpRequest(url, {
|
|
5362
|
+
...options,
|
|
5363
|
+
timeout: parseInt(options.timeout, 10)
|
|
5364
|
+
});
|
|
5365
|
+
});
|
|
5366
|
+
return cmd;
|
|
5367
|
+
}
|
|
5368
|
+
|
|
5369
|
+
// src/commands/utils/jwt.ts
|
|
5370
|
+
import { Command as Command20 } from "commander";
|
|
5371
|
+
async function handleJwtDecode(token) {
|
|
5372
|
+
const service = new UtilsService();
|
|
5373
|
+
try {
|
|
5374
|
+
const { header, payload, signature } = service.jwtDecode(token);
|
|
5375
|
+
console.log("\u{1F513} JWT Decoded:");
|
|
5376
|
+
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");
|
|
5377
|
+
console.log("\u{1F4CB} Header:");
|
|
5378
|
+
console.log(JSON.stringify(header, null, 2));
|
|
5379
|
+
console.log();
|
|
5380
|
+
console.log("\u{1F4C4} Payload:");
|
|
5381
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
5382
|
+
console.log();
|
|
5383
|
+
console.log("\u{1F50F} Signature:");
|
|
5384
|
+
console.log(` ${signature}`);
|
|
5385
|
+
console.log();
|
|
5386
|
+
console.log("\u26A0\uFE0F Note: Token signature is not verified");
|
|
5387
|
+
console.log();
|
|
5388
|
+
} catch (error) {
|
|
5389
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5390
|
+
process.exit(1);
|
|
5391
|
+
}
|
|
5392
|
+
}
|
|
5393
|
+
async function handleJwtEncode(options) {
|
|
5394
|
+
const service = new UtilsService();
|
|
5395
|
+
try {
|
|
5396
|
+
const payload = JSON.parse(options.payload);
|
|
5397
|
+
const header = options.header ? JSON.parse(options.header) : void 0;
|
|
5398
|
+
const token = service.jwtEncode(payload, options.secret, header);
|
|
5399
|
+
console.log("\u{1F510} JWT Encoded:");
|
|
5400
|
+
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");
|
|
5401
|
+
console.log(` ${token}`);
|
|
5402
|
+
console.log();
|
|
5403
|
+
} catch (error) {
|
|
5404
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5405
|
+
process.exit(1);
|
|
5406
|
+
}
|
|
5407
|
+
}
|
|
5408
|
+
function createJwtCommand() {
|
|
5409
|
+
const jwtCommand = new Command20("jwt").description("Decode and encode JWT tokens");
|
|
5410
|
+
jwtCommand.command("decode").description("Decode JWT token").argument("<token>", "JWT token to decode").addHelpText("after", `
|
|
5411
|
+
Examples:
|
|
5412
|
+
$ jai1 utils jwt decode "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
|
|
5413
|
+
$ jai1 utils jwt decode $JWT_TOKEN
|
|
5414
|
+
`).action(async (token) => {
|
|
5415
|
+
await handleJwtDecode(token);
|
|
5416
|
+
});
|
|
5417
|
+
const encodeCommand = 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").addHelpText("after", `
|
|
5418
|
+
Examples:
|
|
5419
|
+
$ jai1 utils jwt encode --payload '{"sub":"123","name":"John"}' --secret "mysecret"
|
|
5420
|
+
$ jai1 utils jwt encode -p '{"userId":"456"}' -s "key123"
|
|
5421
|
+
$ jai1 utils jwt encode -p '{"sub":"789"}' -s "secret" -h '{"alg":"HS256","typ":"JWT"}'
|
|
5422
|
+
`).action(async (options) => {
|
|
5423
|
+
await handleJwtEncode(options);
|
|
5424
|
+
});
|
|
5425
|
+
encodeCommand.showHelpAfterError("(add --help for additional examples)");
|
|
5426
|
+
return jwtCommand;
|
|
5427
|
+
}
|
|
5428
|
+
|
|
5429
|
+
// src/commands/utils/unix-time.ts
|
|
5430
|
+
import { Command as Command21 } from "commander";
|
|
5431
|
+
async function handleUnixTime(input, options) {
|
|
5432
|
+
const service = new UtilsService();
|
|
5433
|
+
try {
|
|
5434
|
+
if (!input) {
|
|
5435
|
+
const now = /* @__PURE__ */ new Date();
|
|
5436
|
+
const timestamp = service.dateToUnix(now, options.ms);
|
|
5437
|
+
console.log("\u{1F552} Current Unix Timestamp:");
|
|
5438
|
+
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");
|
|
5439
|
+
console.log(` ${timestamp}${options.ms ? " (milliseconds)" : ""}`);
|
|
5440
|
+
console.log();
|
|
5441
|
+
console.log(` ISO: ${now.toISOString()}`);
|
|
5442
|
+
console.log(` Local: ${now.toLocaleString()}`);
|
|
5443
|
+
console.log();
|
|
5444
|
+
} else if (/^\d+$/.test(input)) {
|
|
5445
|
+
const timestamp = parseInt(input, 10);
|
|
5446
|
+
const date = service.unixToDate(timestamp, options.ms);
|
|
5447
|
+
console.log("\u{1F552} Unix Timestamp to Date:");
|
|
5448
|
+
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");
|
|
5449
|
+
console.log(` Input: ${timestamp}${options.ms ? " (ms)" : ""}`);
|
|
5450
|
+
console.log();
|
|
5451
|
+
if (options.format === "iso" || options.format === "utc") {
|
|
5452
|
+
console.log(` ${date.toISOString()}`);
|
|
5453
|
+
} else {
|
|
5454
|
+
console.log(` ${date.toLocaleString()}`);
|
|
5455
|
+
}
|
|
5456
|
+
console.log();
|
|
5457
|
+
} else {
|
|
5458
|
+
const date = new Date(input);
|
|
5459
|
+
if (isNaN(date.getTime())) {
|
|
5460
|
+
console.error("\u274C Invalid date format");
|
|
5461
|
+
process.exit(1);
|
|
5462
|
+
}
|
|
5463
|
+
const timestamp = service.dateToUnix(date, options.ms);
|
|
5464
|
+
console.log("\u{1F552} Date to Unix Timestamp:");
|
|
5465
|
+
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");
|
|
5466
|
+
console.log(` Input: ${input}`);
|
|
5467
|
+
console.log(` Parsed: ${date.toISOString()}`);
|
|
5468
|
+
console.log();
|
|
5469
|
+
console.log(` ${timestamp}${options.ms ? " (ms)" : ""}`);
|
|
5470
|
+
console.log();
|
|
5471
|
+
}
|
|
5472
|
+
} catch (error) {
|
|
5473
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5474
|
+
process.exit(1);
|
|
5475
|
+
}
|
|
5476
|
+
}
|
|
5477
|
+
function createUnixTimeCommand() {
|
|
5478
|
+
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").addHelpText("after", `
|
|
5479
|
+
Examples:
|
|
5480
|
+
$ jai1 utils unix-time
|
|
5481
|
+
$ jai1 utils unix-time 1702550400
|
|
5482
|
+
$ jai1 utils unix-time 1702550400000 --ms
|
|
5483
|
+
$ jai1 utils unix-time "2024-01-15 10:30:00"
|
|
5484
|
+
$ jai1 utils unix-time "2024-01-15" --format local
|
|
5485
|
+
$ jai1 utils unix-time --ms
|
|
5486
|
+
`).action(async (input, options) => {
|
|
5487
|
+
await handleUnixTime(input, options);
|
|
5488
|
+
});
|
|
5489
|
+
return cmd;
|
|
5490
|
+
}
|
|
5491
|
+
|
|
5492
|
+
// src/commands/utils/timezone.ts
|
|
5493
|
+
import { Command as Command22 } from "commander";
|
|
5494
|
+
async function handleTimezoneConversion(time, options) {
|
|
5495
|
+
const service = new UtilsService();
|
|
5496
|
+
try {
|
|
5497
|
+
if (options.list) {
|
|
5498
|
+
console.log("\u{1F30D} Available Timezones:");
|
|
5499
|
+
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");
|
|
5500
|
+
const timezones = service.getTimezones();
|
|
5501
|
+
timezones.forEach((tz) => {
|
|
5502
|
+
console.log(` ${tz}`);
|
|
5503
|
+
});
|
|
5504
|
+
console.log();
|
|
5505
|
+
return;
|
|
5506
|
+
}
|
|
5507
|
+
if (!time) {
|
|
5508
|
+
console.error("\u274C Please provide time to convert or use --list to see available timezones");
|
|
5509
|
+
process.exit(1);
|
|
5510
|
+
}
|
|
5511
|
+
if (!options.from || !options.to) {
|
|
5512
|
+
console.error("\u274C Please provide both --from and --to timezones");
|
|
5513
|
+
process.exit(1);
|
|
5514
|
+
}
|
|
5515
|
+
const result = service.convertTimezone(time, options.from, options.to);
|
|
5516
|
+
console.log("\u{1F30D} Timezone Conversion:");
|
|
5517
|
+
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");
|
|
5518
|
+
console.log(` From: ${options.from}`);
|
|
5519
|
+
console.log(` To: ${options.to}`);
|
|
5520
|
+
console.log();
|
|
5521
|
+
console.log(` ${result.time}`);
|
|
5522
|
+
console.log(` ISO: ${result.iso}`);
|
|
5523
|
+
console.log();
|
|
5524
|
+
} catch (error) {
|
|
5525
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5526
|
+
process.exit(1);
|
|
5527
|
+
}
|
|
5528
|
+
}
|
|
5529
|
+
function createTimezoneCommand() {
|
|
5530
|
+
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").addHelpText("after", `
|
|
5531
|
+
Examples:
|
|
5532
|
+
$ jai1 utils timezone --list
|
|
5533
|
+
$ jai1 utils timezone "2024-01-15 10:00" --from "America/New_York" --to "Asia/Tokyo"
|
|
5534
|
+
$ jai1 utils timezone "2024-01-15 14:30" --from "UTC" --to "America/Los_Angeles"
|
|
5535
|
+
$ jai1 utils timezone "2024-12-25 12:00" --from "Europe/London" --to "Asia/Ho_Chi_Minh"
|
|
5536
|
+
`).action(async (time, options) => {
|
|
5537
|
+
await handleTimezoneConversion(time, options);
|
|
5538
|
+
});
|
|
5539
|
+
return cmd;
|
|
5540
|
+
}
|
|
5541
|
+
|
|
5542
|
+
// src/commands/utils/url-encode.ts
|
|
5543
|
+
import { Command as Command23 } from "commander";
|
|
5544
|
+
async function handleUrlEncode(input, options) {
|
|
5545
|
+
const service = new UtilsService();
|
|
5546
|
+
try {
|
|
5547
|
+
const encoded = service.urlEncode(input, options.full);
|
|
5548
|
+
console.log("\u{1F517} URL Encoded:");
|
|
5549
|
+
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");
|
|
5550
|
+
if (options.full) {
|
|
5551
|
+
console.log(" Mode: Full URL (encodeURI)");
|
|
5552
|
+
} else {
|
|
5553
|
+
console.log(" Mode: Component (encodeURIComponent)");
|
|
5554
|
+
}
|
|
5555
|
+
console.log();
|
|
5556
|
+
console.log(` ${encoded}`);
|
|
5557
|
+
console.log();
|
|
5558
|
+
} catch (error) {
|
|
5559
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5560
|
+
process.exit(1);
|
|
5561
|
+
}
|
|
5562
|
+
}
|
|
5563
|
+
function createUrlEncodeCommand() {
|
|
5564
|
+
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)").addHelpText("after", `
|
|
5565
|
+
Examples:
|
|
5566
|
+
$ jai1 utils url-encode "hello world"
|
|
5567
|
+
$ jai1 utils url-encode "hello world & test"
|
|
5568
|
+
$ jai1 utils url-encode "name=John Doe&age=30"
|
|
5569
|
+
$ jai1 utils url-encode "https://example.com/path with spaces" --full
|
|
5570
|
+
`).showHelpAfterError("(add --help for additional examples)").action(async (input, options) => {
|
|
5571
|
+
await handleUrlEncode(input, options);
|
|
5572
|
+
});
|
|
5573
|
+
return cmd;
|
|
5574
|
+
}
|
|
5575
|
+
|
|
5576
|
+
// src/commands/utils/url-decode.ts
|
|
5577
|
+
import { Command as Command24 } from "commander";
|
|
5578
|
+
async function handleUrlDecode(input, options) {
|
|
5579
|
+
const service = new UtilsService();
|
|
5580
|
+
try {
|
|
5581
|
+
const decoded = service.urlDecode(input, options.full);
|
|
5582
|
+
console.log("\u{1F517} URL Decoded:");
|
|
5583
|
+
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");
|
|
5584
|
+
if (options.full) {
|
|
5585
|
+
console.log(" Mode: Full URL (decodeURI)");
|
|
5586
|
+
} else {
|
|
5587
|
+
console.log(" Mode: Component (decodeURIComponent)");
|
|
5588
|
+
}
|
|
5589
|
+
console.log();
|
|
5590
|
+
console.log(` ${decoded}`);
|
|
5591
|
+
console.log();
|
|
5592
|
+
} catch (error) {
|
|
5593
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5594
|
+
process.exit(1);
|
|
5595
|
+
}
|
|
5596
|
+
}
|
|
5597
|
+
function createUrlDecodeCommand() {
|
|
5598
|
+
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)").addHelpText("after", `
|
|
5599
|
+
Examples:
|
|
5600
|
+
$ jai1 utils url-decode "hello%20world"
|
|
5601
|
+
$ jai1 utils url-decode "hello%20world%20%26%20test"
|
|
5602
|
+
$ jai1 utils url-decode "name%3DJohn%20Doe%26age%3D30"
|
|
5603
|
+
$ jai1 utils url-decode "https://example.com/path%20with%20spaces" --full
|
|
5604
|
+
`).showHelpAfterError("(add --help for additional examples)").action(async (input, options) => {
|
|
5605
|
+
await handleUrlDecode(input, options);
|
|
5606
|
+
});
|
|
5607
|
+
return cmd;
|
|
5608
|
+
}
|
|
5609
|
+
|
|
5610
|
+
// src/commands/utils/cron.ts
|
|
5611
|
+
import { Command as Command25 } from "commander";
|
|
5612
|
+
import cronstrue from "cronstrue";
|
|
5613
|
+
async function handleCronParse(expression) {
|
|
5614
|
+
try {
|
|
5615
|
+
const description = cronstrue.toString(expression);
|
|
5616
|
+
console.log("\u23F0 Cron Expression Parser:");
|
|
5617
|
+
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");
|
|
5618
|
+
console.log(` Expression: ${expression}`);
|
|
5619
|
+
console.log(` Meaning: ${description}`);
|
|
5620
|
+
console.log();
|
|
5621
|
+
console.log("\u{1F4C5} Next 5 Executions:");
|
|
5622
|
+
const parts = expression.trim().split(/\s+/);
|
|
5623
|
+
if (parts.length < 5 || parts.length > 6) {
|
|
5624
|
+
console.log(" \u26A0\uFE0F Invalid cron expression format");
|
|
5625
|
+
return;
|
|
5626
|
+
}
|
|
5627
|
+
const now = /* @__PURE__ */ new Date();
|
|
5628
|
+
const executions = [];
|
|
5629
|
+
for (let i = 0; i < 5; i++) {
|
|
5630
|
+
const nextTime = new Date(now);
|
|
5631
|
+
nextTime.setDate(nextTime.getDate() + i);
|
|
5632
|
+
const [minute, hour] = parts.slice(parts.length === 6 ? 1 : 0, parts.length === 6 ? 3 : 2);
|
|
5633
|
+
if (minute !== "*" && !minute.includes("/") && !minute.includes("-")) {
|
|
5634
|
+
nextTime.setMinutes(parseInt(minute, 10));
|
|
5635
|
+
}
|
|
5636
|
+
if (hour !== "*" && !hour.includes("/") && !hour.includes("-")) {
|
|
5637
|
+
nextTime.setHours(parseInt(hour, 10));
|
|
5638
|
+
}
|
|
5639
|
+
executions.push(
|
|
5640
|
+
` ${i + 1}. ${nextTime.toISOString().replace("T", " ").substring(0, 19)}`
|
|
5641
|
+
);
|
|
5642
|
+
}
|
|
5643
|
+
executions.forEach((exec) => console.log(exec));
|
|
5644
|
+
console.log();
|
|
5645
|
+
console.log("\u{1F4A1} Tip: This is an approximate calculation.");
|
|
5646
|
+
console.log(" For exact times, consider your system timezone.");
|
|
5647
|
+
console.log();
|
|
5648
|
+
} catch (error) {
|
|
5649
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5650
|
+
process.exit(1);
|
|
5651
|
+
}
|
|
5652
|
+
}
|
|
5653
|
+
function createCronCommand() {
|
|
5654
|
+
const cmd = new Command25("cron").description("Parse and explain cron expression").argument("<expression>", 'Cron expression (e.g., "0 5 * * *")').addHelpText("after", `
|
|
5655
|
+
Examples:
|
|
5656
|
+
$ jai1 utils cron "0 5 * * *"
|
|
5657
|
+
$ jai1 utils cron "*/15 * * * *"
|
|
5658
|
+
$ jai1 utils cron "0 0 1 * *"
|
|
5659
|
+
$ jai1 utils cron "0 9-17 * * 1-5"
|
|
5660
|
+
$ jai1 utils cron "30 2 * * 0"
|
|
5661
|
+
`).showHelpAfterError("(add --help for additional examples)").action(async (expression) => {
|
|
5662
|
+
await handleCronParse(expression);
|
|
5663
|
+
});
|
|
5664
|
+
return cmd;
|
|
5665
|
+
}
|
|
5666
|
+
|
|
5667
|
+
// src/commands/utils/markdown-preview.ts
|
|
5668
|
+
import { Command as Command26 } from "commander";
|
|
5669
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
5670
|
+
import { marked } from "marked";
|
|
5671
|
+
import TerminalRenderer from "marked-terminal";
|
|
5672
|
+
async function handleMarkdownPreview(file, options) {
|
|
5673
|
+
try {
|
|
5674
|
+
const content = await readFile5(file, "utf-8");
|
|
5675
|
+
if (options.raw) {
|
|
5676
|
+
console.log("\u{1F4C4} Markdown File (Raw):");
|
|
5677
|
+
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");
|
|
5678
|
+
console.log(content);
|
|
5679
|
+
console.log();
|
|
5680
|
+
} else {
|
|
5681
|
+
marked.setOptions({
|
|
5682
|
+
// @ts-ignore - marked-terminal types may not match perfectly
|
|
5683
|
+
renderer: new TerminalRenderer()
|
|
5684
|
+
});
|
|
5685
|
+
const rendered = marked(content);
|
|
5686
|
+
console.log("\u{1F4C4} Markdown Preview:");
|
|
5687
|
+
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");
|
|
5688
|
+
console.log(rendered);
|
|
5689
|
+
}
|
|
5690
|
+
} catch (error) {
|
|
5691
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
5692
|
+
process.exit(1);
|
|
5693
|
+
}
|
|
5694
|
+
}
|
|
5695
|
+
function createMarkdownPreviewCommand() {
|
|
5696
|
+
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").addHelpText("after", `
|
|
5697
|
+
Examples:
|
|
5698
|
+
$ jai1 utils markdown-preview README.md
|
|
5699
|
+
$ jai1 utils markdown-preview ./docs/guide.md
|
|
5700
|
+
$ jai1 utils markdown-preview CHANGELOG.md --raw
|
|
5701
|
+
$ jai1 utils markdown-preview ./notes.md
|
|
5702
|
+
`).showHelpAfterError("(add --help for additional examples)").action(async (file, options) => {
|
|
5703
|
+
await handleMarkdownPreview(file, options);
|
|
5704
|
+
});
|
|
5705
|
+
return cmd;
|
|
5706
|
+
}
|
|
5707
|
+
|
|
5708
|
+
// src/commands/utils/index.ts
|
|
5709
|
+
function createUtilsCommand() {
|
|
5710
|
+
const utilsCommand = new Command27("utils").description("Developer utilities for common tasks");
|
|
5711
|
+
utilsCommand.addCommand(createPasswordCommand());
|
|
5712
|
+
utilsCommand.addCommand(createUuidCommand());
|
|
5713
|
+
utilsCommand.addCommand(createHashCommand());
|
|
5714
|
+
utilsCommand.addCommand(createBase64EncodeCommand());
|
|
5715
|
+
utilsCommand.addCommand(createBase64DecodeCommand());
|
|
5716
|
+
utilsCommand.addCommand(createHttpCommand());
|
|
5717
|
+
utilsCommand.addCommand(createJwtCommand());
|
|
5718
|
+
utilsCommand.addCommand(createUnixTimeCommand());
|
|
5719
|
+
utilsCommand.addCommand(createTimezoneCommand());
|
|
5720
|
+
utilsCommand.addCommand(createUrlEncodeCommand());
|
|
5721
|
+
utilsCommand.addCommand(createUrlDecodeCommand());
|
|
5722
|
+
utilsCommand.addCommand(createCronCommand());
|
|
5723
|
+
utilsCommand.addCommand(createMarkdownPreviewCommand());
|
|
5724
|
+
utilsCommand.action(() => {
|
|
5725
|
+
utilsCommand.help();
|
|
5726
|
+
});
|
|
5727
|
+
return utilsCommand;
|
|
5728
|
+
}
|
|
5729
|
+
|
|
5730
|
+
// src/commands/upgrade.ts
|
|
5731
|
+
import { Command as Command28 } from "commander";
|
|
4795
5732
|
import { confirm as confirm4 } from "@inquirer/prompts";
|
|
4796
5733
|
import { execSync } from "child_process";
|
|
4797
5734
|
var colors2 = {
|
|
@@ -4803,7 +5740,7 @@ var colors2 = {
|
|
|
4803
5740
|
bold: "\x1B[1m"
|
|
4804
5741
|
};
|
|
4805
5742
|
function createUpgradeCommand() {
|
|
4806
|
-
return new
|
|
5743
|
+
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
5744
|
await handleUpgrade(options);
|
|
4808
5745
|
});
|
|
4809
5746
|
}
|
|
@@ -4951,11 +5888,11 @@ function getInstallCommand(packageManager2) {
|
|
|
4951
5888
|
}
|
|
4952
5889
|
|
|
4953
5890
|
// src/commands/clean.ts
|
|
4954
|
-
import { Command as
|
|
5891
|
+
import { Command as Command29 } from "commander";
|
|
4955
5892
|
import { confirm as confirm5, select as select2 } from "@inquirer/prompts";
|
|
4956
5893
|
import { join as join4 } from "path";
|
|
4957
5894
|
function createCleanCommand() {
|
|
4958
|
-
return new
|
|
5895
|
+
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
5896
|
await handleClean(options);
|
|
4960
5897
|
});
|
|
4961
5898
|
}
|
|
@@ -5068,10 +6005,10 @@ async function cleanTarget(target, skipConfirm) {
|
|
|
5068
6005
|
}
|
|
5069
6006
|
|
|
5070
6007
|
// src/commands/redmine/check.ts
|
|
5071
|
-
import { Command as
|
|
6008
|
+
import { Command as Command30 } from "commander";
|
|
5072
6009
|
|
|
5073
6010
|
// src/services/redmine-config.service.ts
|
|
5074
|
-
import { readFile } from "fs/promises";
|
|
6011
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
5075
6012
|
import { resolve } from "path";
|
|
5076
6013
|
|
|
5077
6014
|
// src/types/redmine.types.ts
|
|
@@ -5130,7 +6067,7 @@ var RedmineConfigService = class {
|
|
|
5130
6067
|
*/
|
|
5131
6068
|
async load() {
|
|
5132
6069
|
try {
|
|
5133
|
-
const content = await
|
|
6070
|
+
const content = await readFile6(this.configPath, "utf-8");
|
|
5134
6071
|
const rawConfig = parse(content);
|
|
5135
6072
|
return RedmineConfigSchema.parse(rawConfig);
|
|
5136
6073
|
} catch (error) {
|
|
@@ -5375,7 +6312,7 @@ async function checkConnectivity(config) {
|
|
|
5375
6312
|
|
|
5376
6313
|
// src/commands/redmine/check.ts
|
|
5377
6314
|
function createRedmineCheckCommand() {
|
|
5378
|
-
const cmd = new
|
|
6315
|
+
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
6316
|
await handleRedmineCheck(options);
|
|
5380
6317
|
});
|
|
5381
6318
|
return cmd;
|
|
@@ -5403,7 +6340,7 @@ async function handleRedmineCheck(options) {
|
|
|
5403
6340
|
}
|
|
5404
6341
|
|
|
5405
6342
|
// src/commands/redmine/sync-issue.ts
|
|
5406
|
-
import { Command as
|
|
6343
|
+
import { Command as Command31 } from "commander";
|
|
5407
6344
|
|
|
5408
6345
|
// src/sync-issue.ts
|
|
5409
6346
|
import { resolve as resolve2, relative } from "path";
|
|
@@ -5545,7 +6482,7 @@ function generateFilename(issueId, title, config, existingSlugs = /* @__PURE__ *
|
|
|
5545
6482
|
}
|
|
5546
6483
|
|
|
5547
6484
|
// src/file.util.ts
|
|
5548
|
-
import { readFile as
|
|
6485
|
+
import { readFile as readFile7, writeFile as writeFile2, mkdir } from "fs/promises";
|
|
5549
6486
|
import { dirname } from "path";
|
|
5550
6487
|
import matter3 from "gray-matter";
|
|
5551
6488
|
async function ensureDir(filePath) {
|
|
@@ -5554,7 +6491,7 @@ async function ensureDir(filePath) {
|
|
|
5554
6491
|
}
|
|
5555
6492
|
async function readMarkdownFile(filePath) {
|
|
5556
6493
|
try {
|
|
5557
|
-
const content = await
|
|
6494
|
+
const content = await readFile7(filePath, "utf-8");
|
|
5558
6495
|
return parseMarkdownContent(content);
|
|
5559
6496
|
} catch (error) {
|
|
5560
6497
|
if (error.code === "ENOENT") {
|
|
@@ -5632,7 +6569,7 @@ ${config.anchors.end}`;
|
|
|
5632
6569
|
async function writeMarkdownFile(filePath, data, config) {
|
|
5633
6570
|
await ensureDir(filePath);
|
|
5634
6571
|
const content = buildMarkdownContent(data, config);
|
|
5635
|
-
await
|
|
6572
|
+
await writeFile2(filePath, content, "utf-8");
|
|
5636
6573
|
}
|
|
5637
6574
|
function extractIssueIdFromFrontmatter(frontmatter) {
|
|
5638
6575
|
const id = frontmatter.id;
|
|
@@ -5779,7 +6716,7 @@ function extractIssueIdFromUrl(url) {
|
|
|
5779
6716
|
|
|
5780
6717
|
// src/commands/redmine/sync-issue.ts
|
|
5781
6718
|
function createSyncIssueCommand() {
|
|
5782
|
-
const cmd = new
|
|
6719
|
+
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
6720
|
await handleSyncIssue(options);
|
|
5784
6721
|
});
|
|
5785
6722
|
return cmd;
|
|
@@ -5823,7 +6760,7 @@ async function handleSyncIssue(options) {
|
|
|
5823
6760
|
}
|
|
5824
6761
|
|
|
5825
6762
|
// src/commands/redmine/sync-project.ts
|
|
5826
|
-
import { Command as
|
|
6763
|
+
import { Command as Command32 } from "commander";
|
|
5827
6764
|
|
|
5828
6765
|
// src/sync-project.ts
|
|
5829
6766
|
async function syncProject(config, options = {}) {
|
|
@@ -5893,7 +6830,7 @@ async function syncProject(config, options = {}) {
|
|
|
5893
6830
|
|
|
5894
6831
|
// src/commands/redmine/sync-project.ts
|
|
5895
6832
|
function createSyncProjectCommand() {
|
|
5896
|
-
const cmd = new
|
|
6833
|
+
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
6834
|
await handleSyncProject(options);
|
|
5898
6835
|
});
|
|
5899
6836
|
return cmd;
|
|
@@ -5948,12 +6885,12 @@ async function handleSyncProject(options) {
|
|
|
5948
6885
|
}
|
|
5949
6886
|
|
|
5950
6887
|
// src/commands/framework/info.ts
|
|
5951
|
-
import { Command as
|
|
6888
|
+
import { Command as Command33 } from "commander";
|
|
5952
6889
|
import { promises as fs8 } from "fs";
|
|
5953
6890
|
import { join as join5 } from "path";
|
|
5954
6891
|
import { homedir as homedir5 } from "os";
|
|
5955
6892
|
function createInfoCommand() {
|
|
5956
|
-
const cmd = new
|
|
6893
|
+
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
6894
|
await handleInfo(options);
|
|
5958
6895
|
});
|
|
5959
6896
|
return cmd;
|
|
@@ -6009,7 +6946,7 @@ async function getProjectStatus2() {
|
|
|
6009
6946
|
}
|
|
6010
6947
|
|
|
6011
6948
|
// src/commands/self-update.ts
|
|
6012
|
-
import { Command as
|
|
6949
|
+
import { Command as Command34 } from "commander";
|
|
6013
6950
|
import { confirm as confirm6 } from "@inquirer/prompts";
|
|
6014
6951
|
import { execSync as execSync2 } from "child_process";
|
|
6015
6952
|
var colors3 = {
|
|
@@ -6021,7 +6958,7 @@ var colors3 = {
|
|
|
6021
6958
|
bold: "\x1B[1m"
|
|
6022
6959
|
};
|
|
6023
6960
|
function createSelfUpdateCommand() {
|
|
6024
|
-
return new
|
|
6961
|
+
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
6962
|
await handleSelfUpdate(options);
|
|
6026
6963
|
});
|
|
6027
6964
|
}
|
|
@@ -6161,10 +7098,10 @@ function getInstallCommand2(packageManager2) {
|
|
|
6161
7098
|
}
|
|
6162
7099
|
|
|
6163
7100
|
// src/commands/clear-backups.ts
|
|
6164
|
-
import { Command as
|
|
7101
|
+
import { Command as Command35 } from "commander";
|
|
6165
7102
|
import { confirm as confirm7 } from "@inquirer/prompts";
|
|
6166
7103
|
function createClearBackupsCommand() {
|
|
6167
|
-
return new
|
|
7104
|
+
return new Command35("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
|
|
6168
7105
|
const service = new ComponentsService();
|
|
6169
7106
|
const backups = await service.listBackups(process.cwd());
|
|
6170
7107
|
if (backups.length === 0) {
|
|
@@ -6189,7 +7126,7 @@ function createClearBackupsCommand() {
|
|
|
6189
7126
|
}
|
|
6190
7127
|
|
|
6191
7128
|
// src/commands/vscode/index.ts
|
|
6192
|
-
import { Command as
|
|
7129
|
+
import { Command as Command36 } from "commander";
|
|
6193
7130
|
import { checkbox as checkbox3, confirm as confirm8, select as select3 } from "@inquirer/prompts";
|
|
6194
7131
|
import fs9 from "fs/promises";
|
|
6195
7132
|
import path5 from "path";
|
|
@@ -6329,7 +7266,7 @@ var PERFORMANCE_GROUPS2 = {
|
|
|
6329
7266
|
}
|
|
6330
7267
|
};
|
|
6331
7268
|
function createVSCodeCommand() {
|
|
6332
|
-
const vscodeCommand = new
|
|
7269
|
+
const vscodeCommand = new Command36("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
|
|
6333
7270
|
vscodeCommand.action(async () => {
|
|
6334
7271
|
await interactiveMode2();
|
|
6335
7272
|
});
|
|
@@ -6500,9 +7437,9 @@ async function resetSettings2(groupKeys) {
|
|
|
6500
7437
|
// src/commands/guide.ts
|
|
6501
7438
|
import React27 from "react";
|
|
6502
7439
|
import { render as render5 } from "ink";
|
|
6503
|
-
import { Command as
|
|
7440
|
+
import { Command as Command37 } from "commander";
|
|
6504
7441
|
function createGuideCommand() {
|
|
6505
|
-
const cmd = new
|
|
7442
|
+
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
7443
|
const { waitUntilExit } = render5(
|
|
6507
7444
|
React27.createElement(GuideApp, {
|
|
6508
7445
|
initialTopic: options.topic,
|
|
@@ -6519,9 +7456,9 @@ function createGuideCommand() {
|
|
|
6519
7456
|
// src/commands/context.ts
|
|
6520
7457
|
import React28 from "react";
|
|
6521
7458
|
import { render as render6 } from "ink";
|
|
6522
|
-
import { Command as
|
|
7459
|
+
import { Command as Command38 } from "commander";
|
|
6523
7460
|
function createContextCommand() {
|
|
6524
|
-
const cmd = new
|
|
7461
|
+
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
7462
|
let initialIDE;
|
|
6526
7463
|
if (options.ide) {
|
|
6527
7464
|
const validIDEs = ["cursor", "windsurf", "antigravity", "jai1"];
|
|
@@ -6598,10 +7535,10 @@ async function printStats2() {
|
|
|
6598
7535
|
}
|
|
6599
7536
|
|
|
6600
7537
|
// src/commands/migrate-ide.ts
|
|
6601
|
-
import { Command as
|
|
7538
|
+
import { Command as Command39 } from "commander";
|
|
6602
7539
|
import { checkbox as checkbox4, confirm as confirm9 } from "@inquirer/prompts";
|
|
6603
7540
|
function createMigrateIdeCommand() {
|
|
6604
|
-
const cmd = new
|
|
7541
|
+
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
7542
|
await runMigrateIde(options);
|
|
6606
7543
|
});
|
|
6607
7544
|
return cmd;
|
|
@@ -6707,7 +7644,7 @@ async function runMigrateIde(options) {
|
|
|
6707
7644
|
}
|
|
6708
7645
|
|
|
6709
7646
|
// src/cli.ts
|
|
6710
|
-
var program = new
|
|
7647
|
+
var program = new Command40();
|
|
6711
7648
|
if (process.argv.includes("-v") || process.argv.includes("--version")) {
|
|
6712
7649
|
console.log(package_default.version);
|
|
6713
7650
|
if (!process.argv.includes("--skip-update-check")) {
|
|
@@ -6727,11 +7664,12 @@ program.addCommand(createLearnCommand());
|
|
|
6727
7664
|
program.addCommand(createChatCommand());
|
|
6728
7665
|
program.addCommand(createApiKeysCommand());
|
|
6729
7666
|
program.addCommand(createTranslateCommand());
|
|
7667
|
+
program.addCommand(createUtilsCommand());
|
|
6730
7668
|
program.addCommand(createUpgradeCommand());
|
|
6731
7669
|
program.addCommand(createCleanCommand());
|
|
6732
|
-
var redmineCommand = new
|
|
7670
|
+
var redmineCommand = new Command40("redmine").description("Redmine context sync commands");
|
|
6733
7671
|
redmineCommand.addCommand(createRedmineCheckCommand());
|
|
6734
|
-
var syncCommand = new
|
|
7672
|
+
var syncCommand = new Command40("sync").description("Sync Redmine issues to markdown files");
|
|
6735
7673
|
syncCommand.addCommand(createSyncIssueCommand());
|
|
6736
7674
|
syncCommand.addCommand(createSyncProjectCommand());
|
|
6737
7675
|
redmineCommand.addCommand(syncCommand);
|
|
@@ -6769,6 +7707,9 @@ program.on("command:*", (operands) => {
|
|
|
6769
7707
|
console.error(" api-keys Show OpenAI-compatible API credentials");
|
|
6770
7708
|
console.error(" translate Translate text, files, or folders using AI");
|
|
6771
7709
|
console.error("");
|
|
7710
|
+
console.error(" \u{1F6E0}\uFE0F Developer Utilities");
|
|
7711
|
+
console.error(" utils Developer tools (password, uuid, hash, jwt, etc.)");
|
|
7712
|
+
console.error("");
|
|
6772
7713
|
console.error(" \u{1F527} Maintenance");
|
|
6773
7714
|
console.error(" upgrade Upgrade jai1-client to latest version");
|
|
6774
7715
|
console.error(" clean Clean up backups and cache");
|