Merge branch 'stack/agent-profiles-5-web-ui' into stack/agent-profiles-8-authoring

# Conflicts:
#	apps/cli/tests/web-agent-presets.e2e.ts
#	packages/client/connection/README.i18n.yaml
#	packages/client/connection/README.md
#	packages/client/connection/README.zh.md
#	packages/client/ui-conversation/src/client/contract/slots.ts
#	packages/client/ui-primitives/tests/icons.spec.tsx
#	packages/client/ui-settings/src/client/contract/slots.ts
#	packages/host/apiproxy/tests/api-proxy-agent-preset.spec.ts
This commit is contained in:
Yichen Jiang
2026-08-09 23:02:37 +08:00
825 changed files with 2990 additions and 2066 deletions
@@ -226,10 +226,10 @@ describe('Enter semantics', () => {
})
})
describe('running and lock semantics (queue cut 1)', () => {
describe('running and lock semantics', () => {
it('running keeps the input free (typing + Enter queue) while the primary turns stop', () => {
const { textarea, button, stop, sink } = bench({ running: true, draft: '排队消息' })
expect(textarea.disabled).toBe(false) // running no longer locks
expect(textarea.disabled).toBe(false)
fireEvent.change(textarea, { target: { value: '排队消息2' } })
fireEvent.keyDown(textarea, { key: 'Enter' })
expect(sink).toHaveBeenCalledWith('排队消息2', 'queue')
@@ -429,8 +429,8 @@ describe('running and lock semantics (queue cut 1)', () => {
// scrollport element holds both layers.
expect(scroll.contains(textarea)).toBe(true)
expect(scroll.contains(backdrop)).toBe(true)
// The glyph layer carries the draft and nothing else: with one scrollport
// it no longer pads its own height to match a second box's scroll extent.
// The glyph layer carries the draft and nothing else — no height padding
// to a second box's scroll extent.
expect(backdrop.textContent).toBe('line\n'.repeat(40))
})
@@ -659,7 +659,7 @@ describe('decorations', () => {
expect(shell.snapshot.draft).toBe('参考 \uFFFC 内容')
})
it('a lexicon-matched plain token renders the text-ref mark (decision 21)', () => {
it('a lexicon-matched plain token renders the text-ref mark', () => {
const lexicon = new Map<'/' | '@', readonly string[]>([['/', ['fixture-demo']]])
const { view, shell } = bench({ lexicon })
act(() => { shell.setDraft('use /fixture-demo now') })
@@ -671,7 +671,7 @@ describe('decorations', () => {
})
})
describe('insertText (decision 21 scoped event body)', () => {
describe('insertText (scoped event body)', () => {
it('splices plain text over the span and reports success as true', () => {
const { shell } = bench({ draft: '/fix' })
const ok = shell.insertText('/fixture-demo ', { start: 0, end: 4, draftRev: shell.snapshot.draftRev })
@@ -721,7 +721,7 @@ describe('strips and variants', () => {
})
describe('command launcher chrome and control seats', () => {
it('renders the command launcher; the Access chip is absent without the permissions projection; the control seats render EMPTY without entries (B ruling)', () => {
it('renders the command launcher; the Access chip is absent without the permissions projection; the control seats render EMPTY without entries', () => {
const { view, slotCalls } = bench()
expect(view.getByLabelText('命令')).toBeTruthy()
// Capability absent (no projection value): the chip renders nothing.
@@ -1,6 +1,6 @@
/**
* InputMachine unit account (design §9.1, eng. plan §3.9-3.12): the submit
* plane carried over from the InputCore era (adjudication, span CAS, drift
* InputMachine unit account: the submit
* plane (adjudication, span CAS, drift
* guard, anti-backwash), plus the occurrence table (shift / whole-chip
* deletion / same-name independence), the self-managed undo log (typing
* coalescing, paste two-stage undo, redo chain), consume-token guards, the
@@ -625,7 +625,7 @@ describe('input-machine: projectClipboard', () => {
})
})
describe('decorations: scanTextRefs (decision 21)', () => {
describe('decorations: scanTextRefs', () => {
const LEX: ReadonlyMap<'/' | '@', readonly string[]> = new Map([
['/', ['commit-helper', 'fixture-demo']],
['@', ['worker-1']],
@@ -1,6 +1,6 @@
// @vitest-environment jsdom
/**
* Impact-matrix projection tests (design §5.2 影响矩阵, row by row): what each
* Impact-matrix projection tests (row by row): what each
* phase projects onto the InputBar — enter routing, visuals (token color /
* hint / pending), edit freedom, and the published currency's claim seat.
* React over jsdom per the client testing discipline; the machine is real.
@@ -184,7 +184,7 @@ describe('matrix row: locked (session disabled)', () => {
expect(shell.snapshot.phase).toBe('plain')
})
it('running does NOT lock (queue cut 1): typing and enter-queue stay live', () => {
it('running does NOT lock: typing and enter-queue stay live', () => {
const { textarea, sink } = bench({ running: true })
expect((textarea).disabled).toBe(false)
fireEvent.change(textarea, { target: { value: '排队' } })
@@ -1,6 +1,6 @@
// @vitest-environment jsdom
/**
* Scenario-chain integration (design §8 A/C/D/H/I): the real per-session
* Scenario-chain integration (scenarios A/C/D/H/I): the real per-session
* SlashController pipeline over a real session scope (SessionsService over
* a listed host session) + a command source implementing the decision
* table's relevant cells + the real SessionInput machine (scoped-event
@@ -34,7 +34,7 @@ interface FakeCommand {
input?: { hint: string }
}
/** T6 decision-table source over an in-memory directory (menu/space/enter columns for leadingInput + execute). */
/** Decision-table source over an in-memory directory (menu/space/enter columns for leadingInput + execute). */
function commandSource(commands: FakeCommand[], execute: (line: string) => Promise<SubmitOutcome>) {
const resolve = (name: string): FakeCommand | undefined => commands.find(c => c.name === name)
const leadingClaim = (desc: FakeCommand): CommandClaim => ({
@@ -86,8 +86,8 @@ describe('TodoPanel', () => {
it('marks every parallel active item, and counts them all in the header', () => {
render(<TodoPanel todos={PARALLEL} t={t} />)
fireEvent.click(screen.getByRole('button', { expanded: false }))
// The old unconditional cap made this list unreachable: three items carry
// the in-progress glyph at once, and the header counts all three.
// An unconditional in-progress cap would make this list unreachable: three
// items carry the in-progress glyph at once, and the header counts all three.
const statuses = screen.getAllByRole('listitem').map(li => li.getAttribute('data-status'))
expect(statuses.filter(s => s === 'in_progress')).toHaveLength(3)
expect(screen.getByText('跑后台构建')).toBeTruthy()