@jvittechs/jai1-cli 0.1.76 → 0.1.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { Command as Command40 } from "commander";
4
+ import { Command as Command41 } 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.76",
36
+ version: "0.1.78",
37
37
  description: "A unified CLI tool for JV-IT TECHS developers to manage Jai1 Framework. Please contact TeamAI for usage instructions.",
38
38
  type: "module",
39
39
  bin: {
@@ -4391,13 +4391,13 @@ function createChatCommand() {
4391
4391
  return cmd;
4392
4392
  }
4393
4393
 
4394
- // src/commands/api-keys.ts
4394
+ // src/commands/openai-keys.ts
4395
4395
  import { Command as Command12 } from "commander";
4396
4396
  function maskKey2(key) {
4397
4397
  if (key.length <= 8) return "****";
4398
4398
  return key.slice(0, 8) + "****" + key.slice(-4);
4399
4399
  }
4400
- async function handleApiKeysCommand(options) {
4400
+ async function handleOpenAiKeysCommand(options) {
4401
4401
  const configService = new ConfigService();
4402
4402
  const config = await configService.load();
4403
4403
  if (!config) {
@@ -4436,7 +4436,7 @@ async function handleApiKeysCommand(options) {
4436
4436
  console.log(" - Use as drop-in replacement for OpenAI API");
4437
4437
  console.log(" - Compatible with: OpenAI SDK, LangChain, LlamaIndex, etc.");
4438
4438
  console.log(' - Run "jai1 chat" for interactive mode');
4439
- console.log(' - Run "jai1 api-keys --full" to show full API key');
4439
+ console.log(' - Run "jai1 openai-keys --full" to show full API key');
4440
4440
  } catch (error) {
4441
4441
  console.error(
4442
4442
  "\n\u274C Failed to fetch API info:",
@@ -4445,15 +4445,92 @@ async function handleApiKeysCommand(options) {
4445
4445
  console.log('\n\u{1F4A1} Check your API URL and access key with "jai1 status"');
4446
4446
  }
4447
4447
  }
4448
- function createApiKeysCommand() {
4449
- const cmd = new Command12("api-keys").description("Show OpenAI-compatible API credentials and info").option("--full", "Show full API key (unmasked)").action(async (options) => {
4450
- await handleApiKeysCommand(options);
4448
+ function createOpenAiKeysCommand() {
4449
+ const cmd = new Command12("openai-keys").description("Show OpenAI-compatible API credentials and info").option("--full", "Show full API key (unmasked)").action(async (options) => {
4450
+ await handleOpenAiKeysCommand(options);
4451
4451
  });
4452
4452
  return cmd;
4453
4453
  }
4454
4454
 
4455
- // src/commands/translate.ts
4455
+ // src/commands/stats.ts
4456
4456
  import { Command as Command13 } from "commander";
4457
+ async function handleStatsCommand() {
4458
+ const configService = new ConfigService();
4459
+ const config = await configService.load();
4460
+ if (!config) {
4461
+ throw new ValidationError('Ch\u01B0a x\xE1c th\u1EF1c. Vui l\xF2ng ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.');
4462
+ }
4463
+ const service = new LlmProxyService(config);
4464
+ console.log("\u{1F4CA} Th\u1ED1ng K\xEA S\u1EED D\u1EE5ng LLM");
4465
+ 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\n");
4466
+ try {
4467
+ const [limits, usage7Days, usageToday] = await Promise.all([
4468
+ service.getLimits(),
4469
+ service.getUsage(7),
4470
+ service.getUsage(1)
4471
+ ]);
4472
+ const today = (/* @__PURE__ */ new Date()).toLocaleDateString("en-CA", { timeZone: "Asia/Ho_Chi_Minh" });
4473
+ console.log("\u{1F4C5} Kho\u1EA3ng th\u1EDDi gian: 7 ng\xE0y qua\n");
4474
+ const usageByModel = /* @__PURE__ */ new Map();
4475
+ let total7DaysRequests = 0;
4476
+ usage7Days.data?.forEach((record) => {
4477
+ if (!usageByModel.has(record.model)) {
4478
+ usageByModel.set(record.model, { today: 0, total7Days: 0 });
4479
+ }
4480
+ const modelData = usageByModel.get(record.model);
4481
+ modelData.total7Days += record.count;
4482
+ total7DaysRequests += record.count;
4483
+ });
4484
+ usageToday.data?.forEach((record) => {
4485
+ if (record.date === today) {
4486
+ if (!usageByModel.has(record.model)) {
4487
+ usageByModel.set(record.model, { today: 0, total7Days: 0 });
4488
+ }
4489
+ const modelData = usageByModel.get(record.model);
4490
+ modelData.today = record.count;
4491
+ }
4492
+ });
4493
+ console.log("\u{1F4C8} T\u1ED5ng quan s\u1EED d\u1EE5ng");
4494
+ console.log(` T\u1ED5ng s\u1ED1 y\xEAu c\u1EA7u (7 ng\xE0y): ${total7DaysRequests}
4495
+ `);
4496
+ console.log("\u{1F4E6} Th\u1ED1ng k\xEA theo model\n");
4497
+ console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
4498
+ console.log("\u2502 Model \u2502 H\xF4m nay \u2502 Gi\u1EDBi h\u1EA1n \u2502 T\u1ED5ng 7 ng\xE0y \u2502");
4499
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
4500
+ const allowedModels = limits.effectiveAllowedModels || [];
4501
+ const rateLimits = limits.effectiveRateLimits || {};
4502
+ if (allowedModels.length === 0) {
4503
+ console.log("\u2502 Kh\xF4ng c\xF3 model n\xE0o kh\u1EA3 d\u1EE5ng \u2502");
4504
+ } else {
4505
+ allowedModels.forEach((modelId) => {
4506
+ const usage = usageByModel.get(modelId) || { today: 0, total7Days: 0 };
4507
+ const limit = rateLimits[modelId] || rateLimits[modelId.toLowerCase()] || 0;
4508
+ const modelCol = modelId.padEnd(31);
4509
+ const todayCol = `${usage.today}/${limit}`.padEnd(12);
4510
+ const limitCol = `${limit}/ng\xE0y`.padEnd(12);
4511
+ const totalCol = String(usage.total7Days).padEnd(12);
4512
+ console.log(`\u2502 ${modelCol} \u2502 ${todayCol} \u2502 ${limitCol} \u2502 ${totalCol} \u2502`);
4513
+ });
4514
+ }
4515
+ console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
4516
+ console.log('\n\u{1F4A1} M\u1EB9o: Ch\u1EA1y "jai1 openai-keys" \u0111\u1EC3 xem danh s\xE1ch model kh\u1EA3 d\u1EE5ng');
4517
+ } catch (error) {
4518
+ console.error(
4519
+ "\n\u274C Kh\xF4ng th\u1EC3 l\u1EA5y th\u1ED1ng k\xEA:",
4520
+ error instanceof Error ? error.message : String(error)
4521
+ );
4522
+ console.log('\n\u{1F4A1} Ki\u1EC3m tra k\u1EBFt n\u1ED1i API v\u1EDBi "jai1 status"');
4523
+ }
4524
+ }
4525
+ function createStatsCommand() {
4526
+ const cmd = new Command13("stats").description("Hi\u1EC3n th\u1ECB th\u1ED1ng k\xEA s\u1EED d\u1EE5ng LLM v\xE0 gi\u1EDBi h\u1EA1n").action(async () => {
4527
+ await handleStatsCommand();
4528
+ });
4529
+ return cmd;
4530
+ }
4531
+
4532
+ // src/commands/translate.ts
4533
+ import { Command as Command14 } from "commander";
4457
4534
 
4458
4535
  // src/services/translation.service.ts
4459
4536
  import { promises as fs7 } from "fs";
@@ -4801,17 +4878,17 @@ async function handleFolderTranslation(service, folderPath, options) {
4801
4878
  }
4802
4879
  }
4803
4880
  function createTranslateCommand() {
4804
- const cmd = new Command13("translate").description("D\u1ECBch v\u0103n b\u1EA3n, file ho\u1EB7c th\u01B0 m\u1EE5c b\u1EB1ng AI").argument("<input>", "Chu\u1ED7i v\u0103n b\u1EA3n, \u0111\u01B0\u1EDDng d\u1EABn file ho\u1EB7c th\u01B0 m\u1EE5c").option("--to <language>", "M\xE3 ng\xF4n ng\u1EEF \u0111\xEDch (m\u1EB7c \u0111\u1ECBnh: vi)", "vi").option("-o, --output <path>", "\u0110\u01B0\u1EDDng d\u1EABn output (file/th\u01B0 m\u1EE5c)").option("--dry-run", "Xem tr\u01B0\u1EDBc kh\xF4ng l\u01B0u file").option("--concurrency <number>", "S\u1ED1 file x\u1EED l\xFD song song (m\u1EB7c \u0111\u1ECBnh: 3)", "3").option("--model <model>", "Model LLM (m\u1EB7c \u0111\u1ECBnh: gpt-5.1-codex-mini)").option("--json", "Xu\u1EA5t k\u1EBFt qu\u1EA3 d\u1EA1ng JSON").action(async (input, options) => {
4881
+ const cmd = new Command14("translate").description("D\u1ECBch v\u0103n b\u1EA3n, file ho\u1EB7c th\u01B0 m\u1EE5c b\u1EB1ng AI").argument("<input>", "Chu\u1ED7i v\u0103n b\u1EA3n, \u0111\u01B0\u1EDDng d\u1EABn file ho\u1EB7c th\u01B0 m\u1EE5c").option("--to <language>", "M\xE3 ng\xF4n ng\u1EEF \u0111\xEDch (m\u1EB7c \u0111\u1ECBnh: vi)", "vi").option("-o, --output <path>", "\u0110\u01B0\u1EDDng d\u1EABn output (file/th\u01B0 m\u1EE5c)").option("--dry-run", "Xem tr\u01B0\u1EDBc kh\xF4ng l\u01B0u file").option("--concurrency <number>", "S\u1ED1 file x\u1EED l\xFD song song (m\u1EB7c \u0111\u1ECBnh: 3)", "3").option("--model <model>", "Model LLM (m\u1EB7c \u0111\u1ECBnh: gpt-5.1-codex-mini)").option("--json", "Xu\u1EA5t k\u1EBFt qu\u1EA3 d\u1EA1ng JSON").action(async (input, options) => {
4805
4882
  await handleTranslate(input, options);
4806
4883
  });
4807
4884
  return cmd;
4808
4885
  }
4809
4886
 
4810
4887
  // src/commands/utils/index.ts
4811
- import { Command as Command27 } from "commander";
4888
+ import { Command as Command28 } from "commander";
4812
4889
 
4813
4890
  // src/commands/utils/password.ts
4814
- import { Command as Command14 } from "commander";
4891
+ import { Command as Command15 } from "commander";
4815
4892
 
4816
4893
  // src/services/utils.service.ts
4817
4894
  import crypto from "crypto";
@@ -5080,7 +5157,7 @@ async function handlePasswordGeneration(options) {
5080
5157
  }
5081
5158
  }
5082
5159
  function createPasswordCommand() {
5083
- 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", `
5160
+ const cmd = new Command15("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", `
5084
5161
  Examples:
5085
5162
  $ jai1 utils password
5086
5163
  $ jai1 utils password --length 24
@@ -5098,7 +5175,7 @@ Examples:
5098
5175
  }
5099
5176
 
5100
5177
  // src/commands/utils/uuid.ts
5101
- import { Command as Command15 } from "commander";
5178
+ import { Command as Command16 } from "commander";
5102
5179
  async function handleUuidGeneration(options) {
5103
5180
  const service = new UtilsService();
5104
5181
  try {
@@ -5126,7 +5203,7 @@ async function handleUuidGeneration(options) {
5126
5203
  }
5127
5204
  }
5128
5205
  function createUuidCommand() {
5129
- 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", `
5206
+ const cmd = new Command16("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", `
5130
5207
  Examples:
5131
5208
  $ jai1 utils uuid
5132
5209
  $ jai1 utils uuid --count 10
@@ -5143,7 +5220,7 @@ Examples:
5143
5220
  }
5144
5221
 
5145
5222
  // src/commands/utils/hash.ts
5146
- import { Command as Command16 } from "commander";
5223
+ import { Command as Command17 } from "commander";
5147
5224
  async function handleHashGeneration(input, options) {
5148
5225
  const service = new UtilsService();
5149
5226
  try {
@@ -5183,7 +5260,7 @@ async function handleHashGeneration(input, options) {
5183
5260
  }
5184
5261
  }
5185
5262
  function createHashCommand() {
5186
- const cmd = new Command16("hash").description("Generate hash (MD5, SHA, bcrypt)").argument("[input]", "Text to hash").option(
5263
+ const cmd = new Command17("hash").description("Generate hash (MD5, SHA, bcrypt)").argument("[input]", "Text to hash").option(
5187
5264
  "-a, --algorithm <algorithm>",
5188
5265
  "Hash algorithm (md5, sha1, sha256, sha512, bcrypt)",
5189
5266
  "sha256"
@@ -5205,7 +5282,7 @@ Examples:
5205
5282
  }
5206
5283
 
5207
5284
  // src/commands/utils/base64-encode.ts
5208
- import { Command as Command17 } from "commander";
5285
+ import { Command as Command18 } from "commander";
5209
5286
  import { readFile as readFile2 } from "fs/promises";
5210
5287
  async function handleBase64Encode(input, options) {
5211
5288
  const service = new UtilsService();
@@ -5238,7 +5315,7 @@ async function handleBase64Encode(input, options) {
5238
5315
  }
5239
5316
  }
5240
5317
  function createBase64EncodeCommand() {
5241
- 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", `
5318
+ const cmd = new Command18("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", `
5242
5319
  Examples:
5243
5320
  $ jai1 utils base64-encode "hello world"
5244
5321
  $ jai1 utils base64-encode "hello world" --url-safe
@@ -5251,7 +5328,7 @@ Examples:
5251
5328
  }
5252
5329
 
5253
5330
  // src/commands/utils/base64-decode.ts
5254
- import { Command as Command18 } from "commander";
5331
+ import { Command as Command19 } from "commander";
5255
5332
  import { readFile as readFile3, writeFile } from "fs/promises";
5256
5333
  async function handleBase64Decode(input, options) {
5257
5334
  const service = new UtilsService();
@@ -5283,7 +5360,7 @@ async function handleBase64Decode(input, options) {
5283
5360
  }
5284
5361
  }
5285
5362
  function createBase64DecodeCommand() {
5286
- 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", `
5363
+ const cmd = new Command19("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", `
5287
5364
  Examples:
5288
5365
  $ jai1 utils base64-decode "aGVsbG8gd29ybGQ="
5289
5366
  $ jai1 utils base64-decode --file ./encoded.txt
@@ -5296,7 +5373,7 @@ Examples:
5296
5373
  }
5297
5374
 
5298
5375
  // src/commands/utils/http.ts
5299
- import { Command as Command19 } from "commander";
5376
+ import { Command as Command20 } from "commander";
5300
5377
  import { readFile as readFile4 } from "fs/promises";
5301
5378
  async function handleHttpRequest(url, options) {
5302
5379
  const service = new UtilsService();
@@ -5362,7 +5439,7 @@ async function handleHttpRequest(url, options) {
5362
5439
  }
5363
5440
  }
5364
5441
  function createHttpCommand() {
5365
- 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", `
5442
+ const cmd = new Command20("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", `
5366
5443
  Examples:
5367
5444
  $ jai1 utils http https://api.example.com/users
5368
5445
  $ jai1 utils http https://api.example.com/users -X POST -d '{"name":"John"}'
@@ -5380,7 +5457,7 @@ Examples:
5380
5457
  }
5381
5458
 
5382
5459
  // src/commands/utils/jwt.ts
5383
- import { Command as Command20 } from "commander";
5460
+ import { Command as Command21 } from "commander";
5384
5461
  async function handleJwtDecode(token) {
5385
5462
  const service = new UtilsService();
5386
5463
  try {
@@ -5419,7 +5496,7 @@ async function handleJwtEncode(options) {
5419
5496
  }
5420
5497
  }
5421
5498
  function createJwtCommand() {
5422
- const jwtCommand = new Command20("jwt").description("Decode and encode JWT tokens");
5499
+ const jwtCommand = new Command21("jwt").description("Decode and encode JWT tokens");
5423
5500
  jwtCommand.command("decode").description("Decode JWT token").argument("<token>", "JWT token to decode").addHelpText("after", `
5424
5501
  Examples:
5425
5502
  $ jai1 utils jwt decode "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
@@ -5440,7 +5517,7 @@ Examples:
5440
5517
  }
5441
5518
 
5442
5519
  // src/commands/utils/unix-time.ts
5443
- import { Command as Command21 } from "commander";
5520
+ import { Command as Command22 } from "commander";
5444
5521
  async function handleUnixTime(input, options) {
5445
5522
  const service = new UtilsService();
5446
5523
  try {
@@ -5488,7 +5565,7 @@ async function handleUnixTime(input, options) {
5488
5565
  }
5489
5566
  }
5490
5567
  function createUnixTimeCommand() {
5491
- 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", `
5568
+ const cmd = new Command22("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", `
5492
5569
  Examples:
5493
5570
  $ jai1 utils unix-time
5494
5571
  $ jai1 utils unix-time 1702550400
@@ -5503,7 +5580,7 @@ Examples:
5503
5580
  }
5504
5581
 
5505
5582
  // src/commands/utils/timezone.ts
5506
- import { Command as Command22 } from "commander";
5583
+ import { Command as Command23 } from "commander";
5507
5584
  async function handleTimezoneConversion(time, options) {
5508
5585
  const service = new UtilsService();
5509
5586
  try {
@@ -5540,7 +5617,7 @@ async function handleTimezoneConversion(time, options) {
5540
5617
  }
5541
5618
  }
5542
5619
  function createTimezoneCommand() {
5543
- 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", `
5620
+ const cmd = new Command23("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", `
5544
5621
  Examples:
5545
5622
  $ jai1 utils timezone --list
5546
5623
  $ jai1 utils timezone "2024-01-15 10:00" --from "America/New_York" --to "Asia/Tokyo"
@@ -5553,7 +5630,7 @@ Examples:
5553
5630
  }
5554
5631
 
5555
5632
  // src/commands/utils/url-encode.ts
5556
- import { Command as Command23 } from "commander";
5633
+ import { Command as Command24 } from "commander";
5557
5634
  async function handleUrlEncode(input, options) {
5558
5635
  const service = new UtilsService();
5559
5636
  try {
@@ -5574,7 +5651,7 @@ async function handleUrlEncode(input, options) {
5574
5651
  }
5575
5652
  }
5576
5653
  function createUrlEncodeCommand() {
5577
- 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", `
5654
+ const cmd = new Command24("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", `
5578
5655
  Examples:
5579
5656
  $ jai1 utils url-encode "hello world"
5580
5657
  $ jai1 utils url-encode "hello world & test"
@@ -5587,7 +5664,7 @@ Examples:
5587
5664
  }
5588
5665
 
5589
5666
  // src/commands/utils/url-decode.ts
5590
- import { Command as Command24 } from "commander";
5667
+ import { Command as Command25 } from "commander";
5591
5668
  async function handleUrlDecode(input, options) {
5592
5669
  const service = new UtilsService();
5593
5670
  try {
@@ -5608,7 +5685,7 @@ async function handleUrlDecode(input, options) {
5608
5685
  }
5609
5686
  }
5610
5687
  function createUrlDecodeCommand() {
5611
- 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", `
5688
+ const cmd = new Command25("url-decode").description("Decode URL-encoded string").argument("<input>", "Text to decode").option("--full", "Decode full URL (use decodeURI instead of decodeURIComponent)").addHelpText("after", `
5612
5689
  Examples:
5613
5690
  $ jai1 utils url-decode "hello%20world"
5614
5691
  $ jai1 utils url-decode "hello%20world%20%26%20test"
@@ -5621,7 +5698,7 @@ Examples:
5621
5698
  }
5622
5699
 
5623
5700
  // src/commands/utils/cron.ts
5624
- import { Command as Command25 } from "commander";
5701
+ import { Command as Command26 } from "commander";
5625
5702
  import cronstrue from "cronstrue";
5626
5703
  async function handleCronParse(expression) {
5627
5704
  try {
@@ -5664,7 +5741,7 @@ async function handleCronParse(expression) {
5664
5741
  }
5665
5742
  }
5666
5743
  function createCronCommand() {
5667
- const cmd = new Command25("cron").description("Parse and explain cron expression").argument("<expression>", 'Cron expression (e.g., "0 5 * * *")').addHelpText("after", `
5744
+ const cmd = new Command26("cron").description("Parse and explain cron expression").argument("<expression>", 'Cron expression (e.g., "0 5 * * *")').addHelpText("after", `
5668
5745
  Examples:
5669
5746
  $ jai1 utils cron "0 5 * * *"
5670
5747
  $ jai1 utils cron "*/15 * * * *"
@@ -5678,7 +5755,7 @@ Examples:
5678
5755
  }
5679
5756
 
5680
5757
  // src/commands/utils/markdown-preview.ts
5681
- import { Command as Command26 } from "commander";
5758
+ import { Command as Command27 } from "commander";
5682
5759
  import { readFile as readFile5 } from "fs/promises";
5683
5760
  import { marked } from "marked";
5684
5761
  import TerminalRenderer from "marked-terminal";
@@ -5717,7 +5794,7 @@ ${code.trim()}
5717
5794
  }
5718
5795
  }
5719
5796
  function createMarkdownPreviewCommand() {
5720
- 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", `
5797
+ const cmd = new Command27("markdown-preview").description("Preview markdown file in terminal").argument("<file>", "Markdown file path").option("--raw", "Show raw markdown instead of rendered").addHelpText("after", `
5721
5798
  Examples:
5722
5799
  $ jai1 utils markdown-preview README.md
5723
5800
  $ jai1 utils markdown-preview ./docs/guide.md
@@ -7126,7 +7203,7 @@ async function runInteractiveMode() {
7126
7203
 
7127
7204
  // src/commands/utils/index.ts
7128
7205
  function createUtilsCommand() {
7129
- const utilsCommand = new Command27("utils").description("Developer utilities for common tasks").option("-i, --interactive", "Run in interactive mode").addHelpText("after", `
7206
+ const utilsCommand = new Command28("utils").description("Developer utilities for common tasks").option("-i, --interactive", "Run in interactive mode").addHelpText("after", `
7130
7207
  Interactive Mode:
7131
7208
  $ jai1 utils --interactive
7132
7209
  $ jai1 utils -i
@@ -7161,7 +7238,7 @@ Quick Usage:
7161
7238
  }
7162
7239
 
7163
7240
  // src/commands/upgrade.ts
7164
- import { Command as Command28 } from "commander";
7241
+ import { Command as Command29 } from "commander";
7165
7242
  import { confirm as confirm4 } from "@inquirer/prompts";
7166
7243
  import { execSync } from "child_process";
7167
7244
  var colors2 = {
@@ -7173,7 +7250,7 @@ var colors2 = {
7173
7250
  bold: "\x1B[1m"
7174
7251
  };
7175
7252
  function createUpgradeCommand() {
7176
- 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) => {
7253
+ return new Command29("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) => {
7177
7254
  await handleUpgrade(options);
7178
7255
  });
7179
7256
  }
@@ -7321,11 +7398,11 @@ function getInstallCommand(packageManager2) {
7321
7398
  }
7322
7399
 
7323
7400
  // src/commands/clean.ts
7324
- import { Command as Command29 } from "commander";
7401
+ import { Command as Command30 } from "commander";
7325
7402
  import { confirm as confirm5, select as select2 } from "@inquirer/prompts";
7326
7403
  import { join as join4 } from "path";
7327
7404
  function createCleanCommand() {
7328
- 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) => {
7405
+ return new Command30("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) => {
7329
7406
  await handleClean(options);
7330
7407
  });
7331
7408
  }
@@ -7438,7 +7515,7 @@ async function cleanTarget(target, skipConfirm) {
7438
7515
  }
7439
7516
 
7440
7517
  // src/commands/redmine/check.ts
7441
- import { Command as Command30 } from "commander";
7518
+ import { Command as Command31 } from "commander";
7442
7519
 
7443
7520
  // src/services/redmine-config.service.ts
7444
7521
  import { readFile as readFile6 } from "fs/promises";
@@ -7745,7 +7822,7 @@ async function checkConnectivity(config) {
7745
7822
 
7746
7823
  // src/commands/redmine/check.ts
7747
7824
  function createRedmineCheckCommand() {
7748
- 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) => {
7825
+ const cmd = new Command31("check").description("Check Redmine connectivity").option("-c, --config <path>", "Config file path", "redmine.config.yaml").option("--json", "Output as JSON").action(async (options) => {
7749
7826
  await handleRedmineCheck(options);
7750
7827
  });
7751
7828
  return cmd;
@@ -7773,7 +7850,7 @@ async function handleRedmineCheck(options) {
7773
7850
  }
7774
7851
 
7775
7852
  // src/commands/redmine/sync-issue.ts
7776
- import { Command as Command31 } from "commander";
7853
+ import { Command as Command32 } from "commander";
7777
7854
 
7778
7855
  // src/sync-issue.ts
7779
7856
  import { resolve as resolve3, relative } from "path";
@@ -8149,7 +8226,7 @@ function extractIssueIdFromUrl(url) {
8149
8226
 
8150
8227
  // src/commands/redmine/sync-issue.ts
8151
8228
  function createSyncIssueCommand() {
8152
- 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) => {
8229
+ const cmd = new Command32("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) => {
8153
8230
  await handleSyncIssue(options);
8154
8231
  });
8155
8232
  return cmd;
@@ -8193,7 +8270,7 @@ async function handleSyncIssue(options) {
8193
8270
  }
8194
8271
 
8195
8272
  // src/commands/redmine/sync-project.ts
8196
- import { Command as Command32 } from "commander";
8273
+ import { Command as Command33 } from "commander";
8197
8274
 
8198
8275
  // src/sync-project.ts
8199
8276
  async function syncProject(config, options = {}) {
@@ -8263,7 +8340,7 @@ async function syncProject(config, options = {}) {
8263
8340
 
8264
8341
  // src/commands/redmine/sync-project.ts
8265
8342
  function createSyncProjectCommand() {
8266
- 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) => {
8343
+ const cmd = new Command33("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) => {
8267
8344
  await handleSyncProject(options);
8268
8345
  });
8269
8346
  return cmd;
@@ -8318,12 +8395,12 @@ async function handleSyncProject(options) {
8318
8395
  }
8319
8396
 
8320
8397
  // src/commands/framework/info.ts
8321
- import { Command as Command33 } from "commander";
8398
+ import { Command as Command34 } from "commander";
8322
8399
  import { promises as fs9 } from "fs";
8323
8400
  import { join as join5 } from "path";
8324
8401
  import { homedir as homedir5 } from "os";
8325
8402
  function createInfoCommand() {
8326
- 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) => {
8403
+ const cmd = new Command34("info").description("Show jai1-client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
8327
8404
  await handleInfo(options);
8328
8405
  });
8329
8406
  return cmd;
@@ -8379,7 +8456,7 @@ async function getProjectStatus2() {
8379
8456
  }
8380
8457
 
8381
8458
  // src/commands/self-update.ts
8382
- import { Command as Command34 } from "commander";
8459
+ import { Command as Command35 } from "commander";
8383
8460
  import { confirm as confirm6 } from "@inquirer/prompts";
8384
8461
  import { execSync as execSync2 } from "child_process";
8385
8462
  var colors3 = {
@@ -8391,7 +8468,7 @@ var colors3 = {
8391
8468
  bold: "\x1B[1m"
8392
8469
  };
8393
8470
  function createSelfUpdateCommand() {
8394
- 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) => {
8471
+ return new Command35("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) => {
8395
8472
  await handleSelfUpdate(options);
8396
8473
  });
8397
8474
  }
@@ -8531,10 +8608,10 @@ function getInstallCommand2(packageManager2) {
8531
8608
  }
8532
8609
 
8533
8610
  // src/commands/clear-backups.ts
8534
- import { Command as Command35 } from "commander";
8611
+ import { Command as Command36 } from "commander";
8535
8612
  import { confirm as confirm7 } from "@inquirer/prompts";
8536
8613
  function createClearBackupsCommand() {
8537
- return new Command35("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
8614
+ return new Command36("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
8538
8615
  const service = new ComponentsService();
8539
8616
  const backups = await service.listBackups(process.cwd());
8540
8617
  if (backups.length === 0) {
@@ -8559,7 +8636,7 @@ function createClearBackupsCommand() {
8559
8636
  }
8560
8637
 
8561
8638
  // src/commands/vscode/index.ts
8562
- import { Command as Command36 } from "commander";
8639
+ import { Command as Command37 } from "commander";
8563
8640
  import { checkbox as checkbox3, confirm as confirm8, select as select3 } from "@inquirer/prompts";
8564
8641
  import fs10 from "fs/promises";
8565
8642
  import path6 from "path";
@@ -8699,7 +8776,7 @@ var PERFORMANCE_GROUPS2 = {
8699
8776
  }
8700
8777
  };
8701
8778
  function createVSCodeCommand() {
8702
- const vscodeCommand = new Command36("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
8779
+ const vscodeCommand = new Command37("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
8703
8780
  vscodeCommand.action(async () => {
8704
8781
  await interactiveMode2();
8705
8782
  });
@@ -8870,9 +8947,9 @@ async function resetSettings2(groupKeys) {
8870
8947
  // src/commands/guide.ts
8871
8948
  import React40 from "react";
8872
8949
  import { render as render6 } from "ink";
8873
- import { Command as Command37 } from "commander";
8950
+ import { Command as Command38 } from "commander";
8874
8951
  function createGuideCommand() {
8875
- 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) => {
8952
+ const cmd = new Command38("guide").description("Interactive guide center for Agentic Coding").option("--topic <topic>", "Open specific topic (intro, rules, workflows, prompts, skills)").action(async (options) => {
8876
8953
  const { waitUntilExit } = render6(
8877
8954
  React40.createElement(GuideApp, {
8878
8955
  initialTopic: options.topic,
@@ -8889,9 +8966,9 @@ function createGuideCommand() {
8889
8966
  // src/commands/context.ts
8890
8967
  import React41 from "react";
8891
8968
  import { render as render7 } from "ink";
8892
- import { Command as Command38 } from "commander";
8969
+ import { Command as Command39 } from "commander";
8893
8970
  function createContextCommand() {
8894
- 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) => {
8971
+ const cmd = new Command39("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) => {
8895
8972
  let initialIDE;
8896
8973
  if (options.ide) {
8897
8974
  const validIDEs = ["cursor", "windsurf", "antigravity", "jai1"];
@@ -8968,10 +9045,10 @@ async function printStats2() {
8968
9045
  }
8969
9046
 
8970
9047
  // src/commands/migrate-ide.ts
8971
- import { Command as Command39 } from "commander";
9048
+ import { Command as Command40 } from "commander";
8972
9049
  import { checkbox as checkbox4, confirm as confirm9 } from "@inquirer/prompts";
8973
9050
  function createMigrateIdeCommand() {
8974
- 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) => {
9051
+ const cmd = new Command40("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) => {
8975
9052
  await runMigrateIde(options);
8976
9053
  });
8977
9054
  return cmd;
@@ -9077,7 +9154,7 @@ async function runMigrateIde(options) {
9077
9154
  }
9078
9155
 
9079
9156
  // src/cli.ts
9080
- var program = new Command40();
9157
+ var program = new Command41();
9081
9158
  if (process.argv.includes("-v") || process.argv.includes("--version")) {
9082
9159
  console.log(package_default.version);
9083
9160
  if (!process.argv.includes("--skip-update-check")) {
@@ -9095,14 +9172,15 @@ program.addCommand(createCheckCommand());
9095
9172
  program.addCommand(createIdeCommand());
9096
9173
  program.addCommand(createLearnCommand());
9097
9174
  program.addCommand(createChatCommand());
9098
- program.addCommand(createApiKeysCommand());
9175
+ program.addCommand(createOpenAiKeysCommand());
9176
+ program.addCommand(createStatsCommand());
9099
9177
  program.addCommand(createTranslateCommand());
9100
9178
  program.addCommand(createUtilsCommand());
9101
9179
  program.addCommand(createUpgradeCommand());
9102
9180
  program.addCommand(createCleanCommand());
9103
- var redmineCommand = new Command40("redmine").description("Redmine context sync commands");
9181
+ var redmineCommand = new Command41("redmine").description("Redmine context sync commands");
9104
9182
  redmineCommand.addCommand(createRedmineCheckCommand());
9105
- var syncCommand = new Command40("sync").description("Sync Redmine issues to markdown files");
9183
+ var syncCommand = new Command41("sync").description("Sync Redmine issues to markdown files");
9106
9184
  syncCommand.addCommand(createSyncIssueCommand());
9107
9185
  syncCommand.addCommand(createSyncProjectCommand());
9108
9186
  redmineCommand.addCommand(syncCommand);
@@ -9137,7 +9215,8 @@ program.on("command:*", (operands) => {
9137
9215
  console.error("");
9138
9216
  console.error(" \u{1F916} LLM Proxy");
9139
9217
  console.error(" chat Interactive AI chat");
9140
- console.error(" api-keys Show OpenAI-compatible API credentials");
9218
+ console.error(" openai-keys Show OpenAI-compatible API credentials");
9219
+ console.error(" stats Show LLM usage statistics and limits");
9141
9220
  console.error(" translate Translate text, files, or folders using AI");
9142
9221
  console.error("");
9143
9222
  console.error(" \u{1F6E0}\uFE0F Developer Utilities");