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