@jvittechs/j 1.0.15 → 1.0.17

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.15",
172
+ version: "1.0.17",
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: {
@@ -1140,6 +1140,15 @@ function getMigrationIDEs() {
1140
1140
  return Object.keys(IDE_MIGRATION_CONFIGS);
1141
1141
  }
1142
1142
 
1143
+ // src/utils/heading-utils.ts
1144
+ function downshiftHeadings(content) {
1145
+ return content.replace(/^(#{1,5})\s/gm, (_match, hashes) => "#" + hashes + " ");
1146
+ }
1147
+ function extractBody(content) {
1148
+ const match = content.match(/^---\n[\s\S]*?\n---\n?([\s\S]*)$/);
1149
+ return match ? match[1].trim() : content.trim();
1150
+ }
1151
+
1143
1152
  // src/services/migrate-ide.service.ts
1144
1153
  var MigrateIdeService = class {
1145
1154
  projectPath;
@@ -1248,9 +1257,10 @@ var MigrateIdeService = class {
1248
1257
  return items;
1249
1258
  }
1250
1259
  /**
1251
- * Generate stub file content with @ reference
1260
+ * Generate copied content for IDE rule file.
1261
+ * Reads the actual source file and combines IDE-specific frontmatter with the body content.
1252
1262
  */
1253
- generateStubContent(ide, sourceItem) {
1263
+ async generateCopiedContent(ide, sourceItem) {
1254
1264
  const config = IDE_MIGRATION_CONFIGS[ide];
1255
1265
  if (!config) throw new Error(`Unknown IDE: ${ide}`);
1256
1266
  const frontmatter = config.generateFrontmatter({
@@ -1260,14 +1270,15 @@ var MigrateIdeService = class {
1260
1270
  alwaysApply: sourceItem.alwaysApply,
1261
1271
  sourceFile: sourceItem.relativePath
1262
1272
  });
1263
- const reference = `@${sourceItem.relativePath}`;
1273
+ const sourceContent = await fs5.readFile(sourceItem.filepath, "utf-8");
1274
+ const bodyContent = extractBody(sourceContent);
1264
1275
  if (frontmatter) {
1265
1276
  return `${frontmatter}
1266
1277
 
1267
- ${reference}
1278
+ ${bodyContent}
1268
1279
  `;
1269
1280
  }
1270
- return `${reference}
1281
+ return `${bodyContent}
1271
1282
  `;
1272
1283
  }
1273
1284
  /**
@@ -1316,7 +1327,12 @@ ${reference}
1316
1327
  ""
1317
1328
  ];
1318
1329
  for (const rule of rules) {
1319
- lines.push(`@${rule.relativePath}`);
1330
+ const content = await fs5.readFile(rule.filepath, "utf-8");
1331
+ const body = extractBody(content);
1332
+ if (body.trim()) {
1333
+ lines.push(downshiftHeadings(body));
1334
+ lines.push("");
1335
+ }
1320
1336
  }
1321
1337
  lines.push("");
1322
1338
  await fs5.writeFile(agentsPath, lines.join("\n"), "utf-8");
@@ -1372,8 +1388,8 @@ ${reference}
1372
1388
  status = "updated";
1373
1389
  } catch {
1374
1390
  }
1375
- const stubContent = this.generateStubContent(ide, item);
1376
- await fs5.writeFile(targetPath, stubContent, "utf-8");
1391
+ const copiedContent = await this.generateCopiedContent(ide, item);
1392
+ await fs5.writeFile(targetPath, copiedContent, "utf-8");
1377
1393
  return {
1378
1394
  source: item,
1379
1395
  targetIDE: ide,
@@ -2966,57 +2982,86 @@ var ContextScannerService = class {
2966
2982
  var MAX_TOKENS = 256e3;
2967
2983
  var SYSTEM_PROMPT_TOKENS = 1e4;
2968
2984
  var COMPACT_BUFFER_TOKENS = 56e3;
2969
- var BAR_WIDTH = 40;
2985
+ var BAR_WIDTH = 50;
2970
2986
  var CHARS_PER_TOKEN = 4;
2971
2987
  function estimateTokens(bytes) {
2972
2988
  return Math.ceil(bytes / CHARS_PER_TOKEN);
2973
2989
  }
2990
+ function formatTokens(n) {
2991
+ if (n >= 1e3) {
2992
+ const k = n / 1e3;
2993
+ return k % 1 === 0 ? `${k}k` : `${k.toFixed(1)}k`;
2994
+ }
2995
+ return String(n);
2996
+ }
2974
2997
  function formatNumber(n) {
2975
2998
  return n.toLocaleString("en-US");
2976
2999
  }
2977
- function renderBar(value, total, width, color) {
2978
- const filled = Math.round(value / total * width);
2979
- const empty = width - filled;
2980
- return color("\u2588".repeat(filled)) + chalk6.gray("\u2591".repeat(empty));
2981
- }
2982
- function renderPercentage(value, total) {
3000
+ function pct(value, total) {
2983
3001
  return (value / total * 100).toFixed(1) + "%";
2984
3002
  }
3003
+ function renderStackedBar(segments, total, width) {
3004
+ let bar = "";
3005
+ let usedCols = 0;
3006
+ for (let i = 0; i < segments.length; i++) {
3007
+ const seg = segments[i];
3008
+ const isLast = i === segments.length - 1;
3009
+ const cols = isLast ? width - usedCols : Math.round(seg.tokens / total * width);
3010
+ if (cols > 0) {
3011
+ bar += seg.color(seg.char.repeat(cols));
3012
+ usedCols += cols;
3013
+ }
3014
+ }
3015
+ return bar;
3016
+ }
2985
3017
  function renderIDEContext(ideContext) {
2986
3018
  const { config, items } = ideContext;
2987
3019
  const ruleItems = items.filter((item) => item.type === "rules");
2988
3020
  const rulesTotalBytes = ruleItems.reduce((sum, item) => sum + item.fileSize, 0);
2989
3021
  const rulesTokens = estimateTokens(rulesTotalBytes);
3022
+ const usedTokens = SYSTEM_PROMPT_TOKENS + rulesTokens;
2990
3023
  const userPromptTokens = Math.max(0, MAX_TOKENS - SYSTEM_PROMPT_TOKENS - rulesTokens - COMPACT_BUFFER_TOKENS);
2991
- console.log("");
2992
- console.log(chalk6.bold(`${config.icon} ${config.name} Context Window (${formatNumber(MAX_TOKENS)} tokens)`));
2993
- console.log(chalk6.dim("\u2501".repeat(55)));
3024
+ console.log(`${chalk6.dim("\u2514")} ${chalk6.bold("Context Usage")}`);
2994
3025
  const segments = [
2995
- { icon: "\u{1F4D0}", label: "System Prompt", tokens: SYSTEM_PROMPT_TOKENS, color: chalk6.blue },
2996
- { icon: "\u{1F4CF}", label: "IDE Rules", tokens: rulesTokens, color: chalk6.yellow },
2997
- { icon: "\u{1F4AC}", label: "User Prompt", tokens: userPromptTokens, color: chalk6.green },
2998
- { icon: "\u{1F504}", label: "Compact Buffer", tokens: COMPACT_BUFFER_TOKENS, color: chalk6.magenta }
3026
+ { tokens: SYSTEM_PROMPT_TOKENS, char: "\u2593", color: chalk6.yellow },
3027
+ { tokens: rulesTokens, char: "\u2593", color: chalk6.red },
3028
+ { tokens: userPromptTokens, char: "\u2591", color: chalk6.dim },
3029
+ { tokens: COMPACT_BUFFER_TOKENS, char: "\u2592", color: chalk6.magenta }
3030
+ ];
3031
+ const barLine = renderStackedBar(segments, MAX_TOKENS, BAR_WIDTH);
3032
+ const summary = `${config.icon} ${config.name} \xB7 ${formatTokens(usedTokens)}/${formatTokens(MAX_TOKENS)} tokens (${pct(usedTokens, MAX_TOKENS)})`;
3033
+ console.log(` ${barLine} ${chalk6.bold(summary)}`);
3034
+ const legendItems = [
3035
+ { icon: "\u{1F7E1}", label: "System prompt", tokens: SYSTEM_PROMPT_TOKENS },
3036
+ { icon: "\u{1F534}", label: "IDE Rules", tokens: rulesTokens },
3037
+ { icon: "\u2B1C", label: "Free space", tokens: userPromptTokens },
3038
+ { icon: "\u{1F7E3}", label: "Autocompact buffer", tokens: COMPACT_BUFFER_TOKENS }
2999
3039
  ];
3000
- const maxLabelLen = Math.max(...segments.map((s) => s.label.length));
3001
- for (const seg of segments) {
3002
- const label = seg.label.padEnd(maxLabelLen);
3003
- const bar = renderBar(seg.tokens, MAX_TOKENS, BAR_WIDTH, seg.color);
3004
- const pct = renderPercentage(seg.tokens, MAX_TOKENS);
3005
- console.log(` ${seg.icon} ${label} ${bar} ${chalk6.white(formatNumber(seg.tokens).padStart(7))} tokens ${chalk6.dim(`(${pct})`)}`);
3040
+ const pad = " ".repeat(BAR_WIDTH + 5);
3041
+ for (const item of legendItems) {
3042
+ console.log(`${pad} ${item.icon} ${item.label}: ${formatTokens(item.tokens)} tokens (${pct(item.tokens, MAX_TOKENS)})`);
3006
3043
  }
3007
3044
  if (ruleItems.length > 0) {
3008
3045
  console.log("");
3009
- console.log(chalk6.dim(` Rules breakdown (${config.basePath}):`));
3046
+ console.log(` ${chalk6.bold("Rules")} ${chalk6.dim(`\xB7 ${config.basePath}/rules`)}`);
3010
3047
  const sorted = [...ruleItems].sort((a, b) => b.fileSize - a.fileSize);
3011
3048
  for (const rule of sorted) {
3012
3049
  const tokens = estimateTokens(rule.fileSize);
3013
3050
  const name = typeof rule.name === "string" ? rule.name : rule.relativePath;
3014
- const badge = rule.alwaysApply ? chalk6.cyan(" [always]") : "";
3015
- console.log(` \u2022 ${chalk6.white(name)}${badge} ${chalk6.dim(formatNumber(tokens) + " tokens")}`);
3051
+ const badge = rule.alwaysApply ? chalk6.dim(" [always]") : "";
3052
+ console.log(` ${chalk6.dim("\u2514")} ${name}${badge}: ${formatNumber(tokens)} tokens`);
3016
3053
  }
3017
- } else {
3054
+ }
3055
+ const workflowItems = items.filter((item) => item.type === "workflows");
3056
+ if (workflowItems.length > 0) {
3018
3057
  console.log("");
3019
- console.log(chalk6.dim(" No rules found."));
3058
+ console.log(` ${chalk6.bold("Workflows")} ${chalk6.dim(`\xB7 ${config.basePath}/workflows`)}`);
3059
+ const sorted = [...workflowItems].sort((a, b) => b.fileSize - a.fileSize);
3060
+ for (const wf of sorted) {
3061
+ const tokens = estimateTokens(wf.fileSize);
3062
+ const name = typeof wf.name === "string" ? wf.name : wf.relativePath;
3063
+ console.log(` ${chalk6.dim("\u2514")} ${name}: ${formatNumber(tokens)} tokens`);
3064
+ }
3020
3065
  }
3021
3066
  console.log("");
3022
3067
  }
@@ -3034,9 +3079,8 @@ function createContextCommand() {
3034
3079
  }
3035
3080
  const scanner = new ContextScannerService();
3036
3081
  const targetIDEs = ideArg ? [ideArg] : validIDEs;
3037
- console.log(chalk6.bold.cyan("\n\u{1F9E0} Context Window Analysis"));
3038
- console.log(chalk6.dim(` Max context: ${formatNumber(MAX_TOKENS)} tokens
3039
- `));
3082
+ console.log("");
3083
+ console.log(` ${chalk6.bgGray.white.bold(" /context ")}`);
3040
3084
  let found = false;
3041
3085
  for (const ide of targetIDEs) {
3042
3086
  try {
@@ -3050,8 +3094,8 @@ function createContextCommand() {
3050
3094
  }
3051
3095
  }
3052
3096
  if (!found) {
3053
- console.log(chalk6.yellow("\u26A0\uFE0F No IDEs detected in this project."));
3054
- console.log(chalk6.dim(` Run "${name} apply" to install context for your IDE.
3097
+ console.log(chalk6.yellow(" \u26A0\uFE0F No IDEs detected in this project."));
3098
+ console.log(chalk6.dim(` Run "${name} apply" to install context for your IDE.
3055
3099
  `));
3056
3100
  }
3057
3101
  });
@@ -4899,9 +4943,9 @@ var ChatApp = ({ service, initialModel }) => {
4899
4943
  return /* @__PURE__ */ React11.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1 }, /* @__PURE__ */ React11.createElement(Text9, { bold: true, color: "cyan" }, "\u{1F4CA} Model Usage Statistics"), allowed.map((m) => {
4900
4944
  const limit = m.dailyLimit ?? 0;
4901
4945
  const used = m.usedToday ?? 0;
4902
- const pct = limit > 0 ? Math.round(used / limit * 100) : 0;
4903
- const bar = "\u2588".repeat(Math.round(pct / 5)) + "\u2591".repeat(20 - Math.round(pct / 5));
4904
- return /* @__PURE__ */ React11.createElement(Box8, { key: m.id, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text9, { color: m.id === selectedModel ? "yellow" : "white" }, m.id === selectedModel ? "\u25BA " : " ", m.id), /* @__PURE__ */ React11.createElement(Text9, { color: pct > 80 ? "red" : pct > 50 ? "yellow" : "green" }, " ", bar, " ", /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, used, "/", limit)));
4946
+ const pct2 = limit > 0 ? Math.round(used / limit * 100) : 0;
4947
+ const bar = "\u2588".repeat(Math.round(pct2 / 5)) + "\u2591".repeat(20 - Math.round(pct2 / 5));
4948
+ return /* @__PURE__ */ React11.createElement(Box8, { key: m.id, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text9, { color: m.id === selectedModel ? "yellow" : "white" }, m.id === selectedModel ? "\u25BA " : " ", m.id), /* @__PURE__ */ React11.createElement(Text9, { color: pct2 > 80 ? "red" : pct2 > 50 ? "yellow" : "green" }, " ", bar, " ", /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, used, "/", limit)));
4905
4949
  }), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, "[Esc] Back"));
4906
4950
  }, [models, selectedModel]);
4907
4951
  const footer = currentView === "error" ? "[Enter/r] Retry \u2022 [Esc] Quit" : currentView === "model" || currentView === "stats" ? "[\u2191\u2193] Navigate \u2022 [Enter] Select \u2022 [Esc] Back" : showSlashMenu ? "[\u2191\u2193] Navigate \u2022 [Enter] Select \u2022 [Esc] Cancel" : "[Tab] Next Model \u2022 [/] Commands \u2022 [Esc] Quit";
@@ -12025,7 +12069,7 @@ ${body.trim()}
12025
12069
  `;
12026
12070
  }
12027
12071
  /**
12028
- * Generate Antigravity format (.md files with trigger metadata + @AGENTS.md reference)
12072
+ * Generate Antigravity format (.md files with trigger metadata + actual content)
12029
12073
  */
12030
12074
  generateAntigravityFiles(bundle, format) {
12031
12075
  const files = [];
@@ -12056,9 +12100,7 @@ ${body.trim()}
12056
12100
  }
12057
12101
  const antigravityFrontmatter = `---
12058
12102
  trigger: ${trigger}
12059
- ---
12060
-
12061
- @AGENTS.md`;
12103
+ ---`;
12062
12104
  return `${antigravityFrontmatter}
12063
12105
 
12064
12106
  ${body.trim()}
@@ -12128,7 +12170,7 @@ ${body.trim()}
12128
12170
  const content = bundle.files[filename];
12129
12171
  const withoutFrontmatter = this.removeFrontmatter(content);
12130
12172
  if (withoutFrontmatter.trim()) {
12131
- sections.push(withoutFrontmatter.trim());
12173
+ sections.push(downshiftHeadings(withoutFrontmatter.trim()));
12132
12174
  sections.push("\n");
12133
12175
  }
12134
12176
  }