geo-ai-search-optimization 1.3.4 → 1.3.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 CHANGED
@@ -865,6 +865,13 @@ geo-ai-search-optimization help
865
865
  - 主 `cli.js` 现在更接近纯路由层
866
866
  - CLI 已经形成 `flow / execution / planning-delivery / shared` 四层 command adapter 结构
867
867
 
868
+ ## New in 1.3.5
869
+
870
+ - 继续做 CLI 架构迭代,把 onboarding / audit / scan / doctor / init family 也从主 `cli.js` 拆出
871
+ - 新增 `src/cli-site-ops-commands.js`,接管 `doctor / quick-start / onboard / onboard-url / init-llms / init-schema / audit / scan`
872
+ - 主 `cli.js` 现在只保留 install / skills / where / version / help 与 command routing
873
+ - CLI 已经形成 `flow / execution / planning-delivery / site-ops / shared` 五层 command adapter 结构
874
+
868
875
  ## New in 1.2.20
869
876
 
870
877
  - 新增 `agent-continue`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geo-ai-search-optimization",
3
- "version": "1.3.4",
3
+ "version": "1.3.5",
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": {
@@ -0,0 +1,201 @@
1
+ import { auditProject, renderAuditMarkdown, writeAuditOutput } from "./audit.js";
2
+ import { getFlagValue, hasFlag, parsePositiveInteger } from "./cli-shared.js";
3
+ import { renderDoctorMarkdown, runDoctor } from "./doctor.js";
4
+ import {
5
+ renderInteractiveOnboardingMarkdown,
6
+ runInteractiveOnboarding,
7
+ writeInteractiveOnboardingOutput
8
+ } from "./interactive-onboarding.js";
9
+ import { createLlmsTxt } from "./llms-txt.js";
10
+ import { createQuickStartPlan, renderQuickStartMarkdown, writeQuickStartOutput } from "./quick-start.js";
11
+ import { renderScanMarkdown, scanProject, writeScanOutput } from "./scan.js";
12
+ import { createSchemaTemplate } from "./schema.js";
13
+ import { analyzeWebsiteUrl, renderWebsiteOnboardingMarkdown, writeWebsiteOnboardingOutput } from "./url-onboarding.js";
14
+
15
+ export const SITE_OPS_HELP_LINES = [
16
+ " geo-ai-search-optimization doctor [--json]",
17
+ " geo-ai-search-optimization quick-start [--json] [--out <file>]",
18
+ " geo-ai-search-optimization onboard [--url <website-url>] [--goal <goal>] [--existing-assets <list>] [--json] [--out <file>]",
19
+ " geo-ai-search-optimization onboard-url <website-url> [--json] [--out <file>]",
20
+ " geo-ai-search-optimization init-llms [target-dir] [--site-name <name>] [--site-url <url>] [--overwrite] [--json]",
21
+ " geo-ai-search-optimization init-schema <type> [target-dir] [--site-url <url>] [--overwrite] [--json]",
22
+ " geo-ai-search-optimization audit <project-path> [--json] [--out <file>] [--max-file-size <bytes>] [--max-examples <count>]",
23
+ " geo-ai-search-optimization scan <project-path> [--json] [--out <file>] [--max-file-size <bytes>] [--max-examples <count>]"
24
+ ];
25
+
26
+ async function handleDoctor(args) {
27
+ const report = await runDoctor();
28
+ if (hasFlag(args, "--json")) {
29
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
30
+ return;
31
+ }
32
+
33
+ process.stdout.write(renderDoctorMarkdown(report));
34
+ }
35
+
36
+ async function handleQuickStart(args) {
37
+ const outputJson = hasFlag(args, "--json");
38
+ const plan = createQuickStartPlan({});
39
+ const renderedOutput = outputJson ? `${JSON.stringify(plan, null, 2)}\n` : renderQuickStartMarkdown(plan);
40
+ const outputPath = getFlagValue(args, "--out");
41
+
42
+ if (outputPath) {
43
+ const resolvedOutputPath = await writeQuickStartOutput(outputPath, renderedOutput);
44
+ process.stdout.write(`已保存 quick start 输出:${resolvedOutputPath}\n`);
45
+ return;
46
+ }
47
+
48
+ process.stdout.write(renderedOutput);
49
+ }
50
+
51
+ async function handleInteractiveOnboard(args) {
52
+ const report = await runInteractiveOnboarding({
53
+ url: getFlagValue(args, "--url"),
54
+ goal: getFlagValue(args, "--goal"),
55
+ existingAssets: getFlagValue(args, "--existing-assets")
56
+ });
57
+
58
+ const outputJson = hasFlag(args, "--json");
59
+ const renderedOutput = outputJson
60
+ ? `${JSON.stringify(report, null, 2)}\n`
61
+ : renderInteractiveOnboardingMarkdown(report);
62
+ const outputPath = getFlagValue(args, "--out");
63
+
64
+ if (outputPath) {
65
+ const resolvedOutputPath = await writeInteractiveOnboardingOutput(outputPath, renderedOutput);
66
+ process.stdout.write(`已保存交互式 onboarding 结果:${resolvedOutputPath}\n`);
67
+ return;
68
+ }
69
+
70
+ process.stdout.write(renderedOutput);
71
+ }
72
+
73
+ async function handleOnboardUrl(args) {
74
+ const inputUrl = args.find((value) => !value.startsWith("-"));
75
+ if (!inputUrl) {
76
+ throw new Error("onboard-url requires a website URL");
77
+ }
78
+
79
+ const report = await analyzeWebsiteUrl(inputUrl, {});
80
+ const outputJson = hasFlag(args, "--json");
81
+ const renderedOutput = outputJson
82
+ ? `${JSON.stringify(report, null, 2)}\n`
83
+ : `${renderWebsiteOnboardingMarkdown(report)}\n`;
84
+ const outputPath = getFlagValue(args, "--out");
85
+
86
+ if (outputPath) {
87
+ const resolvedOutputPath = await writeWebsiteOnboardingOutput(outputPath, renderedOutput);
88
+ process.stdout.write(`已保存 onboarding 结果:${resolvedOutputPath}\n`);
89
+ return;
90
+ }
91
+
92
+ process.stdout.write(renderedOutput);
93
+ }
94
+
95
+ async function handleInitLlms(args) {
96
+ const targetDir = args.find((value) => !value.startsWith("-")) || ".";
97
+ const outputJson = hasFlag(args, "--json");
98
+ const result = await createLlmsTxt({
99
+ targetDir,
100
+ siteName: getFlagValue(args, "--site-name"),
101
+ siteUrl: getFlagValue(args, "--site-url"),
102
+ overwrite: hasFlag(args, "--overwrite")
103
+ });
104
+
105
+ if (outputJson) {
106
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
107
+ return;
108
+ }
109
+
110
+ process.stdout.write(`Created llms.txt at ${result.outputPath}\n`);
111
+ }
112
+
113
+ async function handleInitSchema(args) {
114
+ const [schemaType, ...rest] = args;
115
+ if (!schemaType || schemaType.startsWith("-")) {
116
+ throw new Error("init-schema requires a schema type");
117
+ }
118
+
119
+ const targetDir = rest.find((value) => !value.startsWith("-")) || ".";
120
+ const outputJson = hasFlag(rest, "--json");
121
+ const result = await createSchemaTemplate({
122
+ schemaType,
123
+ targetDir,
124
+ siteUrl: getFlagValue(rest, "--site-url"),
125
+ overwrite: hasFlag(rest, "--overwrite")
126
+ });
127
+
128
+ if (outputJson) {
129
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
130
+ return;
131
+ }
132
+
133
+ process.stdout.write(`Created ${result.schemaType} schema template at ${result.outputPath}\n`);
134
+ }
135
+
136
+ async function handleAudit(args) {
137
+ const projectPath = args.find((value) => !value.startsWith("-"));
138
+ if (!projectPath) {
139
+ throw new Error("audit requires a project path");
140
+ }
141
+
142
+ const report = await auditProject(projectPath, {
143
+ maxFileSize: getFlagValue(args, "--max-file-size")
144
+ ? parsePositiveInteger(getFlagValue(args, "--max-file-size"), "--max-file-size")
145
+ : undefined,
146
+ maxExamples: getFlagValue(args, "--max-examples")
147
+ ? parsePositiveInteger(getFlagValue(args, "--max-examples"), "--max-examples")
148
+ : undefined
149
+ });
150
+
151
+ const outputJson = hasFlag(args, "--json");
152
+ const renderedOutput = outputJson
153
+ ? `${JSON.stringify(report, null, 2)}\n`
154
+ : `${renderAuditMarkdown(report)}\n`;
155
+ const outputPath = getFlagValue(args, "--out");
156
+
157
+ if (outputPath) {
158
+ const resolvedOutputPath = await writeAuditOutput(outputPath, renderedOutput);
159
+ process.stdout.write(`已保存审计结果:${resolvedOutputPath}\n`);
160
+ return;
161
+ }
162
+
163
+ process.stdout.write(renderedOutput);
164
+ }
165
+
166
+ async function handleScan(args) {
167
+ const projectPath = args.find((value) => !value.startsWith("-"));
168
+ if (!projectPath) {
169
+ throw new Error("scan requires a project path");
170
+ }
171
+
172
+ const maxFileSizeValue = getFlagValue(args, "--max-file-size");
173
+ const maxExamplesValue = getFlagValue(args, "--max-examples");
174
+ const summary = await scanProject(projectPath, {
175
+ maxFileSize: maxFileSizeValue ? parsePositiveInteger(maxFileSizeValue, "--max-file-size") : undefined,
176
+ maxExamples: maxExamplesValue ? parsePositiveInteger(maxExamplesValue, "--max-examples") : undefined
177
+ });
178
+
179
+ const outputJson = hasFlag(args, "--json");
180
+ const renderedOutput = outputJson ? `${JSON.stringify(summary, null, 2)}\n` : renderScanMarkdown(summary);
181
+ const outputPath = getFlagValue(args, "--out");
182
+
183
+ if (outputPath) {
184
+ const resolvedOutputPath = await writeScanOutput(outputPath, renderedOutput);
185
+ process.stdout.write(`已保存扫描结果:${resolvedOutputPath}\n`);
186
+ return;
187
+ }
188
+
189
+ process.stdout.write(renderedOutput);
190
+ }
191
+
192
+ export const SITE_OPS_COMMAND_HANDLERS = {
193
+ doctor: handleDoctor,
194
+ "quick-start": handleQuickStart,
195
+ onboard: handleInteractiveOnboard,
196
+ "onboard-url": handleOnboardUrl,
197
+ "init-llms": handleInitLlms,
198
+ "init-schema": handleInitSchema,
199
+ audit: handleAudit,
200
+ scan: handleScan
201
+ };
package/src/cli.js CHANGED
@@ -1,6 +1,6 @@
1
- import { fileURLToPath } from "node:url";
2
1
  import { readFile } from "node:fs/promises";
3
2
  import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
4
  import {
5
5
  AGENT_EXECUTION_COMMAND_HANDLERS,
6
6
  AGENT_EXECUTION_HELP_LINES
@@ -10,22 +10,11 @@ import {
10
10
  PLANNING_DELIVERY_COMMAND_HANDLERS,
11
11
  PLANNING_DELIVERY_HELP_LINES
12
12
  } from "./cli-planning-delivery-commands.js";
13
- import { getFlagValue, hasFlag, parsePositiveInteger } from "./cli-shared.js";
13
+ import { SITE_OPS_COMMAND_HANDLERS, SITE_OPS_HELP_LINES } from "./cli-site-ops-commands.js";
14
+ import { getFlagValue, hasFlag } from "./cli-shared.js";
14
15
  import { installSkill } from "./install-skill.js";
15
16
  import { getBundledSkillPath, getInstalledSkillPath, getSkillName, getSkillsDir } from "./paths.js";
16
- import { renderScanMarkdown, scanProject, writeScanOutput } from "./scan.js";
17
- import { renderDoctorMarkdown, runDoctor } from "./doctor.js";
18
- import { createLlmsTxt } from "./llms-txt.js";
19
- import { auditProject, renderAuditMarkdown, writeAuditOutput } from "./audit.js";
20
- import {
21
- renderInteractiveOnboardingMarkdown,
22
- runInteractiveOnboarding,
23
- writeInteractiveOnboardingOutput
24
- } from "./interactive-onboarding.js";
25
- import { createQuickStartPlan, renderQuickStartMarkdown, writeQuickStartOutput } from "./quick-start.js";
26
- import { createSchemaTemplate } from "./schema.js";
27
17
  import { listBundledSkills, renderBundledSkillsMarkdown } from "./skills.js";
28
- import { analyzeWebsiteUrl, renderWebsiteOnboardingMarkdown, writeWebsiteOnboardingOutput } from "./url-onboarding.js";
29
18
 
30
19
  let cachedVersion;
31
20
 
@@ -51,16 +40,9 @@ function printHelp() {
51
40
  ...FLOW_HELP_LINES,
52
41
  ...AGENT_EXECUTION_HELP_LINES,
53
42
  ...PLANNING_DELIVERY_HELP_LINES,
43
+ ...SITE_OPS_HELP_LINES,
54
44
  " geo-ai-search-optimization skills [--json]",
55
45
  " geo-ai-search-optimization where",
56
- " geo-ai-search-optimization doctor [--json]",
57
- " geo-ai-search-optimization quick-start [--json] [--out <file>]",
58
- " geo-ai-search-optimization onboard [--url <website-url>] [--goal <goal>] [--existing-assets <list>] [--json] [--out <file>]",
59
- " geo-ai-search-optimization onboard-url <website-url> [--json] [--out <file>]",
60
- " geo-ai-search-optimization init-llms [target-dir] [--site-name <name>] [--site-url <url>] [--overwrite] [--json]",
61
- " geo-ai-search-optimization init-schema <type> [target-dir] [--site-url <url>] [--overwrite] [--json]",
62
- " geo-ai-search-optimization audit <project-path> [--json] [--out <file>] [--max-file-size <bytes>] [--max-examples <count>]",
63
- " geo-ai-search-optimization scan <project-path> [--json] [--out <file>] [--max-file-size <bytes>] [--max-examples <count>]",
64
46
  " geo-ai-search-optimization version",
65
47
  " geo-ai-search-optimization help",
66
48
  "",
@@ -104,182 +86,12 @@ async function handleSkills(args) {
104
86
  process.stdout.write(renderBundledSkillsMarkdown(bundle));
105
87
  }
106
88
 
107
- async function handleDoctor(args) {
108
- const report = await runDoctor();
109
- if (hasFlag(args, "--json")) {
110
- process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
111
- return;
112
- }
113
- process.stdout.write(renderDoctorMarkdown(report));
114
- }
115
-
116
- async function handleScan(args) {
117
- const projectPath = args.find((value) => !value.startsWith("-"));
118
- if (!projectPath) {
119
- throw new Error("scan requires a project path");
120
- }
121
-
122
- const maxFileSizeValue = getFlagValue(args, "--max-file-size");
123
- const maxExamplesValue = getFlagValue(args, "--max-examples");
124
- const summary = await scanProject(projectPath, {
125
- maxFileSize: maxFileSizeValue ? parsePositiveInteger(maxFileSizeValue, "--max-file-size") : undefined,
126
- maxExamples: maxExamplesValue ? parsePositiveInteger(maxExamplesValue, "--max-examples") : undefined
127
- });
128
-
129
- const outputJson = hasFlag(args, "--json");
130
- const renderedOutput = outputJson
131
- ? `${JSON.stringify(summary, null, 2)}\n`
132
- : renderScanMarkdown(summary);
133
-
134
- const outputPath = getFlagValue(args, "--out");
135
- if (outputPath) {
136
- const resolvedOutputPath = await writeScanOutput(outputPath, renderedOutput);
137
- process.stdout.write(`已保存扫描结果:${resolvedOutputPath}\n`);
138
- return;
139
- }
140
-
141
- process.stdout.write(renderedOutput);
142
- }
143
-
144
- async function handleInitLlms(args) {
145
- const targetDir = args.find((value) => !value.startsWith("-")) || ".";
146
- const outputJson = hasFlag(args, "--json");
147
- const result = await createLlmsTxt({
148
- targetDir,
149
- siteName: getFlagValue(args, "--site-name"),
150
- siteUrl: getFlagValue(args, "--site-url"),
151
- overwrite: hasFlag(args, "--overwrite")
152
- });
153
-
154
- if (outputJson) {
155
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
156
- return;
157
- }
158
-
159
- process.stdout.write(`Created llms.txt at ${result.outputPath}\n`);
160
- }
161
-
162
- async function handleQuickStart(args) {
163
- const outputJson = hasFlag(args, "--json");
164
- const plan = createQuickStartPlan({});
165
- const renderedOutput = outputJson
166
- ? `${JSON.stringify(plan, null, 2)}\n`
167
- : renderQuickStartMarkdown(plan);
168
-
169
- const outputPath = getFlagValue(args, "--out");
170
- if (outputPath) {
171
- const resolvedOutputPath = await writeQuickStartOutput(outputPath, renderedOutput);
172
- process.stdout.write(`已保存 quick start 输出:${resolvedOutputPath}\n`);
173
- return;
174
- }
175
-
176
- process.stdout.write(renderedOutput);
177
- }
178
-
179
- async function handleInitSchema(args) {
180
- const [schemaType, ...rest] = args;
181
- if (!schemaType || schemaType.startsWith("-")) {
182
- throw new Error("init-schema requires a schema type");
183
- }
184
-
185
- const targetDir = rest.find((value) => !value.startsWith("-")) || ".";
186
- const outputJson = hasFlag(rest, "--json");
187
- const result = await createSchemaTemplate({
188
- schemaType,
189
- targetDir,
190
- siteUrl: getFlagValue(rest, "--site-url"),
191
- overwrite: hasFlag(rest, "--overwrite")
192
- });
193
-
194
- if (outputJson) {
195
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
196
- return;
197
- }
198
-
199
- process.stdout.write(`Created ${result.schemaType} schema template at ${result.outputPath}\n`);
200
- }
201
-
202
- async function handleOnboardUrl(args) {
203
- const inputUrl = args.find((value) => !value.startsWith("-"));
204
- if (!inputUrl) {
205
- throw new Error("onboard-url requires a website URL");
206
- }
207
-
208
- const report = await analyzeWebsiteUrl(inputUrl, {
209
- });
210
-
211
- const outputJson = hasFlag(args, "--json");
212
- const renderedOutput = outputJson
213
- ? `${JSON.stringify(report, null, 2)}\n`
214
- : `${renderWebsiteOnboardingMarkdown(report)}\n`;
215
-
216
- const outputPath = getFlagValue(args, "--out");
217
- if (outputPath) {
218
- const resolvedOutputPath = await writeWebsiteOnboardingOutput(outputPath, renderedOutput);
219
- process.stdout.write(`已保存 onboarding 结果:${resolvedOutputPath}\n`);
220
- return;
221
- }
222
-
223
- process.stdout.write(renderedOutput);
224
- }
225
-
226
- async function handleInteractiveOnboard(args) {
227
- const report = await runInteractiveOnboarding({
228
- url: getFlagValue(args, "--url"),
229
- goal: getFlagValue(args, "--goal"),
230
- existingAssets: getFlagValue(args, "--existing-assets")
231
- });
232
-
233
- const outputJson = hasFlag(args, "--json");
234
- const renderedOutput = outputJson
235
- ? `${JSON.stringify(report, null, 2)}\n`
236
- : renderInteractiveOnboardingMarkdown(report);
237
-
238
- const outputPath = getFlagValue(args, "--out");
239
- if (outputPath) {
240
- const resolvedOutputPath = await writeInteractiveOnboardingOutput(outputPath, renderedOutput);
241
- process.stdout.write(`已保存交互式 onboarding 结果:${resolvedOutputPath}\n`);
242
- return;
243
- }
244
-
245
- process.stdout.write(renderedOutput);
246
- }
247
-
248
- async function handleAudit(args) {
249
- const projectPath = args.find((value) => !value.startsWith("-"));
250
- if (!projectPath) {
251
- throw new Error("audit requires a project path");
252
- }
253
-
254
- const report = await auditProject(projectPath, {
255
- maxFileSize: getFlagValue(args, "--max-file-size")
256
- ? parsePositiveInteger(getFlagValue(args, "--max-file-size"), "--max-file-size")
257
- : undefined,
258
- maxExamples: getFlagValue(args, "--max-examples")
259
- ? parsePositiveInteger(getFlagValue(args, "--max-examples"), "--max-examples")
260
- : undefined
261
- });
262
-
263
- const outputJson = hasFlag(args, "--json");
264
- const renderedOutput = outputJson
265
- ? `${JSON.stringify(report, null, 2)}\n`
266
- : `${renderAuditMarkdown(report)}\n`;
267
-
268
- const outputPath = getFlagValue(args, "--out");
269
- if (outputPath) {
270
- const resolvedOutputPath = await writeAuditOutput(outputPath, renderedOutput);
271
- process.stdout.write(`已保存审计结果:${resolvedOutputPath}\n`);
272
- return;
273
- }
274
-
275
- process.stdout.write(renderedOutput);
276
- }
277
-
278
89
  export async function runCli(args = []) {
279
90
  const [command = "install", ...rest] = args;
280
91
  const flowHandler = FLOW_COMMAND_HANDLERS[command];
281
92
  const agentExecutionHandler = AGENT_EXECUTION_COMMAND_HANDLERS[command];
282
93
  const planningDeliveryHandler = PLANNING_DELIVERY_COMMAND_HANDLERS[command];
94
+ const siteOpsHandler = SITE_OPS_COMMAND_HANDLERS[command];
283
95
 
284
96
  if (command === "help" || command === "--help" || command === "-h") {
285
97
  printHelp();
@@ -311,6 +123,11 @@ export async function runCli(args = []) {
311
123
  return;
312
124
  }
313
125
 
126
+ if (siteOpsHandler) {
127
+ await siteOpsHandler(rest);
128
+ return;
129
+ }
130
+
314
131
  if (command === "skills") {
315
132
  await handleSkills(rest);
316
133
  return;
@@ -321,46 +138,6 @@ export async function runCli(args = []) {
321
138
  return;
322
139
  }
323
140
 
324
- if (command === "doctor") {
325
- await handleDoctor(rest);
326
- return;
327
- }
328
-
329
- if (command === "quick-start") {
330
- await handleQuickStart(rest);
331
- return;
332
- }
333
-
334
- if (command === "onboard") {
335
- await handleInteractiveOnboard(rest);
336
- return;
337
- }
338
-
339
- if (command === "onboard-url") {
340
- await handleOnboardUrl(rest);
341
- return;
342
- }
343
-
344
- if (command === "init-llms") {
345
- await handleInitLlms(rest);
346
- return;
347
- }
348
-
349
- if (command === "init-schema") {
350
- await handleInitSchema(rest);
351
- return;
352
- }
353
-
354
- if (command === "audit") {
355
- await handleAudit(rest);
356
- return;
357
- }
358
-
359
- if (command === "scan") {
360
- await handleScan(rest);
361
- return;
362
- }
363
-
364
141
  throw new Error(`Unknown command: ${command}`);
365
142
  }
366
143