Merge remote-tracking branch 'origin/master' into worktree/fix-minimal-preset-prompt
This commit is contained in:
@@ -97,9 +97,9 @@ describe('client bundle purity gate', () => {
|
||||
|
||||
it('carries exactly one documented temporary exemption: runtime/client (store engine pending rehoming)', () => {
|
||||
expect(resolveId('@deepseek-ai/dsh-client-runtime/client')).toBeNull()
|
||||
const dshClientChannels = CLIENT_EXTERNALS.filter(
|
||||
const clientChannels = CLIENT_EXTERNALS.filter(
|
||||
entry => entry.startsWith('@deepseek-ai/') && entry.endsWith('/client'))
|
||||
expect(dshClientChannels).toEqual(['@deepseek-ai/dsh-client-runtime/client'])
|
||||
expect(clientChannels).toEqual(['@deepseek-ai/dsh-client-runtime/client'])
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
+21
-2
@@ -1,9 +1,28 @@
|
||||
import { mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises'
|
||||
import { mkdir, mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { expect, it } from 'vitest'
|
||||
import type { TsdownBundle } from 'tsdown'
|
||||
import { watchClientPlugins } from './dev-web.ts'
|
||||
import { discoverPluginDirs, watchClientPlugins } from './dev-web.ts'
|
||||
|
||||
it('discovers dsh.client packages with sibling roles', async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-dev-web-discovery-'))
|
||||
try {
|
||||
const current = join(root, 'packages', 'client', 'current')
|
||||
await mkdir(current, { recursive: true })
|
||||
await writeFile(join(current, 'package.json'), JSON.stringify({
|
||||
dsh: {
|
||||
bundle: { patch: './cordis.patch.yml' },
|
||||
client: { platform: 'web' },
|
||||
profile: { bundles: [] },
|
||||
},
|
||||
}))
|
||||
|
||||
expect(discoverPluginDirs(root)).toEqual(['packages/client/current'])
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('rebuilds a client-plugin bundle after its source changes', async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-dev-web-watch-'))
|
||||
|
||||
+8
-6
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Watch-build for client-plugin HMR: runs every dshClient plugin package
|
||||
* Watch-build for client-plugin HMR: runs every `dsh.client` plugin package
|
||||
* through the tsdown JS API in watch mode. Reload signaling is not this
|
||||
* script's business — the host webserver stat-polls the bundles it serves and
|
||||
* broadcasts `rebuilt` frames itself (`dsh web --dev`), so any process that
|
||||
@@ -27,7 +27,7 @@ const repoRoot = fileURLToPath(new URL('..', import.meta.url))
|
||||
|
||||
/**
|
||||
* Discover the watch workspace by declaration: every packages/<group>/<name>
|
||||
* whose package.json carries `dshClient` with platform "web" is a client
|
||||
* whose package.json carries `dsh.client` with platform "web" is a client
|
||||
* plugin bundle emitter. Scanned once at startup — a package added while
|
||||
* watching means restarting this script.
|
||||
* @param root - repository root containing the grouped package directories.
|
||||
@@ -36,8 +36,10 @@ const repoRoot = fileURLToPath(new URL('..', import.meta.url))
|
||||
export function discoverPluginDirs(root = repoRoot): string[] {
|
||||
const dirs: string[] = []
|
||||
for (const manifestPath of globSync('packages/*/*/package.json', { cwd: root }).sort()) {
|
||||
const manifest = JSON.parse(readFileSync(join(root, manifestPath), 'utf8')) as { dshClient?: { platform?: unknown } }
|
||||
if (manifest.dshClient?.platform === 'web') dirs.push(dirname(manifestPath).split(sep).join('/'))
|
||||
const manifest = JSON.parse(readFileSync(join(root, manifestPath), 'utf8')) as {
|
||||
dsh?: { client?: { platform?: unknown } }
|
||||
}
|
||||
if (manifest.dsh?.client?.platform === 'web') dirs.push(dirname(manifestPath).split(sep).join('/'))
|
||||
}
|
||||
return dirs
|
||||
}
|
||||
@@ -88,7 +90,7 @@ const isMain = invokedPath !== undefined && import.meta.url === pathToFileURL(re
|
||||
if (isMain) {
|
||||
const pluginDirs = discoverPluginDirs()
|
||||
if (pluginDirs.length === 0) {
|
||||
console.error('dev-web: no dshClient (platform "web") packages found under packages/')
|
||||
console.error('dev-web: no dsh.client (platform "web") packages found under packages/')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
@@ -106,7 +108,7 @@ if (isMain) {
|
||||
|
||||
await watchClientPlugins(repoRoot, pluginDirs, pollInterval)
|
||||
console.log(
|
||||
`dev-web: watching ${String(pluginDirs.length)} dshClient plugin packages`
|
||||
`dev-web: watching ${String(pluginDirs.length)} dsh.client plugin packages`
|
||||
+ `${pollInterval !== undefined ? ` (polling ${String(pollInterval)}ms)` : ''}:\n ${pluginDirs.join('\n ')}`,
|
||||
)
|
||||
}
|
||||
@@ -512,7 +512,7 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
title: 'Client plugin graph host',
|
||||
mode: 'core',
|
||||
consumers: ['hmr'],
|
||||
note: 'Composes the __DSH_BOOT__ entry graph from an incremental dshClient scan, serves plugin bundles, and notifies rebuilt/graph-changed subscribers.',
|
||||
note: 'Composes the __DSH_BOOT__ entry graph from an incremental dsh.client scan, serves plugin bundles, and notifies rebuilt/graph-changed subscribers.',
|
||||
},
|
||||
{
|
||||
key: 'workflows',
|
||||
|
||||
@@ -227,7 +227,7 @@ describe('Node 24 lane ownership', () => {
|
||||
const subject = withPnpmEntrypoint(() => gatesForMode('ci-consumers'))
|
||||
|
||||
expect(defaultConcurrency('ci-consumers', subject.length, 4)).toEqual({
|
||||
workers: 11,
|
||||
workers: 10,
|
||||
source: 'ci-consumers gate count',
|
||||
})
|
||||
expect(subject.map(item => item.id)).toEqual([
|
||||
@@ -241,7 +241,6 @@ describe('Node 24 lane ownership', () => {
|
||||
'doc-typecheck',
|
||||
'node-next-types',
|
||||
'built-bin-smoke',
|
||||
'github-repository-plugin-e2e',
|
||||
])
|
||||
expect(subject.find(item => item.id === 'publint')?.needs).toEqual(['build'])
|
||||
expect(subject.find(item => item.id === 'built-package-invariants')?.needs).toEqual(['publint'])
|
||||
@@ -252,7 +251,6 @@ describe('Node 24 lane ownership', () => {
|
||||
'doc-typecheck',
|
||||
'node-next-types',
|
||||
'built-bin-smoke',
|
||||
'github-repository-plugin-e2e',
|
||||
]) {
|
||||
expect(subject.find(item => item.id === id)?.needs).toEqual(['built-package-invariants'])
|
||||
}
|
||||
@@ -266,16 +264,6 @@ describe('Node 24 lane ownership', () => {
|
||||
'packages/subagent/subagent-claude-code/tests/loader-composition.e2e.ts',
|
||||
]),
|
||||
)
|
||||
const githubRepositoryPlugin = subject.find(item => item.id === 'github-repository-plugin-e2e')
|
||||
expect(githubRepositoryPlugin).toMatchObject({
|
||||
label: 'GitHub repository Plugin dsh run',
|
||||
env: {
|
||||
DSH_REQUIRE_GITHUB_REPOSITORY_PLUGIN_E2E: '1',
|
||||
},
|
||||
})
|
||||
expect(githubRepositoryPlugin?.args).toEqual(
|
||||
expect.arrayContaining(['apps/cli/tests/github-repository-plugin.built.e2e.ts']),
|
||||
)
|
||||
expect(subject.find(item => item.id === 'web-snapshot')).toMatchObject({
|
||||
displayCommand: 'DSH_SNAPSHOT=replay pnpm run test:web:built',
|
||||
env: { DSH_SNAPSHOT: 'replay' },
|
||||
|
||||
+1
-16
@@ -406,7 +406,6 @@ function ciConsumerGates(): Gate[] {
|
||||
needs: validatedBuild,
|
||||
}),
|
||||
builtBinSmokeGate(validatedBuild),
|
||||
githubRepositoryPluginE2eGate(validatedBuild),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -518,7 +517,7 @@ function coverageGates(): Gate[] {
|
||||
}
|
||||
|
||||
// Example and package snapshots boot their bins in `lib` mode (built artifacts under plain Node,
|
||||
// plugins via real exports); repository-script snapshots execute their real source entry path.
|
||||
// plugins via real exports); script snapshots execute their real source entry path.
|
||||
// Callers wait either on `build` or on a validation gate that transitively owns that build.
|
||||
function snapshotGate(needs: string[] = ['build']): Gate {
|
||||
return pnpmScript('snapshot', 'test:snapshot', {
|
||||
@@ -639,20 +638,6 @@ function builtBinSmokeGate(needs: string[] = ['build']): Gate {
|
||||
})
|
||||
}
|
||||
|
||||
function githubRepositoryPluginE2eGate(needs: string[]): Gate {
|
||||
return pnpmExec('github-repository-plugin-e2e', [
|
||||
'vitest',
|
||||
'run',
|
||||
'--config',
|
||||
'vitest.e2e.config.ts',
|
||||
'apps/cli/tests/github-repository-plugin.built.e2e.ts',
|
||||
], {
|
||||
label: 'GitHub repository Plugin dsh run',
|
||||
needs,
|
||||
env: { DSH_REQUIRE_GITHUB_REPOSITORY_PLUGIN_E2E: '1' },
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject a gate list whose graph cannot be executed unambiguously.
|
||||
* @param gates - complete aggregate to validate.
|
||||
|
||||
Reference in New Issue
Block a user