geo-ai-search-optimization 1.2.5 → 1.2.6
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 +25 -0
- package/package.json +1 -1
- package/resources/geo-ai-search-optimization/SKILL.md +1 -0
- package/resources/geo-ai-search-optimization/references/skill-bundle-map.md +81 -0
- package/resources/geo-ai-search-optimization-export-pack/agents/openai.yaml +4 -0
- package/resources/geo-ai-search-optimization-handoff-bundle/agents/openai.yaml +4 -0
- package/resources/geo-ai-search-optimization-html-pack/agents/openai.yaml +4 -0
- package/resources/geo-ai-search-optimization-share-pack/agents/openai.yaml +4 -0
- package/resources/geo-ai-search-optimization-usage/SKILL.md +19 -14
- package/src/cli.js +17 -0
- package/src/index.js +1 -0
- package/src/install-skill.js +43 -1
- package/src/skills.js +169 -0
package/README.md
CHANGED
|
@@ -24,6 +24,23 @@ npx geo-ai-search-optimization
|
|
|
24
24
|
- installs the bundled GEO skills into your Codex skills directory
|
|
25
25
|
- ships a local resource folder with `SKILL.md`, references, and a scanner script
|
|
26
26
|
- provides a CLI for installing, locating, and scanning projects for GEO signals
|
|
27
|
+
- now exposes the bundled skill package directly, so agents can discover which GEO sub-skill to use next
|
|
28
|
+
|
|
29
|
+
## Skills 命令
|
|
30
|
+
|
|
31
|
+
如果你想先看这个 npm 包里到底打包了哪些 skills,现在可以直接用:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
geo-ai-search-optimization skills
|
|
35
|
+
geo-ai-search-optimization skills --json
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
它会列出:
|
|
39
|
+
|
|
40
|
+
- 核心 GEO skill
|
|
41
|
+
- usage / onboarding skill
|
|
42
|
+
- agent 执行闭环相关 skills
|
|
43
|
+
- 分享 / 导出 / 最终交付相关 skills
|
|
27
44
|
|
|
28
45
|
## Quick Start
|
|
29
46
|
|
|
@@ -418,6 +435,7 @@ geo-ai-search-optimization onboard --url https://example.com --json --out ./repo
|
|
|
418
435
|
geo-ai-search-optimization
|
|
419
436
|
geo-ai-search-optimization install
|
|
420
437
|
geo-ai-search-optimization install --target ./tmp/custom-skills --json
|
|
438
|
+
geo-ai-search-optimization skills
|
|
421
439
|
geo-ai-search-optimization where
|
|
422
440
|
geo-ai-search-optimization doctor
|
|
423
441
|
geo-ai-search-optimization quick-start
|
|
@@ -452,6 +470,13 @@ geo-ai-search-optimization version
|
|
|
452
470
|
geo-ai-search-optimization help
|
|
453
471
|
```
|
|
454
472
|
|
|
473
|
+
## New in 1.2.6
|
|
474
|
+
|
|
475
|
+
- 新增 `skills` 命令,直接列出整套 GEO 技能包
|
|
476
|
+
- 安装后会额外写入 `.skill-bundle.json`,方便 agent 自动发现技能
|
|
477
|
+
- 为缺失的 skill 补齐 `agents/openai.yaml`
|
|
478
|
+
- 主 skill 新增 `skill-bundle-map` 参考,usage skill 也同步纳入 `publish-pack` 和 `skills`
|
|
479
|
+
|
|
455
480
|
## New in 1.2.5
|
|
456
481
|
|
|
457
482
|
- 新增 `publish-pack`
|
package/package.json
CHANGED
|
@@ -163,3 +163,4 @@ When the user asks for the latest vendor behavior or policy:
|
|
|
163
163
|
- `references/quick-start.md`: from-0-to-1 startup sequence for using the CLI and the skill together
|
|
164
164
|
- `references/geo-playbook.md`: content patterns and GEO-first page design heuristics
|
|
165
165
|
- `references/implementation-checklist.md`: technical, content, and measurement checklist
|
|
166
|
+
- `references/skill-bundle-map.md`: bundled GEO sub-skills and when to use each one
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# GEO Skill Bundle Map
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- Core skill
|
|
6
|
+
- Usage guide
|
|
7
|
+
- Agent execution loop
|
|
8
|
+
- Delivery chain
|
|
9
|
+
|
|
10
|
+
## Core skill
|
|
11
|
+
|
|
12
|
+
### `geo-ai-search-optimization`
|
|
13
|
+
|
|
14
|
+
Use this first when the task is still about diagnosing or improving GEO readiness itself.
|
|
15
|
+
|
|
16
|
+
Best for:
|
|
17
|
+
|
|
18
|
+
- auditing a website or codebase
|
|
19
|
+
- improving answerability, structure, and citation readiness
|
|
20
|
+
- deciding what the highest-impact GEO fixes are
|
|
21
|
+
|
|
22
|
+
## Usage guide
|
|
23
|
+
|
|
24
|
+
### `geo-ai-search-optimization-usage`
|
|
25
|
+
|
|
26
|
+
Use this when the next agent or user does not know which command or skill to use next.
|
|
27
|
+
|
|
28
|
+
Best for:
|
|
29
|
+
|
|
30
|
+
- onboarding new users
|
|
31
|
+
- explaining command order
|
|
32
|
+
- translating a GEO request into concrete CLI steps
|
|
33
|
+
|
|
34
|
+
## Agent execution loop
|
|
35
|
+
|
|
36
|
+
Use these when the work is moving from analysis into action.
|
|
37
|
+
|
|
38
|
+
### `geo-ai-search-optimization-agent-handoff`
|
|
39
|
+
|
|
40
|
+
Turn GEO findings into a package that another agent can continue from.
|
|
41
|
+
|
|
42
|
+
### `geo-ai-search-optimization-repair-loop`
|
|
43
|
+
|
|
44
|
+
Continue from `apply-plan` style execution tasks and close the loop on actual fixes.
|
|
45
|
+
|
|
46
|
+
### `geo-ai-search-optimization-completion-report`
|
|
47
|
+
|
|
48
|
+
Summarize what finished, what still blocks progress, and what should happen next.
|
|
49
|
+
|
|
50
|
+
### `geo-ai-search-optimization-handoff-bundle`
|
|
51
|
+
|
|
52
|
+
Use when one artifact needs to contain handoff, execution, and closeout together.
|
|
53
|
+
|
|
54
|
+
## Delivery chain
|
|
55
|
+
|
|
56
|
+
Use these when the output needs to be shared, exported, or handed off to humans and agents.
|
|
57
|
+
|
|
58
|
+
### `geo-ai-search-optimization-share-pack`
|
|
59
|
+
|
|
60
|
+
Prepare role-specific views for PM, engineering, management, and the next agent.
|
|
61
|
+
|
|
62
|
+
### `geo-ai-search-optimization-export-pack`
|
|
63
|
+
|
|
64
|
+
Generate a disk folder with ready-to-send markdown or JSON deliverables.
|
|
65
|
+
|
|
66
|
+
### `geo-ai-search-optimization-html-pack`
|
|
67
|
+
|
|
68
|
+
Generate browsable HTML pages for quick sharing.
|
|
69
|
+
|
|
70
|
+
### `geo-ai-search-optimization-publish-pack`
|
|
71
|
+
|
|
72
|
+
Generate the final delivery folder that combines:
|
|
73
|
+
|
|
74
|
+
- `site/` HTML pages
|
|
75
|
+
- `documents/` markdown files
|
|
76
|
+
- `data/` JSON artifacts
|
|
77
|
+
- `START-HERE.md`
|
|
78
|
+
- `AGENT-START.md`
|
|
79
|
+
- `manifest.json`
|
|
80
|
+
|
|
81
|
+
This is the best choice when the output should be directly handed to a PM, a stakeholder group, or another agent without further manual packaging.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "GEO Share Pack"
|
|
3
|
+
short_description: "Prepare audience-specific GEO views for sharing"
|
|
4
|
+
default_prompt: "Use $geo-ai-search-optimization-share-pack to turn this GEO result into role-specific views for PM, engineering, management, and the next agent."
|
|
@@ -13,20 +13,21 @@ 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. `
|
|
16
|
+
The package is best explained as thirteen layers:
|
|
17
|
+
|
|
18
|
+
1. `skills`: inspect the bundled skill package
|
|
19
|
+
2. `onboard-url` / `onboard`: first look
|
|
20
|
+
3. `scan`: raw signal check
|
|
21
|
+
4. `audit` / `report`: diagnosis
|
|
22
|
+
5. `fix-plan` / `owner-board`: execution planning
|
|
23
|
+
6. `agent-handoff`: agent takeover package
|
|
24
|
+
7. `apply-plan`: execution loop
|
|
25
|
+
8. `completion-report`: closeout
|
|
26
|
+
9. `handoff-bundle`: all-in-one package
|
|
27
|
+
10. `share-pack`: audience-ready delivery
|
|
28
|
+
11. `export-pack`: folder export
|
|
29
|
+
12. `html-pack` / `publish-pack`: browsable and final delivery output
|
|
30
|
+
13. `pm-brief` / `roadmap`: stakeholder alignment
|
|
30
31
|
|
|
31
32
|
## Recommended command order
|
|
32
33
|
|
|
@@ -51,6 +52,7 @@ npx geo-ai-search-optimization handoff-bundle ./your-site
|
|
|
51
52
|
npx geo-ai-search-optimization share-pack ./your-site
|
|
52
53
|
npx geo-ai-search-optimization export-pack ./your-site
|
|
53
54
|
npx geo-ai-search-optimization html-pack ./your-site
|
|
55
|
+
npx geo-ai-search-optimization publish-pack ./your-site
|
|
54
56
|
npx geo-ai-search-optimization owner-board ./your-site
|
|
55
57
|
npx geo-ai-search-optimization roadmap ./your-site
|
|
56
58
|
```
|
|
@@ -59,6 +61,7 @@ npx geo-ai-search-optimization roadmap ./your-site
|
|
|
59
61
|
|
|
60
62
|
- `onboard-url`: first-time website check from a live URL
|
|
61
63
|
- `onboard`: interactive first-time onboarding
|
|
64
|
+
- `skills`: list the bundled skills and decide which skill or command chain fits the task
|
|
62
65
|
- `scan`: check raw technical signals across files
|
|
63
66
|
- `audit`: get GEO score, issue areas, blockers, and PM action list
|
|
64
67
|
- `report`: export audit/onboarding/scan into readable files
|
|
@@ -70,6 +73,7 @@ npx geo-ai-search-optimization roadmap ./your-site
|
|
|
70
73
|
- `share-pack`: prepare role-specific shareable outputs for PM, engineering, management, and agents
|
|
71
74
|
- `export-pack`: generate a folder with multiple ready-to-send files
|
|
72
75
|
- `html-pack`: generate static HTML pages for sharing and browsing
|
|
76
|
+
- `publish-pack`: generate the final delivery folder for humans and agents together
|
|
73
77
|
- `owner-board`: group tasks by PM / engineering / SEO / content
|
|
74
78
|
- `pm-brief`: prepare a PM summary for meetings and prioritization
|
|
75
79
|
- `roadmap`: turn tasks into a 2-week / 4-week execution sequence
|
|
@@ -88,6 +92,7 @@ When explaining the tool to a user:
|
|
|
88
92
|
- if the user wants something ready to forward to multiple audiences, move them to `share-pack`
|
|
89
93
|
- if the user wants actual files on disk for each audience, move them to `export-pack`
|
|
90
94
|
- if the user wants browsable HTML pages, move them to `html-pack`
|
|
95
|
+
- if the user wants one final package with HTML, markdown, JSON, and an agent entrypoint, move them to `publish-pack`
|
|
91
96
|
- if the user already has a report, move them to `fix-plan`, `owner-board`, or `roadmap`
|
|
92
97
|
|
|
93
98
|
Read [references/usage-patterns.md](references/usage-patterns.md) when you need response patterns and command selection examples.
|
package/src/cli.js
CHANGED
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
import { createQuickStartPlan, renderQuickStartMarkdown, writeQuickStartOutput } from "./quick-start.js";
|
|
34
34
|
import { createSchemaTemplate } from "./schema.js";
|
|
35
35
|
import { createSharePack, renderSharePackMarkdown, writeSharePackOutput } from "./share-pack.js";
|
|
36
|
+
import { listBundledSkills, renderBundledSkillsMarkdown } from "./skills.js";
|
|
36
37
|
import { analyzeWebsiteUrl, renderWebsiteOnboardingMarkdown, writeWebsiteOnboardingOutput } from "./url-onboarding.js";
|
|
37
38
|
|
|
38
39
|
let cachedVersion;
|
|
@@ -56,6 +57,7 @@ function printHelp() {
|
|
|
56
57
|
"Usage:",
|
|
57
58
|
" geo-ai-search-optimization",
|
|
58
59
|
" geo-ai-search-optimization install [--target <dir>] [--json]",
|
|
60
|
+
" geo-ai-search-optimization skills [--json]",
|
|
59
61
|
" geo-ai-search-optimization where",
|
|
60
62
|
" geo-ai-search-optimization doctor [--json]",
|
|
61
63
|
" geo-ai-search-optimization quick-start [--json] [--out <file>]",
|
|
@@ -136,6 +138,16 @@ function handleWhere() {
|
|
|
136
138
|
);
|
|
137
139
|
}
|
|
138
140
|
|
|
141
|
+
async function handleSkills(args) {
|
|
142
|
+
const bundle = await listBundledSkills();
|
|
143
|
+
if (hasFlag(args, "--json")) {
|
|
144
|
+
process.stdout.write(`${JSON.stringify(bundle, null, 2)}\n`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
process.stdout.write(renderBundledSkillsMarkdown(bundle));
|
|
149
|
+
}
|
|
150
|
+
|
|
139
151
|
async function handleDoctor(args) {
|
|
140
152
|
const report = await runDoctor();
|
|
141
153
|
if (hasFlag(args, "--json")) {
|
|
@@ -655,6 +667,11 @@ export async function runCli(args = []) {
|
|
|
655
667
|
return;
|
|
656
668
|
}
|
|
657
669
|
|
|
670
|
+
if (command === "skills") {
|
|
671
|
+
await handleSkills(rest);
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
|
|
658
675
|
if (command === "where") {
|
|
659
676
|
handleWhere();
|
|
660
677
|
return;
|
package/src/index.js
CHANGED
|
@@ -27,4 +27,5 @@ export { createRoadmap, renderRoadmapMarkdown, writeRoadmapOutput } from "./road
|
|
|
27
27
|
export { createSchemaTemplate } from "./schema.js";
|
|
28
28
|
export { scanProject, renderScanMarkdown, writeScanOutput } from "./scan.js";
|
|
29
29
|
export { createSharePack, renderSharePackMarkdown, writeSharePackOutput } from "./share-pack.js";
|
|
30
|
+
export { listBundledSkills, renderBundledSkillsMarkdown } from "./skills.js";
|
|
30
31
|
export { analyzeWebsiteUrl, renderWebsiteOnboardingMarkdown, writeWebsiteOnboardingOutput } from "./url-onboarding.js";
|
package/src/install-skill.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { getBundledSkillPath, getInstalledSkillPath, getSkillName } from "./paths.js";
|
|
4
|
+
import { listBundledSkills } from "./skills.js";
|
|
4
5
|
|
|
5
6
|
async function pathExists(targetPath) {
|
|
6
7
|
try {
|
|
@@ -11,10 +12,18 @@ async function pathExists(targetPath) {
|
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
function resolveInstalledSkillPath(skillName, targetDir) {
|
|
16
|
+
if (skillName === getSkillName()) {
|
|
17
|
+
return targetDir;
|
|
18
|
+
}
|
|
19
|
+
return path.join(path.dirname(targetDir), skillName);
|
|
20
|
+
}
|
|
21
|
+
|
|
14
22
|
export async function installSkill(options = {}) {
|
|
15
23
|
const sourceDir = getBundledSkillPath();
|
|
16
24
|
const targetDir = options.targetDir || getInstalledSkillPath();
|
|
17
25
|
const silent = Boolean(options.silent);
|
|
26
|
+
const bundle = await listBundledSkills();
|
|
18
27
|
|
|
19
28
|
if (!(await pathExists(sourceDir))) {
|
|
20
29
|
throw new Error(`Bundled skill folder not found: ${sourceDir}`);
|
|
@@ -48,6 +57,14 @@ export async function installSkill(options = {}) {
|
|
|
48
57
|
const manifest = {
|
|
49
58
|
skill: getSkillName(),
|
|
50
59
|
installedSkills,
|
|
60
|
+
installedSkillDetails: bundle.skills
|
|
61
|
+
.filter((skill) => installedSkills.includes(skill.name))
|
|
62
|
+
.map((skill) => ({
|
|
63
|
+
name: skill.name,
|
|
64
|
+
displayName: skill.displayName,
|
|
65
|
+
shortDescription: skill.shortDescription,
|
|
66
|
+
installPath: resolveInstalledSkillPath(skill.name, targetDir)
|
|
67
|
+
})),
|
|
51
68
|
installedAt: new Date().toISOString(),
|
|
52
69
|
installedFrom: sourceDir,
|
|
53
70
|
packageName: "geo-ai-search-optimization",
|
|
@@ -60,6 +77,30 @@ export async function installSkill(options = {}) {
|
|
|
60
77
|
"utf8"
|
|
61
78
|
);
|
|
62
79
|
|
|
80
|
+
const bundleManifestPath = path.join(targetDir, ".skill-bundle.json");
|
|
81
|
+
await fs.writeFile(
|
|
82
|
+
bundleManifestPath,
|
|
83
|
+
`${JSON.stringify(
|
|
84
|
+
{
|
|
85
|
+
kind: bundle.kind,
|
|
86
|
+
totalSkills: bundle.totalSkills,
|
|
87
|
+
groups: bundle.groups.map((group) => ({
|
|
88
|
+
category: group.category,
|
|
89
|
+
label: group.label,
|
|
90
|
+
skills: group.skills.map((skill) => ({
|
|
91
|
+
name: skill.name,
|
|
92
|
+
displayName: skill.displayName,
|
|
93
|
+
shortDescription: skill.shortDescription,
|
|
94
|
+
installPath: resolveInstalledSkillPath(skill.name, targetDir)
|
|
95
|
+
}))
|
|
96
|
+
}))
|
|
97
|
+
},
|
|
98
|
+
null,
|
|
99
|
+
2
|
|
100
|
+
)}\n`,
|
|
101
|
+
"utf8"
|
|
102
|
+
);
|
|
103
|
+
|
|
63
104
|
if (!silent) {
|
|
64
105
|
process.stdout.write(`Installed skills (${installedSkills.join(", ")}) to ${path.dirname(targetDir)}\n`);
|
|
65
106
|
}
|
|
@@ -69,6 +110,7 @@ export async function installSkill(options = {}) {
|
|
|
69
110
|
sourceDir,
|
|
70
111
|
skillName: getSkillName(),
|
|
71
112
|
installedSkills,
|
|
72
|
-
manifest
|
|
113
|
+
manifest,
|
|
114
|
+
bundleManifestPath
|
|
73
115
|
};
|
|
74
116
|
}
|
package/src/skills.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getPackageRoot } from "./paths.js";
|
|
4
|
+
|
|
5
|
+
const SKILL_ORDER = [
|
|
6
|
+
"geo-ai-search-optimization",
|
|
7
|
+
"geo-ai-search-optimization-usage",
|
|
8
|
+
"geo-ai-search-optimization-agent-handoff",
|
|
9
|
+
"geo-ai-search-optimization-repair-loop",
|
|
10
|
+
"geo-ai-search-optimization-completion-report",
|
|
11
|
+
"geo-ai-search-optimization-handoff-bundle",
|
|
12
|
+
"geo-ai-search-optimization-share-pack",
|
|
13
|
+
"geo-ai-search-optimization-export-pack",
|
|
14
|
+
"geo-ai-search-optimization-html-pack",
|
|
15
|
+
"geo-ai-search-optimization-publish-pack"
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const SKILL_CATEGORY = {
|
|
19
|
+
"geo-ai-search-optimization": "core",
|
|
20
|
+
"geo-ai-search-optimization-usage": "guidance",
|
|
21
|
+
"geo-ai-search-optimization-agent-handoff": "execution",
|
|
22
|
+
"geo-ai-search-optimization-repair-loop": "execution",
|
|
23
|
+
"geo-ai-search-optimization-completion-report": "execution",
|
|
24
|
+
"geo-ai-search-optimization-handoff-bundle": "execution",
|
|
25
|
+
"geo-ai-search-optimization-share-pack": "delivery",
|
|
26
|
+
"geo-ai-search-optimization-export-pack": "delivery",
|
|
27
|
+
"geo-ai-search-optimization-html-pack": "delivery",
|
|
28
|
+
"geo-ai-search-optimization-publish-pack": "delivery"
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const CATEGORY_LABELS = {
|
|
32
|
+
core: "核心 GEO 能力",
|
|
33
|
+
guidance: "使用引导",
|
|
34
|
+
execution: "Agent 执行闭环",
|
|
35
|
+
delivery: "交付与分享"
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function stripQuotes(value) {
|
|
39
|
+
return String(value).trim().replace(/^['"]|['"]$/g, "");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parseYamlBlock(raw) {
|
|
43
|
+
const record = {};
|
|
44
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
45
|
+
const trimmed = line.trim();
|
|
46
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const separatorIndex = trimmed.indexOf(":");
|
|
50
|
+
if (separatorIndex === -1) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const key = trimmed.slice(0, separatorIndex).trim();
|
|
54
|
+
const value = stripQuotes(trimmed.slice(separatorIndex + 1));
|
|
55
|
+
record[key] = value;
|
|
56
|
+
}
|
|
57
|
+
return record;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function readSkillMetadata(skillDir) {
|
|
61
|
+
const skillPath = path.join(skillDir, "SKILL.md");
|
|
62
|
+
const raw = await fs.readFile(skillPath, "utf8");
|
|
63
|
+
const frontmatterMatch = raw.match(/^---\n([\s\S]*?)\n---/);
|
|
64
|
+
const frontmatter = frontmatterMatch ? parseYamlBlock(frontmatterMatch[1]) : {};
|
|
65
|
+
const yamlPath = path.join(skillDir, "agents", "openai.yaml");
|
|
66
|
+
|
|
67
|
+
let interfaceMetadata = {};
|
|
68
|
+
try {
|
|
69
|
+
const yamlRaw = await fs.readFile(yamlPath, "utf8");
|
|
70
|
+
const interfaceMatch = yamlRaw.match(/interface:\n([\s\S]*)/);
|
|
71
|
+
if (interfaceMatch) {
|
|
72
|
+
interfaceMetadata = parseYamlBlock(interfaceMatch[1]);
|
|
73
|
+
}
|
|
74
|
+
} catch {
|
|
75
|
+
interfaceMetadata = {};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const directoryName = path.basename(skillDir);
|
|
79
|
+
const name = frontmatter.name || directoryName;
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
name,
|
|
83
|
+
directoryName,
|
|
84
|
+
description: frontmatter.description || "",
|
|
85
|
+
displayName: interfaceMetadata.display_name || name,
|
|
86
|
+
shortDescription: interfaceMetadata.short_description || frontmatter.description || "",
|
|
87
|
+
defaultPrompt: interfaceMetadata.default_prompt || "",
|
|
88
|
+
category: SKILL_CATEGORY[name] || "delivery",
|
|
89
|
+
skillPath
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function sortSkills(skills) {
|
|
94
|
+
return [...skills].sort((left, right) => {
|
|
95
|
+
const leftIndex = SKILL_ORDER.indexOf(left.name);
|
|
96
|
+
const rightIndex = SKILL_ORDER.indexOf(right.name);
|
|
97
|
+
if (leftIndex === -1 && rightIndex === -1) {
|
|
98
|
+
return left.name.localeCompare(right.name);
|
|
99
|
+
}
|
|
100
|
+
if (leftIndex === -1) {
|
|
101
|
+
return 1;
|
|
102
|
+
}
|
|
103
|
+
if (rightIndex === -1) {
|
|
104
|
+
return -1;
|
|
105
|
+
}
|
|
106
|
+
return leftIndex - rightIndex;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export async function listBundledSkills() {
|
|
111
|
+
const resourcesDir = path.join(getPackageRoot(), "resources");
|
|
112
|
+
const entries = await fs.readdir(resourcesDir, { withFileTypes: true });
|
|
113
|
+
const skillDirs = entries
|
|
114
|
+
.filter((entry) => entry.isDirectory())
|
|
115
|
+
.map((entry) => path.join(resourcesDir, entry.name));
|
|
116
|
+
|
|
117
|
+
const skills = [];
|
|
118
|
+
for (const skillDir of skillDirs) {
|
|
119
|
+
try {
|
|
120
|
+
await fs.access(path.join(skillDir, "SKILL.md"));
|
|
121
|
+
} catch {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
skills.push(await readSkillMetadata(skillDir));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const ordered = sortSkills(skills);
|
|
128
|
+
const grouped = Object.entries(CATEGORY_LABELS).map(([category, label]) => ({
|
|
129
|
+
category,
|
|
130
|
+
label,
|
|
131
|
+
skills: ordered.filter((skill) => skill.category === category)
|
|
132
|
+
}));
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
kind: "geo-skill-bundle",
|
|
136
|
+
totalSkills: ordered.length,
|
|
137
|
+
skills: ordered,
|
|
138
|
+
groups: grouped.filter((group) => group.skills.length > 0)
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function renderBundledSkillsMarkdown(bundle) {
|
|
143
|
+
const lines = [
|
|
144
|
+
"# GEO Skill Bundle",
|
|
145
|
+
"",
|
|
146
|
+
`- 技能数量:\`${bundle.totalSkills}\``,
|
|
147
|
+
"",
|
|
148
|
+
"## 推荐理解顺序",
|
|
149
|
+
"",
|
|
150
|
+
"- 先看核心 GEO skill。",
|
|
151
|
+
"- 再看 usage skill,知道什么时候该跑哪个命令。",
|
|
152
|
+
"- 如果要交给 agent 执行,再进入 handoff / apply / completion 这一条执行链。",
|
|
153
|
+
"- 如果要产出给团队分发,再进入 share / export / html / publish 这一条交付链。",
|
|
154
|
+
""
|
|
155
|
+
];
|
|
156
|
+
|
|
157
|
+
for (const group of bundle.groups) {
|
|
158
|
+
lines.push(`## ${group.label}`, "");
|
|
159
|
+
for (const skill of group.skills) {
|
|
160
|
+
lines.push(`- ${skill.name}`);
|
|
161
|
+
lines.push(` - 显示名:${skill.displayName}`);
|
|
162
|
+
lines.push(` - 说明:${skill.shortDescription}`);
|
|
163
|
+
lines.push(` - 路径:\`${skill.skillPath}\``);
|
|
164
|
+
}
|
|
165
|
+
lines.push("");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return `${lines.join("\n")}\n`;
|
|
169
|
+
}
|