geo-ai-search-optimization 1.4.0 → 1.4.1

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.
package/README.md CHANGED
@@ -81,6 +81,25 @@ geo-ai-search-optimization page-audit ./content/posts/geo-guide.mdx --json --out
81
81
  - rewrite brief
82
82
  - 可直接交给 agent 的 page-level prompt
83
83
 
84
+ ## Rewrite Pack 命令
85
+
86
+ 如果你已经知道某个页面有问题,想直接拿到更接近“改写方案”的产物,可以用 `rewrite-pack`:
87
+
88
+ ```bash
89
+ geo-ai-search-optimization rewrite-pack https://example.com/blog/geo-guide
90
+ geo-ai-search-optimization rewrite-pack ./content/posts/geo-guide.mdx
91
+ geo-ai-search-optimization rewrite-pack ./content/posts/geo-guide.mdx --json --out ./reports/rewrite-pack.json
92
+ ```
93
+
94
+ 它会输出:
95
+
96
+ - metadata drafts
97
+ - 建议章节结构
98
+ - FAQ questions
99
+ - schema recommendations
100
+ - execution checklist
101
+ - 可直接交给 agent 的 rewrite prompt
102
+
84
103
  ## Agent Resume 命令
85
104
 
86
105
  如果 GEO 工作已经做过一轮或多轮,你不想让下一个 agent 从头重新判断,而是想让它从最近一个可靠恢复点继续,可以直接用 `agent-resume`:
@@ -963,6 +982,12 @@ geo-ai-search-optimization help
963
982
  - 输出页面分数、问题区域、推荐新增模块、rewrite brief 与 agent prompt
964
983
  - 产品能力从“站点级诊断”扩展到“页面级修复入口”
965
984
 
985
+ ## New in 1.4.1
986
+
987
+ - 新增 `rewrite-pack`
988
+ - 基于 `page-audit` 继续产出 metadata drafts、章节结构、FAQ questions、schema recommendations 与 execution checklist
989
+ - 让产品从“页面级诊断”继续推进到“页面级改写方案”
990
+
966
991
  ## New in 1.2.20
967
992
 
968
993
  - 新增 `agent-continue`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geo-ai-search-optimization",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "Install and run a Generative Engine Optimization (GEO)-first, SEO-supported Codex skill for website optimization.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,6 +15,7 @@ import {
15
15
  import { createLlmsTxt } from "./llms-txt.js";
16
16
  import { auditPage, renderPageAuditMarkdown, writePageAuditOutput } from "./page-audit.js";
17
17
  import { createQuickStartPlan, renderQuickStartMarkdown, writeQuickStartOutput } from "./quick-start.js";
18
+ import { createRewritePack, renderRewritePackMarkdown, writeRewritePackOutput } from "./rewrite-pack.js";
18
19
  import { renderScanMarkdown, scanProject, writeScanOutput } from "./scan.js";
19
20
  import { createSchemaTemplate } from "./schema.js";
20
21
  import { analyzeWebsiteUrl, renderWebsiteOnboardingMarkdown, writeWebsiteOnboardingOutput } from "./url-onboarding.js";
@@ -25,6 +26,7 @@ export const SITE_OPS_HELP_LINES = [
25
26
  " geo-ai-search-optimization onboard [--url <website-url>] [--goal <goal>] [--existing-assets <list>] [--json] [--out <file>]",
26
27
  " geo-ai-search-optimization onboard-url <website-url> [--json] [--out <file>]",
27
28
  " geo-ai-search-optimization page-audit <url-or-file> [--json] [--out <file>]",
29
+ " geo-ai-search-optimization rewrite-pack <url-or-file> [--json] [--out <file>]",
28
30
  " geo-ai-search-optimization init-llms [target-dir] [--site-name <name>] [--site-url <url>] [--overwrite] [--json]",
29
31
  " geo-ai-search-optimization init-schema <type> [target-dir] [--site-url <url>] [--overwrite] [--json]",
30
32
  " geo-ai-search-optimization audit <project-path> [--json] [--out <file>] [--max-file-size <bytes>] [--max-examples <count>]",
@@ -92,6 +94,21 @@ const handlePageAudit = createStructuredOutputCommandHandler({
92
94
  getOutputJson: (args) => hasFlag(args, "--json")
93
95
  });
94
96
 
97
+ const handleRewritePack = createStructuredOutputCommandHandler({
98
+ commandLabel: "rewrite pack",
99
+ execute: async (args) => {
100
+ const input = args.find((value) => !value.startsWith("-"));
101
+ if (!input) {
102
+ throw new Error("rewrite-pack requires a URL or file path");
103
+ }
104
+
105
+ return createRewritePack(input, {});
106
+ },
107
+ renderMarkdown: (report) => `${renderRewritePackMarkdown(report)}\n`,
108
+ writeOutput: writeRewritePackOutput,
109
+ getOutputJson: (args) => hasFlag(args, "--json")
110
+ });
111
+
95
112
  const handleInitLlms = createActionCommandHandler({
96
113
  execute: async (args) =>
97
114
  createLlmsTxt({
@@ -171,6 +188,7 @@ export const SITE_OPS_COMMAND_HANDLERS = {
171
188
  onboard: handleInteractiveOnboard,
172
189
  "onboard-url": handleOnboardUrl,
173
190
  "page-audit": handlePageAudit,
191
+ "rewrite-pack": handleRewritePack,
174
192
  "init-llms": handleInitLlms,
175
193
  "init-schema": handleInitSchema,
176
194
  audit: handleAudit,
package/src/index.js CHANGED
@@ -43,6 +43,7 @@ export { createPmBrief, renderPmBriefMarkdown, writePmBriefOutput } from "./pm-b
43
43
  export { renderPublishPackMarkdown, writePublishPack } from "./publish-pack.js";
44
44
  export { createQuickStartPlan, renderQuickStartMarkdown, writeQuickStartOutput } from "./quick-start.js";
45
45
  export { generateReport, writeReportOutput } from "./report.js";
46
+ export { createRewritePack, renderRewritePackMarkdown, writeRewritePackOutput } from "./rewrite-pack.js";
46
47
  export { createRoadmap, renderRoadmapMarkdown, writeRoadmapOutput } from "./roadmap.js";
47
48
  export { createSchemaTemplate } from "./schema.js";
48
49
  export { scanProject, renderScanMarkdown, writeScanOutput } from "./scan.js";
@@ -0,0 +1,198 @@
1
+ import { auditPage, writePageAuditOutput } from "./page-audit.js";
2
+
3
+ function buildOpeningDraft(report) {
4
+ const title = report.metadata.title || "这个页面";
5
+ return [
6
+ `${title} 是一页需要先用直接答案说明核心价值的内容。`,
7
+ "这页最适合先讲清楚它是什么、适合谁、什么时候不适合,以及用户下一步应该看什么。",
8
+ "如果没有这些信息,生成式搜索系统很难稳定提取出可引用的答案。"
9
+ ].join(" ");
10
+ }
11
+
12
+ function buildSuggestedHeadings(report) {
13
+ const headings = [
14
+ "这是什么",
15
+ "适合谁",
16
+ "什么时候不适合",
17
+ "和其他方案有什么差别",
18
+ "关键事实与证据",
19
+ "下一步该怎么做"
20
+ ];
21
+
22
+ if (report.signals.comparison_intent.count > 0) {
23
+ headings.splice(3, 1, "和替代方案相比有什么差别");
24
+ }
25
+
26
+ return headings.slice(0, 6);
27
+ }
28
+
29
+ function buildFaqQuestions(report) {
30
+ return [
31
+ `${report.metadata.title || "这页的主题"} 适合哪些人?`,
32
+ "什么时候不应该选择这个方案?",
33
+ "有哪些限制条件或前提?",
34
+ "有哪些证据可以支持这页的主张?"
35
+ ];
36
+ }
37
+
38
+ function buildSchemaRecommendations(report) {
39
+ const recommendations = [];
40
+
41
+ if (report.signals.qa_headings.count > 0 || report.headingStats.questionHeadingCount > 0) {
42
+ recommendations.push("FAQPage");
43
+ }
44
+
45
+ if (report.signals.original_research.count > 0) {
46
+ recommendations.push("Article");
47
+ }
48
+
49
+ if (report.signals.comparison_intent.count > 0) {
50
+ recommendations.push("Article");
51
+ }
52
+
53
+ if (recommendations.length === 0) {
54
+ recommendations.push("Article");
55
+ }
56
+
57
+ return Array.from(new Set(recommendations));
58
+ }
59
+
60
+ function buildMetadataDrafts(report) {
61
+ const baseTitle = report.metadata.title || "页面主题";
62
+ return {
63
+ title: `${baseTitle}|适合谁、限制与关键信息`,
64
+ metaDescription: `${baseTitle} 的直接答案、适用对象、限制条件、关键证据与下一步建议。`,
65
+ canonical: report.metadata.canonical || "请设置到该页面的唯一正式 URL"
66
+ };
67
+ }
68
+
69
+ function buildContentSections(report) {
70
+ return [
71
+ {
72
+ name: "Opening summary",
73
+ goal: "用 2 到 4 句先给直接答案。",
74
+ draft: buildOpeningDraft(report)
75
+ },
76
+ {
77
+ name: "Decision block",
78
+ goal: "明确适合谁、什么时候不适合、主要 trade-off。",
79
+ bullets: [
80
+ "适合谁",
81
+ "主要限制",
82
+ "决策条件",
83
+ "如果不适合,应该去看哪一页"
84
+ ]
85
+ },
86
+ {
87
+ name: "Evidence block",
88
+ goal: "把结论和主张接到来源、案例、方法论或数据。",
89
+ bullets: [
90
+ "来源链接",
91
+ "方法论说明",
92
+ "案例或截图",
93
+ "更新时间"
94
+ ]
95
+ }
96
+ ];
97
+ }
98
+
99
+ function buildExecutionChecklist(report) {
100
+ return [
101
+ "先重写 opening summary,让第一屏可以直接回答用户问题。",
102
+ "补上问答式 H2 和 decision block。",
103
+ "补来源链接、作者/更新时间和 evidence block。",
104
+ "补最贴近页面真实内容的 schema。",
105
+ "完成后重新跑 page-audit,对比分数和问题区域。"
106
+ ];
107
+ }
108
+
109
+ export async function createRewritePack(input, options = {}) {
110
+ const pageAudit = await auditPage(input, options);
111
+
112
+ return {
113
+ kind: "geo-rewrite-pack",
114
+ input,
115
+ sourceType: pageAudit.sourceType,
116
+ reference: pageAudit.reference,
117
+ summary: `这份 rewrite pack 基于单页审计生成,优先帮助你把页面改成更适合生成式搜索理解与引用的 answer-first 结构。`,
118
+ currentScore: {
119
+ score: pageAudit.score.score,
120
+ maxScore: pageAudit.score.maxScore,
121
+ label: pageAudit.scoreLabel
122
+ },
123
+ pageAudit,
124
+ metadataDrafts: buildMetadataDrafts(pageAudit),
125
+ suggestedHeadings: buildSuggestedHeadings(pageAudit),
126
+ faqQuestions: buildFaqQuestions(pageAudit),
127
+ schemaRecommendations: buildSchemaRecommendations(pageAudit),
128
+ contentSections: buildContentSections(pageAudit),
129
+ executionChecklist: buildExecutionChecklist(pageAudit),
130
+ agentPrompt: [
131
+ "请根据这份 rewrite pack 改写页面。",
132
+ `页面:${pageAudit.reference}`,
133
+ `当前分数:${pageAudit.score.score}/${pageAudit.score.maxScore}`,
134
+ `优先处理:${pageAudit.problemAreas.map((item) => item.area).join("、") || "opening summary 与 evidence block"}`,
135
+ "先改 metadata drafts 和 opening summary,再补 headings、FAQ、evidence block、schema。",
136
+ "改完后重新跑 page-audit,确认页面级 GEO 分数有提升。"
137
+ ].join(" ")
138
+ };
139
+ }
140
+
141
+ export function renderRewritePackMarkdown(pack) {
142
+ const lines = [
143
+ "# GEO Rewrite Pack",
144
+ "",
145
+ `- 输入:\`${pack.input}\``,
146
+ `- 分析对象:\`${pack.reference}\``,
147
+ `- 当前分数:\`${pack.currentScore.score}/${pack.currentScore.maxScore}\`(${pack.currentScore.label})`,
148
+ `- 总结:${pack.summary}`,
149
+ "",
150
+ "## Metadata Drafts",
151
+ "",
152
+ `- title:${pack.metadataDrafts.title}`,
153
+ `- meta description:${pack.metadataDrafts.metaDescription}`,
154
+ `- canonical:${pack.metadataDrafts.canonical}`,
155
+ "",
156
+ "## Suggested Headings",
157
+ ""
158
+ ];
159
+
160
+ for (const heading of pack.suggestedHeadings) {
161
+ lines.push(`- ${heading}`);
162
+ }
163
+
164
+ lines.push("", "## FAQ Questions", "");
165
+ for (const question of pack.faqQuestions) {
166
+ lines.push(`- ${question}`);
167
+ }
168
+
169
+ lines.push("", "## Schema Recommendations", "");
170
+ for (const schema of pack.schemaRecommendations) {
171
+ lines.push(`- ${schema}`);
172
+ }
173
+
174
+ lines.push("", "## Content Sections", "");
175
+ for (const section of pack.contentSections) {
176
+ lines.push(`- ${section.name}|${section.goal}`);
177
+ if (section.draft) {
178
+ lines.push(` Draft:${section.draft}`);
179
+ }
180
+ if (section.bullets) {
181
+ for (const bullet of section.bullets) {
182
+ lines.push(` - ${bullet}`);
183
+ }
184
+ }
185
+ }
186
+
187
+ lines.push("", "## Execution Checklist", "");
188
+ for (const item of pack.executionChecklist) {
189
+ lines.push(`- ${item}`);
190
+ }
191
+
192
+ lines.push("", "## Agent Prompt", "", pack.agentPrompt, "");
193
+ return lines.join("\n");
194
+ }
195
+
196
+ export async function writeRewritePackOutput(outputPath, content) {
197
+ return writePageAuditOutput(outputPath, content);
198
+ }