@brimveyn/aimux 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
- import { dirname, join } from 'node:path'
2
+ import { join } from 'node:path'
3
3
 
4
- import { CONFIG_PATH } from '../config'
5
4
  import { logDebug } from '../debug/input-log'
5
+ import { getProfileConfigDir } from '../profile-paths'
6
6
  import { isSnippetRecord } from './validation'
7
7
 
8
8
  export interface SnippetRecord {
@@ -11,7 +11,7 @@ export interface SnippetRecord {
11
11
  content: string
12
12
  }
13
13
 
14
- const SNIPPETS_PATH = join(dirname(CONFIG_PATH), 'aimux-snippets.json')
14
+ const SNIPPETS_PATH = join(getProfileConfigDir(), 'aimux-snippets.json')
15
15
 
16
16
  const DEFAULT_SNIPPETS: SnippetRecord[] = [
17
17
  {
@@ -78,7 +78,7 @@ export function loadSnippetCatalog(): SnippetRecord[] {
78
78
 
79
79
  export function saveSnippetCatalog(snippets: SnippetRecord[]): void {
80
80
  try {
81
- mkdirSync(dirname(SNIPPETS_PATH), { recursive: true })
81
+ mkdirSync(getProfileConfigDir(), { recursive: true })
82
82
  writeFileSync(SNIPPETS_PATH, `${JSON.stringify({ snippets, version: 1 }, null, 2)}\n`)
83
83
  } catch (error) {
84
84
  logDebug('snippets.catalog.saveError', {
@@ -0,0 +1,360 @@
1
+ import { EventEmitter } from 'node:events'
2
+ import { connect, Socket } from 'node:net'
3
+
4
+ import type { TerminalModeState, TerminalSnapshot, WorkspaceSnapshotV1 } from '../state/types'
5
+
6
+ import { getTerminalManagerSocketPath } from '../daemon/runtime-paths'
7
+ import { logDebug } from '../debug/input-log'
8
+ import {
9
+ encodeManagerMessage,
10
+ MANAGER_PROTOCOL_MIN_VERSION,
11
+ MANAGER_PROTOCOL_VERSION,
12
+ type ManagerAttachResult,
13
+ type ManagerEvent,
14
+ type ManagerRequest,
15
+ type ManagerResponse,
16
+ MessageDecoder,
17
+ parseManagerMessage,
18
+ } from '../ipc/manager-protocol'
19
+
20
+ type ManagerClientEvents = {
21
+ render: [
22
+ sessionId: string,
23
+ tabId: string,
24
+ viewport: TerminalSnapshot,
25
+ terminalModes: TerminalModeState,
26
+ ]
27
+ exit: [sessionId: string, tabId: string, exitCode: number]
28
+ error: [sessionId: string, tabId: string, message: string]
29
+ }
30
+
31
+ const REQUEST_TIMEOUT_MS = 10_000
32
+
33
+ export class TerminalManagerClient extends EventEmitter<ManagerClientEvents> {
34
+ private socket: Socket | null = null
35
+ private readonly pending = new Map<
36
+ string,
37
+ {
38
+ resolve: (message: ManagerResponse) => void
39
+ reject: (error: Error) => void
40
+ timer: ReturnType<typeof setTimeout>
41
+ }
42
+ >()
43
+ private readonly decoder = new MessageDecoder<ManagerResponse | ManagerEvent>(parseManagerMessage)
44
+ private selectedProtocolVersion: number | null = null
45
+
46
+ private rejectPendingRequests(error: Error): void {
47
+ for (const [id, pending] of this.pending.entries()) {
48
+ clearTimeout(pending.timer)
49
+ this.pending.delete(id)
50
+ pending.reject(error)
51
+ }
52
+ }
53
+
54
+ private resetConnection(reason: string): void {
55
+ logDebug('managerClient.resetConnection', { reason })
56
+ const socket = this.socket
57
+ this.socket = null
58
+ this.selectedProtocolVersion = null
59
+ this.decoder.reset()
60
+ this.rejectPendingRequests(new Error(reason))
61
+
62
+ if (!socket) {
63
+ return
64
+ }
65
+
66
+ socket.removeAllListeners()
67
+ if (!socket.destroyed) {
68
+ socket.end()
69
+ socket.destroy()
70
+ }
71
+ }
72
+
73
+ private getConnectedSocket(): Socket {
74
+ if (!this.socket || this.socket.destroyed) {
75
+ throw new Error('Terminal manager socket is unavailable')
76
+ }
77
+
78
+ return this.socket
79
+ }
80
+
81
+ private send(request: ManagerRequest): Promise<ManagerResponse> {
82
+ const socket = this.getConnectedSocket()
83
+ logDebug('managerClient.send', { id: request.id, type: request.type })
84
+ return new Promise((resolve, reject) => {
85
+ const timer = setTimeout(() => {
86
+ this.pending.delete(request.id)
87
+ logDebug('managerClient.timeout', { id: request.id, type: request.type })
88
+ reject(
89
+ new Error(`Manager request timed out after ${REQUEST_TIMEOUT_MS}ms: ${request.type}`)
90
+ )
91
+ }, REQUEST_TIMEOUT_MS)
92
+ this.pending.set(request.id, { reject, resolve, timer })
93
+ socket.write(encodeManagerMessage(request), (error) => {
94
+ if (error) {
95
+ clearTimeout(timer)
96
+ this.pending.delete(request.id)
97
+ logDebug('managerClient.sendError', {
98
+ error: error.message,
99
+ id: request.id,
100
+ type: request.type,
101
+ })
102
+ reject(error)
103
+ }
104
+ })
105
+ })
106
+ }
107
+
108
+ private async sendExpectOk(request: ManagerRequest): Promise<void> {
109
+ const response = await this.send(request)
110
+ if (response.type === 'ok') {
111
+ return
112
+ }
113
+
114
+ throw new Error(
115
+ response.type === 'error'
116
+ ? response.payload.message
117
+ : `Unexpected response for ${request.type}: ${response.type}`
118
+ )
119
+ }
120
+
121
+ private handleManagerEvent(message: ManagerEvent): void {
122
+ logDebug('managerClient.event', {
123
+ sessionId: message.payload.sessionId,
124
+ tabId: message.payload.tabId,
125
+ type: message.type,
126
+ })
127
+ switch (message.type) {
128
+ case 'tabRender':
129
+ this.emit(
130
+ 'render',
131
+ message.payload.sessionId,
132
+ message.payload.tabId,
133
+ message.payload.viewport,
134
+ message.payload.terminalModes
135
+ )
136
+ break
137
+ case 'tabExit':
138
+ this.emit(
139
+ 'exit',
140
+ message.payload.sessionId,
141
+ message.payload.tabId,
142
+ message.payload.exitCode
143
+ )
144
+ break
145
+ case 'tabError':
146
+ this.emit(
147
+ 'error',
148
+ message.payload.sessionId,
149
+ message.payload.tabId,
150
+ message.payload.message
151
+ )
152
+ break
153
+ }
154
+ }
155
+
156
+ private async performHandshake(): Promise<void> {
157
+ logDebug('managerClient.handshake.start', {
158
+ maxVersion: MANAGER_PROTOCOL_VERSION,
159
+ minVersion: MANAGER_PROTOCOL_MIN_VERSION,
160
+ })
161
+ const response = await this.send({
162
+ id: crypto.randomUUID(),
163
+ payload: {
164
+ maxVersion: MANAGER_PROTOCOL_VERSION,
165
+ minVersion: MANAGER_PROTOCOL_MIN_VERSION,
166
+ },
167
+ type: 'hello',
168
+ })
169
+
170
+ if (response.type !== 'helloResult') {
171
+ throw new Error(
172
+ response.type === 'error' ? response.payload.message : 'Unexpected hello response'
173
+ )
174
+ }
175
+
176
+ this.selectedProtocolVersion = response.payload.selectedVersion
177
+ logDebug('managerClient.handshake.success', {
178
+ processVersion: response.payload.processVersion,
179
+ selectedVersion: this.selectedProtocolVersion,
180
+ })
181
+ }
182
+
183
+ async connect(): Promise<void> {
184
+ if (this.socket && !this.socket.destroyed && this.selectedProtocolVersion !== null) {
185
+ logDebug('managerClient.connect.reuse', {
186
+ selectedProtocolVersion: this.selectedProtocolVersion,
187
+ })
188
+ return
189
+ }
190
+
191
+ this.resetConnection('Terminal manager connection replaced')
192
+
193
+ logDebug('managerClient.connect.start', { socketPath: getTerminalManagerSocketPath() })
194
+ const socket = connect(getTerminalManagerSocketPath())
195
+ this.socket = socket
196
+
197
+ await new Promise<void>((resolve, reject) => {
198
+ socket.once('connect', resolve)
199
+ socket.once('error', reject)
200
+ })
201
+
202
+ logDebug('managerClient.connect.connected', { socketPath: getTerminalManagerSocketPath() })
203
+
204
+ socket.on('error', (error) => {
205
+ if (this.socket !== socket) {
206
+ return
207
+ }
208
+ logDebug('managerClient.socketError', { error: error.message })
209
+ this.resetConnection(`Terminal manager socket error: ${error.message}`)
210
+ })
211
+ socket.on('close', () => {
212
+ if (this.socket !== socket) {
213
+ return
214
+ }
215
+ logDebug('managerClient.socketClose')
216
+ this.resetConnection('Terminal manager socket closed')
217
+ })
218
+ socket.on('data', (chunk) => {
219
+ if (this.socket !== socket) {
220
+ return
221
+ }
222
+
223
+ try {
224
+ for (const message of this.decoder.push(chunk)) {
225
+ if ('id' in message) {
226
+ logDebug('managerClient.response', { id: message.id, type: message.type })
227
+ const pending = this.pending.get(message.id)
228
+ if (pending) {
229
+ clearTimeout(pending.timer)
230
+ this.pending.delete(message.id)
231
+ pending.resolve(message)
232
+ }
233
+ } else {
234
+ this.handleManagerEvent(message)
235
+ }
236
+ }
237
+ } catch (error) {
238
+ const message = error instanceof Error ? error.message : String(error)
239
+ logDebug('managerClient.parseError', { error: message })
240
+ this.resetConnection(`Terminal manager parse error: ${message}`)
241
+ }
242
+ })
243
+
244
+ await this.performHandshake()
245
+ }
246
+
247
+ async attachSession(options: {
248
+ sessionId: string
249
+ cols: number
250
+ rows: number
251
+ workspaceSnapshot?: WorkspaceSnapshotV1
252
+ }): Promise<ManagerAttachResult> {
253
+ logDebug('managerClient.attach.start', {
254
+ cols: options.cols,
255
+ rows: options.rows,
256
+ sessionId: options.sessionId,
257
+ snapshotTabs: options.workspaceSnapshot?.tabs.length ?? 0,
258
+ })
259
+ await this.connect()
260
+ const response = await this.send({
261
+ id: crypto.randomUUID(),
262
+ payload: {
263
+ ...options,
264
+ protocolVersion: this.selectedProtocolVersion ?? MANAGER_PROTOCOL_VERSION,
265
+ },
266
+ type: 'attachSession',
267
+ })
268
+
269
+ if (response.type !== 'attachResult') {
270
+ throw new Error(
271
+ response.type === 'error' ? response.payload.message : 'Unexpected attach response'
272
+ )
273
+ }
274
+
275
+ logDebug('managerClient.attach.success', {
276
+ activeTabId: response.payload.activeTabId,
277
+ sessionId: options.sessionId,
278
+ tabs: response.payload.tabs.length,
279
+ })
280
+ return response.payload
281
+ }
282
+
283
+ createTab(options: Extract<ManagerRequest, { type: 'createTab' }>['payload']): Promise<void> {
284
+ logDebug('managerClient.createTab', {
285
+ command: options.command,
286
+ sessionId: options.sessionId,
287
+ tabId: options.tabId,
288
+ title: options.title,
289
+ })
290
+ return this.sendExpectOk({ id: crypto.randomUUID(), payload: options, type: 'createTab' })
291
+ }
292
+
293
+ write(sessionId: string, tabId: string, data: string): Promise<void> {
294
+ return this.sendExpectOk({
295
+ id: crypto.randomUUID(),
296
+ payload: { data, sessionId, tabId },
297
+ type: 'write',
298
+ })
299
+ }
300
+
301
+ resize(sessionId: string, cols: number, rows: number): Promise<void> {
302
+ return this.sendExpectOk({
303
+ id: crypto.randomUUID(),
304
+ payload: { cols, rows, sessionId },
305
+ type: 'resizeClient',
306
+ })
307
+ }
308
+
309
+ resizeTab(sessionId: string, tabId: string, cols: number, rows: number): Promise<void> {
310
+ return this.sendExpectOk({
311
+ id: crypto.randomUUID(),
312
+ payload: { cols, rows, sessionId, tabId },
313
+ type: 'resizeTab',
314
+ })
315
+ }
316
+
317
+ scroll(sessionId: string, tabId: string, deltaLines: number): Promise<void> {
318
+ return this.sendExpectOk({
319
+ id: crypto.randomUUID(),
320
+ payload: { deltaLines, sessionId, tabId },
321
+ type: 'scroll',
322
+ })
323
+ }
324
+
325
+ scrollToBottom(sessionId: string, tabId: string): Promise<void> {
326
+ return this.sendExpectOk({
327
+ id: crypto.randomUUID(),
328
+ payload: { sessionId, tabId },
329
+ type: 'scrollToBottom',
330
+ })
331
+ }
332
+
333
+ setActiveTab(sessionId: string, tabId: string | null): Promise<void> {
334
+ return this.sendExpectOk({
335
+ id: crypto.randomUUID(),
336
+ payload: { sessionId, tabId },
337
+ type: 'setActiveTab',
338
+ })
339
+ }
340
+
341
+ closeTab(sessionId: string, tabId: string): Promise<void> {
342
+ return this.sendExpectOk({
343
+ id: crypto.randomUUID(),
344
+ payload: { sessionId, tabId },
345
+ type: 'closeTab',
346
+ })
347
+ }
348
+
349
+ disposeSession(sessionId: string): Promise<void> {
350
+ return this.sendExpectOk({
351
+ id: crypto.randomUUID(),
352
+ payload: { sessionId },
353
+ type: 'disposeSession',
354
+ })
355
+ }
356
+
357
+ destroy(): void {
358
+ this.resetConnection('Terminal manager client destroyed')
359
+ }
360
+ }
@@ -0,0 +1,272 @@
1
+ import { createServer, type Socket } from 'node:net'
2
+
3
+ import {
4
+ getTerminalManagerSocketPath,
5
+ removeTerminalManagerSocketIfExists,
6
+ tightenSocketPermissions,
7
+ } from '../daemon/runtime-paths'
8
+ import { SessionManager } from '../daemon/session-manager'
9
+ import { logDebug } from '../debug/input-log'
10
+ import {
11
+ createManagerHelloResult,
12
+ encodeManagerMessage,
13
+ type ManagerEvent,
14
+ type ManagerRequest,
15
+ type ManagerResponse,
16
+ MessageDecoder,
17
+ parseManagerRequest,
18
+ selectManagerProtocolVersion,
19
+ } from '../ipc/manager-protocol'
20
+ import { findSocketProcessPid } from '../platform/daemon-control'
21
+
22
+ function send(socket: Socket, message: ManagerResponse | ManagerEvent): void {
23
+ socket.write(encodeManagerMessage(message))
24
+ }
25
+
26
+ function sendOk(socket: Socket, id: string): void {
27
+ send(socket, { id, payload: {}, type: 'ok' })
28
+ }
29
+
30
+ function requireNegotiatedVersion(socket: Socket, versions: Map<Socket, number>): number {
31
+ const version = versions.get(socket)
32
+ if (version === undefined) {
33
+ throw new Error('Protocol handshake required before using terminal manager')
34
+ }
35
+ return version
36
+ }
37
+
38
+ export async function runTerminalManager(): Promise<void> {
39
+ const socketPath = getTerminalManagerSocketPath()
40
+ logDebug('terminalManager.start', { pid: process.pid, socketPath })
41
+
42
+ const existingPid = await findSocketProcessPid(socketPath)
43
+ if (existingPid !== null && existingPid !== process.pid) {
44
+ logDebug('terminalManager.alreadyRunning', { existingPid })
45
+ process.stderr.write(`aimux terminal manager already running (pid ${existingPid})\n`)
46
+ process.exit(1)
47
+ }
48
+
49
+ removeTerminalManagerSocketIfExists()
50
+
51
+ const sessionManager = new SessionManager()
52
+ const sockets = new Set<Socket>()
53
+ const negotiatedVersions = new Map<Socket, number>()
54
+
55
+ sessionManager.on('render', (sessionId, tabId, viewport, terminalModes) => {
56
+ const event: ManagerEvent = {
57
+ payload: { sessionId, tabId, terminalModes, viewport },
58
+ type: 'tabRender',
59
+ }
60
+ for (const socket of sockets) {
61
+ send(socket, event)
62
+ }
63
+ })
64
+ sessionManager.on('exit', (sessionId, tabId, exitCode) => {
65
+ const event: ManagerEvent = { payload: { exitCode, sessionId, tabId }, type: 'tabExit' }
66
+ for (const socket of sockets) {
67
+ send(socket, event)
68
+ }
69
+ })
70
+ sessionManager.on('error', (sessionId, tabId, message) => {
71
+ const event: ManagerEvent = { payload: { message, sessionId, tabId }, type: 'tabError' }
72
+ for (const socket of sockets) {
73
+ send(socket, event)
74
+ }
75
+ })
76
+
77
+ const server = createServer((socket) => {
78
+ logDebug('terminalManager.client.connected')
79
+ sockets.add(socket)
80
+ const decoder = new MessageDecoder<ManagerRequest>(parseManagerRequest)
81
+
82
+ socket.on('data', (chunk) => {
83
+ try {
84
+ for (const message of decoder.push(chunk)) {
85
+ try {
86
+ switch (message.type) {
87
+ case 'hello': {
88
+ logDebug('terminalManager.request.hello', {
89
+ maxVersion: message.payload.maxVersion,
90
+ minVersion: message.payload.minVersion,
91
+ })
92
+ const selectedVersion = selectManagerProtocolVersion(message.payload)
93
+ if (selectedVersion === null) {
94
+ send(socket, {
95
+ id: message.id,
96
+ payload: { message: 'No compatible terminal-manager protocol version' },
97
+ type: 'error',
98
+ })
99
+ break
100
+ }
101
+
102
+ negotiatedVersions.set(socket, selectedVersion)
103
+ logDebug('terminalManager.request.hello.success', { selectedVersion })
104
+ send(socket, {
105
+ id: message.id,
106
+ payload: createManagerHelloResult(selectedVersion),
107
+ type: 'helloResult',
108
+ })
109
+ break
110
+ }
111
+ case 'attachSession': {
112
+ logDebug('terminalManager.request.attach.start', {
113
+ cols: message.payload.cols,
114
+ rows: message.payload.rows,
115
+ sessionId: message.payload.sessionId,
116
+ snapshotTabs: message.payload.workspaceSnapshot?.tabs.length ?? 0,
117
+ })
118
+ const negotiatedVersion = requireNegotiatedVersion(socket, negotiatedVersions)
119
+ if (message.payload.protocolVersion !== negotiatedVersion) {
120
+ throw new Error(
121
+ `Manager protocol mismatch: client v${message.payload.protocolVersion}, server v${negotiatedVersion}`
122
+ )
123
+ }
124
+ sessionManager.resize(
125
+ message.payload.sessionId,
126
+ message.payload.cols,
127
+ message.payload.rows
128
+ )
129
+ const attachResult = sessionManager.attachSession(
130
+ message.payload.sessionId,
131
+ message.payload.workspaceSnapshot
132
+ )
133
+ send(socket, {
134
+ id: message.id,
135
+ payload: { protocolVersion: negotiatedVersion, ...attachResult },
136
+ type: 'attachResult',
137
+ })
138
+ logDebug('terminalManager.request.attach.success', {
139
+ activeTabId: attachResult.activeTabId,
140
+ sessionId: message.payload.sessionId,
141
+ tabs: attachResult.tabs.length,
142
+ })
143
+ break
144
+ }
145
+ case 'createTab':
146
+ requireNegotiatedVersion(socket, negotiatedVersions)
147
+ logDebug('terminalManager.request.createTab.start', {
148
+ command: message.payload.command,
149
+ sessionId: message.payload.sessionId,
150
+ tabId: message.payload.tabId,
151
+ title: message.payload.title,
152
+ })
153
+ sessionManager.createTab(message.payload.sessionId, message.payload)
154
+ sendOk(socket, message.id)
155
+ logDebug('terminalManager.request.createTab.success', {
156
+ sessionId: message.payload.sessionId,
157
+ tabId: message.payload.tabId,
158
+ })
159
+ break
160
+ case 'write':
161
+ requireNegotiatedVersion(socket, negotiatedVersions)
162
+ sessionManager.write(
163
+ message.payload.sessionId,
164
+ message.payload.tabId,
165
+ message.payload.data
166
+ )
167
+ sendOk(socket, message.id)
168
+ break
169
+ case 'resizeClient':
170
+ requireNegotiatedVersion(socket, negotiatedVersions)
171
+ sessionManager.resize(
172
+ message.payload.sessionId,
173
+ message.payload.cols,
174
+ message.payload.rows
175
+ )
176
+ sendOk(socket, message.id)
177
+ break
178
+ case 'resizeTab':
179
+ requireNegotiatedVersion(socket, negotiatedVersions)
180
+ sessionManager.resizeTab(
181
+ message.payload.sessionId,
182
+ message.payload.tabId,
183
+ message.payload.cols,
184
+ message.payload.rows
185
+ )
186
+ sendOk(socket, message.id)
187
+ break
188
+ case 'scroll':
189
+ requireNegotiatedVersion(socket, negotiatedVersions)
190
+ sessionManager.scroll(
191
+ message.payload.sessionId,
192
+ message.payload.tabId,
193
+ message.payload.deltaLines
194
+ )
195
+ sendOk(socket, message.id)
196
+ break
197
+ case 'scrollToBottom':
198
+ requireNegotiatedVersion(socket, negotiatedVersions)
199
+ sessionManager.scrollToBottom(message.payload.sessionId, message.payload.tabId)
200
+ sendOk(socket, message.id)
201
+ break
202
+ case 'setActiveTab':
203
+ requireNegotiatedVersion(socket, negotiatedVersions)
204
+ sessionManager.setActiveTab(message.payload.sessionId, message.payload.tabId)
205
+ sendOk(socket, message.id)
206
+ break
207
+ case 'closeTab':
208
+ requireNegotiatedVersion(socket, negotiatedVersions)
209
+ sessionManager.closeTab(message.payload.sessionId, message.payload.tabId)
210
+ sendOk(socket, message.id)
211
+ break
212
+ case 'disposeSession':
213
+ requireNegotiatedVersion(socket, negotiatedVersions)
214
+ sessionManager.disposeSession(message.payload.sessionId)
215
+ sendOk(socket, message.id)
216
+ break
217
+ case 'ping':
218
+ sendOk(socket, message.id)
219
+ break
220
+ }
221
+ } catch (error) {
222
+ const errorMessage = error instanceof Error ? error.message : String(error)
223
+ logDebug('terminalManager.request.error', {
224
+ error: errorMessage,
225
+ requestId: message.id,
226
+ type: message.type,
227
+ })
228
+ send(socket, { id: message.id, payload: { message: errorMessage }, type: 'error' })
229
+ }
230
+ }
231
+ } catch (error) {
232
+ const message = error instanceof Error ? error.message : String(error)
233
+ logDebug('terminalManager.decoder.error', { error: message })
234
+ decoder.reset()
235
+ send(socket, { id: crypto.randomUUID(), payload: { message }, type: 'error' })
236
+ }
237
+ })
238
+
239
+ socket.on('close', () => {
240
+ logDebug('terminalManager.client.close')
241
+ sockets.delete(socket)
242
+ negotiatedVersions.delete(socket)
243
+ })
244
+ socket.on('error', () => {
245
+ logDebug('terminalManager.client.error')
246
+ sockets.delete(socket)
247
+ negotiatedVersions.delete(socket)
248
+ })
249
+ })
250
+
251
+ await new Promise<void>((resolve, reject) => {
252
+ server.once('error', reject)
253
+ server.listen(socketPath, () => resolve())
254
+ })
255
+ tightenSocketPermissions(socketPath)
256
+
257
+ const gracefulShutdown = (signal: string) => {
258
+ logDebug(`terminalManager.${signal}`)
259
+ sessionManager.disposeAll()
260
+ server.close()
261
+ process.exit(0)
262
+ }
263
+
264
+ process.on('SIGTERM', () => gracefulShutdown('sigterm'))
265
+ process.on('SIGINT', () => gracefulShutdown('sigint'))
266
+ process.on('uncaughtException', () => gracefulShutdown('uncaughtException'))
267
+ process.on('unhandledRejection', () => gracefulShutdown('unhandledRejection'))
268
+
269
+ await new Promise<void>(() => {
270
+ // Keep the terminal-manager process alive until it is terminated.
271
+ })
272
+ }
package/src/update.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { getDaemonSocketPath } from './daemon/runtime-paths'
2
- import { findDaemonPid } from './platform/daemon-control'
2
+ import { findIpcDaemonPid } from './platform/daemon-control'
3
3
  import { runRestartDaemon } from './restart-daemon'
4
4
 
5
5
  const REPO = 'BrimVeyn/aimux'
@@ -52,9 +52,9 @@ export async function runUpdate(): Promise<number> {
52
52
 
53
53
  process.stdout.write(`Updated to ${latest}.\n`)
54
54
 
55
- const pid = await findDaemonPid(getDaemonSocketPath())
55
+ const pid = await findIpcDaemonPid()
56
56
  if (pid !== null) {
57
- process.stdout.write('Restarting daemon...\n')
57
+ process.stdout.write(`Restarting IPC daemon at ${getDaemonSocketPath()}...\n`)
58
58
  await runRestartDaemon()
59
59
  }
60
60