fix inbox lifecycle downstream contracts

This commit is contained in:
_Kerman
2026-07-31 22:00:39 +08:00
parent 8e88b17c9f
commit afedf18ccf
219 changed files with 5660 additions and 4556 deletions

View File

@@ -1174,7 +1174,7 @@ function renderLifecycle(): string {
` Driver->>Hooks: ${mermaidCode('agent/pre-step')} waterfall`,
' Hooks-->>Driver: authoritative reject or enter(messages)',
' alt proposed step rejected or pre-step failed',
' Driver-->>Driver: claimed batch stays removed; no turn opens',
' Driver-->>Driver: claimed batch stays removed, no turn opens',
' else enter proposed step',
` Driver->>Session: ${mermaidCode('turn/start')}`,
` Driver->>Session: ${mermaidCode('step/start')}`,

View File

@@ -296,7 +296,7 @@ const TOOL_PACKAGES: ToolPackage[] = [
dir: 'tool-goal',
source: 'packages/goal/tool-goal/src/index.ts',
requires: ['ctx.tools', 'ctx.agents', 'ctx.goals', 'ctx.systemPrompt', 'a calling Agent in an authorized open turn'],
writes: ['tool/call', 'user/message goal snapshot for mutations', 'tool/result'],
writes: ['tool/call', 'agent/inbox/spliced goal snapshot for mutations', 'tool/result'],
async mount(ctx) {
await ctx.plugin(AgentRegistry)
await ctx.plugin(GoalService)

View File

@@ -3,6 +3,7 @@ import { randomUUID } from 'node:crypto'
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'
import { spawnSync } from 'node:child_process'
import { dirname, isAbsolute, join, resolve } from 'node:path'
import lefthookPackage from 'lefthook/package.json' with { type: 'json' }
const MINIMUM_GIT = [2, 26, 0]
const HOOKS_DIRECTORY = 'dsh-hooks'
@@ -533,6 +534,7 @@ function refuseScopedHooksPath(entry) {
async function main() {
if (process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true') return
if (typeof lefthookPackage.bin?.lefthook !== 'string') return
const probe = spawnSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf8' })
if (probe.status !== 0) return
const root = stripGitLineTerminator(probe.stdout)

View File

@@ -19,6 +19,9 @@ import { afterEach, describe, expect, it } from 'vitest'
const installer = fileURLToPath(new URL('./install-lefthook.mjs', import.meta.url))
const fixtures: string[] = []
// Multi-worktree cases spawn several Git and Node subprocesses; coverage concurrency can
// legitimately exceed Vitest's default deadline without changing the installer behavior.
const MULTI_PROCESS_TEST_TIMEOUT_MS = 20_000
interface Fixture {
container: string
@@ -260,7 +263,7 @@ describe('worktree-local Lefthook installer', () => {
git(fixture, fixture.main, ['worktree', 'remove', '--force', fixture.linked])
expect(readFileSync(join(mainHooks, 'pre-commit'), 'utf8')).toBe(mainHookBeforeRemoval)
expect(readFileSync(legacyHook, 'utf8')).toBe('#!/bin/sh\n# legacy hook\n')
})
}, MULTI_PROCESS_TEST_TIMEOUT_MS)
it('replaces the owned hook path Git copies into a newly added worktree', async () => {
const fixture = createFixture()
@@ -284,7 +287,7 @@ describe('worktree-local Lefthook installer', () => {
'# config=late-linked-worktree-config',
)
expect(readFileSync(join(mainHooks, 'pre-commit'), 'utf8')).toBe(mainHookBefore)
})
}, MULTI_PROCESS_TEST_TIMEOUT_MS)
it('serializes concurrent installs and keeps repeated output stable', async () => {
const fixture = createFixture()
@@ -305,7 +308,7 @@ describe('worktree-local Lefthook installer', () => {
expect(readFileSync(mainHookPath, 'utf8')).toBe(initialHook)
expect(existsSync(join(commonDirectory(fixture), 'dsh-lefthook-install.lock'))).toBe(false)
expect(existsSync(join(hooksPath(fixture, fixture.main), '.fake-lefthook-running'))).toBe(false)
})
}, MULTI_PROCESS_TEST_TIMEOUT_MS)
it('repairs its owned absolute hook path after the checkout moves', async () => {
const fixture = createFixture()
@@ -327,7 +330,7 @@ describe('worktree-local Lefthook installer', () => {
expect(readFileSync(join(movedHooks, '.dsh-lefthook-owned'), 'utf8')).toContain(
JSON.stringify(movedHooks),
)
})
}, MULTI_PROCESS_TEST_TIMEOUT_MS)
it.skipIf(process.platform === 'win32')('refuses a multiply linked ownership marker before relocation rewrites it', async () => {
const fixture = createFixture()
@@ -368,7 +371,7 @@ describe('worktree-local Lefthook installer', () => {
expect(result.stderr).toContain('non-regular or multiply linked hook entry')
expect(readFileSync(externalHook, 'utf8')).toBe(externalContent)
}
})
}, MULTI_PROCESS_TEST_TIMEOUT_MS)
it('restores the marker-backed stale hook path when relocation reinstall fails', async () => {
const fixture = createFixture()