Merge remote-tracking branch 'origin/master' into feat/loader-entry-disabled-interpolation

# Conflicts:
#	.agents/notes/implemented/feature/2026-08-01-windows-pwsh-default.i18n.yaml
#	.agents/notes/implemented/feature/2026-08-01-windows-pwsh-default.md
#	.agents/notes/implemented/feature/2026-08-01-windows-pwsh-default.zh.md
This commit is contained in:
Huanqi Cao
2026-08-11 15:33:09 +08:00
325 changed files with 7030 additions and 1683 deletions

View File

@@ -27,46 +27,61 @@ describe('CI workflow', () => {
}
})
it('keeps Wine blocking while native Windows reports independently', () => {
it('keeps a required Wine Windows job, a non-blocking native Windows job with failover, and a master-only standby', () => {
const workflow = loadWorkflow('.github/workflows/ci.yml')
if (!isRecord(workflow.jobs)
|| !isRecord(workflow.jobs.windows)
|| !isRecord(workflow.jobs['windows-native'])
|| !isRecord(workflow.jobs['wine-apt-cache'])
|| !isRecord(workflow.jobs['serial-windows'])
|| !isRecord(workflow.jobs['all-checks-passed'])) {
throw new TypeError('CI workflow must define Wine, native Windows, and aggregate jobs')
throw new TypeError('CI workflow must define windows, windows-native, wine-apt-cache, serial-windows, and all-checks-passed jobs')
}
const windows = workflow.jobs.windows
const windowsNative = workflow.jobs['windows-native']
const wineAptCache = workflow.jobs['wine-apt-cache']
const serialWindows = workflow.jobs['serial-windows']
const aggregate = workflow.jobs['all-checks-passed']
if (!Array.isArray(windows.steps) || !Array.isArray(windowsNative.steps) || !Array.isArray(aggregate.needs)) {
throw new TypeError('Windows jobs must define steps and the aggregate must define needs')
if (!Array.isArray(windows.steps) || !Array.isArray(aggregate.needs)) {
throw new TypeError('Windows job must define steps and the aggregate must define needs')
}
const nativeCommandSteps = windowsNative.steps.filter((step): step is Record<string, unknown> & { run: string } => (
const commandSteps = windows.steps.filter((step): step is Record<string, unknown> & { run: string } => (
isRecord(step) && typeof step.run === 'string'
))
// Required PR job: Wine on ubuntu-latest, runs wine-windows-gates.sh.
expect(windows['runs-on']).toBe('ubuntu-latest')
expect(windows.name).toBe('windows node 24 / wine blocking')
expect(windows.if).toBe("github.event_name == 'pull_request'")
expect(JSON.stringify(windows)).toContain('bash scripts/wine-windows-gates.sh')
expect(workflow.jobs).toHaveProperty('wine-apt-cache')
expect(windowsNative['runs-on']).toBe('dsh-windows-2025-16core')
expect(commandSteps.some(step => step.run.includes('wine-windows-gates.sh'))).toBe(true)
// windows-native: non-blocking native job with failover, runs windows-complete.
expect(typeof windowsNative['runs-on']).toBe('string')
expect(windowsNative['runs-on']).toContain('DSH_CI_FAILOVER')
expect(windowsNative['runs-on']).toContain('self-hosted')
expect(windowsNative['runs-on']).toContain('dsh-win-ci')
expect(windowsNative['runs-on']).toContain('dsh-windows-2025-16core')
expect(windowsNative.name).toBe('windows node 24 / native complete')
expect(windowsNative['timeout-minutes']).toBe(60)
expect(windowsNative.if).toBe("github.event_name == 'pull_request'")
expect(windowsNative.env).toMatchObject({
DSH_COVERAGE_MAX_WORKERS: '2',
DSH_GATE_CONCURRENCY: '2',
DSH_PUBLINT_CONCURRENCY: '8',
})
expect(windowsNative).not.toHaveProperty('continue-on-error')
expect(nativeCommandSteps).toHaveLength(3)
expect(nativeCommandSteps.every(step => step.shell === 'pwsh')).toBe(true)
const nativeCommandSteps = (windowsNative.steps as unknown[]).filter((step): step is Record<string, unknown> & { run: string } => (
isRecord(step) && typeof step.run === 'string'
))
expect(nativeCommandSteps.map(step => step.run)).toContain('pnpm run check:ci:windows-complete')
expect(JSON.stringify(windowsNative)).not.toMatch(/wine/i)
// wine-apt-cache: master-only, seeds the Wine apt cache.
expect(wineAptCache.if).toBe("github.event_name == 'push' && github.ref == 'refs/heads/master'")
expect(wineAptCache['runs-on']).toBe('ubuntu-latest')
// serial-windows: master-only standby, self-hosted, non-blocking.
expect(serialWindows.if).toBe("github.event_name == 'push' && github.ref == 'refs/heads/master'")
expect(serialWindows['runs-on']).toEqual(['self-hosted', 'dsh-win-ci', 'windows'])
expect(serialWindows.name).toBe('serial / windows (self-hosted standby)')
// Aggregate: Wine `windows` required, native `windows-native` excluded.
expect(aggregate.needs).toContain('windows')
expect(aggregate.needs).not.toContain('windows-native')
expect(aggregate.needs).not.toContain('serial-windows')
})
it('keeps supported LSP source under native Windows coverage', () => {

View File

@@ -322,6 +322,7 @@ export const LINK_MAP: Readonly<Record<string, string>> = {
SessionLocation: 'persistence.md',
SessionPreparation: 'persistence.md',
SessionPersistenceSnapshot: 'persistence.md',
SessionRawArtifact: 'persistence.md',
ConfinedArgv: 'sandbox.md',
SandboxExecutionPolicy: 'sandbox.md',
SandboxMode: 'sandbox.md',

View File

@@ -32,7 +32,7 @@ import WebService from '@deepseek-ai/dsh-web'
import * as WebSearchExa from '@deepseek-ai/dsh-web-search-exa'
import * as WebFetchLocal from '@deepseek-ai/dsh-web-fetch-local'
import SubagentService from '@deepseek-ai/dsh-subagent'
import type { SubagentProvider } from '@deepseek-ai/dsh-subagent'
import type { SubagentProvider, SubagentReportDelivery } from '@deepseek-ai/dsh-subagent'
import * as ToolSubagentControl from '@deepseek-ai/dsh-tool-subagent-control'
import * as ToolSubagentListAgents from '@deepseek-ai/dsh-tool-subagent-control/list-agents'
import * as ToolSubagentReport from '@deepseek-ai/dsh-tool-subagent-report'
@@ -420,7 +420,7 @@ const TOOL_PACKAGES: ToolPackage[] = [
await ctx.plugin(ToolSubagent, { provider: 'mock' })
},
note:
'The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped example agents load this package once per subagent backend, so the model additionally sees `subagent_fork` (bound to the fork backend) with an identical schema — see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`.',
'The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped compositions load this package once per subagent backend, so the model additionally sees `subagent_fork` bound to the fork backend. Each instance\'s description and `run_in_background` parameter follow its own `backgroundMode` and `enableRunInBackground`, so the two shipped schemas are not identical: `subagent` is `continuable`, while `subagent_fork` stays `one-shot` — see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`.',
},
{
pkg: '@deepseek-ai/dsh-tool-subagent-control',
@@ -448,20 +448,22 @@ const TOOL_PACKAGES: ToolPackage[] = [
pkg: '@deepseek-ai/dsh-tool-subagent-report',
dir: 'tool-subagent-report',
source: 'packages/subagent/tool-subagent-report/src/index.ts',
requires: ['ctx.subagents', 'a live continuable in-process child Agent'],
requires: ['ctx.subagents', 'ctx.systemPrompt', 'a live continuable in-process child Agent'],
writes: ['tool/call', 'tool/result', 'a user-role message in the direct parent session'],
async mount(ctx) {
await ctx.plugin(AgentRegistry)
await ctx.plugin(SubagentService)
const { reportDelivery } = ToolSubagentReport.Config({}) as { reportDelivery: SubagentReportDelivery }
await mountCatalogChildScope(ctx, (childCtx) => {
ToolSubagentReport.installReportTool(childCtx, ctx, 'quiet')
ToolSubagentReport.installReportTool(childCtx, ctx, reportDelivery)
})
},
scope: ctx => catalogChildScopes.get(ctx) as Agent,
note:
'Registered per continuable in-process child rather than globally, so this schema is visible only '
+ 'inside such a child and survives its global `toolFilter`. The parent-facing `send_message` tool '
+ 'is installed independently.',
+ 'inside such a child and survives its global `toolFilter`. The same contribution installs the '
+ 'child-scoped `tool:report` prompt section, which this catalog does not render. The parent-facing '
+ '`send_message` tool is installed independently.',
},
{
pkg: '@deepseek-ai/dsh-tool-tasks',

View File

@@ -440,6 +440,11 @@
"symbol": "SessionLocation",
"source": "packages/session/session-persistence/src/index.ts"
},
{
"doc": "docs/subsystems/persistence.md",
"symbol": "SessionRawArtifact",
"source": "packages/session/session-persistence/src/index.ts"
},
{
"doc": "docs/subsystems/session-query.md",
"symbol": "SessionEventSurface",
@@ -1165,6 +1170,11 @@
"symbol": "SubagentReportDelivery",
"source": "packages/subagent/subagent/src/continuation.ts"
},
{
"doc": "docs/subsystems/subagent.md",
"symbol": "SubagentSettledMessageSource",
"source": "packages/subagent/subagent/src/continuation.ts"
},
{
"doc": "docs/subsystems/subagent.md",
"symbol": "SubagentReportOptions",