geo-ai-search-optimization 1.2.14 → 1.2.15
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 +28 -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-decision-log/SKILL.md +23 -0
- package/resources/geo-ai-search-optimization-agent-decision-log/agents/openai.yaml +4 -0
- package/resources/geo-ai-search-optimization-usage/SKILL.md +19 -14
- package/src/agent-checkpoint.js +20 -0
- package/src/agent-decision-log.js +368 -0
- package/src/agent-progress-tracker.js +36 -0
- package/src/agent-session.js +10 -0
- package/src/agent-status-board.js +20 -0
- package/src/auto-flow.js +39 -0
- package/src/cli.js +37 -0
- package/src/index.js +1 -0
- package/src/skills.js +3 -0
package/README.md
CHANGED
|
@@ -207,6 +207,25 @@ geo-ai-search-optimization agent-checkpoint ./reports/agent-progress-tracker.jso
|
|
|
207
207
|
- 交接说明
|
|
208
208
|
- 可直接复制给 agent 的 checkpoint prompt
|
|
209
209
|
|
|
210
|
+
## Agent Decision Log 命令
|
|
211
|
+
|
|
212
|
+
如果你希望把每一轮 checkpoint 累积成“为什么之前这样决定”的历史,而不是只保留单轮状态,可以直接用 `agent-decision-log`:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
geo-ai-search-optimization agent-decision-log ./your-site
|
|
216
|
+
geo-ai-search-optimization agent-decision-log ./reports/agent-checkpoint.json --note "本轮先解除模板缺失问题"
|
|
217
|
+
geo-ai-search-optimization agent-decision-log ./your-site --append-from ./reports/agent-decision-log.json --blocked "缺少模板文件" --format json --out ./reports/agent-decision-log.json
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
`agent-decision-log` 会输出:
|
|
221
|
+
|
|
222
|
+
- 当前累计决策次数
|
|
223
|
+
- 最新检查点类型与决策
|
|
224
|
+
- 当前重点与开放阻塞
|
|
225
|
+
- 决策时间线
|
|
226
|
+
- 最新建议下一步命令
|
|
227
|
+
- 可直接复制给 agent 的 decision log prompt
|
|
228
|
+
|
|
210
229
|
## Quick Start
|
|
211
230
|
|
|
212
231
|
如果你要从 0 到 1 启动一个 GEO 项目,建议照这个顺序做。
|
|
@@ -608,6 +627,7 @@ geo-ai-search-optimization agent-batch-executor ./your-site
|
|
|
608
627
|
geo-ai-search-optimization agent-progress-tracker ./your-site
|
|
609
628
|
geo-ai-search-optimization agent-status-board ./your-site
|
|
610
629
|
geo-ai-search-optimization agent-checkpoint ./your-site
|
|
630
|
+
geo-ai-search-optimization agent-decision-log ./your-site
|
|
611
631
|
geo-ai-search-optimization skills
|
|
612
632
|
geo-ai-search-optimization where
|
|
613
633
|
geo-ai-search-optimization doctor
|
|
@@ -678,6 +698,13 @@ geo-ai-search-optimization help
|
|
|
678
698
|
- 输出 do-now checklist、stop checklist、success checklist、验证命令和回报模板
|
|
679
699
|
- 新增 `geo-ai-search-optimization-agent-executor` skill
|
|
680
700
|
|
|
701
|
+
## New in 1.2.15
|
|
702
|
+
|
|
703
|
+
- 新增 `agent-decision-log` 命令
|
|
704
|
+
- 把多轮 checkpoint 沉淀成可继承的决策历史,而不是只有单轮阶段判断
|
|
705
|
+
- 支持从 `agent-checkpoint`、`agent-status-board`、`agent-progress-tracker`、目录、网址等输入继续生成或追加决策记录
|
|
706
|
+
- 新增 `geo-ai-search-optimization-agent-decision-log` skill
|
|
707
|
+
|
|
681
708
|
## New in 1.2.14
|
|
682
709
|
|
|
683
710
|
- 新增 `agent-checkpoint` 命令
|
|
@@ -900,6 +927,7 @@ The installed package now includes a bundled GEO skill pack, including:
|
|
|
900
927
|
- `geo-ai-search-optimization-agent-progress-tracker`
|
|
901
928
|
- `geo-ai-search-optimization-agent-status-board`
|
|
902
929
|
- `geo-ai-search-optimization-agent-checkpoint`
|
|
930
|
+
- `geo-ai-search-optimization-agent-decision-log`
|
|
903
931
|
- `geo-ai-search-optimization-usage`
|
|
904
932
|
- `geo-ai-search-optimization-agent-handoff`
|
|
905
933
|
- `geo-ai-search-optimization-repair-loop`
|
package/package.json
CHANGED
|
@@ -102,6 +102,16 @@ Best for:
|
|
|
102
102
|
- producing a clean handoff note at the end of one execution round
|
|
103
103
|
- giving PM and the next agent one checkpoint artifact to align on
|
|
104
104
|
|
|
105
|
+
### `geo-ai-search-optimization-agent-decision-log`
|
|
106
|
+
|
|
107
|
+
Use this when the next agent should inherit decision history, not just one checkpoint.
|
|
108
|
+
|
|
109
|
+
Best for:
|
|
110
|
+
|
|
111
|
+
- preserving why previous rounds continued, paused, or moved to closeout
|
|
112
|
+
- giving PM and the next agent a reusable decision history across rounds
|
|
113
|
+
- appending a fresh checkpoint onto an existing GEO execution history
|
|
114
|
+
|
|
105
115
|
## Usage guide
|
|
106
116
|
|
|
107
117
|
### `geo-ai-search-optimization-usage`
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: geo-ai-search-optimization-agent-decision-log
|
|
3
|
+
description: Turn GEO checkpoints into a reusable decision history. Use when an agent or PM should preserve why each GEO round continued, paused for blockers, or moved to closeout, so the next agent can inherit the reasoning instead of re-evaluating the entire chain from scratch.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GEO Agent Decision Log
|
|
7
|
+
|
|
8
|
+
Use this skill when the team needs durable decision memory across multiple GEO execution rounds.
|
|
9
|
+
|
|
10
|
+
`GEO = Generative Engine Optimization`
|
|
11
|
+
|
|
12
|
+
## What it does
|
|
13
|
+
|
|
14
|
+
- converts the current GEO round into a loggable decision entry
|
|
15
|
+
- preserves why the round continued, paused for blockers, or moved to closeout
|
|
16
|
+
- keeps the latest checkpoint, current packet, next packet, blockers, and handoff note together
|
|
17
|
+
- gives the next agent a stable history instead of isolated one-round artifacts
|
|
18
|
+
|
|
19
|
+
## Best use
|
|
20
|
+
|
|
21
|
+
- when one checkpoint is not enough and the next agent should see decision history
|
|
22
|
+
- when PM asks why the team chose to continue, unblock, or close out in previous rounds
|
|
23
|
+
- when you want to append a new decision to an existing GEO execution history
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "GEO Agent Decision Log"
|
|
3
|
+
short_description: "Preserve GEO round decisions as reusable history"
|
|
4
|
+
default_prompt: "Use $geo-ai-search-optimization-agent-decision-log to turn this GEO execution state into a reusable decision history with latest checkpoint, rationale, and next command."
|
|
@@ -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-
|
|
16
|
+
The package is best explained as twenty-two 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
|
|
@@ -23,19 +23,20 @@ The package is best explained as twenty-one layers:
|
|
|
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
25
|
8. `agent-checkpoint`: freeze the current round into a continue / unblock / closeout decision
|
|
26
|
-
9. `
|
|
27
|
-
10. `
|
|
28
|
-
11. `
|
|
29
|
-
12. `
|
|
30
|
-
13. `
|
|
31
|
-
14. `
|
|
32
|
-
15. `
|
|
33
|
-
16. `
|
|
34
|
-
17. `
|
|
35
|
-
18. `
|
|
36
|
-
19. `
|
|
37
|
-
20. `
|
|
38
|
-
21. `
|
|
26
|
+
9. `agent-decision-log`: preserve why each round continued, paused, or closed out
|
|
27
|
+
10. `skills`: inspect the bundled skill package
|
|
28
|
+
11. `onboard-url` / `onboard`: first look
|
|
29
|
+
12. `scan`: raw signal check
|
|
30
|
+
13. `audit` / `report`: diagnosis
|
|
31
|
+
14. `fix-plan` / `owner-board`: execution planning
|
|
32
|
+
15. `agent-handoff`: agent takeover package
|
|
33
|
+
16. `apply-plan`: execution loop
|
|
34
|
+
17. `completion-report`: closeout
|
|
35
|
+
18. `handoff-bundle`: all-in-one package
|
|
36
|
+
19. `share-pack`: audience-ready delivery
|
|
37
|
+
20. `export-pack`: folder export
|
|
38
|
+
21. `html-pack` / `publish-pack`: browsable and final delivery output
|
|
39
|
+
22. `pm-brief` / `roadmap`: stakeholder alignment
|
|
39
40
|
|
|
40
41
|
## Recommended command order
|
|
41
42
|
|
|
@@ -50,6 +51,7 @@ npx geo-ai-search-optimization agent-batch-executor https://example.com
|
|
|
50
51
|
npx geo-ai-search-optimization agent-progress-tracker https://example.com
|
|
51
52
|
npx geo-ai-search-optimization agent-status-board https://example.com
|
|
52
53
|
npx geo-ai-search-optimization agent-checkpoint https://example.com
|
|
54
|
+
npx geo-ai-search-optimization agent-decision-log https://example.com
|
|
53
55
|
npx geo-ai-search-optimization onboard-url https://example.com
|
|
54
56
|
npx geo-ai-search-optimization pm-brief https://example.com
|
|
55
57
|
npx geo-ai-search-optimization roadmap https://example.com
|
|
@@ -66,6 +68,7 @@ npx geo-ai-search-optimization agent-batch-executor ./your-site
|
|
|
66
68
|
npx geo-ai-search-optimization agent-progress-tracker ./your-site
|
|
67
69
|
npx geo-ai-search-optimization agent-status-board ./your-site
|
|
68
70
|
npx geo-ai-search-optimization agent-checkpoint ./your-site
|
|
71
|
+
npx geo-ai-search-optimization agent-decision-log ./your-site
|
|
69
72
|
npx geo-ai-search-optimization scan ./your-site
|
|
70
73
|
npx geo-ai-search-optimization audit ./your-site
|
|
71
74
|
npx geo-ai-search-optimization fix-plan ./your-site
|
|
@@ -91,6 +94,7 @@ npx geo-ai-search-optimization roadmap ./your-site
|
|
|
91
94
|
- `agent-progress-tracker`: show execution progress, current packet, blockers, and the next packet to advance
|
|
92
95
|
- `agent-status-board`: present the current execution state as a board with done, in-progress, blocked, next, and queued columns
|
|
93
96
|
- `agent-checkpoint`: convert the current round into a checkpoint decision for continue, unblock, or closeout
|
|
97
|
+
- `agent-decision-log`: preserve multiple rounds of checkpoint history so the next agent can inherit the reasoning
|
|
94
98
|
- `onboard-url`: first-time website check from a live URL
|
|
95
99
|
- `onboard`: interactive first-time onboarding
|
|
96
100
|
- `skills`: list the bundled skills and decide which skill or command chain fits the task
|
|
@@ -123,6 +127,7 @@ When explaining the tool to a user:
|
|
|
123
127
|
- if the user wants the next agent to explain current progress, blockers, and the next packet, move them to `agent-progress-tracker`
|
|
124
128
|
- 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
129
|
- if the user wants a per-round decision artifact that says continue, unblock, or close out, move them to `agent-checkpoint`
|
|
130
|
+
- if the user wants cross-round decision memory and not just one checkpoint, move them to `agent-decision-log`
|
|
126
131
|
- explain the result in PM language, not implementation jargon
|
|
127
132
|
- if the user sounds new, start with `onboard-url` or `quick-start`
|
|
128
133
|
- if the user wants another agent to take over, move them to `agent-handoff`
|
package/src/agent-checkpoint.js
CHANGED
|
@@ -45,6 +45,26 @@ async function resolveStatusBoard(input, options = {}) {
|
|
|
45
45
|
: (parsed.statusBoard.tracker?.blockedReasons || []).join(",")
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
|
+
if (parsed?.kind === "geo-agent-decision-log" && parsed.latestCheckpoint?.statusBoard?.kind === "geo-agent-status-board") {
|
|
49
|
+
return createAgentStatusBoard(
|
|
50
|
+
parsed.latestCheckpoint.statusBoard.source || parsed.latestCheckpoint.source || input,
|
|
51
|
+
{
|
|
52
|
+
format: "json",
|
|
53
|
+
currentTaskId:
|
|
54
|
+
options.currentTaskId ||
|
|
55
|
+
parsed.latestCheckpoint.currentPacket?.id ||
|
|
56
|
+
parsed.latestCheckpoint.statusBoard.tracker?.currentTaskId,
|
|
57
|
+
completedPacketIds:
|
|
58
|
+
options.completedPacketIds != null
|
|
59
|
+
? options.completedPacketIds
|
|
60
|
+
: (parsed.latestCheckpoint.completedPackets || []).map((packet) => packet.id).join(","),
|
|
61
|
+
blockedReasons:
|
|
62
|
+
options.blockedReasons != null
|
|
63
|
+
? options.blockedReasons
|
|
64
|
+
: (parsed.latestCheckpoint.blockedItems || []).map((item) => item.title).join(",")
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
}
|
|
48
68
|
} catch {
|
|
49
69
|
// Fall through to status board generation
|
|
50
70
|
}
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createAgentCheckpoint } from "./agent-checkpoint.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-decision-log 格式:${format}。可选值:${Array.from(VALID_FORMATS).join(", ")}`);
|
|
12
|
+
}
|
|
13
|
+
return resolved;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function pathExists(targetPath) {
|
|
17
|
+
try {
|
|
18
|
+
await fs.access(targetPath);
|
|
19
|
+
return true;
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function cloneForFormat(record, format) {
|
|
26
|
+
if (!record || typeof record !== "object") {
|
|
27
|
+
return record;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
...record,
|
|
32
|
+
format
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function buildEntryId(index) {
|
|
37
|
+
return `decision-${String(index).padStart(2, "0")}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function buildDecisionNote(options) {
|
|
41
|
+
return options.note || options.decisionNote || null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function buildRecommendedFocus(checkpoint) {
|
|
45
|
+
switch (checkpoint.decision) {
|
|
46
|
+
case "resolve-blockers":
|
|
47
|
+
return `先解除 ${checkpoint.blockedItems.length || 1} 个阻塞项,再继续当前包。`;
|
|
48
|
+
case "move-to-closeout":
|
|
49
|
+
return "进入复盘、交接和交付,不要再扩展新任务。";
|
|
50
|
+
case "continue-current-packet":
|
|
51
|
+
return `继续推进当前包 ${checkpoint.currentPacket?.id || ""},不要切换任务。`.trim();
|
|
52
|
+
case "start-first-packet":
|
|
53
|
+
return `启动第一包 ${checkpoint.currentPacket?.id || ""},建立第一轮执行节奏。`.trim();
|
|
54
|
+
default:
|
|
55
|
+
return "先补执行上下文,再进入下一轮。";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function buildLogSummary(entries, checkpoint) {
|
|
60
|
+
if (entries.length === 1) {
|
|
61
|
+
return `目前已有 1 次阶段决策,最新结论是 ${checkpoint.decision}。`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return `目前已累计 ${entries.length} 次阶段决策,最新结论是 ${checkpoint.decision},当前重点是:${buildRecommendedFocus(checkpoint)}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function buildEntry(checkpoint, note, index) {
|
|
68
|
+
return {
|
|
69
|
+
id: buildEntryId(index),
|
|
70
|
+
createdAt: new Date().toISOString(),
|
|
71
|
+
checkpointType: checkpoint.checkpointType,
|
|
72
|
+
decision: checkpoint.decision,
|
|
73
|
+
boardStatus: checkpoint.boardStatus,
|
|
74
|
+
progressPercent: checkpoint.progressPercent,
|
|
75
|
+
decisionReason: checkpoint.decisionReason,
|
|
76
|
+
currentPacket: checkpoint.currentPacket
|
|
77
|
+
? {
|
|
78
|
+
id: checkpoint.currentPacket.id,
|
|
79
|
+
title: checkpoint.currentPacket.title,
|
|
80
|
+
owner: checkpoint.currentPacket.owner,
|
|
81
|
+
priority: checkpoint.currentPacket.priority
|
|
82
|
+
}
|
|
83
|
+
: null,
|
|
84
|
+
nextPacket: checkpoint.nextPacket
|
|
85
|
+
? {
|
|
86
|
+
id: checkpoint.nextPacket.id,
|
|
87
|
+
title: checkpoint.nextPacket.title,
|
|
88
|
+
owner: checkpoint.nextPacket.owner,
|
|
89
|
+
priority: checkpoint.nextPacket.priority
|
|
90
|
+
}
|
|
91
|
+
: null,
|
|
92
|
+
blockedItems: checkpoint.blockedItems.map((item) => ({
|
|
93
|
+
id: item.id,
|
|
94
|
+
title: item.title,
|
|
95
|
+
owner: item.owner,
|
|
96
|
+
priority: item.priority
|
|
97
|
+
})),
|
|
98
|
+
suggestedNextCommand: checkpoint.suggestedNextCommand,
|
|
99
|
+
alternateCommands: checkpoint.alternateCommands,
|
|
100
|
+
handoffNote: checkpoint.handoffNote,
|
|
101
|
+
note: note || null
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function buildLogPrompt(log) {
|
|
106
|
+
const latest = log.latestCheckpoint;
|
|
107
|
+
const lines = [
|
|
108
|
+
"你现在进入 GEO 决策历史模式。",
|
|
109
|
+
`当前输入:${log.source}`,
|
|
110
|
+
`已累计决策次数:${log.totalEntries}`,
|
|
111
|
+
`最新检查点类型:${latest.checkpointType}`,
|
|
112
|
+
`最新决策:${latest.decision}`,
|
|
113
|
+
`最新决策原因:${latest.decisionReason}`,
|
|
114
|
+
`当前重点:${log.recommendedFocus}`
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
if (latest.currentPacket) {
|
|
118
|
+
lines.push(`当前包:${latest.currentPacket.id}|${latest.currentPacket.title}`);
|
|
119
|
+
}
|
|
120
|
+
if (latest.nextPacket) {
|
|
121
|
+
lines.push(`下一包:${latest.nextPacket.id}|${latest.nextPacket.title}`);
|
|
122
|
+
}
|
|
123
|
+
if (latest.blockedItems.length > 0) {
|
|
124
|
+
lines.push(`当前阻塞:${latest.blockedItems.map((item) => item.title).join(";")}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
lines.push("请先说明最近几轮是如何决策的,再给出这一轮应该继续、解阻还是收尾。");
|
|
128
|
+
lines.push("最后输出下一步命令、交接说明,以及是否需要追加一条新的决策记录。");
|
|
129
|
+
return lines.join("\n");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function readJsonIfExists(targetPath) {
|
|
133
|
+
if (!(await pathExists(targetPath))) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const raw = await fs.readFile(targetPath, "utf8");
|
|
138
|
+
return JSON.parse(raw);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function resolveExistingLog(options = {}) {
|
|
142
|
+
const appendFrom = options.appendFrom || options.appendPath;
|
|
143
|
+
if (!appendFrom) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const resolvedPath = path.resolve(appendFrom);
|
|
148
|
+
const parsed = await readJsonIfExists(resolvedPath);
|
|
149
|
+
if (!parsed || parsed.kind !== "geo-agent-decision-log") {
|
|
150
|
+
throw new Error(`append-from 需要指向一个 geo-agent-decision-log JSON 工件:${resolvedPath}`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
path: resolvedPath,
|
|
155
|
+
log: parsed
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function shouldReuseDecisionLog(parsed, options = {}) {
|
|
160
|
+
return (
|
|
161
|
+
parsed?.kind === "geo-agent-decision-log" &&
|
|
162
|
+
!options.appendFrom &&
|
|
163
|
+
!options.appendPath &&
|
|
164
|
+
!options.currentTaskId &&
|
|
165
|
+
!options.completedPacketIds &&
|
|
166
|
+
!options.blockedReasons &&
|
|
167
|
+
!buildDecisionNote(options)
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function getCheckpointSourceFromLog(parsed, fallbackInput) {
|
|
172
|
+
return (
|
|
173
|
+
parsed?.latestCheckpoint?.source ||
|
|
174
|
+
parsed?.latestCheckpoint?.statusBoard?.source ||
|
|
175
|
+
parsed?.source ||
|
|
176
|
+
fallbackInput
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function resolveCheckpoint(input, options = {}) {
|
|
181
|
+
const resolvedInput = path.resolve(input);
|
|
182
|
+
if (await pathExists(resolvedInput)) {
|
|
183
|
+
try {
|
|
184
|
+
const raw = await fs.readFile(resolvedInput, "utf8");
|
|
185
|
+
const parsed = JSON.parse(raw);
|
|
186
|
+
|
|
187
|
+
if (shouldReuseDecisionLog(parsed, options)) {
|
|
188
|
+
return {
|
|
189
|
+
reuseLog: cloneForFormat(parsed, normalizeFormat(options.format)),
|
|
190
|
+
checkpoint: parsed.latestCheckpoint || null
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (parsed?.kind === "geo-agent-decision-log" && parsed.latestCheckpoint?.kind === "geo-agent-checkpoint") {
|
|
195
|
+
const checkpointSource = getCheckpointSourceFromLog(parsed, resolvedInput);
|
|
196
|
+
const checkpoint = await createAgentCheckpoint(checkpointSource, {
|
|
197
|
+
format: "json",
|
|
198
|
+
currentTaskId: options.currentTaskId || parsed.latestCheckpoint.currentPacket?.id,
|
|
199
|
+
completedPacketIds:
|
|
200
|
+
options.completedPacketIds != null
|
|
201
|
+
? options.completedPacketIds
|
|
202
|
+
: (parsed.latestCheckpoint.completedPackets || []).map((packet) => packet.id).join(","),
|
|
203
|
+
blockedReasons:
|
|
204
|
+
options.blockedReasons != null
|
|
205
|
+
? options.blockedReasons
|
|
206
|
+
: (parsed.latestCheckpoint.blockedItems || []).map((item) => item.title).join(",")
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
reuseLog: null,
|
|
211
|
+
checkpoint
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
} catch {
|
|
215
|
+
// Fall through to checkpoint generation.
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
reuseLog: null,
|
|
221
|
+
checkpoint: await createAgentCheckpoint(input, {
|
|
222
|
+
format: "json",
|
|
223
|
+
currentTaskId: options.currentTaskId,
|
|
224
|
+
completedPacketIds: options.completedPacketIds,
|
|
225
|
+
blockedReasons: options.blockedReasons
|
|
226
|
+
})
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export async function createAgentDecisionLog(input, options = {}) {
|
|
231
|
+
const format = normalizeFormat(options.format);
|
|
232
|
+
const existing = await resolveExistingLog(options);
|
|
233
|
+
const { reuseLog, checkpoint } = await resolveCheckpoint(input, {
|
|
234
|
+
...options,
|
|
235
|
+
format: "json"
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
if (reuseLog) {
|
|
239
|
+
return reuseLog;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (!checkpoint) {
|
|
243
|
+
throw new Error("无法从当前输入生成 agent checkpoint,因此不能创建 decision log。");
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const note = buildDecisionNote(options);
|
|
247
|
+
const previousEntries = existing?.log?.entries || [];
|
|
248
|
+
const entries = [
|
|
249
|
+
...previousEntries,
|
|
250
|
+
buildEntry(checkpoint, note, previousEntries.length + 1)
|
|
251
|
+
];
|
|
252
|
+
|
|
253
|
+
const log = {
|
|
254
|
+
kind: "geo-agent-decision-log",
|
|
255
|
+
input,
|
|
256
|
+
source: checkpoint.source,
|
|
257
|
+
sourceType: checkpoint.sourceType,
|
|
258
|
+
artifactKind: checkpoint.kind,
|
|
259
|
+
format,
|
|
260
|
+
updatedAt: new Date().toISOString(),
|
|
261
|
+
totalEntries: entries.length,
|
|
262
|
+
latestDecision: checkpoint.decision,
|
|
263
|
+
latestDecisionReason: checkpoint.decisionReason,
|
|
264
|
+
latestCheckpointType: checkpoint.checkpointType,
|
|
265
|
+
latestBoardStatus: checkpoint.boardStatus,
|
|
266
|
+
currentPacket: checkpoint.currentPacket,
|
|
267
|
+
nextPacket: checkpoint.nextPacket,
|
|
268
|
+
openBlockers: checkpoint.blockedItems,
|
|
269
|
+
recommendedFocus: buildRecommendedFocus(checkpoint),
|
|
270
|
+
logSummary: buildLogSummary(entries, checkpoint),
|
|
271
|
+
suggestedNextCommand: checkpoint.suggestedNextCommand,
|
|
272
|
+
alternateCommands: checkpoint.alternateCommands,
|
|
273
|
+
entries,
|
|
274
|
+
latestCheckpoint: checkpoint,
|
|
275
|
+
logPrompt: ""
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
log.logPrompt = buildLogPrompt(log);
|
|
279
|
+
return log;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function renderAgentDecisionLogMarkdown(log) {
|
|
283
|
+
const lines = [
|
|
284
|
+
"# GEO Agent Decision Log",
|
|
285
|
+
"",
|
|
286
|
+
`- 输入:\`${log.source}\``,
|
|
287
|
+
`- 来源类型:\`${log.sourceType}\``,
|
|
288
|
+
`- 最新工件类型:\`${log.artifactKind}\``,
|
|
289
|
+
`- 决策次数:\`${log.totalEntries}\``,
|
|
290
|
+
`- 最新检查点类型:\`${log.latestCheckpointType}\``,
|
|
291
|
+
`- 最新状态:\`${log.latestBoardStatus}\``,
|
|
292
|
+
`- 最新决策:\`${log.latestDecision}\``,
|
|
293
|
+
`- 当前重点:${log.recommendedFocus}`,
|
|
294
|
+
`- 总结:${log.logSummary}`,
|
|
295
|
+
""
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
if (log.currentPacket) {
|
|
299
|
+
lines.push("## 当前包", "", `- ${log.currentPacket.id}|${log.currentPacket.title}`);
|
|
300
|
+
lines.push(`- Owner:${log.currentPacket.owner}`);
|
|
301
|
+
lines.push(`- 优先级:${log.currentPacket.priority}`);
|
|
302
|
+
lines.push("");
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (log.nextPacket) {
|
|
306
|
+
lines.push("## 下一包", "", `- ${log.nextPacket.id}|${log.nextPacket.title}`);
|
|
307
|
+
lines.push(`- Owner:${log.nextPacket.owner}`);
|
|
308
|
+
lines.push(`- 优先级:${log.nextPacket.priority}`);
|
|
309
|
+
lines.push("");
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
lines.push("## 当前阻塞", "");
|
|
313
|
+
if (log.openBlockers.length === 0) {
|
|
314
|
+
lines.push("- 当前没有阻塞。", "");
|
|
315
|
+
} else {
|
|
316
|
+
for (const blocker of log.openBlockers) {
|
|
317
|
+
lines.push(`- ${blocker.id}|${blocker.title}`);
|
|
318
|
+
lines.push(` - Owner:${blocker.owner}`);
|
|
319
|
+
lines.push(` - 优先级:${blocker.priority}`);
|
|
320
|
+
}
|
|
321
|
+
lines.push("");
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
lines.push("## 决策时间线", "");
|
|
325
|
+
for (const entry of [...log.entries].reverse()) {
|
|
326
|
+
lines.push(`### ${entry.id}`);
|
|
327
|
+
lines.push("");
|
|
328
|
+
lines.push(`- 时间:\`${entry.createdAt}\``);
|
|
329
|
+
lines.push(`- 检查点类型:\`${entry.checkpointType}\``);
|
|
330
|
+
lines.push(`- 决策:\`${entry.decision}\``);
|
|
331
|
+
lines.push(`- 状态:\`${entry.boardStatus}\``);
|
|
332
|
+
lines.push(`- 进度:\`${entry.progressPercent}%\``);
|
|
333
|
+
lines.push(`- 原因:${entry.decisionReason}`);
|
|
334
|
+
if (entry.currentPacket) {
|
|
335
|
+
lines.push(`- 当前包:${entry.currentPacket.id}|${entry.currentPacket.title}`);
|
|
336
|
+
}
|
|
337
|
+
if (entry.nextPacket) {
|
|
338
|
+
lines.push(`- 下一包:${entry.nextPacket.id}|${entry.nextPacket.title}`);
|
|
339
|
+
}
|
|
340
|
+
if (entry.blockedItems.length > 0) {
|
|
341
|
+
lines.push(`- 阻塞:${entry.blockedItems.map((item) => item.title).join(";")}`);
|
|
342
|
+
}
|
|
343
|
+
if (entry.note) {
|
|
344
|
+
lines.push(`- 备注:${entry.note}`);
|
|
345
|
+
}
|
|
346
|
+
lines.push(`- 建议命令:\`${entry.suggestedNextCommand}\``);
|
|
347
|
+
lines.push(`- 交接说明:${entry.handoffNote}`);
|
|
348
|
+
lines.push("");
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
lines.push("## 建议下一步命令", "", `- \`${log.suggestedNextCommand}\``);
|
|
352
|
+
|
|
353
|
+
if (log.alternateCommands.length > 0) {
|
|
354
|
+
lines.push("", "## 备选命令", "");
|
|
355
|
+
for (const command of log.alternateCommands) {
|
|
356
|
+
lines.push(`- \`${command}\``);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
lines.push("", "## 最新检查点", "", "```text", log.latestCheckpoint.checkpointPrompt, "```");
|
|
361
|
+
lines.push("", "## 可直接复制给 Agent 的 Decision Log Prompt", "", "```text", log.logPrompt, "```");
|
|
362
|
+
|
|
363
|
+
return `${lines.join("\n")}\n`;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export async function writeAgentDecisionLogOutput(outputPath, content) {
|
|
367
|
+
return writeScanOutput(outputPath, content);
|
|
368
|
+
}
|
|
@@ -168,6 +168,42 @@ function buildExecutionContextFromParsedArtifact(parsed, input) {
|
|
|
168
168
|
};
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
if (parsed?.kind === "geo-agent-decision-log" && parsed.latestCheckpoint?.statusBoard?.tracker?.applyPlan?.kind === "geo-apply-plan") {
|
|
172
|
+
return {
|
|
173
|
+
source:
|
|
174
|
+
parsed.source ||
|
|
175
|
+
parsed.latestCheckpoint.source ||
|
|
176
|
+
parsed.latestCheckpoint.statusBoard.source ||
|
|
177
|
+
parsed.latestCheckpoint.statusBoard.tracker.source ||
|
|
178
|
+
parsed.latestCheckpoint.statusBoard.tracker.applyPlan.source ||
|
|
179
|
+
input,
|
|
180
|
+
sourceType:
|
|
181
|
+
parsed.sourceType ||
|
|
182
|
+
parsed.latestCheckpoint.sourceType ||
|
|
183
|
+
parsed.latestCheckpoint.statusBoard.sourceType ||
|
|
184
|
+
parsed.latestCheckpoint.statusBoard.tracker.sourceType ||
|
|
185
|
+
parsed.latestCheckpoint.statusBoard.tracker.applyPlan.sourceType ||
|
|
186
|
+
"json",
|
|
187
|
+
artifactKind: parsed.kind,
|
|
188
|
+
applyPlan: parsed.latestCheckpoint.statusBoard.tracker.applyPlan,
|
|
189
|
+
trackerState: {
|
|
190
|
+
currentTaskId:
|
|
191
|
+
parsed.latestCheckpoint.currentPacket?.id ||
|
|
192
|
+
parsed.latestCheckpoint.statusBoard.tracker.currentTaskId ||
|
|
193
|
+
parsed.latestCheckpoint.statusBoard.tracker.activePacket?.id ||
|
|
194
|
+
null,
|
|
195
|
+
completedPacketIds:
|
|
196
|
+
parsed.latestCheckpoint.statusBoard.tracker.completedPacketIds ||
|
|
197
|
+
parsed.latestCheckpoint.completedPackets?.map((packet) => packet.id) ||
|
|
198
|
+
[],
|
|
199
|
+
blockedReasons:
|
|
200
|
+
parsed.latestCheckpoint.statusBoard.tracker.blockedReasons ||
|
|
201
|
+
parsed.latestCheckpoint.blockedItems?.map((item) => item.title) ||
|
|
202
|
+
[]
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
171
207
|
if (parsed?.kind === "geo-completion-report") {
|
|
172
208
|
return {
|
|
173
209
|
source: parsed.source || input,
|
package/src/agent-session.js
CHANGED
|
@@ -64,6 +64,9 @@ function inferSkillForCommand(commandName, flow) {
|
|
|
64
64
|
if (commandName === "agent-checkpoint") {
|
|
65
65
|
return "geo-ai-search-optimization-agent-checkpoint";
|
|
66
66
|
}
|
|
67
|
+
if (commandName === "agent-decision-log") {
|
|
68
|
+
return "geo-ai-search-optimization-agent-decision-log";
|
|
69
|
+
}
|
|
67
70
|
if (commandName === "skills" || commandName === "quick-start") {
|
|
68
71
|
return "geo-ai-search-optimization-usage";
|
|
69
72
|
}
|
|
@@ -136,6 +139,8 @@ function inferStepPurpose(commandName, flow) {
|
|
|
136
139
|
return "把当前执行状态整理成 PM 和 agent 都能直接消费的分栏看板。";
|
|
137
140
|
case "agent-checkpoint":
|
|
138
141
|
return "把当前阶段压成继续 / 阻塞 / 收尾的决策检查点。";
|
|
142
|
+
case "agent-decision-log":
|
|
143
|
+
return "把每一轮 checkpoint 沉淀成可继承的决策历史。";
|
|
139
144
|
case "apply-plan":
|
|
140
145
|
return "把交接结果推进到具体执行包。";
|
|
141
146
|
case "completion-report":
|
|
@@ -188,6 +193,8 @@ function inferExpectedArtifact(commandName) {
|
|
|
188
193
|
return "agent 执行状态看板";
|
|
189
194
|
case "agent-checkpoint":
|
|
190
195
|
return "agent 阶段检查点工件";
|
|
196
|
+
case "agent-decision-log":
|
|
197
|
+
return "agent 决策历史工件";
|
|
191
198
|
case "apply-plan":
|
|
192
199
|
return "执行包";
|
|
193
200
|
case "completion-report":
|
|
@@ -238,6 +245,9 @@ function buildStepInstructions(parsedCommand, flow) {
|
|
|
238
245
|
if (parsedCommand.commandName === "agent-checkpoint") {
|
|
239
246
|
lines.push("这一步用于明确此刻应该继续、先解除阻塞,还是进入收尾。");
|
|
240
247
|
}
|
|
248
|
+
if (parsedCommand.commandName === "agent-decision-log") {
|
|
249
|
+
lines.push("这一步用于保留跨轮决策历史,方便下一位 agent 直接承接上一次判断。");
|
|
250
|
+
}
|
|
241
251
|
if (parsedCommand.commandName === "agent-handoff" && flow.intent === "execute") {
|
|
242
252
|
lines.push("如果还是 advice-only,说明还缺仓库或本地项目上下文。");
|
|
243
253
|
}
|
|
@@ -154,6 +154,26 @@ async function resolveTracker(input, options = {}) {
|
|
|
154
154
|
: (parsed.statusBoard.tracker.blockedReasons || []).join(",")
|
|
155
155
|
});
|
|
156
156
|
}
|
|
157
|
+
if (parsed?.kind === "geo-agent-decision-log" && parsed.latestCheckpoint?.statusBoard?.tracker?.kind === "geo-agent-progress-tracker") {
|
|
158
|
+
return createAgentProgressTracker(
|
|
159
|
+
parsed.latestCheckpoint.statusBoard.tracker.source || parsed.latestCheckpoint.source || input,
|
|
160
|
+
{
|
|
161
|
+
format: "json",
|
|
162
|
+
currentTaskId:
|
|
163
|
+
options.currentTaskId ||
|
|
164
|
+
parsed.latestCheckpoint.currentPacket?.id ||
|
|
165
|
+
parsed.latestCheckpoint.statusBoard.tracker.currentTaskId,
|
|
166
|
+
completedPacketIds:
|
|
167
|
+
options.completedPacketIds != null
|
|
168
|
+
? options.completedPacketIds
|
|
169
|
+
: (parsed.latestCheckpoint.statusBoard.tracker.completedPacketIds || []).join(","),
|
|
170
|
+
blockedReasons:
|
|
171
|
+
options.blockedReasons != null
|
|
172
|
+
? options.blockedReasons
|
|
173
|
+
: (parsed.latestCheckpoint.statusBoard.tracker.blockedReasons || []).join(",")
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
}
|
|
157
177
|
} catch {
|
|
158
178
|
// Fall through to tracker generation
|
|
159
179
|
}
|
package/src/auto-flow.js
CHANGED
|
@@ -56,6 +56,9 @@ function inferTaskTextMode(text) {
|
|
|
56
56
|
if (/(checkpoint|检查点|阶段检查点|继续还是收尾|解除阻塞还是继续)/i.test(normalized)) {
|
|
57
57
|
return "execute";
|
|
58
58
|
}
|
|
59
|
+
if (/(decision-log|decision log|决策历史|决策日志|为什么这样决定|历史决策)/i.test(normalized)) {
|
|
60
|
+
return "execute";
|
|
61
|
+
}
|
|
59
62
|
if (/(executor|先做哪一个|先做哪一包|single task|执行第一包|先执行一个任务)/i.test(normalized)) {
|
|
60
63
|
return "execute";
|
|
61
64
|
}
|
|
@@ -177,6 +180,7 @@ function resolveEffectiveIntent(intent, detected) {
|
|
|
177
180
|
"geo-agent-progress-tracker",
|
|
178
181
|
"geo-agent-status-board",
|
|
179
182
|
"geo-agent-checkpoint",
|
|
183
|
+
"geo-agent-decision-log",
|
|
180
184
|
"geo-apply-plan",
|
|
181
185
|
"geo-handoff-bundle",
|
|
182
186
|
"geo-fix-plan"
|
|
@@ -373,6 +377,32 @@ function buildCommandChain(detected, intent) {
|
|
|
373
377
|
`geo-ai-search-optimization agent-progress-tracker ${source}`,
|
|
374
378
|
`geo-ai-search-optimization completion-report ${source}`
|
|
375
379
|
];
|
|
380
|
+
case "geo-agent-decision-log": {
|
|
381
|
+
const baseSource = detected.parsed?.latestCheckpoint?.source || detected.parsed?.source || source;
|
|
382
|
+
const latestDecision = detected.parsed?.latestDecision;
|
|
383
|
+
const suggestedNext =
|
|
384
|
+
detected.parsed?.suggestedNextCommand ||
|
|
385
|
+
detected.parsed?.latestCheckpoint?.suggestedNextCommand ||
|
|
386
|
+
`geo-ai-search-optimization agent-executor ${baseSource}`;
|
|
387
|
+
|
|
388
|
+
return latestDecision === "move-to-closeout"
|
|
389
|
+
? [
|
|
390
|
+
`geo-ai-search-optimization completion-report ${baseSource}`,
|
|
391
|
+
`geo-ai-search-optimization handoff-bundle ${baseSource}`,
|
|
392
|
+
`geo-ai-search-optimization publish-pack ${baseSource}`
|
|
393
|
+
]
|
|
394
|
+
: latestDecision === "resolve-blockers"
|
|
395
|
+
? [
|
|
396
|
+
suggestedNext,
|
|
397
|
+
`geo-ai-search-optimization agent-status-board ${source}`,
|
|
398
|
+
`geo-ai-search-optimization agent-decision-log ${baseSource} --append-from ${source}`
|
|
399
|
+
]
|
|
400
|
+
: [
|
|
401
|
+
suggestedNext,
|
|
402
|
+
`geo-ai-search-optimization agent-progress-tracker ${source}`,
|
|
403
|
+
`geo-ai-search-optimization agent-decision-log ${baseSource} --append-from ${source}`
|
|
404
|
+
];
|
|
405
|
+
}
|
|
376
406
|
case "geo-apply-plan":
|
|
377
407
|
return [
|
|
378
408
|
`geo-ai-search-optimization agent-executor ${source}`,
|
|
@@ -454,6 +484,8 @@ function pickSkillName(detected, intent) {
|
|
|
454
484
|
return "geo-ai-search-optimization-agent-status-board";
|
|
455
485
|
case "geo-agent-checkpoint":
|
|
456
486
|
return "geo-ai-search-optimization-agent-checkpoint";
|
|
487
|
+
case "geo-agent-decision-log":
|
|
488
|
+
return "geo-ai-search-optimization-agent-decision-log";
|
|
457
489
|
case "geo-completion-report":
|
|
458
490
|
return "geo-ai-search-optimization-completion-report";
|
|
459
491
|
case "geo-handoff-bundle":
|
|
@@ -494,6 +526,7 @@ function buildSecondarySkillNames(primarySkill, intent, detected) {
|
|
|
494
526
|
"geo-agent-progress-tracker",
|
|
495
527
|
"geo-agent-status-board",
|
|
496
528
|
"geo-agent-checkpoint",
|
|
529
|
+
"geo-agent-decision-log",
|
|
497
530
|
"geo-apply-plan"
|
|
498
531
|
].includes(
|
|
499
532
|
detected.artifactKind
|
|
@@ -503,6 +536,7 @@ function buildSecondarySkillNames(primarySkill, intent, detected) {
|
|
|
503
536
|
names.add("geo-ai-search-optimization-agent-progress-tracker");
|
|
504
537
|
names.add("geo-ai-search-optimization-agent-status-board");
|
|
505
538
|
names.add("geo-ai-search-optimization-agent-checkpoint");
|
|
539
|
+
names.add("geo-ai-search-optimization-agent-decision-log");
|
|
506
540
|
names.add("geo-ai-search-optimization-agent-executor");
|
|
507
541
|
names.add("geo-ai-search-optimization-agent-runbook");
|
|
508
542
|
names.add("geo-ai-search-optimization-agent-handoff");
|
|
@@ -536,6 +570,7 @@ function buildStage(intent, detected) {
|
|
|
536
570
|
"geo-agent-progress-tracker",
|
|
537
571
|
"geo-agent-status-board",
|
|
538
572
|
"geo-agent-checkpoint",
|
|
573
|
+
"geo-agent-decision-log",
|
|
539
574
|
"geo-apply-plan",
|
|
540
575
|
"geo-handoff-bundle"
|
|
541
576
|
].includes(detected.artifactKind)
|
|
@@ -552,6 +587,7 @@ function buildStage(intent, detected) {
|
|
|
552
587
|
"geo-agent-progress-tracker",
|
|
553
588
|
"geo-agent-status-board",
|
|
554
589
|
"geo-agent-checkpoint",
|
|
590
|
+
"geo-agent-decision-log",
|
|
555
591
|
"geo-apply-plan",
|
|
556
592
|
"geo-handoff-bundle"
|
|
557
593
|
].includes(detected.artifactKind)
|
|
@@ -641,6 +677,9 @@ function buildNextAction(detected, intent, commands) {
|
|
|
641
677
|
if (detected.artifactKind === "geo-agent-progress-tracker") {
|
|
642
678
|
return `先运行 \`${commands[0]}\`,继续当前执行包或校准下一包。`;
|
|
643
679
|
}
|
|
680
|
+
if (detected.artifactKind === "geo-agent-decision-log") {
|
|
681
|
+
return `先运行 \`${commands[0]}\`,沿着最近一次阶段决策继续推进,而不是重新判断整条链。`;
|
|
682
|
+
}
|
|
644
683
|
return `先运行 \`${commands[0]}\`,把当前输入推进到 agent 可执行状态。`;
|
|
645
684
|
}
|
|
646
685
|
if (intent === "closeout") {
|
package/src/cli.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
writeAgentProgressTrackerOutput
|
|
16
16
|
} from "./agent-progress-tracker.js";
|
|
17
17
|
import { createAgentCheckpoint, renderAgentCheckpointMarkdown, writeAgentCheckpointOutput } from "./agent-checkpoint.js";
|
|
18
|
+
import { createAgentDecisionLog, renderAgentDecisionLogMarkdown, writeAgentDecisionLogOutput } from "./agent-decision-log.js";
|
|
18
19
|
import { createAgentStatusBoard, renderAgentStatusBoardMarkdown, writeAgentStatusBoardOutput } from "./agent-status-board.js";
|
|
19
20
|
import { createAgentRunbook, renderAgentRunbookMarkdown, writeAgentRunbookOutput } from "./agent-runbook.js";
|
|
20
21
|
import { createAgentSession, renderAgentSessionMarkdown, writeAgentSessionOutput } from "./agent-session.js";
|
|
@@ -81,6 +82,7 @@ function printHelp() {
|
|
|
81
82
|
" geo-ai-search-optimization agent-progress-tracker <input> [--current <id>] [--completed <id,id>] [--blocked <reason,reason>] [--format <markdown|json>] [--out <file>]",
|
|
82
83
|
" geo-ai-search-optimization agent-status-board <input> [--current <id>] [--completed <id,id>] [--blocked <reason,reason>] [--format <markdown|json>] [--out <file>]",
|
|
83
84
|
" geo-ai-search-optimization agent-checkpoint <input> [--current <id>] [--completed <id,id>] [--blocked <reason,reason>] [--format <markdown|json>] [--out <file>]",
|
|
85
|
+
" geo-ai-search-optimization agent-decision-log <input> [--append-from <file>] [--note <text>] [--current <id>] [--completed <id,id>] [--blocked <reason,reason>] [--format <markdown|json>] [--out <file>]",
|
|
84
86
|
" geo-ai-search-optimization skills [--json]",
|
|
85
87
|
" geo-ai-search-optimization where",
|
|
86
88
|
" geo-ai-search-optimization doctor [--json]",
|
|
@@ -363,6 +365,36 @@ async function handleAgentCheckpoint(args) {
|
|
|
363
365
|
process.stdout.write(renderedOutput);
|
|
364
366
|
}
|
|
365
367
|
|
|
368
|
+
async function handleAgentDecisionLog(args) {
|
|
369
|
+
const input = args.find((value) => !value.startsWith("-"));
|
|
370
|
+
if (!input) {
|
|
371
|
+
throw new Error("agent-decision-log 需要一个输入值,可以是项目路径、网站网址或已导出的工件");
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const format = getFlagValue(args, "--format") || (hasFlag(args, "--json") ? "json" : undefined);
|
|
375
|
+
const decisionLog = await createAgentDecisionLog(input, {
|
|
376
|
+
format,
|
|
377
|
+
appendFrom: getFlagValue(args, "--append-from"),
|
|
378
|
+
note: getFlagValue(args, "--note"),
|
|
379
|
+
currentTaskId: getFlagValue(args, "--current"),
|
|
380
|
+
completedPacketIds: getFlagValue(args, "--completed"),
|
|
381
|
+
blockedReasons: getFlagValue(args, "--blocked")
|
|
382
|
+
});
|
|
383
|
+
const outputJson = decisionLog.format === "json";
|
|
384
|
+
const renderedOutput = outputJson
|
|
385
|
+
? `${JSON.stringify(decisionLog, null, 2)}\n`
|
|
386
|
+
: renderAgentDecisionLogMarkdown(decisionLog);
|
|
387
|
+
|
|
388
|
+
const outputPath = getFlagValue(args, "--out");
|
|
389
|
+
if (outputPath) {
|
|
390
|
+
const resolvedOutputPath = await writeAgentDecisionLogOutput(outputPath, renderedOutput);
|
|
391
|
+
process.stdout.write(`已保存 agent decision log:${resolvedOutputPath}\n`);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
process.stdout.write(renderedOutput);
|
|
396
|
+
}
|
|
397
|
+
|
|
366
398
|
function handleWhere() {
|
|
367
399
|
process.stdout.write(
|
|
368
400
|
[
|
|
@@ -943,6 +975,11 @@ export async function runCli(args = []) {
|
|
|
943
975
|
return;
|
|
944
976
|
}
|
|
945
977
|
|
|
978
|
+
if (command === "agent-decision-log") {
|
|
979
|
+
await handleAgentDecisionLog(rest);
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
|
|
946
983
|
if (command === "skills") {
|
|
947
984
|
await handleSkills(rest);
|
|
948
985
|
return;
|
package/src/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { createAutoFlow, renderAutoFlowMarkdown, writeAutoFlowOutput } from "./a
|
|
|
9
9
|
export { createApplyPlan, renderApplyPlanMarkdown, writeApplyPlanOutput } from "./apply-plan.js";
|
|
10
10
|
export { createAgentBatchExecutor, renderAgentBatchExecutorMarkdown, writeAgentBatchExecutorOutput } from "./agent-batch-executor.js";
|
|
11
11
|
export { createAgentCheckpoint, renderAgentCheckpointMarkdown, writeAgentCheckpointOutput } from "./agent-checkpoint.js";
|
|
12
|
+
export { createAgentDecisionLog, renderAgentDecisionLogMarkdown, writeAgentDecisionLogOutput } from "./agent-decision-log.js";
|
|
12
13
|
export { createAgentHandoff, renderAgentHandoffMarkdown, writeAgentHandoffOutput } from "./agent-handoff.js";
|
|
13
14
|
export { createAgentExecutor, renderAgentExecutorMarkdown, writeAgentExecutorOutput } from "./agent-executor.js";
|
|
14
15
|
export {
|
package/src/skills.js
CHANGED
|
@@ -12,6 +12,7 @@ const SKILL_ORDER = [
|
|
|
12
12
|
"geo-ai-search-optimization-agent-progress-tracker",
|
|
13
13
|
"geo-ai-search-optimization-agent-status-board",
|
|
14
14
|
"geo-ai-search-optimization-agent-checkpoint",
|
|
15
|
+
"geo-ai-search-optimization-agent-decision-log",
|
|
15
16
|
"geo-ai-search-optimization-usage",
|
|
16
17
|
"geo-ai-search-optimization-agent-handoff",
|
|
17
18
|
"geo-ai-search-optimization-repair-loop",
|
|
@@ -33,6 +34,7 @@ const SKILL_CATEGORY = {
|
|
|
33
34
|
"geo-ai-search-optimization-agent-progress-tracker": "execution",
|
|
34
35
|
"geo-ai-search-optimization-agent-status-board": "execution",
|
|
35
36
|
"geo-ai-search-optimization-agent-checkpoint": "execution",
|
|
37
|
+
"geo-ai-search-optimization-agent-decision-log": "execution",
|
|
36
38
|
"geo-ai-search-optimization-usage": "guidance",
|
|
37
39
|
"geo-ai-search-optimization-agent-handoff": "execution",
|
|
38
40
|
"geo-ai-search-optimization-repair-loop": "execution",
|
|
@@ -173,6 +175,7 @@ export function renderBundledSkillsMarkdown(bundle) {
|
|
|
173
175
|
"- 如果要追踪目前做到第几包、卡在哪、下一包是什么,再进入 agent-progress-tracker。",
|
|
174
176
|
"- 如果要把当前执行状态直接整理成看板,再进入 agent-status-board。",
|
|
175
177
|
"- 如果要在每轮结束时做继续 / 阻塞 / 收尾决策,再进入 agent-checkpoint。",
|
|
178
|
+
"- 如果要把多轮决策沉淀成可继承的历史,再进入 agent-decision-log。",
|
|
176
179
|
"- 再看 usage skill,知道什么时候该跑哪个命令。",
|
|
177
180
|
"- 如果要交给 agent 执行,再进入 handoff / apply / completion 这一条执行链。",
|
|
178
181
|
"- 如果要产出给团队分发,再进入 share / export / html / publish 这一条交付链。",
|