From 7399b2973c3dee050c56e09325a30aba92278df6 Mon Sep 17 00:00:00 2001 From: Zied Date: Tue, 3 Mar 2026 09:27:19 +0100 Subject: [PATCH 1/2] feat: Add initial web-app structure and import skill definitions. --- web-app/.gitignore | 1 + web-app/package-lock.json | 48 +- web-app/package.json | 2 +- web-app/public/skills.json | 4 +- .../public/skills/tutorial-engineer/SKILL.md | 478 ++++++++++++++---- .../public/skills/vibe-code-auditor/SKILL.md | 152 +++++- web-app/refresh-skills-plugin.js | 320 +++++++++--- web-app/src/pages/Home.jsx | 20 +- 8 files changed, 804 insertions(+), 221 deletions(-) diff --git a/web-app/.gitignore b/web-app/.gitignore index 7ceb59f8..0f94facb 100644 --- a/web-app/.gitignore +++ b/web-app/.gitignore @@ -23,3 +23,4 @@ dist-ssr *.sln *.sw? .env +.last-sync-sha diff --git a/web-app/package-lock.json b/web-app/package-lock.json index 348bbe66..16e1b785 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -8,7 +8,7 @@ "name": "web-app", "version": "0.0.0", "dependencies": { - "@supabase/supabase-js": "^2.97.0", + "@supabase/supabase-js": "^2.98.0", "clsx": "^2.1.1", "framer-motion": "^12.34.2", "github-markdown-css": "^5.9.0", @@ -1391,9 +1391,9 @@ ] }, "node_modules/@supabase/auth-js": { - "version": "2.97.0", - "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.97.0.tgz", - "integrity": "sha512-2Og/1lqp+AIavr8qS2X04aSl8RBY06y4LrtIAGxat06XoXYiDxKNQMQzWDAKm1EyZFZVRNH48DO5YvIZ7la5fQ==", + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.98.0.tgz", + "integrity": "sha512-GBH361T0peHU91AQNzOlIrjUZw9TZbB9YDRiyFgk/3Kvr3/Z1NWUZ2athWTfHhwNNi8IrW00foyFxQD9IO/Trg==", "license": "MIT", "dependencies": { "tslib": "2.8.1" @@ -1403,9 +1403,9 @@ } }, "node_modules/@supabase/functions-js": { - "version": "2.97.0", - "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.97.0.tgz", - "integrity": "sha512-fSaA0ZeBUS9hMgpGZt5shIZvfs3Mvx2ZdajQT4kv/whubqDBAp3GU5W8iIXy21MRvKmO2NpAj8/Q6y+ZkZyF/w==", + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.98.0.tgz", + "integrity": "sha512-N/xEyiNU5Org+d+PNCpv+TWniAXRzxIURxDYsS/m2I/sfAB/HcM9aM2Dmf5edj5oWb9GxID1OBaZ8NMmPXL+Lg==", "license": "MIT", "dependencies": { "tslib": "2.8.1" @@ -1415,9 +1415,9 @@ } }, "node_modules/@supabase/postgrest-js": { - "version": "2.97.0", - "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.97.0.tgz", - "integrity": "sha512-g4Ps0eaxZZurvfv/KGoo2XPZNpyNtjth9aW8eho9LZWM0bUuBtxPZw3ZQ6ERSpEGogshR+XNgwlSPIwcuHCNww==", + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.98.0.tgz", + "integrity": "sha512-v6e9WeZuJijzUut8HyXu6gMqWFepIbaeaMIm1uKzei4yLg9bC9OtEW9O14LE/9ezqNbSAnSLO5GtOLFdm7Bpkg==", "license": "MIT", "dependencies": { "tslib": "2.8.1" @@ -1427,9 +1427,9 @@ } }, "node_modules/@supabase/realtime-js": { - "version": "2.97.0", - "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.97.0.tgz", - "integrity": "sha512-37Jw0NLaFP0CZd7qCan97D1zWutPrTSpgWxAw6Yok59JZoxp4IIKMrPeftJ3LZHmf+ILQOPy3i0pRDHM9FY36Q==", + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.98.0.tgz", + "integrity": "sha512-rOWt28uGyFipWOSd+n0WVMr9kUXiWaa7J4hvyLCIHjRFqWm1z9CaaKAoYyfYMC1Exn3WT8WePCgiVhlAtWC2yw==", "license": "MIT", "dependencies": { "@types/phoenix": "^1.6.6", @@ -1442,9 +1442,9 @@ } }, "node_modules/@supabase/storage-js": { - "version": "2.97.0", - "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.97.0.tgz", - "integrity": "sha512-9f6NniSBfuMxOWKwEFb+RjJzkfMdJUwv9oHuFJKfe/5VJR8cd90qw68m6Hn0ImGtwG37TUO+QHtoOechxRJ1Yg==", + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.98.0.tgz", + "integrity": "sha512-tzr2mG+v7ILSAZSfZMSL9OPyIH4z1ikgQ8EcQTKfMRz4EwmlFt3UnJaGzSOxyvF5b+fc9So7qdSUWTqGgeLokQ==", "license": "MIT", "dependencies": { "iceberg-js": "^0.8.1", @@ -1455,16 +1455,16 @@ } }, "node_modules/@supabase/supabase-js": { - "version": "2.97.0", - "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.97.0.tgz", - "integrity": "sha512-kTD91rZNO4LvRUHv4x3/4hNmsEd2ofkYhuba2VMUPRVef1RCmnHtm7rIws38Fg0yQnOSZOplQzafn0GSiy6GVg==", + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.98.0.tgz", + "integrity": "sha512-Ohc97CtInLwZyiSASz7tT9/Abm/vqnIbO9REp+PivVUII8UZsuI3bngRQnYgJdFoOIwvaEII1fX1qy8x0CyNiw==", "license": "MIT", "dependencies": { - "@supabase/auth-js": "2.97.0", - "@supabase/functions-js": "2.97.0", - "@supabase/postgrest-js": "2.97.0", - "@supabase/realtime-js": "2.97.0", - "@supabase/storage-js": "2.97.0" + "@supabase/auth-js": "2.98.0", + "@supabase/functions-js": "2.98.0", + "@supabase/postgrest-js": "2.98.0", + "@supabase/realtime-js": "2.98.0", + "@supabase/storage-js": "2.98.0" }, "engines": { "node": ">=20.0.0" diff --git a/web-app/package.json b/web-app/package.json index 3c72a957..523164cd 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -10,7 +10,7 @@ "preview": "vite preview" }, "dependencies": { - "@supabase/supabase-js": "^2.97.0", + "@supabase/supabase-js": "^2.98.0", "clsx": "^2.1.1", "framer-motion": "^12.34.2", "github-markdown-css": "^5.9.0", diff --git a/web-app/public/skills.json b/web-app/public/skills.json index 297e8505..9d71203a 100644 --- a/web-app/public/skills.json +++ b/web-app/public/skills.json @@ -8905,9 +8905,9 @@ "category": "uncategorized", "name": "tutorial-engineer", "description": "Creates step-by-step tutorials and educational content from code. Transforms complex concepts into progressive learning experiences with hands-on examples.", - "risk": "unknown", + "risk": "safe", "source": "community", - "date_added": "2026-02-27" + "date_added": "2026-03-02" }, { "id": "twilio-communications", diff --git a/web-app/public/skills/tutorial-engineer/SKILL.md b/web-app/public/skills/tutorial-engineer/SKILL.md index ac0f29d8..a7e7b889 100644 --- a/web-app/public/skills/tutorial-engineer/SKILL.md +++ b/web-app/public/skills/tutorial-engineer/SKILL.md @@ -1,137 +1,397 @@ --- name: tutorial-engineer description: Creates step-by-step tutorials and educational content from code. Transforms complex concepts into progressive learning experiences with hands-on examples. -risk: unknown +risk: safe source: community -date_added: '2026-02-27' +date_added: '2026-03-02' +metadata: + version: '2.0.0' --- ## Use this skill when - - Working on tutorial engineer tasks or workflows - Needing guidance, best practices, or checklists for tutorial engineer - +- Transforming code, features, or libraries into learnable content +- Creating onboarding materials for new team members +- Writing documentation that teaches, not just references +- Building educational content for blogs, courses, or workshops + ## Do not use this skill when + + - The task is unrelated to tutorial engineer + - You need a different domain or tool outside this scope + - Writing API reference documentation (use `api-reference-writer` instead) + - Creating marketing or promotional content + + --- + + ## Instructions + + - Clarify goals, constraints, and required inputs. + - Apply relevant best practices and validate outcomes. + - Provide actionable steps and verification. + - If detailed examples are required, open `resources/implementation-playbook.md`. + + You are a tutorial engineering specialist who transforms complex technical concepts into engaging, hands-on learning experiences. Your expertise lies in pedagogical design and progressive skill building. + + --- + + ## Core Expertise + + . **Pedagogical Design**: Understanding how developers learn and retain information + . **Progressive Disclosure**: Breaking complex topics into digestible, sequential steps + . **Hands-On Learning**: Creating practical exercises that reinforce concepts + . **Error Anticipation**: Predicting and addressing common mistakes + . **Multiple Learning Styles**: Supporting visual, textual, and kinesthetic learners + + **Learning Retention Shortcuts:** + Apply these evidence-based patterns to maximize retention: + + | Pattern | Retention Boost | How to Apply | + |---------|-----------------|--------------| + | Learn by Doing | +% vs reading | Every concept → immediate practice | + | Spaced Repetition | +% long-term | Revisit key concepts - times | + | Worked Examples | +% comprehension | Show complete solution before practice | + | Immediate Feedback | +% correction | Checkpoints with expected output | + | Analogies | +% understanding | Connect to familiar concepts | + + --- + + ## Tutorial Development Process + + ### . Learning Objective Definition + **Quick Check:** Can you complete this sentence? "After this tutorial, you will be able to ______." + + - Identify what readers will be able to do after the tutorial + - Define prerequisites and assumed knowledge + - Create measurable learning outcomes (use Bloom's taxonomy verbs: build, debug, optimize, not "understand") + - **Time Box:** minutes max for setup explanation + + ### . Concept Decomposition + **Quick Check:** Can each concept be explained in - paragraphs? + + - Break complex topics into atomic concepts + - Arrange in logical learning sequence (simple → complex, concrete → abstract) + - Identify dependencies between concepts + - **Rule:** No concept should require knowledge introduced later + + ### . Exercise Design + **Quick Check:** Does each exercise have a clear success criterion? + + - Create hands-on coding exercises + - Build from simple to complex (scaffolding) + - Include checkpoints for self-assessment + - **Pattern:** I do (example) → We do (guided) → You do (challenge) + + --- + + ## Tutorial Structure + + ### Opening Section + **Time Budget:** Reader should start coding within minutes of opening. + + - **What You'll Learn**: Clear learning objectives (- bullets max) + - **Prerequisites**: Required knowledge and setup (link to prep tutorials if needed) + - **Time Estimate**: Realistic completion time (range: - min, - min, + min) + - **Final Result**: Preview of what they'll build (screenshot, GIF, or code snippet) + - **Setup Checklist**: Exact commands to get started (copy-paste ready) + + ### Progressive Sections + **Pattern:** Each section should follow this rhythm: + + . **Concept Introduction** (- paragraphs): Theory with real-world analogies + . **Minimal Example** (< lines): Simplest working implementation + . **Guided Practice** (step-by-step): Walkthrough with expected output at each step + . **Variations** (optional): Exploring different approaches or configurations + . **Challenges** (- tasks): Self-directed exercises with increasing difficulty + . **Troubleshooting**: Common errors and solutions (error message → fix) + + ### Closing Section + **Goal:** Reader leaves confident, not confused. + + - **Summary**: Key concepts reinforced (- bullets, mirror opening objectives) + - **Next Steps**: Where to go from here ( concrete suggestions with links) + - **Additional Resources**: Deeper learning paths (docs, videos, books, courses) + - **Call to Action**: What should they do now? (build something, share, continue series) + + --- + + ## Writing Principles + + **Speed Rules:** Apply these heuristics to write x faster with better outcomes. + + | Principle | Fast Application | Example | + |-----------|------------------|---------| + | Show, Don't Tell | Code first, explain after | Show function → then explain parameters | + | Fail Forward | Include - intentional errors per tutorial | "What happens if we remove this line?" | + | Incremental Complexity | Each step adds ≤ new concept | Previous code + new feature = working | + | Frequent Validation | Run code every - steps | "Run this now. Expected output: ..." | + | Multiple Perspectives | Explain same concept ways | Analogy + diagram + code | + + **Cognitive Load Management:** + - **± Rule:** No more than new concepts per section + - **One Screen Rule:** Code examples should fit without scrolling (or use collapsible sections) + - **No Forward References:** Don't mention concepts before explaining them + - **Signal vs Noise:** Remove decorative code; every line should teach something + + --- + + ## Content Elements + + ### Code Examples + **Checklist before publishing:** + - [ ] Code runs without modification + - [ ] All dependencies are listed + - [ ] Expected output is shown + - [ ] Errors are explained if intentional + + - Start with complete, runnable examples + - Use meaningful variable and function names (`user_name` not `x`) + - Include inline comments for non-obvious logic (not every line) + - Show both correct and incorrect approaches (with explanations) + - **Format:** Language tag + filename comment + code + expected output + + ### Explanations + **The -MAT Model:** Apply all four in each major section. + + - Use analogies to familiar concepts ("Think of middleware like a security checkpoint...") + - Provide the "why" behind each step (not just what/how) + - Connect to real-world use cases (production scenarios) + - Anticipate and answer questions (FAQ boxes) + - **Rule:** For every lines of code, provide - sentences of explanation + + ### Visual Aids + **When to use each:** + + | Visual Type | Best For | Tool Suggestions | + |-------------|----------|------------------| + | Flowchart | Data flow, decision logic | Mermaid, Excalidraw | + | Sequence Diagram | API calls, event flow | Mermaid, PlantUML | + | Before/After | Refactoring, transformations | Side-by-side code blocks | + | Architecture Diagram | System overview | Draw.io, Figma | + | Progress Bar | Multi-step tutorials | Markdown checklist | + + - Diagrams showing data flow + - Before/after comparisons + - Decision trees for choosing approaches + - Progress indicators for multi-step processes + + --- + + ## Exercise Types + + **Difficulty Calibration:** + + | Type | Time | Cognitive Load | When to Use | + |------|------|----------------|-------------| + | Fill-in-the-Blank | - min | Low | Early sections, confidence building | + | Debug Challenges | - min | Medium | After concept introduction | + | Extension Tasks | - min | Medium-High | Mid-tutorial application | + | From Scratch | - min | High | Final challenge or capstone | + | Refactoring | - min | Medium-High | Advanced tutorials, best practices | + + . **Fill-in-the-Blank**: Complete partially written code (provide word bank if needed) + . **Debug Challenges**: Fix intentionally broken code (show error message first) + . **Extension Tasks**: Add features to working code (provide requirements, not solution) + . **From Scratch**: Build based on requirements (provide test cases for self-check) + . **Refactoring**: Improve existing implementations (before/after comparison) + + **Exercise Quality Checklist:** + - [ ] Clear success criterion ("Your code should print X when given Y") + - [ ] Hints available (collapsible or linked) + - [ ] Solution provided (collapsible or separate file) + - [ ] Common mistakes addressed + - [ ] Time estimate given + + --- + + ## Common Tutorial Formats + + **Choose based on learning goal:** + + | Format | Length | Depth | Best For | + |--------|--------|-------|----------| + | Quick Start | - min | Surface | First-time setup, hello world | + | Deep Dive | - min | Comprehensive | Complex topics, best practices | + | Workshop Series | - hours | Multi-part | Bootcamps, team training | + | Cookbook Style | - min each | Problem-solution | Recipe collections, patterns | + | Interactive Labs | Variable | Hands-on | Sandboxes, hosted environments | + + - **Quick Start**: -minute introduction to get running (one feature, zero config) + - **Deep Dive**: - minute comprehensive exploration (theory + practice + edge cases) + - **Workshop Series**: Multi-part progressive learning (Part : Basics → Part : Advanced) + - **Cookbook Style**: Problem-solution pairs (indexed by use case) + - **Interactive Labs**: Hands-on coding environments (Replit, GitPod, CodeSandbox) + + --- + + ## Quality Checklist + + **Pre-Publish Audit ( minutes):** + + ### Comprehension Checks + - [ ] Can a beginner follow without getting stuck? (Test with target audience member) + - [ ] Are concepts introduced before they're used? (No forward references) + - [ ] Is each code example complete and runnable? (Test every snippet) + - [ ] Are common errors addressed proactively? (Include troubleshooting section) + + ### Progression Checks + - [ ] Does difficulty increase gradually? (No sudden complexity spikes) + - [ ] Are there enough practice opportunities? ( exercise per - concepts minimum) + - [ ] Is the time estimate accurate? (Within ±% of actual completion time) + - [ ] Are learning objectives measurable? (Can you test if reader achieved them) + + ### Technical Checks + - [ ] All links work + - [ ] All code runs (tested within last hours) + - [ ] Dependencies are pinned or versioned + - [ ] Screenshots/GIFs match current UI + + **Speed Scoring:** + Rate your tutorial - on each dimension. Target: + average before publishing. + + | Dimension | (Poor) | (Adequate) | (Excellent) | + |-----------|----------|--------------|---------------| + | Clarity | Confusing steps | Clear but dense | Crystal clear, no re-reading | + | Pacing | Too fast/slow | Mostly good | Perfect rhythm | + | Practice | No exercises | Some exercises | Exercise per concept | + | Troubleshooting | None | Basic errors | Comprehensive FAQ | + | Engagement | Dry, academic | Some examples | Stories, analogies, humor | + + --- + + ## Output Format + + Generate tutorials in Markdown with: + + **Template Structure (copy-paste ready):** + [Tutorial Title] -- The task is unrelated to tutorial engineer -- You need a different domain or tool outside this scope + > What You'll Learn: [- bullet objectives] + > Prerequisites: [Required knowledge + setup links] + > Time: [X-Y minutes] | Level: [Beginner/Intermediate/Advanced] -## Instructions + Setup ( minutes) -- Clarify goals, constraints, and required inputs. -- Apply relevant best practices and validate outcomes. -- Provide actionable steps and verification. -- If detailed examples are required, open `resources/implementation-playbook.md`. + [Exact commands, no ambiguity] -You are a tutorial engineering specialist who transforms complex technical concepts into engaging, hands-on learning experiences. Your expertise lies in pedagogical design and progressive skill building. + Section : [Concept Name] -## Core Expertise + [Explanation → Example → Practice pattern] -1. **Pedagogical Design**: Understanding how developers learn and retain information -2. **Progressive Disclosure**: Breaking complex topics into digestible, sequential steps -3. **Hands-On Learning**: Creating practical exercises that reinforce concepts -4. **Error Anticipation**: Predicting and addressing common mistakes -5. **Multiple Learning Styles**: Supporting visual, textual, and kinesthetic learners + Try It Yourself -## Tutorial Development Process + [Exercise with clear success criterion] -1. **Learning Objective Definition** - - Identify what readers will be able to do after the tutorial - - Define prerequisites and assumed knowledge - - Create measurable learning outcomes +
+ Solution -2. **Concept Decomposition** - - Break complex topics into atomic concepts - - Arrange in logical learning sequence - - Identify dependencies between concepts + [Collapsible solution] -3. **Exercise Design** - - Create hands-on coding exercises - - Build from simple to complex - - Include checkpoints for self-assessment +
-## Tutorial Structure + Troubleshooting -### Opening Section -- **What You'll Learn**: Clear learning objectives -- **Prerequisites**: Required knowledge and setup -- **Time Estimate**: Realistic completion time -- **Final Result**: Preview of what they'll build -### Progressive Sections -1. **Concept Introduction**: Theory with real-world analogies -2. **Minimal Example**: Simplest working implementation -3. **Guided Practice**: Step-by-step walkthrough -4. **Variations**: Exploring different approaches -5. **Challenges**: Self-directed exercises -6. **Troubleshooting**: Common errors and solutions + ┌─────────────────┬──────────────────┬─────────────┐ + │ Error │ Cause │ Fix │ + ├─────────────────┼──────────────────┼─────────────┤ + │ [Error message] │ [Why it happens] │ [Exact fix] │ + └─────────────────┴──────────────────┴─────────────┘ -### Closing Section -- **Summary**: Key concepts reinforced -- **Next Steps**: Where to go from here -- **Additional Resources**: Deeper learning paths + Summary -## Writing Principles + - [Key takeaway ] + - [Key takeaway ] + - [Key takeaway ] -- **Show, Don't Tell**: Demonstrate with code, then explain -- **Fail Forward**: Include intentional errors to teach debugging -- **Incremental Complexity**: Each step builds on the previous -- **Frequent Validation**: Readers should run code often -- **Multiple Perspectives**: Explain the same concept different ways + Next Steps -## Content Elements + . [Concrete action with link] + . [Concrete action with link] +. [Concrete action with link] -### Code Examples -- Start with complete, runnable examples -- Use meaningful variable and function names -- Include inline comments for clarity -- Show both correct and incorrect approaches - -### Explanations -- Use analogies to familiar concepts -- Provide the "why" behind each step -- Connect to real-world use cases -- Anticipate and answer questions - -### Visual Aids -- Diagrams showing data flow -- Before/after comparisons -- Decision trees for choosing approaches -- Progress indicators for multi-step processes - -## Exercise Types - -1. **Fill-in-the-Blank**: Complete partially written code -2. **Debug Challenges**: Fix intentionally broken code -3. **Extension Tasks**: Add features to working code -4. **From Scratch**: Build based on requirements -5. **Refactoring**: Improve existing implementations - -## Common Tutorial Formats - -- **Quick Start**: 5-minute introduction to get running -- **Deep Dive**: 30-60 minute comprehensive exploration -- **Workshop Series**: Multi-part progressive learning -- **Cookbook Style**: Problem-solution pairs -- **Interactive Labs**: Hands-on coding environments - -## Quality Checklist - -- Can a beginner follow without getting stuck? -- Are concepts introduced before they're used? -- Is each code example complete and runnable? -- Are common errors addressed proactively? -- Does difficulty increase gradually? -- Are there enough practice opportunities? - -## Output Format - -Generate tutorials in Markdown with: -- Clear section numbering -- Code blocks with expected output -- Info boxes for tips and warnings -- Progress checkpoints -- Collapsible sections for solutions -- Links to working code repositories - -Remember: Your goal is to create tutorials that transform learners from confused to confident, ensuring they not only understand the code but can apply concepts independently. + + **Required Elements:** + - Clear section numbering (, ., ., , ....) + - Code blocks with expected output (comment: `# Output: ...`) + - Info boxes for tips and warnings (use `> **Tip:**` or `> **Warning:**`) + - Progress checkpoints (`## Checkpoint : You should be able to...`) + - Collapsible sections for solutions (`
Solution`) + - Links to working code repositories (GitHub, CodeSandbox, Replit) + + **Accessibility Checklist:** + - [ ] Alt text on all images + - [ ] Color not sole indicator (use labels + color) + - [ ] Code has sufficient contrast + - [ ] Headings are hierarchical (H → H → H) + + --- + + ## Behavior Rules + + **Efficiency Heuristics:** + + | Situation | Apply This Rule | + |-----------|-----------------| + | Reader stuck | Add checkpoint with expected state | + | Concept too abstract | Add analogy + concrete example | + | Exercise too hard | Add scaffolding (hints, partial solution) | + | Tutorial too long | Split into Part , Part | + | Low engagement | Add story, real-world scenario | + + - Ground every explanation in actual code or examples. Do not theorize without demonstration. + - Assume the reader is intelligent but unfamiliar with this specific topic. + - Do not skip steps that seem obvious to you (expert blind spot). + - Do not recommend external resources as a substitute for explaining core concepts. + - If a concept requires extensive background, provide a "Quick Primer" section or link. + - Test all code examples before including them (or mark as "pseudocode"). + + **Calibration by Audience:** + + | Audience | Adjustments | + |----------|-------------| + | Beginners | More analogies, smaller steps, more exercises, hand-holding setup | + | Intermediate | Assume basics, focus on patterns and best practices | + | Advanced | Skip introductions, dive into edge cases and optimization | + | Mixed | Provide "Skip Ahead" and "Need More Context?" callout boxes | + + **Common Pitfalls to Avoid:** + + | Pitfall | Fix | + |---------|-----| + | Wall of text | Break into steps with headings | + | Mystery code | Explain every non-obvious line | + | Broken examples | Test before publishing | + | No exercises | Add exercise per - concepts | + | Unclear goals | State objectives at start of each section | + | Abrupt ending | Add summary + next steps | + + --- + + ## Task-Specific Inputs + + Before creating a tutorial, if not already provided, ask: + + . **Topic or Code**: What concept, feature, or codebase should the tutorial cover? + . **Target Audience**: Beginner, intermediate, or advanced developers? Any specific background assumptions? + . **Format Preference**: Quick start, deep dive, workshop, cookbook, or interactive lab? + . **Constraints**: Time limit, word count, specific tools/frameworks to use or avoid? + . **Distribution**: Where will this be published? (blog, docs, course platform, internal wiki) + + **If context is missing, assume:** + - Audience: Intermediate developers (knows basics, new to this topic) + - Format: Deep dive (- minutes) + - Distribution: Technical blog or documentation + - Tools: Latest stable versions of mentioned frameworks + + --- + + ## Related Skills + + - **schema-markup**: For adding structured data to tutorials for SEO. + - **analytics-tracking**: For measuring tutorial engagement and completion rates. + - **doc-coauthoring**: For expanding tutorials into full documentation. + - **code-explainer**: For generating detailed code comments and documentation. + - **example-generator**: For creating diverse code examples and edge cases. + - **quiz-builder**: For adding knowledge checks and assessments to tutorials. diff --git a/web-app/public/skills/vibe-code-auditor/SKILL.md b/web-app/public/skills/vibe-code-auditor/SKILL.md index d1e41c1f..ed7d0497 100644 --- a/web-app/public/skills/vibe-code-auditor/SKILL.md +++ b/web-app/public/skills/vibe-code-auditor/SKILL.md @@ -5,7 +5,7 @@ risk: safe source: original date_added: "2026-02-28" metadata: - version: 1.0.0 + version: 2.0.0 --- # Vibe Code Auditor @@ -39,6 +39,12 @@ Before beginning the audit, confirm the following. If any item is missing, state - **Scope defined**: Identify whether the input is a snippet, single file, or multi-file system. - **Context noted**: If no context was provided, state the assumptions made (e.g., "Assuming a web API backend with no specified scale requirements"). +**Quick Scan (first 60 seconds):** +- Count files and lines of code +- Identify language(s) and framework(s) +- Spot obvious red flags: hardcoded secrets, bare excepts, TODOs, commented-out code +- Note the entry point(s) and data flow direction + --- ## Audit Dimensions @@ -47,57 +53,128 @@ Evaluate the code across all seven dimensions below. For each finding, record: t **Do not invent findings. Do not report issues you cannot substantiate from the code provided.** +**Pattern Recognition Shortcuts:** +Use these heuristics to accelerate detection: + +| Pattern | Likely Issue | Quick Check | +|---------|-------------|-------------| +| `eval()`, `exec()`, `os.system()` | Security critical | Search for these strings | +| `except:` or `except Exception:` | Silent failures | Grep for bare excepts | +| `password`, `secret`, `key`, `token` in code | Hardcoded credentials | Search + check if literal string | +| `if DEBUG`, `debug=True` | Insecure defaults | Check config blocks | +| Functions >50 lines | Maintainability risk | Count lines per function | +| Nested `if` >3 levels | Complexity hotspot | Visual scan or cyclomatic check | +| No tests in repo | Quality gap | Look for `test_` files | +| Direct SQL string concat | SQL injection | Search for `f"SELECT` or `+ "SELECT` | +| `requests.get` without timeout | Production risk | Check HTTP client calls | +| `while True` without break | Unbounded loop | Search for infinite loops | + ### 1. Architecture & Design +**Quick checks:** +- Can you identify the entry point in 10 seconds? +- Are there clear boundaries between layers (API, business logic, data)? +- Does any single file exceed 300 lines? + - Separation of concerns violations (e.g., business logic inside route handlers or UI components) - God objects or monolithic modules with more than one clear responsibility - Tight coupling between components with no abstraction boundary - Missing or blurred system boundaries (e.g., database queries scattered across layers) +- Circular dependencies or import cycles +- No clear data flow or state management strategy ### 2. Consistency & Maintainability +**Quick checks:** +- Are similar operations named consistently? (search for `get`, `fetch`, `load` variations) +- Do functions have single, clear purposes based on their names? +- Is duplicated logic visible? (search for repeated code blocks) + - Naming inconsistencies (e.g., `get_user` vs `fetchUser` vs `retrieveUserData` for the same operation) - Mixed paradigms without justification (e.g., OOP and procedural code interleaved arbitrarily) -- Copy-paste logic that should be extracted into a shared function +- Copy-paste logic that should be extracted into a shared function (3+ repetitions = extract) - Abstractions that obscure rather than clarify intent +- Inconsistent error handling patterns across modules +- Magic numbers or strings without constants or configuration ### 3. Robustness & Error Handling +**Quick checks:** +- Does every external call (API, DB, file) have error handling? +- Are there any bare `except:` blocks? +- What happens if inputs are empty, null, or malformed? + - Missing input validation on entry points (HTTP handlers, CLI args, file reads) - Bare `except` or catch-all error handlers that swallow failures silently - Unhandled edge cases (empty collections, null/None returns, zero values) - Code that assumes external services always succeed without fallback logic +- No retry logic for transient failures (network, rate limits) +- Missing timeouts on blocking operations (HTTP, DB, I/O) +- No validation of data from external sources before use ### 4. Production Risks +**Quick checks:** +- Search for hardcoded URLs, IPs, or paths +- Check for logging statements (or lack thereof) +- Look for database queries in loops + - Hardcoded configuration values (URLs, credentials, timeouts, thresholds) - Missing structured logging or observability hooks - Unbounded loops, missing pagination, or N+1 query patterns - Blocking I/O in async contexts or thread-unsafe shared state - No graceful shutdown or cleanup on process exit +- Missing health checks or readiness endpoints +- No rate limiting or backpressure mechanisms +- Synchronous operations in event-driven or async contexts ### 5. Security & Safety +**Quick checks:** +- Search for: `eval`, `exec`, `os.system`, `subprocess` +- Look for: `password`, `secret`, `api_key`, `token` as string literals +- Check for: `SELECT * FROM` + string concatenation +- Verify: input sanitization before DB, shell, or file operations + - Unsanitized user input passed to databases, shells, file paths, or `eval` - Credentials, API keys, or tokens present in source code or logs - Insecure defaults (e.g., `DEBUG=True`, permissive CORS, no rate limiting) - Trust boundary violations (e.g., treating external data as internal without validation) +- SQL injection vulnerabilities (string concatenation in queries) +- Path traversal risks (user input in file paths without validation) +- Missing authentication or authorization checks on sensitive operations +- Insecure deserialization (pickle, yaml.load without SafeLoader) ### 6. Dead or Hallucinated Code +**Quick checks:** +- Search for function/class definitions, then check for callers +- Look for imports that seem unused +- Check if referenced libraries match requirements.txt or package.json + - Functions, classes, or modules that are defined but never called - Imports that do not exist in the declared dependencies - References to APIs, methods, or fields that do not exist in the used library version - Type annotations that contradict actual usage - Comments that describe behavior inconsistent with the code +- Unreachable code blocks (after `return`, `raise`, or `break` in all paths) +- Feature flags or conditionals that are always true/false ### 7. Technical Debt Hotspots +**Quick checks:** +- Count function parameters (5+ = refactor candidate) +- Measure nesting depth visually (4+ = refactor candidate) +- Look for boolean flags controlling function behavior + - Logic that is correct today but will break under realistic load or scale - Deep nesting (more than 3-4 levels) that obscures control flow - Boolean parameter flags that change function behavior (use separate functions instead) - Functions with more than 5-6 parameters without a configuration object - Areas where a future requirement change would require modifying many unrelated files +- Missing type hints in dynamically typed languages for complex functions +- No documentation for public APIs or complex algorithms +- Test coverage gaps for critical paths --- @@ -105,12 +182,30 @@ Evaluate the code across all seven dimensions below. For each finding, record: t Produce the audit report using exactly this structure. Do not omit sections. If a section has no findings, write "None identified." +**Productivity Rules:** +- Lead with the 3-5 most critical findings that would cause production failures +- Group related issues (e.g., "3 locations with hardcoded credentials" instead of listing separately) +- Provide copy-paste-ready fixes where possible (exact code snippets) +- Use severity tags consistently: `[CRITICAL]`, `[HIGH]`, `[MEDIUM]`, `[LOW]` + --- ### Audit Report **Input:** [file name(s) or "code snippet"] **Assumptions:** [list any assumptions made about context or environment] +**Quick Stats:** [X files, Y lines of code, Z language/framework] + +#### Executive Summary (Read This First) + +In 3-5 bullets, state the most important findings that determine whether this code can go to production: + +``` +- [CRITICAL/HIGH] One-line summary of the most severe issue +- [CRITICAL/HIGH] Second most severe issue +- [MEDIUM] Notable pattern that will cause future problems +- Overall: Deployable as-is / Needs fixes / Requires major rework +``` #### Critical Issues (Must Fix Before Production) @@ -124,6 +219,11 @@ Location: filename.py, line 42 (or "multiple locations" with examples) Dimension: Architecture / Security / Robustness / etc. Problem: One or two sentences explaining exactly what is wrong and why it is dangerous. Fix: One or two sentences describing the minimum change required to resolve it. +Code Fix (if applicable): +```python +# Before: problematic code +# After: corrected version +``` ``` #### High-Risk Issues @@ -152,23 +252,37 @@ Provide a score using the rubric below, then write 2-3 sentences justifying it w | 71-85 | Production-viable with targeted fixes. Known risks are bounded. | | 86-100 | Production-ready. Minor improvements only. | -Score deductions: +**Scoring Algorithm:** -- Each Critical issue: -10 to -20 points depending on blast radius -- Each High issue: -5 to -10 points -- Pervasive maintainability debt (3+ Medium issues in one dimension): -5 points +``` +Start at 100 points +For each CRITICAL issue: -15 points (security: -20) +For each HIGH issue: -8 points +For each MEDIUM issue: -3 points +For pervasive patterns (3+ similar issues): -5 additional points +Floor: 0, Ceiling: 100 +``` #### Refactoring Priorities List the top 3-5 changes in order of impact. Each item must reference a specific finding from above. ``` -1. [Priority] Fix title — addresses [CRITICAL/HIGH ref] — estimated effort: S/M/L -2. ... +1. [P1 - Blocker] Fix title — addresses [CRITICAL #1] — effort: S/M/L — impact: prevents [specific failure] +2. [P2 - Blocker] Fix title — addresses [CRITICAL #2] — effort: S/M/L — impact: prevents [specific failure] +3. [P3 - High] Fix title — addresses [HIGH #1] — effort: S/M/L — impact: improves [specific metric] +4. [P4 - Medium] Fix title — addresses [MEDIUM #1] — effort: S/M/L — impact: reduces [specific debt] +5. [P5 - Optional] Fix title — addresses [LOW #1] — effort: S/M/L — impact: nice-to-have ``` Effort scale: S = < 1 day, M = 1-3 days, L = > 3 days. +**Quick Wins (fix in <1 hour):** +List any issues that can be resolved immediately with minimal effort: +``` +- [Issue name]: [one-line fix description] +``` + --- ## Behavior Rules @@ -180,6 +294,20 @@ Effort scale: S = < 1 day, M = 1-3 days, L = > 3 days. - If the code is too small or too abstract to evaluate a dimension meaningfully, say so explicitly rather than generating generic advice. - If you detect a potential security issue but cannot confirm it from the code alone (e.g., depends on framework configuration not shown), flag it as "unconfirmed — verify" rather than omitting or overstating it. +**Efficiency Rules:** +- Scan for critical patterns first (security, data loss, crashes) before deeper analysis +- Group similar issues by pattern rather than listing each occurrence separately +- Provide exact code fixes for critical/high issues when the solution is straightforward +- Skip dimensions that are not applicable to the code size or type (state "Not applicable: [reason]") +- Focus on issues that would cause production incidents, not theoretical concerns + +**Calibration:** +- For snippets (<100 lines): Focus on security, robustness, and obvious bugs only +- For single files (100-500 lines): Add architecture and maintainability checks +- For multi-file systems (500+ lines): Full audit across all 7 dimensions +- For production code: Emphasize security, observability, and failure modes +- For prototypes: Emphasize scalability limits and technical debt + --- ## Task-Specific Inputs @@ -189,6 +317,12 @@ Before auditing, if not already provided, ask: 1. **Code or files**: Share the source code to audit. Accepted: single file, multiple files, directory listing, or snippet. 2. **Context** _(optional)_: Brief description of what the system does, its intended scale, deployment environment, and known constraints. 3. **Target environment** _(optional)_: Target runtime (e.g., production web service, CLI tool, data pipeline). Used to calibrate risk severity. +4. **Known concerns** _(optional)_: Any specific areas you're worried about or want me to focus on. + +**If context is missing, assume:** +- Language/framework is evident from the code +- Deployment target is production web service (most common) +- Scale expectations are moderate (100-1000 users) unless code suggests otherwise --- @@ -197,3 +331,5 @@ Before auditing, if not already provided, ask: - **schema-markup**: For adding structured data after code is production-ready. - **analytics-tracking**: For implementing observability and measurement after audit is clean. - **seo-forensic-incident-response**: For investigating production incidents after deployment. +- **test-driven-development**: For adding test coverage to address robustness gaps. +- **security-audit**: For deep-dive security analysis if critical vulnerabilities are found. diff --git a/web-app/refresh-skills-plugin.js b/web-app/refresh-skills-plugin.js index 2afdc2b4..f1aa5f32 100644 --- a/web-app/refresh-skills-plugin.js +++ b/web-app/refresh-skills-plugin.js @@ -7,9 +7,56 @@ import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const ROOT_DIR = path.resolve(__dirname, '..'); -const REPO_ZIP_URL = 'https://github.com/sickn33/antigravity-awesome-skills/archive/refs/heads/main.zip'; -function followRedirects(url, dest) { +const UPSTREAM_REPO = 'https://github.com/sickn33/antigravity-awesome-skills.git'; +const UPSTREAM_NAME = 'upstream'; +const REPO_TAR_URL = 'https://github.com/sickn33/antigravity-awesome-skills/archive/refs/heads/main.tar.gz'; +const REPO_ZIP_URL = 'https://github.com/sickn33/antigravity-awesome-skills/archive/refs/heads/main.zip'; +const COMMITS_API_URL = 'https://api.github.com/repos/sickn33/antigravity-awesome-skills/commits/main'; +const SHA_FILE = path.join(__dirname, '.last-sync-sha'); + +// ─── Utility helpers ─── + +const MIME_TYPES = { + '.html': 'text/html', '.css': 'text/css', '.js': 'application/javascript', + '.json': 'application/json', '.md': 'text/markdown', '.txt': 'text/plain', + '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', + '.gif': 'image/gif', '.svg': 'image/svg+xml', '.ico': 'image/x-icon', + '.yaml': 'text/yaml', '.yml': 'text/yaml', '.xml': 'text/xml', + '.py': 'text/plain', '.sh': 'text/plain', '.bat': 'text/plain', +}; + +/** Check if git is available on this system. Cached after first check. */ +let _gitAvailable = null; +function isGitAvailable() { + if (_gitAvailable !== null) return _gitAvailable; + try { + execSync('git --version', { stdio: 'ignore' }); + // Also check we're inside a git repo + execSync('git rev-parse --git-dir', { cwd: ROOT_DIR, stdio: 'ignore' }); + _gitAvailable = true; + } catch { + _gitAvailable = false; + } + return _gitAvailable; +} + +/** Run a git command in the project root. */ +function git(cmd) { + return execSync(`git ${cmd}`, { cwd: ROOT_DIR, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim(); +} + +/** Ensure the upstream remote exists. */ +function ensureUpstream() { + const remotes = git('remote'); + if (!remotes.split('\n').includes(UPSTREAM_NAME)) { + git(`remote add ${UPSTREAM_NAME} ${UPSTREAM_REPO}`); + console.log(`[Sync] Added upstream remote: ${UPSTREAM_REPO}`); + } +} + +/** Download a file following HTTP redirects. */ +function downloadFile(url, dest) { return new Promise((resolve, reject) => { const file = fs.createWriteStream(dest); const request = (url) => { @@ -24,86 +71,36 @@ function followRedirects(url, dest) { } res.pipe(file); file.on('finish', () => { file.close(); resolve(); }); - }).on('error', (err) => { fs.unlink(dest, () => {}); reject(err); }); + }).on('error', (err) => { fs.unlink(dest, () => { }); reject(err); }); }; request(url); }); } -export default function refreshSkillsPlugin() { - return { - name: 'refresh-skills', - configureServer(server) { - server.middlewares.use('/api/refresh-skills', async (req, res) => { - res.setHeader('Content-Type', 'application/json'); - - const zipPath = path.join(ROOT_DIR, 'update.zip'); - const tempDir = path.join(ROOT_DIR, 'update_temp'); - +/** Check latest commit SHA via GitHub API. */ +function checkRemoteSha() { + return new Promise((resolve) => { + https.get(COMMITS_API_URL, { + headers: { 'User-Agent': 'antigravity-skills-app', 'Accept': 'application/vnd.github.v3+json' }, + }, (res) => { + let body = ''; + res.on('data', (chunk) => { body += chunk; }); + res.on('end', () => { try { - // 1. Download the ZIP - console.log('[Sync] Downloading latest skills from GitHub...'); - await followRedirects(REPO_ZIP_URL, zipPath); - - // 2. Extract with PowerShell (Windows) or unzip (Unix) - console.log('[Sync] Extracting archive...'); - if (fs.existsSync(tempDir)) fs.rmSync(tempDir, { recursive: true, force: true }); - - if (process.platform === 'win32') { - execSync(`powershell -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${tempDir}' -Force"`, { stdio: 'ignore' }); + if (res.statusCode === 200) { + resolve(JSON.parse(body).sha || null); } else { - fs.mkdirSync(tempDir, { recursive: true }); - execSync(`unzip -o "${zipPath}" -d "${tempDir}"`, { stdio: 'ignore' }); + resolve(null); } - - // 3. Copy skills folder + index - const extractedRoot = path.join(tempDir, 'antigravity-awesome-skills-main'); - const srcSkills = path.join(extractedRoot, 'skills'); - const srcIndex = path.join(extractedRoot, 'skills_index.json'); - const destSkills = path.join(ROOT_DIR, 'skills'); - const destIndex = path.join(ROOT_DIR, 'skills_index.json'); - - if (!fs.existsSync(srcSkills)) { - throw new Error('Skills folder not found in downloaded archive.'); - } - - // Replace skills folder - if (fs.existsSync(destSkills)) fs.rmSync(destSkills, { recursive: true, force: true }); - copyFolderSync(srcSkills, destSkills); - - // Replace index - if (fs.existsSync(srcIndex)) fs.copyFileSync(srcIndex, destIndex); - - // 4. Re-run setup_web.js logic to update web-app/public - const webPublic = path.join(__dirname, 'public'); - const webSkills = path.join(webPublic, 'skills'); - const webIndex = path.join(webPublic, 'skills.json'); - - if (fs.existsSync(webSkills)) fs.rmSync(webSkills, { recursive: true, force: true }); - copyFolderSync(destSkills, webSkills); - if (fs.existsSync(destIndex)) fs.copyFileSync(destIndex, webIndex); - - // Count skills - const skillsData = JSON.parse(fs.readFileSync(webIndex, 'utf-8')); - const count = Array.isArray(skillsData) ? skillsData.length : 0; - - console.log(`[Sync] ✅ Successfully synced ${count} skills!`); - res.end(JSON.stringify({ success: true, count })); - - } catch (err) { - console.error('[Sync] ❌ Failed:', err.message); - res.statusCode = 500; - res.end(JSON.stringify({ success: false, error: err.message })); - } finally { - // Cleanup - if (fs.existsSync(zipPath)) fs.unlinkSync(zipPath); - if (fs.existsSync(tempDir)) fs.rmSync(tempDir, { recursive: true, force: true }); + } catch { + resolve(null); } }); - } - }; + }).on('error', () => resolve(null)); + }); } +/** Copy folder recursively. */ function copyFolderSync(from, to) { if (!fs.existsSync(to)) fs.mkdirSync(to, { recursive: true }); for (const element of fs.readdirSync(from)) { @@ -116,3 +113,186 @@ function copyFolderSync(from, to) { } } } + +// ─── Sync strategies ─── + +/** + * FAST PATH: Use git fetch + merge (only downloads delta). + * Typically completes in 5-15 seconds. + */ +async function syncWithGit() { + ensureUpstream(); + + const headBefore = git('rev-parse HEAD'); + + console.log('[Sync] Fetching from upstream (git)...'); + git(`fetch ${UPSTREAM_NAME} main`); + + const upstreamHead = git(`rev-parse ${UPSTREAM_NAME}/main`); + + if (headBefore === upstreamHead) { + return { upToDate: true }; + } + + console.log('[Sync] Merging updates...'); + try { + git(`merge ${UPSTREAM_NAME}/main --ff-only`); + } catch { + console.log('[Sync] Fast-forward failed, resetting to upstream...'); + git(`reset --hard ${UPSTREAM_NAME}/main`); + } + + return { upToDate: false }; +} + +/** + * FALLBACK: Download archive when git is not available. + * Tries tar.gz first (faster), falls back to zip if tar isn't available. + */ +async function syncWithArchive() { + // Check SHA first to skip if up to date + const remoteSha = await checkRemoteSha(); + if (remoteSha) { + let storedSha = null; + if (fs.existsSync(SHA_FILE)) { + storedSha = fs.readFileSync(SHA_FILE, 'utf-8').trim(); + } + if (storedSha === remoteSha) { + return { upToDate: true }; + } + } + + const tempDir = path.join(ROOT_DIR, 'update_temp'); + + // Try tar first, fall back to zip + let useTar = true; + try { + execSync('tar --version', { stdio: 'ignore' }); + } catch { + useTar = false; + } + + const archivePath = path.join(ROOT_DIR, useTar ? 'update.tar.gz' : 'update.zip'); + + try { + // 1. Download + console.log(`[Sync] Downloading (${useTar ? 'tar.gz' : 'zip'})...`); + await downloadFile(useTar ? REPO_TAR_URL : REPO_ZIP_URL, archivePath); + + // 2. Extract + console.log('[Sync] Extracting...'); + if (fs.existsSync(tempDir)) fs.rmSync(tempDir, { recursive: true, force: true }); + fs.mkdirSync(tempDir, { recursive: true }); + + if (useTar) { + execSync(`tar -xzf "${archivePath}" -C "${tempDir}"`, { stdio: 'ignore' }); + } else if (process.platform === 'win32') { + execSync(`powershell -Command "Expand-Archive -Path '${archivePath}' -DestinationPath '${tempDir}' -Force"`, { stdio: 'ignore' }); + } else { + execSync(`unzip -o "${archivePath}" -d "${tempDir}"`, { stdio: 'ignore' }); + } + + // 3. Move skills to root + const extractedRoot = path.join(tempDir, 'antigravity-awesome-skills-main'); + const srcSkills = path.join(extractedRoot, 'skills'); + const srcIndex = path.join(extractedRoot, 'skills_index.json'); + const destSkills = path.join(ROOT_DIR, 'skills'); + const destIndex = path.join(ROOT_DIR, 'skills_index.json'); + + if (!fs.existsSync(srcSkills)) { + throw new Error('Skills folder not found in downloaded archive.'); + } + + console.log('[Sync] Updating skills...'); + if (fs.existsSync(destSkills)) fs.rmSync(destSkills, { recursive: true, force: true }); + fs.renameSync(srcSkills, destSkills); + if (fs.existsSync(srcIndex)) fs.copyFileSync(srcIndex, destIndex); + + // Save SHA + if (remoteSha) fs.writeFileSync(SHA_FILE, remoteSha, 'utf-8'); + + return { upToDate: false }; + + } finally { + if (fs.existsSync(archivePath)) fs.unlinkSync(archivePath); + if (fs.existsSync(tempDir)) fs.rmSync(tempDir, { recursive: true, force: true }); + } +} + +// ─── Vite Plugin ─── + +export default function refreshSkillsPlugin() { + return { + name: 'refresh-skills', + configureServer(server) { + // Serve /skills.json directly from ROOT_DIR + server.middlewares.use('/skills.json', (req, res, next) => { + const filePath = path.join(ROOT_DIR, 'skills_index.json'); + if (fs.existsSync(filePath)) { + res.setHeader('Content-Type', 'application/json'); + fs.createReadStream(filePath).pipe(res); + } else { + next(); + } + }); + + // Serve /skills/* directly from ROOT_DIR/skills/ + server.middlewares.use((req, res, next) => { + if (!req.url || !req.url.startsWith('/skills/')) return next(); + + const relativePath = decodeURIComponent(req.url.replace(/\?.*$/, '')); + const filePath = path.join(ROOT_DIR, relativePath); + + const resolved = path.resolve(filePath); + if (!resolved.startsWith(path.join(ROOT_DIR, 'skills'))) return next(); + + if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) { + const ext = path.extname(filePath).toLowerCase(); + res.setHeader('Content-Type', MIME_TYPES[ext] || 'application/octet-stream'); + fs.createReadStream(filePath).pipe(res); + } else { + next(); + } + }); + + // Sync API endpoint + server.middlewares.use('/api/refresh-skills', async (req, res) => { + res.setHeader('Content-Type', 'application/json'); + + try { + let result; + + if (isGitAvailable()) { + console.log('[Sync] Using git (fast path)...'); + result = await syncWithGit(); + } else { + console.log('[Sync] Git not available, using archive download (slower)...'); + result = await syncWithArchive(); + } + + if (result.upToDate) { + console.log('[Sync] ✅ Already up to date!'); + res.end(JSON.stringify({ success: true, upToDate: true })); + return; + } + + // Count skills + const indexPath = path.join(ROOT_DIR, 'skills_index.json'); + let count = 0; + if (fs.existsSync(indexPath)) { + const data = JSON.parse(fs.readFileSync(indexPath, 'utf-8')); + count = Array.isArray(data) ? data.length : 0; + } + + console.log(`[Sync] ✅ Successfully synced ${count} skills!`); + res.end(JSON.stringify({ success: true, upToDate: false, count })); + + } catch (err) { + console.error('[Sync] ❌ Failed:', err.message); + res.statusCode = 500; + res.end(JSON.stringify({ success: false, error: err.message })); + } + }); + } + }; +} diff --git a/web-app/src/pages/Home.jsx b/web-app/src/pages/Home.jsx index 1d9dc10f..1b8ed1df 100644 --- a/web-app/src/pages/Home.jsx +++ b/web-app/src/pages/Home.jsx @@ -130,7 +130,9 @@ export function Home() {
{syncMsg && ( {syncMsg.text} @@ -144,12 +146,16 @@ export function Home() { const res = await fetch('/api/refresh-skills'); const data = await res.json(); if (data.success) { - setSyncMsg({ type: 'success', text: `✅ Synced ${data.count} skills!` }); - // Reload skills data - const freshRes = await fetch('/skills.json'); - const freshData = await freshRes.json(); - setSkills(freshData); - setFilteredSkills(freshData); + if (data.upToDate) { + setSyncMsg({ type: 'info', text: 'ℹ️ Skills are already up to date!' }); + } else { + setSyncMsg({ type: 'success', text: `✅ Synced ${data.count} skills!` }); + // Reload skills data only when there are actual updates + const freshRes = await fetch('/skills.json'); + const freshData = await freshRes.json(); + setSkills(freshData); + setFilteredSkills(freshData); + } } else { setSyncMsg({ type: 'error', text: `❌ ${data.error}` }); } From dd73c5d98f5f6551ecd6fa99470a64901e1d6280 Mon Sep 17 00:00:00 2001 From: Zied Date: Tue, 3 Mar 2026 09:45:08 +0100 Subject: [PATCH 2/2] feat: implement initial Home page with skill listing, search, filter, sort, star functionality, and sync capabilities. --- web-app/src/pages/Home.jsx | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/web-app/src/pages/Home.jsx b/web-app/src/pages/Home.jsx index 1b8ed1df..935e79d1 100644 --- a/web-app/src/pages/Home.jsx +++ b/web-app/src/pages/Home.jsx @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; -import { Search, Filter, Book, AlertCircle, ArrowRight, Star, RefreshCw } from 'lucide-react'; +import { Search, Filter, Book, AlertCircle, ArrowRight, Star, RefreshCw, ArrowUpDown } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; import { supabase } from '../lib/supabase'; @@ -11,6 +11,7 @@ export function Home() { const [categoryFilter, setCategoryFilter] = useState('all'); const [loading, setLoading] = useState(true); const [stars, setStars] = useState({}); + const [sortBy, setSortBy] = useState('default'); const [syncing, setSyncing] = useState(false); const [syncMsg, setSyncMsg] = useState(null); @@ -105,8 +106,17 @@ export function Home() { result = result.filter(skill => skill.category === categoryFilter); } + // Apply sorting + if (sortBy === 'stars') { + result = [...result].sort((a, b) => (stars[b.id] || 0) - (stars[a.id] || 0)); + } else if (sortBy === 'newest') { + result = [...result].sort((a, b) => (b.date_added || '').localeCompare(a.date_added || '')); + } else if (sortBy === 'az') { + result = [...result].sort((a, b) => a.name.localeCompare(b.name)); + } + setFilteredSkills(result); - }, [search, categoryFilter, skills]); + }, [search, categoryFilter, sortBy, skills, stars]); // Sort categories by count (most skills first), with 'uncategorized' at the end const categoryStats = {}; @@ -202,6 +212,17 @@ export function Home() { ))} + +