geo-ai-search-optimization 1.3.7 → 1.3.9

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
@@ -886,6 +886,22 @@ geo-ai-search-optimization help
886
886
  - `src/cli-agent-execution-commands.js` 与 `src/cli-planning-delivery-commands.js` 现在改用声明式组合,减少重复的 `create / render / write` handler 模板代码
887
887
  - CLI 架构从“按命令族拆文件”进一步推进到“adapter + shared composition”模式
888
888
 
889
+ ## New in 1.3.8
890
+
891
+ - 继续把共享组合器推广到 `flow` 与 `site-ops` 两层
892
+ - `src/cli-shared.js` 新增 `createStructuredOutputCommandHandler`
893
+ - `src/cli-flow-commands.js` 现在统一通过组合器编排 `auto-flow / agent-orchestrator / agent-resume / agent-continue / agent-state-pack / agent-session`
894
+ - `src/cli-site-ops-commands.js` 现在统一通过组合器编排 `doctor / quick-start / onboard / onboard-url / audit / scan`
895
+ - CLI 架构进一步收敛到“命令族 adapter + shared composition primitives”的模式
896
+
897
+ ## New in 1.3.9
898
+
899
+ - 继续把“直接执行型命令”也纳入共享组合模式
900
+ - `src/cli-shared.js` 新增 `createActionCommandHandler`
901
+ - `src/cli-shell-commands.js` 里的 `install` 已改成声明式 action 组合
902
+ - `src/cli-site-ops-commands.js` 里的 `init-llms / init-schema` 已改成声明式 action 组合
903
+ - CLI 现在同时覆盖 artifact、structured-output、action 三类共享 composition primitives
904
+
889
905
  ## New in 1.2.20
890
906
 
891
907
  - 新增 `agent-continue`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geo-ai-search-optimization",
3
- "version": "1.3.7",
3
+ "version": "1.3.9",
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": {
@@ -17,11 +17,12 @@ import {
17
17
  } from "./agent-state-pack.js";
18
18
  import { createAgentSession, renderAgentSessionMarkdown, writeAgentSessionOutput } from "./agent-session.js";
19
19
  import {
20
+ createArtifactCommandHandler,
21
+ createStructuredOutputCommandHandler,
20
22
  getFlagValue,
21
23
  getJsonCapableFormat,
22
24
  getRequiredInput,
23
- hasFlag,
24
- writeOrPrintArtifact
25
+ hasFlag
25
26
  } from "./cli-shared.js";
26
27
 
27
28
  export const FLOW_HELP_LINES = [
@@ -33,105 +34,80 @@ export const FLOW_HELP_LINES = [
33
34
  " geo-ai-search-optimization agent-session <input> [--intent <auto|diagnose|guide|execute|share|closeout>] [--json] [--out <file>]"
34
35
  ];
35
36
 
36
- async function handleAutoFlow(args) {
37
- const input = getRequiredInput(args, "auto-flow");
38
- const flow = await createAutoFlow(input, {
39
- intent: getFlagValue(args, "--intent")
40
- });
41
- const outputJson = hasFlag(args, "--json");
42
- const renderedOutput = outputJson ? `${JSON.stringify(flow, null, 2)}\n` : renderAutoFlowMarkdown(flow);
43
- const outputPath = getFlagValue(args, "--out");
44
-
45
- if (outputPath) {
46
- const resolvedOutputPath = await writeAutoFlowOutput(outputPath, renderedOutput);
47
- process.stdout.write(`已保存 auto-flow 结果:${resolvedOutputPath}\n`);
48
- return;
49
- }
50
-
51
- process.stdout.write(renderedOutput);
52
- }
37
+ const handleAutoFlow = createStructuredOutputCommandHandler({
38
+ commandLabel: "auto-flow",
39
+ execute: async (args) => {
40
+ const input = getRequiredInput(args, "auto-flow");
41
+ return createAutoFlow(input, {
42
+ intent: getFlagValue(args, "--intent")
43
+ });
44
+ },
45
+ renderMarkdown: renderAutoFlowMarkdown,
46
+ writeOutput: writeAutoFlowOutput,
47
+ getOutputJson: (args) => hasFlag(args, "--json")
48
+ });
53
49
 
54
- async function handleAgentOrchestrator(args) {
55
- const input = getRequiredInput(args, "agent-orchestrator");
56
- const artifact = await createAgentOrchestrator(input, {
50
+ const handleAgentOrchestrator = createArtifactCommandHandler({
51
+ commandName: "agent-orchestrator",
52
+ commandLabel: "agent-orchestrator",
53
+ createArtifact: createAgentOrchestrator,
54
+ renderMarkdown: renderAgentOrchestratorMarkdown,
55
+ writeOutput: writeAgentOrchestratorOutput,
56
+ getOptions: (args) => ({
57
57
  intent: getFlagValue(args, "--intent"),
58
58
  format: getJsonCapableFormat(args)
59
- });
60
- return writeOrPrintArtifact({
61
- args,
62
- commandName: "agent-orchestrator",
63
- artifact,
64
- renderMarkdown: renderAgentOrchestratorMarkdown,
65
- writeOutput: writeAgentOrchestratorOutput,
66
- outputJson: artifact.format === "json"
67
- });
68
- }
59
+ })
60
+ });
69
61
 
70
- async function handleAgentResume(args) {
71
- const input = getRequiredInput(args, "agent-resume");
72
- const artifact = await createAgentResume(input, {
62
+ const handleAgentResume = createArtifactCommandHandler({
63
+ commandName: "agent-resume",
64
+ commandLabel: "agent-resume",
65
+ createArtifact: createAgentResume,
66
+ renderMarkdown: renderAgentResumeMarkdown,
67
+ writeOutput: writeAgentResumeOutput,
68
+ getOptions: (args) => ({
73
69
  intent: getFlagValue(args, "--intent"),
74
70
  format: getJsonCapableFormat(args)
75
- });
76
- return writeOrPrintArtifact({
77
- args,
78
- commandName: "agent-resume",
79
- artifact,
80
- renderMarkdown: renderAgentResumeMarkdown,
81
- writeOutput: writeAgentResumeOutput,
82
- outputJson: artifact.format === "json"
83
- });
84
- }
71
+ })
72
+ });
85
73
 
86
- async function handleAgentContinue(args) {
87
- const input = getRequiredInput(args, "agent-continue");
88
- const artifact = await createAgentContinue(input, {
74
+ const handleAgentContinue = createArtifactCommandHandler({
75
+ commandName: "agent-continue",
76
+ commandLabel: "agent-continue",
77
+ createArtifact: createAgentContinue,
78
+ renderMarkdown: renderAgentContinueMarkdown,
79
+ writeOutput: writeAgentContinueOutput,
80
+ getOptions: (args) => ({
89
81
  intent: getFlagValue(args, "--intent"),
90
82
  format: getJsonCapableFormat(args)
91
- });
92
- return writeOrPrintArtifact({
93
- args,
94
- commandName: "agent-continue",
95
- artifact,
96
- renderMarkdown: renderAgentContinueMarkdown,
97
- writeOutput: writeAgentContinueOutput,
98
- outputJson: artifact.format === "json"
99
- });
100
- }
83
+ })
84
+ });
101
85
 
102
- async function handleAgentStatePack(args) {
103
- const input = getRequiredInput(args, "agent-state-pack");
104
- const artifact = await createAgentStatePack(input, {
86
+ const handleAgentStatePack = createArtifactCommandHandler({
87
+ commandName: "agent-state-pack",
88
+ commandLabel: "agent-state-pack",
89
+ createArtifact: createAgentStatePack,
90
+ renderMarkdown: renderAgentStatePackMarkdown,
91
+ writeOutput: writeAgentStatePackOutput,
92
+ getOptions: (args) => ({
105
93
  intent: getFlagValue(args, "--intent"),
106
94
  format: getJsonCapableFormat(args),
107
95
  currentTaskId: getFlagValue(args, "--current"),
108
96
  completedPacketIds: getFlagValue(args, "--completed"),
109
97
  blockedReasons: getFlagValue(args, "--blocked")
110
- });
111
- return writeOrPrintArtifact({
112
- args,
113
- commandName: "agent-state-pack",
114
- artifact,
115
- renderMarkdown: renderAgentStatePackMarkdown,
116
- writeOutput: writeAgentStatePackOutput,
117
- outputJson: artifact.format === "json"
118
- });
119
- }
98
+ })
99
+ });
120
100
 
121
- async function handleAgentSession(args) {
122
- const input = getRequiredInput(args, "agent-session");
123
- const artifact = await createAgentSession(input, {
101
+ const handleAgentSession = createArtifactCommandHandler({
102
+ commandName: "agent-session",
103
+ commandLabel: "agent-session",
104
+ createArtifact: createAgentSession,
105
+ renderMarkdown: renderAgentSessionMarkdown,
106
+ writeOutput: writeAgentSessionOutput,
107
+ getOptions: (args) => ({
124
108
  intent: getFlagValue(args, "--intent")
125
- });
126
- return writeOrPrintArtifact({
127
- args,
128
- commandName: "agent-session",
129
- artifact,
130
- renderMarkdown: renderAgentSessionMarkdown,
131
- writeOutput: writeAgentSessionOutput,
132
- outputJson: hasFlag(args, "--json")
133
- });
134
- }
109
+ })
110
+ });
135
111
 
136
112
  export const FLOW_COMMAND_HANDLERS = {
137
113
  "auto-flow": handleAutoFlow,
package/src/cli-shared.js CHANGED
@@ -90,3 +90,46 @@ export function createPackCommandHandler({
90
90
  process.stdout.write(renderMarkdown(pack));
91
91
  };
92
92
  }
93
+
94
+ export function createStructuredOutputCommandHandler({
95
+ commandLabel,
96
+ execute,
97
+ renderMarkdown,
98
+ writeOutput,
99
+ getOutputJson
100
+ }) {
101
+ return async function structuredOutputCommandHandler(args) {
102
+ const result = await execute(args);
103
+ const outputJson = getOutputJson ? getOutputJson(args, result) : hasFlag(args, "--json");
104
+ const renderedOutput = outputJson ? `${JSON.stringify(result, null, 2)}\n` : renderMarkdown(result);
105
+ const outputPath = getFlagValue(args, "--out");
106
+
107
+ if (outputPath) {
108
+ const resolvedOutputPath = await writeOutput(outputPath, renderedOutput);
109
+ process.stdout.write(`已保存 ${commandLabel} 结果:${resolvedOutputPath}\n`);
110
+ return;
111
+ }
112
+
113
+ process.stdout.write(renderedOutput);
114
+ };
115
+ }
116
+
117
+ export function createActionCommandHandler({
118
+ execute,
119
+ getOutputJson,
120
+ renderText
121
+ }) {
122
+ return async function actionCommandHandler(args) {
123
+ const result = await execute(args);
124
+ const outputJson = getOutputJson ? getOutputJson(args, result) : hasFlag(args, "--json");
125
+
126
+ if (outputJson) {
127
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
128
+ return;
129
+ }
130
+
131
+ if (renderText) {
132
+ process.stdout.write(renderText(result, args));
133
+ }
134
+ };
135
+ }
@@ -1,4 +1,4 @@
1
- import { getFlagValue, hasFlag } from "./cli-shared.js";
1
+ import { createActionCommandHandler, getFlagValue, hasFlag } from "./cli-shared.js";
2
2
  import { installSkill } from "./install-skill.js";
3
3
  import { getBundledSkillPath, getInstalledSkillPath, getSkillName, getSkillsDir } from "./paths.js";
4
4
  import { listBundledSkills, renderBundledSkillsMarkdown } from "./skills.js";
@@ -9,15 +9,16 @@ export const SHELL_HELP_LINES = [
9
9
  " geo-ai-search-optimization where"
10
10
  ];
11
11
 
12
- async function handleInstall(args) {
13
- const targetDir = getFlagValue(args, "--target");
14
- const outputJson = hasFlag(args, "--json");
15
- const result = await installSkill({ targetDir, silent: outputJson });
16
-
17
- if (outputJson) {
18
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
19
- }
20
- }
12
+ const handleInstall = createActionCommandHandler({
13
+ execute: async (args) => {
14
+ const outputJson = hasFlag(args, "--json");
15
+ return installSkill({
16
+ targetDir: getFlagValue(args, "--target"),
17
+ silent: outputJson
18
+ });
19
+ },
20
+ getOutputJson: (args) => hasFlag(args, "--json")
21
+ });
21
22
 
22
23
  async function handleSkills(args) {
23
24
  const bundle = await listBundledSkills();
@@ -1,5 +1,11 @@
1
1
  import { auditProject, renderAuditMarkdown, writeAuditOutput } from "./audit.js";
2
- import { getFlagValue, hasFlag, parsePositiveInteger } from "./cli-shared.js";
2
+ import {
3
+ createActionCommandHandler,
4
+ createStructuredOutputCommandHandler,
5
+ getFlagValue,
6
+ hasFlag,
7
+ parsePositiveInteger
8
+ } from "./cli-shared.js";
3
9
  import { renderDoctorMarkdown, runDoctor } from "./doctor.js";
4
10
  import {
5
11
  renderInteractiveOnboardingMarkdown,
@@ -23,171 +29,124 @@ export const SITE_OPS_HELP_LINES = [
23
29
  " geo-ai-search-optimization scan <project-path> [--json] [--out <file>] [--max-file-size <bytes>] [--max-examples <count>]"
24
30
  ];
25
31
 
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
- }
32
+ const passthroughWriteOutput = async (outputPath) => outputPath;
33
+
34
+ const handleDoctor = createStructuredOutputCommandHandler({
35
+ commandLabel: "doctor",
36
+ execute: async () => runDoctor(),
37
+ renderMarkdown: renderDoctorMarkdown,
38
+ writeOutput: passthroughWriteOutput,
39
+ getOutputJson: (args) => hasFlag(args, "--json")
40
+ });
41
+
42
+ const handleQuickStart = createStructuredOutputCommandHandler({
43
+ commandLabel: "quick start",
44
+ execute: async () => createQuickStartPlan({}),
45
+ renderMarkdown: renderQuickStartMarkdown,
46
+ writeOutput: writeQuickStartOutput,
47
+ getOutputJson: (args) => hasFlag(args, "--json")
48
+ });
49
+
50
+ const handleInteractiveOnboard = createStructuredOutputCommandHandler({
51
+ commandLabel: "交互式 onboarding",
52
+ execute: async (args) =>
53
+ runInteractiveOnboarding({
54
+ url: getFlagValue(args, "--url"),
55
+ goal: getFlagValue(args, "--goal"),
56
+ existingAssets: getFlagValue(args, "--existing-assets")
57
+ }),
58
+ renderMarkdown: renderInteractiveOnboardingMarkdown,
59
+ writeOutput: writeInteractiveOnboardingOutput,
60
+ getOutputJson: (args) => hasFlag(args, "--json")
61
+ });
62
+
63
+ const handleOnboardUrl = createStructuredOutputCommandHandler({
64
+ commandLabel: "onboarding",
65
+ execute: async (args) => {
66
+ const inputUrl = args.find((value) => !value.startsWith("-"));
67
+ if (!inputUrl) {
68
+ throw new Error("onboard-url requires a website URL");
69
+ }
70
+
71
+ return analyzeWebsiteUrl(inputUrl, {});
72
+ },
73
+ renderMarkdown: (report) => `${renderWebsiteOnboardingMarkdown(report)}\n`,
74
+ writeOutput: writeWebsiteOnboardingOutput,
75
+ getOutputJson: (args) => hasFlag(args, "--json")
76
+ });
77
+
78
+ const handleInitLlms = createActionCommandHandler({
79
+ execute: async (args) =>
80
+ createLlmsTxt({
81
+ targetDir: args.find((value) => !value.startsWith("-")) || ".",
82
+ siteName: getFlagValue(args, "--site-name"),
83
+ siteUrl: getFlagValue(args, "--site-url"),
84
+ overwrite: hasFlag(args, "--overwrite")
85
+ }),
86
+ getOutputJson: (args) => hasFlag(args, "--json"),
87
+ renderText: (result) => `Created llms.txt at ${result.outputPath}\n`
88
+ });
89
+
90
+ const handleInitSchema = createActionCommandHandler({
91
+ execute: async (args) => {
92
+ const [schemaType, ...rest] = args;
93
+ if (!schemaType || schemaType.startsWith("-")) {
94
+ throw new Error("init-schema requires a schema type");
95
+ }
96
+
97
+ return createSchemaTemplate({
98
+ schemaType,
99
+ targetDir: rest.find((value) => !value.startsWith("-")) || ".",
100
+ siteUrl: getFlagValue(rest, "--site-url"),
101
+ overwrite: hasFlag(rest, "--overwrite")
102
+ });
103
+ },
104
+ getOutputJson: (args) => hasFlag(args, "--json"),
105
+ renderText: (result) => `Created ${result.schemaType} schema template at ${result.outputPath}\n`
106
+ });
107
+
108
+ const handleAudit = createStructuredOutputCommandHandler({
109
+ commandLabel: "审计",
110
+ execute: async (args) => {
111
+ const projectPath = args.find((value) => !value.startsWith("-"));
112
+ if (!projectPath) {
113
+ throw new Error("audit requires a project path");
114
+ }
115
+
116
+ return auditProject(projectPath, {
117
+ maxFileSize: getFlagValue(args, "--max-file-size")
118
+ ? parsePositiveInteger(getFlagValue(args, "--max-file-size"), "--max-file-size")
119
+ : undefined,
120
+ maxExamples: getFlagValue(args, "--max-examples")
121
+ ? parsePositiveInteger(getFlagValue(args, "--max-examples"), "--max-examples")
122
+ : undefined
123
+ });
124
+ },
125
+ renderMarkdown: (report) => `${renderAuditMarkdown(report)}\n`,
126
+ writeOutput: writeAuditOutput,
127
+ getOutputJson: (args) => hasFlag(args, "--json")
128
+ });
129
+
130
+ const handleScan = createStructuredOutputCommandHandler({
131
+ commandLabel: "扫描",
132
+ execute: async (args) => {
133
+ const projectPath = args.find((value) => !value.startsWith("-"));
134
+ if (!projectPath) {
135
+ throw new Error("scan requires a project path");
136
+ }
137
+
138
+ const maxFileSizeValue = getFlagValue(args, "--max-file-size");
139
+ const maxExamplesValue = getFlagValue(args, "--max-examples");
140
+
141
+ return scanProject(projectPath, {
142
+ maxFileSize: maxFileSizeValue ? parsePositiveInteger(maxFileSizeValue, "--max-file-size") : undefined,
143
+ maxExamples: maxExamplesValue ? parsePositiveInteger(maxExamplesValue, "--max-examples") : undefined
144
+ });
145
+ },
146
+ renderMarkdown: renderScanMarkdown,
147
+ writeOutput: writeScanOutput,
148
+ getOutputJson: (args) => hasFlag(args, "--json")
149
+ });
191
150
 
192
151
  export const SITE_OPS_COMMAND_HANDLERS = {
193
152
  doctor: handleDoctor,