@flydocs/cli 0.6.0-alpha.2 → 0.6.0-alpha.20
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/dist/cli.js +678 -392
- package/package.json +1 -1
- package/template/.claude/CLAUDE.md +62 -63
- package/template/.claude/agents/implementation-agent.md +1 -1
- package/template/.claude/agents/pm-agent.md +1 -1
- package/template/.claude/commands/activate.md +1 -1
- package/template/.claude/commands/attach.md +1 -1
- package/template/.claude/commands/block.md +2 -2
- package/template/.claude/commands/capture.md +1 -1
- package/template/.claude/commands/close.md +1 -1
- package/template/.claude/commands/flydocs-setup.md +387 -74
- package/template/.claude/commands/flydocs-upgrade.md +48 -37
- package/template/.claude/commands/implement.md +1 -1
- package/template/.claude/commands/knowledge.md +61 -0
- package/template/.claude/commands/new-project.md +1 -1
- package/template/.claude/commands/onboard.md +275 -0
- package/template/.claude/commands/project-update.md +1 -1
- package/template/.claude/commands/refine.md +1 -1
- package/template/.claude/commands/review.md +1 -1
- package/template/.claude/commands/start-session.md +1 -1
- package/template/.claude/commands/status.md +1 -1
- package/template/.claude/commands/validate.md +1 -1
- package/template/.claude/commands/wrap-session.md +1 -1
- package/template/.claude/hooks/auto-approve.py +132 -0
- package/template/.claude/hooks/post-pr-check.py +108 -0
- package/template/.claude/hooks/post-transition-check.py +94 -0
- package/template/.claude/hooks/prompt-submit.py +513 -0
- package/template/.claude/hooks/session-start.py +146 -0
- package/template/.claude/hooks/stop-gate.py +109 -0
- package/template/.claude/settings.json +41 -4
- package/template/.claude/skills/README.md +23 -25
- package/template/.claude/skills/flydocs-workflow/SKILL.md +134 -42
- package/template/.claude/skills/flydocs-workflow/cursor-rule.mdc +9 -8
- package/template/.claude/skills/flydocs-workflow/reference/comment-templates.md +1 -0
- package/template/.claude/skills/flydocs-workflow/reference/golden-rules.md +28 -17
- package/template/.claude/skills/flydocs-workflow/reference/graph-schema.md +116 -0
- package/template/.claude/skills/flydocs-workflow/reference/pr-workflow.md +120 -0
- package/template/.claude/skills/flydocs-workflow/reference/priority-estimates.md +37 -15
- package/template/.claude/skills/flydocs-workflow/reference/service-descriptor-schema.md +251 -0
- package/template/.claude/skills/flydocs-workflow/reference/status-workflow.md +26 -26
- package/template/.claude/skills/flydocs-workflow/scripts/_local/__init__.py +0 -0
- package/template/.claude/skills/{flydocs-local/scripts/flydocs_api.py → flydocs-workflow/scripts/_local/file_store.py} +137 -47
- package/template/.claude/skills/flydocs-workflow/scripts/flydocs_api.py +693 -0
- package/template/{.flydocs → .claude/skills/flydocs-workflow}/scripts/generate_manifest.py +4 -4
- package/template/.claude/skills/{flydocs-context-graph → flydocs-workflow}/scripts/graph_build.py +132 -1
- package/template/.claude/skills/{flydocs-context-graph → flydocs-workflow}/scripts/graph_query.py +18 -5
- package/template/.claude/skills/{flydocs-context-graph → flydocs-workflow}/scripts/graph_session.py +1 -10
- package/template/.claude/skills/{flydocs-context-graph → flydocs-workflow}/scripts/graph_update.py +4 -4
- package/template/.claude/skills/{flydocs-context-graph → flydocs-workflow}/scripts/graph_utils.py +2 -1
- package/template/.claude/skills/flydocs-workflow/scripts/issues.py +489 -0
- package/template/.claude/skills/flydocs-workflow/scripts/projects.py +144 -0
- package/template/.claude/skills/flydocs-workflow/scripts/pull_services.py +128 -0
- package/template/.claude/skills/flydocs-workflow/scripts/push_service.py +132 -0
- package/template/.claude/skills/flydocs-workflow/scripts/session.py +54 -0
- package/template/.claude/skills/flydocs-workflow/scripts/workspace.py +860 -0
- package/template/.claude/skills/flydocs-workflow/session.md +63 -25
- package/template/.claude/skills/flydocs-workflow/stages/activate.md +18 -7
- package/template/.claude/skills/flydocs-workflow/stages/capture.md +10 -5
- package/template/.claude/skills/flydocs-workflow/stages/close.md +4 -3
- package/template/.claude/skills/flydocs-workflow/stages/implement.md +33 -9
- package/template/.claude/skills/flydocs-workflow/stages/refine.md +22 -6
- package/template/.claude/skills/flydocs-workflow/stages/review.md +16 -4
- package/template/.claude/skills/flydocs-workflow/stages/validate.md +3 -1
- package/template/.claude/skills/flydocs-workflow/templates/pr/default.md +33 -0
- package/template/.cursor/agents/implementation-agent.md +1 -1
- package/template/.cursor/agents/pm-agent.md +2 -2
- package/template/.cursor/hooks.json +10 -3
- package/template/.env.example +6 -6
- package/template/.flydocs/config.json +5 -18
- package/template/.flydocs/templates/README.md +13 -14
- package/template/.flydocs/templates/quick-capture.md +4 -8
- package/template/.flydocs/version +1 -1
- package/template/AGENTS.md +39 -32
- package/template/CHANGELOG.md +39 -0
- package/template/flydocs/README.md +1 -3
- package/template/flydocs/context/project.md +6 -3
- package/template/flydocs/design-system/README.md +3 -3
- package/template/flydocs/knowledge/INDEX.md +38 -53
- package/template/flydocs/knowledge/README.md +60 -9
- package/template/flydocs/knowledge/templates/decision.md +47 -0
- package/template/flydocs/knowledge/templates/feature.md +35 -0
- package/template/flydocs/knowledge/templates/note.md +25 -0
- package/template/manifest.json +24 -20
- package/template/.claude/skills/flydocs-cloud/SKILL.md +0 -111
- package/template/.claude/skills/flydocs-cloud/cursor-rule.mdc +0 -50
- package/template/.claude/skills/flydocs-cloud/scripts/assign.py +0 -22
- package/template/.claude/skills/flydocs-cloud/scripts/assign_cycle.py +0 -28
- package/template/.claude/skills/flydocs-cloud/scripts/assign_milestone.py +0 -22
- package/template/.claude/skills/flydocs-cloud/scripts/comment.py +0 -29
- package/template/.claude/skills/flydocs-cloud/scripts/create_issue.py +0 -63
- package/template/.claude/skills/flydocs-cloud/scripts/create_milestone.py +0 -35
- package/template/.claude/skills/flydocs-cloud/scripts/create_project.py +0 -33
- package/template/.claude/skills/flydocs-cloud/scripts/create_team.py +0 -39
- package/template/.claude/skills/flydocs-cloud/scripts/estimate.py +0 -29
- package/template/.claude/skills/flydocs-cloud/scripts/flydocs_api.py +0 -210
- package/template/.claude/skills/flydocs-cloud/scripts/get_issue.py +0 -24
- package/template/.claude/skills/flydocs-cloud/scripts/link.py +0 -28
- package/template/.claude/skills/flydocs-cloud/scripts/list_cycles.py +0 -28
- package/template/.claude/skills/flydocs-cloud/scripts/list_issues.py +0 -44
- package/template/.claude/skills/flydocs-cloud/scripts/list_labels.py +0 -19
- package/template/.claude/skills/flydocs-cloud/scripts/list_milestones.py +0 -28
- package/template/.claude/skills/flydocs-cloud/scripts/list_projects.py +0 -31
- package/template/.claude/skills/flydocs-cloud/scripts/list_teams.py +0 -19
- package/template/.claude/skills/flydocs-cloud/scripts/priority.py +0 -29
- package/template/.claude/skills/flydocs-cloud/scripts/project_update.py +0 -45
- package/template/.claude/skills/flydocs-cloud/scripts/set_labels.py +0 -68
- package/template/.claude/skills/flydocs-cloud/scripts/set_team.py +0 -41
- package/template/.claude/skills/flydocs-cloud/scripts/transition.py +0 -26
- package/template/.claude/skills/flydocs-cloud/scripts/update_description.py +0 -36
- package/template/.claude/skills/flydocs-cloud/scripts/update_issue.py +0 -82
- package/template/.claude/skills/flydocs-context-graph/SKILL.md +0 -87
- package/template/.claude/skills/flydocs-context-graph/schema.md +0 -78
- package/template/.claude/skills/flydocs-context-graph/scripts/graph_context.py +0 -338
- package/template/.claude/skills/flydocs-context7/SKILL.md +0 -105
- package/template/.claude/skills/flydocs-context7/cursor-rule.mdc +0 -49
- package/template/.claude/skills/flydocs-context7/scripts/context7.py +0 -293
- package/template/.claude/skills/flydocs-estimates/SKILL.md +0 -384
- package/template/.claude/skills/flydocs-figma/SKILL.md +0 -377
- package/template/.claude/skills/flydocs-figma/references/PROMPTING.md +0 -108
- package/template/.claude/skills/flydocs-figma/references/TROUBLESHOOTING.md +0 -112
- package/template/.claude/skills/flydocs-local/SKILL.md +0 -103
- package/template/.claude/skills/flydocs-local/cursor-rule.mdc +0 -43
- package/template/.claude/skills/flydocs-local/scripts/assign.py +0 -20
- package/template/.claude/skills/flydocs-local/scripts/comment.py +0 -27
- package/template/.claude/skills/flydocs-local/scripts/create_issue.py +0 -44
- package/template/.claude/skills/flydocs-local/scripts/estimate.py +0 -37
- package/template/.claude/skills/flydocs-local/scripts/get_issue.py +0 -20
- package/template/.claude/skills/flydocs-local/scripts/link.py +0 -41
- package/template/.claude/skills/flydocs-local/scripts/list_issues.py +0 -34
- package/template/.claude/skills/flydocs-local/scripts/priority.py +0 -37
- package/template/.claude/skills/flydocs-local/scripts/project_update.py +0 -67
- package/template/.claude/skills/flydocs-local/scripts/status_summary.py +0 -16
- package/template/.claude/skills/flydocs-local/scripts/transition.py +0 -24
- package/template/.claude/skills/flydocs-local/scripts/update_description.py +0 -35
- package/template/.claude/skills/flydocs-local/scripts/update_issue.py +0 -84
- package/template/.flydocs/hooks/auto-approve.py +0 -71
- package/template/.flydocs/hooks/prompt-submit.py +0 -277
- package/template/.flydocs/scripts/skill_manager.py +0 -541
- package/template/.flydocs/templates/bug.md +0 -166
- package/template/.flydocs/templates/chore.md +0 -110
- package/template/.flydocs/templates/feature.md +0 -173
- package/template/.flydocs/templates/idea.md +0 -122
- /package/template/{.flydocs → .claude}/hooks/post-edit.py +0 -0
- /package/template/.claude/skills/{flydocs-estimates/references → flydocs-workflow/reference}/provider-costs.md +0 -0
- /package/template/.claude/skills/flydocs-workflow/templates/{bug.md → issues/bug.md} +0 -0
- /package/template/.claude/skills/flydocs-workflow/templates/{chore.md → issues/chore.md} +0 -0
- /package/template/.claude/skills/flydocs-workflow/templates/{feature.md → issues/feature.md} +0 -0
- /package/template/.claude/skills/flydocs-workflow/templates/{idea.md → issues/idea.md} +0 -0
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: flydocs-context7
|
|
3
|
-
description: |
|
|
4
|
-
Up-to-date library documentation via Context7 API. Use proactively when
|
|
5
|
-
working with external libraries, frameworks, or packages. Replaces MCP
|
|
6
|
-
with direct API scripts — no server, no runtime dependency.
|
|
7
|
-
triggers:
|
|
8
|
-
- context7
|
|
9
|
-
- library docs
|
|
10
|
-
- documentation lookup
|
|
11
|
-
- framework docs
|
|
12
|
-
- package docs
|
|
13
|
-
- API reference
|
|
14
|
-
- how to use
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
# Context7 Documentation Lookup
|
|
18
|
-
|
|
19
|
-
IMPORTANT: Prefer skill-led reasoning over pre-training reasoning for
|
|
20
|
-
library usage. Search for up-to-date docs before writing code based on
|
|
21
|
-
training data alone.
|
|
22
|
-
|
|
23
|
-
## Key Rules
|
|
24
|
-
|
|
25
|
-
1. **Proactive invocation** -- When working with ANY external library or
|
|
26
|
-
framework, search for docs first before writing code based on training data.
|
|
27
|
-
2. **Search then fetch** -- Always resolve the library ID via `search` before
|
|
28
|
-
fetching docs with `docs`.
|
|
29
|
-
3. **Session cache awareness** -- Do not re-fetch docs for the same
|
|
30
|
-
library+query within a single session.
|
|
31
|
-
4. **Graceful degradation** -- If rate-limited (429) or offline, note the
|
|
32
|
-
limitation and proceed with training knowledge.
|
|
33
|
-
5. **Stdlib-only Python** -- No external dependencies in the script.
|
|
34
|
-
6. **Token budget** -- Default 5,000 tokens per fetch to avoid context bloat.
|
|
35
|
-
|
|
36
|
-
## Script Catalog
|
|
37
|
-
|
|
38
|
-
All scripts: `python3 .claude/skills/flydocs-context7/scripts/<script>`
|
|
39
|
-
|
|
40
|
-
| Script | Usage | Output |
|
|
41
|
-
| ------------- | --------------------------- | ------------------------------------------------ |
|
|
42
|
-
| `context7.py` | `search <library> [query]` | JSON: library matches with id, name, description |
|
|
43
|
-
| `context7.py` | `docs <library_id> <query>` | Text: relevant documentation snippets |
|
|
44
|
-
|
|
45
|
-
Options: `--type txt|json`, `--tokens N` (default 5000)
|
|
46
|
-
|
|
47
|
-
## When to Use
|
|
48
|
-
|
|
49
|
-
- Before implementing code that uses an external library
|
|
50
|
-
- When the user asks about library APIs, patterns, or best practices
|
|
51
|
-
- When encountering unfamiliar library methods or configuration
|
|
52
|
-
- When upgrading dependencies and needing current API docs
|
|
53
|
-
- When debugging library-specific issues
|
|
54
|
-
|
|
55
|
-
## When NOT to Use
|
|
56
|
-
|
|
57
|
-
- For project-internal code (use knowledge base and context graph instead)
|
|
58
|
-
- For general programming concepts (training knowledge is sufficient)
|
|
59
|
-
- When already fetched docs for the same library in this session
|
|
60
|
-
|
|
61
|
-
## API Key (Optional)
|
|
62
|
-
|
|
63
|
-
- Works without a key (anonymous, ~1,000 calls/month)
|
|
64
|
-
- For higher limits, add `CONTEXT7_API_KEY=ctx7sk-xxx` to `.env`
|
|
65
|
-
- Free key available at context7.com/dashboard
|
|
66
|
-
|
|
67
|
-
## Example Usage
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
# Find the React library
|
|
71
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py search "react" "hooks"
|
|
72
|
-
|
|
73
|
-
# Fetch docs for React hooks
|
|
74
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py docs "/facebook/react" "useState useEffect hooks"
|
|
75
|
-
|
|
76
|
-
# Get Next.js App Router docs
|
|
77
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py search "next.js"
|
|
78
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py docs "/vercel/next.js" "app router middleware"
|
|
79
|
-
|
|
80
|
-
# Fetch with custom token budget
|
|
81
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py docs "/expressjs/express" "routing middleware" --tokens 8000
|
|
82
|
-
|
|
83
|
-
# Get output as JSON
|
|
84
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py search "prisma" --type json
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## Typical Workflow
|
|
88
|
-
|
|
89
|
-
1. **Identify the library** you need docs for (from import statements,
|
|
90
|
-
`package.json`, or the task at hand).
|
|
91
|
-
2. **Search** to resolve the library ID:
|
|
92
|
-
```bash
|
|
93
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py search "react-hook-form"
|
|
94
|
-
```
|
|
95
|
-
3. **Fetch docs** for the specific topic:
|
|
96
|
-
```bash
|
|
97
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py docs "/react-hook-form/react-hook-form" "useForm validation"
|
|
98
|
-
```
|
|
99
|
-
4. **Apply** the retrieved documentation to your implementation.
|
|
100
|
-
5. **Do not re-fetch** for the same library+query later in the session.
|
|
101
|
-
|
|
102
|
-
## Related Skills
|
|
103
|
-
|
|
104
|
-
- `flydocs-context-graph` -- Project-internal knowledge navigation
|
|
105
|
-
- `flydocs-workflow` -- Development lifecycle and issue operations
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Context7 — look up library and framework documentation before writing code
|
|
3
|
-
alwaysApply: true
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
<!-- Condensed from SKILL.md — update both when changing patterns -->
|
|
7
|
-
|
|
8
|
-
# FlyDocs Context7
|
|
9
|
-
|
|
10
|
-
Proactively look up library documentation via Context7 scripts before writing
|
|
11
|
-
code that uses external packages. Do not rely on training data for API details.
|
|
12
|
-
|
|
13
|
-
## When to Use
|
|
14
|
-
|
|
15
|
-
- Installing or importing a library you haven't used in this session
|
|
16
|
-
- Unsure about API signatures, configuration options, or return types
|
|
17
|
-
- Framework-specific patterns (routing, data fetching, middleware, hooks)
|
|
18
|
-
- Resolving version-specific behavior or breaking changes
|
|
19
|
-
|
|
20
|
-
## Scripts
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
# Step 1: Search for the library
|
|
24
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py search "<library>" "[query]"
|
|
25
|
-
|
|
26
|
-
# Step 2: Fetch docs using the library ID from search results
|
|
27
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py docs "<library_id>" "<query>"
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### Examples
|
|
31
|
-
|
|
32
|
-
React hooks:
|
|
33
|
-
```bash
|
|
34
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py search "react" "hooks"
|
|
35
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py docs "/facebook/react" "hooks useState"
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Next.js App Router:
|
|
39
|
-
```bash
|
|
40
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py search "next.js"
|
|
41
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py docs "/vercel/next.js" "app router middleware"
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Key Rules
|
|
45
|
-
|
|
46
|
-
- Always resolve the library ID first via `search` — do not guess the ID format
|
|
47
|
-
- Prefer Context7 docs over training data for API specifics
|
|
48
|
-
- If Context7 has no results or is rate-limited, fall back to web search
|
|
49
|
-
- Cache within a session — no need to re-fetch the same library docs repeatedly
|
|
@@ -1,293 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Context7 API client for fetching library documentation.
|
|
3
|
-
|
|
4
|
-
Queries the Context7 REST API to search for libraries and retrieve
|
|
5
|
-
LLM-ready documentation. Replaces the Context7 MCP server with a
|
|
6
|
-
lightweight script that follows the FlyDocs mechanism pattern.
|
|
7
|
-
|
|
8
|
-
Usage:
|
|
9
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py \\
|
|
10
|
-
search <library_name> [query]
|
|
11
|
-
|
|
12
|
-
python3 .claude/skills/flydocs-context7/scripts/context7.py \\
|
|
13
|
-
docs <library_id> <query> [--type txt|json] [--tokens N]
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
import argparse
|
|
17
|
-
import json
|
|
18
|
-
import os
|
|
19
|
-
import sys
|
|
20
|
-
import urllib.error
|
|
21
|
-
import urllib.parse
|
|
22
|
-
import urllib.request
|
|
23
|
-
from pathlib import Path
|
|
24
|
-
|
|
25
|
-
BASE_URL = "https://context7.com/api/v2"
|
|
26
|
-
DEFAULT_TIMEOUT = 10
|
|
27
|
-
DEFAULT_TOKENS = 5000
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# --- Helpers ---
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def fail(message):
|
|
34
|
-
"""Print error to stderr and exit 1."""
|
|
35
|
-
print(message, file=sys.stderr)
|
|
36
|
-
sys.exit(1)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def output_json(data):
|
|
40
|
-
"""Print JSON to stdout."""
|
|
41
|
-
print(json.dumps(data, indent=2))
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def find_project_root(start=None):
|
|
45
|
-
"""Walk up from start (or script location) to find the directory containing .flydocs/."""
|
|
46
|
-
current = Path(start) if start else Path(__file__).resolve().parent
|
|
47
|
-
for parent in [current] + list(current.parents):
|
|
48
|
-
if (parent / ".flydocs").is_dir():
|
|
49
|
-
return parent
|
|
50
|
-
return None
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def read_env_file(root):
|
|
54
|
-
"""Read .env file at project root and return a dict of key=value pairs."""
|
|
55
|
-
env_path = root / ".env"
|
|
56
|
-
if not env_path.is_file():
|
|
57
|
-
return {}
|
|
58
|
-
|
|
59
|
-
env_vars = {}
|
|
60
|
-
try:
|
|
61
|
-
with open(env_path, "r", encoding="utf-8") as f:
|
|
62
|
-
for line in f:
|
|
63
|
-
line = line.strip()
|
|
64
|
-
# Skip empty lines and comments
|
|
65
|
-
if not line or line.startswith("#"):
|
|
66
|
-
continue
|
|
67
|
-
if "=" not in line:
|
|
68
|
-
continue
|
|
69
|
-
key, _, value = line.partition("=")
|
|
70
|
-
key = key.strip()
|
|
71
|
-
value = value.strip()
|
|
72
|
-
# Strip surrounding quotes if present
|
|
73
|
-
if len(value) >= 2 and value[0] == value[-1] and value[0] in ('"', "'"):
|
|
74
|
-
value = value[1:-1]
|
|
75
|
-
env_vars[key] = value
|
|
76
|
-
except OSError:
|
|
77
|
-
pass
|
|
78
|
-
|
|
79
|
-
return env_vars
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def resolve_api_key(args_key):
|
|
83
|
-
"""Resolve the API key from flag, env var, or .env file. Returns None if unavailable."""
|
|
84
|
-
# 1. Explicit flag
|
|
85
|
-
if args_key:
|
|
86
|
-
return args_key
|
|
87
|
-
|
|
88
|
-
# 2. Environment variable
|
|
89
|
-
env_key = os.environ.get("CONTEXT7_API_KEY")
|
|
90
|
-
if env_key:
|
|
91
|
-
return env_key
|
|
92
|
-
|
|
93
|
-
# 3. .env file at project root
|
|
94
|
-
root = find_project_root()
|
|
95
|
-
if root:
|
|
96
|
-
env_vars = read_env_file(root)
|
|
97
|
-
dotenv_key = env_vars.get("CONTEXT7_API_KEY")
|
|
98
|
-
if dotenv_key:
|
|
99
|
-
return dotenv_key
|
|
100
|
-
|
|
101
|
-
# 4. Anonymous (no key)
|
|
102
|
-
return None
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def api_request(path, params, api_key=None):
|
|
106
|
-
"""Make a GET request to the Context7 API and return parsed response data.
|
|
107
|
-
|
|
108
|
-
Handles HTTP errors, timeouts, and network failures with clear messages.
|
|
109
|
-
"""
|
|
110
|
-
query_string = urllib.parse.urlencode(params)
|
|
111
|
-
url = f"{BASE_URL}/{path}?{query_string}"
|
|
112
|
-
|
|
113
|
-
request = urllib.request.Request(url)
|
|
114
|
-
request.add_header("User-Agent", "flydocs-context7/1.0")
|
|
115
|
-
|
|
116
|
-
if api_key:
|
|
117
|
-
request.add_header("Authorization", f"Bearer {api_key}")
|
|
118
|
-
|
|
119
|
-
try:
|
|
120
|
-
with urllib.request.urlopen(request, timeout=DEFAULT_TIMEOUT) as response:
|
|
121
|
-
body = response.read().decode("utf-8")
|
|
122
|
-
content_type = response.headers.get("Content-Type", "")
|
|
123
|
-
if "application/json" in content_type:
|
|
124
|
-
return json.loads(body)
|
|
125
|
-
return body
|
|
126
|
-
except urllib.error.HTTPError as e:
|
|
127
|
-
if e.code == 429:
|
|
128
|
-
fail("Rate limited by Context7 API. Wait a moment and try again.")
|
|
129
|
-
body_text = ""
|
|
130
|
-
try:
|
|
131
|
-
body_text = e.read().decode("utf-8", errors="replace")
|
|
132
|
-
except Exception:
|
|
133
|
-
pass
|
|
134
|
-
fail(f"Context7 API error (HTTP {e.code}): {e.reason}\n{body_text}".strip())
|
|
135
|
-
except urllib.error.URLError as e:
|
|
136
|
-
if "timed out" in str(e.reason).lower():
|
|
137
|
-
fail("Context7 API request timed out (10s). The service may be slow or unavailable.")
|
|
138
|
-
fail(f"Cannot reach Context7 API. Check your network connection.\nDetails: {e.reason}")
|
|
139
|
-
except OSError as e:
|
|
140
|
-
fail(f"Network error connecting to Context7 API: {e}")
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
# --- Commands ---
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
def cmd_search(args):
|
|
147
|
-
"""Search for libraries by name and optional query."""
|
|
148
|
-
params = {"libraryName": args.library_name}
|
|
149
|
-
if args.query:
|
|
150
|
-
params["query"] = args.query
|
|
151
|
-
|
|
152
|
-
api_key = resolve_api_key(args.key)
|
|
153
|
-
data = api_request("libs/search", params, api_key=api_key)
|
|
154
|
-
|
|
155
|
-
# Normalize response — API wraps results in {"results": [...]}
|
|
156
|
-
if isinstance(data, dict) and "results" in data:
|
|
157
|
-
results = data["results"]
|
|
158
|
-
elif isinstance(data, list):
|
|
159
|
-
results = data
|
|
160
|
-
else:
|
|
161
|
-
results = []
|
|
162
|
-
|
|
163
|
-
if args.type == "json" or args.type is None:
|
|
164
|
-
# Default for search is JSON
|
|
165
|
-
compact = []
|
|
166
|
-
for lib in results:
|
|
167
|
-
compact.append({
|
|
168
|
-
"id": lib.get("id", ""),
|
|
169
|
-
"name": lib.get("title", lib.get("name", "")),
|
|
170
|
-
"description": lib.get("description", ""),
|
|
171
|
-
"trustScore": lib.get("trustScore", 0),
|
|
172
|
-
})
|
|
173
|
-
output_json(compact)
|
|
174
|
-
else:
|
|
175
|
-
# txt format for search — one line per result
|
|
176
|
-
for lib in results:
|
|
177
|
-
name = lib.get("title", lib.get("name", "unknown"))
|
|
178
|
-
lib_id = lib.get("id", "")
|
|
179
|
-
desc = lib.get("description", "")
|
|
180
|
-
score = lib.get("trustScore", 0)
|
|
181
|
-
print(f"{lib_id} {name} (trust: {score})")
|
|
182
|
-
if desc:
|
|
183
|
-
print(f" {desc}")
|
|
184
|
-
print()
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def cmd_docs(args):
|
|
188
|
-
"""Fetch documentation for a specific library."""
|
|
189
|
-
params = {
|
|
190
|
-
"libraryId": args.library_id,
|
|
191
|
-
"query": args.query,
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
output_type = args.type if args.type else "txt"
|
|
195
|
-
params["type"] = output_type
|
|
196
|
-
|
|
197
|
-
if args.tokens:
|
|
198
|
-
params["tokens"] = str(args.tokens)
|
|
199
|
-
|
|
200
|
-
api_key = resolve_api_key(args.key)
|
|
201
|
-
data = api_request("context", params, api_key=api_key)
|
|
202
|
-
|
|
203
|
-
if output_type == "json":
|
|
204
|
-
if isinstance(data, str):
|
|
205
|
-
# API returned text when we asked for JSON; wrap it
|
|
206
|
-
output_json({"content": data})
|
|
207
|
-
else:
|
|
208
|
-
output_json(data)
|
|
209
|
-
else:
|
|
210
|
-
# txt — print directly
|
|
211
|
-
if isinstance(data, str):
|
|
212
|
-
print(data)
|
|
213
|
-
elif isinstance(data, dict):
|
|
214
|
-
content = data.get("content", data.get("text", ""))
|
|
215
|
-
if content:
|
|
216
|
-
print(content)
|
|
217
|
-
else:
|
|
218
|
-
output_json(data)
|
|
219
|
-
else:
|
|
220
|
-
output_json(data)
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
# --- Main ---
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
def main():
|
|
227
|
-
parser = argparse.ArgumentParser(
|
|
228
|
-
description="Context7 API client — search libraries and fetch documentation"
|
|
229
|
-
)
|
|
230
|
-
parser.add_argument(
|
|
231
|
-
"--key", type=str, default=None,
|
|
232
|
-
help="API key override (default: CONTEXT7_API_KEY env var or .env file)"
|
|
233
|
-
)
|
|
234
|
-
|
|
235
|
-
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
236
|
-
|
|
237
|
-
# search subcommand
|
|
238
|
-
search_parser = subparsers.add_parser(
|
|
239
|
-
"search",
|
|
240
|
-
help="Search for libraries by name"
|
|
241
|
-
)
|
|
242
|
-
search_parser.add_argument(
|
|
243
|
-
"library_name",
|
|
244
|
-
help="Library name to search for (e.g., 'react', 'next.js')"
|
|
245
|
-
)
|
|
246
|
-
search_parser.add_argument(
|
|
247
|
-
"query", nargs="?", default=None,
|
|
248
|
-
help="Optional search query to refine results"
|
|
249
|
-
)
|
|
250
|
-
search_parser.add_argument(
|
|
251
|
-
"--type", choices=["txt", "json"], default=None,
|
|
252
|
-
help="Output format (default: json for search)"
|
|
253
|
-
)
|
|
254
|
-
search_parser.add_argument(
|
|
255
|
-
"--tokens", type=int, default=DEFAULT_TOKENS,
|
|
256
|
-
help=f"Max tokens budget hint (default: {DEFAULT_TOKENS})"
|
|
257
|
-
)
|
|
258
|
-
|
|
259
|
-
# docs subcommand
|
|
260
|
-
docs_parser = subparsers.add_parser(
|
|
261
|
-
"docs",
|
|
262
|
-
help="Fetch documentation for a library"
|
|
263
|
-
)
|
|
264
|
-
docs_parser.add_argument(
|
|
265
|
-
"library_id",
|
|
266
|
-
help="Library ID from search results (e.g., '/vercel/next.js')"
|
|
267
|
-
)
|
|
268
|
-
docs_parser.add_argument(
|
|
269
|
-
"query",
|
|
270
|
-
help="Documentation query (e.g., 'server components', 'routing')"
|
|
271
|
-
)
|
|
272
|
-
docs_parser.add_argument(
|
|
273
|
-
"--type", choices=["txt", "json"], default=None,
|
|
274
|
-
help="Output format (default: txt for docs)"
|
|
275
|
-
)
|
|
276
|
-
docs_parser.add_argument(
|
|
277
|
-
"--tokens", type=int, default=DEFAULT_TOKENS,
|
|
278
|
-
help=f"Max tokens budget hint (default: {DEFAULT_TOKENS})"
|
|
279
|
-
)
|
|
280
|
-
|
|
281
|
-
args = parser.parse_args()
|
|
282
|
-
|
|
283
|
-
if args.command == "search":
|
|
284
|
-
cmd_search(args)
|
|
285
|
-
elif args.command == "docs":
|
|
286
|
-
cmd_docs(args)
|
|
287
|
-
else:
|
|
288
|
-
parser.print_help()
|
|
289
|
-
sys.exit(1)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
if __name__ == "__main__":
|
|
293
|
-
main()
|