geo-ai-search-optimization 1.2.18 → 1.2.19

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
@@ -63,6 +63,27 @@ geo-ai-search-optimization agent-orchestrator ./reports/agent-playbook-pack.json
63
63
  - 做完之后下一条是什么
64
64
  - 可直接复制给 agent 的 orchestrator prompt
65
65
 
66
+ ## Agent Resume 命令
67
+
68
+ 如果 GEO 工作已经做过一轮或多轮,你不想让下一个 agent 从头重新判断,而是想让它从最近一个可靠恢复点继续,可以直接用 `agent-resume`:
69
+
70
+ ```bash
71
+ geo-ai-search-optimization agent-resume "继续这个 GEO 任务"
72
+ geo-ai-search-optimization agent-resume https://example.com
73
+ geo-ai-search-optimization agent-resume ./your-site
74
+ geo-ai-search-optimization agent-resume ./reports/agent-playbook-pack.json --format json --out ./reports/agent-resume.json
75
+ ```
76
+
77
+ 它会输出:
78
+
79
+ - 恢复模式
80
+ - 从哪里恢复
81
+ - 现在只恢复哪一条命令
82
+ - 恢复前要先确认什么
83
+ - 恢复时不要重置什么
84
+ - 恢复后下一条是什么
85
+ - 可直接复制给 agent 的 resume prompt
86
+
66
87
  ## Auto Flow 命令
67
88
 
68
89
  如果你希望 agent 不用自己判断现在该用哪个 skill、该跑哪个命令,可以直接用 `auto-flow`:
@@ -682,6 +703,7 @@ geo-ai-search-optimization
682
703
  geo-ai-search-optimization install
683
704
  geo-ai-search-optimization install --target ./tmp/custom-skills --json
684
705
  geo-ai-search-optimization agent-orchestrator ./your-site
706
+ geo-ai-search-optimization agent-resume ./your-site
685
707
  geo-ai-search-optimization auto-flow "audit this site and tell me the next skill"
686
708
  geo-ai-search-optimization agent-session ./your-site
687
709
  geo-ai-search-optimization agent-runbook ./your-site
@@ -763,6 +785,14 @@ geo-ai-search-optimization help
763
785
  - 输出 do-now checklist、stop checklist、success checklist、验证命令和回报模板
764
786
  - 新增 `geo-ai-search-optimization-agent-executor` skill
765
787
 
788
+ ## New in 1.2.19
789
+
790
+ - 新增 `agent-resume`
791
+ - 把 `agent-orchestrator + agent-playbook-pack` 收敛成“从最近一个可靠恢复点继续”的恢复入口
792
+ - 输出 `resume_mode`、`resume_from`、`resume_command`、`verify_before_resume`、`do_not_reset`、`after_resume`
793
+ - `auto-flow`、`agent-session`、`skills` 已经把 `agent-resume` 视为正式恢复链路
794
+ - 新增 `geo-ai-search-optimization-agent-resume` skill
795
+
766
796
  ## New in 1.2.18
767
797
 
768
798
  - 新增 `agent-orchestrator`
@@ -1009,6 +1039,7 @@ The installed package now includes a bundled GEO skill pack, including:
1009
1039
  - `geo-ai-search-optimization`
1010
1040
  - `geo-ai-search-optimization-auto-flow`
1011
1041
  - `geo-ai-search-optimization-agent-orchestrator`
1042
+ - `geo-ai-search-optimization-agent-resume`
1012
1043
  - `geo-ai-search-optimization-agent-session`
1013
1044
  - `geo-ai-search-optimization-agent-runbook`
1014
1045
  - `geo-ai-search-optimization-agent-executor`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geo-ai-search-optimization",
3
- "version": "1.2.18",
3
+ "version": "1.2.19",
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
  - returning a short contract with expected artifact, stop conditions, and follow-up command
43
43
  - reducing ambiguity for PM-to-agent or agent-to-agent handoffs
44
44
 
45
+ ### `geo-ai-search-optimization-agent-resume`
46
+
47
+ Use this when the next agent should continue from the latest reliable GEO checkpoint instead of restarting the whole chain.
48
+
49
+ Best for:
50
+
51
+ - resuming from a playbook pack, decision log, status board, checkpoint, or similar GEO artifact
52
+ - telling the next agent exactly where to continue and what not to reset
53
+ - turning a previously interrupted GEO chain into one resume command plus one follow-up command
54
+
45
55
  ### `geo-ai-search-optimization-agent-session`
46
56
 
47
57
  Use this when the next agent needs a runnable session plan, not just a routing answer.
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: geo-ai-search-optimization-agent-resume
3
+ description: Resume a GEO workflow from the latest reliable point instead of restarting the whole chain. Use when an agent, PM, or another workflow has a GEO URL, codebase, playbook pack, decision log, status board, checkpoint, or related artifact and needs the exact resume command, pre-resume checks, and a clear list of what should not be reset.
4
+ ---
5
+
6
+ # GEO Agent Resume
7
+
8
+ Use this skill when the next agent should continue, not restart.
9
+
10
+ `GEO = Generative Engine Optimization`
11
+
12
+ ## What it does
13
+
14
+ - finds the latest reliable GEO recovery point
15
+ - tells the next agent which one command to resume now
16
+ - explains what to verify before resuming
17
+ - lists what should not be reset while continuing the chain
18
+ - keeps the agent aligned with the current packet, next packet, and follow-up command
19
+
20
+ ## Best use
21
+
22
+ - when GEO work was interrupted and another agent needs to continue safely
23
+ - when PM wants to say "pick up from where the last agent left off"
24
+ - when there are already GEO artifacts and the risk is restarting the chain from the wrong place
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "GEO Agent Resume"
3
+ short_description: "Resume GEO work from the latest reliable point"
4
+ default_prompt: "Use $geo-ai-search-optimization-agent-resume to continue this GEO workflow from the latest reliable checkpoint, identify the one resume command to run now, list what to verify first, and explain what must not be reset."
@@ -13,33 +13,34 @@ 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 twenty-five layers:
16
+ The package is best explained as twenty-six layers:
17
17
 
18
18
  1. `agent-orchestrator`: choose the one next GEO command to run right now
19
- 2. `auto-flow`: auto-select the next skill and command chain
20
- 3. `agent-session`: build a runnable session for the next agent
21
- 4. `agent-runbook`: execution manual and checklist for the next agent
22
- 5. `agent-executor`: choose one packet to execute right now
23
- 6. `agent-batch-executor`: queue the first few packets, but still advance one packet at a time
24
- 7. `agent-progress-tracker`: track which packet is done, which one is active, and what comes next
25
- 8. `agent-status-board`: turn the execution state into a board view for PM and agents
26
- 9. `agent-checkpoint`: freeze the current round into a continue / unblock / closeout decision
27
- 10. `agent-decision-log`: preserve why each round continued, paused, or closed out
28
- 11. `agent-retrospective`: explain multi-round patterns, lessons, and next-round advice
29
- 12. `agent-playbook-pack`: compress retrospective, decision history, and handoff into one resume entrypoint
30
- 13. `skills`: inspect the bundled skill package
31
- 14. `onboard-url` / `onboard`: first look
32
- 15. `scan`: raw signal check
33
- 16. `audit` / `report`: diagnosis
34
- 17. `fix-plan` / `owner-board`: execution planning
35
- 18. `agent-handoff`: agent takeover package
36
- 19. `apply-plan`: execution loop
37
- 20. `completion-report`: closeout
38
- 21. `handoff-bundle`: all-in-one package
39
- 22. `share-pack`: audience-ready delivery
40
- 23. `export-pack`: folder export
41
- 24. `html-pack` / `publish-pack`: browsable and final delivery output
42
- 25. `pm-brief` / `roadmap`: stakeholder alignment
19
+ 2. `agent-resume`: resume from the latest reliable GEO checkpoint instead of restarting the whole chain
20
+ 3. `auto-flow`: auto-select the next skill and command chain
21
+ 4. `agent-session`: build a runnable session for the next agent
22
+ 5. `agent-runbook`: execution manual and checklist for the next agent
23
+ 6. `agent-executor`: choose one packet to execute right now
24
+ 7. `agent-batch-executor`: queue the first few packets, but still advance one packet at a time
25
+ 8. `agent-progress-tracker`: track which packet is done, which one is active, and what comes next
26
+ 9. `agent-status-board`: turn the execution state into a board view for PM and agents
27
+ 10. `agent-checkpoint`: freeze the current round into a continue / unblock / closeout decision
28
+ 11. `agent-decision-log`: preserve why each round continued, paused, or closed out
29
+ 12. `agent-retrospective`: explain multi-round patterns, lessons, and next-round advice
30
+ 13. `agent-playbook-pack`: compress retrospective, decision history, and handoff into one resume entrypoint
31
+ 14. `skills`: inspect the bundled skill package
32
+ 15. `onboard-url` / `onboard`: first look
33
+ 16. `scan`: raw signal check
34
+ 17. `audit` / `report`: diagnosis
35
+ 18. `fix-plan` / `owner-board`: execution planning
36
+ 19. `agent-handoff`: agent takeover package
37
+ 20. `apply-plan`: execution loop
38
+ 21. `completion-report`: closeout
39
+ 22. `handoff-bundle`: all-in-one package
40
+ 23. `share-pack`: audience-ready delivery
41
+ 24. `export-pack`: folder export
42
+ 25. `html-pack` / `publish-pack`: browsable and final delivery output
43
+ 26. `pm-brief` / `roadmap`: stakeholder alignment
43
44
 
44
45
  ## Recommended command order
45
46
 
@@ -47,6 +48,7 @@ If the user only has a website URL:
47
48
 
48
49
  ```bash
49
50
  npx geo-ai-search-optimization agent-orchestrator https://example.com
51
+ npx geo-ai-search-optimization agent-resume https://example.com
50
52
  npx geo-ai-search-optimization auto-flow https://example.com
51
53
  npx geo-ai-search-optimization agent-session https://example.com
52
54
  npx geo-ai-search-optimization agent-runbook https://example.com
@@ -67,6 +69,7 @@ If the user has the website codebase:
67
69
 
68
70
  ```bash
69
71
  npx geo-ai-search-optimization agent-orchestrator ./your-site
72
+ npx geo-ai-search-optimization agent-resume ./your-site
70
73
  npx geo-ai-search-optimization auto-flow ./your-site
71
74
  npx geo-ai-search-optimization agent-session ./your-site
72
75
  npx geo-ai-search-optimization agent-runbook ./your-site
@@ -96,6 +99,7 @@ npx geo-ai-search-optimization roadmap ./your-site
96
99
  ## When to recommend each command
97
100
 
98
101
  - `agent-orchestrator`: choose the one next GEO command to run now, plus expected artifact, stop conditions, and follow-up command
102
+ - `agent-resume`: resume from the latest reliable checkpoint, confirm what not to reset, and tell the next agent the one resume command to run
99
103
  - `auto-flow`: auto-select the next skill and command order from a task brief, URL, project path, or GEO artifact
100
104
  - `agent-session`: build a step-by-step session packet for the next agent from the same kinds of inputs
101
105
  - `agent-runbook`: build a checklist-driven runbook with preflight, validation, and reporting rules
@@ -132,6 +136,7 @@ When explaining the tool to a user:
132
136
 
133
137
  - prefer telling them which command to run next, not listing every command
134
138
  - if the user or next agent wants just one next command, move them to `agent-orchestrator`
139
+ - if the user or next agent needs to continue from the latest reliable checkpoint without restarting, move them to `agent-resume`
135
140
  - if the user or the next agent is unsure where to start, move them to `auto-flow` first
136
141
  - if the user wants something the next agent can follow step by step, move them to `agent-session`
137
142
  - if the user wants the next agent to follow a checklist and execution manual, move them to `agent-runbook`
@@ -0,0 +1,329 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { createAgentOrchestrator } from "./agent-orchestrator.js";
4
+ import { createAgentPlaybookPack } from "./agent-playbook-pack.js";
5
+ import { writeScanOutput } from "./scan.js";
6
+
7
+ const VALID_FORMATS = new Set(["markdown", "json"]);
8
+
9
+ function normalizeFormat(format) {
10
+ const resolved = (format || "markdown").toLowerCase();
11
+ if (!VALID_FORMATS.has(resolved)) {
12
+ throw new Error(`不支持的 agent-resume 格式:${format}。可选值:${Array.from(VALID_FORMATS).join(", ")}`);
13
+ }
14
+ return resolved;
15
+ }
16
+
17
+ async function pathExists(targetPath) {
18
+ try {
19
+ await fs.access(targetPath);
20
+ return true;
21
+ } catch {
22
+ return false;
23
+ }
24
+ }
25
+
26
+ async function tryReadExistingPlaybookPack(input) {
27
+ const resolvedPath = path.resolve(String(input));
28
+ if (!(await pathExists(resolvedPath)) || path.extname(resolvedPath).toLowerCase() !== ".json") {
29
+ return null;
30
+ }
31
+
32
+ try {
33
+ const parsed = JSON.parse(await fs.readFile(resolvedPath, "utf8"));
34
+ if (parsed.kind === "geo-agent-playbook-pack") {
35
+ return parsed;
36
+ }
37
+ if (parsed.kind === "geo-agent-resume" && parsed.playbookPack) {
38
+ return parsed.playbookPack;
39
+ }
40
+ } catch {
41
+ return null;
42
+ }
43
+
44
+ return null;
45
+ }
46
+
47
+ async function tryCreatePlaybookPack(input) {
48
+ const existing = await tryReadExistingPlaybookPack(input);
49
+ if (existing) {
50
+ return existing;
51
+ }
52
+ try {
53
+ return await createAgentPlaybookPack(input, { format: "json" });
54
+ } catch {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ function inferResumeMode(orchestrator, playbookPack) {
60
+ if (orchestrator.orchestration_mode === "needs-context") {
61
+ return "needs-context";
62
+ }
63
+ if (playbookPack?.playbookStatus === "closeout-ready") {
64
+ return "resume-closeout";
65
+ }
66
+ if (playbookPack?.playbookStatus === "unblock-first") {
67
+ return "resume-after-unblock";
68
+ }
69
+ if (playbookPack?.playbookStatus === "advice-ready") {
70
+ return "resume-advice";
71
+ }
72
+ if (playbookPack?.currentPacket) {
73
+ return "resume-current-packet";
74
+ }
75
+ return "resume-workflow";
76
+ }
77
+
78
+ function buildResumeFrom(orchestrator, playbookPack) {
79
+ if (playbookPack?.playbookStatus === "closeout-ready") {
80
+ return "从 closeout 阶段继续";
81
+ }
82
+ if (playbookPack?.playbookStatus === "unblock-first") {
83
+ return `先从解除阻塞继续,再回到 ${playbookPack.currentPacket?.id || "当前包"}`;
84
+ }
85
+ if (playbookPack?.currentPacket) {
86
+ return `从 ${playbookPack.currentPacket.id}|${playbookPack.currentPacket.title} 继续`;
87
+ }
88
+ if (orchestrator.next_command) {
89
+ return `从下一条命令继续:${orchestrator.next_command}`;
90
+ }
91
+ return "先补输入后再恢复";
92
+ }
93
+
94
+ function buildResumeSummary(orchestrator, playbookPack) {
95
+ if (orchestrator.orchestration_mode === "needs-context") {
96
+ return "当前还没有足够上下文恢复上一轮工作,先补网址、目录或 GEO 工件。";
97
+ }
98
+ if (playbookPack?.playbookStatus === "closeout-ready") {
99
+ return "当前已经进入或接近收尾,恢复时不要重新回到执行第一包。";
100
+ }
101
+ if (playbookPack?.playbookStatus === "unblock-first") {
102
+ return "当前恢复重点不是继续改动,而是先清掉重复阻塞项,再回到当前包。";
103
+ }
104
+ if (playbookPack?.currentPacket) {
105
+ return `当前最稳的恢复点是 ${playbookPack.currentPacket.id},不要把前面已经排好的链重新拆掉。`;
106
+ }
107
+ return orchestrator.why_now;
108
+ }
109
+
110
+ function shouldUnwrapResumeCommand(orchestrator) {
111
+ return /\bagent-resume\b/.test(orchestrator.next_command || "");
112
+ }
113
+
114
+ function buildResumeCommand(orchestrator, playbookPack) {
115
+ if (shouldUnwrapResumeCommand(orchestrator) && playbookPack?.startCommand) {
116
+ return playbookPack.startCommand;
117
+ }
118
+ return orchestrator.next_command;
119
+ }
120
+
121
+ function buildAfterResume(orchestrator, playbookPack, resumeCommand) {
122
+ if (shouldUnwrapResumeCommand(orchestrator) && Array.isArray(playbookPack?.followupCommands)) {
123
+ return playbookPack.followupCommands.find((command) => command && command !== resumeCommand) || orchestrator.after_that;
124
+ }
125
+ return orchestrator.after_that;
126
+ }
127
+
128
+ function inferExpectedArtifactFromCommand(command) {
129
+ const normalized = String(command || "").toLowerCase();
130
+
131
+ if (normalized.includes("completion-report")) {
132
+ return "复盘工件";
133
+ }
134
+ if (normalized.includes("agent-executor")) {
135
+ return "agent 单任务执行包";
136
+ }
137
+ if (normalized.includes("agent-batch-executor")) {
138
+ return "agent 多任务批次执行包";
139
+ }
140
+ if (normalized.includes("agent-runbook")) {
141
+ return "agent 执行手册";
142
+ }
143
+ if (normalized.includes("agent-status-board")) {
144
+ return "agent 执行状态看板";
145
+ }
146
+ if (normalized.includes("agent-progress-tracker")) {
147
+ return "agent 执行进度追踪工件";
148
+ }
149
+ if (normalized.includes("agent-decision-log")) {
150
+ return "agent 决策历史工件";
151
+ }
152
+ if (normalized.includes("fix-plan")) {
153
+ return "待办清单与优先级";
154
+ }
155
+ if (normalized.includes("audit")) {
156
+ return "GEO 审计结果";
157
+ }
158
+ if (normalized.includes("scan")) {
159
+ return "基础信号扫描结果";
160
+ }
161
+ return null;
162
+ }
163
+
164
+ function buildExpectedArtifact(orchestrator, playbookPack, resumeCommand) {
165
+ if (shouldUnwrapResumeCommand(orchestrator)) {
166
+ return inferExpectedArtifactFromCommand(resumeCommand) || playbookPack?.resumeSummary || "阶段性 GEO 输出";
167
+ }
168
+ return orchestrator.expected_artifact;
169
+ }
170
+
171
+ function buildVerifyBeforeResume(orchestrator, playbookPack) {
172
+ const items = [];
173
+
174
+ if (playbookPack) {
175
+ items.push(...playbookPack.readOrder.slice(0, 2));
176
+ if (playbookPack.currentPacket) {
177
+ items.push(`确认当前包仍然是 ${playbookPack.currentPacket.id},不要在恢复时改成别的包。`);
178
+ }
179
+ } else if (orchestrator.sourceType === "task-text") {
180
+ items.push("先确认是否已经有网址、目录或 JSON 工件,否则无法恢复上一轮。");
181
+ }
182
+
183
+ items.push(...orchestrator.stop_if);
184
+ return Array.from(new Set(items));
185
+ }
186
+
187
+ function buildDoNotReset(playbookPack) {
188
+ if (!playbookPack) {
189
+ return ["没有恢复工件时,不要假装已经知道上一轮做到哪里。"];
190
+ }
191
+
192
+ const items = ["不要从第一步重新跑整条链,除非当前工件已经明显过时。", ...playbookPack.avoidNowChecklist];
193
+ return Array.from(new Set(items));
194
+ }
195
+
196
+ function buildResumePrompt(resume) {
197
+ const lines = [
198
+ `Use $${resume.selectedSkill.name} to resume this GEO task without restarting the chain.`,
199
+ `当前输入:${resume.source}`,
200
+ `恢复模式:${resume.resume_mode}`,
201
+ `恢复点:${resume.resume_from}`,
202
+ `恢复摘要:${resume.resume_summary}`
203
+ ];
204
+
205
+ if (resume.resume_command) {
206
+ lines.push(`现在只恢复这一条命令:${resume.resume_command}`);
207
+ }
208
+ if (resume.expected_artifact) {
209
+ lines.push(`预期恢复产物:${resume.expected_artifact}`);
210
+ }
211
+ if (resume.after_resume) {
212
+ lines.push(`恢复后下一条:${resume.after_resume}`);
213
+ }
214
+ if (resume.verify_before_resume.length > 0) {
215
+ lines.push("恢复前先确认:");
216
+ for (const item of resume.verify_before_resume) {
217
+ lines.push(`- ${item}`);
218
+ }
219
+ }
220
+ if (resume.do_not_reset.length > 0) {
221
+ lines.push("恢复时不要做这些事:");
222
+ for (const item of resume.do_not_reset) {
223
+ lines.push(`- ${item}`);
224
+ }
225
+ }
226
+
227
+ lines.push("输出时先说明你是从哪里恢复的,再说明为什么不需要重新规划整条链。");
228
+ return lines.join("\n");
229
+ }
230
+
231
+ export async function createAgentResume(input, options = {}) {
232
+ const format = normalizeFormat(options.format);
233
+ const [orchestrator, playbookPack] = await Promise.all([
234
+ createAgentOrchestrator(input, { format: "json", intent: options.intent }),
235
+ tryCreatePlaybookPack(input)
236
+ ]);
237
+ const resumeCommand = buildResumeCommand(orchestrator, playbookPack);
238
+ const afterResume = buildAfterResume(orchestrator, playbookPack, resumeCommand);
239
+ const expectedArtifact = buildExpectedArtifact(orchestrator, playbookPack, resumeCommand);
240
+
241
+ const resume = {
242
+ kind: "geo-agent-resume",
243
+ input,
244
+ source: orchestrator.source,
245
+ sourceType: orchestrator.sourceType,
246
+ artifactKind: orchestrator.artifactKind,
247
+ format,
248
+ resume_mode: inferResumeMode(orchestrator, playbookPack),
249
+ resume_from: buildResumeFrom(orchestrator, playbookPack),
250
+ resume_summary: buildResumeSummary(orchestrator, playbookPack),
251
+ resume_command: resumeCommand,
252
+ expected_artifact: expectedArtifact,
253
+ verify_before_resume: buildVerifyBeforeResume(orchestrator, playbookPack),
254
+ do_not_reset: buildDoNotReset(playbookPack),
255
+ after_resume: afterResume,
256
+ selectedSkill: {
257
+ name: "geo-ai-search-optimization-agent-resume",
258
+ displayName: "GEO Agent Resume"
259
+ },
260
+ next_skill: orchestrator.next_skill || orchestrator.selectedSkill?.name || "geo-ai-search-optimization",
261
+ contextNeeded: orchestrator.session?.contextNeeded || [],
262
+ currentPacket: playbookPack?.currentPacket || null,
263
+ nextPacket: playbookPack?.nextPacket || null,
264
+ playbookStatus: playbookPack?.playbookStatus || null,
265
+ orchestrator,
266
+ playbookPack,
267
+ resume_prompt: ""
268
+ };
269
+
270
+ resume.resume_prompt = buildResumePrompt(resume);
271
+ return resume;
272
+ }
273
+
274
+ export function renderAgentResumeMarkdown(resume) {
275
+ const lines = [
276
+ "# GEO Agent Resume",
277
+ "",
278
+ `- 输入:\`${resume.source}\``,
279
+ `- 输入类型:\`${resume.sourceType}\``,
280
+ `- 工件类型:\`${resume.artifactKind}\``,
281
+ `- 恢复模式:\`${resume.resume_mode}\``,
282
+ `- 当前建议 skill:\`${resume.next_skill}\``,
283
+ "",
284
+ "## 从哪里恢复",
285
+ "",
286
+ `- ${resume.resume_from}`,
287
+ `- ${resume.resume_summary}`,
288
+ "",
289
+ "## 现在恢复这一条",
290
+ "",
291
+ `- 命令:\`${resume.resume_command || "先补输入"}\``,
292
+ `- 预期产物:${resume.expected_artifact || "先补输入再恢复"}`,
293
+ ""
294
+ ];
295
+
296
+ if (resume.currentPacket) {
297
+ lines.push("## 当前包", "", `- ${resume.currentPacket.id}|${resume.currentPacket.title}`, "");
298
+ }
299
+ if (resume.nextPacket) {
300
+ lines.push("## 下一包", "", `- ${resume.nextPacket.id}|${resume.nextPacket.title}`, "");
301
+ }
302
+ if (resume.after_resume) {
303
+ lines.push("## 恢复后下一条", "", `- \`${resume.after_resume}\``, "");
304
+ }
305
+
306
+ lines.push("## 恢复前先确认", "");
307
+ for (const item of resume.verify_before_resume) {
308
+ lines.push(`- ${item}`);
309
+ }
310
+
311
+ lines.push("", "## 恢复时不要重置", "");
312
+ for (const item of resume.do_not_reset) {
313
+ lines.push(`- ${item}`);
314
+ }
315
+
316
+ if (resume.contextNeeded.length > 0) {
317
+ lines.push("", "## 还缺什么", "");
318
+ for (const item of resume.contextNeeded) {
319
+ lines.push(`- ${item}`);
320
+ }
321
+ }
322
+
323
+ lines.push("", "## 可直接复制给 Agent 的 Resume Prompt", "", "```text", resume.resume_prompt, "```");
324
+ return `${lines.join("\n")}\n`;
325
+ }
326
+
327
+ export async function writeAgentResumeOutput(outputPath, content) {
328
+ return writeScanOutput(outputPath, content);
329
+ }
@@ -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-resume") {
50
+ return "geo-ai-search-optimization-agent-resume";
51
+ }
49
52
  if (commandName === "agent-runbook") {
50
53
  return "geo-ai-search-optimization-agent-runbook";
51
54
  }
@@ -114,6 +117,8 @@ function inferStepPurpose(commandName, flow) {
114
117
  return "先理解当前技能包结构,避免 agent 选错链路。";
115
118
  case "quick-start":
116
119
  return "快速建立从 0 到 1 的执行顺序。";
120
+ case "agent-resume":
121
+ return "从最近一个可靠恢复点继续,而不是把整条 GEO 链重新跑一遍。";
117
122
  case "onboard":
118
123
  case "onboard-url":
119
124
  return "先从网址或引导流程拿到首轮 GEO 判断。";
@@ -191,6 +196,8 @@ function inferExpectedArtifact(commandName) {
191
196
  return "阶段路线图";
192
197
  case "agent-handoff":
193
198
  return "agent 交接工件";
199
+ case "agent-resume":
200
+ return "agent 恢复入口工件";
194
201
  case "agent-runbook":
195
202
  return "agent 执行手册";
196
203
  case "agent-executor":
@@ -238,6 +245,9 @@ function buildStepInstructions(parsedCommand, flow) {
238
245
  if (parsedCommand.commandName === "publish-pack") {
239
246
  lines.push("完成后把 `START-HERE.md` 和 `AGENT-START.md` 当作最终入口。");
240
247
  }
248
+ if (parsedCommand.commandName === "agent-resume") {
249
+ lines.push("先确认恢复点、当前包和不要重置的内容,再继续执行。");
250
+ }
241
251
  if (parsedCommand.commandName === "apply-plan") {
242
252
  lines.push("执行包出来后,优先从第一包开始,不要同时展开太多任务。");
243
253
  }
package/src/auto-flow.js CHANGED
@@ -41,6 +41,9 @@ function detectArtifactKindFromParsedJson(parsed) {
41
41
  function inferTaskTextMode(text) {
42
42
  const normalized = String(text).toLowerCase();
43
43
 
44
+ if (/(agent-resume|resume|恢复继续|从中断处继续|接着上次继续|从最近恢复点继续)/i.test(normalized)) {
45
+ return "execute";
46
+ }
44
47
  if (/(share-pack|export-pack|html-pack|publish-pack|分享|导出|交付|外发|报告包)/i.test(normalized)) {
45
48
  return "share";
46
49
  }
@@ -171,6 +174,9 @@ function resolveEffectiveIntent(intent, detected) {
171
174
  if (detected.artifactKind === "geo-agent-playbook-pack") {
172
175
  return detected.parsed?.playbookStatus === "closeout-ready" ? "closeout" : "execute";
173
176
  }
177
+ if (detected.artifactKind === "geo-agent-resume") {
178
+ return detected.parsed?.resume_mode === "resume-closeout" ? "closeout" : "execute";
179
+ }
174
180
  if (
175
181
  [
176
182
  "geo-share-pack",
@@ -338,79 +344,79 @@ function buildCommandChain(detected, intent) {
338
344
  case "geo-agent-progress-tracker":
339
345
  return detected.parsed?.status === "completed"
340
346
  ? [
347
+ `geo-ai-search-optimization agent-resume ${source}`,
341
348
  `geo-ai-search-optimization completion-report ${source}`,
342
349
  `geo-ai-search-optimization handoff-bundle ${source}`,
343
350
  `geo-ai-search-optimization publish-pack ${source}`
344
351
  ]
345
352
  : detected.parsed?.currentTaskId
346
353
  ? [
347
- `geo-ai-search-optimization agent-executor ${source} --task ${detected.parsed.currentTaskId}`,
348
- `geo-ai-search-optimization completion-report ${source}`,
349
- `geo-ai-search-optimization handoff-bundle ${source}`
354
+ `geo-ai-search-optimization agent-resume ${source}`,
355
+ `geo-ai-search-optimization agent-progress-tracker ${source}`,
356
+ `geo-ai-search-optimization agent-decision-log ${source}`
350
357
  ]
351
358
  : [
359
+ `geo-ai-search-optimization agent-resume ${source}`,
352
360
  `geo-ai-search-optimization agent-batch-executor ${source}`,
353
- `geo-ai-search-optimization completion-report ${source}`,
354
- `geo-ai-search-optimization handoff-bundle ${source}`
361
+ `geo-ai-search-optimization agent-progress-tracker ${source}`
355
362
  ];
356
363
  case "geo-agent-status-board":
357
364
  return detected.parsed?.boardStatus === "completed"
358
365
  ? [
366
+ `geo-ai-search-optimization agent-resume ${source}`,
359
367
  `geo-ai-search-optimization completion-report ${source}`,
360
368
  `geo-ai-search-optimization handoff-bundle ${source}`,
361
369
  `geo-ai-search-optimization publish-pack ${source}`
362
370
  ]
363
371
  : detected.parsed?.tracker?.currentTaskId
364
372
  ? [
365
- `geo-ai-search-optimization agent-executor ${source} --task ${detected.parsed.tracker.currentTaskId}`,
373
+ `geo-ai-search-optimization agent-resume ${source}`,
366
374
  `geo-ai-search-optimization agent-progress-tracker ${source}`,
367
- `geo-ai-search-optimization completion-report ${source}`
375
+ `geo-ai-search-optimization agent-decision-log ${source}`
368
376
  ]
369
377
  : [
378
+ `geo-ai-search-optimization agent-resume ${source}`,
370
379
  `geo-ai-search-optimization agent-progress-tracker ${source}`,
371
- `geo-ai-search-optimization completion-report ${source}`,
372
- `geo-ai-search-optimization handoff-bundle ${source}`
380
+ `geo-ai-search-optimization agent-decision-log ${source}`
373
381
  ];
374
382
  case "geo-agent-checkpoint":
375
383
  return detected.parsed?.decision === "move-to-closeout"
376
384
  ? [
385
+ `geo-ai-search-optimization agent-resume ${source}`,
377
386
  `geo-ai-search-optimization completion-report ${source}`,
378
387
  `geo-ai-search-optimization handoff-bundle ${source}`,
379
388
  `geo-ai-search-optimization publish-pack ${source}`
380
389
  ]
381
390
  : detected.parsed?.decision === "resolve-blockers"
382
391
  ? [
383
- detected.parsed.suggestedNextCommand || `geo-ai-search-optimization agent-runbook ${source}`,
392
+ `geo-ai-search-optimization agent-resume ${source}`,
384
393
  `geo-ai-search-optimization agent-status-board ${source}`,
385
394
  `geo-ai-search-optimization agent-progress-tracker ${source}`
386
395
  ]
387
396
  : [
388
- detected.parsed?.suggestedNextCommand || `geo-ai-search-optimization agent-executor ${source}`,
397
+ `geo-ai-search-optimization agent-resume ${source}`,
389
398
  `geo-ai-search-optimization agent-progress-tracker ${source}`,
390
- `geo-ai-search-optimization completion-report ${source}`
399
+ `geo-ai-search-optimization agent-decision-log ${source}`
391
400
  ];
392
401
  case "geo-agent-decision-log": {
393
402
  const baseSource = detected.parsed?.latestCheckpoint?.source || detected.parsed?.source || source;
394
403
  const latestDecision = detected.parsed?.latestDecision;
395
- const suggestedNext =
396
- detected.parsed?.suggestedNextCommand ||
397
- detected.parsed?.latestCheckpoint?.suggestedNextCommand ||
398
- `geo-ai-search-optimization agent-executor ${baseSource}`;
399
404
 
400
405
  return latestDecision === "move-to-closeout"
401
406
  ? [
407
+ `geo-ai-search-optimization agent-resume ${source}`,
402
408
  `geo-ai-search-optimization completion-report ${baseSource}`,
403
409
  `geo-ai-search-optimization handoff-bundle ${baseSource}`,
404
410
  `geo-ai-search-optimization publish-pack ${baseSource}`
405
411
  ]
406
412
  : latestDecision === "resolve-blockers"
407
413
  ? [
408
- suggestedNext,
414
+ `geo-ai-search-optimization agent-resume ${source}`,
409
415
  `geo-ai-search-optimization agent-status-board ${source}`,
410
416
  `geo-ai-search-optimization agent-decision-log ${baseSource} --append-from ${source}`
411
417
  ]
412
418
  : [
413
- suggestedNext,
419
+ `geo-ai-search-optimization agent-resume ${source}`,
414
420
  `geo-ai-search-optimization agent-progress-tracker ${source}`,
415
421
  `geo-ai-search-optimization agent-decision-log ${baseSource} --append-from ${source}`
416
422
  ];
@@ -425,16 +431,21 @@ function buildCommandChain(detected, intent) {
425
431
  const baseSource = detected.parsed?.source || source;
426
432
  return detected.parsed?.playbookStatus === "closeout-ready"
427
433
  ? [
428
- detected.parsed?.startCommand || `geo-ai-search-optimization completion-report ${baseSource}`,
434
+ `geo-ai-search-optimization agent-resume ${source}`,
429
435
  `geo-ai-search-optimization meeting-pack ${baseSource}`,
430
436
  `geo-ai-search-optimization publish-pack ${baseSource}`
431
437
  ]
432
438
  : [
433
- detected.parsed?.startCommand || `geo-ai-search-optimization agent-executor ${baseSource}`,
439
+ `geo-ai-search-optimization agent-resume ${source}`,
434
440
  `geo-ai-search-optimization agent-status-board ${baseSource}`,
435
441
  `geo-ai-search-optimization agent-decision-log ${baseSource}`
436
442
  ];
437
443
  }
444
+ case "geo-agent-resume": {
445
+ const resumeCommand = detected.parsed?.resume_command;
446
+ const afterResume = detected.parsed?.after_resume;
447
+ return [resumeCommand, afterResume].filter(Boolean);
448
+ }
438
449
  case "geo-apply-plan":
439
450
  return [
440
451
  `geo-ai-search-optimization agent-executor ${source}`,
@@ -511,17 +522,14 @@ function pickSkillName(detected, intent) {
511
522
  case "geo-agent-batch-executor":
512
523
  return "geo-ai-search-optimization-agent-batch-executor";
513
524
  case "geo-agent-progress-tracker":
514
- return "geo-ai-search-optimization-agent-progress-tracker";
515
525
  case "geo-agent-status-board":
516
- return "geo-ai-search-optimization-agent-status-board";
517
526
  case "geo-agent-checkpoint":
518
- return "geo-ai-search-optimization-agent-checkpoint";
519
527
  case "geo-agent-decision-log":
520
- return "geo-ai-search-optimization-agent-decision-log";
528
+ case "geo-agent-playbook-pack":
529
+ case "geo-agent-resume":
530
+ return "geo-ai-search-optimization-agent-resume";
521
531
  case "geo-agent-retrospective":
522
532
  return "geo-ai-search-optimization-agent-retrospective";
523
- case "geo-agent-playbook-pack":
524
- return "geo-ai-search-optimization-agent-playbook-pack";
525
533
  case "geo-completion-report":
526
534
  return "geo-ai-search-optimization-completion-report";
527
535
  case "geo-handoff-bundle":
@@ -563,12 +571,14 @@ function buildSecondarySkillNames(primarySkill, intent, detected) {
563
571
  "geo-agent-status-board",
564
572
  "geo-agent-checkpoint",
565
573
  "geo-agent-decision-log",
574
+ "geo-agent-resume",
566
575
  "geo-agent-playbook-pack",
567
576
  "geo-apply-plan"
568
577
  ].includes(
569
578
  detected.artifactKind
570
579
  )
571
580
  ) {
581
+ names.add("geo-ai-search-optimization-agent-resume");
572
582
  names.add("geo-ai-search-optimization-agent-batch-executor");
573
583
  names.add("geo-ai-search-optimization-agent-progress-tracker");
574
584
  names.add("geo-ai-search-optimization-agent-status-board");
@@ -590,6 +600,9 @@ function buildSecondarySkillNames(primarySkill, intent, detected) {
590
600
  }
591
601
 
592
602
  function buildStage(intent, detected) {
603
+ if (detected.artifactKind === "geo-agent-resume") {
604
+ return "恢复继续";
605
+ }
593
606
  if (intent === "guide") {
594
607
  return "使用引导";
595
608
  }
@@ -610,6 +623,7 @@ function buildStage(intent, detected) {
610
623
  "geo-agent-status-board",
611
624
  "geo-agent-checkpoint",
612
625
  "geo-agent-decision-log",
626
+ "geo-agent-resume",
613
627
  "geo-agent-playbook-pack",
614
628
  "geo-agent-retrospective",
615
629
  "geo-apply-plan",
@@ -629,6 +643,7 @@ function buildStage(intent, detected) {
629
643
  "geo-agent-status-board",
630
644
  "geo-agent-checkpoint",
631
645
  "geo-agent-decision-log",
646
+ "geo-agent-resume",
632
647
  "geo-agent-playbook-pack",
633
648
  "geo-agent-retrospective",
634
649
  "geo-apply-plan",
@@ -717,14 +732,17 @@ function buildNextAction(detected, intent, commands) {
717
732
  return `先运行 \`${commands[0]}\` 生成适合外发或交接的结果。`;
718
733
  }
719
734
  if (intent === "execute") {
735
+ if (detected.artifactKind === "geo-agent-resume") {
736
+ return `先运行 \`${commands[0]}\`,从最近一个可靠恢复点继续,不要把整条 GEO 链重新跑一遍。`;
737
+ }
720
738
  if (detected.artifactKind === "geo-agent-progress-tracker") {
721
- return `先运行 \`${commands[0]}\`,继续当前执行包或校准下一包。`;
739
+ return `先运行 \`${commands[0]}\`,先确认最近一个可靠恢复点,再继续当前执行包。`;
722
740
  }
723
741
  if (detected.artifactKind === "geo-agent-decision-log") {
724
- return `先运行 \`${commands[0]}\`,沿着最近一次阶段决策继续推进,而不是重新判断整条链。`;
742
+ return `先运行 \`${commands[0]}\`,沿着最近一次阶段决策恢复,而不是重新判断整条链。`;
725
743
  }
726
744
  if (detected.artifactKind === "geo-agent-playbook-pack") {
727
- return `先运行 \`${commands[0]}\`,直接沿着 playbook 的起始命令继续,不要重新拆链。`;
745
+ return `先运行 \`${commands[0]}\`,直接从 playbook 对应的恢复点继续,不要重新拆链。`;
728
746
  }
729
747
  return `先运行 \`${commands[0]}\`,把当前输入推进到 agent 可执行状态。`;
730
748
  }
package/src/cli.js CHANGED
@@ -21,6 +21,7 @@ import {
21
21
  renderAgentOrchestratorMarkdown,
22
22
  writeAgentOrchestratorOutput
23
23
  } from "./agent-orchestrator.js";
24
+ import { createAgentResume, renderAgentResumeMarkdown, writeAgentResumeOutput } from "./agent-resume.js";
24
25
  import {
25
26
  createAgentPlaybookPack,
26
27
  renderAgentPlaybookPackMarkdown,
@@ -86,6 +87,7 @@ function printHelp() {
86
87
  " geo-ai-search-optimization",
87
88
  " geo-ai-search-optimization install [--target <dir>] [--json]",
88
89
  " geo-ai-search-optimization agent-orchestrator <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--format <markdown|json>] [--out <file>]",
90
+ " geo-ai-search-optimization agent-resume <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--format <markdown|json>] [--out <file>]",
89
91
  " geo-ai-search-optimization auto-flow <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--json] [--out <file>]",
90
92
  " geo-ai-search-optimization agent-session <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--json] [--out <file>]",
91
93
  " geo-ai-search-optimization agent-runbook <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--task <id>] [--format <markdown|json>] [--out <file>]",
@@ -215,6 +217,30 @@ async function handleAgentOrchestrator(args) {
215
217
  process.stdout.write(renderedOutput);
216
218
  }
217
219
 
220
+ async function handleAgentResume(args) {
221
+ const input = args.find((value) => !value.startsWith("-"));
222
+ if (!input) {
223
+ throw new Error("agent-resume 需要一个输入值,可以是任务描述、项目路径、网站网址或已导出的工件");
224
+ }
225
+
226
+ const format = getFlagValue(args, "--format") || (hasFlag(args, "--json") ? "json" : undefined);
227
+ const resume = await createAgentResume(input, {
228
+ intent: getFlagValue(args, "--intent"),
229
+ format
230
+ });
231
+ const outputJson = resume.format === "json";
232
+ const renderedOutput = outputJson ? `${JSON.stringify(resume, null, 2)}\n` : renderAgentResumeMarkdown(resume);
233
+
234
+ const outputPath = getFlagValue(args, "--out");
235
+ if (outputPath) {
236
+ const resolvedOutputPath = await writeAgentResumeOutput(outputPath, renderedOutput);
237
+ process.stdout.write(`已保存 agent-resume 结果:${resolvedOutputPath}\n`);
238
+ return;
239
+ }
240
+
241
+ process.stdout.write(renderedOutput);
242
+ }
243
+
218
244
  async function handleAgentSession(args) {
219
245
  const input = args.find((value) => !value.startsWith("-"));
220
246
  if (!input) {
@@ -1036,6 +1062,11 @@ export async function runCli(args = []) {
1036
1062
  return;
1037
1063
  }
1038
1064
 
1065
+ if (command === "agent-resume") {
1066
+ await handleAgentResume(rest);
1067
+ return;
1068
+ }
1069
+
1039
1070
  if (command === "agent-session") {
1040
1071
  await handleAgentSession(rest);
1041
1072
  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 { createAgentOrchestrator, renderAgentOrchestratorMarkdown, writeAgentOrchestratorOutput } from "./agent-orchestrator.js";
11
+ export { createAgentResume, renderAgentResumeMarkdown, writeAgentResumeOutput } from "./agent-resume.js";
11
12
  export { createAgentBatchExecutor, renderAgentBatchExecutorMarkdown, writeAgentBatchExecutorOutput } from "./agent-batch-executor.js";
12
13
  export { createAgentCheckpoint, renderAgentCheckpointMarkdown, writeAgentCheckpointOutput } from "./agent-checkpoint.js";
13
14
  export { createAgentDecisionLog, renderAgentDecisionLogMarkdown, writeAgentDecisionLogOutput } from "./agent-decision-log.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-orchestrator",
9
+ "geo-ai-search-optimization-agent-resume",
9
10
  "geo-ai-search-optimization-agent-session",
10
11
  "geo-ai-search-optimization-agent-runbook",
11
12
  "geo-ai-search-optimization-agent-executor",
@@ -31,6 +32,7 @@ const SKILL_CATEGORY = {
31
32
  "geo-ai-search-optimization": "core",
32
33
  "geo-ai-search-optimization-auto-flow": "routing",
33
34
  "geo-ai-search-optimization-agent-orchestrator": "routing",
35
+ "geo-ai-search-optimization-agent-resume": "routing",
34
36
  "geo-ai-search-optimization-agent-session": "routing",
35
37
  "geo-ai-search-optimization-agent-runbook": "execution",
36
38
  "geo-ai-search-optimization-agent-executor": "execution",
@@ -174,6 +176,7 @@ export function renderBundledSkillsMarkdown(bundle) {
174
176
  "",
175
177
  "- 先看核心 GEO skill。",
176
178
  "- 如果你只想让 agent 立刻知道现在唯一该跑哪条命令,先跑 agent-orchestrator。",
179
+ "- 如果工作中断后要从最近一个可靠恢复点继续,先跑 agent-resume。",
177
180
  "- 如果 agent 需要自动选 skill,先跑 auto-flow。",
178
181
  "- 如果要给 agent 明确步骤,继续进入 agent-session。",
179
182
  "- 如果要给 agent 一份执行手册和检查表,再进入 agent-runbook。",