Files
Coder f27a0dcfb5
Some checks failed
CI / node 22.19 (push) Has been skipped
CI / node 26 (push) Has been skipped
CI / python 3.10 / keyless SDK (push) Has been skipped
CI / python runtime / release-shaped Linux x64 (push) Has been skipped
CI / windows node 24 / wine blocking (push) Has been skipped
CI / wine apt cache (push) Successful in 6s
CI / serial / linux (push) Has been skipped
Release (vendor) / Pack npm tarballs (push) Failing after 1m59s
Release (dsh) / Pack npm tarballs (push) Failing after 1m57s
Sandbox / sandbox e2e (landlock, ubuntu-24.04) (push) Failing after 1m59s
Sandbox / sandbox e2e (bwrap, ubuntu-latest) (push) Failing after 1m23s
Release (vendor) / Publish to npm (push) Has been skipped
Release (dsh) / Publish to npm (push) Has been skipped
CI / node 24 / static (push) Has been cancelled
CI / node 24 / coverage (push) Has been cancelled
CI / larger-runner-benchmark (16, windows, dsh-windows-2025-16core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (32, linux, dsh-ubuntu-24-04-32core, typecheck) (push) Has been cancelled
CI / serial / windows (self-hosted standby) (push) Has been cancelled
CI / larger-runner-benchmark (16, linux, dsh-ubuntu-24-04-16core, typecheck) (push) Has been cancelled
CI / node 24 / snapshots and artifacts (push) Has been cancelled
CI / windows node 24 / native complete (push) Has been cancelled
CI / serial / linux (self-hosted standby) (push) Has been cancelled
CI / serial / macos (push) Has been cancelled
CI / larger-runner-benchmark (32, windows, dsh-windows-2025-32core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (4, linux, dsh-ubuntu-24-04-4core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (4, windows, dsh-windows-2025-4core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (64, linux, dsh-ubuntu-24-04-64core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (64, windows, dsh-windows-2025-64core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (8, linux, dsh-ubuntu-24-04-8core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (8, windows, dsh-windows-2025-8core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (96, linux, dsh-ubuntu-24-04-96core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (96, windows, dsh-windows-2025-96core, production-site) (push) Has been cancelled
CI / consolidated-runner-benchmark (16, linux, dsh-ubuntu-24-04-16core, 16) (push) Has been cancelled
CI / consolidated-runner-benchmark (16, windows, dsh-windows-2025-16core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (32, linux, dsh-ubuntu-24-04-32core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (32, windows, dsh-windows-2025-32core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (4, linux, dsh-ubuntu-24-04-4core, 4) (push) Has been cancelled
CI / consolidated-runner-benchmark (4, windows, dsh-windows-2025-4core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (64, linux, dsh-ubuntu-24-04-64core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (64, windows, dsh-windows-2025-64core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (8, linux, dsh-ubuntu-24-04-8core, 8) (push) Has been cancelled
CI / consolidated-runner-benchmark (8, windows, dsh-windows-2025-8core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (96, linux, dsh-ubuntu-24-04-96core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (96, windows, dsh-windows-2025-96core, 2) (push) Has been cancelled
CI / all checks passed (push) Has been cancelled
Sandbox / sandbox e2e (seatbelt, macos-latest) (push) Has been cancelled
Sandbox / sandbox e2e (landlock, ubuntu-24.04-arm) (push) Has been cancelled
E2E (real DeepSeek API) / e2e (push) Failing after 1m36s
fix(cordis-host-runner): make inspect provider registration idempotent on identical manifest
The Host cordisInspect registry threw on any duplicate provider id, but
tool-cordis is mounted per-preset (standing scope), so two presets that
both include it (e.g. `maximum` and a user copy such as `design`) collide.

`register()` now replaces the stored entry when the incoming manifest is
structurally identical (same id, description, and methods); a provider
with the same id but a different manifest still throws as before.

Added `jsonEqual` and `sameManifest` module-private helpers; new spec
covers first register, identical re-register, different-manifest reject,
empty-id validation, and method-array mismatch.
2026-08-27 14:03:40 +07:00

87 lines
3.3 KiB
TypeScript

import { Context } from '@deepseek-ai/cordis'
import { describe, expect, it } from 'vitest'
import { CordisInspectRegistryService, type HostCordisInspectProviderRegistration } from '../src/inspect-registry.ts'
function makeProvider(id: string, desc: string): HostCordisInspectProviderRegistration {
return {
manifest: {
id,
description: desc,
methods: [{
name: 'list',
description: 'List things.',
inputSchema: { type: 'object', properties: {}, additionalProperties: false },
outputSchema: { description: 'anything' },
}],
},
async query() { return {} },
}
}
describe('CordisInspectRegistryService', () => {
it('accepts the first registration of a provider id', () => {
const ctx = new Context()
const svc = new CordisInspectRegistryService(ctx)
const p = makeProvider('Service', 'desc')
const dispose = svc.register(p)
expect(svc.list()).toContainEqual(expect.objectContaining({ id: 'Service', platform: 'host' }))
dispose()
expect(svc.list()).not.toContainEqual(expect.objectContaining({ id: 'Service' }))
})
it('replaces on identical re-registration without throwing', () => {
const ctx = new Context()
const svc = new CordisInspectRegistryService(ctx)
const p = makeProvider('Service', 'desc')
const disposeA = svc.register(p)
const disposeB = svc.register(p) // same object — identical manifest
// Still in the directory (replaced, not removed)
expect(svc.list()).toContainEqual(expect.objectContaining({ id: 'Service', platform: 'host' }))
// disposeA should be a no-op because the map entry was replaced
disposeA()
expect(svc.list()).toContainEqual(expect.objectContaining({ id: 'Service', platform: 'host' }))
// disposeB removes the current registration
disposeB()
expect(svc.list()).not.toContainEqual(expect.objectContaining({ id: 'Service' }))
})
it('rejects a different manifest claiming the same id', () => {
const ctx = new Context()
const svc = new CordisInspectRegistryService(ctx)
svc.register(makeProvider('Service', 'original'))
expect(() => svc.register(makeProvider('Service', 'different')))
.toThrow('Host Cordis inspect provider "Service" is already registered')
})
it('rejects empty provider id', () => {
const ctx = new Context()
const svc = new CordisInspectRegistryService(ctx)
expect(() => svc.register(makeProvider('', 'empty')))
.toThrow('Cordis inspect provider id must not be empty')
})
it('detects method-array length mismatch as unequal', () => {
const ctx = new Context()
const svc = new CordisInspectRegistryService(ctx)
const a: HostCordisInspectProviderRegistration = {
manifest: {
id: 'X', description: 'd',
methods: [{ name: 'a', description: 'a', inputSchema: {}, outputSchema: {} }],
},
async query() { return {} },
}
const b: HostCordisInspectProviderRegistration = {
manifest: {
id: 'X', description: 'd',
methods: [
{ name: 'a', description: 'a', inputSchema: {}, outputSchema: {} },
{ name: 'b', description: 'b', inputSchema: {}, outputSchema: {} },
],
},
async query() { return {} },
}
svc.register(a)
expect(() => svc.register(b)).toThrow('already registered')
})
})