@tarunachyutuni/seo 2.0.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.
@@ -0,0 +1,4 @@
1
+
2
+ > @tarunachyutuni/seo@2.0.0 build C:\Users\Tarun\lumina\packages\seo
3
+ > tsc
4
+
@@ -0,0 +1,54 @@
1
+ import type { ProjectContext, ProjectPlan } from "@tarunachyutuni/types";
2
+ export interface SEOOptimization {
3
+ title: string;
4
+ description: string;
5
+ keywords: string[];
6
+ openGraph: OpenGraphMeta;
7
+ twitterCard: TwitterCardMeta;
8
+ jsonLD: Record<string, unknown>[];
9
+ canonical: string;
10
+ robotsDirectives: string[];
11
+ headingHierarchy: HeadingAuditResult[];
12
+ internalLinks: InternalLink[];
13
+ }
14
+ export interface OpenGraphMeta {
15
+ title: string;
16
+ description: string;
17
+ type: string;
18
+ url: string;
19
+ image: string;
20
+ siteName: string;
21
+ }
22
+ export interface TwitterCardMeta {
23
+ card: "summary" | "summary_large_image";
24
+ title: string;
25
+ description: string;
26
+ image: string;
27
+ creator?: string;
28
+ }
29
+ export interface HeadingAuditResult {
30
+ page: string;
31
+ h1Count: number;
32
+ h1Text: string[];
33
+ h2Count: number;
34
+ h3Count: number;
35
+ issues: string[];
36
+ }
37
+ export interface InternalLink {
38
+ from: string;
39
+ to: string;
40
+ anchor: string;
41
+ }
42
+ export declare class SEOAgent {
43
+ private context?;
44
+ private plan?;
45
+ optimize(context: ProjectContext, plan: ProjectPlan, domain?: string): Promise<SEOOptimization>;
46
+ generateSitemap(paths: string[], domain: string): string;
47
+ generateRobotsTxt(domain: string): string;
48
+ private extractKeywords;
49
+ private generateJSONLD;
50
+ private auditHeadings;
51
+ private generateInternalLinks;
52
+ private truncate;
53
+ }
54
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,aAAa,CAAC;IACzB,WAAW,EAAE,eAAe,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,gBAAgB,EAAE,kBAAkB,EAAE,CAAC;IACvC,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,GAAG,qBAAqB,CAAC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,QAAQ;IACnB,OAAO,CAAC,OAAO,CAAC,CAAiB;IACjC,OAAO,CAAC,IAAI,CAAC,CAAc;IAErB,QAAQ,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAiCrG,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAKxD,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIzC,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,CAAC,QAAQ;CAIjB"}
package/dist/index.js ADDED
@@ -0,0 +1,101 @@
1
+ // =============================================================================
2
+ // @tarunachyutuni/seo — SEO Intelligence Layer
3
+ // =============================================================================
4
+ export class SEOAgent {
5
+ context;
6
+ plan;
7
+ async optimize(context, plan, domain) {
8
+ this.context = context;
9
+ this.plan = plan;
10
+ const siteName = plan.projectName;
11
+ const baseDescription = context.coreValue;
12
+ return {
13
+ title: `${siteName} — ${this.truncate(baseDescription, 55)}`,
14
+ description: this.truncate(baseDescription, 155),
15
+ keywords: this.extractKeywords(context),
16
+ openGraph: {
17
+ title: siteName,
18
+ description: this.truncate(baseDescription, 200),
19
+ type: "website",
20
+ url: domain ? `https://${domain}` : `https://${siteName.toLowerCase().replace(/\s+/g, "")}.com`,
21
+ image: "/og-image.png",
22
+ siteName,
23
+ },
24
+ twitterCard: {
25
+ card: "summary_large_image",
26
+ title: siteName,
27
+ description: this.truncate(baseDescription, 200),
28
+ image: "/og-image.png",
29
+ },
30
+ jsonLD: this.generateJSONLD(siteName, baseDescription, domain),
31
+ canonical: domain ? `https://${domain}` : `https://${siteName.toLowerCase().replace(/\s+/g, "")}.com`,
32
+ robotsDirectives: ["Allow: /", "Sitemap: /sitemap.xml"],
33
+ headingHierarchy: this.auditHeadings(plan),
34
+ internalLinks: this.generateInternalLinks(plan),
35
+ };
36
+ }
37
+ generateSitemap(paths, domain) {
38
+ const urls = paths.map((p) => ` <url>\n <loc>https://${domain}${p}</loc>\n <changefreq>weekly</changefreq>\n </url>`).join("\n");
39
+ return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls}\n</urlset>`;
40
+ }
41
+ generateRobotsTxt(domain) {
42
+ return `User-agent: *\nAllow: /\nDisallow: /api/\nDisallow: /admin/\n\nSitemap: https://${domain}/sitemap.xml`;
43
+ }
44
+ extractKeywords(context) {
45
+ const words = [
46
+ ...context.industry.split(/[\s-]+/),
47
+ ...context.targetAudience.jobRoles.flatMap((r) => r.split(/[\s-]+/)),
48
+ ...context.brandPersonality,
49
+ ];
50
+ return Array.from(new Set(words.map((w) => w.toLowerCase()).filter((w) => w.length > 3))).slice(0, 10);
51
+ }
52
+ generateJSONLD(name, description, domain) {
53
+ const base = {
54
+ "@context": "https://schema.org",
55
+ "@type": "Organization",
56
+ name,
57
+ description,
58
+ };
59
+ if (domain) {
60
+ base.url = `https://${domain}`;
61
+ base["@type"] = "WebSite";
62
+ base.potentialAction = {
63
+ "@type": "SearchAction",
64
+ target: `https://${domain}/search?q={search_term_string}`,
65
+ "query-input": "required name=search_term_string",
66
+ };
67
+ }
68
+ return [base];
69
+ }
70
+ auditHeadings(plan) {
71
+ return plan.pages.map((page) => ({
72
+ page: page.name,
73
+ h1Count: 1,
74
+ h1Text: [page.name],
75
+ h2Count: page.sections.length,
76
+ h3Count: 0,
77
+ issues: page.sections.length === 0 ? ["No H2 sections found"] : [],
78
+ }));
79
+ }
80
+ generateInternalLinks(plan) {
81
+ const links = [];
82
+ for (let i = 0; i < plan.pages.length; i++) {
83
+ for (let j = 0; j < plan.pages.length; j++) {
84
+ if (i !== j) {
85
+ const fromPage = plan.pages[i];
86
+ const toPage = plan.pages[j];
87
+ if (fromPage && toPage) {
88
+ links.push({ from: fromPage.path, to: toPage.path, anchor: toPage.name });
89
+ }
90
+ }
91
+ }
92
+ }
93
+ return links;
94
+ }
95
+ truncate(text, maxLen) {
96
+ if (text.length <= maxLen)
97
+ return text;
98
+ return text.slice(0, maxLen - 3) + "...";
99
+ }
100
+ }
101
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,+CAA+C;AAC/C,gFAAgF;AAiDhF,MAAM,OAAO,QAAQ;IACX,OAAO,CAAkB;IACzB,IAAI,CAAe;IAE3B,KAAK,CAAC,QAAQ,CAAC,OAAuB,EAAE,IAAiB,EAAE,MAAe;QACxE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAEjB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC;QAClC,MAAM,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC;QAE1C,OAAO;YACL,KAAK,EAAE,GAAG,QAAQ,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,EAAE,CAAC,EAAE;YAC5D,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC;YAChD,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;YACvC,SAAS,EAAE;gBACT,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC;gBAChD,IAAI,EAAE,SAAS;gBACf,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,MAAM,EAAE,CAAC,CAAC,CAAC,WAAW,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM;gBAC/F,KAAK,EAAE,eAAe;gBACtB,QAAQ;aACT;YACD,WAAW,EAAE;gBACX,IAAI,EAAE,qBAAqB;gBAC3B,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC;gBAChD,KAAK,EAAE,eAAe;aACvB;YACD,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,CAAC;YAC9D,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,MAAM,EAAE,CAAC,CAAC,CAAC,WAAW,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM;YACrG,gBAAgB,EAAE,CAAC,UAAU,EAAE,uBAAuB,CAAC;YACvD,gBAAgB,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;YAC1C,aAAa,EAAE,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC;SAChD,CAAC;IACJ,CAAC;IAED,eAAe,CAAC,KAAe,EAAE,MAAc;QAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,6BAA6B,MAAM,GAAG,CAAC,uDAAuD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzI,OAAO,yGAAyG,IAAI,aAAa,CAAC;IACpI,CAAC;IAED,iBAAiB,CAAC,MAAc;QAC9B,OAAO,mFAAmF,MAAM,cAAc,CAAC;IACjH,CAAC;IAEO,eAAe,CAAC,OAAuB;QAC7C,MAAM,KAAK,GAAG;YACZ,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;YACnC,GAAG,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACpE,GAAG,OAAO,CAAC,gBAAgB;SAC5B,CAAC;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACzG,CAAC;IAEO,cAAc,CAAC,IAAY,EAAE,WAAmB,EAAE,MAAe;QACvE,MAAM,IAAI,GAA4B;YACpC,UAAU,EAAE,oBAAoB;YAChC,OAAO,EAAE,cAAc;YACvB,IAAI;YACJ,WAAW;SACZ,CAAC;QACF,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,GAAG,GAAG,WAAW,MAAM,EAAE,CAAC;YAC/B,IAAI,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;YAC1B,IAAI,CAAC,eAAe,GAAG;gBACrB,OAAO,EAAE,cAAc;gBACvB,MAAM,EAAE,WAAW,MAAM,gCAAgC;gBACzD,aAAa,EAAE,kCAAkC;aAClD,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IAEO,aAAa,CAAC,IAAiB;QACrC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC/B,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;YACnB,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM;YAC7B,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,EAAE;SACnE,CAAC,CAAC,CAAC;IACN,CAAC;IAEO,qBAAqB,CAAC,IAAiB;QAC7C,MAAM,KAAK,GAAmB,EAAE,CAAC;QACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBAC7B,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;wBACvB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;oBAC5E,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,QAAQ,CAAC,IAAY,EAAE,MAAc;QAC3C,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM;YAAE,OAAO,IAAI,CAAC;QACvC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;IAC3C,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@tarunachyutuni/seo",
3
+ "version": "2.0.0",
4
+ "description": "Seo package for Lumina",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "dependencies": {
16
+ "@tarunachyutuni/types": "2.0.0"
17
+ },
18
+ "devDependencies": {
19
+ "typescript": "^5.5.0"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc",
26
+ "typecheck": "tsc --noEmit"
27
+ }
28
+ }
package/src/index.ts ADDED
@@ -0,0 +1,158 @@
1
+ // =============================================================================
2
+ // @tarunachyutuni/seo — SEO Intelligence Layer
3
+ // =============================================================================
4
+
5
+ import type { ProjectContext, ProjectPlan } from "@tarunachyutuni/types";
6
+
7
+ export interface SEOOptimization {
8
+ title: string;
9
+ description: string;
10
+ keywords: string[];
11
+ openGraph: OpenGraphMeta;
12
+ twitterCard: TwitterCardMeta;
13
+ jsonLD: Record<string, unknown>[];
14
+ canonical: string;
15
+ robotsDirectives: string[];
16
+ headingHierarchy: HeadingAuditResult[];
17
+ internalLinks: InternalLink[];
18
+ }
19
+
20
+ export interface OpenGraphMeta {
21
+ title: string;
22
+ description: string;
23
+ type: string;
24
+ url: string;
25
+ image: string;
26
+ siteName: string;
27
+ }
28
+
29
+ export interface TwitterCardMeta {
30
+ card: "summary" | "summary_large_image";
31
+ title: string;
32
+ description: string;
33
+ image: string;
34
+ creator?: string;
35
+ }
36
+
37
+ export interface HeadingAuditResult {
38
+ page: string;
39
+ h1Count: number;
40
+ h1Text: string[];
41
+ h2Count: number;
42
+ h3Count: number;
43
+ issues: string[];
44
+ }
45
+
46
+ export interface InternalLink {
47
+ from: string;
48
+ to: string;
49
+ anchor: string;
50
+ }
51
+
52
+ export class SEOAgent {
53
+ private context?: ProjectContext;
54
+ private plan?: ProjectPlan;
55
+
56
+ async optimize(context: ProjectContext, plan: ProjectPlan, domain?: string): Promise<SEOOptimization> {
57
+ this.context = context;
58
+ this.plan = plan;
59
+
60
+ const siteName = plan.projectName;
61
+ const baseDescription = context.coreValue;
62
+
63
+ return {
64
+ title: `${siteName} — ${this.truncate(baseDescription, 55)}`,
65
+ description: this.truncate(baseDescription, 155),
66
+ keywords: this.extractKeywords(context),
67
+ openGraph: {
68
+ title: siteName,
69
+ description: this.truncate(baseDescription, 200),
70
+ type: "website",
71
+ url: domain ? `https://${domain}` : `https://${siteName.toLowerCase().replace(/\s+/g, "")}.com`,
72
+ image: "/og-image.png",
73
+ siteName,
74
+ },
75
+ twitterCard: {
76
+ card: "summary_large_image",
77
+ title: siteName,
78
+ description: this.truncate(baseDescription, 200),
79
+ image: "/og-image.png",
80
+ },
81
+ jsonLD: this.generateJSONLD(siteName, baseDescription, domain),
82
+ canonical: domain ? `https://${domain}` : `https://${siteName.toLowerCase().replace(/\s+/g, "")}.com`,
83
+ robotsDirectives: ["Allow: /", "Sitemap: /sitemap.xml"],
84
+ headingHierarchy: this.auditHeadings(plan),
85
+ internalLinks: this.generateInternalLinks(plan),
86
+ };
87
+ }
88
+
89
+ generateSitemap(paths: string[], domain: string): string {
90
+ const urls = paths.map((p) => ` <url>\n <loc>https://${domain}${p}</loc>\n <changefreq>weekly</changefreq>\n </url>`).join("\n");
91
+ return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls}\n</urlset>`;
92
+ }
93
+
94
+ generateRobotsTxt(domain: string): string {
95
+ return `User-agent: *\nAllow: /\nDisallow: /api/\nDisallow: /admin/\n\nSitemap: https://${domain}/sitemap.xml`;
96
+ }
97
+
98
+ private extractKeywords(context: ProjectContext): string[] {
99
+ const words = [
100
+ ...context.industry.split(/[\s-]+/),
101
+ ...context.targetAudience.jobRoles.flatMap((r) => r.split(/[\s-]+/)),
102
+ ...context.brandPersonality,
103
+ ];
104
+ return Array.from(new Set(words.map((w) => w.toLowerCase()).filter((w) => w.length > 3))).slice(0, 10);
105
+ }
106
+
107
+ private generateJSONLD(name: string, description: string, domain?: string): Record<string, unknown>[] {
108
+ const base: Record<string, unknown> = {
109
+ "@context": "https://schema.org",
110
+ "@type": "Organization",
111
+ name,
112
+ description,
113
+ };
114
+ if (domain) {
115
+ base.url = `https://${domain}`;
116
+ base["@type"] = "WebSite";
117
+ base.potentialAction = {
118
+ "@type": "SearchAction",
119
+ target: `https://${domain}/search?q={search_term_string}`,
120
+ "query-input": "required name=search_term_string",
121
+ };
122
+ }
123
+ return [base];
124
+ }
125
+
126
+ private auditHeadings(plan: ProjectPlan): HeadingAuditResult[] {
127
+ return plan.pages.map((page) => ({
128
+ page: page.name,
129
+ h1Count: 1,
130
+ h1Text: [page.name],
131
+ h2Count: page.sections.length,
132
+ h3Count: 0,
133
+ issues: page.sections.length === 0 ? ["No H2 sections found"] : [],
134
+ }));
135
+ }
136
+
137
+ private generateInternalLinks(plan: ProjectPlan): InternalLink[] {
138
+ const links: InternalLink[] = [];
139
+ for (let i = 0; i < plan.pages.length; i++) {
140
+ for (let j = 0; j < plan.pages.length; j++) {
141
+ if (i !== j) {
142
+ const fromPage = plan.pages[i];
143
+ const toPage = plan.pages[j];
144
+ if (fromPage && toPage) {
145
+ links.push({ from: fromPage.path, to: toPage.path, anchor: toPage.name });
146
+ }
147
+ }
148
+ }
149
+ }
150
+ return links;
151
+ }
152
+
153
+ private truncate(text: string, maxLen: number): string {
154
+ if (text.length <= maxLen) return text;
155
+ return text.slice(0, maxLen - 3) + "...";
156
+ }
157
+ }
158
+
package/tsconfig.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": { "outDir": "./dist", "rootDir": "./src" },
4
+ "include": ["src/**/*"]
5
+ }