-
Notifications
You must be signed in to change notification settings - Fork 16.4k
Expand file tree
/
Copy pathusePipeRouter.ts
More file actions
151 lines (137 loc) · 4.81 KB
/
Copy pathusePipeRouter.ts
File metadata and controls
151 lines (137 loc) · 4.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/**
* usePipeRouter — Route user input to selected pipe targets.
*
* Returns `routeToSelectedPipes(input)` which checks selectedPipes +
* routeMode and sends the prompt to all connected slave targets.
* Returns true if routed (caller should skip local execution).
*/
import { feature } from 'bun:bundle'
import { useCallback } from 'react'
type StoreApi = { getState: () => any }
type SetAppState = (updater: (prev: any) => any) => void
type AddNotification = (opts: {
key: string
text: string
color: string
priority: string
timeoutMs: number
}) => void
type Deps = {
store: StoreApi
setAppState: SetAppState
addNotification: AddNotification
}
/**
* Attempt to route user input to selected pipes.
* Returns true if routed to at least one pipe (skip local execution).
*/
export function usePipeRouter({ store, setAppState, addNotification }: Deps): {
routeToSelectedPipes: (input: string) => boolean
} {
const routeToSelectedPipes = useCallback(
(input: string): boolean => {
if (!feature('UDS_INBOX')) return false
if (!input.trim() || input.trim().startsWith('/')) return false
/* eslint-disable @typescript-eslint/no-require-imports */
const pipeState = store.getState().pipeIpc
const selectedPipes: string[] = pipeState?.selectedPipes ?? []
const routeMode: 'selected' | 'local' = pipeState?.routeMode ?? 'selected'
if (selectedPipes.length === 0 || routeMode === 'local') return false
const { getConnectedSlaveTargets } =
require('./useMasterMonitor.js') as typeof import('./useMasterMonitor.js')
const { getPipeIpc } =
require('../utils/pipeTransport.js') as typeof import('../utils/pipeTransport.js')
/* eslint-enable @typescript-eslint/no-require-imports */
const targets = getConnectedSlaveTargets(selectedPipes)
const pipeIpcForDisplay = getPipeIpc(store.getState())
const discovered: Array<{
pipeName: string
role: string
ip: string
hostname: string
}> = pipeIpcForDisplay.discoveredPipes ?? []
const sentTargetNames: string[] = []
const sentTargetLabels: string[] = []
const failedTargetNames: string[] = []
for (const { name, client } of targets) {
try {
client.send({ type: 'prompt', data: input.trim() })
sentTargetNames.push(name)
// Build display label: [role] hostname/ip for LAN, [role] for local
const info = discovered.find((d: any) => d.pipeName === name)
if (info) {
const isLan = info.ip && info.ip !== pipeIpcForDisplay.localIp
sentTargetLabels.push(
isLan
? `[${info.role}] ${info.hostname}/${info.ip}`
: `[${info.role}]`,
)
} else {
sentTargetLabels.push(name)
}
} catch {
failedTargetNames.push(name)
}
}
if (sentTargetNames.length > 0) {
const promptText = input.trim()
const promptTimestamp = new Date().toISOString()
setAppState((prev: any) => {
const pipeIpc = getPipeIpc(prev)
const nextSlaves = { ...pipeIpc.slaves }
for (const name of sentTargetNames) {
const slave = nextSlaves[name]
if (!slave) continue
nextSlaves[name] = {
...slave,
status: 'busy',
lastActivityAt: promptTimestamp,
lastSummary: `Queued: ${promptText}`,
lastEventType: 'prompt',
history: [
...slave.history,
{
type: 'prompt',
content: promptText,
from: pipeIpc.serverName ?? 'master',
timestamp: promptTimestamp,
},
],
}
}
return {
...prev,
pipeIpc: { ...pipeIpc, slaves: nextSlaves },
}
})
addNotification({
key: 'pipe-route-success',
text: `Routed to ${sentTargetLabels.join(', ')}; main can continue other tasks`,
color: 'success',
priority: 'immediate',
timeoutMs: 3000,
})
} else {
addNotification({
key: 'pipe-route-fallback',
text: 'Selected pipes are unavailable; processing locally.',
color: 'warning',
priority: 'immediate',
timeoutMs: 4000,
})
}
if (failedTargetNames.length > 0) {
addNotification({
key: 'pipe-route-partial-failure',
text: `Failed to send to: ${failedTargetNames.join(', ')}`,
color: 'warning',
priority: 'immediate',
timeoutMs: 4000,
})
}
return sentTargetNames.length > 0
},
[store, setAppState, addNotification],
)
return { routeToSelectedPipes }
}