Files
deepseek-harness/scripts/gen-cordis-inspect-catalog.ts
Tianyi Cui d66b21894c merge: integrate latest master into session-log-v4
Merge master 62b700bba7bb71e66d2d5a3b850ba8f4dd0fd6b4 into release/session-log-v4 at 4825bc01a999f564e79172a6af28e34fc757c540. Preserve this pinned integration checkpoint before any later upstream movement so the dependent session-format repairs have an immutable rebase base.

Keep release projection-backed child catalogs, independent Session references, exact fork behavior, V4 writer, and existing migration data. Adapt the incoming subagent sidebar chat to refreshProjections rather than the removed dedicated catalog API, preserve title projections in complete projection fixtures, and retain both sidebar actions and release lineage/status behavior. Remove the duplicate SessionProjectionMap import introduced by automatic merging.

Preserve both disjoint archive seals without changing any existing hash. Regenerate current Cordis and documentation catalogs from the combined source, retaining release session methods plus master slot factories. The frozen V0-V3 runtime paths are unchanged. Initial validation passed the full build, 93 focused Client tests, and all 1905 archived artifact seals; remaining integration and snapshot checks follow on this checkpoint.
2026-09-17 23:23:48 +08:00

92 lines
4.1 KiB
TypeScript

/** Generate model-visible Host/Client Service and Event inspect catalogs. */
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import { dirname, resolve } from 'node:path'
import { projectCordisCatalog } from '@deepseek-ai/dsh-typert-generator'
import type { CordisCatalogModel, ServiceMethodEntry } from '@deepseek-ai/dsh-typert-generator'
import { CORDIS_CATALOG_POLICY } from './gen-cordis-catalog.ts'
const root = resolve(import.meta.dirname, '..')
const CLIENT_OUT = 'packages/extensions/cordis-client-runner/src/client/api-catalog.ts'
const CLIENT_SERVICES: Readonly<Record<string, readonly string[]>> = {
layout: ['selectPanel', 'beginNavigation', 'toggleSidebar', 'openRightbar', 'closeRightbar'],
locale: ['getLocale', 'getSnapshot', 'subscribe', 'setLocale', 'addLanguage', 'register', 'bind'],
sessions: ['retain', 'using', 'retainInfo', 'refreshProjections', 'search', 'fork', 'scope', 'binding'],
slots: ['register', 'registerFactory', 'inject'],
theme: ['getTheme', 'setTheme', 'setFontSize', 'register', 'overrideTokens'],
uiWorkspace: [
'openSession', 'openWorkspace', 'forkSession', 'connectWorkspace', 'startSession', 'archiveSession', 'unarchiveSession',
'pickDirectory', 'listDirectory', 'createDirectory',
],
workspaces: ['create', 'rename', 'delete', 'insertSessionBefore', 'archiveSession', 'unarchiveSession'],
}
const CLIENT_EVENTS = new Set([
'connection/reset',
'locale/change',
'slots/changed',
'theme/change',
])
function methodName(method: ServiceMethodEntry): string | undefined {
return /^(?:declare\s+)?(?:readonly\s+)?(?:async\s+)?([A-Za-z_$][\w$]*)/.exec(method.signature)?.[1]
}
function clientModel(model: CordisCatalogModel): CordisCatalogModel {
const services = Object.entries(CLIENT_SERVICES).map(([key, allowed]) => {
const matches = model.services.filter(service => service.key === key)
if (matches.length !== 1) {
throw new Error(`gen-cordis-inspect-catalog: expected one Client Service ${JSON.stringify(key)}, found ${matches.length}`)
}
const service = matches[0] as (typeof matches)[number]
const names = new Set(allowed)
const methods = service.methods.filter(method => names.has(methodName(method) ?? ''))
const found = new Set(methods.map(method => methodName(method)))
const missing = allowed.filter(name => !found.has(name))
if (missing.length > 0) {
throw new Error(
`gen-cordis-inspect-catalog: Client Service ${JSON.stringify(key)}`
+ ` is missing allowlisted method(s): ${missing.join(', ')}`,
)
}
return { ...service, methods }
})
const events = [...CLIENT_EVENTS].map((name) => {
const matches = model.events.filter(event => event.name === name)
if (matches.length !== 1) {
throw new Error(`gen-cordis-inspect-catalog: expected one Client Event ${JSON.stringify(name)}, found ${matches.length}`)
}
return matches[0] as (typeof matches)[number]
})
return {
services,
events,
}
}
function main(): void {
const { projector, model } = projectCordisCatalog(root, {
...CORDIS_CATALOG_POLICY,
runtimeDeclarationMaxChars: 4_096,
}, 'client')
const destination = resolve(root, CLIENT_OUT)
const source = projector.renderRuntimeApi(clientModel(model))
.replace('Generated by scripts/gen-cordis-api.ts', 'Generated by scripts/gen-cordis-inspect-catalog.ts')
.replaceAll('pnpm run gen-cordis-api', 'pnpm run gen-cordis-inspect-catalog')
.replaceAll('pnpm run verify-cordis-api', 'pnpm run verify-cordis-inspect-catalog')
.replaceAll('@deepseek-ai/dsh-tool-cordis/api-catalog', '@deepseek-ai/dsh-cordis-client-runner/client/api-catalog')
if (process.argv.includes('--check')) {
if (!existsSync(destination) || readFileSync(destination, 'utf8') !== source) {
throw new Error(`gen-cordis-inspect-catalog: ${CLIENT_OUT} is stale; run pnpm run gen-cordis-inspect-catalog`)
}
console.log(`gen-cordis-inspect-catalog: ${CLIENT_OUT} is up to date`)
return
}
mkdirSync(dirname(destination), { recursive: true })
writeFileSync(destination, source)
console.log(`gen-cordis-inspect-catalog: wrote ${CLIENT_OUT}`)
}
main()