devskill 2.0.4 → 2.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.
Files changed (38) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +4 -1
  4. package/landing/AGENTS.md +5 -0
  5. package/landing/CLAUDE.md +1 -0
  6. package/landing/README.md +36 -0
  7. package/landing/app/[locale]/layout.tsx +58 -0
  8. package/landing/app/[locale]/page.tsx +357 -0
  9. package/landing/app/globals.css +129 -0
  10. package/landing/app/icon.tsx +41 -0
  11. package/landing/app/opengraph-image.tsx +69 -0
  12. package/landing/components/ui/accordion.tsx +74 -0
  13. package/landing/components/ui/badge.tsx +52 -0
  14. package/landing/components/ui/button.tsx +60 -0
  15. package/landing/components/ui/card.tsx +103 -0
  16. package/landing/components/ui/copy-button.tsx +60 -0
  17. package/landing/components/ui/navigation-menu.tsx +168 -0
  18. package/landing/components.json +25 -0
  19. package/landing/eslint.config.mjs +18 -0
  20. package/landing/i18n/request.ts +17 -0
  21. package/landing/i18n/routing.ts +17 -0
  22. package/landing/lib/utils.ts +6 -0
  23. package/landing/messages/en.json +42 -0
  24. package/landing/messages/vi.json +42 -0
  25. package/landing/middleware.ts +9 -0
  26. package/landing/next.config.ts +10 -0
  27. package/landing/package-lock.json +10540 -0
  28. package/landing/package.json +35 -0
  29. package/landing/postcss.config.mjs +7 -0
  30. package/landing/public/file.svg +1 -0
  31. package/landing/public/globe.svg +1 -0
  32. package/landing/public/next.svg +1 -0
  33. package/landing/public/vercel.svg +1 -0
  34. package/landing/public/window.svg +1 -0
  35. package/landing/tsconfig.json +34 -0
  36. package/meta.ts +9 -0
  37. package/package.json +11 -1
  38. package/scripts/cli.ts +121 -37
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "landing",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "eslint"
10
+ },
11
+ "dependencies": {
12
+ "@base-ui/react": "^1.3.0",
13
+ "class-variance-authority": "^0.7.1",
14
+ "clsx": "^2.1.1",
15
+ "framer-motion": "^12.38.0",
16
+ "lucide-react": "^1.0.1",
17
+ "next": "^16.2.1",
18
+ "next-intl": "^4.8.3",
19
+ "react": "^19.2.4",
20
+ "react-dom": "^19.2.4",
21
+ "shadcn": "^4.1.0",
22
+ "tailwind-merge": "^3.5.0",
23
+ "tw-animate-css": "^1.4.0"
24
+ },
25
+ "devDependencies": {
26
+ "@tailwindcss/postcss": "^4.2.2",
27
+ "@types/node": "^20",
28
+ "@types/react": "^19",
29
+ "@types/react-dom": "^19",
30
+ "eslint": "^9",
31
+ "eslint-config-next": "16.2.1",
32
+ "tailwindcss": "^4.2.2",
33
+ "typescript": "^5"
34
+ }
35
+ }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1 @@
1
+ <svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./*"]
23
+ }
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ "**/*.ts",
28
+ "**/*.tsx",
29
+ ".next/types/**/*.ts",
30
+ ".next/dev/types/**/*.ts",
31
+ "**/*.mts"
32
+ ],
33
+ "exclude": ["node_modules"]
34
+ }
package/meta.ts CHANGED
@@ -80,6 +80,15 @@ export const vendors: Record<string, VendorSkillMeta> = {
80
80
  turborepo: 'turborepo',
81
81
  },
82
82
  },
83
+ 'next-skills': {
84
+ official: true,
85
+ source: 'https://github.com/vercel-labs/next-skills',
86
+ skills: {
87
+ 'next-best-practices': 'next-best-practices',
88
+ 'next-cache-components': 'next-cache-components',
89
+ 'next-upgrade': 'next-upgrade',
90
+ },
91
+ }
83
92
  }
84
93
 
85
94
  export const manual = [
package/package.json CHANGED
@@ -1,6 +1,12 @@
1
1
  {
2
2
  "name": "devskill",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
+ "description": "Equip Cursor, Windsurf, Cline, Antigravity, Claude Code, Codex, GitHub Copilot and other AI Agents with expert programming superpowers via a single interactive prompt.",
5
+ "homepage": "https://vskill.vercel.app",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/vuluu2k/skills.git"
9
+ },
4
10
  "type": "module",
5
11
  "bin": {
6
12
  "devskill": "bin/devskill.js"
@@ -12,10 +18,14 @@
12
18
  },
13
19
  "dependencies": {
14
20
  "@clack/prompts": "^1.1.0",
21
+ "@inquirer/prompts": "^8.3.2",
22
+ "enquirer": "^2.4.1",
23
+ "prompts": "^2.4.2",
15
24
  "tsx": "^4.0.0"
16
25
  },
17
26
  "devDependencies": {
18
27
  "@types/node": "^20.0.0",
28
+ "@types/prompts": "^2.4.9",
19
29
  "typescript": "^5.5.0"
20
30
  }
21
31
  }
package/scripts/cli.ts CHANGED
@@ -4,6 +4,7 @@ import { dirname, join } from 'node:path'
4
4
  import process from 'node:process'
5
5
  import { fileURLToPath } from 'node:url'
6
6
  import * as p from '@clack/prompts'
7
+ import prompts from 'prompts'
7
8
  import { collections, manual, submodules, vendors } from '../meta.ts'
8
9
 
9
10
  const __dirname = dirname(fileURLToPath(import.meta.url))
@@ -364,7 +365,7 @@ async function cleanup(skipPrompt = false) {
364
365
  }
365
366
  }
366
367
 
367
- async function installSkills() {
368
+ async function installSkills(targetCollectionNames: string[] = []) {
368
369
  const spinner = p.spinner()
369
370
 
370
371
  const allCollections: Record<string, string[]> = { ...collections }
@@ -378,23 +379,33 @@ async function installSkills() {
378
379
  return
379
380
  }
380
381
 
381
- const selectedCollectionNames = await p.multiselect({
382
- message: 'Select collections to install (Space to select, Enter to confirm)',
383
- options: Object.keys(allCollections).map(name => ({
384
- value: name,
385
- label: name,
386
- hint: `${allCollections[name].length} skills`
387
- }))
388
- })
382
+ let selectedCollectionNames: string[] = []
389
383
 
390
- if (p.isCancel(selectedCollectionNames)) {
391
- p.cancel('Cancelled')
392
- return
393
- }
384
+ if (targetCollectionNames.length > 0) {
385
+ const invalid = targetCollectionNames.filter(name => !allCollections[name])
386
+ if (invalid.length > 0) {
387
+ p.log.error(`Collections not found: ${invalid.join(', ')}`)
388
+ return
389
+ }
390
+ selectedCollectionNames = targetCollectionNames
391
+ } else {
392
+ const response = await prompts({
393
+ type: 'autocompleteMultiselect',
394
+ name: 'selected',
395
+ message: 'Search and select collections to install (Space to select, Enter to confirm)',
396
+ choices: Object.keys(allCollections).map(name => ({
397
+ title: name,
398
+ value: name,
399
+ description: `${allCollections[name].length} skills`
400
+ }))
401
+ })
394
402
 
395
- if (selectedCollectionNames.length === 0) {
396
- p.log.warn('No collections selected')
397
- return
403
+ if (!response.selected || response.selected.length === 0) {
404
+ p.log.warn('No collections selected (or canceled)')
405
+ return
406
+ }
407
+
408
+ selectedCollectionNames = response.selected
398
409
  }
399
410
 
400
411
  const targetProject = await p.text({
@@ -492,7 +503,7 @@ async function installSkills() {
492
503
  spinner.stop(`Installed ${successCount}/${selectedSkills.length} skills to target project`)
493
504
  }
494
505
 
495
- async function installSpecificSkills() {
506
+ async function installSpecificSkills(targetSkillNames: string[] = []) {
496
507
  const spinner = p.spinner()
497
508
 
498
509
  const allSkills = getExistingSkillNames()
@@ -502,22 +513,32 @@ async function installSpecificSkills() {
502
513
  return
503
514
  }
504
515
 
505
- const selectedSkills = await p.multiselect({
506
- message: 'Select specific skills to install (Space to select, Enter to confirm)',
507
- options: allSkills.map(name => ({
508
- value: name,
509
- label: name
510
- }))
511
- })
516
+ let selectedSkills: string[] = []
512
517
 
513
- if (p.isCancel(selectedSkills)) {
514
- p.cancel('Cancelled')
515
- return
516
- }
518
+ if (targetSkillNames.length > 0) {
519
+ const invalid = targetSkillNames.filter(name => !allSkills.includes(name))
520
+ if (invalid.length > 0) {
521
+ p.log.error(`Skills not found: ${invalid.join(', ')}`)
522
+ return
523
+ }
524
+ selectedSkills = targetSkillNames
525
+ } else {
526
+ const response = await prompts({
527
+ type: 'autocompleteMultiselect',
528
+ name: 'selected',
529
+ message: 'Search and select individual skills to install (Space to select, Enter to confirm)',
530
+ choices: allSkills.map(name => ({
531
+ title: name,
532
+ value: name
533
+ }))
534
+ })
517
535
 
518
- if (selectedSkills.length === 0) {
519
- p.log.warn('No skills selected')
520
- return
536
+ if (!response.selected || response.selected.length === 0) {
537
+ p.log.warn('No skills selected (or canceled)')
538
+ return
539
+ }
540
+
541
+ selectedSkills = response.selected
521
542
  }
522
543
 
523
544
  const targetProject = await p.text({
@@ -612,10 +633,67 @@ async function installSpecificSkills() {
612
633
  spinner.stop(`Installed ${successCount}/${selectedSkills.length} skills to target project`)
613
634
  }
614
635
 
636
+ async function findSkills(query?: string) {
637
+ const allSkills = getExistingSkillNames()
638
+ p.intro(`Search results for ${query ? `"${query}"` : 'all'}`)
639
+
640
+ const allCollections: Record<string, string[]> = { ...collections }
641
+ for (const [vendorName, config] of Object.entries(vendors)) {
642
+ const vendorConfig = config as VendorConfig
643
+ allCollections[vendorName] = Object.values(vendorConfig.skills)
644
+ }
645
+
646
+ let q = ''
647
+ if (!query) {
648
+ const userInput = await p.text({
649
+ message: 'Enter keyword to search (leave empty to list all):',
650
+ placeholder: 'e.g. vue'
651
+ })
652
+
653
+ if (p.isCancel(userInput)) {
654
+ p.cancel('Cancelled')
655
+ return
656
+ }
657
+ q = (userInput as string).toLowerCase()
658
+ } else {
659
+ q = query.toLowerCase()
660
+ }
661
+
662
+ const matchedCollections = Object.keys(allCollections).filter(c => c.toLowerCase().includes(q))
663
+ if (matchedCollections.length > 0) {
664
+ p.log.success('📚 Collections found:')
665
+ for (const c of matchedCollections) {
666
+ p.log.message(` - ${c} (${allCollections[c].length} skills) -> \`npx devskill install ${c}\``)
667
+ }
668
+ } else if (q) {
669
+ p.log.warn('No collections found matching query')
670
+ }
671
+
672
+ const matchedSkills = allSkills.filter(s => s.toLowerCase().includes(q))
673
+ if (matchedSkills.length > 0) {
674
+ p.log.success('🛠️ Individual Skills found:')
675
+ for (const s of matchedSkills) {
676
+ p.log.message(` - ${s} -> \`npx devskill add ${s}\``)
677
+ }
678
+ } else if (q) {
679
+ p.log.warn('No individual skills found matching query')
680
+ }
681
+ }
682
+
615
683
  async function main() {
616
684
  const args = process.argv.slice(2)
617
685
  const skipPrompt = args.includes('-y') || args.includes('--yes')
618
- const command = args.find(arg => !arg.startsWith('-'))
686
+
687
+ const positionalArgs = args.filter(arg => !arg.startsWith('-'))
688
+ const command = positionalArgs[0]
689
+ const targetNames = positionalArgs.slice(1)
690
+ const targetName = targetNames[0] // for finding
691
+
692
+ if (command === 'find') {
693
+ await findSkills(targetName)
694
+ p.outro('Done')
695
+ return
696
+ }
619
697
 
620
698
  if (command === 'init') {
621
699
  p.intro('Skills Manager - Init')
@@ -646,22 +724,24 @@ async function main() {
646
724
  }
647
725
 
648
726
  if (command === 'install') {
649
- p.intro('Skills Manager - Install Groups')
650
- await installSkills()
727
+ const namesJoined = targetNames.length > 0 ? ` (${targetNames.join(', ')})` : ''
728
+ p.intro(`Skills Manager - Install Groups${namesJoined}`)
729
+ await installSkills(targetNames)
651
730
  p.outro('Done')
652
731
  return
653
732
  }
654
733
 
655
734
  if (command === 'add') {
656
- p.intro('Skills Manager - Add Specific Skills')
657
- await installSpecificSkills()
735
+ const namesJoined = targetNames.length > 0 ? ` (${targetNames.join(', ')})` : ''
736
+ p.intro(`Skills Manager - Add Specific Skills${namesJoined}`)
737
+ await installSpecificSkills(targetNames)
658
738
  p.outro('Done')
659
739
  return
660
740
  }
661
741
 
662
742
  if (skipPrompt) {
663
743
  p.log.error('Command required when using -y flag')
664
- p.log.info('Available commands: install, add, init, sync, check, cleanup')
744
+ p.log.info('Available commands: find, install, add, init, sync, check, cleanup')
665
745
  process.exit(1)
666
746
  }
667
747
 
@@ -672,6 +752,7 @@ async function main() {
672
752
  options: [
673
753
  { value: 'install', label: 'Install collections', hint: 'Copy entire skill collections to a local project' },
674
754
  { value: 'add', label: 'Add specific skills', hint: 'Choose individual skills to add to your project' },
755
+ { value: 'find', label: 'Find a skill or collection', hint: 'Search by keyword' },
675
756
  { value: 'sync', label: 'Sync submodules', hint: 'Pull latest and sync Type 2 skills' },
676
757
  { value: 'init', label: 'Init submodules', hint: 'Add new submodules from meta.ts' },
677
758
  { value: 'check', label: 'Check updates', hint: 'See available updates' },
@@ -691,6 +772,9 @@ async function main() {
691
772
  case 'add':
692
773
  await installSpecificSkills()
693
774
  break
775
+ case 'find':
776
+ await findSkills()
777
+ break
694
778
  case 'init':
695
779
  await initSubmodules()
696
780
  break