* Stops the CLI server and closes all active sessions. * * This method performs graceful cleanup: * 1. Closes all active sessions (releases in-memory resources) * 2. Requests runtime shutdown for SDK-owned CLI processes * 3. Closes the JSON-RPC connection * 4. Terminate
()
| 852 | * ``` |
| 853 | */ |
| 854 | async stop(): Promise<Error[]> { |
| 855 | const errors: Error[] = []; |
| 856 | |
| 857 | // Disconnect all active sessions with retry logic |
| 858 | const activeSessions = [...this.sessions.values()]; |
| 859 | for (const session of activeSessions) { |
| 860 | const sessionId = session.sessionId; |
| 861 | let lastError: Error | null = null; |
| 862 | |
| 863 | // Try up to 3 times with exponential backoff |
| 864 | for (let attempt = 1; attempt <= 3; attempt++) { |
| 865 | try { |
| 866 | await session.disconnect(); |
| 867 | lastError = null; |
| 868 | break; // Success |
| 869 | } catch (error) { |
| 870 | lastError = error instanceof Error ? error : new Error(String(error)); |
| 871 | |
| 872 | if (attempt < 3) { |
| 873 | // Exponential backoff: 100ms, 200ms |
| 874 | const delay = 100 * Math.pow(2, attempt - 1); |
| 875 | await new Promise((resolve) => setTimeout(resolve, delay)); |
| 876 | } |
| 877 | } |
| 878 | } |
| 879 | |
| 880 | if (lastError) { |
| 881 | errors.push( |
| 882 | new Error( |
| 883 | `Failed to disconnect session ${sessionId} after 3 attempts: ${lastError.message}` |
| 884 | ) |
| 885 | ); |
| 886 | } |
| 887 | } |
| 888 | for (const session of activeSessions) { |
| 889 | session._markDisconnected(); |
| 890 | } |
| 891 | this.sessions.clear(); |
| 892 | |
| 893 | // Ask SDK-owned runtimes to flush and clean up before we tear down |
| 894 | // their transport/process. External runtimes may be shared, so only |
| 895 | // close our connection to them. |
| 896 | if (this.connection && this.cliProcess && !this.isExternalServer) { |
| 897 | const runtimeShutdownStart = Date.now(); |
| 898 | const shutdownPromise = this.rpc.runtime.shutdown(); |
| 899 | void shutdownPromise.catch(() => undefined); |
| 900 | try { |
| 901 | await withTimeout( |
| 902 | shutdownPromise, |
| 903 | RUNTIME_SHUTDOWN_TIMEOUT_MS, |
| 904 | `runtime.shutdown timed out after ${RUNTIME_SHUTDOWN_TIMEOUT_MS}ms` |
| 905 | ); |
| 906 | this.logDebugTiming( |
| 907 | "CopilotClient.stop runtime shutdown complete", |
| 908 | runtimeShutdownStart |
| 909 | ); |
| 910 | } catch (error) { |
| 911 | this.logDebugTiming( |
no test coverage detected