@grove-dev/core 0.1.1

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.
Files changed (70) hide show
  1. package/README.md +89 -0
  2. package/dist/build-data.d.ts +55 -0
  3. package/dist/build-data.d.ts.map +1 -0
  4. package/dist/build-data.js +115 -0
  5. package/dist/build-data.js.map +1 -0
  6. package/dist/config.d.ts +5 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +14 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/decisions.d.ts +28 -0
  11. package/dist/decisions.d.ts.map +1 -0
  12. package/dist/decisions.js +57 -0
  13. package/dist/decisions.js.map +1 -0
  14. package/dist/enrich.d.ts +26 -0
  15. package/dist/enrich.d.ts.map +1 -0
  16. package/dist/enrich.js +121 -0
  17. package/dist/enrich.js.map +1 -0
  18. package/dist/github-client.d.ts +28 -0
  19. package/dist/github-client.d.ts.map +1 -0
  20. package/dist/github-client.js +91 -0
  21. package/dist/github-client.js.map +1 -0
  22. package/dist/github.d.ts +8 -0
  23. package/dist/github.d.ts.map +1 -0
  24. package/dist/github.js +62 -0
  25. package/dist/github.js.map +1 -0
  26. package/dist/health.d.ts +3 -0
  27. package/dist/health.d.ts.map +1 -0
  28. package/dist/health.js +103 -0
  29. package/dist/health.js.map +1 -0
  30. package/dist/importer.d.ts +3 -0
  31. package/dist/importer.d.ts.map +1 -0
  32. package/dist/importer.js +24 -0
  33. package/dist/importer.js.map +1 -0
  34. package/dist/index.d.ts +17 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +17 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/io.d.ts +4 -0
  39. package/dist/io.d.ts.map +1 -0
  40. package/dist/io.js +21 -0
  41. package/dist/io.js.map +1 -0
  42. package/dist/llms.d.ts +34 -0
  43. package/dist/llms.d.ts.map +1 -0
  44. package/dist/llms.js +99 -0
  45. package/dist/llms.js.map +1 -0
  46. package/dist/markdown.d.ts +18 -0
  47. package/dist/markdown.d.ts.map +1 -0
  48. package/dist/markdown.js +182 -0
  49. package/dist/markdown.js.map +1 -0
  50. package/dist/parseReadme.d.ts +25 -0
  51. package/dist/parseReadme.d.ts.map +1 -0
  52. package/dist/parseReadme.js +100 -0
  53. package/dist/parseReadme.js.map +1 -0
  54. package/dist/schema.d.ts +988 -0
  55. package/dist/schema.d.ts.map +1 -0
  56. package/dist/schema.js +729 -0
  57. package/dist/schema.js.map +1 -0
  58. package/dist/sitemap.d.ts +38 -0
  59. package/dist/sitemap.d.ts.map +1 -0
  60. package/dist/sitemap.js +73 -0
  61. package/dist/sitemap.js.map +1 -0
  62. package/dist/slug.d.ts +3 -0
  63. package/dist/slug.d.ts.map +1 -0
  64. package/dist/slug.js +15 -0
  65. package/dist/slug.js.map +1 -0
  66. package/dist/validate.d.ts +11 -0
  67. package/dist/validate.d.ts.map +1 -0
  68. package/dist/validate.js +58 -0
  69. package/dist/validate.js.map +1 -0
  70. package/package.json +50 -0
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Shared GitHub API helpers used by the grove CLI.
3
+ *
4
+ * - ghFetch: fetch + JSON parse + 2-attempt exponential backoff
5
+ * - rateLimitWaitMs: read X-RateLimit-Reset header and return ms to wait
6
+ * - sleep: small helper
7
+ * - pLimit: tiny concurrency cap (no external deps)
8
+ *
9
+ * These exist so a single transient 5xx doesn't fail an entire daily
10
+ * refresh, and so we can run the per-app loop with bounded concurrency
11
+ * instead of one round-trip at a time.
12
+ */
13
+ const DEFAULT_HEADERS = {
14
+ Accept: "application/vnd.github+json",
15
+ "X-GitHub-Api-Version": "2022-11-28",
16
+ "User-Agent": "grove-bot",
17
+ };
18
+ export function rateLimitWaitMs(res, capMs = 5 * 60_000) {
19
+ const reset = res.headers.get("x-ratelimit-reset");
20
+ if (!reset)
21
+ return 0;
22
+ const resetMs = Number(reset) * 1000 - Date.now();
23
+ if (!Number.isFinite(resetMs) || resetMs <= 0)
24
+ return 0;
25
+ return Math.min(resetMs, capMs);
26
+ }
27
+ export function sleep(ms) {
28
+ if (ms <= 0)
29
+ return Promise.resolve();
30
+ return new Promise((r) => setTimeout(r, ms));
31
+ }
32
+ export async function ghFetch(path, options = {}) {
33
+ const { token, userAgent, attempts = 2, onRateLimited } = options;
34
+ const headers = {
35
+ ...DEFAULT_HEADERS,
36
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
37
+ ...(userAgent ? { "User-Agent": userAgent } : {}),
38
+ };
39
+ let lastErr;
40
+ for (let i = 0; i < attempts; i++) {
41
+ let res;
42
+ try {
43
+ res = await fetch(`https://api.github.com${path}`, { headers });
44
+ }
45
+ catch (err) {
46
+ lastErr = err;
47
+ if (i < attempts - 1) {
48
+ await sleep(500 * Math.pow(2, i));
49
+ continue;
50
+ }
51
+ throw err;
52
+ }
53
+ if (res.status === 429 ||
54
+ (res.status === 403 && res.headers.get("x-ratelimit-remaining") === "0")) {
55
+ const wait = onRateLimited ? onRateLimited() : rateLimitWaitMs(res);
56
+ if (wait > 0) {
57
+ console.warn(`[ghFetch] rate limited, waiting ${Math.round(wait / 1000)}s for ${path}`);
58
+ await sleep(wait);
59
+ continue;
60
+ }
61
+ }
62
+ if (res.status >= 500 && i < attempts - 1) {
63
+ lastErr = new Error(`GitHub ${res.status} ${res.statusText} for ${path}`);
64
+ await sleep(500 * Math.pow(2, i));
65
+ continue;
66
+ }
67
+ return res;
68
+ }
69
+ throw lastErr ?? new Error(`ghFetch: gave up after ${attempts} attempts for ${path}`);
70
+ }
71
+ /**
72
+ * Tiny p-limit implementation: a promise-pool that caps how many
73
+ * `fn(item)` calls run at once. Await the returned promise to get the
74
+ * full results array in input order.
75
+ */
76
+ export async function pLimit(concurrency, items, fn) {
77
+ const out = new Array(items.length);
78
+ let next = 0;
79
+ const worker = async () => {
80
+ while (true) {
81
+ const i = next++;
82
+ if (i >= items.length)
83
+ return;
84
+ out[i] = await fn(items[i], i);
85
+ }
86
+ };
87
+ const workers = Array.from({ length: Math.max(1, concurrency) }, () => worker());
88
+ await Promise.all(workers);
89
+ return out;
90
+ }
91
+ //# sourceMappingURL=github-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-client.js","sourceRoot":"","sources":["../src/github-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { GithubMetadata } from "./schema.js";
2
+ export interface GithubRepoRef {
3
+ owner: string;
4
+ repo: string;
5
+ }
6
+ export declare function parseGithubRepoUrl(url: string | undefined): GithubRepoRef | undefined;
7
+ export declare function fetchGithubMetadata(ref: GithubRepoRef, token?: string | undefined): Promise<GithubMetadata | undefined>;
8
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,CAQrF;AAiCD,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,aAAa,EAAE,KAAK,qBAA2B,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAsBnI"}
package/dist/github.js ADDED
@@ -0,0 +1,62 @@
1
+ export function parseGithubRepoUrl(url) {
2
+ if (!url)
3
+ return undefined;
4
+ const match = url.match(/^https?:\/\/github\.com\/([^/\s]+)\/([^/#?\s]+)(?:[/?#].*)?$/i);
5
+ if (!match)
6
+ return undefined;
7
+ return {
8
+ owner: match[1],
9
+ repo: match[2].replace(/\.git$/, ""),
10
+ };
11
+ }
12
+ async function githubJson(path, token) {
13
+ const headers = {
14
+ Accept: "application/vnd.github+json",
15
+ "X-GitHub-Api-Version": "2022-11-28",
16
+ "User-Agent": "grove",
17
+ };
18
+ if (token)
19
+ headers.Authorization = `Bearer ${token}`;
20
+ const response = await fetch(`https://api.github.com${path}`, { headers });
21
+ if (response.status === 404)
22
+ return null;
23
+ if (response.status === 403 && response.headers.get("x-ratelimit-remaining") === "0") {
24
+ throw new Error("GitHub API rate limit reached. Set GITHUB_TOKEN and rerun analyze.");
25
+ }
26
+ if (!response.ok) {
27
+ throw new Error(`GitHub API ${response.status} ${response.statusText} for ${path}`);
28
+ }
29
+ return response.json();
30
+ }
31
+ function asRecord(value) {
32
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
33
+ }
34
+ function asString(value) {
35
+ return typeof value === "string" ? value : undefined;
36
+ }
37
+ function asNumber(value) {
38
+ return typeof value === "number" ? value : undefined;
39
+ }
40
+ export async function fetchGithubMetadata(ref, token = process.env.GITHUB_TOKEN) {
41
+ const repo = asRecord(await githubJson(`/repos/${ref.owner}/${ref.repo}`, token));
42
+ if (Object.keys(repo).length === 0)
43
+ return undefined;
44
+ const latestRelease = asRecord(await githubJson(`/repos/${ref.owner}/${ref.repo}/releases/latest`, token));
45
+ const license = asRecord(repo.license);
46
+ return {
47
+ fullName: asString(repo.full_name),
48
+ stars: asNumber(repo.stargazers_count) ?? 0,
49
+ forks: asNumber(repo.forks_count) ?? 0,
50
+ openIssues: asNumber(repo.open_issues_count),
51
+ archived: Boolean(repo.archived),
52
+ disabled: Boolean(repo.disabled),
53
+ pushedAt: asString(repo.pushed_at) ?? null,
54
+ updatedAt: asString(repo.updated_at) ?? null,
55
+ latestReleaseAt: asString(latestRelease.published_at) ?? null,
56
+ license: asString(license.spdx_id) ?? asString(license.name) ?? null,
57
+ topics: Array.isArray(repo.topics) ? repo.topics.filter((topic) => typeof topic === "string") : [],
58
+ language: asString(repo.language) ?? null,
59
+ defaultBranch: asString(repo.default_branch),
60
+ };
61
+ }
62
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { GithubMetadata, HealthEntry } from "./schema.js";
2
+ export declare function classifyHealth(id: string, github?: GithubMetadata): HealthEntry;
3
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAA4B,MAAM,aAAa,CAAC;AASzF,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,WAAW,CA2F/E"}
package/dist/health.js ADDED
@@ -0,0 +1,103 @@
1
+ function daysSince(value) {
2
+ if (!value)
3
+ return Infinity;
4
+ const date = new Date(value);
5
+ if (Number.isNaN(date.valueOf()))
6
+ return Infinity;
7
+ return (Date.now() - date.valueOf()) / 86_400_000;
8
+ }
9
+ export function classifyHealth(id, github) {
10
+ if (!github) {
11
+ return {
12
+ id,
13
+ health: {
14
+ status: "unknown",
15
+ maturity: "unknown",
16
+ tier: "experimental",
17
+ visibility: "keep",
18
+ cleanupCandidate: false,
19
+ staleReason: null,
20
+ confidence: "low",
21
+ reasons: ["No GitHub metadata available"],
22
+ },
23
+ };
24
+ }
25
+ const reasons = [];
26
+ const pushedDays = daysSince(github.pushedAt);
27
+ const releaseDays = daysSince(github.latestReleaseAt);
28
+ let status = "unknown";
29
+ if (github.archived) {
30
+ status = "archived";
31
+ reasons.push("Repository is archived on GitHub");
32
+ }
33
+ else if (pushedDays <= 183) {
34
+ status = "active";
35
+ reasons.push("Recent repository activity");
36
+ }
37
+ else if (pushedDays <= 548) {
38
+ status = "stale";
39
+ reasons.push("No recent commits in the last 6 months");
40
+ }
41
+ else if (pushedDays > 730) {
42
+ status = "inactive";
43
+ reasons.push("No commits in the last 24 months");
44
+ }
45
+ else {
46
+ status = "needs_review";
47
+ reasons.push("Repository activity is old enough to need review");
48
+ }
49
+ const hasRelease = releaseDays <= 365;
50
+ const hasLicense = Boolean(github.license && github.license !== "NOASSERTION");
51
+ const popular = github.stars >= 500;
52
+ const maintainedSignals = pushedDays <= 183 && (hasRelease || hasLicense);
53
+ let maturity = "unknown";
54
+ if (status === "archived" || status === "inactive") {
55
+ maturity = "unknown";
56
+ }
57
+ else if (popular && maintainedSignals) {
58
+ maturity = "mature";
59
+ if (status === "active")
60
+ status = "mature";
61
+ reasons.push("Strong adoption with maintenance signals");
62
+ }
63
+ else if (github.stars >= 50 || maintainedSignals) {
64
+ maturity = "useful";
65
+ }
66
+ else {
67
+ maturity = "experimental";
68
+ }
69
+ if (hasRelease)
70
+ reasons.push("Recent release found");
71
+ if (hasLicense)
72
+ reasons.push("Clear license found");
73
+ if (!hasLicense)
74
+ reasons.push("License is missing or unclear");
75
+ const tier = status === "archived" || status === "inactive"
76
+ ? "hidden"
77
+ : popular
78
+ ? "curated"
79
+ : github.stars >= 50
80
+ ? "listed"
81
+ : "experimental";
82
+ return {
83
+ id,
84
+ github,
85
+ health: {
86
+ status,
87
+ maturity,
88
+ tier,
89
+ visibility: tier === "hidden" ? "hide" : "keep",
90
+ cleanupCandidate: status === "stale" || status === "archived" || status === "inactive",
91
+ staleReason: status === "inactive"
92
+ ? "no_commits_24_months"
93
+ : status === "stale"
94
+ ? "no_commits_365_days"
95
+ : status === "archived"
96
+ ? "github_archived"
97
+ : null,
98
+ confidence: github.fullName ? "high" : "medium",
99
+ reasons,
100
+ },
101
+ };
102
+ }
103
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAEA,SAAS,SAAS,CAAC,KAAgC;IACjD,IAAI,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAC;IAC5B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAAE,OAAO,QAAQ,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,UAAU,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAAU,EAAE,MAAuB;IAChE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,EAAE;YACF,MAAM,EAAE;gBACN,MAAM,EAAE,SAAS;gBACjB,QAAQ,EAAE,SAAS;gBACnB,IAAI,EAAE,cAAc;gBACpB,UAAU,EAAE,MAAM;gBAClB,gBAAgB,EAAE,KAAK;gBACvB,WAAW,EAAE,IAAI;gBACjB,UAAU,EAAE,KAAK;gBACjB,OAAO,EAAE,CAAC,8BAA8B,CAAC;aAC1C;SACF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAEtD,IAAI,MAAM,GAAiB,SAAS,CAAC;IACrC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,MAAM,GAAG,UAAU,CAAC;QACpB,OAAO,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IACnD,CAAC;SAAM,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;QAC7B,MAAM,GAAG,QAAQ,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAC7C,CAAC;SAAM,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;QAC7B,MAAM,GAAG,OAAO,CAAC;QACjB,OAAO,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IACzD,CAAC;SAAM,IAAI,UAAU,GAAG,GAAG,EAAE,CAAC;QAC5B,MAAM,GAAG,UAAU,CAAC;QACpB,OAAO,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IACnD,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,cAAc,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,UAAU,GAAG,WAAW,IAAI,GAAG,CAAC;IACtC,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,KAAK,aAAa,CAAC,CAAC;IAC/E,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,IAAI,GAAG,CAAC;IACpC,MAAM,iBAAiB,GAAG,UAAU,IAAI,GAAG,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,CAAC;IAE1E,IAAI,QAAQ,GAAsC,SAAS,CAAC;IAC5D,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;QACnD,QAAQ,GAAG,SAAS,CAAC;IACvB,CAAC;SAAM,IAAI,OAAO,IAAI,iBAAiB,EAAE,CAAC;QACxC,QAAQ,GAAG,QAAQ,CAAC;QACpB,IAAI,MAAM,KAAK,QAAQ;YAAE,MAAM,GAAG,QAAQ,CAAC;QAC3C,OAAO,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;IAC3D,CAAC;SAAM,IAAI,MAAM,CAAC,KAAK,IAAI,EAAE,IAAI,iBAAiB,EAAE,CAAC;QACnD,QAAQ,GAAG,QAAQ,CAAC;IACtB,CAAC;SAAM,CAAC;QACN,QAAQ,GAAG,cAAc,CAAC;IAC5B,CAAC;IAED,IAAI,UAAU;QAAE,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACrD,IAAI,UAAU;QAAE,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACpD,IAAI,CAAC,UAAU;QAAE,OAAO,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;IAE/D,MAAM,IAAI,GACR,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,UAAU;QAC5C,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,OAAO;YACP,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;gBAClB,CAAC,CAAC,QAAQ;gBACV,CAAC,CAAC,cAAc,CAAC;IAEzB,OAAO;QACL,EAAE;QACF,MAAM;QACN,MAAM,EAAE;YACN,MAAM;YACN,QAAQ;YACR,IAAI;YACJ,UAAU,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;YAC/C,gBAAgB,EAAE,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,UAAU;YACtF,WAAW,EACT,MAAM,KAAK,UAAU;gBACnB,CAAC,CAAC,sBAAsB;gBACxB,CAAC,CAAC,MAAM,KAAK,OAAO;oBAClB,CAAC,CAAC,qBAAqB;oBACvB,CAAC,CAAC,MAAM,KAAK,UAAU;wBACrB,CAAC,CAAC,iBAAiB;wBACnB,CAAC,CAAC,IAAI;YACd,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ;YAC/C,OAAO;SACR;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type ImportResult } from "./markdown.js";
2
+ export declare function importAwesomeList(input: string): Promise<ImportResult>;
3
+ //# sourceMappingURL=importer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importer.d.ts","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAQxE,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAc5E"}
@@ -0,0 +1,24 @@
1
+ import { basename, resolve } from "node:path";
2
+ import { readFile } from "node:fs/promises";
3
+ import { parseAwesomeMarkdown } from "./markdown.js";
4
+ function githubReadmeUrl(input) {
5
+ const match = input.match(/^https?:\/\/github\.com\/([^/\s]+)\/([^/#?\s]+)(?:\/)?$/i);
6
+ if (!match)
7
+ return undefined;
8
+ return `https://raw.githubusercontent.com/${match[1]}/${match[2]}/HEAD/README.md`;
9
+ }
10
+ export async function importAwesomeList(input) {
11
+ const remote = githubReadmeUrl(input) ?? (/^https?:\/\//.test(input) ? input : undefined);
12
+ if (remote) {
13
+ const response = await fetch(remote);
14
+ if (!response.ok) {
15
+ throw new Error(`Could not fetch ${remote}: ${response.status} ${response.statusText}`);
16
+ }
17
+ const text = await response.text();
18
+ return parseAwesomeMarkdown(text, { file: "sources/README.md", sourceUrl: input });
19
+ }
20
+ const path = resolve(input);
21
+ const text = await readFile(path, "utf8");
22
+ return parseAwesomeMarkdown(text, { file: basename(path) });
23
+ }
24
+ //# sourceMappingURL=importer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importer.js","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAqB,MAAM,eAAe,CAAC;AAExE,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;IACtF,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,OAAO,qCAAqC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,iBAAiB,CAAC;AACpF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAa;IACnD,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC1F,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QAC1F,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,OAAO,oBAAoB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IACrF,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1C,OAAO,oBAAoB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,17 @@
1
+ export * from "./build-data.js";
2
+ export * from "./config.js";
3
+ export * from "./decisions.js";
4
+ export * from "./enrich.js";
5
+ export * from "./github-client.js";
6
+ export * from "./github.js";
7
+ export * from "./health.js";
8
+ export * from "./importer.js";
9
+ export * from "./io.js";
10
+ export * from "./llms.js";
11
+ export * from "./markdown.js";
12
+ export * from "./parseReadme.js";
13
+ export * from "./schema.js";
14
+ export * from "./sitemap.js";
15
+ export * from "./slug.js";
16
+ export * from "./validate.js";
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ export * from "./build-data.js";
2
+ export * from "./config.js";
3
+ export * from "./decisions.js";
4
+ export * from "./enrich.js";
5
+ export * from "./github-client.js";
6
+ export * from "./github.js";
7
+ export * from "./health.js";
8
+ export * from "./importer.js";
9
+ export * from "./io.js";
10
+ export * from "./llms.js";
11
+ export * from "./markdown.js";
12
+ export * from "./parseReadme.js";
13
+ export * from "./schema.js";
14
+ export * from "./sitemap.js";
15
+ export * from "./slug.js";
16
+ export * from "./validate.js";
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
package/dist/io.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export declare function readYamlFile<T>(path: string): Promise<T>;
2
+ export declare function writeYamlFile(path: string, value: unknown): Promise<void>;
3
+ export declare function writeTextFile(path: string, value: string): Promise<void>;
4
+ //# sourceMappingURL=io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"AAIA,wBAAsB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAG9D;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ/E;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG9E"}
package/dist/io.js ADDED
@@ -0,0 +1,21 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ import { parse, stringify } from "yaml";
4
+ export async function readYamlFile(path) {
5
+ const text = await readFile(path, "utf8");
6
+ return parse(text);
7
+ }
8
+ export async function writeYamlFile(path, value) {
9
+ await mkdir(dirname(path), { recursive: true });
10
+ const text = stringify(value, {
11
+ lineWidth: 100,
12
+ singleQuote: false,
13
+ defaultStringType: "PLAIN",
14
+ });
15
+ await writeFile(path, text, "utf8");
16
+ }
17
+ export async function writeTextFile(path, value) {
18
+ await mkdir(dirname(path), { recursive: true });
19
+ await writeFile(path, value, "utf8");
20
+ }
21
+ //# sourceMappingURL=io.js.map
package/dist/io.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.js","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAExC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAI,IAAY;IAChD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1C,OAAO,KAAK,CAAC,IAAI,CAAM,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,KAAc;IAC9D,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE;QAC5B,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,KAAK;QAClB,iBAAiB,EAAE,OAAO;KAC3B,CAAC,CAAC;IACH,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,KAAa;IAC7D,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AACvC,CAAC"}
package/dist/llms.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ import { type CuratedConfig } from "./config.js";
2
+ export interface LlmsAppInput {
3
+ slug: string;
4
+ name: string;
5
+ description?: string;
6
+ category?: string;
7
+ stack?: string;
8
+ stars?: number;
9
+ visibility?: string;
10
+ /** Detail page body — markdown. Used for llms-full.txt sections. */
11
+ detail?: string;
12
+ homepageUrl?: string;
13
+ repoUrl?: string;
14
+ license?: string;
15
+ lastCommitAt?: string | null;
16
+ addedAt?: string | null;
17
+ }
18
+ export interface LlmsInput {
19
+ siteUrl?: string;
20
+ generatedAt: string;
21
+ apps: LlmsAppInput[];
22
+ }
23
+ export interface LlmsResult {
24
+ txtPath: string;
25
+ fullPath: string;
26
+ indexed: number;
27
+ }
28
+ /** Build the llms.txt string — short pointer to llms-full.txt. */
29
+ export declare function buildLlmsTxt(input: LlmsInput, config: CuratedConfig): string;
30
+ /** Build the llms-full.txt string — index + per-app sections. */
31
+ export declare function buildLlmsFullTxt(input: LlmsInput, config: CuratedConfig): string;
32
+ /** Write public/llms.txt and public/llms-full.txt. */
33
+ export declare function buildLlmsFiles(input: LlmsInput, cwd?: string, config?: CuratedConfig): Promise<LlmsResult>;
34
+ //# sourceMappingURL=llms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llms.d.ts","sourceRoot":"","sources":["../src/llms.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAc,MAAM,aAAa,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,YAAY,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAyCD,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,CAgB5E;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,CAyBhF;AAED,sDAAsD;AACtD,wBAAsB,cAAc,CAClC,KAAK,EAAE,SAAS,EAChB,GAAG,SAAgB,EACnB,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,UAAU,CAAC,CAarB"}
package/dist/llms.js ADDED
@@ -0,0 +1,99 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import { loadConfig } from "./config.js";
4
+ function slug(value) {
5
+ return String(value).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
6
+ }
7
+ function truncate(value, max) {
8
+ return value.replace(/\s+/g, " ").slice(0, max);
9
+ }
10
+ function buildIndexLine(app) {
11
+ const desc = truncate(app.description ?? "", 120);
12
+ const cat = app.category ?? "—";
13
+ const stack = app.stack ?? "—";
14
+ const stars = app.stars ?? 0;
15
+ return `- [${app.name}](#${slug(app.slug)}) — ${cat} · ${stack} · ${stars}★ — ${desc}`;
16
+ }
17
+ function buildDetailSection(app, siteUrl, indexSlug) {
18
+ const lines = [
19
+ `### ${app.name}`,
20
+ "",
21
+ app.description ? `${app.description}` : "",
22
+ "",
23
+ `- slug: ${app.slug}`,
24
+ `- category: ${app.category ?? "—"}`,
25
+ `- stack: ${app.stack ?? "—"}`,
26
+ `- stars: ${app.stars ?? 0}`,
27
+ app.license ? `- license: ${app.license}` : "",
28
+ app.repoUrl ? `- repo: ${app.repoUrl}` : "",
29
+ app.homepageUrl ? `- homepage: ${app.homepageUrl}` : "",
30
+ `- url: ${siteUrl}/${indexSlug}/${app.slug}`,
31
+ app.lastCommitAt ? `- lastCommit: ${app.lastCommitAt.slice(0, 10)}` : "",
32
+ app.addedAt ? `- added: ${app.addedAt.slice(0, 10)}` : "",
33
+ ].filter(Boolean);
34
+ if (app.detail) {
35
+ lines.push("", "#### Detail", "", app.detail);
36
+ }
37
+ return lines.join("\n");
38
+ }
39
+ /** Build the llms.txt string — short pointer to llms-full.txt. */
40
+ export function buildLlmsTxt(input, config) {
41
+ const siteUrl = (input.siteUrl ?? config.siteUrl ?? "").replace(/\/$/, "");
42
+ const visible = input.apps.filter((a) => a.visibility !== "hide" && a.visibility !== "remove");
43
+ const indexSlug = config.itemLabel === "app" ? "apps" : "projects";
44
+ return `# ${config.name}
45
+
46
+ ${config.description ?? config.tagline}
47
+
48
+ Directory: ${siteUrl}/${indexSlug}
49
+ Projects indexed: ${visible.length}
50
+ Categories: ${new Set(visible.map((a) => a.category).filter(Boolean)).size}
51
+
52
+ ## Usage
53
+
54
+ Use /llms-full.txt for project-level details. Prefer project detail pages for citations.
55
+ `;
56
+ }
57
+ /** Build the llms-full.txt string — index + per-app sections. */
58
+ export function buildLlmsFullTxt(input, config) {
59
+ const siteUrl = (input.siteUrl ?? config.siteUrl ?? "").replace(/\/$/, "");
60
+ const indexSlug = config.itemLabel === "app" ? "apps" : "projects";
61
+ const visible = input.apps.filter((a) => a.visibility !== "hide" && a.visibility !== "remove");
62
+ const index = visible.map(buildIndexLine).join("\n");
63
+ const sections = visible
64
+ .map((app) => buildDetailSection(app, siteUrl, indexSlug))
65
+ .join("\n\n");
66
+ return [
67
+ `# ${config.name} — full directory`,
68
+ "",
69
+ `> Generated ${input.generatedAt} from ${input.apps.length} app records.`,
70
+ `> Source: ${siteUrl}/${indexSlug} · Regenerate with \`grove build-llms-full\`.`,
71
+ "",
72
+ "Each section below mirrors one app detail page.",
73
+ "",
74
+ "## Index",
75
+ "",
76
+ index,
77
+ "",
78
+ sections ? "## Projects" : "",
79
+ "",
80
+ sections,
81
+ "",
82
+ ].join("\n");
83
+ }
84
+ /** Write public/llms.txt and public/llms-full.txt. */
85
+ export async function buildLlmsFiles(input, cwd = process.cwd(), config) {
86
+ const cfg = config ?? (await loadConfig(cwd));
87
+ const publicDir = resolve(cwd, "public");
88
+ await mkdir(publicDir, { recursive: true });
89
+ const txtPath = join(publicDir, "llms.txt");
90
+ const fullPath = join(publicDir, "llms-full.txt");
91
+ await writeFile(txtPath, buildLlmsTxt(input, cfg), "utf8");
92
+ await writeFile(fullPath, buildLlmsFullTxt(input, cfg), "utf8");
93
+ return {
94
+ txtPath,
95
+ fullPath,
96
+ indexed: input.apps.filter((a) => a.visibility !== "hide" && a.visibility !== "remove").length,
97
+ };
98
+ }
99
+ //# sourceMappingURL=llms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llms.js","sourceRoot":"","sources":["../src/llms.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { CuratedItem } from "./schema.js";
2
+ export interface ImportResult {
3
+ items: CuratedItem[];
4
+ report: {
5
+ imported: number;
6
+ skipped: number;
7
+ categories: string[];
8
+ duplicateSlugs: number;
9
+ tocSkipped: number;
10
+ anchorLinksSkipped: number;
11
+ };
12
+ }
13
+ export declare function detectGithubRepo(url: string): string | undefined;
14
+ export declare function parseAwesomeMarkdown(text: string, options?: {
15
+ file?: string;
16
+ sourceUrl?: string;
17
+ }): ImportResult;
18
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,kBAAkB,EAAE,MAAM,CAAC;KAC5B,CAAC;CACH;AAsBD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMhE;AA4BD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,YAAY,CAiJpH"}