@wix/evalforge-github-client 0.1.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/build/index.js ADDED
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ fetchSkillFolder: () => fetchSkillFolder,
24
+ fetchSkillFolderRaw: () => fetchSkillFolderRaw,
25
+ validateGitHubSource: () => validateGitHubSource
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+
29
+ // src/github-contents-client.ts
30
+ var GITHUB_API_BASE = "https://api.github.com";
31
+ function githubHeaders(options) {
32
+ const token = options?.token ?? process.env.GITHUB_TOKEN;
33
+ const headers = {
34
+ Accept: "application/vnd.github.v3+json",
35
+ "User-Agent": options?.userAgent ?? "EvalForge"
36
+ };
37
+ if (token) {
38
+ headers.Authorization = `Bearer ${token}`;
39
+ }
40
+ return headers;
41
+ }
42
+ async function fetchSkillFolder(source, options) {
43
+ const files = await fetchDirectory(
44
+ source.owner,
45
+ source.repo,
46
+ source.path,
47
+ source.ref,
48
+ "",
49
+ options
50
+ );
51
+ const hasSkillMd = files.some((f) => f.path === "SKILL.md");
52
+ if (!hasSkillMd) {
53
+ throw new Error(
54
+ `SKILL.md not found in ${source.owner}/${source.repo}/${source.path} at ref ${source.ref}`
55
+ );
56
+ }
57
+ return files;
58
+ }
59
+ async function fetchSkillFolderRaw(source, options) {
60
+ return fetchDirectory(
61
+ source.owner,
62
+ source.repo,
63
+ source.path,
64
+ source.ref,
65
+ "",
66
+ options
67
+ );
68
+ }
69
+ async function validateGitHubSource(source, options) {
70
+ await fetchSkillFolder(source, options);
71
+ }
72
+ async function fetchDirectory(owner, repo, dirPath, ref, relativePath, options) {
73
+ const url = `${GITHUB_API_BASE}/repos/${owner}/${repo}/contents/${dirPath}?ref=${ref}`;
74
+ const response = await fetch(url, {
75
+ headers: githubHeaders(options)
76
+ });
77
+ if (!response.ok) {
78
+ throw new Error(
79
+ `GitHub API error: ${response.status} ${response.statusText} for ${url}`
80
+ );
81
+ }
82
+ const entries = await response.json();
83
+ const filePromises = entries.map(async (entry) => {
84
+ if (entry.type === "file") {
85
+ const filePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
86
+ let content;
87
+ if (entry.content && entry.encoding === "base64") {
88
+ content = Buffer.from(entry.content, "base64").toString("utf-8");
89
+ } else {
90
+ content = await fetchFileContent(
91
+ owner,
92
+ repo,
93
+ `${dirPath}/${entry.name}`,
94
+ ref,
95
+ options
96
+ );
97
+ }
98
+ return [{ path: filePath, content }];
99
+ }
100
+ if (entry.type === "dir") {
101
+ const subPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
102
+ return fetchDirectory(
103
+ owner,
104
+ repo,
105
+ `${dirPath}/${entry.name}`,
106
+ ref,
107
+ subPath,
108
+ options
109
+ );
110
+ }
111
+ return [];
112
+ });
113
+ const results = await Promise.all(filePromises);
114
+ return results.flat();
115
+ }
116
+ async function fetchFileContent(owner, repo, filePath, ref, options) {
117
+ const url = `${GITHUB_API_BASE}/repos/${owner}/${repo}/contents/${filePath}?ref=${ref}`;
118
+ const response = await fetch(url, {
119
+ headers: githubHeaders(options)
120
+ });
121
+ if (!response.ok) {
122
+ throw new Error(
123
+ `GitHub API error: ${response.status} ${response.statusText} for ${url}`
124
+ );
125
+ }
126
+ const data = await response.json();
127
+ if (data.content && data.encoding === "base64") {
128
+ return Buffer.from(data.content, "base64").toString("utf-8");
129
+ }
130
+ throw new Error(`No content returned for file: ${filePath}`);
131
+ }
132
+ // Annotate the CommonJS export names for ESM import in node:
133
+ 0 && (module.exports = {
134
+ fetchSkillFolder,
135
+ fetchSkillFolderRaw,
136
+ validateGitHubSource
137
+ });
138
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts", "../src/github-contents-client.ts"],
4
+ "sourcesContent": ["export {\n fetchSkillFolder,\n fetchSkillFolderRaw,\n validateGitHubSource,\n} from \"./github-contents-client.js\";\nexport type { FetchSkillFolderOptions } from \"./github-contents-client.js\";\n", "/**\n * GitHub Contents API client for fetching skill directories.\n *\n * Authenticates with GITHUB_TOKEN if set.\n */\n\nimport type { GitHubSource, SkillFile } from \"@wix/evalforge-types\";\n\nconst GITHUB_API_BASE = \"https://api.github.com\";\n\nexport interface FetchSkillFolderOptions {\n /** GitHub token for authentication (increases rate limit). Read from env if not provided. */\n token?: string;\n /** User-Agent header value. Defaults to \"EvalForge\". */\n userAgent?: string;\n}\n\ninterface GitHubContentsEntry {\n name: string;\n path: string;\n type: \"file\" | \"dir\";\n content?: string;\n encoding?: string;\n}\n\nfunction githubHeaders(\n options?: FetchSkillFolderOptions,\n): Record<string, string> {\n const token = options?.token ?? process.env.GITHUB_TOKEN;\n const headers: Record<string, string> = {\n Accept: \"application/vnd.github.v3+json\",\n \"User-Agent\": options?.userAgent ?? \"EvalForge\",\n };\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n return headers;\n}\n\n/**\n * Fetches all files in a skill directory from a GitHub repo.\n * Validates that SKILL.md exists at the root of the directory.\n */\nexport async function fetchSkillFolder(\n source: GitHubSource,\n options?: FetchSkillFolderOptions,\n): Promise<SkillFile[]> {\n const files = await fetchDirectory(\n source.owner,\n source.repo,\n source.path,\n source.ref,\n \"\",\n options,\n );\n\n const hasSkillMd = files.some((f) => f.path === \"SKILL.md\");\n if (!hasSkillMd) {\n throw new Error(\n `SKILL.md not found in ${source.owner}/${source.repo}/${source.path} at ref ${source.ref}`,\n );\n }\n\n return files;\n}\n\n/**\n * Fetches all files in a skill directory without validating SKILL.md presence.\n */\nexport async function fetchSkillFolderRaw(\n source: GitHubSource,\n options?: FetchSkillFolderOptions,\n): Promise<SkillFile[]> {\n return fetchDirectory(\n source.owner,\n source.repo,\n source.path,\n source.ref,\n \"\",\n options,\n );\n}\n\n/**\n * Validates that a GitHub source points to a valid skill directory\n * (i.e., the directory exists and contains SKILL.md).\n */\nexport async function validateGitHubSource(\n source: GitHubSource,\n options?: FetchSkillFolderOptions,\n): Promise<void> {\n await fetchSkillFolder(source, options);\n}\n\nasync function fetchDirectory(\n owner: string,\n repo: string,\n dirPath: string,\n ref: string,\n relativePath: string,\n options?: FetchSkillFolderOptions,\n): Promise<SkillFile[]> {\n const url = `${GITHUB_API_BASE}/repos/${owner}/${repo}/contents/${dirPath}?ref=${ref}`;\n const response = await fetch(url, {\n headers: githubHeaders(options),\n });\n\n if (!response.ok) {\n throw new Error(\n `GitHub API error: ${response.status} ${response.statusText} for ${url}`,\n );\n }\n\n const entries = (await response.json()) as GitHubContentsEntry[];\n\n const filePromises = entries.map(async (entry): Promise<SkillFile[]> => {\n if (entry.type === \"file\") {\n const filePath = relativePath\n ? `${relativePath}/${entry.name}`\n : entry.name;\n\n let content: string;\n if (entry.content && entry.encoding === \"base64\") {\n content = Buffer.from(entry.content, \"base64\").toString(\"utf-8\");\n } else {\n content = await fetchFileContent(\n owner,\n repo,\n `${dirPath}/${entry.name}`,\n ref,\n options,\n );\n }\n\n return [{ path: filePath, content }];\n }\n\n if (entry.type === \"dir\") {\n const subPath = relativePath\n ? `${relativePath}/${entry.name}`\n : entry.name;\n return fetchDirectory(\n owner,\n repo,\n `${dirPath}/${entry.name}`,\n ref,\n subPath,\n options,\n );\n }\n\n return [];\n });\n\n const results = await Promise.all(filePromises);\n return results.flat();\n}\n\n/**\n * Fetch a single file's content from the GitHub Contents API.\n * The API returns base64-encoded content when requesting a file path directly.\n */\nasync function fetchFileContent(\n owner: string,\n repo: string,\n filePath: string,\n ref: string,\n options?: FetchSkillFolderOptions,\n): Promise<string> {\n const url = `${GITHUB_API_BASE}/repos/${owner}/${repo}/contents/${filePath}?ref=${ref}`;\n const response = await fetch(url, {\n headers: githubHeaders(options),\n });\n\n if (!response.ok) {\n throw new Error(\n `GitHub API error: ${response.status} ${response.statusText} for ${url}`,\n );\n }\n\n const data = (await response.json()) as GitHubContentsEntry;\n if (data.content && data.encoding === \"base64\") {\n return Buffer.from(data.content, \"base64\").toString(\"utf-8\");\n }\n\n throw new Error(`No content returned for file: ${filePath}`);\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,109 @@
1
+ // src/github-contents-client.ts
2
+ var GITHUB_API_BASE = "https://api.github.com";
3
+ function githubHeaders(options) {
4
+ const token = options?.token ?? process.env.GITHUB_TOKEN;
5
+ const headers = {
6
+ Accept: "application/vnd.github.v3+json",
7
+ "User-Agent": options?.userAgent ?? "EvalForge"
8
+ };
9
+ if (token) {
10
+ headers.Authorization = `Bearer ${token}`;
11
+ }
12
+ return headers;
13
+ }
14
+ async function fetchSkillFolder(source, options) {
15
+ const files = await fetchDirectory(
16
+ source.owner,
17
+ source.repo,
18
+ source.path,
19
+ source.ref,
20
+ "",
21
+ options
22
+ );
23
+ const hasSkillMd = files.some((f) => f.path === "SKILL.md");
24
+ if (!hasSkillMd) {
25
+ throw new Error(
26
+ `SKILL.md not found in ${source.owner}/${source.repo}/${source.path} at ref ${source.ref}`
27
+ );
28
+ }
29
+ return files;
30
+ }
31
+ async function fetchSkillFolderRaw(source, options) {
32
+ return fetchDirectory(
33
+ source.owner,
34
+ source.repo,
35
+ source.path,
36
+ source.ref,
37
+ "",
38
+ options
39
+ );
40
+ }
41
+ async function validateGitHubSource(source, options) {
42
+ await fetchSkillFolder(source, options);
43
+ }
44
+ async function fetchDirectory(owner, repo, dirPath, ref, relativePath, options) {
45
+ const url = `${GITHUB_API_BASE}/repos/${owner}/${repo}/contents/${dirPath}?ref=${ref}`;
46
+ const response = await fetch(url, {
47
+ headers: githubHeaders(options)
48
+ });
49
+ if (!response.ok) {
50
+ throw new Error(
51
+ `GitHub API error: ${response.status} ${response.statusText} for ${url}`
52
+ );
53
+ }
54
+ const entries = await response.json();
55
+ const filePromises = entries.map(async (entry) => {
56
+ if (entry.type === "file") {
57
+ const filePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
58
+ let content;
59
+ if (entry.content && entry.encoding === "base64") {
60
+ content = Buffer.from(entry.content, "base64").toString("utf-8");
61
+ } else {
62
+ content = await fetchFileContent(
63
+ owner,
64
+ repo,
65
+ `${dirPath}/${entry.name}`,
66
+ ref,
67
+ options
68
+ );
69
+ }
70
+ return [{ path: filePath, content }];
71
+ }
72
+ if (entry.type === "dir") {
73
+ const subPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
74
+ return fetchDirectory(
75
+ owner,
76
+ repo,
77
+ `${dirPath}/${entry.name}`,
78
+ ref,
79
+ subPath,
80
+ options
81
+ );
82
+ }
83
+ return [];
84
+ });
85
+ const results = await Promise.all(filePromises);
86
+ return results.flat();
87
+ }
88
+ async function fetchFileContent(owner, repo, filePath, ref, options) {
89
+ const url = `${GITHUB_API_BASE}/repos/${owner}/${repo}/contents/${filePath}?ref=${ref}`;
90
+ const response = await fetch(url, {
91
+ headers: githubHeaders(options)
92
+ });
93
+ if (!response.ok) {
94
+ throw new Error(
95
+ `GitHub API error: ${response.status} ${response.statusText} for ${url}`
96
+ );
97
+ }
98
+ const data = await response.json();
99
+ if (data.content && data.encoding === "base64") {
100
+ return Buffer.from(data.content, "base64").toString("utf-8");
101
+ }
102
+ throw new Error(`No content returned for file: ${filePath}`);
103
+ }
104
+ export {
105
+ fetchSkillFolder,
106
+ fetchSkillFolderRaw,
107
+ validateGitHubSource
108
+ };
109
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/github-contents-client.ts"],
4
+ "sourcesContent": ["/**\n * GitHub Contents API client for fetching skill directories.\n *\n * Authenticates with GITHUB_TOKEN if set.\n */\n\nimport type { GitHubSource, SkillFile } from \"@wix/evalforge-types\";\n\nconst GITHUB_API_BASE = \"https://api.github.com\";\n\nexport interface FetchSkillFolderOptions {\n /** GitHub token for authentication (increases rate limit). Read from env if not provided. */\n token?: string;\n /** User-Agent header value. Defaults to \"EvalForge\". */\n userAgent?: string;\n}\n\ninterface GitHubContentsEntry {\n name: string;\n path: string;\n type: \"file\" | \"dir\";\n content?: string;\n encoding?: string;\n}\n\nfunction githubHeaders(\n options?: FetchSkillFolderOptions,\n): Record<string, string> {\n const token = options?.token ?? process.env.GITHUB_TOKEN;\n const headers: Record<string, string> = {\n Accept: \"application/vnd.github.v3+json\",\n \"User-Agent\": options?.userAgent ?? \"EvalForge\",\n };\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n return headers;\n}\n\n/**\n * Fetches all files in a skill directory from a GitHub repo.\n * Validates that SKILL.md exists at the root of the directory.\n */\nexport async function fetchSkillFolder(\n source: GitHubSource,\n options?: FetchSkillFolderOptions,\n): Promise<SkillFile[]> {\n const files = await fetchDirectory(\n source.owner,\n source.repo,\n source.path,\n source.ref,\n \"\",\n options,\n );\n\n const hasSkillMd = files.some((f) => f.path === \"SKILL.md\");\n if (!hasSkillMd) {\n throw new Error(\n `SKILL.md not found in ${source.owner}/${source.repo}/${source.path} at ref ${source.ref}`,\n );\n }\n\n return files;\n}\n\n/**\n * Fetches all files in a skill directory without validating SKILL.md presence.\n */\nexport async function fetchSkillFolderRaw(\n source: GitHubSource,\n options?: FetchSkillFolderOptions,\n): Promise<SkillFile[]> {\n return fetchDirectory(\n source.owner,\n source.repo,\n source.path,\n source.ref,\n \"\",\n options,\n );\n}\n\n/**\n * Validates that a GitHub source points to a valid skill directory\n * (i.e., the directory exists and contains SKILL.md).\n */\nexport async function validateGitHubSource(\n source: GitHubSource,\n options?: FetchSkillFolderOptions,\n): Promise<void> {\n await fetchSkillFolder(source, options);\n}\n\nasync function fetchDirectory(\n owner: string,\n repo: string,\n dirPath: string,\n ref: string,\n relativePath: string,\n options?: FetchSkillFolderOptions,\n): Promise<SkillFile[]> {\n const url = `${GITHUB_API_BASE}/repos/${owner}/${repo}/contents/${dirPath}?ref=${ref}`;\n const response = await fetch(url, {\n headers: githubHeaders(options),\n });\n\n if (!response.ok) {\n throw new Error(\n `GitHub API error: ${response.status} ${response.statusText} for ${url}`,\n );\n }\n\n const entries = (await response.json()) as GitHubContentsEntry[];\n\n const filePromises = entries.map(async (entry): Promise<SkillFile[]> => {\n if (entry.type === \"file\") {\n const filePath = relativePath\n ? `${relativePath}/${entry.name}`\n : entry.name;\n\n let content: string;\n if (entry.content && entry.encoding === \"base64\") {\n content = Buffer.from(entry.content, \"base64\").toString(\"utf-8\");\n } else {\n content = await fetchFileContent(\n owner,\n repo,\n `${dirPath}/${entry.name}`,\n ref,\n options,\n );\n }\n\n return [{ path: filePath, content }];\n }\n\n if (entry.type === \"dir\") {\n const subPath = relativePath\n ? `${relativePath}/${entry.name}`\n : entry.name;\n return fetchDirectory(\n owner,\n repo,\n `${dirPath}/${entry.name}`,\n ref,\n subPath,\n options,\n );\n }\n\n return [];\n });\n\n const results = await Promise.all(filePromises);\n return results.flat();\n}\n\n/**\n * Fetch a single file's content from the GitHub Contents API.\n * The API returns base64-encoded content when requesting a file path directly.\n */\nasync function fetchFileContent(\n owner: string,\n repo: string,\n filePath: string,\n ref: string,\n options?: FetchSkillFolderOptions,\n): Promise<string> {\n const url = `${GITHUB_API_BASE}/repos/${owner}/${repo}/contents/${filePath}?ref=${ref}`;\n const response = await fetch(url, {\n headers: githubHeaders(options),\n });\n\n if (!response.ok) {\n throw new Error(\n `GitHub API error: ${response.status} ${response.statusText} for ${url}`,\n );\n }\n\n const data = (await response.json()) as GitHubContentsEntry;\n if (data.content && data.encoding === \"base64\") {\n return Buffer.from(data.content, \"base64\").toString(\"utf-8\");\n }\n\n throw new Error(`No content returned for file: ${filePath}`);\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * GitHub Contents API client for fetching skill directories.
3
+ *
4
+ * Authenticates with GITHUB_TOKEN if set.
5
+ */
6
+ import type { GitHubSource, SkillFile } from "@wix/evalforge-types";
7
+ export interface FetchSkillFolderOptions {
8
+ /** GitHub token for authentication (increases rate limit). Read from env if not provided. */
9
+ token?: string;
10
+ /** User-Agent header value. Defaults to "EvalForge". */
11
+ userAgent?: string;
12
+ }
13
+ /**
14
+ * Fetches all files in a skill directory from a GitHub repo.
15
+ * Validates that SKILL.md exists at the root of the directory.
16
+ */
17
+ export declare function fetchSkillFolder(source: GitHubSource, options?: FetchSkillFolderOptions): Promise<SkillFile[]>;
18
+ /**
19
+ * Fetches all files in a skill directory without validating SKILL.md presence.
20
+ */
21
+ export declare function fetchSkillFolderRaw(source: GitHubSource, options?: FetchSkillFolderOptions): Promise<SkillFile[]>;
22
+ /**
23
+ * Validates that a GitHub source points to a valid skill directory
24
+ * (i.e., the directory exists and contains SKILL.md).
25
+ */
26
+ export declare function validateGitHubSource(source: GitHubSource, options?: FetchSkillFolderOptions): Promise<void>;
@@ -0,0 +1,2 @@
1
+ export { fetchSkillFolder, fetchSkillFolderRaw, validateGitHubSource, } from "./github-contents-client.js";
2
+ export type { FetchSkillFolderOptions } from "./github-contents-client.js";
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@wix/evalforge-github-client",
3
+ "version": "0.1.0",
4
+ "description": "GitHub Contents API client for fetching skill directories",
5
+ "files": [
6
+ "build"
7
+ ],
8
+ "scripts": {
9
+ "clean": "rm -rf build",
10
+ "build:cjs": "esbuild src/index.ts --bundle --platform=node --outfile=build/index.js --format=cjs --sourcemap --packages=external",
11
+ "build:esm": "esbuild src/index.ts --bundle --platform=node --outfile=build/index.mjs --format=esm --sourcemap --packages=external",
12
+ "build:types": "tsc --emitDeclarationOnly --outDir ./build/types",
13
+ "build": "yarn run clean && yarn run build:cjs && yarn run build:esm && yarn run build:types",
14
+ "lint": "eslint .",
15
+ "test": "echo 'No tests specified' && exit 0"
16
+ },
17
+ "dependencies": {
18
+ "@wix/evalforge-types": "0.26.0"
19
+ },
20
+ "devDependencies": {
21
+ "@eslint/js": "^9.39.2",
22
+ "@types/node": "^22.19.3",
23
+ "esbuild": "^0.27.2",
24
+ "eslint": "^9.39.2",
25
+ "eslint-config-prettier": "^10.1.8",
26
+ "eslint-plugin-prettier": "^5.5.4",
27
+ "prettier": "^3.7.4",
28
+ "typescript": "^5.9.3",
29
+ "typescript-eslint": "^8.51.0"
30
+ },
31
+ "exports": {
32
+ ".": {
33
+ "types": "./build/types/index.d.ts",
34
+ "import": "./build/index.mjs",
35
+ "require": "./build/index.js"
36
+ },
37
+ "./package.json": "./package.json"
38
+ },
39
+ "publishConfig": {
40
+ "registry": "https://registry.npmjs.org/",
41
+ "access": "public"
42
+ },
43
+ "wix": {
44
+ "artifact": {
45
+ "groupId": "com.wixpress",
46
+ "artifactId": "evalforge-github-client"
47
+ }
48
+ },
49
+ "falconPackageHash": "a536720ec887ce7ecbd64a6eae33bd5af88beb9b852aba1249365dae"
50
+ }