@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
@@ -0,0 +1,345 @@
1
+ import { Logger as Logger$1 } from "../utils/logger.js";
2
+ import { Schema } from "effect";
3
+ //#region src/prompts/readme.ts
4
+ /**
5
+ *
6
+ * Copyright 2026 Mike Odnis
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ *
20
+ */
21
+ const DiagramSchema = Schema.Struct({
22
+ keyNodes: Schema.Array(Schema.String),
23
+ purpose: Schema.String,
24
+ scope: Schema.String,
25
+ type: Schema.Literal("c4-context", "er", "flowchart", "sequence", "state")
26
+ });
27
+ const ExistingReadmeSchema = Schema.Struct({
28
+ improve: Schema.Array(Schema.String),
29
+ missing: Schema.Array(Schema.String),
30
+ preserve: Schema.Array(Schema.String),
31
+ quality: Schema.Literal("decent", "good", "none", "poor")
32
+ });
33
+ const IdentitySchema = Schema.Struct({
34
+ differentiators: Schema.Array(Schema.String),
35
+ name: Schema.String,
36
+ oneLiner: Schema.String
37
+ });
38
+ const SectionsSchema = Schema.Struct({
39
+ recommended: Schema.Array(Schema.String),
40
+ skip: Schema.Array(Schema.Struct({
41
+ reason: Schema.String,
42
+ section: Schema.String
43
+ }))
44
+ });
45
+ const ToneSchema = Schema.Literal("casual", "minimal", "professional", "technical");
46
+ const ToneDetectionSchema = Schema.Struct({
47
+ detected: ToneSchema,
48
+ evidence: Schema.String
49
+ });
50
+ const AnalysisResult = Schema.Struct({
51
+ diagrams: Schema.Array(DiagramSchema),
52
+ existingReadme: ExistingReadmeSchema,
53
+ identity: IdentitySchema,
54
+ repoType: Schema.String,
55
+ sections: SectionsSchema,
56
+ tone: ToneDetectionSchema
57
+ });
58
+ const GenerationOptions = Schema.Struct({
59
+ format: Schema.Literal("md", "mdx"),
60
+ style: Schema.Literal("minimal", "standard", "comprehensive"),
61
+ tone: Schema.optional(ToneSchema)
62
+ });
63
+ const RepoData = Schema.Struct({
64
+ content: Schema.String,
65
+ repo_url: Schema.String,
66
+ summary: Schema.String,
67
+ tree: Schema.String
68
+ });
69
+ const DEFAULT_ANALYSIS = {
70
+ diagrams: [],
71
+ existingReadme: {
72
+ improve: [],
73
+ missing: [],
74
+ preserve: [],
75
+ quality: "none"
76
+ },
77
+ identity: {
78
+ differentiators: [],
79
+ name: "Unknown",
80
+ oneLiner: ""
81
+ },
82
+ repoType: "library",
83
+ sections: {
84
+ recommended: [
85
+ "hero",
86
+ "overview",
87
+ "installation",
88
+ "quick-start",
89
+ "usage",
90
+ "development",
91
+ "license"
92
+ ],
93
+ skip: []
94
+ },
95
+ tone: {
96
+ detected: "professional",
97
+ evidence: "fallback default"
98
+ }
99
+ };
100
+ function extractExistingReadme(content) {
101
+ const readmeMatch = /(?:^|\n)(?:={3,}|─{3,})?\s*README\.md\s*(?:={3,}|─{3,})?\n([\s\S]*?)(?=\n(?:={3,}|─{3,})\s*\S+\.\S+|$)/.exec(content);
102
+ if (readmeMatch?.[1] && readmeMatch[1].trim().length > 50) return readmeMatch[1].trim();
103
+ return null;
104
+ }
105
+ function parseAnalysis(raw) {
106
+ try {
107
+ const stripped = raw.replace(/^```(?:json)?\s*/i, "").replace(/\s*```\s*$/, "").trim();
108
+ const json = JSON.parse(stripped);
109
+ const result = Schema.decodeUnknownSync(AnalysisResult)(json);
110
+ if (!result.sections.recommended.length) throw new Error("sections.recommended must not be empty");
111
+ return result;
112
+ } catch (err) {
113
+ new Logger$1("GREPO:README-PROMPT").warn(`Failed to parse analysis JSON, falling back to DEFAULT_ANALYSIS. Error: ${err instanceof Error ? err.message : String(err)}`);
114
+ return DEFAULT_ANALYSIS;
115
+ }
116
+ }
117
+ function buildAnalysisPrompt(repoData, existingReadme) {
118
+ const existingReadmeBlock = existingReadme ? `
119
+ <existing_readme>
120
+ ${existingReadme.slice(0, 4e3)}
121
+ </existing_readme>` : "";
122
+ return `You are an expert technical analyst. Analyze the repository below and return ONLY valid JSON — no markdown fences, no commentary, no extra text.
123
+
124
+ <output_schema>
125
+ {
126
+ "repoType": "string — e.g. cli-tool, library, web-app, api, monorepo, config, data-pipeline, etc.",
127
+ "identity": {
128
+ "name": "string — canonical project name",
129
+ "oneLiner": "string — one sentence describing what it does",
130
+ "differentiators": ["string — unique selling points"]
131
+ },
132
+ "tone": {
133
+ "detected": "casual | professional | minimal | technical",
134
+ "evidence": "string — quote or observation that led to this conclusion"
135
+ },
136
+ "sections": {
137
+ "recommended": ["string — section keys from the catalog below, in logical order"],
138
+ "skip": [{ "section": "string", "reason": "string" }]
139
+ },
140
+ "diagrams": [
141
+ {
142
+ "type": "flowchart | sequence | c4-context | er | state",
143
+ "purpose": "string — what this diagram explains",
144
+ "scope": "string — what subsystem or flow it covers",
145
+ "keyNodes": ["string — important nodes or actors"]
146
+ }
147
+ ],
148
+ "existingReadme": {
149
+ "quality": "good | decent | poor | none",
150
+ "preserve": ["string — sections or content worth keeping verbatim"],
151
+ "improve": ["string — sections that exist but need rework"],
152
+ "missing": ["string — important topics not covered"]
153
+ }
154
+ }
155
+ </output_schema>
156
+
157
+ <section_catalog>
158
+ hero — project name, tagline, badges
159
+ overview — what it does and why it exists
160
+ features — bullet list of capabilities
161
+ architecture — system design, component overview
162
+ installation — how to install/setup
163
+ quick-start — minimal working example
164
+ usage — detailed usage instructions
165
+ cli-reference — CLI flags and subcommands
166
+ api-reference — public API docs
167
+ configuration — env vars, config files
168
+ development — local dev setup, contributing workflow
169
+ deployment — how to deploy/release
170
+ contributing — contribution guidelines
171
+ license — license info
172
+ </section_catalog>
173
+
174
+ <rules>
175
+ - Only recommend sections that have real supporting content in the repository.
176
+ - Recommend at most 2 diagrams. Choose diagram types based on:
177
+ - c4-context: multi-service architectures with external dependencies
178
+ - sequence: request/response workflows or multi-actor interactions
179
+ - flowchart: data pipelines, build processes, or decision trees
180
+ - state: object lifecycle or state machine logic
181
+ - er: data models with relationships
182
+ - Detect tone from existing docs, comments, and README style (if present).
183
+ - Be conservative: fewer well-chosen sections beat a bloated list.
184
+ </rules>
185
+
186
+ <repository_context>
187
+ url: ${repoData.repo_url}
188
+ summary: ${repoData.summary}
189
+
190
+ <tree>
191
+ ${repoData.tree}
192
+ </tree>
193
+
194
+ <content>
195
+ ${repoData.content.slice(0, 8e3)}
196
+ </content>
197
+ </repository_context>
198
+ ${existingReadmeBlock}`;
199
+ }
200
+ const STYLE_GUIDANCE = {
201
+ comprehensive: "Be thorough. Multiple examples, edge cases, full API surface. Expand every recommended section fully.",
202
+ minimal: "Keep it concise. Favor short sentences and small sections. Omit exhaustive examples. Badge count ≤ 3.",
203
+ standard: "Balance depth and brevity. One code example per major section. Moderate badge set. Include a quick-start."
204
+ };
205
+ function buildExistingReadmeInstructions(analysis) {
206
+ if (analysis.existingReadme.quality === "none") return "No existing README was found. Generate the document from scratch.";
207
+ const lines = [`Existing README quality: ${analysis.existingReadme.quality}.`];
208
+ if (analysis.existingReadme.preserve.length > 0) lines.push(`Preserve the following content verbatim where possible:\n${analysis.existingReadme.preserve.map((s) => ` - ${s}`).join("\n")}`);
209
+ if (analysis.existingReadme.improve.length > 0) lines.push(`Improve (rewrite/expand) these sections:\n${analysis.existingReadme.improve.map((s) => ` - ${s}`).join("\n")}`);
210
+ if (analysis.existingReadme.missing.length > 0) lines.push(`Add these missing topics:\n${analysis.existingReadme.missing.map((s) => ` - ${s}`).join("\n")}`);
211
+ return lines.join("\n");
212
+ }
213
+ function buildGenerationPrompt(analysis, repoData, options) {
214
+ const effectiveTone = options.tone ?? analysis.tone.detected;
215
+ return `You are a senior technical writer generating a README for a software project.
216
+
217
+ <output_rules>
218
+ - Output ONLY the raw ${options.format.toUpperCase()} content. No preamble, no explanation, no markdown fences wrapping the whole document.
219
+ - Only generate the sections listed in recommended_sections below. Do not add extras.
220
+ - No generic filler phrases like "In this section we will…" or "This project is a…".
221
+ - Mermaid diagrams must follow diagram_rules exactly.
222
+ </output_rules>
223
+
224
+ <analysis>
225
+ ${JSON.stringify(analysis, null, 2)}
226
+ </analysis>
227
+
228
+ <recommended_sections>
229
+ ${analysis.sections.recommended.join(", ")}
230
+ </recommended_sections>
231
+
232
+ <tone>
233
+ Style: ${effectiveTone}
234
+ Description: ${{
235
+ casual: "Friendly, approachable, first-person plural ('we'). Use contractions. Short paragraphs. Light humor is fine.",
236
+ minimal: "Extremely terse. Bullet points over prose. No introductory fluff. Every word must earn its place.",
237
+ professional: "Clear, precise, authoritative. Third-person or imperative. No jargon without definition. Avoid filler words.",
238
+ technical: "Assume a developer audience. Use correct terminology. Include type signatures, flags, and internals where relevant."
239
+ }[effectiveTone]}
240
+ </tone>
241
+
242
+ <diagram_rules>
243
+ CRITICAL SYNTAX RULES (violations cause render errors):
244
+ - Wrap ALL node labels in quotes if they contain spaces, special chars, or parentheses: A["My Label"]
245
+ - NEVER use bare parentheses in labels — use quotes: A["Deploy (prod)"] NOT A[Deploy (prod)]
246
+ - NEVER use colons in labels without quotes: A["Step: Init"] NOT A[Step: Init]
247
+ - Arrow syntax: use --> for solid, -.-> for dotted. NEVER use -> alone in flowcharts.
248
+ - Subgraph IDs must not contain spaces: subgraph auth_flow["Auth Flow"]
249
+ - Semicolons are NOT terminators — do not end lines with ;
250
+ - Each node definition must be on its own line.
251
+
252
+ STYLE RULES:
253
+ - Use descriptive labels on all nodes — never single letters like A, B, C.
254
+ - Add meaningful labels on edges to describe data flow or actions.
255
+ - Use subgraphs to group related nodes into logical clusters.
256
+ - Limit diagrams to 15 nodes maximum.
257
+
258
+ TYPE-SPECIFIC TEMPLATES (follow these exactly):
259
+
260
+ flowchart (always TD):
261
+ \`\`\`mermaid
262
+ flowchart TD
263
+ A["User Request"] --> B{"Auth Valid?"}
264
+ B -->|Yes| C["Process Request"]
265
+ B -->|No| D["Return 401"]
266
+ C --> E["Send Response"]
267
+ \`\`\`
268
+
269
+ sequence:
270
+ \`\`\`mermaid
271
+ sequenceDiagram
272
+ actor User
273
+ participant API
274
+ participant DB
275
+ User->>API: POST /login
276
+ activate API
277
+ API->>DB: Query user
278
+ DB-->>API: User record
279
+ API-->>User: JWT token
280
+ deactivate API
281
+ \`\`\`
282
+
283
+ c4-context (use C4Context):
284
+ \`\`\`mermaid
285
+ C4Context
286
+ Person(user, "Developer", "Uses the CLI tool")
287
+ System(cli, "CLI", "Command-line interface")
288
+ System_Ext(api, "GitHub API", "Repository management")
289
+ Rel(user, cli, "Runs commands")
290
+ Rel(cli, api, "REST calls")
291
+ \`\`\`
292
+
293
+ er:
294
+ \`\`\`mermaid
295
+ erDiagram
296
+ USER ||--o{ ORDER : places
297
+ ORDER ||--|{ LINE_ITEM : contains
298
+ PRODUCT ||--o{ LINE_ITEM : "ordered in"
299
+ \`\`\`
300
+
301
+ state:
302
+ \`\`\`mermaid
303
+ stateDiagram-v2
304
+ [*] --> Idle
305
+ Idle --> Processing : start
306
+ Processing --> Done : complete
307
+ Processing --> Failed : error
308
+ Failed --> Idle : retry
309
+ Done --> [*]
310
+ \`\`\`
311
+
312
+ COMMON MISTAKES TO AVOID:
313
+ - Using "graph" instead of "flowchart"
314
+ - Missing quotes around labels with special characters
315
+ - Using C4_Context instead of C4Context
316
+ - Forgetting "activate/deactivate" in sequence diagrams
317
+ - Using --> in sequence diagrams (use ->> or -->> instead)
318
+ </diagram_rules>
319
+
320
+ <existing_readme_handling>
321
+ ${buildExistingReadmeInstructions(analysis)}
322
+ </existing_readme_handling>
323
+
324
+ <style_profile>
325
+ Documentation style: ${options.style}
326
+ ${STYLE_GUIDANCE[options.style]}
327
+ </style_profile>
328
+
329
+ <repository_context>
330
+ url: ${repoData.repo_url}
331
+ summary: ${repoData.summary}
332
+
333
+ <tree>
334
+ ${repoData.tree}
335
+ </tree>
336
+
337
+ <content>
338
+ ${repoData.content}
339
+ </content>
340
+ </repository_context>`;
341
+ }
342
+ //#endregion
343
+ export { AnalysisResult, DEFAULT_ANALYSIS, DiagramSchema, ExistingReadmeSchema, GenerationOptions, IdentitySchema, RepoData, STYLE_GUIDANCE, SectionsSchema, ToneDetectionSchema, ToneSchema, buildAnalysisPrompt, buildExistingReadmeInstructions, buildGenerationPrompt, extractExistingReadme, parseAnalysis };
344
+
345
+ //# sourceMappingURL=readme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readme.js","names":["Logger"],"sources":["../../src/prompts/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 { Schema } from \"effect\";\n\nimport type { DocumentationStyle } from \"../config.js\";\nimport { Logger } from \"../utils/logger.js\";\n\n// ============================================================================\n// Types & Schemas\n// ============================================================================\n\nexport const DiagramSchema = Schema.Struct({\n\tkeyNodes: Schema.Array(Schema.String),\n\tpurpose: Schema.String,\n\tscope: Schema.String,\n\ttype: Schema.Literal(\"c4-context\", \"er\", \"flowchart\", \"sequence\", \"state\"),\n});\n\nexport const ExistingReadmeSchema = Schema.Struct({\n\timprove: Schema.Array(Schema.String),\n\tmissing: Schema.Array(Schema.String),\n\tpreserve: Schema.Array(Schema.String),\n\tquality: Schema.Literal(\"decent\", \"good\", \"none\", \"poor\"),\n});\n\nexport const IdentitySchema = Schema.Struct({\n\tdifferentiators: Schema.Array(Schema.String),\n\tname: Schema.String,\n\toneLiner: Schema.String,\n});\n\nexport const SectionsSchema = Schema.Struct({\n\trecommended: Schema.Array(Schema.String),\n\tskip: Schema.Array(\n\t\tSchema.Struct({\n\t\t\treason: Schema.String,\n\t\t\tsection: Schema.String,\n\t\t}),\n\t),\n});\n\nexport const ToneSchema = Schema.Literal(\n\t\"casual\",\n\t\"minimal\",\n\t\"professional\",\n\t\"technical\",\n);\nexport type Tone = Schema.Schema.Type<typeof ToneSchema>;\n\nexport const ToneDetectionSchema = Schema.Struct({\n\tdetected: ToneSchema,\n\tevidence: Schema.String,\n});\n\nexport const AnalysisResult = Schema.Struct({\n\tdiagrams: Schema.Array(DiagramSchema),\n\texistingReadme: ExistingReadmeSchema,\n\tidentity: IdentitySchema,\n\trepoType: Schema.String,\n\tsections: SectionsSchema,\n\ttone: ToneDetectionSchema,\n});\nexport type AnalysisResult = Schema.Schema.Type<typeof AnalysisResult>;\n\nexport const GenerationOptions = Schema.Struct({\n\tformat: Schema.Literal(\"md\", \"mdx\"),\n\tstyle: Schema.Literal(\"minimal\", \"standard\", \"comprehensive\"),\n\ttone: Schema.optional(ToneSchema),\n});\nexport type GenerationOptions = Schema.Schema.Type<typeof GenerationOptions>;\n\n// ============================================================================\n// Repo Data Schema\n// ============================================================================\n\nexport const RepoData = Schema.Struct({\n\tcontent: Schema.String,\n\trepo_url: Schema.String,\n\tsummary: Schema.String,\n\ttree: Schema.String,\n});\nexport type RepoData = Schema.Schema.Type<typeof RepoData>;\n\n// ============================================================================\n// Default Fallback\n// ============================================================================\n\nexport const DEFAULT_ANALYSIS: AnalysisResult = {\n\tdiagrams: [],\n\texistingReadme: {\n\t\timprove: [],\n\t\tmissing: [],\n\t\tpreserve: [],\n\t\tquality: \"none\",\n\t},\n\tidentity: {\n\t\tdifferentiators: [],\n\t\tname: \"Unknown\",\n\t\toneLiner: \"\",\n\t},\n\trepoType: \"library\",\n\tsections: {\n\t\trecommended: [\n\t\t\t\"hero\",\n\t\t\t\"overview\",\n\t\t\t\"installation\",\n\t\t\t\"quick-start\",\n\t\t\t\"usage\",\n\t\t\t\"development\",\n\t\t\t\"license\",\n\t\t],\n\t\tskip: [],\n\t},\n\ttone: {\n\t\tdetected: \"professional\",\n\t\tevidence: \"fallback default\",\n\t},\n};\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\nexport function extractExistingReadme(content: string): string | null {\n\tconst readmeMatch =\n\t\t/(?:^|\\n)(?:={3,}|─{3,})?\\s*README\\.md\\s*(?:={3,}|─{3,})?\\n([\\s\\S]*?)(?=\\n(?:={3,}|─{3,})\\s*\\S+\\.\\S+|$)/.exec(\n\t\t\tcontent,\n\t\t);\n\tif (readmeMatch?.[1] && readmeMatch[1].trim().length > 50) {\n\t\treturn readmeMatch[1].trim();\n\t}\n\treturn null;\n}\n\nexport function parseAnalysis(raw: string): AnalysisResult {\n\ttry {\n\t\tconst stripped = raw\n\t\t\t.replace(/^```(?:json)?\\s*/i, \"\")\n\t\t\t.replace(/\\s*```\\s*$/, \"\")\n\t\t\t.trim();\n\n\t\tconst json = JSON.parse(stripped) as unknown;\n\t\tconst result = Schema.decodeUnknownSync(AnalysisResult)(json);\n\n\t\tif (!result.sections.recommended.length) {\n\t\t\tthrow new Error(\"sections.recommended must not be empty\");\n\t\t}\n\n\t\treturn result;\n\t} catch (err) {\n\t\tconst logger = new Logger(\"GREPO:README-PROMPT\");\n\t\tlogger.warn(\n\t\t\t`Failed to parse analysis JSON, falling back to DEFAULT_ANALYSIS. Error: ${\n\t\t\t\terr instanceof Error ? err.message : String(err)\n\t\t\t}`,\n\t\t);\n\t\treturn DEFAULT_ANALYSIS;\n\t}\n}\n\n// ============================================================================\n// Phase 1: Analysis Prompt\n// ============================================================================\n\nexport function buildAnalysisPrompt(\n\trepoData: RepoData,\n\texistingReadme?: string,\n): string {\n\tconst existingReadmeBlock = existingReadme\n\t\t? `\n<existing_readme>\n${existingReadme.slice(0, 4000)}\n</existing_readme>`\n\t\t: \"\";\n\n\treturn `You are an expert technical analyst. Analyze the repository below and return ONLY valid JSON — no markdown fences, no commentary, no extra text.\n\n<output_schema>\n{\n \"repoType\": \"string — e.g. cli-tool, library, web-app, api, monorepo, config, data-pipeline, etc.\",\n \"identity\": {\n \"name\": \"string — canonical project name\",\n \"oneLiner\": \"string — one sentence describing what it does\",\n \"differentiators\": [\"string — unique selling points\"]\n },\n \"tone\": {\n \"detected\": \"casual | professional | minimal | technical\",\n \"evidence\": \"string — quote or observation that led to this conclusion\"\n },\n \"sections\": {\n \"recommended\": [\"string — section keys from the catalog below, in logical order\"],\n \"skip\": [{ \"section\": \"string\", \"reason\": \"string\" }]\n },\n \"diagrams\": [\n {\n \"type\": \"flowchart | sequence | c4-context | er | state\",\n \"purpose\": \"string — what this diagram explains\",\n \"scope\": \"string — what subsystem or flow it covers\",\n \"keyNodes\": [\"string — important nodes or actors\"]\n }\n ],\n \"existingReadme\": {\n \"quality\": \"good | decent | poor | none\",\n \"preserve\": [\"string — sections or content worth keeping verbatim\"],\n \"improve\": [\"string — sections that exist but need rework\"],\n \"missing\": [\"string — important topics not covered\"]\n }\n}\n</output_schema>\n\n<section_catalog>\nhero — project name, tagline, badges\noverview — what it does and why it exists\nfeatures — bullet list of capabilities\narchitecture — system design, component overview\ninstallation — how to install/setup\nquick-start — minimal working example\nusage — detailed usage instructions\ncli-reference — CLI flags and subcommands\napi-reference — public API docs\nconfiguration — env vars, config files\ndevelopment — local dev setup, contributing workflow\ndeployment — how to deploy/release\ncontributing — contribution guidelines\nlicense — license info\n</section_catalog>\n\n<rules>\n- Only recommend sections that have real supporting content in the repository.\n- Recommend at most 2 diagrams. Choose diagram types based on:\n - c4-context: multi-service architectures with external dependencies\n - sequence: request/response workflows or multi-actor interactions\n - flowchart: data pipelines, build processes, or decision trees\n - state: object lifecycle or state machine logic\n - er: data models with relationships\n- Detect tone from existing docs, comments, and README style (if present).\n- Be conservative: fewer well-chosen sections beat a bloated list.\n</rules>\n\n<repository_context>\nurl: ${repoData.repo_url}\nsummary: ${repoData.summary}\n\n<tree>\n${repoData.tree}\n</tree>\n\n<content>\n${repoData.content.slice(0, 8000)}\n</content>\n</repository_context>\n${existingReadmeBlock}`;\n}\n\n// ============================================================================\n// Phase 2: Generation Helpers\n// ============================================================================\n\nexport const STYLE_GUIDANCE: Record<DocumentationStyle, string> = {\n\tcomprehensive:\n\t\t\"Be thorough. Multiple examples, edge cases, full API surface. Expand every recommended section fully.\",\n\tminimal:\n\t\t\"Keep it concise. Favor short sentences and small sections. Omit exhaustive examples. Badge count ≤ 3.\",\n\tstandard:\n\t\t\"Balance depth and brevity. One code example per major section. Moderate badge set. Include a quick-start.\",\n};\n\nexport function buildExistingReadmeInstructions(\n\tanalysis: AnalysisResult,\n): string {\n\tif (analysis.existingReadme.quality === \"none\") {\n\t\treturn \"No existing README was found. Generate the document from scratch.\";\n\t}\n\n\tconst lines: string[] = [\n\t\t`Existing README quality: ${analysis.existingReadme.quality}.`,\n\t];\n\n\tif (analysis.existingReadme.preserve.length > 0) {\n\t\tlines.push(\n\t\t\t`Preserve the following content verbatim where possible:\\n${analysis.existingReadme.preserve.map((s) => ` - ${s}`).join(\"\\n\")}`,\n\t\t);\n\t}\n\n\tif (analysis.existingReadme.improve.length > 0) {\n\t\tlines.push(\n\t\t\t`Improve (rewrite/expand) these sections:\\n${analysis.existingReadme.improve.map((s) => ` - ${s}`).join(\"\\n\")}`,\n\t\t);\n\t}\n\n\tif (analysis.existingReadme.missing.length > 0) {\n\t\tlines.push(\n\t\t\t`Add these missing topics:\\n${analysis.existingReadme.missing.map((s) => ` - ${s}`).join(\"\\n\")}`,\n\t\t);\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n\n// ============================================================================\n// Phase 2: Generation Prompt\n// ============================================================================\n\nexport function buildGenerationPrompt(\n\tanalysis: AnalysisResult,\n\trepoData: RepoData,\n\toptions: GenerationOptions,\n): string {\n\tconst effectiveTone: Tone = options.tone ?? analysis.tone.detected;\n\n\tconst toneDescriptions: Record<Tone, string> = {\n\t\tcasual:\n\t\t\t\"Friendly, approachable, first-person plural ('we'). Use contractions. Short paragraphs. Light humor is fine.\",\n\t\tminimal:\n\t\t\t\"Extremely terse. Bullet points over prose. No introductory fluff. Every word must earn its place.\",\n\t\tprofessional:\n\t\t\t\"Clear, precise, authoritative. Third-person or imperative. No jargon without definition. Avoid filler words.\",\n\t\ttechnical:\n\t\t\t\"Assume a developer audience. Use correct terminology. Include type signatures, flags, and internals where relevant.\",\n\t};\n\n\treturn `You are a senior technical writer generating a README for a software project.\n\n<output_rules>\n- Output ONLY the raw ${options.format.toUpperCase()} content. No preamble, no explanation, no markdown fences wrapping the whole document.\n- Only generate the sections listed in recommended_sections below. Do not add extras.\n- No generic filler phrases like \"In this section we will…\" or \"This project is a…\".\n- Mermaid diagrams must follow diagram_rules exactly.\n</output_rules>\n\n<analysis>\n${JSON.stringify(analysis, null, 2)}\n</analysis>\n\n<recommended_sections>\n${analysis.sections.recommended.join(\", \")}\n</recommended_sections>\n\n<tone>\nStyle: ${effectiveTone}\nDescription: ${toneDescriptions[effectiveTone]}\n</tone>\n\n<diagram_rules>\nCRITICAL SYNTAX RULES (violations cause render errors):\n- Wrap ALL node labels in quotes if they contain spaces, special chars, or parentheses: A[\"My Label\"]\n- NEVER use bare parentheses in labels — use quotes: A[\"Deploy (prod)\"] NOT A[Deploy (prod)]\n- NEVER use colons in labels without quotes: A[\"Step: Init\"] NOT A[Step: Init]\n- Arrow syntax: use --> for solid, -.-> for dotted. NEVER use -> alone in flowcharts.\n- Subgraph IDs must not contain spaces: subgraph auth_flow[\"Auth Flow\"]\n- Semicolons are NOT terminators — do not end lines with ;\n- Each node definition must be on its own line.\n\nSTYLE RULES:\n- Use descriptive labels on all nodes — never single letters like A, B, C.\n- Add meaningful labels on edges to describe data flow or actions.\n- Use subgraphs to group related nodes into logical clusters.\n- Limit diagrams to 15 nodes maximum.\n\nTYPE-SPECIFIC TEMPLATES (follow these exactly):\n\nflowchart (always TD):\n\\`\\`\\`mermaid\nflowchart TD\n A[\"User Request\"] --> B{\"Auth Valid?\"}\n B -->|Yes| C[\"Process Request\"]\n B -->|No| D[\"Return 401\"]\n C --> E[\"Send Response\"]\n\\`\\`\\`\n\nsequence:\n\\`\\`\\`mermaid\nsequenceDiagram\n actor User\n participant API\n participant DB\n User->>API: POST /login\n activate API\n API->>DB: Query user\n DB-->>API: User record\n API-->>User: JWT token\n deactivate API\n\\`\\`\\`\n\nc4-context (use C4Context):\n\\`\\`\\`mermaid\nC4Context\n Person(user, \"Developer\", \"Uses the CLI tool\")\n System(cli, \"CLI\", \"Command-line interface\")\n System_Ext(api, \"GitHub API\", \"Repository management\")\n Rel(user, cli, \"Runs commands\")\n Rel(cli, api, \"REST calls\")\n\\`\\`\\`\n\ner:\n\\`\\`\\`mermaid\nerDiagram\n USER ||--o{ ORDER : places\n ORDER ||--|{ LINE_ITEM : contains\n PRODUCT ||--o{ LINE_ITEM : \"ordered in\"\n\\`\\`\\`\n\nstate:\n\\`\\`\\`mermaid\nstateDiagram-v2\n [*] --> Idle\n Idle --> Processing : start\n Processing --> Done : complete\n Processing --> Failed : error\n Failed --> Idle : retry\n Done --> [*]\n\\`\\`\\`\n\nCOMMON MISTAKES TO AVOID:\n- Using \"graph\" instead of \"flowchart\"\n- Missing quotes around labels with special characters\n- Using C4_Context instead of C4Context\n- Forgetting \"activate/deactivate\" in sequence diagrams\n- Using --> in sequence diagrams (use ->> or -->> instead)\n</diagram_rules>\n\n<existing_readme_handling>\n${buildExistingReadmeInstructions(analysis)}\n</existing_readme_handling>\n\n<style_profile>\nDocumentation style: ${options.style}\n${STYLE_GUIDANCE[options.style]}\n</style_profile>\n\n<repository_context>\nurl: ${repoData.repo_url}\nsummary: ${repoData.summary}\n\n<tree>\n${repoData.tree}\n</tree>\n\n<content>\n${repoData.content}\n</content>\n</repository_context>`;\n}\n"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { GeminiError, GitHubError, GitIngestError } from "./errors.js";
2
+ import { GitIngestResponse } from "./utils/gitingest.js";
3
+ import { Context, Effect, Layer, Schema } from "effect";
4
+
5
+ //#region src/services.d.ts
6
+
7
+ interface GeminiServiceApi {
8
+ readonly generateContent: (prompt: string) => Effect.Effect<string, GeminiError>;
9
+ }
10
+ declare const Gemini_base: Context.TagClass<Gemini, "Gemini", GeminiServiceApi>;
11
+ declare class Gemini extends Gemini_base {}
12
+ declare const GeminiLive: (apiKey: string) => Layer.Layer<Gemini, never, never>;
13
+ interface GitHubServiceApi {
14
+ readonly getTopics: (owner: string, repo: string) => Effect.Effect<readonly string[], GitHubError>;
15
+ readonly pushFile: (owner: string, repo: string, path: string, content: string, message: string, branch: string) => Effect.Effect<void, GitHubError>;
16
+ readonly setTopics: (owner: string, repo: string, topics: string[]) => Effect.Effect<void, GitHubError>;
17
+ readonly updateRepo: (owner: string, repo: string, data: {
18
+ description?: string;
19
+ homepage?: string;
20
+ }) => Effect.Effect<void, GitHubError>;
21
+ }
22
+ declare const GitHub_base: Context.TagClass<GitHub, "GitHub", GitHubServiceApi>;
23
+ declare class GitHub extends GitHub_base {}
24
+ declare const GitHubLive: (token?: string) => Layer.Layer<GitHub, never, never>;
25
+ type RepoData = Schema.Schema.Type<typeof GitIngestResponse>;
26
+ declare const fetchRepo: (repoUrl: string) => Effect.Effect<RepoData, GitIngestError>;
27
+ //#endregion
28
+ export { Gemini, GeminiLive, GeminiServiceApi, GitHub, GitHubLive, GitHubServiceApi, RepoData, fetchRepo };
29
+ //# sourceMappingURL=services.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,59 @@
1
+ import { GeminiError, GitHubError, GitIngestError } from "./errors.js";
2
+ import { GeminiService } from "./utils/gemini.js";
3
+ import { GitHubClient } from "./utils/github.js";
4
+ import { fetchRepositoryContent } from "./utils/gitingest.js";
5
+ import { Context, Effect, Layer } from "effect";
6
+ //#region src/services.ts
7
+ var Gemini = class extends Context.Tag("Gemini")() {};
8
+ const GeminiLive = (apiKey) => Layer.succeed(Gemini, { generateContent: (prompt) => Effect.tryPromise({
9
+ catch: (error) => new GeminiError({
10
+ cause: error,
11
+ message: error instanceof Error ? error.message : String(error)
12
+ }),
13
+ try: () => new GeminiService(apiKey).generateContent(prompt)
14
+ }) });
15
+ var GitHub = class extends Context.Tag("GitHub")() {};
16
+ const GitHubLive = (token) => {
17
+ const client = new GitHubClient(token);
18
+ return Layer.succeed(GitHub, {
19
+ getTopics: (owner, repo) => Effect.tryPromise({
20
+ catch: (error) => new GitHubError({
21
+ endpoint: `repos/${owner}/${repo}/topics`,
22
+ message: error instanceof Error ? error.message : String(error)
23
+ }),
24
+ try: () => client.getTopics(owner, repo)
25
+ }),
26
+ pushFile: (owner, repo, path, content, message, branch) => Effect.tryPromise({
27
+ catch: (error) => new GitHubError({
28
+ endpoint: `repos/${owner}/${repo}/contents/${path}`,
29
+ message: error instanceof Error ? error.message : String(error)
30
+ }),
31
+ try: () => client.pushFile(owner, repo, path, content, message, branch)
32
+ }),
33
+ setTopics: (owner, repo, topics) => Effect.tryPromise({
34
+ catch: (error) => new GitHubError({
35
+ endpoint: `repos/${owner}/${repo}/topics`,
36
+ message: error instanceof Error ? error.message : String(error)
37
+ }),
38
+ try: () => client.setTopics(owner, repo, topics)
39
+ }),
40
+ updateRepo: (owner, repo, data) => Effect.tryPromise({
41
+ catch: (error) => new GitHubError({
42
+ endpoint: `repos/${owner}/${repo}`,
43
+ message: error instanceof Error ? error.message : String(error)
44
+ }),
45
+ try: () => client.updateRepo(owner, repo, data)
46
+ })
47
+ });
48
+ };
49
+ const fetchRepo = (repoUrl) => Effect.tryPromise({
50
+ catch: (error) => new GitIngestError({
51
+ cause: error,
52
+ message: error instanceof Error ? error.message : String(error)
53
+ }),
54
+ try: () => fetchRepositoryContent(repoUrl)
55
+ });
56
+ //#endregion
57
+ export { Gemini, GeminiLive, GitHub, GitHubLive, fetchRepo };
58
+
59
+ //# sourceMappingURL=services.js.map
@@ -0,0 +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"}
@@ -0,0 +1,15 @@
1
+ import { Schema } from "effect";
2
+
3
+ //#region src/utils/args.d.ts
4
+
5
+ declare const ParsedArgs: Schema.Struct<{
6
+ options: Schema.Record$<typeof Schema.String, Schema.Union<[typeof Schema.String, typeof Schema.Boolean]>>;
7
+ positional: Schema.Array$<typeof Schema.String>;
8
+ }>;
9
+ type ParsedArgs = Schema.Schema.Type<typeof ParsedArgs>;
10
+ declare function parseArgs(args: string[], booleanFlags?: string[]): ParsedArgs;
11
+ declare const SEPARATOR: string;
12
+ declare function displayHeader(title: string, details: Record<string, string>): void;
13
+ //#endregion
14
+ export { ParsedArgs, SEPARATOR, displayHeader, parseArgs };
15
+ //# sourceMappingURL=args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.d.ts","names":[],"sources":["../../src/utils/args.ts"],"sourcesContent":[],"mappings":";;;;cAoBM,YAAU,MAAA,CAAA;;;;KAQJ,UAAA,GAAa,MAAA,CAAO,MAAA,CAAO,YAAY;iBAEnC,SAAA,2CAGb;cAyCU;iBAEG,aAAA,yBAEN"}
@@ -0,0 +1,70 @@
1
+ import { Schema } from "effect";
2
+ //#region src/utils/args.ts
3
+ /**
4
+ *
5
+ * Copyright 2026 Mike Odnis
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ *
19
+ */
20
+ Schema.Struct({
21
+ options: Schema.Record({
22
+ key: Schema.String,
23
+ value: Schema.Union(Schema.String, Schema.Boolean)
24
+ }),
25
+ positional: Schema.Array(Schema.String)
26
+ });
27
+ function parseArgs(args, booleanFlags = []) {
28
+ const positional = [];
29
+ const options = {};
30
+ for (let i = 0; i < args.length; i++) {
31
+ const arg = args[i];
32
+ if (!arg) continue;
33
+ if (arg.startsWith("--")) {
34
+ const longArg = arg.slice(2);
35
+ if (longArg.includes("=")) {
36
+ const [key, ...valueParts] = longArg.split("=");
37
+ if (key) options[key] = valueParts.join("=");
38
+ continue;
39
+ }
40
+ const key = longArg;
41
+ const nextArg = args[i + 1];
42
+ if (booleanFlags.includes(key)) {
43
+ options[key] = true;
44
+ continue;
45
+ }
46
+ if (nextArg && !nextArg.startsWith("--")) {
47
+ options[key] = nextArg;
48
+ i++;
49
+ } else options[key] = true;
50
+ } else positional.push(arg);
51
+ }
52
+ return {
53
+ options,
54
+ positional
55
+ };
56
+ }
57
+ const SEPARATOR = "=".repeat(80);
58
+ function displayHeader(title, details) {
59
+ console.log();
60
+ console.log(SEPARATOR);
61
+ console.log(` 🚀 ${title}`);
62
+ console.log(SEPARATOR);
63
+ for (const [key, value] of Object.entries(details)) console.log(` • ${key}: ${value}`);
64
+ console.log(SEPARATOR);
65
+ console.log();
66
+ }
67
+ //#endregion
68
+ export { SEPARATOR, displayHeader, parseArgs };
69
+
70
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","names":[],"sources":["../../src/utils/args.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 { Schema } from \"effect\";\n\nconst ParsedArgs = Schema.Struct({\n\toptions: Schema.Record({\n\t\tkey: Schema.String,\n\t\tvalue: Schema.Union(Schema.String, Schema.Boolean),\n\t}),\n\tpositional: Schema.Array(Schema.String),\n});\n\nexport type ParsedArgs = Schema.Schema.Type<typeof ParsedArgs>;\n\nexport function parseArgs(\n\targs: string[],\n\tbooleanFlags: string[] = [],\n): ParsedArgs {\n\tconst positional: string[] = [];\n\tconst options: Record<string, boolean | string> = {};\n\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst arg = args[i];\n\t\tif (!arg) continue;\n\n\t\tif (arg.startsWith(\"--\")) {\n\t\t\tconst longArg = arg.slice(2);\n\n\t\t\tif (longArg.includes(\"=\")) {\n\t\t\t\tconst [key, ...valueParts] = longArg.split(\"=\");\n\t\t\t\tif (key) {\n\t\t\t\t\toptions[key] = valueParts.join(\"=\");\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst key = longArg;\n\t\t\tconst nextArg = args[i + 1];\n\n\t\t\tif (booleanFlags.includes(key)) {\n\t\t\t\toptions[key] = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (nextArg && !nextArg.startsWith(\"--\")) {\n\t\t\t\toptions[key] = nextArg;\n\t\t\t\ti++;\n\t\t\t} else {\n\t\t\t\toptions[key] = true;\n\t\t\t}\n\t\t} else {\n\t\t\tpositional.push(arg);\n\t\t}\n\t}\n\n\treturn { options, positional };\n}\n\nexport const SEPARATOR = \"=\".repeat(80);\n\nexport function displayHeader(\n\ttitle: string,\n\tdetails: Record<string, string>,\n): void {\n\tconsole.log();\n\tconsole.log(SEPARATOR);\n\tconsole.log(` 🚀 ${title}`);\n\tconsole.log(SEPARATOR);\n\tfor (const [key, value] of Object.entries(details)) {\n\t\tconsole.log(` • ${key}: ${value}`);\n\t}\n\tconsole.log(SEPARATOR);\n\tconsole.log();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoBmB,OAAO,OAAO;CAChC,SAAS,OAAO,OAAO;EACtB,KAAK,OAAO;EACZ,OAAO,OAAO,MAAM,OAAO,QAAQ,OAAO,QAAQ;EAClD,CAAC;CACF,YAAY,OAAO,MAAM,OAAO,OAAO;CACvC,CAAC;AAIF,SAAgB,UACf,MACA,eAAyB,EAAE,EACd;CACb,MAAM,aAAuB,EAAE;CAC/B,MAAM,UAA4C,EAAE;AAEpD,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACrC,MAAM,MAAM,KAAK;AACjB,MAAI,CAAC,IAAK;AAEV,MAAI,IAAI,WAAW,KAAK,EAAE;GACzB,MAAM,UAAU,IAAI,MAAM,EAAE;AAE5B,OAAI,QAAQ,SAAS,IAAI,EAAE;IAC1B,MAAM,CAAC,KAAK,GAAG,cAAc,QAAQ,MAAM,IAAI;AAC/C,QAAI,IACH,SAAQ,OAAO,WAAW,KAAK,IAAI;AAEpC;;GAGD,MAAM,MAAM;GACZ,MAAM,UAAU,KAAK,IAAI;AAEzB,OAAI,aAAa,SAAS,IAAI,EAAE;AAC/B,YAAQ,OAAO;AACf;;AAGD,OAAI,WAAW,CAAC,QAAQ,WAAW,KAAK,EAAE;AACzC,YAAQ,OAAO;AACf;SAEA,SAAQ,OAAO;QAGhB,YAAW,KAAK,IAAI;;AAItB,QAAO;EAAE;EAAS;EAAY;;AAG/B,MAAa,YAAY,IAAI,OAAO,GAAG;AAEvC,SAAgB,cACf,OACA,SACO;AACP,SAAQ,KAAK;AACb,SAAQ,IAAI,UAAU;AACtB,SAAQ,IAAI,QAAQ,QAAQ;AAC5B,SAAQ,IAAI,UAAU;AACtB,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CACjD,SAAQ,IAAI,OAAO,IAAI,IAAI,QAAQ;AAEpC,SAAQ,IAAI,UAAU;AACtB,SAAQ,KAAK"}
@@ -0,0 +1,44 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { HttpClient } from "@effect/platform";
3
+
4
+ //#region src/utils/fetcher.d.ts
5
+
6
+ interface FetcherOptions<T = unknown> {
7
+ bodyType?: "json" | "text";
8
+ headers?: Record<string, string>;
9
+ onError?: (error: unknown) => void;
10
+ retries?: number;
11
+ retryDelay?: number;
12
+ schema?: Schema.Schema<T, any, never>;
13
+ signal?: AbortSignal;
14
+ timeout?: number;
15
+ }
16
+ type HttpMethod = "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT";
17
+ type QueryParams = Record<string, boolean | null | number | string | undefined | Array<boolean | number | string>>;
18
+ type RequestBody = boolean | null | number | string | unknown[] | Record<string, unknown>;
19
+ declare class ValidationError extends Error {
20
+ readonly url: string;
21
+ readonly problems: string;
22
+ readonly responseData: unknown;
23
+ readonly attempt?: number | undefined;
24
+ constructor(message: string, url: string, problems: string, responseData: unknown, attempt?: number | undefined);
25
+ toString(): string;
26
+ getProblemsString(): string;
27
+ }
28
+ declare class FetcherError extends Error {
29
+ readonly url: string;
30
+ readonly status?: number | undefined;
31
+ readonly responseData?: unknown | undefined;
32
+ readonly attempt?: number | undefined;
33
+ constructor(message: string, url: string, status?: number | undefined, responseData?: unknown | undefined, attempt?: number | undefined);
34
+ toString(): string;
35
+ }
36
+ declare function fetcher<T = unknown>(input: string, method?: HttpMethod, options?: FetcherOptions<T>, params?: QueryParams, body?: RequestBody): Effect.Effect<T, FetcherError | ValidationError, HttpClient.HttpClient>;
37
+ declare function get<T = unknown>(url: string, options?: FetcherOptions<T>, params?: QueryParams): Effect.Effect<T, ValidationError | FetcherError, HttpClient.HttpClient>;
38
+ declare function post<T = unknown>(url: string, body?: RequestBody, options?: FetcherOptions<T>, params?: QueryParams): Effect.Effect<T, ValidationError | FetcherError, HttpClient.HttpClient>;
39
+ declare function put<T = unknown>(url: string, body?: RequestBody, options?: FetcherOptions<T>, params?: QueryParams): Effect.Effect<T, ValidationError | FetcherError, HttpClient.HttpClient>;
40
+ declare function patch<T = unknown>(url: string, body?: RequestBody, options?: FetcherOptions<T>, params?: QueryParams): Effect.Effect<T, ValidationError | FetcherError, HttpClient.HttpClient>;
41
+ declare function del<T = unknown>(url: string, options?: FetcherOptions<T>, params?: QueryParams): Effect.Effect<T, ValidationError | FetcherError, HttpClient.HttpClient>;
42
+ //#endregion
43
+ export { FetcherError, FetcherOptions, HttpMethod, QueryParams, RequestBody, ValidationError, del, fetcher, get, patch, post, put };
44
+ //# sourceMappingURL=fetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.d.ts","names":[],"sources":["../../src/utils/fetcher.ts"],"sourcesContent":[],"mappings":"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"}