fix(gates): recognize scoped executor composition
This commit is contained in:
1 parent
ebd6a9cf79
commit
f0987e7f31
3 files changed
+26
-5
No files matched your search
@@ -16,6 +16,7 @@ export interface ProductPackagePolicy {
|
||||
* Optional integrations may be reached by an optional bundle without becoming default capabilities.
|
||||
*/
|
||||
export const PRODUCT_PACKAGE_POLICY: Readonly<Record<string, ProductPackagePolicy>> = {
|
||||
'packages/core/agent-tool-presentation': { category: 'optional', reason: 'Deprecated selector retained for existing executor configurations.' },
|
||||
'packages/browser-use/browser-use': { category: 'optional', reason: 'Service definition used by explicitly selected browser providers.' },
|
||||
'packages/computer-use/computer-use': { category: 'optional', reason: 'Service definition used by explicitly selected computer providers.' },
|
||||
'packages/lsp/lsp': { category: 'optional', reason: 'Service definition for deployment-configured language servers.' },
|
||||
|
||||
@@ -11,6 +11,7 @@ import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
bundleManifestPaths,
|
||||
bundlePluginDependencyErrors,
|
||||
exclusivePlaneRowIds,
|
||||
metadataExpressionErrors,
|
||||
packageTestFixtureDependencyErrors,
|
||||
packageTestPluginDependencyErrors,
|
||||
@@ -48,6 +49,17 @@ describe('verify-cordis-config metadata expressions', () => {
|
||||
})
|
||||
|
||||
describe('workspace Bundle discovery and product dependency closures', () => {
|
||||
it('allows scoped executors on both planes while retaining other plugin rows', () => {
|
||||
expect([...exclusivePlaneRowIds([{ insert: [
|
||||
{ id: 'native', name: '@deepseek-ai/dsh-tool-executor-native' },
|
||||
{ id: 'ptc', name: '@deepseek-ai/dsh-tool-executor-ptc' },
|
||||
{ id: 'tools', name: '@deepseek-ai/dsh-tools' },
|
||||
{ id: 'group', name: 'cordis:group', group: true, config: [
|
||||
{ id: 'tool-executor-ptc', name: '@deepseek-ai/dsh-tool-fs' },
|
||||
] },
|
||||
] }])]).toEqual(['tools', 'group', 'tool-executor-ptc'])
|
||||
})
|
||||
|
||||
it('discovers a Bundle outside packages/bundle from its manifest declaration', () => {
|
||||
const fixture = mkdtempSync(join(tmpdir(), 'dsh-bundle-discovery-'))
|
||||
try {
|
||||
|
||||
@@ -119,7 +119,8 @@ function validateClientHalvesDeclared(): string[] {
|
||||
}
|
||||
|
||||
/**
|
||||
* No shipped agent preset may repeat a row the host composition still runs.
|
||||
* No shipped agent preset may repeat an unscoped row the host composition still runs.
|
||||
* Tool executors select through the mounting scope and may appear on both planes.
|
||||
*
|
||||
* A preset contributes what ONE session adds to the host's registries. A row
|
||||
* active on both planes is therefore mounted twice — once per process and once
|
||||
@@ -157,7 +158,7 @@ function validatePresetPlaneSeparation(): string[] {
|
||||
const active = new Set([...rowIds(hostFile), ...overlayRows].filter(id => !disabled.has(id)))
|
||||
for (const file of overlayFiles) {
|
||||
for (const definition of presetDefinitions(loadEntries(file))) {
|
||||
for (const id of collectRowIds(definition.plugins)) {
|
||||
for (const id of exclusivePlaneRowIds(definition.plugins)) {
|
||||
if (active.has(id)) problems.push(`${file}#${definition.id}: row "${id}" is also active in the host composition; a row belongs to exactly one plane`)
|
||||
}
|
||||
}
|
||||
@@ -178,10 +179,15 @@ function loadEntries(file: string): unknown[] {
|
||||
* @returns the declared ids.
|
||||
*/
|
||||
function rowIds(file: string): Set<string> {
|
||||
return collectRowIds(loadEntries(file))
|
||||
return exclusivePlaneRowIds(loadEntries(file))
|
||||
}
|
||||
|
||||
function collectRowIds(rows: unknown): Set<string> {
|
||||
/**
|
||||
* Collect rows that cannot be shared between the host and a preset.
|
||||
* @param rows - parsed Loader entries, including inserts and groups.
|
||||
* @returns ids excluding the executor plugins whose registrations are scope-owned.
|
||||
*/
|
||||
export function exclusivePlaneRowIds(rows: unknown): Set<string> {
|
||||
const ids = new Set<string>()
|
||||
const walk = (value: unknown): void => {
|
||||
if (isUnknownArray(value)) {
|
||||
@@ -189,7 +195,9 @@ function collectRowIds(rows: unknown): Set<string> {
|
||||
return
|
||||
}
|
||||
if (!isRecord(value)) return
|
||||
if (typeof value.id === 'string' && typeof value.name === 'string') ids.add(value.id)
|
||||
if (typeof value.id === 'string' && typeof value.name === 'string'
|
||||
&& value.name !== '@deepseek-ai/dsh-tool-executor-native'
|
||||
&& value.name !== '@deepseek-ai/dsh-tool-executor-ptc') ids.add(value.id)
|
||||
walk(value.insert)
|
||||
if (isCordisGroupEntry(value)) walk(value.config)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user