@elysiumoss/grepo 0.2.0 โ†’ 0.3.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 CHANGED
@@ -1,61 +1,100 @@
1
- <h1 align="center">package-template</h1>
1
+ # grepo
2
2
 
3
3
  <p align="center">
4
- A very lovely package.
5
- Hooray!
4
+ <b>An agentic CLI tool for analyzing, describing, and generating documentation for GitHub repositories.</b>
6
5
  </p>
7
6
 
8
7
  <p align="center">
9
- <!-- prettier-ignore-start -->
10
- <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
11
- <a href="#contributors" target="_blank"><img alt="๐Ÿ‘ช All Contributors: 2" src="https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-2-21bb42.svg" /></a>
12
- <!-- ALL-CONTRIBUTORS-BADGE:END -->
13
- <!-- prettier-ignore-end -->
14
- <a href="https://github.com/ElysiumOSS/package-template/blob/main/.github/CODE_OF_CONDUCT.md" target="_blank"><img alt="๐Ÿค Code of Conduct: Kept" src="https://img.shields.io/badge/%F0%9F%A4%9D_code_of_conduct-kept-21bb42" /></a>
15
- <a href="https://codecov.io/gh/ElysiumOSS/package-template" target="_blank"><img alt="๐Ÿงช Coverage" src="https://img.shields.io/codecov/c/github/ElysiumOSS/package-template?label=%F0%9F%A7%AA%20coverage" /></a>
16
- <a href="https://github.com/ElysiumOSS/package-template/blob/main/LICENSE.md" target="_blank"><img alt="๐Ÿ“ License: MIT" src="https://img.shields.io/badge/%F0%9F%93%9D_license-MIT-21bb42.svg" /></a>
17
- <a href="http://npmjs.com/package/package-template" target="_blank"><img alt="๐Ÿ“ฆ npm version" src="https://img.shields.io/npm/v/package-template?color=21bb42&label=%F0%9F%93%A6%20npm" /></a>
18
- <img alt="๐Ÿ’ช TypeScript: Strict" src="https://img.shields.io/badge/%F0%9F%92%AA_typescript-strict-21bb42.svg" />
8
+ <a href="https://github.com/ElysiumOSS/grepo/blob/main/LICENSE.md" target="_blank"><img alt="๐Ÿ“ License: MIT" src="https://img.shields.io/badge/%F0%9F%93%9D_license-MIT-21bb42.svg" /></a>
9
+ <a href="https://npmjs.com/package/@elysiumoss/grepo" target="_blank"><img alt="๐Ÿ“ฆ npm version" src="https://img.shields.io/npm/v/@elysiumoss/grepo?color=21bb42&label=%F0%9F%93%A6%20npm" /></a>
19
10
  </p>
20
11
 
12
+ ## Overview
13
+
14
+ `grepo` automates the heavy lifting of repository maintenance. By integrating with LLM providers like Google Gemini, it intelligently analyzes your codebase to generate professional READMEs, suggest relevant repository topics, and craft repository descriptions.
15
+
16
+ ```mermaid
17
+ flowchart TD
18
+ User["User Command"] --> CLI["grepo CLI"]
19
+ CLI --> GH["GitHub API / Gitingest"]
20
+ GH -->|Repo Context| CLI
21
+ CLI --> LLM["LLM (Gemini)"]
22
+ LLM -->|Analysis/Doc Content| Generator["Documentation Generator"]
23
+ Generator --> Output["Output (README/Mermaid)"]
24
+ ```
25
+
26
+ ## Installation
27
+
28
+ Ensure you have [Bun](https://bun.sh/) installed, then install `grepo` globally:
29
+
30
+ ```bash
31
+ bun add -g @elysiumoss/grepo
32
+ ```
33
+
21
34
  ## Usage
22
35
 
23
- ```shell
24
- npm i package-template
36
+ Generate a new `README.md` for a repository:
37
+
38
+ ```bash
39
+ grepo readme https://github.com/owner/repo --format md --push
25
40
  ```
26
41
 
27
- ```ts
28
- import { greet } from "package-template";
42
+ Automatically update repository topics based on code analysis:
29
43
 
30
- greet("Hello, world! ๐Ÿ’–");
44
+ ```bash
45
+ grepo topics https://github.com/owner/repo --apply --merge
31
46
  ```
32
47
 
33
- ## Development
48
+ ## CLI Reference
49
+
50
+ | Command | Description |
51
+ | :--- | :--- |
52
+ | `readme` | Generate and optionally push a README documentation file |
53
+ | `topics` | Analyze code and suggest/apply repository topics |
54
+ | `describe` | Generate a repository description and detect homepage URLs |
55
+ | `summary` | Provide a comprehensive summary of the repository |
56
+ | `tech` | List technologies, frameworks, and tools used |
57
+ | `improve` | Suggest 5 specific, actionable improvements |
58
+
59
+ **Options:**
60
+ - `--format md|mdx`: Output format (default: `md`)
61
+ - `--push`: Push the generated file directly to the GitHub repository
62
+ - `--apply`: Apply changes (topics/description) directly to the GitHub API
63
+ - `--dry-run`: Preview changes without writing or pushing
64
+ - `--model <id>`: Manually specify the LLM model to use
34
65
 
35
- See [`.github/CONTRIBUTING.md`](./.github/CONTRIBUTING.md), then [`.github/DEVELOPMENT.md`](./.github/DEVELOPMENT.md).
36
- Thanks! ๐Ÿ’–
66
+ ## Configuration
37
67
 
38
- ## Contributors
68
+ `grepo` requires authentication for repository access and AI analysis. Configure these via environment variables or a `.env` file:
39
69
 
40
- <!-- spellchecker: disable -->
41
- <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
42
- <!-- prettier-ignore-start -->
43
- <!-- markdownlint-disable -->
44
- <table>
45
- <tbody>
46
- <tr>
47
- <td align="center"><a href="https://github.com/ElysiumOSS"><img src="https://avatars.githubusercontent.com/u/155137850?v=4?s=100" width="100px;" alt="Elysium Open Source"/><br /><sub><b>Elysium Open Source</b></sub></a><br /><a href="https://github.com/ElysiumOSS/package-template/commits?author=ElysiumOSS" title="Code">๐Ÿ’ป</a> <a href="#content-ElysiumOSS" title="Content">๐Ÿ–‹</a> <a href="https://github.com/ElysiumOSS/package-template/commits?author=ElysiumOSS" title="Documentation">๐Ÿ“–</a> <a href="#ideas-ElysiumOSS" title="Ideas, Planning, & Feedback">๐Ÿค”</a> <a href="#infra-ElysiumOSS" title="Infrastructure (Hosting, Build-Tools, etc)">๐Ÿš‡</a> <a href="#maintenance-ElysiumOSS" title="Maintenance">๐Ÿšง</a> <a href="#projectManagement-ElysiumOSS" title="Project Management">๐Ÿ“†</a> <a href="#tool-ElysiumOSS" title="Tools">๐Ÿ”ง</a></td>
48
- <td align="center"><a href="https://linktr.ee/mikeodnis"><img src="https://avatars.githubusercontent.com/u/95197809?v=4?s=100" width="100px;" alt="Mike Odnis"/><br /><sub><b>Mike Odnis</b></sub></a><br /><a href="https://github.com/ElysiumOSS/package-template/commits?author=WomB0ComB0" title="Code">๐Ÿ’ป</a> <a href="#content-WomB0ComB0" title="Content">๐Ÿ–‹</a> <a href="https://github.com/ElysiumOSS/package-template/commits?author=WomB0ComB0" title="Documentation">๐Ÿ“–</a> <a href="#ideas-WomB0ComB0" title="Ideas, Planning, & Feedback">๐Ÿค”</a> <a href="#infra-WomB0ComB0" title="Infrastructure (Hosting, Build-Tools, etc)">๐Ÿš‡</a> <a href="#maintenance-WomB0ComB0" title="Maintenance">๐Ÿšง</a> <a href="#projectManagement-WomB0ComB0" title="Project Management">๐Ÿ“†</a> <a href="#tool-WomB0ComB0" title="Tools">๐Ÿ”ง</a></td>
49
- </tr>
50
- </tbody>
51
- </table>
70
+ - `GEMINI_API_KEY`: Required for AI code analysis.
71
+ - `GH_TOKEN` or `GITHUB_TOKEN`: Required for pushing files, updating topics, or repository descriptions.
72
+
73
+ **Example `.env` file:**
74
+ ```env
75
+ GEMINI_API_KEY=AIzaSy...
76
+ GH_TOKEN=ghp_...
77
+ ```
78
+
79
+ ## Development
52
80
 
53
- <!-- markdownlint-restore -->
54
- <!-- prettier-ignore-end -->
81
+ 1. **Clone the repo:**
82
+ ```bash
83
+ git clone https://github.com/ElysiumOSS/grepo
84
+ cd grepo
85
+ bun install
86
+ ```
87
+ 2. **Build the project:**
88
+ ```bash
89
+ bun run build
90
+ ```
91
+ 3. **Run tests:**
92
+ ```bash
93
+ bun run test
94
+ ```
55
95
 
56
- <!-- ALL-CONTRIBUTORS-LIST:END -->
57
- <!-- spellchecker: enable -->
96
+ See [`.github/CONTRIBUTING.md`](./.github/CONTRIBUTING.md) and [`.github/DEVELOPMENT.md`](./.github/DEVELOPMENT.md) for detailed guidelines.
58
97
 
59
- <!-- You can remove this notice if you don't want it ๐Ÿ™‚ no worries! -->
98
+ ## License
60
99
 
61
- > ๐Ÿ’ This package was templated with [`create-typescript-app`](https://github.com/JoshuaKGoldberg/create-typescript-app) using the [Bingo framework](https://create.bingo).
100
+ This project is licensed under the [MIT License](LICENSE.md).
package/lib/cli.js CHANGED
@@ -38,7 +38,22 @@ Commands:
38
38
  Run 'grepo <command> --help' for more information.`);
39
39
  process.exit(0);
40
40
  }
41
- const config = buildConfig(argv);
41
+ const parsedConfig = buildConfig(argv);
42
+ let resolvedBranch = parsedConfig.branch;
43
+ if (!resolvedBranch) try {
44
+ const { GitHubClient } = await import("./utils/github.js");
45
+ const { parseGitHubUrl } = await import("./utils/validation.js");
46
+ const { owner, repo } = parseGitHubUrl(parsedConfig.repoUrl);
47
+ resolvedBranch = await new GitHubClient(parsedConfig.githubToken).getDefaultBranch(owner, repo);
48
+ logger.info(`Detected default branch: ${resolvedBranch}`);
49
+ } catch {
50
+ resolvedBranch = "main";
51
+ logger.warn("Could not detect default branch, falling back to 'main'");
52
+ }
53
+ const config = {
54
+ ...parsedConfig,
55
+ branch: resolvedBranch
56
+ };
42
57
  const layers = Layer.merge(GeminiLive(config.geminiApiKey), GitHubLive(config.githubToken));
43
58
  let run;
44
59
  switch (config.command) {
package/lib/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":["Logger"],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n *\n * Copyright 2026 Mike Odnis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport { Effect, Layer } from \"effect\";\n\nimport type { GrepoConfig } from \"./config.js\";\nimport { buildConfig, loadEnv } from \"./config.js\";\nimport type {\n\tGeminiError,\n\tGitHubError,\n\tGitIngestError,\n\tGrepoValidationError,\n} from \"./errors.js\";\nimport type { Gemini, GitHub } from \"./services.js\";\nimport { GeminiLive, GitHubLive } from \"./services.js\";\nimport { Logger } from \"./utils/logger.js\";\n\nconst logger = new Logger(\"GREPO\");\n\nawait loadEnv();\n\nconst argv = process.argv.slice(2);\n\nif (argv.length === 0) {\n\tconsole.log(`Usage: grepo <command> <github-url> [options]\n\nCommands:\n readme Generate README documentation\n topics Generate and apply repository topics\n describe Generate repository description and homepage URL\n summary Summarize repository\n tech List technologies used\n improve Suggest improvements\n\nRun 'grepo <command> --help' for more information.`);\n\tprocess.exit(0);\n}\n\nconst config = buildConfig(argv);\n\nconst layers = Layer.merge(\n\tGeminiLive(config.geminiApiKey),\n\tGitHubLive(config.githubToken),\n);\n\ntype CommandRunner = (\n\tconfig: GrepoConfig,\n) => Effect.Effect<\n\tvoid,\n\tGeminiError | GitHubError | GitIngestError | GrepoValidationError,\n\tGemini | GitHub\n>;\n\nlet run: CommandRunner;\n\nswitch (config.command) {\n\tcase \"readme\":\n\t\trun = (await import(\"./commands/readme.js\")).run;\n\t\tbreak;\n\tcase \"topics\":\n\t\trun = (await import(\"./commands/topics.js\")).run;\n\t\tbreak;\n\tcase \"describe\":\n\t\trun = (await import(\"./commands/describe.js\")).run;\n\t\tbreak;\n\tcase \"summary\":\n\tcase \"tech\":\n\tcase \"improve\":\n\t\trun = (await import(\"./commands/analyze.js\")).run;\n\t\tbreak;\n}\n\nawait Effect.runPromise(\n\trun(config).pipe(\n\t\tEffect.provide(layers),\n\t\tEffect.catchTags({\n\t\t\tGeminiError: (e) =>\n\t\t\t\tEffect.sync(() => {\n\t\t\t\t\tlogger.error(`Gemini Error: ${e.message}`);\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}),\n\t\t\tGitHubError: (e) =>\n\t\t\t\tEffect.sync(() => {\n\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t`GitHub Error (${e.endpoint}): ${e.message}`,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t{ status: e.statusCode },\n\t\t\t\t\t);\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}),\n\t\t\tGitIngestError: (e) =>\n\t\t\t\tEffect.sync(() => {\n\t\t\t\t\tlogger.error(`GitIngest Error: ${e.message}`);\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}),\n\t\t\tGrepoValidationError: (e) =>\n\t\t\t\tEffect.sync(() => {\n\t\t\t\t\tlogger.error(`Validation Error: ${e.message}`, undefined, {\n\t\t\t\t\t\tfield: e.field,\n\t\t\t\t\t});\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}),\n\t\t}),\n\t),\n).catch((error) => {\n\tlogger.error(\"An unexpected error occurred\", error);\n\tprocess.exit(1);\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAiCA,MAAM,SAAS,IAAIA,SAAO,QAAQ;AAElC,MAAM,SAAS;AAEf,MAAM,OAAO,QAAQ,KAAK,MAAM,EAAE;AAElC,IAAI,KAAK,WAAW,GAAG;AACtB,SAAQ,IAAI;;;;;;;;;;oDAUuC;AACnD,SAAQ,KAAK,EAAE;;AAGhB,MAAM,SAAS,YAAY,KAAK;AAEhC,MAAM,SAAS,MAAM,MACpB,WAAW,OAAO,aAAa,EAC/B,WAAW,OAAO,YAAY,CAC9B;AAUD,IAAI;AAEJ,QAAQ,OAAO,SAAf;CACC,KAAK;AACJ,SAAO,MAAM,OAAO,yBAAyB;AAC7C;CACD,KAAK;AACJ,SAAO,MAAM,OAAO,yBAAyB;AAC7C;CACD,KAAK;AACJ,SAAO,MAAM,OAAO,2BAA2B;AAC/C;CACD,KAAK;CACL,KAAK;CACL,KAAK;AACJ,SAAO,MAAM,OAAO,0BAA0B;AAC9C;;AAGF,MAAM,OAAO,WACZ,IAAI,OAAO,CAAC,KACX,OAAO,QAAQ,OAAO,EACtB,OAAO,UAAU;CAChB,cAAc,MACb,OAAO,WAAW;AACjB,SAAO,MAAM,iBAAiB,EAAE,UAAU;AAC1C,UAAQ,KAAK,EAAE;GACd;CACH,cAAc,MACb,OAAO,WAAW;AACjB,SAAO,MACN,iBAAiB,EAAE,SAAS,KAAK,EAAE,WACnC,KAAA,GACA,EAAE,QAAQ,EAAE,YAAY,CACxB;AACD,UAAQ,KAAK,EAAE;GACd;CACH,iBAAiB,MAChB,OAAO,WAAW;AACjB,SAAO,MAAM,oBAAoB,EAAE,UAAU;AAC7C,UAAQ,KAAK,EAAE;GACd;CACH,uBAAuB,MACtB,OAAO,WAAW;AACjB,SAAO,MAAM,qBAAqB,EAAE,WAAW,KAAA,GAAW,EACzD,OAAO,EAAE,OACT,CAAC;AACF,UAAQ,KAAK,EAAE;GACd;CACH,CAAC,CACF,CACD,CAAC,OAAO,UAAU;AAClB,QAAO,MAAM,gCAAgC,MAAM;AACnD,SAAQ,KAAK,EAAE;EACd"}
1
+ {"version":3,"file":"cli.js","names":["Logger"],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n *\n * Copyright 2026 Mike Odnis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport { Effect, Layer } from \"effect\";\n\nimport type { GrepoConfig } from \"./config.js\";\nimport { buildConfig, loadEnv } from \"./config.js\";\nimport type {\n\tGeminiError,\n\tGitHubError,\n\tGitIngestError,\n\tGrepoValidationError,\n} from \"./errors.js\";\nimport type { Gemini, GitHub } from \"./services.js\";\nimport { GeminiLive, GitHubLive } from \"./services.js\";\nimport { Logger } from \"./utils/logger.js\";\n\nconst logger = new Logger(\"GREPO\");\n\nawait loadEnv();\n\nconst argv = process.argv.slice(2);\n\nif (argv.length === 0) {\n\tconsole.log(`Usage: grepo <command> <github-url> [options]\n\nCommands:\n readme Generate README documentation\n topics Generate and apply repository topics\n describe Generate repository description and homepage URL\n summary Summarize repository\n tech List technologies used\n improve Suggest improvements\n\nRun 'grepo <command> --help' for more information.`);\n\tprocess.exit(0);\n}\n\nconst parsedConfig = buildConfig(argv);\n\n// Auto-detect default branch from GitHub API if not explicitly set\nlet resolvedBranch = parsedConfig.branch;\nif (!resolvedBranch) {\n\ttry {\n\t\tconst { GitHubClient } = await import(\"./utils/github.js\");\n\t\tconst { parseGitHubUrl } = await import(\"./utils/validation.js\");\n\t\tconst { owner, repo } = parseGitHubUrl(parsedConfig.repoUrl);\n\t\tconst client = new GitHubClient(parsedConfig.githubToken);\n\t\tresolvedBranch = await client.getDefaultBranch(owner, repo);\n\t\tlogger.info(`Detected default branch: ${resolvedBranch}`);\n\t} catch {\n\t\tresolvedBranch = \"main\";\n\t\tlogger.warn(\"Could not detect default branch, falling back to 'main'\");\n\t}\n}\n\nconst config = { ...parsedConfig, branch: resolvedBranch };\n\nconst layers = Layer.merge(\n\tGeminiLive(config.geminiApiKey),\n\tGitHubLive(config.githubToken),\n);\n\ntype CommandRunner = (\n\tconfig: GrepoConfig,\n) => Effect.Effect<\n\tvoid,\n\tGeminiError | GitHubError | GitIngestError | GrepoValidationError,\n\tGemini | GitHub\n>;\n\nlet run: CommandRunner;\n\nswitch (config.command) {\n\tcase \"readme\":\n\t\trun = (await import(\"./commands/readme.js\")).run;\n\t\tbreak;\n\tcase \"topics\":\n\t\trun = (await import(\"./commands/topics.js\")).run;\n\t\tbreak;\n\tcase \"describe\":\n\t\trun = (await import(\"./commands/describe.js\")).run;\n\t\tbreak;\n\tcase \"summary\":\n\tcase \"tech\":\n\tcase \"improve\":\n\t\trun = (await import(\"./commands/analyze.js\")).run;\n\t\tbreak;\n}\n\nawait Effect.runPromise(\n\trun(config).pipe(\n\t\tEffect.provide(layers),\n\t\tEffect.catchTags({\n\t\t\tGeminiError: (e) =>\n\t\t\t\tEffect.sync(() => {\n\t\t\t\t\tlogger.error(`Gemini Error: ${e.message}`);\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}),\n\t\t\tGitHubError: (e) =>\n\t\t\t\tEffect.sync(() => {\n\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t`GitHub Error (${e.endpoint}): ${e.message}`,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t{ status: e.statusCode },\n\t\t\t\t\t);\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}),\n\t\t\tGitIngestError: (e) =>\n\t\t\t\tEffect.sync(() => {\n\t\t\t\t\tlogger.error(`GitIngest Error: ${e.message}`);\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}),\n\t\t\tGrepoValidationError: (e) =>\n\t\t\t\tEffect.sync(() => {\n\t\t\t\t\tlogger.error(`Validation Error: ${e.message}`, undefined, {\n\t\t\t\t\t\tfield: e.field,\n\t\t\t\t\t});\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}),\n\t\t}),\n\t),\n).catch((error) => {\n\tlogger.error(\"An unexpected error occurred\", error);\n\tprocess.exit(1);\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAiCA,MAAM,SAAS,IAAIA,SAAO,QAAQ;AAElC,MAAM,SAAS;AAEf,MAAM,OAAO,QAAQ,KAAK,MAAM,EAAE;AAElC,IAAI,KAAK,WAAW,GAAG;AACtB,SAAQ,IAAI;;;;;;;;;;oDAUuC;AACnD,SAAQ,KAAK,EAAE;;AAGhB,MAAM,eAAe,YAAY,KAAK;AAGtC,IAAI,iBAAiB,aAAa;AAClC,IAAI,CAAC,eACJ,KAAI;CACH,MAAM,EAAE,iBAAiB,MAAM,OAAO;CACtC,MAAM,EAAE,mBAAmB,MAAM,OAAO;CACxC,MAAM,EAAE,OAAO,SAAS,eAAe,aAAa,QAAQ;AAE5D,kBAAiB,MADF,IAAI,aAAa,aAAa,YAAY,CAC3B,iBAAiB,OAAO,KAAK;AAC3D,QAAO,KAAK,4BAA4B,iBAAiB;QAClD;AACP,kBAAiB;AACjB,QAAO,KAAK,0DAA0D;;AAIxE,MAAM,SAAS;CAAE,GAAG;CAAc,QAAQ;CAAgB;AAE1D,MAAM,SAAS,MAAM,MACpB,WAAW,OAAO,aAAa,EAC/B,WAAW,OAAO,YAAY,CAC9B;AAUD,IAAI;AAEJ,QAAQ,OAAO,SAAf;CACC,KAAK;AACJ,SAAO,MAAM,OAAO,yBAAyB;AAC7C;CACD,KAAK;AACJ,SAAO,MAAM,OAAO,yBAAyB;AAC7C;CACD,KAAK;AACJ,SAAO,MAAM,OAAO,2BAA2B;AAC/C;CACD,KAAK;CACL,KAAK;CACL,KAAK;AACJ,SAAO,MAAM,OAAO,0BAA0B;AAC9C;;AAGF,MAAM,OAAO,WACZ,IAAI,OAAO,CAAC,KACX,OAAO,QAAQ,OAAO,EACtB,OAAO,UAAU;CAChB,cAAc,MACb,OAAO,WAAW;AACjB,SAAO,MAAM,iBAAiB,EAAE,UAAU;AAC1C,UAAQ,KAAK,EAAE;GACd;CACH,cAAc,MACb,OAAO,WAAW;AACjB,SAAO,MACN,iBAAiB,EAAE,SAAS,KAAK,EAAE,WACnC,KAAA,GACA,EAAE,QAAQ,EAAE,YAAY,CACxB;AACD,UAAQ,KAAK,EAAE;GACd;CACH,iBAAiB,MAChB,OAAO,WAAW;AACjB,SAAO,MAAM,oBAAoB,EAAE,UAAU;AAC7C,UAAQ,KAAK,EAAE;GACd;CACH,uBAAuB,MACtB,OAAO,WAAW;AACjB,SAAO,MAAM,qBAAqB,EAAE,WAAW,KAAA,GAAW,EACzD,OAAO,EAAE,OACT,CAAC;AACF,UAAQ,KAAK,EAAE;GACd;CACH,CAAC,CACF,CACD,CAAC,OAAO,UAAU;AAClB,QAAO,MAAM,gCAAgC,MAAM;AACnD,SAAQ,KAAK,EAAE;EACd"}
@@ -59,7 +59,7 @@ const run = (config) => Effect.gen(function* () {
59
59
  if (config.shouldPush) {
60
60
  const { owner, repo } = parseGitHubUrl(config.repoUrl);
61
61
  logger.info(`Pushing README to GitHub (${owner}/${repo})...`);
62
- yield* github.pushFile(owner, repo, config.outputFile, content, "docs: update README with AI-generated content", config.branch);
62
+ yield* github.pushFile(owner, repo, config.outputFile, content, "docs: update README with AI-generated content", config.branch ?? "main");
63
63
  logger.success("Pushed to GitHub successfully");
64
64
  }
65
65
  });
@@ -1 +1 @@
1
- {"version":3,"file":"readme.js","names":["Logger","validation.parseGitHubUrl"],"sources":["../../src/commands/readme.ts"],"sourcesContent":["/**\n *\n * Copyright 2026 Mike Odnis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport { writeFile } from \"node:fs/promises\";\nimport { Effect } from \"effect\";\n\nimport type { GrepoConfig } from \"../config.js\";\nimport { validateAndFixMermaid } from \"../mermaid.js\";\nimport {\n\tbuildAnalysisPrompt,\n\tbuildGenerationPrompt,\n\textractExistingReadme,\n\tparseAnalysis,\n} from \"../prompts/readme.js\";\nimport { fetchRepo, Gemini, GitHub } from \"../services.js\";\nimport { displayHeader } from \"../utils/args.js\";\nimport { Logger } from \"../utils/logger.js\";\nimport * as validation from \"../utils/validation.js\";\n\nconst logger = new Logger(\"GREPO:README\");\n\nexport const run = (config: GrepoConfig) =>\n\tEffect.gen(function* () {\n\t\tconst gemini = yield* Gemini;\n\t\tconst github = yield* GitHub;\n\n\t\tdisplayHeader(\"grepo readme\", {\n\t\t\tFormat: config.outputFormat,\n\t\t\tOutput: config.outputFile,\n\t\t\tPush: config.shouldPush ? `Yes (${config.branch})` : \"No\",\n\t\t\tRepository: config.repoUrl,\n\t\t\tStyle: config.style,\n\t\t});\n\n\t\tlogger.info(\"Fetching repository content via GitIngest...\");\n\t\tconst repoData = yield* fetchRepo(config.repoUrl);\n\t\tlogger.success(\"Content fetched successfully\");\n\n\t\t// Phase 1: Analysis\n\t\tlogger.info(\"Analyzing repository structure...\");\n\t\tconst existingReadme = extractExistingReadme(repoData.content);\n\t\tconst analysisPrompt = buildAnalysisPrompt(\n\t\t\trepoData,\n\t\t\texistingReadme ?? undefined,\n\t\t);\n\t\tconst analysisRaw = yield* gemini.generateContent(analysisPrompt);\n\t\tconst analysis = parseAnalysis(analysisRaw);\n\t\tlogger.success(\"Analysis complete\");\n\n\t\t// Phase 2: Generation\n\t\tlogger.info(\"Generating README content via Gemini...\");\n\t\tconst generationPrompt = buildGenerationPrompt(analysis, repoData, {\n\t\t\tformat: config.outputFormat,\n\t\t\tstyle: config.style,\n\t\t\ttone: config.tone,\n\t\t});\n\t\tconst rawContent = yield* gemini.generateContent(generationPrompt);\n\t\tlogger.success(\"README generated successfully\");\n\n\t\t// Phase 3: Mermaid validation\n\t\tconst content = yield* validateAndFixMermaid(rawContent, gemini);\n\n\t\tif (config.outputFile) {\n\t\t\tlogger.info(`Saving README to ${config.outputFile}...`);\n\t\t\tyield* Effect.promise(() => writeFile(config.outputFile, content));\n\t\t\tlogger.success(\"File saved locally\");\n\t\t}\n\n\t\tif (config.shouldPush) {\n\t\t\tconst { owner, repo } = validation.parseGitHubUrl(config.repoUrl);\n\t\t\tlogger.info(`Pushing README to GitHub (${owner}/${repo})...`);\n\t\t\tyield* github.pushFile(\n\t\t\t\towner,\n\t\t\t\trepo,\n\t\t\t\tconfig.outputFile,\n\t\t\t\tcontent,\n\t\t\t\t\"docs: update README with AI-generated content\",\n\t\t\t\tconfig.branch,\n\t\t\t);\n\t\t\tlogger.success(\"Pushed to GitHub successfully\");\n\t\t}\n\t});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,MAAM,SAAS,IAAIA,SAAO,eAAe;AAEzC,MAAa,OAAO,WACnB,OAAO,IAAI,aAAa;CACvB,MAAM,SAAS,OAAO;CACtB,MAAM,SAAS,OAAO;AAEtB,eAAc,gBAAgB;EAC7B,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,MAAM,OAAO,aAAa,QAAQ,OAAO,OAAO,KAAK;EACrD,YAAY,OAAO;EACnB,OAAO,OAAO;EACd,CAAC;AAEF,QAAO,KAAK,+CAA+C;CAC3D,MAAM,WAAW,OAAO,UAAU,OAAO,QAAQ;AACjD,QAAO,QAAQ,+BAA+B;AAG9C,QAAO,KAAK,oCAAoC;CAEhD,MAAM,iBAAiB,oBACtB,UAFsB,sBAAsB,SAAS,QAAQ,IAG3C,KAAA,EAClB;CAED,MAAM,WAAW,cADG,OAAO,OAAO,gBAAgB,eAAe,CACtB;AAC3C,QAAO,QAAQ,oBAAoB;AAGnC,QAAO,KAAK,0CAA0C;CACtD,MAAM,mBAAmB,sBAAsB,UAAU,UAAU;EAClE,QAAQ,OAAO;EACf,OAAO,OAAO;EACd,MAAM,OAAO;EACb,CAAC;CACF,MAAM,aAAa,OAAO,OAAO,gBAAgB,iBAAiB;AAClE,QAAO,QAAQ,gCAAgC;CAG/C,MAAM,UAAU,OAAO,sBAAsB,YAAY,OAAO;AAEhE,KAAI,OAAO,YAAY;AACtB,SAAO,KAAK,oBAAoB,OAAO,WAAW,KAAK;AACvD,SAAO,OAAO,cAAc,UAAU,OAAO,YAAY,QAAQ,CAAC;AAClE,SAAO,QAAQ,qBAAqB;;AAGrC,KAAI,OAAO,YAAY;EACtB,MAAM,EAAE,OAAO,SAASC,eAA0B,OAAO,QAAQ;AACjE,SAAO,KAAK,6BAA6B,MAAM,GAAG,KAAK,MAAM;AAC7D,SAAO,OAAO,SACb,OACA,MACA,OAAO,YACP,SACA,iDACA,OAAO,OACP;AACD,SAAO,QAAQ,gCAAgC;;EAE/C"}
1
+ {"version":3,"file":"readme.js","names":["Logger","validation.parseGitHubUrl"],"sources":["../../src/commands/readme.ts"],"sourcesContent":["/**\n *\n * Copyright 2026 Mike Odnis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport { writeFile } from \"node:fs/promises\";\nimport { Effect } from \"effect\";\n\nimport type { GrepoConfig } from \"../config.js\";\nimport { validateAndFixMermaid } from \"../mermaid.js\";\nimport {\n\tbuildAnalysisPrompt,\n\tbuildGenerationPrompt,\n\textractExistingReadme,\n\tparseAnalysis,\n} from \"../prompts/readme.js\";\nimport { fetchRepo, Gemini, GitHub } from \"../services.js\";\nimport { displayHeader } from \"../utils/args.js\";\nimport { Logger } from \"../utils/logger.js\";\nimport * as validation from \"../utils/validation.js\";\n\nconst logger = new Logger(\"GREPO:README\");\n\nexport const run = (config: GrepoConfig) =>\n\tEffect.gen(function* () {\n\t\tconst gemini = yield* Gemini;\n\t\tconst github = yield* GitHub;\n\n\t\tdisplayHeader(\"grepo readme\", {\n\t\t\tFormat: config.outputFormat,\n\t\t\tOutput: config.outputFile,\n\t\t\tPush: config.shouldPush ? `Yes (${config.branch})` : \"No\",\n\t\t\tRepository: config.repoUrl,\n\t\t\tStyle: config.style,\n\t\t});\n\n\t\tlogger.info(\"Fetching repository content via GitIngest...\");\n\t\tconst repoData = yield* fetchRepo(config.repoUrl);\n\t\tlogger.success(\"Content fetched successfully\");\n\n\t\t// Phase 1: Analysis\n\t\tlogger.info(\"Analyzing repository structure...\");\n\t\tconst existingReadme = extractExistingReadme(repoData.content);\n\t\tconst analysisPrompt = buildAnalysisPrompt(\n\t\t\trepoData,\n\t\t\texistingReadme ?? undefined,\n\t\t);\n\t\tconst analysisRaw = yield* gemini.generateContent(analysisPrompt);\n\t\tconst analysis = parseAnalysis(analysisRaw);\n\t\tlogger.success(\"Analysis complete\");\n\n\t\t// Phase 2: Generation\n\t\tlogger.info(\"Generating README content via Gemini...\");\n\t\tconst generationPrompt = buildGenerationPrompt(analysis, repoData, {\n\t\t\tformat: config.outputFormat,\n\t\t\tstyle: config.style,\n\t\t\ttone: config.tone,\n\t\t});\n\t\tconst rawContent = yield* gemini.generateContent(generationPrompt);\n\t\tlogger.success(\"README generated successfully\");\n\n\t\t// Phase 3: Mermaid validation\n\t\tconst content = yield* validateAndFixMermaid(rawContent, gemini);\n\n\t\tif (config.outputFile) {\n\t\t\tlogger.info(`Saving README to ${config.outputFile}...`);\n\t\t\tyield* Effect.promise(() => writeFile(config.outputFile, content));\n\t\t\tlogger.success(\"File saved locally\");\n\t\t}\n\n\t\tif (config.shouldPush) {\n\t\t\tconst { owner, repo } = validation.parseGitHubUrl(config.repoUrl);\n\t\t\tlogger.info(`Pushing README to GitHub (${owner}/${repo})...`);\n\t\t\tyield* github.pushFile(\n\t\t\t\towner,\n\t\t\t\trepo,\n\t\t\t\tconfig.outputFile,\n\t\t\t\tcontent,\n\t\t\t\t\"docs: update README with AI-generated content\",\n\t\t\t\tconfig.branch ?? \"main\",\n\t\t\t);\n\t\t\tlogger.success(\"Pushed to GitHub successfully\");\n\t\t}\n\t});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,MAAM,SAAS,IAAIA,SAAO,eAAe;AAEzC,MAAa,OAAO,WACnB,OAAO,IAAI,aAAa;CACvB,MAAM,SAAS,OAAO;CACtB,MAAM,SAAS,OAAO;AAEtB,eAAc,gBAAgB;EAC7B,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,MAAM,OAAO,aAAa,QAAQ,OAAO,OAAO,KAAK;EACrD,YAAY,OAAO;EACnB,OAAO,OAAO;EACd,CAAC;AAEF,QAAO,KAAK,+CAA+C;CAC3D,MAAM,WAAW,OAAO,UAAU,OAAO,QAAQ;AACjD,QAAO,QAAQ,+BAA+B;AAG9C,QAAO,KAAK,oCAAoC;CAEhD,MAAM,iBAAiB,oBACtB,UAFsB,sBAAsB,SAAS,QAAQ,IAG3C,KAAA,EAClB;CAED,MAAM,WAAW,cADG,OAAO,OAAO,gBAAgB,eAAe,CACtB;AAC3C,QAAO,QAAQ,oBAAoB;AAGnC,QAAO,KAAK,0CAA0C;CACtD,MAAM,mBAAmB,sBAAsB,UAAU,UAAU;EAClE,QAAQ,OAAO;EACf,OAAO,OAAO;EACd,MAAM,OAAO;EACb,CAAC;CACF,MAAM,aAAa,OAAO,OAAO,gBAAgB,iBAAiB;AAClE,QAAO,QAAQ,gCAAgC;CAG/C,MAAM,UAAU,OAAO,sBAAsB,YAAY,OAAO;AAEhE,KAAI,OAAO,YAAY;AACtB,SAAO,KAAK,oBAAoB,OAAO,WAAW,KAAK;AACvD,SAAO,OAAO,cAAc,UAAU,OAAO,YAAY,QAAQ,CAAC;AAClE,SAAO,QAAQ,qBAAqB;;AAGrC,KAAI,OAAO,YAAY;EACtB,MAAM,EAAE,OAAO,SAASC,eAA0B,OAAO,QAAQ;AACjE,SAAO,KAAK,6BAA6B,MAAM,GAAG,KAAK,MAAM;AAC7D,SAAO,OAAO,SACb,OACA,MACA,OAAO,YACP,SACA,iDACA,OAAO,UAAU,OACjB;AACD,SAAO,QAAQ,gCAAgC;;EAE/C"}
package/lib/config.d.ts CHANGED
@@ -9,7 +9,7 @@ type OutputFormat = Schema.Schema.Type<typeof OutputFormat>;
9
9
  declare const DocumentationStyle: Schema.Literal<["minimal", "standard", "comprehensive"]>;
10
10
  type DocumentationStyle = Schema.Schema.Type<typeof DocumentationStyle>;
11
11
  declare const GrepoConfig: Schema.Struct<{
12
- branch: typeof Schema.String;
12
+ branch: Schema.optional<typeof Schema.String>;
13
13
  command: Schema.Literal<["readme", "topics", "describe", "summary", "tech", "improve"]>;
14
14
  geminiApiKey: typeof Schema.String;
15
15
  githubToken: Schema.optional<typeof Schema.String>;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;cA+Ba,SAAO,MAAA,CAAA;KAQR,OAAA,GAAU,MAAA,CAAO,MAAA,CAAO,YAAY;cAEnC,cAAY,MAAA,CAAA;KACb,YAAA,GAAe,MAAA,CAAO,MAAA,CAAO,YAAY;cAExC,oBAAkB,MAAA,CAAA;KAKnB,kBAAA,GAAqB,MAAA,CAAO,MAAA,CAAO,YAAY;cAE9C,aAAW,MAAA,CAAA;EAAA,MAAA,EAAA,oBAAA;EAAA,OAAA,gBAAA,CAAA,CAAA,QAAA,EAAA,QAAA,EAAA,UAAA,EAAA,SAAA,EAAA,MAAA,EAAA,SAAA,CAAA,CAAA;EAiBZ,YAAA,EAAW,oBAA6B;EAM9B,WAAO,iBAAI,CAAA,oBAAO,CAAA;EAsExB,QAAA,EAAA,qBAA6B;;;;;;;;;;KA5EjC,WAAA,GAAc,MAAA,CAAO,MAAA,CAAO,YAAY;iBAM9B,OAAA,CAAA,GAAW;iBAsEjB,WAAA,kBAA6B"}
1
+ {"version":3,"file":"config.d.ts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;cA+Ba,SAAO,MAAA,CAAA;KAQR,OAAA,GAAU,MAAA,CAAO,MAAA,CAAO,YAAY;cAEnC,cAAY,MAAA,CAAA;KACb,YAAA,GAAe,MAAA,CAAO,MAAA,CAAO,YAAY;cAExC,oBAAkB,MAAA,CAAA;KAKnB,kBAAA,GAAqB,MAAA,CAAO,MAAA,CAAO,YAAY;cAE9C,aAAW,MAAA,CAAA;;EAAA,OAAA,gBAAA,CAAA,CAAA,QAAA,EAAA,QAAA,EAAA,UAAA,EAAA,SAAA,EAAA,MAAA,EAAA,SAAA,CAAA,CAAA;EAAA,YAAA,EAAA,oBAAA;EAiBZ,WAAA,iBAAwC,CAAA,oBAAnB,CAAA;EAMX,QAAA,EAAO,qBAAW;EAsExB,UAAA,EAAA,oBAA6B;;;;;;;;;KA5EjC,WAAA,GAAc,MAAA,CAAO,MAAA,CAAO,YAAY;iBAM9B,OAAA,CAAA,GAAW;iBAsEjB,WAAA,kBAA6B"}
package/lib/config.js CHANGED
@@ -27,7 +27,7 @@ const Command = Schema.Literal("readme", "topics", "describe", "summary", "tech"
27
27
  const OutputFormat = Schema.Literal("md", "mdx");
28
28
  const DocumentationStyle = Schema.Literal("minimal", "standard", "comprehensive");
29
29
  const GrepoConfig = Schema.Struct({
30
- branch: Schema.String,
30
+ branch: Schema.optional(Schema.String),
31
31
  command: Command,
32
32
  geminiApiKey: Schema.String,
33
33
  githubToken: Schema.optional(Schema.String),
@@ -79,7 +79,7 @@ Options:
79
79
  --apply Apply changes to GitHub (topics, describe)
80
80
  --merge Merge with existing topics (topics only)
81
81
  --dry-run Preview changes without applying
82
- --branch <name> Target branch (default: main)
82
+ --branch <name> Target branch (default: auto-detect from repo)
83
83
  --tone <voice> Tone: casual, professional, minimal, technical (default: auto-detect)`;
84
84
  const VALID_TONES = [
85
85
  "casual",
@@ -128,7 +128,7 @@ function buildConfig(argv) {
128
128
  if ((shouldApply || shouldPush || shouldMerge) && !githubToken) throw new GrepoValidationError({ message: "GitHub token (GITHUB_TOKEN or GH_TOKEN) is required for mutation operations" });
129
129
  const format = options.format || "md";
130
130
  return {
131
- branch: options.branch || "main",
131
+ branch: options.branch || void 0,
132
132
  command,
133
133
  geminiApiKey,
134
134
  githubToken,
package/lib/config.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","names":["validation.isValidGitHubUrl","validation.isValidGeminiApiKey"],"sources":["../src/config.ts"],"sourcesContent":["/**\n *\n * Copyright 2026 Mike Odnis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Schema } from \"effect\";\n\nimport { GrepoValidationError } from \"./errors.js\";\nimport { parseArgs } from \"./utils/args.js\";\nimport * as validation from \"./utils/validation.js\";\n\n// ============================================================================\n// Config Schema\n// ============================================================================\n\nexport const Command = Schema.Literal(\n\t\"readme\",\n\t\"topics\",\n\t\"describe\",\n\t\"summary\",\n\t\"tech\",\n\t\"improve\",\n);\nexport type Command = Schema.Schema.Type<typeof Command>;\n\nexport const OutputFormat = Schema.Literal(\"md\", \"mdx\");\nexport type OutputFormat = Schema.Schema.Type<typeof OutputFormat>;\n\nexport const DocumentationStyle = Schema.Literal(\n\t\"minimal\",\n\t\"standard\",\n\t\"comprehensive\",\n);\nexport type DocumentationStyle = Schema.Schema.Type<typeof DocumentationStyle>;\n\nexport const GrepoConfig = Schema.Struct({\n\tbranch: Schema.String,\n\tcommand: Command,\n\tgeminiApiKey: Schema.String,\n\tgithubToken: Schema.optional(Schema.String),\n\tisDryRun: Schema.Boolean,\n\toutputFile: Schema.String,\n\toutputFormat: OutputFormat,\n\trepoUrl: Schema.String,\n\tshouldApply: Schema.Boolean,\n\tshouldMerge: Schema.Boolean,\n\tshouldPush: Schema.Boolean,\n\tstyle: DocumentationStyle,\n\ttone: Schema.optional(\n\t\tSchema.Literal(\"casual\", \"minimal\", \"professional\", \"technical\"),\n\t),\n});\nexport type GrepoConfig = Schema.Schema.Type<typeof GrepoConfig>;\n\n// ============================================================================\n// Env Loading\n// ============================================================================\n\nexport async function loadEnv(): Promise<void> {\n\tconst __filename = fileURLToPath(import.meta.url);\n\tconst __dirname = dirname(__filename);\n\tconst envPath = resolve(__dirname, \"../.env\");\n\n\tif (!existsSync(envPath)) {\n\t\treturn;\n\t}\n\n\tconst envContent = readFileSync(envPath, \"utf-8\");\n\tfor (const line of envContent.split(\"\\n\")) {\n\t\tconst trimmed = line.trim();\n\t\tif (!trimmed || trimmed.startsWith(\"#\")) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst [key, ...valueParts] = trimmed.split(\"=\");\n\t\tif (key && valueParts.length > 0) {\n\t\t\tconst value = valueParts\n\t\t\t\t.join(\"=\")\n\t\t\t\t.trim()\n\t\t\t\t.replaceAll(/(^[\"'])|(['\"]$)/g, \"\");\n\t\t\tif (!process.env[key.trim()]) {\n\t\t\t\tprocess.env[key.trim()] = value;\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ============================================================================\n// Config Builder\n// ============================================================================\n\nconst BOOLEAN_FLAGS = [\"push\", \"apply\", \"merge\", \"dry-run\"] as const;\n\nconst USAGE = `Usage: grepo <command> <github-url> [options]\n\nCommands:\n readme Generate README documentation\n topics Generate and apply repository topics\n describe Generate repository description and homepage URL\n summary Summarize repository\n tech List technologies used\n improve Suggest improvements\n\nOptions:\n --format md|mdx Output format (readme only, default: md)\n --style minimal|standard|comprehensive Documentation style (readme only, default: standard)\n --output <file> Output file path (readme only)\n --push Push to GitHub (readme only)\n --apply Apply changes to GitHub (topics, describe)\n --merge Merge with existing topics (topics only)\n --dry-run Preview changes without applying\n --branch <name> Target branch (default: main)\n --tone <voice> Tone: casual, professional, minimal, technical (default: auto-detect)`;\n\nconst VALID_TONES = [\"casual\", \"professional\", \"minimal\", \"technical\"] as const;\n\nfunction validateTone(tone: string | undefined): GrepoConfig[\"tone\"] {\n\tif (!tone) {\n\t\treturn undefined;\n\t}\n\tif (!VALID_TONES.includes(tone as (typeof VALID_TONES)[number])) {\n\t\tthrow new GrepoValidationError({\n\t\t\tfield: \"tone\",\n\t\t\tmessage: `Invalid tone \"${tone}\". Must be one of: ${VALID_TONES.join(\", \")}`,\n\t\t});\n\t}\n\treturn tone as GrepoConfig[\"tone\"];\n}\n\nexport function buildConfig(argv: string[]): GrepoConfig {\n\tconst { options, positional } = parseArgs(argv, [...BOOLEAN_FLAGS]);\n\n\tif (positional.length < 2) {\n\t\tconsole.log(USAGE);\n\t\tprocess.exit(1);\n\t}\n\n\tconst command = positional[0];\n\tconst validCommands: Command[] = [\n\t\t\"readme\",\n\t\t\"topics\",\n\t\t\"describe\",\n\t\t\"summary\",\n\t\t\"tech\",\n\t\t\"improve\",\n\t];\n\tif (!validCommands.includes(command as Command)) {\n\t\tconsole.error(`Unknown command: ${command}`);\n\t\tconsole.log(USAGE);\n\t\tprocess.exit(1);\n\t}\n\n\tconst repoUrl = positional[1];\n\tif (!validation.isValidGitHubUrl(repoUrl)) {\n\t\tthrow new GrepoValidationError({\n\t\t\tfield: \"repoUrl\",\n\t\t\tmessage: \"Invalid GitHub URL\",\n\t\t});\n\t}\n\n\tconst geminiApiKey =\n\t\tprocess.env.GEMINI_API_KEY ?? process.env.GOOGLE_API_KEY ?? \"\";\n\tif (!validation.isValidGeminiApiKey(geminiApiKey)) {\n\t\tthrow new GrepoValidationError({\n\t\t\tmessage: \"GEMINI_API_KEY is missing or invalid\",\n\t\t});\n\t}\n\n\tconst githubToken = process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN;\n\tconst shouldApply = !!options.apply;\n\tconst shouldPush = !!options.push;\n\tconst shouldMerge = !!options.merge;\n\n\tif ((shouldApply || shouldPush || shouldMerge) && !githubToken) {\n\t\tthrow new GrepoValidationError({\n\t\t\tmessage:\n\t\t\t\t\"GitHub token (GITHUB_TOKEN or GH_TOKEN) is required for mutation operations\",\n\t\t});\n\t}\n\n\tconst format = (options.format as string) || \"md\";\n\treturn {\n\t\tbranch: (options.branch as string) || \"main\",\n\t\tcommand: command as Command,\n\t\tgeminiApiKey,\n\t\tgithubToken,\n\t\tisDryRun: !!options[\"dry-run\"],\n\t\toutputFile: (options.output as string) || `README.${format}`,\n\t\toutputFormat: format as OutputFormat,\n\t\trepoUrl,\n\t\tshouldApply,\n\t\tshouldMerge,\n\t\tshouldPush,\n\t\tstyle: ((options.style as string) || \"standard\") as DocumentationStyle,\n\t\ttone: validateTone(options.tone as string | undefined),\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"config.js","names":["validation.isValidGitHubUrl","validation.isValidGeminiApiKey"],"sources":["../src/config.ts"],"sourcesContent":["/**\n *\n * Copyright 2026 Mike Odnis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Schema } from \"effect\";\n\nimport { GrepoValidationError } from \"./errors.js\";\nimport { parseArgs } from \"./utils/args.js\";\nimport * as validation from \"./utils/validation.js\";\n\n// ============================================================================\n// Config Schema\n// ============================================================================\n\nexport const Command = Schema.Literal(\n\t\"readme\",\n\t\"topics\",\n\t\"describe\",\n\t\"summary\",\n\t\"tech\",\n\t\"improve\",\n);\nexport type Command = Schema.Schema.Type<typeof Command>;\n\nexport const OutputFormat = Schema.Literal(\"md\", \"mdx\");\nexport type OutputFormat = Schema.Schema.Type<typeof OutputFormat>;\n\nexport const DocumentationStyle = Schema.Literal(\n\t\"minimal\",\n\t\"standard\",\n\t\"comprehensive\",\n);\nexport type DocumentationStyle = Schema.Schema.Type<typeof DocumentationStyle>;\n\nexport const GrepoConfig = Schema.Struct({\n\tbranch: Schema.optional(Schema.String),\n\tcommand: Command,\n\tgeminiApiKey: Schema.String,\n\tgithubToken: Schema.optional(Schema.String),\n\tisDryRun: Schema.Boolean,\n\toutputFile: Schema.String,\n\toutputFormat: OutputFormat,\n\trepoUrl: Schema.String,\n\tshouldApply: Schema.Boolean,\n\tshouldMerge: Schema.Boolean,\n\tshouldPush: Schema.Boolean,\n\tstyle: DocumentationStyle,\n\ttone: Schema.optional(\n\t\tSchema.Literal(\"casual\", \"minimal\", \"professional\", \"technical\"),\n\t),\n});\nexport type GrepoConfig = Schema.Schema.Type<typeof GrepoConfig>;\n\n// ============================================================================\n// Env Loading\n// ============================================================================\n\nexport async function loadEnv(): Promise<void> {\n\tconst __filename = fileURLToPath(import.meta.url);\n\tconst __dirname = dirname(__filename);\n\tconst envPath = resolve(__dirname, \"../.env\");\n\n\tif (!existsSync(envPath)) {\n\t\treturn;\n\t}\n\n\tconst envContent = readFileSync(envPath, \"utf-8\");\n\tfor (const line of envContent.split(\"\\n\")) {\n\t\tconst trimmed = line.trim();\n\t\tif (!trimmed || trimmed.startsWith(\"#\")) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst [key, ...valueParts] = trimmed.split(\"=\");\n\t\tif (key && valueParts.length > 0) {\n\t\t\tconst value = valueParts\n\t\t\t\t.join(\"=\")\n\t\t\t\t.trim()\n\t\t\t\t.replaceAll(/(^[\"'])|(['\"]$)/g, \"\");\n\t\t\tif (!process.env[key.trim()]) {\n\t\t\t\tprocess.env[key.trim()] = value;\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ============================================================================\n// Config Builder\n// ============================================================================\n\nconst BOOLEAN_FLAGS = [\"push\", \"apply\", \"merge\", \"dry-run\"] as const;\n\nconst USAGE = `Usage: grepo <command> <github-url> [options]\n\nCommands:\n readme Generate README documentation\n topics Generate and apply repository topics\n describe Generate repository description and homepage URL\n summary Summarize repository\n tech List technologies used\n improve Suggest improvements\n\nOptions:\n --format md|mdx Output format (readme only, default: md)\n --style minimal|standard|comprehensive Documentation style (readme only, default: standard)\n --output <file> Output file path (readme only)\n --push Push to GitHub (readme only)\n --apply Apply changes to GitHub (topics, describe)\n --merge Merge with existing topics (topics only)\n --dry-run Preview changes without applying\n --branch <name> Target branch (default: auto-detect from repo)\n --tone <voice> Tone: casual, professional, minimal, technical (default: auto-detect)`;\n\nconst VALID_TONES = [\"casual\", \"professional\", \"minimal\", \"technical\"] as const;\n\nfunction validateTone(tone: string | undefined): GrepoConfig[\"tone\"] {\n\tif (!tone) {\n\t\treturn undefined;\n\t}\n\tif (!VALID_TONES.includes(tone as (typeof VALID_TONES)[number])) {\n\t\tthrow new GrepoValidationError({\n\t\t\tfield: \"tone\",\n\t\t\tmessage: `Invalid tone \"${tone}\". Must be one of: ${VALID_TONES.join(\", \")}`,\n\t\t});\n\t}\n\treturn tone as GrepoConfig[\"tone\"];\n}\n\nexport function buildConfig(argv: string[]): GrepoConfig {\n\tconst { options, positional } = parseArgs(argv, [...BOOLEAN_FLAGS]);\n\n\tif (positional.length < 2) {\n\t\tconsole.log(USAGE);\n\t\tprocess.exit(1);\n\t}\n\n\tconst command = positional[0];\n\tconst validCommands: Command[] = [\n\t\t\"readme\",\n\t\t\"topics\",\n\t\t\"describe\",\n\t\t\"summary\",\n\t\t\"tech\",\n\t\t\"improve\",\n\t];\n\tif (!validCommands.includes(command as Command)) {\n\t\tconsole.error(`Unknown command: ${command}`);\n\t\tconsole.log(USAGE);\n\t\tprocess.exit(1);\n\t}\n\n\tconst repoUrl = positional[1];\n\tif (!validation.isValidGitHubUrl(repoUrl)) {\n\t\tthrow new GrepoValidationError({\n\t\t\tfield: \"repoUrl\",\n\t\t\tmessage: \"Invalid GitHub URL\",\n\t\t});\n\t}\n\n\tconst geminiApiKey =\n\t\tprocess.env.GEMINI_API_KEY ?? process.env.GOOGLE_API_KEY ?? \"\";\n\tif (!validation.isValidGeminiApiKey(geminiApiKey)) {\n\t\tthrow new GrepoValidationError({\n\t\t\tmessage: \"GEMINI_API_KEY is missing or invalid\",\n\t\t});\n\t}\n\n\tconst githubToken = process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN;\n\tconst shouldApply = !!options.apply;\n\tconst shouldPush = !!options.push;\n\tconst shouldMerge = !!options.merge;\n\n\tif ((shouldApply || shouldPush || shouldMerge) && !githubToken) {\n\t\tthrow new GrepoValidationError({\n\t\t\tmessage:\n\t\t\t\t\"GitHub token (GITHUB_TOKEN or GH_TOKEN) is required for mutation operations\",\n\t\t});\n\t}\n\n\tconst format = (options.format as string) || \"md\";\n\treturn {\n\t\tbranch: (options.branch as string) || undefined,\n\t\tcommand: command as Command,\n\t\tgeminiApiKey,\n\t\tgithubToken,\n\t\tisDryRun: !!options[\"dry-run\"],\n\t\toutputFile: (options.output as string) || `README.${format}`,\n\t\toutputFormat: format as OutputFormat,\n\t\trepoUrl,\n\t\tshouldApply,\n\t\tshouldMerge,\n\t\tshouldPush,\n\t\tstyle: ((options.style as string) || \"standard\") as DocumentationStyle,\n\t\ttone: validateTone(options.tone as string | undefined),\n\t};\n}\n"],"mappings":"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"}
package/lib/services.d.ts CHANGED
@@ -11,6 +11,7 @@ declare const Gemini_base: Context.TagClass<Gemini, "Gemini", GeminiServiceApi>;
11
11
  declare class Gemini extends Gemini_base {}
12
12
  declare const GeminiLive: (apiKey: string) => Layer.Layer<Gemini, never, never>;
13
13
  interface GitHubServiceApi {
14
+ readonly getDefaultBranch: (owner: string, repo: string) => Effect.Effect<string, GitHubError>;
14
15
  readonly getTopics: (owner: string, repo: string) => Effect.Effect<readonly string[], GitHubError>;
15
16
  readonly pushFile: (owner: string, repo: string, path: string, content: string, message: string, branch: string) => Effect.Effect<void, GitHubError>;
16
17
  readonly setTopics: (owner: string, repo: string, topics: string[]) => Effect.Effect<void, GitHubError>;
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.ts","names":[],"sources":["../src/services.ts"],"sourcesContent":[],"mappings":";;;;;;AAgFM,UA/CW,gBAAA,CA+CJ;EAAM,SAAA,eAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,GA5Cb,MAAA,CAAO,MA4CM,CAAA,MAAA,EA5CS,WA4CT,CAAA;AAClB;cA5CA;cAEY,MAAA,SAAe,WAAA;cAEf,gCAA4B,KAAA,CAAA,MAAA;AA0C5B,UAzBI,gBAAA,CAyBW;EAEf,SAAA,SAwCZ,EAAA,CAAA,KAxCwC,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,GAvBnC,MAAA,CAAO,MAuB4B,CAAA,SAAA,MAAA,EAAA,EAvBF,WAuBE,CAAA;EA8C7B,SAAA,QAAQ,EAAA,CAAA,KAA6B,EAAA,MAAA,EAAA,IAAA,EAAA,MAA1B,EAAO,IAAA,EAAA,MAAW,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,GA7DnC,MAAA,CAAO,MA6D4B,CAAA,IAAA,EA7Df,WA6De,CAAA;EAE5B,SAAA,SAUV,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,EAAA,GApEG,MAAA,CAAO,MAoEV,CAAA,IAAA,EApEuB,WAoEvB,CAAA;EARc,SAAA,UAAA,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA;IAAU,WAAA,CAAA,EAAA,MAAA;IAAjB,QAAA,CAAA,EAAA,MAAA;EAAM,CAAA,EAAA,GAvDV,MAAA,CAAO,MAuDG,CAAA,IAAA,EAvDU,WAuDV,CAAA;;cAtDf;cAEY,MAAA,SAAe,WAAA;cAEf,gCAA4B,KAAA,CAAA,MAAA;KA8C7B,QAAA,GAAW,MAAA,CAAO,MAAA,CAAO,YAAY;cAEpC,gCAEV,MAAA,CAAO,OAAO,UAAU"}
1
+ {"version":3,"file":"services.d.ts","names":[],"sources":["../src/services.ts"],"sourcesContent":[],"mappings":";;;;;;AA+EM,UA9CW,gBAAA,CA8CJ;EAKa,SAAA,eAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,GAhDpB,MAAA,CAAO,MAgDa,CAAA,MAAA,EAhDE,WAgDF,CAAA;;cA/CzB,WA+CkB,kBAAA,OAAA,EAAA,QAAA,kBAAA,CAAA;AAClB,cA9CY,MAAA,SAAe,WAAA,CA8C3B;cA5CY,gCAA4B,KAAA,CAAA,MAAA;UAiBxB,gBAAA;8DAIX,MAAA,CAAO,eAAe;EAyBf,SAAO,SAAA,EAAA,CAAQ,KAAA,EAAA,MAAiD,EAAA,IAAA,EAAA,MAAA,EAAA,GArBvE,MAAA,CAAO,MAqBgE,CAAA,SAAA,MAAA,EAAA,EArBtC,WAqBsC,CAAA;EAEhE,SAAA,QAiDZ,EAAA,CAAA,KAjDwC,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,GAfnC,MAAA,CAAO,MAe4B,CAAA,IAAA,EAff,WAee,CAAA;EAuD7B,SAAA,SAAQ,EAAA,CAAA,KAA6B,EAAA,MAAA,EAAA,IAAA,EAA1B,MAAA,EAAO,MAAO,EAAA,MAAI,EAAA,EAAA,GAjEnC,MAAA,CAAO,MAiE4B,CAAA,IAAA,EAjEf,WAiEe,CAAA;EAE5B,SAAA,UAUV,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA;IARc,WAAA,CAAA,EAAA,MAAA;IAAU,QAAA,CAAA,EAAA,MAAA;EAAxB,CAAA,EAAA,GAhEG,MAAA,CAAO,MAgEH,CAAA,IAAA,EAhEgB,WAgEhB,CAAA;;cA/DT;cAEY,MAAA,SAAe,WAAA;cAEf,gCAA4B,KAAA,CAAA,MAAA;KAuD7B,QAAA,GAAW,MAAA,CAAO,MAAA,CAAO,YAAY;cAEpC,gCAEV,MAAA,CAAO,OAAO,UAAU"}
package/lib/services.js CHANGED
@@ -16,6 +16,13 @@ var GitHub = class extends Context.Tag("GitHub")() {};
16
16
  const GitHubLive = (token) => {
17
17
  const client = new GitHubClient(token);
18
18
  return Layer.succeed(GitHub, {
19
+ getDefaultBranch: (owner, repo) => Effect.tryPromise({
20
+ catch: (error) => new GitHubError({
21
+ endpoint: `repos/${owner}/${repo}`,
22
+ message: error instanceof Error ? error.message : String(error)
23
+ }),
24
+ try: () => client.getDefaultBranch(owner, repo)
25
+ }),
19
26
  getTopics: (owner, repo) => Effect.tryPromise({
20
27
  catch: (error) => new GitHubError({
21
28
  endpoint: `repos/${owner}/${repo}/topics`,
@@ -1 +1 @@
1
- {"version":3,"file":"services.js","names":["GeminiClient"],"sources":["../src/services.ts"],"sourcesContent":["/**\n *\n * Copyright 2026 Mike Odnis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport type { Schema } from \"effect\";\nimport { Context, Effect, Layer } from \"effect\";\n\nimport { GeminiError, GitHubError, GitIngestError } from \"./errors.js\";\nimport { GeminiService as GeminiClient } from \"./utils/gemini.js\";\nimport { GitHubClient } from \"./utils/github.js\";\nimport {\n\tfetchRepositoryContent,\n\ttype GitIngestResponse,\n} from \"./utils/gitingest.js\";\n\n// ============================================================================\n// Gemini Service\n// ============================================================================\n\nexport interface GeminiServiceApi {\n\treadonly generateContent: (\n\t\tprompt: string,\n\t) => Effect.Effect<string, GeminiError>;\n}\n\nexport class Gemini extends Context.Tag(\"Gemini\")<Gemini, GeminiServiceApi>() {}\n\nexport const GeminiLive = (apiKey: string) =>\n\tLayer.succeed(Gemini, {\n\t\tgenerateContent: (prompt: string) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\tcatch: (error) =>\n\t\t\t\t\tnew GeminiError({\n\t\t\t\t\t\tcause: error,\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t}),\n\t\t\t\ttry: () => new GeminiClient(apiKey).generateContent(prompt),\n\t\t\t}),\n\t});\n\n// ============================================================================\n// GitHub Service\n// ============================================================================\n\nexport interface GitHubServiceApi {\n\treadonly getTopics: (\n\t\towner: string,\n\t\trepo: string,\n\t) => Effect.Effect<readonly string[], GitHubError>;\n\treadonly pushFile: (\n\t\towner: string,\n\t\trepo: string,\n\t\tpath: string,\n\t\tcontent: string,\n\t\tmessage: string,\n\t\tbranch: string,\n\t) => Effect.Effect<void, GitHubError>;\n\treadonly setTopics: (\n\t\towner: string,\n\t\trepo: string,\n\t\ttopics: string[],\n\t) => Effect.Effect<void, GitHubError>;\n\treadonly updateRepo: (\n\t\towner: string,\n\t\trepo: string,\n\t\tdata: { description?: string; homepage?: string },\n\t) => Effect.Effect<void, GitHubError>;\n}\n\nexport class GitHub extends Context.Tag(\"GitHub\")<GitHub, GitHubServiceApi>() {}\n\nexport const GitHubLive = (token?: string) => {\n\tconst client = new GitHubClient(token);\n\treturn Layer.succeed(GitHub, {\n\t\tgetTopics: (owner, repo) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\tcatch: (error) =>\n\t\t\t\t\tnew GitHubError({\n\t\t\t\t\t\tendpoint: `repos/${owner}/${repo}/topics`,\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t}),\n\t\t\t\ttry: () => client.getTopics(owner, repo),\n\t\t\t}),\n\t\tpushFile: (owner, repo, path, content, message, branch) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\tcatch: (error) =>\n\t\t\t\t\tnew GitHubError({\n\t\t\t\t\t\tendpoint: `repos/${owner}/${repo}/contents/${path}`,\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t}),\n\t\t\t\ttry: () => client.pushFile(owner, repo, path, content, message, branch),\n\t\t\t}),\n\t\tsetTopics: (owner, repo, topics) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\tcatch: (error) =>\n\t\t\t\t\tnew GitHubError({\n\t\t\t\t\t\tendpoint: `repos/${owner}/${repo}/topics`,\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t}),\n\t\t\t\ttry: () => client.setTopics(owner, repo, topics),\n\t\t\t}),\n\t\tupdateRepo: (owner, repo, data) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\tcatch: (error) =>\n\t\t\t\t\tnew GitHubError({\n\t\t\t\t\t\tendpoint: `repos/${owner}/${repo}`,\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t}),\n\t\t\t\ttry: () => client.updateRepo(owner, repo, data),\n\t\t\t}),\n\t});\n};\n\n// ============================================================================\n// GitIngest Service\n// ============================================================================\n\nexport type RepoData = Schema.Schema.Type<typeof GitIngestResponse>;\n\nexport const fetchRepo = (\n\trepoUrl: string,\n): Effect.Effect<RepoData, GitIngestError> =>\n\tEffect.tryPromise({\n\t\tcatch: (error) =>\n\t\t\tnew GitIngestError({\n\t\t\t\tcause: error,\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t}),\n\t\ttry: () => fetchRepositoryContent(repoUrl),\n\t});\n"],"mappings":";;;;;;AAuCA,IAAa,SAAb,cAA4B,QAAQ,IAAI,SAAS,EAA4B,CAAC;AAE9E,MAAa,cAAc,WAC1B,MAAM,QAAQ,QAAQ,EACrB,kBAAkB,WACjB,OAAO,WAAW;CACjB,QAAQ,UACP,IAAI,YAAY;EACf,OAAO;EACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;EAC/D,CAAC;CACH,WAAW,IAAIA,cAAa,OAAO,CAAC,gBAAgB,OAAO;CAC3D,CAAC,EACH,CAAC;AA+BH,IAAa,SAAb,cAA4B,QAAQ,IAAI,SAAS,EAA4B,CAAC;AAE9E,MAAa,cAAc,UAAmB;CAC7C,MAAM,SAAS,IAAI,aAAa,MAAM;AACtC,QAAO,MAAM,QAAQ,QAAQ;EAC5B,YAAY,OAAO,SAClB,OAAO,WAAW;GACjB,QAAQ,UACP,IAAI,YAAY;IACf,UAAU,SAAS,MAAM,GAAG,KAAK;IACjC,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC/D,CAAC;GACH,WAAW,OAAO,UAAU,OAAO,KAAK;GACxC,CAAC;EACH,WAAW,OAAO,MAAM,MAAM,SAAS,SAAS,WAC/C,OAAO,WAAW;GACjB,QAAQ,UACP,IAAI,YAAY;IACf,UAAU,SAAS,MAAM,GAAG,KAAK,YAAY;IAC7C,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC/D,CAAC;GACH,WAAW,OAAO,SAAS,OAAO,MAAM,MAAM,SAAS,SAAS,OAAO;GACvE,CAAC;EACH,YAAY,OAAO,MAAM,WACxB,OAAO,WAAW;GACjB,QAAQ,UACP,IAAI,YAAY;IACf,UAAU,SAAS,MAAM,GAAG,KAAK;IACjC,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC/D,CAAC;GACH,WAAW,OAAO,UAAU,OAAO,MAAM,OAAO;GAChD,CAAC;EACH,aAAa,OAAO,MAAM,SACzB,OAAO,WAAW;GACjB,QAAQ,UACP,IAAI,YAAY;IACf,UAAU,SAAS,MAAM,GAAG;IAC5B,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC/D,CAAC;GACH,WAAW,OAAO,WAAW,OAAO,MAAM,KAAK;GAC/C,CAAC;EACH,CAAC;;AASH,MAAa,aACZ,YAEA,OAAO,WAAW;CACjB,QAAQ,UACP,IAAI,eAAe;EAClB,OAAO;EACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;EAC/D,CAAC;CACH,WAAW,uBAAuB,QAAQ;CAC1C,CAAC"}
1
+ {"version":3,"file":"services.js","names":["GeminiClient"],"sources":["../src/services.ts"],"sourcesContent":["/**\n *\n * Copyright 2026 Mike Odnis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport type { Schema } from \"effect\";\nimport { Context, Effect, Layer } from \"effect\";\n\nimport { GeminiError, GitHubError, GitIngestError } from \"./errors.js\";\nimport { GeminiService as GeminiClient } from \"./utils/gemini.js\";\nimport { GitHubClient } from \"./utils/github.js\";\nimport {\n\tfetchRepositoryContent,\n\ttype GitIngestResponse,\n} from \"./utils/gitingest.js\";\n\n// ============================================================================\n// Gemini Service\n// ============================================================================\n\nexport interface GeminiServiceApi {\n\treadonly generateContent: (\n\t\tprompt: string,\n\t) => Effect.Effect<string, GeminiError>;\n}\n\nexport class Gemini extends Context.Tag(\"Gemini\")<Gemini, GeminiServiceApi>() {}\n\nexport const GeminiLive = (apiKey: string) =>\n\tLayer.succeed(Gemini, {\n\t\tgenerateContent: (prompt: string) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\tcatch: (error) =>\n\t\t\t\t\tnew GeminiError({\n\t\t\t\t\t\tcause: error,\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t}),\n\t\t\t\ttry: () => new GeminiClient(apiKey).generateContent(prompt),\n\t\t\t}),\n\t});\n\n// ============================================================================\n// GitHub Service\n// ============================================================================\n\nexport interface GitHubServiceApi {\n\treadonly getDefaultBranch: (\n\t\towner: string,\n\t\trepo: string,\n\t) => Effect.Effect<string, GitHubError>;\n\treadonly getTopics: (\n\t\towner: string,\n\t\trepo: string,\n\t) => Effect.Effect<readonly string[], GitHubError>;\n\treadonly pushFile: (\n\t\towner: string,\n\t\trepo: string,\n\t\tpath: string,\n\t\tcontent: string,\n\t\tmessage: string,\n\t\tbranch: string,\n\t) => Effect.Effect<void, GitHubError>;\n\treadonly setTopics: (\n\t\towner: string,\n\t\trepo: string,\n\t\ttopics: string[],\n\t) => Effect.Effect<void, GitHubError>;\n\treadonly updateRepo: (\n\t\towner: string,\n\t\trepo: string,\n\t\tdata: { description?: string; homepage?: string },\n\t) => Effect.Effect<void, GitHubError>;\n}\n\nexport class GitHub extends Context.Tag(\"GitHub\")<GitHub, GitHubServiceApi>() {}\n\nexport const GitHubLive = (token?: string) => {\n\tconst client = new GitHubClient(token);\n\treturn Layer.succeed(GitHub, {\n\t\tgetDefaultBranch: (owner, repo) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\tcatch: (error) =>\n\t\t\t\t\tnew GitHubError({\n\t\t\t\t\t\tendpoint: `repos/${owner}/${repo}`,\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t}),\n\t\t\t\ttry: () => client.getDefaultBranch(owner, repo),\n\t\t\t}),\n\t\tgetTopics: (owner, repo) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\tcatch: (error) =>\n\t\t\t\t\tnew GitHubError({\n\t\t\t\t\t\tendpoint: `repos/${owner}/${repo}/topics`,\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t}),\n\t\t\t\ttry: () => client.getTopics(owner, repo),\n\t\t\t}),\n\t\tpushFile: (owner, repo, path, content, message, branch) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\tcatch: (error) =>\n\t\t\t\t\tnew GitHubError({\n\t\t\t\t\t\tendpoint: `repos/${owner}/${repo}/contents/${path}`,\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t}),\n\t\t\t\ttry: () => client.pushFile(owner, repo, path, content, message, branch),\n\t\t\t}),\n\t\tsetTopics: (owner, repo, topics) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\tcatch: (error) =>\n\t\t\t\t\tnew GitHubError({\n\t\t\t\t\t\tendpoint: `repos/${owner}/${repo}/topics`,\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t}),\n\t\t\t\ttry: () => client.setTopics(owner, repo, topics),\n\t\t\t}),\n\t\tupdateRepo: (owner, repo, data) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\tcatch: (error) =>\n\t\t\t\t\tnew GitHubError({\n\t\t\t\t\t\tendpoint: `repos/${owner}/${repo}`,\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t}),\n\t\t\t\ttry: () => client.updateRepo(owner, repo, data),\n\t\t\t}),\n\t});\n};\n\n// ============================================================================\n// GitIngest Service\n// ============================================================================\n\nexport type RepoData = Schema.Schema.Type<typeof GitIngestResponse>;\n\nexport const fetchRepo = (\n\trepoUrl: string,\n): Effect.Effect<RepoData, GitIngestError> =>\n\tEffect.tryPromise({\n\t\tcatch: (error) =>\n\t\t\tnew GitIngestError({\n\t\t\t\tcause: error,\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t}),\n\t\ttry: () => fetchRepositoryContent(repoUrl),\n\t});\n"],"mappings":";;;;;;AAuCA,IAAa,SAAb,cAA4B,QAAQ,IAAI,SAAS,EAA4B,CAAC;AAE9E,MAAa,cAAc,WAC1B,MAAM,QAAQ,QAAQ,EACrB,kBAAkB,WACjB,OAAO,WAAW;CACjB,QAAQ,UACP,IAAI,YAAY;EACf,OAAO;EACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;EAC/D,CAAC;CACH,WAAW,IAAIA,cAAa,OAAO,CAAC,gBAAgB,OAAO;CAC3D,CAAC,EACH,CAAC;AAmCH,IAAa,SAAb,cAA4B,QAAQ,IAAI,SAAS,EAA4B,CAAC;AAE9E,MAAa,cAAc,UAAmB;CAC7C,MAAM,SAAS,IAAI,aAAa,MAAM;AACtC,QAAO,MAAM,QAAQ,QAAQ;EAC5B,mBAAmB,OAAO,SACzB,OAAO,WAAW;GACjB,QAAQ,UACP,IAAI,YAAY;IACf,UAAU,SAAS,MAAM,GAAG;IAC5B,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC/D,CAAC;GACH,WAAW,OAAO,iBAAiB,OAAO,KAAK;GAC/C,CAAC;EACH,YAAY,OAAO,SAClB,OAAO,WAAW;GACjB,QAAQ,UACP,IAAI,YAAY;IACf,UAAU,SAAS,MAAM,GAAG,KAAK;IACjC,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC/D,CAAC;GACH,WAAW,OAAO,UAAU,OAAO,KAAK;GACxC,CAAC;EACH,WAAW,OAAO,MAAM,MAAM,SAAS,SAAS,WAC/C,OAAO,WAAW;GACjB,QAAQ,UACP,IAAI,YAAY;IACf,UAAU,SAAS,MAAM,GAAG,KAAK,YAAY;IAC7C,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC/D,CAAC;GACH,WAAW,OAAO,SAAS,OAAO,MAAM,MAAM,SAAS,SAAS,OAAO;GACvE,CAAC;EACH,YAAY,OAAO,MAAM,WACxB,OAAO,WAAW;GACjB,QAAQ,UACP,IAAI,YAAY;IACf,UAAU,SAAS,MAAM,GAAG,KAAK;IACjC,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC/D,CAAC;GACH,WAAW,OAAO,UAAU,OAAO,MAAM,OAAO;GAChD,CAAC;EACH,aAAa,OAAO,MAAM,SACzB,OAAO,WAAW;GACjB,QAAQ,UACP,IAAI,YAAY;IACf,UAAU,SAAS,MAAM,GAAG;IAC5B,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC/D,CAAC;GACH,WAAW,OAAO,WAAW,OAAO,MAAM,KAAK;GAC/C,CAAC;EACH,CAAC;;AASH,MAAa,aACZ,YAEA,OAAO,WAAW;CACjB,QAAQ,UACP,IAAI,eAAe;EAClB,OAAO;EACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;EAC/D,CAAC;CACH,WAAW,uBAAuB,QAAQ;CAC1C,CAAC"}
@@ -18,6 +18,7 @@ declare class GitHubClient {
18
18
  pushFile(owner: string, repo: string, path: string, content: string, message: string, branch: string): Promise<void>;
19
19
  getTopics(owner: string, repo: string): Promise<readonly string[]>;
20
20
  setTopics(owner: string, repo: string, topics: string[]): Promise<void>;
21
+ getDefaultBranch(owner: string, repo: string): Promise<string>;
21
22
  updateRepo(owner: string, repo: string, data: {
22
23
  description?: string;
23
24
  homepage?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"github.d.ts","names":[],"sources":["../../src/utils/github.ts"],"sourcesContent":[],"mappings":";;;;AA0II,cA/GS,iBA+GT,EA/G0B,MAAA,CAAA,MA+G1B,CAAA;EA0BA,OAAA,EAAA,oBAAA;EAAO,QAAA,EAAA,oBAAA;;;;;;cAhIE,YAAA;;;;sDAkBT,QAAQ,MAAA,CAAO,MAAA,CAAO,YAAY;yGAmClC;0CA6B2C;4DAoB3C;;;;MA0BA"}
1
+ {"version":3,"file":"github.d.ts","names":[],"sources":["../../src/utils/github.ts"],"sourcesContent":[],"mappings":";;;;AA0II,cA/GS,iBA+GT,EA/G0B,MAAA,CAAA,MA+G1B,CAAA;EAsBkD,OAAA,EAAA,oBAAA;EAoBlD,QAAA,EAAA,oBAAA;EAAO,IAAA,EAAA,oBAAA;;;;;cAhJE,YAAA;;;;sDAkBT,QAAQ,MAAA,CAAO,MAAA,CAAO,YAAY;yGAmClC;0CA6B2C;4DAoB3C;iDAsBkD;;;;MAoBlD"}
@@ -80,6 +80,13 @@ var GitHubClient = class {
80
80
  "Content-Type": "application/json"
81
81
  } }), FetchHttpClient.layer));
82
82
  }
83
+ async getDefaultBranch(owner, repo) {
84
+ const RepoResponse = Schema.Struct({ default_branch: Schema.String });
85
+ return (await Effect.runPromise(Effect.provide(get(`${GITHUB_API}/repos/${owner}/${repo}`, {
86
+ headers: this.headers,
87
+ schema: RepoResponse
88
+ }), FetchHttpClient.layer))).default_branch;
89
+ }
83
90
  async updateRepo(owner, repo, data) {
84
91
  if (!this.token) throw new Error("GitHub token is required for updating repository");
85
92
  await Effect.runPromise(Effect.provide(patch(`${GITHUB_API}/repos/${owner}/${repo}`, data, { headers: {
@@ -1 +1 @@
1
- {"version":3,"file":"github.js","names":[],"sources":["../../src/utils/github.ts"],"sourcesContent":["/**\n *\n * Copyright 2026 Mike Odnis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport * as FetchHttpClient from \"@effect/platform/FetchHttpClient\";\nimport { Effect, Schema } from \"effect\";\n\nimport { get, patch, put } from \"./fetcher.js\";\nimport { ApiError } from \"./validation.js\";\n\nconst GITHUB_API = \"https://api.github.com\" as const;\nconst GITHUB_API_VERSION = \"2022-11-28\" as const;\n\nexport const GitHubFileContent = Schema.Struct({\n\tcontent: Schema.String,\n\tencoding: Schema.String,\n\tname: Schema.String,\n\tpath: Schema.String,\n\tsha: Schema.String,\n\tsize: Schema.Number,\n});\n\nexport class GitHubClient {\n\tconstructor(private readonly token?: string) {}\n\n\tprivate get headers(): Record<string, string> {\n\t\tconst headers: Record<string, string> = {\n\t\t\tAccept: \"application/vnd.github+json\",\n\t\t\t\"X-GitHub-Api-Version\": GITHUB_API_VERSION,\n\t\t};\n\t\tif (this.token) {\n\t\t\theaders.Authorization = `Bearer ${this.token}`;\n\t\t}\n\t\treturn headers;\n\t}\n\n\tasync getFile(\n\t\towner: string,\n\t\trepo: string,\n\t\tpath: string,\n\t): Promise<Schema.Schema.Type<typeof GitHubFileContent> | null> {\n\t\ttry {\n\t\t\treturn Effect.runPromise(\n\t\t\t\tEffect.provide(\n\t\t\t\t\tget(`${GITHUB_API}/repos/${owner}/${repo}/contents/${path}`, {\n\t\t\t\t\t\theaders: this.headers,\n\t\t\t\t\t\tschema: GitHubFileContent,\n\t\t\t\t\t}),\n\t\t\t\t\tFetchHttpClient.layer,\n\t\t\t\t),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (\n\t\t\t\terror &&\n\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\"status\" in error &&\n\t\t\t\terror.status === 404\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tthrow new ApiError(\n\t\t\t\t`GitHub API error: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\tundefined,\n\t\t\t\t\"GitHub API\",\n\t\t\t);\n\t\t}\n\t}\n\n\tasync pushFile(\n\t\towner: string,\n\t\trepo: string,\n\t\tpath: string,\n\t\tcontent: string,\n\t\tmessage: string,\n\t\tbranch: string,\n\t): Promise<void> {\n\t\tif (!this.token) {\n\t\t\tthrow new Error(\"GitHub token is required for push operations\");\n\t\t}\n\n\t\tconst existingFile = await this.getFile(owner, repo, path);\n\n\t\tawait Effect.runPromise(\n\t\t\tEffect.provide(\n\t\t\t\tput(\n\t\t\t\t\t`${GITHUB_API}/repos/${owner}/${repo}/contents/${path}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tbranch,\n\t\t\t\t\t\tcontent: Buffer.from(content).toString(\"base64\"),\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t...(existingFile && { sha: existingFile.sha }),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t...this.headers,\n\t\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tFetchHttpClient.layer,\n\t\t\t),\n\t\t);\n\t}\n\n\tasync getTopics(owner: string, repo: string): Promise<readonly string[]> {\n\t\tconst TopicsResponse = Schema.Struct({\n\t\t\tnames: Schema.Array(Schema.String),\n\t\t});\n\t\tconst result = await Effect.runPromise(\n\t\t\tEffect.provide(\n\t\t\t\tget(`${GITHUB_API}/repos/${owner}/${repo}/topics`, {\n\t\t\t\t\theaders: this.headers,\n\t\t\t\t\tschema: TopicsResponse,\n\t\t\t\t}),\n\t\t\t\tFetchHttpClient.layer,\n\t\t\t),\n\t\t);\n\t\treturn result.names;\n\t}\n\n\tasync setTopics(\n\t\towner: string,\n\t\trepo: string,\n\t\ttopics: string[],\n\t): Promise<void> {\n\t\tif (!this.token) {\n\t\t\tthrow new Error(\"GitHub token is required for setting topics\");\n\t\t}\n\n\t\tawait Effect.runPromise(\n\t\t\tEffect.provide(\n\t\t\t\tput(\n\t\t\t\t\t`${GITHUB_API}/repos/${owner}/${repo}/topics`,\n\t\t\t\t\t{ names: topics },\n\t\t\t\t\t{\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t...this.headers,\n\t\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tFetchHttpClient.layer,\n\t\t\t),\n\t\t);\n\t}\n\n\tasync updateRepo(\n\t\towner: string,\n\t\trepo: string,\n\t\tdata: { description?: string; homepage?: string },\n\t): Promise<void> {\n\t\tif (!this.token) {\n\t\t\tthrow new Error(\"GitHub token is required for updating repository\");\n\t\t}\n\n\t\tawait Effect.runPromise(\n\t\t\tEffect.provide(\n\t\t\t\tpatch(`${GITHUB_API}/repos/${owner}/${repo}`, data, {\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t...this.headers,\n\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tFetchHttpClient.layer,\n\t\t\t),\n\t\t);\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,aAAa;AACnB,MAAM,qBAAqB;AAE3B,MAAa,oBAAoB,OAAO,OAAO;CAC9C,SAAS,OAAO;CAChB,UAAU,OAAO;CACjB,MAAM,OAAO;CACb,MAAM,OAAO;CACb,KAAK,OAAO;CACZ,MAAM,OAAO;CACb,CAAC;AAEF,IAAa,eAAb,MAA0B;CACzB,YAAY,OAAiC;AAAhB,OAAA,QAAA;;CAE7B,IAAY,UAAkC;EAC7C,MAAM,UAAkC;GACvC,QAAQ;GACR,wBAAwB;GACxB;AACD,MAAI,KAAK,MACR,SAAQ,gBAAgB,UAAU,KAAK;AAExC,SAAO;;CAGR,MAAM,QACL,OACA,MACA,MAC+D;AAC/D,MAAI;AACH,UAAO,OAAO,WACb,OAAO,QACN,IAAI,GAAG,WAAW,SAAS,MAAM,GAAG,KAAK,YAAY,QAAQ;IAC5D,SAAS,KAAK;IACd,QAAQ;IACR,CAAC,EACF,gBAAgB,MAChB,CACD;WACO,OAAO;AACf,OACC,SACA,OAAO,UAAU,YACjB,YAAY,SACZ,MAAM,WAAW,IAEjB,QAAO;AAER,SAAM,IAAI,SACT,qBAAqB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IAC3E,KAAA,GACA,aACA;;;CAIH,MAAM,SACL,OACA,MACA,MACA,SACA,SACA,QACgB;AAChB,MAAI,CAAC,KAAK,MACT,OAAM,IAAI,MAAM,+CAA+C;EAGhE,MAAM,eAAe,MAAM,KAAK,QAAQ,OAAO,MAAM,KAAK;AAE1D,QAAM,OAAO,WACZ,OAAO,QACN,IACC,GAAG,WAAW,SAAS,MAAM,GAAG,KAAK,YAAY,QACjD;GACC;GACA,SAAS,OAAO,KAAK,QAAQ,CAAC,SAAS,SAAS;GAChD;GACA,GAAI,gBAAgB,EAAE,KAAK,aAAa,KAAK;GAC7C,EACD,EACC,SAAS;GACR,GAAG,KAAK;GACR,gBAAgB;GAChB,EACD,CACD,EACD,gBAAgB,MAChB,CACD;;CAGF,MAAM,UAAU,OAAe,MAA0C;EACxE,MAAM,iBAAiB,OAAO,OAAO,EACpC,OAAO,OAAO,MAAM,OAAO,OAAO,EAClC,CAAC;AAUF,UATe,MAAM,OAAO,WAC3B,OAAO,QACN,IAAI,GAAG,WAAW,SAAS,MAAM,GAAG,KAAK,UAAU;GAClD,SAAS,KAAK;GACd,QAAQ;GACR,CAAC,EACF,gBAAgB,MAChB,CACD,EACa;;CAGf,MAAM,UACL,OACA,MACA,QACgB;AAChB,MAAI,CAAC,KAAK,MACT,OAAM,IAAI,MAAM,8CAA8C;AAG/D,QAAM,OAAO,WACZ,OAAO,QACN,IACC,GAAG,WAAW,SAAS,MAAM,GAAG,KAAK,UACrC,EAAE,OAAO,QAAQ,EACjB,EACC,SAAS;GACR,GAAG,KAAK;GACR,gBAAgB;GAChB,EACD,CACD,EACD,gBAAgB,MAChB,CACD;;CAGF,MAAM,WACL,OACA,MACA,MACgB;AAChB,MAAI,CAAC,KAAK,MACT,OAAM,IAAI,MAAM,mDAAmD;AAGpE,QAAM,OAAO,WACZ,OAAO,QACN,MAAM,GAAG,WAAW,SAAS,MAAM,GAAG,QAAQ,MAAM,EACnD,SAAS;GACR,GAAG,KAAK;GACR,gBAAgB;GAChB,EACD,CAAC,EACF,gBAAgB,MAChB,CACD"}
1
+ {"version":3,"file":"github.js","names":[],"sources":["../../src/utils/github.ts"],"sourcesContent":["/**\n *\n * Copyright 2026 Mike Odnis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport * as FetchHttpClient from \"@effect/platform/FetchHttpClient\";\nimport { Effect, Schema } from \"effect\";\n\nimport { get, patch, put } from \"./fetcher.js\";\nimport { ApiError } from \"./validation.js\";\n\nconst GITHUB_API = \"https://api.github.com\" as const;\nconst GITHUB_API_VERSION = \"2022-11-28\" as const;\n\nexport const GitHubFileContent = Schema.Struct({\n\tcontent: Schema.String,\n\tencoding: Schema.String,\n\tname: Schema.String,\n\tpath: Schema.String,\n\tsha: Schema.String,\n\tsize: Schema.Number,\n});\n\nexport class GitHubClient {\n\tconstructor(private readonly token?: string) {}\n\n\tprivate get headers(): Record<string, string> {\n\t\tconst headers: Record<string, string> = {\n\t\t\tAccept: \"application/vnd.github+json\",\n\t\t\t\"X-GitHub-Api-Version\": GITHUB_API_VERSION,\n\t\t};\n\t\tif (this.token) {\n\t\t\theaders.Authorization = `Bearer ${this.token}`;\n\t\t}\n\t\treturn headers;\n\t}\n\n\tasync getFile(\n\t\towner: string,\n\t\trepo: string,\n\t\tpath: string,\n\t): Promise<Schema.Schema.Type<typeof GitHubFileContent> | null> {\n\t\ttry {\n\t\t\treturn Effect.runPromise(\n\t\t\t\tEffect.provide(\n\t\t\t\t\tget(`${GITHUB_API}/repos/${owner}/${repo}/contents/${path}`, {\n\t\t\t\t\t\theaders: this.headers,\n\t\t\t\t\t\tschema: GitHubFileContent,\n\t\t\t\t\t}),\n\t\t\t\t\tFetchHttpClient.layer,\n\t\t\t\t),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (\n\t\t\t\terror &&\n\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\"status\" in error &&\n\t\t\t\terror.status === 404\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tthrow new ApiError(\n\t\t\t\t`GitHub API error: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\tundefined,\n\t\t\t\t\"GitHub API\",\n\t\t\t);\n\t\t}\n\t}\n\n\tasync pushFile(\n\t\towner: string,\n\t\trepo: string,\n\t\tpath: string,\n\t\tcontent: string,\n\t\tmessage: string,\n\t\tbranch: string,\n\t): Promise<void> {\n\t\tif (!this.token) {\n\t\t\tthrow new Error(\"GitHub token is required for push operations\");\n\t\t}\n\n\t\tconst existingFile = await this.getFile(owner, repo, path);\n\n\t\tawait Effect.runPromise(\n\t\t\tEffect.provide(\n\t\t\t\tput(\n\t\t\t\t\t`${GITHUB_API}/repos/${owner}/${repo}/contents/${path}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tbranch,\n\t\t\t\t\t\tcontent: Buffer.from(content).toString(\"base64\"),\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t...(existingFile && { sha: existingFile.sha }),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t...this.headers,\n\t\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tFetchHttpClient.layer,\n\t\t\t),\n\t\t);\n\t}\n\n\tasync getTopics(owner: string, repo: string): Promise<readonly string[]> {\n\t\tconst TopicsResponse = Schema.Struct({\n\t\t\tnames: Schema.Array(Schema.String),\n\t\t});\n\t\tconst result = await Effect.runPromise(\n\t\t\tEffect.provide(\n\t\t\t\tget(`${GITHUB_API}/repos/${owner}/${repo}/topics`, {\n\t\t\t\t\theaders: this.headers,\n\t\t\t\t\tschema: TopicsResponse,\n\t\t\t\t}),\n\t\t\t\tFetchHttpClient.layer,\n\t\t\t),\n\t\t);\n\t\treturn result.names;\n\t}\n\n\tasync setTopics(\n\t\towner: string,\n\t\trepo: string,\n\t\ttopics: string[],\n\t): Promise<void> {\n\t\tif (!this.token) {\n\t\t\tthrow new Error(\"GitHub token is required for setting topics\");\n\t\t}\n\n\t\tawait Effect.runPromise(\n\t\t\tEffect.provide(\n\t\t\t\tput(\n\t\t\t\t\t`${GITHUB_API}/repos/${owner}/${repo}/topics`,\n\t\t\t\t\t{ names: topics },\n\t\t\t\t\t{\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t...this.headers,\n\t\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tFetchHttpClient.layer,\n\t\t\t),\n\t\t);\n\t}\n\n\tasync getDefaultBranch(owner: string, repo: string): Promise<string> {\n\t\tconst RepoResponse = Schema.Struct({\n\t\t\tdefault_branch: Schema.String,\n\t\t});\n\t\tconst result = await Effect.runPromise(\n\t\t\tEffect.provide(\n\t\t\t\tget(`${GITHUB_API}/repos/${owner}/${repo}`, {\n\t\t\t\t\theaders: this.headers,\n\t\t\t\t\tschema: RepoResponse,\n\t\t\t\t}),\n\t\t\t\tFetchHttpClient.layer,\n\t\t\t),\n\t\t);\n\t\treturn result.default_branch;\n\t}\n\n\tasync updateRepo(\n\t\towner: string,\n\t\trepo: string,\n\t\tdata: { description?: string; homepage?: string },\n\t): Promise<void> {\n\t\tif (!this.token) {\n\t\t\tthrow new Error(\"GitHub token is required for updating repository\");\n\t\t}\n\n\t\tawait Effect.runPromise(\n\t\t\tEffect.provide(\n\t\t\t\tpatch(`${GITHUB_API}/repos/${owner}/${repo}`, data, {\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t...this.headers,\n\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tFetchHttpClient.layer,\n\t\t\t),\n\t\t);\n\t}\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elysiumoss/grepo",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "AI-powered GitHub repository management CLI โ€” generate READMEs, topics, descriptions, and more using Gemini",
5
5
  "keywords": [
6
6
  "ai",