@flydocs/cli 0.5.0-beta.7 → 0.5.0-beta.8
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 +13 -2
- package/package.json +1 -1
- package/template/.claude/CLAUDE.md +1 -0
- package/template/.claude/skills/README.md +1 -0
- package/template/.claude/skills/flydocs-context7/SKILL.md +105 -0
- package/template/.claude/skills/flydocs-context7/cursor-rule.mdc +49 -0
- package/template/.claude/skills/flydocs-context7/scripts/context7.py +293 -0
- package/template/.env.example +9 -1
- package/template/.flydocs/config.json +1 -1
- package/template/.flydocs/hooks/auto-approve.py +1 -1
- package/template/.flydocs/version +1 -1
- package/template/AGENTS.md +1 -0
- package/template/CHANGELOG.md +78 -0
- package/template/manifest.json +4 -2
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ var CLI_VERSION, CLI_NAME, PACKAGE_NAME;
|
|
|
15
15
|
var init_constants = __esm({
|
|
16
16
|
"src/lib/constants.ts"() {
|
|
17
17
|
"use strict";
|
|
18
|
-
CLI_VERSION = "0.5.0-beta.
|
|
18
|
+
CLI_VERSION = "0.5.0-beta.8";
|
|
19
19
|
CLI_NAME = "flydocs";
|
|
20
20
|
PACKAGE_NAME = "@flydocs/cli";
|
|
21
21
|
}
|
|
@@ -371,6 +371,16 @@ async function copyCursorRules(targetDir) {
|
|
|
371
371
|
await copyFile(mechRule, join4(rulesDir, "flydocs-mechanism.mdc"));
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
|
+
const context7Rule = join4(
|
|
375
|
+
targetDir,
|
|
376
|
+
".claude",
|
|
377
|
+
"skills",
|
|
378
|
+
"flydocs-context7",
|
|
379
|
+
"cursor-rule.mdc"
|
|
380
|
+
);
|
|
381
|
+
if (await pathExists(context7Rule)) {
|
|
382
|
+
await copyFile(context7Rule, join4(rulesDir, "flydocs-context7.mdc"));
|
|
383
|
+
}
|
|
374
384
|
}
|
|
375
385
|
var OWNED_SKILLS, MECHANISM_SKILLS;
|
|
376
386
|
var init_skills = __esm({
|
|
@@ -381,7 +391,8 @@ var init_skills = __esm({
|
|
|
381
391
|
"flydocs-workflow",
|
|
382
392
|
"flydocs-figma",
|
|
383
393
|
"flydocs-estimates",
|
|
384
|
-
"flydocs-context-graph"
|
|
394
|
+
"flydocs-context-graph",
|
|
395
|
+
"flydocs-context7"
|
|
385
396
|
];
|
|
386
397
|
MECHANISM_SKILLS = {
|
|
387
398
|
local: "flydocs-local",
|
package/package.json
CHANGED
|
@@ -116,6 +116,7 @@ Consult the relevant skill BEFORE writing code or making workflow decisions.
|
|
|
116
116
|
| Skill | Triggers | Entry |
|
|
117
117
|
| ----------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
|
|
118
118
|
| flydocs-cloud | create issue, transition, comment, list issues, assign, update description, update issue, project update, Linear, cloud | .claude/skills/flydocs-cloud/SKILL.md |
|
|
119
|
+
| flydocs-context7 | context7, library docs, documentation lookup, framework docs, package docs, API reference | .claude/skills/flydocs-context7/SKILL.md |
|
|
119
120
|
| flydocs-estimates | estimate, cost, token usage, API cost, labor estimate, sizing, effort | .claude/skills/flydocs-estimates/SKILL.md |
|
|
120
121
|
| flydocs-figma | Figma, design, screenshot, token mapping, component from design, pixel-perfect, design system | .claude/skills/flydocs-figma/SKILL.md |
|
|
121
122
|
| flydocs-local | create issue, transition, comment, list issues, assign, update description, status summary, local | .claude/skills/flydocs-local/SKILL.md |
|
|
@@ -16,6 +16,7 @@ functionality gated via API relay.
|
|
|
16
16
|
| `flydocs-workflow` | Core | Lifecycle stages, session management, comment templates |
|
|
17
17
|
| `flydocs-local` | Mechanism (free) | File-based issue management |
|
|
18
18
|
| `flydocs-cloud` | Mechanism (paid) | Linear/provider issue management via API |
|
|
19
|
+
| `flydocs-context7` | Core | Library documentation lookup via Context7 API |
|
|
19
20
|
| `flydocs-figma` | Premium | Design extraction from Figma |
|
|
20
21
|
| `flydocs-estimates` | Premium | AI token/labor cost estimation |
|
|
21
22
|
|
|
@@ -0,0 +1,105 @@
|
|
|
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
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
|
@@ -0,0 +1,293 @@
|
|
|
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()
|
package/template/.env.example
CHANGED
|
@@ -33,9 +33,17 @@ LINEAR_API_KEY=
|
|
|
33
33
|
# OPTIONAL: Figma Access Token
|
|
34
34
|
# ===========================================
|
|
35
35
|
# Get from: Figma → Settings → Personal Access Tokens
|
|
36
|
-
# Only needed if using
|
|
36
|
+
# Only needed if using the flydocs-figma skill for design integration
|
|
37
37
|
FIGMA_ACCESS_TOKEN=
|
|
38
38
|
|
|
39
|
+
# ===========================================
|
|
40
|
+
# OPTIONAL: Context7 API Key
|
|
41
|
+
# ===========================================
|
|
42
|
+
# Enables higher rate limits for library documentation lookup
|
|
43
|
+
# Get from: context7.com/dashboard (free account)
|
|
44
|
+
# Works without a key at lower rate limits (~1,000 calls/month)
|
|
45
|
+
CONTEXT7_API_KEY=
|
|
46
|
+
|
|
39
47
|
# ===========================================
|
|
40
48
|
# NOTE: Team ID and Project ID are discovered automatically
|
|
41
49
|
# ===========================================
|
|
@@ -21,7 +21,7 @@ import re
|
|
|
21
21
|
# Pattern matches any flydocs skill scripts directory
|
|
22
22
|
# Covers: flydocs-local, flydocs-cloud, flydocs-workflow, flydocs-context-graph
|
|
23
23
|
APPROVED_PATTERN = re.compile(
|
|
24
|
-
r'python3?\s+(?:["\']?(?:\$CLAUDE_PROJECT_DIR|\$\{CLAUDE_PROJECT_DIR\}|\.)["\']?/)?\.?claude/skills/flydocs-(?:local|cloud|workflow|context-graph)/scripts/\w+\.py'
|
|
24
|
+
r'python3?\s+(?:["\']?(?:\$CLAUDE_PROJECT_DIR|\$\{CLAUDE_PROJECT_DIR\}|\.)["\']?/)?\.?claude/skills/flydocs-(?:local|cloud|workflow|context-graph|context7)/scripts/\w+\.py'
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.5.0-beta.
|
|
1
|
+
0.5.0-beta.8
|
package/template/AGENTS.md
CHANGED
|
@@ -95,6 +95,7 @@ Consult the relevant skill BEFORE writing code or making workflow decisions.
|
|
|
95
95
|
| Skill | Triggers | Entry |
|
|
96
96
|
| ----------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
|
|
97
97
|
| flydocs-cloud | create issue, transition, comment, list issues, assign, update description, update issue, project update, Linear, cloud | .claude/skills/flydocs-cloud/SKILL.md |
|
|
98
|
+
| flydocs-context7 | context7, library docs, documentation lookup, framework docs, package docs, API reference | .claude/skills/flydocs-context7/SKILL.md |
|
|
98
99
|
| flydocs-estimates | estimate, cost, token usage, API cost, labor estimate, sizing, effort | .claude/skills/flydocs-estimates/SKILL.md |
|
|
99
100
|
| flydocs-figma | Figma, design, screenshot, token mapping, component from design, pixel-perfect, design system | .claude/skills/flydocs-figma/SKILL.md |
|
|
100
101
|
| flydocs-local | create issue, transition, comment, list issues, assign, update description, status summary, local | .claude/skills/flydocs-local/SKILL.md |
|
package/template/CHANGELOG.md
CHANGED
|
@@ -7,9 +7,62 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [0.5.0-beta.8] — 2026-02-22
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Context7 documentation skill** (`flydocs-context7`) — stdlib-only Python script
|
|
15
|
+
that calls the Context7 REST API to fetch up-to-date library documentation.
|
|
16
|
+
Replaces the removed Context7 MCP with a skill+script pattern.
|
|
17
|
+
- `context7.py search <library> [query]` — resolve library name to Context7 ID
|
|
18
|
+
- `context7.py docs <library_id> <query>` — fetch relevant documentation snippets
|
|
19
|
+
- Works without API key (anonymous, ~1,000 calls/month); optional
|
|
20
|
+
`CONTEXT7_API_KEY` in `.env` for higher rate limits
|
|
21
|
+
- Auto-approved by hook for seamless agent invocation
|
|
22
|
+
- Cursor rule included for cross-IDE support
|
|
23
|
+
- **Context7 API key** in `.env.example` — optional configuration for higher rate limits
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- `.env.example` — corrected "Figma MCP" reference to "flydocs-figma skill"
|
|
28
|
+
|
|
29
|
+
## [0.5.0-beta.7] — 2026-02-22
|
|
30
|
+
|
|
31
|
+
### Removed
|
|
32
|
+
|
|
33
|
+
- **All MCP references** — removed `.cursor/mcp.json`, `prefer-scripts.py` hook,
|
|
34
|
+
MCP config preservation in update flow, MCP section in instructions template.
|
|
35
|
+
Skills fully replace MCPs as the FlyDocs architecture.
|
|
36
|
+
- **Phantom skills** — removed references to `implementation-flow`, `review-workflow`,
|
|
37
|
+
`spec-templates` skills that were never shipped.
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- **Command injection** (`connect.ts`) — replaced `execSync` subprocess with native
|
|
42
|
+
`fetch()` for Linear API key validation.
|
|
43
|
+
- **Version comparison** — pre-release versions (e.g. `0.5.0-beta.3`) now compare
|
|
44
|
+
correctly instead of returning NaN.
|
|
45
|
+
- **Auto-approve hook** — tightened regex to anchor script paths, preventing potential
|
|
46
|
+
pattern-matching bypasses.
|
|
47
|
+
- **Post-edit hook** — added path traversal validation using `os.path.realpath()`.
|
|
48
|
+
- **Post-install scripts** — switched from `execSync` to `execFileSync` for subprocess safety.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- **Stack detection** — now reads `flydocs/context/project.md` in addition to
|
|
53
|
+
`package.json` for declared stack frameworks.
|
|
54
|
+
- **Community skills on update** — filters already-installed skills before prompting.
|
|
55
|
+
- **Cloud exposure** — `.env.example` marked as cloud tier only, `flydocs/README.md`
|
|
56
|
+
rewritten as tier-generic, config defaults changed to `tier: "local"`.
|
|
57
|
+
- **Deprecated cleanup** — `.cursor/mcp.json` and `prefer-scripts.py` added to
|
|
58
|
+
deprecated files list for automatic cleanup on update.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
10
62
|
## [0.4.0] — 2026-02-18
|
|
11
63
|
|
|
12
64
|
### Added
|
|
65
|
+
|
|
13
66
|
- **Context Graph skill** (`flydocs-context-graph`) — relationship-aware knowledge
|
|
14
67
|
graph that connects skills, ADRs, issues, modules, and sessions. Implemented as
|
|
15
68
|
ADR-006 across five phases:
|
|
@@ -32,12 +85,14 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
32
85
|
graph automatically.
|
|
33
86
|
|
|
34
87
|
### Changed
|
|
88
|
+
|
|
35
89
|
- **Session wrap procedure** — `session.md` now includes a step to record session
|
|
36
90
|
outcomes in the context graph via `graph_session.py`. Skips silently if not installed.
|
|
37
91
|
- **Session staleness policy** — session nodes within 7 days get full weight, linear
|
|
38
92
|
decay to 30 days, then excluded from context.
|
|
39
93
|
|
|
40
94
|
### Migration
|
|
95
|
+
|
|
41
96
|
- **`.gitignore` update** — `flydocs/context/graph.json` is automatically added to
|
|
42
97
|
`.gitignore` during update if missing. The graph is gitignored because it contains
|
|
43
98
|
session-specific data and can be rebuilt from sources.
|
|
@@ -47,6 +102,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
47
102
|
## [0.3.10] — 2026-02-17
|
|
48
103
|
|
|
49
104
|
### Fixed
|
|
105
|
+
|
|
50
106
|
- **API null data crash** (FLY-178) — `flydocs_api.py` now normalizes `null` data
|
|
51
107
|
responses to empty dict before returning. Fixes `AttributeError` crashes in all
|
|
52
108
|
20+ scripts when Linear returns API errors. `create_issue.py` also retries without
|
|
@@ -65,6 +121,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
65
121
|
## [0.3.9] — 2026-02-17
|
|
66
122
|
|
|
67
123
|
### Added
|
|
124
|
+
|
|
68
125
|
- **Skill search and install CLI** (ENG-443) — `flydocs skills` subcommand with
|
|
69
126
|
`search`, `add`, `remove`, and `list` operations. Search the curated community
|
|
70
127
|
skills catalog, install from known names or GitHub repo references, and manage
|
|
@@ -81,6 +138,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
81
138
|
## [0.3.8] — 2026-02-14
|
|
82
139
|
|
|
83
140
|
### Added
|
|
141
|
+
|
|
84
142
|
- **`create_issue.py --description-file` and stdin** — both cloud and local tiers now
|
|
85
143
|
accept `--description-file PATH` or piped stdin for issue descriptions. Eliminates
|
|
86
144
|
the two-step create + update_description workaround for long descriptions.
|
|
@@ -92,6 +150,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
92
150
|
## [0.3.7] — 2026-02-11
|
|
93
151
|
|
|
94
152
|
### Added
|
|
153
|
+
|
|
95
154
|
- **Skill manifest generator** (ENG-442) — `generate_manifest.py` scans SKILL.md
|
|
96
155
|
frontmatter and produces a compressed skills index table. Injected into CLAUDE.md
|
|
97
156
|
and AGENTS.md between `<!-- flydocs:skills-manifest -->` markers. Bridges skill
|
|
@@ -104,12 +163,14 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
104
163
|
## [0.3.6] — 2026-02-10
|
|
105
164
|
|
|
106
165
|
### Added
|
|
166
|
+
|
|
107
167
|
- **Milestone, project, and dueDate in issue output** — `list_issues.py` now returns
|
|
108
168
|
`milestone`, `milestoneId`, `milestoneSortOrder`, `project`, `projectId`, and `dueDate`
|
|
109
169
|
for every issue. `get_issue.py` returns the same fields (minus `milestoneSortOrder`).
|
|
110
170
|
Enables milestone-grouped dashboards and priority-based session planning.
|
|
111
171
|
|
|
112
172
|
### Changed
|
|
173
|
+
|
|
113
174
|
- **Session start workflow rewritten** — `session.md` now instructs agents to group issues
|
|
114
175
|
by milestone (in milestone order), identify the current milestone, suggest a starting point
|
|
115
176
|
based on priority cascade (blocked → in-progress → due soon → highest priority in current
|
|
@@ -117,6 +178,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
117
178
|
the product scope.
|
|
118
179
|
|
|
119
180
|
### Fixed
|
|
181
|
+
|
|
120
182
|
- **`create_milestone.py` missing projectId** — `ProjectMilestoneCreateInput` requires a
|
|
121
183
|
`projectId`. Script now defaults to first `activeProject` from config, with `--project`
|
|
122
184
|
flag to override.
|
|
@@ -126,10 +188,12 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
126
188
|
## [0.3.5] — 2026-02-10
|
|
127
189
|
|
|
128
190
|
### Added
|
|
191
|
+
|
|
129
192
|
- **`list_projects.py` product scope** (ENG-475) — now respects `workspace.activeProjects`
|
|
130
193
|
config. `--all` bypasses product scope to show all team projects.
|
|
131
194
|
|
|
132
195
|
### Fixed
|
|
196
|
+
|
|
133
197
|
- **`list_projects.py` 400 error** (ENG-474) — state filter was using nested
|
|
134
198
|
`{type: {nin: [...]}}` instead of direct `StringComparator` `{nin: [...]}`.
|
|
135
199
|
Both `--active` (started only) and default (excludes completed/canceled) now work.
|
|
@@ -143,6 +207,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
143
207
|
## [0.3.4] — 2026-02-10
|
|
144
208
|
|
|
145
209
|
### Added
|
|
210
|
+
|
|
146
211
|
- **`list_issues.py --milestone` filter** — filter issues by project milestone ID.
|
|
147
212
|
Get milestone IDs from `list_milestones.py`, then pass to `list_issues.py --milestone <ID>`
|
|
148
213
|
to see all issues within a specific milestone.
|
|
@@ -152,6 +217,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
152
217
|
## [0.3.3] — 2026-02-10
|
|
153
218
|
|
|
154
219
|
### Fixed
|
|
220
|
+
|
|
155
221
|
- **Shell escaping in `update_description.py`** — descriptions with apostrophes,
|
|
156
222
|
parentheses, quotes, and other shell metacharacters no longer break when passed
|
|
157
223
|
via `--text`. Scripts now accept stdin as input, allowing safe heredoc piping:
|
|
@@ -164,6 +230,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
164
230
|
## [0.3.2] — 2026-02-09
|
|
165
231
|
|
|
166
232
|
### Fixed
|
|
233
|
+
|
|
167
234
|
- **API connection reliability** — reduced socket timeout from 30s to 10s and increased
|
|
168
235
|
max retries from 3 to 5. Resolves intermittent hangs caused by DNS returning unreachable
|
|
169
236
|
Cloudflare edge IPs. Scripts now fail over to a working IP within seconds instead of
|
|
@@ -176,11 +243,13 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
176
243
|
## [0.3.1] — 2026-02-08
|
|
177
244
|
|
|
178
245
|
### Fixed
|
|
246
|
+
|
|
179
247
|
- **`list_issues.py` product scope** — scoping via `activeProjects` and `product.labelIds`
|
|
180
248
|
now applies regardless of `--active` or `--status` flags. Previously, these flags
|
|
181
249
|
bypassed product scope entirely, returning all team issues.
|
|
182
250
|
|
|
183
251
|
### Added
|
|
252
|
+
|
|
184
253
|
- **`build_product_scope()` API helper** — new method on `FlyDocsClient` implements the
|
|
185
254
|
product scope cascade: `activeProjects` → `product.labelIds` → team-wide.
|
|
186
255
|
- **Multiple `activeProjects` support** — `list_issues.py` now uses OR logic when
|
|
@@ -193,6 +262,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
193
262
|
## [0.3.0] — 2026-02-08
|
|
194
263
|
|
|
195
264
|
### Added
|
|
265
|
+
|
|
196
266
|
- **`update_issue.py` bulk update script** — set multiple fields (priority, estimate,
|
|
197
267
|
assignee, state, description, comment) in a single API call instead of separate scripts.
|
|
198
268
|
- **`list_issues.py --active` flag** — returns all non-terminal issues (excludes Done,
|
|
@@ -204,12 +274,14 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
204
274
|
cached within each script invocation to reduce redundant API calls.
|
|
205
275
|
|
|
206
276
|
### Changed
|
|
277
|
+
|
|
207
278
|
- **`transition.py` optimized** — combined state update and cycle assignment into a
|
|
208
279
|
single `issueUpdate` mutation (was two separate calls for IMPLEMENTING transitions).
|
|
209
280
|
- **Session start efficiency** — single `list_issues.py --active` call replaces
|
|
210
281
|
per-status queries. Issues grouped by status in response.
|
|
211
282
|
|
|
212
283
|
### Removed
|
|
284
|
+
|
|
213
285
|
- **`status_summary.py`** — retired from cloud mechanism. Use `list_issues.py --active`
|
|
214
286
|
and group results by the status field instead.
|
|
215
287
|
|
|
@@ -218,6 +290,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
218
290
|
## [0.2.1] — 2026-02-07
|
|
219
291
|
|
|
220
292
|
### Fixed
|
|
293
|
+
|
|
221
294
|
- **Commands not fully populating** — changed from additive `cp` to clear-then-copy
|
|
222
295
|
for `.claude/commands/` and `.cursor/commands/` directories.
|
|
223
296
|
- **`docflow-core.mdc` not cleaned up** — added to deprecated cursor rules list.
|
|
@@ -227,6 +300,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
227
300
|
synced with version file.
|
|
228
301
|
|
|
229
302
|
### Added
|
|
303
|
+
|
|
230
304
|
- **`--force` flag** — force update even when versions match.
|
|
231
305
|
- **Old cursor rule directories and commands** added to deprecated cleanup.
|
|
232
306
|
|
|
@@ -235,6 +309,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
235
309
|
## [0.2.0] — 2026-02-06
|
|
236
310
|
|
|
237
311
|
### Added
|
|
312
|
+
|
|
238
313
|
- **Scenario-aware setup command** — `/flydocs-setup` rewritten as a comprehensive
|
|
239
314
|
agent prompt handling three scenarios: New Project, DocFlow Migration, FlyDocs Update.
|
|
240
315
|
Includes proactive repo scanning for PRDs and existing documentation.
|
|
@@ -247,10 +322,12 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
247
322
|
pre-v1.0 artifacts: old skills, rules, hooks, and cursor rules.
|
|
248
323
|
|
|
249
324
|
### Changed
|
|
325
|
+
|
|
250
326
|
- **Version file synced with manifest** — `.flydocs/version` now matches
|
|
251
327
|
`manifest.json` version field (was out of sync in 0.1.0).
|
|
252
328
|
|
|
253
329
|
### Removed
|
|
330
|
+
|
|
254
331
|
- Orphaned hook scripts: `session-end.py`, `linear-auto-approve.py`
|
|
255
332
|
|
|
256
333
|
---
|
|
@@ -258,6 +335,7 @@ Versioning: [Semantic Versioning](https://semver.org/).
|
|
|
258
335
|
## [0.1.0] — 2026-01-15
|
|
259
336
|
|
|
260
337
|
### Added
|
|
338
|
+
|
|
261
339
|
- Initial release of FlyDocs Core
|
|
262
340
|
- Workflow skill (`flydocs-workflow`) with full lifecycle stages
|
|
263
341
|
- Mechanism skills: `flydocs-cloud` (Linear API) and `flydocs-local` (file-based)
|
package/template/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.5.0-beta.
|
|
2
|
+
"version": "0.5.0-beta.8",
|
|
3
3
|
"description": "FlyDocs Core - Manifest of all managed files",
|
|
4
4
|
"repository": "github.com/plastrlab/flydocs-core",
|
|
5
5
|
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
".claude/skills/flydocs-figma",
|
|
19
19
|
".claude/skills/flydocs-estimates",
|
|
20
20
|
".claude/skills/flydocs-context-graph",
|
|
21
|
+
".claude/skills/flydocs-context7",
|
|
21
22
|
".flydocs/scripts",
|
|
22
23
|
".cursor/agents"
|
|
23
24
|
]
|
|
@@ -145,7 +146,8 @@
|
|
|
145
146
|
"flydocs-local": ["SKILL.md", "cursor-rule.mdc", "scripts/"],
|
|
146
147
|
"flydocs-figma": ["SKILL.md", "references/"],
|
|
147
148
|
"flydocs-estimates": ["SKILL.md", "references/"],
|
|
148
|
-
"flydocs-context-graph": ["SKILL.md", "schema.md", "scripts/"]
|
|
149
|
+
"flydocs-context-graph": ["SKILL.md", "schema.md", "scripts/"],
|
|
150
|
+
"flydocs-context7": ["SKILL.md", "cursor-rule.mdc", "scripts/"]
|
|
149
151
|
}
|
|
150
152
|
},
|
|
151
153
|
".cursor": {
|