agent-md-generator 0.1.0 → 0.1.1

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 (4) hide show
  1. package/README.md +84 -119
  2. package/dist/cli.js +1541 -0
  3. package/package.json +15 -40
  4. package/dist/cli.mjs +0 -456
package/package.json CHANGED
@@ -1,59 +1,34 @@
1
1
  {
2
2
  "name": "agent-md-generator",
3
- "version": "0.1.0",
4
- "description": "Generate production-grade AGENT.md files for your project via an interactive terminal wizard.",
3
+ "version": "0.1.1",
4
+ "description": "Generate production-grade AGENT.md files via an interactive terminal wizard.",
5
5
  "keywords": ["agent", "ai", "claude", "cursor", "kiro", "copilot", "cli", "generator"],
6
6
  "homepage": "https://agent-md-generator.edwinfom.dev",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/Edwinfom00/agent-md-generator"
9
+ "url": "https://github.com/Edwinfom00/agent.md-generator"
10
10
  },
11
11
  "license": "MIT",
12
12
  "author": "Edwin Fom",
13
- "engines": {
14
- "node": ">=20"
15
- },
16
- "files": [
17
- "dist/cli.mjs",
18
- "README.md"
19
- ],
20
- "bin": {
21
- "agent-md-generator": "./dist/cli.mjs"
22
- },
13
+ "engines": { "node": ">=20" },
14
+ "files": ["dist/cli.js", "README.md"],
15
+ "type": "module",
16
+ "bin": "dist/cli.js",
23
17
  "scripts": {
24
- "dev": "next dev",
25
- "build": "next build",
26
- "build:cli": "tsup",
27
- "cli": "node ./dist/cli.mjs",
28
- "start": "next start",
29
- "lint": "eslint"
18
+ "build": "tsup",
19
+ "dev": "tsup --watch"
30
20
  },
31
21
  "dependencies": {
22
+ "@agent-md/shared": "workspace:*",
32
23
  "@ai-sdk/deepseek": "^2.0.35",
33
- "@upstash/ratelimit": "^2.0.8",
34
- "@upstash/redis": "^1.38.0",
24
+ "@ai-sdk/google": "^1.0.0",
25
+ "@ai-sdk/xai": "^1.0.0",
26
+ "ollama-ai-provider": "^0.16.0",
35
27
  "ai": "^6.0.184",
36
- "clsx": "^2.1.1",
37
- "framer-motion": "^12.39.0",
38
- "lucide-react": "^1.16.0",
39
- "next": "16.2.6",
40
- "react": "19.2.4",
41
- "react-dom": "19.2.4",
42
- "react-icons": "^5.6.0",
43
- "react-markdown": "^10.1.0",
44
- "remark-gfm": "^4.0.1",
45
- "tailwind-merge": "^3.6.0",
46
28
  "@clack/prompts": "^0.9.1"
47
29
  },
48
30
  "devDependencies": {
49
- "@tailwindcss/postcss": "^4",
50
- "@types/node": "^20",
51
- "@types/react": "^19",
52
- "@types/react-dom": "^19",
53
- "eslint": "^9",
54
- "eslint-config-next": "16.2.6",
55
- "tailwindcss": "^4",
56
- "typescript": "^5",
57
- "tsup": "^8.5.0"
31
+ "tsup": "^8.5.0",
32
+ "typescript": "^5"
58
33
  }
59
34
  }
package/dist/cli.mjs DELETED
@@ -1,456 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // cli/index.ts
4
- import * as p2 from "@clack/prompts";
5
- import { existsSync, readFileSync, writeFileSync } from "fs";
6
- import { resolve } from "path";
7
-
8
- // src/lib/questions.ts
9
- var QUESTIONS = [
10
- {
11
- id: "project_name",
12
- step: 1,
13
- category: "Identity",
14
- question: "What is the name of your project?",
15
- hint: "This will be the main title of your AGENT.md",
16
- type: "text",
17
- placeholder: "e.g. MyApp, Preflight, DeutschFlow...",
18
- required: true
19
- },
20
- {
21
- id: "project_type",
22
- step: 1,
23
- category: "Identity",
24
- question: "What type of project is this?",
25
- hint: "This defines the overall architecture and conventions",
26
- type: "select",
27
- required: true,
28
- options: [
29
- { value: "web_app", label: "Web Application", description: "Next.js, React, Vue, SvelteKit..." },
30
- { value: "mobile_app", label: "Mobile Application", description: "React Native, Expo, Flutter..." },
31
- { value: "vscode_extension", label: "VS Code Extension", description: "TypeScript, VS Code API..." },
32
- { value: "npm_package", label: "npm Package / Library", description: "TypeScript library, SDK, CLI..." },
33
- { value: "api_backend", label: "API / Backend", description: "Express, Fastify, NestJS, Hono..." },
34
- { value: "fullstack", label: "Full-Stack Application", description: "Frontend + Backend in one repo" },
35
- { value: "cli_tool", label: "CLI Tool", description: "Command-line application" },
36
- { value: "other", label: "Other", description: "Something else entirely" }
37
- ]
38
- },
39
- {
40
- id: "mobile_platforms",
41
- step: 1,
42
- category: "Identity",
43
- question: "What mobile platforms will you target?",
44
- hint: "Affects build config, testing setup, and platform-specific code conventions",
45
- type: "select",
46
- required: false,
47
- dependsOn: { questionId: "project_type", value: "mobile_app" },
48
- options: [
49
- { value: "ios_only", label: "iOS only", description: "Target Apple devices only" },
50
- { value: "android_only", label: "Android only", description: "Target Android devices only" },
51
- { value: "both", label: "iOS + Android", description: "Cross-platform for both" }
52
- ]
53
- },
54
- {
55
- id: "npm_distribution",
56
- step: 1,
57
- category: "Identity",
58
- question: "How will your package be distributed?",
59
- hint: "Affects build output, bundler config, and import conventions",
60
- type: "select",
61
- required: false,
62
- dependsOn: { questionId: "project_type", value: "npm_package" },
63
- options: [
64
- { value: "esm_only", label: "ESM only", description: "Modern ESM-only package" },
65
- { value: "cjs_esm", label: "CommonJS + ESM", description: "Dual-format for broad compatibility" },
66
- { value: "browser_node", label: "Browser + Node.js", description: "Universal package for both environments" }
67
- ]
68
- },
69
- {
70
- id: "project_description",
71
- step: 1,
72
- category: "Identity",
73
- question: "Describe your project in 2-3 sentences.",
74
- hint: "What does it do? Who is it for? What problem does it solve?",
75
- type: "textarea",
76
- placeholder: "e.g. Preflight is a VS Code extension that helps developers ship cleaner code by detecting debug statements, tracking TODOs with deadlines, and generating AI-powered commit messages...",
77
- required: true
78
- },
79
- {
80
- id: "tech_stack",
81
- step: 2,
82
- category: "Tech Stack",
83
- question: "What is your primary tech stack?",
84
- hint: "Select all that apply to your project",
85
- type: "multiselect",
86
- required: true,
87
- options: [
88
- { value: "typescript", label: "TypeScript" },
89
- { value: "javascript", label: "JavaScript" },
90
- { value: "react", label: "React" },
91
- { value: "nextjs", label: "Next.js" },
92
- { value: "react_native", label: "React Native" },
93
- { value: "expo", label: "Expo" },
94
- { value: "tailwind", label: "Tailwind CSS" },
95
- { value: "nodejs", label: "Node.js" },
96
- { value: "python", label: "Python" },
97
- { value: "go", label: "Go" },
98
- { value: "rust", label: "Rust" },
99
- { value: "prisma", label: "Prisma" },
100
- { value: "supabase", label: "Supabase" },
101
- { value: "vercel_ai", label: "Vercel AI SDK" },
102
- { value: "zustand", label: "Zustand" },
103
- { value: "zod", label: "Zod" }
104
- ]
105
- },
106
- {
107
- id: "ai_features",
108
- step: 2,
109
- category: "Tech Stack",
110
- question: "Does your project use AI / LLM features?",
111
- type: "select",
112
- required: true,
113
- options: [
114
- { value: "yes_core", label: "Yes \u2014 AI is a core feature", description: "The app is built around AI capabilities" },
115
- { value: "yes_secondary", label: "Yes \u2014 AI is a secondary feature", description: "AI enhances some features but is not the core" },
116
- { value: "no", label: "No AI features", description: "Pure logic, no LLM integration" }
117
- ]
118
- },
119
- {
120
- id: "ai_providers",
121
- step: 2,
122
- category: "Tech Stack",
123
- question: "Which AI providers will you use?",
124
- hint: "Select all that apply",
125
- type: "multiselect",
126
- required: false,
127
- dependsOn: { questionId: "ai_features", value: ["yes_core", "yes_secondary"] },
128
- options: [
129
- { value: "openai", label: "OpenAI" },
130
- { value: "anthropic", label: "Anthropic (Claude)" },
131
- { value: "deepseek", label: "DeepSeek" },
132
- { value: "google", label: "Google Gemini" },
133
- { value: "ollama", label: "Ollama (local)" },
134
- { value: "model_agnostic", label: "Model-agnostic (any provider)" }
135
- ]
136
- },
137
- {
138
- id: "python_framework",
139
- step: 2,
140
- category: "Tech Stack",
141
- question: "Which Python framework are you using?",
142
- hint: "Determines routing, ORM, and project structure conventions",
143
- type: "select",
144
- required: false,
145
- dependsOn: { questionId: "tech_stack", value: "python" },
146
- options: [
147
- { value: "django", label: "Django", description: "Full-stack web framework with ORM" },
148
- { value: "fastapi", label: "FastAPI", description: "Modern async API framework" },
149
- { value: "flask", label: "Flask", description: "Lightweight WSGI microframework" },
150
- { value: "none", label: "No framework", description: "Pure Python / scripts" }
151
- ]
152
- },
153
- {
154
- id: "folder_structure",
155
- step: 3,
156
- category: "Architecture",
157
- question: "Describe your folder structure.",
158
- hint: "List the main folders and what they contain. The AI will use this to enforce conventions.",
159
- type: "textarea",
160
- placeholder: `src/
161
- app/ <- Next.js App Router pages
162
- components/ <- reusable UI components
163
- lib/ <- utilities and helpers
164
- types/ <- TypeScript types
165
- hooks/ <- custom React hooks`,
166
- required: true
167
- },
168
- {
169
- id: "coding_conventions",
170
- step: 3,
171
- category: "Architecture",
172
- question: "What are your most important coding conventions?",
173
- hint: "Rules the AI must always follow when writing code for this project",
174
- type: "multiselect",
175
- required: true,
176
- options: [
177
- { value: "no_any", label: "No TypeScript any", description: "Strict typing, use unknown instead" },
178
- { value: "no_comments", label: "No code comments", description: "Code must be self-documenting" },
179
- { value: "functional", label: "Functional components only", description: "No class components" },
180
- { value: "server_components", label: "Prefer Server Components", description: "Use client components only when needed" },
181
- { value: "named_exports", label: "Named exports only", description: "No default exports" },
182
- { value: "small_files", label: "Small focused files", description: "One responsibility per file" },
183
- { value: "no_overengineering", label: "No overengineering", description: "Build the simplest thing that works" },
184
- { value: "modular", label: "Modular architecture", description: "Clear separation of concerns" },
185
- { value: "error_handling", label: "Explicit error handling", description: "Always handle errors gracefully" },
186
- { value: "env_secrets", label: "No secrets in frontend", description: "API keys only in server/env" }
187
- ]
188
- },
189
- {
190
- id: "ui_style",
191
- step: 3,
192
- category: "Architecture",
193
- question: "What is the UI style and tone?",
194
- hint: "How should the interface feel?",
195
- type: "multiselect",
196
- required: false,
197
- dependsOn: { questionId: "project_type", value: ["web_app", "mobile_app", "fullstack"] },
198
- options: [
199
- { value: "modern", label: "Modern & minimal" },
200
- { value: "playful", label: "Playful & friendly" },
201
- { value: "premium", label: "Premium & polished" },
202
- { value: "dark", label: "Dark theme first" },
203
- { value: "accessible", label: "Accessibility first" },
204
- { value: "mobile_first", label: "Mobile first" },
205
- { value: "pixel_perfect", label: "Pixel-perfect from designs" }
206
- ]
207
- },
208
- {
209
- id: "constraints",
210
- step: 4,
211
- category: "Constraints",
212
- question: "What are the hard constraints for this project?",
213
- hint: "Things the AI must NEVER do in this project",
214
- type: "multiselect",
215
- required: true,
216
- options: [
217
- { value: "no_db", label: "No database", description: "Use local state or files only" },
218
- { value: "no_auth", label: "No authentication", description: "No login or user accounts" },
219
- { value: "no_new_deps", label: "No new dependencies without approval", description: "Ask before adding packages" },
220
- { value: "no_telemetry", label: "No telemetry or tracking", description: "No analytics or user tracking" },
221
- { value: "no_breaking_changes", label: "No breaking API changes", description: "Maintain backward compatibility" },
222
- { value: "offline_first", label: "Offline first", description: "Must work without internet" },
223
- { value: "lightweight", label: "Keep it lightweight", description: "Minimize bundle size" },
224
- { value: "no_class_components", label: "No class components" }
225
- ]
226
- },
227
- {
228
- id: "dev_philosophy",
229
- step: 4,
230
- category: "Constraints",
231
- question: "What is your development philosophy?",
232
- hint: "How should the AI approach building features?",
233
- type: "select",
234
- required: true,
235
- options: [
236
- { value: "mvp_first", label: "MVP first, iterate later", description: "Build the smallest useful version, then improve" },
237
- { value: "production_grade", label: "Production-grade from day one", description: "Build it right the first time" },
238
- { value: "teachable", label: "Teachable & approachable", description: "Code should be easy to understand and explain" },
239
- { value: "performance", label: "Performance first", description: "Optimize for speed and efficiency" }
240
- ]
241
- },
242
- {
243
- id: "extra_context",
244
- step: 4,
245
- category: "Constraints",
246
- question: "Any additional context or special instructions?",
247
- hint: "Anything else the AI should know \u2014 edge cases, specific patterns, important decisions already made...",
248
- type: "textarea",
249
- placeholder: "e.g. This project uses the Vercel AI SDK for all LLM calls. The API keys are stored in .env.local and never exposed to the client. The app is deployed on Vercel...",
250
- required: false
251
- }
252
- ];
253
- function isQuestionVisible(question, answers) {
254
- if (!question.dependsOn) return true;
255
- const { questionId, value } = question.dependsOn;
256
- const answer = answers[questionId];
257
- if (!answer) return false;
258
- if (Array.isArray(value)) {
259
- if (Array.isArray(answer)) return value.some((v) => answer.includes(v));
260
- return value.includes(answer);
261
- }
262
- if (Array.isArray(answer)) return answer.includes(value);
263
- return answer === value;
264
- }
265
-
266
- // src/lib/buildPrompt.ts
267
- function getLabel(questionId, value) {
268
- const question = QUESTIONS.find((q) => q.id === questionId);
269
- if (!question?.options) return Array.isArray(value) ? value.join(", ") : value;
270
- if (Array.isArray(value)) {
271
- return value.map((v) => question.options?.find((o) => o.value === v)?.label ?? v).join(", ");
272
- }
273
- return question.options.find((o) => o.value === value)?.label ?? value;
274
- }
275
- function buildPrompt(answers) {
276
- const projectName = answers["project_name"] ?? "My Project";
277
- const projectType = getLabel("project_type", answers["project_type"] ?? "");
278
- const description = answers["project_description"] ?? "";
279
- const mobilePlatforms = answers["mobile_platforms"] ? getLabel("mobile_platforms", answers["mobile_platforms"]) : null;
280
- const npmDistribution = answers["npm_distribution"] ? getLabel("npm_distribution", answers["npm_distribution"]) : null;
281
- const techStack = getLabel("tech_stack", answers["tech_stack"] ?? []);
282
- const pythonFramework = answers["python_framework"] ? getLabel("python_framework", answers["python_framework"]) : null;
283
- const aiFeatures = getLabel("ai_features", answers["ai_features"] ?? "no");
284
- const aiProviders = answers["ai_providers"] ? getLabel("ai_providers", answers["ai_providers"]) : "None";
285
- const folderStructure = answers["folder_structure"] ?? "";
286
- const conventions = getLabel("coding_conventions", answers["coding_conventions"] ?? []);
287
- const uiStyle = answers["ui_style"] ? getLabel("ui_style", answers["ui_style"]) : "Not specified";
288
- const constraints = getLabel("constraints", answers["constraints"] ?? []);
289
- const devPhilosophy = getLabel("dev_philosophy", answers["dev_philosophy"] ?? "");
290
- const extraContext = answers["extra_context"] ?? "";
291
- return `You are an expert software architect. Generate a complete, detailed, and production-quality AGENT.md file for the following project.
292
-
293
- The AGENT.md is a comprehensive engineering README that will be used by AI coding assistants (like Claude, GPT-4, Kiro, Cursor) to understand the project deeply and write code that perfectly matches the project's conventions, architecture, and constraints.
294
-
295
- The output must be a single Markdown document. It must be thorough, specific, and actionable \u2014 not generic. Every section should contain real, project-specific content.
296
-
297
- Use the DeutschFlow AGENT.md and Preflight AGENT.md as structural references for quality and depth. Match that level of detail.
298
-
299
- ---
300
-
301
- PROJECT INFORMATION:
302
-
303
- Project Name: ${projectName}
304
- Project Type: ${projectType}${mobilePlatforms ? `
305
- Mobile Platforms: ${mobilePlatforms}` : ""}${npmDistribution ? `
306
- Package Distribution: ${npmDistribution}` : ""}
307
- Description: ${description}
308
-
309
- Tech Stack: ${techStack}${pythonFramework ? `
310
- Python Framework: ${pythonFramework}` : ""}
311
- AI Features: ${aiFeatures}
312
- AI Providers: ${aiProviders}
313
-
314
- Folder Structure:
315
- ${folderStructure}
316
-
317
- Coding Conventions: ${conventions}
318
- UI Style: ${uiStyle}
319
- Hard Constraints: ${constraints}
320
- Development Philosophy: ${devPhilosophy}
321
- ${extraContext ? `
322
- Additional Context:
323
- ${extraContext}` : ""}
324
-
325
- ---
326
-
327
- Generate the AGENT.md with these sections (adapt section names to fit the project):
328
-
329
- 1. A header introducing the AI assistant's role for this specific project
330
- 2. Project Identity (name, vision, what makes it unique)
331
- 3. Core Product Principles (what it does and does NOT do)
332
- 4. Important Constraints (VERY IMPORTANT section \u2014 hard rules)
333
- 5. Tech Stack (with specific versions/choices and why)
334
- 6. Folder Structure (with role of each folder/file)
335
- 7. Architecture Guidelines (patterns, naming conventions, component rules)
336
- 8. Coding Conventions (with \u2705 CORRECT and \u274C INCORRECT examples where useful)
337
- 9. TypeScript Rules (if applicable)
338
- 10. Feature Implementation Rules (step-by-step process)
339
- 11. Development Philosophy
340
- 12. Decision Making & Clarifications
341
- 13. Communication Style
342
- 14. Final Reminder
343
-
344
- Rules for the output:
345
- - Be specific to THIS project, not generic
346
- - Use real code examples that match the tech stack
347
- - Include \u2705 CORRECT / \u274C INCORRECT examples for important rules
348
- - Use tables where they add clarity
349
- - Keep the tone direct and professional
350
- - No filler content \u2014 every sentence must be actionable
351
- - The document should be long enough to be genuinely useful (aim for 600-1000 lines)
352
- - Output ONLY the Markdown content, no preamble, no explanation`;
353
- }
354
-
355
- // cli/generate.ts
356
- import { createDeepSeek } from "@ai-sdk/deepseek";
357
- import { generateText } from "ai";
358
- async function callDeepSeek(apiKey, prompt) {
359
- const deepseek = createDeepSeek({ apiKey });
360
- const { text: text2 } = await generateText({
361
- model: deepseek("deepseek-chat"),
362
- prompt,
363
- temperature: 0.3,
364
- maxOutputTokens: 8e3
365
- });
366
- return text2;
367
- }
368
-
369
- // cli/prompts.ts
370
- import * as p from "@clack/prompts";
371
- async function promptQuestion(question) {
372
- const message = question.hint ? `${question.question}
373
- ${question.hint}` : question.question;
374
- switch (question.type) {
375
- case "text":
376
- case "textarea":
377
- return p.text({
378
- message,
379
- placeholder: question.placeholder,
380
- validate: question.required ? (v) => v.trim() === "" ? "This field is required." : void 0 : void 0
381
- });
382
- case "select":
383
- return p.select({
384
- message,
385
- options: (question.options ?? []).map((o) => ({
386
- value: o.value,
387
- label: o.label,
388
- hint: o.description
389
- }))
390
- });
391
- case "multiselect":
392
- return p.multiselect({
393
- message,
394
- options: (question.options ?? []).map((o) => ({
395
- value: o.value,
396
- label: o.label,
397
- hint: o.description
398
- })),
399
- required: question.required
400
- });
401
- }
402
- }
403
-
404
- // cli/index.ts
405
- function loadEnvLocal() {
406
- const envPath = resolve(process.cwd(), ".env.local");
407
- if (!existsSync(envPath)) return;
408
- const lines = readFileSync(envPath, "utf-8").split("\n");
409
- for (const line of lines) {
410
- const trimmed = line.trim();
411
- if (!trimmed || trimmed.startsWith("#")) continue;
412
- const eqIndex = trimmed.indexOf("=");
413
- if (eqIndex === -1) continue;
414
- const key = trimmed.slice(0, eqIndex).trim();
415
- const val = trimmed.slice(eqIndex + 1).trim().replace(/^["']|["']$/g, "");
416
- if (!process.env[key]) process.env[key] = val;
417
- }
418
- }
419
- async function main() {
420
- loadEnvLocal();
421
- console.clear();
422
- p2.intro(" agent-md-generator ");
423
- const apiKey = process.env["DEEPSEEK_API_KEY"];
424
- if (!apiKey) {
425
- p2.cancel(
426
- "DEEPSEEK_API_KEY is not set. Add it to .env.local or export it in your shell."
427
- );
428
- process.exit(1);
429
- }
430
- const answers = {};
431
- for (const question of QUESTIONS) {
432
- if (!isQuestionVisible(question, answers)) continue;
433
- const value = await promptQuestion(question);
434
- if (p2.isCancel(value)) {
435
- p2.cancel("Cancelled.");
436
- process.exit(0);
437
- }
438
- if (value !== void 0 && (typeof value !== "string" || value !== "")) {
439
- answers[question.id] = value;
440
- }
441
- }
442
- const s = p2.spinner();
443
- s.start("Generating your AGENT.md with DeepSeek...");
444
- try {
445
- const content = await callDeepSeek(apiKey, buildPrompt(answers));
446
- const outputPath = resolve(process.cwd(), "AGENT.md");
447
- writeFileSync(outputPath, content, "utf-8");
448
- s.stop("Done!");
449
- p2.outro(`AGENT.md written to ${outputPath}`);
450
- } catch (err) {
451
- s.stop("Generation failed.");
452
- p2.cancel(err instanceof Error ? err.message : "Unknown error");
453
- process.exit(1);
454
- }
455
- }
456
- main();