refactor(pty): rename model-facing tools to terminal_* and harden teardown

Rename the six model-facing tools pty_* -> terminal_* and align every
description, guidance section, ACP card title, and rendered result to
terminal terminology. Package and service internals keep their technical
PTY names (PtyService, "unknown PTY session", node-pty).

Harden the local backend teardown:
- a failed close is retryable: drop the memoized rejection so a later
  terminal_close re-runs against the live process table
- service disposal clears the backend, reservation, and owner-cleanup
  registries even when a close fails
- stop readiness polling before teardown so an in-flight send settles as
  session_exit instead of a mis-inferred wait reason
- bound the sanitizer's pending buffer against unterminated escape runs

Update the tool catalog, package READMEs, the bilingual Agent Note, and the
acp/headless pty-tools snapshots to match.
This commit is contained in:
NI0317
2026-07-21 19:29:56 +08:00
parent 85ac747208
commit a7bfade7eb
28 changed files with 568 additions and 401 deletions

View File

@@ -331,12 +331,18 @@ export class PtyService extends Service {
private async disposeAll(): Promise<void> {
this.disposing = true
const records = [...this.sessions.values()]
await this.closeRecords(records, 'PTY service disposed')
this.backends.clear()
this.reservedNames.clear()
const cleanups = [...this.ownerCleanups.values()]
this.ownerCleanups.clear()
await Promise.all(cleanups.map(cleanup => Promise.resolve(cleanup())))
// Teardown is best-effort: a close failure still clears registries and runs
// owner cleanups before the aggregated error propagates, so one stuck
// session cannot orphan backends, reservations, or owner detachers.
try {
await this.closeRecords(records, 'PTY service disposed')
} finally {
this.backends.clear()
this.reservedNames.clear()
const cleanups = [...this.ownerCleanups.values()]
this.ownerCleanups.clear()
await Promise.all(cleanups.map(cleanup => Promise.resolve(cleanup())))
}
}
private async closeRecords(records: SessionRecord[], reason: string): Promise<void> {