@jvittechs/j 1.0.19 → 1.0.21

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
@@ -169,7 +169,7 @@ import { basename as basename4 } from "path";
169
169
  // package.json
170
170
  var package_default = {
171
171
  name: "@jvittechs/j",
172
- version: "1.0.19",
172
+ version: "1.0.21",
173
173
  description: "A unified CLI tool for JV-IT TECHS developers to manage Jai1 Framework. Supports both `j` and `jai1` commands. Please contact TeamAI for usage instructions.",
174
174
  type: "module",
175
175
  bin: {
@@ -2696,6 +2696,47 @@ var IDE_CONFIGS = {
2696
2696
  descriptionField: "description"
2697
2697
  }
2698
2698
  },
2699
+ claudecode: {
2700
+ id: "claudecode",
2701
+ name: "Claude Code",
2702
+ icon: "\u{1F916}",
2703
+ basePath: ".claude",
2704
+ contentPaths: {
2705
+ rules: "rules",
2706
+ workflows: "commands"
2707
+ // Claude Code uses "commands" for workflows
2708
+ },
2709
+ fileExtensions: {
2710
+ rules: [".md"],
2711
+ workflows: [".md"]
2712
+ },
2713
+ frontmatterSchema: {
2714
+ triggerField: "paths",
2715
+ descriptionField: "description"
2716
+ }
2717
+ },
2718
+ opencode: {
2719
+ id: "opencode",
2720
+ name: "OpenCode",
2721
+ icon: "\u{1F4BB}",
2722
+ basePath: ".",
2723
+ // AGENTS.md lives at project root
2724
+ contentPaths: {
2725
+ rules: ".",
2726
+ // Single file: AGENTS.md
2727
+ workflows: ".opencode/command"
2728
+ },
2729
+ fileExtensions: {
2730
+ rules: [".md"],
2731
+ // Only AGENTS.md
2732
+ workflows: [".md"]
2733
+ },
2734
+ frontmatterSchema: {
2735
+ triggerField: "trigger",
2736
+ alwaysApplyField: "trigger",
2737
+ descriptionField: "description"
2738
+ }
2739
+ },
2699
2740
  jai1: {
2700
2741
  id: "jai1",
2701
2742
  name: "Jai1 Framework",
@@ -2792,6 +2833,9 @@ var ContextScannerService = class {
2792
2833
  const config = IDE_CONFIGS[ide];
2793
2834
  const relativePath = config.contentPaths[type];
2794
2835
  if (!relativePath) return [];
2836
+ if (ide === "opencode" && type === "rules") {
2837
+ return this.scanOpenCodeRules();
2838
+ }
2795
2839
  let dirPath;
2796
2840
  if (ide === "jai1") {
2797
2841
  const jai1Path = path2.join(this.projectPath, ".jai1", relativePath);
@@ -2861,6 +2905,22 @@ var ContextScannerService = class {
2861
2905
  }
2862
2906
  return items;
2863
2907
  }
2908
+ /**
2909
+ * Scan OpenCode rules (AGENTS.md at project root)
2910
+ */
2911
+ async scanOpenCodeRules() {
2912
+ const agentsPath = path2.join(this.projectPath, "AGENTS.md");
2913
+ if (!await this.pathExists(agentsPath)) {
2914
+ return [];
2915
+ }
2916
+ try {
2917
+ const item = await this.parseContextItem(agentsPath, "opencode", "rules");
2918
+ item.alwaysApply = true;
2919
+ return [item];
2920
+ } catch {
2921
+ return [];
2922
+ }
2923
+ }
2864
2924
  /**
2865
2925
  * Parse a context item from file
2866
2926
  */
@@ -2934,6 +2994,12 @@ var ContextScannerService = class {
2934
2994
  if (await this.pathExists(jai1Path) || await this.pathExists(frameworkPath)) {
2935
2995
  ides.push(ide);
2936
2996
  }
2997
+ } else if (ide === "opencode") {
2998
+ const agentsPath = path2.join(this.projectPath, "AGENTS.md");
2999
+ const opencodePath = path2.join(this.projectPath, ".opencode");
3000
+ if (await this.pathExists(agentsPath) || await this.pathExists(opencodePath)) {
3001
+ ides.push(ide);
3002
+ }
2937
3003
  } else {
2938
3004
  const idePath = path2.join(this.projectPath, config.basePath);
2939
3005
  if (await this.pathExists(idePath)) {
@@ -3041,7 +3107,8 @@ function renderIDEContext(ideContext) {
3041
3107
  }
3042
3108
  if (ruleItems.length > 0) {
3043
3109
  console.log("");
3044
- console.log(` ${chalk6.bold("Rules")} ${chalk6.dim(`\xB7 ${config.basePath}/rules`)}`);
3110
+ const rulesPath = config.id === "opencode" ? "AGENTS.md" : `${config.basePath}/rules`;
3111
+ console.log(` ${chalk6.bold("Rules")} ${chalk6.dim(`\xB7 ${rulesPath}`)}`);
3045
3112
  const sorted = [...ruleItems].sort((a, b) => b.fileSize - a.fileSize);
3046
3113
  for (const rule of sorted) {
3047
3114
  const tokens = estimateTokens(rule.fileSize);
@@ -3053,7 +3120,9 @@ function renderIDEContext(ideContext) {
3053
3120
  const workflowItems = items.filter((item) => item.type === "workflows");
3054
3121
  if (workflowItems.length > 0) {
3055
3122
  console.log("");
3056
- console.log(` ${chalk6.bold("Workflows")} ${chalk6.dim(`\xB7 ${config.basePath}/workflows`)}`);
3123
+ const wfPath = config.contentPaths.workflows || "workflows";
3124
+ const wfDisplayPath = config.basePath === "." ? wfPath : `${config.basePath}/${wfPath}`;
3125
+ console.log(` ${chalk6.bold("Workflows")} ${chalk6.dim(`\xB7 ${wfDisplayPath}`)}`);
3057
3126
  const sorted = [...workflowItems].sort((a, b) => b.fileSize - a.fileSize);
3058
3127
  for (const wf of sorted) {
3059
3128
  const tokens = estimateTokens(wf.fileSize);
@@ -3064,9 +3133,9 @@ function renderIDEContext(ideContext) {
3064
3133
  console.log("");
3065
3134
  }
3066
3135
  function createContextCommand() {
3067
- const cmd = new Command7("context").description("Visualize IDE context window token budget").argument("[ide]", "Show specific IDE only (cursor, windsurf, antigravity)").action(async (ideArg) => {
3136
+ const cmd = new Command7("context").description("Visualize IDE context window token budget").argument("[ide]", "Show specific IDE only (cursor, windsurf, antigravity, claudecode, opencode)").action(async (ideArg) => {
3068
3137
  const name = getCliName();
3069
- const allIDEs = ["cursor", "windsurf", "antigravity"];
3138
+ const allIDEs = ["cursor", "windsurf", "antigravity", "claudecode", "opencode"];
3070
3139
  if (ideArg) {
3071
3140
  if (!allIDEs.includes(ideArg)) {
3072
3141
  console.error(chalk6.red(`\u274C Invalid IDE: ${ideArg}`));
@@ -3648,6 +3717,7 @@ var IDE_FORMATS = {
3648
3717
  };
3649
3718
 
3650
3719
  // src/services/ide-detection.service.ts
3720
+ var DEFAULT_RULE_KEYWORD = "jai1";
3651
3721
  var IdeDetectionService = class {
3652
3722
  projectPath;
3653
3723
  constructor(projectPath = process.cwd()) {
@@ -3711,9 +3781,11 @@ var IdeDetectionService = class {
3711
3781
  const rulesPath = join5(this.projectPath, format.rulesPath);
3712
3782
  const rulesExist = await this.pathExists(rulesPath);
3713
3783
  if (rulesExist) {
3714
- detection.hasRules = true;
3715
- detection.ruleCount = await this.countFiles(rulesPath, format.fileExtension);
3716
- if (detection.ruleCount > 0) {
3784
+ const totalRules = await this.countFiles(rulesPath, format.fileExtension);
3785
+ const customRules = await this.countFiles(rulesPath, format.fileExtension, [DEFAULT_RULE_KEYWORD]);
3786
+ detection.hasRules = customRules > 0;
3787
+ detection.ruleCount = customRules;
3788
+ if (totalRules > 0) {
3717
3789
  detection.detected = true;
3718
3790
  }
3719
3791
  }
@@ -3833,10 +3905,17 @@ var IdeDetectionService = class {
3833
3905
  /**
3834
3906
  * Count files with specific extension in a directory
3835
3907
  */
3836
- async countFiles(dirPath, extension) {
3908
+ async countFiles(dirPath, extension, excludeKeywords = []) {
3837
3909
  try {
3838
3910
  const entries = await fs8.readdir(dirPath, { withFileTypes: true });
3839
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(extension)).length;
3911
+ return entries.filter((entry) => {
3912
+ if (!entry.isFile() || !entry.name.endsWith(extension)) return false;
3913
+ if (excludeKeywords.length > 0) {
3914
+ const nameLower = entry.name.toLowerCase();
3915
+ return !excludeKeywords.some((kw) => nameLower.includes(kw));
3916
+ }
3917
+ return true;
3918
+ }).length;
3840
3919
  } catch {
3841
3920
  return 0;
3842
3921
  }