geo-ai-search-optimization 1.2.6 → 1.2.8
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 +55 -0
- package/package.json +1 -1
- package/resources/geo-ai-search-optimization/references/skill-bundle-map.md +23 -0
- package/resources/geo-ai-search-optimization-agent-session/SKILL.md +24 -0
- package/resources/geo-ai-search-optimization-agent-session/agents/openai.yaml +4 -0
- package/resources/geo-ai-search-optimization-auto-flow/SKILL.md +23 -0
- package/resources/geo-ai-search-optimization-auto-flow/agents/openai.yaml +4 -0
- package/resources/geo-ai-search-optimization-usage/SKILL.md +25 -15
- package/src/agent-session.js +297 -0
- package/src/auto-flow.js +563 -0
- package/src/cli.js +60 -0
- package/src/index.js +2 -0
- package/src/skills.js +6 -0
package/README.md
CHANGED
|
@@ -42,6 +42,45 @@ geo-ai-search-optimization skills --json
|
|
|
42
42
|
- agent 执行闭环相关 skills
|
|
43
43
|
- 分享 / 导出 / 最终交付相关 skills
|
|
44
44
|
|
|
45
|
+
## Auto Flow 命令
|
|
46
|
+
|
|
47
|
+
如果你希望 agent 不用自己判断现在该用哪个 skill、该跑哪个命令,可以直接用 `auto-flow`:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
geo-ai-search-optimization auto-flow "我想把这份 GEO 结果交给下一个 agent 继续修"
|
|
51
|
+
geo-ai-search-optimization auto-flow https://example.com
|
|
52
|
+
geo-ai-search-optimization auto-flow ./your-site
|
|
53
|
+
geo-ai-search-optimization auto-flow ./reports/apply-plan.json --json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
它会自动输出:
|
|
57
|
+
|
|
58
|
+
- 当前输入属于哪一类
|
|
59
|
+
- 现在更像诊断、执行、复盘还是交付阶段
|
|
60
|
+
- 最适合的下一个 skill
|
|
61
|
+
- 建议命令顺序
|
|
62
|
+
- 可直接复制给 agent 的 prompt
|
|
63
|
+
|
|
64
|
+
## Agent Session 命令
|
|
65
|
+
|
|
66
|
+
如果你希望不只是“选 skill”,而是直接产出一份给 agent 跟着执行的会话包,可以用 `agent-session`:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
geo-ai-search-optimization agent-session "我想把这份 GEO 结果交给下一个 agent 继续修"
|
|
70
|
+
geo-ai-search-optimization agent-session https://example.com
|
|
71
|
+
geo-ai-search-optimization agent-session ./your-site
|
|
72
|
+
geo-ai-search-optimization agent-session ./reports/apply-plan.json --json
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
它会输出:
|
|
76
|
+
|
|
77
|
+
- 当前阶段与会话状态
|
|
78
|
+
- 会话目标
|
|
79
|
+
- 自动选择的 skill
|
|
80
|
+
- 一步步该跑什么命令
|
|
81
|
+
- 每一步的目的与预期产物
|
|
82
|
+
- 可直接复制给 agent 的 session prompt
|
|
83
|
+
|
|
45
84
|
## Quick Start
|
|
46
85
|
|
|
47
86
|
如果你要从 0 到 1 启动一个 GEO 项目,建议照这个顺序做。
|
|
@@ -435,6 +474,8 @@ geo-ai-search-optimization onboard --url https://example.com --json --out ./repo
|
|
|
435
474
|
geo-ai-search-optimization
|
|
436
475
|
geo-ai-search-optimization install
|
|
437
476
|
geo-ai-search-optimization install --target ./tmp/custom-skills --json
|
|
477
|
+
geo-ai-search-optimization auto-flow "audit this site and tell me the next skill"
|
|
478
|
+
geo-ai-search-optimization agent-session ./your-site
|
|
438
479
|
geo-ai-search-optimization skills
|
|
439
480
|
geo-ai-search-optimization where
|
|
440
481
|
geo-ai-search-optimization doctor
|
|
@@ -477,6 +518,20 @@ geo-ai-search-optimization help
|
|
|
477
518
|
- 为缺失的 skill 补齐 `agents/openai.yaml`
|
|
478
519
|
- 主 skill 新增 `skill-bundle-map` 参考,usage skill 也同步纳入 `publish-pack` 和 `skills`
|
|
479
520
|
|
|
521
|
+
## New in 1.2.7
|
|
522
|
+
|
|
523
|
+
- 新增 `auto-flow` 命令,自动选择下一步该用哪个 GEO skill
|
|
524
|
+
- 支持任务描述、网站网址、本地项目目录和 JSON 工件作为输入
|
|
525
|
+
- 输出推荐 skill、命令顺序与可直接复制给 agent 的 prompt
|
|
526
|
+
- 新增 `geo-ai-search-optimization-auto-flow` skill,作为 agent 的自动路由入口
|
|
527
|
+
|
|
528
|
+
## New in 1.2.8
|
|
529
|
+
|
|
530
|
+
- 新增 `agent-session` 命令,生成给 agent 跟着执行的会话包
|
|
531
|
+
- 在 `auto-flow` 之上补上步骤级说明、预期产物和 session prompt
|
|
532
|
+
- 新增 `geo-ai-search-optimization-agent-session` skill
|
|
533
|
+
- 更适合把 GEO 任务直接交给下一个 agent 连续推进
|
|
534
|
+
|
|
480
535
|
## New in 1.2.5
|
|
481
536
|
|
|
482
537
|
- 新增 `publish-pack`
|
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
## Table of Contents
|
|
4
4
|
|
|
5
5
|
- Core skill
|
|
6
|
+
- Auto entry
|
|
6
7
|
- Usage guide
|
|
7
8
|
- Agent execution loop
|
|
8
9
|
- Delivery chain
|
|
@@ -19,6 +20,28 @@ Best for:
|
|
|
19
20
|
- improving answerability, structure, and citation readiness
|
|
20
21
|
- deciding what the highest-impact GEO fixes are
|
|
21
22
|
|
|
23
|
+
## Auto entry
|
|
24
|
+
|
|
25
|
+
### `geo-ai-search-optimization-auto-flow`
|
|
26
|
+
|
|
27
|
+
Use this when the next agent needs a routing entrypoint and should not have to decide manually which skill to use.
|
|
28
|
+
|
|
29
|
+
Best for:
|
|
30
|
+
|
|
31
|
+
- selecting the next skill from a URL, directory, or artifact
|
|
32
|
+
- turning one-line task briefs into a concrete command sequence
|
|
33
|
+
- deciding whether the work should move into diagnosis, execution, closeout, or delivery
|
|
34
|
+
|
|
35
|
+
### `geo-ai-search-optimization-agent-session`
|
|
36
|
+
|
|
37
|
+
Use this when the next agent needs a runnable session plan, not just a routing answer.
|
|
38
|
+
|
|
39
|
+
Best for:
|
|
40
|
+
|
|
41
|
+
- turning `auto-flow` output into a step-by-step execution sequence
|
|
42
|
+
- giving the next agent a first command, second command, and expected artifact list
|
|
43
|
+
- reducing ambiguity at handoff time
|
|
44
|
+
|
|
22
45
|
## Usage guide
|
|
23
46
|
|
|
24
47
|
### `geo-ai-search-optimization-usage`
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: geo-ai-search-optimization-agent-session
|
|
3
|
+
description: Turn a GEO input into a step-by-step agent session plan. Use when an agent should not only pick the next GEO skill, but also receive a runnable session sequence with step goals, expected artifacts, and a copyable session prompt.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GEO Agent Session
|
|
7
|
+
|
|
8
|
+
Use this skill when the next agent should receive a full GEO session plan instead of only a routing recommendation.
|
|
9
|
+
|
|
10
|
+
`GEO = Generative Engine Optimization`
|
|
11
|
+
|
|
12
|
+
## What it does
|
|
13
|
+
|
|
14
|
+
- choose the current GEO stage
|
|
15
|
+
- choose the right next skill
|
|
16
|
+
- build a step-by-step command sequence
|
|
17
|
+
- explain what each step should produce
|
|
18
|
+
- generate a copyable session prompt
|
|
19
|
+
|
|
20
|
+
## Best use
|
|
21
|
+
|
|
22
|
+
- start a new agent run from a URL, project directory, or GEO artifact
|
|
23
|
+
- turn `auto-flow` output into an execution-ready session
|
|
24
|
+
- hand another agent a clear “do this first, then this” sequence
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "GEO Agent Session"
|
|
3
|
+
short_description: "Build a runnable GEO session for the next agent"
|
|
4
|
+
default_prompt: "Use $geo-ai-search-optimization-agent-session to turn this input into a runnable GEO agent session with step order, expected outputs, and a session prompt."
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: geo-ai-search-optimization-auto-flow
|
|
3
|
+
description: Automatically choose the next GEO skill and command chain from a task description, website URL, local project directory, or existing GEO artifact. Use when an agent needs a routing entrypoint to decide which GEO skill to invoke next and what commands should follow.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GEO Auto Flow
|
|
7
|
+
|
|
8
|
+
Use this skill when the next agent should not have to guess which GEO skill to use.
|
|
9
|
+
|
|
10
|
+
`GEO = Generative Engine Optimization`
|
|
11
|
+
|
|
12
|
+
## What it does
|
|
13
|
+
|
|
14
|
+
- identify whether the input is a task brief, URL, project directory, or GEO artifact
|
|
15
|
+
- route to the most suitable next GEO skill
|
|
16
|
+
- recommend the next commands
|
|
17
|
+
- generate a copyable agent prompt
|
|
18
|
+
|
|
19
|
+
## Best use
|
|
20
|
+
|
|
21
|
+
- start a new agent session from one line of user input
|
|
22
|
+
- continue from an existing GEO artifact without re-reading the whole system
|
|
23
|
+
- decide whether the next move is diagnosis, execution, closeout, or delivery
|
|
@@ -13,27 +13,31 @@ 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
|
|
17
|
-
|
|
18
|
-
1. `
|
|
19
|
-
2. `
|
|
20
|
-
3. `
|
|
21
|
-
4. `
|
|
22
|
-
5. `
|
|
23
|
-
6. `
|
|
24
|
-
7. `
|
|
25
|
-
8. `
|
|
26
|
-
9. `
|
|
27
|
-
10. `
|
|
28
|
-
11. `
|
|
29
|
-
12. `
|
|
30
|
-
13. `
|
|
16
|
+
The package is best explained as fifteen layers:
|
|
17
|
+
|
|
18
|
+
1. `auto-flow`: auto-select the next skill and command chain
|
|
19
|
+
2. `agent-session`: build a runnable session for the next agent
|
|
20
|
+
3. `skills`: inspect the bundled skill package
|
|
21
|
+
4. `onboard-url` / `onboard`: first look
|
|
22
|
+
5. `scan`: raw signal check
|
|
23
|
+
6. `audit` / `report`: diagnosis
|
|
24
|
+
7. `fix-plan` / `owner-board`: execution planning
|
|
25
|
+
8. `agent-handoff`: agent takeover package
|
|
26
|
+
9. `apply-plan`: execution loop
|
|
27
|
+
10. `completion-report`: closeout
|
|
28
|
+
11. `handoff-bundle`: all-in-one package
|
|
29
|
+
12. `share-pack`: audience-ready delivery
|
|
30
|
+
13. `export-pack`: folder export
|
|
31
|
+
14. `html-pack` / `publish-pack`: browsable and final delivery output
|
|
32
|
+
15. `pm-brief` / `roadmap`: stakeholder alignment
|
|
31
33
|
|
|
32
34
|
## Recommended command order
|
|
33
35
|
|
|
34
36
|
If the user only has a website URL:
|
|
35
37
|
|
|
36
38
|
```bash
|
|
39
|
+
npx geo-ai-search-optimization auto-flow https://example.com
|
|
40
|
+
npx geo-ai-search-optimization agent-session https://example.com
|
|
37
41
|
npx geo-ai-search-optimization onboard-url https://example.com
|
|
38
42
|
npx geo-ai-search-optimization pm-brief https://example.com
|
|
39
43
|
npx geo-ai-search-optimization roadmap https://example.com
|
|
@@ -42,6 +46,8 @@ npx geo-ai-search-optimization roadmap https://example.com
|
|
|
42
46
|
If the user has the website codebase:
|
|
43
47
|
|
|
44
48
|
```bash
|
|
49
|
+
npx geo-ai-search-optimization auto-flow ./your-site
|
|
50
|
+
npx geo-ai-search-optimization agent-session ./your-site
|
|
45
51
|
npx geo-ai-search-optimization scan ./your-site
|
|
46
52
|
npx geo-ai-search-optimization audit ./your-site
|
|
47
53
|
npx geo-ai-search-optimization fix-plan ./your-site
|
|
@@ -59,6 +65,8 @@ npx geo-ai-search-optimization roadmap ./your-site
|
|
|
59
65
|
|
|
60
66
|
## When to recommend each command
|
|
61
67
|
|
|
68
|
+
- `auto-flow`: auto-select the next skill and command order from a task brief, URL, project path, or GEO artifact
|
|
69
|
+
- `agent-session`: build a step-by-step session packet for the next agent from the same kinds of inputs
|
|
62
70
|
- `onboard-url`: first-time website check from a live URL
|
|
63
71
|
- `onboard`: interactive first-time onboarding
|
|
64
72
|
- `skills`: list the bundled skills and decide which skill or command chain fits the task
|
|
@@ -83,6 +91,8 @@ npx geo-ai-search-optimization roadmap ./your-site
|
|
|
83
91
|
When explaining the tool to a user:
|
|
84
92
|
|
|
85
93
|
- prefer telling them which command to run next, not listing every command
|
|
94
|
+
- if the user or the next agent is unsure where to start, move them to `auto-flow` first
|
|
95
|
+
- if the user wants something the next agent can follow step by step, move them to `agent-session`
|
|
86
96
|
- explain the result in PM language, not implementation jargon
|
|
87
97
|
- if the user sounds new, start with `onboard-url` or `quick-start`
|
|
88
98
|
- if the user wants another agent to take over, move them to `agent-handoff`
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { createAutoFlow } from "./auto-flow.js";
|
|
2
|
+
import { writeScanOutput } from "./scan.js";
|
|
3
|
+
|
|
4
|
+
function inferSessionStatus(flow) {
|
|
5
|
+
if (flow.contextNeeded.length > 0) {
|
|
6
|
+
return "needs-context";
|
|
7
|
+
}
|
|
8
|
+
if (flow.intent === "share") {
|
|
9
|
+
return "delivery-ready";
|
|
10
|
+
}
|
|
11
|
+
if (flow.intent === "closeout") {
|
|
12
|
+
return "closeout-ready";
|
|
13
|
+
}
|
|
14
|
+
if (flow.intent === "execute") {
|
|
15
|
+
return "execution-ready";
|
|
16
|
+
}
|
|
17
|
+
return "analysis-ready";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function inferSessionGoal(flow) {
|
|
21
|
+
if (flow.intent === "share") {
|
|
22
|
+
return "把当前 GEO 结果整理成适合分享、外发或交接的产物。";
|
|
23
|
+
}
|
|
24
|
+
if (flow.intent === "closeout") {
|
|
25
|
+
return "整理本轮 GEO 执行结果、剩余风险和下一轮任务。";
|
|
26
|
+
}
|
|
27
|
+
if (flow.intent === "execute") {
|
|
28
|
+
return "把当前输入推进到 agent 可接手、可执行、可验证的 GEO 修复链。";
|
|
29
|
+
}
|
|
30
|
+
if (flow.intent === "guide") {
|
|
31
|
+
return "明确现在该用哪个 skill、该跑哪些命令,以及先后顺序。";
|
|
32
|
+
}
|
|
33
|
+
return "建立当前 GEO 状态、优先级和下一步执行方向。";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function parseCommand(command) {
|
|
37
|
+
const parts = String(command).trim().split(/\s+/);
|
|
38
|
+
const commandName = parts[1] || parts[0] || "";
|
|
39
|
+
return {
|
|
40
|
+
raw: command,
|
|
41
|
+
commandName
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function inferSkillForCommand(commandName, flow) {
|
|
46
|
+
if (commandName === "auto-flow") {
|
|
47
|
+
return "geo-ai-search-optimization-auto-flow";
|
|
48
|
+
}
|
|
49
|
+
if (commandName === "skills" || commandName === "quick-start") {
|
|
50
|
+
return "geo-ai-search-optimization-usage";
|
|
51
|
+
}
|
|
52
|
+
if (["share-pack"].includes(commandName)) {
|
|
53
|
+
return "geo-ai-search-optimization-share-pack";
|
|
54
|
+
}
|
|
55
|
+
if (["export-pack"].includes(commandName)) {
|
|
56
|
+
return "geo-ai-search-optimization-export-pack";
|
|
57
|
+
}
|
|
58
|
+
if (["html-pack"].includes(commandName)) {
|
|
59
|
+
return "geo-ai-search-optimization-html-pack";
|
|
60
|
+
}
|
|
61
|
+
if (["publish-pack"].includes(commandName)) {
|
|
62
|
+
return "geo-ai-search-optimization-publish-pack";
|
|
63
|
+
}
|
|
64
|
+
if (["agent-handoff"].includes(commandName)) {
|
|
65
|
+
return "geo-ai-search-optimization-agent-handoff";
|
|
66
|
+
}
|
|
67
|
+
if (["apply-plan"].includes(commandName)) {
|
|
68
|
+
return "geo-ai-search-optimization-repair-loop";
|
|
69
|
+
}
|
|
70
|
+
if (["completion-report"].includes(commandName)) {
|
|
71
|
+
return "geo-ai-search-optimization-completion-report";
|
|
72
|
+
}
|
|
73
|
+
if (["handoff-bundle"].includes(commandName)) {
|
|
74
|
+
return "geo-ai-search-optimization-handoff-bundle";
|
|
75
|
+
}
|
|
76
|
+
if (["onboard", "onboard-url", "scan", "audit", "report", "fix-plan", "owner-board", "pm-brief", "roadmap", "meeting-pack", "exec-summary"].includes(commandName)) {
|
|
77
|
+
return flow.selectedSkill.name === "geo-ai-search-optimization-usage"
|
|
78
|
+
? "geo-ai-search-optimization"
|
|
79
|
+
: flow.selectedSkill.name;
|
|
80
|
+
}
|
|
81
|
+
return flow.selectedSkill.name;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function inferStepPurpose(commandName, flow) {
|
|
85
|
+
switch (commandName) {
|
|
86
|
+
case "skills":
|
|
87
|
+
return "先理解当前技能包结构,避免 agent 选错链路。";
|
|
88
|
+
case "quick-start":
|
|
89
|
+
return "快速建立从 0 到 1 的执行顺序。";
|
|
90
|
+
case "onboard":
|
|
91
|
+
case "onboard-url":
|
|
92
|
+
return "先从网址或引导流程拿到首轮 GEO 判断。";
|
|
93
|
+
case "scan":
|
|
94
|
+
return "先做原始信号扫描,确认基础缺口。";
|
|
95
|
+
case "audit":
|
|
96
|
+
return "拿到分数、问题区域和优先级。";
|
|
97
|
+
case "report":
|
|
98
|
+
return "把当前结果整理成可读报告。";
|
|
99
|
+
case "fix-plan":
|
|
100
|
+
return "把诊断结果转成待办和优先级。";
|
|
101
|
+
case "owner-board":
|
|
102
|
+
return "把任务按角色拆开,方便 PM 与执行团队分工。";
|
|
103
|
+
case "pm-brief":
|
|
104
|
+
return "先给 PM 一个可快速理解的摘要。";
|
|
105
|
+
case "roadmap":
|
|
106
|
+
return "把修复顺序转成阶段计划。";
|
|
107
|
+
case "agent-handoff":
|
|
108
|
+
return "把当前结果交接成 agent 可继续执行的工件。";
|
|
109
|
+
case "apply-plan":
|
|
110
|
+
return "把交接结果推进到具体执行包。";
|
|
111
|
+
case "completion-report":
|
|
112
|
+
return "整理本轮完成项、剩余风险和下一轮动作。";
|
|
113
|
+
case "handoff-bundle":
|
|
114
|
+
return "把交接、执行与复盘整成一个总包。";
|
|
115
|
+
case "share-pack":
|
|
116
|
+
return "给不同角色生成可直接分享的视图。";
|
|
117
|
+
case "export-pack":
|
|
118
|
+
return "把分享结果导出成目录文件。";
|
|
119
|
+
case "html-pack":
|
|
120
|
+
return "把产物转成可浏览页面。";
|
|
121
|
+
case "publish-pack":
|
|
122
|
+
return "形成最终可交付包。";
|
|
123
|
+
default:
|
|
124
|
+
return "推进当前 GEO 会话到下一阶段。";
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function inferExpectedArtifact(commandName) {
|
|
129
|
+
switch (commandName) {
|
|
130
|
+
case "onboard":
|
|
131
|
+
case "onboard-url":
|
|
132
|
+
return "网址级 onboarding 结果";
|
|
133
|
+
case "scan":
|
|
134
|
+
return "基础信号扫描结果";
|
|
135
|
+
case "audit":
|
|
136
|
+
return "GEO 审计结果";
|
|
137
|
+
case "report":
|
|
138
|
+
return "可读报告";
|
|
139
|
+
case "fix-plan":
|
|
140
|
+
return "待办清单与优先级";
|
|
141
|
+
case "owner-board":
|
|
142
|
+
return "角色分栏任务板";
|
|
143
|
+
case "pm-brief":
|
|
144
|
+
return "PM 摘要";
|
|
145
|
+
case "roadmap":
|
|
146
|
+
return "阶段路线图";
|
|
147
|
+
case "agent-handoff":
|
|
148
|
+
return "agent 交接工件";
|
|
149
|
+
case "apply-plan":
|
|
150
|
+
return "执行包";
|
|
151
|
+
case "completion-report":
|
|
152
|
+
return "复盘工件";
|
|
153
|
+
case "handoff-bundle":
|
|
154
|
+
return "执行总包";
|
|
155
|
+
case "share-pack":
|
|
156
|
+
return "角色化分享包";
|
|
157
|
+
case "export-pack":
|
|
158
|
+
return "导出目录";
|
|
159
|
+
case "html-pack":
|
|
160
|
+
return "HTML 页面包";
|
|
161
|
+
case "publish-pack":
|
|
162
|
+
return "最终可交付包";
|
|
163
|
+
default:
|
|
164
|
+
return "阶段性 GEO 输出";
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function buildStepInstructions(parsedCommand, flow) {
|
|
169
|
+
const lines = [
|
|
170
|
+
`运行 \`${parsedCommand.raw}\`。`,
|
|
171
|
+
inferStepPurpose(parsedCommand.commandName, flow),
|
|
172
|
+
`预期得到:${inferExpectedArtifact(parsedCommand.commandName)}。`
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
if (parsedCommand.commandName === "publish-pack") {
|
|
176
|
+
lines.push("完成后把 `START-HERE.md` 和 `AGENT-START.md` 当作最终入口。");
|
|
177
|
+
}
|
|
178
|
+
if (parsedCommand.commandName === "apply-plan") {
|
|
179
|
+
lines.push("执行包出来后,优先从第一包开始,不要同时展开太多任务。");
|
|
180
|
+
}
|
|
181
|
+
if (parsedCommand.commandName === "agent-handoff" && flow.intent === "execute") {
|
|
182
|
+
lines.push("如果还是 advice-only,说明还缺仓库或本地项目上下文。");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return lines;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function buildSessionPrompt(flow, steps) {
|
|
189
|
+
const lines = [
|
|
190
|
+
`Use $${flow.selectedSkill.name} to continue this GEO session.`,
|
|
191
|
+
`当前输入:${flow.source}`,
|
|
192
|
+
`当前阶段:${flow.stage}`,
|
|
193
|
+
`当前意图:${flow.intent}`,
|
|
194
|
+
`会话目标:${inferSessionGoal(flow)}`,
|
|
195
|
+
"请按下面顺序推进,不要跳步骤:"
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
for (const step of steps) {
|
|
199
|
+
lines.push(`${step.id}. ${step.command}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (flow.contextNeeded.length > 0) {
|
|
203
|
+
lines.push("如果当前缺上下文,请先明确缺什么,不要假装已经完成执行。");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
lines.push("每一步都要说明:你为什么做、得到什么、下一步是什么。");
|
|
207
|
+
return lines.join("\n");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export async function createAgentSession(input, options = {}) {
|
|
211
|
+
const flow = await createAutoFlow(input, { intent: options.intent });
|
|
212
|
+
const steps = flow.commandChain.map((command, index) => {
|
|
213
|
+
const parsedCommand = parseCommand(command);
|
|
214
|
+
return {
|
|
215
|
+
id: `step-${String(index + 1).padStart(2, "0")}`,
|
|
216
|
+
command,
|
|
217
|
+
commandName: parsedCommand.commandName,
|
|
218
|
+
suggestedSkill: inferSkillForCommand(parsedCommand.commandName, flow),
|
|
219
|
+
purpose: inferStepPurpose(parsedCommand.commandName, flow),
|
|
220
|
+
expectedArtifact: inferExpectedArtifact(parsedCommand.commandName),
|
|
221
|
+
instructions: buildStepInstructions(parsedCommand, flow)
|
|
222
|
+
};
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
kind: "geo-agent-session",
|
|
227
|
+
input,
|
|
228
|
+
source: flow.source,
|
|
229
|
+
sourceType: flow.sourceType,
|
|
230
|
+
artifactKind: flow.artifactKind,
|
|
231
|
+
intent: flow.intent,
|
|
232
|
+
stage: flow.stage,
|
|
233
|
+
status: inferSessionStatus(flow),
|
|
234
|
+
goal: inferSessionGoal(flow),
|
|
235
|
+
selectedSkill: flow.selectedSkill,
|
|
236
|
+
secondarySkills: flow.secondarySkills,
|
|
237
|
+
whyThisSkill: flow.whyThisSkill,
|
|
238
|
+
contextNeeded: flow.contextNeeded,
|
|
239
|
+
nextAction: flow.nextAction,
|
|
240
|
+
steps,
|
|
241
|
+
sessionPrompt: buildSessionPrompt(flow, steps),
|
|
242
|
+
autoFlow: flow
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function renderAgentSessionMarkdown(session) {
|
|
247
|
+
const lines = [
|
|
248
|
+
"# GEO Agent Session",
|
|
249
|
+
"",
|
|
250
|
+
`- 输入:\`${session.source}\``,
|
|
251
|
+
`- 输入类型:\`${session.sourceType}\``,
|
|
252
|
+
`- 工件类型:\`${session.artifactKind}\``,
|
|
253
|
+
`- 当前阶段:${session.stage}`,
|
|
254
|
+
`- 会话状态:${session.status}`,
|
|
255
|
+
`- 当前意图:${session.intent}`,
|
|
256
|
+
`- 目标:${session.goal}`,
|
|
257
|
+
`- 自动选择的 skill:\`${session.selectedSkill.name}\``,
|
|
258
|
+
"",
|
|
259
|
+
"## 为什么这样安排",
|
|
260
|
+
"",
|
|
261
|
+
`- ${session.whyThisSkill}`,
|
|
262
|
+
"",
|
|
263
|
+
"## 下一步",
|
|
264
|
+
"",
|
|
265
|
+
`- ${session.nextAction}`
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
if (session.contextNeeded.length > 0) {
|
|
269
|
+
lines.push("", "## 还缺什么", "");
|
|
270
|
+
for (const item of session.contextNeeded) {
|
|
271
|
+
lines.push(`- ${item}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
lines.push("", "## 会话步骤", "");
|
|
276
|
+
for (const step of session.steps) {
|
|
277
|
+
lines.push(`### ${step.id}|${step.commandName}`);
|
|
278
|
+
lines.push("");
|
|
279
|
+
lines.push(`- 命令:\`${step.command}\``);
|
|
280
|
+
lines.push(`- 建议 skill:\`${step.suggestedSkill}\``);
|
|
281
|
+
lines.push(`- 目的:${step.purpose}`);
|
|
282
|
+
lines.push(`- 预期产物:${step.expectedArtifact}`);
|
|
283
|
+
lines.push("- 操作说明:");
|
|
284
|
+
for (const instruction of step.instructions) {
|
|
285
|
+
lines.push(` - ${instruction}`);
|
|
286
|
+
}
|
|
287
|
+
lines.push("");
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
lines.push("", "## 可直接复制给 Agent 的 Session Prompt", "", "```text", session.sessionPrompt, "```");
|
|
291
|
+
|
|
292
|
+
return `${lines.join("\n")}\n`;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export async function writeAgentSessionOutput(outputPath, content) {
|
|
296
|
+
return writeScanOutput(outputPath, content);
|
|
297
|
+
}
|
package/src/auto-flow.js
ADDED
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { writeScanOutput } from "./scan.js";
|
|
4
|
+
import { listBundledSkills } from "./skills.js";
|
|
5
|
+
|
|
6
|
+
const VALID_INTENTS = new Set(["auto", "diagnose", "guide", "execute", "share", "closeout"]);
|
|
7
|
+
|
|
8
|
+
function isUrlInput(input) {
|
|
9
|
+
return /^https?:\/\//i.test(input);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function normalizeIntent(intent) {
|
|
13
|
+
const resolved = (intent || "auto").toLowerCase();
|
|
14
|
+
if (!VALID_INTENTS.has(resolved)) {
|
|
15
|
+
throw new Error(`不支持的 auto-flow intent:${intent}。可选值:${Array.from(VALID_INTENTS).join(", ")}`);
|
|
16
|
+
}
|
|
17
|
+
return resolved;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function pathExists(targetPath) {
|
|
21
|
+
try {
|
|
22
|
+
await fs.access(targetPath);
|
|
23
|
+
return true;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function detectArtifactKindFromParsedJson(parsed) {
|
|
30
|
+
if (!parsed || typeof parsed !== "object") {
|
|
31
|
+
return "unknown-json";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (parsed.kind === "geo-report") {
|
|
35
|
+
return `geo-report:${parsed.mode || "unknown"}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return parsed.kind || "unknown-json";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function inferTaskTextMode(text) {
|
|
42
|
+
const normalized = String(text).toLowerCase();
|
|
43
|
+
|
|
44
|
+
if (/(share-pack|export-pack|html-pack|publish-pack|分享|导出|交付|外发|报告包)/i.test(normalized)) {
|
|
45
|
+
return "share";
|
|
46
|
+
}
|
|
47
|
+
if (/(apply-plan|handoff|接手|交给.*agent|继续修|继续做|修复|执行|修改|落地|repair|implement|fix)/i.test(normalized)) {
|
|
48
|
+
return "execute";
|
|
49
|
+
}
|
|
50
|
+
if (/(completion-report|closeout|复盘|收尾|总结|剩余风险)/i.test(normalized)) {
|
|
51
|
+
return "closeout";
|
|
52
|
+
}
|
|
53
|
+
if (/(how to use|怎么用|如何用|命令|skill|技能|流程|next step|下一步)/i.test(normalized)) {
|
|
54
|
+
return "guide";
|
|
55
|
+
}
|
|
56
|
+
return "diagnose";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function detectInput(input) {
|
|
60
|
+
if (!input) {
|
|
61
|
+
throw new Error("auto-flow 需要一个输入值,可以是任务描述、项目路径、网站网址或已导出的工件。");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (isUrlInput(input)) {
|
|
65
|
+
return {
|
|
66
|
+
source: input,
|
|
67
|
+
sourceType: "url",
|
|
68
|
+
artifactKind: "website-url",
|
|
69
|
+
summary: "公开网站网址"
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const resolvedPath = path.resolve(input);
|
|
74
|
+
if (!(await pathExists(resolvedPath))) {
|
|
75
|
+
return {
|
|
76
|
+
source: input,
|
|
77
|
+
sourceType: "task-text",
|
|
78
|
+
artifactKind: "task-brief",
|
|
79
|
+
summary: "自然语言任务描述",
|
|
80
|
+
inferredTextIntent: inferTaskTextMode(input)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const stat = await fs.stat(resolvedPath);
|
|
85
|
+
if (stat.isDirectory()) {
|
|
86
|
+
return {
|
|
87
|
+
source: resolvedPath,
|
|
88
|
+
sourceType: "directory",
|
|
89
|
+
artifactKind: "project-directory",
|
|
90
|
+
summary: "本地网站项目目录"
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const extension = path.extname(resolvedPath).toLowerCase();
|
|
95
|
+
if (extension === ".json") {
|
|
96
|
+
const raw = await fs.readFile(resolvedPath, "utf8");
|
|
97
|
+
const parsed = JSON.parse(raw);
|
|
98
|
+
return {
|
|
99
|
+
source: resolvedPath,
|
|
100
|
+
sourceType: "json",
|
|
101
|
+
artifactKind: detectArtifactKindFromParsedJson(parsed),
|
|
102
|
+
summary: "GEO JSON 工件",
|
|
103
|
+
parsed
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const fileName = path.basename(resolvedPath);
|
|
108
|
+
let artifactKind = "generic-file";
|
|
109
|
+
if (fileName === "START-HERE.md" || fileName === "AGENT-START.md" || fileName === "manifest.json") {
|
|
110
|
+
artifactKind = "geo-publish-pack-entry";
|
|
111
|
+
} else if (/share-pack/i.test(fileName)) {
|
|
112
|
+
artifactKind = "geo-share-pack-file";
|
|
113
|
+
} else if (/owner-board/i.test(fileName)) {
|
|
114
|
+
artifactKind = "geo-owner-board-file";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
source: resolvedPath,
|
|
119
|
+
sourceType: "file",
|
|
120
|
+
artifactKind,
|
|
121
|
+
summary: "本地文件工件"
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function resolveEffectiveIntent(intent, detected) {
|
|
126
|
+
if (intent !== "auto") {
|
|
127
|
+
return intent;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (detected.sourceType === "task-text") {
|
|
131
|
+
return detected.inferredTextIntent || "diagnose";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (detected.artifactKind === "geo-completion-report") {
|
|
135
|
+
return "closeout";
|
|
136
|
+
}
|
|
137
|
+
if (
|
|
138
|
+
[
|
|
139
|
+
"geo-share-pack",
|
|
140
|
+
"geo-export-pack",
|
|
141
|
+
"geo-html-pack",
|
|
142
|
+
"geo-publish-pack",
|
|
143
|
+
"geo-publish-pack-entry",
|
|
144
|
+
"geo-share-pack-file"
|
|
145
|
+
].includes(detected.artifactKind)
|
|
146
|
+
) {
|
|
147
|
+
return "share";
|
|
148
|
+
}
|
|
149
|
+
if (
|
|
150
|
+
["geo-agent-handoff", "geo-apply-plan", "geo-handoff-bundle", "geo-fix-plan"].includes(detected.artifactKind)
|
|
151
|
+
) {
|
|
152
|
+
return "execute";
|
|
153
|
+
}
|
|
154
|
+
if (detected.artifactKind === "task-brief") {
|
|
155
|
+
return detected.inferredTextIntent || "diagnose";
|
|
156
|
+
}
|
|
157
|
+
return "diagnose";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function buildCommandChain(detected, intent) {
|
|
161
|
+
const source = detected.source;
|
|
162
|
+
|
|
163
|
+
if (detected.sourceType === "task-text") {
|
|
164
|
+
return [`geo-ai-search-optimization skills`, `geo-ai-search-optimization quick-start`];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (intent === "guide") {
|
|
168
|
+
return [`geo-ai-search-optimization skills`, `geo-ai-search-optimization quick-start`, `geo-ai-search-optimization auto-flow ${source}`];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (intent === "share") {
|
|
172
|
+
if (detected.artifactKind === "geo-completion-report") {
|
|
173
|
+
return [
|
|
174
|
+
`geo-ai-search-optimization share-pack ${source}`,
|
|
175
|
+
`geo-ai-search-optimization export-pack ${source}`,
|
|
176
|
+
`geo-ai-search-optimization publish-pack ${source}`
|
|
177
|
+
];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return [
|
|
181
|
+
`geo-ai-search-optimization share-pack ${source}`,
|
|
182
|
+
`geo-ai-search-optimization html-pack ${source}`,
|
|
183
|
+
`geo-ai-search-optimization publish-pack ${source}`
|
|
184
|
+
];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (intent === "closeout") {
|
|
188
|
+
return [
|
|
189
|
+
`geo-ai-search-optimization completion-report ${source}`,
|
|
190
|
+
`geo-ai-search-optimization meeting-pack ${source}`,
|
|
191
|
+
`geo-ai-search-optimization publish-pack ${source}`
|
|
192
|
+
];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (detected.sourceType === "url") {
|
|
196
|
+
if (intent === "execute") {
|
|
197
|
+
return [
|
|
198
|
+
`geo-ai-search-optimization onboard-url ${source}`,
|
|
199
|
+
`geo-ai-search-optimization fix-plan ${source}`,
|
|
200
|
+
`geo-ai-search-optimization agent-handoff ${source}`
|
|
201
|
+
];
|
|
202
|
+
}
|
|
203
|
+
return [
|
|
204
|
+
`geo-ai-search-optimization onboard-url ${source}`,
|
|
205
|
+
`geo-ai-search-optimization pm-brief ${source}`,
|
|
206
|
+
`geo-ai-search-optimization report ${source} --mode onboarding --format markdown`
|
|
207
|
+
];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (detected.sourceType === "directory") {
|
|
211
|
+
if (intent === "execute") {
|
|
212
|
+
return [
|
|
213
|
+
`geo-ai-search-optimization audit ${source}`,
|
|
214
|
+
`geo-ai-search-optimization fix-plan ${source}`,
|
|
215
|
+
`geo-ai-search-optimization agent-handoff ${source}`,
|
|
216
|
+
`geo-ai-search-optimization apply-plan ${source}`
|
|
217
|
+
];
|
|
218
|
+
}
|
|
219
|
+
return [
|
|
220
|
+
`geo-ai-search-optimization scan ${source}`,
|
|
221
|
+
`geo-ai-search-optimization audit ${source}`,
|
|
222
|
+
`geo-ai-search-optimization fix-plan ${source}`
|
|
223
|
+
];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
switch (detected.artifactKind) {
|
|
227
|
+
case "geo-report:audit":
|
|
228
|
+
case "geo-audit":
|
|
229
|
+
return intent === "execute"
|
|
230
|
+
? [
|
|
231
|
+
`geo-ai-search-optimization fix-plan ${source}`,
|
|
232
|
+
`geo-ai-search-optimization agent-handoff ${source}`,
|
|
233
|
+
`geo-ai-search-optimization apply-plan ${source}`
|
|
234
|
+
]
|
|
235
|
+
: [`geo-ai-search-optimization fix-plan ${source}`, `geo-ai-search-optimization owner-board ${source}`];
|
|
236
|
+
case "geo-url-onboarding":
|
|
237
|
+
case "geo-report:onboarding":
|
|
238
|
+
return [
|
|
239
|
+
`geo-ai-search-optimization pm-brief ${source}`,
|
|
240
|
+
`geo-ai-search-optimization fix-plan ${source}`,
|
|
241
|
+
`geo-ai-search-optimization roadmap ${source}`
|
|
242
|
+
];
|
|
243
|
+
case "geo-fix-plan":
|
|
244
|
+
return [
|
|
245
|
+
`geo-ai-search-optimization agent-handoff ${source}`,
|
|
246
|
+
`geo-ai-search-optimization apply-plan ${source}`
|
|
247
|
+
];
|
|
248
|
+
case "geo-agent-handoff":
|
|
249
|
+
return [
|
|
250
|
+
`geo-ai-search-optimization apply-plan ${source}`,
|
|
251
|
+
`geo-ai-search-optimization completion-report ${source}`
|
|
252
|
+
];
|
|
253
|
+
case "geo-apply-plan":
|
|
254
|
+
return [
|
|
255
|
+
`geo-ai-search-optimization apply-plan ${source}`,
|
|
256
|
+
`geo-ai-search-optimization completion-report ${source}`,
|
|
257
|
+
`geo-ai-search-optimization handoff-bundle ${source}`
|
|
258
|
+
];
|
|
259
|
+
case "geo-completion-report":
|
|
260
|
+
return [
|
|
261
|
+
`geo-ai-search-optimization meeting-pack ${source}`,
|
|
262
|
+
`geo-ai-search-optimization share-pack ${source}`,
|
|
263
|
+
`geo-ai-search-optimization publish-pack ${source}`
|
|
264
|
+
];
|
|
265
|
+
case "geo-handoff-bundle":
|
|
266
|
+
return [
|
|
267
|
+
`geo-ai-search-optimization apply-plan ${source}`,
|
|
268
|
+
`geo-ai-search-optimization completion-report ${source}`,
|
|
269
|
+
`geo-ai-search-optimization publish-pack ${source}`
|
|
270
|
+
];
|
|
271
|
+
case "geo-share-pack":
|
|
272
|
+
case "geo-share-pack-file":
|
|
273
|
+
return [
|
|
274
|
+
`geo-ai-search-optimization export-pack ${source}`,
|
|
275
|
+
`geo-ai-search-optimization html-pack ${source}`,
|
|
276
|
+
`geo-ai-search-optimization publish-pack ${source}`
|
|
277
|
+
];
|
|
278
|
+
case "geo-export-pack":
|
|
279
|
+
return [`geo-ai-search-optimization html-pack ${source}`, `geo-ai-search-optimization publish-pack ${source}`];
|
|
280
|
+
case "geo-html-pack":
|
|
281
|
+
return [`geo-ai-search-optimization publish-pack ${source}`];
|
|
282
|
+
case "geo-publish-pack":
|
|
283
|
+
case "geo-publish-pack-entry":
|
|
284
|
+
return [`geo-ai-search-optimization auto-flow ${source} --intent guide`, `geo-ai-search-optimization skills`];
|
|
285
|
+
default:
|
|
286
|
+
return [`geo-ai-search-optimization skills`, `geo-ai-search-optimization quick-start`];
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function pickSkillName(detected, intent) {
|
|
291
|
+
if (intent === "guide") {
|
|
292
|
+
return "geo-ai-search-optimization-usage";
|
|
293
|
+
}
|
|
294
|
+
if (intent === "share") {
|
|
295
|
+
return "geo-ai-search-optimization-publish-pack";
|
|
296
|
+
}
|
|
297
|
+
if (intent === "closeout") {
|
|
298
|
+
return "geo-ai-search-optimization-completion-report";
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
switch (detected.artifactKind) {
|
|
302
|
+
case "task-brief":
|
|
303
|
+
return detected.inferredTextIntent === "share"
|
|
304
|
+
? "geo-ai-search-optimization-publish-pack"
|
|
305
|
+
: detected.inferredTextIntent === "execute"
|
|
306
|
+
? "geo-ai-search-optimization-agent-handoff"
|
|
307
|
+
: "geo-ai-search-optimization-usage";
|
|
308
|
+
case "website-url":
|
|
309
|
+
case "project-directory":
|
|
310
|
+
case "geo-audit":
|
|
311
|
+
case "geo-report:audit":
|
|
312
|
+
case "geo-url-onboarding":
|
|
313
|
+
case "geo-report:onboarding":
|
|
314
|
+
return intent === "execute" ? "geo-ai-search-optimization-agent-handoff" : "geo-ai-search-optimization";
|
|
315
|
+
case "geo-fix-plan":
|
|
316
|
+
case "geo-agent-handoff":
|
|
317
|
+
return "geo-ai-search-optimization-agent-handoff";
|
|
318
|
+
case "geo-apply-plan":
|
|
319
|
+
return "geo-ai-search-optimization-repair-loop";
|
|
320
|
+
case "geo-completion-report":
|
|
321
|
+
return "geo-ai-search-optimization-completion-report";
|
|
322
|
+
case "geo-handoff-bundle":
|
|
323
|
+
return "geo-ai-search-optimization-handoff-bundle";
|
|
324
|
+
case "geo-share-pack":
|
|
325
|
+
case "geo-share-pack-file":
|
|
326
|
+
return "geo-ai-search-optimization-share-pack";
|
|
327
|
+
case "geo-export-pack":
|
|
328
|
+
return "geo-ai-search-optimization-export-pack";
|
|
329
|
+
case "geo-html-pack":
|
|
330
|
+
return "geo-ai-search-optimization-html-pack";
|
|
331
|
+
case "geo-publish-pack":
|
|
332
|
+
case "geo-publish-pack-entry":
|
|
333
|
+
return "geo-ai-search-optimization-publish-pack";
|
|
334
|
+
default:
|
|
335
|
+
return "geo-ai-search-optimization-usage";
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function buildSecondarySkillNames(primarySkill, intent, detected) {
|
|
340
|
+
const names = new Set(["geo-ai-search-optimization-usage"]);
|
|
341
|
+
|
|
342
|
+
if (primarySkill !== "geo-ai-search-optimization") {
|
|
343
|
+
names.add("geo-ai-search-optimization");
|
|
344
|
+
}
|
|
345
|
+
if (intent === "share") {
|
|
346
|
+
names.add("geo-ai-search-optimization-share-pack");
|
|
347
|
+
names.add("geo-ai-search-optimization-publish-pack");
|
|
348
|
+
}
|
|
349
|
+
if (intent === "execute" || ["geo-fix-plan", "geo-agent-handoff", "geo-apply-plan"].includes(detected.artifactKind)) {
|
|
350
|
+
names.add("geo-ai-search-optimization-agent-handoff");
|
|
351
|
+
names.add("geo-ai-search-optimization-repair-loop");
|
|
352
|
+
}
|
|
353
|
+
if (intent === "closeout") {
|
|
354
|
+
names.add("geo-ai-search-optimization-completion-report");
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
names.delete(primarySkill);
|
|
358
|
+
return Array.from(names);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function buildStage(intent, detected) {
|
|
362
|
+
if (intent === "guide") {
|
|
363
|
+
return "使用引导";
|
|
364
|
+
}
|
|
365
|
+
if (intent === "share") {
|
|
366
|
+
return "交付分享";
|
|
367
|
+
}
|
|
368
|
+
if (intent === "closeout") {
|
|
369
|
+
return "执行复盘";
|
|
370
|
+
}
|
|
371
|
+
if (intent === "execute") {
|
|
372
|
+
return ["geo-fix-plan", "geo-agent-handoff", "geo-apply-plan", "geo-handoff-bundle"].includes(detected.artifactKind)
|
|
373
|
+
? "Agent 执行"
|
|
374
|
+
: "执行准备";
|
|
375
|
+
}
|
|
376
|
+
if (["geo-fix-plan", "geo-agent-handoff", "geo-apply-plan", "geo-handoff-bundle"].includes(detected.artifactKind)) {
|
|
377
|
+
return "Agent 执行";
|
|
378
|
+
}
|
|
379
|
+
return "诊断规划";
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function buildWhy(detected, intent, primarySkillLabel) {
|
|
383
|
+
if (detected.sourceType === "task-text") {
|
|
384
|
+
return `当前输入是一段任务描述,还不是具体工件,所以先用 ${primarySkillLabel} 来判断阶段,并明确下一步还缺什么上下文。`;
|
|
385
|
+
}
|
|
386
|
+
if (detected.sourceType === "url") {
|
|
387
|
+
return `当前只有公开网址,没有仓库上下文,最适合先走网址级 GEO 流程,再决定是否进入 agent 执行。`;
|
|
388
|
+
}
|
|
389
|
+
if (detected.sourceType === "directory") {
|
|
390
|
+
return intent === "execute"
|
|
391
|
+
? "当前已经有本地项目目录,可以直接进入 GEO 诊断到 agent 接手的执行链。"
|
|
392
|
+
: "当前已有本地项目目录,先跑诊断和优先级判断最稳妥。";
|
|
393
|
+
}
|
|
394
|
+
if (detected.sourceType === "json") {
|
|
395
|
+
return `当前输入已经是 GEO 工件(${detected.artifactKind}),所以可以跳过前置步骤,直接进入对应阶段。`;
|
|
396
|
+
}
|
|
397
|
+
return "当前输入更像中间结果或说明文本,先根据上下文自动选择最接近的 skill。";
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function buildContextNeeded(detected, intent) {
|
|
401
|
+
if (detected.sourceType === "task-text") {
|
|
402
|
+
const items = ["至少补一个公开网址、本地项目路径,或已有 GEO JSON 工件。"];
|
|
403
|
+
if (intent === "execute") {
|
|
404
|
+
items.push("如果希望 agent 直接修复,最好提供代码仓库或本地项目目录。");
|
|
405
|
+
}
|
|
406
|
+
if (intent === "share") {
|
|
407
|
+
items.push("如果希望直接交付,最好提供已生成的 audit / handoff / completion 等工件。");
|
|
408
|
+
}
|
|
409
|
+
return items;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (detected.sourceType === "url" && intent === "execute") {
|
|
413
|
+
return ["当前只有公开网址,能先做建议型执行。若要直接修复,后续仍需提供本地项目目录或仓库上下文。"];
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return [];
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function buildAgentPrompt(skill, detected, intent, commands) {
|
|
420
|
+
const lines = [
|
|
421
|
+
skill.defaultPrompt || `Use $${skill.name} to continue this GEO task.`,
|
|
422
|
+
`输入:${detected.source}`,
|
|
423
|
+
`意图:${intent}`,
|
|
424
|
+
"请先说明你为什么选择这个 skill,然后按建议命令顺序继续。"
|
|
425
|
+
];
|
|
426
|
+
|
|
427
|
+
if (commands.length > 0) {
|
|
428
|
+
lines.push("建议命令顺序:");
|
|
429
|
+
for (const command of commands) {
|
|
430
|
+
lines.push(`- ${command}`);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
return lines.join("\n");
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function buildNextAction(detected, intent, commands) {
|
|
438
|
+
if (detected.sourceType === "task-text") {
|
|
439
|
+
if (intent === "execute") {
|
|
440
|
+
return "先补一个公开网址、本地项目目录或 GEO JSON 工件;有了具体输入后再重跑 auto-flow,才能真正进入 agent 执行链。";
|
|
441
|
+
}
|
|
442
|
+
if (intent === "share") {
|
|
443
|
+
return "先补一个 GEO 工件或项目输入,再生成可分享的交付包。";
|
|
444
|
+
}
|
|
445
|
+
if (intent === "closeout") {
|
|
446
|
+
return "先补 completion-report、apply-plan 或 handoff-bundle 这类执行工件,再进入复盘。";
|
|
447
|
+
}
|
|
448
|
+
return "先补一个公开网址、本地项目目录或 GEO 工件,让系统能自动定位到正确阶段。";
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (commands.length === 0) {
|
|
452
|
+
return "先运行 skills 查看整套技能包。";
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (intent === "share") {
|
|
456
|
+
return `先运行 \`${commands[0]}\` 生成适合外发或交接的结果。`;
|
|
457
|
+
}
|
|
458
|
+
if (intent === "execute") {
|
|
459
|
+
return `先运行 \`${commands[0]}\`,把当前输入推进到 agent 可执行状态。`;
|
|
460
|
+
}
|
|
461
|
+
if (intent === "closeout") {
|
|
462
|
+
return `先运行 \`${commands[0]}\`,整理本轮完成情况和剩余风险。`;
|
|
463
|
+
}
|
|
464
|
+
if (intent === "guide") {
|
|
465
|
+
return `先运行 \`${commands[0]}\`,确认技能包与命令顺序。`;
|
|
466
|
+
}
|
|
467
|
+
return `先运行 \`${commands[0]}\`,建立当前阶段的 GEO 基线。`;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export async function createAutoFlow(input, options = {}) {
|
|
471
|
+
const bundle = await listBundledSkills();
|
|
472
|
+
const detected = await detectInput(input);
|
|
473
|
+
const intent = resolveEffectiveIntent(normalizeIntent(options.intent), detected);
|
|
474
|
+
const primarySkillName = pickSkillName(detected, intent);
|
|
475
|
+
const primarySkill = bundle.skills.find((skill) => skill.name === primarySkillName);
|
|
476
|
+
|
|
477
|
+
if (!primarySkill) {
|
|
478
|
+
throw new Error(`找不到技能:${primarySkillName}`);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const secondarySkillNames = buildSecondarySkillNames(primarySkillName, intent, detected);
|
|
482
|
+
const secondarySkills = bundle.skills.filter((skill) => secondarySkillNames.includes(skill.name));
|
|
483
|
+
const commandChain = buildCommandChain(detected, intent);
|
|
484
|
+
|
|
485
|
+
return {
|
|
486
|
+
kind: "geo-auto-flow",
|
|
487
|
+
input,
|
|
488
|
+
source: detected.source,
|
|
489
|
+
sourceType: detected.sourceType,
|
|
490
|
+
artifactKind: detected.artifactKind,
|
|
491
|
+
summary: detected.summary,
|
|
492
|
+
intent,
|
|
493
|
+
stage: buildStage(intent, detected),
|
|
494
|
+
selectedSkill: {
|
|
495
|
+
name: primarySkill.name,
|
|
496
|
+
displayName: primarySkill.displayName,
|
|
497
|
+
shortDescription: primarySkill.shortDescription,
|
|
498
|
+
defaultPrompt: primarySkill.defaultPrompt,
|
|
499
|
+
skillPath: primarySkill.skillPath
|
|
500
|
+
},
|
|
501
|
+
secondarySkills: secondarySkills.map((skill) => ({
|
|
502
|
+
name: skill.name,
|
|
503
|
+
displayName: skill.displayName,
|
|
504
|
+
shortDescription: skill.shortDescription,
|
|
505
|
+
skillPath: skill.skillPath
|
|
506
|
+
})),
|
|
507
|
+
whyThisSkill: buildWhy(detected, intent, primarySkill.displayName),
|
|
508
|
+
contextNeeded: buildContextNeeded(detected, intent),
|
|
509
|
+
nextAction: buildNextAction(detected, intent, commandChain),
|
|
510
|
+
commandChain,
|
|
511
|
+
agentPrompt: buildAgentPrompt(primarySkill, detected, intent, commandChain)
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
export function renderAutoFlowMarkdown(flow) {
|
|
516
|
+
const lines = [
|
|
517
|
+
"# GEO Auto Flow",
|
|
518
|
+
"",
|
|
519
|
+
`- 输入:\`${flow.source}\``,
|
|
520
|
+
`- 输入类型:\`${flow.sourceType}\``,
|
|
521
|
+
`- 工件类型:\`${flow.artifactKind}\``,
|
|
522
|
+
`- 当前阶段:${flow.stage}`,
|
|
523
|
+
`- 当前意图:${flow.intent}`,
|
|
524
|
+
`- 自动选择的 skill:\`${flow.selectedSkill.name}\``,
|
|
525
|
+
`- 显示名:${flow.selectedSkill.displayName}`,
|
|
526
|
+
`- 说明:${flow.selectedSkill.shortDescription}`,
|
|
527
|
+
"",
|
|
528
|
+
"## 为什么是这个 skill",
|
|
529
|
+
"",
|
|
530
|
+
`- ${flow.whyThisSkill}`,
|
|
531
|
+
"",
|
|
532
|
+
"## 下一步",
|
|
533
|
+
"",
|
|
534
|
+
`- ${flow.nextAction}`,
|
|
535
|
+
"",
|
|
536
|
+
"## 建议命令顺序",
|
|
537
|
+
""
|
|
538
|
+
];
|
|
539
|
+
|
|
540
|
+
for (const command of flow.commandChain) {
|
|
541
|
+
lines.push(`- \`${command}\``);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (flow.contextNeeded.length > 0) {
|
|
545
|
+
lines.push("", "## 还需要补什么", "");
|
|
546
|
+
for (const item of flow.contextNeeded) {
|
|
547
|
+
lines.push(`- ${item}`);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
lines.push("", "## 可一起参考的 skill", "");
|
|
552
|
+
for (const skill of flow.secondarySkills) {
|
|
553
|
+
lines.push(`- ${skill.name}|${skill.displayName}|${skill.shortDescription}`);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
lines.push("", "## 可直接复制给 Agent 的 Prompt", "", "```text", flow.agentPrompt, "```");
|
|
557
|
+
|
|
558
|
+
return `${lines.join("\n")}\n`;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
export async function writeAutoFlowOutput(outputPath, content) {
|
|
562
|
+
return writeScanOutput(outputPath, content);
|
|
563
|
+
}
|
package/src/cli.js
CHANGED
|
@@ -3,6 +3,8 @@ import { readFile } from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { createApplyPlan, renderApplyPlanMarkdown, writeApplyPlanOutput } from "./apply-plan.js";
|
|
5
5
|
import { createAgentHandoff, renderAgentHandoffMarkdown, writeAgentHandoffOutput } from "./agent-handoff.js";
|
|
6
|
+
import { createAgentSession, renderAgentSessionMarkdown, writeAgentSessionOutput } from "./agent-session.js";
|
|
7
|
+
import { createAutoFlow, renderAutoFlowMarkdown, writeAutoFlowOutput } from "./auto-flow.js";
|
|
6
8
|
import {
|
|
7
9
|
createCompletionReport,
|
|
8
10
|
renderCompletionReportMarkdown,
|
|
@@ -57,6 +59,8 @@ function printHelp() {
|
|
|
57
59
|
"Usage:",
|
|
58
60
|
" geo-ai-search-optimization",
|
|
59
61
|
" geo-ai-search-optimization install [--target <dir>] [--json]",
|
|
62
|
+
" geo-ai-search-optimization auto-flow <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--json] [--out <file>]",
|
|
63
|
+
" geo-ai-search-optimization agent-session <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--json] [--out <file>]",
|
|
60
64
|
" geo-ai-search-optimization skills [--json]",
|
|
61
65
|
" geo-ai-search-optimization where",
|
|
62
66
|
" geo-ai-search-optimization doctor [--json]",
|
|
@@ -127,6 +131,52 @@ async function handleInstall(args) {
|
|
|
127
131
|
}
|
|
128
132
|
}
|
|
129
133
|
|
|
134
|
+
async function handleAutoFlow(args) {
|
|
135
|
+
const input = args.find((value) => !value.startsWith("-"));
|
|
136
|
+
if (!input) {
|
|
137
|
+
throw new Error("auto-flow 需要一个输入值,可以是任务描述、项目路径、网站网址或已导出的工件");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const flow = await createAutoFlow(input, {
|
|
141
|
+
intent: getFlagValue(args, "--intent")
|
|
142
|
+
});
|
|
143
|
+
const outputJson = hasFlag(args, "--json");
|
|
144
|
+
const renderedOutput = outputJson ? `${JSON.stringify(flow, null, 2)}\n` : renderAutoFlowMarkdown(flow);
|
|
145
|
+
|
|
146
|
+
const outputPath = getFlagValue(args, "--out");
|
|
147
|
+
if (outputPath) {
|
|
148
|
+
const resolvedOutputPath = await writeAutoFlowOutput(outputPath, renderedOutput);
|
|
149
|
+
process.stdout.write(`已保存 auto-flow 结果:${resolvedOutputPath}\n`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
process.stdout.write(renderedOutput);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function handleAgentSession(args) {
|
|
157
|
+
const input = args.find((value) => !value.startsWith("-"));
|
|
158
|
+
if (!input) {
|
|
159
|
+
throw new Error("agent-session 需要一个输入值,可以是任务描述、项目路径、网站网址或已导出的工件");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const session = await createAgentSession(input, {
|
|
163
|
+
intent: getFlagValue(args, "--intent")
|
|
164
|
+
});
|
|
165
|
+
const outputJson = hasFlag(args, "--json");
|
|
166
|
+
const renderedOutput = outputJson
|
|
167
|
+
? `${JSON.stringify(session, null, 2)}\n`
|
|
168
|
+
: renderAgentSessionMarkdown(session);
|
|
169
|
+
|
|
170
|
+
const outputPath = getFlagValue(args, "--out");
|
|
171
|
+
if (outputPath) {
|
|
172
|
+
const resolvedOutputPath = await writeAgentSessionOutput(outputPath, renderedOutput);
|
|
173
|
+
process.stdout.write(`已保存 agent-session 结果:${resolvedOutputPath}\n`);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
process.stdout.write(renderedOutput);
|
|
178
|
+
}
|
|
179
|
+
|
|
130
180
|
function handleWhere() {
|
|
131
181
|
process.stdout.write(
|
|
132
182
|
[
|
|
@@ -667,6 +717,16 @@ export async function runCli(args = []) {
|
|
|
667
717
|
return;
|
|
668
718
|
}
|
|
669
719
|
|
|
720
|
+
if (command === "auto-flow") {
|
|
721
|
+
await handleAutoFlow(rest);
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
if (command === "agent-session") {
|
|
726
|
+
await handleAgentSession(rest);
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
|
|
670
730
|
if (command === "skills") {
|
|
671
731
|
await handleSkills(rest);
|
|
672
732
|
return;
|
package/src/index.js
CHANGED
|
@@ -5,8 +5,10 @@ export {
|
|
|
5
5
|
runInteractiveOnboarding,
|
|
6
6
|
writeInteractiveOnboardingOutput
|
|
7
7
|
} from "./interactive-onboarding.js";
|
|
8
|
+
export { createAutoFlow, renderAutoFlowMarkdown, writeAutoFlowOutput } from "./auto-flow.js";
|
|
8
9
|
export { createApplyPlan, renderApplyPlanMarkdown, writeApplyPlanOutput } from "./apply-plan.js";
|
|
9
10
|
export { createAgentHandoff, renderAgentHandoffMarkdown, writeAgentHandoffOutput } from "./agent-handoff.js";
|
|
11
|
+
export { createAgentSession, renderAgentSessionMarkdown, writeAgentSessionOutput } from "./agent-session.js";
|
|
10
12
|
export { createCompletionReport, renderCompletionReportMarkdown, writeCompletionReportOutput } from "./completion-report.js";
|
|
11
13
|
export { createFixPlan, renderFixPlanMarkdown, writeFixPlanOutput } from "./fix-plan.js";
|
|
12
14
|
export { createHandoffBundle, renderHandoffBundleMarkdown, writeHandoffBundleOutput } from "./handoff-bundle.js";
|
package/src/skills.js
CHANGED
|
@@ -4,6 +4,8 @@ import { getPackageRoot } from "./paths.js";
|
|
|
4
4
|
|
|
5
5
|
const SKILL_ORDER = [
|
|
6
6
|
"geo-ai-search-optimization",
|
|
7
|
+
"geo-ai-search-optimization-auto-flow",
|
|
8
|
+
"geo-ai-search-optimization-agent-session",
|
|
7
9
|
"geo-ai-search-optimization-usage",
|
|
8
10
|
"geo-ai-search-optimization-agent-handoff",
|
|
9
11
|
"geo-ai-search-optimization-repair-loop",
|
|
@@ -17,6 +19,8 @@ const SKILL_ORDER = [
|
|
|
17
19
|
|
|
18
20
|
const SKILL_CATEGORY = {
|
|
19
21
|
"geo-ai-search-optimization": "core",
|
|
22
|
+
"geo-ai-search-optimization-auto-flow": "routing",
|
|
23
|
+
"geo-ai-search-optimization-agent-session": "routing",
|
|
20
24
|
"geo-ai-search-optimization-usage": "guidance",
|
|
21
25
|
"geo-ai-search-optimization-agent-handoff": "execution",
|
|
22
26
|
"geo-ai-search-optimization-repair-loop": "execution",
|
|
@@ -30,6 +34,7 @@ const SKILL_CATEGORY = {
|
|
|
30
34
|
|
|
31
35
|
const CATEGORY_LABELS = {
|
|
32
36
|
core: "核心 GEO 能力",
|
|
37
|
+
routing: "自动入口",
|
|
33
38
|
guidance: "使用引导",
|
|
34
39
|
execution: "Agent 执行闭环",
|
|
35
40
|
delivery: "交付与分享"
|
|
@@ -148,6 +153,7 @@ export function renderBundledSkillsMarkdown(bundle) {
|
|
|
148
153
|
"## 推荐理解顺序",
|
|
149
154
|
"",
|
|
150
155
|
"- 先看核心 GEO skill。",
|
|
156
|
+
"- 如果 agent 需要自动选 skill,先跑 auto-flow。",
|
|
151
157
|
"- 再看 usage skill,知道什么时候该跑哪个命令。",
|
|
152
158
|
"- 如果要交给 agent 执行,再进入 handoff / apply / completion 这一条执行链。",
|
|
153
159
|
"- 如果要产出给团队分发,再进入 share / export / html / publish 这一条交付链。",
|