claude-skill-lord 2.1.1 → 2.2.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.
Files changed (59) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/CLAUDE.md +2 -2
  4. package/README.md +139 -225
  5. package/manifests/install-modules.json +1 -1
  6. package/package.json +3 -7
  7. package/scripts/lib/profile-utils.js +3 -3
  8. package/scripts/sl.js +13 -4
  9. package/.commitlintrc.json +0 -27
  10. package/.env.example +0 -26
  11. package/.releaserc.json +0 -119
  12. package/.repomixignore +0 -22
  13. package/skills/SKILL.md +0 -207
  14. package/skills/ai-multimodal/scripts/tests/requirements.txt +0 -20
  15. package/skills/ai-multimodal/scripts/tests/test_document_converter.py +0 -74
  16. package/skills/ai-multimodal/scripts/tests/test_failures.log +0 -258
  17. package/skills/ai-multimodal/scripts/tests/test_gemini_batch_process.py +0 -362
  18. package/skills/ai-multimodal/scripts/tests/test_media_optimizer.py +0 -373
  19. package/skills/better-auth/scripts/tests/test_better_auth_init.py +0 -421
  20. package/skills/chrome-devtools/scripts/__tests__/selector.test.js +0 -210
  21. package/skills/databases/scripts/tests/coverage-db.json +0 -1
  22. package/skills/databases/scripts/tests/requirements.txt +0 -4
  23. package/skills/databases/scripts/tests/test_db_backup.py +0 -340
  24. package/skills/databases/scripts/tests/test_db_migrate.py +0 -277
  25. package/skills/databases/scripts/tests/test_db_performance_check.py +0 -370
  26. package/skills/debugging/scripts/find-polluter.test.md +0 -102
  27. package/skills/devops/scripts/tests/requirements.txt +0 -3
  28. package/skills/devops/scripts/tests/test_cloudflare_deploy.py +0 -285
  29. package/skills/devops/scripts/tests/test_docker_optimize.py +0 -436
  30. package/skills/docs-seeker/scripts/tests/run-tests.js +0 -72
  31. package/skills/docs-seeker/scripts/tests/test-analyze-llms.js +0 -119
  32. package/skills/docs-seeker/scripts/tests/test-detect-topic.js +0 -112
  33. package/skills/docs-seeker/scripts/tests/test-fetch-docs.js +0 -84
  34. package/skills/fixtures/compliant_trace.jsonl +0 -5
  35. package/skills/fixtures/noncompliant_trace.jsonl +0 -3
  36. package/skills/fixtures/tdd_spec.yaml +0 -44
  37. package/skills/media-processing/scripts/tests/requirements.txt +0 -2
  38. package/skills/media-processing/scripts/tests/test_batch_resize.py +0 -372
  39. package/skills/media-processing/scripts/tests/test_media_convert.py +0 -259
  40. package/skills/media-processing/scripts/tests/test_video_optimize.py +0 -397
  41. package/skills/repomix/scripts/tests/test_repomix_batch.py +0 -531
  42. package/skills/sequential-thinking/tests/format-thought.test.js +0 -133
  43. package/skills/sequential-thinking/tests/process-thought.test.js +0 -215
  44. package/skills/shopify/scripts/tests/test_shopify_init.py +0 -385
  45. package/skills/skill-comply/fixtures/compliant_trace.jsonl +0 -5
  46. package/skills/skill-comply/fixtures/noncompliant_trace.jsonl +0 -3
  47. package/skills/skill-comply/fixtures/tdd_spec.yaml +0 -44
  48. package/skills/skill-comply/tests/test_grader.py +0 -137
  49. package/skills/skill-comply/tests/test_parser.py +0 -90
  50. package/skills/tests/test_grader.py +0 -137
  51. package/skills/tests/test_parser.py +0 -90
  52. package/skills/ui-styling/scripts/tests/coverage-ui.json +0 -1
  53. package/skills/ui-styling/scripts/tests/requirements.txt +0 -3
  54. package/skills/ui-styling/scripts/tests/test_shadcn_add.py +0 -266
  55. package/skills/ui-styling/scripts/tests/test_tailwind_config_gen.py +0 -336
  56. package/skills/web-frameworks/scripts/tests/coverage-web.json +0 -1
  57. package/skills/web-frameworks/scripts/tests/requirements.txt +0 -3
  58. package/skills/web-frameworks/scripts/tests/test_nextjs_init.py +0 -319
  59. package/skills/web-frameworks/scripts/tests/test_turborepo_migrate.py +0 -374
package/scripts/sl.js CHANGED
@@ -294,9 +294,18 @@ const commands = {
294
294
  agents.forEach(a => console.log(` - ${a.replace('.md', '')}`));
295
295
 
296
296
  const skillsDir = path.join(rootDir, 'skills');
297
- const skills = fs.readdirSync(skillsDir, { withFileTypes: true })
298
- .filter(e => e.isDirectory() && fs.existsSync(path.join(skillsDir, e.name, 'SKILL.md')))
299
- .map(e => e.name);
297
+ const skills = [];
298
+ const collectSkills = (dir, prefix) => {
299
+ fs.readdirSync(dir, { withFileTypes: true }).forEach(e => {
300
+ if (!e.isDirectory()) return;
301
+ const full = path.join(dir, e.name);
302
+ const label = prefix ? `${prefix}/${e.name}` : e.name;
303
+ if (fs.existsSync(path.join(full, 'SKILL.md'))) skills.push(label);
304
+ else collectSkills(full, label);
305
+ });
306
+ };
307
+ collectSkills(skillsDir, '');
308
+ skills.sort();
300
309
  console.log(`\n Skills: ${skills.length}`);
301
310
  skills.forEach(s => console.log(` - ${s}`));
302
311
 
@@ -449,7 +458,7 @@ const commands = {
449
458
  Usage: csl <command> [options]
450
459
 
451
460
  Commands:
452
- init Install in current project (43 agents, 161 skills, 114 commands)
461
+ init Install in current project (43 agents, 165 skills, 114 commands)
453
462
  update Update CLI to latest version
454
463
  migrate Update project files after csl update
455
464
  diff Compare project files with source package
@@ -1,27 +0,0 @@
1
- {
2
- "extends": ["@commitlint/config-conventional"],
3
- "rules": {
4
- "type-enum": [
5
- 2,
6
- "always",
7
- [
8
- "build",
9
- "chore",
10
- "ci",
11
- "docs",
12
- "feat",
13
- "fix",
14
- "perf",
15
- "refactor",
16
- "revert",
17
- "style",
18
- "test"
19
- ]
20
- ],
21
- "subject-case": [2, "never", ["sentence-case", "start-case", "pascal-case", "upper-case"]],
22
- "subject-empty": [2, "never"],
23
- "subject-full-stop": [2, "never", "."],
24
- "header-max-length": [2, "always", 100],
25
- "body-max-line-length": [1, "always", 300]
26
- }
27
- }
package/.env.example DELETED
@@ -1,26 +0,0 @@
1
- # Claude Code Notification Hooks - Environment Variables
2
- # Copy this file to .env and fill in your actual values
3
- # NEVER commit .env files to version control
4
-
5
- # ============================================
6
- # Discord Notifications
7
- # ============================================
8
- # Get your webhook URL from Discord:
9
- # Server Settings → Integrations → Webhooks → New Webhook
10
- # Format: https://discord.com/api/webhooks/WEBHOOK_ID/WEBHOOK_TOKEN
11
- DISCORD_WEBHOOK_URL=
12
-
13
- # ============================================
14
- # Telegram Notifications
15
- # ============================================
16
- # Get bot token from @BotFather in Telegram
17
- # Send /newbot to @BotFather and follow the prompts
18
- # Format: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz
19
- TELEGRAM_BOT_TOKEN=
20
-
21
- # Get chat ID from Telegram
22
- # For DM: Send message to bot, then visit:
23
- # https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates
24
- # For groups: Add bot to group, send message, check same URL
25
- # Format: 987654321 (positive) or -100123456789 (negative for groups)
26
- TELEGRAM_CHAT_ID=
package/.releaserc.json DELETED
@@ -1,119 +0,0 @@
1
- {
2
- "branches": [
3
- "main"
4
- ],
5
- "plugins": [
6
- [
7
- "@semantic-release/commit-analyzer",
8
- {
9
- "preset": "conventionalcommits",
10
- "releaseRules": [
11
- {
12
- "type": "docs",
13
- "scope": "README",
14
- "release": "patch"
15
- },
16
- {
17
- "type": "refactor",
18
- "release": "patch"
19
- },
20
- {
21
- "type": "style",
22
- "release": "patch"
23
- }
24
- ]
25
- }
26
- ],
27
- [
28
- "@semantic-release/release-notes-generator",
29
- {
30
- "preset": "conventionalcommits",
31
- "presetConfig": {
32
- "types": [
33
- {
34
- "type": "feat",
35
- "section": "🚀 Features"
36
- },
37
- {
38
- "type": "fix",
39
- "section": "🐞 Bug Fixes"
40
- },
41
- {
42
- "type": "docs",
43
- "section": "📚 Documentation"
44
- },
45
- {
46
- "type": "style",
47
- "section": "💄 Styles"
48
- },
49
- {
50
- "type": "refactor",
51
- "section": "♻️ Code Refactoring"
52
- },
53
- {
54
- "type": "perf",
55
- "section": "⚡ Performance Improvements"
56
- },
57
- {
58
- "type": "test",
59
- "section": "✅ Tests"
60
- },
61
- {
62
- "type": "build",
63
- "section": "🏗️ Build System"
64
- },
65
- {
66
- "type": "ci",
67
- "section": "👷 CI"
68
- }
69
- ]
70
- }
71
- }
72
- ],
73
- [
74
- "@semantic-release/changelog",
75
- {
76
- "changelogFile": "CHANGELOG.md"
77
- }
78
- ],
79
- [
80
- "@semantic-release/npm",
81
- {
82
- "npmPublish": false
83
- }
84
- ],
85
- [
86
- "@semantic-release/exec",
87
- {
88
- "prepareCmd": "node scripts/prepare-release-assets.cjs ${nextRelease.version}"
89
- }
90
- ],
91
- [
92
- "@semantic-release/github",
93
- {
94
- "assets": [
95
- {
96
- "path": "CHANGELOG.md",
97
- "label": "Changelog"
98
- },
99
- {
100
- "path": "dist/claude-skill-lord.zip",
101
- "label": "Claude Skill Lord Package"
102
- }
103
- ]
104
- }
105
- ],
106
- [
107
- "@semantic-release/git",
108
- {
109
- "assets": [
110
- "CHANGELOG.md",
111
- "package.json",
112
- "package-lock.json",
113
- ".claude/metadata.json"
114
- ],
115
- "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
116
- }
117
- ]
118
- ]
119
- }
package/.repomixignore DELETED
@@ -1,22 +0,0 @@
1
- docs/*
2
- plans/*
3
- assets/*
4
- dist/*
5
- coverage/*
6
- build/*
7
- ios/*
8
- android/*
9
- tests/*
10
- __tests__/*
11
- __pycache__/*
12
- node_modules/*
13
-
14
- .opencode/*
15
- .claude/*
16
- .serena/*
17
- .pnpm-store/*
18
- .github/*
19
- .dart_tool/*
20
- .idea/*
21
- .husky/*
22
- .venv/*
package/skills/SKILL.md DELETED
@@ -1,207 +0,0 @@
1
- ---
2
- name: x-api
3
- description: X/Twitter API integration for posting tweets, threads, reading timelines, search, and analytics. Covers OAuth auth patterns, rate limits, and platform-native content posting. Use when the user wants to interact with X programmatically.
4
- ---
5
-
6
- # X API
7
-
8
- Programmatic interaction with X (Twitter) for posting, reading, searching, and analytics.
9
-
10
- ## When to Activate
11
-
12
- - User wants to post tweets or threads programmatically
13
- - Reading timeline, mentions, or user data from X
14
- - Searching X for content, trends, or conversations
15
- - Building X integrations or bots
16
- - Analytics and engagement tracking
17
- - User says "post to X", "tweet", "X API", or "Twitter API"
18
-
19
- ## Authentication
20
-
21
- ### OAuth 2.0 Bearer Token (App-Only)
22
-
23
- Best for: read-heavy operations, search, public data.
24
-
25
- ```bash
26
- # Environment setup
27
- export X_BEARER_TOKEN="your-bearer-token"
28
- ```
29
-
30
- ```python
31
- import os
32
- import requests
33
-
34
- bearer = os.environ["X_BEARER_TOKEN"]
35
- headers = {"Authorization": f"Bearer {bearer}"}
36
-
37
- # Search recent tweets
38
- resp = requests.get(
39
- "https://api.x.com/2/tweets/search/recent",
40
- headers=headers,
41
- params={"query": "claude code", "max_results": 10}
42
- )
43
- tweets = resp.json()
44
- ```
45
-
46
- ### OAuth 1.0a (User Context)
47
-
48
- Required for: posting tweets, managing account, DMs.
49
-
50
- ```bash
51
- # Environment setup — source before use
52
- export X_API_KEY="your-api-key"
53
- export X_API_SECRET="your-api-secret"
54
- export X_ACCESS_TOKEN="your-access-token"
55
- export X_ACCESS_SECRET="your-access-secret"
56
- ```
57
-
58
- ```python
59
- import os
60
- from requests_oauthlib import OAuth1Session
61
-
62
- oauth = OAuth1Session(
63
- os.environ["X_API_KEY"],
64
- client_secret=os.environ["X_API_SECRET"],
65
- resource_owner_key=os.environ["X_ACCESS_TOKEN"],
66
- resource_owner_secret=os.environ["X_ACCESS_SECRET"],
67
- )
68
- ```
69
-
70
- ## Core Operations
71
-
72
- ### Post a Tweet
73
-
74
- ```python
75
- resp = oauth.post(
76
- "https://api.x.com/2/tweets",
77
- json={"text": "Hello from Claude Code"}
78
- )
79
- resp.raise_for_status()
80
- tweet_id = resp.json()["data"]["id"]
81
- ```
82
-
83
- ### Post a Thread
84
-
85
- ```python
86
- def post_thread(oauth, tweets: list[str]) -> list[str]:
87
- ids = []
88
- reply_to = None
89
- for text in tweets:
90
- payload = {"text": text}
91
- if reply_to:
92
- payload["reply"] = {"in_reply_to_tweet_id": reply_to}
93
- resp = oauth.post("https://api.x.com/2/tweets", json=payload)
94
- tweet_id = resp.json()["data"]["id"]
95
- ids.append(tweet_id)
96
- reply_to = tweet_id
97
- return ids
98
- ```
99
-
100
- ### Read User Timeline
101
-
102
- ```python
103
- resp = requests.get(
104
- f"https://api.x.com/2/users/{user_id}/tweets",
105
- headers=headers,
106
- params={
107
- "max_results": 10,
108
- "tweet.fields": "created_at,public_metrics",
109
- }
110
- )
111
- ```
112
-
113
- ### Search Tweets
114
-
115
- ```python
116
- resp = requests.get(
117
- "https://api.x.com/2/tweets/search/recent",
118
- headers=headers,
119
- params={
120
- "query": "from:affaanmustafa -is:retweet",
121
- "max_results": 10,
122
- "tweet.fields": "public_metrics,created_at",
123
- }
124
- )
125
- ```
126
-
127
- ### Get User by Username
128
-
129
- ```python
130
- resp = requests.get(
131
- "https://api.x.com/2/users/by/username/affaanmustafa",
132
- headers=headers,
133
- params={"user.fields": "public_metrics,description,created_at"}
134
- )
135
- ```
136
-
137
- ### Upload Media and Post
138
-
139
- ```python
140
- # Media upload uses v1.1 endpoint
141
-
142
- # Step 1: Upload media
143
- media_resp = oauth.post(
144
- "https://upload.twitter.com/1.1/media/upload.json",
145
- files={"media": open("image.png", "rb")}
146
- )
147
- media_id = media_resp.json()["media_id_string"]
148
-
149
- # Step 2: Post with media
150
- resp = oauth.post(
151
- "https://api.x.com/2/tweets",
152
- json={"text": "Check this out", "media": {"media_ids": [media_id]}}
153
- )
154
- ```
155
-
156
- ## Rate Limits
157
-
158
- X API rate limits vary by endpoint, auth method, and account tier, and they change over time. Always:
159
- - Check the current X developer docs before hardcoding assumptions
160
- - Read `x-rate-limit-remaining` and `x-rate-limit-reset` headers at runtime
161
- - Back off automatically instead of relying on static tables in code
162
-
163
- ```python
164
- import time
165
-
166
- remaining = int(resp.headers.get("x-rate-limit-remaining", 0))
167
- if remaining < 5:
168
- reset = int(resp.headers.get("x-rate-limit-reset", 0))
169
- wait = max(0, reset - int(time.time()))
170
- print(f"Rate limit approaching. Resets in {wait}s")
171
- ```
172
-
173
- ## Error Handling
174
-
175
- ```python
176
- resp = oauth.post("https://api.x.com/2/tweets", json={"text": content})
177
- if resp.status_code == 201:
178
- return resp.json()["data"]["id"]
179
- elif resp.status_code == 429:
180
- reset = int(resp.headers["x-rate-limit-reset"])
181
- raise Exception(f"Rate limited. Resets at {reset}")
182
- elif resp.status_code == 403:
183
- raise Exception(f"Forbidden: {resp.json().get('detail', 'check permissions')}")
184
- else:
185
- raise Exception(f"X API error {resp.status_code}: {resp.text}")
186
- ```
187
-
188
- ## Security
189
-
190
- - **Never hardcode tokens.** Use environment variables or `.env` files.
191
- - **Never commit `.env` files.** Add to `.gitignore`.
192
- - **Rotate tokens** if exposed. Regenerate at developer.x.com.
193
- - **Use read-only tokens** when write access is not needed.
194
- - **Store OAuth secrets securely** — not in source code or logs.
195
-
196
- ## Integration with Content Engine
197
-
198
- Use `content-engine` skill to generate platform-native content, then post via X API:
199
- 1. Generate content with content-engine (X platform format)
200
- 2. Validate length (280 chars for single tweet)
201
- 3. Post via X API using patterns above
202
- 4. Track engagement via public_metrics
203
-
204
- ## Related Skills
205
-
206
- - `content-engine` — Generate platform-native content for X
207
- - `crosspost` — Distribute content across X, LinkedIn, and other platforms
@@ -1,20 +0,0 @@
1
- # Core dependencies
2
- google-genai>=0.2.0
3
- python-dotenv>=1.0.0
4
-
5
- # Image processing
6
- pillow>=10.0.0
7
-
8
- # PDF processing
9
- pypdf>=3.0.0
10
-
11
- # Document conversion
12
- markdown>=3.5
13
-
14
- # Testing
15
- pytest>=7.4.0
16
- pytest-cov>=4.1.0
17
- pytest-mock>=3.12.0
18
-
19
- # Optional dependencies for full functionality
20
- # ffmpeg-python>=0.2.0 # For media optimization (requires ffmpeg installed)
@@ -1,74 +0,0 @@
1
- """
2
- Tests for document_converter.py
3
- """
4
-
5
- import pytest
6
- import sys
7
- from pathlib import Path
8
- from unittest.mock import Mock, patch, MagicMock, mock_open
9
-
10
- sys.path.insert(0, str(Path(__file__).parent.parent))
11
-
12
- import document_converter as dc
13
-
14
-
15
- class TestAPIKeyFinder:
16
- """Test API key finding logic."""
17
-
18
- @patch.dict('os.environ', {'GEMINI_API_KEY': 'test-key-from-env'})
19
- def test_find_api_key_from_env(self):
20
- """Test finding API key from environment."""
21
- api_key = dc.find_api_key()
22
- assert api_key == 'test-key-from-env'
23
-
24
- @patch.dict('os.environ', {}, clear=True)
25
- @patch('document_converter.load_dotenv', None)
26
- def test_find_api_key_no_key(self):
27
- """Test when no API key is available."""
28
- api_key = dc.find_api_key()
29
- assert api_key is None
30
-
31
-
32
- class TestProjectRoot:
33
- """Test project root finding."""
34
-
35
- @patch('pathlib.Path.exists')
36
- def test_find_project_root_with_git(self, mock_exists):
37
- """Test finding project root with .git directory."""
38
- root = dc.find_project_root()
39
- assert isinstance(root, Path)
40
-
41
-
42
- class TestMimeType:
43
- """Test MIME type detection."""
44
-
45
- def test_pdf_mime_type(self):
46
- """Test PDF MIME type."""
47
- assert dc.get_mime_type('document.pdf') == 'application/pdf'
48
-
49
- def test_image_mime_types(self):
50
- """Test image MIME types."""
51
- assert dc.get_mime_type('image.jpg') == 'image/jpeg'
52
- assert dc.get_mime_type('image.png') == 'image/png'
53
-
54
- def test_unknown_mime_type(self):
55
- """Test unknown file extension."""
56
- assert dc.get_mime_type('file.unknown') == 'application/octet-stream'
57
-
58
-
59
- class TestIntegration:
60
- """Integration tests."""
61
-
62
- def test_mime_type_integration(self):
63
- """Test MIME type detection with various extensions."""
64
- test_cases = [
65
- ('document.pdf', 'application/pdf'),
66
- ('image.jpg', 'image/jpeg'),
67
- ('unknown.xyz', 'application/octet-stream'),
68
- ]
69
- for file_path, expected_mime in test_cases:
70
- assert dc.get_mime_type(file_path) == expected_mime
71
-
72
-
73
- if __name__ == '__main__':
74
- pytest.main([__file__, '-v', '--cov=document_converter', '--cov-report=term-missing'])