@skilly-hand/skilly-hand 0.11.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -1
- package/SECURITY.md +37 -0
- package/catalog/skills/figma-mcp-0to1/manifest.json +1 -1
- package/package.json +5 -3
- package/packages/detectors/src/index.js +83 -31
package/CHANGELOG.md
CHANGED
|
@@ -5,11 +5,32 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
7
|
### Added
|
|
8
|
-
-
|
|
8
|
+
- Figma plugin detection support
|
|
9
|
+
- New test fixtures for figma-plugin projects
|
|
9
10
|
|
|
10
11
|
### Changed
|
|
12
|
+
- Improved project detection logic with configExists helper function
|
|
13
|
+
- Updated skill recommendations for React, Next.js, Angular, Vite, and other technologies
|
|
14
|
+
- Changed figma-mcp-0to1 skill detectors from "always" to "figma"
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- _None._
|
|
18
|
+
|
|
19
|
+
### Removed
|
|
11
20
|
- _None._
|
|
12
21
|
|
|
22
|
+
## [0.12.0] - 2026-04-05
|
|
23
|
+
[View on npm](https://www.npmjs.com/package/@skilly-hand/skilly-hand/v/0.12.0)
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- Added `SECURITY.md` policy for vulnerability reporting and response procedures.
|
|
27
|
+
- Added `security-check` script to scan source code for exposed secrets and API keys.
|
|
28
|
+
- Integrated security scanning into the `verify:publish` pipeline to catch credential leaks before release.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- Updated `.gitignore` to include `.env*` pattern for environment variable files.
|
|
32
|
+
- Updated `verify-packlist.mjs` to whitelist `SECURITY.md` in npm package.
|
|
33
|
+
|
|
13
34
|
### Fixed
|
|
14
35
|
- _None._
|
|
15
36
|
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
Only the latest version published on npm is supported with security fixes. No backport patches are issued for older versions.
|
|
6
|
+
|
|
7
|
+
## Reporting a Vulnerability
|
|
8
|
+
|
|
9
|
+
If you discover a security vulnerability, please **do not open a public GitHub issue**. Instead, use [GitHub Security Advisories](https://github.com/Davecelot/skilly-hand/security/advisories/new) to report it privately.
|
|
10
|
+
|
|
11
|
+
Include as much detail as possible:
|
|
12
|
+
|
|
13
|
+
- A description of the vulnerability and its potential impact
|
|
14
|
+
- Steps to reproduce or a minimal proof-of-concept
|
|
15
|
+
- The version of `@skilly-hand/skilly-hand` you are using
|
|
16
|
+
- Your environment (OS, Node.js version)
|
|
17
|
+
|
|
18
|
+
## Response Timeline
|
|
19
|
+
|
|
20
|
+
This is a solo-maintained project. I will do my best to:
|
|
21
|
+
|
|
22
|
+
- Acknowledge the report within a few days
|
|
23
|
+
- Triage and provide an estimated fix timeline once reviewed
|
|
24
|
+
- Publish a patch and disclose the issue publicly after the fix ships
|
|
25
|
+
|
|
26
|
+
## Out of Scope
|
|
27
|
+
|
|
28
|
+
The following are not considered security vulnerabilities in this project:
|
|
29
|
+
|
|
30
|
+
- Content inside skill `.md` files — these are prose instructions for AI agents, not executable code
|
|
31
|
+
- Vulnerabilities in third-party dependencies — please report those directly to the upstream package maintainers
|
|
32
|
+
- Issues that require physical access to the machine running the CLI
|
|
33
|
+
|
|
34
|
+
## Please Do Not
|
|
35
|
+
|
|
36
|
+
- Disclose the vulnerability publicly before a fix has been released
|
|
37
|
+
- Open a public GitHub issue to report security concerns
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"description": "Guide users from Figma MCP installation and authentication through first canvas creation, with function-level tool coverage and operational recovery patterns.",
|
|
5
5
|
"portable": true,
|
|
6
6
|
"tags": ["figma", "mcp", "workflow", "design"],
|
|
7
|
-
"detectors": ["
|
|
7
|
+
"detectors": ["figma"],
|
|
8
8
|
"detectionTriggers": ["manual"],
|
|
9
9
|
"installsFor": ["all"],
|
|
10
10
|
"agentSupport": ["codex", "claude", "cursor", "gemini", "copilot", "antigravity", "windsurf", "trae"],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skilly-hand/skilly-hand",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"license": "CC-BY-NC-4.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"packages",
|
|
15
15
|
"README.md",
|
|
16
16
|
"CHANGELOG.md",
|
|
17
|
-
"LICENSE"
|
|
17
|
+
"LICENSE",
|
|
18
|
+
"SECURITY.md"
|
|
18
19
|
],
|
|
19
20
|
"workspaces": [
|
|
20
21
|
"packages/*"
|
|
@@ -28,8 +29,9 @@
|
|
|
28
29
|
"catalog:sync": "node ./scripts/sync-catalog-readme.mjs",
|
|
29
30
|
"agentic:self:sync": "node ./scripts/sync-self-agentic.mjs",
|
|
30
31
|
"test": "node --test tests/*.test.js",
|
|
32
|
+
"security:check": "node ./scripts/security-check.mjs",
|
|
31
33
|
"verify:packlist": "node ./scripts/verify-packlist.mjs",
|
|
32
|
-
"verify:publish": "npm run catalog:check && npm test && npm run verify:packlist",
|
|
34
|
+
"verify:publish": "npm run security:check && npm run catalog:check && npm test && npm run verify:packlist",
|
|
33
35
|
"publish:prepare": "npm run verify:publish && npm pack --dry-run --json",
|
|
34
36
|
"publish:otp": "node ./scripts/publish-with-otp.mjs",
|
|
35
37
|
"publish:next": "node ./scripts/publish-with-otp.mjs --tag next",
|
|
@@ -10,6 +10,13 @@ async function pathExists(filePath) {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
async function configExists(cwd, base, extensions = ["js", "ts"]) {
|
|
14
|
+
for (const ext of extensions) {
|
|
15
|
+
if (await pathExists(path.join(cwd, `${base}.${ext}`))) return true;
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
|
|
13
20
|
async function readJson(filePath) {
|
|
14
21
|
if (!(await pathExists(filePath))) {
|
|
15
22
|
return null;
|
|
@@ -41,14 +48,10 @@ export async function detectProject(cwd) {
|
|
|
41
48
|
const packageJson = await readJson(path.join(cwd, "package.json"));
|
|
42
49
|
const tsconfigExists = await pathExists(path.join(cwd, "tsconfig.json"));
|
|
43
50
|
const angularJsonExists = await pathExists(path.join(cwd, "angular.json"));
|
|
44
|
-
const viteConfigExists =
|
|
45
|
-
|
|
46
|
-
(await pathExists(path.join(cwd, "vite.config.ts")));
|
|
47
|
-
const nextConfigExists =
|
|
48
|
-
(await pathExists(path.join(cwd, "next.config.js"))) ||
|
|
49
|
-
(await pathExists(path.join(cwd, "next.config.mjs"))) ||
|
|
50
|
-
(await pathExists(path.join(cwd, "next.config.ts")));
|
|
51
|
+
const viteConfigExists = await configExists(cwd, "vite.config");
|
|
52
|
+
const nextConfigExists = await configExists(cwd, "next.config", ["js", "mjs", "ts"]);
|
|
51
53
|
const storybookDirExists = await pathExists(path.join(cwd, ".storybook"));
|
|
54
|
+
const figmaConfigExists = await configExists(cwd, "figma.config");
|
|
52
55
|
const results = [];
|
|
53
56
|
|
|
54
57
|
if (packageJson) {
|
|
@@ -56,27 +59,34 @@ export async function detectProject(cwd) {
|
|
|
56
59
|
technology: "nodejs",
|
|
57
60
|
confidence: 1,
|
|
58
61
|
reasons: ["Found package.json"],
|
|
59
|
-
recommendedSkillIds: [
|
|
62
|
+
recommendedSkillIds: [
|
|
63
|
+
"token-optimizer",
|
|
64
|
+
"spec-driven-development",
|
|
65
|
+
"review-rangers",
|
|
66
|
+
"project-teacher"
|
|
67
|
+
]
|
|
60
68
|
});
|
|
61
69
|
}
|
|
62
70
|
|
|
63
|
-
|
|
71
|
+
const deps = packageJson ? { ...packageJson.dependencies, ...packageJson.devDependencies } : {};
|
|
72
|
+
|
|
73
|
+
if (tsconfigExists || "typescript" in deps) {
|
|
64
74
|
addDetection(results, {
|
|
65
75
|
technology: "typescript",
|
|
66
|
-
confidence: tsconfigExists ? 0.95 : 0.
|
|
67
|
-
reasons: tsconfigExists
|
|
76
|
+
confidence: tsconfigExists ? 0.95 : 0.9,
|
|
77
|
+
reasons: tsconfigExists
|
|
78
|
+
? ["Found tsconfig.json"]
|
|
79
|
+
: ['Dependency "typescript" found in package.json'],
|
|
68
80
|
recommendedSkillIds: ["token-optimizer"]
|
|
69
81
|
});
|
|
70
82
|
}
|
|
71
83
|
|
|
72
|
-
const deps = packageJson ? { ...packageJson.dependencies, ...packageJson.devDependencies } : {};
|
|
73
|
-
|
|
74
84
|
if ("react" in deps) {
|
|
75
85
|
addDetection(results, {
|
|
76
86
|
technology: "react",
|
|
77
87
|
confidence: 0.95,
|
|
78
88
|
reasons: ['Dependency "react" found in package.json'],
|
|
79
|
-
recommendedSkillIds: ["accessibility-audit", "
|
|
89
|
+
recommendedSkillIds: ["accessibility-audit", "react-guidelines", "frontend-design"]
|
|
80
90
|
});
|
|
81
91
|
}
|
|
82
92
|
|
|
@@ -84,8 +94,15 @@ export async function detectProject(cwd) {
|
|
|
84
94
|
addDetection(results, {
|
|
85
95
|
technology: "nextjs",
|
|
86
96
|
confidence: nextConfigExists ? 1 : 0.9,
|
|
87
|
-
reasons: nextConfigExists
|
|
88
|
-
|
|
97
|
+
reasons: nextConfigExists
|
|
98
|
+
? ["Found next.config.*"]
|
|
99
|
+
: ['Dependency "next" found in package.json'],
|
|
100
|
+
recommendedSkillIds: [
|
|
101
|
+
"accessibility-audit",
|
|
102
|
+
"spec-driven-development",
|
|
103
|
+
"react-guidelines",
|
|
104
|
+
"frontend-design"
|
|
105
|
+
]
|
|
89
106
|
});
|
|
90
107
|
}
|
|
91
108
|
|
|
@@ -93,12 +110,14 @@ export async function detectProject(cwd) {
|
|
|
93
110
|
addDetection(results, {
|
|
94
111
|
technology: "angular",
|
|
95
112
|
confidence: angularJsonExists ? 1 : 0.95,
|
|
96
|
-
reasons: angularJsonExists
|
|
113
|
+
reasons: angularJsonExists
|
|
114
|
+
? ["Found angular.json"]
|
|
115
|
+
: ['Dependency "@angular/core" found in package.json'],
|
|
97
116
|
recommendedSkillIds: [
|
|
98
117
|
"angular-guidelines",
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"
|
|
118
|
+
"accessibility-audit",
|
|
119
|
+
"frontend-design",
|
|
120
|
+
"test-driven-development"
|
|
102
121
|
]
|
|
103
122
|
});
|
|
104
123
|
}
|
|
@@ -107,8 +126,10 @@ export async function detectProject(cwd) {
|
|
|
107
126
|
addDetection(results, {
|
|
108
127
|
technology: "vite",
|
|
109
128
|
confidence: viteConfigExists ? 1 : 0.9,
|
|
110
|
-
reasons: viteConfigExists
|
|
111
|
-
|
|
129
|
+
reasons: viteConfigExists
|
|
130
|
+
? ["Found vite.config.*"]
|
|
131
|
+
: ['Dependency "vite" found in package.json'],
|
|
132
|
+
recommendedSkillIds: ["frontend-design"]
|
|
112
133
|
});
|
|
113
134
|
}
|
|
114
135
|
|
|
@@ -117,7 +138,7 @@ export async function detectProject(cwd) {
|
|
|
117
138
|
technology: "playwright",
|
|
118
139
|
confidence: 0.95,
|
|
119
140
|
reasons: ['Dependency "@playwright/test" found in package.json'],
|
|
120
|
-
recommendedSkillIds: ["
|
|
141
|
+
recommendedSkillIds: ["test-driven-development"]
|
|
121
142
|
});
|
|
122
143
|
}
|
|
123
144
|
|
|
@@ -126,16 +147,19 @@ export async function detectProject(cwd) {
|
|
|
126
147
|
technology: "vitest",
|
|
127
148
|
confidence: 0.95,
|
|
128
149
|
reasons: ['Dependency "vitest" found in package.json'],
|
|
129
|
-
recommendedSkillIds: ["
|
|
150
|
+
recommendedSkillIds: ["test-driven-development"]
|
|
130
151
|
});
|
|
131
152
|
}
|
|
132
153
|
|
|
133
|
-
|
|
154
|
+
const tailwindConfigExists = await configExists(cwd, "tailwind.config");
|
|
155
|
+
if ("tailwindcss" in deps || tailwindConfigExists) {
|
|
134
156
|
addDetection(results, {
|
|
135
157
|
technology: "tailwindcss",
|
|
136
|
-
confidence: 0.9,
|
|
137
|
-
reasons:
|
|
138
|
-
|
|
158
|
+
confidence: tailwindConfigExists ? 1 : 0.9,
|
|
159
|
+
reasons: tailwindConfigExists
|
|
160
|
+
? ["Found tailwind.config.*"]
|
|
161
|
+
: ['Dependency "tailwindcss" found in package.json'],
|
|
162
|
+
recommendedSkillIds: ["accessibility-audit", "frontend-design"]
|
|
139
163
|
});
|
|
140
164
|
}
|
|
141
165
|
|
|
@@ -143,8 +167,23 @@ export async function detectProject(cwd) {
|
|
|
143
167
|
addDetection(results, {
|
|
144
168
|
technology: "storybook",
|
|
145
169
|
confidence: storybookDirExists ? 1 : 0.9,
|
|
146
|
-
reasons: storybookDirExists
|
|
147
|
-
|
|
170
|
+
reasons: storybookDirExists
|
|
171
|
+
? ["Found .storybook directory"]
|
|
172
|
+
: ["Storybook dependency found in package.json"],
|
|
173
|
+
recommendedSkillIds: ["frontend-design"]
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const figmaDeps = ["@figma/plugin-typings", "@figma/widget-typings", "figma-api"];
|
|
178
|
+
const figmaDepFound = figmaDeps.find((dep) => dep in deps);
|
|
179
|
+
if (figmaConfigExists || figmaDepFound) {
|
|
180
|
+
addDetection(results, {
|
|
181
|
+
technology: "figma",
|
|
182
|
+
confidence: figmaConfigExists ? 1 : 0.95,
|
|
183
|
+
reasons: figmaConfigExists
|
|
184
|
+
? ["Found figma.config.*"]
|
|
185
|
+
: [`Dependency "${figmaDepFound}" found in package.json`],
|
|
186
|
+
recommendedSkillIds: ["figma-mcp-0to1"]
|
|
148
187
|
});
|
|
149
188
|
}
|
|
150
189
|
|
|
@@ -152,7 +191,20 @@ export async function detectProject(cwd) {
|
|
|
152
191
|
}
|
|
153
192
|
|
|
154
193
|
export async function inspectProjectFiles(cwd) {
|
|
155
|
-
const probes = [
|
|
194
|
+
const probes = [
|
|
195
|
+
"package.json",
|
|
196
|
+
"tsconfig.json",
|
|
197
|
+
"angular.json",
|
|
198
|
+
".storybook",
|
|
199
|
+
"vite.config.js",
|
|
200
|
+
"vite.config.ts",
|
|
201
|
+
"next.config.js",
|
|
202
|
+
"next.config.mjs",
|
|
203
|
+
"tailwind.config.js",
|
|
204
|
+
"tailwind.config.ts",
|
|
205
|
+
"figma.config.js",
|
|
206
|
+
"figma.config.ts"
|
|
207
|
+
];
|
|
156
208
|
const statuses = [];
|
|
157
209
|
|
|
158
210
|
for (const probe of probes) {
|