geo-ai-search-optimization 1.2.10 → 1.2.11
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 +30 -0
- package/package.json +1 -1
- package/resources/geo-ai-search-optimization/references/skill-bundle-map.md +10 -0
- package/resources/geo-ai-search-optimization-agent-batch-executor/SKILL.md +24 -0
- package/resources/geo-ai-search-optimization-agent-batch-executor/agents/openai.yaml +4 -0
- package/resources/geo-ai-search-optimization-usage/SKILL.md +19 -14
- package/src/agent-batch-executor.js +327 -0
- package/src/agent-session.js +10 -0
- package/src/auto-flow.js +34 -1
- package/src/cli.js +39 -0
- package/src/index.js +1 -0
- package/src/skills.js +3 -0
package/README.md
CHANGED
|
@@ -124,6 +124,27 @@ geo-ai-search-optimization agent-executor ./reports/apply-plan.json --task fix-0
|
|
|
124
124
|
- 给用户的回报模板
|
|
125
125
|
- 可直接复制给 agent 的 executor prompt
|
|
126
126
|
|
|
127
|
+
## Agent Batch Executor 命令
|
|
128
|
+
|
|
129
|
+
如果你希望 agent 不只做 1 包,而是把前 2 到 3 包排成一个连续执行序列,同时仍然保持“一次只推进一包”,可以直接用 `agent-batch-executor`:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
geo-ai-search-optimization agent-batch-executor ./your-site
|
|
133
|
+
geo-ai-search-optimization agent-batch-executor ./reports/apply-plan.json
|
|
134
|
+
geo-ai-search-optimization agent-batch-executor ./reports/apply-plan.json --task fix-02 --count 3 --format json --out ./reports/agent-batch-executor.json
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`agent-batch-executor` 会输出:
|
|
138
|
+
|
|
139
|
+
- 当前批次先推进哪几包
|
|
140
|
+
- 为什么按这个顺序推进
|
|
141
|
+
- 每一包的 do-now checklist
|
|
142
|
+
- 每一包的 stop checklist
|
|
143
|
+
- 每一包的 success checklist
|
|
144
|
+
- 批次总验证命令
|
|
145
|
+
- 批次收尾命令
|
|
146
|
+
- 可直接复制给 agent 的 batch prompt
|
|
147
|
+
|
|
127
148
|
## Quick Start
|
|
128
149
|
|
|
129
150
|
如果你要从 0 到 1 启动一个 GEO 项目,建议照这个顺序做。
|
|
@@ -521,6 +542,7 @@ geo-ai-search-optimization auto-flow "audit this site and tell me the next skill
|
|
|
521
542
|
geo-ai-search-optimization agent-session ./your-site
|
|
522
543
|
geo-ai-search-optimization agent-runbook ./your-site
|
|
523
544
|
geo-ai-search-optimization agent-executor ./your-site
|
|
545
|
+
geo-ai-search-optimization agent-batch-executor ./your-site
|
|
524
546
|
geo-ai-search-optimization skills
|
|
525
547
|
geo-ai-search-optimization where
|
|
526
548
|
geo-ai-search-optimization doctor
|
|
@@ -591,6 +613,13 @@ geo-ai-search-optimization help
|
|
|
591
613
|
- 输出 do-now checklist、stop checklist、success checklist、验证命令和回报模板
|
|
592
614
|
- 新增 `geo-ai-search-optimization-agent-executor` skill
|
|
593
615
|
|
|
616
|
+
## New in 1.2.11
|
|
617
|
+
|
|
618
|
+
- 新增 `agent-batch-executor` 命令
|
|
619
|
+
- 让 agent 可以连续推进前几包任务,但仍然保持一次只执行一包
|
|
620
|
+
- 输出批次顺序、每包检查清单、批次总验证命令和收尾命令
|
|
621
|
+
- 新增 `geo-ai-search-optimization-agent-batch-executor` skill
|
|
622
|
+
|
|
594
623
|
## New in 1.2.5
|
|
595
624
|
|
|
596
625
|
- 新增 `publish-pack`
|
|
@@ -781,6 +810,7 @@ The installed package now includes a bundled GEO skill pack, including:
|
|
|
781
810
|
- `geo-ai-search-optimization-agent-session`
|
|
782
811
|
- `geo-ai-search-optimization-agent-runbook`
|
|
783
812
|
- `geo-ai-search-optimization-agent-executor`
|
|
813
|
+
- `geo-ai-search-optimization-agent-batch-executor`
|
|
784
814
|
- `geo-ai-search-optimization-usage`
|
|
785
815
|
- `geo-ai-search-optimization-agent-handoff`
|
|
786
816
|
- `geo-ai-search-optimization-repair-loop`
|
package/package.json
CHANGED
|
@@ -62,6 +62,16 @@ Best for:
|
|
|
62
62
|
- reducing a runbook into one actionable task
|
|
63
63
|
- giving the next agent a single-task prompt, validation commands, and reply template
|
|
64
64
|
|
|
65
|
+
### `geo-ai-search-optimization-agent-batch-executor`
|
|
66
|
+
|
|
67
|
+
Use this when the next agent should continuously advance the first few execution packets, but still only work on one packet at a time.
|
|
68
|
+
|
|
69
|
+
Best for:
|
|
70
|
+
|
|
71
|
+
- turning an `apply-plan` into a short execution queue
|
|
72
|
+
- making the next agent finish packet 1 before packet 2 starts
|
|
73
|
+
- giving the next agent a batch-level prompt, per-packet checklists, and final closeout commands
|
|
74
|
+
|
|
65
75
|
## Usage guide
|
|
66
76
|
|
|
67
77
|
### `geo-ai-search-optimization-usage`
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: geo-ai-search-optimization-agent-batch-executor
|
|
3
|
+
description: Turn a GEO input into a short multi-packet execution queue for the next agent. Use when an agent should continuously advance the first 2 to 3 GEO packets in order, while still executing only one packet at a time, with per-packet checklists, validation commands, and closeout steps.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GEO Agent Batch Executor
|
|
7
|
+
|
|
8
|
+
Use this skill when the next agent should not stop at one task, but also should not expand into an uncontrolled multi-task run.
|
|
9
|
+
|
|
10
|
+
`GEO = Generative Engine Optimization`
|
|
11
|
+
|
|
12
|
+
## What it does
|
|
13
|
+
|
|
14
|
+
- select the first few execution packets from an apply-plan or equivalent artifact
|
|
15
|
+
- keep the execution order explicit
|
|
16
|
+
- enforce one-packet-at-a-time progress
|
|
17
|
+
- provide per-packet do-now, stop, and success checklists
|
|
18
|
+
- give the next agent one batch prompt plus final closeout commands
|
|
19
|
+
|
|
20
|
+
## Best use
|
|
21
|
+
|
|
22
|
+
- when `agent-executor` is too narrow because the next agent should keep going after packet 1
|
|
23
|
+
- when a PM wants “finish the first 2 to 3 packets in order”
|
|
24
|
+
- when the next agent needs a short queue, not a full open-ended plan
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "GEO Agent Batch Executor"
|
|
3
|
+
short_description: "Queue the first GEO packets for one-by-one execution"
|
|
4
|
+
default_prompt: "Use $geo-ai-search-optimization-agent-batch-executor to choose the first 2 to 3 GEO packets to advance in order, while still executing only one packet at a time."
|
|
@@ -13,25 +13,26 @@ Treat this tool as a PM-friendly GEO workflow for websites.
|
|
|
13
13
|
|
|
14
14
|
`GEO = Generative Engine Optimization`
|
|
15
15
|
|
|
16
|
-
The package is best explained as
|
|
16
|
+
The package is best explained as eighteen 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
20
|
3. `agent-runbook`: execution manual and checklist for the next agent
|
|
21
21
|
4. `agent-executor`: choose one packet to execute right now
|
|
22
|
-
5. `
|
|
23
|
-
6. `
|
|
24
|
-
7. `
|
|
25
|
-
8. `
|
|
26
|
-
9. `
|
|
27
|
-
10. `
|
|
28
|
-
11. `
|
|
29
|
-
12. `
|
|
30
|
-
13. `
|
|
31
|
-
14. `
|
|
32
|
-
15. `
|
|
33
|
-
16. `
|
|
34
|
-
17. `
|
|
22
|
+
5. `agent-batch-executor`: queue the first few packets, but still advance one packet at a time
|
|
23
|
+
6. `skills`: inspect the bundled skill package
|
|
24
|
+
7. `onboard-url` / `onboard`: first look
|
|
25
|
+
8. `scan`: raw signal check
|
|
26
|
+
9. `audit` / `report`: diagnosis
|
|
27
|
+
10. `fix-plan` / `owner-board`: execution planning
|
|
28
|
+
11. `agent-handoff`: agent takeover package
|
|
29
|
+
12. `apply-plan`: execution loop
|
|
30
|
+
13. `completion-report`: closeout
|
|
31
|
+
14. `handoff-bundle`: all-in-one package
|
|
32
|
+
15. `share-pack`: audience-ready delivery
|
|
33
|
+
16. `export-pack`: folder export
|
|
34
|
+
17. `html-pack` / `publish-pack`: browsable and final delivery output
|
|
35
|
+
18. `pm-brief` / `roadmap`: stakeholder alignment
|
|
35
36
|
|
|
36
37
|
## Recommended command order
|
|
37
38
|
|
|
@@ -42,6 +43,7 @@ npx geo-ai-search-optimization auto-flow https://example.com
|
|
|
42
43
|
npx geo-ai-search-optimization agent-session https://example.com
|
|
43
44
|
npx geo-ai-search-optimization agent-runbook https://example.com
|
|
44
45
|
npx geo-ai-search-optimization agent-executor https://example.com
|
|
46
|
+
npx geo-ai-search-optimization agent-batch-executor https://example.com
|
|
45
47
|
npx geo-ai-search-optimization onboard-url https://example.com
|
|
46
48
|
npx geo-ai-search-optimization pm-brief https://example.com
|
|
47
49
|
npx geo-ai-search-optimization roadmap https://example.com
|
|
@@ -54,6 +56,7 @@ npx geo-ai-search-optimization auto-flow ./your-site
|
|
|
54
56
|
npx geo-ai-search-optimization agent-session ./your-site
|
|
55
57
|
npx geo-ai-search-optimization agent-runbook ./your-site
|
|
56
58
|
npx geo-ai-search-optimization agent-executor ./your-site
|
|
59
|
+
npx geo-ai-search-optimization agent-batch-executor ./your-site
|
|
57
60
|
npx geo-ai-search-optimization scan ./your-site
|
|
58
61
|
npx geo-ai-search-optimization audit ./your-site
|
|
59
62
|
npx geo-ai-search-optimization fix-plan ./your-site
|
|
@@ -75,6 +78,7 @@ npx geo-ai-search-optimization roadmap ./your-site
|
|
|
75
78
|
- `agent-session`: build a step-by-step session packet for the next agent from the same kinds of inputs
|
|
76
79
|
- `agent-runbook`: build a checklist-driven runbook with preflight, validation, and reporting rules
|
|
77
80
|
- `agent-executor`: select one packet to execute now and package it into a single-task entrypoint
|
|
81
|
+
- `agent-batch-executor`: line up the first few packets in execution order while preserving one-packet-at-a-time discipline
|
|
78
82
|
- `onboard-url`: first-time website check from a live URL
|
|
79
83
|
- `onboard`: interactive first-time onboarding
|
|
80
84
|
- `skills`: list the bundled skills and decide which skill or command chain fits the task
|
|
@@ -103,6 +107,7 @@ When explaining the tool to a user:
|
|
|
103
107
|
- if the user wants something the next agent can follow step by step, move them to `agent-session`
|
|
104
108
|
- if the user wants the next agent to follow a checklist and execution manual, move them to `agent-runbook`
|
|
105
109
|
- if the user wants the next agent to start one concrete task now, move them to `agent-executor`
|
|
110
|
+
- if the user wants the next agent to continuously advance the first 2 to 3 packets in order, move them to `agent-batch-executor`
|
|
106
111
|
- explain the result in PM language, not implementation jargon
|
|
107
112
|
- if the user sounds new, start with `onboard-url` or `quick-start`
|
|
108
113
|
- if the user wants another agent to take over, move them to `agent-handoff`
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { createApplyPlan } from "./apply-plan.js";
|
|
3
|
+
import { createAgentExecutor } from "./agent-executor.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-batch-executor 格式:${format}。可选值:${Array.from(VALID_FORMATS).join(", ")}`);
|
|
12
|
+
}
|
|
13
|
+
return resolved;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function normalizeCount(count) {
|
|
17
|
+
if (count == null) {
|
|
18
|
+
return 3;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const parsed = Number.parseInt(count, 10);
|
|
22
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
23
|
+
throw new Error("--count 必须是正整数");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return Math.min(parsed, 5);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function loadApplyPlanArtifact(input) {
|
|
30
|
+
const raw = await readFile(input, "utf8");
|
|
31
|
+
const parsed = JSON.parse(raw);
|
|
32
|
+
|
|
33
|
+
if (parsed?.kind === "geo-apply-plan") {
|
|
34
|
+
return parsed;
|
|
35
|
+
}
|
|
36
|
+
if (parsed?.kind === "geo-agent-runbook" && parsed.applyPlan?.kind === "geo-apply-plan") {
|
|
37
|
+
return parsed.applyPlan;
|
|
38
|
+
}
|
|
39
|
+
if (parsed?.kind === "geo-agent-executor" && parsed.applyPlan?.kind === "geo-apply-plan") {
|
|
40
|
+
return parsed.applyPlan;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function resolveApplyPlan(input) {
|
|
47
|
+
const artifact = await loadApplyPlanArtifact(input).catch(() => null);
|
|
48
|
+
if (artifact) {
|
|
49
|
+
return artifact;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return createApplyPlan(input, {
|
|
53
|
+
format: "json"
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function selectPackets(applyPlan, count, startTaskId) {
|
|
58
|
+
const packets = applyPlan?.packets || [];
|
|
59
|
+
if (packets.length === 0) {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let startIndex = 0;
|
|
64
|
+
if (startTaskId) {
|
|
65
|
+
startIndex = packets.findIndex((packet) => packet.id === startTaskId);
|
|
66
|
+
if (startIndex === -1) {
|
|
67
|
+
throw new Error(`找不到执行包:${startTaskId}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return packets.slice(startIndex, startIndex + count);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function buildPacketExecutors(input, packets, options) {
|
|
75
|
+
const results = [];
|
|
76
|
+
|
|
77
|
+
for (const packet of packets) {
|
|
78
|
+
const executor = await createAgentExecutor(input, {
|
|
79
|
+
format: "json",
|
|
80
|
+
intent: options.intent,
|
|
81
|
+
taskId: packet.id
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
results.push({
|
|
85
|
+
position: results.length + 1,
|
|
86
|
+
id: packet.id,
|
|
87
|
+
title: packet.title,
|
|
88
|
+
priority: packet.priority,
|
|
89
|
+
owner: packet.owner,
|
|
90
|
+
executorMode: executor.executorMode,
|
|
91
|
+
doNowChecklist: executor.doNowChecklist,
|
|
92
|
+
stopChecklist: executor.stopChecklist,
|
|
93
|
+
successChecklist: executor.successChecklist,
|
|
94
|
+
validationCommands: executor.validationCommands,
|
|
95
|
+
userReplyTemplate: executor.userReplyTemplate,
|
|
96
|
+
executorPrompt: executor.executorPrompt,
|
|
97
|
+
startCommand: `geo-ai-search-optimization agent-executor ${executor.source} --task ${packet.id}`,
|
|
98
|
+
nextCommands: executor.nextCommands
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return results;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function inferBatchMode(packetExecutors) {
|
|
106
|
+
if (packetExecutors.length === 0) {
|
|
107
|
+
return "needs-context";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const modes = new Set(packetExecutors.map((packet) => packet.executorMode));
|
|
111
|
+
if (modes.size === 1) {
|
|
112
|
+
return packetExecutors[0].executorMode;
|
|
113
|
+
}
|
|
114
|
+
return "mixed";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function buildSelectionReason(packets, applyPlan, count, startTaskId) {
|
|
118
|
+
if (packets.length === 0) {
|
|
119
|
+
return "当前还没有可批量执行的任务包,说明需要先补上下文或先生成 apply-plan。";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (startTaskId) {
|
|
123
|
+
return `已从指定任务 ${startTaskId} 开始,连续选出后续 ${packets.length} 包,按顺序推进。`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (packets.length === 1) {
|
|
127
|
+
return "当前只拿到 1 个任务包,因此直接把它作为本轮批处理入口。";
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const available = applyPlan?.packets?.length || packets.length;
|
|
131
|
+
if (available < count) {
|
|
132
|
+
return `计划最多取前 ${count} 包,但当前只有 ${available} 包可用,因此按现有顺序推进这 ${packets.length} 包。`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return `已按优先级选出前 ${packets.length} 包,按顺序推进,但一次只执行一包。`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function buildBatchRules(batchMode) {
|
|
139
|
+
const items = [
|
|
140
|
+
"始终一次只推进一包,不要同时展开多个修复包。",
|
|
141
|
+
"每做完一包,都先检查完成标准和验证命令,再决定是否进入下一包。",
|
|
142
|
+
"如果上一包没有通过验收,不要直接跳到下一包。"
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
if (batchMode === "direct-fix") {
|
|
146
|
+
items.push("每包都优先改复用层,而不是只 patch 单页。");
|
|
147
|
+
}
|
|
148
|
+
if (batchMode === "recommendation-only") {
|
|
149
|
+
items.push("当前更适合给建议,不要伪造已经完成的代码修改。");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return items;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function buildQueueSummary(packetExecutors) {
|
|
156
|
+
return packetExecutors.map((packet, index) => ({
|
|
157
|
+
position: index + 1,
|
|
158
|
+
id: packet.id,
|
|
159
|
+
title: packet.title,
|
|
160
|
+
priority: packet.priority,
|
|
161
|
+
owner: packet.owner,
|
|
162
|
+
startCommand: packet.startCommand,
|
|
163
|
+
stopIf: packet.stopChecklist[packet.stopChecklist.length - 1] || "当前包未达成完成标准时不要继续。",
|
|
164
|
+
afterSuccess:
|
|
165
|
+
index < packetExecutors.length - 1
|
|
166
|
+
? `进入下一包:${packetExecutors[index + 1].id}`
|
|
167
|
+
: "进入 completion-report 与 handoff-bundle 收尾。"
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function buildValidationRollup(packetExecutors) {
|
|
172
|
+
const commands = new Set();
|
|
173
|
+
for (const packet of packetExecutors) {
|
|
174
|
+
for (const command of packet.validationCommands) {
|
|
175
|
+
commands.add(command);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return Array.from(commands);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function buildFinalCommands(source) {
|
|
182
|
+
return [
|
|
183
|
+
`geo-ai-search-optimization completion-report ${source}`,
|
|
184
|
+
`geo-ai-search-optimization handoff-bundle ${source}`,
|
|
185
|
+
`geo-ai-search-optimization publish-pack ${source}`
|
|
186
|
+
];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function buildBatchPrompt(batch) {
|
|
190
|
+
const lines = [
|
|
191
|
+
"你现在进入 GEO 多任务批次执行模式。",
|
|
192
|
+
`当前输入:${batch.source}`,
|
|
193
|
+
`批次模式:${batch.batchMode}`,
|
|
194
|
+
`批次目标:${batch.goal}`,
|
|
195
|
+
`批次选择原因:${batch.selectionReason}`,
|
|
196
|
+
"请遵守:一次只推进一包,上一包通过验证后再进入下一包。"
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
if (batch.packetExecutors.length > 0) {
|
|
200
|
+
lines.push("当前批次顺序:");
|
|
201
|
+
for (const packet of batch.packetExecutors) {
|
|
202
|
+
lines.push(`${packet.position}. ${packet.id}|${packet.title}`);
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
lines.push("当前还没有可执行包。请先告诉用户缺什么上下文。");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
lines.push("每一包都要输出:先检查什么、怎么做、如何验证、完成后如何回报。");
|
|
209
|
+
return lines.join("\n");
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export async function createAgentBatchExecutor(input, options = {}) {
|
|
213
|
+
const format = normalizeFormat(options.format);
|
|
214
|
+
const count = normalizeCount(options.count);
|
|
215
|
+
const applyPlan = await resolveApplyPlan(input);
|
|
216
|
+
const selectedPackets = selectPackets(applyPlan, count, options.taskId);
|
|
217
|
+
const packetExecutors = await buildPacketExecutors(input, selectedPackets, options);
|
|
218
|
+
const batchMode = inferBatchMode(packetExecutors);
|
|
219
|
+
const source = packetExecutors[0]?.startCommand ? applyPlan.source || input : applyPlan?.source || input;
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
kind: "geo-agent-batch-executor",
|
|
223
|
+
input,
|
|
224
|
+
source,
|
|
225
|
+
sourceType: applyPlan?.sourceType || "unknown",
|
|
226
|
+
artifactKind: applyPlan?.kind || "unknown",
|
|
227
|
+
format,
|
|
228
|
+
batchMode,
|
|
229
|
+
packetCount: packetExecutors.length,
|
|
230
|
+
goal:
|
|
231
|
+
packetExecutors.length > 0
|
|
232
|
+
? `按顺序推进这 ${packetExecutors.length} 包,但每次只执行一包。`
|
|
233
|
+
: "当前先补上下文,再进入多任务批次执行。",
|
|
234
|
+
selectionReason: buildSelectionReason(selectedPackets, applyPlan, count, options.taskId),
|
|
235
|
+
batchRules: buildBatchRules(batchMode),
|
|
236
|
+
queueSummary: buildQueueSummary(packetExecutors),
|
|
237
|
+
packetExecutors,
|
|
238
|
+
validationRollup: buildValidationRollup(packetExecutors),
|
|
239
|
+
finalCommands: buildFinalCommands(source),
|
|
240
|
+
batchPrompt: buildBatchPrompt({
|
|
241
|
+
source,
|
|
242
|
+
batchMode,
|
|
243
|
+
goal:
|
|
244
|
+
packetExecutors.length > 0
|
|
245
|
+
? `按顺序推进这 ${packetExecutors.length} 包,但每次只执行一包。`
|
|
246
|
+
: "当前先补上下文,再进入多任务批次执行。",
|
|
247
|
+
selectionReason: buildSelectionReason(selectedPackets, applyPlan, count, options.taskId),
|
|
248
|
+
packetExecutors
|
|
249
|
+
}),
|
|
250
|
+
applyPlan
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function renderAgentBatchExecutorMarkdown(batch) {
|
|
255
|
+
const lines = [
|
|
256
|
+
"# GEO Agent Batch Executor",
|
|
257
|
+
"",
|
|
258
|
+
`- 输入:\`${batch.source}\``,
|
|
259
|
+
`- 来源类型:\`${batch.sourceType}\``,
|
|
260
|
+
`- 工件类型:\`${batch.artifactKind}\``,
|
|
261
|
+
`- 批次模式:\`${batch.batchMode}\``,
|
|
262
|
+
`- 批次数量:\`${batch.packetCount}\``,
|
|
263
|
+
`- 目标:${batch.goal}`,
|
|
264
|
+
`- 选择原因:${batch.selectionReason}`,
|
|
265
|
+
"",
|
|
266
|
+
"## 批次规则",
|
|
267
|
+
""
|
|
268
|
+
];
|
|
269
|
+
|
|
270
|
+
for (const item of batch.batchRules) {
|
|
271
|
+
lines.push(`- [ ] ${item}`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
lines.push("", "## 执行顺序", "");
|
|
275
|
+
for (const item of batch.queueSummary) {
|
|
276
|
+
lines.push(`### ${item.position}. ${item.id}|${item.title}`, "");
|
|
277
|
+
lines.push(`- 优先级:${item.priority}`);
|
|
278
|
+
lines.push(`- Owner:${item.owner}`);
|
|
279
|
+
lines.push(`- 开始命令:\`${item.startCommand}\``);
|
|
280
|
+
lines.push(`- 继续条件:${item.afterSuccess}`);
|
|
281
|
+
lines.push(`- 停下条件:${item.stopIf}`);
|
|
282
|
+
lines.push("");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
for (const packet of batch.packetExecutors) {
|
|
286
|
+
lines.push(`## ${packet.position}. ${packet.id}|${packet.title}`, "");
|
|
287
|
+
lines.push("- Do now:");
|
|
288
|
+
for (const item of packet.doNowChecklist) {
|
|
289
|
+
lines.push(` - [ ] ${item}`);
|
|
290
|
+
}
|
|
291
|
+
lines.push("- 停下条件:");
|
|
292
|
+
for (const item of packet.stopChecklist) {
|
|
293
|
+
lines.push(` - [ ] ${item}`);
|
|
294
|
+
}
|
|
295
|
+
lines.push("- 完成标准:");
|
|
296
|
+
for (const item of packet.successChecklist) {
|
|
297
|
+
lines.push(` - [ ] ${item}`);
|
|
298
|
+
}
|
|
299
|
+
lines.push("- 验证命令:");
|
|
300
|
+
for (const command of packet.validationCommands) {
|
|
301
|
+
lines.push(` - \`${command}\``);
|
|
302
|
+
}
|
|
303
|
+
lines.push("- 回报模板:");
|
|
304
|
+
lines.push("```text");
|
|
305
|
+
lines.push(packet.userReplyTemplate);
|
|
306
|
+
lines.push("```");
|
|
307
|
+
lines.push("");
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
lines.push("## 批次总验证命令", "");
|
|
311
|
+
for (const command of batch.validationRollup) {
|
|
312
|
+
lines.push(`- \`${command}\``);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
lines.push("", "## 最终收尾命令", "");
|
|
316
|
+
for (const command of batch.finalCommands) {
|
|
317
|
+
lines.push(`- \`${command}\``);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
lines.push("", "## 可直接复制给 Agent 的 Batch Prompt", "", "```text", batch.batchPrompt, "```");
|
|
321
|
+
|
|
322
|
+
return `${lines.join("\n")}\n`;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export async function writeAgentBatchExecutorOutput(outputPath, content) {
|
|
326
|
+
return writeScanOutput(outputPath, content);
|
|
327
|
+
}
|
package/src/agent-session.js
CHANGED
|
@@ -52,6 +52,9 @@ function inferSkillForCommand(commandName, flow) {
|
|
|
52
52
|
if (commandName === "agent-executor") {
|
|
53
53
|
return "geo-ai-search-optimization-agent-executor";
|
|
54
54
|
}
|
|
55
|
+
if (commandName === "agent-batch-executor") {
|
|
56
|
+
return "geo-ai-search-optimization-agent-batch-executor";
|
|
57
|
+
}
|
|
55
58
|
if (commandName === "skills" || commandName === "quick-start") {
|
|
56
59
|
return "geo-ai-search-optimization-usage";
|
|
57
60
|
}
|
|
@@ -116,6 +119,8 @@ function inferStepPurpose(commandName, flow) {
|
|
|
116
119
|
return "把当前链路整理成 agent 可照着执行的手册和检查表。";
|
|
117
120
|
case "agent-executor":
|
|
118
121
|
return "把这一轮先做哪一个任务包压成单任务执行入口。";
|
|
122
|
+
case "agent-batch-executor":
|
|
123
|
+
return "把前几包任务排成连续执行顺序,但保持一次只推进一包。";
|
|
119
124
|
case "apply-plan":
|
|
120
125
|
return "把交接结果推进到具体执行包。";
|
|
121
126
|
case "completion-report":
|
|
@@ -160,6 +165,8 @@ function inferExpectedArtifact(commandName) {
|
|
|
160
165
|
return "agent 执行手册";
|
|
161
166
|
case "agent-executor":
|
|
162
167
|
return "agent 单任务执行包";
|
|
168
|
+
case "agent-batch-executor":
|
|
169
|
+
return "agent 多任务批次执行包";
|
|
163
170
|
case "apply-plan":
|
|
164
171
|
return "执行包";
|
|
165
172
|
case "completion-report":
|
|
@@ -198,6 +205,9 @@ function buildStepInstructions(parsedCommand, flow) {
|
|
|
198
205
|
if (parsedCommand.commandName === "agent-executor") {
|
|
199
206
|
lines.push("这一轮只推进一包任务,不要把多个修复包混在同一次执行里。");
|
|
200
207
|
}
|
|
208
|
+
if (parsedCommand.commandName === "agent-batch-executor") {
|
|
209
|
+
lines.push("批次模式下也要一次只做一包,上一包通过验证后再进入下一包。");
|
|
210
|
+
}
|
|
201
211
|
if (parsedCommand.commandName === "agent-handoff" && flow.intent === "execute") {
|
|
202
212
|
lines.push("如果还是 advice-only,说明还缺仓库或本地项目上下文。");
|
|
203
213
|
}
|
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 (/(batch-executor|batch executor|多包|前3包|批次执行|连续推进前几包)/i.test(normalized)) {
|
|
48
|
+
return "execute";
|
|
49
|
+
}
|
|
47
50
|
if (/(executor|先做哪一个|先做哪一包|single task|执行第一包|先执行一个任务)/i.test(normalized)) {
|
|
48
51
|
return "execute";
|
|
49
52
|
}
|
|
@@ -62,6 +65,10 @@ function inferTaskTextMode(text) {
|
|
|
62
65
|
return "diagnose";
|
|
63
66
|
}
|
|
64
67
|
|
|
68
|
+
function taskTextWantsBatch(text) {
|
|
69
|
+
return /(batch-executor|batch executor|多包|前3包|前 3 包|批次执行|连续推进前几包|前几包)/i.test(String(text));
|
|
70
|
+
}
|
|
71
|
+
|
|
65
72
|
async function detectInput(input) {
|
|
66
73
|
if (!input) {
|
|
67
74
|
throw new Error("auto-flow 需要一个输入值,可以是任务描述、项目路径、网站网址或已导出的工件。");
|
|
@@ -157,6 +164,7 @@ function resolveEffectiveIntent(intent, detected) {
|
|
|
157
164
|
"geo-agent-handoff",
|
|
158
165
|
"geo-agent-runbook",
|
|
159
166
|
"geo-agent-executor",
|
|
167
|
+
"geo-agent-batch-executor",
|
|
160
168
|
"geo-apply-plan",
|
|
161
169
|
"geo-handoff-bundle",
|
|
162
170
|
"geo-fix-plan"
|
|
@@ -263,17 +271,20 @@ function buildCommandChain(detected, intent) {
|
|
|
263
271
|
return [
|
|
264
272
|
`geo-ai-search-optimization agent-runbook ${source}`,
|
|
265
273
|
`geo-ai-search-optimization agent-executor ${source}`,
|
|
274
|
+
`geo-ai-search-optimization agent-batch-executor ${source}`,
|
|
266
275
|
`geo-ai-search-optimization completion-report ${source}`
|
|
267
276
|
];
|
|
268
277
|
case "geo-agent-handoff":
|
|
269
278
|
return [
|
|
270
279
|
`geo-ai-search-optimization agent-runbook ${source}`,
|
|
271
280
|
`geo-ai-search-optimization agent-executor ${source}`,
|
|
281
|
+
`geo-ai-search-optimization agent-batch-executor ${source}`,
|
|
272
282
|
`geo-ai-search-optimization completion-report ${source}`
|
|
273
283
|
];
|
|
274
284
|
case "geo-agent-runbook":
|
|
275
285
|
return [
|
|
276
286
|
`geo-ai-search-optimization agent-executor ${source}`,
|
|
287
|
+
`geo-ai-search-optimization agent-batch-executor ${source}`,
|
|
277
288
|
`geo-ai-search-optimization completion-report ${source}`,
|
|
278
289
|
`geo-ai-search-optimization handoff-bundle ${source}`
|
|
279
290
|
];
|
|
@@ -283,9 +294,16 @@ function buildCommandChain(detected, intent) {
|
|
|
283
294
|
`geo-ai-search-optimization handoff-bundle ${source}`,
|
|
284
295
|
`geo-ai-search-optimization publish-pack ${source}`
|
|
285
296
|
];
|
|
297
|
+
case "geo-agent-batch-executor":
|
|
298
|
+
return [
|
|
299
|
+
`geo-ai-search-optimization completion-report ${source}`,
|
|
300
|
+
`geo-ai-search-optimization handoff-bundle ${source}`,
|
|
301
|
+
`geo-ai-search-optimization publish-pack ${source}`
|
|
302
|
+
];
|
|
286
303
|
case "geo-apply-plan":
|
|
287
304
|
return [
|
|
288
305
|
`geo-ai-search-optimization agent-executor ${source}`,
|
|
306
|
+
`geo-ai-search-optimization agent-batch-executor ${source}`,
|
|
289
307
|
`geo-ai-search-optimization completion-report ${source}`,
|
|
290
308
|
`geo-ai-search-optimization handoff-bundle ${source}`
|
|
291
309
|
];
|
|
@@ -333,6 +351,9 @@ function pickSkillName(detected, intent) {
|
|
|
333
351
|
|
|
334
352
|
switch (detected.artifactKind) {
|
|
335
353
|
case "task-brief":
|
|
354
|
+
if (detected.inferredTextIntent === "execute" && taskTextWantsBatch(detected.source)) {
|
|
355
|
+
return "geo-ai-search-optimization-agent-batch-executor";
|
|
356
|
+
}
|
|
336
357
|
return detected.inferredTextIntent === "share"
|
|
337
358
|
? "geo-ai-search-optimization-publish-pack"
|
|
338
359
|
: detected.inferredTextIntent === "execute"
|
|
@@ -351,6 +372,8 @@ function pickSkillName(detected, intent) {
|
|
|
351
372
|
case "geo-agent-executor":
|
|
352
373
|
case "geo-apply-plan":
|
|
353
374
|
return "geo-ai-search-optimization-agent-executor";
|
|
375
|
+
case "geo-agent-batch-executor":
|
|
376
|
+
return "geo-ai-search-optimization-agent-batch-executor";
|
|
354
377
|
case "geo-completion-report":
|
|
355
378
|
return "geo-ai-search-optimization-completion-report";
|
|
356
379
|
case "geo-handoff-bundle":
|
|
@@ -382,10 +405,18 @@ function buildSecondarySkillNames(primarySkill, intent, detected) {
|
|
|
382
405
|
}
|
|
383
406
|
if (
|
|
384
407
|
intent === "execute" ||
|
|
385
|
-
[
|
|
408
|
+
[
|
|
409
|
+
"geo-fix-plan",
|
|
410
|
+
"geo-agent-handoff",
|
|
411
|
+
"geo-agent-runbook",
|
|
412
|
+
"geo-agent-executor",
|
|
413
|
+
"geo-agent-batch-executor",
|
|
414
|
+
"geo-apply-plan"
|
|
415
|
+
].includes(
|
|
386
416
|
detected.artifactKind
|
|
387
417
|
)
|
|
388
418
|
) {
|
|
419
|
+
names.add("geo-ai-search-optimization-agent-batch-executor");
|
|
389
420
|
names.add("geo-ai-search-optimization-agent-executor");
|
|
390
421
|
names.add("geo-ai-search-optimization-agent-runbook");
|
|
391
422
|
names.add("geo-ai-search-optimization-agent-handoff");
|
|
@@ -415,6 +446,7 @@ function buildStage(intent, detected) {
|
|
|
415
446
|
"geo-agent-handoff",
|
|
416
447
|
"geo-agent-runbook",
|
|
417
448
|
"geo-agent-executor",
|
|
449
|
+
"geo-agent-batch-executor",
|
|
418
450
|
"geo-apply-plan",
|
|
419
451
|
"geo-handoff-bundle"
|
|
420
452
|
].includes(detected.artifactKind)
|
|
@@ -427,6 +459,7 @@ function buildStage(intent, detected) {
|
|
|
427
459
|
"geo-agent-handoff",
|
|
428
460
|
"geo-agent-runbook",
|
|
429
461
|
"geo-agent-executor",
|
|
462
|
+
"geo-agent-batch-executor",
|
|
430
463
|
"geo-apply-plan",
|
|
431
464
|
"geo-handoff-bundle"
|
|
432
465
|
].includes(detected.artifactKind)
|
package/src/cli.js
CHANGED
|
@@ -2,6 +2,11 @@ import { fileURLToPath } from "node:url";
|
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { createApplyPlan, renderApplyPlanMarkdown, writeApplyPlanOutput } from "./apply-plan.js";
|
|
5
|
+
import {
|
|
6
|
+
createAgentBatchExecutor,
|
|
7
|
+
renderAgentBatchExecutorMarkdown,
|
|
8
|
+
writeAgentBatchExecutorOutput
|
|
9
|
+
} from "./agent-batch-executor.js";
|
|
5
10
|
import { createAgentExecutor, renderAgentExecutorMarkdown, writeAgentExecutorOutput } from "./agent-executor.js";
|
|
6
11
|
import { createAgentHandoff, renderAgentHandoffMarkdown, writeAgentHandoffOutput } from "./agent-handoff.js";
|
|
7
12
|
import { createAgentRunbook, renderAgentRunbookMarkdown, writeAgentRunbookOutput } from "./agent-runbook.js";
|
|
@@ -65,6 +70,7 @@ function printHelp() {
|
|
|
65
70
|
" geo-ai-search-optimization agent-session <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--json] [--out <file>]",
|
|
66
71
|
" geo-ai-search-optimization agent-runbook <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--task <id>] [--format <markdown|json>] [--out <file>]",
|
|
67
72
|
" geo-ai-search-optimization agent-executor <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--task <id>] [--format <markdown|json>] [--out <file>]",
|
|
73
|
+
" geo-ai-search-optimization agent-batch-executor <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--task <id>] [--count <count>] [--format <markdown|json>] [--out <file>]",
|
|
68
74
|
" geo-ai-search-optimization skills [--json]",
|
|
69
75
|
" geo-ai-search-optimization where",
|
|
70
76
|
" geo-ai-search-optimization doctor [--json]",
|
|
@@ -235,6 +241,34 @@ async function handleAgentExecutor(args) {
|
|
|
235
241
|
process.stdout.write(renderedOutput);
|
|
236
242
|
}
|
|
237
243
|
|
|
244
|
+
async function handleAgentBatchExecutor(args) {
|
|
245
|
+
const input = args.find((value) => !value.startsWith("-"));
|
|
246
|
+
if (!input) {
|
|
247
|
+
throw new Error("agent-batch-executor 需要一个输入值,可以是任务描述、项目路径、网站网址或已导出的工件");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const format = getFlagValue(args, "--format") || (hasFlag(args, "--json") ? "json" : undefined);
|
|
251
|
+
const batch = await createAgentBatchExecutor(input, {
|
|
252
|
+
intent: getFlagValue(args, "--intent"),
|
|
253
|
+
format,
|
|
254
|
+
taskId: getFlagValue(args, "--task"),
|
|
255
|
+
count: getFlagValue(args, "--count")
|
|
256
|
+
});
|
|
257
|
+
const outputJson = batch.format === "json";
|
|
258
|
+
const renderedOutput = outputJson
|
|
259
|
+
? `${JSON.stringify(batch, null, 2)}\n`
|
|
260
|
+
: renderAgentBatchExecutorMarkdown(batch);
|
|
261
|
+
|
|
262
|
+
const outputPath = getFlagValue(args, "--out");
|
|
263
|
+
if (outputPath) {
|
|
264
|
+
const resolvedOutputPath = await writeAgentBatchExecutorOutput(outputPath, renderedOutput);
|
|
265
|
+
process.stdout.write(`已保存 agent batch executor:${resolvedOutputPath}\n`);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
process.stdout.write(renderedOutput);
|
|
270
|
+
}
|
|
271
|
+
|
|
238
272
|
function handleWhere() {
|
|
239
273
|
process.stdout.write(
|
|
240
274
|
[
|
|
@@ -795,6 +829,11 @@ export async function runCli(args = []) {
|
|
|
795
829
|
return;
|
|
796
830
|
}
|
|
797
831
|
|
|
832
|
+
if (command === "agent-batch-executor") {
|
|
833
|
+
await handleAgentBatchExecutor(rest);
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
|
|
798
837
|
if (command === "skills") {
|
|
799
838
|
await handleSkills(rest);
|
|
800
839
|
return;
|
package/src/index.js
CHANGED
|
@@ -7,6 +7,7 @@ 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 { createAgentBatchExecutor, renderAgentBatchExecutorMarkdown, writeAgentBatchExecutorOutput } from "./agent-batch-executor.js";
|
|
10
11
|
export { createAgentHandoff, renderAgentHandoffMarkdown, writeAgentHandoffOutput } from "./agent-handoff.js";
|
|
11
12
|
export { createAgentExecutor, renderAgentExecutorMarkdown, writeAgentExecutorOutput } from "./agent-executor.js";
|
|
12
13
|
export { createAgentRunbook, renderAgentRunbookMarkdown, writeAgentRunbookOutput } from "./agent-runbook.js";
|
package/src/skills.js
CHANGED
|
@@ -8,6 +8,7 @@ const SKILL_ORDER = [
|
|
|
8
8
|
"geo-ai-search-optimization-agent-session",
|
|
9
9
|
"geo-ai-search-optimization-agent-runbook",
|
|
10
10
|
"geo-ai-search-optimization-agent-executor",
|
|
11
|
+
"geo-ai-search-optimization-agent-batch-executor",
|
|
11
12
|
"geo-ai-search-optimization-usage",
|
|
12
13
|
"geo-ai-search-optimization-agent-handoff",
|
|
13
14
|
"geo-ai-search-optimization-repair-loop",
|
|
@@ -25,6 +26,7 @@ const SKILL_CATEGORY = {
|
|
|
25
26
|
"geo-ai-search-optimization-agent-session": "routing",
|
|
26
27
|
"geo-ai-search-optimization-agent-runbook": "execution",
|
|
27
28
|
"geo-ai-search-optimization-agent-executor": "execution",
|
|
29
|
+
"geo-ai-search-optimization-agent-batch-executor": "execution",
|
|
28
30
|
"geo-ai-search-optimization-usage": "guidance",
|
|
29
31
|
"geo-ai-search-optimization-agent-handoff": "execution",
|
|
30
32
|
"geo-ai-search-optimization-repair-loop": "execution",
|
|
@@ -161,6 +163,7 @@ export function renderBundledSkillsMarkdown(bundle) {
|
|
|
161
163
|
"- 如果要给 agent 明确步骤,继续进入 agent-session。",
|
|
162
164
|
"- 如果要给 agent 一份执行手册和检查表,再进入 agent-runbook。",
|
|
163
165
|
"- 如果要直接告诉 agent 这轮先做哪 1 包,再进入 agent-executor。",
|
|
166
|
+
"- 如果要连续推进前 2 到 3 包,但仍然一次只做一包,再进入 agent-batch-executor。",
|
|
164
167
|
"- 再看 usage skill,知道什么时候该跑哪个命令。",
|
|
165
168
|
"- 如果要交给 agent 执行,再进入 handoff / apply / completion 这一条执行链。",
|
|
166
169
|
"- 如果要产出给团队分发,再进入 share / export / html / publish 这一条交付链。",
|