@rankcli/agent-runtime 0.0.15 → 0.0.17

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 (203) hide show
  1. package/README.md +5 -4
  2. package/dist/index.d.mts +44 -393
  3. package/dist/index.d.ts +44 -393
  4. package/dist/index.js +22098 -26131
  5. package/dist/index.mjs +11834 -15857
  6. package/package.json +10 -4
  7. package/scripts/build-deno.ts +0 -134
  8. package/src/analyzers/core-web-vitals-analyzer.test.ts +0 -236
  9. package/src/analyzers/core-web-vitals-analyzer.ts +0 -557
  10. package/src/analyzers/geo-analyzer.test.ts +0 -310
  11. package/src/analyzers/geo-analyzer.ts +0 -814
  12. package/src/analyzers/image-optimization-analyzer.test.ts +0 -145
  13. package/src/analyzers/image-optimization-analyzer.ts +0 -348
  14. package/src/analyzers/index.ts +0 -233
  15. package/src/analyzers/internal-linking-analyzer.test.ts +0 -141
  16. package/src/analyzers/internal-linking-analyzer.ts +0 -419
  17. package/src/analyzers/mobile-seo-analyzer.test.ts +0 -140
  18. package/src/analyzers/mobile-seo-analyzer.ts +0 -455
  19. package/src/analyzers/security-headers-analyzer.test.ts +0 -115
  20. package/src/analyzers/security-headers-analyzer.ts +0 -318
  21. package/src/analyzers/structured-data-analyzer.test.ts +0 -210
  22. package/src/analyzers/structured-data-analyzer.ts +0 -590
  23. package/src/audit/ai/analyzer.ts +0 -347
  24. package/src/audit/ai/index.ts +0 -29
  25. package/src/audit/ai/prompts/content-analysis.ts +0 -271
  26. package/src/audit/ai/types.ts +0 -179
  27. package/src/audit/checks/additional-checks.ts +0 -439
  28. package/src/audit/checks/agent-experience.ts +0 -108
  29. package/src/audit/checks/ai-citation-worthiness.ts +0 -399
  30. package/src/audit/checks/ai-content-structure.ts +0 -325
  31. package/src/audit/checks/ai-readiness.ts +0 -406
  32. package/src/audit/checks/anchor-text.ts +0 -179
  33. package/src/audit/checks/answer-conciseness.ts +0 -322
  34. package/src/audit/checks/asset-minification.ts +0 -270
  35. package/src/audit/checks/bing-optimization.ts +0 -206
  36. package/src/audit/checks/brand-mention-optimization.ts +0 -349
  37. package/src/audit/checks/caching-headers.ts +0 -305
  38. package/src/audit/checks/canonical-advanced.ts +0 -150
  39. package/src/audit/checks/canonical-domain.ts +0 -196
  40. package/src/audit/checks/citation-quality.ts +0 -358
  41. package/src/audit/checks/client-rendering.ts +0 -542
  42. package/src/audit/checks/color-contrast.ts +0 -342
  43. package/src/audit/checks/content-freshness.ts +0 -170
  44. package/src/audit/checks/content-science.ts +0 -589
  45. package/src/audit/checks/conversion-elements.ts +0 -526
  46. package/src/audit/checks/crawlability.ts +0 -220
  47. package/src/audit/checks/directory-listing.ts +0 -172
  48. package/src/audit/checks/dom-analysis.ts +0 -191
  49. package/src/audit/checks/dom-size.ts +0 -246
  50. package/src/audit/checks/duplicate-content.ts +0 -194
  51. package/src/audit/checks/eeat-signals.ts +0 -990
  52. package/src/audit/checks/entity-seo.ts +0 -396
  53. package/src/audit/checks/featured-snippet.ts +0 -473
  54. package/src/audit/checks/freshness-signals.ts +0 -443
  55. package/src/audit/checks/funnel-intent.ts +0 -463
  56. package/src/audit/checks/hreflang.ts +0 -174
  57. package/src/audit/checks/html-compliance.ts +0 -302
  58. package/src/audit/checks/image-dimensions.ts +0 -167
  59. package/src/audit/checks/images.ts +0 -160
  60. package/src/audit/checks/indexnow.ts +0 -275
  61. package/src/audit/checks/interactive-tools.ts +0 -475
  62. package/src/audit/checks/internal-link-graph.ts +0 -436
  63. package/src/audit/checks/keyword-analysis.ts +0 -239
  64. package/src/audit/checks/keyword-cannibalization.ts +0 -385
  65. package/src/audit/checks/keyword-placement.ts +0 -471
  66. package/src/audit/checks/links.ts +0 -273
  67. package/src/audit/checks/llms-txt.ts +0 -224
  68. package/src/audit/checks/local-seo.ts +0 -296
  69. package/src/audit/checks/mobile.ts +0 -167
  70. package/src/audit/checks/modern-images.ts +0 -226
  71. package/src/audit/checks/navboost-signals.ts +0 -395
  72. package/src/audit/checks/on-page.ts +0 -209
  73. package/src/audit/checks/page-resources.ts +0 -285
  74. package/src/audit/checks/pagination.ts +0 -180
  75. package/src/audit/checks/performance.ts +0 -153
  76. package/src/audit/checks/platform-presence.ts +0 -580
  77. package/src/audit/checks/rag-chunk-readiness.test.ts +0 -159
  78. package/src/audit/checks/rag-chunk-readiness.ts +0 -163
  79. package/src/audit/checks/redirect-analysis.ts +0 -153
  80. package/src/audit/checks/redirect-chain.ts +0 -389
  81. package/src/audit/checks/resource-hints.ts +0 -420
  82. package/src/audit/checks/responsive-css.ts +0 -247
  83. package/src/audit/checks/responsive-images.ts +0 -396
  84. package/src/audit/checks/review-ecosystem.ts +0 -415
  85. package/src/audit/checks/robots-validation.ts +0 -373
  86. package/src/audit/checks/security-headers.ts +0 -188
  87. package/src/audit/checks/security.ts +0 -144
  88. package/src/audit/checks/serp-preview.ts +0 -251
  89. package/src/audit/checks/site-maturity.ts +0 -453
  90. package/src/audit/checks/social-meta.test.ts +0 -275
  91. package/src/audit/checks/social-meta.ts +0 -134
  92. package/src/audit/checks/soft-404.ts +0 -151
  93. package/src/audit/checks/structured-data.ts +0 -238
  94. package/src/audit/checks/tech-detection.ts +0 -496
  95. package/src/audit/checks/topical-clusters.ts +0 -435
  96. package/src/audit/checks/tracker-bloat.ts +0 -462
  97. package/src/audit/checks/tracking-verification.test.ts +0 -371
  98. package/src/audit/checks/tracking-verification.ts +0 -636
  99. package/src/audit/checks/url-safety.ts +0 -682
  100. package/src/audit/deno-entry.ts +0 -66
  101. package/src/audit/discovery/index.ts +0 -15
  102. package/src/audit/discovery/link-crawler.ts +0 -233
  103. package/src/audit/discovery/repo-routes.ts +0 -347
  104. package/src/audit/engine.ts +0 -633
  105. package/src/audit/fixes/index.ts +0 -209
  106. package/src/audit/fixes/social-meta-fixes.test.ts +0 -329
  107. package/src/audit/fixes/social-meta-fixes.ts +0 -463
  108. package/src/audit/index.ts +0 -74
  109. package/src/audit/runner.test.ts +0 -299
  110. package/src/audit/runner.ts +0 -130
  111. package/src/audit/types.ts +0 -1987
  112. package/src/content/featured-snippet.ts +0 -367
  113. package/src/content/generator.test.ts +0 -534
  114. package/src/content/generator.ts +0 -501
  115. package/src/content/headline.ts +0 -317
  116. package/src/content/index.ts +0 -62
  117. package/src/content/intent.ts +0 -258
  118. package/src/content/keyword-density.ts +0 -349
  119. package/src/content/readability.ts +0 -262
  120. package/src/executor.ts +0 -336
  121. package/src/fixer/framework-fixes.test.ts +0 -489
  122. package/src/fixer/framework-fixes.ts +0 -5287
  123. package/src/fixer/index.ts +0 -6
  124. package/src/fixer/schemas.ts +0 -971
  125. package/src/fixer.ts +0 -642
  126. package/src/frameworks/detector.test.ts +0 -248
  127. package/src/frameworks/detector.ts +0 -899
  128. package/src/frameworks/index.ts +0 -68
  129. package/src/frameworks/recipes/angular.yaml +0 -171
  130. package/src/frameworks/recipes/astro.yaml +0 -206
  131. package/src/frameworks/recipes/django.yaml +0 -180
  132. package/src/frameworks/recipes/laravel.yaml +0 -137
  133. package/src/frameworks/recipes/nextjs.yaml +0 -268
  134. package/src/frameworks/recipes/nuxt.yaml +0 -175
  135. package/src/frameworks/recipes/rails.yaml +0 -188
  136. package/src/frameworks/recipes/react.yaml +0 -202
  137. package/src/frameworks/recipes/sveltekit.yaml +0 -154
  138. package/src/frameworks/recipes/vue.yaml +0 -137
  139. package/src/frameworks/recipes/wordpress.yaml +0 -209
  140. package/src/frameworks/suggestion-engine.ts +0 -357
  141. package/src/geo/geo-content.test.ts +0 -305
  142. package/src/geo/geo-content.ts +0 -266
  143. package/src/geo/geo-history.test.ts +0 -473
  144. package/src/geo/geo-history.ts +0 -433
  145. package/src/geo/geo-tracker.test.ts +0 -359
  146. package/src/geo/geo-tracker.ts +0 -411
  147. package/src/geo/index.ts +0 -11
  148. package/src/geo/llm-citation-checker.ts +0 -188
  149. package/src/git/commit-helper.test.ts +0 -261
  150. package/src/git/commit-helper.ts +0 -329
  151. package/src/git/index.ts +0 -12
  152. package/src/git/pr-helper.test.ts +0 -284
  153. package/src/git/pr-helper.ts +0 -307
  154. package/src/index.ts +0 -76
  155. package/src/keywords/ai-keyword-engine.ts +0 -1062
  156. package/src/keywords/ai-summarizer.ts +0 -387
  157. package/src/keywords/ci-mode.ts +0 -555
  158. package/src/keywords/engine.ts +0 -359
  159. package/src/keywords/index.ts +0 -151
  160. package/src/keywords/llm-judge.ts +0 -357
  161. package/src/keywords/nlp-analysis.ts +0 -706
  162. package/src/keywords/prioritizer.ts +0 -295
  163. package/src/keywords/site-crawler.ts +0 -342
  164. package/src/keywords/sources/autocomplete.ts +0 -139
  165. package/src/keywords/sources/competitive-search.ts +0 -450
  166. package/src/keywords/sources/competitor-analysis.ts +0 -374
  167. package/src/keywords/sources/dataforseo.ts +0 -206
  168. package/src/keywords/sources/free-sources.ts +0 -294
  169. package/src/keywords/sources/gsc.ts +0 -123
  170. package/src/keywords/topic-grouping.ts +0 -327
  171. package/src/keywords/types.ts +0 -144
  172. package/src/keywords/wizard.ts +0 -457
  173. package/src/loader.ts +0 -40
  174. package/src/ranking/index.ts +0 -5
  175. package/src/ranking/serp-client.ts +0 -348
  176. package/src/ranking/tracker.ts +0 -380
  177. package/src/ranking/types.ts +0 -123
  178. package/src/reports/index.ts +0 -7
  179. package/src/reports/report-generator.test.ts +0 -293
  180. package/src/reports/report-generator.ts +0 -713
  181. package/src/scheduler/alerts.test.ts +0 -458
  182. package/src/scheduler/alerts.ts +0 -328
  183. package/src/scheduler/index.ts +0 -8
  184. package/src/scheduler/scheduled-audit.test.ts +0 -377
  185. package/src/scheduler/scheduled-audit.ts +0 -149
  186. package/src/test/integration-test.ts +0 -325
  187. package/src/tools/analyzer.ts +0 -373
  188. package/src/tools/crawl.ts +0 -293
  189. package/src/tools/files.ts +0 -301
  190. package/src/tools/h1-fixer.ts +0 -249
  191. package/src/tools/index.ts +0 -67
  192. package/src/tracking/github-action.ts +0 -326
  193. package/src/tracking/google-analytics.ts +0 -265
  194. package/src/tracking/index.ts +0 -45
  195. package/src/tracking/report-generator.ts +0 -386
  196. package/src/tracking/search-console.ts +0 -335
  197. package/src/types.ts +0 -148
  198. package/src/utils/http.ts +0 -302
  199. package/src/wasm-adapter.ts +0 -297
  200. package/src/wasm-entry.ts +0 -14
  201. package/tsconfig.json +0 -17
  202. package/tsup.wasm.config.ts +0 -26
  203. 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';