master now ships the reminder stack as the optional `@deepseek-ai/dsh-experimental-schedule-bundle`; this branch keeps the preset-level ownership beside it. Resolutions: - The Host rows keep master's `disabled: true`. The optional bundle switches `schedule` and `ui-schedule` on and no longer `time-context`: the clock row is preset-level, so flipping the Host row as well would mount the plugin in two scopes and write two readings per step. - `standard`, `cordis`, and `ptc` declare `preset-time-context` and `tool-schedule`; `minimal` declares neither. - `tool-schedule` injects `tools` and resolves `schedule` per scope through `ctx.inject`, so the row stays valid but produces no tools while the service is off, and produces them once the bundle mounts it. - The assembled-Web Schedule spec keeps master's bundle overlay and restates the shipped `preset-standard` row instead of the deleted fixture, because a top-level patch cannot reach a plugin a preset declares. - Documentation and Agent Notes describe both layers; the note master archived stays frozen with its manifest hashes.
56 lines
2.0 KiB
TypeScript
56 lines
2.0 KiB
TypeScript
/** The experimental Schedule switch must turn on exactly the two Host rows the Web bundle inserts. */
|
|
|
|
import { readFileSync } from 'node:fs'
|
|
import { resolve } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { describe, expect, it } from 'vitest'
|
|
import * as yaml from 'js-yaml'
|
|
import { entryListSchema } from '@deepseek-ai/cordis-plugin-include'
|
|
|
|
const root = fileURLToPath(new URL('..', import.meta.url))
|
|
|
|
interface Manifest {
|
|
name?: string
|
|
icon?: string
|
|
private?: boolean
|
|
publishConfig?: { access?: string }
|
|
exports?: Record<string, unknown>
|
|
dependencies?: Record<string, string>
|
|
dsh?: { bundle?: { patch?: string } }
|
|
}
|
|
|
|
interface Patch {
|
|
id?: string
|
|
name?: string
|
|
disabled?: boolean
|
|
insert?: unknown[]
|
|
}
|
|
|
|
describe('experimental Schedule bundle', () => {
|
|
const manifest = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8')) as Manifest
|
|
|
|
it('publishes as an experimental bundle with plugin-manager display metadata', () => {
|
|
expect(manifest.name).toBe('@deepseek-ai/dsh-experimental-schedule-bundle')
|
|
expect(manifest.private).toBeUndefined()
|
|
expect(manifest.publishConfig?.access).toBe('public')
|
|
expect(manifest.icon).toBe('./icon.svg')
|
|
expect(manifest.dsh?.bundle?.patch).toBe('./cordis.patch.yml')
|
|
expect(manifest.exports?.['./locale/*.json']).toBe('./locale/*.json')
|
|
expect(manifest.exports?.['./cordis.patch.yml']).toBe('./cordis.patch.yml')
|
|
// The patch only overrides rows another layer inserts, so it depends on no plugin package.
|
|
expect(manifest.dependencies).toBeUndefined()
|
|
})
|
|
|
|
it('turns the two shipped Host rows on and appends none', () => {
|
|
const parsed = yaml.load(readFileSync(resolve(root, './cordis.patch.yml'), 'utf8'), { schema: entryListSchema })
|
|
expect(parsed).toEqual([
|
|
{ id: 'schedule', disabled: false },
|
|
{ id: 'ui-schedule', disabled: false },
|
|
])
|
|
for (const patch of parsed as Patch[]) {
|
|
expect(patch.insert).toBeUndefined()
|
|
expect(patch.name).toBeUndefined()
|
|
}
|
|
})
|
|
})
|