@jvittechs/jai1-cli 0.1.90 → 0.1.92

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 Command55 } from "commander";
4
+ import { Command as Command60 } 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.90",
36
+ version: "0.1.92",
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: {
@@ -97,6 +97,7 @@ var package_default = {
97
97
  "p-retry": "^6.2.0",
98
98
  react: "^18.3.1",
99
99
  slugify: "^1.6.6",
100
+ "terminal-image": "^4.1.0",
100
101
  undici: "^6.19.5",
101
102
  yaml: "^2.5.0",
102
103
  zod: "^3.23.8"
@@ -539,7 +540,11 @@ var ComponentsService = class {
539
540
  const bundleJson = gunzipSync(compressed).toString("utf-8");
540
541
  checksumContent = bundleJson;
541
542
  const bundle = JSON.parse(bundleJson);
542
- const presetDir = join2(targetDir, filepath);
543
+ const presetDir = join2(targetDir, "rule-preset");
544
+ try {
545
+ await fs2.rm(presetDir, { recursive: true, force: true });
546
+ } catch {
547
+ }
543
548
  await fs2.mkdir(presetDir, { recursive: true });
544
549
  await fs2.writeFile(
545
550
  join2(presetDir, "preset.json"),
@@ -879,7 +884,7 @@ var UnifiedApplyApp = ({
879
884
  const [searchQuery, setSearchQuery] = useState("");
880
885
  const [selectedPaths, setSelectedPaths] = useState(/* @__PURE__ */ new Set());
881
886
  const [cursorIndex, setCursorIndex] = useState(0);
882
- const [focusArea, setFocusArea] = useState("components");
887
+ const [focusArea, setFocusArea] = useState("packages");
883
888
  const [selectedPackageIndex, setSelectedPackageIndex] = useState(0);
884
889
  const [installProgress, setInstallProgress] = useState([]);
885
890
  const [installStats, setInstallStats] = useState({ total: 0, completed: 0, added: 0, updated: 0, failed: 0 });
@@ -922,9 +927,9 @@ var UnifiedApplyApp = ({
922
927
  return;
923
928
  }
924
929
  if (key.tab) {
925
- if (focusArea === "search") setFocusArea("packages");
926
- else if (focusArea === "packages") setFocusArea("components");
927
- else setFocusArea("search");
930
+ if (focusArea === "packages") setFocusArea("components");
931
+ else if (focusArea === "components") setFocusArea("search");
932
+ else setFocusArea("packages");
928
933
  return;
929
934
  }
930
935
  if (key.escape || input4 === "q") {
@@ -937,6 +942,19 @@ var UnifiedApplyApp = ({
937
942
  }
938
943
  return;
939
944
  }
945
+ if (focusArea !== "search") {
946
+ if (input4 === "a") {
947
+ setSelectedPaths((prev) => {
948
+ const next = new Set(prev);
949
+ filteredComponents.forEach((c) => next.add(c.filepath));
950
+ return next;
951
+ });
952
+ return;
953
+ } else if (input4 === "c") {
954
+ setSelectedPaths(/* @__PURE__ */ new Set());
955
+ return;
956
+ }
957
+ }
940
958
  if (focusArea === "components") {
941
959
  if (key.upArrow) {
942
960
  setCursorIndex((prev) => Math.max(0, prev - 1));
@@ -955,14 +973,6 @@ var UnifiedApplyApp = ({
955
973
  return next;
956
974
  });
957
975
  }
958
- } else if (input4 === "a") {
959
- setSelectedPaths((prev) => {
960
- const next = new Set(prev);
961
- filteredComponents.forEach((c) => next.add(c.filepath));
962
- return next;
963
- });
964
- } else if (input4 === "c") {
965
- setSelectedPaths(/* @__PURE__ */ new Set());
966
976
  }
967
977
  }
968
978
  if (focusArea === "packages") {
@@ -1067,7 +1077,7 @@ var UnifiedApplyApp = ({
1067
1077
  const isChecked = selectedPaths.has(comp.filepath);
1068
1078
  const isInstalled = installedPaths.has(comp.filepath);
1069
1079
  return /* @__PURE__ */ React3.createElement(Box2, { key: comp.filepath }, /* @__PURE__ */ React3.createElement(Text3, { color: isCursor ? "cyan" : "white" }, isCursor ? "\u276F " : " ", isChecked ? "[\u2713]" : "[ ]", " ", comp.filepath), /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, " ", isInstalled ? "\u2713 installed" : "\u25CB new"));
1070
- }), filteredComponents.length === 0 && /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "No components match your search")), selectedPaths.size > 0 && /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Selected: ", selectedPaths.size, " components"), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", marginLeft: 2 }, Array.from(selectedPaths).slice(0, 4).map((fp) => /* @__PURE__ */ React3.createElement(Text3, { key: fp, dimColor: true }, "\u{1F4CC} ", fp)), selectedPaths.size > 4 && /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, " ... and ", selectedPaths.size - 4, " more"))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "[Tab] Switch area \xB7 [\u2191\u2193] Navigate \xB7 [\u2423] Toggle \xB7 [a] Select all \xB7 [c] Clear \xB7 [Enter] Apply \xB7 [q] Quit")));
1080
+ }), filteredComponents.length === 0 && /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "No components match your search")), selectedPaths.size > 0 && /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Selected: ", selectedPaths.size, " components"), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", marginLeft: 2 }, Array.from(selectedPaths).slice(0, 4).map((fp) => /* @__PURE__ */ React3.createElement(Text3, { key: fp, dimColor: true }, "\u{1F4CC} ", fp)), selectedPaths.size > 4 && /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, " ... and ", selectedPaths.size - 4, " more"))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "[Tab] Switch area \xB7 [\u2191\u2193/\u2190\u2192] Navigate \xB7 [\u2423] Toggle \xB7 [A] Select all \xB7 [C] Clear \xB7 [Enter] Apply \xB7 [Q] Quit")));
1071
1081
  };
1072
1082
 
1073
1083
  // src/commands/apply.ts
@@ -2529,17 +2539,20 @@ trigger: ${trigger}
2529
2539
  name: "Claude Code",
2530
2540
  icon: "\u{1F916}",
2531
2541
  basePath: ".claude",
2532
- rulesPath: null,
2542
+ rulesPath: "rules",
2533
2543
  workflowsPath: null,
2534
2544
  commandsPath: "commands",
2535
2545
  fileExtension: ".md",
2536
2546
  generateFrontmatter: (opts) => {
2547
+ const lines = ["---"];
2537
2548
  if (opts.description) {
2538
- return `---
2539
- description: ${opts.description}
2540
- ---`;
2549
+ lines.push(`description: ${opts.description}`);
2541
2550
  }
2542
- return "";
2551
+ if (opts.globs && opts.globs.length > 0) {
2552
+ lines.push(`paths: ${opts.globs.join(", ")}`);
2553
+ }
2554
+ lines.push("---");
2555
+ return lines.join("\n");
2543
2556
  }
2544
2557
  },
2545
2558
  opencode: {
@@ -2575,7 +2588,9 @@ var MigrateIdeService = class {
2575
2588
  * Scan .jai1/ directory for content
2576
2589
  */
2577
2590
  async scanJai1Content() {
2578
- const rules = await this.scanContentType("rules");
2591
+ const manualRules = await this.scanContentType("rules");
2592
+ const presetRules = await this.scanRulePreset();
2593
+ const rules = [...presetRules, ...manualRules];
2579
2594
  const workflows = await this.scanContentType("workflows");
2580
2595
  const commands = [];
2581
2596
  return {
@@ -2585,6 +2600,42 @@ var MigrateIdeService = class {
2585
2600
  totalCount: rules.length + workflows.length + commands.length
2586
2601
  };
2587
2602
  }
2603
+ /**
2604
+ * Scan .jai1/rule-preset/ directory for rule preset files
2605
+ */
2606
+ async scanRulePreset() {
2607
+ const items = [];
2608
+ const presetDir = path3.join(this.jai1Path, "rule-preset");
2609
+ try {
2610
+ await fs6.access(presetDir);
2611
+ } catch {
2612
+ return items;
2613
+ }
2614
+ const files = await fs6.readdir(presetDir);
2615
+ for (const file of files) {
2616
+ if (!file.endsWith(".mdc")) continue;
2617
+ const filepath = path3.join(presetDir, file);
2618
+ const stat = await fs6.stat(filepath);
2619
+ if (!stat.isFile()) continue;
2620
+ const content = await fs6.readFile(filepath, "utf-8");
2621
+ let frontmatter = {};
2622
+ try {
2623
+ const { data } = matter2(content);
2624
+ frontmatter = data;
2625
+ } catch {
2626
+ }
2627
+ items.push({
2628
+ type: "rules",
2629
+ name: path3.basename(file, ".mdc"),
2630
+ filepath,
2631
+ relativePath: path3.relative(this.projectPath, filepath),
2632
+ description: frontmatter.description,
2633
+ globs: this.extractGlobs(frontmatter),
2634
+ alwaysApply: this.extractAlwaysApply(frontmatter)
2635
+ });
2636
+ }
2637
+ return items;
2638
+ }
2588
2639
  /**
2589
2640
  * Scan a specific content type
2590
2641
  */
@@ -2708,7 +2759,7 @@ ${reference}
2708
2759
  contentPath = config.rulesPath;
2709
2760
  break;
2710
2761
  case "workflows":
2711
- contentPath = config.workflowsPath;
2762
+ contentPath = config.workflowsPath ?? config.commandsPath;
2712
2763
  break;
2713
2764
  case "commands":
2714
2765
  contentPath = config.commandsPath;
@@ -2743,13 +2794,17 @@ async function runSync(options) {
2743
2794
  const service = new MigrateIdeService();
2744
2795
  console.log("\n\u{1F504} Sync rules and workflows to IDE(s)\n");
2745
2796
  console.log("\u{1F4C1} Scanning .jai1/ directory...");
2797
+ console.log(" \u2022 .jai1/rule-preset/ (active rule preset)");
2798
+ console.log(" \u2022 .jai1/rules/ (manual rules)");
2799
+ console.log(" \u2022 .jai1/workflows/\n");
2746
2800
  const content = await service.scanJai1Content();
2747
2801
  if (content.totalCount === 0) {
2748
- console.log("\n\u26A0\uFE0F No content found in .jai1/");
2749
- console.log(" \u{1F4A1} Create files in .jai1/rules/ or .jai1/workflows/ first.\n");
2802
+ console.log("\u26A0\uFE0F No content found in .jai1/");
2803
+ console.log(' \u{1F4A1} Run "jai1 rules apply" to apply a rule preset, or');
2804
+ console.log(" \u{1F4A1} Create files in .jai1/rules/ or .jai1/workflows/\n");
2750
2805
  process.exit(1);
2751
2806
  }
2752
- console.log(` Found: ${content.rules.length} rules, ${content.workflows.length} workflows
2807
+ console.log(`\u2713 Found: ${content.rules.length} rules, ${content.workflows.length} workflows
2753
2808
  `);
2754
2809
  let selectedIdes;
2755
2810
  if (options.ide && options.ide.length > 0) {
@@ -5360,11 +5415,266 @@ function createTranslateCommand() {
5360
5415
  return cmd;
5361
5416
  }
5362
5417
 
5418
+ // src/commands/image/index.ts
5419
+ import { Command as Command20 } from "commander";
5420
+
5421
+ // src/commands/image/gen.ts
5422
+ import { Command as Command16 } from "commander";
5423
+
5424
+ // src/services/image.service.ts
5425
+ var ImageService = class {
5426
+ /**
5427
+ * Generate image from prompt
5428
+ */
5429
+ async generate(config, options) {
5430
+ const response = await fetch(`${config.apiUrl}/api/image/generate`, {
5431
+ method: "POST",
5432
+ headers: {
5433
+ "Content-Type": "application/json",
5434
+ "JAI1-Access-Key": config.accessKey
5435
+ },
5436
+ body: JSON.stringify(options)
5437
+ });
5438
+ if (!response.ok) {
5439
+ let errorMessage = `HTTP ${response.status}`;
5440
+ try {
5441
+ const error = await response.json();
5442
+ errorMessage = error.message || errorMessage;
5443
+ } catch (e) {
5444
+ }
5445
+ throw new NetworkError(errorMessage);
5446
+ }
5447
+ const data = await response.json();
5448
+ return data.data;
5449
+ }
5450
+ /**
5451
+ * List generated images
5452
+ */
5453
+ async list(config, options) {
5454
+ const params = new URLSearchParams();
5455
+ if (options.model) params.set("model", options.model);
5456
+ if (options.limit) params.set("limit", options.limit.toString());
5457
+ if (options.offset) params.set("offset", options.offset.toString());
5458
+ const url = `${config.apiUrl}/api/image/list?${params}`;
5459
+ const response = await fetch(url, {
5460
+ headers: {
5461
+ "JAI1-Access-Key": config.accessKey
5462
+ }
5463
+ });
5464
+ if (!response.ok) {
5465
+ throw new NetworkError(`Failed to list images: HTTP ${response.status}`);
5466
+ }
5467
+ const data = await response.json();
5468
+ return data.data;
5469
+ }
5470
+ /**
5471
+ * Get image info
5472
+ */
5473
+ async getInfo(config, id) {
5474
+ const response = await fetch(`${config.apiUrl}/api/image/${id}`, {
5475
+ headers: {
5476
+ "JAI1-Access-Key": config.accessKey
5477
+ }
5478
+ });
5479
+ if (!response.ok) {
5480
+ if (response.status === 404) {
5481
+ throw new Error("Image not found");
5482
+ }
5483
+ throw new NetworkError(`Failed to get image: HTTP ${response.status}`);
5484
+ }
5485
+ const data = await response.json();
5486
+ return data.data;
5487
+ }
5488
+ /**
5489
+ * Delete image
5490
+ */
5491
+ async delete(config, id) {
5492
+ const response = await fetch(`${config.apiUrl}/api/image/${id}`, {
5493
+ method: "DELETE",
5494
+ headers: {
5495
+ "JAI1-Access-Key": config.accessKey
5496
+ }
5497
+ });
5498
+ if (!response.ok) {
5499
+ if (response.status === 404) {
5500
+ throw new Error("Image not found");
5501
+ }
5502
+ throw new NetworkError(`Failed to delete image: HTTP ${response.status}`);
5503
+ }
5504
+ }
5505
+ };
5506
+
5507
+ // src/commands/image/gen.ts
5508
+ import terminalImage from "terminal-image";
5509
+ function createImageGenCommand() {
5510
+ return new Command16("gen").description("Generate an image from text prompt").argument("<prompt>", "Image description prompt").option("-m, --model <model>", "Model to use", "gemini-3-flash-preview").option("-w, --width <number>", "Image width").option("-h, --height <number>", "Image height").option("-r, --ratio <ratio>", "Aspect ratio (1:1, 16:9, 9:16, 4:3, 3:4)").option("--negative <prompt>", "Negative prompt").option("--seed <number>", "Random seed").option("--no-display", "Don't display image in terminal").action(async (prompt, options) => {
5511
+ const configService = new ConfigService();
5512
+ const config = await configService.load();
5513
+ if (!config) {
5514
+ throw new ValidationError('Not initialized. Run "jai1 auth" first.');
5515
+ }
5516
+ const imageService = new ImageService();
5517
+ console.log("\u{1F3A8} Generating image...");
5518
+ console.log(` Prompt: ${prompt}`);
5519
+ console.log(` Model: ${options.model}`);
5520
+ try {
5521
+ const result = await imageService.generate(config, {
5522
+ prompt,
5523
+ model: options.model,
5524
+ ...options.width && { width: parseInt(options.width) },
5525
+ ...options.height && { height: parseInt(options.height) },
5526
+ ...options.ratio && { aspectRatio: options.ratio },
5527
+ ...options.negative && { negativePrompt: options.negative },
5528
+ ...options.seed && { seed: parseInt(options.seed) }
5529
+ });
5530
+ console.log("\n\u2705 Image generated successfully!");
5531
+ console.log(` URL: ${result.url}`);
5532
+ console.log(` Size: ${(result.contentSize / 1024).toFixed(2)} KB`);
5533
+ console.log(` ID: ${result.id}`);
5534
+ if (options.display !== false) {
5535
+ try {
5536
+ const imageResponse = await fetch(result.url);
5537
+ const arrayBuffer = await imageResponse.arrayBuffer();
5538
+ const imageBuffer = Buffer.from(arrayBuffer);
5539
+ const rendered = await terminalImage.buffer(imageBuffer, {
5540
+ width: "50%",
5541
+ height: "50%"
5542
+ });
5543
+ console.log("\n" + rendered);
5544
+ } catch (displayError) {
5545
+ }
5546
+ }
5547
+ console.log('\n\u{1F4A1} Tip: Use "jai1 image list" to view all your images');
5548
+ console.log(' Use "jai1 image info <id>" for details');
5549
+ } catch (error) {
5550
+ if (error instanceof Error) {
5551
+ if (error.message.includes("Rate limit")) {
5552
+ console.error("\n\u26A0\uFE0F Rate limit exceeded");
5553
+ console.error(' Use "jai1 image limits" to check your quota');
5554
+ } else {
5555
+ throw error;
5556
+ }
5557
+ }
5558
+ throw error;
5559
+ }
5560
+ });
5561
+ }
5562
+
5563
+ // src/commands/image/list.ts
5564
+ import { Command as Command17 } from "commander";
5565
+ function createImageListCommand() {
5566
+ return new Command17("list").description("List generated images").option("-m, --model <model>", "Filter by model").option("-l, --limit <number>", "Number of results", "20").option("-o, --offset <number>", "Offset for pagination", "0").action(async (options) => {
5567
+ const configService = new ConfigService();
5568
+ const config = await configService.load();
5569
+ if (!config) {
5570
+ throw new ValidationError('Not initialized. Run "jai1 auth" first.');
5571
+ }
5572
+ const imageService = new ImageService();
5573
+ const result = await imageService.list(config, {
5574
+ model: options.model,
5575
+ limit: parseInt(options.limit),
5576
+ offset: parseInt(options.offset)
5577
+ });
5578
+ if (result.images.length === 0) {
5579
+ console.log("No images found.");
5580
+ return;
5581
+ }
5582
+ console.log(`
5583
+ \u{1F4F8} Your Generated Images (${result.total} total):
5584
+ `);
5585
+ for (const img of result.images) {
5586
+ const date = new Date(img.createdAt).toLocaleString();
5587
+ const promptPreview = img.prompt.length > 50 ? img.prompt.slice(0, 50) + "..." : img.prompt;
5588
+ console.log(`ID: ${img.id.toString().padEnd(6)} | ${date}`);
5589
+ console.log(` Model: ${img.model}`);
5590
+ console.log(` Prompt: ${promptPreview}`);
5591
+ console.log(` URL: ${img.url}`);
5592
+ console.log();
5593
+ }
5594
+ if (result.total > result.offset + result.limit) {
5595
+ const nextOffset = result.offset + result.limit;
5596
+ console.log(`\u{1F4A1} Show more: jai1 image list -o ${nextOffset}`);
5597
+ }
5598
+ });
5599
+ }
5600
+
5601
+ // src/commands/image/info.ts
5602
+ import { Command as Command18 } from "commander";
5603
+ function createImageInfoCommand() {
5604
+ return new Command18("info").description("Get detailed info about an image").argument("<id>", "Image ID").action(async (id) => {
5605
+ const configService = new ConfigService();
5606
+ const config = await configService.load();
5607
+ if (!config) {
5608
+ throw new ValidationError('Not initialized. Run "jai1 auth" first.');
5609
+ }
5610
+ const imageService = new ImageService();
5611
+ const image = await imageService.getInfo(config, parseInt(id));
5612
+ console.log("\n\u{1F4F8} Image Details:\n");
5613
+ console.log(`ID: ${image.id}`);
5614
+ console.log(`Model: ${image.model}`);
5615
+ console.log(`Prompt: ${image.prompt}`);
5616
+ console.log(`URL: ${image.url}`);
5617
+ console.log(`Size: ${(image.contentSize / 1024).toFixed(2)} KB`);
5618
+ if (image.width && image.height) {
5619
+ console.log(`Dimensions: ${image.width}x${image.height}`);
5620
+ }
5621
+ console.log(`Created: ${new Date(image.createdAt).toLocaleString()}`);
5622
+ if (image.metadata) {
5623
+ const meta = typeof image.metadata === "string" ? JSON.parse(image.metadata) : image.metadata;
5624
+ if (meta.aspectRatio) {
5625
+ console.log(`Ratio: ${meta.aspectRatio}`);
5626
+ }
5627
+ if (meta.negativePrompt) {
5628
+ console.log(`Negative: ${meta.negativePrompt}`);
5629
+ }
5630
+ if (meta.seed) {
5631
+ console.log(`Seed: ${meta.seed}`);
5632
+ }
5633
+ }
5634
+ });
5635
+ }
5636
+
5637
+ // src/commands/image/delete.ts
5638
+ import { Command as Command19 } from "commander";
5639
+ import { confirm as confirm4 } from "@inquirer/prompts";
5640
+ function createImageDeleteCommand() {
5641
+ return new Command19("delete").description("Delete a generated image").argument("<id>", "Image ID").option("-y, --yes", "Skip confirmation").action(async (id, options) => {
5642
+ const configService = new ConfigService();
5643
+ const config = await configService.load();
5644
+ if (!config) {
5645
+ throw new ValidationError('Not initialized. Run "jai1 auth" first.');
5646
+ }
5647
+ if (!options.yes) {
5648
+ const confirmed = await confirm4({
5649
+ message: `Are you sure you want to delete image #${id}?`,
5650
+ default: false
5651
+ });
5652
+ if (!confirmed) {
5653
+ console.log("Cancelled.");
5654
+ return;
5655
+ }
5656
+ }
5657
+ const imageService = new ImageService();
5658
+ await imageService.delete(config, parseInt(id));
5659
+ console.log(`\u2705 Image #${id} deleted successfully.`);
5660
+ });
5661
+ }
5662
+
5663
+ // src/commands/image/index.ts
5664
+ function createImageCommand() {
5665
+ const cmd = new Command20("image").description("Image generation commands");
5666
+ cmd.addCommand(createImageGenCommand());
5667
+ cmd.addCommand(createImageListCommand());
5668
+ cmd.addCommand(createImageInfoCommand());
5669
+ cmd.addCommand(createImageDeleteCommand());
5670
+ return cmd;
5671
+ }
5672
+
5363
5673
  // src/commands/utils/index.ts
5364
- import { Command as Command29 } from "commander";
5674
+ import { Command as Command34 } from "commander";
5365
5675
 
5366
5676
  // src/commands/utils/password.ts
5367
- import { Command as Command16 } from "commander";
5677
+ import { Command as Command21 } from "commander";
5368
5678
 
5369
5679
  // src/services/utils.service.ts
5370
5680
  import crypto from "crypto";
@@ -5633,7 +5943,7 @@ async function handlePasswordGeneration(options) {
5633
5943
  }
5634
5944
  }
5635
5945
  function createPasswordCommand() {
5636
- const cmd = new Command16("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", `
5946
+ const cmd = new Command21("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", `
5637
5947
  Examples:
5638
5948
  $ jai1 utils password
5639
5949
  $ jai1 utils password --length 24
@@ -5651,7 +5961,7 @@ Examples:
5651
5961
  }
5652
5962
 
5653
5963
  // src/commands/utils/uuid.ts
5654
- import { Command as Command17 } from "commander";
5964
+ import { Command as Command22 } from "commander";
5655
5965
  async function handleUuidGeneration(options) {
5656
5966
  const service = new UtilsService();
5657
5967
  try {
@@ -5679,7 +5989,7 @@ async function handleUuidGeneration(options) {
5679
5989
  }
5680
5990
  }
5681
5991
  function createUuidCommand() {
5682
- const cmd = new Command17("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", `
5992
+ const cmd = new Command22("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", `
5683
5993
  Examples:
5684
5994
  $ jai1 utils uuid
5685
5995
  $ jai1 utils uuid --count 10
@@ -5696,7 +6006,7 @@ Examples:
5696
6006
  }
5697
6007
 
5698
6008
  // src/commands/utils/hash.ts
5699
- import { Command as Command18 } from "commander";
6009
+ import { Command as Command23 } from "commander";
5700
6010
  async function handleHashGeneration(input4, options) {
5701
6011
  const service = new UtilsService();
5702
6012
  try {
@@ -5736,7 +6046,7 @@ async function handleHashGeneration(input4, options) {
5736
6046
  }
5737
6047
  }
5738
6048
  function createHashCommand() {
5739
- const cmd = new Command18("hash").description("Generate hash (MD5, SHA, bcrypt)").argument("[input]", "Text to hash").option(
6049
+ const cmd = new Command23("hash").description("Generate hash (MD5, SHA, bcrypt)").argument("[input]", "Text to hash").option(
5740
6050
  "-a, --algorithm <algorithm>",
5741
6051
  "Hash algorithm (md5, sha1, sha256, sha512, bcrypt)",
5742
6052
  "sha256"
@@ -5758,7 +6068,7 @@ Examples:
5758
6068
  }
5759
6069
 
5760
6070
  // src/commands/utils/base64-encode.ts
5761
- import { Command as Command19 } from "commander";
6071
+ import { Command as Command24 } from "commander";
5762
6072
  import { readFile as readFile2 } from "fs/promises";
5763
6073
  async function handleBase64Encode(input4, options) {
5764
6074
  const service = new UtilsService();
@@ -5791,7 +6101,7 @@ async function handleBase64Encode(input4, options) {
5791
6101
  }
5792
6102
  }
5793
6103
  function createBase64EncodeCommand() {
5794
- const cmd = new Command19("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", `
6104
+ const cmd = new Command24("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", `
5795
6105
  Examples:
5796
6106
  $ jai1 utils base64-encode "hello world"
5797
6107
  $ jai1 utils base64-encode "hello world" --url-safe
@@ -5804,7 +6114,7 @@ Examples:
5804
6114
  }
5805
6115
 
5806
6116
  // src/commands/utils/base64-decode.ts
5807
- import { Command as Command20 } from "commander";
6117
+ import { Command as Command25 } from "commander";
5808
6118
  import { readFile as readFile3, writeFile } from "fs/promises";
5809
6119
  async function handleBase64Decode(input4, options) {
5810
6120
  const service = new UtilsService();
@@ -5836,7 +6146,7 @@ async function handleBase64Decode(input4, options) {
5836
6146
  }
5837
6147
  }
5838
6148
  function createBase64DecodeCommand() {
5839
- const cmd = new Command20("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", `
6149
+ const cmd = new Command25("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", `
5840
6150
  Examples:
5841
6151
  $ jai1 utils base64-decode "aGVsbG8gd29ybGQ="
5842
6152
  $ jai1 utils base64-decode --file ./encoded.txt
@@ -5849,7 +6159,7 @@ Examples:
5849
6159
  }
5850
6160
 
5851
6161
  // src/commands/utils/http.ts
5852
- import { Command as Command21 } from "commander";
6162
+ import { Command as Command26 } from "commander";
5853
6163
  import { readFile as readFile4 } from "fs/promises";
5854
6164
  async function handleHttpRequest(url, options) {
5855
6165
  const service = new UtilsService();
@@ -5915,7 +6225,7 @@ async function handleHttpRequest(url, options) {
5915
6225
  }
5916
6226
  }
5917
6227
  function createHttpCommand() {
5918
- const cmd = new Command21("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", `
6228
+ const cmd = new Command26("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", `
5919
6229
  Examples:
5920
6230
  $ jai1 utils http https://api.example.com/users
5921
6231
  $ jai1 utils http https://api.example.com/users -X POST -d '{"name":"John"}'
@@ -5933,7 +6243,7 @@ Examples:
5933
6243
  }
5934
6244
 
5935
6245
  // src/commands/utils/jwt.ts
5936
- import { Command as Command22 } from "commander";
6246
+ import { Command as Command27 } from "commander";
5937
6247
  async function handleJwtDecode(token) {
5938
6248
  const service = new UtilsService();
5939
6249
  try {
@@ -5972,7 +6282,7 @@ async function handleJwtEncode(options) {
5972
6282
  }
5973
6283
  }
5974
6284
  function createJwtCommand() {
5975
- const jwtCommand = new Command22("jwt").description("Decode and encode JWT tokens");
6285
+ const jwtCommand = new Command27("jwt").description("Decode and encode JWT tokens");
5976
6286
  jwtCommand.command("decode").description("Decode JWT token").argument("<token>", "JWT token to decode").addHelpText("after", `
5977
6287
  Examples:
5978
6288
  $ jai1 utils jwt decode "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
@@ -5993,7 +6303,7 @@ Examples:
5993
6303
  }
5994
6304
 
5995
6305
  // src/commands/utils/unix-time.ts
5996
- import { Command as Command23 } from "commander";
6306
+ import { Command as Command28 } from "commander";
5997
6307
  async function handleUnixTime(input4, options) {
5998
6308
  const service = new UtilsService();
5999
6309
  try {
@@ -6041,7 +6351,7 @@ async function handleUnixTime(input4, options) {
6041
6351
  }
6042
6352
  }
6043
6353
  function createUnixTimeCommand() {
6044
- const cmd = new Command23("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", `
6354
+ const cmd = new Command28("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", `
6045
6355
  Examples:
6046
6356
  $ jai1 utils unix-time
6047
6357
  $ jai1 utils unix-time 1702550400
@@ -6056,7 +6366,7 @@ Examples:
6056
6366
  }
6057
6367
 
6058
6368
  // src/commands/utils/timezone.ts
6059
- import { Command as Command24 } from "commander";
6369
+ import { Command as Command29 } from "commander";
6060
6370
  async function handleTimezoneConversion(time, options) {
6061
6371
  const service = new UtilsService();
6062
6372
  try {
@@ -6093,7 +6403,7 @@ async function handleTimezoneConversion(time, options) {
6093
6403
  }
6094
6404
  }
6095
6405
  function createTimezoneCommand() {
6096
- const cmd = new Command24("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", `
6406
+ const cmd = new Command29("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", `
6097
6407
  Examples:
6098
6408
  $ jai1 utils timezone --list
6099
6409
  $ jai1 utils timezone "2024-01-15 10:00" --from "America/New_York" --to "Asia/Tokyo"
@@ -6106,7 +6416,7 @@ Examples:
6106
6416
  }
6107
6417
 
6108
6418
  // src/commands/utils/url-encode.ts
6109
- import { Command as Command25 } from "commander";
6419
+ import { Command as Command30 } from "commander";
6110
6420
  async function handleUrlEncode(input4, options) {
6111
6421
  const service = new UtilsService();
6112
6422
  try {
@@ -6127,7 +6437,7 @@ async function handleUrlEncode(input4, options) {
6127
6437
  }
6128
6438
  }
6129
6439
  function createUrlEncodeCommand() {
6130
- const cmd = new Command25("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", `
6440
+ const cmd = new Command30("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", `
6131
6441
  Examples:
6132
6442
  $ jai1 utils url-encode "hello world"
6133
6443
  $ jai1 utils url-encode "hello world & test"
@@ -6140,7 +6450,7 @@ Examples:
6140
6450
  }
6141
6451
 
6142
6452
  // src/commands/utils/url-decode.ts
6143
- import { Command as Command26 } from "commander";
6453
+ import { Command as Command31 } from "commander";
6144
6454
  async function handleUrlDecode(input4, options) {
6145
6455
  const service = new UtilsService();
6146
6456
  try {
@@ -6161,7 +6471,7 @@ async function handleUrlDecode(input4, options) {
6161
6471
  }
6162
6472
  }
6163
6473
  function createUrlDecodeCommand() {
6164
- const cmd = new Command26("url-decode").description("Decode URL-encoded string").argument("<input>", "Text to decode").option("--full", "Decode full URL (use decodeURI instead of decodeURIComponent)").addHelpText("after", `
6474
+ const cmd = new Command31("url-decode").description("Decode URL-encoded string").argument("<input>", "Text to decode").option("--full", "Decode full URL (use decodeURI instead of decodeURIComponent)").addHelpText("after", `
6165
6475
  Examples:
6166
6476
  $ jai1 utils url-decode "hello%20world"
6167
6477
  $ jai1 utils url-decode "hello%20world%20%26%20test"
@@ -6174,7 +6484,7 @@ Examples:
6174
6484
  }
6175
6485
 
6176
6486
  // src/commands/utils/cron.ts
6177
- import { Command as Command27 } from "commander";
6487
+ import { Command as Command32 } from "commander";
6178
6488
  import cronstrue from "cronstrue";
6179
6489
  async function handleCronParse(expression) {
6180
6490
  try {
@@ -6217,7 +6527,7 @@ async function handleCronParse(expression) {
6217
6527
  }
6218
6528
  }
6219
6529
  function createCronCommand() {
6220
- const cmd = new Command27("cron").description("Parse and explain cron expression").argument("<expression>", 'Cron expression (e.g., "0 5 * * *")').addHelpText("after", `
6530
+ const cmd = new Command32("cron").description("Parse and explain cron expression").argument("<expression>", 'Cron expression (e.g., "0 5 * * *")').addHelpText("after", `
6221
6531
  Examples:
6222
6532
  $ jai1 utils cron "0 5 * * *"
6223
6533
  $ jai1 utils cron "*/15 * * * *"
@@ -6231,7 +6541,7 @@ Examples:
6231
6541
  }
6232
6542
 
6233
6543
  // src/commands/utils/markdown-preview.ts
6234
- import { Command as Command28 } from "commander";
6544
+ import { Command as Command33 } from "commander";
6235
6545
  import { readFile as readFile5 } from "fs/promises";
6236
6546
  import { marked } from "marked";
6237
6547
  import TerminalRenderer from "marked-terminal";
@@ -6270,7 +6580,7 @@ ${code.trim()}
6270
6580
  }
6271
6581
  }
6272
6582
  function createMarkdownPreviewCommand() {
6273
- const cmd = new Command28("markdown-preview").description("Preview markdown file in terminal").argument("<file>", "Markdown file path").option("--raw", "Show raw markdown instead of rendered").addHelpText("after", `
6583
+ const cmd = new Command33("markdown-preview").description("Preview markdown file in terminal").argument("<file>", "Markdown file path").option("--raw", "Show raw markdown instead of rendered").addHelpText("after", `
6274
6584
  Examples:
6275
6585
  $ jai1 utils markdown-preview README.md
6276
6586
  $ jai1 utils markdown-preview ./docs/guide.md
@@ -7679,7 +7989,7 @@ async function runInteractiveMode() {
7679
7989
 
7680
7990
  // src/commands/utils/index.ts
7681
7991
  function createUtilsCommand() {
7682
- const utilsCommand = new Command29("utils").description("Developer utilities for common tasks").option("-i, --interactive", "Run in interactive mode").addHelpText("after", `
7992
+ const utilsCommand = new Command34("utils").description("Developer utilities for common tasks").option("-i, --interactive", "Run in interactive mode").addHelpText("after", `
7683
7993
  Interactive Mode:
7684
7994
  $ jai1 utils --interactive
7685
7995
  $ jai1 utils -i
@@ -7714,11 +8024,11 @@ Quick Usage:
7714
8024
  }
7715
8025
 
7716
8026
  // src/commands/deps/index.ts
7717
- import { Command as Command31 } from "commander";
8027
+ import { Command as Command36 } from "commander";
7718
8028
 
7719
8029
  // src/commands/deps/upgrade.ts
7720
- import { Command as Command30 } from "commander";
7721
- import { checkbox as checkbox3, confirm as confirm4 } from "@inquirer/prompts";
8030
+ import { Command as Command35 } from "commander";
8031
+ import { checkbox as checkbox3, confirm as confirm5 } from "@inquirer/prompts";
7722
8032
 
7723
8033
  // src/services/deps.service.ts
7724
8034
  import { promises as fs10 } from "fs";
@@ -7931,7 +8241,7 @@ var colors2 = {
7931
8241
  dim: "\x1B[2m"
7932
8242
  };
7933
8243
  function createDepsUpgradeCommand() {
7934
- return new Command30("upgrade").description("Upgrade npm packages l\xEAn version m\u1EDBi nh\u1EA5t").option("--check", "Ch\u1EC9 ki\u1EC3m tra, kh\xF4ng upgrade").option("--all", "Upgrade t\u1EA5t c\u1EA3 kh\xF4ng c\u1EA7n ch\u1ECDn").option("--deps-only", "Ch\u1EC9 upgrade dependencies").option("--dev-only", "Ch\u1EC9 upgrade devDependencies").action(async (options) => {
8244
+ return new Command35("upgrade").description("Upgrade npm packages l\xEAn version m\u1EDBi nh\u1EA5t").option("--check", "Ch\u1EC9 ki\u1EC3m tra, kh\xF4ng upgrade").option("--all", "Upgrade t\u1EA5t c\u1EA3 kh\xF4ng c\u1EA7n ch\u1ECDn").option("--deps-only", "Ch\u1EC9 upgrade dependencies").option("--dev-only", "Ch\u1EC9 upgrade devDependencies").action(async (options) => {
7935
8245
  await handleDepsUpgrade(options);
7936
8246
  });
7937
8247
  }
@@ -8023,7 +8333,7 @@ ${colors2.yellow}\u23F8\uFE0F \u0110\xE3 h\u1EE7y${colors2.reset}
8023
8333
  }
8024
8334
  let shouldProceed;
8025
8335
  try {
8026
- shouldProceed = await confirm4({
8336
+ shouldProceed = await confirm5({
8027
8337
  message: `Ti\u1EBFn h\xE0nh upgrade ${selectedPackages.length} packages?`,
8028
8338
  default: true
8029
8339
  });
@@ -8111,16 +8421,16 @@ function displayUpgradeTable(packages) {
8111
8421
 
8112
8422
  // src/commands/deps/index.ts
8113
8423
  function createDepsCommand() {
8114
- const depsCommand = new Command31("deps").description("Qu\u1EA3n l\xFD dependencies trong project");
8424
+ const depsCommand = new Command36("deps").description("Qu\u1EA3n l\xFD dependencies trong project");
8115
8425
  depsCommand.addCommand(createDepsUpgradeCommand());
8116
8426
  return depsCommand;
8117
8427
  }
8118
8428
 
8119
8429
  // src/commands/kit/index.ts
8120
- import { Command as Command35 } from "commander";
8430
+ import { Command as Command40 } from "commander";
8121
8431
 
8122
8432
  // src/commands/kit/list.ts
8123
- import { Command as Command32 } from "commander";
8433
+ import { Command as Command37 } from "commander";
8124
8434
 
8125
8435
  // src/services/starter-kit.service.ts
8126
8436
  import { promises as fs11 } from "fs";
@@ -8187,7 +8497,7 @@ var StarterKitService = class {
8187
8497
 
8188
8498
  // src/commands/kit/list.ts
8189
8499
  function createKitListCommand() {
8190
- return new Command32("list").description("List available starter kits").option("-c, --category <category>", "Filter by category (backend, frontend, fullstack)").option("-s, --search <term>", "Search kits by name or description").action(async (options) => {
8500
+ return new Command37("list").description("List available starter kits").option("-c, --category <category>", "Filter by category (backend, frontend, fullstack)").option("-s, --search <term>", "Search kits by name or description").action(async (options) => {
8191
8501
  const configService = new ConfigService();
8192
8502
  const config = await configService.load();
8193
8503
  if (!config) {
@@ -8224,9 +8534,9 @@ function createKitListCommand() {
8224
8534
  }
8225
8535
 
8226
8536
  // src/commands/kit/info.ts
8227
- import { Command as Command33 } from "commander";
8537
+ import { Command as Command38 } from "commander";
8228
8538
  function createKitInfoCommand() {
8229
- return new Command33("info").description("Show detailed information about a starter kit").argument("<slug>", "Starter kit slug").action(async (slug) => {
8539
+ return new Command38("info").description("Show detailed information about a starter kit").argument("<slug>", "Starter kit slug").action(async (slug) => {
8230
8540
  const configService = new ConfigService();
8231
8541
  const config = await configService.load();
8232
8542
  if (!config) {
@@ -8275,7 +8585,7 @@ Post-Init Commands:`);
8275
8585
  }
8276
8586
 
8277
8587
  // src/commands/kit/create.ts
8278
- import { Command as Command34 } from "commander";
8588
+ import { Command as Command39 } from "commander";
8279
8589
  import { promises as fs12 } from "fs";
8280
8590
  import { join as join6 } from "path";
8281
8591
  import { select as select2, input, checkbox as checkbox4 } from "@inquirer/prompts";
@@ -8320,7 +8630,7 @@ var HookExecutor = class {
8320
8630
 
8321
8631
  // src/commands/kit/create.ts
8322
8632
  function createKitCreateCommand() {
8323
- return new Command34("create").description("Create a new project from a starter kit").argument("<slug>", "Starter kit slug").argument("[directory]", "Project directory (default: ./<slug>)").option("-y, --yes", "Auto mode - use defaults, no prompts").option("--name <name>", "Project name").option("--skip-install", "Skip dependency installation").option("--skip-git", "Skip git initialization").option("--skip-framework", "Skip framework apply").option("--skip-ide", "Skip IDE sync").action(async (slug, directory, options) => {
8633
+ return new Command39("create").description("Create a new project from a starter kit").argument("<slug>", "Starter kit slug").argument("[directory]", "Project directory (default: ./<slug>)").option("-y, --yes", "Auto mode - use defaults, no prompts").option("--name <name>", "Project name").option("--skip-install", "Skip dependency installation").option("--skip-git", "Skip git initialization").option("--skip-framework", "Skip framework apply").option("--skip-ide", "Skip IDE sync").action(async (slug, directory, options) => {
8324
8634
  const configService = new ConfigService();
8325
8635
  const config = await configService.load();
8326
8636
  if (!config) {
@@ -8492,7 +8802,7 @@ async function getAllFiles(dir) {
8492
8802
 
8493
8803
  // src/commands/kit/index.ts
8494
8804
  function createKitCommand() {
8495
- const cmd = new Command35("kit").description("Manage starter kits for new projects").action(() => {
8805
+ const cmd = new Command40("kit").description("Manage starter kits for new projects").action(() => {
8496
8806
  cmd.help();
8497
8807
  });
8498
8808
  cmd.addCommand(createKitListCommand());
@@ -8502,12 +8812,12 @@ function createKitCommand() {
8502
8812
  }
8503
8813
 
8504
8814
  // src/commands/rules/index.ts
8505
- import { Command as Command42 } from "commander";
8815
+ import { Command as Command47 } from "commander";
8506
8816
 
8507
8817
  // src/commands/rules/list.ts
8508
- import { Command as Command36 } from "commander";
8818
+ import { Command as Command41 } from "commander";
8509
8819
  function createRulesListCommand() {
8510
- return new Command36("list").description("List available rule presets").option("--json", "Output as JSON").action(async (options) => {
8820
+ return new Command41("list").description("List available rule presets").option("--json", "Output as JSON").action(async (options) => {
8511
8821
  const configService = new ConfigService();
8512
8822
  const config = await configService.load();
8513
8823
  if (!config) {
@@ -8562,12 +8872,12 @@ function createRulesListCommand() {
8562
8872
  }
8563
8873
 
8564
8874
  // src/commands/rules/init.ts
8565
- import { Command as Command37 } from "commander";
8875
+ import { Command as Command42 } from "commander";
8566
8876
  import { promises as fs13 } from "fs";
8567
8877
  import { join as join7 } from "path";
8568
- import { select as select3, confirm as confirm5 } from "@inquirer/prompts";
8878
+ import { select as select3, confirm as confirm6 } from "@inquirer/prompts";
8569
8879
  function createRulesInitCommand() {
8570
- return new Command37("init").description("Apply rule preset to project").option("--preset <slug>", "Preset slug to apply").option("--output <format>", "Output format: cursor, agents-md, both (default: cursor)", "cursor").option("-y, --yes", "Skip confirmations").action(async (options) => {
8880
+ return new Command42("init").description("Apply rule preset to project").option("--preset <slug>", "Preset slug to apply").option("--output <format>", "Output format: cursor, agents-md, both (default: cursor)", "cursor").option("-y, --yes", "Skip confirmations").action(async (options) => {
8571
8881
  const configService = new ConfigService();
8572
8882
  const config = await configService.load();
8573
8883
  if (!config) {
@@ -8627,7 +8937,7 @@ function createRulesInitCommand() {
8627
8937
  });
8628
8938
  }
8629
8939
  if (!options.yes) {
8630
- const proceed = await confirm5({
8940
+ const proceed = await confirm6({
8631
8941
  message: `Apply preset '${bundle.preset.name}' to current directory?`,
8632
8942
  default: true
8633
8943
  });
@@ -8695,10 +9005,10 @@ async function applyAgentsMdFormat(bundle) {
8695
9005
  }
8696
9006
 
8697
9007
  // src/commands/rules/apply.ts
8698
- import { Command as Command38 } from "commander";
9008
+ import { Command as Command43 } from "commander";
8699
9009
  import { promises as fs15 } from "fs";
8700
9010
  import { join as join9 } from "path";
8701
- import { select as select4, confirm as confirm6, checkbox as checkbox5 } from "@inquirer/prompts";
9011
+ import { select as select4, confirm as confirm7, checkbox as checkbox5 } from "@inquirer/prompts";
8702
9012
 
8703
9013
  // src/services/rules-generator.service.ts
8704
9014
  var RulesGeneratorService = class {
@@ -9278,7 +9588,7 @@ Restoring backup from ${metadata.timestamp}...`);
9278
9588
 
9279
9589
  // src/commands/rules/apply.ts
9280
9590
  function createRulesApplyCommand() {
9281
- return new Command38("apply").description("Apply rule preset to project with multi-IDE support").argument("[preset]", "Preset slug to apply (optional)").option("--ides <ides>", "Comma-separated list of IDE formats (cursor,windsurf,antigravity,claude,agentsmd,gemini)").option("--skip-backup", "Skip backup creation").option("-y, --yes", "Skip all confirmations (auto mode)").action(async (presetSlug, options) => {
9591
+ return new Command43("apply").description("Apply rule preset to project with multi-IDE support").argument("[preset]", "Preset slug to apply (optional)").option("--ides <ides>", "Comma-separated list of IDE formats (cursor,windsurf,antigravity,claude,agentsmd,gemini)").option("--skip-backup", "Skip backup creation").option("-y, --yes", "Skip all confirmations (auto mode)").action(async (presetSlug, options) => {
9282
9592
  const configService = new ConfigService();
9283
9593
  const config = await configService.load();
9284
9594
  if (!config) {
@@ -9418,7 +9728,7 @@ function createRulesApplyCommand() {
9418
9728
  if (backupPath) {
9419
9729
  console.log(` Backup: ${backupPath}`);
9420
9730
  }
9421
- const proceed = await confirm6({
9731
+ const proceed = await confirm7({
9422
9732
  message: "Apply these rules to the current directory?",
9423
9733
  default: true
9424
9734
  });
@@ -9428,19 +9738,23 @@ function createRulesApplyCommand() {
9428
9738
  }
9429
9739
  }
9430
9740
  console.log("\n\u{1F4DD} Applying preset...\n");
9431
- const presetDir = join9(process.cwd(), ".jai1", "rule-presets", bundle.preset.slug);
9432
- await fs15.mkdir(presetDir, { recursive: true });
9741
+ const rulePresetDir = join9(process.cwd(), ".jai1", "rule-preset");
9742
+ try {
9743
+ await fs15.rm(rulePresetDir, { recursive: true, force: true });
9744
+ } catch {
9745
+ }
9746
+ await fs15.mkdir(rulePresetDir, { recursive: true });
9433
9747
  await fs15.writeFile(
9434
- join9(presetDir, "preset.json"),
9748
+ join9(rulePresetDir, "preset.json"),
9435
9749
  JSON.stringify(bundle.preset, null, 2),
9436
9750
  "utf-8"
9437
9751
  );
9438
9752
  for (const [filename, content] of Object.entries(bundle.files)) {
9439
- const filePath = join9(presetDir, filename);
9753
+ const filePath = join9(rulePresetDir, filename);
9440
9754
  await fs15.mkdir(join9(filePath, ".."), { recursive: true });
9441
9755
  await fs15.writeFile(filePath, content, "utf-8");
9442
9756
  }
9443
- console.log(`\u2713 Saved preset to .jai1/rule-presets/${bundle.preset.slug}/`);
9757
+ console.log(`\u2713 Saved preset to .jai1/rule-preset/`);
9444
9758
  const allGeneratedFiles = [];
9445
9759
  for (const ideId of resolvedIdes) {
9446
9760
  try {
@@ -9511,19 +9825,19 @@ function createRulesApplyCommand() {
9511
9825
  }
9512
9826
  console.log("\n\u{1F4DD} Next steps:");
9513
9827
  console.log(" 1. Review generated files in your IDE");
9514
- console.log(" 2. Edit custom rules if needed (look for 09-custom.*)");
9515
- console.log(" 3. Commit the rules to git");
9516
- console.log(' 4. Use "jai1 rules sync" to regenerate after editing');
9828
+ console.log(" 2. Edit rules in .jai1/rule-preset/ (source of truth)");
9829
+ console.log(' 3. Run "jai1 rules sync" to regenerate IDE outputs');
9830
+ console.log(" 4. Commit the rules to git");
9517
9831
  console.log(' 5. Use "jai1 ide status" to check IDE configuration\n');
9518
9832
  });
9519
9833
  }
9520
9834
 
9521
9835
  // src/commands/rules/restore.ts
9522
- import { Command as Command39 } from "commander";
9836
+ import { Command as Command44 } from "commander";
9523
9837
  import { join as join10 } from "path";
9524
- import { select as select5, confirm as confirm7 } from "@inquirer/prompts";
9838
+ import { select as select5, confirm as confirm8 } from "@inquirer/prompts";
9525
9839
  function createRulesRestoreCommand() {
9526
- return new Command39("restore").description("Restore rules from a backup").option("--latest", "Restore the most recent backup").option("-y, --yes", "Skip confirmation").action(async (options) => {
9840
+ return new Command44("restore").description("Restore rules from a backup").option("--latest", "Restore the most recent backup").option("-y, --yes", "Skip confirmation").action(async (options) => {
9527
9841
  const backupService = new BackupService();
9528
9842
  const backups = await backupService.listBackups();
9529
9843
  if (backups.length === 0) {
@@ -9555,7 +9869,7 @@ function createRulesRestoreCommand() {
9555
9869
  console.log(` IDEs: ${selectedBackup.ides.join(", ")}`);
9556
9870
  console.log(` Files: ${selectedBackup.files.length}`);
9557
9871
  if (!options.yes) {
9558
- const proceed = await confirm7({
9872
+ const proceed = await confirm8({
9559
9873
  message: "This will overwrite current rules. Continue?",
9560
9874
  default: false
9561
9875
  });
@@ -9591,12 +9905,12 @@ function formatTimestamp(timestamp) {
9591
9905
  }
9592
9906
 
9593
9907
  // src/commands/rules/sync.ts
9594
- import { Command as Command40 } from "commander";
9908
+ import { Command as Command45 } from "commander";
9595
9909
  import { promises as fs16 } from "fs";
9596
9910
  import { join as join11 } from "path";
9597
- import { confirm as confirm8 } from "@inquirer/prompts";
9911
+ import { confirm as confirm9 } from "@inquirer/prompts";
9598
9912
  function createRulesSyncCommand() {
9599
- return new Command40("sync").description("Regenerate rule outputs for all configured IDEs").option("--ides <ides>", "Comma-separated list of IDEs to sync (default: all configured)").option("--detect", "Auto-detect active IDEs instead of using config").option("-y, --yes", "Skip confirmations").action(async (options) => {
9913
+ return new Command45("sync").description("Regenerate rule outputs for all configured IDEs").option("--ides <ides>", "Comma-separated list of IDEs to sync (default: all configured)").option("--detect", "Auto-detect active IDEs instead of using config").option("-y, --yes", "Skip confirmations").action(async (options) => {
9600
9914
  const configPath = join11(process.cwd(), "jai1-rules.json");
9601
9915
  let projectConfig;
9602
9916
  try {
@@ -9627,7 +9941,7 @@ Detected ${detected.length} active IDE(s):
9627
9941
  console.log(` ${confidence} ${d.name} - ${d.ruleCount} rules`);
9628
9942
  });
9629
9943
  if (!options.yes) {
9630
- const proceed = await confirm8({
9944
+ const proceed = await confirm9({
9631
9945
  message: "\nSync these detected IDEs?",
9632
9946
  default: true
9633
9947
  });
@@ -9680,17 +9994,21 @@ Detected ${detected.length} active IDE(s):
9680
9994
  throw new Error(`Failed to fetch preset: ${presetResponse.statusText}`);
9681
9995
  }
9682
9996
  const bundle = await presetResponse.json();
9683
- const sourceDir = join11(process.cwd(), ".cursor", "rules");
9684
- const sourceExists = await checkPathExists(sourceDir);
9685
- if (sourceExists) {
9686
- const files = await fs16.readdir(sourceDir);
9997
+ const rulePresetDir = join11(process.cwd(), ".jai1", "rule-preset");
9998
+ const presetExists = await checkPathExists(rulePresetDir);
9999
+ if (presetExists) {
10000
+ const files = await fs16.readdir(rulePresetDir);
9687
10001
  for (const file of files) {
9688
10002
  if (file.endsWith(".mdc")) {
9689
- const filePath = join11(sourceDir, file);
10003
+ const filePath = join11(rulePresetDir, file);
9690
10004
  const content = await fs16.readFile(filePath, "utf-8");
9691
10005
  bundle.files[file] = content;
9692
10006
  }
9693
10007
  }
10008
+ } else {
10009
+ console.log("\n\u26A0\uFE0F No rule preset found in .jai1/rule-preset/");
10010
+ console.log(' Run "jai1 rules apply" first to apply a preset.\n');
10011
+ return;
9694
10012
  }
9695
10013
  const generatorService = new RulesGeneratorService();
9696
10014
  for (const ideId of idesToSync) {
@@ -9724,12 +10042,12 @@ Detected ${detected.length} active IDE(s):
9724
10042
  console.log("\u{1F4A1} Next steps:");
9725
10043
  console.log(" \u2022 Your IDE may need to be restarted to pick up changes");
9726
10044
  console.log(' \u2022 Use "jai1 ide status" to verify IDE configuration');
9727
- console.log(" \u2022 Edit source files in .cursor/rules/ and sync again\n");
10045
+ console.log(" \u2022 Edit source files in .jai1/rule-preset/ and sync again\n");
9728
10046
  });
9729
10047
  }
9730
- async function checkPathExists(path8) {
10048
+ async function checkPathExists(absolutePath) {
9731
10049
  try {
9732
- await fs16.access(join11(process.cwd(), path8));
10050
+ await fs16.access(absolutePath);
9733
10051
  return true;
9734
10052
  } catch {
9735
10053
  return false;
@@ -9737,11 +10055,11 @@ async function checkPathExists(path8) {
9737
10055
  }
9738
10056
 
9739
10057
  // src/commands/rules/info.ts
9740
- import { Command as Command41 } from "commander";
10058
+ import { Command as Command46 } from "commander";
9741
10059
  import { promises as fs17 } from "fs";
9742
10060
  import { join as join12 } from "path";
9743
10061
  function createRulesInfoCommand() {
9744
- return new Command41("info").description("Show current preset information").option("--json", "Output as JSON").action(async (options) => {
10062
+ return new Command46("info").description("Show current preset information").option("--json", "Output as JSON").action(async (options) => {
9745
10063
  const configPath = join12(process.cwd(), "jai1-rules.json");
9746
10064
  let projectConfig;
9747
10065
  try {
@@ -9757,10 +10075,43 @@ function createRulesInfoCommand() {
9757
10075
  return;
9758
10076
  }
9759
10077
  console.log("\u{1F4CB} Current Preset Information\n");
9760
- console.log(`Preset: ${projectConfig.preset}`);
9761
- console.log(`Version: ${projectConfig.version}`);
10078
+ const rulePresetDir = join12(process.cwd(), ".jai1", "rule-preset");
10079
+ const presetJsonPath = join12(rulePresetDir, "preset.json");
10080
+ let presetMetadata = null;
10081
+ let presetFiles = [];
10082
+ try {
10083
+ const presetContent = await fs17.readFile(presetJsonPath, "utf-8");
10084
+ presetMetadata = JSON.parse(presetContent);
10085
+ const files = await fs17.readdir(rulePresetDir);
10086
+ presetFiles = files.filter((f) => f.endsWith(".mdc"));
10087
+ } catch {
10088
+ }
10089
+ if (presetMetadata) {
10090
+ console.log(`Preset: ${presetMetadata.name} (${presetMetadata.slug})`);
10091
+ console.log(`Version: ${presetMetadata.version}`);
10092
+ console.log(`Description: ${presetMetadata.description}`);
10093
+ if (presetMetadata.tags && presetMetadata.tags.length > 0) {
10094
+ console.log(`Tags: ${presetMetadata.tags.join(", ")}`);
10095
+ }
10096
+ } else {
10097
+ console.log(`Preset: ${projectConfig.preset}`);
10098
+ console.log(`Version: ${projectConfig.version}`);
10099
+ }
9762
10100
  console.log(`Applied at: ${new Date(projectConfig.appliedAt).toLocaleString()}`);
9763
- console.log(`Custom rules: ${projectConfig.customContext}`);
10101
+ console.log(`
10102
+ Source of Truth:`);
10103
+ if (presetFiles.length > 0) {
10104
+ console.log(` \u{1F4C1} .jai1/rule-preset/ (${presetFiles.length} files)`);
10105
+ for (const file of presetFiles.slice(0, 5)) {
10106
+ console.log(` \u2022 ${file}`);
10107
+ }
10108
+ if (presetFiles.length > 5) {
10109
+ console.log(` ... and ${presetFiles.length - 5} more`);
10110
+ }
10111
+ } else {
10112
+ console.log(` \u26A0\uFE0F .jai1/rule-preset/ not found`);
10113
+ console.log(` Run "jai1 rules apply" to create it`);
10114
+ }
9764
10115
  if (projectConfig.ides && projectConfig.ides.length > 0) {
9765
10116
  console.log(`
9766
10117
  Configured IDEs (${projectConfig.ides.length}):`);
@@ -9785,9 +10136,9 @@ Available Backups (${projectConfig.backups.length}):`);
9785
10136
  }
9786
10137
  }
9787
10138
  console.log("\n\u2139\uFE0F Commands:");
9788
- console.log(' \u2022 "jai1 rules sync" - Regenerate outputs after editing');
10139
+ console.log(' \u2022 "jai1 rules sync" - Regenerate IDE outputs after editing .jai1/rule-preset/');
9789
10140
  console.log(' \u2022 "jai1 rules restore" - Restore from backup');
9790
- console.log(' \u2022 "jai1 rules apply" - Apply a different preset');
10141
+ console.log(' \u2022 "jai1 rules apply" - Apply a different preset (replaces current)');
9791
10142
  });
9792
10143
  }
9793
10144
  async function checkPathExists2(path8) {
@@ -9814,7 +10165,7 @@ async function checkIdeFilesExist(ideId, format) {
9814
10165
 
9815
10166
  // src/commands/rules/index.ts
9816
10167
  function createRulesCommand() {
9817
- const rulesCommand = new Command42("rules").description("Manage rule presets for AI agents");
10168
+ const rulesCommand = new Command47("rules").description("Manage rule presets for AI agents");
9818
10169
  rulesCommand.addCommand(createRulesListCommand());
9819
10170
  rulesCommand.addCommand(createRulesInitCommand());
9820
10171
  rulesCommand.addCommand(createRulesApplyCommand());
@@ -9825,8 +10176,8 @@ function createRulesCommand() {
9825
10176
  }
9826
10177
 
9827
10178
  // src/commands/upgrade.ts
9828
- import { Command as Command43 } from "commander";
9829
- import { confirm as confirm9 } from "@inquirer/prompts";
10179
+ import { Command as Command48 } from "commander";
10180
+ import { confirm as confirm10 } from "@inquirer/prompts";
9830
10181
  import { execSync as execSync2 } from "child_process";
9831
10182
  var colors3 = {
9832
10183
  yellow: "\x1B[33m",
@@ -9837,7 +10188,7 @@ var colors3 = {
9837
10188
  bold: "\x1B[1m"
9838
10189
  };
9839
10190
  function createUpgradeCommand() {
9840
- return new Command43("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) => {
10191
+ return new Command48("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) => {
9841
10192
  await handleUpgrade(options);
9842
10193
  });
9843
10194
  }
@@ -9881,7 +10232,7 @@ ${colors3.bold}Current version:${colors3.reset} ${currentVersion}`);
9881
10232
  return;
9882
10233
  }
9883
10234
  if (!options.force) {
9884
- const shouldUpdate = await confirm9({
10235
+ const shouldUpdate = await confirm10({
9885
10236
  message: "Update to the latest version now?",
9886
10237
  default: true
9887
10238
  });
@@ -9985,11 +10336,11 @@ function getInstallCommand(packageManager2) {
9985
10336
  }
9986
10337
 
9987
10338
  // src/commands/clean.ts
9988
- import { Command as Command44 } from "commander";
9989
- import { confirm as confirm10, select as select6 } from "@inquirer/prompts";
10339
+ import { Command as Command49 } from "commander";
10340
+ import { confirm as confirm11, select as select6 } from "@inquirer/prompts";
9990
10341
  import { join as join13 } from "path";
9991
10342
  function createCleanCommand() {
9992
- return new Command44("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) => {
10343
+ return new Command49("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) => {
9993
10344
  await handleClean(options);
9994
10345
  });
9995
10346
  }
@@ -10084,7 +10435,7 @@ async function cleanTarget(target, skipConfirm) {
10084
10435
  }
10085
10436
  const countStr = info.count ? ` (${info.count} items)` : "";
10086
10437
  if (!skipConfirm) {
10087
- const confirmed = await confirm10({
10438
+ const confirmed = await confirm11({
10088
10439
  message: `Delete ${target.name}${countStr}?`,
10089
10440
  default: false
10090
10441
  });
@@ -10102,7 +10453,7 @@ async function cleanTarget(target, skipConfirm) {
10102
10453
  }
10103
10454
 
10104
10455
  // src/commands/redmine/check.ts
10105
- import { Command as Command45 } from "commander";
10456
+ import { Command as Command50 } from "commander";
10106
10457
 
10107
10458
  // src/services/redmine-config.service.ts
10108
10459
  import { readFile as readFile6 } from "fs/promises";
@@ -10409,7 +10760,7 @@ async function checkConnectivity(config) {
10409
10760
 
10410
10761
  // src/commands/redmine/check.ts
10411
10762
  function createRedmineCheckCommand() {
10412
- const cmd = new Command45("check").description("Check Redmine connectivity").option("-c, --config <path>", "Config file path", "redmine.config.yaml").option("--json", "Output as JSON").action(async (options) => {
10763
+ const cmd = new Command50("check").description("Check Redmine connectivity").option("-c, --config <path>", "Config file path", "redmine.config.yaml").option("--json", "Output as JSON").action(async (options) => {
10413
10764
  await handleRedmineCheck(options);
10414
10765
  });
10415
10766
  return cmd;
@@ -10437,7 +10788,7 @@ async function handleRedmineCheck(options) {
10437
10788
  }
10438
10789
 
10439
10790
  // src/commands/redmine/sync-issue.ts
10440
- import { Command as Command46 } from "commander";
10791
+ import { Command as Command51 } from "commander";
10441
10792
 
10442
10793
  // src/sync-issue.ts
10443
10794
  import { resolve as resolve3, relative } from "path";
@@ -10813,7 +11164,7 @@ function extractIssueIdFromUrl(url) {
10813
11164
 
10814
11165
  // src/commands/redmine/sync-issue.ts
10815
11166
  function createSyncIssueCommand() {
10816
- const cmd = new Command46("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) => {
11167
+ const cmd = new Command51("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) => {
10817
11168
  await handleSyncIssue(options);
10818
11169
  });
10819
11170
  return cmd;
@@ -10857,7 +11208,7 @@ async function handleSyncIssue(options) {
10857
11208
  }
10858
11209
 
10859
11210
  // src/commands/redmine/sync-project.ts
10860
- import { Command as Command47 } from "commander";
11211
+ import { Command as Command52 } from "commander";
10861
11212
 
10862
11213
  // src/sync-project.ts
10863
11214
  async function syncProject(config, options = {}) {
@@ -10927,7 +11278,7 @@ async function syncProject(config, options = {}) {
10927
11278
 
10928
11279
  // src/commands/redmine/sync-project.ts
10929
11280
  function createSyncProjectCommand() {
10930
- const cmd = new Command47("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) => {
11281
+ const cmd = new Command52("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) => {
10931
11282
  await handleSyncProject(options);
10932
11283
  });
10933
11284
  return cmd;
@@ -10982,12 +11333,12 @@ async function handleSyncProject(options) {
10982
11333
  }
10983
11334
 
10984
11335
  // src/commands/framework/info.ts
10985
- import { Command as Command48 } from "commander";
11336
+ import { Command as Command53 } from "commander";
10986
11337
  import { promises as fs18 } from "fs";
10987
11338
  import { join as join14 } from "path";
10988
11339
  import { homedir as homedir5 } from "os";
10989
11340
  function createInfoCommand() {
10990
- const cmd = new Command48("info").description("Show jai1-client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
11341
+ const cmd = new Command53("info").description("Show jai1-client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
10991
11342
  await handleInfo(options);
10992
11343
  });
10993
11344
  return cmd;
@@ -11043,8 +11394,8 @@ async function getProjectStatus2() {
11043
11394
  }
11044
11395
 
11045
11396
  // src/commands/self-update.ts
11046
- import { Command as Command49 } from "commander";
11047
- import { confirm as confirm11 } from "@inquirer/prompts";
11397
+ import { Command as Command54 } from "commander";
11398
+ import { confirm as confirm12 } from "@inquirer/prompts";
11048
11399
  import { execSync as execSync3 } from "child_process";
11049
11400
  var colors4 = {
11050
11401
  yellow: "\x1B[33m",
@@ -11055,7 +11406,7 @@ var colors4 = {
11055
11406
  bold: "\x1B[1m"
11056
11407
  };
11057
11408
  function createSelfUpdateCommand() {
11058
- return new Command49("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) => {
11409
+ return new Command54("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) => {
11059
11410
  await handleSelfUpdate(options);
11060
11411
  });
11061
11412
  }
@@ -11099,7 +11450,7 @@ ${colors4.bold}Current version:${colors4.reset} ${currentVersion}`);
11099
11450
  return;
11100
11451
  }
11101
11452
  if (!options.force) {
11102
- const shouldUpdate = await confirm11({
11453
+ const shouldUpdate = await confirm12({
11103
11454
  message: "Update to the latest version now?",
11104
11455
  default: true
11105
11456
  });
@@ -11195,10 +11546,10 @@ function getInstallCommand2(packageManager2) {
11195
11546
  }
11196
11547
 
11197
11548
  // src/commands/clear-backups.ts
11198
- import { Command as Command50 } from "commander";
11199
- import { confirm as confirm12 } from "@inquirer/prompts";
11549
+ import { Command as Command55 } from "commander";
11550
+ import { confirm as confirm13 } from "@inquirer/prompts";
11200
11551
  function createClearBackupsCommand() {
11201
- return new Command50("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
11552
+ return new Command55("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
11202
11553
  const service = new ComponentsService();
11203
11554
  const backups = await service.listBackups(process.cwd());
11204
11555
  if (backups.length === 0) {
@@ -11214,7 +11565,7 @@ function createClearBackupsCommand() {
11214
11565
  }
11215
11566
  console.log();
11216
11567
  if (!options.yes) {
11217
- const ok = await confirm12({ message: "Delete all backups?", default: false });
11568
+ const ok = await confirm13({ message: "Delete all backups?", default: false });
11218
11569
  if (!ok) return;
11219
11570
  }
11220
11571
  await service.clearBackups(process.cwd());
@@ -11223,8 +11574,8 @@ function createClearBackupsCommand() {
11223
11574
  }
11224
11575
 
11225
11576
  // src/commands/vscode/index.ts
11226
- import { Command as Command51 } from "commander";
11227
- import { checkbox as checkbox7, confirm as confirm13, select as select7 } from "@inquirer/prompts";
11577
+ import { Command as Command56 } from "commander";
11578
+ import { checkbox as checkbox7, confirm as confirm14, select as select7 } from "@inquirer/prompts";
11228
11579
  import fs19 from "fs/promises";
11229
11580
  import path7 from "path";
11230
11581
  import { existsSync as existsSync3 } from "fs";
@@ -11363,7 +11714,7 @@ var PERFORMANCE_GROUPS2 = {
11363
11714
  }
11364
11715
  };
11365
11716
  function createVSCodeCommand() {
11366
- const vscodeCommand = new Command51("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
11717
+ const vscodeCommand = new Command56("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
11367
11718
  vscodeCommand.action(async () => {
11368
11719
  await interactiveMode2();
11369
11720
  });
@@ -11467,7 +11818,7 @@ async function applyGroups2(groupKeys, action) {
11467
11818
  console.log("\u{1F4C4} \u0110\xE3 \u0111\u1ECDc c\xE0i \u0111\u1EB7t hi\u1EC7n t\u1EA1i t\u1EEB settings.json");
11468
11819
  } catch {
11469
11820
  console.warn("\u26A0\uFE0F Kh\xF4ng th\u1EC3 \u0111\u1ECDc settings.json (c\xF3 th\u1EC3 ch\u1EE9a comments).");
11470
- const confirmOverwrite = await confirm13({
11821
+ const confirmOverwrite = await confirm14({
11471
11822
  message: "Ghi \u0111\xE8 file settings.json hi\u1EC7n t\u1EA1i?",
11472
11823
  default: false
11473
11824
  });
@@ -11514,7 +11865,7 @@ async function resetSettings2(groupKeys) {
11514
11865
  console.log("\n\u26A0\uFE0F Kh\xF4ng t\xECm th\u1EA5y file settings.json");
11515
11866
  return;
11516
11867
  }
11517
- const confirmReset = await confirm13({
11868
+ const confirmReset = await confirm14({
11518
11869
  message: groupKeys.length === 0 ? "Reset T\u1EA4T C\u1EA2 settings v\u1EC1 m\u1EB7c \u0111\u1ECBnh (x\xF3a to\xE0n b\u1ED9 file)?" : `Reset c\xE1c nh\xF3m: ${groupKeys.join(", ")}?`,
11519
11870
  default: false
11520
11871
  });
@@ -11534,9 +11885,9 @@ async function resetSettings2(groupKeys) {
11534
11885
  // src/commands/guide.ts
11535
11886
  import React40 from "react";
11536
11887
  import { render as render6 } from "ink";
11537
- import { Command as Command52 } from "commander";
11888
+ import { Command as Command57 } from "commander";
11538
11889
  function createGuideCommand() {
11539
- const cmd = new Command52("guide").description("Interactive guide center for Agentic Coding").option("--topic <topic>", "Open specific topic (intro, rules, workflows, prompts, skills)").action(async (options) => {
11890
+ const cmd = new Command57("guide").description("Interactive guide center for Agentic Coding").option("--topic <topic>", "Open specific topic (intro, rules, workflows, prompts, skills)").action(async (options) => {
11540
11891
  const { waitUntilExit } = render6(
11541
11892
  React40.createElement(GuideApp, {
11542
11893
  initialTopic: options.topic,
@@ -11553,9 +11904,9 @@ function createGuideCommand() {
11553
11904
  // src/commands/context.ts
11554
11905
  import React41 from "react";
11555
11906
  import { render as render7 } from "ink";
11556
- import { Command as Command53 } from "commander";
11907
+ import { Command as Command58 } from "commander";
11557
11908
  function createContextCommand() {
11558
- const cmd = new Command53("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) => {
11909
+ const cmd = new Command58("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) => {
11559
11910
  let initialIDE;
11560
11911
  if (options.ide) {
11561
11912
  const validIDEs = ["cursor", "windsurf", "antigravity", "jai1"];
@@ -11632,10 +11983,10 @@ async function printStats2() {
11632
11983
  }
11633
11984
 
11634
11985
  // src/commands/migrate-ide.ts
11635
- import { Command as Command54 } from "commander";
11636
- import { checkbox as checkbox8, confirm as confirm14 } from "@inquirer/prompts";
11986
+ import { Command as Command59 } from "commander";
11987
+ import { checkbox as checkbox8, confirm as confirm15 } from "@inquirer/prompts";
11637
11988
  function createMigrateIdeCommand() {
11638
- const cmd = new Command54("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) => {
11989
+ const cmd = new Command59("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) => {
11639
11990
  await runMigrateIde(options);
11640
11991
  });
11641
11992
  return cmd;
@@ -11704,7 +12055,7 @@ async function runMigrateIde(options) {
11704
12055
  if (options.dryRun) {
11705
12056
  console.log("\u{1F50D} DRY RUN - No files will be written\n");
11706
12057
  }
11707
- const confirmed = await confirm14({
12058
+ const confirmed = await confirm15({
11708
12059
  message: "Proceed with migration?",
11709
12060
  default: true
11710
12061
  });
@@ -11741,7 +12092,7 @@ async function runMigrateIde(options) {
11741
12092
  }
11742
12093
 
11743
12094
  // src/cli.ts
11744
- var program = new Command55();
12095
+ var program = new Command60();
11745
12096
  if (process.argv.includes("-v") || process.argv.includes("--version")) {
11746
12097
  console.log(package_default.version);
11747
12098
  if (!process.argv.includes("--skip-update-check")) {
@@ -11762,15 +12113,16 @@ program.addCommand(createChatCommand());
11762
12113
  program.addCommand(createOpenAiKeysCommand());
11763
12114
  program.addCommand(createStatsCommand());
11764
12115
  program.addCommand(createTranslateCommand());
12116
+ program.addCommand(createImageCommand());
11765
12117
  program.addCommand(createUtilsCommand());
11766
12118
  program.addCommand(createDepsCommand());
11767
12119
  program.addCommand(createKitCommand());
11768
12120
  program.addCommand(createRulesCommand());
11769
12121
  program.addCommand(createUpgradeCommand());
11770
12122
  program.addCommand(createCleanCommand());
11771
- var redmineCommand = new Command55("redmine").description("Redmine context sync commands");
12123
+ var redmineCommand = new Command60("redmine").description("Redmine context sync commands");
11772
12124
  redmineCommand.addCommand(createRedmineCheckCommand());
11773
- var syncCommand = new Command55("sync").description("Sync Redmine issues to markdown files");
12125
+ var syncCommand = new Command60("sync").description("Sync Redmine issues to markdown files");
11774
12126
  syncCommand.addCommand(createSyncIssueCommand());
11775
12127
  syncCommand.addCommand(createSyncProjectCommand());
11776
12128
  redmineCommand.addCommand(syncCommand);