devskill 2.0.5 → 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.
@@ -76,10 +76,10 @@ export default function LandingPage() {
76
76
  <h1 className="text-6xl md:text-8xl font-extrabold mb-8 tracking-tight bg-clip-text text-transparent bg-gradient-to-br from-white via-zinc-200 to-zinc-500 pb-2">
77
77
  {t('title')}
78
78
  </h1>
79
- <p className="text-xl md:text-2xl text-zinc-300 max-w-3xl mx-auto mb-12 leading-relaxed text-balance font-light">
79
+ <p className="text-xl md:text-2xl text-zinc-300 max-w-5xl mx-auto mb-12 leading-relaxed text-balance font-light">
80
80
  {t('subtitle')}
81
81
  </p>
82
- <p className="text-lg text-zinc-400 max-w-2xl mx-auto mb-12 leading-relaxed text-balance">
82
+ <p className="text-lg text-zinc-400 max-w-4xl mx-auto mb-12 leading-relaxed text-balance">
83
83
  {h('description')}
84
84
  </p>
85
85
  <div className="flex flex-col sm:flex-row items-center justify-center gap-4 w-full max-w-md mx-auto sm:max-w-none">
@@ -270,6 +270,72 @@ export default function LandingPage() {
270
270
  </Card>
271
271
  </div>
272
272
  </section>
273
+
274
+ {/* Architecture Section */}
275
+ <section id="architecture" className="container mx-auto px-4 mb-40 relative z-10">
276
+ <div className="text-center mb-16">
277
+ <h2 className="text-4xl md:text-5xl font-extrabold mb-6 tracking-tight text-white">{t('architecture_title')}</h2>
278
+ <div className="w-24 h-1.5 bg-gradient-to-r from-cyan-400 to-rose-500 mx-auto rounded-full mb-6" />
279
+ <p className="text-xl text-zinc-400 max-w-3xl mx-auto leading-relaxed">{t('architecture_desc')}</p>
280
+ </div>
281
+
282
+ <div className="grid md:grid-cols-2 gap-8 max-w-5xl mx-auto">
283
+ <Card className="bg-zinc-900/60 border-cyan-400/20 backdrop-blur-xl hover:bg-zinc-900/80 hover:border-cyan-400/50 hover:-translate-y-2 hover:shadow-2xl hover:shadow-cyan-400/20 transition-all duration-300 group overflow-hidden relative">
284
+ <div className="absolute top-0 right-0 p-32 bg-cyan-400/5 rounded-full blur-[80px] -mr-16 -mt-16 transition-opacity opacity-0 group-hover:opacity-100" />
285
+ <CardHeader className="relative z-10">
286
+ <div className="w-14 h-14 rounded-2xl bg-cyan-400/10 flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-500 border border-cyan-400/20">
287
+ <Database className="w-7 h-7 text-cyan-400" />
288
+ </div>
289
+ <CardTitle className="text-2xl text-white font-bold tracking-tight">{t('sources_title')}</CardTitle>
290
+ </CardHeader>
291
+ <CardContent className="relative z-10">
292
+ <p className="text-zinc-300 leading-relaxed text-base">{t('sources_desc')}</p>
293
+ </CardContent>
294
+ </Card>
295
+
296
+ <Card className="bg-zinc-900/60 border-rose-500/20 backdrop-blur-xl hover:bg-zinc-900/80 hover:border-rose-500/50 hover:-translate-y-2 hover:shadow-2xl hover:shadow-rose-500/20 transition-all duration-300 group overflow-hidden relative">
297
+ <div className="absolute top-0 right-0 p-32 bg-rose-500/5 rounded-full blur-[80px] -mr-16 -mt-16 transition-opacity opacity-0 group-hover:opacity-100" />
298
+ <CardHeader className="relative z-10">
299
+ <div className="w-14 h-14 rounded-2xl bg-rose-500/10 flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-500 border border-rose-500/20">
300
+ <Boxes className="w-7 h-7 text-rose-500" />
301
+ </div>
302
+ <CardTitle className="text-2xl text-white font-bold tracking-tight">{t('vendor_title')}</CardTitle>
303
+ </CardHeader>
304
+ <CardContent className="relative z-10">
305
+ <p className="text-zinc-300 leading-relaxed text-base">{t('vendor_desc')}</p>
306
+ </CardContent>
307
+ </Card>
308
+ </div>
309
+ </section>
310
+
311
+ {/* Contribute Section */}
312
+ <section id="contribute" className="container mx-auto px-4 mb-40 text-center relative z-10">
313
+ <div className="max-w-4xl mx-auto bg-gradient-to-br from-zinc-900/80 to-zinc-950 border border-white/10 p-10 md:p-14 rounded-3xl shadow-2xl relative overflow-hidden group">
314
+ <div className="absolute top-0 right-0 p-32 bg-rose-500/10 rounded-full blur-[100px] -mr-16 -mt-16 pointer-events-none" />
315
+ <div className="absolute bottom-0 left-0 p-32 bg-cyan-400/10 rounded-full blur-[100px] -ml-16 -mb-16 pointer-events-none" />
316
+
317
+ <h2 className="text-3xl md:text-5xl font-extrabold mb-6 tracking-tight text-white">{t('contribute_title')}</h2>
318
+ <p className="text-lg md:text-xl text-zinc-300 max-w-3xl mx-auto mb-10 leading-relaxed font-light">
319
+ {t('contribute_desc')}
320
+ </p>
321
+ <div className="flex flex-col sm:flex-row items-center justify-center gap-4">
322
+ <a
323
+ href="https://github.com/vuluu2k/skills/issues"
324
+ target="_blank"
325
+ className="px-8 py-4 rounded-xl font-bold bg-white text-zinc-950 hover:bg-zinc-200 transition-colors shadow-lg shadow-white/10"
326
+ >
327
+ {t('contribute_cta_issue')}
328
+ </a>
329
+ <a
330
+ href="https://github.com/vuluu2k/skills"
331
+ target="_blank"
332
+ className="px-8 py-4 rounded-xl font-bold bg-zinc-800 text-white hover:bg-zinc-700 border border-white/10 transition-colors"
333
+ >
334
+ {t('contribute_cta_build')}
335
+ </a>
336
+ </div>
337
+ </div>
338
+ </section>
273
339
  </main>
274
340
 
275
341
  <footer className="border-t border-white/10 py-12 bg-zinc-950/80 backdrop-blur-sm">
@@ -5,9 +5,19 @@
5
5
  "problem": "The Problem",
6
6
  "solution": "The Solution",
7
7
  "why_devskill": "The power of devskill",
8
- "installation": "Simple Installation",
8
+ "installation": "Installation & Quick Start",
9
9
  "collections": "Skill Collections",
10
- "footer": "Built with ❤️ by vuluu2k. License: MIT"
10
+ "footer": "© 2026 devskill. Empower your AI assistants.",
11
+ "contribute_title": "Build & Contribute",
12
+ "contribute_desc": "Does your team have unique coding standards? You can easily build a completely customized AI brain! If you have any awesome frameworks or best-practices you'd like to share, create an Issue on GitHub so we can add it to devskill.",
13
+ "contribute_cta_issue": "💡 Suggest a Skill",
14
+ "contribute_cta_build": "🛠️ Build Your Own",
15
+ "architecture_title": "Smart Directory Architecture",
16
+ "architecture_desc": "More than just a CLI, devskill provides a clearly stratified Knowledge Base management pipeline.",
17
+ "sources_title": "The Root (sources/)",
18
+ "sources_desc": "The raw data layer. Stores official documentation, template repos, and guidelines (often tracked as git submodules). AI reads this to generate your SKILL.md rules.",
19
+ "vendor_title": "Submodules (vendor/)",
20
+ "vendor_desc": "Your external dependency layer. Automatically syncs community or third-party high-quality skills into your project. Keep them fresh with a single 'npm start sync'."
11
21
  },
12
22
  "Hero": {
13
23
  "badge": "🚀 NEW: devskill v2.0",
@@ -5,9 +5,19 @@
5
5
  "problem": "Vấn đề",
6
6
  "solution": "Giải pháp",
7
7
  "why_devskill": "Sức mạnh thực sự của devskill",
8
- "installation": "Cài đặt đơn giản",
9
- "collections": "Thư viện kỹ năng (Collections)",
10
- "footer": "Thiết kế với ❤️ bởi vuluu2k. Giấy phép: MIT"
8
+ "installation": "Cài đặt & Trải nghiệm",
9
+ "collections": "Bộ sưu tập Skills",
10
+ "footer": "© 2026 devskill. Xây dựng bộ não mạnh mẽ nhất cho AI của bạn.",
11
+ "contribute_title": "Tự Xây Dựng & Đóng Góp",
12
+ "contribute_desc": "Đội ngũ của bạn có quy chuẩn code riêng? Đừng lo, bạn có thể tự build bộ não AI chuyên biệt cho team! Nếu bạn biết một framework hay best-practices nào đỉnh cao, hãy tạo Issue trên GitHub để mình thêm vào devskill nhé.",
13
+ "contribute_cta_issue": "💡 Gợi ý Skills (Tạo Issue)",
14
+ "contribute_cta_build": "🛠️ Tự Build Skills",
15
+ "architecture_title": "Cấu trúc Thư mục Thông minh",
16
+ "architecture_desc": "Không chỉ là một CLI, devskill cung cấp vòng đời quản lý tri thức (Knowledge Base) phân tầng rõ rệt.",
17
+ "sources_title": "Nguồn gốc (sources/)",
18
+ "sources_desc": "Nơi chứa tài liệu gốc, mã nguồn mẫu, official documentation (thường track dưới dạng git submodules). AI sẽ đọc và đọc hiểu tự động để trích xuất các quy chuẩn ra file SKILL.md.",
19
+ "vendor_title": "Cộng đồng (vendor/)",
20
+ "vendor_desc": "Kho lưu trữ các skill chất lượng cao được chia sẻ từ cộng đồng hoặc tổ chức khác. Chỉ cần 1 lệnh 'npm start sync' để cập nhật liên tục mọi thay đổi về máy!"
11
21
  },
12
22
  "Hero": {
13
23
  "badge": "🚀 MỚI: devskill v2.0",
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,6 @@
1
1
  {
2
2
  "name": "devskill",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
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
5
  "homepage": "https://vskill.vercel.app",
6
6
  "repository": {
@@ -18,10 +18,14 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@clack/prompts": "^1.1.0",
21
+ "@inquirer/prompts": "^8.3.2",
22
+ "enquirer": "^2.4.1",
23
+ "prompts": "^2.4.2",
21
24
  "tsx": "^4.0.0"
22
25
  },
23
26
  "devDependencies": {
24
27
  "@types/node": "^20.0.0",
28
+ "@types/prompts": "^2.4.9",
25
29
  "typescript": "^5.5.0"
26
30
  }
27
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