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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geo-ai-search-optimization",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "description": "Install and run a Generative Engine Optimization (GEO)-first, SEO-supported Codex skill for website optimization.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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 Export Pack"
3
+ short_description: "Export GEO deliverables into a shareable folder"
4
+ default_prompt: "Use $geo-ai-search-optimization-export-pack to generate a folder of GEO deliverables for PM, engineering, management, and agent handoff."
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "GEO Handoff Bundle"
3
+ short_description: "Continue from one bundled GEO execution artifact"
4
+ default_prompt: "Use $geo-ai-search-optimization-handoff-bundle to continue from this combined GEO handoff, execution, and closeout artifact."
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "GEO HTML Pack"
3
+ short_description: "Generate browsable HTML pages from GEO outputs"
4
+ default_prompt: "Use $geo-ai-search-optimization-html-pack to convert these GEO deliverables into browsable HTML pages for sharing."
@@ -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 twelve layers:
17
-
18
- 1. `onboard-url` / `onboard`: first look
19
- 2. `scan`: raw signal check
20
- 3. `audit` / `report`: diagnosis
21
- 4. `fix-plan` / `owner-board`: execution planning
22
- 5. `agent-handoff`: agent takeover package
23
- 6. `apply-plan`: execution loop
24
- 7. `completion-report`: closeout
25
- 8. `handoff-bundle`: all-in-one package
26
- 9. `share-pack`: audience-ready delivery
27
- 10. `export-pack`: folder export
28
- 11. `html-pack`: browsable output
29
- 12. `pm-brief` / `roadmap`: stakeholder alignment
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";
@@ -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
+ }