@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
@@ -0,0 +1,160 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import ora from 'ora';
5
+ import inquirer from 'inquirer';
6
+ import { load as loadCheerio } from 'cheerio';
7
+ export async function initCommand(options) {
8
+ console.log(chalk.cyan.bold('\nšŸš€ Initializing Edtools...\n'));
9
+ const projectPath = path.resolve(options.path);
10
+ const configPath = path.join(projectPath, 'edtools.config.js');
11
+ if (await fs.pathExists(configPath)) {
12
+ const { overwrite } = await inquirer.prompt([
13
+ {
14
+ type: 'confirm',
15
+ name: 'overwrite',
16
+ message: 'edtools.config.js already exists. Overwrite?',
17
+ default: false,
18
+ },
19
+ ]);
20
+ if (!overwrite) {
21
+ console.log(chalk.yellow('Cancelled.'));
22
+ return;
23
+ }
24
+ }
25
+ const spinner = ora('Analyzing your landing page...').start();
26
+ let productInfo = {};
27
+ try {
28
+ const indexPath = path.join(projectPath, 'index.html');
29
+ if (await fs.pathExists(indexPath)) {
30
+ const html = await fs.readFile(indexPath, 'utf-8');
31
+ const $ = loadCheerio(html);
32
+ productInfo = {
33
+ name: $('title').text() || $('h1').first().text() || 'My Product',
34
+ description: $('meta[name="description"]').attr('content') || '',
35
+ websiteUrl: 'https://example.com',
36
+ category: 'technology',
37
+ features: [],
38
+ keywords: [],
39
+ };
40
+ const features = [];
41
+ $('ul li, ol li').each((i, el) => {
42
+ const text = $(el).text().trim();
43
+ if (text && text.length < 100) {
44
+ features.push(text);
45
+ }
46
+ });
47
+ productInfo.features = features.slice(0, 5);
48
+ spinner.succeed('Landing page analyzed');
49
+ }
50
+ else {
51
+ spinner.warn('No index.html found, will prompt for info');
52
+ }
53
+ }
54
+ catch (error) {
55
+ spinner.fail('Failed to analyze landing page');
56
+ }
57
+ console.log(chalk.cyan('\nšŸ“ Please provide some information about your product:\n'));
58
+ const answers = await inquirer.prompt([
59
+ {
60
+ type: 'input',
61
+ name: 'name',
62
+ message: 'Product name:',
63
+ default: productInfo.name,
64
+ validate: (input) => input.length > 0 || 'Product name is required',
65
+ },
66
+ {
67
+ type: 'input',
68
+ name: 'tagline',
69
+ message: 'Tagline (short description):',
70
+ default: productInfo.description,
71
+ },
72
+ {
73
+ type: 'list',
74
+ name: 'category',
75
+ message: 'Category:',
76
+ choices: [
77
+ 'education',
78
+ 'productivity',
79
+ 'business',
80
+ 'development',
81
+ 'design',
82
+ 'marketing',
83
+ 'finance',
84
+ 'health',
85
+ 'other',
86
+ ],
87
+ default: 'technology',
88
+ },
89
+ {
90
+ type: 'input',
91
+ name: 'websiteUrl',
92
+ message: 'Website URL:',
93
+ default: productInfo.websiteUrl,
94
+ validate: (input) => {
95
+ try {
96
+ new URL(input);
97
+ return true;
98
+ }
99
+ catch {
100
+ return 'Please enter a valid URL';
101
+ }
102
+ },
103
+ },
104
+ {
105
+ type: 'list',
106
+ name: 'pricingModel',
107
+ message: 'Pricing model:',
108
+ choices: ['free', 'freemium', 'paid', 'open_source'],
109
+ default: 'freemium',
110
+ },
111
+ {
112
+ type: 'input',
113
+ name: 'features',
114
+ message: 'Main features (comma-separated):',
115
+ default: productInfo.features?.join(', '),
116
+ filter: (input) => input.split(',').map((f) => f.trim()).filter(Boolean),
117
+ },
118
+ ]);
119
+ const finalProductInfo = {
120
+ ...productInfo,
121
+ ...answers,
122
+ };
123
+ const config = `module.exports = {
124
+ product: {
125
+ name: ${JSON.stringify(finalProductInfo.name)},
126
+ tagline: ${JSON.stringify(finalProductInfo.tagline)},
127
+ description: ${JSON.stringify(finalProductInfo.description)},
128
+ category: ${JSON.stringify(finalProductInfo.category)},
129
+ websiteUrl: ${JSON.stringify(finalProductInfo.websiteUrl)},
130
+ pricingModel: ${JSON.stringify(finalProductInfo.pricingModel)},
131
+ features: ${JSON.stringify(finalProductInfo.features, null, 2)},
132
+ },
133
+
134
+ content: {
135
+ outputDir: './blog',
136
+ generateBlog: true,
137
+ },
138
+
139
+ seo: {
140
+ siteMapPath: './sitemap.xml',
141
+ robotsPath: './robots.txt',
142
+ allowAICrawlers: true,
143
+ },
144
+ };
145
+ `;
146
+ await fs.writeFile(configPath, config, 'utf-8');
147
+ const edtoolsDir = path.join(projectPath, '.edtools');
148
+ await fs.ensureDir(edtoolsDir);
149
+ const gitignorePath = path.join(edtoolsDir, '.gitignore');
150
+ await fs.writeFile(gitignorePath, '*\n!.gitignore\n', 'utf-8');
151
+ console.log(chalk.green('\nāœ“ Configuration created successfully!\n'));
152
+ console.log(chalk.cyan('Files created:'));
153
+ console.log(` - ${chalk.white('edtools.config.js')}`);
154
+ console.log(` - ${chalk.white('.edtools/')} (local data directory)\n`);
155
+ console.log(chalk.cyan('Next steps:'));
156
+ console.log(` 1. Review ${chalk.white('edtools.config.js')}`);
157
+ console.log(` 2. Set your API key: ${chalk.white('export ANTHROPIC_API_KEY=sk-ant-...')}`);
158
+ console.log(` 3. Generate content: ${chalk.white('edtools generate')}\n`);
159
+ }
160
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,286 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ContentGenerator,
4
+ __require
5
+ } from "../chunk-6534GCE5.js";
6
+
7
+ // src/cli/index.ts
8
+ import { Command } from "commander";
9
+ import chalk3 from "chalk";
10
+
11
+ // src/cli/commands/init.ts
12
+ import fs from "fs-extra";
13
+ import path from "path";
14
+ import chalk from "chalk";
15
+ import ora from "ora";
16
+ import inquirer from "inquirer";
17
+ import { load as loadCheerio } from "cheerio";
18
+ async function initCommand(options) {
19
+ console.log(chalk.cyan.bold("\n\u{1F680} Initializing Edtools...\n"));
20
+ const projectPath = path.resolve(options.path);
21
+ const configPath = path.join(projectPath, "edtools.config.js");
22
+ if (await fs.pathExists(configPath)) {
23
+ const { overwrite } = await inquirer.prompt([
24
+ {
25
+ type: "confirm",
26
+ name: "overwrite",
27
+ message: "edtools.config.js already exists. Overwrite?",
28
+ default: false
29
+ }
30
+ ]);
31
+ if (!overwrite) {
32
+ console.log(chalk.yellow("Cancelled."));
33
+ return;
34
+ }
35
+ }
36
+ const spinner = ora("Analyzing your landing page...").start();
37
+ let productInfo = {};
38
+ try {
39
+ const indexPath = path.join(projectPath, "index.html");
40
+ if (await fs.pathExists(indexPath)) {
41
+ const html = await fs.readFile(indexPath, "utf-8");
42
+ const $ = loadCheerio(html);
43
+ productInfo = {
44
+ name: $("title").text() || $("h1").first().text() || "My Product",
45
+ description: $('meta[name="description"]').attr("content") || "",
46
+ websiteUrl: "https://example.com",
47
+ category: "technology",
48
+ features: [],
49
+ keywords: []
50
+ };
51
+ const features = [];
52
+ $("ul li, ol li").each((i, el) => {
53
+ const text = $(el).text().trim();
54
+ if (text && text.length < 100) {
55
+ features.push(text);
56
+ }
57
+ });
58
+ productInfo.features = features.slice(0, 5);
59
+ spinner.succeed("Landing page analyzed");
60
+ } else {
61
+ spinner.warn("No index.html found, will prompt for info");
62
+ }
63
+ } catch (error) {
64
+ spinner.fail("Failed to analyze landing page");
65
+ }
66
+ console.log(chalk.cyan("\n\u{1F4DD} Please provide some information about your product:\n"));
67
+ const answers = await inquirer.prompt([
68
+ {
69
+ type: "input",
70
+ name: "name",
71
+ message: "Product name:",
72
+ default: productInfo.name,
73
+ validate: (input) => input.length > 0 || "Product name is required"
74
+ },
75
+ {
76
+ type: "input",
77
+ name: "tagline",
78
+ message: "Tagline (short description):",
79
+ default: productInfo.description
80
+ },
81
+ {
82
+ type: "list",
83
+ name: "category",
84
+ message: "Category:",
85
+ choices: [
86
+ "education",
87
+ "productivity",
88
+ "business",
89
+ "development",
90
+ "design",
91
+ "marketing",
92
+ "finance",
93
+ "health",
94
+ "other"
95
+ ],
96
+ default: "technology"
97
+ },
98
+ {
99
+ type: "input",
100
+ name: "websiteUrl",
101
+ message: "Website URL:",
102
+ default: productInfo.websiteUrl,
103
+ validate: (input) => {
104
+ try {
105
+ new URL(input);
106
+ return true;
107
+ } catch {
108
+ return "Please enter a valid URL";
109
+ }
110
+ }
111
+ },
112
+ {
113
+ type: "list",
114
+ name: "pricingModel",
115
+ message: "Pricing model:",
116
+ choices: ["free", "freemium", "paid", "open_source"],
117
+ default: "freemium"
118
+ },
119
+ {
120
+ type: "input",
121
+ name: "features",
122
+ message: "Main features (comma-separated):",
123
+ default: productInfo.features?.join(", "),
124
+ filter: (input) => input.split(",").map((f) => f.trim()).filter(Boolean)
125
+ }
126
+ ]);
127
+ const finalProductInfo = {
128
+ ...productInfo,
129
+ ...answers
130
+ };
131
+ const config = `module.exports = {
132
+ product: {
133
+ name: ${JSON.stringify(finalProductInfo.name)},
134
+ tagline: ${JSON.stringify(finalProductInfo.tagline)},
135
+ description: ${JSON.stringify(finalProductInfo.description)},
136
+ category: ${JSON.stringify(finalProductInfo.category)},
137
+ websiteUrl: ${JSON.stringify(finalProductInfo.websiteUrl)},
138
+ pricingModel: ${JSON.stringify(finalProductInfo.pricingModel)},
139
+ features: ${JSON.stringify(finalProductInfo.features, null, 2)},
140
+ },
141
+
142
+ content: {
143
+ outputDir: './blog',
144
+ generateBlog: true,
145
+ },
146
+
147
+ seo: {
148
+ siteMapPath: './sitemap.xml',
149
+ robotsPath: './robots.txt',
150
+ allowAICrawlers: true,
151
+ },
152
+ };
153
+ `;
154
+ await fs.writeFile(configPath, config, "utf-8");
155
+ const edtoolsDir = path.join(projectPath, ".edtools");
156
+ await fs.ensureDir(edtoolsDir);
157
+ const gitignorePath = path.join(edtoolsDir, ".gitignore");
158
+ await fs.writeFile(gitignorePath, "*\n!.gitignore\n", "utf-8");
159
+ console.log(chalk.green("\n\u2713 Configuration created successfully!\n"));
160
+ console.log(chalk.cyan("Files created:"));
161
+ console.log(` - ${chalk.white("edtools.config.js")}`);
162
+ console.log(` - ${chalk.white(".edtools/")} (local data directory)
163
+ `);
164
+ console.log(chalk.cyan("Next steps:"));
165
+ console.log(` 1. Review ${chalk.white("edtools.config.js")}`);
166
+ console.log(` 2. Set your API key: ${chalk.white("export ANTHROPIC_API_KEY=sk-ant-...")}`);
167
+ console.log(` 3. Generate content: ${chalk.white("edtools generate")}
168
+ `);
169
+ }
170
+
171
+ // src/cli/commands/generate.ts
172
+ import fs2 from "fs-extra";
173
+ import path2 from "path";
174
+ import chalk2 from "chalk";
175
+ import ora2 from "ora";
176
+ async function generateCommand(options) {
177
+ console.log(chalk2.cyan.bold("\n\u{1F4DD} Generating content...\n"));
178
+ const projectPath = process.cwd();
179
+ const configPath = path2.join(projectPath, "edtools.config.js");
180
+ if (!await fs2.pathExists(configPath)) {
181
+ console.log(chalk2.red("\u2717 No edtools.config.js found"));
182
+ console.log(chalk2.yellow(' Run "edtools init" first\n'));
183
+ process.exit(1);
184
+ }
185
+ const config = __require(configPath);
186
+ const productInfo = config.product;
187
+ if (!productInfo || !productInfo.name) {
188
+ console.log(chalk2.red("\u2717 Invalid configuration in edtools.config.js"));
189
+ process.exit(1);
190
+ }
191
+ const apiKey = options.apiKey || process.env.ANTHROPIC_API_KEY;
192
+ if (!apiKey) {
193
+ console.log(chalk2.red("\u2717 No API key found"));
194
+ console.log(chalk2.yellow(" Set ANTHROPIC_API_KEY environment variable"));
195
+ console.log(chalk2.yellow(" Or use --api-key option\n"));
196
+ process.exit(1);
197
+ }
198
+ const count = parseInt(options.posts, 10);
199
+ if (isNaN(count) || count < 1 || count > 10) {
200
+ console.log(chalk2.red("\u2717 Invalid number of posts (must be 1-10)"));
201
+ process.exit(1);
202
+ }
203
+ if (count > 5) {
204
+ console.log(chalk2.yellow(`\u26A0\uFE0F Generating ${count} posts at once may trigger spam detection`));
205
+ console.log(chalk2.yellow(" Recommended: 3-5 posts per week\n"));
206
+ }
207
+ const outputDir = path2.resolve(projectPath, options.output);
208
+ await fs2.ensureDir(outputDir);
209
+ console.log(chalk2.cyan("Configuration:"));
210
+ console.log(` Product: ${chalk2.white(productInfo.name)}`);
211
+ console.log(` Category: ${chalk2.white(productInfo.category)}`);
212
+ console.log(` Posts to generate: ${chalk2.white(count)}`);
213
+ console.log(` Output directory: ${chalk2.white(outputDir)}
214
+ `);
215
+ const generator = new ContentGenerator(apiKey);
216
+ const generateConfig = {
217
+ productInfo,
218
+ topics: options.topics,
219
+ count,
220
+ outputDir,
221
+ projectPath,
222
+ avoidDuplicates: true,
223
+ similarityThreshold: 0.85
224
+ };
225
+ const spinner = ora2("Generating content with Claude...").start();
226
+ try {
227
+ const result = await generator.generate(generateConfig);
228
+ if (result.success && result.posts.length > 0) {
229
+ spinner.succeed("Content generated successfully!");
230
+ console.log(chalk2.green("\n\u2713 Generated posts:\n"));
231
+ result.posts.forEach((post, i) => {
232
+ console.log(`${i + 1}. ${chalk2.white(post.title)}`);
233
+ console.log(` ${chalk2.gray(post.path)}`);
234
+ console.log(` ${chalk2.cyan("SEO Score:")} ${getScoreColor(post.seoScore)}${post.seoScore}/100${chalk2.reset()}`);
235
+ });
236
+ if (result.warnings && result.warnings.length > 0) {
237
+ console.log(chalk2.yellow("\n\u26A0\uFE0F Warnings:"));
238
+ result.warnings.forEach((warning) => {
239
+ console.log(` ${warning}`);
240
+ });
241
+ }
242
+ console.log(chalk2.cyan("\nNext steps:"));
243
+ console.log(` 1. Review generated content in ${chalk2.white(outputDir)}`);
244
+ console.log(` 2. Edit posts to add personal experience/expertise`);
245
+ console.log(` 3. Deploy to your website`);
246
+ console.log(chalk2.yellow(`
247
+ \u{1F4A1} Tip: Wait 3-7 days before generating more posts to avoid spam detection
248
+ `));
249
+ } else {
250
+ spinner.fail("Failed to generate content");
251
+ if (result.errors && result.errors.length > 0) {
252
+ console.log(chalk2.red("\nErrors:"));
253
+ result.errors.forEach((error) => {
254
+ console.log(` ${error}`);
255
+ });
256
+ }
257
+ process.exit(1);
258
+ }
259
+ } catch (error) {
260
+ spinner.fail("Error during generation");
261
+ console.log(chalk2.red(`
262
+ ${error.message}
263
+ `));
264
+ process.exit(1);
265
+ }
266
+ }
267
+ function getScoreColor(score) {
268
+ if (score >= 80) return chalk2.green("");
269
+ if (score >= 60) return chalk2.yellow("");
270
+ return chalk2.red("");
271
+ }
272
+
273
+ // src/cli/index.ts
274
+ var program = new Command();
275
+ program.name("edtools").description("Generate SEO-optimized content for LLM discovery").version("0.1.0");
276
+ program.command("init").description("Initialize edtools in your project").option("-p, --path <path>", "Project path", process.cwd()).action(initCommand);
277
+ program.command("generate").description("Generate blog posts").option("-n, --posts <number>", "Number of posts to generate", "3").option("-t, --topics <topics...>", "Specific topics to write about").option("-o, --output <dir>", "Output directory", "./blog").option("--api-key <key>", "Anthropic API key (or set ANTHROPIC_API_KEY env var)").action(generateCommand);
278
+ program.command("config").description("View or set configuration").option("--set-api-key <key>", "Set Anthropic API key").action(async (options) => {
279
+ if (options.setApiKey) {
280
+ console.log(chalk3.green("\u2713 API key saved"));
281
+ } else {
282
+ console.log(chalk3.cyan("Configuration:"));
283
+ console.log(` API Key: ${process.env.ANTHROPIC_API_KEY ? "[set]" : "[not set]"}`);
284
+ }
285
+ });
286
+ program.parse();
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,kDAAkD,CAAC;KAC/D,OAAO,CAAC,OAAO,CAAC,CAAC;AAGpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,oCAAoC,CAAC;KACjD,MAAM,CAAC,mBAAmB,EAAE,cAAc,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;KAC1D,MAAM,CAAC,WAAW,CAAC,CAAC;AAGvB,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,qBAAqB,CAAC;KAClC,MAAM,CAAC,sBAAsB,EAAE,6BAA6B,EAAE,GAAG,CAAC;KAClE,MAAM,CAAC,0BAA0B,EAAE,gCAAgC,CAAC;KACpE,MAAM,CAAC,oBAAoB,EAAE,kBAAkB,EAAE,QAAQ,CAAC;KAC1D,MAAM,CAAC,iBAAiB,EAAE,sDAAsD,CAAC;KACjF,MAAM,CAAC,eAAe,CAAC,CAAC;AAG3B,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,2BAA2B,CAAC;KACxC,MAAM,CAAC,qBAAqB,EAAE,uBAAuB,CAAC;KACtD,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QAEtB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC9C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACrF,CAAC;AACH,CAAC,CAAC,CAAC;AAGL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { GenerateConfig, GenerateResult } from '../types/index.js';
2
+ export declare class ContentGenerator {
3
+ private anthropic;
4
+ private adapters;
5
+ constructor(apiKey?: string);
6
+ generate(config: GenerateConfig): Promise<GenerateResult>;
7
+ private generateContent;
8
+ private buildPrompt;
9
+ private generateSchemaOrg;
10
+ private calculateSEOScore;
11
+ private generateTopics;
12
+ private updateSitemap;
13
+ }
14
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/core/generator.ts"],"names":[],"mappings":"AASA,OAAO,EAKL,cAAc,EACd,cAAc,EAEf,MAAM,mBAAmB,CAAC;AAI3B,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,QAAQ,CAAkB;gBAEtB,MAAM,CAAC,EAAE,MAAM;IAerB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;YAsEjD,eAAe;IAuD7B,OAAO,CAAC,WAAW;IAkDnB,OAAO,CAAC,iBAAiB;YAwBX,iBAAiB;YAsCjB,cAAc;YAuCd,aAAa;CAyB5B"}