@rankcli/agent-runtime 0.0.15 → 0.0.16

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 (202) hide show
  1. package/dist/index.d.mts +43 -393
  2. package/dist/index.d.ts +43 -393
  3. package/dist/index.js +306 -6526
  4. package/dist/index.mjs +202 -6412
  5. package/package.json +6 -1
  6. package/scripts/build-deno.ts +0 -134
  7. package/src/analyzers/core-web-vitals-analyzer.test.ts +0 -236
  8. package/src/analyzers/core-web-vitals-analyzer.ts +0 -557
  9. package/src/analyzers/geo-analyzer.test.ts +0 -310
  10. package/src/analyzers/geo-analyzer.ts +0 -814
  11. package/src/analyzers/image-optimization-analyzer.test.ts +0 -145
  12. package/src/analyzers/image-optimization-analyzer.ts +0 -348
  13. package/src/analyzers/index.ts +0 -233
  14. package/src/analyzers/internal-linking-analyzer.test.ts +0 -141
  15. package/src/analyzers/internal-linking-analyzer.ts +0 -419
  16. package/src/analyzers/mobile-seo-analyzer.test.ts +0 -140
  17. package/src/analyzers/mobile-seo-analyzer.ts +0 -455
  18. package/src/analyzers/security-headers-analyzer.test.ts +0 -115
  19. package/src/analyzers/security-headers-analyzer.ts +0 -318
  20. package/src/analyzers/structured-data-analyzer.test.ts +0 -210
  21. package/src/analyzers/structured-data-analyzer.ts +0 -590
  22. package/src/audit/ai/analyzer.ts +0 -347
  23. package/src/audit/ai/index.ts +0 -29
  24. package/src/audit/ai/prompts/content-analysis.ts +0 -271
  25. package/src/audit/ai/types.ts +0 -179
  26. package/src/audit/checks/additional-checks.ts +0 -439
  27. package/src/audit/checks/agent-experience.ts +0 -108
  28. package/src/audit/checks/ai-citation-worthiness.ts +0 -399
  29. package/src/audit/checks/ai-content-structure.ts +0 -325
  30. package/src/audit/checks/ai-readiness.ts +0 -406
  31. package/src/audit/checks/anchor-text.ts +0 -179
  32. package/src/audit/checks/answer-conciseness.ts +0 -322
  33. package/src/audit/checks/asset-minification.ts +0 -270
  34. package/src/audit/checks/bing-optimization.ts +0 -206
  35. package/src/audit/checks/brand-mention-optimization.ts +0 -349
  36. package/src/audit/checks/caching-headers.ts +0 -305
  37. package/src/audit/checks/canonical-advanced.ts +0 -150
  38. package/src/audit/checks/canonical-domain.ts +0 -196
  39. package/src/audit/checks/citation-quality.ts +0 -358
  40. package/src/audit/checks/client-rendering.ts +0 -542
  41. package/src/audit/checks/color-contrast.ts +0 -342
  42. package/src/audit/checks/content-freshness.ts +0 -170
  43. package/src/audit/checks/content-science.ts +0 -589
  44. package/src/audit/checks/conversion-elements.ts +0 -526
  45. package/src/audit/checks/crawlability.ts +0 -220
  46. package/src/audit/checks/directory-listing.ts +0 -172
  47. package/src/audit/checks/dom-analysis.ts +0 -191
  48. package/src/audit/checks/dom-size.ts +0 -246
  49. package/src/audit/checks/duplicate-content.ts +0 -194
  50. package/src/audit/checks/eeat-signals.ts +0 -990
  51. package/src/audit/checks/entity-seo.ts +0 -396
  52. package/src/audit/checks/featured-snippet.ts +0 -473
  53. package/src/audit/checks/freshness-signals.ts +0 -443
  54. package/src/audit/checks/funnel-intent.ts +0 -463
  55. package/src/audit/checks/hreflang.ts +0 -174
  56. package/src/audit/checks/html-compliance.ts +0 -302
  57. package/src/audit/checks/image-dimensions.ts +0 -167
  58. package/src/audit/checks/images.ts +0 -160
  59. package/src/audit/checks/indexnow.ts +0 -275
  60. package/src/audit/checks/interactive-tools.ts +0 -475
  61. package/src/audit/checks/internal-link-graph.ts +0 -436
  62. package/src/audit/checks/keyword-analysis.ts +0 -239
  63. package/src/audit/checks/keyword-cannibalization.ts +0 -385
  64. package/src/audit/checks/keyword-placement.ts +0 -471
  65. package/src/audit/checks/links.ts +0 -273
  66. package/src/audit/checks/llms-txt.ts +0 -224
  67. package/src/audit/checks/local-seo.ts +0 -296
  68. package/src/audit/checks/mobile.ts +0 -167
  69. package/src/audit/checks/modern-images.ts +0 -226
  70. package/src/audit/checks/navboost-signals.ts +0 -395
  71. package/src/audit/checks/on-page.ts +0 -209
  72. package/src/audit/checks/page-resources.ts +0 -285
  73. package/src/audit/checks/pagination.ts +0 -180
  74. package/src/audit/checks/performance.ts +0 -153
  75. package/src/audit/checks/platform-presence.ts +0 -580
  76. package/src/audit/checks/rag-chunk-readiness.test.ts +0 -159
  77. package/src/audit/checks/rag-chunk-readiness.ts +0 -163
  78. package/src/audit/checks/redirect-analysis.ts +0 -153
  79. package/src/audit/checks/redirect-chain.ts +0 -389
  80. package/src/audit/checks/resource-hints.ts +0 -420
  81. package/src/audit/checks/responsive-css.ts +0 -247
  82. package/src/audit/checks/responsive-images.ts +0 -396
  83. package/src/audit/checks/review-ecosystem.ts +0 -415
  84. package/src/audit/checks/robots-validation.ts +0 -373
  85. package/src/audit/checks/security-headers.ts +0 -188
  86. package/src/audit/checks/security.ts +0 -144
  87. package/src/audit/checks/serp-preview.ts +0 -251
  88. package/src/audit/checks/site-maturity.ts +0 -453
  89. package/src/audit/checks/social-meta.test.ts +0 -275
  90. package/src/audit/checks/social-meta.ts +0 -134
  91. package/src/audit/checks/soft-404.ts +0 -151
  92. package/src/audit/checks/structured-data.ts +0 -238
  93. package/src/audit/checks/tech-detection.ts +0 -496
  94. package/src/audit/checks/topical-clusters.ts +0 -435
  95. package/src/audit/checks/tracker-bloat.ts +0 -462
  96. package/src/audit/checks/tracking-verification.test.ts +0 -371
  97. package/src/audit/checks/tracking-verification.ts +0 -636
  98. package/src/audit/checks/url-safety.ts +0 -682
  99. package/src/audit/deno-entry.ts +0 -66
  100. package/src/audit/discovery/index.ts +0 -15
  101. package/src/audit/discovery/link-crawler.ts +0 -233
  102. package/src/audit/discovery/repo-routes.ts +0 -347
  103. package/src/audit/engine.ts +0 -633
  104. package/src/audit/fixes/index.ts +0 -209
  105. package/src/audit/fixes/social-meta-fixes.test.ts +0 -329
  106. package/src/audit/fixes/social-meta-fixes.ts +0 -463
  107. package/src/audit/index.ts +0 -74
  108. package/src/audit/runner.test.ts +0 -299
  109. package/src/audit/runner.ts +0 -130
  110. package/src/audit/types.ts +0 -1987
  111. package/src/content/featured-snippet.ts +0 -367
  112. package/src/content/generator.test.ts +0 -534
  113. package/src/content/generator.ts +0 -501
  114. package/src/content/headline.ts +0 -317
  115. package/src/content/index.ts +0 -62
  116. package/src/content/intent.ts +0 -258
  117. package/src/content/keyword-density.ts +0 -349
  118. package/src/content/readability.ts +0 -262
  119. package/src/executor.ts +0 -336
  120. package/src/fixer/framework-fixes.test.ts +0 -489
  121. package/src/fixer/framework-fixes.ts +0 -5287
  122. package/src/fixer/index.ts +0 -6
  123. package/src/fixer/schemas.ts +0 -971
  124. package/src/fixer.ts +0 -642
  125. package/src/frameworks/detector.test.ts +0 -248
  126. package/src/frameworks/detector.ts +0 -899
  127. package/src/frameworks/index.ts +0 -68
  128. package/src/frameworks/recipes/angular.yaml +0 -171
  129. package/src/frameworks/recipes/astro.yaml +0 -206
  130. package/src/frameworks/recipes/django.yaml +0 -180
  131. package/src/frameworks/recipes/laravel.yaml +0 -137
  132. package/src/frameworks/recipes/nextjs.yaml +0 -268
  133. package/src/frameworks/recipes/nuxt.yaml +0 -175
  134. package/src/frameworks/recipes/rails.yaml +0 -188
  135. package/src/frameworks/recipes/react.yaml +0 -202
  136. package/src/frameworks/recipes/sveltekit.yaml +0 -154
  137. package/src/frameworks/recipes/vue.yaml +0 -137
  138. package/src/frameworks/recipes/wordpress.yaml +0 -209
  139. package/src/frameworks/suggestion-engine.ts +0 -357
  140. package/src/geo/geo-content.test.ts +0 -305
  141. package/src/geo/geo-content.ts +0 -266
  142. package/src/geo/geo-history.test.ts +0 -473
  143. package/src/geo/geo-history.ts +0 -433
  144. package/src/geo/geo-tracker.test.ts +0 -359
  145. package/src/geo/geo-tracker.ts +0 -411
  146. package/src/geo/index.ts +0 -11
  147. package/src/geo/llm-citation-checker.ts +0 -188
  148. package/src/git/commit-helper.test.ts +0 -261
  149. package/src/git/commit-helper.ts +0 -329
  150. package/src/git/index.ts +0 -12
  151. package/src/git/pr-helper.test.ts +0 -284
  152. package/src/git/pr-helper.ts +0 -307
  153. package/src/index.ts +0 -76
  154. package/src/keywords/ai-keyword-engine.ts +0 -1062
  155. package/src/keywords/ai-summarizer.ts +0 -387
  156. package/src/keywords/ci-mode.ts +0 -555
  157. package/src/keywords/engine.ts +0 -359
  158. package/src/keywords/index.ts +0 -151
  159. package/src/keywords/llm-judge.ts +0 -357
  160. package/src/keywords/nlp-analysis.ts +0 -706
  161. package/src/keywords/prioritizer.ts +0 -295
  162. package/src/keywords/site-crawler.ts +0 -342
  163. package/src/keywords/sources/autocomplete.ts +0 -139
  164. package/src/keywords/sources/competitive-search.ts +0 -450
  165. package/src/keywords/sources/competitor-analysis.ts +0 -374
  166. package/src/keywords/sources/dataforseo.ts +0 -206
  167. package/src/keywords/sources/free-sources.ts +0 -294
  168. package/src/keywords/sources/gsc.ts +0 -123
  169. package/src/keywords/topic-grouping.ts +0 -327
  170. package/src/keywords/types.ts +0 -144
  171. package/src/keywords/wizard.ts +0 -457
  172. package/src/loader.ts +0 -40
  173. package/src/ranking/index.ts +0 -5
  174. package/src/ranking/serp-client.ts +0 -348
  175. package/src/ranking/tracker.ts +0 -380
  176. package/src/ranking/types.ts +0 -123
  177. package/src/reports/index.ts +0 -7
  178. package/src/reports/report-generator.test.ts +0 -293
  179. package/src/reports/report-generator.ts +0 -713
  180. package/src/scheduler/alerts.test.ts +0 -458
  181. package/src/scheduler/alerts.ts +0 -328
  182. package/src/scheduler/index.ts +0 -8
  183. package/src/scheduler/scheduled-audit.test.ts +0 -377
  184. package/src/scheduler/scheduled-audit.ts +0 -149
  185. package/src/test/integration-test.ts +0 -325
  186. package/src/tools/analyzer.ts +0 -373
  187. package/src/tools/crawl.ts +0 -293
  188. package/src/tools/files.ts +0 -301
  189. package/src/tools/h1-fixer.ts +0 -249
  190. package/src/tools/index.ts +0 -67
  191. package/src/tracking/github-action.ts +0 -326
  192. package/src/tracking/google-analytics.ts +0 -265
  193. package/src/tracking/index.ts +0 -45
  194. package/src/tracking/report-generator.ts +0 -386
  195. package/src/tracking/search-console.ts +0 -335
  196. package/src/types.ts +0 -148
  197. package/src/utils/http.ts +0 -302
  198. package/src/wasm-adapter.ts +0 -297
  199. package/src/wasm-entry.ts +0 -14
  200. package/tsconfig.json +0 -17
  201. package/tsup.wasm.config.ts +0 -26
  202. package/vitest.config.ts +0 -15
@@ -1,261 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import {
3
- formatConventionalCommit,
4
- formatSEOCommitMessage,
5
- isGitRepo,
6
- detectGitHubPages,
7
- generateCommitSummary,
8
- COMMIT_TYPES,
9
- SEO_SCOPES,
10
- type ConventionalCommit,
11
- type SEOFixCommit,
12
- type CommitConfig,
13
- } from './commit-helper.js';
14
-
15
- describe('commit-helper', () => {
16
- describe('formatConventionalCommit', () => {
17
- it('formats a basic commit message', () => {
18
- const commit: ConventionalCommit = {
19
- type: 'fix',
20
- description: 'resolve meta tag issue',
21
- };
22
- expect(formatConventionalCommit(commit)).toBe('fix: resolve meta tag issue');
23
- });
24
-
25
- it('includes scope when provided', () => {
26
- const commit: ConventionalCommit = {
27
- type: 'fix',
28
- scope: 'seo',
29
- description: 'add missing title tag',
30
- };
31
- expect(formatConventionalCommit(commit)).toBe('fix(seo): add missing title tag');
32
- });
33
-
34
- it('adds breaking change indicator', () => {
35
- const commit: ConventionalCommit = {
36
- type: 'feat',
37
- scope: 'schema',
38
- description: 'change JSON-LD format',
39
- breaking: true,
40
- };
41
- expect(formatConventionalCommit(commit)).toBe('feat(schema)!: change JSON-LD format');
42
- });
43
-
44
- it('includes body when provided', () => {
45
- const commit: ConventionalCommit = {
46
- type: 'fix',
47
- scope: 'meta',
48
- description: 'add meta description',
49
- body: 'Added meta descriptions to all pages.\nThis improves SEO score.',
50
- };
51
- const result = formatConventionalCommit(commit);
52
- expect(result).toContain('fix(meta): add meta description');
53
- expect(result).toContain('Added meta descriptions to all pages.');
54
- expect(result).toContain('This improves SEO score.');
55
- });
56
-
57
- it('includes issue codes when provided', () => {
58
- const commit: ConventionalCommit = {
59
- type: 'fix',
60
- scope: 'seo',
61
- description: 'fix crawlability issues',
62
- issues: ['ROBOTS_TXT_MISSING', 'SITEMAP_MISSING'],
63
- };
64
- const result = formatConventionalCommit(commit);
65
- expect(result).toContain('Issue codes: ROBOTS_TXT_MISSING, SITEMAP_MISSING');
66
- });
67
- });
68
-
69
- describe('formatSEOCommitMessage', () => {
70
- it('formats SEO fix with co-author', () => {
71
- const fix: SEOFixCommit = {
72
- category: 'on-page',
73
- issues: ['TITLE_MISSING', 'META_DESC_MISSING'],
74
- filesChanged: ['index.html'],
75
- description: 'add on page improvements',
76
- };
77
- const config: CommitConfig = {
78
- systemName: 'SEO Autopilot',
79
- systemEmail: 'bot@seo-autopilot.dev',
80
- };
81
-
82
- const result = formatSEOCommitMessage(fix, config);
83
-
84
- expect(result).toContain('fix(meta): add on page improvements');
85
- expect(result).toContain('Files changed:');
86
- expect(result).toContain('- index.html');
87
- expect(result).toContain('Issue codes: TITLE_MISSING, META_DESC_MISSING');
88
- expect(result).toContain('Co-Authored-By: SEO Autopilot <bot@seo-autopilot.dev>');
89
- });
90
-
91
- it('maps categories to correct commit types', () => {
92
- const testCases = [
93
- { category: 'crawlability', expectedType: 'fix', expectedScope: 'seo' },
94
- { category: 'on-page', expectedType: 'fix', expectedScope: 'meta' },
95
- { category: 'structured-data', expectedType: 'feat', expectedScope: 'schema' },
96
- { category: 'performance', expectedType: 'perf', expectedScope: 'web' },
97
- { category: 'social-meta', expectedType: 'feat', expectedScope: 'og' },
98
- { category: 'images', expectedType: 'fix', expectedScope: 'images' },
99
- { category: 'links', expectedType: 'fix', expectedScope: 'links' },
100
- { category: 'security', expectedType: 'fix', expectedScope: 'security' },
101
- ];
102
-
103
- testCases.forEach(({ category, expectedType, expectedScope }) => {
104
- const fix: SEOFixCommit = {
105
- category,
106
- issues: ['TEST_ISSUE'],
107
- filesChanged: ['test.html'],
108
- description: 'test fix',
109
- };
110
- const result = formatSEOCommitMessage(fix);
111
- expect(result).toContain(`${expectedType}(${expectedScope}): test fix`);
112
- });
113
- });
114
-
115
- it('uses default scope for unknown categories', () => {
116
- const fix: SEOFixCommit = {
117
- category: 'unknown-category',
118
- issues: ['TEST_ISSUE'],
119
- filesChanged: ['test.html'],
120
- description: 'test fix',
121
- };
122
- const result = formatSEOCommitMessage(fix);
123
- expect(result).toContain('fix(seo): test fix');
124
- });
125
-
126
- it('handles multiple files', () => {
127
- const fix: SEOFixCommit = {
128
- category: 'on-page',
129
- issues: ['TEST'],
130
- filesChanged: ['index.html', 'about.html', 'contact.html'],
131
- description: 'fix meta tags',
132
- };
133
- const result = formatSEOCommitMessage(fix);
134
- expect(result).toContain('- index.html');
135
- expect(result).toContain('- about.html');
136
- expect(result).toContain('- contact.html');
137
- });
138
-
139
- it('uses custom system name and email', () => {
140
- const fix: SEOFixCommit = {
141
- category: 'on-page',
142
- issues: ['TEST'],
143
- filesChanged: ['index.html'],
144
- description: 'test',
145
- };
146
- const config: CommitConfig = {
147
- systemName: 'Custom Bot',
148
- systemEmail: 'custom@example.com',
149
- };
150
- const result = formatSEOCommitMessage(fix, config);
151
- expect(result).toContain('Co-Authored-By: Custom Bot <custom@example.com>');
152
- });
153
- });
154
-
155
- describe('generateCommitSummary', () => {
156
- it('generates summary for successful commits', () => {
157
- const commits = [
158
- {
159
- fix: {
160
- category: 'on-page',
161
- issues: ['TITLE_MISSING'],
162
- filesChanged: ['index.html'],
163
- description: 'add title tags',
164
- },
165
- result: { success: true, hash: 'abc1234' },
166
- },
167
- {
168
- fix: {
169
- category: 'social-meta',
170
- issues: ['OG_TITLE_MISSING'],
171
- filesChanged: ['index.html'],
172
- description: 'add og tags',
173
- },
174
- result: { success: true, hash: 'def5678' },
175
- },
176
- ];
177
-
178
- const summary = generateCommitSummary(commits);
179
-
180
- expect(summary).toContain('## SEO Fix Commits Summary');
181
- expect(summary).toContain('2 commits created');
182
- expect(summary).toContain('abc1234');
183
- expect(summary).toContain('def5678');
184
- expect(summary).toContain('add title tags');
185
- expect(summary).toContain('add og tags');
186
- });
187
-
188
- it('includes failed commits in summary', () => {
189
- const commits = [
190
- {
191
- fix: {
192
- category: 'on-page',
193
- issues: ['TITLE_MISSING'],
194
- filesChanged: ['index.html'],
195
- description: 'add title tags',
196
- },
197
- result: { success: true, hash: 'abc1234' },
198
- },
199
- {
200
- fix: {
201
- category: 'crawlability',
202
- issues: ['ROBOTS_TXT_MISSING'],
203
- filesChanged: ['robots.txt'],
204
- description: 'add robots.txt',
205
- },
206
- result: { success: false, error: 'Permission denied' },
207
- },
208
- ];
209
-
210
- const summary = generateCommitSummary(commits);
211
-
212
- expect(summary).toContain('1 commits created');
213
- expect(summary).toContain('1 commits failed');
214
- expect(summary).toContain('### Failed Commits');
215
- expect(summary).toContain('Permission denied');
216
- });
217
- });
218
-
219
- describe('COMMIT_TYPES and SEO_SCOPES', () => {
220
- it('has all expected commit types', () => {
221
- const types = COMMIT_TYPES.map((t) => t.type);
222
- expect(types).toContain('fix');
223
- expect(types).toContain('feat');
224
- expect(types).toContain('docs');
225
- expect(types).toContain('perf');
226
- expect(types).toContain('chore');
227
- });
228
-
229
- it('has all expected SEO scopes', () => {
230
- expect(SEO_SCOPES).toContain('seo');
231
- expect(SEO_SCOPES).toContain('meta');
232
- expect(SEO_SCOPES).toContain('og');
233
- expect(SEO_SCOPES).toContain('schema');
234
- expect(SEO_SCOPES).toContain('images');
235
- expect(SEO_SCOPES).toContain('links');
236
- expect(SEO_SCOPES).toContain('security');
237
- });
238
- });
239
- });
240
-
241
- describe('detectGitHubPages', () => {
242
- // These tests would need filesystem mocking
243
- // For now, we test the function exists and returns expected shape
244
- it('returns expected structure', () => {
245
- // Test with a non-existent path returns false
246
- const result = detectGitHubPages('/non/existent/path');
247
- expect(result).toHaveProperty('isGitHubPages');
248
- expect(typeof result.isGitHubPages).toBe('boolean');
249
- });
250
- });
251
-
252
- describe('isGitRepo', () => {
253
- it('returns false for non-git directory', () => {
254
- expect(isGitRepo('/tmp')).toBe(false);
255
- });
256
-
257
- it('returns boolean', () => {
258
- const result = isGitRepo();
259
- expect(typeof result).toBe('boolean');
260
- });
261
- });
@@ -1,329 +0,0 @@
1
- /**
2
- * Git Commit Helper
3
- *
4
- * Creates conventional commits for SEO fixes with proper co-authoring.
5
- * Supports GitHub Pages and various static site generators.
6
- */
7
-
8
- import { execSync, exec } from 'child_process';
9
- import { promisify } from 'util';
10
-
11
- const execAsync = promisify(exec);
12
-
13
- // System name is configurable (TBD - SEO Autopilot is temporary)
14
- const SYSTEM_NAME = process.env.SEO_SYSTEM_NAME || 'SEO Autopilot';
15
- const SYSTEM_EMAIL = process.env.SEO_SYSTEM_EMAIL || 'bot@seo-autopilot.dev';
16
-
17
- export interface CommitConfig {
18
- systemName?: string;
19
- systemEmail?: string;
20
- dryRun?: boolean;
21
- }
22
-
23
- export interface ConventionalCommit {
24
- type: 'fix' | 'feat' | 'docs' | 'style' | 'refactor' | 'perf' | 'chore';
25
- scope?: string;
26
- description: string;
27
- body?: string;
28
- breaking?: boolean;
29
- issues?: string[]; // Issue codes like TITLE_MISSING
30
- }
31
-
32
- export interface SEOFixCommit {
33
- category: string;
34
- issues: string[];
35
- filesChanged: string[];
36
- description: string;
37
- }
38
-
39
- /**
40
- * Maps SEO issue categories to conventional commit types and scopes
41
- */
42
- const CATEGORY_MAPPING: Record<string, { type: ConventionalCommit['type']; scope: string }> = {
43
- 'crawlability': { type: 'fix', scope: 'seo' },
44
- 'indexability': { type: 'fix', scope: 'seo' },
45
- 'on-page': { type: 'fix', scope: 'meta' },
46
- 'content': { type: 'fix', scope: 'content' },
47
- 'links': { type: 'fix', scope: 'links' },
48
- 'images': { type: 'fix', scope: 'images' },
49
- 'structured-data': { type: 'feat', scope: 'schema' },
50
- 'performance': { type: 'perf', scope: 'web' },
51
- 'security': { type: 'fix', scope: 'security' },
52
- 'mobile': { type: 'fix', scope: 'mobile' },
53
- 'international': { type: 'fix', scope: 'i18n' },
54
- 'social-meta': { type: 'feat', scope: 'og' },
55
- };
56
-
57
- /**
58
- * Formats a conventional commit message
59
- */
60
- export function formatConventionalCommit(commit: ConventionalCommit): string {
61
- let message = commit.type;
62
-
63
- if (commit.scope) {
64
- message += `(${commit.scope})`;
65
- }
66
-
67
- if (commit.breaking) {
68
- message += '!';
69
- }
70
-
71
- message += `: ${commit.description}`;
72
-
73
- if (commit.body) {
74
- message += `\n\n${commit.body}`;
75
- }
76
-
77
- if (commit.issues && commit.issues.length > 0) {
78
- message += `\n\nIssue codes: ${commit.issues.join(', ')}`;
79
- }
80
-
81
- return message;
82
- }
83
-
84
- /**
85
- * Formats a commit message for SEO fixes
86
- */
87
- export function formatSEOCommitMessage(fix: SEOFixCommit, config?: CommitConfig): string {
88
- const mapping = CATEGORY_MAPPING[fix.category] || { type: 'fix', scope: 'seo' };
89
- const systemName = config?.systemName || SYSTEM_NAME;
90
- const systemEmail = config?.systemEmail || SYSTEM_EMAIL;
91
-
92
- const commit: ConventionalCommit = {
93
- type: mapping.type,
94
- scope: mapping.scope,
95
- description: fix.description,
96
- body: `Files changed:\n${fix.filesChanged.map(f => ` - ${f}`).join('\n')}`,
97
- issues: fix.issues,
98
- };
99
-
100
- let message = formatConventionalCommit(commit);
101
-
102
- // Add co-author trailer
103
- message += `\n\nCo-Authored-By: ${systemName} <${systemEmail}>`;
104
-
105
- return message;
106
- }
107
-
108
- /**
109
- * Creates a git commit with the SEO fix
110
- */
111
- export async function createSEOCommit(
112
- fix: SEOFixCommit,
113
- config?: CommitConfig
114
- ): Promise<{ success: boolean; hash?: string; error?: string }> {
115
- const message = formatSEOCommitMessage(fix, config);
116
-
117
- if (config?.dryRun) {
118
- console.log('DRY RUN - Would create commit:');
119
- console.log('---');
120
- console.log(message);
121
- console.log('---');
122
- return { success: true, hash: 'dry-run' };
123
- }
124
-
125
- try {
126
- // Stage the files
127
- for (const file of fix.filesChanged) {
128
- await execAsync(`git add "${file}"`);
129
- }
130
-
131
- // Create the commit using heredoc for proper message formatting
132
- const { stdout } = await execAsync(`git commit -m "$(cat <<'EOF'
133
- ${message}
134
- EOF
135
- )"`);
136
-
137
- // Extract commit hash
138
- const hashMatch = stdout.match(/\[[\w-]+ ([a-f0-9]+)\]/);
139
- const hash = hashMatch ? hashMatch[1] : undefined;
140
-
141
- return { success: true, hash };
142
- } catch (error) {
143
- return { success: false, error: (error as Error).message };
144
- }
145
- }
146
-
147
- /**
148
- * Creates multiple commits, one per category
149
- */
150
- export async function createSEOCommits(
151
- fixes: SEOFixCommit[],
152
- config?: CommitConfig
153
- ): Promise<{ commits: Array<{ fix: SEOFixCommit; result: Awaited<ReturnType<typeof createSEOCommit>> }> }> {
154
- const commits = [];
155
-
156
- for (const fix of fixes) {
157
- const result = await createSEOCommit(fix, config);
158
- commits.push({ fix, result });
159
- }
160
-
161
- return { commits };
162
- }
163
-
164
- /**
165
- * Checks if the current directory is a git repository
166
- */
167
- export function isGitRepo(dir?: string): boolean {
168
- try {
169
- const cwd = dir ? { cwd: dir } : undefined;
170
- execSync('git rev-parse --is-inside-work-tree', { ...cwd, stdio: 'ignore' });
171
- return true;
172
- } catch {
173
- return false;
174
- }
175
- }
176
-
177
- /**
178
- * Initializes a git repository if not already initialized
179
- */
180
- export async function ensureGitRepo(dir?: string): Promise<void> {
181
- if (!isGitRepo(dir)) {
182
- const cwd = dir ? { cwd: dir } : undefined;
183
- await execAsync('git init', cwd);
184
- }
185
- }
186
-
187
- /**
188
- * Gets the current git user config
189
- */
190
- export function getGitUser(): { name?: string; email?: string } {
191
- try {
192
- const name = execSync('git config user.name', { encoding: 'utf8' }).trim();
193
- const email = execSync('git config user.email', { encoding: 'utf8' }).trim();
194
- return { name, email };
195
- } catch {
196
- return {};
197
- }
198
- }
199
-
200
- /**
201
- * Detects if this is a GitHub Pages repository
202
- */
203
- export function detectGitHubPages(dir: string): {
204
- isGitHubPages: boolean;
205
- type?: 'jekyll' | 'static' | 'docs' | 'custom';
206
- baseUrl?: string;
207
- } {
208
- const fs = require('fs');
209
- const path = require('path');
210
-
211
- // Check for common GitHub Pages indicators
212
- const checks = [
213
- { file: '_config.yml', type: 'jekyll' as const },
214
- { file: 'docs/index.html', type: 'docs' as const },
215
- { file: 'CNAME', type: 'custom' as const },
216
- { file: '.nojekyll', type: 'static' as const },
217
- { file: 'index.html', type: 'static' as const },
218
- ];
219
-
220
- for (const check of checks) {
221
- const filePath = path.join(dir, check.file);
222
- if (fs.existsSync(filePath)) {
223
- // Try to extract base URL from _config.yml
224
- if (check.file === '_config.yml') {
225
- try {
226
- const content = fs.readFileSync(filePath, 'utf8');
227
- const baseUrlMatch = content.match(/baseurl:\s*["']?([^"'\n]+)/);
228
- const urlMatch = content.match(/url:\s*["']?([^"'\n]+)/);
229
- return {
230
- isGitHubPages: true,
231
- type: check.type,
232
- baseUrl: urlMatch ? urlMatch[1] + (baseUrlMatch?.[1] || '') : undefined,
233
- };
234
- } catch {
235
- // Continue
236
- }
237
- }
238
-
239
- // Check for CNAME (custom domain)
240
- if (check.file === 'CNAME') {
241
- try {
242
- const cname = fs.readFileSync(path.join(dir, 'CNAME'), 'utf8').trim();
243
- return {
244
- isGitHubPages: true,
245
- type: check.type,
246
- baseUrl: `https://${cname}`,
247
- };
248
- } catch {
249
- // Continue
250
- }
251
- }
252
-
253
- return { isGitHubPages: true, type: check.type };
254
- }
255
- }
256
-
257
- // Check if remote is github.io
258
- try {
259
- const remote = execSync('git remote get-url origin', { cwd: dir, encoding: 'utf8' }).trim();
260
- if (remote.includes('github.io') || remote.includes('.github.')) {
261
- return { isGitHubPages: true, type: 'static' };
262
- }
263
- } catch {
264
- // Not a git repo or no remote
265
- }
266
-
267
- return { isGitHubPages: false };
268
- }
269
-
270
- /**
271
- * Generates a summary of commits made
272
- */
273
- export function generateCommitSummary(
274
- commits: Array<{ fix: SEOFixCommit; result: { success: boolean; hash?: string; error?: string } }>
275
- ): string {
276
- const successful = commits.filter(c => c.result.success);
277
- const failed = commits.filter(c => !c.result.success);
278
-
279
- let summary = `## SEO Fix Commits Summary\n\n`;
280
- summary += `✅ ${successful.length} commits created\n`;
281
- if (failed.length > 0) {
282
- summary += `❌ ${failed.length} commits failed\n`;
283
- }
284
- summary += '\n';
285
-
286
- if (successful.length > 0) {
287
- summary += `### Commits Created\n\n`;
288
- for (const { fix, result } of successful) {
289
- const mapping = CATEGORY_MAPPING[fix.category] || { type: 'fix', scope: 'seo' };
290
- summary += `- \`${result.hash?.slice(0, 7) || 'N/A'}\` ${mapping.type}(${mapping.scope}): ${fix.description}\n`;
291
- summary += ` - Files: ${fix.filesChanged.join(', ')}\n`;
292
- summary += ` - Issues: ${fix.issues.join(', ')}\n`;
293
- }
294
- }
295
-
296
- if (failed.length > 0) {
297
- summary += `\n### Failed Commits\n\n`;
298
- for (const { fix, result } of failed) {
299
- summary += `- ❌ ${fix.description}: ${result.error}\n`;
300
- }
301
- }
302
-
303
- return summary;
304
- }
305
-
306
- // Export types for conventional commit categories
307
- export const COMMIT_TYPES = [
308
- { type: 'fix', description: 'Bug fix (SEO issue correction)' },
309
- { type: 'feat', description: 'New feature (schema, OG tags, etc.)' },
310
- { type: 'docs', description: 'Documentation update' },
311
- { type: 'style', description: 'Code style changes (formatting)' },
312
- { type: 'refactor', description: 'Code restructuring' },
313
- { type: 'perf', description: 'Performance improvement' },
314
- { type: 'chore', description: 'Maintenance task' },
315
- ] as const;
316
-
317
- export const SEO_SCOPES = [
318
- 'seo', // General SEO
319
- 'meta', // Meta tags (title, description)
320
- 'og', // Open Graph / Twitter Cards
321
- 'schema', // Structured data / JSON-LD
322
- 'images', // Image optimization
323
- 'links', // Link fixes
324
- 'content', // Content optimization
325
- 'security', // Security headers
326
- 'mobile', // Mobile optimization
327
- 'i18n', // Internationalization
328
- 'perf', // Performance
329
- ] as const;
package/src/git/index.ts DELETED
@@ -1,12 +0,0 @@
1
- /**
2
- * Git integration module
3
- *
4
- * Provides git operations for SEO fixes including:
5
- * - Conventional commit formatting
6
- * - Co-author support
7
- * - GitHub Pages detection
8
- * - Pull request generation
9
- */
10
-
11
- export * from './commit-helper.js';
12
- export * from './pr-helper.js';