@jvittechs/j 1.0.15 → 1.0.16

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.16",
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: {
@@ -2966,57 +2966,86 @@ var ContextScannerService = class {
2966
2966
  var MAX_TOKENS = 256e3;
2967
2967
  var SYSTEM_PROMPT_TOKENS = 1e4;
2968
2968
  var COMPACT_BUFFER_TOKENS = 56e3;
2969
- var BAR_WIDTH = 40;
2969
+ var BAR_WIDTH = 50;
2970
2970
  var CHARS_PER_TOKEN = 4;
2971
2971
  function estimateTokens(bytes) {
2972
2972
  return Math.ceil(bytes / CHARS_PER_TOKEN);
2973
2973
  }
2974
+ function formatTokens(n) {
2975
+ if (n >= 1e3) {
2976
+ const k = n / 1e3;
2977
+ return k % 1 === 0 ? `${k}k` : `${k.toFixed(1)}k`;
2978
+ }
2979
+ return String(n);
2980
+ }
2974
2981
  function formatNumber(n) {
2975
2982
  return n.toLocaleString("en-US");
2976
2983
  }
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) {
2984
+ function pct(value, total) {
2983
2985
  return (value / total * 100).toFixed(1) + "%";
2984
2986
  }
2987
+ function renderStackedBar(segments, total, width) {
2988
+ let bar = "";
2989
+ let usedCols = 0;
2990
+ for (let i = 0; i < segments.length; i++) {
2991
+ const seg = segments[i];
2992
+ const isLast = i === segments.length - 1;
2993
+ const cols = isLast ? width - usedCols : Math.round(seg.tokens / total * width);
2994
+ if (cols > 0) {
2995
+ bar += seg.color(seg.char.repeat(cols));
2996
+ usedCols += cols;
2997
+ }
2998
+ }
2999
+ return bar;
3000
+ }
2985
3001
  function renderIDEContext(ideContext) {
2986
3002
  const { config, items } = ideContext;
2987
3003
  const ruleItems = items.filter((item) => item.type === "rules");
2988
3004
  const rulesTotalBytes = ruleItems.reduce((sum, item) => sum + item.fileSize, 0);
2989
3005
  const rulesTokens = estimateTokens(rulesTotalBytes);
3006
+ const usedTokens = SYSTEM_PROMPT_TOKENS + rulesTokens;
2990
3007
  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)));
3008
+ console.log(`${chalk6.dim("\u2514")} ${chalk6.bold("Context Usage")}`);
2994
3009
  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 }
3010
+ { tokens: SYSTEM_PROMPT_TOKENS, char: "\u2593", color: chalk6.yellow },
3011
+ { tokens: rulesTokens, char: "\u2593", color: chalk6.red },
3012
+ { tokens: userPromptTokens, char: "\u2591", color: chalk6.dim },
3013
+ { tokens: COMPACT_BUFFER_TOKENS, char: "\u2592", color: chalk6.magenta }
3014
+ ];
3015
+ const barLine = renderStackedBar(segments, MAX_TOKENS, BAR_WIDTH);
3016
+ const summary = `${config.icon} ${config.name} \xB7 ${formatTokens(usedTokens)}/${formatTokens(MAX_TOKENS)} tokens (${pct(usedTokens, MAX_TOKENS)})`;
3017
+ console.log(` ${barLine} ${chalk6.bold(summary)}`);
3018
+ const legendItems = [
3019
+ { icon: "\u{1F7E1}", label: "System prompt", tokens: SYSTEM_PROMPT_TOKENS },
3020
+ { icon: "\u{1F534}", label: "IDE Rules", tokens: rulesTokens },
3021
+ { icon: "\u2B1C", label: "Free space", tokens: userPromptTokens },
3022
+ { icon: "\u{1F7E3}", label: "Autocompact buffer", tokens: COMPACT_BUFFER_TOKENS }
2999
3023
  ];
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})`)}`);
3024
+ const pad = " ".repeat(BAR_WIDTH + 5);
3025
+ for (const item of legendItems) {
3026
+ console.log(`${pad} ${item.icon} ${item.label}: ${formatTokens(item.tokens)} tokens (${pct(item.tokens, MAX_TOKENS)})`);
3006
3027
  }
3007
3028
  if (ruleItems.length > 0) {
3008
3029
  console.log("");
3009
- console.log(chalk6.dim(` Rules breakdown (${config.basePath}):`));
3030
+ console.log(` ${chalk6.bold("Rules")} ${chalk6.dim(`\xB7 ${config.basePath}/rules`)}`);
3010
3031
  const sorted = [...ruleItems].sort((a, b) => b.fileSize - a.fileSize);
3011
3032
  for (const rule of sorted) {
3012
3033
  const tokens = estimateTokens(rule.fileSize);
3013
3034
  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")}`);
3035
+ const badge = rule.alwaysApply ? chalk6.dim(" [always]") : "";
3036
+ console.log(` ${chalk6.dim("\u2514")} ${name}${badge}: ${formatNumber(tokens)} tokens`);
3016
3037
  }
3017
- } else {
3038
+ }
3039
+ const workflowItems = items.filter((item) => item.type === "workflows");
3040
+ if (workflowItems.length > 0) {
3018
3041
  console.log("");
3019
- console.log(chalk6.dim(" No rules found."));
3042
+ console.log(` ${chalk6.bold("Workflows")} ${chalk6.dim(`\xB7 ${config.basePath}/workflows`)}`);
3043
+ const sorted = [...workflowItems].sort((a, b) => b.fileSize - a.fileSize);
3044
+ for (const wf of sorted) {
3045
+ const tokens = estimateTokens(wf.fileSize);
3046
+ const name = typeof wf.name === "string" ? wf.name : wf.relativePath;
3047
+ console.log(` ${chalk6.dim("\u2514")} ${name}: ${formatNumber(tokens)} tokens`);
3048
+ }
3020
3049
  }
3021
3050
  console.log("");
3022
3051
  }
@@ -3034,9 +3063,8 @@ function createContextCommand() {
3034
3063
  }
3035
3064
  const scanner = new ContextScannerService();
3036
3065
  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
- `));
3066
+ console.log("");
3067
+ console.log(` ${chalk6.bgGray.white.bold(" /context ")}`);
3040
3068
  let found = false;
3041
3069
  for (const ide of targetIDEs) {
3042
3070
  try {
@@ -3050,8 +3078,8 @@ function createContextCommand() {
3050
3078
  }
3051
3079
  }
3052
3080
  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.
3081
+ console.log(chalk6.yellow(" \u26A0\uFE0F No IDEs detected in this project."));
3082
+ console.log(chalk6.dim(` Run "${name} apply" to install context for your IDE.
3055
3083
  `));
3056
3084
  }
3057
3085
  });
@@ -4899,9 +4927,9 @@ var ChatApp = ({ service, initialModel }) => {
4899
4927
  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
4928
  const limit = m.dailyLimit ?? 0;
4901
4929
  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)));
4930
+ const pct2 = limit > 0 ? Math.round(used / limit * 100) : 0;
4931
+ const bar = "\u2588".repeat(Math.round(pct2 / 5)) + "\u2591".repeat(20 - Math.round(pct2 / 5));
4932
+ 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
4933
  }), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, "[Esc] Back"));
4906
4934
  }, [models, selectedModel]);
4907
4935
  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";