Skip to content

Commit 1221961

Browse files
committed
feat(cli): add validate command for source document validation
This commit adds a new `validate` CLI command that runs source validation for agent-html documents without producing runtime build output. It also updates project roadmap and component adoption documentation: 1. Defines standardized component expansion rhythm grouped by archetypes 2. Locks down public contract to semantic fields only 3. Moves detailed component status to spec/components-adoption.md
1 parent 7e10848 commit 1221961

5 files changed

Lines changed: 140 additions & 0 deletions

File tree

packages/ahtml/src/cli/artifact-workflow.mjs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,36 @@ export function createArtifactWorkflow({
133133
return parseJson(source, "agent-html.inspect.json must be valid JSON.")
134134
}
135135

136+
async function validateDocument(inputPath, options = {}) {
137+
const inputFilePath = path.resolve(userRoot, inputPath)
138+
const source = await readFile(inputFilePath, "utf8")
139+
const validation = await validateAgentHtmlSource(source)
140+
141+
if (validation.diagnostics.length > 0) {
142+
if (options.printDiagnostics !== false) {
143+
printDiagnostics(validation.diagnostics)
144+
}
145+
process.exitCode = 1
146+
return createValidationResult({
147+
diagnostics: validation.diagnostics,
148+
inputPath: inputFilePath,
149+
ok: false,
150+
})
151+
}
152+
153+
return createValidationResult({
154+
inputPath: inputFilePath,
155+
inspection: createInspection(validation.document),
156+
ok: true,
157+
})
158+
}
159+
136160
return {
137161
buildArtifact,
138162
ensureManagedRuntime,
139163
inspectArtifactDir,
140164
inspectDocument,
165+
validateDocument,
141166
}
142167
}
143168

@@ -178,6 +203,17 @@ function createBuildResult({
178203
}
179204
}
180205

206+
function createValidationResult({ diagnostics = [], inputPath, inspection, ok }) {
207+
return {
208+
kind: "agent-html-validation-result",
209+
version: 1,
210+
ok,
211+
inputPath,
212+
...(inspection ? { inspection } : {}),
213+
...(diagnostics.length > 0 ? { diagnostics } : {}),
214+
}
215+
}
216+
181217
export function formatInspectionSummary(inspection) {
182218
const lines = [
183219
"agent-html inspection",

packages/ahtml/src/cli/commands.mjs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,22 @@ export const commandMetadata = {
5959
],
6060
example: "ahtml prompt",
6161
},
62+
validate: {
63+
summary: "Validate a source document without building runtime output.",
64+
purpose:
65+
"Run source validation and return structured diagnostics or inspection metadata.",
66+
usage: "ahtml validate --input <path> [--format text|json]",
67+
options: [
68+
{ name: "input", description: "Agent-html document path.", value: true },
69+
{
70+
name: "format",
71+
description: "Output format. Defaults to text.",
72+
value: true,
73+
},
74+
],
75+
example: `ahtml validate --input ${cliDefaults.documentPath} --format json`,
76+
hidden: true,
77+
},
6278
build: {
6379
summary: "Validate and build a static HTML artifact.",
6480
purpose: "Validate, sanitize, and build a static artifact directory.",

packages/ahtml/src/cli/index.mjs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ const {
5353
ensureManagedRuntime,
5454
inspectArtifactDir,
5555
inspectDocument,
56+
validateDocument,
5657
} = createArtifactWorkflow({
5758
userRoot,
5859
defaultOutputDir,
@@ -65,6 +66,7 @@ const args = process.argv.slice(3)
6566
const commandHandlers = {
6667
setup: setupCommand,
6768
prompt: promptCommand,
69+
validate: validateCommand,
6870
build: buildCommand,
6971
inspect: inspectCommand,
7072
preview: previewCommand,
@@ -271,6 +273,37 @@ async function buildCommand(commandArgs, definition) {
271273
}
272274
}
273275

276+
async function validateCommand(commandArgs, definition) {
277+
const { options, positionals } = parseOptions(commandArgs, definition)
278+
279+
if (positionals.length > 0) {
280+
fail(`Unexpected argument "${positionals[0]}".`)
281+
}
282+
283+
if (!options.input) {
284+
fail("validate requires --input <path>.")
285+
}
286+
287+
const format = options.format ?? "text"
288+
289+
if (format !== "text" && format !== "json") {
290+
fail('validate --format must be "text" or "json".')
291+
}
292+
293+
const result = await validateDocument(options.input, {
294+
printDiagnostics: format !== "json",
295+
})
296+
297+
if (format === "json") {
298+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`)
299+
return
300+
}
301+
302+
if (result.ok) {
303+
process.stdout.write(formatInspectionSummary(result.inspection))
304+
}
305+
}
306+
274307
async function previewCommand(commandArgs, definition) {
275308
const { options, positionals } = parseOptions(commandArgs, definition)
276309
const inputPath = options.input ?? positionals[0] ?? cliDefaults.documentPath

spec/map.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ components plus named presentation profiles on the public side, and
5454
shadcn-native template/init/registry plus internal capability verification on
5555
the runtime side.
5656

57+
Current expansion posture: do not respond to that gap by expanding the public
58+
parameter bag or by adding isolated components one by one. The current
59+
execution rhythm is to keep the public contract semantic and profile-first,
60+
keep shadcn details inside the managed runtime, then expand breadth by adding
61+
shared renderer archetypes and admitting components in grouped waves. Detailed
62+
component grouping and sequencing now live in `spec/components-adoption.md`.
63+
5764
## Final Decisions
5865

5966
These decisions are locked for the next implementation pass.
@@ -385,6 +392,10 @@ fields and generic ui/slot compatibility paths.
385392
- The generic registry / resolver layer remains the key product layer on the
386393
runtime side. It must map semantic agent-html into legal shadcn/native React
387394
composition without one-off adapters for each component.
395+
- Broader component coverage should follow grouped semantic adoption, not
396+
opportunistic shadcn install order. The next expansion path is `progress`,
397+
then `field/control`, then `option-set`; overlay, menu, navigation, and
398+
app-shell semantics remain out of the near-term lane.
388399
- Generic fallback is no longer the renderer path for unsupported component
389400
names; build now emits structured runtime-render diagnostics before
390401
SSR/runtime failure.

spec/roadmap.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,40 @@ semantic component contract
1515
-> shadcn/native artifact
1616
```
1717

18+
## Current Execution Rhythm
19+
20+
当前主线不是继续扩张 public 参数数量,也不是直接铺开新组件数量。
21+
22+
当前主线是:
23+
24+
1. 继续收紧 public contract。
25+
2. 继续把 shadcn 细节留在 runtime 内部。
26+
3. 先补通用 renderer archetype,再按 archetype 成批扩组件。
27+
28+
### Parameter And Data-Dimension Priorities
29+
30+
- public 参数继续收敛到语义字段,而不是视觉实现字段。
31+
- 优先规范的内容维度是 `title``label``description``value``text`
32+
- 优先规范的状态维度是 `tone``kind``default``required``disabled`
33+
`invalid`
34+
- 优先规范的结构维度是 `item``row``cell``tab``accordion-item`,以及
35+
未来 `option` 一类受控结构节点。
36+
- 当前不应继续扩张 `variant``size``surface``radius``spacing`
37+
`className` 或 raw shadcn props 这类 public 参数面。
38+
39+
### Component Expansion Order
40+
41+
- 第一步先接 `progress`,验证新增只读显示型组件能否低成本进入 schema、
42+
renderer、runtime verification 和 artifact tests。
43+
- 第二步补 `field/control` archetype,再按该 contract 成批接入 `textarea`
44+
`input``checkbox``radio-group`
45+
- 第三步补 `option-set` archetype,再按该 contract 成批接入 `toggle-group`
46+
`select``combobox`
47+
- `dialog``sheet``drawer``popover``tooltip`、menu、navigation 和
48+
app-shell 语义不属于当前近期开发表。
49+
50+
Detailed component status and grouping now live in `spec/components-adoption.md`.
51+
1852
## Phase 1: Lock The Public Contract
1953

2054
- 对外 authoring contract 只保留语义组件和 profile 选择。
@@ -147,6 +181,16 @@ Done when:
147181
必须作为真实语义能力返回,而不是直接暴露底层 shadcn 细节。
148182
- 不重新长出第二套 ahtml UI framework,也不重新长出第二套对外 runtime 协议。
149183

184+
Current state:
185+
186+
- 已明确当前组件接入节奏:先 `progress`,再 `field/control`,再 `option-set`
187+
不直接扩到 overlay、menu 或 navigation。
188+
- 已明确当前参数策略:继续收紧到语义字段,不继续扩张视觉实现字段或 raw shadcn
189+
props。
190+
- 已新增 `spec/components-adoption.md` 作为组件接入分组和优先级清单。
191+
150192
Done when:
151193

152194
- 扩展组件目录不会重新把 agent-facing 合同拖回 runtime-first 思路。
195+
- 新增组件的实现顺序默认由 archetype 和 adoption status 驱动,而不是按 shadcn
196+
安装便利度零散扩张。

0 commit comments

Comments
 (0)