codymaster 4.1.2 → 4.1.3

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
@@ -59,28 +59,84 @@ const skill_chain_1 = require("./skill-chain");
59
59
  const path_1 = __importDefault(require("path"));
60
60
  const os_1 = __importDefault(require("os"));
61
61
  const https_1 = __importDefault(require("https"));
62
- const VERSION = '3.4.0';
62
+ // 🐹 Hamster Shell UI modules
63
+ const theme_1 = require("./ui/theme");
64
+ const box_1 = require("./ui/box");
65
+ const hamster_1 = require("./ui/hamster");
66
+ const hooks_1 = require("./ui/hooks");
67
+ const onboarding_1 = require("./ui/onboarding");
68
+ const VERSION = require('../package.json').version;
69
+ // ─── Update Check ───────────────────────────────────────────────────────────
70
+ let _updateMessage = '';
71
+ function checkForUpdates() {
72
+ return __awaiter(this, void 0, void 0, function* () {
73
+ try {
74
+ const cacheDir = path_1.default.join(os_1.default.homedir(), '.codymaster');
75
+ const cacheFile = path_1.default.join(cacheDir, '.update-check');
76
+ // Check cache (24h TTL)
77
+ try {
78
+ if (fs_1.default.existsSync(cacheFile)) {
79
+ const stat = fs_1.default.statSync(cacheFile);
80
+ const age = Date.now() - stat.mtimeMs;
81
+ if (age < 24 * 60 * 60 * 1000) {
82
+ const cached = fs_1.default.readFileSync(cacheFile, 'utf-8').trim();
83
+ if (cached && cached !== VERSION) {
84
+ _updateMessage = cached;
85
+ }
86
+ return;
87
+ }
88
+ }
89
+ }
90
+ catch ( /* ignore cache errors */_a) { /* ignore cache errors */ }
91
+ // Fetch latest version from npm (2s timeout)
92
+ const latestVersion = yield new Promise((resolve, reject) => {
93
+ const timer = setTimeout(() => reject(new Error('timeout')), 2000);
94
+ https_1.default.get('https://registry.npmjs.org/codymaster/latest', { headers: { 'Accept': 'application/json' } }, (res) => {
95
+ let data = '';
96
+ res.on('data', (chunk) => { data += chunk; });
97
+ res.on('end', () => {
98
+ clearTimeout(timer);
99
+ try {
100
+ const json = JSON.parse(data);
101
+ resolve(json.version || VERSION);
102
+ }
103
+ catch (_a) {
104
+ resolve(VERSION);
105
+ }
106
+ });
107
+ }).on('error', () => { clearTimeout(timer); reject(new Error('fetch failed')); });
108
+ });
109
+ // Cache result
110
+ try {
111
+ if (!fs_1.default.existsSync(cacheDir))
112
+ fs_1.default.mkdirSync(cacheDir, { recursive: true });
113
+ fs_1.default.writeFileSync(cacheFile, latestVersion);
114
+ }
115
+ catch ( /* ignore */_b) { /* ignore */ }
116
+ if (latestVersion !== VERSION) {
117
+ _updateMessage = latestVersion;
118
+ }
119
+ }
120
+ catch ( /* silently skip — offline or timeout */_c) { /* silently skip — offline or timeout */ }
121
+ });
122
+ }
123
+ function printUpdateNotice() {
124
+ if (_updateMessage) {
125
+ console.log(chalk_1.default.yellow(` ⚠️ Update available: ${VERSION} → ${_updateMessage}`) + chalk_1.default.gray(' Run: ') + chalk_1.default.cyan('npm i -g codymaster'));
126
+ }
127
+ }
63
128
  // ─── Branding ───────────────────────────────────────────────────────────────
64
129
  function showBanner() {
65
130
  const cPath = process.cwd().replace(os_1.default.homedir(), '~');
66
- const bg = chalk_1.default.bgHex('#F59E0B');
67
- console.log('');
68
- console.log(` ${bg(' ')} ${chalk_1.default.bold.white('CodyMaster')} ${chalk_1.default.gray(`v${VERSION}`)}`);
69
- console.log(` ${bg.black.bold(' CM ')} ${chalk_1.default.gray('34 Skills. Ship 10x faster.')}`);
70
- console.log(` ${bg(' ')} ${chalk_1.default.gray(cPath)}`);
71
- console.log(chalk_1.default.gray(' ' + '─'.repeat(46)));
131
+ const profile = (0, hooks_1.loadProfile)();
132
+ console.log((0, hamster_1.renderHamsterBanner)(profile.userName || undefined, VERSION, cPath));
133
+ printUpdateNotice();
72
134
  }
73
135
  // ─── Utility ────────────────────────────────────────────────────────────────
74
- const COL_COLORS = {
75
- 'backlog': chalk_1.default.gray, 'in-progress': chalk_1.default.blue, 'review': chalk_1.default.yellow, 'done': chalk_1.default.green,
76
- };
77
- const PRIORITY_COLORS = {
78
- 'low': chalk_1.default.green, 'medium': chalk_1.default.yellow, 'high': chalk_1.default.red, 'urgent': chalk_1.default.magenta,
79
- };
80
- const STATUS_COLORS = {
81
- 'success': chalk_1.default.green, 'failed': chalk_1.default.red, 'pending': chalk_1.default.yellow,
82
- 'running': chalk_1.default.blue, 'rolled_back': chalk_1.default.magenta,
83
- };
136
+ // Color maps now imported from ./ui/theme (COL, PRI, STATUS)
137
+ const COL_COLORS = theme_1.COL;
138
+ const PRIORITY_COLORS = theme_1.PRI;
139
+ const STATUS_COLORS = theme_1.STATUS;
84
140
  function padRight(str, len) {
85
141
  return str.length >= len ? str.substring(0, len) : str + ' '.repeat(len - str.length);
86
142
  }
@@ -94,138 +150,132 @@ function openUrl(url) {
94
150
  // ─── Post-install Onboarding ─────────────────────────────────────────────────
95
151
  function postInstallOnboarding(platform) {
96
152
  return __awaiter(this, void 0, void 0, function* () {
97
- console.log();
98
- console.log(chalk_1.default.green('╔══════════════════════════════════════════════════╗'));
99
- console.log(chalk_1.default.green('║ 🎉 You\'re all set! What would you like to do? ║'));
100
- console.log(chalk_1.default.green('╚══════════════════════════════════════════════════╝'));
101
- console.log();
102
- const p = (yield Promise.resolve().then(() => __importStar(require('prompts')))).default;
103
- const invoke = platform === 'claude' ? '/cm:demo (type in Claude Code)' :
104
- platform === 'gemini' ? '@[/cm-planning] in Gemini CLI' :
105
- platform === 'cursor' ? '@cm-planning in Cursor Agent' :
106
- '@cm-planning in your AI tool';
107
- const resp = yield p({
108
- type: 'select',
109
- name: 'action',
110
- message: 'Choose an action:',
111
- choices: [
112
- {
113
- title: chalk_1.default.cyan('📊 Launch Dashboard'), value: 'dashboard',
114
- description: `Open Mission Control → http://localhost:${data_1.DEFAULT_PORT}`
115
- },
116
- {
117
- title: chalk_1.default.magenta('🚀 Start in ' + platform.charAt(0).toUpperCase() + platform.slice(1)), value: 'invoke',
118
- description: invoke
119
- },
120
- {
121
- title: chalk_1.default.white('🧩 Browse all 34 skills'), value: 'skills',
122
- description: 'See every skill, domain, and usage'
123
- },
124
- {
125
- title: chalk_1.default.yellow('⚡ Install `cm` globally'), value: 'global',
126
- description: 'Add cody / cm / codymaster to your PATH'
127
- },
128
- { title: chalk_1.default.gray('✅ Done'), value: 'done' },
129
- ],
130
- hint: '↑↓ navigate · Enter select · Ctrl+C exit',
131
- });
132
- switch (resp === null || resp === void 0 ? void 0 : resp.action) {
133
- case 'dashboard': {
134
- console.log();
135
- if (!isDashboardRunning()) {
136
- (0, dashboard_1.launchDashboard)(data_1.DEFAULT_PORT, false);
137
- yield new Promise(r => setTimeout(r, 800)); // let server start
138
- }
139
- console.log(chalk_1.default.cyan(`🌐 Opening http://localhost:${data_1.DEFAULT_PORT} ...`));
140
- openUrl(`http://localhost:${data_1.DEFAULT_PORT}`);
141
- console.log(chalk_1.default.gray(' Dashboard is running. Press Ctrl+C to stop.\n'));
142
- break;
153
+ // Run the self-onboarding wizard
154
+ const profile = (0, hooks_1.loadProfile)();
155
+ if (!profile.onboardingComplete) {
156
+ // Set platform from install if not already set
157
+ if (platform && !profile.platform) {
158
+ profile.platform = platform;
159
+ (0, hooks_1.saveProfile)(profile);
160
+ }
161
+ yield (0, onboarding_1.runOnboarding)(VERSION);
162
+ }
163
+ else {
164
+ // Already onboarded — show returning welcome
165
+ const p = yield Promise.resolve().then(() => __importStar(require('@clack/prompts')));
166
+ console.log('');
167
+ console.log((0, hamster_1.getHamsterArt)('celebrating'));
168
+ console.log('');
169
+ console.log(` ${(0, theme_1.success)('🎉')} ${(0, theme_1.brandBold)(`Welcome back, ${profile.userName || 'friend'}!`)}`);
170
+ console.log('');
171
+ const action = yield p.select({
172
+ message: 'What would you like to do?',
173
+ options: [
174
+ { label: `${theme_1.ICONS.dashboard} Launch Dashboard`, value: 'dashboard', hint: `localhost:${data_1.DEFAULT_PORT}` },
175
+ { label: `${theme_1.ICONS.skill} Browse all 34 skills`, value: 'skills' },
176
+ { label: `${theme_1.ICONS.deploy} Start with your AI`, value: 'invoke', hint: profile.platform || 'any agent' },
177
+ { label: `${(0, theme_1.success)('')} Done`, value: 'done' },
178
+ ],
179
+ });
180
+ if (p.isCancel(action))
181
+ return;
182
+ switch (action) {
183
+ case 'dashboard':
184
+ if (!isDashboardRunning()) {
185
+ (0, dashboard_1.launchDashboard)(data_1.DEFAULT_PORT, false);
186
+ yield new Promise(r => setTimeout(r, 800));
187
+ }
188
+ console.log((0, theme_1.info)(`\n 🌐 Opening http://localhost:${data_1.DEFAULT_PORT} ...\n`));
189
+ openUrl(`http://localhost:${data_1.DEFAULT_PORT}`);
190
+ break;
191
+ case 'skills':
192
+ console.log('');
193
+ skillList();
194
+ break;
195
+ case 'invoke':
196
+ console.log('');
197
+ const invoke = profile.platform === 'claude' ? '/cm:demo' :
198
+ profile.platform === 'gemini' ? '@[/cm-planning]' :
199
+ '@cm-planning';
200
+ console.log(` ${(0, theme_1.brand)('→')} Type ${(0, theme_1.brandBold)(invoke)} in your AI agent\n`);
201
+ break;
202
+ default:
203
+ console.log((0, theme_1.dim)('\n Run cm any time! 🐹\n'));
143
204
  }
144
- case 'invoke':
145
- console.log();
146
- if (platform === 'claude') {
147
- console.log(chalk_1.default.white('Open Claude Code and type:\n'));
148
- console.log(chalk_1.default.cyan(' /cm:demo'));
149
- console.log(chalk_1.default.gray('\n This will run an interactive tour of all 34 skills.\n'));
150
- }
151
- else {
152
- console.log(chalk_1.default.cyan(` ${invoke}\n`));
153
- }
154
- break;
155
- case 'skills':
156
- console.log();
157
- skillList();
158
- break;
159
- case 'global':
160
- console.log();
161
- console.log(chalk_1.default.white('Run this to install the `cm` CLI globally:\n'));
162
- console.log(chalk_1.default.cyan(' npm install -g codymaster'));
163
- console.log(chalk_1.default.gray('\nThen use:'));
164
- console.log(chalk_1.default.cyan(' cm task add "My task"'));
165
- console.log(chalk_1.default.cyan(' cm dashboard'));
166
- console.log(chalk_1.default.cyan(' cm status\n'));
167
- break;
168
- default:
169
- console.log(chalk_1.default.gray('\nRun `npx codymaster` any time to open the menu.\n'));
170
205
  }
171
206
  });
172
207
  }
173
208
  // ─── Interactive Quick Menu (no-args entry point) ─────────────────────────────
174
209
  function showInteractiveMenu() {
175
210
  return __awaiter(this, void 0, void 0, function* () {
211
+ const profile = (0, hooks_1.loadProfile)();
212
+ // 🎳 First Run → Start onboarding wizard
213
+ if (!profile.onboardingComplete) {
214
+ yield (0, onboarding_1.runOnboarding)(VERSION);
215
+ return;
216
+ }
217
+ // 🪝 Hook: Record command + check achievements
218
+ (0, hooks_1.recordCommand)(profile, 'menu');
219
+ const newAchievements = (0, hooks_1.checkAchievements)(profile);
220
+ (0, hooks_1.saveProfile)(profile);
221
+ // Show banner with hamster
176
222
  showBanner();
223
+ // 🪝 Hook: Contextual trigger
224
+ const data = (0, data_1.loadData)();
225
+ const taskCounts = {
226
+ tasksInProgress: data.tasks.filter(t => t.column === 'in-progress').length,
227
+ tasksInReview: data.tasks.filter(t => t.column === 'review').length,
228
+ tasksDone: data.tasks.filter(t => t.column === 'done').length,
229
+ totalTasks: data.tasks.length,
230
+ };
231
+ const trigger = (0, hooks_1.getContextualTrigger)(profile, taskCounts);
232
+ console.log(` ${(0, theme_1.brand)(theme_1.ICONS.hamster)} ${(0, theme_1.dim)(trigger)}`);
233
+ // Dashboard status
177
234
  const dashStatus = isDashboardRunning()
178
- ? chalk_1.default.green('● RUNNING') + chalk_1.default.gray(` http://localhost:${data_1.DEFAULT_PORT}`)
179
- : chalk_1.default.gray('○ stopped');
180
- console.log(chalk_1.default.gray(` Dashboard: ${dashStatus}`));
181
- console.log();
182
- const p = (yield Promise.resolve().then(() => __importStar(require('prompts')))).default;
183
- const resp = yield p({
184
- type: 'select',
185
- name: 'action',
186
- message: 'Quick menu:',
187
- choices: [
188
- {
189
- title: chalk_1.default.cyan('📊 Dashboard'), value: 'dashboard',
190
- description: isDashboardRunning() ? 'Open in browser' : 'Start & open in browser'
191
- },
192
- {
193
- title: chalk_1.default.white('📋 My Tasks'), value: 'tasks',
194
- description: 'View all tasks across projects'
195
- },
196
- {
197
- title: chalk_1.default.white('📈 Status'), value: 'status',
198
- description: 'Project health snapshot'
199
- },
200
- {
201
- title: chalk_1.default.magenta('🧩 Browse Skills'), value: 'skills',
202
- description: 'All 34 skills by domain'
203
- },
204
- {
205
- title: chalk_1.default.yellow('➕ Add a Task'), value: 'addtask',
206
- description: 'Quickly add a task to backlog'
207
- },
208
- {
209
- title: chalk_1.default.green('⚡ Install/Update Skills'), value: 'install',
210
- description: 'npx codymaster add --all'
211
- },
212
- { title: chalk_1.default.gray('❓ Help'), value: 'help' },
235
+ ? (0, theme_1.success)(`${theme_1.ICONS.dot} RUNNING`) + (0, theme_1.dim)(` http://localhost:${data_1.DEFAULT_PORT}`)
236
+ : (0, theme_1.muted)(`${theme_1.ICONS.dotEmpty} stopped`);
237
+ console.log(` ${(0, theme_1.dim)('Dashboard:')} ${dashStatus}`);
238
+ console.log('');
239
+ // Show new achievements
240
+ for (const id of newAchievements) {
241
+ console.log((0, hooks_1.formatAchievement)(id));
242
+ }
243
+ if (newAchievements.length > 0)
244
+ console.log('');
245
+ // Level indicator
246
+ console.log(` ${(0, theme_1.dim)('Level:')} ${(0, hooks_1.getLevelDisplay)(profile.level)} ${(0, theme_1.dim)('•')} ${(0, theme_1.dim)('Streak:')} ${profile.streak > 0 ? (0, theme_1.brand)(`${theme_1.ICONS.fire} ${profile.streak}d`) : (0, theme_1.muted)('')}`);
247
+ console.log('');
248
+ // Quick menu with @clack/prompts
249
+ const p = yield Promise.resolve().then(() => __importStar(require('@clack/prompts')));
250
+ const action = yield p.select({
251
+ message: 'Quick menu',
252
+ options: [
253
+ { label: `${theme_1.ICONS.dashboard} Dashboard`, value: 'dashboard', hint: isDashboardRunning() ? 'Open' : 'Start & open' },
254
+ { label: `${theme_1.ICONS.task} My Tasks`, value: 'tasks', hint: `${taskCounts.totalTasks} total` },
255
+ { label: `📈 Status`, value: 'status', hint: 'Health snapshot' },
256
+ { label: `${theme_1.ICONS.skill} Browse Skills`, value: 'skills', hint: '34 skills' },
257
+ { label: `➕ Add a Task`, value: 'addtask', hint: 'Quick add' },
258
+ { label: `⚡ Install Skills`, value: 'install', hint: 'Update all' },
259
+ { label: `${theme_1.ICONS.hamster} My Profile`, value: 'profile', hint: `${profile.level}` },
260
+ { label: `❓ Help`, value: 'help' },
213
261
  ],
214
- hint: '↑↓ navigate · Enter select · Ctrl+C exit',
215
262
  });
216
- console.log();
217
- switch (resp === null || resp === void 0 ? void 0 : resp.action) {
263
+ if (p.isCancel(action)) {
264
+ console.log((0, theme_1.dim)('\n See you soon! 🐹\n'));
265
+ return;
266
+ }
267
+ console.log('');
268
+ switch (action) {
218
269
  case 'dashboard':
219
270
  if (!isDashboardRunning()) {
220
271
  (0, dashboard_1.launchDashboard)(data_1.DEFAULT_PORT, false);
221
272
  yield new Promise(r => setTimeout(r, 800));
222
273
  }
223
- console.log(chalk_1.default.cyan(`🌐 Opening http://localhost:${data_1.DEFAULT_PORT} ...`));
274
+ console.log((0, theme_1.info)(` 🌐 Opening http://localhost:${data_1.DEFAULT_PORT} ...`));
224
275
  openUrl(`http://localhost:${data_1.DEFAULT_PORT}`);
225
- console.log(chalk_1.default.gray('Dashboard is running. Ctrl+C to stop.\n'));
276
+ console.log((0, theme_1.dim)(' Dashboard is running. Ctrl+C to stop.\n'));
226
277
  break;
227
278
  case 'tasks':
228
- // Inline task list
229
279
  require('child_process').spawnSync(process.execPath, [process.argv[1], 'task', 'list'], { stdio: 'inherit' });
230
280
  break;
231
281
  case 'status':
@@ -235,25 +285,41 @@ function showInteractiveMenu() {
235
285
  skillList();
236
286
  break;
237
287
  case 'addtask': {
238
- const t = yield p({ type: 'text', name: 'title', message: 'Task title:' });
239
- if (t === null || t === void 0 ? void 0 : t.title) {
240
- require('child_process').spawnSync(process.execPath, [process.argv[1], 'task', 'add', t.title], { stdio: 'inherit' });
288
+ const title = yield p.text({
289
+ message: 'Task title:',
290
+ placeholder: 'What are you working on?',
291
+ validate: (val) => {
292
+ if (!val || val.trim().length === 0)
293
+ return 'Give your task a title!';
294
+ return undefined;
295
+ },
296
+ });
297
+ if (!p.isCancel(title) && title) {
298
+ require('child_process').spawnSync(process.execPath, [process.argv[1], 'task', 'add', title], { stdio: 'inherit' });
241
299
  }
242
300
  break;
243
301
  }
244
302
  case 'install':
245
- console.log(chalk_1.default.cyan('Run: npx codymaster add --all\n'));
303
+ console.log(` ${(0, theme_1.brand)('→')} Run: ${(0, theme_1.brandBold)('npx codymaster add --all')}\n`);
304
+ break;
305
+ case 'profile':
306
+ console.log((0, hooks_1.formatProfileSummary)(profile));
246
307
  break;
247
308
  case 'help':
248
- default:
249
- console.log(chalk_1.default.white('Usage: cm <command> [options]\n'));
250
- console.log(chalk_1.default.gray(' cm dashboard Open Mission Control'));
251
- console.log(chalk_1.default.gray(' cm status Project overview'));
252
- console.log(chalk_1.default.gray(' cm task add "Title" Add a task'));
253
- console.log(chalk_1.default.gray(' cm task list View tasks'));
254
- console.log(chalk_1.default.gray(' cm list Browse 34 skills'));
255
- console.log(chalk_1.default.gray(' cm deploy staging Record deployment'));
256
- console.log(chalk_1.default.gray(' npx codymaster add --all Install/update skills\n'));
309
+ default: {
310
+ const helpItems = [
311
+ `${(0, theme_1.brand)('cm')} ${(0, theme_1.dim)('Quick menu')}`,
312
+ `${(0, theme_1.brand)('cm task add')} ${(0, theme_1.dim)('"..."')} ${(0, theme_1.dim)('Add a task')}`,
313
+ `${(0, theme_1.brand)('cm task list')} ${(0, theme_1.dim)('View tasks')}`,
314
+ `${(0, theme_1.brand)('cm status')} ${(0, theme_1.dim)('Project health')}`,
315
+ `${(0, theme_1.brand)('cm dashboard')} ${(0, theme_1.dim)('Mission Control')}`,
316
+ `${(0, theme_1.brand)('cm list')} ${(0, theme_1.dim)('Browse 34 skills')}`,
317
+ `${(0, theme_1.brand)('cm deploy')} ${(0, theme_1.dim)('<env>')} ${(0, theme_1.dim)('Record deploy')}`,
318
+ `${(0, theme_1.brand)('cm profile')} ${(0, theme_1.dim)('Your stats')}`,
319
+ ];
320
+ console.log((0, box_1.renderBox)(helpItems, { title: 'Commands', width: 52 }));
321
+ console.log('');
322
+ }
257
323
  }
258
324
  });
259
325
  }
@@ -1043,6 +1109,10 @@ const PLATFORM_TARGETS = {
1043
1109
  opencode: { dir: '.opencode/skills', invoke: '@[/<skill>]', note: 'OpenCode skills directory' },
1044
1110
  kiro: { dir: '.kiro/steering', invoke: '@<skill>', note: 'Kiro steering documents' },
1045
1111
  copilot: { dir: '.github', invoke: '(auto-context)', note: 'Added to copilot-instructions.md' },
1112
+ aider: { dir: '.aider/skills', invoke: '@[/<skill>]', note: 'Aider skills directory (reference in .aider.conf.yml)' },
1113
+ continue: { dir: '.continue/rules', invoke: '@<skill>', note: 'Continue.dev rules directory' },
1114
+ amazonq: { dir: '.aws/amazonq/skills', invoke: '@<skill>', note: 'Amazon Q skills directory' },
1115
+ amp: { dir: '.amp/skills', invoke: '@<skill>', note: 'Amp skills directory' },
1046
1116
  };
1047
1117
  const RAW_BASE = 'https://raw.githubusercontent.com/tody-agent/codymaster/main';
1048
1118
  function autoDetectPlatform() {
@@ -1129,19 +1199,8 @@ function doAddSkills(skills, platform) {
1129
1199
  }
1130
1200
  return;
1131
1201
  }
1132
- if (platform === 'gemini') {
1133
- console.log(chalk_1.default.cyan('💻 Gemini CLI Installing via extensions'));
1134
- try {
1135
- execFileSync('gemini', ['extensions', 'install', 'https://github.com/tody-agent/codymaster'], { stdio: 'inherit' });
1136
- console.log('\n' + chalk_1.default.green('✅ All 34 skills installed for Gemini CLI!'));
1137
- yield postInstallOnboarding('gemini');
1138
- }
1139
- catch (_c) {
1140
- console.log(chalk_1.default.yellow('💡 Run this in your terminal:\n'));
1141
- console.log(chalk_1.default.cyan(' gemini extensions install https://github.com/tody-agent/codymaster\n'));
1142
- }
1143
- return;
1144
- }
1202
+ // Removed the fictional gemini extensions install block.
1203
+ // Gemini now falls through to the standard file-cloning logic below.
1145
1204
  const target = PLATFORM_TARGETS[platform];
1146
1205
  if (!target) {
1147
1206
  console.log(chalk_1.default.red(`❌ Unknown platform: ${platform}`));
@@ -1169,8 +1228,30 @@ function doAddSkills(skills, platform) {
1169
1228
  let ok = 0, fail = 0;
1170
1229
  for (const skill of skills) {
1171
1230
  const url = `${RAW_BASE}/skills/${skill}/SKILL.md`;
1172
- const dest = path_1.default.join(target.dir, skill, 'SKILL.md');
1231
+ let dest = path_1.default.join(target.dir, skill, 'SKILL.md');
1232
+ // Formatting logic to adapt to specific IDE required formats
1233
+ if (platform === 'cursor') {
1234
+ dest = path_1.default.join(target.dir, `${skill}.mdc`);
1235
+ }
1236
+ else if (platform === 'continue') {
1237
+ dest = path_1.default.join(target.dir, `${skill}.md`);
1238
+ }
1173
1239
  const success = yield downloadFile(url, dest);
1240
+ // Prepend Cursor MDC glob formatting
1241
+ if (success && platform === 'cursor') {
1242
+ try {
1243
+ const content = fs_1.default.readFileSync(dest, 'utf-8');
1244
+ if (!content.startsWith('---')) {
1245
+ const yamlFrontmatter = `---\ndescription: ${skill}\nglobs: *\n---\n`;
1246
+ fs_1.default.writeFileSync(dest, yamlFrontmatter + content);
1247
+ }
1248
+ else if (!content.includes('globs:')) {
1249
+ const newContent = content.replace(/^---/, '---\nglobs: *');
1250
+ fs_1.default.writeFileSync(dest, newContent);
1251
+ }
1252
+ }
1253
+ catch (err) { }
1254
+ }
1174
1255
  if (success) {
1175
1256
  process.stdout.write(chalk_1.default.green(` ✅ ${skill}\n`));
1176
1257
  ok++;
@@ -1229,13 +1310,17 @@ program
1229
1310
  type: 'select', name: 'platform', message: 'Select your AI coding platform:',
1230
1311
  choices: [
1231
1312
  { title: '🟣 Claude Code (recommended)', value: 'claude' },
1232
- { title: '💻 Gemini CLI', value: 'gemini' },
1313
+ { title: '💻 Gemini CLI & Antigravity', value: 'gemini' },
1233
1314
  { title: '🔵 Cursor', value: 'cursor' },
1234
1315
  { title: '🟠 Windsurf', value: 'windsurf' },
1235
1316
  { title: '⚫ Cline / RooCode', value: 'cline' },
1236
1317
  { title: '📦 OpenCode', value: 'opencode' },
1237
1318
  { title: '🔶 Kiro (AWS)', value: 'kiro' },
1238
1319
  { title: '🐙 GitHub Copilot', value: 'copilot' },
1320
+ { title: '🤖 Aider', value: 'aider' },
1321
+ { title: '🔗 Continue.dev', value: 'continue' },
1322
+ { title: '☁️ Amazon Q', value: 'amazonq' },
1323
+ { title: '⚡ Amp', value: 'amp' },
1239
1324
  ],
1240
1325
  });
1241
1326
  if (!resp.platform)
@@ -1281,6 +1366,24 @@ program
1281
1366
  .action((opts) => {
1282
1367
  skillList(opts.domain);
1283
1368
  });
1369
+ // ─── Profile Command ──────────────────────────────────────────────────────────
1370
+ program
1371
+ .command('profile')
1372
+ .description('View your CodyMaster profile, stats, and achievements')
1373
+ .action(() => {
1374
+ const profile = (0, hooks_1.loadProfile)();
1375
+ if (!profile.onboardingComplete) {
1376
+ console.log((0, theme_1.dim)('\n Run cm first to complete setup! 🐹\n'));
1377
+ return;
1378
+ }
1379
+ (0, hooks_1.recordCommand)(profile, 'profile');
1380
+ const newAchievements = (0, hooks_1.checkAchievements)(profile);
1381
+ (0, hooks_1.saveProfile)(profile);
1382
+ console.log((0, hooks_1.formatProfileSummary)(profile));
1383
+ for (const id of newAchievements) {
1384
+ console.log((0, hooks_1.formatAchievement)(id));
1385
+ }
1386
+ });
1284
1387
  // ─── Continuity Command (Working Memory) ────────────────────────────────────
1285
1388
  program
1286
1389
  .command('continuity [cmd]')
@@ -2431,4 +2534,6 @@ if (!SKIP_DASHBOARD_CMDS.has(firstArg) && firstArg !== '' && !firstArg.startsWit
2431
2534
  (0, dashboard_1.launchDashboard)(data_1.DEFAULT_PORT, true);
2432
2535
  }
2433
2536
  }
2537
+ // Kick off update check (non-blocking)
2538
+ checkForUpdates().catch(() => { });
2434
2539
  program.parse(process.argv);