geo-ai-search-optimization 1.2.8 → 1.2.9

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,28 @@ geo-ai-search-optimization agent-session ./reports/apply-plan.json --json
81
81
  - 每一步的目的与预期产物
82
82
  - 可直接复制给 agent 的 session prompt
83
83
 
84
+ ## Agent Runbook 命令
85
+
86
+ 如果你希望 agent 拿到的不只是会话步骤,而是一份更稳定的执行手册和检查清单,可以直接用 `agent-runbook`:
87
+
88
+ ```bash
89
+ geo-ai-search-optimization agent-runbook "我想把这份 GEO 结果交给下一个 agent 继续修"
90
+ geo-ai-search-optimization agent-runbook https://example.com
91
+ geo-ai-search-optimization agent-runbook ./your-site
92
+ geo-ai-search-optimization agent-runbook ./reports/apply-plan.json --json
93
+ ```
94
+
95
+ 它会输出:
96
+
97
+ - 开始前检查
98
+ - 工作规则
99
+ - 需要停下来的情况
100
+ - 命令执行清单
101
+ - 重点执行包
102
+ - 验证清单
103
+ - 回报清单
104
+ - 可直接复制给 agent 的 runbook prompt
105
+
84
106
  ## Quick Start
85
107
 
86
108
  如果你要从 0 到 1 启动一个 GEO 项目,建议照这个顺序做。
@@ -476,6 +498,7 @@ geo-ai-search-optimization install
476
498
  geo-ai-search-optimization install --target ./tmp/custom-skills --json
477
499
  geo-ai-search-optimization auto-flow "audit this site and tell me the next skill"
478
500
  geo-ai-search-optimization agent-session ./your-site
501
+ geo-ai-search-optimization agent-runbook ./your-site
479
502
  geo-ai-search-optimization skills
480
503
  geo-ai-search-optimization where
481
504
  geo-ai-search-optimization doctor
@@ -532,6 +555,13 @@ geo-ai-search-optimization help
532
555
  - 新增 `geo-ai-search-optimization-agent-session` skill
533
556
  - 更适合把 GEO 任务直接交给下一个 agent 连续推进
534
557
 
558
+ ## New in 1.2.9
559
+
560
+ - 新增 `agent-runbook` 命令
561
+ - 把 `agent-session` 继续推进成给 agent 使用的执行手册和检查清单
562
+ - 输出开始前检查、工作规则、停止条件、验证清单、回报清单
563
+ - 新增 `geo-ai-search-optimization-agent-runbook` skill
564
+
535
565
  ## New in 1.2.5
536
566
 
537
567
  - 新增 `publish-pack`
@@ -715,10 +745,21 @@ Override with:
715
745
 
716
746
  ## Resource contents
717
747
 
718
- The installed package now includes two bundled skills:
748
+ The installed package now includes a bundled GEO skill pack, including:
719
749
 
720
750
  - `geo-ai-search-optimization`
751
+ - `geo-ai-search-optimization-auto-flow`
752
+ - `geo-ai-search-optimization-agent-session`
753
+ - `geo-ai-search-optimization-agent-runbook`
721
754
  - `geo-ai-search-optimization-usage`
755
+ - `geo-ai-search-optimization-agent-handoff`
756
+ - `geo-ai-search-optimization-repair-loop`
757
+ - `geo-ai-search-optimization-completion-report`
758
+ - `geo-ai-search-optimization-handoff-bundle`
759
+ - `geo-ai-search-optimization-share-pack`
760
+ - `geo-ai-search-optimization-export-pack`
761
+ - `geo-ai-search-optimization-html-pack`
762
+ - `geo-ai-search-optimization-publish-pack`
722
763
 
723
764
  ## License
724
765
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geo-ai-search-optimization",
3
- "version": "1.2.8",
3
+ "version": "1.2.9",
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": {
@@ -42,6 +42,16 @@ Best for:
42
42
  - giving the next agent a first command, second command, and expected artifact list
43
43
  - reducing ambiguity at handoff time
44
44
 
45
+ ### `geo-ai-search-optimization-agent-runbook`
46
+
47
+ Use this when the next agent needs an execution manual, not just a session sequence.
48
+
49
+ Best for:
50
+
51
+ - turning a GEO session into a checklist-driven runbook
52
+ - telling the next agent what to check before acting
53
+ - defining stop conditions, validation checklist, and reporting checklist
54
+
45
55
  ## Usage guide
46
56
 
47
57
  ### `geo-ai-search-optimization-usage`
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: geo-ai-search-optimization-agent-runbook
3
+ description: Turn a GEO input into an execution runbook for the next agent. Use when an agent needs more than routing or a session plan, and should receive a checklist-driven manual with preflight checks, stop conditions, validation steps, reporting expectations, and optional execution packets.
4
+ ---
5
+
6
+ # GEO Agent Runbook
7
+
8
+ Use this skill when the next agent should receive a practical runbook, not just a list of commands.
9
+
10
+ `GEO = Generative Engine Optimization`
11
+
12
+ ## What it does
13
+
14
+ - turn a GEO input into a checklist-driven execution manual
15
+ - define what to check before acting
16
+ - define what should stop execution
17
+ - define how validation and reporting should work
18
+ - carry the next agent from session planning into disciplined execution
19
+
20
+ ## Best use
21
+
22
+ - when `agent-session` is still too light and the next agent needs a more operational checklist
23
+ - when a PM or another agent wants a stable “follow this runbook” artifact
24
+ - when execution needs preflight, validation, and reporting rules
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "GEO Agent Runbook"
3
+ short_description: "Build a checklist-driven GEO execution manual"
4
+ default_prompt: "Use $geo-ai-search-optimization-agent-runbook to turn this input into a GEO runbook with preflight checks, execution checklist, validation steps, and reporting guidance."
@@ -13,23 +13,24 @@ 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 fifteen layers:
16
+ The package is best explained as sixteen layers:
17
17
 
18
18
  1. `auto-flow`: auto-select the next skill and command chain
19
19
  2. `agent-session`: build a runnable session for the next agent
20
- 3. `skills`: inspect the bundled skill package
21
- 4. `onboard-url` / `onboard`: first look
22
- 5. `scan`: raw signal check
23
- 6. `audit` / `report`: diagnosis
24
- 7. `fix-plan` / `owner-board`: execution planning
25
- 8. `agent-handoff`: agent takeover package
26
- 9. `apply-plan`: execution loop
27
- 10. `completion-report`: closeout
28
- 11. `handoff-bundle`: all-in-one package
29
- 12. `share-pack`: audience-ready delivery
30
- 13. `export-pack`: folder export
31
- 14. `html-pack` / `publish-pack`: browsable and final delivery output
32
- 15. `pm-brief` / `roadmap`: stakeholder alignment
20
+ 3. `agent-runbook`: execution manual and checklist for the next agent
21
+ 4. `skills`: inspect the bundled skill package
22
+ 5. `onboard-url` / `onboard`: first look
23
+ 6. `scan`: raw signal check
24
+ 7. `audit` / `report`: diagnosis
25
+ 8. `fix-plan` / `owner-board`: execution planning
26
+ 9. `agent-handoff`: agent takeover package
27
+ 10. `apply-plan`: execution loop
28
+ 11. `completion-report`: closeout
29
+ 12. `handoff-bundle`: all-in-one package
30
+ 13. `share-pack`: audience-ready delivery
31
+ 14. `export-pack`: folder export
32
+ 15. `html-pack` / `publish-pack`: browsable and final delivery output
33
+ 16. `pm-brief` / `roadmap`: stakeholder alignment
33
34
 
34
35
  ## Recommended command order
35
36
 
@@ -38,6 +39,7 @@ If the user only has a website URL:
38
39
  ```bash
39
40
  npx geo-ai-search-optimization auto-flow https://example.com
40
41
  npx geo-ai-search-optimization agent-session https://example.com
42
+ npx geo-ai-search-optimization agent-runbook https://example.com
41
43
  npx geo-ai-search-optimization onboard-url https://example.com
42
44
  npx geo-ai-search-optimization pm-brief https://example.com
43
45
  npx geo-ai-search-optimization roadmap https://example.com
@@ -48,6 +50,7 @@ If the user has the website codebase:
48
50
  ```bash
49
51
  npx geo-ai-search-optimization auto-flow ./your-site
50
52
  npx geo-ai-search-optimization agent-session ./your-site
53
+ npx geo-ai-search-optimization agent-runbook ./your-site
51
54
  npx geo-ai-search-optimization scan ./your-site
52
55
  npx geo-ai-search-optimization audit ./your-site
53
56
  npx geo-ai-search-optimization fix-plan ./your-site
@@ -67,6 +70,7 @@ npx geo-ai-search-optimization roadmap ./your-site
67
70
 
68
71
  - `auto-flow`: auto-select the next skill and command order from a task brief, URL, project path, or GEO artifact
69
72
  - `agent-session`: build a step-by-step session packet for the next agent from the same kinds of inputs
73
+ - `agent-runbook`: build a checklist-driven runbook with preflight, validation, and reporting rules
70
74
  - `onboard-url`: first-time website check from a live URL
71
75
  - `onboard`: interactive first-time onboarding
72
76
  - `skills`: list the bundled skills and decide which skill or command chain fits the task
@@ -93,6 +97,7 @@ When explaining the tool to a user:
93
97
  - prefer telling them which command to run next, not listing every command
94
98
  - if the user or the next agent is unsure where to start, move them to `auto-flow` first
95
99
  - if the user wants something the next agent can follow step by step, move them to `agent-session`
100
+ - if the user wants the next agent to follow a checklist and execution manual, move them to `agent-runbook`
96
101
  - explain the result in PM language, not implementation jargon
97
102
  - if the user sounds new, start with `onboard-url` or `quick-start`
98
103
  - if the user wants another agent to take over, move them to `agent-handoff`
@@ -0,0 +1,438 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { createApplyPlan } from "./apply-plan.js";
3
+ import { createAgentSession } from "./agent-session.js";
4
+ import { writeScanOutput } from "./scan.js";
5
+
6
+ const VALID_FORMATS = new Set(["markdown", "json"]);
7
+
8
+ function normalizeFormat(format) {
9
+ const resolved = (format || "markdown").toLowerCase();
10
+ if (!VALID_FORMATS.has(resolved)) {
11
+ throw new Error(`不支持的 agent-runbook 格式:${format}。可选值:${Array.from(VALID_FORMATS).join(", ")}`);
12
+ }
13
+ return resolved;
14
+ }
15
+
16
+ async function tryCreateExecutionPlan(input, options, session) {
17
+ if (session.sourceType === "json" && session.artifactKind === "geo-apply-plan") {
18
+ const parsed = JSON.parse(await readFile(input, "utf8"));
19
+ if (parsed?.kind === "geo-apply-plan") {
20
+ return parsed;
21
+ }
22
+ }
23
+
24
+ if (session.sourceType === "task-text" || session.intent === "guide") {
25
+ return null;
26
+ }
27
+
28
+ try {
29
+ return await createApplyPlan(input, {
30
+ format: "json",
31
+ taskId: options.taskId
32
+ });
33
+ } catch {
34
+ return null;
35
+ }
36
+ }
37
+
38
+ function inferRunbookMode(session, executionPlan) {
39
+ if (session.intent === "share") {
40
+ return "delivery-support";
41
+ }
42
+ if (session.intent === "closeout") {
43
+ return "closeout-support";
44
+ }
45
+ if (executionPlan?.executionType === "direct-fix") {
46
+ return "hands-on-fix";
47
+ }
48
+ if (executionPlan?.executionType === "recommendation-only") {
49
+ return "advisory-runbook";
50
+ }
51
+ if (executionPlan?.executionType === "guided-planning") {
52
+ return "guided-preparation";
53
+ }
54
+ if (session.intent === "execute") {
55
+ return "execution-preparation";
56
+ }
57
+ return "diagnostic-runbook";
58
+ }
59
+
60
+ function buildModeSummary(mode) {
61
+ switch (mode) {
62
+ case "hands-on-fix":
63
+ return "当前已经接近可直接动手修复的状态,runbook 应优先帮助 agent 在仓库里按检查表推进。";
64
+ case "advisory-runbook":
65
+ return "当前更适合输出结构化建议和修复手册,不要假装已经拥有仓库写入权限。";
66
+ case "guided-preparation":
67
+ return "当前已有部分执行工件,但还需要一个更稳定的执行手册来控制顺序和验收。";
68
+ case "delivery-support":
69
+ return "当前重点是把 GEO 结果整理成交付物,而不是重新做大范围诊断。";
70
+ case "closeout-support":
71
+ return "当前重点是整理完成情况、剩余风险和下一轮动作。";
72
+ case "execution-preparation":
73
+ return "当前需要把诊断结果继续推进成 agent 可执行的链路和检查表。";
74
+ default:
75
+ return "当前仍以诊断和建立执行方向为主,runbook 用于稳定下一步顺序。";
76
+ }
77
+ }
78
+
79
+ function buildPreflightChecklist(session, executionPlan, mode) {
80
+ const items = [
81
+ `确认当前输入 \`${session.source}\` 是最新的,而不是过期工件。`,
82
+ `确认这轮目标仍然是:${session.goal}`
83
+ ];
84
+
85
+ if (session.sourceType === "directory") {
86
+ items.push("确认当前目录就是可编辑的网站项目根目录,并且可以运行 CLI 复测命令。");
87
+ } else if (session.sourceType === "url") {
88
+ items.push("确认当前只有公开网址可见,不要把线上观察误写成已经完成代码修改。");
89
+ } else if (session.sourceType === "json" || session.sourceType === "file") {
90
+ items.push("确认当前工件和目标站点版本一致,避免基于旧结果继续执行。");
91
+ }
92
+
93
+ if (executionPlan?.executionType === "direct-fix") {
94
+ items.push("开始前先找模板层、metadata helper、schema 输出点,不要一上来只 patch 单页。");
95
+ }
96
+
97
+ if (session.contextNeeded.length > 0) {
98
+ for (const item of session.contextNeeded) {
99
+ items.push(`补齐上下文:${item}`);
100
+ }
101
+ }
102
+
103
+ if (mode === "delivery-support") {
104
+ items.push("确认这轮重点是整理对外产物,不要重复打开无关的诊断分支。");
105
+ }
106
+
107
+ return items;
108
+ }
109
+
110
+ function buildOperatingRules(session, executionPlan, mode) {
111
+ const items = [
112
+ "所有输出都要保持 PM 可读,避免只给技术术语不给业务含义。",
113
+ "每完成一步,都说明为什么这样做、得到什么、下一步是什么。",
114
+ "优先修复可复用模板、metadata helper、schema 生成逻辑,而不是只修一页。",
115
+ "如果没有仓库或写入权限,不要声称已经完成代码修改。"
116
+ ];
117
+
118
+ if (executionPlan?.executionType === "direct-fix") {
119
+ items.push("每做完一轮修改,就要立刻复跑至少一条 GEO CLI 验证命令。");
120
+ }
121
+
122
+ if (mode === "delivery-support") {
123
+ items.push("交付阶段以整理和包装结果为主,不要在没有必要时重新定义优先级。");
124
+ }
125
+
126
+ if (mode === "closeout-support") {
127
+ items.push("收尾阶段必须清楚区分:已完成、未完成、待验证、下一轮任务。");
128
+ }
129
+
130
+ return items;
131
+ }
132
+
133
+ function buildStopConditions(session, executionPlan) {
134
+ const items = [
135
+ "找不到当前输入对应的网站、项目目录或工件,无法确认执行对象。",
136
+ "CLI 输出与当前假设冲突,例如问题区域和已有工件不一致。",
137
+ "无法给出明确验收标准时,不要继续扩大范围。"
138
+ ];
139
+
140
+ if (executionPlan?.executionType === "direct-fix") {
141
+ items.push("明明需要直接修复,但拿不到仓库、模板或关键文件时,应先停下并说明缺的上下文。");
142
+ }
143
+
144
+ if (session.sourceType === "url") {
145
+ items.push("只有网址没有仓库时,不要进入假想修复,应切回建议模式。");
146
+ }
147
+
148
+ return items;
149
+ }
150
+
151
+ function buildCommandChecklist(steps) {
152
+ return steps.map((step, index) => {
153
+ const doneWhen = [
154
+ `已经运行或明确评估:\`${step.command}\``,
155
+ `已经拿到或确认:${step.expectedArtifact}`,
156
+ "已经记录本步结论,并说明下一步是否需要继续"
157
+ ];
158
+
159
+ if (index === 0) {
160
+ doneWhen.push("已经确认第一步不是跑偏,而是符合当前会话阶段。");
161
+ }
162
+
163
+ return {
164
+ id: step.id,
165
+ command: step.command,
166
+ commandName: step.commandName,
167
+ suggestedSkill: step.suggestedSkill,
168
+ purpose: step.purpose,
169
+ expectedArtifact: step.expectedArtifact,
170
+ instructions: step.instructions,
171
+ doneWhen
172
+ };
173
+ });
174
+ }
175
+
176
+ function buildExecutionPackets(executionPlan) {
177
+ if (!executionPlan) {
178
+ return [];
179
+ }
180
+
181
+ return executionPlan.packets.map((packet) => ({
182
+ id: packet.id,
183
+ title: packet.title,
184
+ priority: packet.priority,
185
+ owner: packet.owner,
186
+ executionType: packet.executionType,
187
+ inspectTargets: packet.inspectTargets,
188
+ editPlan: packet.editPlan,
189
+ validationCommands: packet.validationCommands,
190
+ deliverables: packet.deliverables,
191
+ doneWhen: packet.doneWhen
192
+ }));
193
+ }
194
+
195
+ function buildValidationChecklist(session, executionPlan) {
196
+ const items = [];
197
+
198
+ if (executionPlan?.packets?.length) {
199
+ const commands = Array.from(
200
+ new Set(executionPlan.packets.flatMap((packet) => packet.validationCommands || []))
201
+ );
202
+ for (const command of commands) {
203
+ items.push(`复跑验证命令:\`${command}\``);
204
+ }
205
+ } else if (session.steps.length > 0) {
206
+ items.push(`至少重新确认第一条关键命令是否已达成预期:\`${session.steps[0].command}\``);
207
+ }
208
+
209
+ items.push("确认最高优先级问题是否真的下降,而不是只改变了表述。");
210
+ items.push("确认输出仍然能解释:哪里被修复、哪里还没修、下一步是什么。");
211
+
212
+ if (session.sourceType === "url") {
213
+ items.push("如果只有网址,验证重点应放在公开可观察信号和建议质量,而不是虚构代码变更。");
214
+ }
215
+
216
+ return items;
217
+ }
218
+
219
+ function buildReportingChecklist(session, executionPlan) {
220
+ const items = [
221
+ "总结这轮做了什么,按问题区域或任务包分组,而不是只贴命令输出。",
222
+ "明确剩余风险、未完成项和下一轮最该先做的 1 到 3 件事。",
223
+ "告诉用户下一位 agent 或下一轮流程应该从哪个命令继续。"
224
+ ];
225
+
226
+ if (executionPlan?.executionType === "direct-fix") {
227
+ items.push("回报时带上复测命令和结果,说明这次修复是否真的改变了 GEO 状态。");
228
+ } else {
229
+ items.push("回报时明确哪些建议还需要仓库、权限或更多页面上下文才能继续落地。");
230
+ }
231
+
232
+ if (session.intent === "share") {
233
+ items.push("如果这轮目标是交付,回报里要说明应该把结果发给谁,以及推荐使用哪个分享包。");
234
+ }
235
+
236
+ return items;
237
+ }
238
+
239
+ function buildNextCommands(session, executionPlan) {
240
+ if (session.intent === "share") {
241
+ return [
242
+ `geo-ai-search-optimization share-pack ${session.source}`,
243
+ `geo-ai-search-optimization publish-pack ${session.source}`
244
+ ];
245
+ }
246
+
247
+ if (session.intent === "closeout") {
248
+ return [
249
+ `geo-ai-search-optimization completion-report ${session.source}`,
250
+ `geo-ai-search-optimization handoff-bundle ${session.source}`
251
+ ];
252
+ }
253
+
254
+ if (executionPlan) {
255
+ return [
256
+ `geo-ai-search-optimization apply-plan ${session.source}`,
257
+ `geo-ai-search-optimization completion-report ${session.source}`
258
+ ];
259
+ }
260
+
261
+ return session.steps.slice(0, 2).map((step) => step.command);
262
+ }
263
+
264
+ function buildRunbookPrompt(session, runbookMode, executionPackets) {
265
+ const lines = [
266
+ `Use $geo-ai-search-optimization-agent-runbook to continue this GEO task.`,
267
+ `当前输入:${session.source}`,
268
+ `当前阶段:${session.stage}`,
269
+ `当前意图:${session.intent}`,
270
+ `runbook 模式:${runbookMode}`,
271
+ `目标:${session.goal}`,
272
+ "请按下面顺序推进:",
273
+ "1. 先执行开始前检查。",
274
+ "2. 再按命令执行清单推进。",
275
+ "3. 如果有重点执行包,优先做最高优先级那一包。",
276
+ "4. 每完成一轮动作,都做验证清单。",
277
+ "5. 最后按回报清单整理给用户的结果。"
278
+ ];
279
+
280
+ if (executionPackets.length > 0) {
281
+ lines.push("当前重点执行包:");
282
+ for (const packet of executionPackets) {
283
+ lines.push(`- ${packet.priority}|${packet.title}`);
284
+ }
285
+ }
286
+
287
+ if (session.contextNeeded.length > 0) {
288
+ lines.push("如果上下文不足,必须先明确缺什么,再决定是否继续。");
289
+ }
290
+
291
+ return lines.join("\n");
292
+ }
293
+
294
+ export async function createAgentRunbook(input, options = {}) {
295
+ const format = normalizeFormat(options.format);
296
+ const session = await createAgentSession(input, {
297
+ intent: options.intent
298
+ });
299
+ const executionPlan = await tryCreateExecutionPlan(input, options, session);
300
+ const runbookMode = inferRunbookMode(session, executionPlan);
301
+ const commandChecklist = buildCommandChecklist(session.steps);
302
+ const executionPackets = buildExecutionPackets(executionPlan);
303
+
304
+ return {
305
+ kind: "geo-agent-runbook",
306
+ input,
307
+ source: session.source,
308
+ sourceType: session.sourceType,
309
+ artifactKind: session.artifactKind,
310
+ format,
311
+ intent: session.intent,
312
+ stage: session.stage,
313
+ status: session.status,
314
+ runbookMode,
315
+ modeSummary: buildModeSummary(runbookMode),
316
+ goal: session.goal,
317
+ selectedSkill: session.selectedSkill,
318
+ secondarySkills: session.secondarySkills,
319
+ whyThisSkill: session.whyThisSkill,
320
+ nextAction: session.nextAction,
321
+ preflightChecklist: buildPreflightChecklist(session, executionPlan, runbookMode),
322
+ operatingRules: buildOperatingRules(session, executionPlan, runbookMode),
323
+ stopConditions: buildStopConditions(session, executionPlan),
324
+ commandChecklist,
325
+ executionPackets,
326
+ validationChecklist: buildValidationChecklist(session, executionPlan),
327
+ reportingChecklist: buildReportingChecklist(session, executionPlan),
328
+ nextCommands: buildNextCommands(session, executionPlan),
329
+ runbookPrompt: buildRunbookPrompt(session, runbookMode, executionPackets),
330
+ agentSession: session,
331
+ applyPlan: executionPlan
332
+ };
333
+ }
334
+
335
+ export function renderAgentRunbookMarkdown(runbook) {
336
+ const lines = [
337
+ "# GEO Agent Runbook",
338
+ "",
339
+ `- 输入:\`${runbook.source}\``,
340
+ `- 输入类型:\`${runbook.sourceType}\``,
341
+ `- 工件类型:\`${runbook.artifactKind}\``,
342
+ `- 当前阶段:${runbook.stage}`,
343
+ `- 当前状态:${runbook.status}`,
344
+ `- runbook 模式:\`${runbook.runbookMode}\``,
345
+ `- 模式说明:${runbook.modeSummary}`,
346
+ `- 目标:${runbook.goal}`,
347
+ `- 当前主 skill:\`${runbook.selectedSkill.name}\``,
348
+ "",
349
+ "## 开始前检查",
350
+ ""
351
+ ];
352
+
353
+ for (const item of runbook.preflightChecklist) {
354
+ lines.push(`- [ ] ${item}`);
355
+ }
356
+
357
+ lines.push("", "## 工作规则", "");
358
+ for (const item of runbook.operatingRules) {
359
+ lines.push(`- [ ] ${item}`);
360
+ }
361
+
362
+ lines.push("", "## 需要停下来的情况", "");
363
+ for (const item of runbook.stopConditions) {
364
+ lines.push(`- [ ] ${item}`);
365
+ }
366
+
367
+ lines.push("", "## 命令执行清单", "");
368
+ for (const item of runbook.commandChecklist) {
369
+ lines.push(`### ${item.id}|${item.commandName}`, "");
370
+ lines.push(`- 命令:\`${item.command}\``);
371
+ lines.push(`- 建议 skill:\`${item.suggestedSkill}\``);
372
+ lines.push(`- 目的:${item.purpose}`);
373
+ lines.push(`- 预期产物:${item.expectedArtifact}`);
374
+ lines.push("- 操作说明:");
375
+ for (const instruction of item.instructions) {
376
+ lines.push(` - ${instruction}`);
377
+ }
378
+ lines.push("- 完成标准:");
379
+ for (const doneWhen of item.doneWhen) {
380
+ lines.push(` - [ ] ${doneWhen}`);
381
+ }
382
+ lines.push("");
383
+ }
384
+
385
+ if (runbook.executionPackets.length > 0) {
386
+ lines.push("## 重点执行包", "");
387
+ for (const packet of runbook.executionPackets) {
388
+ lines.push(`### ${packet.id}|${packet.title}`, "");
389
+ lines.push(`- 优先级:${packet.priority}`);
390
+ lines.push(`- Owner:${packet.owner}`);
391
+ lines.push(`- 执行类型:\`${packet.executionType}\``);
392
+ lines.push("- 先检查:");
393
+ for (const target of packet.inspectTargets) {
394
+ lines.push(` - [ ] ${target}`);
395
+ }
396
+ lines.push("- 建议动作:");
397
+ for (const step of packet.editPlan) {
398
+ lines.push(` - [ ] ${step}`);
399
+ }
400
+ lines.push("- 验证命令:");
401
+ for (const command of packet.validationCommands) {
402
+ lines.push(` - \`${command}\``);
403
+ }
404
+ lines.push("- 交付物:");
405
+ for (const item of packet.deliverables) {
406
+ lines.push(` - ${item}`);
407
+ }
408
+ lines.push("- Done when:");
409
+ for (const item of packet.doneWhen) {
410
+ lines.push(` - [ ] ${item}`);
411
+ }
412
+ lines.push("");
413
+ }
414
+ }
415
+
416
+ lines.push("## 验证清单", "");
417
+ for (const item of runbook.validationChecklist) {
418
+ lines.push(`- [ ] ${item}`);
419
+ }
420
+
421
+ lines.push("", "## 回报清单", "");
422
+ for (const item of runbook.reportingChecklist) {
423
+ lines.push(`- [ ] ${item}`);
424
+ }
425
+
426
+ lines.push("", "## 下一步推荐命令", "");
427
+ for (const command of runbook.nextCommands) {
428
+ lines.push(`- \`${command}\``);
429
+ }
430
+
431
+ lines.push("", "## 可直接复制给 Agent 的 Runbook Prompt", "", "```text", runbook.runbookPrompt, "```");
432
+
433
+ return `${lines.join("\n")}\n`;
434
+ }
435
+
436
+ export async function writeAgentRunbookOutput(outputPath, content) {
437
+ return writeScanOutput(outputPath, content);
438
+ }
@@ -46,6 +46,9 @@ function inferSkillForCommand(commandName, flow) {
46
46
  if (commandName === "auto-flow") {
47
47
  return "geo-ai-search-optimization-auto-flow";
48
48
  }
49
+ if (commandName === "agent-runbook") {
50
+ return "geo-ai-search-optimization-agent-runbook";
51
+ }
49
52
  if (commandName === "skills" || commandName === "quick-start") {
50
53
  return "geo-ai-search-optimization-usage";
51
54
  }
@@ -106,6 +109,8 @@ function inferStepPurpose(commandName, flow) {
106
109
  return "把修复顺序转成阶段计划。";
107
110
  case "agent-handoff":
108
111
  return "把当前结果交接成 agent 可继续执行的工件。";
112
+ case "agent-runbook":
113
+ return "把当前链路整理成 agent 可照着执行的手册和检查表。";
109
114
  case "apply-plan":
110
115
  return "把交接结果推进到具体执行包。";
111
116
  case "completion-report":
@@ -146,6 +151,8 @@ function inferExpectedArtifact(commandName) {
146
151
  return "阶段路线图";
147
152
  case "agent-handoff":
148
153
  return "agent 交接工件";
154
+ case "agent-runbook":
155
+ return "agent 执行手册";
149
156
  case "apply-plan":
150
157
  return "执行包";
151
158
  case "completion-report":
@@ -178,6 +185,9 @@ function buildStepInstructions(parsedCommand, flow) {
178
185
  if (parsedCommand.commandName === "apply-plan") {
179
186
  lines.push("执行包出来后,优先从第一包开始,不要同时展开太多任务。");
180
187
  }
188
+ if (parsedCommand.commandName === "agent-runbook") {
189
+ lines.push("先用 runbook 稳定顺序、检查项和回报方式,再开始真正执行。");
190
+ }
181
191
  if (parsedCommand.commandName === "agent-handoff" && flow.intent === "execute") {
182
192
  lines.push("如果还是 advice-only,说明还缺仓库或本地项目上下文。");
183
193
  }
package/src/auto-flow.js CHANGED
@@ -44,6 +44,9 @@ function inferTaskTextMode(text) {
44
44
  if (/(share-pack|export-pack|html-pack|publish-pack|分享|导出|交付|外发|报告包)/i.test(normalized)) {
45
45
  return "share";
46
46
  }
47
+ if (/(runbook|checklist|playbook|执行手册|检查清单|操作手册)/i.test(normalized)) {
48
+ return "execute";
49
+ }
47
50
  if (/(apply-plan|handoff|接手|交给.*agent|继续修|继续做|修复|执行|修改|落地|repair|implement|fix)/i.test(normalized)) {
48
51
  return "execute";
49
52
  }
@@ -147,7 +150,9 @@ function resolveEffectiveIntent(intent, detected) {
147
150
  return "share";
148
151
  }
149
152
  if (
150
- ["geo-agent-handoff", "geo-apply-plan", "geo-handoff-bundle", "geo-fix-plan"].includes(detected.artifactKind)
153
+ ["geo-agent-handoff", "geo-agent-runbook", "geo-apply-plan", "geo-handoff-bundle", "geo-fix-plan"].includes(
154
+ detected.artifactKind
155
+ )
151
156
  ) {
152
157
  return "execute";
153
158
  }
@@ -197,7 +202,8 @@ function buildCommandChain(detected, intent) {
197
202
  return [
198
203
  `geo-ai-search-optimization onboard-url ${source}`,
199
204
  `geo-ai-search-optimization fix-plan ${source}`,
200
- `geo-ai-search-optimization agent-handoff ${source}`
205
+ `geo-ai-search-optimization agent-handoff ${source}`,
206
+ `geo-ai-search-optimization agent-runbook ${source}`
201
207
  ];
202
208
  }
203
209
  return [
@@ -213,6 +219,7 @@ function buildCommandChain(detected, intent) {
213
219
  `geo-ai-search-optimization audit ${source}`,
214
220
  `geo-ai-search-optimization fix-plan ${source}`,
215
221
  `geo-ai-search-optimization agent-handoff ${source}`,
222
+ `geo-ai-search-optimization agent-runbook ${source}`,
216
223
  `geo-ai-search-optimization apply-plan ${source}`
217
224
  ];
218
225
  }
@@ -230,6 +237,7 @@ function buildCommandChain(detected, intent) {
230
237
  ? [
231
238
  `geo-ai-search-optimization fix-plan ${source}`,
232
239
  `geo-ai-search-optimization agent-handoff ${source}`,
240
+ `geo-ai-search-optimization agent-runbook ${source}`,
233
241
  `geo-ai-search-optimization apply-plan ${source}`
234
242
  ]
235
243
  : [`geo-ai-search-optimization fix-plan ${source}`, `geo-ai-search-optimization owner-board ${source}`];
@@ -243,15 +251,24 @@ function buildCommandChain(detected, intent) {
243
251
  case "geo-fix-plan":
244
252
  return [
245
253
  `geo-ai-search-optimization agent-handoff ${source}`,
254
+ `geo-ai-search-optimization agent-runbook ${source}`,
246
255
  `geo-ai-search-optimization apply-plan ${source}`
247
256
  ];
248
257
  case "geo-agent-handoff":
249
258
  return [
259
+ `geo-ai-search-optimization agent-runbook ${source}`,
250
260
  `geo-ai-search-optimization apply-plan ${source}`,
251
261
  `geo-ai-search-optimization completion-report ${source}`
252
262
  ];
263
+ case "geo-agent-runbook":
264
+ return [
265
+ `geo-ai-search-optimization apply-plan ${source}`,
266
+ `geo-ai-search-optimization completion-report ${source}`,
267
+ `geo-ai-search-optimization handoff-bundle ${source}`
268
+ ];
253
269
  case "geo-apply-plan":
254
270
  return [
271
+ `geo-ai-search-optimization agent-runbook ${source}`,
255
272
  `geo-ai-search-optimization apply-plan ${source}`,
256
273
  `geo-ai-search-optimization completion-report ${source}`,
257
274
  `geo-ai-search-optimization handoff-bundle ${source}`
@@ -313,10 +330,11 @@ function pickSkillName(detected, intent) {
313
330
  case "geo-report:onboarding":
314
331
  return intent === "execute" ? "geo-ai-search-optimization-agent-handoff" : "geo-ai-search-optimization";
315
332
  case "geo-fix-plan":
316
- case "geo-agent-handoff":
317
333
  return "geo-ai-search-optimization-agent-handoff";
334
+ case "geo-agent-handoff":
335
+ case "geo-agent-runbook":
318
336
  case "geo-apply-plan":
319
- return "geo-ai-search-optimization-repair-loop";
337
+ return "geo-ai-search-optimization-agent-runbook";
320
338
  case "geo-completion-report":
321
339
  return "geo-ai-search-optimization-completion-report";
322
340
  case "geo-handoff-bundle":
@@ -346,7 +364,11 @@ function buildSecondarySkillNames(primarySkill, intent, detected) {
346
364
  names.add("geo-ai-search-optimization-share-pack");
347
365
  names.add("geo-ai-search-optimization-publish-pack");
348
366
  }
349
- if (intent === "execute" || ["geo-fix-plan", "geo-agent-handoff", "geo-apply-plan"].includes(detected.artifactKind)) {
367
+ if (
368
+ intent === "execute" ||
369
+ ["geo-fix-plan", "geo-agent-handoff", "geo-agent-runbook", "geo-apply-plan"].includes(detected.artifactKind)
370
+ ) {
371
+ names.add("geo-ai-search-optimization-agent-runbook");
350
372
  names.add("geo-ai-search-optimization-agent-handoff");
351
373
  names.add("geo-ai-search-optimization-repair-loop");
352
374
  }
@@ -369,11 +391,17 @@ function buildStage(intent, detected) {
369
391
  return "执行复盘";
370
392
  }
371
393
  if (intent === "execute") {
372
- return ["geo-fix-plan", "geo-agent-handoff", "geo-apply-plan", "geo-handoff-bundle"].includes(detected.artifactKind)
394
+ return ["geo-fix-plan", "geo-agent-handoff", "geo-agent-runbook", "geo-apply-plan", "geo-handoff-bundle"].includes(
395
+ detected.artifactKind
396
+ )
373
397
  ? "Agent 执行"
374
398
  : "执行准备";
375
399
  }
376
- if (["geo-fix-plan", "geo-agent-handoff", "geo-apply-plan", "geo-handoff-bundle"].includes(detected.artifactKind)) {
400
+ if (
401
+ ["geo-fix-plan", "geo-agent-handoff", "geo-agent-runbook", "geo-apply-plan", "geo-handoff-bundle"].includes(
402
+ detected.artifactKind
403
+ )
404
+ ) {
377
405
  return "Agent 执行";
378
406
  }
379
407
  return "诊断规划";
package/src/cli.js CHANGED
@@ -3,6 +3,7 @@ import { readFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { createApplyPlan, renderApplyPlanMarkdown, writeApplyPlanOutput } from "./apply-plan.js";
5
5
  import { createAgentHandoff, renderAgentHandoffMarkdown, writeAgentHandoffOutput } from "./agent-handoff.js";
6
+ import { createAgentRunbook, renderAgentRunbookMarkdown, writeAgentRunbookOutput } from "./agent-runbook.js";
6
7
  import { createAgentSession, renderAgentSessionMarkdown, writeAgentSessionOutput } from "./agent-session.js";
7
8
  import { createAutoFlow, renderAutoFlowMarkdown, writeAutoFlowOutput } from "./auto-flow.js";
8
9
  import {
@@ -61,6 +62,7 @@ function printHelp() {
61
62
  " geo-ai-search-optimization install [--target <dir>] [--json]",
62
63
  " geo-ai-search-optimization auto-flow <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--json] [--out <file>]",
63
64
  " geo-ai-search-optimization agent-session <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--json] [--out <file>]",
65
+ " geo-ai-search-optimization agent-runbook <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--task <id>] [--format <markdown|json>] [--out <file>]",
64
66
  " geo-ai-search-optimization skills [--json]",
65
67
  " geo-ai-search-optimization where",
66
68
  " geo-ai-search-optimization doctor [--json]",
@@ -177,6 +179,33 @@ async function handleAgentSession(args) {
177
179
  process.stdout.write(renderedOutput);
178
180
  }
179
181
 
182
+ async function handleAgentRunbook(args) {
183
+ const input = args.find((value) => !value.startsWith("-"));
184
+ if (!input) {
185
+ throw new Error("agent-runbook 需要一个输入值,可以是任务描述、项目路径、网站网址或已导出的工件");
186
+ }
187
+
188
+ const format = getFlagValue(args, "--format");
189
+ const runbook = await createAgentRunbook(input, {
190
+ intent: getFlagValue(args, "--intent"),
191
+ format,
192
+ taskId: getFlagValue(args, "--task")
193
+ });
194
+ const outputJson = format === "json";
195
+ const renderedOutput = outputJson
196
+ ? `${JSON.stringify(runbook, null, 2)}\n`
197
+ : renderAgentRunbookMarkdown(runbook);
198
+
199
+ const outputPath = getFlagValue(args, "--out");
200
+ if (outputPath) {
201
+ const resolvedOutputPath = await writeAgentRunbookOutput(outputPath, renderedOutput);
202
+ process.stdout.write(`已保存 agent runbook:${resolvedOutputPath}\n`);
203
+ return;
204
+ }
205
+
206
+ process.stdout.write(renderedOutput);
207
+ }
208
+
180
209
  function handleWhere() {
181
210
  process.stdout.write(
182
211
  [
@@ -727,6 +756,11 @@ export async function runCli(args = []) {
727
756
  return;
728
757
  }
729
758
 
759
+ if (command === "agent-runbook") {
760
+ await handleAgentRunbook(rest);
761
+ return;
762
+ }
763
+
730
764
  if (command === "skills") {
731
765
  await handleSkills(rest);
732
766
  return;
package/src/index.js CHANGED
@@ -8,6 +8,7 @@ export {
8
8
  export { createAutoFlow, renderAutoFlowMarkdown, writeAutoFlowOutput } from "./auto-flow.js";
9
9
  export { createApplyPlan, renderApplyPlanMarkdown, writeApplyPlanOutput } from "./apply-plan.js";
10
10
  export { createAgentHandoff, renderAgentHandoffMarkdown, writeAgentHandoffOutput } from "./agent-handoff.js";
11
+ export { createAgentRunbook, renderAgentRunbookMarkdown, writeAgentRunbookOutput } from "./agent-runbook.js";
11
12
  export { createAgentSession, renderAgentSessionMarkdown, writeAgentSessionOutput } from "./agent-session.js";
12
13
  export { createCompletionReport, renderCompletionReportMarkdown, writeCompletionReportOutput } from "./completion-report.js";
13
14
  export { createFixPlan, renderFixPlanMarkdown, writeFixPlanOutput } from "./fix-plan.js";
package/src/skills.js CHANGED
@@ -6,6 +6,7 @@ const SKILL_ORDER = [
6
6
  "geo-ai-search-optimization",
7
7
  "geo-ai-search-optimization-auto-flow",
8
8
  "geo-ai-search-optimization-agent-session",
9
+ "geo-ai-search-optimization-agent-runbook",
9
10
  "geo-ai-search-optimization-usage",
10
11
  "geo-ai-search-optimization-agent-handoff",
11
12
  "geo-ai-search-optimization-repair-loop",
@@ -21,6 +22,7 @@ const SKILL_CATEGORY = {
21
22
  "geo-ai-search-optimization": "core",
22
23
  "geo-ai-search-optimization-auto-flow": "routing",
23
24
  "geo-ai-search-optimization-agent-session": "routing",
25
+ "geo-ai-search-optimization-agent-runbook": "execution",
24
26
  "geo-ai-search-optimization-usage": "guidance",
25
27
  "geo-ai-search-optimization-agent-handoff": "execution",
26
28
  "geo-ai-search-optimization-repair-loop": "execution",
@@ -154,6 +156,8 @@ export function renderBundledSkillsMarkdown(bundle) {
154
156
  "",
155
157
  "- 先看核心 GEO skill。",
156
158
  "- 如果 agent 需要自动选 skill,先跑 auto-flow。",
159
+ "- 如果要给 agent 明确步骤,继续进入 agent-session。",
160
+ "- 如果要给 agent 一份执行手册和检查表,再进入 agent-runbook。",
157
161
  "- 再看 usage skill,知道什么时候该跑哪个命令。",
158
162
  "- 如果要交给 agent 执行,再进入 handoff / apply / completion 这一条执行链。",
159
163
  "- 如果要产出给团队分发,再进入 share / export / html / publish 这一条交付链。",