@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,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* YC Launch (Y Combinator) crawler via HTML scraping.
|
|
4
|
+
* Usage: node search-yc-launch.mjs "<keywords>" [limit]
|
|
5
|
+
* Output: JSON CrawlResult to stdout
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
const cheerio = __importStar(require("cheerio"));
|
|
42
|
+
const shared_types_js_1 = require("./shared-types.js");
|
|
43
|
+
/** Extract launch URLs from YC launches listing page */
|
|
44
|
+
function extractLaunchUrls($) {
|
|
45
|
+
const urls = [];
|
|
46
|
+
$('a[href*="/launches/"]').each((_, el) => {
|
|
47
|
+
const href = $(el).attr("href");
|
|
48
|
+
if (href) {
|
|
49
|
+
const fullUrl = href.startsWith("http")
|
|
50
|
+
? href
|
|
51
|
+
: `https://www.ycombinator.com${href}`;
|
|
52
|
+
if (fullUrl.includes("/launches/") && !urls.includes(fullUrl)) {
|
|
53
|
+
urls.push(fullUrl);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return urls;
|
|
58
|
+
}
|
|
59
|
+
/** Extract launch details from a YC launch page */
|
|
60
|
+
function extractLaunchFromPage($, url) {
|
|
61
|
+
// Try structured data first
|
|
62
|
+
let name = "";
|
|
63
|
+
let description = "";
|
|
64
|
+
$('script[type="application/ld+json"]').each((_, el) => {
|
|
65
|
+
try {
|
|
66
|
+
const data = JSON.parse($(el).html() || "");
|
|
67
|
+
if (data.name)
|
|
68
|
+
name = data.name;
|
|
69
|
+
if (data.description)
|
|
70
|
+
description = data.description;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// ignore
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
// Fallback to meta tags and page content
|
|
77
|
+
if (!name) {
|
|
78
|
+
name =
|
|
79
|
+
$('meta[property="og:title"]')
|
|
80
|
+
.attr("content")
|
|
81
|
+
?.replace(" | Y Combinator", "")
|
|
82
|
+
?.replace("Launch YC: ", "") ||
|
|
83
|
+
$("h1").first().text().trim() ||
|
|
84
|
+
"";
|
|
85
|
+
}
|
|
86
|
+
if (!description) {
|
|
87
|
+
description =
|
|
88
|
+
$('meta[property="og:description"]').attr("content") ||
|
|
89
|
+
$('meta[name="description"]').attr("content") ||
|
|
90
|
+
"";
|
|
91
|
+
}
|
|
92
|
+
if (!name)
|
|
93
|
+
return null;
|
|
94
|
+
// Extract the launch pitch content (typically the main body text)
|
|
95
|
+
let pitch = "";
|
|
96
|
+
// YC launch pages often have the pitch in a main content area
|
|
97
|
+
$("article, [class*='launch'] [class*='body'], [class*='content'] p").each((_, el) => {
|
|
98
|
+
const text = $(el).text().trim();
|
|
99
|
+
if (text.length > pitch.length)
|
|
100
|
+
pitch = text;
|
|
101
|
+
});
|
|
102
|
+
// Extract comments as review snippets
|
|
103
|
+
const reviews = [];
|
|
104
|
+
$('[class*="comment"] [class*="body"], [class*="comment"] p, [class*="Comment"] p')
|
|
105
|
+
.slice(0, 6)
|
|
106
|
+
.each((_, el) => {
|
|
107
|
+
const text = $(el).text().trim();
|
|
108
|
+
if (text.length > 20) {
|
|
109
|
+
reviews.push({
|
|
110
|
+
text: (0, shared_types_js_1.truncate)(text, 300),
|
|
111
|
+
sentiment: "neutral",
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
return {
|
|
116
|
+
name,
|
|
117
|
+
url,
|
|
118
|
+
description: (0, shared_types_js_1.truncate)(pitch || description),
|
|
119
|
+
tagline: description.length < 150 ? description : undefined,
|
|
120
|
+
pricing: {
|
|
121
|
+
free: true, // YC launches typically don't list pricing
|
|
122
|
+
other: undefined,
|
|
123
|
+
},
|
|
124
|
+
features: [],
|
|
125
|
+
reviews,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/** Try to extract launches from the listing page directly */
|
|
129
|
+
function extractLaunchCardsFromListing($) {
|
|
130
|
+
const entries = [];
|
|
131
|
+
// YC launches page often has cards with title and description
|
|
132
|
+
$('[class*="launch"], [class*="Launch"]').each((_, el) => {
|
|
133
|
+
const card$ = $(el);
|
|
134
|
+
const link = card$.find('a[href*="/launches/"]').first();
|
|
135
|
+
const href = link.attr("href");
|
|
136
|
+
const name = link.text().trim() ||
|
|
137
|
+
card$.find("h2, h3, [class*='title']").first().text().trim();
|
|
138
|
+
const description = card$
|
|
139
|
+
.find("p, [class*='description'], [class*='tagline']")
|
|
140
|
+
.first()
|
|
141
|
+
.text()
|
|
142
|
+
.trim();
|
|
143
|
+
if (name && href) {
|
|
144
|
+
const url = href.startsWith("http")
|
|
145
|
+
? href
|
|
146
|
+
: `https://www.ycombinator.com${href}`;
|
|
147
|
+
entries.push({
|
|
148
|
+
name,
|
|
149
|
+
url,
|
|
150
|
+
description: (0, shared_types_js_1.truncate)(description || ""),
|
|
151
|
+
pricing: { free: true },
|
|
152
|
+
features: [],
|
|
153
|
+
reviews: [],
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
return entries;
|
|
158
|
+
}
|
|
159
|
+
async function main() {
|
|
160
|
+
const { query, limit } = (0, shared_types_js_1.parseArgs)();
|
|
161
|
+
const errors = [];
|
|
162
|
+
// Fetch YC launches listing
|
|
163
|
+
const searchUrl = `https://www.ycombinator.com/launches?q=${encodeURIComponent(query)}`;
|
|
164
|
+
let searchHtml;
|
|
165
|
+
try {
|
|
166
|
+
const res = await (0, shared_types_js_1.safeFetch)(searchUrl);
|
|
167
|
+
if (!res.ok) {
|
|
168
|
+
return (0, shared_types_js_1.outputError)("yc_launch", query, `YC launches page returned ${res.status}`);
|
|
169
|
+
}
|
|
170
|
+
searchHtml = await res.text();
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
return (0, shared_types_js_1.outputError)("yc_launch", query, `Failed to fetch YC launches: ${err instanceof Error ? err.message : String(err)}`);
|
|
174
|
+
}
|
|
175
|
+
const $ = cheerio.load(searchHtml);
|
|
176
|
+
const launchUrls = extractLaunchUrls($).slice(0, limit);
|
|
177
|
+
// If no individual URLs found, try extracting cards from the listing page
|
|
178
|
+
if (launchUrls.length === 0) {
|
|
179
|
+
const cards = extractLaunchCardsFromListing($).slice(0, limit);
|
|
180
|
+
if (cards.length > 0) {
|
|
181
|
+
return (0, shared_types_js_1.outputResult)({
|
|
182
|
+
platform: "yc_launch",
|
|
183
|
+
query,
|
|
184
|
+
timestamp: new Date().toISOString(),
|
|
185
|
+
results: cards,
|
|
186
|
+
errors: [
|
|
187
|
+
"Extracted from listing page only — individual pages not fetched",
|
|
188
|
+
],
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
errors.push("No launch URLs found — page may require JS rendering");
|
|
192
|
+
return (0, shared_types_js_1.outputResult)({
|
|
193
|
+
platform: "yc_launch",
|
|
194
|
+
query,
|
|
195
|
+
timestamp: new Date().toISOString(),
|
|
196
|
+
results: [],
|
|
197
|
+
errors,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
// Fetch each launch page
|
|
201
|
+
const results = [];
|
|
202
|
+
for (const url of launchUrls) {
|
|
203
|
+
try {
|
|
204
|
+
const res = await (0, shared_types_js_1.safeFetch)(url);
|
|
205
|
+
if (!res.ok) {
|
|
206
|
+
errors.push(`Failed to fetch ${url}: ${res.status}`);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const html = await res.text();
|
|
210
|
+
const page$ = cheerio.load(html);
|
|
211
|
+
const entry = extractLaunchFromPage(page$, url);
|
|
212
|
+
if (entry)
|
|
213
|
+
results.push(entry);
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
errors.push(`Error fetching ${url}: ${err instanceof Error ? err.message : String(err)}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
const result = {
|
|
220
|
+
platform: "yc_launch",
|
|
221
|
+
query,
|
|
222
|
+
timestamp: new Date().toISOString(),
|
|
223
|
+
results,
|
|
224
|
+
errors,
|
|
225
|
+
};
|
|
226
|
+
(0, shared_types_js_1.outputResult)(result);
|
|
227
|
+
}
|
|
228
|
+
main();
|
|
229
|
+
//# sourceMappingURL=search-yc-launch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-yc-launch.js","sourceRoot":"","sources":["../../../src/scripts/market-intel/search-yc-launch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Shared types and helpers for market-intel crawler scripts */
|
|
2
|
+
export interface CrawlResult {
|
|
3
|
+
platform: "app_store" | "google_play" | "product_hunt" | "yc_launch";
|
|
4
|
+
query: string;
|
|
5
|
+
timestamp: string;
|
|
6
|
+
results: CompetitorEntry[];
|
|
7
|
+
errors: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface CompetitorEntry {
|
|
10
|
+
name: string;
|
|
11
|
+
url: string;
|
|
12
|
+
description: string;
|
|
13
|
+
tagline?: string;
|
|
14
|
+
rating?: number;
|
|
15
|
+
reviewCount?: number;
|
|
16
|
+
pricing: PricingInfo;
|
|
17
|
+
features: string[];
|
|
18
|
+
reviews: ReviewSnippet[];
|
|
19
|
+
}
|
|
20
|
+
export interface PricingInfo {
|
|
21
|
+
free: boolean;
|
|
22
|
+
monthly?: number;
|
|
23
|
+
yearly?: number;
|
|
24
|
+
other?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ReviewSnippet {
|
|
27
|
+
text: string;
|
|
28
|
+
rating?: number;
|
|
29
|
+
sentiment: "positive" | "negative" | "neutral";
|
|
30
|
+
}
|
|
31
|
+
/** Parse CLI args: keyword + optional limit */
|
|
32
|
+
export declare function parseArgs(): {
|
|
33
|
+
query: string;
|
|
34
|
+
limit: number;
|
|
35
|
+
};
|
|
36
|
+
/** Output result as JSON to stdout */
|
|
37
|
+
export declare function outputResult(result: CrawlResult): void;
|
|
38
|
+
/** Output error result and exit cleanly */
|
|
39
|
+
export declare function outputError(platform: CrawlResult["platform"], query: string, message: string): void;
|
|
40
|
+
/** Safe fetch with timeout and user-agent */
|
|
41
|
+
export declare function safeFetch(url: string, timeoutMs?: number): Promise<Response>;
|
|
42
|
+
/** Truncate text to max length */
|
|
43
|
+
export declare function truncate(text: string, maxLen?: number): string;
|
|
44
|
+
//# sourceMappingURL=shared-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-types.d.ts","sourceRoot":"","sources":["../../../src/scripts/market-intel/shared-types.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAEhE,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,WAAW,GAAG,aAAa,GAAG,cAAc,GAAG,WAAW,CAAC;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;CAChD;AAED,+CAA+C;AAC/C,wBAAgB,SAAS,IAAI;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAc5D;AAED,sCAAsC;AACtC,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAEtD;AAED,2CAA2C;AAC3C,wBAAgB,WAAW,CACzB,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,EACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,IAAI,CAUN;AAED,6CAA6C;AAC7C,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,SAAS,SAAQ,GAChB,OAAO,CAAC,QAAQ,CAAC,CAiBnB;AAED,kCAAkC;AAClC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAM,GAAG,MAAM,CAG3D"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Shared types and helpers for market-intel crawler scripts */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.parseArgs = parseArgs;
|
|
5
|
+
exports.outputResult = outputResult;
|
|
6
|
+
exports.outputError = outputError;
|
|
7
|
+
exports.safeFetch = safeFetch;
|
|
8
|
+
exports.truncate = truncate;
|
|
9
|
+
/** Parse CLI args: keyword + optional limit */
|
|
10
|
+
function parseArgs() {
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
const query = args[0];
|
|
13
|
+
if (!query) {
|
|
14
|
+
console.error(JSON.stringify({
|
|
15
|
+
error: "Usage: node search-<platform>.mjs <keywords> [limit]",
|
|
16
|
+
}));
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
const parsed = parseInt(args[1] || "5", 10);
|
|
20
|
+
const limit = Number.isNaN(parsed) ? 5 : Math.min(Math.max(parsed, 1), 10);
|
|
21
|
+
return { query, limit };
|
|
22
|
+
}
|
|
23
|
+
/** Output result as JSON to stdout */
|
|
24
|
+
function outputResult(result) {
|
|
25
|
+
console.log(JSON.stringify(result, null, 2));
|
|
26
|
+
}
|
|
27
|
+
/** Output error result and exit cleanly */
|
|
28
|
+
function outputError(platform, query, message) {
|
|
29
|
+
const result = {
|
|
30
|
+
platform,
|
|
31
|
+
query,
|
|
32
|
+
timestamp: new Date().toISOString(),
|
|
33
|
+
results: [],
|
|
34
|
+
errors: [message],
|
|
35
|
+
};
|
|
36
|
+
console.log(JSON.stringify(result, null, 2));
|
|
37
|
+
process.exit(0); // exit 0 so Claude can still read the JSON
|
|
38
|
+
}
|
|
39
|
+
/** Safe fetch with timeout and user-agent */
|
|
40
|
+
async function safeFetch(url, timeoutMs = 10000) {
|
|
41
|
+
const controller = new AbortController();
|
|
42
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
43
|
+
try {
|
|
44
|
+
return await fetch(url, {
|
|
45
|
+
signal: controller.signal,
|
|
46
|
+
headers: {
|
|
47
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
48
|
+
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
49
|
+
"Accept-Language": "en-US,en;q=0.9",
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
clearTimeout(timer);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Truncate text to max length */
|
|
58
|
+
function truncate(text, maxLen = 500) {
|
|
59
|
+
if (text.length <= maxLen)
|
|
60
|
+
return text;
|
|
61
|
+
return text.slice(0, maxLen) + "...";
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=shared-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-types.js","sourceRoot":"","sources":["../../../src/scripts/market-intel/shared-types.ts"],"names":[],"mappings":";AAAA,gEAAgE;;AAoChE,8BAcC;AAGD,oCAEC;AAGD,kCAcC;AAGD,8BAoBC;AAGD,4BAGC;AAlED,+CAA+C;AAC/C,SAAgB,SAAS;IACvB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CACX,IAAI,CAAC,SAAS,CAAC;YACb,KAAK,EAAE,sDAAsD;SAC9D,CAAC,CACH,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3E,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC;AAED,sCAAsC;AACtC,SAAgB,YAAY,CAAC,MAAmB;IAC9C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,2CAA2C;AAC3C,SAAgB,WAAW,CACzB,QAAiC,EACjC,KAAa,EACb,OAAe;IAEf,MAAM,MAAM,GAAgB;QAC1B,QAAQ;QACR,KAAK;QACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,CAAC,OAAO,CAAC;KAClB,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,2CAA2C;AAC9D,CAAC;AAED,6CAA6C;AACtC,KAAK,UAAU,SAAS,CAC7B,GAAW,EACX,SAAS,GAAG,KAAK;IAEjB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,GAAG,EAAE;YACtB,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,OAAO,EAAE;gBACP,YAAY,EACV,uHAAuH;gBACzH,MAAM,EACJ,iEAAiE;gBACnE,iBAAiB,EAAE,gBAAgB;aACpC;SACF,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,kCAAkC;AAClC,SAAgB,QAAQ,CAAC,IAAY,EAAE,MAAM,GAAG,GAAG;IACjD,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC;AACvC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tydung26/product-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "🐳 Product engineer skills kit",
|
|
5
5
|
"bin": {
|
|
6
6
|
"pkit": "bin/pkit.js"
|
|
7
7
|
},
|
|
8
8
|
"main": "dist/index.js",
|
|
9
|
-
"scripts": {
|
|
10
|
-
"build": "tsc",
|
|
11
|
-
"dev": "tsx src/index.ts",
|
|
12
|
-
"lint": "tsc --noEmit",
|
|
13
|
-
"test": "vitest run",
|
|
14
|
-
"prepublishOnly": "npm run lint && npm run build && npm test"
|
|
15
|
-
},
|
|
16
9
|
"engines": {
|
|
17
10
|
"node": ">=18.0.0"
|
|
18
11
|
},
|
|
@@ -47,5 +40,11 @@
|
|
|
47
40
|
"tsx": "^4.21.0",
|
|
48
41
|
"typescript": "^5.9.3",
|
|
49
42
|
"vitest": "^4.0.18"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"dev": "tsx src/index.ts",
|
|
47
|
+
"lint": "tsc --noEmit",
|
|
48
|
+
"test": "vitest run"
|
|
50
49
|
}
|
|
51
|
-
}
|
|
50
|
+
}
|