@wix/evalforge-github-client 0.3.0 → 0.4.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 CHANGED
@@ -20,8 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ fetchGitHubFolder: () => fetchGitHubFolder,
23
24
  fetchSkillFolder: () => fetchSkillFolder,
24
- fetchSkillFolderRaw: () => fetchSkillFolderRaw,
25
25
  validateGitHubSource: () => validateGitHubSource
26
26
  });
27
27
  module.exports = __toCommonJS(index_exports);
@@ -40,14 +40,7 @@ function githubHeaders(options) {
40
40
  return headers;
41
41
  }
42
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
- );
43
+ const files = await fetchGitHubFolder(source, options);
51
44
  const hasSkillMd = files.some((f) => f.path === "SKILL.md");
52
45
  if (!hasSkillMd) {
53
46
  throw new Error(
@@ -56,7 +49,7 @@ async function fetchSkillFolder(source, options) {
56
49
  }
57
50
  return files;
58
51
  }
59
- async function fetchSkillFolderRaw(source, options) {
52
+ async function fetchGitHubFolder(source, options) {
60
53
  return fetchDirectory(
61
54
  source.owner,
62
55
  source.repo,
@@ -131,8 +124,8 @@ async function fetchFileContent(owner, repo, filePath, ref, options) {
131
124
  }
132
125
  // Annotate the CommonJS export names for ESM import in node:
133
126
  0 && (module.exports = {
127
+ fetchGitHubFolder,
134
128
  fetchSkillFolder,
135
- fetchSkillFolderRaw,
136
129
  validateGitHubSource
137
130
  });
138
131
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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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",
4
+ "sourcesContent": ["export {\n fetchSkillFolder,\n fetchGitHubFolder,\n validateGitHubSource,\n} from \"./github-contents-client.js\";\nexport type { FetchGitHubFolderOptions } from \"./github-contents-client.js\";\n", "/**\n * GitHub Contents API client for fetching directory contents.\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 FetchGitHubFolderOptions {\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?: FetchGitHubFolderOptions,\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?: FetchGitHubFolderOptions,\n): Promise<SkillFile[]> {\n const files = await fetchGitHubFolder(source, options);\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 GitHub directory (recursive).\n */\nexport async function fetchGitHubFolder(\n source: GitHubSource,\n options?: FetchGitHubFolderOptions,\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?: FetchGitHubFolderOptions,\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?: FetchGitHubFolderOptions,\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?: FetchGitHubFolderOptions,\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
6
  "names": []
7
7
  }
package/build/index.mjs CHANGED
@@ -12,14 +12,7 @@ function githubHeaders(options) {
12
12
  return headers;
13
13
  }
14
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
- );
15
+ const files = await fetchGitHubFolder(source, options);
23
16
  const hasSkillMd = files.some((f) => f.path === "SKILL.md");
24
17
  if (!hasSkillMd) {
25
18
  throw new Error(
@@ -28,7 +21,7 @@ async function fetchSkillFolder(source, options) {
28
21
  }
29
22
  return files;
30
23
  }
31
- async function fetchSkillFolderRaw(source, options) {
24
+ async function fetchGitHubFolder(source, options) {
32
25
  return fetchDirectory(
33
26
  source.owner,
34
27
  source.repo,
@@ -102,8 +95,8 @@ async function fetchFileContent(owner, repo, filePath, ref, options) {
102
95
  throw new Error(`No content returned for file: ${filePath}`);
103
96
  }
104
97
  export {
98
+ fetchGitHubFolder,
105
99
  fetchSkillFolder,
106
- fetchSkillFolderRaw,
107
100
  validateGitHubSource
108
101
  };
109
102
  //# sourceMappingURL=index.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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": ";AAQA,IAAM,kBAAkB;AAiBxB,SAAS,cACP,SACwB;AACxB,QAAM,QAAQ,SAAS,SAAS,QAAQ,IAAI;AAC5C,QAAM,UAAkC;AAAA,IACtC,QAAQ;AAAA,IACR,cAAc,SAAS,aAAa;AAAA,EACtC;AACA,MAAI,OAAO;AACT,YAAQ,gBAAgB,UAAU,KAAK;AAAA,EACzC;AACA,SAAO;AACT;AAMA,eAAsB,iBACpB,QACA,SACsB;AACtB,QAAM,QAAQ,MAAM;AAAA,IAClB,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,UAAU;AAC1D,MAAI,CAAC,YAAY;AACf,UAAM,IAAI;AAAA,MACR,yBAAyB,OAAO,KAAK,IAAI,OAAO,IAAI,IAAI,OAAO,IAAI,WAAW,OAAO,GAAG;AAAA,IAC1F;AAAA,EACF;AAEA,SAAO;AACT;AAKA,eAAsB,oBACpB,QACA,SACsB;AACtB,SAAO;AAAA,IACL,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EACF;AACF;AAMA,eAAsB,qBACpB,QACA,SACe;AACf,QAAM,iBAAiB,QAAQ,OAAO;AACxC;AAEA,eAAe,eACb,OACA,MACA,SACA,KACA,cACA,SACsB;AACtB,QAAM,MAAM,GAAG,eAAe,UAAU,KAAK,IAAI,IAAI,aAAa,OAAO,QAAQ,GAAG;AACpF,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS,cAAc,OAAO;AAAA,EAChC,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI;AAAA,MACR,qBAAqB,SAAS,MAAM,IAAI,SAAS,UAAU,QAAQ,GAAG;AAAA,IACxE;AAAA,EACF;AAEA,QAAM,UAAW,MAAM,SAAS,KAAK;AAErC,QAAM,eAAe,QAAQ,IAAI,OAAO,UAAgC;AACtE,QAAI,MAAM,SAAS,QAAQ;AACzB,YAAM,WAAW,eACb,GAAG,YAAY,IAAI,MAAM,IAAI,KAC7B,MAAM;AAEV,UAAI;AACJ,UAAI,MAAM,WAAW,MAAM,aAAa,UAAU;AAChD,kBAAU,OAAO,KAAK,MAAM,SAAS,QAAQ,EAAE,SAAS,OAAO;AAAA,MACjE,OAAO;AACL,kBAAU,MAAM;AAAA,UACd;AAAA,UACA;AAAA,UACA,GAAG,OAAO,IAAI,MAAM,IAAI;AAAA,UACxB;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,aAAO,CAAC,EAAE,MAAM,UAAU,QAAQ,CAAC;AAAA,IACrC;AAEA,QAAI,MAAM,SAAS,OAAO;AACxB,YAAM,UAAU,eACZ,GAAG,YAAY,IAAI,MAAM,IAAI,KAC7B,MAAM;AACV,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,GAAG,OAAO,IAAI,MAAM,IAAI;AAAA,QACxB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,WAAO,CAAC;AAAA,EACV,CAAC;AAED,QAAM,UAAU,MAAM,QAAQ,IAAI,YAAY;AAC9C,SAAO,QAAQ,KAAK;AACtB;AAMA,eAAe,iBACb,OACA,MACA,UACA,KACA,SACiB;AACjB,QAAM,MAAM,GAAG,eAAe,UAAU,KAAK,IAAI,IAAI,aAAa,QAAQ,QAAQ,GAAG;AACrF,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS,cAAc,OAAO;AAAA,EAChC,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI;AAAA,MACR,qBAAqB,SAAS,MAAM,IAAI,SAAS,UAAU,QAAQ,GAAG;AAAA,IACxE;AAAA,EACF;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,MAAI,KAAK,WAAW,KAAK,aAAa,UAAU;AAC9C,WAAO,OAAO,KAAK,KAAK,SAAS,QAAQ,EAAE,SAAS,OAAO;AAAA,EAC7D;AAEA,QAAM,IAAI,MAAM,iCAAiC,QAAQ,EAAE;AAC7D;",
4
+ "sourcesContent": ["/**\n * GitHub Contents API client for fetching directory contents.\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 FetchGitHubFolderOptions {\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?: FetchGitHubFolderOptions,\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?: FetchGitHubFolderOptions,\n): Promise<SkillFile[]> {\n const files = await fetchGitHubFolder(source, options);\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 GitHub directory (recursive).\n */\nexport async function fetchGitHubFolder(\n source: GitHubSource,\n options?: FetchGitHubFolderOptions,\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?: FetchGitHubFolderOptions,\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?: FetchGitHubFolderOptions,\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?: FetchGitHubFolderOptions,\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
6
  "names": []
7
7
  }
@@ -1,10 +1,10 @@
1
1
  /**
2
- * GitHub Contents API client for fetching skill directories.
2
+ * GitHub Contents API client for fetching directory contents.
3
3
  *
4
4
  * Authenticates with GITHUB_TOKEN if set.
5
5
  */
6
6
  import type { GitHubSource, SkillFile } from "@wix/evalforge-types";
7
- export interface FetchSkillFolderOptions {
7
+ export interface FetchGitHubFolderOptions {
8
8
  /** GitHub token for authentication (increases rate limit). Read from env if not provided. */
9
9
  token?: string;
10
10
  /** User-Agent header value. Defaults to "EvalForge". */
@@ -14,13 +14,13 @@ export interface FetchSkillFolderOptions {
14
14
  * Fetches all files in a skill directory from a GitHub repo.
15
15
  * Validates that SKILL.md exists at the root of the directory.
16
16
  */
17
- export declare function fetchSkillFolder(source: GitHubSource, options?: FetchSkillFolderOptions): Promise<SkillFile[]>;
17
+ export declare function fetchSkillFolder(source: GitHubSource, options?: FetchGitHubFolderOptions): Promise<SkillFile[]>;
18
18
  /**
19
- * Fetches all files in a skill directory without validating SKILL.md presence.
19
+ * Fetches all files in a GitHub directory (recursive).
20
20
  */
21
- export declare function fetchSkillFolderRaw(source: GitHubSource, options?: FetchSkillFolderOptions): Promise<SkillFile[]>;
21
+ export declare function fetchGitHubFolder(source: GitHubSource, options?: FetchGitHubFolderOptions): Promise<SkillFile[]>;
22
22
  /**
23
23
  * Validates that a GitHub source points to a valid skill directory
24
24
  * (i.e., the directory exists and contains SKILL.md).
25
25
  */
26
- export declare function validateGitHubSource(source: GitHubSource, options?: FetchSkillFolderOptions): Promise<void>;
26
+ export declare function validateGitHubSource(source: GitHubSource, options?: FetchGitHubFolderOptions): Promise<void>;
@@ -1,2 +1,2 @@
1
- export { fetchSkillFolder, fetchSkillFolderRaw, validateGitHubSource, } from "./github-contents-client.js";
2
- export type { FetchSkillFolderOptions } from "./github-contents-client.js";
1
+ export { fetchSkillFolder, fetchGitHubFolder, validateGitHubSource, } from "./github-contents-client.js";
2
+ export type { FetchGitHubFolderOptions } from "./github-contents-client.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/evalforge-github-client",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "GitHub Contents API client for fetching skill directories",
5
5
  "files": [
6
6
  "build"
@@ -15,7 +15,7 @@
15
15
  "test": "echo 'No tests specified' && exit 0"
16
16
  },
17
17
  "dependencies": {
18
- "@wix/evalforge-types": "0.28.0"
18
+ "@wix/evalforge-types": "0.29.0"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@eslint/js": "^9.39.2",
@@ -46,5 +46,5 @@
46
46
  "artifactId": "evalforge-github-client"
47
47
  }
48
48
  },
49
- "falconPackageHash": "530116870c1c5af659c76fc368447d9990f6af972e2a6764448e513b"
49
+ "falconPackageHash": "da8aa59301c4b6be5e5b76da7aa610591c4b8223f6d443e72463d567"
50
50
  }