@valentia-ai-skills/framework 1.0.4 → 1.0.6

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/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.6",
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",
@@ -1,25 +0,0 @@
1
- ## Test 1: CRUD Endpoint Design
2
- **Prompt**: "Design the REST API endpoints for a blog post system with posts, comments, and tags"
3
- **Expected**:
4
- - Plural nouns: /posts, /comments, /tags
5
- - Proper nesting: /posts/:id/comments (max 2 levels)
6
- - All CRUD methods with correct status codes
7
- - Response envelope with data/error pattern
8
- - Pagination on list endpoints
9
-
10
- ## Test 2: Error Handling
11
- **Prompt**: "Write the error handling middleware for an Express API that returns consistent error responses"
12
- **Expected**:
13
- - Error envelope: { error: { code, message, details } }
14
- - Correct status codes (400 for validation, 401 for auth, 404 for not found)
15
- - No stack traces or internal details exposed
16
- - Proper differentiation between 401 and 403
17
-
18
- ## Test 3: Complex Query Endpoint
19
- **Prompt**: "Build a product search endpoint with filtering by price range, category, and rating, with sorting and pagination"
20
- **Expected**:
21
- - Query params: minPrice, maxPrice, category, minRating
22
- - Sort format: sort=price:asc
23
- - Offset pagination with page, pageSize, totalItems
24
- - Default and max page sizes enforced
25
- - Input validation on all query params
@@ -1,26 +0,0 @@
1
- ## Test 1: New Function Creation
2
- **Prompt**: "Write a function that fetches a user from the database by email, checks if they're active, and returns their profile with recent orders"
3
- **Expected**:
4
- - Function named descriptively (e.g., `getUserProfileWithOrders`)
5
- - Parameters use camelCase
6
- - Boolean check uses `isActive` pattern
7
- - Error handling with context
8
- - Under 40 lines, early returns
9
-
10
- ## Test 2: Refactoring Messy Code
11
- **Prompt**: "Refactor this: `function do_stuff(a, b, c, d, e, f) { try { if (a) { if (b) { if (c) { return process(d, e, f); } } } } catch(e) {} }`"
12
- **Expected**:
13
- - Renamed to descriptive name
14
- - Parameters grouped into options object (>4 params)
15
- - Nesting reduced via early returns
16
- - Error handling added (not swallowed)
17
- - camelCase naming
18
-
19
- ## Test 3: File Organization
20
- **Prompt**: "Create a user registration module with validation, database save, email notification, and audit logging"
21
- **Expected**:
22
- - Split into multiple files (not one 500-line file)
23
- - kebab-case file names
24
- - Proper import ordering
25
- - Named exports
26
- - Each file has single responsibility
@@ -1,240 +0,0 @@
1
- ---
2
- name: deployment
3
- description: >
4
- Organization-wide deployment standards for CI/CD pipelines, environment
5
- management, release processes, and rollback procedures. Use this skill
6
- whenever writing, reviewing, or discussing deployment configurations,
7
- CI/CD pipelines, Docker files, environment promotion, feature flags,
8
- release management, or rollback strategies. Triggers on: "deploy",
9
- "deployment", "CI/CD", "pipeline", "GitHub Actions", "Docker", "Dockerfile",
10
- "container", "Kubernetes", "k8s", "helm", "terraform", "release",
11
- "rollback", "staging", "production", "environment", "feature flag",
12
- "blue-green", "canary", "rolling update". Applies to all teams.
13
- version: "1.0.0"
14
- scope: global
15
- author: Framework Admin
16
- last_reviewed: 2026-03-19
17
- ---
18
-
19
- # Deployment Standards
20
-
21
- ## Overview
22
-
23
- Consistent deployment practices ensure reliable, safe releases across all
24
- services. These standards cover CI/CD pipelines, environment management,
25
- containerization, and rollback procedures.
26
-
27
- ## 1. Environment Promotion
28
-
29
- ### Environment Ladder
30
-
31
- ```
32
- Development → Staging → Production
33
- ```
34
-
35
- | Environment | Purpose | Who Deploys | Auto/Manual |
36
- |-------------|---------|-------------|-------------|
37
- | Development | Feature testing, integration | Any developer | Auto on PR merge to dev |
38
- | Staging | Pre-production validation, QA | CI/CD pipeline | Auto on merge to main |
39
- | Production | Live users | CI/CD + manual approval | Manual gate after staging |
40
-
41
- ### Rules
42
- - Code must pass through ALL environments in order — no skipping staging
43
- - Staging must mirror production configuration (same infra, same env vars pattern)
44
- - Production deployments require at least 1 manual approval
45
- - Exception: hotfix branches can fast-track with 2 approvals
46
-
47
- ## 2. CI/CD Pipeline Structure
48
-
49
- ### Required Pipeline Stages
50
-
51
- ```yaml
52
- # Every service must implement these stages:
53
-
54
- stages:
55
- # Stage 1: Quality Gates (runs on every PR)
56
- - lint # Code style, formatting
57
- - typecheck # TypeScript / mypy
58
- - test:unit # Unit tests with coverage
59
- - security:scan # Dependency vulnerability scan
60
-
61
- # Stage 2: Build (runs on merge to main)
62
- - build # Compile, bundle, Docker build
63
- - test:integration # Integration tests against test DB
64
-
65
- # Stage 3: Deploy (runs after build succeeds)
66
- - deploy:staging # Auto-deploy to staging
67
- - test:e2e # E2E tests against staging
68
- - deploy:production # Manual approval gate → production
69
- ```
70
-
71
- ### Rules
72
- - PRs cannot merge if any Stage 1 check fails
73
- - Build artifacts are created ONCE and promoted through environments
74
- - Never rebuild between staging and production — same artifact, different config
75
- - Pipeline must complete in under 15 minutes for Stage 1 (fast feedback)
76
- - Full pipeline (through staging E2E) under 30 minutes
77
-
78
- ## 3. Containerization (Docker)
79
-
80
- ### Dockerfile Standards
81
-
82
- ```dockerfile
83
- # ── Stage 1: Dependencies ──
84
- FROM node:20-alpine AS deps
85
- WORKDIR /app
86
- COPY package.json package-lock.json ./
87
- RUN npm ci --production=false
88
-
89
- # ── Stage 2: Build ──
90
- FROM node:20-alpine AS build
91
- WORKDIR /app
92
- COPY --from=deps /app/node_modules ./node_modules
93
- COPY . .
94
- RUN npm run build
95
- RUN npm prune --production
96
-
97
- # ── Stage 3: Production ──
98
- FROM node:20-alpine AS production
99
- WORKDIR /app
100
-
101
- # Security: run as non-root
102
- RUN addgroup -g 1001 appgroup && \
103
- adduser -u 1001 -G appgroup -D appuser
104
- USER appuser
105
-
106
- COPY --from=build /app/dist ./dist
107
- COPY --from=build /app/node_modules ./node_modules
108
- COPY --from=build /app/package.json ./
109
-
110
- EXPOSE 3000
111
- HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
112
- CMD wget -qO- http://localhost:3000/health || exit 1
113
-
114
- CMD ["node", "dist/main.js"]
115
- ```
116
-
117
- ### Rules
118
- - Multi-stage builds always — keep production image minimal
119
- - Run as non-root user — never run as root in production
120
- - Include HEALTHCHECK in Dockerfile
121
- - Pin base image versions: `node:20.11-alpine` not `node:latest`
122
- - Use `.dockerignore` to exclude: node_modules, .git, .env, tests, docs
123
- - Production image should be under 200MB
124
- - No dev dependencies in production stage
125
-
126
- ## 4. Environment Configuration
127
-
128
- ### Config by Environment
129
-
130
- ```
131
- # Pattern: same env var names, different values per environment
132
- DATABASE_URL=postgres://... # different per environment
133
- LOG_LEVEL=debug # development
134
- LOG_LEVEL=info # staging
135
- LOG_LEVEL=warn # production
136
- ```
137
-
138
- ### Rules
139
- - Same env var names across all environments
140
- - Secrets stored in secrets manager (not in CI/CD variables for production)
141
- - Environment-specific config via env vars, never via code branches
142
- - Every env var documented in README (see documentation skill)
143
- - Config validated at startup (see security-baseline skill)
144
-
145
- ## 5. Release Strategy
146
-
147
- ### Semantic Versioning
148
- ```
149
- v{MAJOR}.{MINOR}.{PATCH}
150
-
151
- MAJOR: Breaking changes (API incompatibility)
152
- MINOR: New features (backward compatible)
153
- PATCH: Bug fixes (backward compatible)
154
- ```
155
-
156
- ### Release Process
157
- 1. Merge to main → auto-deploy to staging
158
- 2. QA validates on staging (manual or automated)
159
- 3. Create GitHub Release with tag `v1.2.3`
160
- 4. Release triggers production deployment (with manual approval gate)
161
- 5. Monitor dashboards for 15 minutes post-deploy
162
- 6. If issues: rollback immediately
163
-
164
- ### Feature Flags
165
- For risky changes, use feature flags:
166
-
167
- ```typescript
168
- // Feature flag pattern
169
- if (featureFlags.isEnabled("new-checkout-flow", { userId: user.id })) {
170
- return newCheckoutFlow(order);
171
- } else {
172
- return legacyCheckoutFlow(order);
173
- }
174
- ```
175
-
176
- ### Rules
177
- - Feature flags for any change affecting > 10% of users
178
- - Flags have an expiry date — clean up within 2 weeks of full rollout
179
- - Flag states stored in config service (not hardcoded)
180
- - Always have a kill switch that reverts to old behavior
181
-
182
- ## 6. Rollback Procedures
183
-
184
- ### Automated Rollback Triggers
185
- - Error rate > 5% for 2 minutes
186
- - p99 latency > 5s for 5 minutes
187
- - Health check failures on > 25% of instances
188
-
189
- ### Manual Rollback Process
190
- ```bash
191
- # Option 1: Revert to previous container image
192
- kubectl rollout undo deployment/my-service
193
-
194
- # Option 2: Deploy a specific known-good version
195
- kubectl set image deployment/my-service app=my-service:v1.2.2
196
-
197
- # Option 3: Disable via feature flag (fastest)
198
- # Toggle flag off in config service
199
- ```
200
-
201
- ### Rules
202
- - Every deployment must be rollback-ready before proceeding
203
- - Database migrations must be backward-compatible (new code works with old schema AND new schema)
204
- - Rollback should complete in under 5 minutes
205
- - Post-rollback: create incident ticket, investigate, fix forward
206
- - Never rollback database migrations in production — fix forward only
207
-
208
- ## 7. Database Migration Safety
209
-
210
- ### Safe Migration Patterns
211
- ```
212
- ✅ ADD a new column (nullable or with default)
213
- ✅ ADD a new table
214
- ✅ ADD a new index (CONCURRENTLY)
215
- ✅ RENAME with a transition period (old name → alias → new name)
216
-
217
- ❌ DROP a column (in same deploy as code change)
218
- ❌ RENAME a column (without transition period)
219
- ❌ CHANGE column type (without transition period)
220
- ❌ ADD NOT NULL without default
221
- ```
222
-
223
- ### Two-Phase Migration Pattern
224
- For breaking schema changes:
225
- 1. **Phase 1**: Deploy code that works with BOTH old and new schema. Run migration to add new structure.
226
- 2. **Phase 2** (next release): Deploy code that uses only new schema. Remove old structure.
227
-
228
- ## Checklist
229
-
230
- Before deploying:
231
- - [ ] All CI stages pass (lint, typecheck, unit tests, security scan)
232
- - [ ] Docker image is multi-stage, runs as non-root, under 200MB
233
- - [ ] Integration tests pass against staging
234
- - [ ] E2E tests pass against staging
235
- - [ ] Database migration is backward-compatible
236
- - [ ] Rollback plan documented and tested
237
- - [ ] Feature flags in place for risky changes
238
- - [ ] Monitoring dashboards ready for post-deploy observation
239
- - [ ] Manual approval obtained for production
240
- - [ ] Changelog updated
@@ -1,27 +0,0 @@
1
- ## Test 1: Dockerfile Creation
2
- **Prompt**: "Write a Dockerfile for a Node.js Express API service with TypeScript compilation"
3
- **Expected**:
4
- - Multi-stage build (deps → build → production)
5
- - Non-root user
6
- - HEALTHCHECK instruction
7
- - Pinned base image version
8
- - Production-only dependencies in final stage
9
- - .dockerignore mentioned
10
-
11
- ## Test 2: CI/CD Pipeline
12
- **Prompt**: "Set up a GitHub Actions workflow for a Python FastAPI service with linting, testing, Docker build, and deployment to staging"
13
- **Expected**:
14
- - Stages: lint → typecheck → test → build → deploy
15
- - Runs on PR and merge to main
16
- - Docker build with caching
17
- - Integration tests before deploy
18
- - Environment-specific secrets handling
19
-
20
- ## Test 3: Database Migration Strategy
21
- **Prompt**: "I need to rename the 'username' column to 'display_name' in our users table. How do I do this safely?"
22
- **Expected**:
23
- - Two-phase migration approach
24
- - Phase 1: add display_name, backfill, deploy code that reads both
25
- - Phase 2: drop username column in next release
26
- - Never rename in a single deploy
27
- - Backward compatibility emphasized