kungeskill 0.1.0 → 0.3.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/.claude-plugin/marketplace.json +37 -0
- package/README.md +39 -3
- package/package.json +4 -2
- package/plugins/openspec-trace/plugin.json +6 -0
- package/plugins/openspec-trace/skills/opst-business-search/SKILL.md +154 -0
- package/plugins/openspec-trace/skills/opst-code-anysic/SKILL.md +237 -0
- package/plugins/openspec-workflow/plugin.json +6 -0
- package/plugins/openspec-workflow/skills/openspec-apply-change/SKILL.md +156 -0
- package/plugins/openspec-workflow/skills/openspec-archive-change/SKILL.md +114 -0
- package/plugins/openspec-workflow/skills/openspec-explore/SKILL.md +288 -0
- package/plugins/openspec-workflow/skills/openspec-propose/SKILL.md +110 -0
- package/plugins/publish/plugin.json +6 -0
- package/plugins/publish/skills/npm-publish/SKILL.md +255 -0
- package/src/commands/add.js +3 -3
- package/src/commands/list.js +3 -3
- package/src/core/cache.js +34 -2
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: npm-publish
|
|
3
|
+
description: Publish npm packages with full troubleshooting for 2FA, token types, registry mirrors, and cross-platform issues. Use when the user asks to publish a package to npm, fix npm publish errors, or set up npm authentication.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# npm Publish Skill
|
|
7
|
+
|
|
8
|
+
Publish Node.js packages to npm registry with complete error handling and troubleshooting.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
- User asks to publish a package to npm
|
|
13
|
+
- User encounters npm publish errors (401, 403, 404)
|
|
14
|
+
- User needs to configure npm authentication
|
|
15
|
+
- User needs to set up npm tokens with correct permissions
|
|
16
|
+
|
|
17
|
+
## Pre-flight Checklist
|
|
18
|
+
|
|
19
|
+
Before publishing, verify ALL of the following:
|
|
20
|
+
|
|
21
|
+
1. **package.json exists** with required fields:
|
|
22
|
+
- `name` — package name (check availability: `curl -s https://registry.npmjs.org/<name> | head -5`)
|
|
23
|
+
- `version` — semver version
|
|
24
|
+
- `main` or `bin` — entry point
|
|
25
|
+
- `files` — whitelist of files to include (recommended)
|
|
26
|
+
- `license` — MIT, ISC, etc.
|
|
27
|
+
- `description` — short description
|
|
28
|
+
- `keywords` — for discoverability
|
|
29
|
+
|
|
30
|
+
2. **Registry is official npm** (NOT a mirror):
|
|
31
|
+
```bash
|
|
32
|
+
npm config get registry
|
|
33
|
+
# MUST be: https://registry.npmjs.org/
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
3. **Auth token is configured** with correct permissions
|
|
37
|
+
|
|
38
|
+
4. **.npmignore or files field** — ensure only necessary files are published
|
|
39
|
+
|
|
40
|
+
## Step-by-Step Publishing Flow
|
|
41
|
+
|
|
42
|
+
### Step 1: Check and Fix Registry
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Check current registry
|
|
46
|
+
npm config get registry
|
|
47
|
+
|
|
48
|
+
# If it shows a mirror (huawei/taobao/cnpm), switch to official:
|
|
49
|
+
npm config set registry https://registry.npmjs.org/
|
|
50
|
+
|
|
51
|
+
# Common mirrors that will FAIL for publishing:
|
|
52
|
+
# - https://mirrors.huaweicloud.com/repository/npm/
|
|
53
|
+
# - https://registry.npmmirror.com/
|
|
54
|
+
# - https://registry.npm.taobao.org/
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**IMPORTANT**: Mirror registries (华为云/淘宝/cnpm) only support READ operations. Publishing MUST go to the official registry.
|
|
58
|
+
|
|
59
|
+
### Step 2: Generate npm Token
|
|
60
|
+
|
|
61
|
+
Go to https://www.npmjs.com/settings/<username>/tokens
|
|
62
|
+
|
|
63
|
+
**Token Type Selection Guide:**
|
|
64
|
+
|
|
65
|
+
| Token Type | Can Publish | Needs 2FA Bypass | Use Case |
|
|
66
|
+
|------------|-------------|------------------|----------|
|
|
67
|
+
| Classic - Automation | ✗ NO | N/A | CI read-only |
|
|
68
|
+
| Classic - Publish | ✓ YES | Only if 2FA enabled | Simple publish |
|
|
69
|
+
| Granular (recommended) | ✓ YES | Must enable bypass | Fine-grained control |
|
|
70
|
+
|
|
71
|
+
**For accounts with 2FA enabled (most accounts), you MUST:**
|
|
72
|
+
1. Choose **Granular Token**
|
|
73
|
+
2. Set permissions to **Read and publish**
|
|
74
|
+
3. **Enable "Bypass 2FA for publishing"** ← CRITICAL, without this you get 403
|
|
75
|
+
|
|
76
|
+
### Step 3: Configure Auth Token
|
|
77
|
+
|
|
78
|
+
Create `.npmrc` in project root:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
echo "//registry.npmjs.org/:_authToken=npm_YOUR_TOKEN_HERE" > .npmrc
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**SECURITY**: Add `.npmrc` to `.gitignore` and `.npmignore`:
|
|
85
|
+
```bash
|
|
86
|
+
echo ".npmrc" >> .gitignore
|
|
87
|
+
echo ".npmrc" >> .npmignore
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Step 4: Verify Authentication
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm whoami
|
|
94
|
+
# Should output your npm username
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
If empty or error → token is invalid, regenerate.
|
|
98
|
+
|
|
99
|
+
### Step 5: Dry Run (Recommended)
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npm pack --dry-run
|
|
103
|
+
# Shows what files will be included in the package
|
|
104
|
+
# Verify no secrets, no unnecessary files
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Step 6: Publish
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npm publish --access public
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For scoped packages (`@scope/name`):
|
|
114
|
+
```bash
|
|
115
|
+
npm publish --access public
|
|
116
|
+
# --access public is REQUIRED for scoped packages (default is restricted)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Step 7: Verify
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
curl -s https://registry.npmjs.org/<package-name> | head -5
|
|
123
|
+
# Or
|
|
124
|
+
npm info <package-name>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Error Troubleshooting
|
|
128
|
+
|
|
129
|
+
### E401 - Unauthorized
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
npm error code E401
|
|
133
|
+
npm error 401 Unauthorized - GET https://registry.npmjs.org/-/whoami
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Causes & Fixes:**
|
|
137
|
+
1. Token expired → Regenerate at npmjs.com/settings/tokens
|
|
138
|
+
2. Token invalid (typo) → Check `.npmrc` content
|
|
139
|
+
3. Token was revoked → Generate new token
|
|
140
|
+
4. Wrong registry in `.npmrc` → Ensure `//registry.npmjs.org/:_authToken=...`
|
|
141
|
+
|
|
142
|
+
### E403 - Forbidden
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
npm error code E403
|
|
146
|
+
npm error 403 Forbidden - PUT https://registry.npmjs.org/<pkg>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Variant 1: "You may not perform that action with these credentials"**
|
|
150
|
+
- Token type is Automation (read-only) → Regenerate as Publish or Granular token
|
|
151
|
+
|
|
152
|
+
**Variant 2: "Two-factor authentication or granular access token with bypass 2fa enabled is required"**
|
|
153
|
+
- Account has 2FA but token doesn't bypass it
|
|
154
|
+
- Fix: Regenerate Granular Token with "Bypass 2FA for publishing" enabled
|
|
155
|
+
|
|
156
|
+
**Variant 3: "Package name too similar to existing packages"**
|
|
157
|
+
- npm name squatting protection
|
|
158
|
+
- Fix: Choose a different package name or use scoped name `@scope/name`
|
|
159
|
+
|
|
160
|
+
### E404 - Not Found
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
npm error code E404
|
|
164
|
+
npm error 404 Not Found - PUT https://registry.npmjs.org/<pkg>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Causes & Fixes:**
|
|
168
|
+
1. Token doesn't have publish permission → Regenerate with publish access
|
|
169
|
+
2. Publishing to wrong registry → Check `npm config get registry`
|
|
170
|
+
3. Scoped package without org membership → Use `--access public`
|
|
171
|
+
|
|
172
|
+
### ENEEDAUTH - Need Auth
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
npm error code ENEEDAUTH
|
|
176
|
+
npm error need auth This command requires you to be logged in to https://mirrors.xxx.com/
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Cause**: Registry is set to a mirror that requires auth.
|
|
180
|
+
**Fix**: Switch to official registry:
|
|
181
|
+
```bash
|
|
182
|
+
npm config set registry https://registry.npmjs.org/
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Windows-Specific Issues
|
|
186
|
+
|
|
187
|
+
### npm commands produce no output
|
|
188
|
+
|
|
189
|
+
Some Windows shell environments swallow npm output.
|
|
190
|
+
|
|
191
|
+
**Fix**: Call npm via Node directly:
|
|
192
|
+
```bash
|
|
193
|
+
node "/path/to/nodejs/node_modules/npm/bin/npm-cli.js" publish --access public
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Common paths:
|
|
197
|
+
- `C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js`
|
|
198
|
+
- `/d/Program Files/nodejs/node_modules/npm/bin/npm-cli.js` (Git Bash)
|
|
199
|
+
|
|
200
|
+
### npm install creates no node_modules
|
|
201
|
+
|
|
202
|
+
Same shell issue. Use direct invocation:
|
|
203
|
+
```bash
|
|
204
|
+
node "/path/to/nodejs/node_modules/npm/bin/npm-cli.js" install
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Version Bumping
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Patch: 0.1.0 → 0.1.1 (bug fixes)
|
|
211
|
+
npm version patch
|
|
212
|
+
|
|
213
|
+
# Minor: 0.1.0 → 0.2.0 (new features, backwards compatible)
|
|
214
|
+
npm version minor
|
|
215
|
+
|
|
216
|
+
# Major: 0.1.0 → 1.0.0 (breaking changes)
|
|
217
|
+
npm version major
|
|
218
|
+
|
|
219
|
+
# Then publish
|
|
220
|
+
npm publish --access public
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Complete Example Session
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
# 1. Verify registry
|
|
227
|
+
npm config set registry https://registry.npmjs.org/
|
|
228
|
+
|
|
229
|
+
# 2. Create .npmrc with token
|
|
230
|
+
echo "//registry.npmjs.org/:_authToken=npm_xxxxx" > .npmrc
|
|
231
|
+
|
|
232
|
+
# 3. Verify auth
|
|
233
|
+
npm whoami
|
|
234
|
+
# → kungeskills
|
|
235
|
+
|
|
236
|
+
# 4. Check package contents
|
|
237
|
+
npm pack --dry-run
|
|
238
|
+
|
|
239
|
+
# 5. Publish
|
|
240
|
+
npm publish --access public
|
|
241
|
+
# → + kungeskill@0.1.0
|
|
242
|
+
|
|
243
|
+
# 6. Verify on registry
|
|
244
|
+
curl -s https://registry.npmjs.org/kungeskill | head -5
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Checklist Before Every Publish
|
|
248
|
+
|
|
249
|
+
- [ ] `npm config get registry` → `https://registry.npmjs.org/`
|
|
250
|
+
- [ ] `npm whoami` → shows username
|
|
251
|
+
- [ ] `package.json` version is bumped
|
|
252
|
+
- [ ] `.npmrc` has valid token (Granular + bypass 2FA)
|
|
253
|
+
- [ ] `.npmrc` is in `.gitignore` (never commit tokens)
|
|
254
|
+
- [ ] `npm pack --dry-run` → no secrets, no junk files
|
|
255
|
+
- [ ] `npm publish --access public`
|
package/src/commands/add.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const { getMarketplaceSourceDir, isCacheValid } = require('../core/cache');
|
|
5
|
+
const { getMarketplaceSourceDir, isCacheValid, hasBundledPlugins } = require('../core/cache');
|
|
6
6
|
const { parseMarketplace, findSkill } = require('../core/registry');
|
|
7
7
|
const { createSkillSymlink, canCreateJunction, copyDirRecursive } = require('../core/symlink');
|
|
8
8
|
const { findProjectSkillsDir } = require('./shared');
|
|
@@ -11,8 +11,8 @@ const logger = require('../utils/logger');
|
|
|
11
11
|
async function cmdAdd(skillName, opts) {
|
|
12
12
|
const force = opts.force || false;
|
|
13
13
|
|
|
14
|
-
// Ensure cache
|
|
15
|
-
if (!isCacheValid()) {
|
|
14
|
+
// Ensure cache or bundled plugins are available
|
|
15
|
+
if (!isCacheValid() && !hasBundledPlugins()) {
|
|
16
16
|
logger.info('Marketplace cache not initialized. Running init...');
|
|
17
17
|
const { cmdInit } = require('./init');
|
|
18
18
|
await cmdInit();
|
package/src/commands/list.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const { getMarketplaceSourceDir, isCacheValid } = require('../core/cache');
|
|
5
|
+
const { getMarketplaceSourceDir, isCacheValid, hasBundledPlugins } = require('../core/cache');
|
|
6
6
|
const { parseMarketplace, listAllSkills } = require('../core/registry');
|
|
7
7
|
const { findProjectSkillsDir } = require('./shared');
|
|
8
8
|
const logger = require('../utils/logger');
|
|
9
9
|
|
|
10
10
|
function cmdList(opts) {
|
|
11
|
-
if (!isCacheValid()) {
|
|
12
|
-
logger.error('Marketplace
|
|
11
|
+
if (!isCacheValid() && !hasBundledPlugins()) {
|
|
12
|
+
logger.error('Marketplace not available. Run "kungeskill init" first.');
|
|
13
13
|
process.exit(1);
|
|
14
14
|
}
|
|
15
15
|
|
package/src/core/cache.js
CHANGED
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const { getKungeskillsDir
|
|
5
|
+
const { getKungeskillsDir } = require('./config');
|
|
6
|
+
|
|
7
|
+
// Bundled plugins directory (shipped with the npm package)
|
|
8
|
+
const BUNDLED_DIR = path.resolve(__dirname, '..', '..', 'plugins');
|
|
9
|
+
const BUNDLED_MANIFEST = path.resolve(__dirname, '..', '..', '.claude-plugin', 'marketplace.json');
|
|
6
10
|
|
|
7
11
|
function getCacheDir() {
|
|
8
12
|
return path.join(getKungeskillsDir(), 'cache', 'marketplace');
|
|
@@ -22,8 +26,34 @@ function isCacheValid() {
|
|
|
22
26
|
return fs.existsSync(gitDir);
|
|
23
27
|
}
|
|
24
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Check if bundled plugins exist (shipped with npm package).
|
|
31
|
+
* @returns {boolean}
|
|
32
|
+
*/
|
|
33
|
+
function hasBundledPlugins() {
|
|
34
|
+
return fs.existsSync(BUNDLED_MANIFEST) && fs.existsSync(BUNDLED_DIR);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get the bundled plugins directory path.
|
|
39
|
+
* @returns {string}
|
|
40
|
+
*/
|
|
41
|
+
function getBundledDir() {
|
|
42
|
+
return path.resolve(__dirname, '..', '..');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get the effective marketplace source directory.
|
|
47
|
+
* Priority: git cache > bundled plugins
|
|
48
|
+
* @returns {string}
|
|
49
|
+
*/
|
|
25
50
|
function getMarketplaceSourceDir() {
|
|
26
|
-
|
|
51
|
+
if (isCacheValid()) {
|
|
52
|
+
return getCacheDir();
|
|
53
|
+
}
|
|
54
|
+
if (hasBundledPlugins()) {
|
|
55
|
+
return getBundledDir();
|
|
56
|
+
}
|
|
27
57
|
return getCacheDir();
|
|
28
58
|
}
|
|
29
59
|
|
|
@@ -31,5 +61,7 @@ module.exports = {
|
|
|
31
61
|
getCacheDir,
|
|
32
62
|
ensureCacheDir,
|
|
33
63
|
isCacheValid,
|
|
64
|
+
hasBundledPlugins,
|
|
65
|
+
getBundledDir,
|
|
34
66
|
getMarketplaceSourceDir
|
|
35
67
|
};
|