@elysiumoss/grepo 0.2.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.
Files changed (72) hide show
  1. package/LICENSE.md +20 -0
  2. package/README.md +61 -0
  3. package/lib/cli.d.ts +1 -0
  4. package/lib/cli.js +84 -0
  5. package/lib/cli.js.map +1 -0
  6. package/lib/commands/analyze.d.ts +11 -0
  7. package/lib/commands/analyze.d.ts.map +1 -0
  8. package/lib/commands/analyze.js +49 -0
  9. package/lib/commands/analyze.js.map +1 -0
  10. package/lib/commands/describe.d.ts +11 -0
  11. package/lib/commands/describe.d.ts.map +1 -0
  12. package/lib/commands/describe.js +89 -0
  13. package/lib/commands/describe.js.map +1 -0
  14. package/lib/commands/readme.d.ts +11 -0
  15. package/lib/commands/readme.d.ts.map +1 -0
  16. package/lib/commands/readme.js +69 -0
  17. package/lib/commands/readme.js.map +1 -0
  18. package/lib/commands/topics.d.ts +11 -0
  19. package/lib/commands/topics.d.ts.map +1 -0
  20. package/lib/commands/topics.js +74 -0
  21. package/lib/commands/topics.js.map +1 -0
  22. package/lib/config.d.ts +31 -0
  23. package/lib/config.d.ts.map +1 -0
  24. package/lib/config.js +149 -0
  25. package/lib/config.js.map +1 -0
  26. package/lib/errors.d.ts +55 -0
  27. package/lib/errors.d.ts.map +1 -0
  28. package/lib/errors.js +27 -0
  29. package/lib/errors.js.map +1 -0
  30. package/lib/index.d.ts +14 -0
  31. package/lib/index.js +14 -0
  32. package/lib/mermaid.d.ts +17 -0
  33. package/lib/mermaid.d.ts.map +1 -0
  34. package/lib/mermaid.js +132 -0
  35. package/lib/mermaid.js.map +1 -0
  36. package/lib/prompts/readme.d.ts +90 -0
  37. package/lib/prompts/readme.d.ts.map +1 -0
  38. package/lib/prompts/readme.js +345 -0
  39. package/lib/prompts/readme.js.map +1 -0
  40. package/lib/services.d.ts +29 -0
  41. package/lib/services.d.ts.map +1 -0
  42. package/lib/services.js +59 -0
  43. package/lib/services.js.map +1 -0
  44. package/lib/utils/args.d.ts +15 -0
  45. package/lib/utils/args.d.ts.map +1 -0
  46. package/lib/utils/args.js +70 -0
  47. package/lib/utils/args.js.map +1 -0
  48. package/lib/utils/fetcher.d.ts +44 -0
  49. package/lib/utils/fetcher.d.ts.map +1 -0
  50. package/lib/utils/fetcher.js +173 -0
  51. package/lib/utils/fetcher.js.map +1 -0
  52. package/lib/utils/gemini.d.ts +25 -0
  53. package/lib/utils/gemini.d.ts.map +1 -0
  54. package/lib/utils/gemini.js +108 -0
  55. package/lib/utils/gemini.js.map +1 -0
  56. package/lib/utils/github.d.ts +28 -0
  57. package/lib/utils/github.d.ts.map +1 -0
  58. package/lib/utils/github.js +94 -0
  59. package/lib/utils/github.js.map +1 -0
  60. package/lib/utils/gitingest.d.ts +19 -0
  61. package/lib/utils/gitingest.d.ts.map +1 -0
  62. package/lib/utils/gitingest.js +46 -0
  63. package/lib/utils/gitingest.js.map +1 -0
  64. package/lib/utils/logger.d.ts +47 -0
  65. package/lib/utils/logger.d.ts.map +1 -0
  66. package/lib/utils/logger.js +155 -0
  67. package/lib/utils/logger.js.map +1 -0
  68. package/lib/utils/validation.d.ts +38 -0
  69. package/lib/utils/validation.d.ts.map +1 -0
  70. package/lib/utils/validation.js +65 -0
  71. package/lib/utils/validation.js.map +1 -0
  72. package/package.json +81 -0
package/LICENSE.md ADDED
@@ -0,0 +1,20 @@
1
+ # MIT License
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ 'Software'), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ <h1 align="center">package-template</h1>
2
+
3
+ <p align="center">
4
+ A very lovely package.
5
+ Hooray!
6
+ </p>
7
+
8
+ <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" />
19
+ </p>
20
+
21
+ ## Usage
22
+
23
+ ```shell
24
+ npm i package-template
25
+ ```
26
+
27
+ ```ts
28
+ import { greet } from "package-template";
29
+
30
+ greet("Hello, world! 💖");
31
+ ```
32
+
33
+ ## Development
34
+
35
+ See [`.github/CONTRIBUTING.md`](./.github/CONTRIBUTING.md), then [`.github/DEVELOPMENT.md`](./.github/DEVELOPMENT.md).
36
+ Thanks! 💖
37
+
38
+ ## Contributors
39
+
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>
52
+
53
+ <!-- markdownlint-restore -->
54
+ <!-- prettier-ignore-end -->
55
+
56
+ <!-- ALL-CONTRIBUTORS-LIST:END -->
57
+ <!-- spellchecker: enable -->
58
+
59
+ <!-- You can remove this notice if you don't want it 🙂 no worries! -->
60
+
61
+ > 💝 This package was templated with [`create-typescript-app`](https://github.com/JoshuaKGoldberg/create-typescript-app) using the [Bingo framework](https://create.bingo).
package/lib/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/lib/cli.js ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ import { buildConfig, loadEnv } from "./config.js";
3
+ import { Logger as Logger$1 } from "./utils/logger.js";
4
+ import { GeminiLive, GitHubLive } from "./services.js";
5
+ import { Effect, Layer } from "effect";
6
+ //#region src/cli.ts
7
+ /**
8
+ *
9
+ * Copyright 2026 Mike Odnis
10
+ *
11
+ * Licensed under the Apache License, Version 2.0 (the "License");
12
+ * you may not use this file except in compliance with the License.
13
+ * You may obtain a copy of the License at
14
+ *
15
+ * http://www.apache.org/licenses/LICENSE-2.0
16
+ *
17
+ * Unless required by applicable law or agreed to in writing, software
18
+ * distributed under the License is distributed on an "AS IS" BASIS,
19
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+ * See the License for the specific language governing permissions and
21
+ * limitations under the License.
22
+ *
23
+ */
24
+ const logger = new Logger$1("GREPO");
25
+ await loadEnv();
26
+ const argv = process.argv.slice(2);
27
+ if (argv.length === 0) {
28
+ console.log(`Usage: grepo <command> <github-url> [options]
29
+
30
+ Commands:
31
+ readme Generate README documentation
32
+ topics Generate and apply repository topics
33
+ describe Generate repository description and homepage URL
34
+ summary Summarize repository
35
+ tech List technologies used
36
+ improve Suggest improvements
37
+
38
+ Run 'grepo <command> --help' for more information.`);
39
+ process.exit(0);
40
+ }
41
+ const config = buildConfig(argv);
42
+ const layers = Layer.merge(GeminiLive(config.geminiApiKey), GitHubLive(config.githubToken));
43
+ let run;
44
+ switch (config.command) {
45
+ case "readme":
46
+ run = (await import("./commands/readme.js")).run;
47
+ break;
48
+ case "topics":
49
+ run = (await import("./commands/topics.js")).run;
50
+ break;
51
+ case "describe":
52
+ run = (await import("./commands/describe.js")).run;
53
+ break;
54
+ case "summary":
55
+ case "tech":
56
+ case "improve":
57
+ run = (await import("./commands/analyze.js")).run;
58
+ break;
59
+ }
60
+ await Effect.runPromise(run(config).pipe(Effect.provide(layers), Effect.catchTags({
61
+ GeminiError: (e) => Effect.sync(() => {
62
+ logger.error(`Gemini Error: ${e.message}`);
63
+ process.exit(1);
64
+ }),
65
+ GitHubError: (e) => Effect.sync(() => {
66
+ logger.error(`GitHub Error (${e.endpoint}): ${e.message}`, void 0, { status: e.statusCode });
67
+ process.exit(1);
68
+ }),
69
+ GitIngestError: (e) => Effect.sync(() => {
70
+ logger.error(`GitIngest Error: ${e.message}`);
71
+ process.exit(1);
72
+ }),
73
+ GrepoValidationError: (e) => Effect.sync(() => {
74
+ logger.error(`Validation Error: ${e.message}`, void 0, { field: e.field });
75
+ process.exit(1);
76
+ })
77
+ }))).catch((error) => {
78
+ logger.error("An unexpected error occurred", error);
79
+ process.exit(1);
80
+ });
81
+ //#endregion
82
+ export {};
83
+
84
+ //# sourceMappingURL=cli.js.map
package/lib/cli.js.map ADDED
@@ -0,0 +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"}
@@ -0,0 +1,11 @@
1
+ import { GeminiError, GitIngestError } from "../errors.js";
2
+ import { GrepoConfig } from "../config.js";
3
+ import { Gemini } from "../services.js";
4
+ import { Effect } from "effect";
5
+
6
+ //#region src/commands/analyze.d.ts
7
+
8
+ declare const run: (config: GrepoConfig) => Effect.Effect<void, GitIngestError | GeminiError, Gemini>;
9
+ //#endregion
10
+ export { run };
11
+ //# sourceMappingURL=analyze.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.d.ts","names":[],"sources":["../../src/commands/analyze.ts"],"sourcesContent":[],"mappings":";;;;;;;cAmCa,cAAe,gBAAW,MAAA,CAAA,aAAA,cAAA,GAAA,aAAA"}
@@ -0,0 +1,49 @@
1
+ import { SEPARATOR, displayHeader } from "../utils/args.js";
2
+ import { Logger as Logger$1 } from "../utils/logger.js";
3
+ import { Gemini, fetchRepo } from "../services.js";
4
+ import { Effect } from "effect";
5
+ //#region src/commands/analyze.ts
6
+ /**
7
+ *
8
+ * Copyright 2026 Mike Odnis
9
+ *
10
+ * Licensed under the Apache License, Version 2.0 (the "License");
11
+ * you may not use this file except in compliance with the License.
12
+ * You may obtain a copy of the License at
13
+ *
14
+ * http://www.apache.org/licenses/LICENSE-2.0
15
+ *
16
+ * Unless required by applicable law or agreed to in writing, software
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ * See the License for the specific language governing permissions and
20
+ * limitations under the License.
21
+ *
22
+ */
23
+ const logger = new Logger$1("GREPO:ANALYZE");
24
+ const PROMPTS = {
25
+ improve: "Suggest 5 specific, actionable improvements for this repository.",
26
+ summary: "Provide a comprehensive 2-3 paragraph summary of this repository.",
27
+ tech: "List all technologies, frameworks, and tools used in this repository as a categorized markdown list."
28
+ };
29
+ const run = (config) => Effect.gen(function* () {
30
+ const gemini = yield* Gemini;
31
+ const analysisType = config.command;
32
+ displayHeader(`grepo ${analysisType}`, { Repository: config.repoUrl });
33
+ logger.info("Fetching repository content via GitIngest...");
34
+ const repoData = yield* fetchRepo(config.repoUrl);
35
+ logger.success("Content fetched successfully");
36
+ logger.info(`Running ${analysisType} analysis via Gemini...`);
37
+ const prompt = `${PROMPTS[analysisType]}\n\nTree:\n${repoData.tree}\n\nContent:\n${repoData.content.slice(0, 4e3)}`;
38
+ const result = yield* gemini.generateContent(prompt);
39
+ logger.success("Analysis complete");
40
+ console.log();
41
+ console.log(SEPARATOR);
42
+ console.log(result);
43
+ console.log(SEPARATOR);
44
+ console.log();
45
+ });
46
+ //#endregion
47
+ export { run };
48
+
49
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.js","names":["Logger"],"sources":["../../src/commands/analyze.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 { Effect } from \"effect\";\n\nimport type { GrepoConfig } from \"../config.js\";\nimport { fetchRepo, Gemini } from \"../services.js\";\nimport { displayHeader, SEPARATOR } from \"../utils/args.js\";\nimport { Logger } from \"../utils/logger.js\";\n\nconst logger = new Logger(\"GREPO:ANALYZE\");\n\ntype AnalysisType = \"improve\" | \"summary\" | \"tech\";\n\nconst PROMPTS: Record<AnalysisType, string> = {\n\timprove: \"Suggest 5 specific, actionable improvements for this repository.\",\n\tsummary: \"Provide a comprehensive 2-3 paragraph summary of this repository.\",\n\ttech: \"List all technologies, frameworks, and tools used in this repository as a categorized markdown list.\",\n};\n\nexport const run = (config: GrepoConfig) =>\n\tEffect.gen(function* () {\n\t\tconst gemini = yield* Gemini;\n\t\tconst analysisType = config.command as AnalysisType;\n\n\t\tdisplayHeader(`grepo ${analysisType}`, {\n\t\t\tRepository: config.repoUrl,\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\tlogger.info(`Running ${analysisType} analysis via Gemini...`);\n\t\tconst prompt = `${PROMPTS[analysisType]}\\n\\nTree:\\n${repoData.tree}\\n\\nContent:\\n${repoData.content.slice(0, 4000)}`;\n\t\tconst result = yield* gemini.generateContent(prompt);\n\t\tlogger.success(\"Analysis complete\");\n\n\t\tconsole.log();\n\t\tconsole.log(SEPARATOR);\n\t\tconsole.log(result);\n\t\tconsole.log(SEPARATOR);\n\t\tconsole.log();\n\t});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAM,SAAS,IAAIA,SAAO,gBAAgB;AAI1C,MAAM,UAAwC;CAC7C,SAAS;CACT,SAAS;CACT,MAAM;CACN;AAED,MAAa,OAAO,WACnB,OAAO,IAAI,aAAa;CACvB,MAAM,SAAS,OAAO;CACtB,MAAM,eAAe,OAAO;AAE5B,eAAc,SAAS,gBAAgB,EACtC,YAAY,OAAO,SACnB,CAAC;AAEF,QAAO,KAAK,+CAA+C;CAC3D,MAAM,WAAW,OAAO,UAAU,OAAO,QAAQ;AACjD,QAAO,QAAQ,+BAA+B;AAE9C,QAAO,KAAK,WAAW,aAAa,yBAAyB;CAC7D,MAAM,SAAS,GAAG,QAAQ,cAAc,aAAa,SAAS,KAAK,gBAAgB,SAAS,QAAQ,MAAM,GAAG,IAAK;CAClH,MAAM,SAAS,OAAO,OAAO,gBAAgB,OAAO;AACpD,QAAO,QAAQ,oBAAoB;AAEnC,SAAQ,KAAK;AACb,SAAQ,IAAI,UAAU;AACtB,SAAQ,IAAI,OAAO;AACnB,SAAQ,IAAI,UAAU;AACtB,SAAQ,KAAK;EACZ"}
@@ -0,0 +1,11 @@
1
+ import { GeminiError, GitHubError, GitIngestError } from "../errors.js";
2
+ import { GrepoConfig } from "../config.js";
3
+ import { Gemini, GitHub } from "../services.js";
4
+ import { Effect } from "effect";
5
+
6
+ //#region src/commands/describe.d.ts
7
+
8
+ declare const run: (config: GrepoConfig) => Effect.Effect<void, GitIngestError | GeminiError | GitHubError, Gemini | GitHub>;
9
+ //#endregion
10
+ export { run };
11
+ //# sourceMappingURL=describe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe.d.ts","names":[],"sources":["../../src/commands/describe.ts"],"sourcesContent":[],"mappings":";;;;;;;cA6Ca,cAAe,gBAAW,MAAA,CAAA,aAAA,cAAA,GAAA,WAAA,GAAA,aAAA,SAAA"}
@@ -0,0 +1,89 @@
1
+ import { SEPARATOR, displayHeader } from "../utils/args.js";
2
+ import { parseGitHubUrl } from "../utils/validation.js";
3
+ import { Logger as Logger$1 } from "../utils/logger.js";
4
+ import { Gemini, GitHub, fetchRepo } from "../services.js";
5
+ import { Effect } from "effect";
6
+ //#region src/commands/describe.ts
7
+ /**
8
+ *
9
+ * Copyright 2026 Mike Odnis
10
+ *
11
+ * Licensed under the Apache License, Version 2.0 (the "License");
12
+ * you may not use this file except in compliance with the License.
13
+ * You may obtain a copy of the License at
14
+ *
15
+ * http://www.apache.org/licenses/LICENSE-2.0
16
+ *
17
+ * Unless required by applicable law or agreed to in writing, software
18
+ * distributed under the License is distributed on an "AS IS" BASIS,
19
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+ * See the License for the specific language governing permissions and
21
+ * limitations under the License.
22
+ *
23
+ */
24
+ const logger = new Logger$1("GREPO:DESCRIBE");
25
+ const DESCRIBE_PROMPT = `Analyze this repository and generate:
26
+ 1. A concise repository description (max 350 characters) suitable for GitHub's "About" section
27
+ 2. A homepage URL if you can detect one from the repository content
28
+
29
+ Look for homepage URLs in:
30
+ - package.json "homepage" field
31
+ - docs site configurations (docusaurus, vitepress, mkdocs, etc.)
32
+ - deployment configs referencing domains (vercel.json, netlify.toml, CNAME files)
33
+ - GitHub Pages configuration
34
+ - README badges or links pointing to live demos, docs, or package registries (npm, PyPI, crates.io, etc.)
35
+
36
+ Return ONLY a JSON object with this shape:
37
+ {
38
+ "description": "the description here",
39
+ "homepage": "https://example.com or null if not found"
40
+ }`;
41
+ const run = (config) => Effect.gen(function* () {
42
+ const gemini = yield* Gemini;
43
+ const github = yield* GitHub;
44
+ displayHeader("grepo describe", {
45
+ Apply: config.shouldApply ? "Yes" : "No",
46
+ "Dry Run": config.isDryRun ? "Yes" : "No",
47
+ Repository: config.repoUrl
48
+ });
49
+ logger.info("Fetching repository content via GitIngest...");
50
+ const repoData = yield* fetchRepo(config.repoUrl);
51
+ logger.success("Content fetched successfully");
52
+ logger.info("Generating description and detecting homepage via Gemini...");
53
+ const prompt = `${DESCRIBE_PROMPT}\n\nURL: ${repoData.repo_url}\nSummary: ${repoData.summary}\nTree:\n${repoData.tree}\n\nContent:\n${repoData.content.slice(0, 6e3)}`;
54
+ const result = yield* gemini.generateContent(prompt);
55
+ logger.success("Analysis complete");
56
+ const jsonMatch = /\{[\s\S]*?\}/.exec(result);
57
+ if (!jsonMatch) {
58
+ logger.warn("Could not parse AI response");
59
+ console.log();
60
+ console.log(SEPARATOR);
61
+ console.log(result);
62
+ console.log(SEPARATOR);
63
+ return;
64
+ }
65
+ const parsed = JSON.parse(jsonMatch[0]);
66
+ console.log();
67
+ console.log(SEPARATOR);
68
+ console.log(` Description: ${parsed.description}`);
69
+ console.log(` Homepage: ${parsed.homepage || "(none detected)"}`);
70
+ console.log(SEPARATOR);
71
+ console.log();
72
+ if (parsed.description.length > 350) logger.warn(`Description is ${parsed.description.length} chars (max 350), it will be truncated by GitHub`);
73
+ const { owner, repo } = parseGitHubUrl(config.repoUrl);
74
+ const updateData = { description: parsed.description };
75
+ if (parsed.homepage) updateData.homepage = parsed.homepage;
76
+ if (config.isDryRun) {
77
+ logger.info("DRY RUN: Would set:", updateData);
78
+ return;
79
+ }
80
+ if (config.shouldApply) {
81
+ logger.info(`Updating ${owner}/${repo} on GitHub...`);
82
+ yield* github.updateRepo(owner, repo, updateData);
83
+ logger.success("Repository description and homepage updated successfully");
84
+ } else logger.info("Use --apply to set description and homepage on GitHub");
85
+ });
86
+ //#endregion
87
+ export { run };
88
+
89
+ //# sourceMappingURL=describe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe.js","names":["Logger","validation.parseGitHubUrl"],"sources":["../../src/commands/describe.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 { Effect } from \"effect\";\n\nimport type { GrepoConfig } from \"../config.js\";\nimport { fetchRepo, Gemini, GitHub } from \"../services.js\";\nimport { displayHeader, SEPARATOR } from \"../utils/args.js\";\nimport { Logger } from \"../utils/logger.js\";\nimport * as validation from \"../utils/validation.js\";\n\nconst logger = new Logger(\"GREPO:DESCRIBE\");\n\nconst DESCRIBE_PROMPT = `Analyze this repository and generate:\n1. A concise repository description (max 350 characters) suitable for GitHub's \"About\" section\n2. A homepage URL if you can detect one from the repository content\n\nLook for homepage URLs in:\n- package.json \"homepage\" field\n- docs site configurations (docusaurus, vitepress, mkdocs, etc.)\n- deployment configs referencing domains (vercel.json, netlify.toml, CNAME files)\n- GitHub Pages configuration\n- README badges or links pointing to live demos, docs, or package registries (npm, PyPI, crates.io, etc.)\n\nReturn ONLY a JSON object with this shape:\n{\n \"description\": \"the description here\",\n \"homepage\": \"https://example.com or null if not found\"\n}`;\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 describe\", {\n\t\t\tApply: config.shouldApply ? \"Yes\" : \"No\",\n\t\t\t\"Dry Run\": config.isDryRun ? \"Yes\" : \"No\",\n\t\t\tRepository: config.repoUrl,\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\tlogger.info(\"Generating description and detecting homepage via Gemini...\");\n\t\tconst prompt = `${DESCRIBE_PROMPT}\\n\\nURL: ${repoData.repo_url}\\nSummary: ${repoData.summary}\\nTree:\\n${repoData.tree}\\n\\nContent:\\n${repoData.content.slice(0, 6000)}`;\n\t\tconst result = yield* gemini.generateContent(prompt);\n\t\tlogger.success(\"Analysis complete\");\n\n\t\tconst jsonMatch = /\\{[\\s\\S]*?\\}/.exec(result);\n\t\tif (!jsonMatch) {\n\t\t\tlogger.warn(\"Could not parse AI response\");\n\t\t\tconsole.log();\n\t\t\tconsole.log(SEPARATOR);\n\t\t\tconsole.log(result);\n\t\t\tconsole.log(SEPARATOR);\n\t\t\treturn;\n\t\t}\n\n\t\tconst parsed = JSON.parse(jsonMatch[0]) as {\n\t\t\tdescription: string;\n\t\t\thomepage: string | null;\n\t\t};\n\n\t\tconsole.log();\n\t\tconsole.log(SEPARATOR);\n\t\tconsole.log(` Description: ${parsed.description}`);\n\t\tconsole.log(` Homepage: ${parsed.homepage || \"(none detected)\"}`);\n\t\tconsole.log(SEPARATOR);\n\t\tconsole.log();\n\n\t\tif (parsed.description.length > 350) {\n\t\t\tlogger.warn(\n\t\t\t\t`Description is ${parsed.description.length} chars (max 350), it will be truncated by GitHub`,\n\t\t\t);\n\t\t}\n\n\t\tconst { owner, repo } = validation.parseGitHubUrl(config.repoUrl);\n\n\t\tconst updateData: { description?: string; homepage?: string } = {\n\t\t\tdescription: parsed.description,\n\t\t};\n\t\tif (parsed.homepage) {\n\t\t\tupdateData.homepage = parsed.homepage;\n\t\t}\n\n\t\tif (config.isDryRun) {\n\t\t\tlogger.info(\"DRY RUN: Would set:\", updateData);\n\t\t\treturn;\n\t\t}\n\n\t\tif (config.shouldApply) {\n\t\t\tlogger.info(`Updating ${owner}/${repo} on GitHub...`);\n\t\t\tyield* github.updateRepo(owner, repo, updateData);\n\t\t\tlogger.success(\n\t\t\t\t\"Repository description and homepage updated successfully\",\n\t\t\t);\n\t\t} else {\n\t\t\tlogger.info(\"Use --apply to set description and homepage on GitHub\");\n\t\t}\n\t});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAM,SAAS,IAAIA,SAAO,iBAAiB;AAE3C,MAAM,kBAAkB;;;;;;;;;;;;;;;;AAiBxB,MAAa,OAAO,WACnB,OAAO,IAAI,aAAa;CACvB,MAAM,SAAS,OAAO;CACtB,MAAM,SAAS,OAAO;AAEtB,eAAc,kBAAkB;EAC/B,OAAO,OAAO,cAAc,QAAQ;EACpC,WAAW,OAAO,WAAW,QAAQ;EACrC,YAAY,OAAO;EACnB,CAAC;AAEF,QAAO,KAAK,+CAA+C;CAC3D,MAAM,WAAW,OAAO,UAAU,OAAO,QAAQ;AACjD,QAAO,QAAQ,+BAA+B;AAE9C,QAAO,KAAK,8DAA8D;CAC1E,MAAM,SAAS,GAAG,gBAAgB,WAAW,SAAS,SAAS,aAAa,SAAS,QAAQ,WAAW,SAAS,KAAK,gBAAgB,SAAS,QAAQ,MAAM,GAAG,IAAK;CACrK,MAAM,SAAS,OAAO,OAAO,gBAAgB,OAAO;AACpD,QAAO,QAAQ,oBAAoB;CAEnC,MAAM,YAAY,eAAe,KAAK,OAAO;AAC7C,KAAI,CAAC,WAAW;AACf,SAAO,KAAK,8BAA8B;AAC1C,UAAQ,KAAK;AACb,UAAQ,IAAI,UAAU;AACtB,UAAQ,IAAI,OAAO;AACnB,UAAQ,IAAI,UAAU;AACtB;;CAGD,MAAM,SAAS,KAAK,MAAM,UAAU,GAAG;AAKvC,SAAQ,KAAK;AACb,SAAQ,IAAI,UAAU;AACtB,SAAQ,IAAI,kBAAkB,OAAO,cAAc;AACnD,SAAQ,IAAI,kBAAkB,OAAO,YAAY,oBAAoB;AACrE,SAAQ,IAAI,UAAU;AACtB,SAAQ,KAAK;AAEb,KAAI,OAAO,YAAY,SAAS,IAC/B,QAAO,KACN,kBAAkB,OAAO,YAAY,OAAO,kDAC5C;CAGF,MAAM,EAAE,OAAO,SAASC,eAA0B,OAAO,QAAQ;CAEjE,MAAM,aAA0D,EAC/D,aAAa,OAAO,aACpB;AACD,KAAI,OAAO,SACV,YAAW,WAAW,OAAO;AAG9B,KAAI,OAAO,UAAU;AACpB,SAAO,KAAK,uBAAuB,WAAW;AAC9C;;AAGD,KAAI,OAAO,aAAa;AACvB,SAAO,KAAK,YAAY,MAAM,GAAG,KAAK,eAAe;AACrD,SAAO,OAAO,WAAW,OAAO,MAAM,WAAW;AACjD,SAAO,QACN,2DACA;OAED,QAAO,KAAK,wDAAwD;EAEpE"}
@@ -0,0 +1,11 @@
1
+ import { GeminiError, GitHubError, GitIngestError } from "../errors.js";
2
+ import { GrepoConfig } from "../config.js";
3
+ import { Gemini, GitHub } from "../services.js";
4
+ import { Effect } from "effect";
5
+
6
+ //#region src/commands/readme.d.ts
7
+
8
+ declare const run: (config: GrepoConfig) => Effect.Effect<void, GitIngestError | GeminiError | GitHubError, Gemini | GitHub>;
9
+ //#endregion
10
+ export { run };
11
+ //# sourceMappingURL=readme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readme.d.ts","names":[],"sources":["../../src/commands/readme.ts"],"sourcesContent":[],"mappings":";;;;;;;cAoCa,cAAe,gBAAW,MAAA,CAAA,aAAA,cAAA,GAAA,WAAA,GAAA,aAAA,SAAA"}
@@ -0,0 +1,69 @@
1
+ import { displayHeader } from "../utils/args.js";
2
+ import { parseGitHubUrl } from "../utils/validation.js";
3
+ import { Logger as Logger$1 } from "../utils/logger.js";
4
+ import { Gemini, GitHub, fetchRepo } from "../services.js";
5
+ import { validateAndFixMermaid } from "../mermaid.js";
6
+ import { buildAnalysisPrompt, buildGenerationPrompt, extractExistingReadme, parseAnalysis } from "../prompts/readme.js";
7
+ import { Effect } from "effect";
8
+ import { writeFile } from "node:fs/promises";
9
+ //#region src/commands/readme.ts
10
+ /**
11
+ *
12
+ * Copyright 2026 Mike Odnis
13
+ *
14
+ * Licensed under the Apache License, Version 2.0 (the "License");
15
+ * you may not use this file except in compliance with the License.
16
+ * You may obtain a copy of the License at
17
+ *
18
+ * http://www.apache.org/licenses/LICENSE-2.0
19
+ *
20
+ * Unless required by applicable law or agreed to in writing, software
21
+ * distributed under the License is distributed on an "AS IS" BASIS,
22
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23
+ * See the License for the specific language governing permissions and
24
+ * limitations under the License.
25
+ *
26
+ */
27
+ const logger = new Logger$1("GREPO:README");
28
+ const run = (config) => Effect.gen(function* () {
29
+ const gemini = yield* Gemini;
30
+ const github = yield* GitHub;
31
+ displayHeader("grepo readme", {
32
+ Format: config.outputFormat,
33
+ Output: config.outputFile,
34
+ Push: config.shouldPush ? `Yes (${config.branch})` : "No",
35
+ Repository: config.repoUrl,
36
+ Style: config.style
37
+ });
38
+ logger.info("Fetching repository content via GitIngest...");
39
+ const repoData = yield* fetchRepo(config.repoUrl);
40
+ logger.success("Content fetched successfully");
41
+ logger.info("Analyzing repository structure...");
42
+ const analysisPrompt = buildAnalysisPrompt(repoData, extractExistingReadme(repoData.content) ?? void 0);
43
+ const analysis = parseAnalysis(yield* gemini.generateContent(analysisPrompt));
44
+ logger.success("Analysis complete");
45
+ logger.info("Generating README content via Gemini...");
46
+ const generationPrompt = buildGenerationPrompt(analysis, repoData, {
47
+ format: config.outputFormat,
48
+ style: config.style,
49
+ tone: config.tone
50
+ });
51
+ const rawContent = yield* gemini.generateContent(generationPrompt);
52
+ logger.success("README generated successfully");
53
+ const content = yield* validateAndFixMermaid(rawContent, gemini);
54
+ if (config.outputFile) {
55
+ logger.info(`Saving README to ${config.outputFile}...`);
56
+ yield* Effect.promise(() => writeFile(config.outputFile, content));
57
+ logger.success("File saved locally");
58
+ }
59
+ if (config.shouldPush) {
60
+ const { owner, repo } = parseGitHubUrl(config.repoUrl);
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);
63
+ logger.success("Pushed to GitHub successfully");
64
+ }
65
+ });
66
+ //#endregion
67
+ export { run };
68
+
69
+ //# sourceMappingURL=readme.js.map
@@ -0,0 +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"}
@@ -0,0 +1,11 @@
1
+ import { GeminiError, GitHubError, GitIngestError } from "../errors.js";
2
+ import { GrepoConfig } from "../config.js";
3
+ import { Gemini, GitHub } from "../services.js";
4
+ import { Effect } from "effect";
5
+
6
+ //#region src/commands/topics.d.ts
7
+
8
+ declare const run: (config: GrepoConfig) => Effect.Effect<void, GitIngestError | GeminiError | GitHubError, Gemini | GitHub>;
9
+ //#endregion
10
+ export { run };
11
+ //# sourceMappingURL=topics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topics.d.ts","names":[],"sources":["../../src/commands/topics.ts"],"sourcesContent":[],"mappings":";;;;;;;cA+Ba,cAAe,gBAAW,MAAA,CAAA,aAAA,cAAA,GAAA,WAAA,GAAA,aAAA,SAAA"}
@@ -0,0 +1,74 @@
1
+ import { SEPARATOR, displayHeader } from "../utils/args.js";
2
+ import { parseGitHubUrl } from "../utils/validation.js";
3
+ import { Logger as Logger$1 } from "../utils/logger.js";
4
+ import { Gemini, GitHub, fetchRepo } from "../services.js";
5
+ import { Effect } from "effect";
6
+ //#region src/commands/topics.ts
7
+ /**
8
+ *
9
+ * Copyright 2026 Mike Odnis
10
+ *
11
+ * Licensed under the Apache License, Version 2.0 (the "License");
12
+ * you may not use this file except in compliance with the License.
13
+ * You may obtain a copy of the License at
14
+ *
15
+ * http://www.apache.org/licenses/LICENSE-2.0
16
+ *
17
+ * Unless required by applicable law or agreed to in writing, software
18
+ * distributed under the License is distributed on an "AS IS" BASIS,
19
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+ * See the License for the specific language governing permissions and
21
+ * limitations under the License.
22
+ *
23
+ */
24
+ const logger = new Logger$1("GREPO:TOPICS");
25
+ const TOPICS_PROMPT = `Analyze this repository and suggest 5-8 relevant GitHub topics.
26
+ Return ONLY a JSON array of lowercase, hyphenated strings. Example: ["typescript", "cli-tool", "ai-powered"]`;
27
+ const run = (config) => Effect.gen(function* () {
28
+ const gemini = yield* Gemini;
29
+ const github = yield* GitHub;
30
+ displayHeader("grepo topics", {
31
+ Apply: config.shouldApply ? "Yes" : "No",
32
+ "Dry Run": config.isDryRun ? "Yes" : "No",
33
+ Merge: config.shouldMerge ? "Yes" : "No",
34
+ Repository: config.repoUrl
35
+ });
36
+ logger.info("Fetching repository content via GitIngest...");
37
+ const repoData = yield* fetchRepo(config.repoUrl);
38
+ logger.success("Content fetched successfully");
39
+ logger.info("Running topics analysis via Gemini...");
40
+ const prompt = `${TOPICS_PROMPT}\n\nTree:\n${repoData.tree}\n\nContent:\n${repoData.content.slice(0, 4e3)}`;
41
+ const result = yield* gemini.generateContent(prompt);
42
+ logger.success("Analysis complete");
43
+ console.log();
44
+ console.log(SEPARATOR);
45
+ console.log(result);
46
+ console.log(SEPARATOR);
47
+ console.log();
48
+ const jsonMatch = /\[[\s\S]*?\]/.exec(result);
49
+ if (!jsonMatch) {
50
+ logger.warn("Could not find topics list in AI response");
51
+ return;
52
+ }
53
+ const suggested = JSON.parse(jsonMatch[0]).map((t) => t.toLowerCase().trim().replaceAll(/\s+/g, "-"));
54
+ const { owner, repo } = parseGitHubUrl(config.repoUrl);
55
+ let finalTopics = suggested;
56
+ if (config.shouldMerge && config.githubToken) {
57
+ logger.info("Fetching current topics from GitHub...");
58
+ const current = yield* github.getTopics(owner, repo);
59
+ finalTopics = [...new Set([...current, ...suggested])].sort((a, b) => a.localeCompare(b));
60
+ }
61
+ if (config.isDryRun) {
62
+ logger.info("DRY RUN: Would apply these topics:", { topics: finalTopics });
63
+ return;
64
+ }
65
+ if (config.shouldApply) {
66
+ logger.info("Applying topics to GitHub...");
67
+ yield* github.setTopics(owner, repo, finalTopics);
68
+ logger.success("Topics applied successfully");
69
+ } else logger.info("Use --apply to set these topics on GitHub");
70
+ });
71
+ //#endregion
72
+ export { run };
73
+
74
+ //# sourceMappingURL=topics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topics.js","names":["Logger","validation.parseGitHubUrl"],"sources":["../../src/commands/topics.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 { Effect } from \"effect\";\n\nimport type { GrepoConfig } from \"../config.js\";\nimport { fetchRepo, Gemini, GitHub } from \"../services.js\";\nimport { displayHeader, SEPARATOR } from \"../utils/args.js\";\nimport { Logger } from \"../utils/logger.js\";\nimport * as validation from \"../utils/validation.js\";\n\nconst logger = new Logger(\"GREPO:TOPICS\");\n\nconst TOPICS_PROMPT = `Analyze this repository and suggest 5-8 relevant GitHub topics.\nReturn ONLY a JSON array of lowercase, hyphenated strings. Example: [\"typescript\", \"cli-tool\", \"ai-powered\"]`;\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 topics\", {\n\t\t\tApply: config.shouldApply ? \"Yes\" : \"No\",\n\t\t\t\"Dry Run\": config.isDryRun ? \"Yes\" : \"No\",\n\t\t\tMerge: config.shouldMerge ? \"Yes\" : \"No\",\n\t\t\tRepository: config.repoUrl,\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\tlogger.info(\"Running topics analysis via Gemini...\");\n\t\tconst prompt = `${TOPICS_PROMPT}\\n\\nTree:\\n${repoData.tree}\\n\\nContent:\\n${repoData.content.slice(0, 4000)}`;\n\t\tconst result = yield* gemini.generateContent(prompt);\n\t\tlogger.success(\"Analysis complete\");\n\n\t\tconsole.log();\n\t\tconsole.log(SEPARATOR);\n\t\tconsole.log(result);\n\t\tconsole.log(SEPARATOR);\n\t\tconsole.log();\n\n\t\tconst jsonMatch = /\\[[\\s\\S]*?\\]/.exec(result);\n\t\tif (!jsonMatch) {\n\t\t\tlogger.warn(\"Could not find topics list in AI response\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst suggested = (JSON.parse(jsonMatch[0]) as string[]).map((t) =>\n\t\t\tt.toLowerCase().trim().replaceAll(/\\s+/g, \"-\"),\n\t\t);\n\n\t\tconst { owner, repo } = validation.parseGitHubUrl(config.repoUrl);\n\n\t\tlet finalTopics = suggested;\n\t\tif (config.shouldMerge && config.githubToken) {\n\t\t\tlogger.info(\"Fetching current topics from GitHub...\");\n\t\t\tconst current = yield* github.getTopics(owner, repo);\n\t\t\tfinalTopics = [...new Set([...current, ...suggested])].sort((a, b) =>\n\t\t\t\ta.localeCompare(b),\n\t\t\t);\n\t\t}\n\n\t\tif (config.isDryRun) {\n\t\t\tlogger.info(\"DRY RUN: Would apply these topics:\", {\n\t\t\t\ttopics: finalTopics,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (config.shouldApply) {\n\t\t\tlogger.info(\"Applying topics to GitHub...\");\n\t\t\tyield* github.setTopics(owner, repo, finalTopics);\n\t\t\tlogger.success(\"Topics applied successfully\");\n\t\t} else {\n\t\t\tlogger.info(\"Use --apply to set these topics on GitHub\");\n\t\t}\n\t});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAM,SAAS,IAAIA,SAAO,eAAe;AAEzC,MAAM,gBAAgB;;AAGtB,MAAa,OAAO,WACnB,OAAO,IAAI,aAAa;CACvB,MAAM,SAAS,OAAO;CACtB,MAAM,SAAS,OAAO;AAEtB,eAAc,gBAAgB;EAC7B,OAAO,OAAO,cAAc,QAAQ;EACpC,WAAW,OAAO,WAAW,QAAQ;EACrC,OAAO,OAAO,cAAc,QAAQ;EACpC,YAAY,OAAO;EACnB,CAAC;AAEF,QAAO,KAAK,+CAA+C;CAC3D,MAAM,WAAW,OAAO,UAAU,OAAO,QAAQ;AACjD,QAAO,QAAQ,+BAA+B;AAE9C,QAAO,KAAK,wCAAwC;CACpD,MAAM,SAAS,GAAG,cAAc,aAAa,SAAS,KAAK,gBAAgB,SAAS,QAAQ,MAAM,GAAG,IAAK;CAC1G,MAAM,SAAS,OAAO,OAAO,gBAAgB,OAAO;AACpD,QAAO,QAAQ,oBAAoB;AAEnC,SAAQ,KAAK;AACb,SAAQ,IAAI,UAAU;AACtB,SAAQ,IAAI,OAAO;AACnB,SAAQ,IAAI,UAAU;AACtB,SAAQ,KAAK;CAEb,MAAM,YAAY,eAAe,KAAK,OAAO;AAC7C,KAAI,CAAC,WAAW;AACf,SAAO,KAAK,4CAA4C;AACxD;;CAGD,MAAM,YAAa,KAAK,MAAM,UAAU,GAAG,CAAc,KAAK,MAC7D,EAAE,aAAa,CAAC,MAAM,CAAC,WAAW,QAAQ,IAAI,CAC9C;CAED,MAAM,EAAE,OAAO,SAASC,eAA0B,OAAO,QAAQ;CAEjE,IAAI,cAAc;AAClB,KAAI,OAAO,eAAe,OAAO,aAAa;AAC7C,SAAO,KAAK,yCAAyC;EACrD,MAAM,UAAU,OAAO,OAAO,UAAU,OAAO,KAAK;AACpD,gBAAc,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,GAAG,MAC/D,EAAE,cAAc,EAAE,CAClB;;AAGF,KAAI,OAAO,UAAU;AACpB,SAAO,KAAK,sCAAsC,EACjD,QAAQ,aACR,CAAC;AACF;;AAGD,KAAI,OAAO,aAAa;AACvB,SAAO,KAAK,+BAA+B;AAC3C,SAAO,OAAO,UAAU,OAAO,MAAM,YAAY;AACjD,SAAO,QAAQ,8BAA8B;OAE7C,QAAO,KAAK,4CAA4C;EAExD"}
@@ -0,0 +1,31 @@
1
+ import { Schema } from "effect";
2
+
3
+ //#region src/config.d.ts
4
+
5
+ declare const Command: Schema.Literal<["readme", "topics", "describe", "summary", "tech", "improve"]>;
6
+ type Command = Schema.Schema.Type<typeof Command>;
7
+ declare const OutputFormat: Schema.Literal<["md", "mdx"]>;
8
+ type OutputFormat = Schema.Schema.Type<typeof OutputFormat>;
9
+ declare const DocumentationStyle: Schema.Literal<["minimal", "standard", "comprehensive"]>;
10
+ type DocumentationStyle = Schema.Schema.Type<typeof DocumentationStyle>;
11
+ declare const GrepoConfig: Schema.Struct<{
12
+ branch: typeof Schema.String;
13
+ command: Schema.Literal<["readme", "topics", "describe", "summary", "tech", "improve"]>;
14
+ geminiApiKey: typeof Schema.String;
15
+ githubToken: Schema.optional<typeof Schema.String>;
16
+ isDryRun: typeof Schema.Boolean;
17
+ outputFile: typeof Schema.String;
18
+ outputFormat: Schema.Literal<["md", "mdx"]>;
19
+ repoUrl: typeof Schema.String;
20
+ shouldApply: typeof Schema.Boolean;
21
+ shouldMerge: typeof Schema.Boolean;
22
+ shouldPush: typeof Schema.Boolean;
23
+ style: Schema.Literal<["minimal", "standard", "comprehensive"]>;
24
+ tone: Schema.optional<Schema.Literal<["casual", "minimal", "professional", "technical"]>>;
25
+ }>;
26
+ type GrepoConfig = Schema.Schema.Type<typeof GrepoConfig>;
27
+ declare function loadEnv(): Promise<void>;
28
+ declare function buildConfig(argv: string[]): GrepoConfig;
29
+ //#endregion
30
+ export { Command, DocumentationStyle, GrepoConfig, OutputFormat, buildConfig, loadEnv };
31
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +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"}