@muyichengshayu/promptx 0.2.2 → 0.2.3
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.
- package/CHANGELOG.md +8 -0
- package/apps/server/src/gitDiff.js +238 -35
- package/apps/server/src/gitDiffClient.js +311 -149
- package/apps/server/src/taskRoutes.js +1 -0
- package/apps/web/dist/assets/{CodexSessionManagerDialog-CELTkz9T.js → CodexSessionManagerDialog-ALNJ5DHK.js} +1 -1
- package/apps/web/dist/assets/TaskDiffReviewDialog-70bO8EPm.js +4 -0
- package/apps/web/dist/assets/TaskDiffReviewDialog-hxUGDcmF.css +1 -0
- package/apps/web/dist/assets/{WorkbenchSettingsDialog-CThWkZHd.js → WorkbenchSettingsDialog-DjMkkdSp.js} +1 -1
- package/apps/web/dist/assets/{WorkbenchView-D6auwJnA.js → WorkbenchView-CdD65SV0.js} +18 -18
- package/apps/web/dist/assets/index-Ca-xxeXy.js +2 -0
- package/apps/web/dist/index.html +1 -1
- package/package.json +1 -1
- package/apps/web/dist/assets/TaskDiffReviewDialog-CeGj0idf.css +0 -1
- package/apps/web/dist/assets/TaskDiffReviewDialog-VwZmo00b.js +0 -3
- package/apps/web/dist/assets/index-8vfFmsVl.js +0 -2
|
@@ -3,17 +3,19 @@ import process from 'node:process'
|
|
|
3
3
|
import { spawn } from 'node:child_process'
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
5
|
|
|
6
|
-
const DEFAULT_TIMEOUT_MS =
|
|
6
|
+
const DEFAULT_TIMEOUT_MS = Math.max(1_000, Number(process.env.PROMPTX_GIT_DIFF_TIMEOUT_MS) || 60_000)
|
|
7
|
+
const DEFAULT_MAX_WORKERS = Math.max(1, Number(process.env.PROMPTX_GIT_DIFF_WORKER_POOL_SIZE) || 2)
|
|
7
8
|
const MAX_STDERR_LENGTH = 4000
|
|
8
9
|
|
|
9
10
|
const currentDir = path.dirname(fileURLToPath(import.meta.url))
|
|
10
11
|
const workerEntryPath = path.join(currentDir, 'gitDiffWorker.js')
|
|
11
12
|
|
|
12
|
-
let workerProcess = null
|
|
13
|
-
let workerStdoutBuffer = ''
|
|
14
|
-
let workerStderrBuffer = ''
|
|
15
13
|
let nextRequestId = 1
|
|
16
|
-
|
|
14
|
+
let nextWorkerId = 1
|
|
15
|
+
const workerPool = []
|
|
16
|
+
const requestQueue = []
|
|
17
|
+
const requestMap = new Map()
|
|
18
|
+
const activeRequests = new Map()
|
|
17
19
|
const workerMetrics = {
|
|
18
20
|
startedAt: new Date().toISOString(),
|
|
19
21
|
spawnCount: 0,
|
|
@@ -44,11 +46,6 @@ function createWorkerError(message = '') {
|
|
|
44
46
|
return error
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
function resetWorkerBuffers() {
|
|
48
|
-
workerStdoutBuffer = ''
|
|
49
|
-
workerStderrBuffer = ''
|
|
50
|
-
}
|
|
51
|
-
|
|
52
49
|
function createLastRequestSnapshot(request = {}, patch = {}) {
|
|
53
50
|
return {
|
|
54
51
|
requestId: String(request.requestId || patch.requestId || '').trim(),
|
|
@@ -68,91 +65,266 @@ function markLastRequest(request = {}, patch = {}) {
|
|
|
68
65
|
workerMetrics.lastRequest = createLastRequestSnapshot(request, patch)
|
|
69
66
|
}
|
|
70
67
|
|
|
71
|
-
function
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
68
|
+
function getNowIso() {
|
|
69
|
+
return new Date().toISOString()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function getRequestDurationMs(request = {}) {
|
|
73
|
+
const startedAt = Date.parse(String(request.requestMeta?.startedAt || ''))
|
|
74
|
+
return Number.isFinite(startedAt) ? Math.max(0, Date.now() - startedAt) : 0
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getWorkerIndex(workerId = '') {
|
|
78
|
+
return workerPool.findIndex((worker) => worker.id === workerId)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getWorkerById(workerId = '') {
|
|
82
|
+
const index = getWorkerIndex(workerId)
|
|
83
|
+
return index >= 0 ? workerPool[index] : null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function removeWorker(worker) {
|
|
87
|
+
const index = getWorkerIndex(worker?.id)
|
|
88
|
+
if (index >= 0) {
|
|
89
|
+
workerPool.splice(index, 1)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function clearRequestTimer(request) {
|
|
94
|
+
if (request?.timer) {
|
|
95
|
+
clearTimeout(request.timer)
|
|
96
|
+
request.timer = null
|
|
75
97
|
}
|
|
76
98
|
}
|
|
77
99
|
|
|
78
|
-
function
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
100
|
+
function removeQueuedRequest(requestId = '') {
|
|
101
|
+
const index = requestQueue.findIndex((request) => request.requestId === requestId)
|
|
102
|
+
if (index >= 0) {
|
|
103
|
+
requestQueue.splice(index, 1)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function updateWorkerExitMetrics({ code = null, signal = '', reason = '' } = {}) {
|
|
108
|
+
workerMetrics.lastWorkerExitAt = getNowIso()
|
|
109
|
+
workerMetrics.lastWorkerExitCode = typeof code === 'number' ? code : null
|
|
110
|
+
workerMetrics.lastWorkerExitSignal = String(signal || '').trim()
|
|
111
|
+
workerMetrics.lastWorkerExitReason = String(reason || '').trim()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function finalizeRequest(request, handler) {
|
|
115
|
+
if (!request || request.settled) {
|
|
81
116
|
return
|
|
82
117
|
}
|
|
83
118
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
119
|
+
request.settled = true
|
|
120
|
+
clearRequestTimer(request)
|
|
121
|
+
removeQueuedRequest(request.requestId)
|
|
122
|
+
requestMap.delete(request.requestId)
|
|
123
|
+
activeRequests.delete(request.requestId)
|
|
124
|
+
handler(request)
|
|
87
125
|
}
|
|
88
126
|
|
|
89
|
-
function
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
127
|
+
function rejectRequestWithError(request, error) {
|
|
128
|
+
finalizeRequest(request, (pending) => {
|
|
129
|
+
workerMetrics.failedRequests += 1
|
|
130
|
+
markLastRequest(pending.requestMeta, {
|
|
131
|
+
finishedAt: getNowIso(),
|
|
132
|
+
durationMs: getRequestDurationMs(pending),
|
|
133
|
+
status: error?.code === 'GIT_DIFF_TIMEOUT' ? 'timeout' : 'failed',
|
|
134
|
+
timeout: error?.code === 'GIT_DIFF_TIMEOUT',
|
|
135
|
+
errorMessage: String(error?.message || error || 'git diff request failed'),
|
|
136
|
+
})
|
|
93
137
|
pending.reject(error)
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function resolveRequest(request, value) {
|
|
142
|
+
finalizeRequest(request, (pending) => {
|
|
143
|
+
workerMetrics.completedRequests += 1
|
|
144
|
+
markLastRequest(pending.requestMeta, {
|
|
145
|
+
finishedAt: getNowIso(),
|
|
146
|
+
durationMs: getRequestDurationMs(pending),
|
|
147
|
+
status: 'completed',
|
|
148
|
+
})
|
|
149
|
+
pending.resolve(value)
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function createWorkerState(child) {
|
|
154
|
+
return {
|
|
155
|
+
id: `git-diff-worker-${nextWorkerId++}`,
|
|
156
|
+
child,
|
|
157
|
+
stdoutBuffer: '',
|
|
158
|
+
stderrBuffer: '',
|
|
159
|
+
activeRequestId: '',
|
|
160
|
+
startedAt: getNowIso(),
|
|
161
|
+
stopping: false,
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function appendWorkerStderr(worker, chunk) {
|
|
166
|
+
worker.stderrBuffer = `${worker.stderrBuffer}${Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk || '')}`
|
|
167
|
+
if (worker.stderrBuffer.length > MAX_STDERR_LENGTH) {
|
|
168
|
+
worker.stderrBuffer = worker.stderrBuffer.slice(-MAX_STDERR_LENGTH)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function stopWorker(worker, reason = '') {
|
|
173
|
+
if (!worker || worker.stopping) {
|
|
174
|
+
return
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
worker.stopping = true
|
|
178
|
+
removeWorker(worker)
|
|
179
|
+
updateWorkerExitMetrics({
|
|
180
|
+
signal: 'manual_stop',
|
|
181
|
+
reason,
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
if (worker.child?.exitCode === null && !worker.child?.killed) {
|
|
185
|
+
worker.child.kill()
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function dispatchQueuedRequests() {
|
|
190
|
+
while (requestQueue.length) {
|
|
191
|
+
let worker = workerPool.find((item) => !item.activeRequestId && !item.stopping) || null
|
|
192
|
+
if (!worker && workerPool.length < DEFAULT_MAX_WORKERS) {
|
|
193
|
+
worker = ensureGitDiffWorker()
|
|
194
|
+
}
|
|
195
|
+
if (!worker) {
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const request = requestQueue.shift()
|
|
200
|
+
if (!request || request.settled) {
|
|
201
|
+
continue
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
request.workerId = worker.id
|
|
205
|
+
worker.activeRequestId = request.requestId
|
|
206
|
+
activeRequests.set(request.requestId, request)
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
worker.child.stdin?.write(`${JSON.stringify({
|
|
210
|
+
requestId: request.requestId,
|
|
211
|
+
action: 'getTaskGitDiffReview',
|
|
212
|
+
taskSlug: request.taskSlug,
|
|
213
|
+
options: request.options,
|
|
214
|
+
})}\n`)
|
|
215
|
+
} catch (error) {
|
|
216
|
+
worker.activeRequestId = ''
|
|
217
|
+
activeRequests.delete(request.requestId)
|
|
218
|
+
request.workerId = ''
|
|
219
|
+
rejectRequestWithError(request, createWorkerError(String(error?.message || error)))
|
|
220
|
+
stopWorker(worker, String(error?.message || error || 'worker write failed'))
|
|
221
|
+
}
|
|
94
222
|
}
|
|
95
223
|
}
|
|
96
224
|
|
|
97
|
-
function
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
225
|
+
function settleWorkerRequest(worker, requestId, handler) {
|
|
226
|
+
const request = activeRequests.get(requestId)
|
|
227
|
+
if (!request) {
|
|
228
|
+
return
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (worker.activeRequestId === requestId) {
|
|
232
|
+
worker.activeRequestId = ''
|
|
233
|
+
}
|
|
234
|
+
request.workerId = ''
|
|
235
|
+
handler(request)
|
|
236
|
+
dispatchQueuedRequests()
|
|
101
237
|
}
|
|
102
238
|
|
|
103
|
-
function handleWorkerLine(line) {
|
|
239
|
+
function handleWorkerLine(worker, line) {
|
|
104
240
|
let payload
|
|
105
241
|
try {
|
|
106
242
|
payload = JSON.parse(line)
|
|
107
243
|
} catch {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
244
|
+
const error = createWorkerError(`git diff worker returned invalid JSON: ${line.slice(0, 200)}`)
|
|
245
|
+
if (worker.activeRequestId) {
|
|
246
|
+
settleWorkerRequest(worker, worker.activeRequestId, (request) => {
|
|
247
|
+
rejectRequestWithError(request, error)
|
|
248
|
+
})
|
|
249
|
+
}
|
|
250
|
+
stopWorker(worker, error.message)
|
|
112
251
|
return
|
|
113
252
|
}
|
|
114
253
|
|
|
115
254
|
const requestId = String(payload?.requestId || '').trim()
|
|
116
255
|
if (!requestId) {
|
|
117
|
-
|
|
118
|
-
|
|
256
|
+
const error = createWorkerError(
|
|
257
|
+
String(payload?.error?.message || '').trim() || 'git diff worker returned a response without requestId.'
|
|
119
258
|
)
|
|
120
|
-
|
|
259
|
+
if (worker.activeRequestId) {
|
|
260
|
+
settleWorkerRequest(worker, worker.activeRequestId, (request) => {
|
|
261
|
+
rejectRequestWithError(request, error)
|
|
262
|
+
})
|
|
263
|
+
}
|
|
264
|
+
stopWorker(worker, error.message)
|
|
121
265
|
return
|
|
122
266
|
}
|
|
123
267
|
|
|
124
|
-
|
|
268
|
+
settleWorkerRequest(worker, requestId, (request) => {
|
|
125
269
|
if (!payload?.ok) {
|
|
126
|
-
|
|
270
|
+
const error = createWorkerError(String(payload?.error?.message || '').trim() || worker.stderrBuffer.trim())
|
|
271
|
+
rejectRequestWithError(request, error)
|
|
127
272
|
return
|
|
128
273
|
}
|
|
129
|
-
|
|
274
|
+
resolveRequest(request, payload.result)
|
|
130
275
|
})
|
|
131
276
|
}
|
|
132
277
|
|
|
133
|
-
function handleWorkerStdout(chunk) {
|
|
134
|
-
|
|
278
|
+
function handleWorkerStdout(worker, chunk) {
|
|
279
|
+
worker.stdoutBuffer = `${worker.stdoutBuffer}${Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk || '')}`
|
|
135
280
|
|
|
136
|
-
let newlineIndex =
|
|
281
|
+
let newlineIndex = worker.stdoutBuffer.indexOf('\n')
|
|
137
282
|
while (newlineIndex !== -1) {
|
|
138
|
-
const line =
|
|
139
|
-
|
|
283
|
+
const line = worker.stdoutBuffer.slice(0, newlineIndex).trim()
|
|
284
|
+
worker.stdoutBuffer = worker.stdoutBuffer.slice(newlineIndex + 1)
|
|
140
285
|
if (line) {
|
|
141
|
-
handleWorkerLine(line)
|
|
286
|
+
handleWorkerLine(worker, line)
|
|
142
287
|
}
|
|
143
|
-
newlineIndex =
|
|
288
|
+
newlineIndex = worker.stdoutBuffer.indexOf('\n')
|
|
144
289
|
}
|
|
145
290
|
}
|
|
146
291
|
|
|
147
|
-
function
|
|
148
|
-
|
|
149
|
-
|
|
292
|
+
function handleWorkerFailure(worker, error) {
|
|
293
|
+
removeWorker(worker)
|
|
294
|
+
updateWorkerExitMetrics({
|
|
295
|
+
reason: String(error?.message || error || 'worker error'),
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
if (worker.activeRequestId) {
|
|
299
|
+
settleWorkerRequest(worker, worker.activeRequestId, (request) => {
|
|
300
|
+
rejectRequestWithError(request, createWorkerError(String(error?.message || error)))
|
|
301
|
+
})
|
|
150
302
|
}
|
|
151
303
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
304
|
+
dispatchQueuedRequests()
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function handleWorkerClose(worker, code, signal) {
|
|
308
|
+
removeWorker(worker)
|
|
309
|
+
updateWorkerExitMetrics({
|
|
310
|
+
code,
|
|
311
|
+
signal,
|
|
312
|
+
reason: worker.stderrBuffer.trim() || (signal ? `signal:${signal}` : `code:${code}`),
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
if (worker.activeRequestId) {
|
|
316
|
+
const error = worker.stderrBuffer.trim()
|
|
317
|
+
? createWorkerError(`git diff worker exited unexpectedly: ${worker.stderrBuffer.trim()}`)
|
|
318
|
+
: createWorkerError('git diff worker exited unexpectedly.')
|
|
319
|
+
settleWorkerRequest(worker, worker.activeRequestId, (request) => {
|
|
320
|
+
rejectRequestWithError(request, error)
|
|
321
|
+
})
|
|
155
322
|
}
|
|
323
|
+
|
|
324
|
+
dispatchQueuedRequests()
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function ensureGitDiffWorker() {
|
|
156
328
|
const child = spawn(process.execPath, [workerEntryPath], {
|
|
157
329
|
cwd: currentDir,
|
|
158
330
|
env: {
|
|
@@ -161,58 +333,46 @@ function ensureGitDiffWorker() {
|
|
|
161
333
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
162
334
|
windowsHide: true,
|
|
163
335
|
})
|
|
336
|
+
|
|
337
|
+
if (workerMetrics.spawnCount > 0) {
|
|
338
|
+
workerMetrics.restartCount += 1
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const worker = createWorkerState(child)
|
|
342
|
+
workerPool.push(worker)
|
|
164
343
|
workerMetrics.spawnCount += 1
|
|
165
|
-
workerMetrics.lastWorkerSpawnedAt =
|
|
344
|
+
workerMetrics.lastWorkerSpawnedAt = worker.startedAt
|
|
166
345
|
|
|
167
|
-
child.stdout?.on('data',
|
|
168
|
-
|
|
346
|
+
child.stdout?.on('data', (chunk) => {
|
|
347
|
+
handleWorkerStdout(worker, chunk)
|
|
348
|
+
})
|
|
349
|
+
child.stderr?.on('data', (chunk) => {
|
|
350
|
+
appendWorkerStderr(worker, chunk)
|
|
351
|
+
})
|
|
169
352
|
child.on('error', (error) => {
|
|
170
|
-
|
|
171
|
-
workerMetrics.lastWorkerExitCode = null
|
|
172
|
-
workerMetrics.lastWorkerExitSignal = ''
|
|
173
|
-
workerMetrics.lastWorkerExitReason = String(error?.message || error || 'worker error')
|
|
174
|
-
rejectAllPendingRequests(createWorkerError(String(error?.message || error)))
|
|
175
|
-
if (workerProcess === child) {
|
|
176
|
-
workerProcess = null
|
|
177
|
-
}
|
|
178
|
-
detachWorkerListeners(child)
|
|
353
|
+
handleWorkerFailure(worker, error)
|
|
179
354
|
})
|
|
180
355
|
child.on('close', (code, signal) => {
|
|
181
|
-
|
|
182
|
-
workerMetrics.lastWorkerExitAt = new Date().toISOString()
|
|
183
|
-
workerMetrics.lastWorkerExitCode = typeof code === 'number' ? code : null
|
|
184
|
-
workerMetrics.lastWorkerExitSignal = String(signal || '').trim()
|
|
185
|
-
workerMetrics.lastWorkerExitReason = tail || (signal ? `signal:${signal}` : `code:${code}`)
|
|
186
|
-
rejectAllPendingRequests(
|
|
187
|
-
tail
|
|
188
|
-
? createWorkerError(`git diff worker exited unexpectedly: ${tail}`)
|
|
189
|
-
: createWorkerError('git diff worker exited unexpectedly.')
|
|
190
|
-
)
|
|
191
|
-
if (workerProcess === child) {
|
|
192
|
-
workerProcess = null
|
|
193
|
-
}
|
|
194
|
-
detachWorkerListeners(child)
|
|
195
|
-
resetWorkerBuffers()
|
|
356
|
+
handleWorkerClose(worker, code, signal)
|
|
196
357
|
})
|
|
197
358
|
|
|
198
|
-
|
|
199
|
-
return child
|
|
359
|
+
return worker
|
|
200
360
|
}
|
|
201
361
|
|
|
202
362
|
export function stopGitDiffWorker() {
|
|
203
|
-
|
|
204
|
-
return
|
|
205
|
-
}
|
|
363
|
+
const stopError = createWorkerError('git diff worker stopped.')
|
|
206
364
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
detachWorkerListeners(child)
|
|
211
|
-
resetWorkerBuffers()
|
|
365
|
+
requestQueue.splice(0, requestQueue.length).forEach((request) => {
|
|
366
|
+
rejectRequestWithError(request, stopError)
|
|
367
|
+
})
|
|
212
368
|
|
|
213
|
-
|
|
214
|
-
|
|
369
|
+
for (const request of [...activeRequests.values()]) {
|
|
370
|
+
rejectRequestWithError(request, stopError)
|
|
215
371
|
}
|
|
372
|
+
|
|
373
|
+
;[...workerPool].forEach((worker) => {
|
|
374
|
+
stopWorker(worker, 'stopped')
|
|
375
|
+
})
|
|
216
376
|
}
|
|
217
377
|
|
|
218
378
|
export function getTaskGitDiffReviewInSubprocess(taskSlug = '', options = {}) {
|
|
@@ -223,81 +383,83 @@ export function getTaskGitDiffReviewInSubprocess(taskSlug = '', options = {}) {
|
|
|
223
383
|
taskSlug: String(taskSlug || '').trim(),
|
|
224
384
|
scope: String(options.scope || '').trim(),
|
|
225
385
|
filePath: String(options.filePath || '').trim(),
|
|
226
|
-
startedAt:
|
|
386
|
+
startedAt: getNowIso(),
|
|
227
387
|
}
|
|
228
|
-
|
|
388
|
+
|
|
229
389
|
workerMetrics.totalRequests += 1
|
|
230
390
|
|
|
231
391
|
return new Promise((resolve, reject) => {
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
errorMessage: String(error?.message || error || 'git diff request failed'),
|
|
265
|
-
})
|
|
266
|
-
reject(error)
|
|
267
|
-
},
|
|
268
|
-
timer,
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
try {
|
|
272
|
-
child.stdin?.write(`${JSON.stringify({
|
|
273
|
-
requestId,
|
|
274
|
-
action: 'getTaskGitDiffReview',
|
|
275
|
-
taskSlug: String(taskSlug || '').trim(),
|
|
276
|
-
options,
|
|
277
|
-
})}\n`)
|
|
278
|
-
} catch (error) {
|
|
279
|
-
settlePendingRequest(requestId, ({ reject: rejectPending }) => {
|
|
280
|
-
rejectPending(createWorkerError(String(error?.message || error)))
|
|
281
|
-
})
|
|
282
|
-
stopGitDiffWorker()
|
|
392
|
+
const request = {
|
|
393
|
+
requestId,
|
|
394
|
+
taskSlug: String(taskSlug || '').trim(),
|
|
395
|
+
options,
|
|
396
|
+
resolve,
|
|
397
|
+
reject,
|
|
398
|
+
requestMeta,
|
|
399
|
+
settled: false,
|
|
400
|
+
workerId: '',
|
|
401
|
+
timer: setTimeout(() => {
|
|
402
|
+
const currentRequest = requestMap.get(requestId)
|
|
403
|
+
if (!currentRequest || currentRequest.settled) {
|
|
404
|
+
return
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
workerMetrics.timeoutRequests += 1
|
|
408
|
+
const timeoutError = createTimeoutError(timeoutMs)
|
|
409
|
+
if (currentRequest.workerId) {
|
|
410
|
+
const worker = getWorkerById(currentRequest.workerId)
|
|
411
|
+
if (worker && worker.activeRequestId === requestId) {
|
|
412
|
+
worker.activeRequestId = ''
|
|
413
|
+
}
|
|
414
|
+
rejectRequestWithError(currentRequest, timeoutError)
|
|
415
|
+
if (worker) {
|
|
416
|
+
stopWorker(worker, `request_timeout:${requestId}`)
|
|
417
|
+
}
|
|
418
|
+
dispatchQueuedRequests()
|
|
419
|
+
return
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
rejectRequestWithError(currentRequest, timeoutError)
|
|
423
|
+
}, timeoutMs),
|
|
283
424
|
}
|
|
425
|
+
|
|
426
|
+
request.timer.unref?.()
|
|
427
|
+
requestMap.set(requestId, request)
|
|
428
|
+
requestQueue.push(request)
|
|
429
|
+
dispatchQueuedRequests()
|
|
284
430
|
})
|
|
285
431
|
}
|
|
286
432
|
|
|
287
433
|
export function __getGitDiffWorkerPidForTest() {
|
|
288
|
-
return Number(
|
|
434
|
+
return Number(workerPool[0]?.child?.pid || 0)
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export function __getGitDiffWorkerPidsForTest() {
|
|
438
|
+
return workerPool.map((worker) => Number(worker.child?.pid || 0)).filter((pid) => pid > 0)
|
|
289
439
|
}
|
|
290
440
|
|
|
291
441
|
export function getGitDiffWorkerDiagnostics() {
|
|
292
442
|
return {
|
|
293
443
|
worker: {
|
|
294
|
-
pid: Number(
|
|
295
|
-
running:
|
|
296
|
-
pendingRequests:
|
|
297
|
-
stderrTail:
|
|
444
|
+
pid: Number(workerPool[0]?.child?.pid || 0),
|
|
445
|
+
running: workerPool.some((worker) => !worker.stopping && worker.child?.exitCode === null && !worker.child?.killed),
|
|
446
|
+
pendingRequests: requestQueue.length + activeRequests.size,
|
|
447
|
+
stderrTail: String(workerPool[0]?.stderrBuffer || '').trim(),
|
|
298
448
|
},
|
|
449
|
+
workers: workerPool.map((worker) => ({
|
|
450
|
+
id: worker.id,
|
|
451
|
+
pid: Number(worker.child?.pid || 0),
|
|
452
|
+
running: !worker.stopping && worker.child?.exitCode === null && !worker.child?.killed,
|
|
453
|
+
activeRequestId: String(worker.activeRequestId || '').trim(),
|
|
454
|
+
stderrTail: String(worker.stderrBuffer || '').trim(),
|
|
455
|
+
startedAt: worker.startedAt,
|
|
456
|
+
})),
|
|
299
457
|
metrics: {
|
|
300
458
|
...workerMetrics,
|
|
459
|
+
maxWorkers: DEFAULT_MAX_WORKERS,
|
|
460
|
+
queueDepth: requestQueue.length,
|
|
461
|
+
activeRequestCount: activeRequests.size,
|
|
462
|
+
workerCount: workerPool.length,
|
|
301
463
|
lastWorkerExitSignal: String(workerMetrics.lastWorkerExitSignal || ''),
|
|
302
464
|
lastWorkerExitReason: String(workerMetrics.lastWorkerExitReason || ''),
|
|
303
465
|
lastRequest: workerMetrics.lastRequest ? { ...workerMetrics.lastRequest } : null,
|
|
@@ -413,6 +413,7 @@ function registerTaskRoutes(app, options = {}) {
|
|
|
413
413
|
filePath: request.query?.filePath,
|
|
414
414
|
includeFiles: String(request.query?.includeFiles || '').trim() !== 'false',
|
|
415
415
|
includeStats: String(request.query?.includeStats || '').trim() !== 'false',
|
|
416
|
+
timeoutMs: request.query?.timeoutMs,
|
|
416
417
|
})
|
|
417
418
|
} catch (error) {
|
|
418
419
|
if (error?.statusCode) {
|