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:
@@ -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', () => {
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user