@jvittechs/jai1-cli 0.1.90 → 0.1.91

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
@@ -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.91",
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: {
@@ -539,7 +539,11 @@ var ComponentsService = class {
539
539
  const bundleJson = gunzipSync(compressed).toString("utf-8");
540
540
  checksumContent = bundleJson;
541
541
  const bundle = JSON.parse(bundleJson);
542
- const presetDir = join2(targetDir, filepath);
542
+ const presetDir = join2(targetDir, "rule-preset");
543
+ try {
544
+ await fs2.rm(presetDir, { recursive: true, force: true });
545
+ } catch {
546
+ }
543
547
  await fs2.mkdir(presetDir, { recursive: true });
544
548
  await fs2.writeFile(
545
549
  join2(presetDir, "preset.json"),
@@ -879,7 +883,7 @@ var UnifiedApplyApp = ({
879
883
  const [searchQuery, setSearchQuery] = useState("");
880
884
  const [selectedPaths, setSelectedPaths] = useState(/* @__PURE__ */ new Set());
881
885
  const [cursorIndex, setCursorIndex] = useState(0);
882
- const [focusArea, setFocusArea] = useState("components");
886
+ const [focusArea, setFocusArea] = useState("packages");
883
887
  const [selectedPackageIndex, setSelectedPackageIndex] = useState(0);
884
888
  const [installProgress, setInstallProgress] = useState([]);
885
889
  const [installStats, setInstallStats] = useState({ total: 0, completed: 0, added: 0, updated: 0, failed: 0 });
@@ -922,9 +926,9 @@ var UnifiedApplyApp = ({
922
926
  return;
923
927
  }
924
928
  if (key.tab) {
925
- if (focusArea === "search") setFocusArea("packages");
926
- else if (focusArea === "packages") setFocusArea("components");
927
- else setFocusArea("search");
929
+ if (focusArea === "packages") setFocusArea("components");
930
+ else if (focusArea === "components") setFocusArea("search");
931
+ else setFocusArea("packages");
928
932
  return;
929
933
  }
930
934
  if (key.escape || input4 === "q") {
@@ -937,6 +941,19 @@ var UnifiedApplyApp = ({
937
941
  }
938
942
  return;
939
943
  }
944
+ if (focusArea !== "search") {
945
+ if (input4 === "a") {
946
+ setSelectedPaths((prev) => {
947
+ const next = new Set(prev);
948
+ filteredComponents.forEach((c) => next.add(c.filepath));
949
+ return next;
950
+ });
951
+ return;
952
+ } else if (input4 === "c") {
953
+ setSelectedPaths(/* @__PURE__ */ new Set());
954
+ return;
955
+ }
956
+ }
940
957
  if (focusArea === "components") {
941
958
  if (key.upArrow) {
942
959
  setCursorIndex((prev) => Math.max(0, prev - 1));
@@ -955,14 +972,6 @@ var UnifiedApplyApp = ({
955
972
  return next;
956
973
  });
957
974
  }
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
975
  }
967
976
  }
968
977
  if (focusArea === "packages") {
@@ -1067,7 +1076,7 @@ var UnifiedApplyApp = ({
1067
1076
  const isChecked = selectedPaths.has(comp.filepath);
1068
1077
  const isInstalled = installedPaths.has(comp.filepath);
1069
1078
  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")));
1079
+ }), 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
1080
  };
1072
1081
 
1073
1082
  // src/commands/apply.ts
@@ -2529,17 +2538,20 @@ trigger: ${trigger}
2529
2538
  name: "Claude Code",
2530
2539
  icon: "\u{1F916}",
2531
2540
  basePath: ".claude",
2532
- rulesPath: null,
2541
+ rulesPath: "rules",
2533
2542
  workflowsPath: null,
2534
2543
  commandsPath: "commands",
2535
2544
  fileExtension: ".md",
2536
2545
  generateFrontmatter: (opts) => {
2546
+ const lines = ["---"];
2537
2547
  if (opts.description) {
2538
- return `---
2539
- description: ${opts.description}
2540
- ---`;
2548
+ lines.push(`description: ${opts.description}`);
2549
+ }
2550
+ if (opts.globs && opts.globs.length > 0) {
2551
+ lines.push(`paths: ${opts.globs.join(", ")}`);
2541
2552
  }
2542
- return "";
2553
+ lines.push("---");
2554
+ return lines.join("\n");
2543
2555
  }
2544
2556
  },
2545
2557
  opencode: {
@@ -2575,7 +2587,9 @@ var MigrateIdeService = class {
2575
2587
  * Scan .jai1/ directory for content
2576
2588
  */
2577
2589
  async scanJai1Content() {
2578
- const rules = await this.scanContentType("rules");
2590
+ const manualRules = await this.scanContentType("rules");
2591
+ const presetRules = await this.scanRulePreset();
2592
+ const rules = [...presetRules, ...manualRules];
2579
2593
  const workflows = await this.scanContentType("workflows");
2580
2594
  const commands = [];
2581
2595
  return {
@@ -2585,6 +2599,42 @@ var MigrateIdeService = class {
2585
2599
  totalCount: rules.length + workflows.length + commands.length
2586
2600
  };
2587
2601
  }
2602
+ /**
2603
+ * Scan .jai1/rule-preset/ directory for rule preset files
2604
+ */
2605
+ async scanRulePreset() {
2606
+ const items = [];
2607
+ const presetDir = path3.join(this.jai1Path, "rule-preset");
2608
+ try {
2609
+ await fs6.access(presetDir);
2610
+ } catch {
2611
+ return items;
2612
+ }
2613
+ const files = await fs6.readdir(presetDir);
2614
+ for (const file of files) {
2615
+ if (!file.endsWith(".mdc")) continue;
2616
+ const filepath = path3.join(presetDir, file);
2617
+ const stat = await fs6.stat(filepath);
2618
+ if (!stat.isFile()) continue;
2619
+ const content = await fs6.readFile(filepath, "utf-8");
2620
+ let frontmatter = {};
2621
+ try {
2622
+ const { data } = matter2(content);
2623
+ frontmatter = data;
2624
+ } catch {
2625
+ }
2626
+ items.push({
2627
+ type: "rules",
2628
+ name: path3.basename(file, ".mdc"),
2629
+ filepath,
2630
+ relativePath: path3.relative(this.projectPath, filepath),
2631
+ description: frontmatter.description,
2632
+ globs: this.extractGlobs(frontmatter),
2633
+ alwaysApply: this.extractAlwaysApply(frontmatter)
2634
+ });
2635
+ }
2636
+ return items;
2637
+ }
2588
2638
  /**
2589
2639
  * Scan a specific content type
2590
2640
  */
@@ -2708,7 +2758,7 @@ ${reference}
2708
2758
  contentPath = config.rulesPath;
2709
2759
  break;
2710
2760
  case "workflows":
2711
- contentPath = config.workflowsPath;
2761
+ contentPath = config.workflowsPath ?? config.commandsPath;
2712
2762
  break;
2713
2763
  case "commands":
2714
2764
  contentPath = config.commandsPath;
@@ -2743,13 +2793,17 @@ async function runSync(options) {
2743
2793
  const service = new MigrateIdeService();
2744
2794
  console.log("\n\u{1F504} Sync rules and workflows to IDE(s)\n");
2745
2795
  console.log("\u{1F4C1} Scanning .jai1/ directory...");
2796
+ console.log(" \u2022 .jai1/rule-preset/ (active rule preset)");
2797
+ console.log(" \u2022 .jai1/rules/ (manual rules)");
2798
+ console.log(" \u2022 .jai1/workflows/\n");
2746
2799
  const content = await service.scanJai1Content();
2747
2800
  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");
2801
+ console.log("\u26A0\uFE0F No content found in .jai1/");
2802
+ console.log(' \u{1F4A1} Run "jai1 rules apply" to apply a rule preset, or');
2803
+ console.log(" \u{1F4A1} Create files in .jai1/rules/ or .jai1/workflows/\n");
2750
2804
  process.exit(1);
2751
2805
  }
2752
- console.log(` Found: ${content.rules.length} rules, ${content.workflows.length} workflows
2806
+ console.log(`\u2713 Found: ${content.rules.length} rules, ${content.workflows.length} workflows
2753
2807
  `);
2754
2808
  let selectedIdes;
2755
2809
  if (options.ide && options.ide.length > 0) {
@@ -9428,19 +9482,23 @@ function createRulesApplyCommand() {
9428
9482
  }
9429
9483
  }
9430
9484
  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 });
9485
+ const rulePresetDir = join9(process.cwd(), ".jai1", "rule-preset");
9486
+ try {
9487
+ await fs15.rm(rulePresetDir, { recursive: true, force: true });
9488
+ } catch {
9489
+ }
9490
+ await fs15.mkdir(rulePresetDir, { recursive: true });
9433
9491
  await fs15.writeFile(
9434
- join9(presetDir, "preset.json"),
9492
+ join9(rulePresetDir, "preset.json"),
9435
9493
  JSON.stringify(bundle.preset, null, 2),
9436
9494
  "utf-8"
9437
9495
  );
9438
9496
  for (const [filename, content] of Object.entries(bundle.files)) {
9439
- const filePath = join9(presetDir, filename);
9497
+ const filePath = join9(rulePresetDir, filename);
9440
9498
  await fs15.mkdir(join9(filePath, ".."), { recursive: true });
9441
9499
  await fs15.writeFile(filePath, content, "utf-8");
9442
9500
  }
9443
- console.log(`\u2713 Saved preset to .jai1/rule-presets/${bundle.preset.slug}/`);
9501
+ console.log(`\u2713 Saved preset to .jai1/rule-preset/`);
9444
9502
  const allGeneratedFiles = [];
9445
9503
  for (const ideId of resolvedIdes) {
9446
9504
  try {
@@ -9511,9 +9569,9 @@ function createRulesApplyCommand() {
9511
9569
  }
9512
9570
  console.log("\n\u{1F4DD} Next steps:");
9513
9571
  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');
9572
+ console.log(" 2. Edit rules in .jai1/rule-preset/ (source of truth)");
9573
+ console.log(' 3. Run "jai1 rules sync" to regenerate IDE outputs');
9574
+ console.log(" 4. Commit the rules to git");
9517
9575
  console.log(' 5. Use "jai1 ide status" to check IDE configuration\n');
9518
9576
  });
9519
9577
  }
@@ -9680,17 +9738,21 @@ Detected ${detected.length} active IDE(s):
9680
9738
  throw new Error(`Failed to fetch preset: ${presetResponse.statusText}`);
9681
9739
  }
9682
9740
  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);
9741
+ const rulePresetDir = join11(process.cwd(), ".jai1", "rule-preset");
9742
+ const presetExists = await checkPathExists(rulePresetDir);
9743
+ if (presetExists) {
9744
+ const files = await fs16.readdir(rulePresetDir);
9687
9745
  for (const file of files) {
9688
9746
  if (file.endsWith(".mdc")) {
9689
- const filePath = join11(sourceDir, file);
9747
+ const filePath = join11(rulePresetDir, file);
9690
9748
  const content = await fs16.readFile(filePath, "utf-8");
9691
9749
  bundle.files[file] = content;
9692
9750
  }
9693
9751
  }
9752
+ } else {
9753
+ console.log("\n\u26A0\uFE0F No rule preset found in .jai1/rule-preset/");
9754
+ console.log(' Run "jai1 rules apply" first to apply a preset.\n');
9755
+ return;
9694
9756
  }
9695
9757
  const generatorService = new RulesGeneratorService();
9696
9758
  for (const ideId of idesToSync) {
@@ -9724,12 +9786,12 @@ Detected ${detected.length} active IDE(s):
9724
9786
  console.log("\u{1F4A1} Next steps:");
9725
9787
  console.log(" \u2022 Your IDE may need to be restarted to pick up changes");
9726
9788
  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");
9789
+ console.log(" \u2022 Edit source files in .jai1/rule-preset/ and sync again\n");
9728
9790
  });
9729
9791
  }
9730
- async function checkPathExists(path8) {
9792
+ async function checkPathExists(absolutePath) {
9731
9793
  try {
9732
- await fs16.access(join11(process.cwd(), path8));
9794
+ await fs16.access(absolutePath);
9733
9795
  return true;
9734
9796
  } catch {
9735
9797
  return false;
@@ -9757,10 +9819,43 @@ function createRulesInfoCommand() {
9757
9819
  return;
9758
9820
  }
9759
9821
  console.log("\u{1F4CB} Current Preset Information\n");
9760
- console.log(`Preset: ${projectConfig.preset}`);
9761
- console.log(`Version: ${projectConfig.version}`);
9822
+ const rulePresetDir = join12(process.cwd(), ".jai1", "rule-preset");
9823
+ const presetJsonPath = join12(rulePresetDir, "preset.json");
9824
+ let presetMetadata = null;
9825
+ let presetFiles = [];
9826
+ try {
9827
+ const presetContent = await fs17.readFile(presetJsonPath, "utf-8");
9828
+ presetMetadata = JSON.parse(presetContent);
9829
+ const files = await fs17.readdir(rulePresetDir);
9830
+ presetFiles = files.filter((f) => f.endsWith(".mdc"));
9831
+ } catch {
9832
+ }
9833
+ if (presetMetadata) {
9834
+ console.log(`Preset: ${presetMetadata.name} (${presetMetadata.slug})`);
9835
+ console.log(`Version: ${presetMetadata.version}`);
9836
+ console.log(`Description: ${presetMetadata.description}`);
9837
+ if (presetMetadata.tags && presetMetadata.tags.length > 0) {
9838
+ console.log(`Tags: ${presetMetadata.tags.join(", ")}`);
9839
+ }
9840
+ } else {
9841
+ console.log(`Preset: ${projectConfig.preset}`);
9842
+ console.log(`Version: ${projectConfig.version}`);
9843
+ }
9762
9844
  console.log(`Applied at: ${new Date(projectConfig.appliedAt).toLocaleString()}`);
9763
- console.log(`Custom rules: ${projectConfig.customContext}`);
9845
+ console.log(`
9846
+ Source of Truth:`);
9847
+ if (presetFiles.length > 0) {
9848
+ console.log(` \u{1F4C1} .jai1/rule-preset/ (${presetFiles.length} files)`);
9849
+ for (const file of presetFiles.slice(0, 5)) {
9850
+ console.log(` \u2022 ${file}`);
9851
+ }
9852
+ if (presetFiles.length > 5) {
9853
+ console.log(` ... and ${presetFiles.length - 5} more`);
9854
+ }
9855
+ } else {
9856
+ console.log(` \u26A0\uFE0F .jai1/rule-preset/ not found`);
9857
+ console.log(` Run "jai1 rules apply" to create it`);
9858
+ }
9764
9859
  if (projectConfig.ides && projectConfig.ides.length > 0) {
9765
9860
  console.log(`
9766
9861
  Configured IDEs (${projectConfig.ides.length}):`);
@@ -9785,9 +9880,9 @@ Available Backups (${projectConfig.backups.length}):`);
9785
9880
  }
9786
9881
  }
9787
9882
  console.log("\n\u2139\uFE0F Commands:");
9788
- console.log(' \u2022 "jai1 rules sync" - Regenerate outputs after editing');
9883
+ console.log(' \u2022 "jai1 rules sync" - Regenerate IDE outputs after editing .jai1/rule-preset/');
9789
9884
  console.log(' \u2022 "jai1 rules restore" - Restore from backup');
9790
- console.log(' \u2022 "jai1 rules apply" - Apply a different preset');
9885
+ console.log(' \u2022 "jai1 rules apply" - Apply a different preset (replaces current)');
9791
9886
  });
9792
9887
  }
9793
9888
  async function checkPathExists2(path8) {