fix(ui): surface declarative startup failures

This commit is contained in:
Turtle
2026-07-17 16:44:25 +08:00
parent 1119c537d0
commit 12b7ac67ba
20 changed files with 484 additions and 72 deletions

View File

@@ -23,7 +23,7 @@ Each run starts a fresh session by default (its event log lands under `./.sessio
RESUME_SESSION_ID=<prior-session-id> pnpm run demo:repl
```
The id is wired through `cordis.yml` (`resumeSessionId: !!js process.env.RESUME_SESSION_ID`); unset, the agent starts a new session. A missing or unreadable id starts no `main` agent, so unset it or choose an existing session id.
The id is wired through `cordis.yml` (`resumeSessionId: !!js process.env.RESUME_SESSION_ID`); unset, the agent starts a new session. A missing or unreadable id starts no `main` agent and emits `agent/start-failed`; both terminal front doors print the failure and exit nonzero, so unset it or choose an existing session id.
## Code Mode

View File

@@ -13,7 +13,7 @@ const tsxLoader = fileURLToPath(import.meta.resolve('tsx'))
const PTY_DRIVER = String.raw`
import errno, os, pty, select, signal, sys, time
node, tsx_loader, bin_script, config_path, tsconfig_path, cwd = sys.argv[1:]
node, tsx_loader, bin_script, config_path, tsconfig_path, cwd, resume_session_id = sys.argv[1:]
env = os.environ.copy()
env.update({
"DEEPSEEK_API_KEY": "keyless-tui-no-call",
@@ -21,6 +21,8 @@ env.update({
"DSH_AGENTS_HOME": os.path.join(cwd, ".agents"),
"TSX_TSCONFIG_PATH": tsconfig_path,
})
if resume_session_id:
env["RESUME_SESSION_ID"] = resume_session_id
pid, fd = pty.fork()
if pid == 0:
os.chdir(cwd)
@@ -53,15 +55,23 @@ if status is None:
os.kill(pid, signal.SIGKILL)
_, status = os.waitpid(pid, 0)
sys.stdout.buffer.write(output)
if not sent_exit:
sys.stderr.write("TUI did not render its welcome marker before timeout\n")
sys.exit(124)
if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
sys.stderr.write("TUI child did not exit cleanly\n")
sys.exit(125)
if resume_session_id:
if b'ui-tui: agent "main" failed to start:' not in output:
sys.stderr.write("TUI did not render the startup failure before timeout\n")
sys.exit(126)
if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 1:
sys.stderr.write("TUI startup failure did not exit with status 1\n")
sys.exit(127)
else:
if not sent_exit:
sys.stderr.write("TUI did not render its welcome marker before timeout\n")
sys.exit(124)
if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
sys.stderr.write("TUI child did not exit cleanly\n")
sys.exit(125)
`
async function runTuiLoaderSmoke(): Promise<string> {
async function runTuiLoaderSmoke(resumeSessionId = ''): Promise<string> {
const cwd = await mkdtemp(join(tmpdir(), 'coding-tui-smoke-'))
try {
return await new Promise((resolve, reject) => {
@@ -74,6 +84,7 @@ async function runTuiLoaderSmoke(): Promise<string> {
configPath,
tsconfigPath,
cwd,
resumeSessionId,
], { stdio: ['ignore', 'pipe', 'pipe'] })
let stdout = ''
let stderr = ''
@@ -98,4 +109,10 @@ describe('coding-agent TUI keyless smoke (real Loader tree in a PTY)', () => {
expect(output).toContain('DEEPSEEK')
expect(output).toContain('agent REPL ready.')
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
it('prints a config-resume failure and exits instead of leaving a blank terminal', async () => {
const output = await runTuiLoaderSmoke('missing-session')
expect(output).toContain('ui-tui: agent "main" failed to start:')
expect(output).toContain('missing-session')
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
})