@tydung26/product-kit 1.3.2 → 1.5.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/README.md +4 -8
- package/dist/scripts/market-intel/search-app-store.d.ts +7 -0
- package/dist/scripts/market-intel/search-app-store.d.ts.map +1 -0
- package/dist/scripts/market-intel/search-app-store.js +91 -0
- package/dist/scripts/market-intel/search-app-store.js.map +1 -0
- package/dist/scripts/market-intel/search-google-play.d.ts +7 -0
- package/dist/scripts/market-intel/search-google-play.d.ts.map +1 -0
- package/dist/scripts/market-intel/search-google-play.js +195 -0
- package/dist/scripts/market-intel/search-google-play.js.map +1 -0
- package/dist/scripts/market-intel/search-product-hunt.d.ts +7 -0
- package/dist/scripts/market-intel/search-product-hunt.d.ts.map +1 -0
- package/dist/scripts/market-intel/search-product-hunt.js +236 -0
- package/dist/scripts/market-intel/search-product-hunt.js.map +1 -0
- package/dist/scripts/market-intel/search-yc-launch.d.ts +7 -0
- package/dist/scripts/market-intel/search-yc-launch.d.ts.map +1 -0
- package/dist/scripts/market-intel/search-yc-launch.js +229 -0
- package/dist/scripts/market-intel/search-yc-launch.js.map +1 -0
- package/dist/scripts/market-intel/shared-types.d.ts +44 -0
- package/dist/scripts/market-intel/shared-types.d.ts.map +1 -0
- package/dist/scripts/market-intel/shared-types.js +63 -0
- package/dist/scripts/market-intel/shared-types.js.map +1 -0
- package/package.json +8 -9
- package/skills/market-intel/SKILL.md +184 -61
- package/skills/market-intel/scripts/search-app-store.py +117 -0
- package/skills/market-intel/scripts/search-google-play.py +179 -0
- package/skills/market-intel/scripts/search-product-hunt.py +194 -0
- package/skills/market-intel/scripts/search-yc-launch.py +160 -0
- package/skills/naming/SKILL.md +66 -0
- package/dist/commands/config/index.d.ts +0 -3
- package/dist/commands/config/index.d.ts.map +0 -1
- package/dist/commands/config/index.js +0 -34
- package/dist/commands/config/index.js.map +0 -1
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Product Hunt crawler via HTML scraping + __NEXT_DATA__ extraction. Zero deps.
|
|
3
|
+
Usage: python3 search-product-hunt.py "<keywords>" [limit]
|
|
4
|
+
Output: JSON CrawlResult to stdout
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import re
|
|
9
|
+
import sys
|
|
10
|
+
import urllib.request
|
|
11
|
+
import urllib.parse
|
|
12
|
+
from datetime import datetime, timezone
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def safe_fetch(url, timeout=10):
|
|
16
|
+
"""Fetch URL with timeout and user-agent header."""
|
|
17
|
+
req = urllib.request.Request(url, headers={
|
|
18
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
|
19
|
+
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
|
20
|
+
"Chrome/120.0.0.0 Safari/537.36",
|
|
21
|
+
"Accept-Language": "en-US,en;q=0.9",
|
|
22
|
+
})
|
|
23
|
+
return urllib.request.urlopen(req, timeout=timeout).read().decode("utf-8", errors="replace")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def truncate(text, max_len=500):
|
|
27
|
+
return text[:max_len] + "..." if len(text) > max_len else text
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def extract_next_data(html):
|
|
31
|
+
"""Extract __NEXT_DATA__ JSON from a Next.js page."""
|
|
32
|
+
match = re.search(r'<script\s+id="__NEXT_DATA__"[^>]*>(.*?)</script>', html, re.DOTALL)
|
|
33
|
+
if not match:
|
|
34
|
+
return None
|
|
35
|
+
try:
|
|
36
|
+
return json.loads(match.group(1))
|
|
37
|
+
except (json.JSONDecodeError, ValueError):
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def deep_find_posts(obj, depth=0, max_depth=8):
|
|
42
|
+
"""Recursively find post-like objects in nested data."""
|
|
43
|
+
if depth > max_depth or not isinstance(obj, (dict, list)):
|
|
44
|
+
return []
|
|
45
|
+
|
|
46
|
+
posts = []
|
|
47
|
+
if isinstance(obj, list):
|
|
48
|
+
for item in obj:
|
|
49
|
+
posts.extend(deep_find_posts(item, depth + 1, max_depth))
|
|
50
|
+
return posts
|
|
51
|
+
|
|
52
|
+
# Check if this dict looks like a post
|
|
53
|
+
if "slug" in obj and "name" in obj and isinstance(obj.get("name"), str):
|
|
54
|
+
posts.append(obj)
|
|
55
|
+
|
|
56
|
+
for value in obj.values():
|
|
57
|
+
if isinstance(value, (dict, list)):
|
|
58
|
+
posts.extend(deep_find_posts(value, depth + 1, max_depth))
|
|
59
|
+
|
|
60
|
+
return posts
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def extract_post_urls(html):
|
|
64
|
+
"""Extract product post URLs from search results."""
|
|
65
|
+
urls = []
|
|
66
|
+
seen = set()
|
|
67
|
+
for match in re.finditer(r'href="(/posts/[^"?#]+)"', html):
|
|
68
|
+
path = match.group(1)
|
|
69
|
+
if path not in seen:
|
|
70
|
+
seen.add(path)
|
|
71
|
+
urls.append(f"https://www.producthunt.com{path}")
|
|
72
|
+
return urls
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def extract_post_from_page(html, url):
|
|
76
|
+
"""Extract product details from a Product Hunt post page."""
|
|
77
|
+
next_data = extract_next_data(html)
|
|
78
|
+
|
|
79
|
+
if next_data:
|
|
80
|
+
# Search for post object in __NEXT_DATA__
|
|
81
|
+
posts = deep_find_posts(next_data)
|
|
82
|
+
for post in posts:
|
|
83
|
+
name = post.get("name", "")
|
|
84
|
+
if not name:
|
|
85
|
+
continue
|
|
86
|
+
|
|
87
|
+
tagline = post.get("tagline", "")
|
|
88
|
+
description = post.get("description", "") or tagline
|
|
89
|
+
votes = post.get("votesCount", 0)
|
|
90
|
+
rating = post.get("reviewsRating")
|
|
91
|
+
review_count = post.get("reviewsCount") or votes
|
|
92
|
+
topics = [t.get("name", "") for t in post.get("topics", []) if isinstance(t, dict)]
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
"name": name,
|
|
96
|
+
"url": url,
|
|
97
|
+
"description": truncate(description),
|
|
98
|
+
"tagline": tagline or None,
|
|
99
|
+
"rating": round(float(rating), 1) if rating else None,
|
|
100
|
+
"reviewCount": review_count or None,
|
|
101
|
+
"pricing": {"free": True, "other": post.get("pricing")},
|
|
102
|
+
"features": [t for t in topics[:5] if t],
|
|
103
|
+
"reviews": [],
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
# Fallback: meta tags
|
|
107
|
+
name_match = re.search(r'<meta\s+property="og:title"\s+content="([^"]*)"', html)
|
|
108
|
+
desc_match = re.search(r'<meta\s+property="og:description"\s+content="([^"]*)"', html)
|
|
109
|
+
name = name_match.group(1).replace(" | Product Hunt", "") if name_match else ""
|
|
110
|
+
description = desc_match.group(1) if desc_match else ""
|
|
111
|
+
|
|
112
|
+
if not name:
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
"name": name,
|
|
117
|
+
"url": url,
|
|
118
|
+
"description": truncate(description),
|
|
119
|
+
"tagline": None,
|
|
120
|
+
"pricing": {"free": True},
|
|
121
|
+
"features": [],
|
|
122
|
+
"reviews": [],
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def main():
|
|
127
|
+
if len(sys.argv) < 2:
|
|
128
|
+
print(json.dumps({"error": "Usage: python3 search-product-hunt.py <keywords> [limit]"}))
|
|
129
|
+
sys.exit(1)
|
|
130
|
+
|
|
131
|
+
query = sys.argv[1]
|
|
132
|
+
limit = 5
|
|
133
|
+
if len(sys.argv) >= 3:
|
|
134
|
+
try:
|
|
135
|
+
limit = max(1, min(int(sys.argv[2]), 10))
|
|
136
|
+
except ValueError:
|
|
137
|
+
limit = 5
|
|
138
|
+
|
|
139
|
+
errors = []
|
|
140
|
+
search_url = f"https://www.producthunt.com/search?q={urllib.parse.quote(query)}"
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
search_html = safe_fetch(search_url)
|
|
144
|
+
except Exception as e:
|
|
145
|
+
print(json.dumps({
|
|
146
|
+
"platform": "product_hunt", "query": query,
|
|
147
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
148
|
+
"results": [], "errors": [f"Product Hunt search error: {e}"],
|
|
149
|
+
}, indent=2))
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
# Try to get post URLs from search page
|
|
153
|
+
post_urls = extract_post_urls(search_html)[:limit]
|
|
154
|
+
|
|
155
|
+
# Fallback: extract from __NEXT_DATA__ on search page
|
|
156
|
+
if not post_urls:
|
|
157
|
+
next_data = extract_next_data(search_html)
|
|
158
|
+
if next_data:
|
|
159
|
+
posts = deep_find_posts(next_data)
|
|
160
|
+
post_urls = [
|
|
161
|
+
f"https://www.producthunt.com/posts/{p['slug']}"
|
|
162
|
+
for p in posts[:limit] if p.get("slug")
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
if not post_urls:
|
|
166
|
+
errors.append("No post URLs found — page may require JS rendering")
|
|
167
|
+
print(json.dumps({
|
|
168
|
+
"platform": "product_hunt", "query": query,
|
|
169
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
170
|
+
"results": [], "errors": errors,
|
|
171
|
+
}, indent=2))
|
|
172
|
+
return
|
|
173
|
+
|
|
174
|
+
results = []
|
|
175
|
+
for url in post_urls:
|
|
176
|
+
try:
|
|
177
|
+
page_html = safe_fetch(url)
|
|
178
|
+
entry = extract_post_from_page(page_html, url)
|
|
179
|
+
if entry:
|
|
180
|
+
results.append(entry)
|
|
181
|
+
except Exception as e:
|
|
182
|
+
errors.append(f"Error fetching {url}: {e}")
|
|
183
|
+
|
|
184
|
+
print(json.dumps({
|
|
185
|
+
"platform": "product_hunt",
|
|
186
|
+
"query": query,
|
|
187
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
188
|
+
"results": results,
|
|
189
|
+
"errors": errors,
|
|
190
|
+
}, indent=2))
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
if __name__ == "__main__":
|
|
194
|
+
main()
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""YC Launch (Y Combinator) crawler via HTML scraping. Zero external dependencies.
|
|
3
|
+
Usage: python3 search-yc-launch.py "<keywords>" [limit]
|
|
4
|
+
Output: JSON CrawlResult to stdout
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import re
|
|
9
|
+
import sys
|
|
10
|
+
import urllib.request
|
|
11
|
+
import urllib.parse
|
|
12
|
+
from datetime import datetime, timezone
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def safe_fetch(url, timeout=10):
|
|
16
|
+
"""Fetch URL with timeout and user-agent header."""
|
|
17
|
+
req = urllib.request.Request(url, headers={
|
|
18
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
|
19
|
+
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
|
20
|
+
"Chrome/120.0.0.0 Safari/537.36",
|
|
21
|
+
"Accept-Language": "en-US,en;q=0.9",
|
|
22
|
+
})
|
|
23
|
+
return urllib.request.urlopen(req, timeout=timeout).read().decode("utf-8", errors="replace")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def truncate(text, max_len=500):
|
|
27
|
+
return text[:max_len] + "..." if len(text) > max_len else text
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def extract_launch_urls(html):
|
|
31
|
+
"""Extract launch URLs from YC launches page."""
|
|
32
|
+
urls = []
|
|
33
|
+
seen = set()
|
|
34
|
+
for match in re.finditer(r'href="(/launches/[^"?#]+)"', html):
|
|
35
|
+
path = match.group(1)
|
|
36
|
+
if path not in seen:
|
|
37
|
+
seen.add(path)
|
|
38
|
+
urls.append(f"https://www.ycombinator.com{path}")
|
|
39
|
+
return urls
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def extract_launch_from_page(html, url):
|
|
43
|
+
"""Extract launch details from a YC launch page."""
|
|
44
|
+
# Try JSON-LD
|
|
45
|
+
ld_match = re.search(
|
|
46
|
+
r'<script[^>]*type="application/ld\+json"[^>]*>(.*?)</script>',
|
|
47
|
+
html, re.DOTALL
|
|
48
|
+
)
|
|
49
|
+
name = ""
|
|
50
|
+
description = ""
|
|
51
|
+
|
|
52
|
+
if ld_match:
|
|
53
|
+
try:
|
|
54
|
+
data = json.loads(ld_match.group(1))
|
|
55
|
+
name = data.get("name", "")
|
|
56
|
+
description = data.get("description", "")
|
|
57
|
+
except (json.JSONDecodeError, ValueError):
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
# Fallback: meta tags
|
|
61
|
+
if not name:
|
|
62
|
+
m = re.search(r'<meta\s+property="og:title"\s+content="([^"]*)"', html)
|
|
63
|
+
if m:
|
|
64
|
+
name = m.group(1).replace(" | Y Combinator", "").replace("Launch YC: ", "")
|
|
65
|
+
|
|
66
|
+
if not description:
|
|
67
|
+
m = re.search(r'<meta\s+property="og:description"\s+content="([^"]*)"', html)
|
|
68
|
+
if not m:
|
|
69
|
+
m = re.search(r'<meta\s+name="description"\s+content="([^"]*)"', html)
|
|
70
|
+
if m:
|
|
71
|
+
description = m.group(1)
|
|
72
|
+
|
|
73
|
+
if not name:
|
|
74
|
+
# Try h1 tag
|
|
75
|
+
m = re.search(r'<h1[^>]*>([^<]+)</h1>', html)
|
|
76
|
+
if m:
|
|
77
|
+
name = m.group(1).strip()
|
|
78
|
+
|
|
79
|
+
if not name:
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
# Try to extract longer pitch from page body
|
|
83
|
+
pitch = ""
|
|
84
|
+
# Look for main content paragraphs
|
|
85
|
+
for m in re.finditer(r'<p[^>]*>([^<]{50,})</p>', html):
|
|
86
|
+
candidate = m.group(1).strip()
|
|
87
|
+
if len(candidate) > len(pitch):
|
|
88
|
+
pitch = candidate
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
"name": name,
|
|
92
|
+
"url": url,
|
|
93
|
+
"description": truncate(pitch or description),
|
|
94
|
+
"tagline": description[:150] if len(description) < 150 else None,
|
|
95
|
+
"rating": None,
|
|
96
|
+
"reviewCount": None,
|
|
97
|
+
"pricing": {"free": True, "other": None},
|
|
98
|
+
"features": [],
|
|
99
|
+
"reviews": [],
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def main():
|
|
104
|
+
if len(sys.argv) < 2:
|
|
105
|
+
print(json.dumps({"error": "Usage: python3 search-yc-launch.py <keywords> [limit]"}))
|
|
106
|
+
sys.exit(1)
|
|
107
|
+
|
|
108
|
+
query = sys.argv[1]
|
|
109
|
+
limit = 5
|
|
110
|
+
if len(sys.argv) >= 3:
|
|
111
|
+
try:
|
|
112
|
+
limit = max(1, min(int(sys.argv[2]), 10))
|
|
113
|
+
except ValueError:
|
|
114
|
+
limit = 5
|
|
115
|
+
|
|
116
|
+
errors = []
|
|
117
|
+
search_url = f"https://www.ycombinator.com/launches?q={urllib.parse.quote(query)}"
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
search_html = safe_fetch(search_url)
|
|
121
|
+
except Exception as e:
|
|
122
|
+
print(json.dumps({
|
|
123
|
+
"platform": "yc_launch", "query": query,
|
|
124
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
125
|
+
"results": [], "errors": [f"YC launches error: {e}"],
|
|
126
|
+
}, indent=2))
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
launch_urls = extract_launch_urls(search_html)[:limit]
|
|
130
|
+
|
|
131
|
+
if not launch_urls:
|
|
132
|
+
errors.append("No launch URLs found — page may require JS rendering")
|
|
133
|
+
print(json.dumps({
|
|
134
|
+
"platform": "yc_launch", "query": query,
|
|
135
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
136
|
+
"results": [], "errors": errors,
|
|
137
|
+
}, indent=2))
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
results = []
|
|
141
|
+
for url in launch_urls:
|
|
142
|
+
try:
|
|
143
|
+
page_html = safe_fetch(url)
|
|
144
|
+
entry = extract_launch_from_page(page_html, url)
|
|
145
|
+
if entry:
|
|
146
|
+
results.append(entry)
|
|
147
|
+
except Exception as e:
|
|
148
|
+
errors.append(f"Error fetching {url}: {e}")
|
|
149
|
+
|
|
150
|
+
print(json.dumps({
|
|
151
|
+
"platform": "yc_launch",
|
|
152
|
+
"query": query,
|
|
153
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
154
|
+
"results": results,
|
|
155
|
+
"errors": errors,
|
|
156
|
+
}, indent=2))
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
if __name__ == "__main__":
|
|
160
|
+
main()
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "pkit:naming"
|
|
3
|
+
description: >
|
|
4
|
+
Generate product/project name suggestions across multiple naming styles.
|
|
5
|
+
Use when user says "name my product", "name my app", "suggest a product name",
|
|
6
|
+
"I need a name for my project/tool/service". For software products only.
|
|
7
|
+
license: MIT
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Naming
|
|
11
|
+
|
|
12
|
+
Interview the user and propose **product names** across 8 naming styles. This skill is for naming software products, apps, tools, APIs, and services — not general naming tasks.
|
|
13
|
+
|
|
14
|
+
**⚠️ ONLY for naming/renaming software products, apps, tools, APIs, or services.**
|
|
15
|
+
Do NOT use for: naming people/pets/companies/teams, branding exercises, or domain research.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
/pkit:naming <optional context>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Workflow
|
|
24
|
+
|
|
25
|
+
### Step 1 — Interview
|
|
26
|
+
|
|
27
|
+
Use `AskUserQuestion` with up to 4 questions at once:
|
|
28
|
+
|
|
29
|
+
1. What does this project do? (1-sentence pitch)
|
|
30
|
+
2. Who is the audience? (developers, consumers, enterprise, internal team)
|
|
31
|
+
3. What personality/feel? (serious, playful, minimal, bold, technical, approachable)
|
|
32
|
+
4. Any keywords, domain concepts, or technologies central to it?
|
|
33
|
+
|
|
34
|
+
If answers are thin, ask a follow-up batch:
|
|
35
|
+
|
|
36
|
+
1. Any hard constraints? (must be pronounceable, short, avoid certain words)
|
|
37
|
+
2. Any names you already like or dislike — and why?
|
|
38
|
+
|
|
39
|
+
### Step 2 — Generate Names
|
|
40
|
+
|
|
41
|
+
Propose **exactly 3 names per style** across all 6 styles (18 total).
|
|
42
|
+
|
|
43
|
+
Per name format: `**Name** — one-line reason it fits (5–10 words)`
|
|
44
|
+
|
|
45
|
+
| Style | Approach | Example |
|
|
46
|
+
| ------------------ | ----------------------------------- | ------------------------------ |
|
|
47
|
+
| **Descriptive** | Says exactly what it does | `product-kit`, `file-sync` |
|
|
48
|
+
| **Portmanteau** | Blend 2 relevant words | `Snapchat`, `DevKit` |
|
|
49
|
+
| **Brandable** | Invented/abstract, memorable | `Notion`, `Vercel`, `Supabase` |
|
|
50
|
+
| **Metaphor** | Abstract concept mirroring essence | `Forge`, `Anchor`, `Tide` |
|
|
51
|
+
| **Greek / Latin** | Classical roots, timeless authority | `Hermes`, `Aether`, `Kairos` |
|
|
52
|
+
| **Simple / Plain** | Common everyday words, zero jargon | `Quick`, `Base`, `Core`, `Kit` |
|
|
53
|
+
|
|
54
|
+
### Step 3 — Follow-up
|
|
55
|
+
|
|
56
|
+
End with:
|
|
57
|
+
|
|
58
|
+
> "Want more in a specific style, or variations on any of these?"
|
|
59
|
+
|
|
60
|
+
## Rules
|
|
61
|
+
|
|
62
|
+
- **Product names only** — for software, apps, tools
|
|
63
|
+
- If user asks to name something non-product (person, pet, etc.), politely redirect: "This skill is for product naming — try `/pkit:naming` with a product concept."
|
|
64
|
+
- **Names only** — no domain checks, no trademark lookups, no availability
|
|
65
|
+
- Group output by style with a `##` heading per style
|
|
66
|
+
- If user provides very little context, state your assumptions briefly and proceed
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAI/B,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,QA2BtC"}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerConfig = registerConfig;
|
|
4
|
-
const config_1 = require("../../domains/config");
|
|
5
|
-
const logger_1 = require("../../shared/logger");
|
|
6
|
-
function registerConfig(cli) {
|
|
7
|
-
// pkit config → show current config
|
|
8
|
-
cli
|
|
9
|
-
.command('config', 'View or set pkit configuration')
|
|
10
|
-
.action(() => {
|
|
11
|
-
const config = (0, config_1.getConfig)();
|
|
12
|
-
logger_1.log.plain('\npkit configuration\n');
|
|
13
|
-
logger_1.log.plain(` defaultScope ${config.defaultScope}`);
|
|
14
|
-
logger_1.log.plain(` toolPaths.claude ${config.toolPaths.claude}`);
|
|
15
|
-
logger_1.log.plain(` toolPaths.antigravity ${config.toolPaths.antigravity}`);
|
|
16
|
-
logger_1.log.plain(` toolPaths.opencode ${config.toolPaths.opencode}`);
|
|
17
|
-
logger_1.log.plain('\nChange with: pkit config set <key> <value>');
|
|
18
|
-
logger_1.log.plain('Keys: defaultScope, toolPaths.claude, toolPaths.antigravity, toolPaths.opencode');
|
|
19
|
-
});
|
|
20
|
-
// pkit config set <key> <value>
|
|
21
|
-
cli
|
|
22
|
-
.command('config set <key> <value>', 'Set a configuration value')
|
|
23
|
-
.action((key, value) => {
|
|
24
|
-
try {
|
|
25
|
-
(0, config_1.setConfigValue)(key, value);
|
|
26
|
-
logger_1.log.success(`Set ${key} = ${value}`);
|
|
27
|
-
}
|
|
28
|
-
catch (err) {
|
|
29
|
-
logger_1.log.error(err instanceof Error ? err.message : String(err));
|
|
30
|
-
process.exit(1);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":";;AAIA,wCA2BC;AA9BD,iDAAiE;AACjE,gDAA0C;AAE1C,SAAgB,cAAc,CAAC,GAAQ;IACrC,oCAAoC;IACpC,GAAG;SACA,OAAO,CAAC,QAAQ,EAAE,gCAAgC,CAAC;SACnD,MAAM,CAAC,GAAG,EAAE;QACX,MAAM,MAAM,GAAG,IAAA,kBAAS,GAAE,CAAC;QAC3B,YAAG,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACpC,YAAG,CAAC,KAAK,CAAC,0BAA0B,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QAC3D,YAAG,CAAC,KAAK,CAAC,0BAA0B,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/D,YAAG,CAAC,KAAK,CAAC,4BAA4B,MAAM,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;QACtE,YAAG,CAAC,KAAK,CAAC,0BAA0B,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;QACjE,YAAG,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAC1D,YAAG,CAAC,KAAK,CAAC,iFAAiF,CAAC,CAAC;IAC/F,CAAC,CAAC,CAAC;IAEL,gCAAgC;IAChC,GAAG;SACA,OAAO,CAAC,0BAA0B,EAAE,2BAA2B,CAAC;SAChE,MAAM,CAAC,CAAC,GAAW,EAAE,KAAa,EAAE,EAAE;QACrC,IAAI,CAAC;YACH,IAAA,uBAAc,EAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3B,YAAG,CAAC,OAAO,CAAC,OAAO,GAAG,MAAM,KAAK,EAAE,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,YAAG,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|