@valentia-ai-skills/framework 1.0.4 → 1.0.5

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.
Files changed (2) hide show
  1. package/bin/cli.js +90 -18
  2. package/package.json +2 -2
package/bin/cli.js CHANGED
@@ -214,6 +214,71 @@ function getLocalSkills() {
214
214
  return skills;
215
215
  }
216
216
 
217
+ // ── Email + OTP Verification ──
218
+
219
+ async function requestOtpForEmail(emailInput) {
220
+ let email = emailInput;
221
+ let attempts = 0;
222
+
223
+ while (attempts < 2) {
224
+ if (!email || !email.includes("@")) {
225
+ console.log(c("red", "Invalid email."));
226
+ process.exit(1);
227
+ }
228
+
229
+ console.log(c("dim", "\nVerifying your email..."));
230
+
231
+ const response = await fetchJSON(SUPABASE_FUNCTION_URL, { email, action: "request_otp" });
232
+
233
+ if (response.error === "not_found") {
234
+ attempts++;
235
+ if (attempts >= 2) {
236
+ console.log(c("red", "\n✗ Email not recognized. Access denied."));
237
+ console.log(c("dim", " Contact your Framework Admin to be added to the system.\n"));
238
+ process.exit(1);
239
+ }
240
+ console.log(c("yellow", "\n⚠ Email not found. Please check and try again.\n"));
241
+ email = await ask(`${c("bold", "Enter your work email:")} `);
242
+ continue;
243
+ }
244
+
245
+ if (response.error) {
246
+ throw new Error(response.error);
247
+ }
248
+
249
+ // OTP sent successfully
250
+ console.log(c("green", `\n✓ Found: ${response.user_name}`));
251
+ console.log(c("dim", ` A verification code has been sent to ${email}\n`));
252
+
253
+ return email;
254
+ }
255
+ }
256
+
257
+ async function verifyOtp(email) {
258
+ const otp = await ask(`${c("bold", "Enter the 6-digit code:")} `);
259
+
260
+ if (!otp || otp.length < 4) {
261
+ console.log(c("red", "Invalid code."));
262
+ process.exit(1);
263
+ }
264
+
265
+ console.log(c("dim", "\nVerifying code..."));
266
+
267
+ const response = await fetchJSON(SUPABASE_FUNCTION_URL, { email, otp, action: "verify_otp" });
268
+
269
+ if (response.error === "invalid_otp") {
270
+ console.log(c("red", "\n✗ Invalid verification code. Please run setup again."));
271
+ process.exit(1);
272
+ }
273
+
274
+ if (response.error) {
275
+ throw new Error(response.error);
276
+ }
277
+
278
+ console.log(c("green", "✓ Verified!\n"));
279
+ return response;
280
+ }
281
+
217
282
  // ── Commands ──
218
283
 
219
284
  async function cmdSetup() {
@@ -229,37 +294,39 @@ async function cmdSetup() {
229
294
  }
230
295
 
231
296
  // 2. Ask for email
232
- const email = await ask(`${c("bold", "Enter your work email:")} `);
233
- if (!email || !email.includes("@")) {
234
- console.log(c("red", "Invalid email. Please try again."));
235
- process.exit(1);
236
- }
237
-
238
- // 3. Lookup team from Supabase
239
- console.log(c("dim", "\nLooking up your team..."));
297
+ let email = await ask(`${c("bold", "Enter your work email:")} `);
240
298
 
241
- let response;
242
299
  let skills;
243
300
  let teamName = null;
244
301
  let useRemote = true;
245
302
 
246
303
  try {
247
- response = await fetchJSON(SUPABASE_FUNCTION_URL, { email });
304
+ // 3. Request OTP (with 1 retry for wrong email)
305
+ email = await requestOtpForEmail(email);
306
+
307
+ // 4. Verify OTP and get skills
308
+ const response = await verifyOtp(email);
248
309
 
249
310
  if (response.team) {
250
311
  teamName = response.team.name;
251
- console.log(c("green", `\n✓ Team: ${teamName}`));
312
+ console.log(c("green", `✓ Team: ${teamName}`));
252
313
  if (response.user) {
253
314
  console.log(c("dim", ` Welcome, ${response.user.name} (${response.user.role})`));
254
315
  }
255
316
  if (response.team.stack_tags?.length) {
256
317
  console.log(c("dim", ` Stack: ${response.team.stack_tags.join(", ")}`));
257
318
  }
258
- } else {
259
- console.log(c("yellow", `\n⚠ ${response.message || "No team found for this email."}`));
319
+ } else if (response.message) {
320
+ console.log(c("yellow", `⚠ ${response.message}`));
260
321
  }
261
322
 
262
323
  skills = response.skills || [];
324
+
325
+ if (skills.length === 0) {
326
+ console.log(c("yellow", "\n⚠ No skills are enabled for your team. Contact your Team Lead."));
327
+ process.exit(1);
328
+ }
329
+
263
330
  console.log(` ${c("bold", skills.length)} skill(s) to install\n`);
264
331
 
265
332
  } catch (err) {
@@ -275,7 +342,7 @@ async function cmdSetup() {
275
342
  process.exit(1);
276
343
  }
277
344
 
278
- // 4. Install for each tool
345
+ // 5. Install for each tool
279
346
  for (const toolKey of tools) {
280
347
  const tool = TOOL_CONFIGS[toolKey];
281
348
  if (!tool) continue;
@@ -290,7 +357,7 @@ async function cmdSetup() {
290
357
  console.log("");
291
358
  }
292
359
 
293
- // 5. Save config
360
+ // 6. Save config
294
361
  const config = {
295
362
  version: require(path.join(__dirname, "..", "package.json")).version,
296
363
  email,
@@ -302,7 +369,7 @@ async function cmdSetup() {
302
369
  };
303
370
  saveConfig(config);
304
371
 
305
- // 6. Summary
372
+ // 7. Summary
306
373
  console.log(c("blue", "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"));
307
374
  console.log(c("green", "✅ Setup complete!"));
308
375
  console.log(` ${skills.length} skills installed for ${tools.length} tool(s)`);
@@ -320,13 +387,18 @@ async function cmdUpdate() {
320
387
  process.exit(1);
321
388
  }
322
389
 
323
- console.log(c("dim", `Updating for ${config.email}...`));
390
+ const email = config.email;
391
+ console.log(c("dim", `Updating for ${email}...`));
324
392
 
325
393
  let skills;
326
394
  let teamName = config.team;
327
395
 
328
396
  try {
329
- const response = await fetchJSON(SUPABASE_FUNCTION_URL, { email: config.email });
397
+ // Request OTP for the saved email
398
+ await requestOtpForEmail(email);
399
+
400
+ // Verify OTP
401
+ const response = await verifyOtp(email);
330
402
  skills = response.skills || [];
331
403
  teamName = response.team?.name || config.team;
332
404
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@valentia-ai-skills/framework",
3
- "version": "1.0.4",
4
- "description": "AI development skills framework — centralized coding standards, security patterns, and SOPs for AI-assisted development. Works with Claude Code, Cursor, Copilot, Windsurf, and any AI coding tool.",
3
+ "version": "1.0.5",
4
+ "description": "AI development skills framework — centralized coding standards, security patterns, and SOPs for AI-assisted development. Works with Claude Code, Cursor, Copilot, Windsurf, and any AI coding tool.",
5
5
  "keywords": [
6
6
  "ai-skills",
7
7
  "claude-code",