393 lines
20 KiB
TypeScript
393 lines
20 KiB
TypeScript
/**
|
|
* Generate committed Cordis artifacts from the Typert catalog projector and
|
|
* the independent vendored-core projector.
|
|
*/
|
|
|
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
import { dirname, resolve } from 'node:path'
|
|
import {
|
|
projectCordisCatalog,
|
|
renderEvents,
|
|
renderServices,
|
|
} from '@deepseek-ai/dsh-typert-generator'
|
|
import type { CordisCatalogPolicy } from '@deepseek-ai/dsh-typert-generator'
|
|
import { renderCordisCoreApiPages } from './cordis-core-api.ts'
|
|
|
|
const root = resolve(import.meta.dirname, '..')
|
|
const OUT_EVENTS = 'docs/cordis-catalog/events.md'
|
|
const OUT_SERVICES = 'docs/cordis-catalog/services.md'
|
|
const OUT_RUNTIME_API = 'packages/cordis/tool-cordis/src/api-catalog.ts'
|
|
|
|
/** One primary core-data-structures page per project type used by a generated signature. */
|
|
export const LINK_MAP: Readonly<Record<string, string>> = {
|
|
Agent: 'core.md',
|
|
AgentCancelCause: 'core.md',
|
|
AgentOptions: 'core.md',
|
|
AgentStatus: 'core.md',
|
|
ContentBlock: 'core.md',
|
|
ContinuationDecision: 'core.md',
|
|
ContinuationStop: 'core.md',
|
|
GenerateOptions: 'core.md',
|
|
MessageId: 'core.md',
|
|
HookContext: 'core.md',
|
|
SettleReason: 'core.md',
|
|
AdapterRegistrationHandle: 'core.md',
|
|
DirectoryRegistrationHandle: 'core.md',
|
|
LlmCallConfig: 'core.md',
|
|
LlmModelContext: 'core.md',
|
|
LlmModelReasoningInfo: 'core.md',
|
|
LlmResolvedModelInfo: 'core.md',
|
|
LlmFailure: 'llm-streaming.md',
|
|
LlmModelInfo: 'core.md',
|
|
LlmProviderInfo: 'core.md',
|
|
LlmConfigurableProvider: 'core.md',
|
|
LlmModelDiscoveryRequest: 'core.md',
|
|
LlmDiscoveredModel: 'core.md',
|
|
ResolvedRetryPolicy: 'llm-streaming.md',
|
|
Message: 'core.md',
|
|
MessageSource: 'core.md',
|
|
UserMessage: 'session.md',
|
|
PreStepDecision: 'core.md',
|
|
PreStepContext: 'core.md',
|
|
RequestErrorAction: 'core.md',
|
|
RequestFailureContext: 'core.md',
|
|
PreparedReferencedMessage: 'session-reference.md',
|
|
SessionReferenceCandidate: 'session-reference.md',
|
|
SessionReferenceInput: 'session-reference.md',
|
|
SessionEvent: 'core.md',
|
|
SessionId: 'core.md',
|
|
SessionStartSource: 'core.md',
|
|
SessionLogSnapshot: 'session-query.md',
|
|
SessionSurfaceSnapshot: 'session-query.md',
|
|
ApprovalOutcome: 'approval.md',
|
|
ApprovalPolicy: 'approval.md',
|
|
ApprovalRequest: 'approval.md',
|
|
ApprovalService: 'approval.md',
|
|
BashExecRequest: 'bash.md',
|
|
BashExecSpec: 'bash.md',
|
|
BashProcess: 'bash.md',
|
|
BashRunResult: 'bash.md',
|
|
DshEnvironment: 'subprocess.md',
|
|
SubprocessHandle: 'subprocess.md',
|
|
SubprocessOutcome: 'subprocess.md',
|
|
SubprocessOutputRead: 'subprocess.md',
|
|
SubprocessOutputReader: 'subprocess.md',
|
|
SubprocessSpawnSpec: 'subprocess.md',
|
|
SubprocessTerminalHandle: 'subprocess.md',
|
|
SubprocessTerminalSpawnSpec: 'subprocess.md',
|
|
CodeRunRequest: 'code-runtime.md',
|
|
CodeRunResult: 'code-runtime.md',
|
|
CompactionResult: 'compaction.md',
|
|
CompactionTrigger: 'compaction.md',
|
|
PruneResult: 'compaction.md',
|
|
FileReadOutcome: 'filesystem.md',
|
|
FsDirEntry: 'filesystem.md',
|
|
FsEditOutcome: 'filesystem.md',
|
|
FsEditRequest: 'filesystem.md',
|
|
FsInfo: 'filesystem.md',
|
|
FsPathInfo: 'filesystem.md',
|
|
FsPolicyExec: 'filesystem.md',
|
|
FsTarget: 'filesystem.md',
|
|
FsVersion: 'filesystem.md',
|
|
FsWriteIntent: 'filesystem.md',
|
|
FsWriteOutcome: 'filesystem.md',
|
|
CreateGoalRequest: 'goal.md',
|
|
CreateGoalResult: 'goal.md',
|
|
EditGoalRequest: 'goal.md',
|
|
GoalBlockReason: 'goal.md',
|
|
GoalChanged: 'goal.md',
|
|
GoalRef: 'goal.md',
|
|
GoalView: 'goal.md',
|
|
CommandDefinition: 'commands.md',
|
|
CommandDescriptor: 'commands.md',
|
|
CommandResult: 'commands.md',
|
|
CommandSurface: 'commands.md',
|
|
LlmAdapter: 'llm-streaming.md',
|
|
PreparedLlmCall: 'llm-streaming.md',
|
|
LlmService: 'llm-streaming.md',
|
|
StreamChunk: 'llm-streaming.md',
|
|
SkillProviderControl: 'skills.md',
|
|
CreateSessionOptions: 'persistence.md',
|
|
PrepareSessionOptions: 'persistence.md',
|
|
SessionHeader: 'persistence.md',
|
|
SessionInspection: 'persistence.md',
|
|
SessionLocation: 'persistence.md',
|
|
SessionPreparation: 'persistence.md',
|
|
SessionPersistenceSnapshot: 'persistence.md',
|
|
ConfinedArgv: 'sandbox.md',
|
|
SandboxExecutionPolicy: 'sandbox.md',
|
|
SandboxMode: 'sandbox.md',
|
|
SandboxPolicy: 'sandbox.md',
|
|
PtyBackend: 'pty.md',
|
|
PtyReadRequest: 'pty.md',
|
|
PtyReadResult: 'pty.md',
|
|
PtySendOperation: 'pty.md',
|
|
PtySendRequest: 'pty.md',
|
|
PtySessionId: 'pty.md',
|
|
PtySessionSnapshot: 'pty.md',
|
|
PtySignal: 'pty.md',
|
|
PtySignalResult: 'pty.md',
|
|
PtySpawnRequest: 'pty.md',
|
|
PtySpawnResult: 'pty.md',
|
|
SandboxPolicyRequest: 'sandbox.md',
|
|
ScopeKey: 'scope.md',
|
|
Scoped: 'scope.md',
|
|
EpochHeader: 'session.md',
|
|
Session: 'session.md',
|
|
SessionEventMap: 'session.md',
|
|
TurnEndReason: 'session.md',
|
|
TurnTrigger: 'session.md',
|
|
SessionEventReadRequest: 'session-query.md',
|
|
SessionEventRecord: 'session-query.md',
|
|
SessionEventResultFilter: 'session-query.md',
|
|
SessionEventSearchDocument: 'session-query.md',
|
|
SessionEventSearchHit: 'session-query.md',
|
|
SessionEventSearchPage: 'session-query.md',
|
|
SessionEventSearchRequest: 'session-query.md',
|
|
SessionEventTrace: 'session-query.md',
|
|
SessionEventTraceObservation: 'session-query.md',
|
|
SessionEventTraceRequest: 'session-query.md',
|
|
SessionEventWindow: 'session-query.md',
|
|
SessionLineageTrace: 'session-query.md',
|
|
SessionRecord: 'session-query.md',
|
|
SessionResultFilter: 'session-query.md',
|
|
SessionSearchExecContext: 'session-query.md',
|
|
SessionSearchHit: 'session-query.md',
|
|
SessionSearchPage: 'session-query.md',
|
|
SessionSearchRequest: 'session-query.md',
|
|
SessionTitleObservation: 'session-query.md',
|
|
SessionTitleObservationResult: 'session-query.md',
|
|
SessionTitleProvider: 'session-title.md',
|
|
SessionTitleSnapshot: 'session-title.md',
|
|
SkillCatalogSnapshot: 'skills.md',
|
|
SkillDefinition: 'skills.md',
|
|
SkillLookupOptions: 'skills.md',
|
|
SkillProvider: 'skills.md',
|
|
SkillProviderObservation: 'skills.md',
|
|
SkillRegistration: 'skills.md',
|
|
SkillSummary: 'skills.md',
|
|
SaveTextSpill: 'spill.md',
|
|
SpillRef: 'spill.md',
|
|
ContinuableCreateRequest: 'subagent.md',
|
|
ContinuableCreateSpec: 'subagent.md',
|
|
ContinuableSetupContribution: 'subagent.md',
|
|
ContinuableStart: 'subagent.md',
|
|
ContinuableStartSpec: 'subagent.md',
|
|
CoordinatorMessageSource: 'subagent.md',
|
|
SubagentDescendantListEntry: 'subagent.md',
|
|
SubagentFollowupOptions: 'subagent.md',
|
|
SubagentInterruptAuthority: 'subagent.md',
|
|
SubagentListEntry: 'subagent.md',
|
|
SubagentProvider: 'subagent.md',
|
|
SubagentReportDelivery: 'subagent.md',
|
|
SubagentReportMessageSource: 'subagent.md',
|
|
SubagentReportOptions: 'subagent.md',
|
|
SubagentRun: 'subagent.md',
|
|
SubagentService: 'subagent.md',
|
|
SubagentStartRequest: 'subagent.md',
|
|
AssembleContext: 'system-prompt.md',
|
|
PromptContext: 'system-prompt.md',
|
|
PromptSection: 'system-prompt.md',
|
|
SystemPrompt: 'system-prompt.md',
|
|
ToolProviderResult: 'system-prompt.md',
|
|
TaskDoneListener: 'tasks.md',
|
|
TaskId: 'tasks.md',
|
|
TaskRead: 'tasks.md',
|
|
TaskSnapshot: 'tasks.md',
|
|
TaskStart: 'tasks.md',
|
|
TokenMeasurement: 'token-meter.md',
|
|
CodeDispatchLog: 'tools.md',
|
|
PostToolDecision: 'tools.md',
|
|
PreToolDecision: 'tools.md',
|
|
ToolDefinition: 'tools.md',
|
|
ToolExecution: 'tools.md',
|
|
ToolDispatchExecution: 'tools.md',
|
|
ToolExecutionInput: 'tools.md',
|
|
ToolExecutionMode: 'tools.md',
|
|
ToolExecutionResult: 'tools.md',
|
|
ToolExecutionToken: 'tools.md',
|
|
ToolGuard: 'tools.md',
|
|
ToolRegistry: 'tools.md',
|
|
ToolRestriction: 'tools.md',
|
|
ToolSchema: 'tools.md',
|
|
SettingsNamespace: 'settings.md',
|
|
SettingsRegisterOptions: 'settings.md',
|
|
SettingsScope: 'settings.md',
|
|
SettingsDescriptor: 'settings.md',
|
|
SettingsPathOp: 'settings.md',
|
|
SettingsDescribeOptions: 'settings.md',
|
|
SettingsUpdateSource: 'settings.md',
|
|
CredentialRef: 'credentials.md',
|
|
CredentialInfo: 'credentials.md',
|
|
ResolvedCredential: 'credentials.md',
|
|
AskUserQuestionAnswer: 'user-interaction.md',
|
|
AskUserQuestionRequest: 'user-interaction.md',
|
|
UserInteractionProvider: 'user-interaction.md',
|
|
WebFetchProvider: 'web.md',
|
|
WebFetchRequest: 'web.md',
|
|
WebFetchResult: 'web.md',
|
|
WebSearchProvider: 'web.md',
|
|
WebSearchRequest: 'web.md',
|
|
WebSearchResult: 'web.md',
|
|
WorkflowRun: 'workflow.md',
|
|
WorkflowRunInfo: 'workflow.md',
|
|
WorkflowStartRequest: 'workflow.md',
|
|
}
|
|
|
|
/** TypeScript lib and pinned framework types with no repository-owned data page. */
|
|
export const FOUNDATION_TYPE_NAMES: ReadonlySet<string> = new Set([
|
|
'AbortSignal',
|
|
'AsyncIterable',
|
|
'Context',
|
|
'Error',
|
|
'Map',
|
|
'Partial',
|
|
'Pick',
|
|
'Promise',
|
|
'Record',
|
|
'Readonly',
|
|
])
|
|
|
|
/** Project types deliberately documented outside the core-data catalog. */
|
|
export const TYPE_LINK_EXEMPTIONS: Readonly<Record<string, string>> = {
|
|
AgentFactory: 'agent creation seam is owned by packages/core/agent/README.md',
|
|
z: 'schemastery schema constructor is owned by vendor/schemastery (vendored upstream)',
|
|
BeginCommandRequest: 'event-local request contract is owned by packages/client/ui-slash/src/types.ts',
|
|
InsertReferenceRequest: 'event-local request contract is owned by packages/client/ui-slash/src/types.ts',
|
|
ConsumeTokenRequest: 'event-local request contract is owned by packages/client/ui-slash/src/types.ts',
|
|
InsertTextRequest: 'event-local request contract is owned by packages/client/ui-slash/src/types.ts',
|
|
AgentHandle: 'agent ownership handle is owned by packages/core/agent/README.md',
|
|
BashEnvContributor: 'service-local extension type is owned by packages/bash/tool-bash/src/index.ts',
|
|
BashEnvVariableInfo: 'service-local metadata type is owned by packages/bash/tool-bash/src/index.ts',
|
|
CompactAgentContext: 'compaction service input is owned by packages/compact/compact/src/index.ts',
|
|
ManualCompactAgentContext: 'manual compaction service input is owned by packages/compact/compact/src/index.ts',
|
|
DirectoryPickerCapability: 'picker interaction contract is owned by packages/host/directory-picker/README.md',
|
|
CreateAgentOptions: 'agent creation contract is owned by packages/core/agent/README.md',
|
|
Domain: 'domain interface is owned by packages/storage/storage-domain/README.md',
|
|
DomainChanged: 'event-local snapshot is owned by packages/storage/storage-domain/src/events.ts',
|
|
DomainFacility: 'domain form facility is owned by packages/storage/storage-domain/README.md',
|
|
DomainImpl: 'domain implementation contract is owned by packages/storage/storage-domain/README.md',
|
|
DomainSpec: 'domain declaration contract is owned by packages/storage/storage-domain/README.md',
|
|
StorageBackend: 'backend contract is owned by packages/storage/storage/src/backend.ts',
|
|
StorageForms: 'merge-extensible form map is owned by packages/storage/storage/src/index.ts',
|
|
ProjectionDefinition: 'projection unit contract is owned by packages/session-projection/session-projection/README.md',
|
|
SessionProjectionMap: 'merge-extensible projection key map is owned by packages/session-projection/session-projection/src/types.ts',
|
|
ProjectionChangeListener: 'change-feed listener contract is owned by packages/session-projection/session-projection/src/index.ts',
|
|
ProjectionSnapshot: 'watermark snapshot shape is owned by packages/session-projection/session-projection/src/index.ts',
|
|
ProjectionCheckpoint: 'persisted checkpoint row map is owned by packages/session-projection/session-projection/src/index.ts',
|
|
CommandExecution: 'executor return contract is owned by packages/ui/commands/src/index.ts',
|
|
TypertContribution: 'registry contribution contract is owned by packages/typert/registry/README.md',
|
|
TypertFace: 'registry face identity is owned by packages/typert/registry/README.md',
|
|
TypertPackageFilter: 'registry package query filter is owned by packages/typert/registry/README.md',
|
|
TypertPackageRecord: 'registry package record is owned by packages/typert/registry/README.md',
|
|
TypertSchemaFilter: 'registry schema query filter is owned by packages/typert/registry/README.md',
|
|
TypertSchemaRecord: 'registry schema record is owned by packages/typert/registry/README.md',
|
|
TypeRTDisposer: 'TypeRT lifecycle contract is owned by packages/typert/type-meta/README.md',
|
|
'z.core.JSONSchema.BaseSchema': 'zod projection output is owned by the zod v4 API',
|
|
'z.core.ToJSONSchemaParams': 'zod projection parameters are owned by the zod v4 API',
|
|
InvariantInstaller: 'service-local contribution contract is owned by packages/support/invariants/README.md',
|
|
LocaleDict: 'service-local dictionary shape is owned by packages/client/i18n/src/index.ts',
|
|
WebBootGraph: 'web boot graph wire shape is owned by packages/client/modules/src/client/index.ts',
|
|
WebRoute: 'route registration contract is owned by packages/host/webserver/src/index.ts',
|
|
WebUpgradeRoute:
|
|
'upgrade route registration contract is owned by packages/host/webserver/src/index.ts',
|
|
ThemeTokens: 'service-local token dictionary is owned by packages/client/ui-theme/src/index.ts',
|
|
Translate: 'service-local bound translator is owned by packages/client/i18n/src/index.ts',
|
|
InvariantRegistration: 'service-local lifecycle handle is owned by packages/support/invariants/README.md',
|
|
InvokeRemoteRequest: 'gateway invocation contract is owned by packages/api/gateway/README.md',
|
|
PresetOption: 'deployment menu metadata is owned by packages/ui/permission/README.md',
|
|
PresetSpec: 'deployment preset composition is owned by packages/ui/permission/README.md',
|
|
KnobState: 'projection unit state shape is owned by packages/ui/permission/README.md',
|
|
PermissionSelect: 'permissions projection payload is owned by packages/ui/permission/src/types.ts',
|
|
PromptAssembly: 'assembly result is owned by packages/core/system-prompt/README.md',
|
|
ResumeAgentOptions: 'agent resume contract is owned by packages/core/agent/README.md',
|
|
Sandbox: 'external E2B SDK handle is owned by packages/e2b/e2b/README.md',
|
|
SessionForkSource: 'service-local fork input is owned by packages/core/session/src/index.ts',
|
|
SubagentRunEndInfo: 'event payload contract is owned by packages/subagent/subagent/src/types.ts',
|
|
SubagentRunInfo: 'event payload contract is owned by packages/subagent/subagent/src/types.ts',
|
|
TelemetryRecord: 'seam-local record contract is owned by packages/telemetry/session-telemetry/src/index.ts',
|
|
WorkflowAgentEndInfo: 'event-local snapshot is owned by packages/workflow/workflow/src/index.ts',
|
|
WorkflowAgentInfo: 'event-local snapshot is owned by packages/workflow/workflow/src/index.ts',
|
|
WorkflowResultInfo: 'event-local snapshot is owned by packages/workflow/workflow/src/index.ts',
|
|
Workspace: 'workspace entity contract is owned by packages/workspace/workspace/README.md',
|
|
WorkspaceId: 'branded id is owned by packages/workspace/workspace/README.md',
|
|
}
|
|
|
|
/** Repository data policy consumed by the Cordis catalog projector. */
|
|
export const CORDIS_CATALOG_POLICY: CordisCatalogPolicy = {
|
|
linkedTypePages: LINK_MAP,
|
|
foundationTypeNames: FOUNDATION_TYPE_NAMES,
|
|
typeLinkExemptions: TYPE_LINK_EXEMPTIONS,
|
|
inheritedEvents: [
|
|
{ name: 'internal/plugin', summary: 'A plugin fiber was created.', source: 'vendor/cordis/src/events.ts:328' },
|
|
{ name: 'internal/status', summary: 'A fiber changed lifecycle state.', source: 'vendor/cordis/src/events.ts:330' },
|
|
{ name: 'internal/service', summary: 'Interception hook for a service binding (no core producer).', source: 'vendor/cordis/src/events.ts:332' },
|
|
{ name: 'internal/update', summary: 'Waterfall: a fiber config update is being applied.', source: 'vendor/cordis/src/events.ts:334' },
|
|
{ name: 'internal/get', summary: 'Waterfall: a service is being read from the store.', source: 'vendor/cordis/src/events.ts:336' },
|
|
{ name: 'internal/set', summary: 'Waterfall: a service is being written to the store.', source: 'vendor/cordis/src/events.ts:338' },
|
|
{ name: 'internal/listener', summary: 'A listener was registered.', source: 'vendor/cordis/src/events.ts:340' },
|
|
{ name: 'internal/dispatch', summary: 'An event is being dispatched to listeners.', source: 'vendor/cordis/src/events.ts:342' },
|
|
{ name: 'hmr/change', summary: 'A watched source file changed on disk.', source: 'vendor/hmr/src/index.ts:20' },
|
|
{ name: 'hmr/reload', summary: 'Plugins are being reloaded after a change.', source: 'vendor/hmr/src/index.ts:22' },
|
|
{ name: 'hmr/config-update-failed', summary: 'A watched config-file refresh failed.', source: 'vendor/hmr/src/index.ts:29' },
|
|
{ name: 'exit', summary: 'The process is exiting on a signal.', source: 'vendor/loader/src/index.ts:23' },
|
|
{ name: 'loader/config-update', summary: 'The loader config tree changed.', source: 'vendor/loader/src/index.ts:24' },
|
|
{ name: 'loader/entry-init', summary: 'A config entry is being initialized.', source: 'vendor/loader/src/index.ts:25' },
|
|
{ name: 'loader/partial-dispose', summary: 'An entry is being partially disposed on reload.', source: 'vendor/loader/src/index.ts:26' },
|
|
{ name: 'loader/patch-context', summary: 'A context is being patched during a reload.', source: 'vendor/loader/src/index.ts:27' },
|
|
],
|
|
inheritedServices: [
|
|
{ name: 'ctx.on / ctx.once', summary: 'Register an event listener (disposable).', source: 'vendor/cordis/src/events.ts:34' },
|
|
{ name: 'ctx.emit / ctx.parallel / ctx.serial / ctx.bail / ctx.waterfall', summary: 'Dispatch an event (sync / awaited / first-bail / veto-chain).', source: 'vendor/cordis/src/events.ts:34' },
|
|
{ name: 'ctx.plugin / ctx.inject', summary: 'Load a plugin / declare required services.', source: 'vendor/cordis/src/registry.ts:164' },
|
|
{ name: 'ctx.effect', summary: 'Register a disposable side effect tied to the fiber.', source: 'vendor/cordis/src/fiber.ts:9' },
|
|
{ name: 'ctx.get / ctx.set / ctx.provide / ctx.accessor / ctx.mixin', summary: 'Low-level service-store access and binding.', source: 'vendor/cordis/src/reflect.ts:7' },
|
|
{ name: 'ctx.extend / ctx.isolate / ctx.intercept', summary: 'Derive a child context (scoped services / isolation / interception).', source: 'vendor/cordis/src/context.ts:42' },
|
|
{ name: 'ctx.root / ctx.scope / ctx.fiber / ctx.registry / ctx.reflect / ctx.events / ctx.logger', summary: 'Ambient handles onto the running context graph.', source: 'vendor/cordis/src/context.ts:16' },
|
|
{ name: 'ctx.timer (+ interval / timeout / throttle / debounce / setTimeout / setInterval)', summary: 'Disposable timer helpers. The `timer` key is provided at runtime; the six helpers are mixed onto ctx directly (declared via Pick).', source: 'vendor/timer/src/index.ts:4' },
|
|
{ name: 'ctx.loader', summary: 'The config Loader that booted the app (present under the loader).', source: 'vendor/loader/src/index.ts:30' },
|
|
{ name: 'ctx.hmr', summary: 'The hot-module-reload watcher (present under the hmr plugin).', source: 'vendor/hmr/src/index.ts:15' },
|
|
],
|
|
}
|
|
|
|
/** CLI entry: default writes every artifact; `--check` reports stale files.
|
|
* @returns nothing; writes files or reports freshness through the process.
|
|
*/
|
|
export function main(): void {
|
|
const { projector, model } = projectCordisCatalog(root, CORDIS_CATALOG_POLICY)
|
|
const outputs: [string, string][] = [
|
|
[OUT_EVENTS, renderEvents([...model.events], CORDIS_CATALOG_POLICY)],
|
|
[OUT_SERVICES, renderServices([...model.services], CORDIS_CATALOG_POLICY)],
|
|
[OUT_RUNTIME_API, projector.renderRuntimeApi(model)],
|
|
...renderCordisCoreApiPages(),
|
|
]
|
|
if (process.argv.includes('--check')) {
|
|
const stale: string[] = []
|
|
for (const [out, content] of outputs) {
|
|
let committed: string | null = null
|
|
try {
|
|
committed = readFileSync(resolve(root, out), 'utf8')
|
|
} catch {
|
|
// Only ENOENT is expected; either read failure has the same remedy.
|
|
committed = null
|
|
}
|
|
if (committed !== content) stale.push(out)
|
|
}
|
|
if (stale.length === 0) {
|
|
console.log(`gen-cordis-catalog: ${outputs.length} generated file(s) are up to date.`)
|
|
process.exit(0)
|
|
}
|
|
console.error(`gen-cordis-catalog: ${stale.join(' and ')} ${stale.length === 1 ? 'is' : 'are'} stale. Run \`pnpm run gen-cordis-catalog\` and commit the result.`)
|
|
process.exit(1)
|
|
}
|
|
|
|
for (const [out, content] of outputs) {
|
|
const destination = resolve(root, out)
|
|
mkdirSync(dirname(destination), { recursive: true })
|
|
writeFileSync(destination, content)
|
|
}
|
|
console.log(`gen-cordis-catalog: wrote ${outputs.length} generated file(s).`)
|
|
}
|
|
|
|
if (process.argv[1] && import.meta.filename === resolve(process.argv[1])) main()
|