@edtools/cli 0.1.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 (40) hide show
  1. package/README.md +219 -0
  2. package/bin/edtools.js +9 -0
  3. package/dist/adapters/html/index.d.ts +18 -0
  4. package/dist/adapters/html/index.d.ts.map +1 -0
  5. package/dist/adapters/html/index.js +132 -0
  6. package/dist/adapters/html/index.js.map +1 -0
  7. package/dist/chunk-6534GCE5.js +458 -0
  8. package/dist/cli/commands/generate.d.ts +9 -0
  9. package/dist/cli/commands/generate.d.ts.map +1 -0
  10. package/dist/cli/commands/generate.js +101 -0
  11. package/dist/cli/commands/generate.js.map +1 -0
  12. package/dist/cli/commands/init.d.ts +6 -0
  13. package/dist/cli/commands/init.d.ts.map +1 -0
  14. package/dist/cli/commands/init.js +160 -0
  15. package/dist/cli/commands/init.js.map +1 -0
  16. package/dist/cli/index.d.ts +1 -0
  17. package/dist/cli/index.d.ts.map +1 -0
  18. package/dist/cli/index.js +286 -0
  19. package/dist/cli/index.js.map +1 -0
  20. package/dist/core/generator.d.ts +14 -0
  21. package/dist/core/generator.d.ts.map +1 -0
  22. package/dist/core/generator.js +241 -0
  23. package/dist/core/generator.js.map +1 -0
  24. package/dist/index.d.ts +170 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +10 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/types/adapter.d.ts +22 -0
  29. package/dist/types/adapter.d.ts.map +1 -0
  30. package/dist/types/adapter.js +24 -0
  31. package/dist/types/adapter.js.map +1 -0
  32. package/dist/types/content.d.ts +118 -0
  33. package/dist/types/content.d.ts.map +1 -0
  34. package/dist/types/content.js +2 -0
  35. package/dist/types/content.js.map +1 -0
  36. package/dist/types/index.d.ts +3 -0
  37. package/dist/types/index.d.ts.map +1 -0
  38. package/dist/types/index.js +3 -0
  39. package/dist/types/index.js.map +1 -0
  40. package/package.json +51 -0
package/README.md ADDED
@@ -0,0 +1,219 @@
1
+ # @edtools/cli
2
+
3
+ > Generate SEO-optimized content for LLM discovery
4
+
5
+ Make your product discoverable by AI assistants like Claude and ChatGPT through semantic search and SEO-optimized static pages.
6
+
7
+ ## Features
8
+
9
+ - ✅ **Framework Agnostic** - Works with HTML, Next.js, and more
10
+ - ✅ **AI-Powered** - Uses Claude to generate high-quality content
11
+ - ✅ **SEO Optimized** - Built-in SEO scoring and Schema.org markup
12
+ - ✅ **Local Processing** - No centralized database, everything runs locally
13
+ - ✅ **Anti-Spam Safeguards** - Prevents Google penalties with rate limiting
14
+ - ✅ **Extensible** - Plugin system for custom adapters
15
+
16
+ ## Quick Start
17
+
18
+ ### Installation
19
+
20
+ ```bash
21
+ npm install -g @edtools/cli
22
+ ```
23
+
24
+ ### Setup
25
+
26
+ ```bash
27
+ cd your-project
28
+ edtools init
29
+ ```
30
+
31
+ This will:
32
+ 1. Analyze your landing page
33
+ 2. Create `edtools.config.js`
34
+ 3. Prompt for product information
35
+
36
+ ### Generate Content
37
+
38
+ ```bash
39
+ # Set your Anthropic API key
40
+ export ANTHROPIC_API_KEY=sk-ant-...
41
+
42
+ # Generate 3 blog posts
43
+ edtools generate
44
+ ```
45
+
46
+ ## How It Works
47
+
48
+ ```
49
+ Your Landing Page
50
+
51
+ edtools init (analyzes & creates config)
52
+
53
+ edtools generate (creates blog posts)
54
+
55
+ Static HTML files optimized for:
56
+ - Google SEO
57
+ - AI crawlers (Claude, ChatGPT)
58
+ - Schema.org markup
59
+ - llms.txt format
60
+ ```
61
+
62
+ ## CLI Commands
63
+
64
+ ### `edtools init`
65
+
66
+ Initialize edtools in your project.
67
+
68
+ ```bash
69
+ edtools init [options]
70
+
71
+ Options:
72
+ -p, --path <path> Project path (default: current directory)
73
+ ```
74
+
75
+ ### `edtools generate`
76
+
77
+ Generate SEO-optimized blog posts.
78
+
79
+ ```bash
80
+ edtools generate [options]
81
+
82
+ Options:
83
+ -n, --posts <number> Number of posts (default: 3, max: 10)
84
+ -t, --topics <topics...> Specific topics to write about
85
+ -o, --output <dir> Output directory (default: ./blog)
86
+ --api-key <key> Anthropic API key
87
+ ```
88
+
89
+ **Example:**
90
+
91
+ ```bash
92
+ edtools generate -n 5 -o ./content/blog
93
+ ```
94
+
95
+ ### `edtools config`
96
+
97
+ View or set configuration.
98
+
99
+ ```bash
100
+ edtools config [options]
101
+
102
+ Options:
103
+ --set-api-key <key> Set Anthropic API key
104
+ ```
105
+
106
+ ## Configuration
107
+
108
+ The `edtools.config.js` file contains your product information:
109
+
110
+ ```javascript
111
+ module.exports = {
112
+ product: {
113
+ name: "My Product",
114
+ tagline: "One-line description",
115
+ description: "Longer description...",
116
+ category: "productivity",
117
+ websiteUrl: "https://myproduct.com",
118
+ pricingModel: "freemium",
119
+ features: [
120
+ "Feature 1",
121
+ "Feature 2",
122
+ ],
123
+ },
124
+
125
+ content: {
126
+ outputDir: './blog',
127
+ generateBlog: true,
128
+ },
129
+
130
+ seo: {
131
+ siteMapPath: './sitemap.xml',
132
+ robotsPath: './robots.txt',
133
+ allowAICrawlers: true,
134
+ },
135
+ };
136
+ ```
137
+
138
+ ## Architecture
139
+
140
+ ### Framework Agnostic Design
141
+
142
+ Edtools uses a 3-layer architecture:
143
+
144
+ 1. **Core Layer** - Generates content in universal JSON format
145
+ 2. **Adapter Layer** - Converts JSON to framework-specific code
146
+ 3. **Template Layer** - Renders final output
147
+
148
+ **Current Adapters:**
149
+ - ✅ HTML (static)
150
+ - 🔄 Next.js (coming in v1.1)
151
+ - 🔄 Markdown (coming in v1.1)
152
+
153
+ ### Avoiding Google Penalties
154
+
155
+ Edtools includes safeguards to prevent spam detection:
156
+
157
+ - **Rate Limiting**: Maximum 10 posts per run
158
+ - **Spacing Recommendations**: Warns if generating too quickly
159
+ - **Human Review**: Generated content requires review before publishing
160
+ - **SEO Scoring**: Validates content quality
161
+ - **No Keyword Stuffing**: Natural language generation
162
+
163
+ ## Best Practices
164
+
165
+ 1. **Generate Slowly**: 3-5 posts per week maximum
166
+ 2. **Review Content**: Always add personal experience/expertise
167
+ 3. **Space Publications**: Wait 3-7 days between batches
168
+ 4. **Verify Facts**: Check all statistics and claims
169
+ 5. **Add Examples**: Include real-world use cases
170
+
171
+ ## API Usage (Programmatic)
172
+
173
+ ```typescript
174
+ import { ContentGenerator } from '@edtools/cli';
175
+
176
+ const generator = new ContentGenerator(apiKey);
177
+
178
+ const result = await generator.generate({
179
+ productInfo: {
180
+ name: "My Product",
181
+ category: "productivity",
182
+ // ...
183
+ },
184
+ outputDir: './blog',
185
+ count: 3,
186
+ });
187
+ ```
188
+
189
+ ## Requirements
190
+
191
+ - Node.js 18+
192
+ - Anthropic API key ([get one here](https://console.anthropic.com/))
193
+
194
+ ## Roadmap
195
+
196
+ - [ ] **v1.1**: MCP Server for Claude Code integration
197
+ - [ ] **v1.1**: Next.js adapter
198
+ - [ ] **v1.1**: Markdown adapter
199
+ - [ ] **v1.2**: Local embeddings for duplicate detection
200
+ - [ ] **v1.3**: Shopify adapter
201
+ - [ ] **v2.0**: Dashboard web interface
202
+
203
+ ## Contributing
204
+
205
+ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md).
206
+
207
+ ## License
208
+
209
+ MIT © Edtools Team
210
+
211
+ ## Links
212
+
213
+ - **Documentation**: [https://docs.edtools.dev](https://docs.edtools.dev)
214
+ - **GitHub**: [https://github.com/edtools/cli](https://github.com/edtools/cli)
215
+ - **Issues**: [https://github.com/edtools/cli/issues](https://github.com/edtools/cli/issues)
216
+
217
+ ---
218
+
219
+ **Made with ❤️ to help products get discovered by AI assistants**
package/bin/edtools.js ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Entry point for the edtools CLI
4
+ // This file will be linked to node_modules/.bin/edtools
5
+
6
+ import('../dist/cli/index.js').catch((err) => {
7
+ console.error('Failed to load edtools CLI:', err);
8
+ process.exit(1);
9
+ });
@@ -0,0 +1,18 @@
1
+ import { Adapter, BlogPostContent } from '../../types/index.js';
2
+ export declare class HTMLAdapter implements Adapter {
3
+ name: string;
4
+ private templatePath;
5
+ constructor();
6
+ detect(projectPath: string): Promise<boolean>;
7
+ render(content: BlogPostContent): Promise<string>;
8
+ write(output: string, outputPath: string): Promise<void>;
9
+ getFileExtension(): string;
10
+ transformPath(basePath: string): string;
11
+ private markdownToHTML;
12
+ private renderSectionContent;
13
+ private renderComparisonTable;
14
+ private renderList;
15
+ private renderCode;
16
+ private escapeHtml;
17
+ }
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/html/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEhE,qBAAa,WAAY,YAAW,OAAO;IACzC,IAAI,SAAU;IACd,OAAO,CAAC,YAAY,CAAS;;IAOvB,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAe7C,MAAM,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IA2BjD,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9D,gBAAgB,IAAI,MAAM;IAI1B,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;YAWzB,cAAc;YAOd,oBAAoB;IAsBlC,OAAO,CAAC,qBAAqB;IAiC7B,OAAO,CAAC,UAAU;IAyBlB,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,UAAU;CAUnB"}
@@ -0,0 +1,132 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import ejs from 'ejs';
4
+ import { marked } from 'marked';
5
+ export class HTMLAdapter {
6
+ name = 'html';
7
+ templatePath;
8
+ constructor() {
9
+ this.templatePath = path.join(__dirname, 'templates', 'blog-post.html.ejs');
10
+ }
11
+ async detect(projectPath) {
12
+ try {
13
+ const files = await fs.readdir(projectPath);
14
+ const hasHtml = files.some(f => f.endsWith('.html'));
15
+ const hasIndexHtml = await fs.pathExists(path.join(projectPath, 'index.html'));
16
+ return hasHtml || hasIndexHtml;
17
+ }
18
+ catch (error) {
19
+ return false;
20
+ }
21
+ }
22
+ async render(content) {
23
+ const template = await fs.readFile(this.templatePath, 'utf-8');
24
+ const templateData = {
25
+ metadata: content.metadata,
26
+ schemaOrg: JSON.stringify(content.schemaOrg, null, 2),
27
+ intro: await this.markdownToHTML(content.content.intro),
28
+ sections: await Promise.all(content.content.sections.map(async (section) => ({
29
+ ...section,
30
+ content: await this.renderSectionContent(section),
31
+ }))),
32
+ conclusion: await this.markdownToHTML(content.content.conclusion),
33
+ cta: content.content.cta,
34
+ relatedPosts: content.relatedPosts || [],
35
+ seoScore: content.seo.score,
36
+ };
37
+ const html = ejs.render(template, templateData);
38
+ return html;
39
+ }
40
+ async write(output, outputPath) {
41
+ await fs.ensureDir(path.dirname(outputPath));
42
+ await fs.writeFile(outputPath, output, 'utf-8');
43
+ }
44
+ getFileExtension() {
45
+ return '.html';
46
+ }
47
+ transformPath(basePath) {
48
+ if (!basePath.endsWith('.html')) {
49
+ return basePath + '/index.html';
50
+ }
51
+ return basePath;
52
+ }
53
+ async markdownToHTML(markdown) {
54
+ return marked(markdown);
55
+ }
56
+ async renderSectionContent(section) {
57
+ switch (section.type) {
58
+ case 'text':
59
+ return await this.markdownToHTML(section.content);
60
+ case 'comparison':
61
+ return this.renderComparisonTable(section.data);
62
+ case 'list':
63
+ return this.renderList(section.data);
64
+ case 'code':
65
+ return this.renderCode(section.data);
66
+ default:
67
+ return await this.markdownToHTML(section.content);
68
+ }
69
+ }
70
+ renderComparisonTable(data) {
71
+ if (!data || !data.headers || !data.rows) {
72
+ return '';
73
+ }
74
+ let html = '<table class="comparison-table">\n';
75
+ html += ' <thead>\n <tr>\n';
76
+ data.headers.forEach((header) => {
77
+ html += ` <th>${header}</th>\n`;
78
+ });
79
+ html += ' </tr>\n </thead>\n';
80
+ html += ' <tbody>\n';
81
+ data.rows.forEach((row) => {
82
+ html += ' <tr>\n';
83
+ row.forEach((cell) => {
84
+ html += ` <td>${cell}</td>\n`;
85
+ });
86
+ html += ' </tr>\n';
87
+ });
88
+ html += ' </tbody>\n';
89
+ html += '</table>';
90
+ return html;
91
+ }
92
+ renderList(data) {
93
+ if (!data || !data.items) {
94
+ return '';
95
+ }
96
+ const tag = data.ordered ? 'ol' : 'ul';
97
+ let html = `<${tag} class="content-list">\n`;
98
+ data.items.forEach((item) => {
99
+ html += ' <li>\n';
100
+ html += ` <strong>${item.title}</strong>\n`;
101
+ if (item.description) {
102
+ html += ` <p>${item.description}</p>\n`;
103
+ }
104
+ html += ' </li>\n';
105
+ });
106
+ html += `</${tag}>`;
107
+ return html;
108
+ }
109
+ renderCode(data) {
110
+ if (!data || !data.code) {
111
+ return '';
112
+ }
113
+ let html = '<div class="code-block">\n';
114
+ if (data.caption) {
115
+ html += ` <div class="code-caption">${data.caption}</div>\n`;
116
+ }
117
+ html += ` <pre><code class="language-${data.language || 'plaintext'}">${this.escapeHtml(data.code)}</code></pre>\n`;
118
+ html += '</div>';
119
+ return html;
120
+ }
121
+ escapeHtml(text) {
122
+ const map = {
123
+ '&': '&amp;',
124
+ '<': '&lt;',
125
+ '>': '&gt;',
126
+ '"': '&quot;',
127
+ "'": '&#039;'
128
+ };
129
+ return text.replace(/[&<>"']/g, (m) => map[m]);
130
+ }
131
+ }
132
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/html/index.ts"],"names":[],"mappings":"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"}