Merge remote-tracking branch 'origin/master' into worktree/skill-invocation-controls

# Conflicts:
#	packages/host/apiproxy/README.i18n.yaml
#	packages/host/apiproxy/README.md
#	packages/host/apiproxy/README.zh.md
#	packages/host/apiproxy/src/api-proxy.ts
This commit is contained in:
Yichen Jiang
2026-07-28 18:00:40 +08:00
136 changed files with 3689 additions and 576 deletions

View File

@@ -1107,12 +1107,12 @@ export function createTuiChat(
const controller = new AbortController()
commandControllers.add(controller)
void ctx.commands.execute(agent, text, controller.signal).then(
(result) => {
(execution) => {
if (disposed) return
if (result === undefined) {
if (execution === undefined) {
appendNotice(`Unknown command: ${text}`, 'warning')
} else if (result.text !== undefined && result.text !== '') {
appendNotice(result.text, result.kind === 'error' ? 'error' : 'info')
} else if (execution.result.text !== undefined && execution.result.text !== '') {
appendNotice(execution.result.text, execution.result.kind === 'error' ? 'error' : 'info')
}
},
(error: unknown) => {

View File

@@ -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

View File

@@ -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

View File

@@ -1309,6 +1309,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')
@@ -2139,7 +2140,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)')
@@ -2180,7 +2182,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')
@@ -2232,8 +2235,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')