codymaster 4.1.2 â 4.1.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/CHANGELOG.md +25 -2
- package/README.md +108 -35
- package/dist/index.js +728 -658
- package/dist/ui/box.js +237 -0
- package/dist/ui/hamster.js +223 -0
- package/dist/ui/hooks.js +253 -0
- package/dist/ui/onboarding.js +315 -0
- package/dist/ui/theme.js +105 -0
- package/install.sh +143 -64
- package/package.json +5 -6
- package/skills/cm-quality-gate/SKILL.md +15 -0
- package/skills/cm-safe-i18n/SKILL.md +4 -1
- package/skills/cm-tdd/SKILL.md +8 -8
package/dist/ui/hooks.js
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* đĒ Hook Engine â Trigger â Action â Variable Reward â Investment
|
|
4
|
+
* Based on Nir Eyal's Hook Model for habit-forming CLI experience
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.loadProfile = loadProfile;
|
|
11
|
+
exports.saveProfile = saveProfile;
|
|
12
|
+
exports.isFirstRun = isFirstRun;
|
|
13
|
+
exports.getContextualTrigger = getContextualTrigger;
|
|
14
|
+
exports.checkAchievements = checkAchievements;
|
|
15
|
+
exports.formatAchievement = formatAchievement;
|
|
16
|
+
exports.recordCommand = recordCommand;
|
|
17
|
+
exports.getLevelDisplay = getLevelDisplay;
|
|
18
|
+
exports.formatProfileSummary = formatProfileSummary;
|
|
19
|
+
const fs_1 = __importDefault(require("fs"));
|
|
20
|
+
const path_1 = __importDefault(require("path"));
|
|
21
|
+
const os_1 = __importDefault(require("os"));
|
|
22
|
+
const theme_1 = require("./theme");
|
|
23
|
+
const theme_2 = require("./theme");
|
|
24
|
+
// âââ Profile Storage âââââââââââââââââââââââââââââââââââââââââââââââââââââââ
|
|
25
|
+
const PROFILE_DIR = path_1.default.join(os_1.default.homedir(), '.codymaster');
|
|
26
|
+
const PROFILE_FILE = path_1.default.join(PROFILE_DIR, 'profile.json');
|
|
27
|
+
const DEFAULT_PROFILE = {
|
|
28
|
+
userName: '',
|
|
29
|
+
platform: '',
|
|
30
|
+
onboardingStep: 0,
|
|
31
|
+
onboardingComplete: false,
|
|
32
|
+
firstRunAt: '',
|
|
33
|
+
lastRunAt: '',
|
|
34
|
+
totalCommands: 0,
|
|
35
|
+
streak: 0,
|
|
36
|
+
lastStreakDate: '',
|
|
37
|
+
level: 'beginner',
|
|
38
|
+
achievements: [],
|
|
39
|
+
commandHistory: {},
|
|
40
|
+
skillsUsed: [],
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Load user profile from disk
|
|
44
|
+
*/
|
|
45
|
+
function loadProfile() {
|
|
46
|
+
try {
|
|
47
|
+
if (fs_1.default.existsSync(PROFILE_FILE)) {
|
|
48
|
+
const raw = fs_1.default.readFileSync(PROFILE_FILE, 'utf-8');
|
|
49
|
+
return Object.assign(Object.assign({}, DEFAULT_PROFILE), JSON.parse(raw));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
53
|
+
return Object.assign({}, DEFAULT_PROFILE);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Save user profile to disk
|
|
57
|
+
*/
|
|
58
|
+
function saveProfile(profile) {
|
|
59
|
+
try {
|
|
60
|
+
if (!fs_1.default.existsSync(PROFILE_DIR)) {
|
|
61
|
+
fs_1.default.mkdirSync(PROFILE_DIR, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
fs_1.default.writeFileSync(PROFILE_FILE, JSON.stringify(profile, null, 2));
|
|
64
|
+
}
|
|
65
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if this is the first run (profile doesn't exist)
|
|
69
|
+
*/
|
|
70
|
+
function isFirstRun() {
|
|
71
|
+
return !fs_1.default.existsSync(PROFILE_FILE);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get a contextual trigger message based on user data
|
|
75
|
+
* Hook Model: External trigger that becomes internal over time
|
|
76
|
+
*/
|
|
77
|
+
function getContextualTrigger(profile, ctx) {
|
|
78
|
+
const now = new Date();
|
|
79
|
+
const lastRun = profile.lastRunAt ? new Date(profile.lastRunAt) : null;
|
|
80
|
+
const hoursSinceLastRun = lastRun ? (now.getTime() - lastRun.getTime()) / 3600000 : 999;
|
|
81
|
+
// Re-engagement trigger
|
|
82
|
+
if (hoursSinceLastRun > 48) {
|
|
83
|
+
return `Haven't seen you in a while! đ Let's get back to it`;
|
|
84
|
+
}
|
|
85
|
+
// Streak trigger
|
|
86
|
+
if (profile.streak >= 3) {
|
|
87
|
+
return `${theme_2.ICONS.fire} ${profile.streak}-day streak! Keep it going!`;
|
|
88
|
+
}
|
|
89
|
+
// Task-based triggers
|
|
90
|
+
if ((ctx === null || ctx === void 0 ? void 0 : ctx.tasksInProgress) && ctx.tasksInProgress > 0) {
|
|
91
|
+
return `${ctx.tasksInProgress} task${ctx.tasksInProgress > 1 ? 's' : ''} cooking! ${theme_2.ICONS.hamster}`;
|
|
92
|
+
}
|
|
93
|
+
if ((ctx === null || ctx === void 0 ? void 0 : ctx.tasksInReview) && ctx.tasksInReview > 0) {
|
|
94
|
+
return `${ctx.tasksInReview} task${ctx.tasksInReview > 1 ? 's' : ''} waiting for review đ`;
|
|
95
|
+
}
|
|
96
|
+
if ((ctx === null || ctx === void 0 ? void 0 : ctx.totalTasks) === 0) {
|
|
97
|
+
return `Clean slate! What shall we build? đī¸`;
|
|
98
|
+
}
|
|
99
|
+
if ((ctx === null || ctx === void 0 ? void 0 : ctx.tasksDone) && ctx.totalTasks && ctx.tasksDone === ctx.totalTasks) {
|
|
100
|
+
return `All clear! ${theme_2.ICONS.star} What's next?`;
|
|
101
|
+
}
|
|
102
|
+
// Default
|
|
103
|
+
return `Ready when you are! ${theme_2.ICONS.hamster}`;
|
|
104
|
+
}
|
|
105
|
+
// âââ VARIABLE REWARD: Achievement System âââââââââââââââââââââââââââââââââââ
|
|
106
|
+
const ACHIEVEMENTS = {
|
|
107
|
+
'first_run': { name: 'Hello World', emoji: 'đ', desc: 'First time running CodyMaster' },
|
|
108
|
+
'first_task': { name: 'Task Master', emoji: 'â
', desc: 'Created your first task' },
|
|
109
|
+
'first_done': { name: 'Shipper', emoji: 'đ', desc: 'Completed your first task' },
|
|
110
|
+
'five_tasks': { name: 'Busy Bee', emoji: 'đ', desc: 'Created 5 tasks' },
|
|
111
|
+
'first_deploy': { name: 'Deploy Hero', emoji: 'đϏ', desc: 'First deployment recorded' },
|
|
112
|
+
'first_skill': { name: 'Skill Hunter', emoji: 'đ§Š', desc: 'Used your first skill' },
|
|
113
|
+
'streak_3': { name: 'On Fire', emoji: 'đĨ', desc: '3-day usage streak' },
|
|
114
|
+
'streak_7': { name: 'Committed', emoji: 'đ', desc: '7-day usage streak' },
|
|
115
|
+
'commands_50': { name: 'Power User', emoji: 'âĄ', desc: '50 commands executed' },
|
|
116
|
+
'commands_100': { name: 'CLI Ninja', emoji: 'đĨˇ', desc: '100 commands executed' },
|
|
117
|
+
'level_builder': { name: 'Builder', emoji: 'đī¸', desc: 'Reached Builder level' },
|
|
118
|
+
'level_master': { name: 'Master', emoji: 'đ', desc: 'Reached Master level' },
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Check and unlock new achievements
|
|
122
|
+
* Returns newly unlocked achievements
|
|
123
|
+
*/
|
|
124
|
+
function checkAchievements(profile) {
|
|
125
|
+
const newAchievements = [];
|
|
126
|
+
const check = (id, condition) => {
|
|
127
|
+
if (condition && !profile.achievements.includes(id)) {
|
|
128
|
+
profile.achievements.push(id);
|
|
129
|
+
newAchievements.push(id);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
check('first_run', profile.totalCommands >= 1);
|
|
133
|
+
check('first_task', (profile.commandHistory['task add'] || 0) >= 1);
|
|
134
|
+
check('five_tasks', (profile.commandHistory['task add'] || 0) >= 5);
|
|
135
|
+
check('first_done', (profile.commandHistory['task done'] || 0) >= 1);
|
|
136
|
+
check('first_deploy', (profile.commandHistory['deploy'] || 0) >= 1);
|
|
137
|
+
check('first_skill', profile.skillsUsed.length >= 1);
|
|
138
|
+
check('streak_3', profile.streak >= 3);
|
|
139
|
+
check('streak_7', profile.streak >= 7);
|
|
140
|
+
check('commands_50', profile.totalCommands >= 50);
|
|
141
|
+
check('commands_100', profile.totalCommands >= 100);
|
|
142
|
+
check('level_builder', profile.level === 'builder' || profile.level === 'master' || profile.level === 'legend');
|
|
143
|
+
check('level_master', profile.level === 'master' || profile.level === 'legend');
|
|
144
|
+
return newAchievements;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Format achievement unlock message
|
|
148
|
+
*/
|
|
149
|
+
function formatAchievement(id) {
|
|
150
|
+
const a = ACHIEVEMENTS[id];
|
|
151
|
+
if (!a)
|
|
152
|
+
return '';
|
|
153
|
+
return ` ${a.emoji} ${(0, theme_1.success)('Achievement Unlocked:')} ${(0, theme_1.brand)(a.name)} â ${(0, theme_1.dim)(a.desc)}`;
|
|
154
|
+
}
|
|
155
|
+
// âââ INVESTMENT: Track & Level Up ââââââââââââââââââââââââââââââââââââââââââ
|
|
156
|
+
/**
|
|
157
|
+
* Record a command execution (Investment phase)
|
|
158
|
+
* Updates profile with usage data â CLI becomes more personal
|
|
159
|
+
*/
|
|
160
|
+
function recordCommand(profile, command) {
|
|
161
|
+
const now = new Date();
|
|
162
|
+
const today = now.toISOString().split('T')[0];
|
|
163
|
+
// Update totals
|
|
164
|
+
profile.totalCommands++;
|
|
165
|
+
profile.commandHistory[command] = (profile.commandHistory[command] || 0) + 1;
|
|
166
|
+
profile.lastRunAt = now.toISOString();
|
|
167
|
+
// First run
|
|
168
|
+
if (!profile.firstRunAt) {
|
|
169
|
+
profile.firstRunAt = now.toISOString();
|
|
170
|
+
}
|
|
171
|
+
// Streak calculation
|
|
172
|
+
if (profile.lastStreakDate !== today) {
|
|
173
|
+
const yesterday = new Date(now);
|
|
174
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
175
|
+
const yesterdayStr = yesterday.toISOString().split('T')[0];
|
|
176
|
+
if (profile.lastStreakDate === yesterdayStr) {
|
|
177
|
+
profile.streak++;
|
|
178
|
+
}
|
|
179
|
+
else if (profile.lastStreakDate !== today) {
|
|
180
|
+
profile.streak = 1;
|
|
181
|
+
}
|
|
182
|
+
profile.lastStreakDate = today;
|
|
183
|
+
}
|
|
184
|
+
// Level calculation
|
|
185
|
+
updateLevel(profile);
|
|
186
|
+
}
|
|
187
|
+
function updateLevel(profile) {
|
|
188
|
+
const cmds = profile.totalCommands;
|
|
189
|
+
const skills = profile.skillsUsed.length;
|
|
190
|
+
if (cmds >= 100 && skills >= 10) {
|
|
191
|
+
profile.level = 'legend';
|
|
192
|
+
}
|
|
193
|
+
else if (cmds >= 50 && skills >= 5) {
|
|
194
|
+
profile.level = 'master';
|
|
195
|
+
}
|
|
196
|
+
else if (cmds >= 10 && skills >= 1) {
|
|
197
|
+
profile.level = 'builder';
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
profile.level = 'beginner';
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Get level display with emoji
|
|
205
|
+
*/
|
|
206
|
+
function getLevelDisplay(level) {
|
|
207
|
+
const levels = {
|
|
208
|
+
beginner: { emoji: 'đą', color: theme_1.dim },
|
|
209
|
+
builder: { emoji: 'đī¸', color: theme_1.info },
|
|
210
|
+
master: { emoji: 'đ', color: theme_1.brand },
|
|
211
|
+
legend: { emoji: 'đ', color: theme_1.success },
|
|
212
|
+
};
|
|
213
|
+
const l = levels[level] || levels.beginner;
|
|
214
|
+
return `${l.emoji} ${l.color(level.charAt(0).toUpperCase() + level.slice(1))}`;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Format profile summary for `cm profile` command
|
|
218
|
+
*/
|
|
219
|
+
function formatProfileSummary(profile) {
|
|
220
|
+
const lines = [
|
|
221
|
+
'',
|
|
222
|
+
` ${(0, theme_1.brand)('đš Your Profile')}`,
|
|
223
|
+
'',
|
|
224
|
+
` ${(0, theme_1.dim)('Name:')} ${profile.userName || (0, theme_1.dim)('(not set)')}`,
|
|
225
|
+
` ${(0, theme_1.dim)('Level:')} ${getLevelDisplay(profile.level)}`,
|
|
226
|
+
` ${(0, theme_1.dim)('Streak:')} ${profile.streak > 0 ? `${theme_2.ICONS.fire} ${(0, theme_1.brand)(String(profile.streak))} days` : (0, theme_1.dim)('Start today!')}`,
|
|
227
|
+
` ${(0, theme_1.dim)('Commands:')} ${(0, theme_1.brand)(String(profile.totalCommands))} total`,
|
|
228
|
+
` ${(0, theme_1.dim)('Platform:')} ${profile.platform || (0, theme_1.dim)('(auto-detect)')}`,
|
|
229
|
+
'',
|
|
230
|
+
];
|
|
231
|
+
// Achievements
|
|
232
|
+
if (profile.achievements.length > 0) {
|
|
233
|
+
lines.push(` ${(0, theme_1.brand)('Achievements')} (${profile.achievements.length}/${Object.keys(ACHIEVEMENTS).length})`);
|
|
234
|
+
for (const id of profile.achievements) {
|
|
235
|
+
const a = ACHIEVEMENTS[id];
|
|
236
|
+
if (a)
|
|
237
|
+
lines.push(` ${a.emoji} ${a.name}`);
|
|
238
|
+
}
|
|
239
|
+
lines.push('');
|
|
240
|
+
}
|
|
241
|
+
// Top commands
|
|
242
|
+
const topCmds = Object.entries(profile.commandHistory)
|
|
243
|
+
.sort(([, a], [, b]) => b - a)
|
|
244
|
+
.slice(0, 5);
|
|
245
|
+
if (topCmds.length > 0) {
|
|
246
|
+
lines.push(` ${(0, theme_1.brand)('Top Commands')}`);
|
|
247
|
+
for (const [cmd, count] of topCmds) {
|
|
248
|
+
lines.push(` ${(0, theme_1.dim)('cm')} ${cmd} ${(0, theme_1.muted)(`Ã${count}`)}`);
|
|
249
|
+
}
|
|
250
|
+
lines.push('');
|
|
251
|
+
}
|
|
252
|
+
return lines.join('\n');
|
|
253
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* đŗ Self-Onboarding System â Bowling Alley / Straight-Line Onboarding
|
|
4
|
+
* Based on ProductLed EUREKA framework by Ramli John
|
|
5
|
+
*
|
|
6
|
+
* 5 Steps â First Strike (Aha! moment) â Power User
|
|
7
|
+
* Each step: ONE action + bumpers to prevent confusion
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
43
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
44
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
45
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
46
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
47
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
48
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
+
exports.runOnboarding = runOnboarding;
|
|
53
|
+
exports.showReturningWelcome = showReturningWelcome;
|
|
54
|
+
const theme_1 = require("./theme");
|
|
55
|
+
const theme_2 = require("./theme");
|
|
56
|
+
const box_1 = require("./box");
|
|
57
|
+
const hamster_1 = require("./hamster");
|
|
58
|
+
const hooks_1 = require("./hooks");
|
|
59
|
+
// âââ Onboarding Steps ââââââââââââââââââââââââââââââââââââââââââââââââââââââ
|
|
60
|
+
const TOTAL_STEPS = 5;
|
|
61
|
+
const STEP_INFO = {
|
|
62
|
+
1: { title: 'Meet your assistant', desc: 'What should I call you?' },
|
|
63
|
+
2: { title: 'Pick your platform', desc: 'Where do you code?' },
|
|
64
|
+
3: { title: 'Your first task', desc: 'Add something to build' },
|
|
65
|
+
4: { title: 'See the magic', desc: 'Discover your 34 skills' },
|
|
66
|
+
5: { title: 'You\'re ready!', desc: 'Welcome to the team' },
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Run the full onboarding wizard
|
|
70
|
+
* Returns the updated profile
|
|
71
|
+
*/
|
|
72
|
+
function runOnboarding(version) {
|
|
73
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
74
|
+
const profile = (0, hooks_1.loadProfile)();
|
|
75
|
+
const p = (yield Promise.resolve().then(() => __importStar(require('@clack/prompts')))).default || (yield Promise.resolve().then(() => __importStar(require('@clack/prompts'))));
|
|
76
|
+
// If already complete, skip
|
|
77
|
+
if (profile.onboardingComplete)
|
|
78
|
+
return profile;
|
|
79
|
+
const startStep = profile.onboardingStep || 0;
|
|
80
|
+
// âââ STEP 1: Name ââââââââââââââââââââââââââââââ
|
|
81
|
+
if (startStep < 1) {
|
|
82
|
+
console.clear();
|
|
83
|
+
console.log('');
|
|
84
|
+
console.log((0, hamster_1.getHamsterArt)('greeting'));
|
|
85
|
+
console.log('');
|
|
86
|
+
console.log(` ${(0, theme_1.brandBold)('Hi there! I\'m Cody')} ${theme_2.ICONS.hamster}`);
|
|
87
|
+
console.log(` ${(0, theme_1.dim)('Your smart coding companion.')}`);
|
|
88
|
+
console.log('');
|
|
89
|
+
console.log((0, box_1.renderStepProgress)(1, TOTAL_STEPS));
|
|
90
|
+
console.log('');
|
|
91
|
+
const nameResult = yield p.text({
|
|
92
|
+
message: 'What should I call you?',
|
|
93
|
+
placeholder: 'Your name',
|
|
94
|
+
validate: (val) => {
|
|
95
|
+
if (!val || val.trim().length === 0)
|
|
96
|
+
return 'Just type your name â even a nickname works!';
|
|
97
|
+
if (val.trim().length > 30)
|
|
98
|
+
return 'That\'s a bit long! Try a shorter name';
|
|
99
|
+
return undefined;
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
if (p.isCancel(nameResult)) {
|
|
103
|
+
console.log((0, theme_1.dim)('\n No worries! Run cm again anytime. đ\n'));
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
106
|
+
profile.userName = nameResult.trim();
|
|
107
|
+
profile.onboardingStep = 1;
|
|
108
|
+
profile.firstRunAt = new Date().toISOString();
|
|
109
|
+
(0, hooks_1.saveProfile)(profile);
|
|
110
|
+
}
|
|
111
|
+
// âââ STEP 2: Platform ââââââââââââââââââââââââââ
|
|
112
|
+
if (startStep < 2) {
|
|
113
|
+
console.log('');
|
|
114
|
+
console.log(` ${(0, theme_1.success)('â')} ${(0, theme_1.dim)('Nice to meet you,')} ${(0, theme_1.brand)(profile.userName)}${(0, theme_1.dim)('!')}`);
|
|
115
|
+
console.log('');
|
|
116
|
+
console.log((0, box_1.renderStepProgress)(2, TOTAL_STEPS));
|
|
117
|
+
console.log('');
|
|
118
|
+
const platformResult = yield p.select({
|
|
119
|
+
message: 'Where do you code?',
|
|
120
|
+
options: [
|
|
121
|
+
{ label: 'âĻ Google Antigravity (Gemini)', value: 'gemini', hint: 'recommended' },
|
|
122
|
+
{ label: 'đŖ Claude Code', value: 'claude', hint: 'plugin system' },
|
|
123
|
+
{ label: 'âŦĄ Cursor', value: 'cursor', hint: 'rules directory' },
|
|
124
|
+
{ label: 'đ Windsurf', value: 'windsurf', hint: 'rules directory' },
|
|
125
|
+
{ label: 'đļ Cline / RooCode', value: 'cline', hint: 'skills directory' },
|
|
126
|
+
{ label: 'đĻ OpenCode', value: 'opencode', hint: 'skills directory' },
|
|
127
|
+
{ label: 'đĒ Kiro', value: 'kiro', hint: 'steering docs' },
|
|
128
|
+
{ label: 'đ¤ GitHub Copilot', value: 'copilot', hint: 'auto-context' },
|
|
129
|
+
{ label: 'đ§ Other / Not sure', value: 'other', hint: 'auto-detect' },
|
|
130
|
+
],
|
|
131
|
+
});
|
|
132
|
+
if (p.isCancel(platformResult)) {
|
|
133
|
+
profile.onboardingStep = 1;
|
|
134
|
+
(0, hooks_1.saveProfile)(profile);
|
|
135
|
+
console.log((0, theme_1.dim)('\n No worries! Run cm again to continue. đ\n'));
|
|
136
|
+
process.exit(0);
|
|
137
|
+
}
|
|
138
|
+
profile.platform = platformResult;
|
|
139
|
+
profile.onboardingStep = 2;
|
|
140
|
+
(0, hooks_1.saveProfile)(profile);
|
|
141
|
+
}
|
|
142
|
+
// âââ STEP 3: First Task (The First Strike đŗ) ââ
|
|
143
|
+
if (startStep < 3) {
|
|
144
|
+
console.log('');
|
|
145
|
+
console.log(` ${(0, theme_1.success)('â')} ${(0, theme_1.dim)('Great choice!')} ${(0, theme_1.brand)(profile.platform)}`);
|
|
146
|
+
console.log('');
|
|
147
|
+
console.log((0, box_1.renderStepProgress)(3, TOTAL_STEPS));
|
|
148
|
+
console.log('');
|
|
149
|
+
console.log(` ${(0, theme_1.brandBold)('Let\'s add your first task!')} ${theme_2.ICONS.sparkle}`);
|
|
150
|
+
console.log(` ${(0, theme_1.dim)('This is what you want to build or work on.')}`);
|
|
151
|
+
console.log('');
|
|
152
|
+
const taskResult = yield p.text({
|
|
153
|
+
message: 'What are you working on?',
|
|
154
|
+
placeholder: 'e.g., "Build my landing page"',
|
|
155
|
+
validate: (val) => {
|
|
156
|
+
if (!val || val.trim().length === 0)
|
|
157
|
+
return 'Just describe what you\'re building â keep it simple!';
|
|
158
|
+
return undefined;
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
if (p.isCancel(taskResult)) {
|
|
162
|
+
profile.onboardingStep = 2;
|
|
163
|
+
(0, hooks_1.saveProfile)(profile);
|
|
164
|
+
console.log((0, theme_1.dim)('\n No worries! Run cm again to continue. đ\n'));
|
|
165
|
+
process.exit(0);
|
|
166
|
+
}
|
|
167
|
+
// Actually create the task
|
|
168
|
+
const taskTitle = taskResult.trim();
|
|
169
|
+
try {
|
|
170
|
+
const { loadData, saveData, logActivity, shortId, DATA_FILE } = yield Promise.resolve().then(() => __importStar(require('../data')));
|
|
171
|
+
const crypto = yield Promise.resolve().then(() => __importStar(require('crypto')));
|
|
172
|
+
const data = loadData();
|
|
173
|
+
// Ensure default project exists
|
|
174
|
+
if (data.projects.length === 0) {
|
|
175
|
+
const dp = {
|
|
176
|
+
id: crypto.randomUUID(),
|
|
177
|
+
name: 'My Project',
|
|
178
|
+
path: process.cwd(),
|
|
179
|
+
agents: [],
|
|
180
|
+
createdAt: new Date().toISOString(),
|
|
181
|
+
};
|
|
182
|
+
data.projects.push(dp);
|
|
183
|
+
}
|
|
184
|
+
const projectId = data.projects[0].id;
|
|
185
|
+
const now = new Date().toISOString();
|
|
186
|
+
const task = {
|
|
187
|
+
id: crypto.randomUUID(),
|
|
188
|
+
projectId,
|
|
189
|
+
title: taskTitle,
|
|
190
|
+
description: '',
|
|
191
|
+
column: 'backlog',
|
|
192
|
+
order: 0,
|
|
193
|
+
priority: 'medium',
|
|
194
|
+
agent: '',
|
|
195
|
+
skill: '',
|
|
196
|
+
createdAt: now,
|
|
197
|
+
updatedAt: now,
|
|
198
|
+
};
|
|
199
|
+
data.tasks.push(task);
|
|
200
|
+
logActivity(data, 'task_created', `Task "${taskTitle}" created during onboarding`, projectId);
|
|
201
|
+
saveData(data);
|
|
202
|
+
console.log('');
|
|
203
|
+
console.log((0, hamster_1.getHamsterArt)('celebrating'));
|
|
204
|
+
console.log('');
|
|
205
|
+
console.log(` ${(0, theme_1.success)('â
')} ${(0, theme_1.brandBold)('First task created!')} ${(0, hamster_1.getCelebration)()}`);
|
|
206
|
+
console.log(` ${(0, theme_1.dim)(`"${taskTitle}"`)}`);
|
|
207
|
+
console.log('');
|
|
208
|
+
}
|
|
209
|
+
catch (_a) {
|
|
210
|
+
console.log('');
|
|
211
|
+
console.log(` ${(0, theme_1.success)('â')} ${(0, theme_1.dim)('Got it!')} ${(0, theme_1.brand)(taskTitle)}`);
|
|
212
|
+
console.log('');
|
|
213
|
+
}
|
|
214
|
+
profile.onboardingStep = 3;
|
|
215
|
+
(0, hooks_1.recordCommand)(profile, 'task add');
|
|
216
|
+
(0, hooks_1.saveProfile)(profile);
|
|
217
|
+
}
|
|
218
|
+
// âââ STEP 4: Skill Discovery âââââââââââââââââââ
|
|
219
|
+
if (startStep < 4) {
|
|
220
|
+
console.log((0, box_1.renderStepProgress)(4, TOTAL_STEPS));
|
|
221
|
+
console.log('');
|
|
222
|
+
console.log(` ${(0, theme_1.brandBold)('You have 34 superpowers!')} ${theme_2.ICONS.skill}`);
|
|
223
|
+
console.log(` ${(0, theme_1.dim)('Grouped by what they help you do:')}`);
|
|
224
|
+
console.log('');
|
|
225
|
+
const SKILL_DOMAINS = [
|
|
226
|
+
{ domain: 'âī¸ Engineering', skills: [
|
|
227
|
+
{ name: 'cm-tdd', desc: 'Test-driven development' },
|
|
228
|
+
{ name: 'cm-debugging', desc: 'Smart bug hunting' },
|
|
229
|
+
{ name: 'cm-quality-gate', desc: 'Pre-deploy verification' },
|
|
230
|
+
] },
|
|
231
|
+
{ domain: 'đ Operations', skills: [
|
|
232
|
+
{ name: 'cm-safe-deploy', desc: 'Multi-gate deploy' },
|
|
233
|
+
{ name: 'cm-secret-shield', desc: 'Secret scanning' },
|
|
234
|
+
{ name: 'cm-git-worktrees', desc: 'Isolated branches' },
|
|
235
|
+
] },
|
|
236
|
+
{ domain: 'đ¨ Product & Design', skills: [
|
|
237
|
+
{ name: 'cm-planning', desc: 'Plan before you code' },
|
|
238
|
+
{ name: 'cm-ui-preview', desc: 'AI-powered UI design' },
|
|
239
|
+
{ name: 'cm-ux-master', desc: '48 UX Laws + design system' },
|
|
240
|
+
] },
|
|
241
|
+
{ domain: 'đ Growth & Content', skills: [
|
|
242
|
+
{ name: 'cm-content-factory', desc: 'Self-learning content engine' },
|
|
243
|
+
{ name: 'cm-ads-tracker', desc: 'Conversion tracking setup' },
|
|
244
|
+
{ name: 'cro-methodology', desc: 'Conversion rate optimization' },
|
|
245
|
+
] },
|
|
246
|
+
{ domain: 'đ¤ Orchestration', skills: [
|
|
247
|
+
{ name: 'cm-execution', desc: 'Parallel agent dispatch' },
|
|
248
|
+
{ name: 'cm-skill-chain', desc: 'Multi-skill pipelines' },
|
|
249
|
+
{ name: 'cm-continuity', desc: 'Working memory protocol' },
|
|
250
|
+
] },
|
|
251
|
+
{ domain: 'đ§ Workflow', skills: [
|
|
252
|
+
{ name: 'cm-start', desc: 'Idea â production code' },
|
|
253
|
+
{ name: 'cm-project-bootstrap', desc: 'Zero-to-production setup' },
|
|
254
|
+
{ name: 'cm-dashboard', desc: 'Visual Mission Control' },
|
|
255
|
+
] },
|
|
256
|
+
];
|
|
257
|
+
for (const d of SKILL_DOMAINS) {
|
|
258
|
+
console.log(` ${(0, theme_1.brand)(d.domain)}`);
|
|
259
|
+
for (const s of d.skills) {
|
|
260
|
+
console.log(` ${(0, theme_1.dim)('âē')} ${s.name.padEnd(22)} ${(0, theme_1.muted)(s.desc)}`);
|
|
261
|
+
}
|
|
262
|
+
console.log('');
|
|
263
|
+
}
|
|
264
|
+
console.log(` ${(0, theme_1.dim)(`Total: 34 skills across 6 domains`)}`);
|
|
265
|
+
console.log('');
|
|
266
|
+
const viewAll = yield p.confirm({
|
|
267
|
+
message: 'Want to browse all 34 skills in detail?',
|
|
268
|
+
initialValue: false,
|
|
269
|
+
});
|
|
270
|
+
profile.onboardingStep = 4;
|
|
271
|
+
(0, hooks_1.saveProfile)(profile);
|
|
272
|
+
if (viewAll === true) {
|
|
273
|
+
console.log((0, theme_1.dim)('\n Run: cm list to see all skills\n'));
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
// âââ STEP 5: Complete! đ ââââââââââââââââââââââ
|
|
277
|
+
if (startStep < 5) {
|
|
278
|
+
console.log('');
|
|
279
|
+
console.log((0, box_1.renderStepProgress)(5, TOTAL_STEPS));
|
|
280
|
+
console.log('');
|
|
281
|
+
console.log((0, hamster_1.getHamsterArt)('celebrating'));
|
|
282
|
+
console.log('');
|
|
283
|
+
console.log(` ${(0, theme_1.success)('đ')} ${(0, theme_1.brandBold)(`You're all set, ${profile.userName}!`)}`);
|
|
284
|
+
console.log('');
|
|
285
|
+
const quickRef = [
|
|
286
|
+
`${(0, theme_1.brand)('cm')} ${(0, theme_1.dim)('Quick menu')}`,
|
|
287
|
+
`${(0, theme_1.brand)('cm task add')} ${(0, theme_1.dim)('"..."')} ${(0, theme_1.dim)('Add a task')}`,
|
|
288
|
+
`${(0, theme_1.brand)('cm status')} ${(0, theme_1.dim)('See progress')}`,
|
|
289
|
+
`${(0, theme_1.brand)('cm list')} ${(0, theme_1.dim)('Browse skills')}`,
|
|
290
|
+
`${(0, theme_1.brand)('cm dashboard')} ${(0, theme_1.dim)('Open Mission Control')}`,
|
|
291
|
+
`${(0, theme_1.brand)('cm profile')} ${(0, theme_1.dim)('Your stats & achievements')}`,
|
|
292
|
+
];
|
|
293
|
+
console.log((0, box_1.renderBox)(quickRef, { title: 'Quick Reference', width: 52 }));
|
|
294
|
+
console.log('');
|
|
295
|
+
profile.onboardingStep = 5;
|
|
296
|
+
profile.onboardingComplete = true;
|
|
297
|
+
const newAchievements = (0, hooks_1.checkAchievements)(profile);
|
|
298
|
+
(0, hooks_1.saveProfile)(profile);
|
|
299
|
+
// Show achievements
|
|
300
|
+
for (const id of newAchievements) {
|
|
301
|
+
console.log((0, hooks_1.formatAchievement)(id));
|
|
302
|
+
}
|
|
303
|
+
if (newAchievements.length > 0)
|
|
304
|
+
console.log('');
|
|
305
|
+
}
|
|
306
|
+
return profile;
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Show returning user welcome (post-onboarding)
|
|
311
|
+
* Displays hamster + trigger + quick action
|
|
312
|
+
*/
|
|
313
|
+
function showReturningWelcome(profile, version, cwd) {
|
|
314
|
+
console.log((0, hamster_1.renderHamsterBanner)(profile.userName, version, cwd));
|
|
315
|
+
}
|
package/dist/ui/theme.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* đ¨ CodyMaster Theme â Centralized color palette & styling
|
|
4
|
+
* Warm amber/orange accent system for the Hamster Shell
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.ICONS = exports.STATUS = exports.PRI = exports.COL = exports.info = exports.warning = exports.error = exports.success = exports.text = exports.muted = exports.dim = exports.brandBg = exports.brandBold = exports.brand = exports.COLORS = void 0;
|
|
11
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
+
// âââ Brand Colors ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
|
|
13
|
+
exports.COLORS = {
|
|
14
|
+
// Primary brand
|
|
15
|
+
primary: '#F59E0B', // Amber/orange
|
|
16
|
+
primaryDim: '#D97706',
|
|
17
|
+
primaryBright: '#FBBF24',
|
|
18
|
+
// Backgrounds
|
|
19
|
+
bg: '#1a1b26',
|
|
20
|
+
bgPanel: '#24283b',
|
|
21
|
+
// Status
|
|
22
|
+
success: '#10B981',
|
|
23
|
+
error: '#EF4444',
|
|
24
|
+
warning: '#F59E0B',
|
|
25
|
+
info: '#3B82F6',
|
|
26
|
+
// Task columns
|
|
27
|
+
backlog: '#6B7280',
|
|
28
|
+
inProgress: '#3B82F6',
|
|
29
|
+
review: '#F59E0B',
|
|
30
|
+
done: '#10B981',
|
|
31
|
+
// Priority
|
|
32
|
+
low: '#10B981',
|
|
33
|
+
medium: '#F59E0B',
|
|
34
|
+
high: '#EF4444',
|
|
35
|
+
urgent: '#A855F7',
|
|
36
|
+
// Text
|
|
37
|
+
text: '#E5E7EB',
|
|
38
|
+
textDim: '#6B7280',
|
|
39
|
+
textMuted: '#4B5563',
|
|
40
|
+
};
|
|
41
|
+
// âââ Chalk Helpers âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
|
|
42
|
+
exports.brand = chalk_1.default.hex(exports.COLORS.primary);
|
|
43
|
+
exports.brandBold = chalk_1.default.hex(exports.COLORS.primary).bold;
|
|
44
|
+
exports.brandBg = chalk_1.default.bgHex(exports.COLORS.primary).black;
|
|
45
|
+
exports.dim = chalk_1.default.hex(exports.COLORS.textDim);
|
|
46
|
+
exports.muted = chalk_1.default.hex(exports.COLORS.textMuted);
|
|
47
|
+
exports.text = chalk_1.default.hex(exports.COLORS.text);
|
|
48
|
+
exports.success = chalk_1.default.hex(exports.COLORS.success);
|
|
49
|
+
exports.error = chalk_1.default.hex(exports.COLORS.error);
|
|
50
|
+
exports.warning = chalk_1.default.hex(exports.COLORS.warning);
|
|
51
|
+
exports.info = chalk_1.default.hex(exports.COLORS.info);
|
|
52
|
+
// Column colors
|
|
53
|
+
exports.COL = {
|
|
54
|
+
backlog: chalk_1.default.hex(exports.COLORS.backlog),
|
|
55
|
+
'in-progress': chalk_1.default.hex(exports.COLORS.inProgress),
|
|
56
|
+
review: chalk_1.default.hex(exports.COLORS.review),
|
|
57
|
+
done: chalk_1.default.hex(exports.COLORS.done),
|
|
58
|
+
};
|
|
59
|
+
// Priority colors
|
|
60
|
+
exports.PRI = {
|
|
61
|
+
low: chalk_1.default.hex(exports.COLORS.low),
|
|
62
|
+
medium: chalk_1.default.hex(exports.COLORS.medium),
|
|
63
|
+
high: chalk_1.default.hex(exports.COLORS.high),
|
|
64
|
+
urgent: chalk_1.default.hex(exports.COLORS.urgent),
|
|
65
|
+
};
|
|
66
|
+
// Status colors
|
|
67
|
+
exports.STATUS = {
|
|
68
|
+
success: chalk_1.default.hex(exports.COLORS.success),
|
|
69
|
+
failed: chalk_1.default.hex(exports.COLORS.error),
|
|
70
|
+
pending: chalk_1.default.hex(exports.COLORS.warning),
|
|
71
|
+
running: chalk_1.default.hex(exports.COLORS.inProgress),
|
|
72
|
+
rolled_back: chalk_1.default.hex(exports.COLORS.urgent),
|
|
73
|
+
};
|
|
74
|
+
// âââ Icons âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
|
|
75
|
+
exports.ICONS = {
|
|
76
|
+
// Status
|
|
77
|
+
dot: 'â',
|
|
78
|
+
dotEmpty: 'â',
|
|
79
|
+
check: 'â',
|
|
80
|
+
cross: 'â',
|
|
81
|
+
arrow: 'âē',
|
|
82
|
+
arrowRight: 'â',
|
|
83
|
+
// Categories
|
|
84
|
+
task: 'đ',
|
|
85
|
+
project: 'đĻ',
|
|
86
|
+
deploy: 'đ',
|
|
87
|
+
skill: 'đ§Š',
|
|
88
|
+
dashboard: 'đ',
|
|
89
|
+
history: 'đ',
|
|
90
|
+
settings: 'âī¸',
|
|
91
|
+
// Status
|
|
92
|
+
success: 'â
',
|
|
93
|
+
error: 'â',
|
|
94
|
+
warning: 'â ī¸',
|
|
95
|
+
info: 'âšī¸',
|
|
96
|
+
// Hamster
|
|
97
|
+
hamster: 'đš',
|
|
98
|
+
fire: 'đĨ',
|
|
99
|
+
star: 'â',
|
|
100
|
+
trophy: 'đ',
|
|
101
|
+
sparkle: 'â¨',
|
|
102
|
+
party: 'đ',
|
|
103
|
+
muscle: 'đĒ',
|
|
104
|
+
rocket: 'đ',
|
|
105
|
+
};
|