Merge remote-tracking branch 'origin/master' into codex/project-instruction-files

# Conflicts:
#	AGENTS.md
#	docs/config-catalog.md
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.md
#	docs/event-producer-consumer.md
#	docs/persistence-catalog.md
#	docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md
#	docs/rfc/implemented/feature/2026-06-15-code-mode.md
#	docs/rfc/implemented/feature/2026-06-30-hook-bridges.md
#	docs/rfc/implemented/feature/2026-06-30-interception-seams.md
#	docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md
#	docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md
#	examples/AGENTS.md
#	examples/acp-agent/cordis.yml
#	examples/acp-agent/tests/acp.snapshot.ts
#	examples/echo-agent/cordis.yml
#	examples/sandbox-acp-agent/cordis.yml
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/core/agent-core/README.md
#	packages/core/agent-core/src/index.ts
#	packages/core/agent-loop/README.md
#	packages/core/agent-loop/src/loop.ts
#	packages/core/agent-loop/tests/interception.spec.ts
#	packages/core/agent/src/types.ts
#	packages/core/tools/README.md
#	packages/core/tools/src/code-mode.ts
#	packages/core/tools/src/index.ts
#	packages/fs/fs-local/src/index.ts
#	packages/fs/fs/README.md
#	packages/fs/fs/src/index.ts
#	packages/guard/repeat-tool-guard/README.md
#	packages/guard/repeat-tool-guard/src/index.ts
#	packages/hooks/hooks-claude/src/index.ts
#	packages/hooks/hooks-codex/src/index.ts
#	packages/ui/acp-agent/src/index.ts
This commit is contained in:
Yichen Jiang
2026-07-14 19:50:25 +08:00
720 changed files with 21199 additions and 14129 deletions

View File

@@ -774,16 +774,9 @@ describe('ToolRegistry', () => {
})
it('register() returns the EXACT effect disposer: a composite yield nests the teardown in order', async () => {
// The registry-disposer convention (set by agents.register): the returned
// function IS the cordis effect disposer, so a composite (generator)
// effect that yields it has the unregistration run at that yield's LIFO
// position on owner unload. A wrapper would leave the inner effect
// disposing as a CONCURRENT SIBLING of the composite; the async probe
// below (disposed first, LIFO) yields the event loop exactly like the
// agent factory's stop-and-drain link, and a sibling unregistration fires
// in that window — the probe would observe the tool already gone. Pins
// the convention for the whole register-method family (system-prompt
// registrars, registerProvider, setFactory share the same return).
// Registry methods return the exact Cordis effect disposer so a composite yield places
// unregistration at its LIFO position. A wrapper would create a concurrent sibling; this async
// probe yields during earlier teardown and would then observe the tool already removed.
const ctx = await setup()
const order: string[] = []
const fiber = await ctx.plugin(Object.assign((inner: Context) => {
@@ -1070,20 +1063,18 @@ describe('schema DSL edge cases', () => {
port: { type: 'number' },
},
})
// no 'required' key in the nested object because nothing is required
const config = jsonSchema.properties['config'] as Record<string, unknown>
expect('required' in config).toBe(false)
})
})
describe('schema DSL regressions (Codex review round 2)', () => {
describe('schema DSL optional and nested contracts', () => {
it('InferArgs makes non-required keys genuinely optional (omittable)', () => {
type Args = InferArgs<{
path: { type: 'string'; required: true }
limit: { type: 'number' }
}>
expectTypeOf<Args>().toEqualTypeOf<{ path: string; limit?: number }>()
// omitting the optional key is assignable — the actual regression
const omitted: Args = { path: '/tmp' }
expect(omitted.limit).toBeUndefined()
})