Merge branch 'worktree/schedule-explicit-at' into worktree/schedule-fixed-rate

This commit is contained in:
Tianyi Cui
2026-08-11 20:34:42 +08:00
133 changed files with 4907 additions and 207 deletions

View File

@@ -80,6 +80,7 @@ errors.push(...validateExampleResolution())
errors.push(...validateAppResolution())
errors.push(...validateSourcePlaneResolution())
errors.push(...validatePresetPlaneSeparation())
errors.push(...validateClientHalvesDeclared())
if (errors.length > 0) {
console.error('verify-cordis-config: invalid Loader metadata or plugin package resolution:')
@@ -89,6 +90,35 @@ if (errors.length > 0) {
console.log(`verify-cordis-config: ${files.length} config files passed.`)
}
/**
* A browser plugin must declare the browser half it ships.
*
* The browser roster is discovered by scanning composed packages for a
* `dsh.client` block, and the node half of a surface plugin is an empty
* `apply`. A `packages/client` package that exports `./client` without that
* block therefore composes, activates, and contributes nothing — its bundle is
* never served and no error is raised anywhere. The mismatch is invisible in
* the composition file, so it is checked against the manifests instead. Only
* this group is checked: a Host package's `./client` export is the typed wire
* face its browser consumers import, not a plugin the roster serves.
* @returns one violation per client package whose `./client` export and
* `dsh.client` declaration disagree.
*/
function validateClientHalvesDeclared(): string[] {
return globSync('packages/client/*/package.json', { cwd: root }).flatMap((manifestPath) => {
const manifest = readManifest(manifestPath) as PackageManifest & {
exports?: Record<string, unknown>
dsh?: { client?: unknown }
}
const shipsClient = manifest.exports !== undefined && Object.hasOwn(manifest.exports, './client')
const declaresClient = manifest.dsh?.client !== undefined
if (shipsClient === declaresClient) return []
return [shipsClient
? `${manifestPath}: exports "./client" but declares no dsh.client, so its browser half is never served`
: `${manifestPath}: declares dsh.client but exports no "./client" entry to serve`]
})
}
/**
* No shipped agent preset may repeat a row the host composition still runs.
*

View File

@@ -84,7 +84,9 @@ const mermaid = (await import('mermaid')).default
// maxEdges: mermaid's default 500-edge render guard; the module graph grows
// with every package edge and crossed it legitimately. Raise the guard here
// (a secure config settable only via initialize) rather than trimming edges.
mermaid.initialize({ startOnLoad: false, maxEdges: 1000 })
// The graph passed 1000 the same way it passed 500, so the headroom doubles
// again rather than being set to whatever the current count happens to be.
mermaid.initialize({ startOnLoad: false, maxEdges: 2000 })
for (const block of blocks) {
try {
await mermaid.parse(block.source, { suppressErrors: false })

View File

@@ -80,6 +80,7 @@ const SENTENCE_MODEL_EXPERIENCE: Readonly<Record<string, SentenceContract>> = {
'packages/client/ui-model': { kind: 'indirect', reason: 'Selection routes session.selectModel; the Host snapshots the selection at the next prompt-assembly boundary and owns the model-visible effect.' },
'packages/client/ui-goal': { kind: 'indirect', reason: 'The strip verbs route goal.* mutations; the host GoalService owns the model-visible goal/change context message.' },
'packages/client/ui-permission': { kind: 'indirect', reason: 'The picker submits the host /permission command; the knob events it appends own the model-visible effect through the sandbox/approval consumers.' },
'packages/client/ui-plugin-config': { kind: 'none', reason: 'Browser-side settings surface; registers no model surface.' },
'packages/client/ui-plan': { kind: 'indirect', reason: 'The chip dispatches /plan off; dsh-plan-mode owns the model-visible policy, exit tool, and logged state.' },
'packages/client/ui-question': { kind: 'indirect', reason: 'The package mounts dsh-tool-ask-user; that tool owns the model-visible schema and answer rendering.' },
'packages/client/ui-trajectory': { kind: 'none', reason: 'Browser-side UI plugin layer; registers nothing model-facing.' },