Merge remote-tracking branch 'origin/master' into feat/read-image-context
This commit is contained in:
@@ -13,6 +13,7 @@ import { parseJsDoc, pointer, rawJsDoc, reportViolations } from './jsdoc.ts'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
const OUT = 'docs/persistence-catalog.md'
|
||||
const OUT_RUNTIME_TYPES = 'packages/core/session/src/known-event-types.ts'
|
||||
|
||||
/** The fenced-block info string for generated declaration blocks (skipped by
|
||||
* doc-typecheck, since their imported types are not standalone-compilable). */
|
||||
@@ -359,7 +360,7 @@ export function render(events: AnnotatedLogEventEntry[], envelopeTypes: EventEnv
|
||||
'',
|
||||
'This file is GENERATED from source (`scripts/gen-persistence-catalog.ts`) and verified fresh by `pnpm run verify-persistence-catalog` (part of `doc-sync`) — do not edit it by hand. Declaration blocks retain the source declaration and nested property JSDoc, removing only the indentation imposed by a containing interface/module, and use a `ts persistence-catalog` fence (skipped by doc-typecheck because declarations reference types from their owning modules). Type names in a payload link to the page that documents them. See [the persistence-log-catalog Agent Note](../.agents/notes/archived/process/2026-07-04-persistence-log-catalog.md).',
|
||||
'',
|
||||
'The envelope declarations below compose each event\'s `type`, monotonic `seq`, epoch-ms `time`, `data`, and the conditional `surfaceOp`/`sourceEventSeqs` fields. **surface** marks a `SurfaceEventType` member: it produces an LLM message and declares how it joins the surface list. **log-only** marks everything else: a durable, replayable record with no derived-history contribution. Every payload is JSON-serializable (enforced at `Session.append`), and the whole format is pinned at `SESSION_FORMAT_VERSION = 0` — pre-release, no compatibility implied ([the version stance](subsystems/persistence.md)). Scope: the packages in this repo; a downstream plugin can merge further event types, which are outside this catalog by construction.',
|
||||
'The envelope declarations below compose each event\'s `type`, monotonic `seq`, epoch-ms `time`, `data`, the optional `ignorable` unknown-type skip marker, and the conditional `surfaceOp`/`sourceEventSeqs` fields. **surface** marks a `SurfaceEventType` member: it produces an LLM message and declares how it joins the surface list. **log-only** marks everything else: a durable, replayable record with no derived-history contribution. Every payload is JSON-serializable (enforced at `Session.append`), and the whole format is pinned at `SESSION_FORMAT_VERSION = 0` — pre-release, no compatibility implied ([the version stance](subsystems/persistence.md)). Scope: the packages in this repo; a downstream plugin can merge further event types, which are outside this catalog by construction.',
|
||||
'',
|
||||
'## Event envelope',
|
||||
'',
|
||||
@@ -382,31 +383,79 @@ export function render(events: AnnotatedLogEventEntry[], envelopeTypes: EventEnv
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
/** CLI entry: default writes the catalog, `--check` fails if the committed copy
|
||||
/**
|
||||
* Render the runtime known-vocabulary module: every event type the packages in
|
||||
* this repo can write, as a generated `ReadonlySet` the read path checks
|
||||
* unknown-type refusal against (`SessionEvent.ignorable` contract).
|
||||
*/
|
||||
export function renderKnownEventTypes(events: AnnotatedLogEventEntry[]): string {
|
||||
const names = [...new Set(events.map(e => e.name))].sort()
|
||||
return [
|
||||
'/**',
|
||||
' * GENERATED by `scripts/gen-persistence-catalog.ts` — do not edit by hand; run',
|
||||
' * `pnpm run gen-persistence-catalog` to regenerate (verified fresh by',
|
||||
' * `pnpm run verify-persistence-catalog`, part of `doc-sync`).',
|
||||
' * @module @deepseek-ai/dsh-session/known-event-types',
|
||||
' */',
|
||||
'',
|
||||
'/**',
|
||||
' * Every `SessionEventMap` member declared in this repository — the event',
|
||||
' * vocabulary this build understands. The persistence read path refuses to',
|
||||
' * interpret a log containing a type outside this set unless the event',
|
||||
' * carries the envelope\'s `ignorable` marker (see `SessionEvent.ignorable`',
|
||||
' * in `./types.ts`): such a log was likely written by a newer harness, and',
|
||||
' * silently skipping a required event would reconstruct a wrong session.',
|
||||
' * Downstream (out-of-repo) plugin events are outside this list by',
|
||||
' * construction; a registration surface for them is deferred until such a',
|
||||
' * consumer exists.',
|
||||
' */',
|
||||
'export const KNOWN_SESSION_EVENT_TYPES: ReadonlySet<string> = new Set([',
|
||||
...names.map(name => ` '${name}',`),
|
||||
'])',
|
||||
'',
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
/** One generated artifact: repo-relative target and its freshly-rendered content. */
|
||||
interface GeneratedArtifact {
|
||||
readonly out: string
|
||||
readonly content: string
|
||||
}
|
||||
|
||||
/** CLI entry: default writes the artifacts, `--check` fails if a committed copy
|
||||
* is stale. Guarded behind an entry-point check so importing this module for
|
||||
* tests neither regenerates the committed file nor calls process.exit. */
|
||||
* tests neither regenerates the committed files nor calls process.exit. */
|
||||
function main(): void {
|
||||
const content = render(annotateSurface(collectLogEvents(), collectSurfaceEventTypes()), collectEventEnvelopeTypes())
|
||||
const events = annotateSurface(collectLogEvents(), collectSurfaceEventTypes())
|
||||
const artifacts: GeneratedArtifact[] = [
|
||||
{ out: OUT, content: render(events, collectEventEnvelopeTypes()) },
|
||||
{ out: OUT_RUNTIME_TYPES, content: renderKnownEventTypes(events) },
|
||||
]
|
||||
if (process.argv.includes('--check')) {
|
||||
let committed: string | null = null
|
||||
try {
|
||||
committed = readFileSync(resolve(root, OUT), 'utf8')
|
||||
} catch {
|
||||
// Only ENOENT (not yet generated) is expected; a present-but-unreadable
|
||||
// file is not a state this repo produces. Either way the remedy is the
|
||||
// same — regenerate — so treat a read failure as "stale".
|
||||
committed = null
|
||||
}
|
||||
if (committed === content) {
|
||||
console.log(`gen-persistence-catalog: ${OUT} is up to date.`)
|
||||
const stale = artifacts.filter((artifact) => {
|
||||
let committed: string | null = null
|
||||
try {
|
||||
committed = readFileSync(resolve(root, artifact.out), 'utf8')
|
||||
} catch {
|
||||
// Only ENOENT (not yet generated) is expected; a present-but-unreadable
|
||||
// file is not a state this repo produces. Either way the remedy is the
|
||||
// same — regenerate — so treat a read failure as "stale".
|
||||
committed = null
|
||||
}
|
||||
return committed !== artifact.content
|
||||
})
|
||||
if (stale.length === 0) {
|
||||
console.log(`gen-persistence-catalog: ${artifacts.map(a => a.out).join(', ')} are up to date.`)
|
||||
process.exit(0)
|
||||
}
|
||||
console.error(`gen-persistence-catalog: ${OUT} is stale. Run \`pnpm run gen-persistence-catalog\` and commit ${OUT}.`)
|
||||
console.error(`gen-persistence-catalog: ${stale.map(a => a.out).join(', ')} stale. Run \`pnpm run gen-persistence-catalog\` and commit the result.`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
writeFileSync(resolve(root, OUT), content)
|
||||
console.log(`gen-persistence-catalog: wrote ${OUT}.`)
|
||||
for (const artifact of artifacts) {
|
||||
writeFileSync(resolve(root, artifact.out), artifact.content)
|
||||
console.log(`gen-persistence-catalog: wrote ${artifact.out}.`)
|
||||
}
|
||||
}
|
||||
|
||||
// Run only when invoked as a script, not when imported by a test.
|
||||
|
||||
Reference in New Issue
Block a user