geo-ai-search-optimization 1.2.3 → 1.2.5
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 +52 -0
- package/package.json +1 -1
- package/resources/geo-ai-search-optimization/references/quick-start.md +3 -1
- package/resources/geo-ai-search-optimization-html-pack/SKILL.md +24 -0
- package/resources/geo-ai-search-optimization-publish-pack/SKILL.md +26 -0
- package/resources/geo-ai-search-optimization-publish-pack/agents/openai.yaml +4 -0
- package/resources/geo-ai-search-optimization-usage/SKILL.md +6 -2
- package/resources/geo-ai-search-optimization-usage/references/usage-patterns.md +8 -0
- package/src/cli.js +42 -0
- package/src/html-pack.js +177 -0
- package/src/index.js +2 -0
- package/src/publish-pack.js +420 -0
- package/src/quick-start.js +2 -1
package/README.md
CHANGED
|
@@ -243,6 +243,42 @@ geo-ai-search-optimization export-pack https://example.com --out-dir ./exports/e
|
|
|
243
243
|
- `agent-handoff-bundle`
|
|
244
244
|
- `share-pack`
|
|
245
245
|
|
|
246
|
+
## HTML Pack 命令
|
|
247
|
+
|
|
248
|
+
如果你希望直接生成可浏览的静态 HTML 页面,而不是 Markdown 文件,现在可以用 `html-pack`:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
geo-ai-search-optimization html-pack ./your-site --out-dir ./exports/your-site-html
|
|
252
|
+
geo-ai-search-optimization html-pack https://example.com --out-dir ./exports/example-html
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
`html-pack` 会生成:
|
|
256
|
+
|
|
257
|
+
- `index.html`
|
|
258
|
+
- `pm.html`
|
|
259
|
+
- `engineering.html`
|
|
260
|
+
- `exec.html`
|
|
261
|
+
- `agent.html`
|
|
262
|
+
- `share.html`
|
|
263
|
+
|
|
264
|
+
## Publish Pack 命令
|
|
265
|
+
|
|
266
|
+
如果你希望直接生成一份“最终可交付包”,同时给人和 agent 使用,现在可以用 `publish-pack`:
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
geo-ai-search-optimization publish-pack ./your-site --out-dir ./exports/your-site-publish-pack
|
|
270
|
+
geo-ai-search-optimization publish-pack https://example.com --out-dir ./exports/example-publish-pack
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
`publish-pack` 会一次生成:
|
|
274
|
+
|
|
275
|
+
- `site/`: 可浏览的静态 HTML 页面
|
|
276
|
+
- `documents/`: 给 PM、工程、管理层直接转发的 Markdown 文档
|
|
277
|
+
- `data/`: 给 agent 或自动化流程使用的 JSON 工件
|
|
278
|
+
- `START-HERE.md`: 给人的起始说明
|
|
279
|
+
- `AGENT-START.md`: 给 agent 的执行入口
|
|
280
|
+
- `manifest.json`: 机器可读总索引
|
|
281
|
+
|
|
246
282
|
## Fix Plan 命令
|
|
247
283
|
|
|
248
284
|
如果你已经跑过 `audit`、`report` 或 `onboard-url`,下一步就可以直接把结果转成 PM 待办清单:
|
|
@@ -399,6 +435,8 @@ geo-ai-search-optimization completion-report ./my-site
|
|
|
399
435
|
geo-ai-search-optimization handoff-bundle ./my-site
|
|
400
436
|
geo-ai-search-optimization share-pack ./my-site
|
|
401
437
|
geo-ai-search-optimization export-pack ./my-site --out-dir ./exports/my-site-pack
|
|
438
|
+
geo-ai-search-optimization html-pack ./my-site --out-dir ./exports/my-site-html
|
|
439
|
+
geo-ai-search-optimization publish-pack ./my-site --out-dir ./exports/my-site-publish-pack
|
|
402
440
|
geo-ai-search-optimization exec-summary ./my-site
|
|
403
441
|
geo-ai-search-optimization fix-plan ./my-site
|
|
404
442
|
geo-ai-search-optimization owner-board ./my-site
|
|
@@ -414,6 +452,20 @@ geo-ai-search-optimization version
|
|
|
414
452
|
geo-ai-search-optimization help
|
|
415
453
|
```
|
|
416
454
|
|
|
455
|
+
## New in 1.2.5
|
|
456
|
+
|
|
457
|
+
- 新增 `publish-pack`
|
|
458
|
+
- 一次生成最终可交付目录,而不是手动拼 HTML、Markdown、JSON
|
|
459
|
+
- 增加 `START-HERE.md`、`AGENT-START.md`、`manifest.json`
|
|
460
|
+
- 新增 `geo-ai-search-optimization-publish-pack` skill,帮助 agent 直接接手最终交付包
|
|
461
|
+
|
|
462
|
+
## New in 1.2.4
|
|
463
|
+
|
|
464
|
+
- 新增 `html-pack`
|
|
465
|
+
- 直接生成可浏览的静态 HTML 页面目录
|
|
466
|
+
- 更适合直接分享链接或打包给不同角色查看
|
|
467
|
+
- 新增 `geo-ai-search-optimization-html-pack` skill,帮助消费 HTML 包
|
|
468
|
+
|
|
417
469
|
## New in 1.2.3
|
|
418
470
|
|
|
419
471
|
- 新增 `export-pack`
|
package/package.json
CHANGED
|
@@ -48,6 +48,7 @@ geo-ai-search-optimization completion-report ./your-site --out ./reports/complet
|
|
|
48
48
|
geo-ai-search-optimization handoff-bundle ./your-site --out ./reports/handoff-bundle.md
|
|
49
49
|
geo-ai-search-optimization share-pack ./your-site --out ./reports/share-pack.md
|
|
50
50
|
geo-ai-search-optimization export-pack ./your-site --out-dir ./exports/your-site-pack
|
|
51
|
+
geo-ai-search-optimization html-pack ./your-site --out-dir ./exports/your-site-html
|
|
51
52
|
geo-ai-search-optimization owner-board ./your-site --out ./reports/owner-board.md
|
|
52
53
|
geo-ai-search-optimization meeting-pack ./your-site --out ./reports/meeting-pack.md
|
|
53
54
|
geo-ai-search-optimization pm-brief ./your-site --out ./reports/pm-brief.md
|
|
@@ -67,7 +68,8 @@ geo-ai-search-optimization roadmap ./your-site --out ./reports/roadmap.md
|
|
|
67
68
|
7. 需要完整交接包时生成 handoff-bundle
|
|
68
69
|
8. 需要发给不同角色时生成 share-pack
|
|
69
70
|
9. 需要一整包文件时生成 export-pack
|
|
70
|
-
10.
|
|
71
|
+
10. 需要直接分享页面时生成 html-pack
|
|
72
|
+
11. 重跑 scan / audit / report 验证是否改善
|
|
71
73
|
|
|
72
74
|
## 推荐节奏
|
|
73
75
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: geo-ai-search-optimization-html-pack
|
|
3
|
+
description: Generate a static HTML share package for GEO results. Use when the user wants browsable files like index.html, pm.html, engineering.html, exec.html, and agent.html instead of plain markdown or JSON exports.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GEO HTML Pack
|
|
7
|
+
|
|
8
|
+
Use this skill when the user wants a visually shareable GEO output package.
|
|
9
|
+
|
|
10
|
+
`GEO = Generative Engine Optimization`
|
|
11
|
+
|
|
12
|
+
## What it generates
|
|
13
|
+
|
|
14
|
+
- `index.html`
|
|
15
|
+
- `pm.html`
|
|
16
|
+
- `engineering.html`
|
|
17
|
+
- `exec.html`
|
|
18
|
+
- `agent.html`
|
|
19
|
+
- `share.html`
|
|
20
|
+
|
|
21
|
+
## Best use
|
|
22
|
+
|
|
23
|
+
- send `index.html` as the landing page
|
|
24
|
+
- share role-specific pages directly when needed
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: geo-ai-search-optimization-publish-pack
|
|
3
|
+
description: Generate a final GEO delivery package that combines HTML pages, markdown documents, JSON artifacts, and agent start files. Use when a PM or agent wants one folder that can be shared directly with humans and handed off directly to another agent.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GEO Publish Pack
|
|
7
|
+
|
|
8
|
+
Use this skill when the user wants a single final package instead of separate GEO artifacts.
|
|
9
|
+
|
|
10
|
+
`GEO = Generative Engine Optimization`
|
|
11
|
+
|
|
12
|
+
## What it generates
|
|
13
|
+
|
|
14
|
+
- `site/` for browsable HTML pages
|
|
15
|
+
- `documents/` for markdown files that can be sent to PM, engineering, or management
|
|
16
|
+
- `data/` for machine-readable JSON artifacts
|
|
17
|
+
- `START-HERE.md` for people
|
|
18
|
+
- `AGENT-START.md` for the next agent
|
|
19
|
+
- `manifest.json` for automation and indexing
|
|
20
|
+
|
|
21
|
+
## Best use
|
|
22
|
+
|
|
23
|
+
- generate one delivery folder at the end of an analysis round
|
|
24
|
+
- share `site/index.html` for quick browsing
|
|
25
|
+
- point the next agent to `AGENT-START.md`
|
|
26
|
+
- use `manifest.json` when another tool needs to ingest the package
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "GEO Publish Pack"
|
|
3
|
+
short_description: "Build a final delivery folder for humans and agents"
|
|
4
|
+
default_prompt: "Use $geo-ai-search-optimization-publish-pack to generate a final GEO delivery package with HTML, markdown, JSON, and an agent handoff entrypoint."
|
|
@@ -13,7 +13,7 @@ Treat this tool as a PM-friendly GEO workflow for websites.
|
|
|
13
13
|
|
|
14
14
|
`GEO = Generative Engine Optimization`
|
|
15
15
|
|
|
16
|
-
The package is best explained as
|
|
16
|
+
The package is best explained as twelve layers:
|
|
17
17
|
|
|
18
18
|
1. `onboard-url` / `onboard`: first look
|
|
19
19
|
2. `scan`: raw signal check
|
|
@@ -25,7 +25,8 @@ The package is best explained as eleven layers:
|
|
|
25
25
|
8. `handoff-bundle`: all-in-one package
|
|
26
26
|
9. `share-pack`: audience-ready delivery
|
|
27
27
|
10. `export-pack`: folder export
|
|
28
|
-
11. `
|
|
28
|
+
11. `html-pack`: browsable output
|
|
29
|
+
12. `pm-brief` / `roadmap`: stakeholder alignment
|
|
29
30
|
|
|
30
31
|
## Recommended command order
|
|
31
32
|
|
|
@@ -49,6 +50,7 @@ npx geo-ai-search-optimization completion-report ./your-site
|
|
|
49
50
|
npx geo-ai-search-optimization handoff-bundle ./your-site
|
|
50
51
|
npx geo-ai-search-optimization share-pack ./your-site
|
|
51
52
|
npx geo-ai-search-optimization export-pack ./your-site
|
|
53
|
+
npx geo-ai-search-optimization html-pack ./your-site
|
|
52
54
|
npx geo-ai-search-optimization owner-board ./your-site
|
|
53
55
|
npx geo-ai-search-optimization roadmap ./your-site
|
|
54
56
|
```
|
|
@@ -67,6 +69,7 @@ npx geo-ai-search-optimization roadmap ./your-site
|
|
|
67
69
|
- `handoff-bundle`: combine handoff, execution, and closeout into one artifact
|
|
68
70
|
- `share-pack`: prepare role-specific shareable outputs for PM, engineering, management, and agents
|
|
69
71
|
- `export-pack`: generate a folder with multiple ready-to-send files
|
|
72
|
+
- `html-pack`: generate static HTML pages for sharing and browsing
|
|
70
73
|
- `owner-board`: group tasks by PM / engineering / SEO / content
|
|
71
74
|
- `pm-brief`: prepare a PM summary for meetings and prioritization
|
|
72
75
|
- `roadmap`: turn tasks into a 2-week / 4-week execution sequence
|
|
@@ -84,6 +87,7 @@ When explaining the tool to a user:
|
|
|
84
87
|
- if the user wants one consolidated artifact, move them to `handoff-bundle`
|
|
85
88
|
- if the user wants something ready to forward to multiple audiences, move them to `share-pack`
|
|
86
89
|
- if the user wants actual files on disk for each audience, move them to `export-pack`
|
|
90
|
+
- if the user wants browsable HTML pages, move them to `html-pack`
|
|
87
91
|
- if the user already has a report, move them to `fix-plan`, `owner-board`, or `roadmap`
|
|
88
92
|
|
|
89
93
|
Read [references/usage-patterns.md](references/usage-patterns.md) when you need response patterns and command selection examples.
|
|
@@ -111,6 +111,14 @@ Recommend:
|
|
|
111
111
|
npx geo-ai-search-optimization export-pack ./your-site --out-dir ./exports/your-site-pack
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
+
## If the user says "我想直接分享 HTML 页面"
|
|
115
|
+
|
|
116
|
+
Recommend:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npx geo-ai-search-optimization html-pack ./your-site --out-dir ./exports/your-site-html
|
|
120
|
+
```
|
|
121
|
+
|
|
114
122
|
## If the user says "我要开会同步"
|
|
115
123
|
|
|
116
124
|
Recommend:
|
package/src/cli.js
CHANGED
|
@@ -18,9 +18,11 @@ import { auditProject, renderAuditMarkdown, writeAuditOutput } from "./audit.js"
|
|
|
18
18
|
import { createFixPlan, renderFixPlanMarkdown, writeFixPlanOutput } from "./fix-plan.js";
|
|
19
19
|
import { createExecSummary, renderExecSummaryMarkdown, writeExecSummaryOutput } from "./exec-summary.js";
|
|
20
20
|
import { renderExportPackMarkdown, writeExportPack } from "./export-pack.js";
|
|
21
|
+
import { renderHtmlPackMarkdown, writeHtmlPack } from "./html-pack.js";
|
|
21
22
|
import { createOwnerBoard, renderOwnerBoardMarkdown, writeOwnerBoardOutput } from "./owner-board.js";
|
|
22
23
|
import { createMeetingPack, renderMeetingPackMarkdown, writeMeetingPackOutput } from "./meeting-pack.js";
|
|
23
24
|
import { createPmBrief, renderPmBriefMarkdown, writePmBriefOutput } from "./pm-brief.js";
|
|
25
|
+
import { renderPublishPackMarkdown, writePublishPack } from "./publish-pack.js";
|
|
24
26
|
import { generateReport, writeReportOutput } from "./report.js";
|
|
25
27
|
import { createRoadmap, renderRoadmapMarkdown, writeRoadmapOutput } from "./roadmap.js";
|
|
26
28
|
import {
|
|
@@ -68,6 +70,8 @@ function printHelp() {
|
|
|
68
70
|
" geo-ai-search-optimization handoff-bundle <input> [--task <id>] [--format <markdown|json>] [--out <file>]",
|
|
69
71
|
" geo-ai-search-optimization share-pack <input> [--task <id>] [--format <markdown|json>] [--out <file>]",
|
|
70
72
|
" geo-ai-search-optimization export-pack <input> [--task <id>] [--format <markdown|json>] [--out-dir <dir>]",
|
|
73
|
+
" geo-ai-search-optimization html-pack <input> [--task <id>] [--out-dir <dir>]",
|
|
74
|
+
" geo-ai-search-optimization publish-pack <input> [--task <id>] [--out-dir <dir>]",
|
|
71
75
|
" geo-ai-search-optimization exec-summary <input> [--format <markdown|json>] [--out <file>]",
|
|
72
76
|
" geo-ai-search-optimization fix-plan <input> [--format <markdown|json>] [--out <file>]",
|
|
73
77
|
" geo-ai-search-optimization owner-board <input> [--format <markdown|json>] [--out <file>]",
|
|
@@ -490,6 +494,34 @@ async function handleExportPack(args) {
|
|
|
490
494
|
process.stdout.write(renderExportPackMarkdown(pack));
|
|
491
495
|
}
|
|
492
496
|
|
|
497
|
+
async function handleHtmlPack(args) {
|
|
498
|
+
const input = args.find((value) => !value.startsWith("-"));
|
|
499
|
+
if (!input) {
|
|
500
|
+
throw new Error("html-pack 需要一个输入值,可以是项目路径、网站网址或已导出的 JSON 工件");
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const pack = await writeHtmlPack(input, {
|
|
504
|
+
taskId: getFlagValue(args, "--task"),
|
|
505
|
+
outputDir: getFlagValue(args, "--out-dir")
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
process.stdout.write(renderHtmlPackMarkdown(pack));
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
async function handlePublishPack(args) {
|
|
512
|
+
const input = args.find((value) => !value.startsWith("-"));
|
|
513
|
+
if (!input) {
|
|
514
|
+
throw new Error("publish-pack 需要一个输入值,可以是项目路径、网站网址或已导出的 JSON 工件");
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const pack = await writePublishPack(input, {
|
|
518
|
+
taskId: getFlagValue(args, "--task"),
|
|
519
|
+
outputDir: getFlagValue(args, "--out-dir")
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
process.stdout.write(renderPublishPackMarkdown(pack));
|
|
523
|
+
}
|
|
524
|
+
|
|
493
525
|
async function handleExecSummary(args) {
|
|
494
526
|
const input = args.find((value) => !value.startsWith("-"));
|
|
495
527
|
if (!input) {
|
|
@@ -693,6 +725,16 @@ export async function runCli(args = []) {
|
|
|
693
725
|
return;
|
|
694
726
|
}
|
|
695
727
|
|
|
728
|
+
if (command === "html-pack") {
|
|
729
|
+
await handleHtmlPack(rest);
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
if (command === "publish-pack") {
|
|
734
|
+
await handlePublishPack(rest);
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
|
|
696
738
|
if (command === "exec-summary") {
|
|
697
739
|
await handleExecSummary(rest);
|
|
698
740
|
return;
|
package/src/html-pack.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createExportPack } from "./export-pack.js";
|
|
4
|
+
|
|
5
|
+
function escapeHtml(value) {
|
|
6
|
+
return String(value)
|
|
7
|
+
.replaceAll("&", "&")
|
|
8
|
+
.replaceAll("<", "<")
|
|
9
|
+
.replaceAll(">", ">")
|
|
10
|
+
.replaceAll('"', """)
|
|
11
|
+
.replaceAll("'", "'");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function wrapHtml(title, body) {
|
|
15
|
+
return [
|
|
16
|
+
"<!doctype html>",
|
|
17
|
+
'<html lang="zh-Hant">',
|
|
18
|
+
"<head>",
|
|
19
|
+
'<meta charset="utf-8">',
|
|
20
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1">',
|
|
21
|
+
`<title>${escapeHtml(title)}</title>`,
|
|
22
|
+
"<style>",
|
|
23
|
+
"body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;margin:0;background:#f5f7fb;color:#16324f;}",
|
|
24
|
+
".shell{max-width:1100px;margin:0 auto;padding:32px 20px 64px;}",
|
|
25
|
+
".hero,.card{background:#fff;border:1px solid #d9e2ec;border-radius:16px;box-shadow:0 8px 24px rgba(15,23,42,.06);}",
|
|
26
|
+
".hero{padding:28px;margin-bottom:24px;}",
|
|
27
|
+
".grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;}",
|
|
28
|
+
".card{padding:20px;}",
|
|
29
|
+
"h1,h2,h3{margin-top:0;color:#102a43;}",
|
|
30
|
+
"ul{padding-left:20px;line-height:1.7;}",
|
|
31
|
+
"a{color:#0b7285;text-decoration:none;}",
|
|
32
|
+
"code,pre{background:#f4f7fb;border-radius:10px;}",
|
|
33
|
+
"pre{padding:16px;white-space:pre-wrap;overflow:auto;}",
|
|
34
|
+
".meta{display:flex;gap:12px;flex-wrap:wrap;color:#486581;}",
|
|
35
|
+
"</style>",
|
|
36
|
+
"</head>",
|
|
37
|
+
"<body>",
|
|
38
|
+
body,
|
|
39
|
+
"</body>",
|
|
40
|
+
"</html>"
|
|
41
|
+
].join("");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function buildIndexHtml(pack) {
|
|
45
|
+
const cards = pack.files
|
|
46
|
+
.map(
|
|
47
|
+
(file) => `
|
|
48
|
+
<article class="card">
|
|
49
|
+
<h3>${escapeHtml(file.label)}</h3>
|
|
50
|
+
<p>${escapeHtml(file.description)}</p>
|
|
51
|
+
<a href="./${escapeHtml(file.filename)}">打开 ${escapeHtml(file.filename)}</a>
|
|
52
|
+
</article>
|
|
53
|
+
`
|
|
54
|
+
)
|
|
55
|
+
.join("");
|
|
56
|
+
|
|
57
|
+
return wrapHtml(
|
|
58
|
+
"GEO HTML Pack",
|
|
59
|
+
`
|
|
60
|
+
<main class="shell">
|
|
61
|
+
<section class="hero">
|
|
62
|
+
<h1>GEO HTML Pack</h1>
|
|
63
|
+
<div class="meta">
|
|
64
|
+
<span>来源:${escapeHtml(pack.source)}</span>
|
|
65
|
+
<span>类型:${escapeHtml(pack.sourceType)}</span>
|
|
66
|
+
<span>目录:${escapeHtml(pack.outputDir)}</span>
|
|
67
|
+
</div>
|
|
68
|
+
<p>这是一个适合直接分享的静态 GEO 页面包,分别提供给 PM、工程、管理层和下一位 agent。</p>
|
|
69
|
+
</section>
|
|
70
|
+
<section class="grid">
|
|
71
|
+
${cards}
|
|
72
|
+
</section>
|
|
73
|
+
</main>
|
|
74
|
+
`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function buildDocumentHtml(title, content) {
|
|
79
|
+
return wrapHtml(
|
|
80
|
+
title,
|
|
81
|
+
`
|
|
82
|
+
<main class="shell">
|
|
83
|
+
<section class="hero">
|
|
84
|
+
<h1>${escapeHtml(title)}</h1>
|
|
85
|
+
</section>
|
|
86
|
+
<section class="card">
|
|
87
|
+
<pre>${escapeHtml(content)}</pre>
|
|
88
|
+
</section>
|
|
89
|
+
</main>
|
|
90
|
+
`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function writeHtmlPack(input, options = {}) {
|
|
95
|
+
const baseOutputDir = path.resolve(options.outputDir || "./exports/html-pack");
|
|
96
|
+
const exportPack = await createExportPack(input, {
|
|
97
|
+
format: "markdown",
|
|
98
|
+
taskId: options.taskId,
|
|
99
|
+
outputDir: baseOutputDir
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await fs.mkdir(baseOutputDir, { recursive: true });
|
|
103
|
+
|
|
104
|
+
const files = [
|
|
105
|
+
{
|
|
106
|
+
key: "pm",
|
|
107
|
+
label: "PM Brief",
|
|
108
|
+
description: "给 PM 的优先级与推进摘要。",
|
|
109
|
+
filename: "pm.html",
|
|
110
|
+
content: exportPack.files.find((file) => file.key === "pm")?.content || ""
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
key: "engineering",
|
|
114
|
+
label: "Owner Board",
|
|
115
|
+
description: "给工程与执行团队的任务视图。",
|
|
116
|
+
filename: "engineering.html",
|
|
117
|
+
content: exportPack.files.find((file) => file.key === "engineering")?.content || ""
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
key: "exec",
|
|
121
|
+
label: "Exec Summary",
|
|
122
|
+
description: "给管理层的高层摘要。",
|
|
123
|
+
filename: "exec.html",
|
|
124
|
+
content: exportPack.files.find((file) => file.key === "exec")?.content || ""
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
key: "agent",
|
|
128
|
+
label: "Agent Bundle",
|
|
129
|
+
description: "给下一位 agent 的交接入口。",
|
|
130
|
+
filename: "agent.html",
|
|
131
|
+
content: exportPack.files.find((file) => file.key === "agent")?.content || ""
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
key: "share",
|
|
135
|
+
label: "Share Pack",
|
|
136
|
+
description: "给协调者的总览页面。",
|
|
137
|
+
filename: "share.html",
|
|
138
|
+
content: exportPack.files.find((file) => file.key === "share_pack")?.content || ""
|
|
139
|
+
}
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
await fs.writeFile(path.join(baseOutputDir, "index.html"), buildIndexHtml({ ...exportPack, files }), "utf8");
|
|
143
|
+
|
|
144
|
+
for (const file of files) {
|
|
145
|
+
await fs.writeFile(path.join(baseOutputDir, file.filename), buildDocumentHtml(file.label, file.content), "utf8");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
kind: "geo-html-pack",
|
|
150
|
+
source: exportPack.source,
|
|
151
|
+
sourceType: exportPack.sourceType,
|
|
152
|
+
outputDir: baseOutputDir,
|
|
153
|
+
files: [
|
|
154
|
+
{ key: "index", path: path.join(baseOutputDir, "index.html") },
|
|
155
|
+
...files.map((file) => ({ key: file.key, path: path.join(baseOutputDir, file.filename) }))
|
|
156
|
+
]
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function renderHtmlPackMarkdown(pack) {
|
|
161
|
+
const lines = [
|
|
162
|
+
"# GEO HTML Pack",
|
|
163
|
+
"",
|
|
164
|
+
`- 输入来源:\`${pack.source}\``,
|
|
165
|
+
`- 来源类型:\`${pack.sourceType}\``,
|
|
166
|
+
`- 输出目录:\`${pack.outputDir}\``,
|
|
167
|
+
"",
|
|
168
|
+
"## 页面文件",
|
|
169
|
+
""
|
|
170
|
+
];
|
|
171
|
+
|
|
172
|
+
for (const file of pack.files) {
|
|
173
|
+
lines.push(`- ${file.key}:\`${file.path}\``);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return `${lines.join("\n")}\n`;
|
|
177
|
+
}
|
package/src/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export { createAgentHandoff, renderAgentHandoffMarkdown, writeAgentHandoffOutput
|
|
|
10
10
|
export { createCompletionReport, renderCompletionReportMarkdown, writeCompletionReportOutput } from "./completion-report.js";
|
|
11
11
|
export { createFixPlan, renderFixPlanMarkdown, writeFixPlanOutput } from "./fix-plan.js";
|
|
12
12
|
export { createHandoffBundle, renderHandoffBundleMarkdown, writeHandoffBundleOutput } from "./handoff-bundle.js";
|
|
13
|
+
export { renderHtmlPackMarkdown, writeHtmlPack } from "./html-pack.js";
|
|
13
14
|
export { installSkill } from "./install-skill.js";
|
|
14
15
|
export { runCli } from "./cli.js";
|
|
15
16
|
export { runDoctor, renderDoctorMarkdown } from "./doctor.js";
|
|
@@ -19,6 +20,7 @@ export { createExportPack, renderExportPackMarkdown, writeExportPack } from "./e
|
|
|
19
20
|
export { createMeetingPack, renderMeetingPackMarkdown, writeMeetingPackOutput } from "./meeting-pack.js";
|
|
20
21
|
export { createOwnerBoard, renderOwnerBoardMarkdown, writeOwnerBoardOutput } from "./owner-board.js";
|
|
21
22
|
export { createPmBrief, renderPmBriefMarkdown, writePmBriefOutput } from "./pm-brief.js";
|
|
23
|
+
export { renderPublishPackMarkdown, writePublishPack } from "./publish-pack.js";
|
|
22
24
|
export { createQuickStartPlan, renderQuickStartMarkdown, writeQuickStartOutput } from "./quick-start.js";
|
|
23
25
|
export { generateReport, writeReportOutput } from "./report.js";
|
|
24
26
|
export { createRoadmap, renderRoadmapMarkdown, writeRoadmapOutput } from "./roadmap.js";
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createExecSummary, renderExecSummaryMarkdown } from "./exec-summary.js";
|
|
4
|
+
import { createHandoffBundle, renderHandoffBundleMarkdown } from "./handoff-bundle.js";
|
|
5
|
+
import { createOwnerBoard, renderOwnerBoardMarkdown } from "./owner-board.js";
|
|
6
|
+
import { createPmBrief, renderPmBriefMarkdown } from "./pm-brief.js";
|
|
7
|
+
import { createSharePack, renderSharePackMarkdown } from "./share-pack.js";
|
|
8
|
+
|
|
9
|
+
function sanitizeSegment(value) {
|
|
10
|
+
return String(value)
|
|
11
|
+
.replace(/[^a-z0-9-_]+/gi, "-")
|
|
12
|
+
.replace(/^-+|-+$/g, "")
|
|
13
|
+
.toLowerCase();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function buildBaseName(sourceType, source) {
|
|
17
|
+
if (sourceType === "url") {
|
|
18
|
+
try {
|
|
19
|
+
const hostname = new URL(source).hostname || "website";
|
|
20
|
+
return sanitizeSegment(hostname) || "website";
|
|
21
|
+
} catch {
|
|
22
|
+
return "website";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return sanitizeSegment(path.basename(source)) || "site";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function escapeHtml(value) {
|
|
30
|
+
return String(value)
|
|
31
|
+
.replaceAll("&", "&")
|
|
32
|
+
.replaceAll("<", "<")
|
|
33
|
+
.replaceAll(">", ">")
|
|
34
|
+
.replaceAll('"', """)
|
|
35
|
+
.replaceAll("'", "'");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function wrapHtml(title, body) {
|
|
39
|
+
return [
|
|
40
|
+
"<!doctype html>",
|
|
41
|
+
'<html lang="zh-Hant">',
|
|
42
|
+
"<head>",
|
|
43
|
+
'<meta charset="utf-8">',
|
|
44
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1">',
|
|
45
|
+
`<title>${escapeHtml(title)}</title>`,
|
|
46
|
+
"<style>",
|
|
47
|
+
"body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;margin:0;background:#f5f7fb;color:#16324f;}",
|
|
48
|
+
".shell{max-width:1100px;margin:0 auto;padding:32px 20px 64px;}",
|
|
49
|
+
".hero,.card{background:#fff;border:1px solid #d9e2ec;border-radius:16px;box-shadow:0 8px 24px rgba(15,23,42,.06);}",
|
|
50
|
+
".hero{padding:28px;margin-bottom:24px;}",
|
|
51
|
+
".grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;}",
|
|
52
|
+
".card{padding:20px;}",
|
|
53
|
+
"h1,h2,h3{margin-top:0;color:#102a43;}",
|
|
54
|
+
"ul{padding-left:20px;line-height:1.7;}",
|
|
55
|
+
"a{color:#0b7285;text-decoration:none;}",
|
|
56
|
+
"code,pre{background:#f4f7fb;border-radius:10px;}",
|
|
57
|
+
"pre{padding:16px;white-space:pre-wrap;overflow:auto;}",
|
|
58
|
+
".meta{display:flex;gap:12px;flex-wrap:wrap;color:#486581;}",
|
|
59
|
+
"</style>",
|
|
60
|
+
"</head>",
|
|
61
|
+
"<body>",
|
|
62
|
+
body,
|
|
63
|
+
"</body>",
|
|
64
|
+
"</html>"
|
|
65
|
+
].join("");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function buildDocumentHtml(title, content) {
|
|
69
|
+
return wrapHtml(
|
|
70
|
+
title,
|
|
71
|
+
`
|
|
72
|
+
<main class="shell">
|
|
73
|
+
<section class="hero">
|
|
74
|
+
<h1>${escapeHtml(title)}</h1>
|
|
75
|
+
</section>
|
|
76
|
+
<section class="card">
|
|
77
|
+
<pre>${escapeHtml(content)}</pre>
|
|
78
|
+
</section>
|
|
79
|
+
</main>
|
|
80
|
+
`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function buildIndexHtml(pack) {
|
|
85
|
+
const cards = pack.htmlFiles
|
|
86
|
+
.map(
|
|
87
|
+
(file) => `
|
|
88
|
+
<article class="card">
|
|
89
|
+
<h3>${escapeHtml(file.label)}</h3>
|
|
90
|
+
<p>${escapeHtml(file.description)}</p>
|
|
91
|
+
<a href="./${escapeHtml(file.filename)}">打开 ${escapeHtml(file.filename)}</a>
|
|
92
|
+
</article>
|
|
93
|
+
`
|
|
94
|
+
)
|
|
95
|
+
.join("");
|
|
96
|
+
|
|
97
|
+
return wrapHtml(
|
|
98
|
+
"GEO Publish Pack",
|
|
99
|
+
`
|
|
100
|
+
<main class="shell">
|
|
101
|
+
<section class="hero">
|
|
102
|
+
<h1>GEO Publish Pack</h1>
|
|
103
|
+
<div class="meta">
|
|
104
|
+
<span>来源:${escapeHtml(pack.source)}</span>
|
|
105
|
+
<span>类型:${escapeHtml(pack.sourceType)}</span>
|
|
106
|
+
<span>目录:${escapeHtml(pack.outputDir)}</span>
|
|
107
|
+
</div>
|
|
108
|
+
<p>这是一个适合直接交付、分发与交接的 GEO 最终发布包,覆盖 PM、工程、管理层与下一位 agent。</p>
|
|
109
|
+
</section>
|
|
110
|
+
<section class="grid">
|
|
111
|
+
${cards}
|
|
112
|
+
</section>
|
|
113
|
+
</main>
|
|
114
|
+
`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function buildStartHereContent(pack) {
|
|
119
|
+
return [
|
|
120
|
+
"# GEO Publish Pack",
|
|
121
|
+
"",
|
|
122
|
+
`- 输入来源:\`${pack.source}\``,
|
|
123
|
+
`- 来源类型:\`${pack.sourceType}\``,
|
|
124
|
+
`- 生成时间:${pack.generatedAt}`,
|
|
125
|
+
"",
|
|
126
|
+
"## 这份包怎么用",
|
|
127
|
+
"",
|
|
128
|
+
"1. 人先打开 `site/index.html` 看总览。",
|
|
129
|
+
"2. PM 看 `documents/pm-brief.md` 或 `site/pm.html`。",
|
|
130
|
+
"3. 工程 / 执行团队看 `documents/owner-board.md` 或 `site/engineering.html`。",
|
|
131
|
+
"4. 管理层看 `documents/exec-summary.md` 或 `site/exec.html`。",
|
|
132
|
+
"5. 下一位 agent 从 `AGENT-START.md` 和 `data/agent-handoff-bundle.json` 开始。",
|
|
133
|
+
"",
|
|
134
|
+
"## 目录结构",
|
|
135
|
+
"",
|
|
136
|
+
"- `site/`: 可浏览的静态 HTML 页面。",
|
|
137
|
+
"- `documents/`: 可直接分享的 Markdown 文档。",
|
|
138
|
+
"- `data/`: 给 agent 或自动化流程使用的 JSON 工件。",
|
|
139
|
+
"- `START-HERE.md`: 给人看的起始说明。",
|
|
140
|
+
"- `AGENT-START.md`: 给 agent 的执行入口。",
|
|
141
|
+
"- `manifest.json`: 机器可读的总索引。",
|
|
142
|
+
"",
|
|
143
|
+
"## 快速入口",
|
|
144
|
+
"",
|
|
145
|
+
`- 总览页:\`${pack.quickLinks.indexHtml}\``,
|
|
146
|
+
`- PM:\`${pack.quickLinks.pmDocument}\``,
|
|
147
|
+
`- 工程:\`${pack.quickLinks.engineeringDocument}\``,
|
|
148
|
+
`- 管理层:\`${pack.quickLinks.execDocument}\``,
|
|
149
|
+
`- Agent:\`${pack.quickLinks.agentData}\``,
|
|
150
|
+
"",
|
|
151
|
+
"## 推荐分发顺序",
|
|
152
|
+
""
|
|
153
|
+
].concat(pack.sharePack.audienceOrder.map((item) => `- ${item}`)).join("\n") + "\n";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function buildAgentStartContent(pack) {
|
|
157
|
+
const firstPacket = pack.handoffBundle.applyPlan.packets[0];
|
|
158
|
+
const firstValidation = firstPacket?.validationCommands ?? [];
|
|
159
|
+
const nextRoundTasks = pack.handoffBundle.completionReport.nextRoundTasks.slice(0, 3);
|
|
160
|
+
|
|
161
|
+
const lines = [
|
|
162
|
+
"# AGENT START",
|
|
163
|
+
"",
|
|
164
|
+
"你现在接手这份 GEO 发布包。",
|
|
165
|
+
"",
|
|
166
|
+
`- 输入来源:\`${pack.source}\``,
|
|
167
|
+
`- 来源类型:\`${pack.sourceType}\``,
|
|
168
|
+
`- 执行模式:\`${pack.handoffBundle.summary.executionMode}\``,
|
|
169
|
+
`- 执行类型:\`${pack.handoffBundle.summary.executionType}\``,
|
|
170
|
+
"",
|
|
171
|
+
"## 先读什么",
|
|
172
|
+
"",
|
|
173
|
+
"1. `data/agent-handoff-bundle.json`",
|
|
174
|
+
"2. `documents/share-pack.md`",
|
|
175
|
+
"3. `documents/owner-board.md`",
|
|
176
|
+
"4. `documents/pm-brief.md`",
|
|
177
|
+
"",
|
|
178
|
+
"## 你现在该做什么",
|
|
179
|
+
""
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
if (firstPacket) {
|
|
183
|
+
lines.push(`- 先从任务包 \`${firstPacket.id}\` 开始:${firstPacket.title}`);
|
|
184
|
+
lines.push(`- 负责人建议:${firstPacket.owner}`);
|
|
185
|
+
} else {
|
|
186
|
+
lines.push("- 当前没有具体任务包,请先根据 share-pack 和 owner-board 重新确认优先级。");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (pack.handoffBundle.summary.executionMode === "implementation-ready") {
|
|
190
|
+
lines.push("- 当前已有本地项目上下文,可以直接检查模板、metadata、schema 或内容文件并实施修复。");
|
|
191
|
+
} else if (pack.handoffBundle.summary.executionMode === "advice-only") {
|
|
192
|
+
lines.push("- 当前更适合先给结构化建议,不要假设你已经拥有代码仓库写入权限。");
|
|
193
|
+
lines.push("- 如果用户能提供仓库或 CMS 上下文,请在拿到后重新生成 publish-pack,再进入直接执行。");
|
|
194
|
+
} else {
|
|
195
|
+
lines.push("- 当前输入主要来自已有工件,先根据工件整理修复顺序,再等待更多上下文。");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
lines.push("", "## 建议先跑的验证命令", "");
|
|
199
|
+
|
|
200
|
+
for (const command of firstValidation) {
|
|
201
|
+
lines.push(`- \`${command}\``);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (firstValidation.length === 0) {
|
|
205
|
+
lines.push("- 当前没有额外验证命令,先检查 handoff bundle 中的任务描述。");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
lines.push("", "## 下一轮任务", "");
|
|
209
|
+
|
|
210
|
+
for (const task of nextRoundTasks) {
|
|
211
|
+
lines.push(`- ${task.id}|${task.title}|${task.nextAction}`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (nextRoundTasks.length === 0) {
|
|
215
|
+
lines.push("- 暂无下一轮任务,先根据当前工件确认缺口。");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
lines.push(
|
|
219
|
+
"",
|
|
220
|
+
"## 完成后怎么回报",
|
|
221
|
+
"",
|
|
222
|
+
"- 完成后更新 completion-report 风格的总结。",
|
|
223
|
+
"- 说明你检查了哪些文件、修改了什么、如何验证、还剩什么风险。",
|
|
224
|
+
"- 如果无法直接修复,要明确说明缺少哪些上下文或权限。"
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
return `${lines.join("\n")}\n`;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function buildManifest(pack) {
|
|
231
|
+
return {
|
|
232
|
+
kind: "geo-publish-pack",
|
|
233
|
+
generatedAt: pack.generatedAt,
|
|
234
|
+
source: pack.source,
|
|
235
|
+
sourceType: pack.sourceType,
|
|
236
|
+
outputDir: pack.outputDir,
|
|
237
|
+
directories: {
|
|
238
|
+
site: pack.siteDir,
|
|
239
|
+
documents: pack.documentsDir,
|
|
240
|
+
data: pack.dataDir
|
|
241
|
+
},
|
|
242
|
+
quickLinks: pack.quickLinks,
|
|
243
|
+
shareAudienceOrder: pack.sharePack.audienceOrder,
|
|
244
|
+
executionMode: pack.handoffBundle.summary.executionMode,
|
|
245
|
+
executionType: pack.handoffBundle.summary.executionType
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export async function writePublishPack(input, options = {}) {
|
|
250
|
+
const [sharePack, pmBrief, ownerBoard, execSummary, handoffBundle] = await Promise.all([
|
|
251
|
+
createSharePack(input, { format: "json", taskId: options.taskId }),
|
|
252
|
+
createPmBrief(input, { format: "json" }),
|
|
253
|
+
createOwnerBoard(input, { format: "json" }),
|
|
254
|
+
createExecSummary(input, { format: "json" }),
|
|
255
|
+
createHandoffBundle(input, { format: "json", taskId: options.taskId })
|
|
256
|
+
]);
|
|
257
|
+
|
|
258
|
+
const baseName = buildBaseName(sharePack.sourceType, sharePack.source);
|
|
259
|
+
const outputDir = path.resolve(options.outputDir || `./exports/${baseName}-geo-publish-pack`);
|
|
260
|
+
const documentsDir = path.join(outputDir, "documents");
|
|
261
|
+
const dataDir = path.join(outputDir, "data");
|
|
262
|
+
const siteDir = path.join(outputDir, "site");
|
|
263
|
+
|
|
264
|
+
await fs.mkdir(documentsDir, { recursive: true });
|
|
265
|
+
await fs.mkdir(dataDir, { recursive: true });
|
|
266
|
+
await fs.mkdir(siteDir, { recursive: true });
|
|
267
|
+
|
|
268
|
+
const documentFiles = [
|
|
269
|
+
{ key: "share_pack", filename: "share-pack.md", content: renderSharePackMarkdown(sharePack) },
|
|
270
|
+
{ key: "pm", filename: "pm-brief.md", content: renderPmBriefMarkdown(pmBrief) },
|
|
271
|
+
{ key: "engineering", filename: "owner-board.md", content: renderOwnerBoardMarkdown(ownerBoard) },
|
|
272
|
+
{ key: "exec", filename: "exec-summary.md", content: renderExecSummaryMarkdown(execSummary) },
|
|
273
|
+
{ key: "agent", filename: "agent-handoff-bundle.md", content: renderHandoffBundleMarkdown(handoffBundle) }
|
|
274
|
+
];
|
|
275
|
+
|
|
276
|
+
const dataFiles = [
|
|
277
|
+
{ key: "share_pack", filename: "share-pack.json", content: `${JSON.stringify(sharePack, null, 2)}\n` },
|
|
278
|
+
{ key: "pm", filename: "pm-brief.json", content: `${JSON.stringify(pmBrief, null, 2)}\n` },
|
|
279
|
+
{ key: "engineering", filename: "owner-board.json", content: `${JSON.stringify(ownerBoard, null, 2)}\n` },
|
|
280
|
+
{ key: "exec", filename: "exec-summary.json", content: `${JSON.stringify(execSummary, null, 2)}\n` },
|
|
281
|
+
{ key: "agent", filename: "agent-handoff-bundle.json", content: `${JSON.stringify(handoffBundle, null, 2)}\n` }
|
|
282
|
+
];
|
|
283
|
+
|
|
284
|
+
const htmlFiles = [
|
|
285
|
+
{
|
|
286
|
+
key: "index",
|
|
287
|
+
label: "总览页",
|
|
288
|
+
description: "适合直接打开给团队看的入口。",
|
|
289
|
+
filename: "index.html",
|
|
290
|
+
content: ""
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
key: "pm",
|
|
294
|
+
label: "PM Brief",
|
|
295
|
+
description: "给 PM 的优先级和推进摘要。",
|
|
296
|
+
filename: "pm.html",
|
|
297
|
+
content: documentFiles.find((file) => file.key === "pm")?.content || ""
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
key: "engineering",
|
|
301
|
+
label: "Owner Board",
|
|
302
|
+
description: "给工程与执行团队的任务视图。",
|
|
303
|
+
filename: "engineering.html",
|
|
304
|
+
content: documentFiles.find((file) => file.key === "engineering")?.content || ""
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
key: "exec",
|
|
308
|
+
label: "Exec Summary",
|
|
309
|
+
description: "给管理层的高层摘要。",
|
|
310
|
+
filename: "exec.html",
|
|
311
|
+
content: documentFiles.find((file) => file.key === "exec")?.content || ""
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
key: "agent",
|
|
315
|
+
label: "Agent Bundle",
|
|
316
|
+
description: "给下一位 agent 的交接入口。",
|
|
317
|
+
filename: "agent.html",
|
|
318
|
+
content: documentFiles.find((file) => file.key === "agent")?.content || ""
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
key: "share",
|
|
322
|
+
label: "Share Pack",
|
|
323
|
+
description: "给协调者的总览文档。",
|
|
324
|
+
filename: "share.html",
|
|
325
|
+
content: documentFiles.find((file) => file.key === "share_pack")?.content || ""
|
|
326
|
+
}
|
|
327
|
+
];
|
|
328
|
+
|
|
329
|
+
const generatedAt = new Date().toISOString();
|
|
330
|
+
const quickLinks = {
|
|
331
|
+
startHere: "START-HERE.md",
|
|
332
|
+
agentStart: "AGENT-START.md",
|
|
333
|
+
manifest: "manifest.json",
|
|
334
|
+
indexHtml: "site/index.html",
|
|
335
|
+
pmDocument: "documents/pm-brief.md",
|
|
336
|
+
engineeringDocument: "documents/owner-board.md",
|
|
337
|
+
execDocument: "documents/exec-summary.md",
|
|
338
|
+
agentData: "data/agent-handoff-bundle.json"
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const pack = {
|
|
342
|
+
kind: "geo-publish-pack",
|
|
343
|
+
generatedAt,
|
|
344
|
+
source: sharePack.source,
|
|
345
|
+
sourceType: sharePack.sourceType,
|
|
346
|
+
outputDir,
|
|
347
|
+
documentsDir,
|
|
348
|
+
dataDir,
|
|
349
|
+
siteDir,
|
|
350
|
+
quickLinks,
|
|
351
|
+
sharePack,
|
|
352
|
+
handoffBundle,
|
|
353
|
+
htmlFiles
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
await Promise.all(
|
|
357
|
+
documentFiles.map((file) => fs.writeFile(path.join(documentsDir, file.filename), file.content, "utf8"))
|
|
358
|
+
);
|
|
359
|
+
await Promise.all(dataFiles.map((file) => fs.writeFile(path.join(dataDir, file.filename), file.content, "utf8")));
|
|
360
|
+
|
|
361
|
+
const indexHtml = buildIndexHtml(pack);
|
|
362
|
+
await fs.writeFile(path.join(siteDir, "index.html"), indexHtml, "utf8");
|
|
363
|
+
|
|
364
|
+
for (const file of htmlFiles.filter((file) => file.key !== "index")) {
|
|
365
|
+
await fs.writeFile(path.join(siteDir, file.filename), buildDocumentHtml(file.label, file.content), "utf8");
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
await fs.writeFile(path.join(outputDir, "START-HERE.md"), buildStartHereContent(pack), "utf8");
|
|
369
|
+
await fs.writeFile(path.join(outputDir, "AGENT-START.md"), buildAgentStartContent(pack), "utf8");
|
|
370
|
+
|
|
371
|
+
const manifest = buildManifest(pack);
|
|
372
|
+
await fs.writeFile(path.join(outputDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
373
|
+
|
|
374
|
+
return {
|
|
375
|
+
...manifest,
|
|
376
|
+
files: {
|
|
377
|
+
root: [
|
|
378
|
+
path.join(outputDir, "START-HERE.md"),
|
|
379
|
+
path.join(outputDir, "AGENT-START.md"),
|
|
380
|
+
path.join(outputDir, "manifest.json")
|
|
381
|
+
],
|
|
382
|
+
documents: documentFiles.map((file) => path.join(documentsDir, file.filename)),
|
|
383
|
+
data: dataFiles.map((file) => path.join(dataDir, file.filename)),
|
|
384
|
+
site: htmlFiles.map((file) => path.join(siteDir, file.filename))
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export function renderPublishPackMarkdown(pack) {
|
|
390
|
+
const lines = [
|
|
391
|
+
"# GEO Publish Pack",
|
|
392
|
+
"",
|
|
393
|
+
`- 输入来源:\`${pack.source}\``,
|
|
394
|
+
`- 来源类型:\`${pack.sourceType}\``,
|
|
395
|
+
`- 输出目录:\`${pack.outputDir}\``,
|
|
396
|
+
`- 生成时间:${pack.generatedAt}`,
|
|
397
|
+
"",
|
|
398
|
+
"## 快速入口",
|
|
399
|
+
"",
|
|
400
|
+
`- 人类入口:\`${path.join(pack.outputDir, pack.quickLinks.startHere)}\``,
|
|
401
|
+
`- Agent 入口:\`${path.join(pack.outputDir, pack.quickLinks.agentStart)}\``,
|
|
402
|
+
`- 静态页面:\`${path.join(pack.outputDir, pack.quickLinks.indexHtml)}\``,
|
|
403
|
+
`- 机器索引:\`${path.join(pack.outputDir, pack.quickLinks.manifest)}\``,
|
|
404
|
+
"",
|
|
405
|
+
"## 目录",
|
|
406
|
+
"",
|
|
407
|
+
`- 文档:\`${pack.directories.documents}\``,
|
|
408
|
+
`- 数据:\`${pack.directories.data}\``,
|
|
409
|
+
`- 页面:\`${pack.directories.site}\``,
|
|
410
|
+
"",
|
|
411
|
+
"## 适合怎么用",
|
|
412
|
+
""
|
|
413
|
+
];
|
|
414
|
+
|
|
415
|
+
lines.push("- 先把 `site/index.html` 发给需要快速了解现状的人。");
|
|
416
|
+
lines.push("- 把 `documents/pm-brief.md`、`documents/owner-board.md`、`documents/exec-summary.md` 分别发给不同角色。");
|
|
417
|
+
lines.push("- 让下一位 agent 从 `AGENT-START.md` 和 `data/agent-handoff-bundle.json` 继续接手。");
|
|
418
|
+
|
|
419
|
+
return `${lines.join("\n")}\n`;
|
|
420
|
+
}
|
package/src/quick-start.js
CHANGED
|
@@ -63,7 +63,8 @@ function buildSteps() {
|
|
|
63
63
|
"geo-ai-search-optimization completion-report ./your-site --out ./reports/completion-report.md",
|
|
64
64
|
"geo-ai-search-optimization handoff-bundle ./your-site --out ./reports/handoff-bundle.md",
|
|
65
65
|
"geo-ai-search-optimization share-pack ./your-site --out ./reports/share-pack.md",
|
|
66
|
-
"geo-ai-search-optimization export-pack ./your-site --out-dir ./exports/your-site-pack"
|
|
66
|
+
"geo-ai-search-optimization export-pack ./your-site --out-dir ./exports/your-site-pack",
|
|
67
|
+
"geo-ai-search-optimization html-pack ./your-site --out-dir ./exports/your-site-html"
|
|
67
68
|
]
|
|
68
69
|
},
|
|
69
70
|
{
|