New top-level packages/cordis/ group with the self-referential toolset: cordis_inspect (services / plugin tree / tools / dynamic mounts / api / events, the api section intersecting the generated catalog with the live service store), cordis_mount (model-written code evaluated in a node:vm sandbox, mounted under one cordis-dynamic group fiber as dyn-<n>), cordis_unmount (awaited disposal to quiescence). Boundary mechanisms: dual-realm instanceof, JSON realm normalization of dynamic tool results, marker-guarded registration, SchemaSpec teaching errors, parse failures surfaced with the offending line + caret and a line-scoped TypeScript hint, and the unmount-first recipe on tool-name collisions. Config: vmTimeoutMs (schemastery, default 5000). Design record: docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md. The tool-catalog boot manifest, its regenerated output, and the pinned tool-name list land here rather than with the other repo registration: the completeness guard globs packages/*/tool-* and fails the generator (and the core/tools spec) the moment the package directory exists.
106 lines
5.3 KiB
TypeScript
106 lines
5.3 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { call, CONSUMER_CODE, PROVIDER_CODE, setup, text } from './helpers.ts'
|
|
|
|
/**
|
|
* Cross-mount composition through ordinary cordis provide/inject semantics:
|
|
* one mount provides a service, another injects it, and mount ids stay the
|
|
* lifecycle handles. Every assertion is against the WORLD — the registry, the
|
|
* service store, real tool dispatch — not the tool's own summary line.
|
|
*/
|
|
|
|
describe('cross-mount provide/inject', () => {
|
|
it('provider first: the consumer activates immediately and its tool reaches the provided service', async () => {
|
|
const ctx = await setup()
|
|
const provider = await call(ctx, 'cordis_mount', { code: PROVIDER_CODE })
|
|
expect(text(provider)).toContain('state: active')
|
|
|
|
const consumer = await call(ctx, 'cordis_mount', { code: CONSUMER_CODE })
|
|
expect(consumer.isError).toBe(false)
|
|
expect(text(consumer)).toContain('state: active')
|
|
|
|
// The vm-realm service value is callable across mounts, and the result
|
|
// normalizes into the host realm like any dynamic tool result.
|
|
const greeted = await call(ctx, 'greet', { name: 'harness' })
|
|
expect(greeted.isError).toBe(false)
|
|
expect(text(greeted)).toBe('hi harness')
|
|
})
|
|
|
|
it('consumer first: stays pending naming the missing service, then activates when the provider mounts', async () => {
|
|
const ctx = await setup()
|
|
const consumer = await call(ctx, 'cordis_mount', { code: CONSUMER_CODE })
|
|
expect(consumer.isError).toBe(false)
|
|
expect(text(consumer)).toContain('state: pending')
|
|
expect(text(consumer)).toContain('waiting for service(s): greeter')
|
|
expect(text(await call(ctx, 'cordis_inspect', { what: 'dynamic' }))).toContain('waiting for: greeter')
|
|
expect(ctx.tools.get('greet')).toBeUndefined()
|
|
|
|
await call(ctx, 'cordis_mount', { code: PROVIDER_CODE })
|
|
expect(ctx.tools.get('greet')).toBeDefined()
|
|
expect(text(await call(ctx, 'greet', { name: 'late' }))).toBe('hi late')
|
|
})
|
|
|
|
it('unmounting the provider sends the consumer back to pending and unwinds its registrations', async () => {
|
|
const ctx = await setup()
|
|
await call(ctx, 'cordis_mount', { code: PROVIDER_CODE }) // dyn-1
|
|
await call(ctx, 'cordis_mount', { code: CONSUMER_CODE }) // dyn-2
|
|
expect(ctx.tools.get('greet')).toBeDefined()
|
|
|
|
const unmounted = await call(ctx, 'cordis_unmount', { id: 'dyn-1' })
|
|
expect(unmounted.isError).toBe(false)
|
|
expect(ctx.tools.get('greet')).toBeUndefined()
|
|
const report = text(await call(ctx, 'cordis_inspect', { what: 'dynamic' }))
|
|
expect(report).toContain('dyn-2: greeter-consumer [pending] — waiting for: greeter')
|
|
})
|
|
|
|
it('re-providing the service re-runs the consumer through the same guard (active again, tool back)', async () => {
|
|
const ctx = await setup()
|
|
await call(ctx, 'cordis_mount', { code: PROVIDER_CODE }) // dyn-1
|
|
await call(ctx, 'cordis_mount', { code: CONSUMER_CODE }) // dyn-2
|
|
await call(ctx, 'cordis_unmount', { id: 'dyn-1' })
|
|
expect(ctx.tools.get('greet')).toBeUndefined()
|
|
|
|
await call(ctx, 'cordis_mount', { code: PROVIDER_CODE }) // dyn-3
|
|
expect(ctx.tools.get('greet')).toBeDefined()
|
|
expect(text(await call(ctx, 'greet', { name: 'again' }))).toBe('hi again')
|
|
expect(text(await call(ctx, 'cordis_inspect', { what: 'dynamic' }))).toContain('dyn-2: greeter-consumer [active]')
|
|
})
|
|
|
|
it('a duplicate provide fails loud with the owning fiber named, and the failed mount is disposed', async () => {
|
|
const ctx = await setup()
|
|
await call(ctx, 'cordis_mount', { code: PROVIDER_CODE })
|
|
const duplicate = await call(ctx, 'cordis_mount', { code: PROVIDER_CODE })
|
|
expect(duplicate.isError).toBe(true)
|
|
expect(text(duplicate)).toContain('has been registered')
|
|
const report = text(await call(ctx, 'cordis_inspect', { what: 'dynamic' }))
|
|
expect(report).toContain('dyn-1: greeter-provider')
|
|
expect(report).not.toContain('dyn-2')
|
|
})
|
|
|
|
it('inspect surfaces the linkage: provides on the provider row, the service in services and api sections', async () => {
|
|
const ctx = await setup()
|
|
await call(ctx, 'cordis_mount', { code: PROVIDER_CODE })
|
|
await call(ctx, 'cordis_mount', { code: CONSUMER_CODE })
|
|
|
|
const dynamic = text(await call(ctx, 'cordis_inspect', { what: 'dynamic' }))
|
|
expect(dynamic).toContain('dyn-1: greeter-provider [active] — provides: greeter')
|
|
|
|
const services = text(await call(ctx, 'cordis_inspect', { what: 'services' }))
|
|
expect(services).toContain('- greeter (provided by greeter-provider)')
|
|
|
|
const api = text(await call(ctx, 'cordis_inspect', { what: 'api' }))
|
|
expect(api).toContain('- greeter (provided by greeter-provider, no catalog entry)')
|
|
})
|
|
|
|
it('unmounting the consumer leaves the provider and its service intact', async () => {
|
|
const ctx = await setup()
|
|
await call(ctx, 'cordis_mount', { code: PROVIDER_CODE }) // dyn-1
|
|
await call(ctx, 'cordis_mount', { code: CONSUMER_CODE }) // dyn-2
|
|
await call(ctx, 'cordis_unmount', { id: 'dyn-2' })
|
|
|
|
expect(ctx.tools.get('greet')).toBeUndefined()
|
|
const services = text(await call(ctx, 'cordis_inspect', { what: 'services' }))
|
|
expect(services).toContain('- greeter (provided by greeter-provider)')
|
|
expect(text(await call(ctx, 'cordis_inspect', { what: 'dynamic' }))).toContain('dyn-1: greeter-provider [active]')
|
|
})
|
|
})
|