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.
@@ -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`
@@ -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 exists
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();
@@ -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 cache not initialized. Run "kungeskill init" first.');
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, getConfig, saveConfig } = require('./config');
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
- // The root of the cloned marketplace within the cache
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
  };