geo-ai-search-optimization 1.2.17 → 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
@@ -42,6 +42,48 @@ geo-ai-search-optimization skills --json
42
42
  - agent 执行闭环相关 skills
43
43
  - 分享 / 导出 / 最终交付相关 skills
44
44
 
45
+ ## Agent Orchestrator 命令
46
+
47
+ 如果你希望 agent 不要看长链路,而是直接拿到“现在唯一该跑哪条命令”,可以直接用 `agent-orchestrator`:
48
+
49
+ ```bash
50
+ geo-ai-search-optimization agent-orchestrator "继续这个 GEO 任务"
51
+ geo-ai-search-optimization agent-orchestrator https://example.com
52
+ geo-ai-search-optimization agent-orchestrator ./your-site
53
+ geo-ai-search-optimization agent-orchestrator ./reports/agent-playbook-pack.json --format json --out ./reports/agent-orchestrator.json
54
+ ```
55
+
56
+ 它会输出:
57
+
58
+ - 当前阶段
59
+ - 为什么现在该做这一步
60
+ - 现在只该跑哪条命令
61
+ - 预期产物
62
+ - 什么时候先停下
63
+ - 做完之后下一条是什么
64
+ - 可直接复制给 agent 的 orchestrator prompt
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
+
45
87
  ## Auto Flow 命令
46
88
 
47
89
  如果你希望 agent 不用自己判断现在该用哪个 skill、该跑哪个命令,可以直接用 `auto-flow`:
@@ -660,6 +702,8 @@ geo-ai-search-optimization onboard --url https://example.com --json --out ./repo
660
702
  geo-ai-search-optimization
661
703
  geo-ai-search-optimization install
662
704
  geo-ai-search-optimization install --target ./tmp/custom-skills --json
705
+ geo-ai-search-optimization agent-orchestrator ./your-site
706
+ geo-ai-search-optimization agent-resume ./your-site
663
707
  geo-ai-search-optimization auto-flow "audit this site and tell me the next skill"
664
708
  geo-ai-search-optimization agent-session ./your-site
665
709
  geo-ai-search-optimization agent-runbook ./your-site
@@ -741,6 +785,22 @@ geo-ai-search-optimization help
741
785
  - 输出 do-now checklist、stop checklist、success checklist、验证命令和回报模板
742
786
  - 新增 `geo-ai-search-optimization-agent-executor` skill
743
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
+
796
+ ## New in 1.2.18
797
+
798
+ - 新增 `agent-orchestrator`
799
+ - 把 `auto-flow + agent-session` 收敛成一个“现在只该做哪条命令”的总入口
800
+ - 输出固定 contract:`current_stage`、`why_now`、`next_command`、`expected_artifact`、`stop_if`、`after_that`
801
+ - 更适合 PM 把任务直接交给 agent,或 agent 接着前一个工件继续做
802
+ - 新增 `geo-ai-search-optimization-agent-orchestrator` skill
803
+
744
804
  ## New in 1.2.17
745
805
 
746
806
  - 新增 `agent-playbook-pack`
@@ -978,6 +1038,8 @@ The installed package now includes a bundled GEO skill pack, including:
978
1038
 
979
1039
  - `geo-ai-search-optimization`
980
1040
  - `geo-ai-search-optimization-auto-flow`
1041
+ - `geo-ai-search-optimization-agent-orchestrator`
1042
+ - `geo-ai-search-optimization-agent-resume`
981
1043
  - `geo-ai-search-optimization-agent-session`
982
1044
  - `geo-ai-search-optimization-agent-runbook`
983
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.17",
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": {
@@ -32,6 +32,26 @@ Best for:
32
32
  - turning one-line task briefs into a concrete command sequence
33
33
  - deciding whether the work should move into diagnosis, execution, closeout, or delivery
34
34
 
35
+ ### `geo-ai-search-optimization-agent-orchestrator`
36
+
37
+ Use this when the next agent should get one immediate next command instead of reading a full command chain.
38
+
39
+ Best for:
40
+
41
+ - deciding the one command to run now
42
+ - returning a short contract with expected artifact, stop conditions, and follow-up command
43
+ - reducing ambiguity for PM-to-agent or agent-to-agent handoffs
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
+
35
55
  ### `geo-ai-search-optimization-agent-session`
36
56
 
37
57
  Use this when the next agent needs a runnable session plan, not just a routing answer.
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: geo-ai-search-optimization-agent-orchestrator
3
+ description: Choose the one next GEO command an agent should run right now. Use when an agent, PM, or another workflow has a GEO URL, codebase, task brief, or artifact and wants a single next command, expected artifact, stop conditions, and follow-up command instead of a full chain.
4
+ ---
5
+
6
+ # GEO Agent Orchestrator
7
+
8
+ Use this skill when the next agent should not browse a long command chain.
9
+
10
+ `GEO = Generative Engine Optimization`
11
+
12
+ ## What it does
13
+
14
+ - turns a GEO input into one immediate next command
15
+ - explains why this command should run now
16
+ - shows what artifact should come out of that command
17
+ - tells the next agent when to stop and what to run after that
18
+
19
+ ## Best use
20
+
21
+ - when PM wants the next agent to start without reading the whole GEO stack
22
+ - when another agent says "just tell me the next command"
23
+ - when GEO work should continue from a URL, codebase, playbook pack, decision log, or other GEO artifact with minimal ambiguity
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "GEO Agent Orchestrator"
3
+ short_description: "Choose the one next GEO command to run now"
4
+ default_prompt: "Use $geo-ai-search-optimization-agent-orchestrator to pick the one next GEO command to run now, explain why, define the expected artifact, and list stop conditions plus the follow-up command."
@@ -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,38 +13,42 @@ 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-four layers:
17
-
18
- 1. `auto-flow`: auto-select the next skill and command chain
19
- 2. `agent-session`: build a runnable session for the next agent
20
- 3. `agent-runbook`: execution manual and checklist for the next agent
21
- 4. `agent-executor`: choose one packet to execute right now
22
- 5. `agent-batch-executor`: queue the first few packets, but still advance one packet at a time
23
- 6. `agent-progress-tracker`: track which packet is done, which one is active, and what comes next
24
- 7. `agent-status-board`: turn the execution state into a board view for PM and agents
25
- 8. `agent-checkpoint`: freeze the current round into a continue / unblock / closeout decision
26
- 9. `agent-decision-log`: preserve why each round continued, paused, or closed out
27
- 10. `agent-retrospective`: explain multi-round patterns, lessons, and next-round advice
28
- 11. `agent-playbook-pack`: compress retrospective, decision history, and handoff into one resume entrypoint
29
- 12. `skills`: inspect the bundled skill package
30
- 13. `onboard-url` / `onboard`: first look
31
- 14. `scan`: raw signal check
32
- 15. `audit` / `report`: diagnosis
33
- 16. `fix-plan` / `owner-board`: execution planning
34
- 17. `agent-handoff`: agent takeover package
35
- 18. `apply-plan`: execution loop
36
- 19. `completion-report`: closeout
37
- 20. `handoff-bundle`: all-in-one package
38
- 21. `share-pack`: audience-ready delivery
39
- 22. `export-pack`: folder export
40
- 23. `html-pack` / `publish-pack`: browsable and final delivery output
41
- 24. `pm-brief` / `roadmap`: stakeholder alignment
16
+ The package is best explained as twenty-six layers:
17
+
18
+ 1. `agent-orchestrator`: choose the one next GEO command to run right now
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
42
44
 
43
45
  ## Recommended command order
44
46
 
45
47
  If the user only has a website URL:
46
48
 
47
49
  ```bash
50
+ npx geo-ai-search-optimization agent-orchestrator https://example.com
51
+ npx geo-ai-search-optimization agent-resume https://example.com
48
52
  npx geo-ai-search-optimization auto-flow https://example.com
49
53
  npx geo-ai-search-optimization agent-session https://example.com
50
54
  npx geo-ai-search-optimization agent-runbook https://example.com
@@ -64,6 +68,8 @@ npx geo-ai-search-optimization roadmap https://example.com
64
68
  If the user has the website codebase:
65
69
 
66
70
  ```bash
71
+ npx geo-ai-search-optimization agent-orchestrator ./your-site
72
+ npx geo-ai-search-optimization agent-resume ./your-site
67
73
  npx geo-ai-search-optimization auto-flow ./your-site
68
74
  npx geo-ai-search-optimization agent-session ./your-site
69
75
  npx geo-ai-search-optimization agent-runbook ./your-site
@@ -92,6 +98,8 @@ npx geo-ai-search-optimization roadmap ./your-site
92
98
 
93
99
  ## When to recommend each command
94
100
 
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
95
103
  - `auto-flow`: auto-select the next skill and command order from a task brief, URL, project path, or GEO artifact
96
104
  - `agent-session`: build a step-by-step session packet for the next agent from the same kinds of inputs
97
105
  - `agent-runbook`: build a checklist-driven runbook with preflight, validation, and reporting rules
@@ -127,6 +135,8 @@ npx geo-ai-search-optimization roadmap ./your-site
127
135
  When explaining the tool to a user:
128
136
 
129
137
  - prefer telling them which command to run next, not listing every command
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`
130
140
  - if the user or the next agent is unsure where to start, move them to `auto-flow` first
131
141
  - if the user wants something the next agent can follow step by step, move them to `agent-session`
132
142
  - if the user wants the next agent to follow a checklist and execution manual, move them to `agent-runbook`
@@ -0,0 +1,191 @@
1
+ import { createAgentSession } from "./agent-session.js";
2
+ import { writeScanOutput } from "./scan.js";
3
+
4
+ const VALID_FORMATS = new Set(["markdown", "json"]);
5
+
6
+ function normalizeFormat(format) {
7
+ const resolved = (format || "markdown").toLowerCase();
8
+ if (!VALID_FORMATS.has(resolved)) {
9
+ throw new Error(`不支持的 agent-orchestrator 格式:${format}。可选值:${Array.from(VALID_FORMATS).join(", ")}`);
10
+ }
11
+ return resolved;
12
+ }
13
+
14
+ function inferOrchestrationMode(session) {
15
+ if (session.status === "needs-context") {
16
+ return "needs-context";
17
+ }
18
+ if (session.intent === "share") {
19
+ return "delivery";
20
+ }
21
+ if (session.intent === "closeout") {
22
+ return "closeout";
23
+ }
24
+ if (session.intent === "execute") {
25
+ return "execution";
26
+ }
27
+ if (session.intent === "guide") {
28
+ return "guidance";
29
+ }
30
+ return "diagnosis";
31
+ }
32
+
33
+ function buildWhyNow(session, nextStep) {
34
+ if (!nextStep) {
35
+ return "当前还没有足够上下文来确定下一步命令,先补输入。";
36
+ }
37
+
38
+ if (session.artifactKind === "geo-agent-playbook-pack") {
39
+ return "当前已经有单入口 playbook,不应该重新规划整条链,直接沿着既有恢复点继续最稳。";
40
+ }
41
+ if (session.artifactKind === "geo-agent-decision-log") {
42
+ return "当前已经有跨轮决策历史,下一步应沿着最近一次决策继续,而不是重新做全量判断。";
43
+ }
44
+ if (session.artifactKind === "geo-agent-retrospective") {
45
+ return "当前已经有多轮复盘,下一步应该把复盘结论转成正式动作,而不是回到最前面的扫描阶段。";
46
+ }
47
+ if (session.sourceType === "url" && session.intent === "execute") {
48
+ return "当前只有公开网址,最重要的是先把建议型执行入口建立好,再决定是否需要仓库上下文。";
49
+ }
50
+
51
+ return `${session.whyThisSkill} 当前最该先跑的是 ${nextStep.commandName},因为它会直接产出下一阶段需要的关键工件。`;
52
+ }
53
+
54
+ function buildStopIf(session, nextStep) {
55
+ const items = [...session.contextNeeded];
56
+
57
+ if (session.sourceType === "url" && session.intent === "execute") {
58
+ items.push("只有网址时,不要宣称已经完成代码级修复。");
59
+ }
60
+ if (session.artifactKind === "geo-agent-playbook-pack") {
61
+ items.push("不要绕开 playbook 重新拆一条新链,除非当前 playbook 已明显过时。");
62
+ }
63
+ if (nextStep?.commandName === "agent-executor") {
64
+ items.push("不要同时展开多个任务包;这一轮先推进当前单包。");
65
+ }
66
+ if (nextStep?.commandName === "completion-report") {
67
+ items.push("如果这一轮还没有完成或没有明确验证结果,不要过早进入 closeout。");
68
+ }
69
+ if (nextStep?.commandName === "publish-pack") {
70
+ items.push("如果前面的 completion-report 或 share 结果还不完整,不要直接产出最终交付包。");
71
+ }
72
+
73
+ return Array.from(new Set(items));
74
+ }
75
+
76
+ function buildAfterThat(session) {
77
+ return session.steps[1]?.command || null;
78
+ }
79
+
80
+ function buildOrchestratorPrompt(orchestrator) {
81
+ const lines = [
82
+ `Use $${orchestrator.selectedSkill.name} to continue this GEO task.`,
83
+ `当前输入:${orchestrator.source}`,
84
+ `当前阶段:${orchestrator.current_stage}`,
85
+ `当前模式:${orchestrator.orchestration_mode}`,
86
+ `为什么现在做这一步:${orchestrator.why_now}`
87
+ ];
88
+
89
+ if (orchestrator.next_command) {
90
+ lines.push(`现在只运行这一条命令:${orchestrator.next_command}`);
91
+ }
92
+ if (orchestrator.expected_artifact) {
93
+ lines.push(`预期产物:${orchestrator.expected_artifact}`);
94
+ }
95
+ if (orchestrator.after_that) {
96
+ lines.push(`完成后下一条:${orchestrator.after_that}`);
97
+ }
98
+ if (orchestrator.stop_if.length > 0) {
99
+ lines.push("出现以下情况就先停下:");
100
+ for (const item of orchestrator.stop_if) {
101
+ lines.push(`- ${item}`);
102
+ }
103
+ }
104
+
105
+ lines.push("输出时先说明为什么执行这一步,再说明得到什么,以及之后怎么继续。");
106
+ return lines.join("\n");
107
+ }
108
+
109
+ export async function createAgentOrchestrator(input, options = {}) {
110
+ const format = normalizeFormat(options.format);
111
+ const session = await createAgentSession(input, {
112
+ intent: options.intent
113
+ });
114
+ const nextStep = session.steps[0] || null;
115
+
116
+ const orchestrator = {
117
+ kind: "geo-agent-orchestrator",
118
+ input,
119
+ source: session.source,
120
+ sourceType: session.sourceType,
121
+ artifactKind: session.artifactKind,
122
+ format,
123
+ orchestration_mode: inferOrchestrationMode(session),
124
+ current_stage: session.stage,
125
+ why_now: buildWhyNow(session, nextStep),
126
+ next_command: nextStep?.command || null,
127
+ expected_artifact: nextStep?.expectedArtifact || null,
128
+ stop_if: buildStopIf(session, nextStep),
129
+ after_that: buildAfterThat(session),
130
+ selectedSkill: session.selectedSkill,
131
+ next_skill: nextStep?.suggestedSkill || session.selectedSkill.name,
132
+ session_status: session.status,
133
+ next_action: session.nextAction,
134
+ session,
135
+ orchestrator_prompt: ""
136
+ };
137
+
138
+ orchestrator.orchestrator_prompt = buildOrchestratorPrompt(orchestrator);
139
+ return orchestrator;
140
+ }
141
+
142
+ export function renderAgentOrchestratorMarkdown(orchestrator) {
143
+ const lines = [
144
+ "# GEO Agent Orchestrator",
145
+ "",
146
+ `- 输入:\`${orchestrator.source}\``,
147
+ `- 输入类型:\`${orchestrator.sourceType}\``,
148
+ `- 工件类型:\`${orchestrator.artifactKind}\``,
149
+ `- 当前阶段:${orchestrator.current_stage}`,
150
+ `- orchestration mode:\`${orchestrator.orchestration_mode}\``,
151
+ `- 当前建议 skill:\`${orchestrator.next_skill}\``,
152
+ "",
153
+ "## 为什么现在做这一步",
154
+ "",
155
+ `- ${orchestrator.why_now}`,
156
+ "",
157
+ "## 现在只做这一条",
158
+ "",
159
+ `- 命令:\`${orchestrator.next_command || "先补输入"}\``,
160
+ `- 预期产物:${orchestrator.expected_artifact || "先明确需要什么上下文"}`,
161
+ ""
162
+ ];
163
+
164
+ if (orchestrator.after_that) {
165
+ lines.push("## 做完之后", "", `- 下一条:\`${orchestrator.after_that}\``, "");
166
+ }
167
+
168
+ lines.push("## 什么时候先停下", "");
169
+ if (orchestrator.stop_if.length === 0) {
170
+ lines.push("- 当前没有额外 stop 条件。");
171
+ } else {
172
+ for (const item of orchestrator.stop_if) {
173
+ lines.push(`- ${item}`);
174
+ }
175
+ }
176
+
177
+ lines.push(
178
+ "",
179
+ "## 可直接复制给 Agent 的 Orchestrator Prompt",
180
+ "",
181
+ "```text",
182
+ orchestrator.orchestrator_prompt,
183
+ "```"
184
+ );
185
+
186
+ return `${lines.join("\n")}\n`;
187
+ }
188
+
189
+ export async function writeAgentOrchestratorOutput(outputPath, content) {
190
+ return writeScanOutput(outputPath, content);
191
+ }
@@ -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
@@ -16,6 +16,12 @@ import {
16
16
  } from "./agent-progress-tracker.js";
17
17
  import { createAgentCheckpoint, renderAgentCheckpointMarkdown, writeAgentCheckpointOutput } from "./agent-checkpoint.js";
18
18
  import { createAgentDecisionLog, renderAgentDecisionLogMarkdown, writeAgentDecisionLogOutput } from "./agent-decision-log.js";
19
+ import {
20
+ createAgentOrchestrator,
21
+ renderAgentOrchestratorMarkdown,
22
+ writeAgentOrchestratorOutput
23
+ } from "./agent-orchestrator.js";
24
+ import { createAgentResume, renderAgentResumeMarkdown, writeAgentResumeOutput } from "./agent-resume.js";
19
25
  import {
20
26
  createAgentPlaybookPack,
21
27
  renderAgentPlaybookPackMarkdown,
@@ -80,6 +86,8 @@ function printHelp() {
80
86
  "Usage:",
81
87
  " geo-ai-search-optimization",
82
88
  " geo-ai-search-optimization install [--target <dir>] [--json]",
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>]",
83
91
  " geo-ai-search-optimization auto-flow <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--json] [--out <file>]",
84
92
  " geo-ai-search-optimization agent-session <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--json] [--out <file>]",
85
93
  " geo-ai-search-optimization agent-runbook <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--task <id>] [--format <markdown|json>] [--out <file>]",
@@ -183,6 +191,56 @@ async function handleAutoFlow(args) {
183
191
  process.stdout.write(renderedOutput);
184
192
  }
185
193
 
194
+ async function handleAgentOrchestrator(args) {
195
+ const input = args.find((value) => !value.startsWith("-"));
196
+ if (!input) {
197
+ throw new Error("agent-orchestrator 需要一个输入值,可以是任务描述、项目路径、网站网址或已导出的工件");
198
+ }
199
+
200
+ const format = getFlagValue(args, "--format") || (hasFlag(args, "--json") ? "json" : undefined);
201
+ const orchestrator = await createAgentOrchestrator(input, {
202
+ intent: getFlagValue(args, "--intent"),
203
+ format
204
+ });
205
+ const outputJson = orchestrator.format === "json";
206
+ const renderedOutput = outputJson
207
+ ? `${JSON.stringify(orchestrator, null, 2)}\n`
208
+ : renderAgentOrchestratorMarkdown(orchestrator);
209
+
210
+ const outputPath = getFlagValue(args, "--out");
211
+ if (outputPath) {
212
+ const resolvedOutputPath = await writeAgentOrchestratorOutput(outputPath, renderedOutput);
213
+ process.stdout.write(`已保存 agent-orchestrator 结果:${resolvedOutputPath}\n`);
214
+ return;
215
+ }
216
+
217
+ process.stdout.write(renderedOutput);
218
+ }
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
+
186
244
  async function handleAgentSession(args) {
187
245
  const input = args.find((value) => !value.startsWith("-"));
188
246
  if (!input) {
@@ -999,6 +1057,16 @@ export async function runCli(args = []) {
999
1057
  return;
1000
1058
  }
1001
1059
 
1060
+ if (command === "agent-orchestrator") {
1061
+ await handleAgentOrchestrator(rest);
1062
+ return;
1063
+ }
1064
+
1065
+ if (command === "agent-resume") {
1066
+ await handleAgentResume(rest);
1067
+ return;
1068
+ }
1069
+
1002
1070
  if (command === "agent-session") {
1003
1071
  await handleAgentSession(rest);
1004
1072
  return;
package/src/index.js CHANGED
@@ -7,6 +7,8 @@ export {
7
7
  } from "./interactive-onboarding.js";
8
8
  export { createAutoFlow, renderAutoFlowMarkdown, writeAutoFlowOutput } from "./auto-flow.js";
9
9
  export { createApplyPlan, renderApplyPlanMarkdown, writeApplyPlanOutput } from "./apply-plan.js";
10
+ export { createAgentOrchestrator, renderAgentOrchestratorMarkdown, writeAgentOrchestratorOutput } from "./agent-orchestrator.js";
11
+ export { createAgentResume, renderAgentResumeMarkdown, writeAgentResumeOutput } from "./agent-resume.js";
10
12
  export { createAgentBatchExecutor, renderAgentBatchExecutorMarkdown, writeAgentBatchExecutorOutput } from "./agent-batch-executor.js";
11
13
  export { createAgentCheckpoint, renderAgentCheckpointMarkdown, writeAgentCheckpointOutput } from "./agent-checkpoint.js";
12
14
  export { createAgentDecisionLog, renderAgentDecisionLogMarkdown, writeAgentDecisionLogOutput } from "./agent-decision-log.js";
package/src/skills.js CHANGED
@@ -5,6 +5,8 @@ import { getPackageRoot } from "./paths.js";
5
5
  const SKILL_ORDER = [
6
6
  "geo-ai-search-optimization",
7
7
  "geo-ai-search-optimization-auto-flow",
8
+ "geo-ai-search-optimization-agent-orchestrator",
9
+ "geo-ai-search-optimization-agent-resume",
8
10
  "geo-ai-search-optimization-agent-session",
9
11
  "geo-ai-search-optimization-agent-runbook",
10
12
  "geo-ai-search-optimization-agent-executor",
@@ -29,6 +31,8 @@ const SKILL_ORDER = [
29
31
  const SKILL_CATEGORY = {
30
32
  "geo-ai-search-optimization": "core",
31
33
  "geo-ai-search-optimization-auto-flow": "routing",
34
+ "geo-ai-search-optimization-agent-orchestrator": "routing",
35
+ "geo-ai-search-optimization-agent-resume": "routing",
32
36
  "geo-ai-search-optimization-agent-session": "routing",
33
37
  "geo-ai-search-optimization-agent-runbook": "execution",
34
38
  "geo-ai-search-optimization-agent-executor": "execution",
@@ -171,6 +175,8 @@ export function renderBundledSkillsMarkdown(bundle) {
171
175
  "## 推荐理解顺序",
172
176
  "",
173
177
  "- 先看核心 GEO skill。",
178
+ "- 如果你只想让 agent 立刻知道现在唯一该跑哪条命令,先跑 agent-orchestrator。",
179
+ "- 如果工作中断后要从最近一个可靠恢复点继续,先跑 agent-resume。",
174
180
  "- 如果 agent 需要自动选 skill,先跑 auto-flow。",
175
181
  "- 如果要给 agent 明确步骤,继续进入 agent-session。",
176
182
  "- 如果要给 agent 一份执行手册和检查表,再进入 agent-runbook。",