neo-skill 0.1.21 → 0.1.23

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.
@@ -0,0 +1,4 @@
1
+ [
2
+ "gh:aider-chat/aider",
3
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill"
4
+ ]
@@ -0,0 +1,6 @@
1
+ [
2
+ "gh:aider-chat/aider#code-edit",
3
+ "gh:aider-chat/aider#git-commit",
4
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
5
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
6
+ ]
@@ -0,0 +1,68 @@
1
+ {
2
+ "antigravity": [
3
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
4
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
5
+ ],
6
+ "claude": [
7
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
8
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
9
+ ],
10
+ "codebuddy": [
11
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
12
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
13
+ ],
14
+ "codex": [
15
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
16
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
17
+ ],
18
+ "continue": [
19
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
20
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
21
+ ],
22
+ "copilot": [
23
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
24
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
25
+ ],
26
+ "cursor": [
27
+ "gh:aider-chat/aider#code-edit",
28
+ "gh:aider-chat/aider#git-commit",
29
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
30
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
31
+ ],
32
+ "gemini": [
33
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
34
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
35
+ ],
36
+ "generic": [
37
+ "gh:aider-chat/aider#code-edit",
38
+ "gh:aider-chat/aider#git-commit",
39
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
40
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
41
+ ],
42
+ "kiro": [
43
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
44
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
45
+ ],
46
+ "opencode": [
47
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
48
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
49
+ ],
50
+ "qoder": [
51
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
52
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
53
+ ],
54
+ "roocode": [
55
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
56
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
57
+ ],
58
+ "trae": [
59
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
60
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
61
+ ],
62
+ "windsurf": [
63
+ "gh:aider-chat/aider#code-edit",
64
+ "gh:aider-chat/aider#git-commit",
65
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
66
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
67
+ ]
68
+ }
@@ -0,0 +1,96 @@
1
+ {
2
+ "ai coding": [
3
+ "gh:aider-chat/aider#code-edit"
4
+ ],
5
+ "aider": [
6
+ "gh:aider-chat/aider#code-edit",
7
+ "gh:aider-chat/aider#git-commit"
8
+ ],
9
+ "auto commit": [
10
+ "gh:aider-chat/aider#git-commit"
11
+ ],
12
+ "code assistant": [
13
+ "gh:aider-chat/aider#code-edit"
14
+ ],
15
+ "color palette": [
16
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
17
+ ],
18
+ "commit message": [
19
+ "gh:aider-chat/aider#git-commit"
20
+ ],
21
+ "components": [
22
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
23
+ ],
24
+ "dashboard": [
25
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
26
+ ],
27
+ "design": [
28
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
29
+ ],
30
+ "design system": [
31
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
32
+ ],
33
+ "design tokens": [
34
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
35
+ ],
36
+ "edit multiple files": [
37
+ "gh:aider-chat/aider#code-edit"
38
+ ],
39
+ "flutter": [
40
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
41
+ ],
42
+ "git commit": [
43
+ "gh:aider-chat/aider#git-commit"
44
+ ],
45
+ "landing page": [
46
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
47
+ ],
48
+ "mobile app": [
49
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
50
+ ],
51
+ "nextjs": [
52
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
53
+ ],
54
+ "pair programming": [
55
+ "gh:aider-chat/aider#code-edit"
56
+ ],
57
+ "react": [
58
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
59
+ ],
60
+ "refactor": [
61
+ "gh:aider-chat/aider#code-edit"
62
+ ],
63
+ "shadcn": [
64
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
65
+ ],
66
+ "spacing": [
67
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
68
+ ],
69
+ "style guide": [
70
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
71
+ ],
72
+ "swiftui": [
73
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
74
+ ],
75
+ "tailwind": [
76
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
77
+ ],
78
+ "typography": [
79
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
80
+ ],
81
+ "ui": [
82
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
83
+ ],
84
+ "ui library": [
85
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
86
+ ],
87
+ "ux": [
88
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
89
+ ],
90
+ "vue": [
91
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
92
+ ],
93
+ "website": [
94
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
95
+ ]
96
+ }
@@ -0,0 +1,60 @@
1
+ {
2
+ "code-generation": [
3
+ "gh:aider-chat/aider#code-edit"
4
+ ],
5
+ "code-refactoring": [
6
+ "gh:aider-chat/aider#code-edit"
7
+ ],
8
+ "commit-message": [
9
+ "gh:aider-chat/aider#git-commit"
10
+ ],
11
+ "component-library": [
12
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
13
+ ],
14
+ "context-aware": [
15
+ "gh:aider-chat/aider#code-edit"
16
+ ],
17
+ "design-guidelines": [
18
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
19
+ ],
20
+ "design-system": [
21
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
22
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
23
+ ],
24
+ "design-tokens": [
25
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
26
+ ],
27
+ "frontend": [
28
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
29
+ ],
30
+ "git-commit": [
31
+ "gh:aider-chat/aider#git-commit"
32
+ ],
33
+ "git-integration": [
34
+ "gh:aider-chat/aider#code-edit"
35
+ ],
36
+ "git-workflow": [
37
+ "gh:aider-chat/aider#git-commit"
38
+ ],
39
+ "mobile-design": [
40
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
41
+ ],
42
+ "multi-file-editing": [
43
+ "gh:aider-chat/aider#code-edit"
44
+ ],
45
+ "responsive-design": [
46
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
47
+ ],
48
+ "style-guide": [
49
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
50
+ ],
51
+ "ui-design": [
52
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
53
+ ],
54
+ "ux-design": [
55
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
56
+ ],
57
+ "web-design": [
58
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design"
59
+ ]
60
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "package_id": "gh:aider-chat/aider",
3
+ "name": "Aider",
4
+ "description": "AI pair programming in your terminal - multi-file editing, git integration, LLM-powered coding assistant",
5
+ "source": {
6
+ "type": "git",
7
+ "repo": "aider-chat/aider",
8
+ "ref": "main"
9
+ },
10
+ "docs": {
11
+ "readme": "https://github.com/aider-chat/aider/blob/main/README.md",
12
+ "homepage": "https://aider.chat",
13
+ "issues": "https://github.com/aider-chat/aider/issues"
14
+ },
15
+ "supported_ides": ["windsurf", "cursor", "generic"],
16
+ "install": {
17
+ "method": "pip",
18
+ "auto_install_cmd": "pip install aider-chat",
19
+ "manual_install_cmd": "pip install aider-chat",
20
+ "uninstall_cmd": "pip uninstall -y aider-chat",
21
+ "notes": "需要 Python 3.8+;需配置 OPENAI_API_KEY 或其他 LLM provider"
22
+ },
23
+ "units": [
24
+ "gh:aider-chat/aider#code-edit",
25
+ "gh:aider-chat/aider#git-commit"
26
+ ],
27
+ "trust_level": "trusted",
28
+ "notes": "成熟开源项目,活跃维护"
29
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "package_id": "gh:nextlevelbuilder/ui-ux-pro-max-skill",
3
+ "name": "UI UX Pro Max",
4
+ "description": "AI skill that provides design intelligence for building professional UI/UX across multiple platforms and frameworks. Includes 67 UI styles, 96 color palettes, 57 font pairings, and 100 reasoning rules for intelligent design system generation.",
5
+ "source": {
6
+ "type": "git",
7
+ "repo": "nextlevelbuilder/ui-ux-pro-max-skill",
8
+ "ref": "main"
9
+ },
10
+ "docs": {
11
+ "readme": "https://github.com/nextlevelbuilder/ui-ux-pro-max-skill/blob/main/README.md",
12
+ "homepage": "https://github.com/nextlevelbuilder/ui-ux-pro-max-skill"
13
+ },
14
+ "supported_ides": ["claude", "windsurf", "cursor", "antigravity", "copilot", "kiro", "codex", "qoder", "roocode", "gemini", "trae", "opencode", "continue", "codebuddy", "generic"],
15
+ "install": {
16
+ "method": "npm",
17
+ "auto_install_cmd": "npm install -g uipro-cli && uipro init --ai windsurf",
18
+ "manual_install_cmd": "npm install -g uipro-cli\nuipro init --ai <your-ai-assistant>",
19
+ "uninstall_cmd": "npm uninstall -g uipro-cli",
20
+ "notes": "需要 Node.js 16+;安装后需要在项目目录中运行 uipro init 命令指定 AI 助手类型"
21
+ },
22
+ "units": [
23
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design",
24
+ "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system"
25
+ ],
26
+ "trust_level": "trusted",
27
+ "notes": "成熟开源项目,支持 13 种技术栈,包含 100 条行业特定推理规则"
28
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "unit_id": "gh:aider-chat/aider#code-edit",
3
+ "package_id": "gh:aider-chat/aider",
4
+ "name": "Aider Code Editing",
5
+ "description": "AI-powered multi-file code editing with context awareness and git integration",
6
+ "capability_tags": [
7
+ "code-generation",
8
+ "code-refactoring",
9
+ "multi-file-editing",
10
+ "git-integration",
11
+ "context-aware"
12
+ ],
13
+ "keywords": [
14
+ "aider",
15
+ "ai coding",
16
+ "pair programming",
17
+ "code assistant",
18
+ "refactor",
19
+ "edit multiple files"
20
+ ],
21
+ "ide_support": ["windsurf", "cursor", "generic"],
22
+ "entrypoints": [
23
+ {
24
+ "command": "aider",
25
+ "args": "[files...] [--model MODEL] [--message MSG]",
26
+ "cwd": "项目根目录(需要 git repo)",
27
+ "examples": [
28
+ "aider src/main.py src/utils.py",
29
+ "aider --model gpt-4 --message 'refactor authentication logic'",
30
+ "aider --yes --message 'add error handling to all API calls'"
31
+ ]
32
+ }
33
+ ],
34
+ "usage_notes": "Aider 在终端中运行,支持对话式编辑多个文件。\n- 自动追踪文件依赖\n- 生成 git commit\n- 支持多种 LLM(OpenAI/Anthropic/本地模型)\n- 可通过 --yes 跳过确认直接执行\n\n典型工作流:\n1. cd 到 git repo\n2. 运行 aider <files>\n3. 对话式描述需求\n4. Aider 自动编辑并 commit",
35
+ "conflicts": "与其他自动 commit 工具可能冲突;需要干净的 git 工作区"
36
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "unit_id": "gh:aider-chat/aider#git-commit",
3
+ "package_id": "gh:aider-chat/aider",
4
+ "name": "Aider Git Commit Generator",
5
+ "description": "AI-generated commit messages based on code changes",
6
+ "capability_tags": [
7
+ "git-commit",
8
+ "commit-message",
9
+ "git-workflow"
10
+ ],
11
+ "keywords": [
12
+ "git commit",
13
+ "commit message",
14
+ "auto commit",
15
+ "aider"
16
+ ],
17
+ "ide_support": ["windsurf", "cursor", "generic"],
18
+ "entrypoints": [
19
+ {
20
+ "command": "aider --commit",
21
+ "args": "[--message MSG]",
22
+ "cwd": "git repo with staged changes",
23
+ "examples": [
24
+ "aider --commit",
25
+ "aider --commit --message 'feat: add user authentication'"
26
+ ]
27
+ }
28
+ ],
29
+ "usage_notes": "使用 Aider 的 commit 功能生成语义化 commit message。\n- 分析 staged changes\n- 生成符合 conventional commits 的消息\n- 可手动覆盖\n\n使用场景:\n- 快速生成规范 commit message\n- 团队统一 commit 风格",
30
+ "conflicts": null
31
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "unit_id": "gh:nextlevelbuilder/ui-ux-pro-max-skill#design-system",
3
+ "package_id": "gh:nextlevelbuilder/ui-ux-pro-max-skill",
4
+ "name": "UI UX Pro Max - Design System Generator",
5
+ "description": "Intelligent design system generation with 100 industry-specific reasoning rules. Automatically generates complete design systems including colors, typography, spacing, and component guidelines based on product type and requirements.",
6
+ "capability_tags": [
7
+ "design-system",
8
+ "design-tokens",
9
+ "style-guide",
10
+ "component-library",
11
+ "design-guidelines"
12
+ ],
13
+ "keywords": [
14
+ "design system",
15
+ "design tokens",
16
+ "style guide",
17
+ "color palette",
18
+ "typography",
19
+ "spacing",
20
+ "components",
21
+ "ui library"
22
+ ],
23
+ "ide_support": ["claude", "windsurf", "cursor", "antigravity", "copilot", "kiro", "codex", "qoder", "roocode", "gemini", "trae", "opencode", "continue", "codebuddy", "generic"],
24
+ "entrypoints": [
25
+ {
26
+ "command": "/design-system",
27
+ "args": "[product-type] [requirements]",
28
+ "cwd": "项目目录",
29
+ "examples": [
30
+ "/design-system Generate a design system for a SaaS dashboard",
31
+ "/design-system Create design tokens for a healthcare app",
32
+ "/design-system Build a style guide for an e-commerce platform"
33
+ ]
34
+ }
35
+ ],
36
+ "usage_notes": "设计系统生成器使用 100 条行业特定推理规则自动生成完整的设计系统。\n\n**功能特性**:\n- 67 种 UI 样式(Glassmorphism, Claymorphism, Minimalism, Brutalism, Neumorphism, Bento Grid, Dark Mode, AI-Native UI 等)\n- 96 种行业特定色板(SaaS, E-commerce, Healthcare, Fintech, Beauty 等)\n- 57 种字体配对(包含 Google Fonts 导入)\n- 25 种图表类型推荐(用于仪表板和分析)\n- 99 条 UX 指南(最佳实践、反模式、无障碍规则)\n\n**设计系统持久化**(Master + Overrides 模式):\n生成的设计系统可以保存并在项目中复用,支持覆盖特定组件的样式。\n\n**智能推荐**:\n根据产品类型(SaaS/电商/医疗/金融等)和需求自动匹配最佳设计方案。",
37
+ "conflicts": null
38
+ }
@@ -0,0 +1,57 @@
1
+ {
2
+ "unit_id": "gh:nextlevelbuilder/ui-ux-pro-max-skill#ui-design",
3
+ "package_id": "gh:nextlevelbuilder/ui-ux-pro-max-skill",
4
+ "name": "UI UX Pro Max - UI Design",
5
+ "description": "Professional UI/UX design and implementation across multiple platforms. Auto-generates design systems with 67 UI styles, 96 color palettes, 57 font pairings, and intelligent recommendations based on product type.",
6
+ "capability_tags": [
7
+ "ui-design",
8
+ "ux-design",
9
+ "design-system",
10
+ "frontend",
11
+ "web-design",
12
+ "mobile-design",
13
+ "responsive-design"
14
+ ],
15
+ "keywords": [
16
+ "ui",
17
+ "ux",
18
+ "design",
19
+ "landing page",
20
+ "dashboard",
21
+ "website",
22
+ "mobile app",
23
+ "react",
24
+ "nextjs",
25
+ "vue",
26
+ "tailwind",
27
+ "shadcn",
28
+ "swiftui",
29
+ "flutter"
30
+ ],
31
+ "ide_support": ["claude", "windsurf", "cursor", "antigravity", "copilot", "kiro", "codex", "qoder", "roocode", "gemini", "trae", "opencode", "continue", "codebuddy", "generic"],
32
+ "entrypoints": [
33
+ {
34
+ "command": "自然语言触发(Skill Mode)",
35
+ "args": "直接描述需求,如 'Build a landing page for my SaaS product'",
36
+ "cwd": "项目目录",
37
+ "examples": [
38
+ "Build a landing page for my SaaS product",
39
+ "Create a dashboard for healthcare analytics",
40
+ "Design a portfolio website with dark mode",
41
+ "Make a mobile app UI for e-commerce",
42
+ "Build a fintech banking app with dark theme"
43
+ ]
44
+ },
45
+ {
46
+ "command": "/ui-ux-pro-max(Workflow Mode)",
47
+ "args": "描述 UI/UX 需求",
48
+ "cwd": "项目目录",
49
+ "examples": [
50
+ "/ui-ux-pro-max Build a landing page for my SaaS product",
51
+ "/ui-ux-pro-max Create a dashboard for healthcare analytics"
52
+ ]
53
+ }
54
+ ],
55
+ "usage_notes": "UI UX Pro Max 提供智能设计系统生成和 UI/UX 实现。\n\n**工作流程**:\n1. 描述需求 - 请求任何 UI/UX 任务\n2. 自动生成设计系统 - AI 使用推理引擎生成完整设计系统\n3. 智能推荐 - 根据产品类型和需求匹配最佳样式、颜色、字体\n4. 代码生成 - 实现 UI 并遵循最佳实践\n5. 交付前检查 - 验证常见 UI/UX 反模式\n\n**支持的技术栈**:\n- Web: HTML+Tailwind, React, Next.js, Vue, Nuxt.js, Svelte, Astro, shadcn/ui, Nuxt UI\n- iOS: SwiftUI\n- Android: Jetpack Compose\n- 跨平台: React Native, Flutter\n\n**触发方式**:\n- Claude/Windsurf/Antigravity 等:自动激活(Skill Mode)\n- Cursor/Kiro/Copilot/Roo Code:使用 /ui-ux-pro-max 命令",
56
+ "conflicts": null
57
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo-skill",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "A multi-assistant skill generator (Claude/Windsurf/Cursor/GitHub Skills) driven by a canonical SkillSpec.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -9,6 +9,7 @@
9
9
  "files": [
10
10
  "bin/**",
11
11
  "src/**",
12
+ "data/**",
12
13
  "skills/**",
13
14
  ".shared/**",
14
15
  ".claude/**",
@@ -5,10 +5,10 @@
5
5
  "primary_target": "windsurf",
6
6
  "backward_compat": ["claude", "cursor", "github"],
7
7
  "questions": [
8
- "你想实现什么目标?(一句话描述任务)",
9
- "输入是什么?(文件/代码/数据/命令等)",
10
- "运行环境?(OS/Shell/Runtime)",
11
- "使用哪个 IDE/编辑器?(windsurf/cursor/vscode/generic)"
8
+ "你需要什么能力?(一句话描述目标,例如:需要一个开发 UI/UX 的 skill)",
9
+ "你的技术栈/平台是什么?(如 React/Vue/Next.js/SwiftUI/Flutter/HTML+Tailwind;不确定可回车)",
10
+ "硬约束有哪些?(如不可联网/必须离线/不可修改文件等;无则回车)",
11
+ "你使用哪个 IDE?(默认当前 IDE;不确定可回车)"
12
12
  ],
13
13
  "triggers": [
14
14
  "找第三方 skill",
@@ -27,21 +27,23 @@
27
27
  "title": "两级提问收集需求",
28
28
  "kind": "action",
29
29
  "commands": [],
30
- "notes": "Level 1 固定 3-4 问(goal/input/env/ide);Level 2 仅不确定时追问 1-2 个。详见 references/interview-protocol.md"
30
+ "notes": "优先少问:先用用户原始请求直接匹配;若已高置信命中则不要反问,直接给出 Top1-3。\n\n若信息不足,仅允许 1 轮补充提问(总问题数<=5),问完立即进入匹配,不要进入第二轮追问。"
31
31
  },
32
32
  {
33
33
  "id": "match",
34
34
  "title": "匹配第三方 unit",
35
35
  "kind": "action",
36
- "commands": [],
37
- "notes": "两阶段:粗筛(倒排索引)+ 精排(tag 覆盖率 + 约束过滤)。置信度 < 60% 必须拒绝并说明原因。详见 references/matching-algorithm.md"
36
+ "commands": [
37
+ "python -m skill_finder.cli match --goal \"<goal>\" --ide <ide> --format json"
38
+ ],
39
+ "notes": "优先使用内置第三方 registry(packages/units)作为事实来源进行匹配。\n\n匹配策略:\n- 先从用户 goal 里推断 tags/keywords(如 UI/UX/设计系统/原型/React 等),避免过多追问\n- 两阶段:粗筛(倒排索引或扫描 registry 文件降级)+ 精排(tag/keyword 覆盖率 + IDE 支持 + 约束过滤)\n- 置信度 < 60% 必须拒绝并说明原因\n\n当候选数量较少(例如 <=20)且语义需要判断时,可以把候选摘要(unit name/description/tags/keywords/IDE/README)作为输入交给 AI 做最终判定,但不得捏造“缺少 registry/索引”。"
38
40
  },
39
41
  {
40
42
  "id": "present",
41
43
  "title": "展示结果(Top 1-3 或拒绝)",
42
44
  "kind": "gate",
43
45
  "commands": [],
44
- "notes": "命中:列出 unit + package + 匹配原因 + README 链接 + 使用方式。未命中:明确拒绝原因分类(no_candidates_by_tag/no_ide_support/incompatible_env/insufficient_info"
46
+ "notes": "命中:列出 unit + package + 匹配原因 + README 链接 + 使用方式。\n未命中:明确拒绝原因分类(no_candidates_by_tag/no_ide_support/incompatible_env/insufficient_info)。\n禁止输出不实诊断(例如声称索引文件缺失),除非你已实际检查过本地文件。"
45
47
  },
46
48
  {
47
49
  "id": "install",
@@ -1,5 +1,7 @@
1
1
  """主动搜索入口 - CLI 接口"""
2
2
 
3
+ import argparse
4
+ import json
3
5
  import sys
4
6
  from typing import Optional
5
7
  from .interview import Interview
@@ -89,17 +91,101 @@ class SkillFinderCLI:
89
91
  if selected.unit.usage_notes:
90
92
  print(f"\n使用说明:\n{selected.unit.usage_notes}")
91
93
 
94
+ def run_match(
95
+ self,
96
+ goal: str,
97
+ ide: Optional[str] = None,
98
+ env: Optional[str] = None,
99
+ constraints: Optional[str] = None,
100
+ top: int = 3,
101
+ output_format: str = "text",
102
+ min_score: Optional[float] = None,
103
+ ):
104
+ if min_score is not None:
105
+ self.matcher.min_score = min_score
106
+
107
+ constraints_list = None
108
+ if constraints:
109
+ constraints_list = [c.strip() for c in constraints.replace(",", ",").split(",") if c.strip()]
110
+
111
+ from .models import SearchQuery
112
+
113
+ query = SearchQuery(goal=goal, ide=ide, env=env, constraints=constraints_list)
114
+ result = self.matcher.match(query)
115
+
116
+ if output_format == "json":
117
+ payload = {
118
+ "query": result.query.model_dump(),
119
+ "matches": [
120
+ {
121
+ "score": m.score,
122
+ "reasons": m.reasons,
123
+ "warnings": m.warnings,
124
+ "unit": m.unit.model_dump(),
125
+ "package": m.package.model_dump(),
126
+ }
127
+ for m in result.matches[: max(0, top)]
128
+ ],
129
+ "rejection_reason": result.rejection_reason,
130
+ "rejection_category": result.rejection_category,
131
+ }
132
+ print(json.dumps(payload, ensure_ascii=False, indent=2))
133
+ return
134
+
135
+ print("\n=== 匹配结果 ===")
136
+ if not result.matches:
137
+ print("✗ 未找到匹配的第三方能力\n")
138
+ print(f"拒绝原因: {result.rejection_reason}")
139
+ return
140
+
141
+ print(f"找到 {min(len(result.matches), top)} 个匹配的能力:\n")
142
+ for i, match in enumerate(result.matches[: max(0, top)], 1):
143
+ print(f"【{i}】{match.unit.name} ({match.package.name})")
144
+ print(f"- 描述: {match.unit.description}")
145
+ print(f"- 匹配原因: {'; '.join(match.reasons)}")
146
+ print(f"- 置信度: {match.score:.2f}")
147
+ print(f"- README: {match.package.docs.readme}")
148
+ if match.warnings:
149
+ print(f"- ⚠ 警告: {'; '.join(match.warnings)}")
150
+ print()
151
+
92
152
 
93
153
  def main():
94
154
  """CLI 入口"""
95
- if len(sys.argv) > 1 and sys.argv[1] == "doctor":
96
- from .models import SearchQuery
97
- doctor = Doctor()
98
- query = SearchQuery(goal="测试", ide="windsurf")
99
- print(doctor.show_install_records())
100
- else:
101
- cli = SkillFinderCLI()
102
- cli.run()
155
+ parser = argparse.ArgumentParser(prog="skill-finder")
156
+ sub = parser.add_subparsers(dest="cmd")
157
+
158
+ match_p = sub.add_parser("match")
159
+ match_p.add_argument("--goal", required=True)
160
+ match_p.add_argument("--ide", default=None)
161
+ match_p.add_argument("--env", default=None)
162
+ match_p.add_argument("--constraints", default=None)
163
+ match_p.add_argument("--top", type=int, default=3)
164
+ match_p.add_argument("--format", choices=["text", "json"], default="text")
165
+ match_p.add_argument("--min-score", type=float, default=None)
166
+
167
+ sub.add_parser("doctor")
168
+
169
+ args = parser.parse_args(sys.argv[1:])
170
+ cli = SkillFinderCLI()
171
+
172
+ if args.cmd == "doctor":
173
+ print(cli.doctor.show_install_records())
174
+ return
175
+
176
+ if args.cmd == "match":
177
+ cli.run_match(
178
+ goal=args.goal,
179
+ ide=args.ide,
180
+ env=args.env,
181
+ constraints=args.constraints,
182
+ top=args.top,
183
+ output_format=args.format,
184
+ min_score=args.min_score,
185
+ )
186
+ return
187
+
188
+ cli.run()
103
189
 
104
190
 
105
191
  if __name__ == "__main__":
@@ -1,5 +1,6 @@
1
1
  """两级提问逻辑"""
2
2
 
3
+ import re
3
4
  from typing import Dict, List, Optional
4
5
  from .models import SearchQuery
5
6
 
@@ -13,15 +14,9 @@ class Interview:
13
14
  "text": "你想实现什么目标?(一句话描述任务)",
14
15
  "required": True
15
16
  },
16
- {
17
- "id": "input",
18
- "text": "输入是什么?(文件/代码/数据/命令等)",
19
- "required": False,
20
- "default": "任意"
21
- },
22
17
  {
23
18
  "id": "env",
24
- "text": "运行环境?(OS/Shell/Runtime,如 Windows/Linux/Python/Node)",
19
+ "text": "技术栈/环境?(如 React/Vue/Next.js/SwiftUI/Flutter/HTML+Tailwind;不确定可回车)",
25
20
  "required": False,
26
21
  "default": "通用"
27
22
  },
@@ -29,14 +24,19 @@ class Interview:
29
24
  "id": "ide",
30
25
  "text": "使用哪个 IDE/编辑器?(windsurf/cursor/vscode/generic)",
31
26
  "required": True
27
+ },
28
+ {
29
+ "id": "constraints",
30
+ "text": "硬约束?(如不可联网/必须离线/不可修改文件等;无则回车)",
31
+ "required": False
32
32
  }
33
33
  ]
34
34
 
35
35
  def collect(self) -> SearchQuery:
36
- """收集需求"""
36
+ """收集需求(最多 1 轮,最多 4 问)"""
37
37
  answers = {}
38
38
 
39
- print("=== 需求收集(Level 1)===\n")
39
+ print("=== 需求收集 ===\n")
40
40
  for q in self.LEVEL1_QUESTIONS:
41
41
  if q["required"]:
42
42
  answer = input(f"{q['text']}: ").strip()
@@ -47,45 +47,41 @@ class Interview:
47
47
  default_hint = f" [默认: {q.get('default', '跳过')}]" if q.get('default') else ""
48
48
  answer = input(f"{q['text']}{default_hint}: ").strip()
49
49
  answers[q["id"]] = answer if answer else q.get("default")
50
-
51
- if self._needs_clarification(answers):
52
- print("\n=== 补充信息(Level 2)===\n")
53
-
54
- if len(answers["goal"].split()) < 3:
55
- detail = input("能否详细描述一下具体要做什么?: ").strip()
56
- if detail:
57
- answers["goal"] += f" - {detail}"
58
-
59
- constraints = input("有什么硬约束吗?(如不可联网/必须离线/不可修改文件等,无则回车): ").strip()
60
- if constraints:
61
- answers["constraints"] = [c.strip() for c in constraints.split(",")]
50
+
51
+ constraints_value = answers.get("constraints")
52
+ constraints_list: Optional[List[str]] = None
53
+ if isinstance(constraints_value, str) and constraints_value and constraints_value != "通用":
54
+ constraints_list = [c.strip() for c in re.split(r"[,,]", constraints_value) if c.strip()]
62
55
 
63
56
  return SearchQuery(
64
57
  goal=answers["goal"],
65
- input_type=answers.get("input"),
66
58
  env=answers.get("env"),
67
59
  ide=answers["ide"],
68
- constraints=answers.get("constraints"),
60
+ constraints=constraints_list,
69
61
  tags=self._extract_tags(answers["goal"]),
70
62
  keywords=self._extract_keywords(answers["goal"])
71
63
  )
72
64
 
73
- def _needs_clarification(self, answers: Dict) -> bool:
74
- """判断是否需要 Level 2"""
75
- return len(answers["goal"].split()) < 5
76
-
77
65
  def _extract_tags(self, goal: str) -> List[str]:
78
66
  """从 goal 提取 tags(简单关键词映射)"""
79
67
  tag_map = {
80
- "代码": "code-generation",
81
- "生成": "code-generation",
82
- "重构": "code-refactoring",
83
- "git": "git-integration",
84
- "commit": "git-commit",
85
- "多文件": "multi-file-editing",
86
- "测试": "testing",
87
- "文档": "documentation",
88
- "编辑": "code-generation",
68
+ "ui": "ui-design",
69
+ "ux": "ux-design",
70
+ "ui/ux": "ui-design",
71
+ "原型": "ui-design",
72
+ "prototype": "ui-design",
73
+ "landing": "web-design",
74
+ "落地页": "web-design",
75
+ "dashboard": "frontend",
76
+ "仪表板": "frontend",
77
+ "设计系统": "design-system",
78
+ "design system": "design-system",
79
+ "style guide": "style-guide",
80
+ "组件库": "component-library",
81
+ "component library": "component-library",
82
+ "design token": "design-tokens",
83
+ "无障碍": "design-guidelines",
84
+ "accessibility": "design-guidelines",
89
85
  }
90
86
  tags = []
91
87
  goal_lower = goal.lower()
@@ -97,5 +93,32 @@ class Interview:
97
93
 
98
94
  def _extract_keywords(self, goal: str) -> List[str]:
99
95
  """提取关键词"""
100
- words = goal.split()
101
- return [w.strip() for w in words if len(w.strip()) > 2]
96
+ keywords: List[str] = []
97
+ text = goal.strip()
98
+
99
+ for token in re.findall(r"[A-Za-z0-9][A-Za-z0-9\+\-\./#]*", text):
100
+ for part in re.split(r"[/_]+", token):
101
+ part = part.strip()
102
+ if part and part.lower() not in [k.lower() for k in keywords]:
103
+ keywords.append(part)
104
+
105
+ for token in re.split(r"\s+", text):
106
+ token = token.strip()
107
+ if token and len(token) > 2 and token.lower() not in [k.lower() for k in keywords]:
108
+ keywords.append(token)
109
+
110
+ synonyms = {
111
+ "ui/ux": ["ui", "ux"],
112
+ "用户体验": ["ux"],
113
+ "设计系统": ["design system", "design tokens"],
114
+ "原型": ["prototype"],
115
+ "落地页": ["landing page"],
116
+ }
117
+ lowered = text.lower()
118
+ for k, vals in synonyms.items():
119
+ if k in lowered:
120
+ for v in vals:
121
+ if v.lower() not in [x.lower() for x in keywords]:
122
+ keywords.append(v)
123
+
124
+ return keywords
@@ -1,5 +1,6 @@
1
1
  """匹配算法实现 - 两阶段匹配"""
2
2
 
3
+ import re
3
4
  from typing import List, Dict, Set
4
5
  from .models import SearchQuery, SearchResult, MatchResult
5
6
  from .registry import Registry
@@ -11,9 +12,67 @@ class Matcher:
11
12
  def __init__(self, registry: Registry, min_score: float = 0.6):
12
13
  self.registry = registry
13
14
  self.min_score = min_score
15
+
16
+ def _infer_tags_keywords(self, goal: str) -> Dict[str, List[str]]:
17
+ """从自然语言 goal 粗提取 tags/keywords(用于减少追问)"""
18
+ goal_lower = (goal or "").lower()
19
+
20
+ tag_map = {
21
+ "ui": "ui-design",
22
+ "ux": "ux-design",
23
+ "ui/ux": "ui-design",
24
+ "用户体验": "ux-design",
25
+ "原型": "ui-design",
26
+ "prototype": "ui-design",
27
+ "设计系统": "design-system",
28
+ "design system": "design-system",
29
+ "design token": "design-tokens",
30
+ "design tokens": "design-tokens",
31
+ "style guide": "style-guide",
32
+ "组件库": "component-library",
33
+ "component library": "component-library",
34
+ "landing": "web-design",
35
+ "落地页": "web-design",
36
+ "dashboard": "frontend",
37
+ "仪表板": "frontend",
38
+ "无障碍": "design-guidelines",
39
+ "accessibility": "design-guidelines",
40
+ }
41
+
42
+ tags: List[str] = []
43
+ for keyword, tag in tag_map.items():
44
+ if keyword in goal_lower and tag not in tags:
45
+ tags.append(tag)
46
+
47
+ keywords: List[str] = []
48
+ for token in re.findall(r"[A-Za-z0-9][A-Za-z0-9\+\-\./#]*", goal or ""):
49
+ for part in re.split(r"[/_]+", token):
50
+ part = part.strip()
51
+ if part and part.lower() not in [k.lower() for k in keywords]:
52
+ keywords.append(part)
53
+
54
+ synonyms = {
55
+ "ui/ux": ["ui", "ux"],
56
+ "原型": ["prototype"],
57
+ "落地页": ["landing page"],
58
+ "设计系统": ["design system", "design tokens"],
59
+ }
60
+ for k, vals in synonyms.items():
61
+ if k in goal_lower:
62
+ for v in vals:
63
+ if v.lower() not in [x.lower() for x in keywords]:
64
+ keywords.append(v)
65
+
66
+ return {"tags": tags, "keywords": keywords}
14
67
 
15
68
  def match(self, query: SearchQuery) -> SearchResult:
16
69
  """执行两阶段匹配"""
70
+ inferred = self._infer_tags_keywords(query.goal)
71
+ if not query.tags and inferred["tags"]:
72
+ query.tags = inferred["tags"]
73
+ if not query.keywords and inferred["keywords"]:
74
+ query.keywords = inferred["keywords"]
75
+
17
76
  candidates = self._coarse_filter(query)
18
77
 
19
78
  if not candidates:
@@ -54,6 +113,12 @@ class Matcher:
54
113
  if query.keywords:
55
114
  for kw in query.keywords:
56
115
  unit_ids.update(self.registry.search_by_keyword(kw))
116
+
117
+ if not unit_ids:
118
+ if query.ide:
119
+ unit_ids = set(self.registry.search_by_ide(query.ide))
120
+ else:
121
+ unit_ids = set(self.registry.get_all_units())
57
122
 
58
123
  if query.ide:
59
124
  ide_units = set(self.registry.search_by_ide(query.ide))
@@ -21,13 +21,24 @@ class Registry:
21
21
  self._packages_cache: Dict[str, SkillPackage] = {}
22
22
  self._units_cache: Dict[str, SkillUnit] = {}
23
23
  self.indexes: Dict[str, dict] = {}
24
+ self.indexes_available: bool = False
24
25
 
25
26
  self._load_indexes()
26
27
 
27
28
  def _load_indexes(self):
28
29
  """加载所有索引文件"""
29
30
  if not self.indexes_dir.exists():
30
- raise FileNotFoundError(f"索引目录不存在: {self.indexes_dir}")
31
+ self.indexes_available = False
32
+ self.indexes = {
33
+ "by_tag": {},
34
+ "by_keyword": {},
35
+ "by_ide": {},
36
+ "packages_all": [],
37
+ "units_all": [],
38
+ }
39
+ return
40
+
41
+ self.indexes_available = True
31
42
 
32
43
  index_files = {
33
44
  "by_tag": "units.by_tag.json",
@@ -44,6 +55,44 @@ class Registry:
44
55
  self.indexes[key] = json.load(f)
45
56
  else:
46
57
  self.indexes[key] = {} if key != "packages_all" and key != "units_all" else []
58
+
59
+ def _load_all_units_from_disk(self) -> Dict[str, SkillUnit]:
60
+ """从磁盘加载所有 units(用于索引缺失时的降级查询)"""
61
+ if self._units_cache:
62
+ return self._units_cache
63
+
64
+ if not self.units_dir.exists():
65
+ return self._units_cache
66
+
67
+ for unit_path in self.units_dir.glob("*.json"):
68
+ try:
69
+ with open(unit_path, 'r', encoding='utf-8') as f:
70
+ data = json.load(f)
71
+ unit = SkillUnit(**data)
72
+ self._units_cache[unit.unit_id] = unit
73
+ except Exception as e:
74
+ print(f"加载 unit 文件 {unit_path} 失败: {e}")
75
+
76
+ return self._units_cache
77
+
78
+ def _load_all_packages_from_disk(self) -> Dict[str, SkillPackage]:
79
+ """从磁盘加载所有 packages(用于索引缺失时的降级查询)"""
80
+ if self._packages_cache:
81
+ return self._packages_cache
82
+
83
+ if not self.packages_dir.exists():
84
+ return self._packages_cache
85
+
86
+ for package_path in self.packages_dir.glob("*.json"):
87
+ try:
88
+ with open(package_path, 'r', encoding='utf-8') as f:
89
+ data = json.load(f)
90
+ package = SkillPackage(**data)
91
+ self._packages_cache[package.package_id] = package
92
+ except Exception as e:
93
+ print(f"加载 package 文件 {package_path} 失败: {e}")
94
+
95
+ return self._packages_cache
47
96
 
48
97
  def get_package(self, package_id: str) -> Optional[SkillPackage]:
49
98
  """获取 package(带缓存)"""
@@ -54,7 +103,8 @@ class Registry:
54
103
  package_path = self.packages_dir / f"{sanitized_id}.json"
55
104
 
56
105
  if not package_path.exists():
57
- return None
106
+ self._load_all_packages_from_disk()
107
+ return self._packages_cache.get(package_id)
58
108
 
59
109
  try:
60
110
  with open(package_path, 'r', encoding='utf-8') as f:
@@ -75,7 +125,8 @@ class Registry:
75
125
  unit_path = self.units_dir / f"{sanitized_id}.json"
76
126
 
77
127
  if not unit_path.exists():
78
- return None
128
+ self._load_all_units_from_disk()
129
+ return self._units_cache.get(unit_id)
79
130
 
80
131
  try:
81
132
  with open(unit_path, 'r', encoding='utf-8') as f:
@@ -89,20 +140,55 @@ class Registry:
89
140
 
90
141
  def search_by_tag(self, tag: str) -> List[str]:
91
142
  """通过 tag 搜索 unit_id 列表"""
92
- return self.indexes.get("by_tag", {}).get(tag.lower(), [])
143
+ by_tag = self.indexes.get("by_tag", {})
144
+ if by_tag:
145
+ return by_tag.get(tag.lower(), [])
146
+
147
+ tag_lower = tag.lower()
148
+ unit_ids: List[str] = []
149
+ for unit in self._load_all_units_from_disk().values():
150
+ if tag_lower in [t.lower() for t in unit.capability_tags]:
151
+ unit_ids.append(unit.unit_id)
152
+ return unit_ids
93
153
 
94
154
  def search_by_keyword(self, keyword: str) -> List[str]:
95
155
  """通过 keyword 搜索 unit_id 列表"""
96
- return self.indexes.get("by_keyword", {}).get(keyword.lower(), [])
156
+ by_keyword = self.indexes.get("by_keyword", {})
157
+ if by_keyword:
158
+ return by_keyword.get(keyword.lower(), [])
159
+
160
+ kw_lower = keyword.lower()
161
+ unit_ids: List[str] = []
162
+ for unit in self._load_all_units_from_disk().values():
163
+ if kw_lower in [k.lower() for k in unit.keywords]:
164
+ unit_ids.append(unit.unit_id)
165
+ return unit_ids
97
166
 
98
167
  def search_by_ide(self, ide: str) -> List[str]:
99
168
  """通过 IDE 搜索 unit_id 列表"""
100
- return self.indexes.get("by_ide", {}).get(ide.lower(), [])
169
+ by_ide = self.indexes.get("by_ide", {})
170
+ if by_ide:
171
+ return by_ide.get(ide.lower(), [])
172
+
173
+ ide_lower = ide.lower()
174
+ unit_ids: List[str] = []
175
+ for unit in self._load_all_units_from_disk().values():
176
+ if ide_lower in [i.lower() for i in unit.ide_support]:
177
+ unit_ids.append(unit.unit_id)
178
+ return unit_ids
101
179
 
102
180
  def get_all_packages(self) -> List[str]:
103
181
  """获取所有 package_id"""
104
- return self.indexes.get("packages_all", [])
182
+ packages_all = self.indexes.get("packages_all", [])
183
+ if packages_all:
184
+ return packages_all
185
+
186
+ return list(self._load_all_packages_from_disk().keys())
105
187
 
106
188
  def get_all_units(self) -> List[str]:
107
189
  """获取所有 unit_id"""
108
- return self.indexes.get("units_all", [])
190
+ units_all = self.indexes.get("units_all", [])
191
+ if units_all:
192
+ return units_all
193
+
194
+ return list(self._load_all_units_from_disk().keys())