geo-ai-search-optimization 1.2.13 → 1.2.14

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
@@ -186,6 +186,27 @@ geo-ai-search-optimization agent-status-board ./reports/agent-progress-tracker.j
186
186
  - 建议下一步命令
187
187
  - 可直接复制给 agent 的 status board prompt
188
188
 
189
+ ## Agent Checkpoint 命令
190
+
191
+ 如果你希望在每一轮执行结束时,产出一个明确的阶段决策,而不只是状态展示,可以直接用 `agent-checkpoint`:
192
+
193
+ ```bash
194
+ geo-ai-search-optimization agent-checkpoint ./your-site
195
+ geo-ai-search-optimization agent-checkpoint ./reports/agent-status-board.json --completed fix-01 --current fix-02
196
+ geo-ai-search-optimization agent-checkpoint ./reports/agent-progress-tracker.json --blocked "缺少仓库权限" --format json --out ./reports/agent-checkpoint.json
197
+ ```
198
+
199
+ `agent-checkpoint` 会输出:
200
+
201
+ - 当前检查点类型
202
+ - 当前决策是继续、解除阻塞还是进入收尾
203
+ - gate checks
204
+ - 决策清单
205
+ - 建议下一步命令
206
+ - 备选命令
207
+ - 交接说明
208
+ - 可直接复制给 agent 的 checkpoint prompt
209
+
189
210
  ## Quick Start
190
211
 
191
212
  如果你要从 0 到 1 启动一个 GEO 项目,建议照这个顺序做。
@@ -586,6 +607,7 @@ geo-ai-search-optimization agent-executor ./your-site
586
607
  geo-ai-search-optimization agent-batch-executor ./your-site
587
608
  geo-ai-search-optimization agent-progress-tracker ./your-site
588
609
  geo-ai-search-optimization agent-status-board ./your-site
610
+ geo-ai-search-optimization agent-checkpoint ./your-site
589
611
  geo-ai-search-optimization skills
590
612
  geo-ai-search-optimization where
591
613
  geo-ai-search-optimization doctor
@@ -656,6 +678,13 @@ geo-ai-search-optimization help
656
678
  - 输出 do-now checklist、stop checklist、success checklist、验证命令和回报模板
657
679
  - 新增 `geo-ai-search-optimization-agent-executor` skill
658
680
 
681
+ ## New in 1.2.14
682
+
683
+ - 新增 `agent-checkpoint` 命令
684
+ - 把每一轮执行状态压成 continue / unblock / closeout 的阶段决策工件
685
+ - 支持从 `agent-progress-tracker`、`agent-status-board`、`apply-plan` 等工件继续生成检查点
686
+ - 新增 `geo-ai-search-optimization-agent-checkpoint` skill
687
+
659
688
  ## New in 1.2.13
660
689
 
661
690
  - 新增 `agent-status-board` 命令
@@ -870,6 +899,7 @@ The installed package now includes a bundled GEO skill pack, including:
870
899
  - `geo-ai-search-optimization-agent-batch-executor`
871
900
  - `geo-ai-search-optimization-agent-progress-tracker`
872
901
  - `geo-ai-search-optimization-agent-status-board`
902
+ - `geo-ai-search-optimization-agent-checkpoint`
873
903
  - `geo-ai-search-optimization-usage`
874
904
  - `geo-ai-search-optimization-agent-handoff`
875
905
  - `geo-ai-search-optimization-repair-loop`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geo-ai-search-optimization",
3
- "version": "1.2.13",
3
+ "version": "1.2.14",
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": {
@@ -92,6 +92,16 @@ Best for:
92
92
  - showing done, in-progress, blocked, next, and queued packets in one artifact
93
93
  - turning progress tracking into a more shareable coordination output
94
94
 
95
+ ### `geo-ai-search-optimization-agent-checkpoint`
96
+
97
+ Use this when the next agent should make a stage decision, not just show the current state.
98
+
99
+ Best for:
100
+
101
+ - deciding whether the round should continue, unblock, or close out
102
+ - producing a clean handoff note at the end of one execution round
103
+ - giving PM and the next agent one checkpoint artifact to align on
104
+
95
105
  ## Usage guide
96
106
 
97
107
  ### `geo-ai-search-optimization-usage`
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: geo-ai-search-optimization-agent-checkpoint
3
+ description: Turn GEO execution state into a stage checkpoint decision. Use when an agent should decide whether the current round should continue, first resolve blockers, or move into closeout, based on progress trackers, status boards, apply-plan artifacts, or related execution outputs.
4
+ ---
5
+
6
+ # GEO Agent Checkpoint
7
+
8
+ Use this skill when the next agent should make a round-level execution decision, not just summarize state.
9
+
10
+ `GEO = Generative Engine Optimization`
11
+
12
+ ## What it does
13
+
14
+ - converts current GEO execution state into a checkpoint artifact
15
+ - decides whether to continue, unblock, or close out
16
+ - adds gate checks and a decision checklist
17
+ - produces a handoff note and next command for the next agent
18
+
19
+ ## Best use
20
+
21
+ - when one execution round ends and the team needs a checkpoint
22
+ - when PM asks whether the team should keep going or stop and unblock first
23
+ - when another agent should take over from a stable checkpoint instead of raw state
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "GEO Agent Checkpoint"
3
+ short_description: "Decide continue, unblock, or closeout for this GEO round"
4
+ default_prompt: "Use $geo-ai-search-optimization-agent-checkpoint to turn this GEO execution state into a checkpoint decision with gate checks, next command, and handoff note."
@@ -13,7 +13,7 @@ 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 layers:
16
+ The package is best explained as twenty-one 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
@@ -22,19 +22,20 @@ The package is best explained as twenty layers:
22
22
  5. `agent-batch-executor`: queue the first few packets, but still advance one packet at a time
23
23
  6. `agent-progress-tracker`: track which packet is done, which one is active, and what comes next
24
24
  7. `agent-status-board`: turn the execution state into a board view for PM and agents
25
- 8. `skills`: inspect the bundled skill package
26
- 9. `onboard-url` / `onboard`: first look
27
- 10. `scan`: raw signal check
28
- 11. `audit` / `report`: diagnosis
29
- 12. `fix-plan` / `owner-board`: execution planning
30
- 13. `agent-handoff`: agent takeover package
31
- 14. `apply-plan`: execution loop
32
- 15. `completion-report`: closeout
33
- 16. `handoff-bundle`: all-in-one package
34
- 17. `share-pack`: audience-ready delivery
35
- 18. `export-pack`: folder export
36
- 19. `html-pack` / `publish-pack`: browsable and final delivery output
37
- 20. `pm-brief` / `roadmap`: stakeholder alignment
25
+ 8. `agent-checkpoint`: freeze the current round into a continue / unblock / closeout decision
26
+ 9. `skills`: inspect the bundled skill package
27
+ 10. `onboard-url` / `onboard`: first look
28
+ 11. `scan`: raw signal check
29
+ 12. `audit` / `report`: diagnosis
30
+ 13. `fix-plan` / `owner-board`: execution planning
31
+ 14. `agent-handoff`: agent takeover package
32
+ 15. `apply-plan`: execution loop
33
+ 16. `completion-report`: closeout
34
+ 17. `handoff-bundle`: all-in-one package
35
+ 18. `share-pack`: audience-ready delivery
36
+ 19. `export-pack`: folder export
37
+ 20. `html-pack` / `publish-pack`: browsable and final delivery output
38
+ 21. `pm-brief` / `roadmap`: stakeholder alignment
38
39
 
39
40
  ## Recommended command order
40
41
 
@@ -48,6 +49,7 @@ npx geo-ai-search-optimization agent-executor https://example.com
48
49
  npx geo-ai-search-optimization agent-batch-executor https://example.com
49
50
  npx geo-ai-search-optimization agent-progress-tracker https://example.com
50
51
  npx geo-ai-search-optimization agent-status-board https://example.com
52
+ npx geo-ai-search-optimization agent-checkpoint https://example.com
51
53
  npx geo-ai-search-optimization onboard-url https://example.com
52
54
  npx geo-ai-search-optimization pm-brief https://example.com
53
55
  npx geo-ai-search-optimization roadmap https://example.com
@@ -63,6 +65,7 @@ npx geo-ai-search-optimization agent-executor ./your-site
63
65
  npx geo-ai-search-optimization agent-batch-executor ./your-site
64
66
  npx geo-ai-search-optimization agent-progress-tracker ./your-site
65
67
  npx geo-ai-search-optimization agent-status-board ./your-site
68
+ npx geo-ai-search-optimization agent-checkpoint ./your-site
66
69
  npx geo-ai-search-optimization scan ./your-site
67
70
  npx geo-ai-search-optimization audit ./your-site
68
71
  npx geo-ai-search-optimization fix-plan ./your-site
@@ -87,6 +90,7 @@ npx geo-ai-search-optimization roadmap ./your-site
87
90
  - `agent-batch-executor`: line up the first few packets in execution order while preserving one-packet-at-a-time discipline
88
91
  - `agent-progress-tracker`: show execution progress, current packet, blockers, and the next packet to advance
89
92
  - `agent-status-board`: present the current execution state as a board with done, in-progress, blocked, next, and queued columns
93
+ - `agent-checkpoint`: convert the current round into a checkpoint decision for continue, unblock, or closeout
90
94
  - `onboard-url`: first-time website check from a live URL
91
95
  - `onboard`: interactive first-time onboarding
92
96
  - `skills`: list the bundled skills and decide which skill or command chain fits the task
@@ -118,6 +122,7 @@ When explaining the tool to a user:
118
122
  - if the user wants the next agent to continuously advance the first 2 to 3 packets in order, move them to `agent-batch-executor`
119
123
  - if the user wants the next agent to explain current progress, blockers, and the next packet, move them to `agent-progress-tracker`
120
124
  - if the user wants the next agent to present execution state as a board for PM and agent coordination, move them to `agent-status-board`
125
+ - if the user wants a per-round decision artifact that says continue, unblock, or close out, move them to `agent-checkpoint`
121
126
  - explain the result in PM language, not implementation jargon
122
127
  - if the user sounds new, start with `onboard-url` or `quick-start`
123
128
  - if the user wants another agent to take over, move them to `agent-handoff`
@@ -0,0 +1,358 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import {
4
+ createAgentStatusBoard,
5
+ renderAgentStatusBoardMarkdown,
6
+ writeAgentStatusBoardOutput
7
+ } from "./agent-status-board.js";
8
+
9
+ const VALID_FORMATS = new Set(["markdown", "json"]);
10
+
11
+ function normalizeFormat(format) {
12
+ const resolved = (format || "markdown").toLowerCase();
13
+ if (!VALID_FORMATS.has(resolved)) {
14
+ throw new Error(`不支持的 agent-checkpoint 格式:${format}。可选值:${Array.from(VALID_FORMATS).join(", ")}`);
15
+ }
16
+ return resolved;
17
+ }
18
+
19
+ async function pathExists(targetPath) {
20
+ try {
21
+ await fs.access(targetPath);
22
+ return true;
23
+ } catch {
24
+ return false;
25
+ }
26
+ }
27
+
28
+ async function resolveStatusBoard(input, options = {}) {
29
+ const resolvedPath = path.resolve(input);
30
+ if (await pathExists(resolvedPath)) {
31
+ try {
32
+ const raw = await fs.readFile(resolvedPath, "utf8");
33
+ const parsed = JSON.parse(raw);
34
+ if (parsed?.kind === "geo-agent-checkpoint" && parsed.statusBoard?.kind === "geo-agent-status-board") {
35
+ return createAgentStatusBoard(parsed.statusBoard.source || input, {
36
+ format: "json",
37
+ currentTaskId: options.currentTaskId || parsed.currentPacket?.id || parsed.statusBoard.tracker?.currentTaskId,
38
+ completedPacketIds:
39
+ options.completedPacketIds != null
40
+ ? options.completedPacketIds
41
+ : (parsed.statusBoard.tracker?.completedPacketIds || []).join(","),
42
+ blockedReasons:
43
+ options.blockedReasons != null
44
+ ? options.blockedReasons
45
+ : (parsed.statusBoard.tracker?.blockedReasons || []).join(",")
46
+ });
47
+ }
48
+ } catch {
49
+ // Fall through to status board generation
50
+ }
51
+ }
52
+
53
+ return createAgentStatusBoard(input, {
54
+ format: "json",
55
+ currentTaskId: options.currentTaskId,
56
+ completedPacketIds: options.completedPacketIds,
57
+ blockedReasons: options.blockedReasons
58
+ });
59
+ }
60
+
61
+ function inferDecision(board) {
62
+ switch (board.boardStatus) {
63
+ case "blocked":
64
+ return "resolve-blockers";
65
+ case "completed":
66
+ return "move-to-closeout";
67
+ case "in-progress":
68
+ return "continue-current-packet";
69
+ case "not-started":
70
+ return "start-first-packet";
71
+ default:
72
+ return "gather-context";
73
+ }
74
+ }
75
+
76
+ function inferCheckpointType(decision) {
77
+ switch (decision) {
78
+ case "resolve-blockers":
79
+ return "blocker-checkpoint";
80
+ case "move-to-closeout":
81
+ return "closeout-checkpoint";
82
+ case "continue-current-packet":
83
+ case "start-first-packet":
84
+ return "execution-checkpoint";
85
+ default:
86
+ return "context-checkpoint";
87
+ }
88
+ }
89
+
90
+ function buildDecisionReason(board, decision) {
91
+ switch (decision) {
92
+ case "resolve-blockers":
93
+ return `当前存在 ${board.columns.blocked.length} 个阻塞项,先解除阻塞,再继续推进 ${board.columns.inProgress[0]?.id || "当前包"}。`;
94
+ case "move-to-closeout":
95
+ return "当前执行包已经全部完成,适合进入复盘、交接和交付阶段。";
96
+ case "continue-current-packet":
97
+ return `当前已有明确执行包 ${board.columns.inProgress[0]?.id || ""},且没有阻塞,可以继续推进。`;
98
+ case "start-first-packet":
99
+ return `当前尚未开始,但第一包 ${board.columns.inProgress[0]?.id || ""} 已经明确,可以直接启动。`;
100
+ default:
101
+ return "当前还缺执行上下文,先补充上下文再做下一步决策。";
102
+ }
103
+ }
104
+
105
+ function buildGateChecks(board, decision) {
106
+ const hasActive = board.columns.inProgress.length > 0;
107
+ const hasBlockers = board.columns.blocked.length > 0;
108
+ const canCloseout = board.boardStatus === "completed";
109
+ const hasNextCommand = Boolean(board.suggestedNextCommand);
110
+
111
+ return [
112
+ {
113
+ id: "gate-active-packet",
114
+ label: "当前是否有明确执行包",
115
+ status: hasActive ? "pass" : "fail",
116
+ detail: hasActive ? `当前包:${board.columns.inProgress[0].id}` : "当前没有明确执行包。"
117
+ },
118
+ {
119
+ id: "gate-blockers",
120
+ label: "当前是否无阻塞",
121
+ status: hasBlockers ? "fail" : "pass",
122
+ detail: hasBlockers ? `阻塞数:${board.columns.blocked.length}` : "当前没有阻塞。"
123
+ },
124
+ {
125
+ id: "gate-closeout",
126
+ label: "是否达到收尾条件",
127
+ status: canCloseout ? "pass" : "warn",
128
+ detail: canCloseout ? "已可进入 closeout。" : "当前仍处于执行中或待开始。"
129
+ },
130
+ {
131
+ id: "gate-next-command",
132
+ label: "是否有下一步命令",
133
+ status: hasNextCommand ? "pass" : "fail",
134
+ detail: hasNextCommand ? board.suggestedNextCommand : "还没有稳定的下一步命令。"
135
+ },
136
+ {
137
+ id: "gate-decision-fit",
138
+ label: "当前决策是否匹配状态",
139
+ status:
140
+ (decision === "resolve-blockers" && hasBlockers) ||
141
+ (decision === "move-to-closeout" && canCloseout) ||
142
+ (decision === "continue-current-packet" && hasActive && !hasBlockers) ||
143
+ (decision === "start-first-packet" && board.boardStatus === "not-started") ||
144
+ (decision === "gather-context" && board.boardStatus === "needs-context")
145
+ ? "pass"
146
+ : "warn",
147
+ detail: `当前决策:${decision}`
148
+ }
149
+ ];
150
+ }
151
+
152
+ function buildDecisionChecklist(decision) {
153
+ switch (decision) {
154
+ case "resolve-blockers":
155
+ return [
156
+ "先确认阻塞是不是会影响当前包验收。",
157
+ "先补权限、仓库、模板或关键上下文。",
158
+ "阻塞解除后,重新生成 progress tracker 或 status board。"
159
+ ];
160
+ case "move-to-closeout":
161
+ return [
162
+ "确认本轮执行包已全部完成。",
163
+ "进入 completion-report,总结已完成、剩余风险和下一轮任务。",
164
+ "进入 handoff-bundle 或 publish-pack 进行交接或交付。"
165
+ ];
166
+ case "continue-current-packet":
167
+ return [
168
+ "继续推进当前执行包,不要切换到其他包。",
169
+ "先完成当前包的验证与回报,再进入下一包。",
170
+ "完成后重新生成 progress tracker 或 status board。"
171
+ ];
172
+ case "start-first-packet":
173
+ return [
174
+ "从第一包开始执行。",
175
+ "不要同时展开多包任务。",
176
+ "开始后马上用 progress tracker 记录当前包。"
177
+ ];
178
+ default:
179
+ return [
180
+ "先补仓库、模板、页面或执行工件上下文。",
181
+ "补完上下文后重新生成 checkpoint。",
182
+ "不要假装已经进入执行阶段。"
183
+ ];
184
+ }
185
+ }
186
+
187
+ function buildSuggestedNextCommand(board, decision) {
188
+ if (decision === "move-to-closeout") {
189
+ return `geo-ai-search-optimization completion-report ${board.source}`;
190
+ }
191
+ if (decision === "gather-context") {
192
+ return `geo-ai-search-optimization agent-session ${board.source}`;
193
+ }
194
+ return board.suggestedNextCommand;
195
+ }
196
+
197
+ function buildAlternateCommands(board, decision) {
198
+ const commands = new Set();
199
+
200
+ if (decision === "resolve-blockers") {
201
+ commands.add(board.suggestedNextCommand);
202
+ commands.add(`geo-ai-search-optimization agent-status-board ${board.source}`);
203
+ commands.add(`geo-ai-search-optimization agent-progress-tracker ${board.source}`);
204
+ } else if (decision === "move-to-closeout") {
205
+ commands.add(`geo-ai-search-optimization handoff-bundle ${board.source}`);
206
+ commands.add(`geo-ai-search-optimization publish-pack ${board.source}`);
207
+ } else if (decision === "continue-current-packet" || decision === "start-first-packet") {
208
+ commands.add(board.suggestedNextCommand);
209
+ commands.add(`geo-ai-search-optimization agent-progress-tracker ${board.source}`);
210
+ commands.add(`geo-ai-search-optimization agent-status-board ${board.source}`);
211
+ } else {
212
+ commands.add(`geo-ai-search-optimization agent-session ${board.source}`);
213
+ commands.add(`geo-ai-search-optimization agent-runbook ${board.source}`);
214
+ }
215
+
216
+ return Array.from(commands).filter(Boolean);
217
+ }
218
+
219
+ function buildHandoffNote(board, decision) {
220
+ switch (decision) {
221
+ case "resolve-blockers":
222
+ return "下一位 agent 先不要继续修代码,先解除阻塞项,再回到当前执行包。";
223
+ case "move-to-closeout":
224
+ return "下一位 agent 可以直接进入复盘、交接和交付流程。";
225
+ case "continue-current-packet":
226
+ return `下一位 agent 继续当前包 ${board.columns.inProgress[0]?.id || ""},不要切换任务。`;
227
+ case "start-first-packet":
228
+ return `下一位 agent 从第一包 ${board.columns.inProgress[0]?.id || ""} 开始。`;
229
+ default:
230
+ return "下一位 agent 先补上下文,不要直接开始修改。";
231
+ }
232
+ }
233
+
234
+ function buildCheckpointPrompt(checkpoint) {
235
+ const lines = [
236
+ "你现在进入 GEO 阶段检查点模式。",
237
+ `当前输入:${checkpoint.source}`,
238
+ `检查点类型:${checkpoint.checkpointType}`,
239
+ `当前状态:${checkpoint.boardStatus}`,
240
+ `当前决策:${checkpoint.decision}`,
241
+ `决策原因:${checkpoint.decisionReason}`
242
+ ];
243
+
244
+ if (checkpoint.currentPacket) {
245
+ lines.push(`当前包:${checkpoint.currentPacket.id}|${checkpoint.currentPacket.title}`);
246
+ }
247
+ if (checkpoint.nextPacket) {
248
+ lines.push(`下一包:${checkpoint.nextPacket.id}|${checkpoint.nextPacket.title}`);
249
+ }
250
+ if (checkpoint.blockedItems.length > 0) {
251
+ lines.push(`阻塞项:${checkpoint.blockedItems.map((item) => item.title).join(";")}`);
252
+ }
253
+
254
+ lines.push("请先回答:现在该继续、该解除阻塞,还是该进入收尾。");
255
+ lines.push("然后给出本轮 checkpoint 结论、下一步命令和交接说明。");
256
+ return lines.join("\n");
257
+ }
258
+
259
+ export async function createAgentCheckpoint(input, options = {}) {
260
+ const format = normalizeFormat(options.format);
261
+ const statusBoard = await resolveStatusBoard(input, options);
262
+ const decision = inferDecision(statusBoard);
263
+
264
+ const checkpoint = {
265
+ kind: "geo-agent-checkpoint",
266
+ input,
267
+ source: statusBoard.source,
268
+ sourceType: statusBoard.sourceType,
269
+ artifactKind: statusBoard.kind,
270
+ format,
271
+ checkpointType: inferCheckpointType(decision),
272
+ boardStatus: statusBoard.boardStatus,
273
+ decision,
274
+ decisionReason: buildDecisionReason(statusBoard, decision),
275
+ progressPercent: statusBoard.progressPercent,
276
+ currentPacket: statusBoard.columns.inProgress[0] || null,
277
+ nextPacket: statusBoard.columns.nextUp[0] || null,
278
+ completedPackets: statusBoard.columns.completed,
279
+ blockedItems: statusBoard.columns.blocked,
280
+ gateChecks: buildGateChecks(statusBoard, decision),
281
+ decisionChecklist: buildDecisionChecklist(decision),
282
+ suggestedNextCommand: buildSuggestedNextCommand(statusBoard, decision),
283
+ alternateCommands: buildAlternateCommands(statusBoard, decision),
284
+ handoffNote: buildHandoffNote(statusBoard, decision),
285
+ checkpointPrompt: "",
286
+ statusBoard
287
+ };
288
+
289
+ checkpoint.checkpointPrompt = buildCheckpointPrompt(checkpoint);
290
+ return checkpoint;
291
+ }
292
+
293
+ export function renderAgentCheckpointMarkdown(checkpoint) {
294
+ const lines = [
295
+ "# GEO Agent Checkpoint",
296
+ "",
297
+ `- 输入:\`${checkpoint.source}\``,
298
+ `- 来源类型:\`${checkpoint.sourceType}\``,
299
+ `- 工件类型:\`${checkpoint.artifactKind}\``,
300
+ `- 检查点类型:\`${checkpoint.checkpointType}\``,
301
+ `- 当前状态:\`${checkpoint.boardStatus}\``,
302
+ `- 当前决策:\`${checkpoint.decision}\``,
303
+ `- 进度:\`${checkpoint.progressPercent}%\``,
304
+ `- 决策原因:${checkpoint.decisionReason}`,
305
+ ""
306
+ ];
307
+
308
+ if (checkpoint.currentPacket) {
309
+ lines.push("## 当前包", "");
310
+ lines.push(`- ${checkpoint.currentPacket.id}|${checkpoint.currentPacket.title}`);
311
+ lines.push(`- Owner:${checkpoint.currentPacket.owner}`);
312
+ lines.push(`- 优先级:${checkpoint.currentPacket.priority}`);
313
+ lines.push("");
314
+ }
315
+
316
+ if (checkpoint.nextPacket) {
317
+ lines.push("## 下一包", "");
318
+ lines.push(`- ${checkpoint.nextPacket.id}|${checkpoint.nextPacket.title}`);
319
+ lines.push(`- Owner:${checkpoint.nextPacket.owner}`);
320
+ lines.push(`- 优先级:${checkpoint.nextPacket.priority}`);
321
+ lines.push("");
322
+ }
323
+
324
+ lines.push("## Gate Checks", "");
325
+ for (const gate of checkpoint.gateChecks) {
326
+ lines.push(`- [${gate.status}] ${gate.label}:${gate.detail}`);
327
+ }
328
+
329
+ lines.push("", "## 决策清单", "");
330
+ for (const item of checkpoint.decisionChecklist) {
331
+ lines.push(`- [ ] ${item}`);
332
+ }
333
+
334
+ lines.push("", "## 建议下一步命令", "");
335
+ lines.push(`- \`${checkpoint.suggestedNextCommand}\``);
336
+
337
+ lines.push("", "## 备选命令", "");
338
+ for (const command of checkpoint.alternateCommands) {
339
+ lines.push(`- \`${command}\``);
340
+ }
341
+
342
+ lines.push("", "## 交接说明", "");
343
+ lines.push(`- ${checkpoint.handoffNote}`);
344
+
345
+ lines.push("", "## 可直接复制给 Agent 的 Checkpoint Prompt", "", "```text");
346
+ lines.push(checkpoint.checkpointPrompt);
347
+ lines.push("```");
348
+
349
+ lines.push("", "## 状态看板", "");
350
+ lines.push(renderAgentStatusBoardMarkdown(checkpoint.statusBoard).trim());
351
+ lines.push("");
352
+
353
+ return `${lines.join("\n")}\n`;
354
+ }
355
+
356
+ export async function writeAgentCheckpointOutput(outputPath, content) {
357
+ return writeAgentStatusBoardOutput(outputPath, content);
358
+ }
@@ -134,6 +134,40 @@ function buildExecutionContextFromParsedArtifact(parsed, input) {
134
134
  };
135
135
  }
136
136
 
137
+ if (parsed?.kind === "geo-agent-checkpoint" && parsed.statusBoard?.tracker?.applyPlan?.kind === "geo-apply-plan") {
138
+ return {
139
+ source:
140
+ parsed.source ||
141
+ parsed.statusBoard.source ||
142
+ parsed.statusBoard.tracker.source ||
143
+ parsed.statusBoard.tracker.applyPlan.source ||
144
+ input,
145
+ sourceType:
146
+ parsed.sourceType ||
147
+ parsed.statusBoard.sourceType ||
148
+ parsed.statusBoard.tracker.sourceType ||
149
+ parsed.statusBoard.tracker.applyPlan.sourceType ||
150
+ "json",
151
+ artifactKind: parsed.kind,
152
+ applyPlan: parsed.statusBoard.tracker.applyPlan,
153
+ trackerState: {
154
+ currentTaskId:
155
+ parsed.currentPacket?.id ||
156
+ parsed.statusBoard.tracker.currentTaskId ||
157
+ parsed.statusBoard.tracker.activePacket?.id ||
158
+ null,
159
+ completedPacketIds:
160
+ parsed.statusBoard.tracker.completedPacketIds ||
161
+ parsed.completedPackets?.map((packet) => packet.id) ||
162
+ [],
163
+ blockedReasons:
164
+ parsed.statusBoard.tracker.blockedReasons ||
165
+ parsed.blockedItems?.map((item) => item.title) ||
166
+ []
167
+ }
168
+ };
169
+ }
170
+
137
171
  if (parsed?.kind === "geo-completion-report") {
138
172
  return {
139
173
  source: parsed.source || input,
@@ -61,6 +61,9 @@ function inferSkillForCommand(commandName, flow) {
61
61
  if (commandName === "agent-status-board") {
62
62
  return "geo-ai-search-optimization-agent-status-board";
63
63
  }
64
+ if (commandName === "agent-checkpoint") {
65
+ return "geo-ai-search-optimization-agent-checkpoint";
66
+ }
64
67
  if (commandName === "skills" || commandName === "quick-start") {
65
68
  return "geo-ai-search-optimization-usage";
66
69
  }
@@ -131,6 +134,8 @@ function inferStepPurpose(commandName, flow) {
131
134
  return "追踪当前做到第几包、卡点在哪里,以及下一包该推进什么。";
132
135
  case "agent-status-board":
133
136
  return "把当前执行状态整理成 PM 和 agent 都能直接消费的分栏看板。";
137
+ case "agent-checkpoint":
138
+ return "把当前阶段压成继续 / 阻塞 / 收尾的决策检查点。";
134
139
  case "apply-plan":
135
140
  return "把交接结果推进到具体执行包。";
136
141
  case "completion-report":
@@ -181,6 +186,8 @@ function inferExpectedArtifact(commandName) {
181
186
  return "agent 执行进度追踪工件";
182
187
  case "agent-status-board":
183
188
  return "agent 执行状态看板";
189
+ case "agent-checkpoint":
190
+ return "agent 阶段检查点工件";
184
191
  case "apply-plan":
185
192
  return "执行包";
186
193
  case "completion-report":
@@ -228,6 +235,9 @@ function buildStepInstructions(parsedCommand, flow) {
228
235
  if (parsedCommand.commandName === "agent-status-board") {
229
236
  lines.push("这一步用于把当前执行状态转成看板视图,方便 PM 和 agent 对齐当前阶段。");
230
237
  }
238
+ if (parsedCommand.commandName === "agent-checkpoint") {
239
+ lines.push("这一步用于明确此刻应该继续、先解除阻塞,还是进入收尾。");
240
+ }
231
241
  if (parsedCommand.commandName === "agent-handoff" && flow.intent === "execute") {
232
242
  lines.push("如果还是 advice-only,说明还缺仓库或本地项目上下文。");
233
243
  }
@@ -139,6 +139,21 @@ async function resolveTracker(input, options = {}) {
139
139
  options.blockedReasons != null ? options.blockedReasons : (parsed.tracker.blockedReasons || []).join(",")
140
140
  });
141
141
  }
142
+ if (parsed?.kind === "geo-agent-checkpoint" && parsed.statusBoard?.tracker?.kind === "geo-agent-progress-tracker") {
143
+ return createAgentProgressTracker(parsed.statusBoard.tracker.source || input, {
144
+ format: "json",
145
+ currentTaskId:
146
+ options.currentTaskId || parsed.currentPacket?.id || parsed.statusBoard.tracker.currentTaskId,
147
+ completedPacketIds:
148
+ options.completedPacketIds != null
149
+ ? options.completedPacketIds
150
+ : (parsed.statusBoard.tracker.completedPacketIds || []).join(","),
151
+ blockedReasons:
152
+ options.blockedReasons != null
153
+ ? options.blockedReasons
154
+ : (parsed.statusBoard.tracker.blockedReasons || []).join(",")
155
+ });
156
+ }
142
157
  } catch {
143
158
  // Fall through to tracker generation
144
159
  }
package/src/auto-flow.js CHANGED
@@ -53,6 +53,9 @@ function inferTaskTextMode(text) {
53
53
  if (/(status-board|status board|状态看板|执行看板|看板视图|board 视图)/i.test(normalized)) {
54
54
  return "execute";
55
55
  }
56
+ if (/(checkpoint|检查点|阶段检查点|继续还是收尾|解除阻塞还是继续)/i.test(normalized)) {
57
+ return "execute";
58
+ }
56
59
  if (/(executor|先做哪一个|先做哪一包|single task|执行第一包|先执行一个任务)/i.test(normalized)) {
57
60
  return "execute";
58
61
  }
@@ -173,6 +176,7 @@ function resolveEffectiveIntent(intent, detected) {
173
176
  "geo-agent-batch-executor",
174
177
  "geo-agent-progress-tracker",
175
178
  "geo-agent-status-board",
179
+ "geo-agent-checkpoint",
176
180
  "geo-apply-plan",
177
181
  "geo-handoff-bundle",
178
182
  "geo-fix-plan"
@@ -351,6 +355,24 @@ function buildCommandChain(detected, intent) {
351
355
  `geo-ai-search-optimization completion-report ${source}`,
352
356
  `geo-ai-search-optimization handoff-bundle ${source}`
353
357
  ];
358
+ case "geo-agent-checkpoint":
359
+ return detected.parsed?.decision === "move-to-closeout"
360
+ ? [
361
+ `geo-ai-search-optimization completion-report ${source}`,
362
+ `geo-ai-search-optimization handoff-bundle ${source}`,
363
+ `geo-ai-search-optimization publish-pack ${source}`
364
+ ]
365
+ : detected.parsed?.decision === "resolve-blockers"
366
+ ? [
367
+ detected.parsed.suggestedNextCommand || `geo-ai-search-optimization agent-runbook ${source}`,
368
+ `geo-ai-search-optimization agent-status-board ${source}`,
369
+ `geo-ai-search-optimization agent-progress-tracker ${source}`
370
+ ]
371
+ : [
372
+ detected.parsed?.suggestedNextCommand || `geo-ai-search-optimization agent-executor ${source}`,
373
+ `geo-ai-search-optimization agent-progress-tracker ${source}`,
374
+ `geo-ai-search-optimization completion-report ${source}`
375
+ ];
354
376
  case "geo-apply-plan":
355
377
  return [
356
378
  `geo-ai-search-optimization agent-executor ${source}`,
@@ -430,6 +452,8 @@ function pickSkillName(detected, intent) {
430
452
  return "geo-ai-search-optimization-agent-progress-tracker";
431
453
  case "geo-agent-status-board":
432
454
  return "geo-ai-search-optimization-agent-status-board";
455
+ case "geo-agent-checkpoint":
456
+ return "geo-ai-search-optimization-agent-checkpoint";
433
457
  case "geo-completion-report":
434
458
  return "geo-ai-search-optimization-completion-report";
435
459
  case "geo-handoff-bundle":
@@ -469,6 +493,7 @@ function buildSecondarySkillNames(primarySkill, intent, detected) {
469
493
  "geo-agent-batch-executor",
470
494
  "geo-agent-progress-tracker",
471
495
  "geo-agent-status-board",
496
+ "geo-agent-checkpoint",
472
497
  "geo-apply-plan"
473
498
  ].includes(
474
499
  detected.artifactKind
@@ -477,6 +502,7 @@ function buildSecondarySkillNames(primarySkill, intent, detected) {
477
502
  names.add("geo-ai-search-optimization-agent-batch-executor");
478
503
  names.add("geo-ai-search-optimization-agent-progress-tracker");
479
504
  names.add("geo-ai-search-optimization-agent-status-board");
505
+ names.add("geo-ai-search-optimization-agent-checkpoint");
480
506
  names.add("geo-ai-search-optimization-agent-executor");
481
507
  names.add("geo-ai-search-optimization-agent-runbook");
482
508
  names.add("geo-ai-search-optimization-agent-handoff");
@@ -509,6 +535,7 @@ function buildStage(intent, detected) {
509
535
  "geo-agent-batch-executor",
510
536
  "geo-agent-progress-tracker",
511
537
  "geo-agent-status-board",
538
+ "geo-agent-checkpoint",
512
539
  "geo-apply-plan",
513
540
  "geo-handoff-bundle"
514
541
  ].includes(detected.artifactKind)
@@ -524,6 +551,7 @@ function buildStage(intent, detected) {
524
551
  "geo-agent-batch-executor",
525
552
  "geo-agent-progress-tracker",
526
553
  "geo-agent-status-board",
554
+ "geo-agent-checkpoint",
527
555
  "geo-apply-plan",
528
556
  "geo-handoff-bundle"
529
557
  ].includes(detected.artifactKind)
package/src/cli.js CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  renderAgentProgressTrackerMarkdown,
15
15
  writeAgentProgressTrackerOutput
16
16
  } from "./agent-progress-tracker.js";
17
+ import { createAgentCheckpoint, renderAgentCheckpointMarkdown, writeAgentCheckpointOutput } from "./agent-checkpoint.js";
17
18
  import { createAgentStatusBoard, renderAgentStatusBoardMarkdown, writeAgentStatusBoardOutput } from "./agent-status-board.js";
18
19
  import { createAgentRunbook, renderAgentRunbookMarkdown, writeAgentRunbookOutput } from "./agent-runbook.js";
19
20
  import { createAgentSession, renderAgentSessionMarkdown, writeAgentSessionOutput } from "./agent-session.js";
@@ -79,6 +80,7 @@ function printHelp() {
79
80
  " geo-ai-search-optimization agent-batch-executor <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--task <id>] [--count <count>] [--format <markdown|json>] [--out <file>]",
80
81
  " geo-ai-search-optimization agent-progress-tracker <input> [--current <id>] [--completed <id,id>] [--blocked <reason,reason>] [--format <markdown|json>] [--out <file>]",
81
82
  " geo-ai-search-optimization agent-status-board <input> [--current <id>] [--completed <id,id>] [--blocked <reason,reason>] [--format <markdown|json>] [--out <file>]",
83
+ " geo-ai-search-optimization agent-checkpoint <input> [--current <id>] [--completed <id,id>] [--blocked <reason,reason>] [--format <markdown|json>] [--out <file>]",
82
84
  " geo-ai-search-optimization skills [--json]",
83
85
  " geo-ai-search-optimization where",
84
86
  " geo-ai-search-optimization doctor [--json]",
@@ -333,6 +335,34 @@ async function handleAgentStatusBoard(args) {
333
335
  process.stdout.write(renderedOutput);
334
336
  }
335
337
 
338
+ async function handleAgentCheckpoint(args) {
339
+ const input = args.find((value) => !value.startsWith("-"));
340
+ if (!input) {
341
+ throw new Error("agent-checkpoint 需要一个输入值,可以是项目路径、网站网址或已导出的工件");
342
+ }
343
+
344
+ const format = getFlagValue(args, "--format") || (hasFlag(args, "--json") ? "json" : undefined);
345
+ const checkpoint = await createAgentCheckpoint(input, {
346
+ format,
347
+ currentTaskId: getFlagValue(args, "--current"),
348
+ completedPacketIds: getFlagValue(args, "--completed"),
349
+ blockedReasons: getFlagValue(args, "--blocked")
350
+ });
351
+ const outputJson = checkpoint.format === "json";
352
+ const renderedOutput = outputJson
353
+ ? `${JSON.stringify(checkpoint, null, 2)}\n`
354
+ : renderAgentCheckpointMarkdown(checkpoint);
355
+
356
+ const outputPath = getFlagValue(args, "--out");
357
+ if (outputPath) {
358
+ const resolvedOutputPath = await writeAgentCheckpointOutput(outputPath, renderedOutput);
359
+ process.stdout.write(`已保存 agent checkpoint:${resolvedOutputPath}\n`);
360
+ return;
361
+ }
362
+
363
+ process.stdout.write(renderedOutput);
364
+ }
365
+
336
366
  function handleWhere() {
337
367
  process.stdout.write(
338
368
  [
@@ -908,6 +938,11 @@ export async function runCli(args = []) {
908
938
  return;
909
939
  }
910
940
 
941
+ if (command === "agent-checkpoint") {
942
+ await handleAgentCheckpoint(rest);
943
+ return;
944
+ }
945
+
911
946
  if (command === "skills") {
912
947
  await handleSkills(rest);
913
948
  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 { createAgentBatchExecutor, renderAgentBatchExecutorMarkdown, writeAgentBatchExecutorOutput } from "./agent-batch-executor.js";
11
+ export { createAgentCheckpoint, renderAgentCheckpointMarkdown, writeAgentCheckpointOutput } from "./agent-checkpoint.js";
11
12
  export { createAgentHandoff, renderAgentHandoffMarkdown, writeAgentHandoffOutput } from "./agent-handoff.js";
12
13
  export { createAgentExecutor, renderAgentExecutorMarkdown, writeAgentExecutorOutput } from "./agent-executor.js";
13
14
  export {
package/src/skills.js CHANGED
@@ -11,6 +11,7 @@ const SKILL_ORDER = [
11
11
  "geo-ai-search-optimization-agent-batch-executor",
12
12
  "geo-ai-search-optimization-agent-progress-tracker",
13
13
  "geo-ai-search-optimization-agent-status-board",
14
+ "geo-ai-search-optimization-agent-checkpoint",
14
15
  "geo-ai-search-optimization-usage",
15
16
  "geo-ai-search-optimization-agent-handoff",
16
17
  "geo-ai-search-optimization-repair-loop",
@@ -31,6 +32,7 @@ const SKILL_CATEGORY = {
31
32
  "geo-ai-search-optimization-agent-batch-executor": "execution",
32
33
  "geo-ai-search-optimization-agent-progress-tracker": "execution",
33
34
  "geo-ai-search-optimization-agent-status-board": "execution",
35
+ "geo-ai-search-optimization-agent-checkpoint": "execution",
34
36
  "geo-ai-search-optimization-usage": "guidance",
35
37
  "geo-ai-search-optimization-agent-handoff": "execution",
36
38
  "geo-ai-search-optimization-repair-loop": "execution",
@@ -170,6 +172,7 @@ export function renderBundledSkillsMarkdown(bundle) {
170
172
  "- 如果要连续推进前 2 到 3 包,但仍然一次只做一包,再进入 agent-batch-executor。",
171
173
  "- 如果要追踪目前做到第几包、卡在哪、下一包是什么,再进入 agent-progress-tracker。",
172
174
  "- 如果要把当前执行状态直接整理成看板,再进入 agent-status-board。",
175
+ "- 如果要在每轮结束时做继续 / 阻塞 / 收尾决策,再进入 agent-checkpoint。",
173
176
  "- 再看 usage skill,知道什么时候该跑哪个命令。",
174
177
  "- 如果要交给 agent 执行,再进入 handoff / apply / completion 这一条执行链。",
175
178
  "- 如果要产出给团队分发,再进入 share / export / html / publish 这一条交付链。",