geo-ai-search-optimization 1.1.8 → 1.2.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.
- package/README.md +58 -0
- package/package.json +1 -1
- package/resources/geo-ai-search-optimization/references/quick-start.md +5 -1
- package/resources/geo-ai-search-optimization-completion-report/SKILL.md +43 -0
- package/resources/geo-ai-search-optimization-completion-report/agents/openai.yaml +4 -0
- package/resources/geo-ai-search-optimization-completion-report/references/completion-patterns.md +25 -0
- package/resources/geo-ai-search-optimization-repair-loop/SKILL.md +40 -0
- package/resources/geo-ai-search-optimization-repair-loop/agents/openai.yaml +4 -0
- package/resources/geo-ai-search-optimization-repair-loop/references/repair-loop-patterns.md +33 -0
- package/resources/geo-ai-search-optimization-usage/SKILL.md +10 -2
- package/resources/geo-ai-search-optimization-usage/references/usage-patterns.md +28 -0
- package/src/apply-plan.js +303 -0
- package/src/cli.js +67 -0
- package/src/completion-report.js +220 -0
- package/src/index.js +2 -0
- package/src/quick-start.js +3 -1
package/README.md
CHANGED
|
@@ -147,6 +147,48 @@ geo-ai-search-optimization agent-handoff https://example.com
|
|
|
147
147
|
- 让 agent 先基于当前工件给出结构化建议
|
|
148
148
|
- 让 PM 把 GEO 问题变成交接包,而不是临时口头说明
|
|
149
149
|
|
|
150
|
+
## Apply Plan 命令
|
|
151
|
+
|
|
152
|
+
如果你希望 agent 不只是“接手”,而是直接进入执行闭环,现在可以用 `apply-plan`:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
geo-ai-search-optimization apply-plan ./your-site
|
|
156
|
+
geo-ai-search-optimization apply-plan ./your-site --task fix-01 --format json --out ./reports/apply-plan.json
|
|
157
|
+
geo-ai-search-optimization apply-plan https://example.com
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`apply-plan` 会输出:
|
|
161
|
+
|
|
162
|
+
- 本轮应该先执行哪些任务
|
|
163
|
+
- 每个任务先检查什么
|
|
164
|
+
- 建议怎么改
|
|
165
|
+
- 该跑哪些验证命令
|
|
166
|
+
- 完成后怎么向用户回报
|
|
167
|
+
|
|
168
|
+
这适合:
|
|
169
|
+
|
|
170
|
+
- 让 agent 直接开始修复
|
|
171
|
+
- 让 agent 在每个任务完成后有一致的回报格式
|
|
172
|
+
- 把 GEO workflow 从“分析”推进到“执行 + 验证 + 回报”
|
|
173
|
+
|
|
174
|
+
## Completion Report 命令
|
|
175
|
+
|
|
176
|
+
如果你希望 agent 在完成一轮修复或建议后,自动产出复盘、剩余风险和下一轮任务,现在可以用 `completion-report`:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
geo-ai-search-optimization completion-report ./your-site
|
|
180
|
+
geo-ai-search-optimization completion-report ./reports/apply-plan.json --format json --out ./reports/completion-report.json
|
|
181
|
+
geo-ai-search-optimization completion-report https://example.com
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`completion-report` 会输出:
|
|
185
|
+
|
|
186
|
+
- 本轮已完成什么
|
|
187
|
+
- 当前还剩哪些风险
|
|
188
|
+
- 下一轮建议先做哪些任务
|
|
189
|
+
- 建议复测命令
|
|
190
|
+
- 可直接复用的完成回报模板
|
|
191
|
+
|
|
150
192
|
## Fix Plan 命令
|
|
151
193
|
|
|
152
194
|
如果你已经跑过 `audit`、`report` 或 `onboard-url`,下一步就可以直接把结果转成 PM 待办清单:
|
|
@@ -298,6 +340,8 @@ geo-ai-search-optimization init-schema organization ./site --site-url "https://e
|
|
|
298
340
|
geo-ai-search-optimization init-schema faq-page ./site --json
|
|
299
341
|
geo-ai-search-optimization audit ./my-site
|
|
300
342
|
geo-ai-search-optimization agent-handoff ./my-site
|
|
343
|
+
geo-ai-search-optimization apply-plan ./my-site
|
|
344
|
+
geo-ai-search-optimization completion-report ./my-site
|
|
301
345
|
geo-ai-search-optimization exec-summary ./my-site
|
|
302
346
|
geo-ai-search-optimization fix-plan ./my-site
|
|
303
347
|
geo-ai-search-optimization owner-board ./my-site
|
|
@@ -313,6 +357,20 @@ geo-ai-search-optimization version
|
|
|
313
357
|
geo-ai-search-optimization help
|
|
314
358
|
```
|
|
315
359
|
|
|
360
|
+
## New in 1.2.0
|
|
361
|
+
|
|
362
|
+
- 新增 `completion-report`
|
|
363
|
+
- 让 agent 在完成一轮 GEO 修复或建议后自动产出 closeout report
|
|
364
|
+
- 会输出本轮完成项、剩余风险、下一轮任务、复测命令和完成回报模板
|
|
365
|
+
- 新增 `geo-ai-search-optimization-completion-report` skill,帮助 agent 稳定产出复盘
|
|
366
|
+
|
|
367
|
+
## New in 1.1.9
|
|
368
|
+
|
|
369
|
+
- 新增 `apply-plan`
|
|
370
|
+
- 让 agent-handoff 继续进入执行闭环,而不是停在交接阶段
|
|
371
|
+
- 会输出任务执行包、验证指令、Done 定义、完成回报模板
|
|
372
|
+
- 新增 `geo-ai-search-optimization-repair-loop` skill,帮助 agent 继续做修复、验证和回报
|
|
373
|
+
|
|
316
374
|
## New in 1.1.8
|
|
317
375
|
|
|
318
376
|
- 新增 `agent-handoff`
|
package/package.json
CHANGED
|
@@ -43,6 +43,8 @@ geo-ai-search-optimization report ./your-site --mode audit --format html --out .
|
|
|
43
43
|
geo-ai-search-optimization exec-summary ./your-site --out ./reports/exec-summary.md
|
|
44
44
|
geo-ai-search-optimization fix-plan ./your-site --format json --out ./reports/fix-plan.json
|
|
45
45
|
geo-ai-search-optimization agent-handoff ./your-site --out ./reports/agent-handoff.md
|
|
46
|
+
geo-ai-search-optimization apply-plan ./your-site --out ./reports/apply-plan.md
|
|
47
|
+
geo-ai-search-optimization completion-report ./your-site --out ./reports/completion-report.md
|
|
46
48
|
geo-ai-search-optimization owner-board ./your-site --out ./reports/owner-board.md
|
|
47
49
|
geo-ai-search-optimization meeting-pack ./your-site --out ./reports/meeting-pack.md
|
|
48
50
|
geo-ai-search-optimization pm-brief ./your-site --out ./reports/pm-brief.md
|
|
@@ -57,7 +59,9 @@ geo-ai-search-optimization roadmap ./your-site --out ./reports/roadmap.md
|
|
|
57
59
|
2. 再补 llms.txt / schema / author / freshness
|
|
58
60
|
3. 再做 FAQ / comparison / methodology / evidence 页面
|
|
59
61
|
4. 需要交接给 agent 时,生成 agent-handoff 工件
|
|
60
|
-
5.
|
|
62
|
+
5. 需要 agent 直接开始做时,生成 apply-plan
|
|
63
|
+
6. 完成一轮后生成 completion-report
|
|
64
|
+
7. 重跑 scan / audit / report 验证是否改善
|
|
61
65
|
|
|
62
66
|
## 推荐节奏
|
|
63
67
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: geo-ai-search-optimization-completion-report
|
|
3
|
+
description: Create GEO completion reports after an execution round. Use when an agent has already produced fixes or recommendations and needs to summarize what was completed, what risks remain, what should happen next, and how to report the outcome back to PM or stakeholders.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GEO Completion Report
|
|
7
|
+
|
|
8
|
+
Use this skill when GEO work is no longer at the planning stage and the user needs a closeout report for the round.
|
|
9
|
+
|
|
10
|
+
`GEO = Generative Engine Optimization`
|
|
11
|
+
|
|
12
|
+
## What this skill is for
|
|
13
|
+
|
|
14
|
+
Create a clear post-execution report that answers:
|
|
15
|
+
|
|
16
|
+
1. what got done this round
|
|
17
|
+
2. what still remains risky
|
|
18
|
+
3. what should happen in the next round
|
|
19
|
+
4. what validation should be rerun
|
|
20
|
+
5. how the agent should report completion back
|
|
21
|
+
|
|
22
|
+
## Preferred input order
|
|
23
|
+
|
|
24
|
+
Prefer these artifacts in order:
|
|
25
|
+
|
|
26
|
+
1. `completion-report`
|
|
27
|
+
2. `apply-plan`
|
|
28
|
+
3. `agent-handoff`
|
|
29
|
+
4. `fix-plan` or `report`
|
|
30
|
+
|
|
31
|
+
If only a repo path or URL is available, derive the report from the latest GEO execution context.
|
|
32
|
+
|
|
33
|
+
## Response order
|
|
34
|
+
|
|
35
|
+
Always return:
|
|
36
|
+
|
|
37
|
+
1. round summary
|
|
38
|
+
2. completed this round
|
|
39
|
+
3. residual risks
|
|
40
|
+
4. next-round tasks
|
|
41
|
+
5. validation commands
|
|
42
|
+
|
|
43
|
+
Read [references/completion-patterns.md](references/completion-patterns.md) when you need concrete closeout patterns.
|
package/resources/geo-ai-search-optimization-completion-report/references/completion-patterns.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# GEO Completion Patterns
|
|
2
|
+
|
|
3
|
+
## Good completion report shape
|
|
4
|
+
|
|
5
|
+
1. round summary
|
|
6
|
+
2. completed this round
|
|
7
|
+
3. residual risks
|
|
8
|
+
4. next-round tasks
|
|
9
|
+
5. validation rerun commands
|
|
10
|
+
|
|
11
|
+
## If the round was direct implementation
|
|
12
|
+
|
|
13
|
+
Emphasize:
|
|
14
|
+
|
|
15
|
+
- what changed
|
|
16
|
+
- what was verified
|
|
17
|
+
- what still needs monitoring
|
|
18
|
+
|
|
19
|
+
## If the round was recommendation only
|
|
20
|
+
|
|
21
|
+
Emphasize:
|
|
22
|
+
|
|
23
|
+
- what was clarified
|
|
24
|
+
- what context is still missing
|
|
25
|
+
- what must happen before implementation can start
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: geo-ai-search-optimization-repair-loop
|
|
3
|
+
description: Execute GEO repair work from apply-plan and agent-handoff artifacts. Use when an agent should move past recommendations and actually perform a fix, validate the result, and report completion in a PM-readable format.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GEO Repair Loop
|
|
7
|
+
|
|
8
|
+
Use this skill when a GEO artifact is no longer just for reading or planning, and the user expects the agent to continue through execution, validation, and completion reporting.
|
|
9
|
+
|
|
10
|
+
`GEO = Generative Engine Optimization`
|
|
11
|
+
|
|
12
|
+
## Preferred flow
|
|
13
|
+
|
|
14
|
+
When possible, use this order:
|
|
15
|
+
|
|
16
|
+
1. read `agent-handoff` to understand the task and mode
|
|
17
|
+
2. read `apply-plan` to get the execution packet
|
|
18
|
+
3. perform the fix or produce the next-best structured recommendation
|
|
19
|
+
4. rerun the suggested GEO CLI validation commands
|
|
20
|
+
5. generate `completion-report`
|
|
21
|
+
6. report back using the completion template
|
|
22
|
+
|
|
23
|
+
## Execution rules
|
|
24
|
+
|
|
25
|
+
- if the artifact says `implementation-ready`, prefer direct code changes over advice-only text
|
|
26
|
+
- if the artifact says `advice-only`, do not pretend code was changed
|
|
27
|
+
- if the artifact says `artifact-guided`, explain what additional repo or page context is needed before direct implementation
|
|
28
|
+
- keep outputs PM-readable while still naming the specific files, templates, or systems you inspected
|
|
29
|
+
|
|
30
|
+
## Completion reporting
|
|
31
|
+
|
|
32
|
+
Always include:
|
|
33
|
+
|
|
34
|
+
1. what you checked
|
|
35
|
+
2. what you changed or recommended
|
|
36
|
+
3. what validation you ran
|
|
37
|
+
4. whether the task can be marked done
|
|
38
|
+
5. what remains next
|
|
39
|
+
|
|
40
|
+
Read [references/repair-loop-patterns.md](references/repair-loop-patterns.md) when you need concrete execution patterns.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "GEO Repair Loop"
|
|
3
|
+
short_description: "Execute GEO fixes from apply-plan and validate completion"
|
|
4
|
+
default_prompt: "Use $geo-ai-search-optimization-repair-loop to continue from this apply-plan or handoff artifact and complete the next GEO repair task."
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# GEO Repair Loop Patterns
|
|
2
|
+
|
|
3
|
+
## If you have a local project directory
|
|
4
|
+
|
|
5
|
+
Do:
|
|
6
|
+
|
|
7
|
+
- inspect reusable templates, metadata helpers, schema generators, and content models first
|
|
8
|
+
- fix the shared layer before patching individual pages where possible
|
|
9
|
+
- rerun the validation commands from `apply-plan`
|
|
10
|
+
- report completion using the provided completion template
|
|
11
|
+
|
|
12
|
+
## If you only have a public URL
|
|
13
|
+
|
|
14
|
+
Do:
|
|
15
|
+
|
|
16
|
+
- give structured recommendations
|
|
17
|
+
- identify the smallest set of pages or templates the user should share next
|
|
18
|
+
- keep the output close to implementation, but do not claim code changes were made
|
|
19
|
+
|
|
20
|
+
## If you have only exported artifacts
|
|
21
|
+
|
|
22
|
+
Do:
|
|
23
|
+
|
|
24
|
+
- use them to determine order, dependencies, and done criteria
|
|
25
|
+
- state clearly when repo access is required for the next step
|
|
26
|
+
|
|
27
|
+
## Good completion report shape
|
|
28
|
+
|
|
29
|
+
1. checked
|
|
30
|
+
2. changed or recommended
|
|
31
|
+
3. validation run
|
|
32
|
+
4. done or not done
|
|
33
|
+
5. next step
|
|
@@ -13,14 +13,16 @@ Treat this tool as a PM-friendly GEO workflow for websites.
|
|
|
13
13
|
|
|
14
14
|
`GEO = Generative Engine Optimization`
|
|
15
15
|
|
|
16
|
-
The package is best explained as
|
|
16
|
+
The package is best explained as eight layers:
|
|
17
17
|
|
|
18
18
|
1. `onboard-url` / `onboard`: first look
|
|
19
19
|
2. `scan`: raw signal check
|
|
20
20
|
3. `audit` / `report`: diagnosis
|
|
21
21
|
4. `fix-plan` / `owner-board`: execution planning
|
|
22
22
|
5. `agent-handoff`: agent takeover package
|
|
23
|
-
6. `
|
|
23
|
+
6. `apply-plan`: execution loop
|
|
24
|
+
7. `completion-report`: closeout
|
|
25
|
+
8. `pm-brief` / `roadmap`: stakeholder alignment
|
|
24
26
|
|
|
25
27
|
## Recommended command order
|
|
26
28
|
|
|
@@ -39,6 +41,8 @@ npx geo-ai-search-optimization scan ./your-site
|
|
|
39
41
|
npx geo-ai-search-optimization audit ./your-site
|
|
40
42
|
npx geo-ai-search-optimization fix-plan ./your-site
|
|
41
43
|
npx geo-ai-search-optimization agent-handoff ./your-site
|
|
44
|
+
npx geo-ai-search-optimization apply-plan ./your-site
|
|
45
|
+
npx geo-ai-search-optimization completion-report ./your-site
|
|
42
46
|
npx geo-ai-search-optimization owner-board ./your-site
|
|
43
47
|
npx geo-ai-search-optimization roadmap ./your-site
|
|
44
48
|
```
|
|
@@ -52,6 +56,8 @@ npx geo-ai-search-optimization roadmap ./your-site
|
|
|
52
56
|
- `report`: export audit/onboarding/scan into readable files
|
|
53
57
|
- `fix-plan`: turn issues into backlog-ready tasks
|
|
54
58
|
- `agent-handoff`: turn GEO findings into an artifact an agent can directly continue from
|
|
59
|
+
- `apply-plan`: turn handoff into execution packets with validation commands and completion template
|
|
60
|
+
- `completion-report`: summarize what the agent finished, residual risks, and next-round work
|
|
55
61
|
- `owner-board`: group tasks by PM / engineering / SEO / content
|
|
56
62
|
- `pm-brief`: prepare a PM summary for meetings and prioritization
|
|
57
63
|
- `roadmap`: turn tasks into a 2-week / 4-week execution sequence
|
|
@@ -64,6 +70,8 @@ When explaining the tool to a user:
|
|
|
64
70
|
- explain the result in PM language, not implementation jargon
|
|
65
71
|
- if the user sounds new, start with `onboard-url` or `quick-start`
|
|
66
72
|
- if the user wants another agent to take over, move them to `agent-handoff`
|
|
73
|
+
- if the user wants the next agent to start executing, move them to `apply-plan`
|
|
74
|
+
- if the user wants a closeout summary after one round, move them to `completion-report`
|
|
67
75
|
- if the user already has a report, move them to `fix-plan`, `owner-board`, or `roadmap`
|
|
68
76
|
|
|
69
77
|
Read [references/usage-patterns.md](references/usage-patterns.md) when you need response patterns and command selection examples.
|
|
@@ -59,6 +59,34 @@ If they only have a URL:
|
|
|
59
59
|
npx geo-ai-search-optimization agent-handoff https://example.com
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
## If the user says "我想让 agent 直接开始执行"
|
|
63
|
+
|
|
64
|
+
Recommend:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npx geo-ai-search-optimization apply-plan ./your-site
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
If they only have a URL:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npx geo-ai-search-optimization apply-plan https://example.com
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## If the user says "我想看这一轮做完后的复盘"
|
|
77
|
+
|
|
78
|
+
Recommend:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx geo-ai-search-optimization completion-report ./your-site
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
If they only have a URL:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx geo-ai-search-optimization completion-report https://example.com
|
|
88
|
+
```
|
|
89
|
+
|
|
62
90
|
## If the user says "我要开会同步"
|
|
63
91
|
|
|
64
92
|
Recommend:
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { createAgentHandoff, writeAgentHandoffOutput } from "./agent-handoff.js";
|
|
2
|
+
|
|
3
|
+
const VALID_FORMATS = new Set(["markdown", "json"]);
|
|
4
|
+
|
|
5
|
+
function normalizeFormat(format) {
|
|
6
|
+
const resolved = (format || "markdown").toLowerCase();
|
|
7
|
+
if (!VALID_FORMATS.has(resolved)) {
|
|
8
|
+
throw new Error(`不支持的 apply-plan 格式:${format}。可选值:${Array.from(VALID_FORMATS).join(", ")}`);
|
|
9
|
+
}
|
|
10
|
+
return resolved;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function slugifyTaskTitle(value) {
|
|
14
|
+
return value
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.replace(/[^a-z0-9\u4e00-\u9fff]+/gi, "-")
|
|
17
|
+
.replace(/^-+|-+$/g, "");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function inferExecutionType(mode) {
|
|
21
|
+
if (mode === "implementation-ready") {
|
|
22
|
+
return "direct-fix";
|
|
23
|
+
}
|
|
24
|
+
if (mode === "advice-only") {
|
|
25
|
+
return "recommendation-only";
|
|
26
|
+
}
|
|
27
|
+
return "guided-planning";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function buildInspectTargets(task, mode) {
|
|
31
|
+
const targets = [];
|
|
32
|
+
|
|
33
|
+
if (mode === "implementation-ready") {
|
|
34
|
+
targets.push("站点全局 layout、SEO metadata helper、head 输出逻辑。");
|
|
35
|
+
targets.push("会影响该问题区域的可复用页面模板,而不是只看单页。");
|
|
36
|
+
} else {
|
|
37
|
+
targets.push("首页与最关键的 1 到 3 个落地页。");
|
|
38
|
+
targets.push("能体现该问题的模板类型、导航层级或内容模块。");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (task.title.includes("robots.txt")) {
|
|
42
|
+
targets.push("robots.txt 生成逻辑、静态文件目录或部署输出目录。");
|
|
43
|
+
}
|
|
44
|
+
if (task.title.includes("sitemap")) {
|
|
45
|
+
targets.push("sitemap.xml 生成逻辑、路由清单或内容集合。");
|
|
46
|
+
}
|
|
47
|
+
if (task.title.includes("canonical")) {
|
|
48
|
+
targets.push("canonical 计算逻辑、metadata 映射层、URL 归一策略。");
|
|
49
|
+
}
|
|
50
|
+
if (task.title.includes("llms.txt")) {
|
|
51
|
+
targets.push("llms.txt 文件、站点导航概览、核心页面入口。");
|
|
52
|
+
}
|
|
53
|
+
if (task.title.includes("JSON-LD") || task.title.includes("schema")) {
|
|
54
|
+
targets.push("JSON-LD 输出逻辑、结构化数据模板、页面可见内容是否匹配。");
|
|
55
|
+
}
|
|
56
|
+
if (task.title.includes("meta description") || task.title.includes("标题")) {
|
|
57
|
+
targets.push("title / meta description 模板、字段来源、默认值与覆盖逻辑。");
|
|
58
|
+
}
|
|
59
|
+
if (task.title.includes("breadcrumb")) {
|
|
60
|
+
targets.push("站点层级、breadcrumb 组件或 breadcrumb schema 输出点。");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return Array.from(new Set(targets));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function buildEditPlan(task, mode) {
|
|
67
|
+
const steps = [];
|
|
68
|
+
|
|
69
|
+
if (mode === "implementation-ready") {
|
|
70
|
+
steps.push("先定位复用层,再判断是否能一次修复整类页面。");
|
|
71
|
+
steps.push("优先改模板、helper、内容模型或生成逻辑,避免只 patch 单页。");
|
|
72
|
+
} else if (mode === "advice-only") {
|
|
73
|
+
steps.push("先输出页面层、模板层、流程层三层建议。");
|
|
74
|
+
steps.push("把需要工程、SEO、内容团队补充的前置条件写清楚。");
|
|
75
|
+
} else {
|
|
76
|
+
steps.push("先把任务拆成可执行顺序,再明确哪一步需要代码仓库。");
|
|
77
|
+
steps.push("把实施前必须补齐的上下文列出来。");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
steps.push(`围绕任务「${task.title}」设计最小可落地改动,不要把范围扩散到整站重构。`);
|
|
81
|
+
steps.push("完成后一定要回到验收标准,确认问题真的被修掉,而不是只做表面调整。");
|
|
82
|
+
|
|
83
|
+
return steps;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function buildValidationCommands(source, mode) {
|
|
87
|
+
if (mode === "implementation-ready") {
|
|
88
|
+
return [
|
|
89
|
+
`geo-ai-search-optimization audit ${source}`,
|
|
90
|
+
`geo-ai-search-optimization fix-plan ${source}`,
|
|
91
|
+
`geo-ai-search-optimization agent-handoff ${source}`
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (mode === "advice-only") {
|
|
96
|
+
return [
|
|
97
|
+
`geo-ai-search-optimization onboard-url ${source}`,
|
|
98
|
+
`geo-ai-search-optimization pm-brief ${source}`,
|
|
99
|
+
`geo-ai-search-optimization report ${source} --mode onboarding --format markdown`
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return [
|
|
104
|
+
`geo-ai-search-optimization agent-handoff ${source}`,
|
|
105
|
+
`geo-ai-search-optimization meeting-pack ${source}`
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function buildDeliverables(task, executionType) {
|
|
110
|
+
const deliverables = [
|
|
111
|
+
"当前问题摘要",
|
|
112
|
+
"你检查过的页面、模板或文件",
|
|
113
|
+
"实际修改或建议动作",
|
|
114
|
+
"验收结果",
|
|
115
|
+
"下一步建议"
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
if (executionType === "direct-fix") {
|
|
119
|
+
deliverables.push("修改后的验证结果和剩余风险");
|
|
120
|
+
} else if (executionType === "recommendation-only") {
|
|
121
|
+
deliverables.push("用户还需要提供的仓库、页面或权限");
|
|
122
|
+
} else {
|
|
123
|
+
deliverables.push("进入直接修复前的补充上下文清单");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return deliverables;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function buildCompletionTemplate(task, executionType) {
|
|
130
|
+
const closingLine =
|
|
131
|
+
executionType === "direct-fix"
|
|
132
|
+
? "我已经完成可直接落地的部分,并附上复测结果。"
|
|
133
|
+
: executionType === "recommendation-only"
|
|
134
|
+
? "我已经给出建议路径,下一步需要用户提供更多上下文后再继续落地。"
|
|
135
|
+
: "我已经把后续执行顺序整理好,待补齐仓库或页面上下文后可进入直接实施。";
|
|
136
|
+
|
|
137
|
+
return [
|
|
138
|
+
`任务:${task.title}`,
|
|
139
|
+
`结论:${closingLine}`,
|
|
140
|
+
"我先做了什么:",
|
|
141
|
+
"- ",
|
|
142
|
+
"我检查了哪些页面 / 文件 / 模板:",
|
|
143
|
+
"- ",
|
|
144
|
+
"我实际修改或建议了什么:",
|
|
145
|
+
"- ",
|
|
146
|
+
"验收结果:",
|
|
147
|
+
"- ",
|
|
148
|
+
"剩余风险或下一步:",
|
|
149
|
+
"- "
|
|
150
|
+
].join("\n");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function buildExecutionPrompt(task, handoff, executionType, source) {
|
|
154
|
+
return [
|
|
155
|
+
"你现在进入 GEO 修复执行阶段。",
|
|
156
|
+
`任务:${task.title}`,
|
|
157
|
+
`执行类型:${executionType}`,
|
|
158
|
+
`输入来源:${source}`,
|
|
159
|
+
`本轮目标:${handoff.primaryObjective}`,
|
|
160
|
+
"请你按以下顺序输出:",
|
|
161
|
+
"1. 先检查什么",
|
|
162
|
+
"2. 你准备如何执行",
|
|
163
|
+
"3. 你会如何验证",
|
|
164
|
+
"4. 完成后如何向用户回报",
|
|
165
|
+
"",
|
|
166
|
+
"必须遵守:",
|
|
167
|
+
executionType === "direct-fix"
|
|
168
|
+
? "如果已经有仓库访问权限,优先直接修复。"
|
|
169
|
+
: "如果没有仓库访问权限,不要假装已经完成代码修改。",
|
|
170
|
+
"输出要保持 PM 可读,同时明确技术执行动作。"
|
|
171
|
+
].join("\n");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function buildGlobalWorkflow(mode) {
|
|
175
|
+
if (mode === "implementation-ready") {
|
|
176
|
+
return [
|
|
177
|
+
"先找复用模板和 metadata / schema 输出点。",
|
|
178
|
+
"按优先级修复 1 到 3 个最高价值任务。",
|
|
179
|
+
"每完成一轮修改就复跑 GEO CLI 验证。"
|
|
180
|
+
];
|
|
181
|
+
}
|
|
182
|
+
if (mode === "advice-only") {
|
|
183
|
+
return [
|
|
184
|
+
"先用当前网址确认最高优先级问题。",
|
|
185
|
+
"给出结构化建议,并说明需要哪些工程上下文。",
|
|
186
|
+
"拿到仓库后再切换到直接修复。"
|
|
187
|
+
];
|
|
188
|
+
}
|
|
189
|
+
return [
|
|
190
|
+
"先用工件整理顺序和依赖关系。",
|
|
191
|
+
"确认哪些任务可先给建议,哪些任务必须等仓库。",
|
|
192
|
+
"当用户补充仓库后,转成 implementation-ready 再执行。"
|
|
193
|
+
];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export async function createApplyPlan(input, options = {}) {
|
|
197
|
+
const format = normalizeFormat(options.format);
|
|
198
|
+
const handoff = await createAgentHandoff(input, { format: "json" });
|
|
199
|
+
const executionType = inferExecutionType(handoff.executionMode);
|
|
200
|
+
const requestedTaskId = options.taskId || null;
|
|
201
|
+
const selectedTasks = requestedTaskId
|
|
202
|
+
? handoff.tasks.filter((task) => task.id === requestedTaskId)
|
|
203
|
+
: handoff.tasks.slice(0, 3);
|
|
204
|
+
|
|
205
|
+
if (selectedTasks.length === 0) {
|
|
206
|
+
throw new Error(`找不到任务:${requestedTaskId}`);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const executionPackets = selectedTasks.map((task) => ({
|
|
210
|
+
id: task.id,
|
|
211
|
+
title: task.title,
|
|
212
|
+
packetSlug: `${task.id}-${slugifyTaskTitle(task.title)}`,
|
|
213
|
+
priority: task.priority,
|
|
214
|
+
owner: task.owner,
|
|
215
|
+
executionType,
|
|
216
|
+
inspectTargets: buildInspectTargets(task, handoff.executionMode),
|
|
217
|
+
editPlan: buildEditPlan(task, handoff.executionMode),
|
|
218
|
+
validationCommands: buildValidationCommands(handoff.source, handoff.executionMode),
|
|
219
|
+
deliverables: buildDeliverables(task, executionType),
|
|
220
|
+
doneWhen: task.acceptanceCriteria,
|
|
221
|
+
completionTemplate: buildCompletionTemplate(task, executionType),
|
|
222
|
+
executionPrompt: buildExecutionPrompt(task, handoff, executionType, handoff.source)
|
|
223
|
+
}));
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
kind: "geo-apply-plan",
|
|
227
|
+
source: handoff.source,
|
|
228
|
+
sourceType: handoff.sourceType,
|
|
229
|
+
format,
|
|
230
|
+
executionMode: handoff.executionMode,
|
|
231
|
+
executionType,
|
|
232
|
+
summary: handoff.summary,
|
|
233
|
+
primaryObjective: handoff.primaryObjective,
|
|
234
|
+
workflow: buildGlobalWorkflow(handoff.executionMode),
|
|
235
|
+
selectedTaskCount: executionPackets.length,
|
|
236
|
+
packets: executionPackets
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function renderApplyPlanMarkdown(plan) {
|
|
241
|
+
const lines = [
|
|
242
|
+
"# GEO Apply Plan",
|
|
243
|
+
"",
|
|
244
|
+
`- 输入来源:\`${plan.source}\``,
|
|
245
|
+
`- 来源类型:\`${plan.sourceType}\``,
|
|
246
|
+
`- 执行模式:\`${plan.executionMode}\``,
|
|
247
|
+
`- 执行类型:\`${plan.executionType}\``,
|
|
248
|
+
`- 当前总结:${plan.summary}`,
|
|
249
|
+
`- 本轮目标:${plan.primaryObjective}`,
|
|
250
|
+
"",
|
|
251
|
+
"## 全局执行顺序",
|
|
252
|
+
""
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
for (const step of plan.workflow) {
|
|
256
|
+
lines.push(`- ${step}`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
lines.push("", "## 执行包", "");
|
|
260
|
+
|
|
261
|
+
for (const packet of plan.packets) {
|
|
262
|
+
lines.push(`### ${packet.id}|${packet.title}`);
|
|
263
|
+
lines.push("");
|
|
264
|
+
lines.push(`- 负责人:${packet.owner}`);
|
|
265
|
+
lines.push(`- 执行类型:${packet.executionType}`);
|
|
266
|
+
lines.push(`- 包标识:\`${packet.packetSlug}\``);
|
|
267
|
+
lines.push("- 先检查:");
|
|
268
|
+
for (const target of packet.inspectTargets) {
|
|
269
|
+
lines.push(` - ${target}`);
|
|
270
|
+
}
|
|
271
|
+
lines.push("- 执行步骤:");
|
|
272
|
+
for (const step of packet.editPlan) {
|
|
273
|
+
lines.push(` - ${step}`);
|
|
274
|
+
}
|
|
275
|
+
lines.push("- 验证指令:");
|
|
276
|
+
for (const command of packet.validationCommands) {
|
|
277
|
+
lines.push(` - \`${command}\``);
|
|
278
|
+
}
|
|
279
|
+
lines.push("- 交付物:");
|
|
280
|
+
for (const deliverable of packet.deliverables) {
|
|
281
|
+
lines.push(` - ${deliverable}`);
|
|
282
|
+
}
|
|
283
|
+
lines.push("- Done 定义:");
|
|
284
|
+
for (const criterion of packet.doneWhen) {
|
|
285
|
+
lines.push(` - ${criterion}`);
|
|
286
|
+
}
|
|
287
|
+
lines.push("- 执行提示词:");
|
|
288
|
+
lines.push("```text");
|
|
289
|
+
lines.push(packet.executionPrompt);
|
|
290
|
+
lines.push("```");
|
|
291
|
+
lines.push("- 完成回报模板:");
|
|
292
|
+
lines.push("```text");
|
|
293
|
+
lines.push(packet.completionTemplate);
|
|
294
|
+
lines.push("```");
|
|
295
|
+
lines.push("");
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return `${lines.join("\n")}\n`;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export async function writeApplyPlanOutput(outputPath, content) {
|
|
302
|
+
return writeAgentHandoffOutput(outputPath, content);
|
|
303
|
+
}
|
package/src/cli.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { createApplyPlan, renderApplyPlanMarkdown, writeApplyPlanOutput } from "./apply-plan.js";
|
|
4
5
|
import { createAgentHandoff, renderAgentHandoffMarkdown, writeAgentHandoffOutput } from "./agent-handoff.js";
|
|
6
|
+
import {
|
|
7
|
+
createCompletionReport,
|
|
8
|
+
renderCompletionReportMarkdown,
|
|
9
|
+
writeCompletionReportOutput
|
|
10
|
+
} from "./completion-report.js";
|
|
5
11
|
import { installSkill } from "./install-skill.js";
|
|
6
12
|
import { getBundledSkillPath, getInstalledSkillPath, getSkillName, getSkillsDir } from "./paths.js";
|
|
7
13
|
import { renderScanMarkdown, scanProject, writeScanOutput } from "./scan.js";
|
|
@@ -54,6 +60,8 @@ function printHelp() {
|
|
|
54
60
|
" geo-ai-search-optimization init-schema <type> [target-dir] [--site-url <url>] [--overwrite] [--json]",
|
|
55
61
|
" geo-ai-search-optimization audit <project-path> [--json] [--out <file>] [--max-file-size <bytes>] [--max-examples <count>]",
|
|
56
62
|
" geo-ai-search-optimization agent-handoff <input> [--format <markdown|json>] [--out <file>]",
|
|
63
|
+
" geo-ai-search-optimization apply-plan <input> [--task <id>] [--format <markdown|json>] [--out <file>]",
|
|
64
|
+
" geo-ai-search-optimization completion-report <input> [--format <markdown|json>] [--out <file>]",
|
|
57
65
|
" geo-ai-search-optimization exec-summary <input> [--format <markdown|json>] [--out <file>]",
|
|
58
66
|
" geo-ai-search-optimization fix-plan <input> [--format <markdown|json>] [--out <file>]",
|
|
59
67
|
" geo-ai-search-optimization owner-board <input> [--format <markdown|json>] [--out <file>]",
|
|
@@ -360,6 +368,55 @@ async function handleAgentHandoff(args) {
|
|
|
360
368
|
process.stdout.write(renderedOutput);
|
|
361
369
|
}
|
|
362
370
|
|
|
371
|
+
async function handleApplyPlan(args) {
|
|
372
|
+
const input = args.find((value) => !value.startsWith("-"));
|
|
373
|
+
if (!input) {
|
|
374
|
+
throw new Error("apply-plan 需要一个输入值,可以是项目路径、网站网址或已导出的 JSON 报告");
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const format = getFlagValue(args, "--format");
|
|
378
|
+
const plan = await createApplyPlan(input, {
|
|
379
|
+
format,
|
|
380
|
+
taskId: getFlagValue(args, "--task")
|
|
381
|
+
});
|
|
382
|
+
const outputJson = format === "json";
|
|
383
|
+
const renderedOutput = outputJson
|
|
384
|
+
? `${JSON.stringify(plan, null, 2)}\n`
|
|
385
|
+
: renderApplyPlanMarkdown(plan);
|
|
386
|
+
|
|
387
|
+
const outputPath = getFlagValue(args, "--out");
|
|
388
|
+
if (outputPath) {
|
|
389
|
+
const resolvedOutputPath = await writeApplyPlanOutput(outputPath, renderedOutput);
|
|
390
|
+
process.stdout.write(`已保存 apply plan:${resolvedOutputPath}\n`);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
process.stdout.write(renderedOutput);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
async function handleCompletionReport(args) {
|
|
398
|
+
const input = args.find((value) => !value.startsWith("-"));
|
|
399
|
+
if (!input) {
|
|
400
|
+
throw new Error("completion-report 需要一个输入值,可以是项目路径、网站网址或已导出的 JSON 工件");
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const format = getFlagValue(args, "--format");
|
|
404
|
+
const report = await createCompletionReport(input, { format });
|
|
405
|
+
const outputJson = format === "json";
|
|
406
|
+
const renderedOutput = outputJson
|
|
407
|
+
? `${JSON.stringify(report, null, 2)}\n`
|
|
408
|
+
: renderCompletionReportMarkdown(report);
|
|
409
|
+
|
|
410
|
+
const outputPath = getFlagValue(args, "--out");
|
|
411
|
+
if (outputPath) {
|
|
412
|
+
const resolvedOutputPath = await writeCompletionReportOutput(outputPath, renderedOutput);
|
|
413
|
+
process.stdout.write(`已保存 completion report:${resolvedOutputPath}\n`);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
process.stdout.write(renderedOutput);
|
|
418
|
+
}
|
|
419
|
+
|
|
363
420
|
async function handleExecSummary(args) {
|
|
364
421
|
const input = args.find((value) => !value.startsWith("-"));
|
|
365
422
|
if (!input) {
|
|
@@ -538,6 +595,16 @@ export async function runCli(args = []) {
|
|
|
538
595
|
return;
|
|
539
596
|
}
|
|
540
597
|
|
|
598
|
+
if (command === "apply-plan") {
|
|
599
|
+
await handleApplyPlan(rest);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
if (command === "completion-report") {
|
|
604
|
+
await handleCompletionReport(rest);
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
|
|
541
608
|
if (command === "exec-summary") {
|
|
542
609
|
await handleExecSummary(rest);
|
|
543
610
|
return;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createApplyPlan, writeApplyPlanOutput } from "./apply-plan.js";
|
|
4
|
+
|
|
5
|
+
const VALID_FORMATS = new Set(["markdown", "json"]);
|
|
6
|
+
|
|
7
|
+
function normalizeFormat(format) {
|
|
8
|
+
const resolved = (format || "markdown").toLowerCase();
|
|
9
|
+
if (!VALID_FORMATS.has(resolved)) {
|
|
10
|
+
throw new Error(`不支持的 completion-report 格式:${format}。可选值:${Array.from(VALID_FORMATS).join(", ")}`);
|
|
11
|
+
}
|
|
12
|
+
return resolved;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function pathExists(targetPath) {
|
|
16
|
+
try {
|
|
17
|
+
await fs.access(targetPath);
|
|
18
|
+
return true;
|
|
19
|
+
} catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isUrlInput(input) {
|
|
25
|
+
return /^https?:\/\//i.test(input);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function inferProgressStatus(plan) {
|
|
29
|
+
if (plan.executionType === "direct-fix") {
|
|
30
|
+
return "已进入执行与验证阶段";
|
|
31
|
+
}
|
|
32
|
+
if (plan.executionType === "recommendation-only") {
|
|
33
|
+
return "已完成建议输出,待补仓库上下文";
|
|
34
|
+
}
|
|
35
|
+
return "已完成计划整理,待进入直接实施";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function buildCompletedThisRound(plan) {
|
|
39
|
+
if (plan.executionType === "direct-fix") {
|
|
40
|
+
return [
|
|
41
|
+
"已整理本轮最优先执行的任务包。",
|
|
42
|
+
"已明确每个任务先检查哪些模板、页面或系统。",
|
|
43
|
+
"已为每个任务准备验证命令与完成回报模板。"
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
if (plan.executionType === "recommendation-only") {
|
|
47
|
+
return [
|
|
48
|
+
"已确认当前网址级问题与首批建议任务。",
|
|
49
|
+
"已准备好建议型执行包,避免在没有仓库时误报已修复。",
|
|
50
|
+
"已整理下一步需要用户提供的仓库或页面上下文。"
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
return [
|
|
54
|
+
"已把现有工件整理成执行顺序。",
|
|
55
|
+
"已明确哪些任务可先建议,哪些需要仓库后再落地。",
|
|
56
|
+
"已为下一阶段实施准备验证与回报结构。"
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function buildResidualRisks(plan) {
|
|
61
|
+
if (plan.executionType === "direct-fix") {
|
|
62
|
+
return [
|
|
63
|
+
"如果只修单页、不修模板,问题可能会在其他页面重复出现。",
|
|
64
|
+
"如果修完后没有重跑 GEO CLI,团队无法确认问题是否真正下降。",
|
|
65
|
+
"如果结构化数据与页面可见内容不一致,可能造成新的理解偏差。"
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
if (plan.executionType === "recommendation-only") {
|
|
69
|
+
return [
|
|
70
|
+
"当前仍缺少代码仓库或 CMS 上下文,暂时不能确认修复会落在哪些模板。",
|
|
71
|
+
"如果只停留在建议层,没有工程落地,问题不会真正消失。",
|
|
72
|
+
"仅凭首页和公开页面可能无法覆盖深层模板问题。"
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
return [
|
|
76
|
+
"当前还是工件驱动阶段,尚未确认具体模板或文件路径。",
|
|
77
|
+
"没有仓库权限前,无法验证修复动作是否会影响整类页面。",
|
|
78
|
+
"如果不补齐上下文,执行顺序再清楚也无法进入真正落地。"
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function buildNextRoundTasks(plan) {
|
|
83
|
+
return plan.packets.map((packet) => ({
|
|
84
|
+
id: packet.id,
|
|
85
|
+
title: packet.title,
|
|
86
|
+
owner: packet.owner,
|
|
87
|
+
nextAction:
|
|
88
|
+
plan.executionType === "direct-fix"
|
|
89
|
+
? "按执行包完成修改并立刻复测。"
|
|
90
|
+
: plan.executionType === "recommendation-only"
|
|
91
|
+
? "先补仓库或页面上下文,再把建议转成直接实施。"
|
|
92
|
+
: "先补上下文,再切到 implementation-ready 模式执行。",
|
|
93
|
+
doneWhen: packet.doneWhen
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function buildManagementSummary(plan) {
|
|
98
|
+
if (plan.executionType === "direct-fix") {
|
|
99
|
+
return "团队已经具备直接执行条件,重点是尽快完成首批高优先级修复并验证结果。";
|
|
100
|
+
}
|
|
101
|
+
if (plan.executionType === "recommendation-only") {
|
|
102
|
+
return "当前更适合先完成建议与对齐,拿到仓库或 CMS 访问后再进入正式修复。";
|
|
103
|
+
}
|
|
104
|
+
return "当前已经明确下一轮执行顺序,但仍需要额外上下文才能真正进入修复。";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function resolveApplyPlan(input) {
|
|
108
|
+
if (!input) {
|
|
109
|
+
throw new Error("completion-report 需要一个输入值,可以是项目路径、网站网址或已导出的 JSON 工件。");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (isUrlInput(input)) {
|
|
113
|
+
return createApplyPlan(input, { format: "json" });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const resolvedPath = path.resolve(input);
|
|
117
|
+
const exists = await pathExists(resolvedPath);
|
|
118
|
+
if (!exists) {
|
|
119
|
+
return createApplyPlan(input, { format: "json" });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const stat = await fs.stat(resolvedPath);
|
|
123
|
+
if (stat.isDirectory()) {
|
|
124
|
+
return createApplyPlan(resolvedPath, { format: "json" });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const raw = await fs.readFile(resolvedPath, "utf8");
|
|
128
|
+
const parsed = JSON.parse(raw);
|
|
129
|
+
|
|
130
|
+
if (parsed.kind === "geo-apply-plan") {
|
|
131
|
+
return parsed;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return createApplyPlan(resolvedPath, { format: "json" });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export async function createCompletionReport(input, options = {}) {
|
|
138
|
+
const format = normalizeFormat(options.format);
|
|
139
|
+
const plan = await resolveApplyPlan(input);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
kind: "geo-completion-report",
|
|
143
|
+
source: plan.source,
|
|
144
|
+
sourceType: plan.sourceType,
|
|
145
|
+
format,
|
|
146
|
+
executionMode: plan.executionMode,
|
|
147
|
+
executionType: plan.executionType,
|
|
148
|
+
progressStatus: inferProgressStatus(plan),
|
|
149
|
+
summary: plan.summary,
|
|
150
|
+
managementSummary: buildManagementSummary(plan),
|
|
151
|
+
completedThisRound: buildCompletedThisRound(plan),
|
|
152
|
+
residualRisks: buildResidualRisks(plan),
|
|
153
|
+
nextRoundTasks: buildNextRoundTasks(plan),
|
|
154
|
+
validationChecklist: Array.from(new Set(plan.packets.flatMap((packet) => packet.validationCommands))),
|
|
155
|
+
completionTemplates: plan.packets.map((packet) => ({
|
|
156
|
+
id: packet.id,
|
|
157
|
+
title: packet.title,
|
|
158
|
+
template: packet.completionTemplate
|
|
159
|
+
}))
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function renderCompletionReportMarkdown(report) {
|
|
164
|
+
const lines = [
|
|
165
|
+
"# GEO Completion Report",
|
|
166
|
+
"",
|
|
167
|
+
`- 输入来源:\`${report.source}\``,
|
|
168
|
+
`- 来源类型:\`${report.sourceType}\``,
|
|
169
|
+
`- 执行模式:\`${report.executionMode}\``,
|
|
170
|
+
`- 执行类型:\`${report.executionType}\``,
|
|
171
|
+
`- 当前进度:${report.progressStatus}`,
|
|
172
|
+
`- 当前总结:${report.summary}`,
|
|
173
|
+
`- 管理层摘要:${report.managementSummary}`,
|
|
174
|
+
"",
|
|
175
|
+
"## 本轮已完成",
|
|
176
|
+
""
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
for (const item of report.completedThisRound) {
|
|
180
|
+
lines.push(`- ${item}`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
lines.push("", "## 剩余风险", "");
|
|
184
|
+
for (const risk of report.residualRisks) {
|
|
185
|
+
lines.push(`- ${risk}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
lines.push("", "## 下一轮任务", "");
|
|
189
|
+
for (const task of report.nextRoundTasks) {
|
|
190
|
+
lines.push(`### ${task.id}|${task.title}`);
|
|
191
|
+
lines.push("");
|
|
192
|
+
lines.push(`- 负责人:${task.owner}`);
|
|
193
|
+
lines.push(`- 下一步:${task.nextAction}`);
|
|
194
|
+
lines.push("- 完成标准:");
|
|
195
|
+
for (const criterion of task.doneWhen) {
|
|
196
|
+
lines.push(` - ${criterion}`);
|
|
197
|
+
}
|
|
198
|
+
lines.push("");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
lines.push("## 建议复测指令", "");
|
|
202
|
+
for (const command of report.validationChecklist) {
|
|
203
|
+
lines.push(`- \`${command}\``);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
lines.push("", "## 完成回报模板", "");
|
|
207
|
+
for (const template of report.completionTemplates) {
|
|
208
|
+
lines.push(`### ${template.id}|${template.title}`);
|
|
209
|
+
lines.push("```text");
|
|
210
|
+
lines.push(template.template);
|
|
211
|
+
lines.push("```");
|
|
212
|
+
lines.push("");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return `${lines.join("\n")}\n`;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export async function writeCompletionReportOutput(outputPath, content) {
|
|
219
|
+
return writeApplyPlanOutput(outputPath, content);
|
|
220
|
+
}
|
package/src/index.js
CHANGED
|
@@ -5,7 +5,9 @@ export {
|
|
|
5
5
|
runInteractiveOnboarding,
|
|
6
6
|
writeInteractiveOnboardingOutput
|
|
7
7
|
} from "./interactive-onboarding.js";
|
|
8
|
+
export { createApplyPlan, renderApplyPlanMarkdown, writeApplyPlanOutput } from "./apply-plan.js";
|
|
8
9
|
export { createAgentHandoff, renderAgentHandoffMarkdown, writeAgentHandoffOutput } from "./agent-handoff.js";
|
|
10
|
+
export { createCompletionReport, renderCompletionReportMarkdown, writeCompletionReportOutput } from "./completion-report.js";
|
|
9
11
|
export { createFixPlan, renderFixPlanMarkdown, writeFixPlanOutput } from "./fix-plan.js";
|
|
10
12
|
export { installSkill } from "./install-skill.js";
|
|
11
13
|
export { runCli } from "./cli.js";
|
package/src/quick-start.js
CHANGED
|
@@ -58,7 +58,9 @@ function buildSteps() {
|
|
|
58
58
|
goal: "让 PM、工程、内容、SEO 各自知道先做什么。",
|
|
59
59
|
commands: [
|
|
60
60
|
"geo-ai-search-optimization fix-plan ./your-site --out ./reports/fix-plan.md",
|
|
61
|
-
"geo-ai-search-optimization agent-handoff ./your-site --out ./reports/agent-handoff.md"
|
|
61
|
+
"geo-ai-search-optimization agent-handoff ./your-site --out ./reports/agent-handoff.md",
|
|
62
|
+
"geo-ai-search-optimization apply-plan ./your-site --out ./reports/apply-plan.md",
|
|
63
|
+
"geo-ai-search-optimization completion-report ./your-site --out ./reports/completion-report.md"
|
|
62
64
|
]
|
|
63
65
|
},
|
|
64
66
|
{
|