feat: 增加固定工作台应用目录兼容格式

This commit is contained in:
2026-10-13 16:48:14 +08:00
parent 70f3132ec4
commit 0c0f991baa
21 changed files with 2408 additions and 19 deletions

View File

@@ -4,6 +4,7 @@ import { basename, join, relative, resolve, sep } from 'node:path'
import { validateJsonSchema } from './json-schema.mjs'
import { findStaticMetrics } from './static-metadata.mjs'
import { validateApplicationContract } from './application-contract.mjs'
import { validateApplicationReleaseContract } from './application-release-contract.mjs'
export const CATALOG_SIDECAR_FILENAME = 'catalog-metadata.v1.json'
@@ -77,7 +78,7 @@ function timestampShapeIsConsistent(timestamp) {
function validateSidecarSemantics(manifest, sidecar, file) {
const errors = []
const add = (code, path, message) => errors.push(diagnostic('error', code, file, path, message))
const expectedKind = ['docker-app', 'native-app', 'artifact'].includes(manifest.type) ? 'app' : 'service'
const expectedKind = ['docker-app', 'native-app', 'artifact', 'web-bundle'].includes(manifest.type) ? 'app' : 'service'
if (sidecar.identity?.id !== manifest.id) add('identity-mismatch', '$.identity.id', 'sidecar identity.id 必须与 legacy manifest.id 一致')
if (sidecar.identity?.kind !== expectedKind) add('kind-mismatch', '$.identity.kind', `legacy ${manifest.type} 必须映射为 ${expectedKind}`)
@@ -140,7 +141,7 @@ function validateSidecarSemantics(manifest, sidecar, file) {
if (manifest.toolCount !== undefined && sidecar.spec?.toolCount !== manifest.toolCount) add('spec-mismatch', '$.spec.toolCount', 'toolCount 必须与 legacy 一致')
}
if (['native-app', 'artifact'].includes(manifest.type)) {
if (['native-app', 'artifact', 'web-bundle'].includes(manifest.type)) {
for (const field of ['stewardship', 'availability', 'redistribution', 'listingMaintainer', 'upstreamMaintainer', 'branding', 'compliance']) {
if (!isDeepStrictEqual(manifest[field], sidecar.governance?.[field])) add('native-governance-mismatch', '$.governance.' + field, '原生应用 manifest 与 sidecar 的治理事实必须一致')
}
@@ -237,12 +238,14 @@ export function validateRegistry(repoRoot, options = {}) {
if (entry.type === 'docker-app') counts.dockerApps += 1
if (entry.type === 'native-app') counts.nativeApps = (counts.nativeApps ?? 0) + 1
if (entry.type === 'artifact') counts.artifactApps = (counts.artifactApps ?? 0) + 1
if (entry.type === 'web-bundle') counts.webBundles = (counts.webBundles ?? 0) + 1
if (entry.type === 'mcp') counts.mcpServices += 1
if (entry.type === 'http-api') counts.httpApis += 1
if (entry.type === 'external-integration') counts.externalIntegrations += 1
const effectiveEntrySchema = ['external-integration', 'native-app', 'artifact'].includes(entry.type) ? externalEntrySchema : currentEntrySchema
const effectiveEntrySchema = ['external-integration', 'native-app', 'artifact', 'web-bundle'].includes(entry.type) ? externalEntrySchema : currentEntrySchema
if (effectiveEntrySchema) diagnostics.push(...schemaDiagnostics(entry, effectiveEntrySchema, manifestRelative))
for (const message of validateApplicationContract(entry)) diagnostics.push(diagnostic('error', 'application-contract', manifestRelative, '$', message))
for (const message of validateApplicationReleaseContract(entry)) diagnostics.push(diagnostic('error', 'application-release-contract', manifestRelative, '$', message))
if (entry.id !== basename(entryDir)) diagnostics.push(diagnostic('error', 'directory-id-mismatch', manifestRelative, '$.id', 'manifest.id 必须与 entries/<id> 目录名一致'))
if (seenIds.has(entry.id)) diagnostics.push(diagnostic('error', 'duplicate-id', manifestRelative, '$.id', 'Registry 条目 ID 重复'))
seenIds.add(entry.id)
@@ -264,8 +267,8 @@ export function validateRegistry(repoRoot, options = {}) {
}
if (rootManifest?.stats) {
for (const key of ['totalEntries', 'dockerApps', 'nativeApps', 'artifactApps', 'mcpServices', 'httpApis', 'externalIntegrations']) {
if (['nativeApps', 'artifactApps'].includes(key) && rootManifest.stats[key] === undefined && !counts[key]) continue
for (const key of ['totalEntries', 'dockerApps', 'nativeApps', 'artifactApps', 'webBundles', 'mcpServices', 'httpApis', 'externalIntegrations']) {
if (['nativeApps', 'artifactApps', 'webBundles'].includes(key) && rootManifest.stats[key] === undefined && !counts[key]) continue
if (rootManifest.stats[key] === undefined && key === 'externalIntegrations' && counts[key] === 0) continue
if (rootManifest.stats[key] !== (counts[key] ?? 0)) diagnostics.push(diagnostic('error', 'stats-mismatch', 'manifest.json', `$.stats.${key}`, `声明 ${rootManifest.stats[key]},实际 ${counts[key] ?? 0}`))
}