@opendirectory.dev/skills 0.1.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/skills/claude-md-generator/.env.example +7 -0
- package/.claude/skills/claude-md-generator/README.md +78 -0
- package/.claude/skills/claude-md-generator/SKILL.md +248 -0
- package/.claude/skills/claude-md-generator/evals/evals.json +35 -0
- package/.claude/skills/claude-md-generator/references/section-guide.md +175 -0
- package/dist/e2e.test.d.ts +1 -0
- package/dist/e2e.test.js +62 -0
- package/dist/fs-adapters.d.ts +4 -0
- package/dist/fs-adapters.js +101 -0
- package/dist/fs-adapters.test.d.ts +1 -0
- package/dist/fs-adapters.test.js +108 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +211 -0
- package/dist/transformers.d.ts +6 -0
- package/dist/transformers.js +2 -0
- package/package.json +25 -0
- package/registry.json +226 -0
- package/skills/blog-cover-image-cli/.github/workflows/publish.yml +19 -0
- package/skills/blog-cover-image-cli/LICENSE +15 -0
- package/skills/blog-cover-image-cli/README.md +126 -0
- package/skills/blog-cover-image-cli/SKILL.md +7 -0
- package/skills/blog-cover-image-cli/agent-skill/blog-cover-generator/README.md +30 -0
- package/skills/blog-cover-image-cli/agent-skill/blog-cover-generator/SKILL.md +72 -0
- package/skills/blog-cover-image-cli/bin/cli.js +226 -0
- package/skills/blog-cover-image-cli/examples/100x_UX_Research_AI_Agent.png +0 -0
- package/skills/blog-cover-image-cli/examples/Firecrawl-supabase-bolt.png +0 -0
- package/skills/blog-cover-image-cli/examples/Git-City_Case_study_Cover_Image.jpg +0 -0
- package/skills/blog-cover-image-cli/examples/THE DISTRIBUTION LAYER (2).png +0 -0
- package/skills/blog-cover-image-cli/examples/canva-perplexity-duolingo-cover-image.png +0 -0
- package/skills/blog-cover-image-cli/examples/gamma-mistral-veed.png +0 -0
- package/skills/blog-cover-image-cli/examples/server-survival-case-study-cover-image(1).png +0 -0
- package/skills/blog-cover-image-cli/examples/viral-meme-automation.png +0 -0
- package/skills/blog-cover-image-cli/index.js +2 -0
- package/skills/blog-cover-image-cli/package-lock.json +2238 -0
- package/skills/blog-cover-image-cli/package.json +37 -0
- package/skills/blog-cover-image-cli/src/geminiGenerator.js +126 -0
- package/skills/blog-cover-image-cli/src/imageValidator.js +54 -0
- package/skills/blog-cover-image-cli/src/logoFetcher.js +86 -0
- package/skills/claude-md-generator/.env.example +7 -0
- package/skills/claude-md-generator/README.md +78 -0
- package/skills/claude-md-generator/SKILL.md +254 -0
- package/skills/claude-md-generator/evals/evals.json +35 -0
- package/skills/claude-md-generator/references/section-guide.md +175 -0
- package/skills/cook-the-blog/README.md +86 -0
- package/skills/cook-the-blog/SKILL.md +130 -0
- package/skills/dependency-update-bot/.env.example +13 -0
- package/skills/dependency-update-bot/README.md +101 -0
- package/skills/dependency-update-bot/SKILL.md +376 -0
- package/skills/dependency-update-bot/evals/evals.json +45 -0
- package/skills/dependency-update-bot/references/changelog-patterns.md +201 -0
- package/skills/docs-from-code/.env.example +13 -0
- package/skills/docs-from-code/README.md +97 -0
- package/skills/docs-from-code/SKILL.md +160 -0
- package/skills/docs-from-code/evals/evals.json +29 -0
- package/skills/docs-from-code/references/extraction-guide.md +174 -0
- package/skills/docs-from-code/references/output-template.md +135 -0
- package/skills/docs-from-code/scripts/extract_py.py +238 -0
- package/skills/docs-from-code/scripts/extract_ts.ts +284 -0
- package/skills/docs-from-code/scripts/package.json +18 -0
- package/skills/explain-this-pr/README.md +74 -0
- package/skills/explain-this-pr/SKILL.md +130 -0
- package/skills/explain-this-pr/evals/evals.json +35 -0
- package/skills/google-trends-api-skills/README.md +78 -0
- package/skills/google-trends-api-skills/SKILL.md +7 -0
- package/skills/google-trends-api-skills/google-trends-api/SKILL.md +163 -0
- package/skills/google-trends-api-skills/google-trends-api/references/api-responses.md +188 -0
- package/skills/google-trends-api-skills/google-trends-api/scripts/discover_keywords.py +344 -0
- package/skills/google-trends-api-skills/seo-keyword-research/SKILL.md +205 -0
- package/skills/google-trends-api-skills/seo-keyword-research/references/keyword-placement-guide.md +89 -0
- package/skills/google-trends-api-skills/seo-keyword-research/references/tech-blog-examples.md +207 -0
- package/skills/google-trends-api-skills/seo-keyword-research/scripts/blog_seo_research.py +373 -0
- package/skills/hackernews-intel/.env.example +33 -0
- package/skills/hackernews-intel/README.md +161 -0
- package/skills/hackernews-intel/SKILL.md +156 -0
- package/skills/hackernews-intel/evals/evals.json +35 -0
- package/skills/hackernews-intel/package.json +15 -0
- package/skills/hackernews-intel/scripts/monitor-hn.js +258 -0
- package/skills/kill-the-standup/.env.example +22 -0
- package/skills/kill-the-standup/README.md +84 -0
- package/skills/kill-the-standup/SKILL.md +169 -0
- package/skills/kill-the-standup/evals/evals.json +35 -0
- package/skills/kill-the-standup/references/standup-format.md +102 -0
- package/skills/linkedin-post-generator/.env.example +14 -0
- package/skills/linkedin-post-generator/README.md +107 -0
- package/skills/linkedin-post-generator/SKILL.md +228 -0
- package/skills/linkedin-post-generator/evals/evals.json +35 -0
- package/skills/linkedin-post-generator/references/linkedin-format.md +216 -0
- package/skills/linkedin-post-generator/references/output-template.md +154 -0
- package/skills/llms-txt-generator/.env.example +18 -0
- package/skills/llms-txt-generator/README.md +142 -0
- package/skills/llms-txt-generator/SKILL.md +176 -0
- package/skills/llms-txt-generator/evals/evals.json +35 -0
- package/skills/llms-txt-generator/references/llms-txt-spec.md +88 -0
- package/skills/llms-txt-generator/references/output-template.md +76 -0
- package/skills/llms-txt-generator/test-output/genzcareer.in/llms.txt +31 -0
- package/skills/luma-attendees-scraper/README.md +170 -0
- package/skills/luma-attendees-scraper/SKILL.md +7 -0
- package/skills/luma-attendees-scraper/luma_attendees_export.js +223 -0
- package/skills/meeting-brief-generator/.env.example +21 -0
- package/skills/meeting-brief-generator/README.md +90 -0
- package/skills/meeting-brief-generator/SKILL.md +275 -0
- package/skills/meeting-brief-generator/evals/evals.json +35 -0
- package/skills/meeting-brief-generator/references/brief-format.md +114 -0
- package/skills/meeting-brief-generator/references/output-template.md +150 -0
- package/skills/meta-ads-skill/README.md +100 -0
- package/skills/meta-ads-skill/SKILL.md +7 -0
- package/skills/meta-ads-skill/meta-ads-skill/SKILL.md +41 -0
- package/skills/meta-ads-skill/meta-ads-skill/references/report_templates.md +47 -0
- package/skills/meta-ads-skill/meta-ads-skill/references/workflows.md +51 -0
- package/skills/meta-ads-skill/meta-ads-skill/scripts/auth_check.py +22 -0
- package/skills/meta-ads-skill/meta-ads-skill/scripts/formatters.py +46 -0
- package/skills/newsletter-digest/.env.example +20 -0
- package/skills/newsletter-digest/README.md +147 -0
- package/skills/newsletter-digest/SKILL.md +221 -0
- package/skills/newsletter-digest/evals/evals.json +35 -0
- package/skills/newsletter-digest/feeds.json +7 -0
- package/skills/newsletter-digest/package.json +15 -0
- package/skills/newsletter-digest/references/digest-format.md +123 -0
- package/skills/newsletter-digest/references/output-template.md +136 -0
- package/skills/newsletter-digest/scripts/fetch-feeds.js +141 -0
- package/skills/newsletter-digest/scripts/ghost-publish.js +147 -0
- package/skills/noise2blog/.env.example +16 -0
- package/skills/noise2blog/README.md +107 -0
- package/skills/noise2blog/SKILL.md +229 -0
- package/skills/noise2blog/evals/evals.json +35 -0
- package/skills/noise2blog/references/blog-format.md +188 -0
- package/skills/noise2blog/references/output-template.md +184 -0
- package/skills/outreach-sequence-builder/.env.example +12 -0
- package/skills/outreach-sequence-builder/README.md +108 -0
- package/skills/outreach-sequence-builder/SKILL.md +248 -0
- package/skills/outreach-sequence-builder/evals/evals.json +36 -0
- package/skills/outreach-sequence-builder/references/output-template.md +171 -0
- package/skills/outreach-sequence-builder/references/sequence-format.md +167 -0
- package/skills/outreach-sequence-builder/references/signal-playbook.md +117 -0
- package/skills/position-me/README.md +71 -0
- package/skills/position-me/SKILL.md +7 -0
- package/skills/position-me/position-me/SKILL.md +50 -0
- package/skills/position-me/position-me/references/EVALUATION_SOP.md +40 -0
- package/skills/position-me/position-me/references/REPORT_TEMPLATE.md +58 -0
- package/skills/position-me/position-me/scripts/extract_links.py +49 -0
- package/skills/pr-description-writer/README.md +81 -0
- package/skills/pr-description-writer/SKILL.md +141 -0
- package/skills/pr-description-writer/evals/evals.json +35 -0
- package/skills/pr-description-writer/references/pr-format-guide.md +145 -0
- package/skills/producthunt-launch-kit/.env.example +7 -0
- package/skills/producthunt-launch-kit/README.md +95 -0
- package/skills/producthunt-launch-kit/SKILL.md +380 -0
- package/skills/producthunt-launch-kit/evals/evals.json +35 -0
- package/skills/producthunt-launch-kit/references/copy-rules.md +124 -0
- package/skills/reddit-icp-monitor/.env.example +16 -0
- package/skills/reddit-icp-monitor/README.md +117 -0
- package/skills/reddit-icp-monitor/SKILL.md +271 -0
- package/skills/reddit-icp-monitor/evals/evals.json +40 -0
- package/skills/reddit-icp-monitor/references/icp-format.md +131 -0
- package/skills/reddit-icp-monitor/references/reply-rules.md +110 -0
- package/skills/reddit-post-engine/.env.example +13 -0
- package/skills/reddit-post-engine/README.md +103 -0
- package/skills/reddit-post-engine/SKILL.md +303 -0
- package/skills/reddit-post-engine/evals/evals.json +35 -0
- package/skills/reddit-post-engine/references/subreddit-playbook.md +156 -0
- package/skills/schema-markup-generator/.env.example +19 -0
- package/skills/schema-markup-generator/README.md +114 -0
- package/skills/schema-markup-generator/SKILL.md +192 -0
- package/skills/schema-markup-generator/evals/evals.json +35 -0
- package/skills/schema-markup-generator/references/json-ld-spec.md +263 -0
- package/skills/schema-markup-generator/references/output-template.md +556 -0
- package/skills/show-hn-writer/.env.example +14 -0
- package/skills/show-hn-writer/README.md +88 -0
- package/skills/show-hn-writer/SKILL.md +303 -0
- package/skills/show-hn-writer/evals/evals.json +35 -0
- package/skills/show-hn-writer/references/hn-rules.md +74 -0
- package/skills/show-hn-writer/references/title-formulas.md +93 -0
- package/skills/stargazer/README.md +79 -0
- package/skills/stargazer/SKILL.md +7 -0
- package/skills/stargazer/stargazer-skill/SKILL.md +58 -0
- package/skills/stargazer/stargazer-skill/assets/.env.example +18 -0
- package/skills/stargazer/stargazer-skill/scripts/convert_to_csv.py +63 -0
- package/skills/stargazer/stargazer-skill/scripts/count_emails.py +52 -0
- package/skills/stargazer/stargazer-skill/scripts/stargazer_deep_extractor.py +450 -0
- package/skills/tweet-thread-from-blog/.env.example +14 -0
- package/skills/tweet-thread-from-blog/README.md +109 -0
- package/skills/tweet-thread-from-blog/SKILL.md +177 -0
- package/skills/tweet-thread-from-blog/evals/evals.json +35 -0
- package/skills/tweet-thread-from-blog/references/output-template.md +193 -0
- package/skills/tweet-thread-from-blog/references/thread-format.md +107 -0
- package/skills/twitter-GTM-find-skill/README.md +43 -0
- package/skills/twitter-GTM-find-skill/SKILL.md +7 -0
- package/skills/twitter-GTM-find-skill/twitter-GTM-find/SKILL.md +37 -0
- package/skills/twitter-GTM-find-skill/twitter-GTM-find/references/icp-checklist.md +35 -0
- package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/package.json +23 -0
- package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/run_pipeline.sh +8 -0
- package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/debug.ts +23 -0
- package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/extractor.ts +79 -0
- package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/icp-filter.ts +87 -0
- package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/index.ts +94 -0
- package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/scraper.ts +41 -0
- package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/tsconfig.json +13 -0
- package/skills/yc-intent-radar-skill/README.md +39 -0
- package/skills/yc-intent-radar-skill/SKILL.md +7 -0
- package/skills/yc-intent-radar-skill/yc-jobs-scraper/SKILL.md +59 -0
- package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/auth.js +29 -0
- package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/db.js +62 -0
- package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/export_radar_candidates.js +40 -0
- package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/package-lock.json +1525 -0
- package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/package.json +12 -0
- package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/scraper.js +217 -0
- package/src/e2e.test.ts +35 -0
- package/src/fs-adapters.test.ts +91 -0
- package/src/fs-adapters.ts +65 -0
- package/src/index.ts +182 -0
- package/src/transformers.ts +6 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dependency-update-bot
|
|
3
|
+
description: Scans your project for outdated npm, pip, Cargo, Go, or Ruby packages. Runs a CVE security audit. Fetches changelogs, summarizes breaking changes with Gemini, and opens one PR per risk group (patch, minor, major). Includes Diagnosis Mode for install conflicts. Use when asked to update dependencies, check for outdated packages, open dependency PRs, scan for package updates, audit for CVEs, or flag breaking changes in upgrades. Trigger when a user says "check for outdated packages", "update my dependencies", "open PRs for dependency updates", "scan for CVEs", or "which packages need upgrading".
|
|
4
|
+
compatibility: [claude-code, gemini-cli, github-copilot]
|
|
5
|
+
author: OpenDirectory
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Dependency Update Bot
|
|
10
|
+
|
|
11
|
+
Scan for outdated packages. Run a security audit. Fetch changelogs. Summarize breaking changes. Open one PR per risk group.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
**Critical rule:** Only update packages that the package manager's outdated command actually reports. Never guess or invent version numbers. If a changelog cannot be fetched, note the gap rather than inventing content.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Step 1: Setup Check
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
echo "GEMINI_API_KEY: ${GEMINI_API_KEY:+set}"
|
|
23
|
+
echo "GITHUB_TOKEN: ${GITHUB_TOKEN:-not set, changelog fetching rate-limited to 60/hour}"
|
|
24
|
+
gh auth status 2>/dev/null | head -1 || echo "gh: not authenticated"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**If GEMINI_API_KEY is missing:** Stop. Tell the user: "GEMINI_API_KEY is required. Get it at aistudio.google.com. Add it to your .env file."
|
|
28
|
+
|
|
29
|
+
**If gh is not authenticated:** Stop. Tell the user: "GitHub CLI must be authenticated. Run: gh auth login"
|
|
30
|
+
|
|
31
|
+
**Detect package manager(s):**
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
ls package.json 2>/dev/null && echo "npm"
|
|
35
|
+
ls requirements.txt pyproject.toml 2>/dev/null && echo "pip"
|
|
36
|
+
ls Cargo.toml 2>/dev/null && echo "cargo"
|
|
37
|
+
ls go.mod 2>/dev/null && echo "go"
|
|
38
|
+
ls Gemfile 2>/dev/null && echo "ruby"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If multiple are found, ask: "Found [list]. Which should I scan? (all / npm / pip / cargo / go / ruby)"
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Step 2: Detect Outdated Packages
|
|
46
|
+
|
|
47
|
+
**npm:**
|
|
48
|
+
```bash
|
|
49
|
+
npm outdated --json --long 2>/dev/null | python3 -c "
|
|
50
|
+
import sys, json
|
|
51
|
+
data = json.load(sys.stdin)
|
|
52
|
+
for name, info in data.items():
|
|
53
|
+
print(json.dumps({'name': name, 'current': info.get('current','?'), 'latest': info.get('latest','?'), 'dep_type': info.get('type','dependencies')}))
|
|
54
|
+
"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**pip:**
|
|
58
|
+
```bash
|
|
59
|
+
pip list --outdated --format=json 2>/dev/null | python3 -c "
|
|
60
|
+
import sys, json
|
|
61
|
+
for p in json.load(sys.stdin):
|
|
62
|
+
print(json.dumps({'name': p['name'], 'current': p['version'], 'latest': p['latest_version']}))
|
|
63
|
+
"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Cargo (Rust):**
|
|
67
|
+
```bash
|
|
68
|
+
cargo outdated --format json 2>/dev/null || \
|
|
69
|
+
cargo outdated 2>/dev/null | grep -v "^---" | tail -n +3 | head -30
|
|
70
|
+
# If cargo-outdated not installed: cargo install cargo-outdated
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Go modules:**
|
|
74
|
+
```bash
|
|
75
|
+
go list -u -m -json all 2>/dev/null | python3 -c "
|
|
76
|
+
import sys, json
|
|
77
|
+
decoder = json.JSONDecoder()
|
|
78
|
+
buf = sys.stdin.read()
|
|
79
|
+
pos = 0
|
|
80
|
+
while pos < len(buf):
|
|
81
|
+
try:
|
|
82
|
+
obj, idx = decoder.raw_decode(buf, pos)
|
|
83
|
+
if obj.get('Update'):
|
|
84
|
+
print(json.dumps({'name': obj['Path'], 'current': obj['Version'], 'latest': obj['Update']['Version']}))
|
|
85
|
+
pos += idx
|
|
86
|
+
except: break
|
|
87
|
+
"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Ruby (Bundler):**
|
|
91
|
+
```bash
|
|
92
|
+
bundle outdated --parseable 2>/dev/null | python3 -c "
|
|
93
|
+
import sys
|
|
94
|
+
for line in sys.stdin:
|
|
95
|
+
parts = line.strip().split()
|
|
96
|
+
if len(parts) >= 4:
|
|
97
|
+
print('{\"name\":\"' + parts[0] + '\",\"current\":\"' + parts[3].strip('()') + '\",\"latest\":\"' + parts[1] + '\"}')
|
|
98
|
+
"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
If all return empty: "All packages are up to date." Stop.
|
|
102
|
+
|
|
103
|
+
State count before proceeding: "Found X outdated packages."
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Step 3: Classify by Risk Level
|
|
108
|
+
|
|
109
|
+
Parse version bump (current → latest):
|
|
110
|
+
- MAJOR: first digit changed (1.x.x → 2.x.x)
|
|
111
|
+
- MINOR: second digit changed (1.2.x → 1.3.x)
|
|
112
|
+
- PATCH: third digit changed (1.2.3 → 1.2.4)
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
python3 -c "
|
|
116
|
+
def classify(current, latest):
|
|
117
|
+
try:
|
|
118
|
+
c = [int(x) for x in current.lstrip('v').split('.')[:3]]
|
|
119
|
+
l = [int(x) for x in latest.lstrip('v').split('.')[:3]]
|
|
120
|
+
if l[0] > c[0]: return 'major'
|
|
121
|
+
if len(l) > 1 and len(c) > 1 and l[1] > c[1]: return 'minor'
|
|
122
|
+
return 'patch'
|
|
123
|
+
except: return 'unknown'
|
|
124
|
+
"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
State the breakdown: "Patch: X packages. Minor: Y packages. Major: Z packages."
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Step 4: Security Audit
|
|
132
|
+
|
|
133
|
+
Run a CVE scan before creating any PRs. This determines urgency.
|
|
134
|
+
|
|
135
|
+
**npm:**
|
|
136
|
+
```bash
|
|
137
|
+
npm audit --json 2>/dev/null | python3 -c "
|
|
138
|
+
import sys, json
|
|
139
|
+
d = json.load(sys.stdin)
|
|
140
|
+
vulns = d.get('vulnerabilities', {})
|
|
141
|
+
for pkg, info in vulns.items():
|
|
142
|
+
sev = info.get('severity', 'unknown')
|
|
143
|
+
via = [v.get('title','') for v in info.get('via',[]) if isinstance(v, dict)]
|
|
144
|
+
print(f' [{sev.upper()}] {pkg}: {via[0] if via else \"see npm audit\"}')
|
|
145
|
+
" 2>/dev/null || echo "No vulnerabilities found or npm audit not available"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**pip:**
|
|
149
|
+
```bash
|
|
150
|
+
pip-audit --format=json 2>/dev/null | python3 -c "
|
|
151
|
+
import sys, json
|
|
152
|
+
for vuln in json.load(sys.stdin):
|
|
153
|
+
print(f' [{vuln.get(\"aliases\",[\"\"])[0]}] {vuln[\"name\"]} {vuln[\"version\"]}: {vuln[\"description\"][:80]}')
|
|
154
|
+
" 2>/dev/null || echo "pip-audit not installed. Run: pip install pip-audit"
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Cargo:**
|
|
158
|
+
```bash
|
|
159
|
+
cargo audit 2>/dev/null | grep -E "^(ID|Package|Severity|URL)" | head -30 \
|
|
160
|
+
|| echo "cargo-audit not installed. Run: cargo install cargo-audit"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Escalation rule:** If a PATCH or MINOR update has a Critical or High CVE, promote it to MAJOR priority: it gets its own PR and the CVE details go in the PR body.
|
|
164
|
+
|
|
165
|
+
Report security findings before proceeding:
|
|
166
|
+
```
|
|
167
|
+
Security audit: [N] vulnerabilities found
|
|
168
|
+
[CRITICAL] lodash 4.17.19: Prototype Pollution (CVE-2021-23337)
|
|
169
|
+
[HIGH] axios 0.21.1: Server-Side Request Forgery (CVE-2021-3749)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
If no vulnerabilities: "Security audit: clean."
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Step 5: Fetch Changelogs
|
|
177
|
+
|
|
178
|
+
For each package, try sources in order. Stop at first that returns content.
|
|
179
|
+
|
|
180
|
+
**Source 1: GitHub Releases API**
|
|
181
|
+
|
|
182
|
+
Get repo URL from registry:
|
|
183
|
+
```bash
|
|
184
|
+
# npm
|
|
185
|
+
curl -s "https://registry.npmjs.org/{PACKAGE}/latest" \
|
|
186
|
+
| python3 -c "import sys,json; d=json.load(sys.stdin); r=d.get('repository',{}); print(r.get('url','') if isinstance(r,dict) else str(r))"
|
|
187
|
+
|
|
188
|
+
# pip
|
|
189
|
+
curl -s "https://pypi.org/pypi/{PACKAGE}/json" \
|
|
190
|
+
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('info',{}).get('home_page','') or d.get('info',{}).get('project_urls',{}).get('Source',''))"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Fetch last 5 releases:
|
|
194
|
+
```bash
|
|
195
|
+
AUTH_HEADER=""
|
|
196
|
+
[ -n "$GITHUB_TOKEN" ] && AUTH_HEADER="-H \"Authorization: Bearer $GITHUB_TOKEN\""
|
|
197
|
+
curl -s $AUTH_HEADER \
|
|
198
|
+
"https://api.github.com/repos/{OWNER}/{REPO}/releases?per_page=5" \
|
|
199
|
+
| python3 -c "import sys,json; [print(json.dumps({'tag':r.get('tag_name',''),'body':r.get('body','')[:1500]})) for r in json.load(sys.stdin)]"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Keep releases between current and latest version only.
|
|
203
|
+
|
|
204
|
+
**Source 2: npm registry README (fallback)**
|
|
205
|
+
```bash
|
|
206
|
+
curl -s "https://registry.npmjs.org/{PACKAGE}" \
|
|
207
|
+
| python3 -c "import sys,json; print(json.load(sys.stdin).get('readme','')[:3000])"
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Source 3: PyPI description (last resort for pip)**
|
|
211
|
+
```bash
|
|
212
|
+
curl -s "https://pypi.org/pypi/{PACKAGE}/json" \
|
|
213
|
+
| python3 -c "import sys,json; print(json.load(sys.stdin).get('info',{}).get('description','')[:2000])"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
If no source returns content: note "No changelog found" and continue.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Step 6: Summarize with Gemini
|
|
221
|
+
|
|
222
|
+
One request per risk group. Include security findings for any CVE-affected packages:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
cat > /tmp/deps-summary-request.json << 'ENDJSON'
|
|
226
|
+
{
|
|
227
|
+
"system_instruction": {
|
|
228
|
+
"parts": [{
|
|
229
|
+
"text": "You are a developer writing a GitHub PR description for a dependency update. Given a list of packages being updated and their raw changelog content, write a concise PR body in Markdown. Rules: For each package, list only what changed between the OLD version and the NEW version. Use bullet points. Flag breaking changes with a BREAKING prefix. Flag CVE fixes with a SECURITY prefix and include the CVE ID. Keep each package section to 3-5 bullets maximum. If no changelog was found for a package, write 'No changelog available.' Do not use em dashes. Do not use these words: seamless, robust, leverage, transform, innovative. Output only the Markdown PR body, no commentary."
|
|
230
|
+
}]
|
|
231
|
+
},
|
|
232
|
+
"contents": [{
|
|
233
|
+
"parts": [{
|
|
234
|
+
"text": "PACKAGES_AND_CHANGELOGS_HERE"
|
|
235
|
+
}]
|
|
236
|
+
}],
|
|
237
|
+
"generationConfig": {
|
|
238
|
+
"temperature": 0.2,
|
|
239
|
+
"maxOutputTokens": 2048
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
ENDJSON
|
|
243
|
+
|
|
244
|
+
curl -s -X POST \
|
|
245
|
+
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GEMINI_API_KEY" \
|
|
246
|
+
-H "Content-Type: application/json" \
|
|
247
|
+
-d @/tmp/deps-summary-request.json \
|
|
248
|
+
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d['candidates'][0]['content']['parts'][0]['text'])"
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Step 7: Create PRs
|
|
254
|
+
|
|
255
|
+
One PR per non-empty risk group. One PR per package for major updates (individual review required).
|
|
256
|
+
|
|
257
|
+
**1. Create branch:**
|
|
258
|
+
```bash
|
|
259
|
+
BRANCH="deps/{RISK}-updates-$(date +%Y%m%d)"
|
|
260
|
+
git checkout -b "$BRANCH"
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**2. Update package file:**
|
|
264
|
+
|
|
265
|
+
npm:
|
|
266
|
+
```bash
|
|
267
|
+
npm install {package}@{latest_version} --save-exact
|
|
268
|
+
# devDependencies:
|
|
269
|
+
npm install {package}@{latest_version} --save-dev --save-exact
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
pip:
|
|
273
|
+
```bash
|
|
274
|
+
python3 -c "
|
|
275
|
+
import re, sys
|
|
276
|
+
pkg, version, filename = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
277
|
+
with open(filename) as f: content = f.read()
|
|
278
|
+
pattern = rf'^{re.escape(pkg)}[>=<!\s].*$'
|
|
279
|
+
new_content = re.sub(pattern, f'{pkg}=={version}', content, flags=re.MULTILINE|re.IGNORECASE)
|
|
280
|
+
if new_content == content: new_content = content + f'\n{pkg}=={version}'
|
|
281
|
+
open(filename, 'w').write(new_content)
|
|
282
|
+
" "{PACKAGE}" "{LATEST}" "requirements.txt"
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Cargo:
|
|
286
|
+
```bash
|
|
287
|
+
# Edit Cargo.toml version field for the package, then:
|
|
288
|
+
cargo update {package}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Go:
|
|
292
|
+
```bash
|
|
293
|
+
go get {module}@{latest_version}
|
|
294
|
+
go mod tidy
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Ruby:
|
|
298
|
+
```bash
|
|
299
|
+
bundle update {gem_name}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**3. Commit:**
|
|
303
|
+
```bash
|
|
304
|
+
git add -A
|
|
305
|
+
git commit -m "chore(deps): update {RISK} dependencies $(date +%Y-%m-%d)"
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**4. Create PR:**
|
|
309
|
+
```bash
|
|
310
|
+
cat > /tmp/dep-pr-body-{RISK}.md << 'ENDMD'
|
|
311
|
+
PR_BODY_FROM_GEMINI
|
|
312
|
+
ENDMD
|
|
313
|
+
|
|
314
|
+
gh pr create \
|
|
315
|
+
--title "chore(deps): update {RISK} dependencies" \
|
|
316
|
+
--body-file /tmp/dep-pr-body-{RISK}.md \
|
|
317
|
+
--label "dependencies" \
|
|
318
|
+
--base main
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Major updates get label `dependencies,breaking-change`. CVE-fixing updates get label `dependencies,security`.
|
|
322
|
+
|
|
323
|
+
After each PR, return to main: `git checkout main`
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Step 8: Diagnosis Mode
|
|
328
|
+
|
|
329
|
+
**Trigger:** If any package install command fails mid-run, enter Diagnosis Mode instead of stopping.
|
|
330
|
+
|
|
331
|
+
Detect the failure type:
|
|
332
|
+
|
|
333
|
+
| Error pattern | Likely cause | Suggested fix |
|
|
334
|
+
|---------------|-------------|--------------|
|
|
335
|
+
| `peer dep conflict` | Peer dependency incompatibility | Show conflicting pair, suggest `--legacy-peer-deps` flag or downgrade |
|
|
336
|
+
| `ERESOLVE` | npm resolution conflict | Run `npm install --legacy-peer-deps` for the affected package only |
|
|
337
|
+
| `version not found` | Version does not exist in registry | Check registry with `npm view {pkg} versions` |
|
|
338
|
+
| `python requires` | Python version incompatibility | Note required Python version, skip package |
|
|
339
|
+
| `cargo E0463` | Rust edition incompatibility | Flag for manual review |
|
|
340
|
+
|
|
341
|
+
Present a diagnosis summary:
|
|
342
|
+
```
|
|
343
|
+
Install failed for {package}: {error type}
|
|
344
|
+
Likely cause: {explanation}
|
|
345
|
+
Suggested fix: {specific command or action}
|
|
346
|
+
Remaining packages: proceeding with {N} that succeeded.
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
Do not stop the entire run when one package fails. Continue with packages that succeed.
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Step 9: Output Summary
|
|
354
|
+
|
|
355
|
+
```
|
|
356
|
+
## Dependency Update Summary: [YYYY-MM-DD]
|
|
357
|
+
|
|
358
|
+
### Security
|
|
359
|
+
[CRITICAL] lodash: CVE-2021-23337 fixed in 4.17.21: PR #42
|
|
360
|
+
[HIGH] axios: CVE-2021-3749 fixed in 0.21.4: PR #42
|
|
361
|
+
|
|
362
|
+
| Risk Level | Packages | PR |
|
|
363
|
+
|------------|----------|-----|
|
|
364
|
+
| Patch | lodash 4.17.19→4.17.21, axios 0.21.1→0.21.4 | #42 |
|
|
365
|
+
| Minor | express 4.17.1→4.18.2 | #43 |
|
|
366
|
+
| Major | react 17.0.2→18.2.0 | #44 |
|
|
367
|
+
|
|
368
|
+
PRs opened: 3
|
|
369
|
+
|
|
370
|
+
Packages with no changelog: some-obscure-pkg (no GitHub repo in registry)
|
|
371
|
+
Install failures: none
|
|
372
|
+
|
|
373
|
+
Next action: Review major update PRs individually before merging.
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "dependency-update-bot",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "Check for outdated packages and open PRs. The project uses npm.",
|
|
7
|
+
"expected_output": "Agent checks GEMINI_API_KEY (set) and gh auth status (authenticated). Detects package.json. Runs npm outdated --json --long. Finds outdated packages. Classifies each by semver diff into patch, minor, or major. For each package, fetches changelog via GitHub Releases API (parses repo URL from npm registry first), falls back to raw CHANGELOG.md, falls back to npm registry README. Writes changelog content to /tmp/deps-summary-request.json and calls Gemini at temperature 0.2 for summarization. Creates one branch per risk group, runs npm install for each package in the group, commits, creates PR using gh pr create with --body-file and heredoc. States PR numbers in final summary table. Returns to main branch after each PR.",
|
|
8
|
+
"files": [
|
|
9
|
+
"package.json"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": 2,
|
|
14
|
+
"prompt": "Scan my Python packages for updates.",
|
|
15
|
+
"expected_output": "Agent detects requirements.txt (or pyproject.toml). Runs pip list --outdated --format=json. Finds outdated packages. Classifies each by semver diff. For each package, fetches repo URL from PyPI JSON API and then fetches GitHub Releases. Falls back to raw CHANGELOG.md from GitHub, then PyPI project description. Groups into patch, minor, major. Creates branches, updates requirements.txt using the Python regex replacement script for each package, commits, creates PRs. Major updates each get their own branch and PR with label 'dependencies,breaking-change'. Summary table shows all PRs created.",
|
|
16
|
+
"files": [
|
|
17
|
+
"requirements.txt"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": 3,
|
|
22
|
+
"prompt": "Check for outdated packages.",
|
|
23
|
+
"expected_output": "Agent detects GEMINI_API_KEY is missing. Stops immediately at Step 1. Tells the user: 'GEMINI_API_KEY is required. Get it at aistudio.google.com. Add it to your .env file.' No package scanning or PR creation attempted.",
|
|
24
|
+
"files": [],
|
|
25
|
+
"setup": "GEMINI_API_KEY not set in environment"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": 4,
|
|
29
|
+
"prompt": "Run the dependency update bot.",
|
|
30
|
+
"expected_output": "Agent runs npm outdated --json --long. Command returns empty object {}. Agent reports: 'All dependencies are up to date. Nothing to update.' No branches created, no PRs opened. Does not error or proceed to changelog fetching.",
|
|
31
|
+
"files": [
|
|
32
|
+
"package.json"
|
|
33
|
+
],
|
|
34
|
+
"setup": "All packages already at latest versions"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": 5,
|
|
38
|
+
"prompt": "Update my dependencies. There is a major version update for react (17.0.2 to 18.2.0) and a patch update for lodash (4.17.19 to 4.17.21).",
|
|
39
|
+
"expected_output": "Agent classifies react as major (17 to 18) and lodash as patch (4.17.19 to 4.17.21). Fetches changelogs for both. For react, GitHub Releases shows BREAKING CHANGES in the migration guide. For lodash, changelog shows two CVE security fixes. Gemini summarizes each group. Creates two branches: deps/patch-updates-YYYYMMDD and deps/major-updates-YYYYMMDD (or deps/react-v18). Patch PR groups lodash with its CVE notes. Major PR for react includes the breaking change summary with BREAKING prefix. Two separate PRs opened. Patch PR gets label 'dependencies', major PR gets label 'dependencies,breaking-change'. Summary table shows both PRs.",
|
|
40
|
+
"files": [
|
|
41
|
+
"package.json"
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Changelog Patterns
|
|
2
|
+
|
|
3
|
+
How to fetch and parse changelogs for npm and pip packages. Fallback strategies when the primary source has no content.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Source Priority
|
|
8
|
+
|
|
9
|
+
Try sources in this order. Stop at the first that returns usable content (more than 50 characters of actual release notes).
|
|
10
|
+
|
|
11
|
+
1. GitHub Releases API (best — structured, version-tagged)
|
|
12
|
+
2. Raw CHANGELOG.md from GitHub (good — often more detailed than release notes)
|
|
13
|
+
3. npm registry README (fallback — unstructured but usually mentions recent changes)
|
|
14
|
+
4. PyPI project description (last resort — often just the README)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Source 1: GitHub Releases API
|
|
19
|
+
|
|
20
|
+
**When it works:** The package has a GitHub repo AND publishes versioned releases with release notes.
|
|
21
|
+
|
|
22
|
+
**How to find the repo URL:**
|
|
23
|
+
|
|
24
|
+
For npm packages:
|
|
25
|
+
```bash
|
|
26
|
+
curl -s "https://registry.npmjs.org/{PACKAGE}/latest" \
|
|
27
|
+
| python3 -c "
|
|
28
|
+
import sys, json
|
|
29
|
+
d = json.load(sys.stdin)
|
|
30
|
+
repo = d.get('repository', {})
|
|
31
|
+
url = repo.get('url', '') if isinstance(repo, dict) else str(repo)
|
|
32
|
+
# Clean up git+https:// or git:// prefixes
|
|
33
|
+
import re
|
|
34
|
+
url = re.sub(r'^git\+|^git:', '', url).replace('.git', '')
|
|
35
|
+
print(url.strip())
|
|
36
|
+
"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For PyPI packages:
|
|
40
|
+
```bash
|
|
41
|
+
curl -s "https://pypi.org/pypi/{PACKAGE}/json" \
|
|
42
|
+
| python3 -c "
|
|
43
|
+
import sys, json
|
|
44
|
+
d = json.load(sys.stdin)
|
|
45
|
+
info = d.get('info', {})
|
|
46
|
+
urls = info.get('project_urls') or {}
|
|
47
|
+
# Try multiple URL fields in priority order
|
|
48
|
+
for key in ['Source', 'Homepage', 'Repository', 'Code']:
|
|
49
|
+
if key in urls and 'github.com' in urls[key]:
|
|
50
|
+
print(urls[key])
|
|
51
|
+
break
|
|
52
|
+
else:
|
|
53
|
+
hp = info.get('home_page', '')
|
|
54
|
+
print(hp if 'github.com' in hp else '')
|
|
55
|
+
"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Parse owner/repo from URL:**
|
|
59
|
+
```bash
|
|
60
|
+
python3 -c "
|
|
61
|
+
import re, sys
|
|
62
|
+
url = sys.argv[1]
|
|
63
|
+
m = re.search(r'github\.com[/:]([^/\s]+)/([^/.\s]+)', url)
|
|
64
|
+
if m:
|
|
65
|
+
print(m.group(1), m.group(2))
|
|
66
|
+
else:
|
|
67
|
+
print('', '')
|
|
68
|
+
" "URL_HERE"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Fetch releases:**
|
|
72
|
+
```bash
|
|
73
|
+
curl -s ${GITHUB_TOKEN:+-H "Authorization: Bearer $GITHUB_TOKEN"} \
|
|
74
|
+
"https://api.github.com/repos/{OWNER}/{REPO}/releases?per_page=10" \
|
|
75
|
+
| python3 -c "
|
|
76
|
+
import sys, json
|
|
77
|
+
releases = json.load(sys.stdin)
|
|
78
|
+
if isinstance(releases, dict) and 'message' in releases:
|
|
79
|
+
print('ERROR:', releases['message'])
|
|
80
|
+
else:
|
|
81
|
+
for r in releases[:5]:
|
|
82
|
+
body = r.get('body') or ''
|
|
83
|
+
if body.strip():
|
|
84
|
+
print('TAG:', r.get('tag_name', ''))
|
|
85
|
+
print(body[:1500])
|
|
86
|
+
print('---')
|
|
87
|
+
"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Version matching:** Tags may be prefixed (`v4.17.21`, `4.17.21`, `release-4.17.21`). Strip non-numeric prefixes before comparing to package versions.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Source 2: Raw CHANGELOG.md from GitHub
|
|
95
|
+
|
|
96
|
+
**When it works:** The repo maintains a CHANGELOG.md but does not use GitHub Releases.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
curl -s "https://raw.githubusercontent.com/{OWNER}/{REPO}/main/CHANGELOG.md" \
|
|
100
|
+
| head -200
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Also try `HEAD`, `master`, `trunk` if `main` returns 404.
|
|
104
|
+
|
|
105
|
+
**Extract the relevant section** (between current version header and previous version header):
|
|
106
|
+
```bash
|
|
107
|
+
python3 -c "
|
|
108
|
+
import sys, re
|
|
109
|
+
content = sys.stdin.read()
|
|
110
|
+
# Find section starting with target version
|
|
111
|
+
pattern = r'#+\s*\[?{TARGET_VERSION}\]?.*?(?=\n#+\s*\[?[0-9]|\Z)'
|
|
112
|
+
m = re.search(pattern, content, re.DOTALL | re.IGNORECASE)
|
|
113
|
+
if m:
|
|
114
|
+
print(m.group(0)[:2000])
|
|
115
|
+
else:
|
|
116
|
+
print('Version section not found in CHANGELOG.md')
|
|
117
|
+
"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Source 3: npm Registry README (Fallback)
|
|
123
|
+
|
|
124
|
+
**When it works:** Package has no GitHub repo or does not use GitHub Releases, but includes a changelog in the README.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
curl -s "https://registry.npmjs.org/{PACKAGE}" \
|
|
128
|
+
| python3 -c "
|
|
129
|
+
import sys, json
|
|
130
|
+
d = json.load(sys.stdin)
|
|
131
|
+
readme = d.get('readme', '')
|
|
132
|
+
if readme:
|
|
133
|
+
# Look for changelog section
|
|
134
|
+
import re
|
|
135
|
+
m = re.search(r'#+\s*(changelog|changes|release notes|history).*', readme, re.IGNORECASE | re.DOTALL)
|
|
136
|
+
if m:
|
|
137
|
+
print(m.group(0)[:2000])
|
|
138
|
+
else:
|
|
139
|
+
# Just print the first 1500 chars of README
|
|
140
|
+
print(readme[:1500])
|
|
141
|
+
else:
|
|
142
|
+
print('No README found in registry')
|
|
143
|
+
"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Source 4: PyPI Project Description (Last Resort)
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
curl -s "https://pypi.org/pypi/{PACKAGE}/json" \
|
|
152
|
+
| python3 -c "
|
|
153
|
+
import sys, json
|
|
154
|
+
d = json.load(sys.stdin)
|
|
155
|
+
desc = d.get('info', {}).get('description', '')
|
|
156
|
+
print(desc[:2000] if desc else 'No description found')
|
|
157
|
+
"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Handling Missing Changelogs
|
|
163
|
+
|
|
164
|
+
If all four sources fail or return less than 50 characters of useful content:
|
|
165
|
+
|
|
166
|
+
- Record: "No changelog found for {package}"
|
|
167
|
+
- In the PR body, write: "No changelog available for {package}. Review the diff manually before merging."
|
|
168
|
+
- Do NOT skip the package from the PR — still include the version bump, just with no notes
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Identifying Breaking Changes
|
|
173
|
+
|
|
174
|
+
Gemini handles most of this, but these patterns in raw changelog text are strong signals to flag:
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
BREAKING CHANGE:
|
|
178
|
+
BREAKING:
|
|
179
|
+
[BREAKING]
|
|
180
|
+
!BREAKING
|
|
181
|
+
Removed support for
|
|
182
|
+
Dropped support for
|
|
183
|
+
No longer supports
|
|
184
|
+
Migration required
|
|
185
|
+
Deprecated in X, removed in Y
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
If a changelog contains any of these patterns for a patch or minor update, escalate that package's risk classification to major before PR creation.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Rate Limits
|
|
193
|
+
|
|
194
|
+
| Source | Rate Limit | Auth |
|
|
195
|
+
|--------|-----------|------|
|
|
196
|
+
| GitHub API (unauthenticated) | 60 requests/hour | None |
|
|
197
|
+
| GitHub API (with GITHUB_TOKEN) | 5,000 requests/hour | Bearer token |
|
|
198
|
+
| npm registry | No documented limit (generous) | None |
|
|
199
|
+
| PyPI API | No documented limit | None |
|
|
200
|
+
|
|
201
|
+
For most projects (under 60 outdated packages), unauthenticated GitHub API is sufficient. Set GITHUB_TOKEN if you have more than 30-40 packages to scan (2 API calls per package).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# docs-from-code — Environment Variables
|
|
2
|
+
# =========================================
|
|
3
|
+
# Most of this skill works with zero config — it reads your codebase directly.
|
|
4
|
+
# Only GitHub integration requires a token.
|
|
5
|
+
|
|
6
|
+
# Optional: GitHub token for opening a PR with generated docs
|
|
7
|
+
# Scopes needed: repo (read + write)
|
|
8
|
+
# Get one at: https://github.com/settings/tokens
|
|
9
|
+
GITHUB_TOKEN=your_github_token_here
|
|
10
|
+
|
|
11
|
+
# Optional: Override the detected project root (absolute path)
|
|
12
|
+
# By default the skill uses the current working directory
|
|
13
|
+
# PROJECT_ROOT=/path/to/your/project
|