Merge remote-tracking branch 'origin/master' into xtr/identified-immutable-messages

# Conflicts:
#	docs/event-producer-consumer.md
#	packages/client/connection/src/client/fixture.ts
#	packages/goal/command-goal/tests/command-goal.spec.ts
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/host/apiproxy/src/api/events.schema.ts
#	packages/host/apiproxy/src/api/events.ts
#	packages/host/apiproxy/tests/api-proxy-view.spec.ts
#	packages/host/apiproxy/tests/rpc-schemas.spec.ts
#	tsconfig.base.json
This commit is contained in:
_Kerman
2026-07-28 18:11:13 +08:00
176 changed files with 4436 additions and 855 deletions
@@ -48,7 +48,7 @@ buffer
17| "│ │"
style 0-0 dim
style 55-55 dim
18| "│ Agent: idle · 6 events · 1 turn · 1 step · 1 │"
18| "│ Agent: idle · 7 events · 1 turn · 1 step · 1 │"
style 0-0 dim
style 3-12 fg=bright-black
style 55-55 dim
@@ -45,7 +45,7 @@ buffer
16| "│ │"
style 0-0 dim
style 81-81 dim
17| "│ Agent: idle · 6 events · 1 turn · 1 step · 1 tool call │"
17| "│ Agent: idle · 7 events · 1 turn · 1 step · 1 tool call │"
style 0-0 dim
style 3-12 fg=bright-black
style 81-81 dim
+6 -3
View File
@@ -1345,6 +1345,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
})
result.terminal.send('/clear')
result.terminal.send('\r')
await tick() // the executor logs command/run durably before the handler clears
appendAssistant(result.session, [{ type: 'text', text: 'answer after clear' }], undefined, { turn: 3, step: 1 })
await tick()
expect(result.terminal.output).toContain('answer after clear')
@@ -2216,7 +2217,8 @@ describe('pi-tui chat lifecycle and transcript', () => {
expect(result.terminal.output).toContain('/workspace/status')
expect(result.terminal.output).toContain('deepseek/deepseek-v4-pro (effort default; reasoning blocks')
expect(result.terminal.output).toContain('hidden)')
expect(result.terminal.output).toContain('running · 6 events · 1 turn · 1 step · 2 tool calls')
// 6 domain events + the /status invocation's own command/run (open turn: joined directly).
expect(result.terminal.output).toContain('running · 7 events · 1 turn · 1 step · 2 tool calls')
expect(result.terminal.output).toContain('1,250 input + 340 output')
expect(result.terminal.output).toContain('[███████████░░░░░] 67% hit (3,000 read + 250 write)')
expect(result.terminal.output).toContain('[█████░░░░░░░░░░░] 33% used (42,000 / 128,000)')
@@ -2257,7 +2259,8 @@ describe('pi-tui chat lifecycle and transcript', () => {
expect(result.terminal.output).toContain('untitled')
expect(result.terminal.output).toContain('unset (effort unset; reasoning blocks shown)')
expect(result.terminal.output).toContain('idle · 0 events · 0 turns · 0 steps · 0 tool calls')
// The /status invocation's command/run lands directly on the empty log — no turn wraps it.
expect(result.terminal.output).toContain('idle · 1 event · 0 turns · 0 steps · 0 tool calls')
expect(result.terminal.output).toContain('n/a (0 read + 0 write)')
expect(result.terminal.output).toContain('7 used · capacity unknown')
expect(result.terminal.output).toContain('2026-07-22 10:11:12 UTC')
@@ -2309,8 +2312,8 @@ describe('pi-tui chat lifecycle and transcript', () => {
for (const command of ['/clear', '/wat']) {
result.terminal.send(command)
result.terminal.send('\r')
await tick() // /clear's handler runs after the durable command/run append; keep it from wiping the next notice
}
await tick()
result.terminal.send('draft')
result.terminal.send('\x03')
result.terminal.send('\x04')