fix(review): audit prepared-wrapper activation and pin generated shapes
ds-review-bot round 1 on the DSH-home integration: - generated wrappers now inject the services their manifest needs (skills/ tools beside loader), and loadPreparedRepository rejects a wrapper fiber that settles anything but ACTIVE — a composition missing a required service fails the repository transaction instead of committing an ACTIVE row over a silently PENDING child (critical finding) - the github: source ref segment excludes '#', so 'a#b' refs fail at the config parser with the promised syntax instead of inside pnpm - watchPersonalPatches re-reads the include's non-patch options per refresh instead of a registration-time snapshot - the TUI smoke's cache-seeded wrapper is produced by the real prepareDshPlugin (cache LAYOUT stays a deliberate external pin) - new Loader integration test drives a live repositories update through entry.update: generation swap, old skills removed, failed candidate rolled back to the previous generation
This commit is contained in:
@@ -7,6 +7,7 @@ import { dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { LOADER_SMOKE_TEST_TIMEOUT_MS } from '@deepseek-ai/dsh-loader-smoke'
|
||||
import { PREPARED_ENTRY_FILENAME, prepareDshPlugin } from '@deepseek-ai/dsh-repository-plugin'
|
||||
import { packChunkRuns, SessionId, type SessionEvent, type SessionHeader } from '@deepseek-ai/dsh-session'
|
||||
import { logPath, toHeaderLine } from '../../../packages/session-persistence/session-persistence-jsonl/src/format.ts'
|
||||
import { runTuiPtySmoke, type TuiPtySmokeOptions } from './pty-harness.ts'
|
||||
@@ -67,6 +68,38 @@ function seedWorkspace(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the real `prepareDshPlugin` over an equivalent one-skill `.dsh-plugin`
|
||||
* package and return the generated wrapper text, so the smoke's cache-seeded
|
||||
* wrapper can never drift from the generator's template.
|
||||
*/
|
||||
async function generatePreparedWrapper(pluginName: string): Promise<string> {
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-smoke-wrapper-'))
|
||||
try {
|
||||
const plugin = join(root, '.dsh-plugin')
|
||||
await mkdir(join(root, 'skills', 'config-only-repository'), { recursive: true })
|
||||
await writeFile(join(root, 'skills', 'config-only-repository', 'SKILL.md'), [
|
||||
'---',
|
||||
'name: config-only-repository',
|
||||
'description: Generator input; the seeded cache copy owns the visible text.',
|
||||
'---',
|
||||
'',
|
||||
'Repository instructions.',
|
||||
'',
|
||||
].join('\n'))
|
||||
await mkdir(plugin, { recursive: true })
|
||||
await writeFile(join(plugin, 'package.json'), `${JSON.stringify({
|
||||
name: pluginName,
|
||||
version: '0.0.0',
|
||||
dsh: { skills: ['../skills'] },
|
||||
}, undefined, 2)}\n`)
|
||||
await prepareDshPlugin(plugin)
|
||||
return await readFile(join(plugin, PREPARED_ENTRY_FILENAME), 'utf8')
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true })
|
||||
}
|
||||
}
|
||||
|
||||
/** Seed one real plaintext JSONL session for the `/resume` selector and host handoff smoke. */
|
||||
async function seedResumeSession(cwd: string): Promise<void> {
|
||||
const sessionCwd = realpathSync.native(cwd)
|
||||
@@ -646,19 +679,12 @@ describe('dsh CLI keyless smoke (apps/cli through the same PTY)', () => {
|
||||
const specifier = `${source}&path:/.dsh-plugin`
|
||||
const key = createHash('sha256').update(specifier).digest('hex')
|
||||
const packageRoot = `cache/repository-plugins/${key}/node_modules/repository`
|
||||
const manifest = { name: 'config-only-fixture', skills: ['dsh-plugin-assets/skills/0'] }
|
||||
const wrapper = [
|
||||
'// Generated by dsh-plugin-prepare. Do not edit.',
|
||||
`const manifest = ${JSON.stringify(manifest)}`,
|
||||
`export const name = ${JSON.stringify(manifest.name)}`,
|
||||
"export const inject = ['loader']",
|
||||
'export async function apply(ctx) {',
|
||||
" const runtime = ctx.loader.builtins['dsh-repository-plugin']",
|
||||
" if (runtime === undefined) throw new Error('missing Cordis builtin dsh-repository-plugin')",
|
||||
' await ctx.plugin(runtime, { baseUrl: import.meta.url, manifest })',
|
||||
'}',
|
||||
'',
|
||||
].join('\n')
|
||||
// Produced by the real generator (prepareDshPlugin over an equivalent
|
||||
// .dsh-plugin package) rather than hand-written, so a wrapper-template
|
||||
// change cannot leave this smoke exercising a stale shape. The cache
|
||||
// LAYOUT below (sha256 key, marker, node_modules/repository) remains a
|
||||
// deliberate external pin of the durable on-disk format.
|
||||
const wrapper = await generatePreparedWrapper('config-only-fixture')
|
||||
const output = await smoke({
|
||||
label: 'dsh personal repository Plugin',
|
||||
tempDirPrefix: 'dsh-personal-repository-plugin-',
|
||||
|
||||
Reference in New Issue
Block a user