codymaster 4.5.2 → 4.5.4

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/index.js CHANGED
@@ -71,6 +71,30 @@ const hamster_1 = require("./ui/hamster");
71
71
  const hooks_1 = require("./ui/hooks");
72
72
  const onboarding_1 = require("./ui/onboarding");
73
73
  const VERSION = require('../package.json').version;
74
+ let ALL_SKILLS = [];
75
+ try {
76
+ const distSkillsDir = path_1.default.join(__dirname, '..', 'skills');
77
+ if (fs_1.default.existsSync(distSkillsDir)) {
78
+ ALL_SKILLS = fs_1.default.readdirSync(distSkillsDir).filter(f => {
79
+ const fullPath = path_1.default.join(distSkillsDir, f);
80
+ return fs_1.default.statSync(fullPath).isDirectory() && fs_1.default.existsSync(path_1.default.join(fullPath, 'SKILL.md'));
81
+ });
82
+ }
83
+ }
84
+ catch (e) {
85
+ // Silent fallback
86
+ }
87
+ if (ALL_SKILLS.length === 0) {
88
+ ALL_SKILLS = [
89
+ 'cm-tdd', 'cm-debugging', 'cm-quality-gate', 'cm-test-gate', 'cm-code-review',
90
+ 'cm-safe-deploy', 'cm-identity-guard', 'cm-git-worktrees', 'cm-terminal', 'cm-secret-shield', 'cm-security-gate', 'cm-safe-i18n',
91
+ 'cm-planning', 'cm-ux-master', 'cm-ui-preview', 'cm-brainstorm-idea', 'cm-jtbd', 'cm-dockit', 'cm-project-bootstrap', 'cm-readit',
92
+ 'cm-content-factory', 'cm-ads-tracker', 'cro-methodology', 'cm-deep-search',
93
+ 'cm-execution', 'cm-continuity', 'cm-skill-index', 'cm-skill-mastery', 'cm-skill-chain',
94
+ 'cm-start', 'cm-dashboard', 'cm-status', 'cm-how-it-work', 'cm-example',
95
+ ];
96
+ }
97
+ const SKILL_COUNT = ALL_SKILLS.length;
74
98
  // ─── Update Check ───────────────────────────────────────────────────────────
75
99
  let _updateMessage = '';
76
100
  function checkForUpdates() {
@@ -134,7 +158,7 @@ function printUpdateNotice() {
134
158
  function showBanner() {
135
159
  const cPath = process.cwd().replace(os_1.default.homedir(), '~');
136
160
  const profile = (0, hooks_1.loadProfile)();
137
- console.log((0, hamster_1.renderHamsterBanner)(profile.userName || undefined, VERSION, cPath));
161
+ console.log((0, hamster_1.renderHamsterBanner)(profile.userName || undefined, VERSION, cPath, SKILL_COUNT));
138
162
  printUpdateNotice();
139
163
  }
140
164
  // ─── Utility ────────────────────────────────────────────────────────────────
@@ -177,7 +201,7 @@ function postInstallOnboarding(platform) {
177
201
  message: 'What would you like to do?',
178
202
  options: [
179
203
  { label: `${theme_1.ICONS.dashboard} Launch Dashboard`, value: 'dashboard', hint: `localhost:${data_1.DEFAULT_PORT}` },
180
- { label: `${theme_1.ICONS.skill} Browse all 65 skills`, value: 'skills' },
204
+ { label: `${theme_1.ICONS.skill} Browse all ${SKILL_COUNT} skills`, value: 'skills' },
181
205
  { label: `${theme_1.ICONS.deploy} Start with your AI`, value: 'invoke', hint: profile.platform || 'any agent' },
182
206
  { label: `${(0, theme_1.success)('✓')} Done`, value: 'done' },
183
207
  ],
@@ -258,7 +282,7 @@ function showInteractiveMenu() {
258
282
  { label: `${theme_1.ICONS.dashboard} Dashboard`, value: 'dashboard', hint: isDashboardRunning() ? 'Open' : 'Start & open' },
259
283
  { label: `${theme_1.ICONS.task} My Tasks`, value: 'tasks', hint: `${taskCounts.totalTasks} total` },
260
284
  { label: `📈 Status`, value: 'status', hint: 'Health snapshot' },
261
- { label: `${theme_1.ICONS.skill} Browse Skills`, value: 'skills', hint: '65 skills' },
285
+ { label: `${theme_1.ICONS.skill} Browse Skills`, value: 'skills', hint: `${SKILL_COUNT} skills` },
262
286
  { label: `➕ Add a Task`, value: 'addtask', hint: 'Quick add' },
263
287
  { label: `⚡ Install Skills`, value: 'install', hint: 'Update all' },
264
288
  { label: `${theme_1.ICONS.hamster} My Profile`, value: 'profile', hint: `${profile.level}` },
@@ -318,7 +342,7 @@ function showInteractiveMenu() {
318
342
  `${(0, theme_1.brand)('cm task list')} ${(0, theme_1.dim)('View tasks')}`,
319
343
  `${(0, theme_1.brand)('cm status')} ${(0, theme_1.dim)('Project health')}`,
320
344
  `${(0, theme_1.brand)('cm dashboard')} ${(0, theme_1.dim)('Mission Control')}`,
321
- `${(0, theme_1.brand)('cm list')} ${(0, theme_1.dim)('Browse 65 skills')}`,
345
+ `${(0, theme_1.brand)('cm list')} ${(0, theme_1.dim)(`Browse ${SKILL_COUNT} skills`)}`,
322
346
  `${(0, theme_1.brand)('cm deploy')} ${(0, theme_1.dim)('<env>')} ${(0, theme_1.dim)('Record deploy')}`,
323
347
  `${(0, theme_1.brand)('cm profile')} ${(0, theme_1.dim)('Your stats')}`,
324
348
  ];
@@ -332,7 +356,7 @@ function showInteractiveMenu() {
332
356
  const program = new commander_1.Command();
333
357
  program
334
358
  .name('cm')
335
- .description('Cody — 65 Skills. Ship 10x faster.')
359
+ .description(`Cody — ${SKILL_COUNT} Skills. Ship 10x faster.`)
336
360
  .version(VERSION, '-v, --version', 'Show version')
337
361
  .argument('[cmd]', 'Command to run', '')
338
362
  .action((cmd) => __awaiter(void 0, void 0, void 0, function* () {
@@ -1093,20 +1117,6 @@ program
1093
1117
  console.log((0, box_1.renderResult)('success', `Skill '${skill}' installed for ${opts.platform}!`));
1094
1118
  }));
1095
1119
  // ─── Add Command (npx codymaster add --skill cm-debugging) ───────────────────
1096
- const ALL_SKILLS = [
1097
- // Engineering
1098
- 'cm-tdd', 'cm-debugging', 'cm-quality-gate', 'cm-test-gate', 'cm-code-review',
1099
- // Operations
1100
- 'cm-safe-deploy', 'cm-identity-guard', 'cm-git-worktrees', 'cm-terminal', 'cm-secret-shield', 'cm-security-gate', 'cm-safe-i18n',
1101
- // Product
1102
- 'cm-planning', 'cm-ux-master', 'cm-ui-preview', 'cm-brainstorm-idea', 'cm-jtbd', 'cm-dockit', 'cm-project-bootstrap', 'cm-readit',
1103
- // Growth
1104
- 'cm-content-factory', 'cm-ads-tracker', 'cro-methodology', 'cm-deep-search',
1105
- // Orchestration
1106
- 'cm-execution', 'cm-continuity', 'cm-skill-index', 'cm-skill-mastery', 'cm-skill-chain',
1107
- // Workflow
1108
- 'cm-start', 'cm-dashboard', 'cm-status', 'cm-how-it-work', 'cm-example',
1109
- ];
1110
1120
  const PLATFORM_TARGETS = {
1111
1121
  gemini: { dir: '.gemini/skills', invoke: '@[/<skill>]', note: 'or ~/.gemini/antigravity/skills/ for global' },
1112
1122
  cursor: { dir: '.cursor/rules', invoke: '@<skill>', note: 'Cursor rules directory' },
@@ -1169,7 +1179,7 @@ function doAddSkills(skills, platform) {
1169
1179
  const { execFileSync } = require('child_process');
1170
1180
  if (platform === 'claude') {
1171
1181
  console.log((0, theme_1.brand)('🟣 Claude Code — Installing via plugin system'));
1172
- console.log((0, theme_1.dim)(' (Claude installs all 65 skills as one bundle)\n'));
1182
+ console.log((0, theme_1.dim)(' (Claude installs all ${SKILL_COUNT} skills as one bundle)\n'));
1173
1183
  // Step 1: Register marketplace
1174
1184
  console.log((0, theme_1.dim)(' $ claude plugin marketplace add tody-agent/codymaster'));
1175
1185
  try {
@@ -1193,7 +1203,7 @@ function doAddSkills(skills, platform) {
1193
1203
  console.log((0, theme_1.dim)(' $ claude plugin install codymaster@codymaster'));
1194
1204
  try {
1195
1205
  execFileSync('claude', ['plugin', 'install', 'codymaster@codymaster'], { stdio: 'inherit' });
1196
- console.log((0, box_1.renderResult)('success', 'All 65 skills installed!'));
1206
+ console.log((0, box_1.renderResult)('success', `All ${SKILL_COUNT} skills installed!`));
1197
1207
  yield postInstallOnboarding('claude');
1198
1208
  }
1199
1209
  catch (_b) {
@@ -1225,7 +1235,7 @@ function doAddSkills(skills, platform) {
1225
1235
  }
1226
1236
  const icons = { cursor: '🔵', windsurf: '🟠', cline: '⚫', opencode: '📦', kiro: '🔶' };
1227
1237
  const icon = icons[platform] || '📦';
1228
- const label = skills.length === ALL_SKILLS.length ? 'all 65 skills' : skills.join(', ');
1238
+ const label = skills.length === ALL_SKILLS.length ? `all ${SKILL_COUNT} skills` : skills.join(', ');
1229
1239
  console.log(`${icon} ${(0, theme_1.brand)(`${platform} — Installing ${label}`)}`);
1230
1240
  console.log((0, theme_1.dim)(` Target: ./${target.dir}/\n`));
1231
1241
  let ok = 0, fail = 0;
@@ -1282,7 +1292,7 @@ program
1282
1292
  .command('add')
1283
1293
  .description('Add skills to your AI agent (npx codymaster add --skill cm-debugging)')
1284
1294
  .option('--skill <name>', 'Specific skill to add (e.g. cm-debugging)')
1285
- .option('--all', 'Add all 65 skills')
1295
+ .option('--all', `Add all ${SKILL_COUNT} skills`)
1286
1296
  .option('--platform <platform>', 'Target: claude|gemini|cursor|windsurf|cline|opencode|kiro|copilot')
1287
1297
  .option('--list', 'Show available skills and exit')
1288
1298
  .action((opts) => __awaiter(void 0, void 0, void 0, function* () {
@@ -1339,7 +1349,7 @@ program
1339
1349
  const mode = yield p.select({
1340
1350
  message: 'What to install?',
1341
1351
  options: [
1342
- { label: 'All 65 skills (full kit)', value: 'all' },
1352
+ { label: `All ${SKILL_COUNT} skills (full kit)`, value: 'all' },
1343
1353
  { label: 'Search & pick one skill', value: 'pick' },
1344
1354
  ],
1345
1355
  });
@@ -1365,7 +1375,7 @@ program
1365
1375
  program
1366
1376
  .command('list')
1367
1377
  .alias('ls')
1368
- .description('List all 65 available skills')
1378
+ .description(`List all ${SKILL_COUNT} available skills`)
1369
1379
  .option('-d, --domain <domain>', 'Filter by domain')
1370
1380
  .action((opts) => {
1371
1381
  skillList(opts.domain);
@@ -1978,7 +1988,7 @@ const SKILL_CATALOG = {
1978
1988
  { name: 'cm-start', desc: 'Onboarding & session kick-off wizard' },
1979
1989
  { name: 'cm-dashboard', desc: 'Project status & task Kanban board' },
1980
1990
  { name: 'cm-status', desc: 'Quick project health snapshot' },
1981
- { name: 'cm-how-it-work', desc: 'Interactive explainer for all 65 skills' },
1991
+ { name: 'cm-how-it-work', desc: `Interactive explainer for all ${SKILL_COUNT} skills` },
1982
1992
  { name: 'cm-example', desc: 'Minimal template for new skills' },
1983
1993
  ],
1984
1994
  },
@@ -2024,7 +2034,7 @@ function skillList(filterDomain) {
2024
2034
  console.log((0, box_1.renderResult)('error', `Domain not found: ${filterDomain}`, [(0, theme_1.dim)('Domains: engineering, operations, product, growth, orchestration, workflow')]));
2025
2035
  return;
2026
2036
  }
2027
- console.log((0, box_1.renderCommandHeader)('Cody Master — 65 Skills', '🧩'));
2037
+ console.log((0, box_1.renderCommandHeader)(`Cody Master — ${SKILL_COUNT} Skills`, '🧩'));
2028
2038
  let total = 0;
2029
2039
  for (const [domain, data] of entries) {
2030
2040
  console.log((0, theme_1.brand)(` ${data.icon} ${domain.charAt(0).toUpperCase() + domain.slice(1)}`));
@@ -193,7 +193,7 @@ function getErrorGuidance() {
193
193
  /**
194
194
  * Render the full hamster banner with greeting
195
195
  */
196
- function renderHamsterBanner(userName, version, cwd) {
196
+ function renderHamsterBanner(userName, version, cwd, skillCount = 34) {
197
197
  const art = getHamsterArt(getTimeOfDay() === 'night' ? 'sleeping' : 'greeting');
198
198
  const greeting = getGreeting(userName);
199
199
  const lines = [
@@ -202,7 +202,7 @@ function renderHamsterBanner(userName, version, cwd) {
202
202
  '',
203
203
  ` ${(0, theme_1.brandBold)(greeting)}`,
204
204
  '',
205
- ` ${(0, theme_1.dim)('CodyMaster')} ${(0, theme_1.brand)(`v${version || '?'}`)} ${(0, theme_1.dim)('•')} ${(0, theme_1.dim)('34 Skills')} ${(0, theme_1.dim)('•')} ${(0, theme_1.dim)(cwd || '~')}`,
205
+ ` ${(0, theme_1.dim)('CodyMaster')} ${(0, theme_1.brand)(`v${version || '?'}`)} ${(0, theme_1.dim)('•')} ${(0, theme_1.dim)(`${skillCount} Skills`)} ${(0, theme_1.dim)('•')} ${(0, theme_1.dim)(cwd || '~')}`,
206
206
  (0, theme_1.dim)(' ' + '─'.repeat(50)),
207
207
  ];
208
208
  return lines.join('\n');
@@ -56,13 +56,26 @@ const theme_2 = require("./theme");
56
56
  const box_1 = require("./box");
57
57
  const hamster_1 = require("./hamster");
58
58
  const hooks_1 = require("./hooks");
59
+ let SKILL_COUNT = 33;
60
+ try {
61
+ const fs = require('fs');
62
+ const path = require('path');
63
+ const distSkillsDir = path.join(__dirname, '..', '..', 'skills');
64
+ if (fs.existsSync(distSkillsDir)) {
65
+ SKILL_COUNT = fs.readdirSync(distSkillsDir).filter((f) => {
66
+ const fullPath = path.join(distSkillsDir, f);
67
+ return fs.statSync(fullPath).isDirectory() && fs.existsSync(path.join(fullPath, 'SKILL.md'));
68
+ }).length;
69
+ }
70
+ }
71
+ catch (e) { }
59
72
  // ─── Onboarding Steps ──────────────────────────────────────────────────────
60
73
  const TOTAL_STEPS = 5;
61
74
  const STEP_INFO = {
62
75
  1: { title: 'Meet your assistant', desc: 'What should I call you?' },
63
76
  2: { title: 'Pick your platform', desc: 'Where do you code?' },
64
77
  3: { title: 'Your first task', desc: 'Add something to build' },
65
- 4: { title: 'See the magic', desc: 'Discover your 65 skills' },
78
+ 4: { title: 'See the magic', desc: `Discover your ${SKILL_COUNT} skills` },
66
79
  5: { title: 'You\'re ready!', desc: 'Welcome to the team' },
67
80
  };
68
81
  /**
@@ -219,7 +232,7 @@ function runOnboarding(version) {
219
232
  if (startStep < 4) {
220
233
  console.log((0, box_1.renderStepProgress)(4, TOTAL_STEPS));
221
234
  console.log('');
222
- console.log(` ${(0, theme_1.brandBold)('You have 65 superpowers!')} ${theme_2.ICONS.skill}`);
235
+ console.log(` ${(0, theme_1.brandBold)(`You have ${SKILL_COUNT} superpowers!`)} ${theme_2.ICONS.skill}`);
223
236
  console.log(` ${(0, theme_1.dim)('Grouped by what they help you do:')}`);
224
237
  console.log('');
225
238
  const SKILL_DOMAINS = [
@@ -267,10 +280,10 @@ function runOnboarding(version) {
267
280
  }
268
281
  console.log('');
269
282
  }
270
- console.log(` ${(0, theme_1.dim)(`Total: 65 skills across 6 domains`)}`);
283
+ console.log(` ${(0, theme_1.dim)(`Total: ${SKILL_COUNT} skills across 6 domains`)}`);
271
284
  console.log('');
272
285
  const viewAll = yield p.confirm({
273
- message: 'Want to browse all 65 skills in detail?',
286
+ message: `Want to browse all ${SKILL_COUNT} skills in detail?`,
274
287
  initialValue: false,
275
288
  });
276
289
  profile.onboardingStep = 4;
@@ -317,5 +330,5 @@ function runOnboarding(version) {
317
330
  * Displays hamster + trigger + quick action
318
331
  */
319
332
  function showReturningWelcome(profile, version, cwd) {
320
- console.log((0, hamster_1.renderHamsterBanner)(profile.userName, version, cwd));
333
+ console.log((0, hamster_1.renderHamsterBanner)(profile.userName, version, cwd, SKILL_COUNT));
321
334
  }
package/install.sh CHANGED
@@ -27,6 +27,15 @@ RAW_URL="https://raw.githubusercontent.com/tody-agent/codymaster/main"
27
27
  VERSION="4.4.0"
28
28
  SCOPE="user" # default scope for Claude Code
29
29
 
30
+ if [ -d "skills" ]; then
31
+ TOTAL_SKILLS=$(ls -1d skills/*/SKILL.md 2>/dev/null | wc -l | tr -d ' ')
32
+ elif [ -d "$HOME/.cody-master/skills" ]; then
33
+ TOTAL_SKILLS=$(ls -1d "$HOME/.cody-master/skills"/*/SKILL.md 2>/dev/null | wc -l | tr -d ' ')
34
+ else
35
+ TOTAL_SKILLS="60+"
36
+ fi
37
+
38
+
30
39
  # ── i18n ────────────────────────────────────────────────────────
31
40
  detect_lang() {
32
41
  local lang="${LANG:-en}"
@@ -115,7 +124,7 @@ print_header() {
115
124
  echo ""
116
125
  echo -e " ${O}${BOLD}$(msg welcome)${NC} 🐹"
117
126
  echo ""
118
- echo -e " ${DIM}CodyMaster${NC} ${O}v${VERSION}${NC} ${DIM}• 65 Skills • ~${NC}"
127
+ echo -e " ${DIM}CodyMaster${NC} ${O}v${VERSION}${NC} ${DIM}• ${TOTAL_SKILLS} Skills • ~${NC}"
119
128
  echo -e "${DIM} ──────────────────────────────────────────────────${NC}"
120
129
  echo ""
121
130
  }
@@ -206,7 +215,7 @@ hamster_sentiment() {
206
215
  "start")
207
216
  case $idx in
208
217
  0) echo -e " ${C}🐹: Whiskers twitching... CodyMaster incoming!${NC}" ;;
209
- 1) echo -e " ${C}🐹: Let's fill these cheeks with 65 skills! ✨${NC}" ;;
218
+ 1) echo -e " ${C}🐹: Let's fill these cheeks with ${TOTAL_SKILLS} skills! ✨${NC}" ;;
210
219
  2) echo -e " ${C}🐹: Waking up from a power nap! Let's build! 🐭${NC}" ;;
211
220
  esac
212
221
  ;;
@@ -220,7 +229,7 @@ hamster_sentiment() {
220
229
  "finish")
221
230
  case $idx in
222
231
  0) echo -e " ${C}🐹: Mission accomplished! Can I have a walnut now? 🥜${NC}" ;;
223
- 1) echo -e " ${C}🐹: My cheeks are stuffed with 65 skills for you! ✨${NC}" ;;
232
+ 1) echo -e " ${C}🐹: My cheeks are stuffed with ${TOTAL_SKILLS} skills for you! ✨${NC}" ;;
224
233
  2) echo -e " ${C}🐹: Terminal is Hamster-approved! Better than a wheel! 🎡${NC}" ;;
225
234
  esac
226
235
  ;;
@@ -403,7 +412,7 @@ print_onboarding() {
403
412
  print_header
404
413
 
405
414
  if [ "$LANG_CODE" = "vi" ]; then
406
- echo -e " ${W}${BOLD}🎉 Thành công! Bạn đã mở khóa 65 kỹ năng AI toàn năng:${NC}"
415
+ echo -e " ${W}${BOLD}🎉 Thành công! Bạn đã mở khóa ${TOTAL_SKILLS} kỹ năng AI toàn năng:${NC}"
407
416
  echo ""
408
417
  hamster_sentiment "finish"
409
418
  echo ""
@@ -429,7 +438,7 @@ print_onboarding() {
429
438
  echo -e " 11. ${Y}Xem Demo tự động ${NC} → /cm:demo"
430
439
  echo -e " 12. ${Y}Trợ giúp & Cú pháp lệnh ${NC} → cm help"
431
440
  else
432
- echo -e " ${W}${BOLD}🎉 Success! You just unlocked 65 omnipotent AI skills:${NC}"
441
+ echo -e " ${W}${BOLD}🎉 Success! You just unlocked ${TOTAL_SKILLS} omnipotent AI skills:${NC}"
433
442
  echo ""
434
443
  hamster_sentiment "finish"
435
444
  echo ""
@@ -611,6 +620,7 @@ install_skills_to() {
611
620
  echo ""
612
621
  mkdir -p "$target"
613
622
  local count=0
623
+ local installed=()
614
624
  for skill_dir in "${CLONE_DIR}"/skills/*/; do
615
625
  skill_name=$(basename "$skill_dir")
616
626
  if [ -f "${skill_dir}SKILL.md" ]; then
@@ -621,19 +631,32 @@ install_skills_to() {
621
631
  echo "globs: *" >> "${target}/${skill_name}.mdc"
622
632
  echo "---" >> "${target}/${skill_name}.mdc"
623
633
  cat "${skill_dir}SKILL.md" >> "${target}/${skill_name}.mdc"
624
- echo -e " ${G}✅${NC} ${skill_name}.mdc"
634
+ installed+=("${skill_name}.mdc")
625
635
  elif [[ "$format" == "md" ]]; then
626
636
  cp "${skill_dir}SKILL.md" "${target}/${skill_name}.md"
627
- echo -e " ${G}✅${NC} ${skill_name}.md"
637
+ installed+=("${skill_name}.md")
628
638
  else
629
639
  cp -r "$skill_dir" "${target}/${skill_name}"
630
- echo -e " ${G}✅${NC} $skill_name"
640
+ installed+=("$skill_name")
631
641
  fi
632
642
  count=$((count + 1))
633
643
  fi
634
644
  done
645
+
646
+ local line=" ${DIM}"
647
+ for s in "${installed[@]}"; do
648
+ if [ ${#line} -gt 70 ]; then
649
+ echo -e "${line}${NC}"
650
+ line=" ${DIM}"
651
+ fi
652
+ line="${line}${s}, "
653
+ done
654
+ if [ "${line}" != " ${DIM}" ]; then
655
+ echo -e "${line%, }${NC}"
656
+ fi
657
+
635
658
  echo ""
636
- echo -e "${G}${count} skills installed to ${target}${NC}"
659
+ echo -e "${G}${count} skills installed to ${target}${NC}"
637
660
  }
638
661
 
639
662
  # ── Legacy alias ─────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codymaster",
3
- "version": "4.5.2",
3
+ "version": "4.5.4",
4
4
  "description": "68+ Skills. Ship 10x faster. AI-powered coding skill kit for Claude, Cursor, Gemini & more.",
5
5
  "main": "dist/index.js",
6
6
  "repository": {
@@ -9,13 +9,29 @@ const BOLD = '\x1b[1m';
9
9
  const DIM = '\x1b[2m';
10
10
  const NC = '\x1b[0m';
11
11
 
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ let skillCount = 60;
15
+ try {
16
+ const skillsDir = path.join(__dirname, '..', 'skills');
17
+ if (fs.existsSync(skillsDir)) {
18
+ skillCount = fs.readdirSync(skillsDir)
19
+ .filter(f => {
20
+ const fullPath = path.join(skillsDir, f);
21
+ return fs.statSync(fullPath).isDirectory() && fs.existsSync(path.join(fullPath, 'SKILL.md'));
22
+ })
23
+ .length;
24
+ }
25
+ } catch (e) {}
26
+
27
+
12
28
  // Simple check for Vietnamese environment for the CORE UI
13
29
  const isVi = Intl.DateTimeFormat().resolvedOptions().locale.startsWith('vi');
14
30
 
15
31
  const sentiments = {
16
32
  start: [
17
33
  "🐹: Whiskers twitching... CodyMaster incoming!",
18
- "🐹: Let's fill these cheeks with 65 skills! ✨",
34
+ `🐹: Let's fill these cheeks with ${skillCount} skills! ✨`,
19
35
  "🐹: Waking up from a power nap! Let's build! 🐭"
20
36
  ],
21
37
  progress: [
@@ -25,9 +41,9 @@ const sentiments = {
25
41
  ],
26
42
  finish: [
27
43
  "🐹: Mission accomplished! Can I have a walnut now? 🥜",
28
- "🐹: My cheeks are stuffed with 65 skills for you! ✨",
44
+ `🐹: My cheeks are stuffed with ${skillCount} skills for you! ✨`,
29
45
  "🐹: Terminal is Hamster-approved! Better than a wheel! 🎡",
30
- "🐹: 65 skills stored. I'm ready for vibe coding! ⚡"
46
+ `🐹: ${skillCount} skills stored. I'm ready for vibe coding! ⚡`
31
47
  ]
32
48
  };
33
49
 
@@ -209,9 +225,9 @@ const printMenu = () => {
209
225
  console.log('');
210
226
 
211
227
  if (isVi) {
212
- console.log(` ${W}${BOLD}🎉 Thành công! Bạn đã mở khóa 65 kỹ năng AI toàn năng:${NC}`);
228
+ console.log(` ${W}${BOLD}🎉 Thành công! Bạn đã mở khóa ${skillCount} kỹ năng AI toàn năng:${NC}`);
213
229
  } else {
214
- console.log(` ${W}${BOLD}🎉 Success! You just unlocked 65 omnipotent AI skills:${NC}`);
230
+ console.log(` ${W}${BOLD}🎉 Success! You just unlocked ${skillCount} omnipotent AI skills:${NC}`);
215
231
  }
216
232
 
217
233
  console.log('');
@@ -267,35 +283,10 @@ const printMenu = () => {
267
283
  console.log('');
268
284
  console.log(` ${W}${BOLD}${isVi ? '📚 Tài liệu:' : '📚 Documentation:'}${NC} ${C}https://cody.todyle.com/docs${NC}`);
269
285
  console.log('');
270
- console.log(` ${DIM}Press 'q' to exit.${NC}`);
271
286
  };
272
287
 
273
- const main = async () => {
274
- if (!process.stdout.isTTY) {
275
- printMenu();
276
- return;
277
- }
278
-
279
- const readline = require('readline');
280
- const rl = readline.createInterface({
281
- input: process.stdin,
282
- output: process.stdout
283
- });
284
-
285
- const question = (query) => new Promise(resolve => rl.question(query, resolve));
286
-
287
- while (true) {
288
- printMenu();
289
- const answer = await question(' > ');
290
- if (answer.toLowerCase() === 'q') break;
291
- if (parseInt(answer) >= 1 && parseInt(answer) <= 12) {
292
- showSkillGuide(answer);
293
- await question('');
294
- } else if (answer === '') {
295
- break;
296
- }
297
- }
298
- rl.close();
288
+ const main = () => {
289
+ printMenu();
299
290
  };
300
291
 
301
292
  main();