@muyichengshayu/promptx 0.2.7 → 0.2.8

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/apps/runner/src/engines/claudeCodeRunner.js +69 -1
  3. package/apps/runner/src/engines/claudeCodeRunner.test.js +279 -0
  4. package/apps/runner/src/engines/openCodeRunner.test.js +73 -0
  5. package/apps/runner/src/engines/shellRunner.test.js +46 -0
  6. package/apps/runner/src/runManager.js +110 -11
  7. package/apps/runner/src/runManager.test.js +913 -0
  8. package/apps/runner/src/serverClient.test.js +93 -0
  9. package/apps/server/src/agentSessionDiscovery.test.js +127 -0
  10. package/apps/server/src/agents/claudeCodeRunner.test.js +433 -0
  11. package/apps/server/src/agents/openCodeRunner.test.js +236 -0
  12. package/apps/server/src/agents/runnerContract.test.js +382 -0
  13. package/apps/server/src/appPaths.test.js +52 -0
  14. package/apps/server/src/assetRoutes.test.js +168 -0
  15. package/apps/server/src/codex.test.js +518 -0
  16. package/apps/server/src/codexRoutes.test.js +376 -0
  17. package/apps/server/src/codexRuns.test.js +160 -0
  18. package/apps/server/src/codexSessions.test.js +369 -0
  19. package/apps/server/src/db.test.js +182 -0
  20. package/apps/server/src/gitDiff.test.js +542 -0
  21. package/apps/server/src/gitDiffClient.test.js +140 -0
  22. package/apps/server/src/internalRoutes.test.js +134 -0
  23. package/apps/server/src/maintenance.test.js +154 -0
  24. package/apps/server/src/processControl.test.js +147 -0
  25. package/apps/server/src/relayClient.test.js +478 -0
  26. package/apps/server/src/relayConfig.test.js +73 -0
  27. package/apps/server/src/relayProtocol.test.js +49 -0
  28. package/apps/server/src/relayServer.test.js +798 -0
  29. package/apps/server/src/relayTenants.test.js +137 -0
  30. package/apps/server/src/relayUsageStore.test.js +65 -0
  31. package/apps/server/src/repository.test.js +150 -0
  32. package/apps/server/src/runDispatchService.test.js +563 -0
  33. package/apps/server/src/runEventIngest.test.js +225 -0
  34. package/apps/server/src/runRecovery.test.js +73 -0
  35. package/apps/server/src/runnerClient.test.js +80 -0
  36. package/apps/server/src/runnerDispatch.test.js +136 -0
  37. package/apps/server/src/systemConfig.test.js +112 -0
  38. package/apps/server/src/systemRoutes.test.js +319 -0
  39. package/apps/server/src/taskRoutes.test.js +726 -0
  40. package/apps/server/src/upload.test.js +30 -0
  41. package/apps/server/src/webAppRoutes.test.js +67 -0
  42. package/apps/server/src/workspaceFiles.test.js +262 -0
  43. package/package.json +14 -21
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  createSessionEnvelopeEvent,
3
3
  createSessionUpdatedEnvelopeEvent,
4
+ createStatusEnvelopeEvent,
4
5
  createStoppedEnvelopeEvent,
6
+ getAgentEngineLabel,
5
7
  } from '../../../packages/shared/src/index.js'
6
8
  import { assertAgentRunner } from './engines/index.js'
7
9
  import { getChildStopDiagnostics } from './processControl.js'
@@ -23,6 +25,14 @@ const DEFAULT_EVENT_BATCH_BYTES = Math.max(
23
25
  64 * 1024,
24
26
  Number(process.env.PROMPTX_RUNNER_EVENT_BATCH_BYTES) || 512 * 1024
25
27
  )
28
+ const DEFAULT_IDLE_PROGRESS_EVENT_MS = Math.max(
29
+ 5000,
30
+ Number(process.env.PROMPTX_RUNNER_IDLE_PROGRESS_EVENT_MS) || 15000
31
+ )
32
+ const DEFAULT_IDLE_PROGRESS_EVENT_REPEAT_MS = Math.max(
33
+ DEFAULT_IDLE_PROGRESS_EVENT_MS,
34
+ Number(process.env.PROMPTX_RUNNER_IDLE_PROGRESS_EVENT_REPEAT_MS) || DEFAULT_IDLE_PROGRESS_EVENT_MS
35
+ )
26
36
  const RUNNER_ID = String(process.env.PROMPTX_RUNNER_ID || 'local-runner').trim() || 'local-runner'
27
37
  const DISPOSE_POLL_INTERVAL_MS = Math.max(50, Number(process.env.PROMPTX_RUNNER_DISPOSE_POLL_MS) || 100)
28
38
 
@@ -195,10 +205,57 @@ function sleep(ms) {
195
205
  })
196
206
  }
197
207
 
208
+ function isProgressPayload(payload = {}) {
209
+ const type = String(payload?.type || '').trim()
210
+ return !['status', 'session', 'session.updated'].includes(type)
211
+ }
212
+
213
+ function createIdleProgressEvent(context = {}) {
214
+ const status = String(context.status || '').trim()
215
+ if (status === 'queued') {
216
+ return createStatusEnvelopeEvent({
217
+ stage: 'queued',
218
+ message: '当前仍在排队,等待 runner 空闲后开始执行。',
219
+ })
220
+ }
221
+
222
+ if (status === 'stopping') {
223
+ return createStatusEnvelopeEvent({
224
+ stage: 'stopping',
225
+ message: '正在停止执行,等待引擎退出...',
226
+ })
227
+ }
228
+
229
+ return createStatusEnvelopeEvent({
230
+ stage: 'running',
231
+ message: `${getAgentEngineLabel(context.engine || 'codex')} 仍在执行中,最近暂无新的过程输出。`,
232
+ })
233
+ }
234
+
198
235
  export function createRunManager(options = {}) {
199
236
  const serverClient = options.serverClient
200
237
  const logger = options.logger || console
201
238
  const resolveRunner = typeof options.resolveRunner === 'function' ? options.resolveRunner : assertAgentRunner
239
+ const eventFlushIntervalMs = Math.max(20, Number(options.eventFlushIntervalMs) || EVENT_FLUSH_INTERVAL_MS)
240
+ const heartbeatIntervalMs = Math.max(100, Number(options.heartbeatIntervalMs) || HEARTBEAT_INTERVAL_MS)
241
+ const stoppingHeartbeatIntervalMs = Math.max(
242
+ 100,
243
+ Number(options.stoppingHeartbeatIntervalMs) || STOPPING_HEARTBEAT_INTERVAL_MS
244
+ )
245
+ const queuedHeartbeatIntervalMs = Math.max(
246
+ 100,
247
+ Number(options.queuedHeartbeatIntervalMs) || QUEUED_HEARTBEAT_INTERVAL_MS
248
+ )
249
+ const defaultStopTimeoutMs = Math.max(1000, Number(options.defaultStopTimeoutMs) || DEFAULT_STOP_TIMEOUT_MS)
250
+ const stopTimeoutBufferMs = Math.max(200, Number(options.stopTimeoutBufferMs) || STOP_TIMEOUT_BUFFER_MS)
251
+ const idleProgressEventMs = Math.max(
252
+ heartbeatIntervalMs,
253
+ Number(options.idleProgressEventMs) || DEFAULT_IDLE_PROGRESS_EVENT_MS
254
+ )
255
+ const idleProgressEventRepeatMs = Math.max(
256
+ idleProgressEventMs,
257
+ Number(options.idleProgressEventRepeatMs) || DEFAULT_IDLE_PROGRESS_EVENT_REPEAT_MS
258
+ )
202
259
  const runtimeConfig = {
203
260
  maxConcurrentRuns: normalizeMaxConcurrentRuns(options.maxConcurrentRuns, DEFAULT_MAX_CONCURRENT_RUNS),
204
261
  }
@@ -268,6 +325,11 @@ export function createRunManager(options = {}) {
268
325
  ? payload
269
326
  : { type: 'status', message: String(payload || '') }
270
327
 
328
+ if (isProgressPayload(normalizedPayload)) {
329
+ context.lastProgressEventAt = Date.now()
330
+ context.lastIdleProgressEventAt = 0
331
+ }
332
+
271
333
  context.lastSeq += 1
272
334
  context.eventBuffer.push({
273
335
  runId: context.runId,
@@ -371,10 +433,40 @@ export function createRunManager(options = {}) {
371
433
  context.flushTimer = setTimeout(() => {
372
434
  context.flushTimer = null
373
435
  flushEvents(context).catch(() => {})
374
- }, EVENT_FLUSH_INTERVAL_MS)
436
+ }, eventFlushIntervalMs)
375
437
  context.flushTimer.unref?.()
376
438
  }
377
439
 
440
+ function maybeQueueIdleProgressEvent(context) {
441
+ if (!context || context.finalized) {
442
+ return
443
+ }
444
+
445
+ const status = String(context.status || '').trim()
446
+ if (!['queued', 'starting', 'running', 'stopping'].includes(status)) {
447
+ return
448
+ }
449
+
450
+ const now = Date.now()
451
+ const lastProgressAt = Math.max(
452
+ 0,
453
+ Number(context.lastProgressEventAt) || 0,
454
+ Date.parse(String(context.startedAt || '')) || 0
455
+ )
456
+ const lastIdleProgressEventAt = Math.max(0, Number(context.lastIdleProgressEventAt) || 0)
457
+
458
+ if (!lastProgressAt || now - lastProgressAt < idleProgressEventMs) {
459
+ return
460
+ }
461
+
462
+ if (lastIdleProgressEventAt && now - lastIdleProgressEventAt < idleProgressEventRepeatMs) {
463
+ return
464
+ }
465
+
466
+ queueEvent(context, createIdleProgressEvent(context))
467
+ context.lastIdleProgressEventAt = now
468
+ }
469
+
378
470
  function startHeartbeat(context) {
379
471
  if (context.heartbeatTimer) {
380
472
  return
@@ -384,8 +476,9 @@ export function createRunManager(options = {}) {
384
476
  if (context.finalized) {
385
477
  return
386
478
  }
479
+ maybeQueueIdleProgressEvent(context)
387
480
  postStatus(context).catch(() => {})
388
- }, HEARTBEAT_INTERVAL_MS)
481
+ }, heartbeatIntervalMs)
389
482
  context.heartbeatTimer.unref?.()
390
483
  }
391
484
 
@@ -405,8 +498,9 @@ export function createRunManager(options = {}) {
405
498
  if (context.finalized || !isQueuedRunStatus(context.status)) {
406
499
  return
407
500
  }
501
+ maybeQueueIdleProgressEvent(context)
408
502
  postStatus(context).catch(() => {})
409
- }, QUEUED_HEARTBEAT_INTERVAL_MS)
503
+ }, queuedHeartbeatIntervalMs)
410
504
  context.queueHeartbeatTimer.unref?.()
411
505
  }
412
506
 
@@ -426,10 +520,11 @@ export function createRunManager(options = {}) {
426
520
  if (context.finalized || !context.stopRequestedAt) {
427
521
  return
428
522
  }
523
+ maybeQueueIdleProgressEvent(context)
429
524
  postStatus(context, {
430
525
  stopRequestedAt: context.stopRequestedAt,
431
526
  }).catch(() => {})
432
- }, STOPPING_HEARTBEAT_INTERVAL_MS)
527
+ }, stoppingHeartbeatIntervalMs)
433
528
  context.stopProgressTimer.unref?.()
434
529
  }
435
530
 
@@ -706,11 +801,13 @@ export function createRunManager(options = {}) {
706
801
  },
707
802
  config: {
708
803
  maxConcurrentRuns: runtimeConfig.maxConcurrentRuns,
709
- eventFlushIntervalMs: EVENT_FLUSH_INTERVAL_MS,
710
- heartbeatIntervalMs: HEARTBEAT_INTERVAL_MS,
711
- queuedHeartbeatIntervalMs: QUEUED_HEARTBEAT_INTERVAL_MS,
712
- stoppingHeartbeatIntervalMs: STOPPING_HEARTBEAT_INTERVAL_MS,
713
- defaultStopTimeoutMs: DEFAULT_STOP_TIMEOUT_MS,
804
+ eventFlushIntervalMs,
805
+ heartbeatIntervalMs,
806
+ queuedHeartbeatIntervalMs,
807
+ stoppingHeartbeatIntervalMs,
808
+ idleProgressEventMs,
809
+ idleProgressEventRepeatMs,
810
+ defaultStopTimeoutMs,
714
811
  },
715
812
  }
716
813
  },
@@ -752,6 +849,8 @@ export function createRunManager(options = {}) {
752
849
  finishedAt: '',
753
850
  stopRequestedAt: '',
754
851
  lastHeartbeatAt: '',
852
+ lastProgressEventAt: Date.now(),
853
+ lastIdleProgressEventAt: 0,
755
854
  lastSeq: 0,
756
855
  eventBuffer: [],
757
856
  flushTimer: null,
@@ -818,7 +917,7 @@ export function createRunManager(options = {}) {
818
917
 
819
918
  const stopGraceMs = Math.max(200, Number(options.forceAfterMs) || 1500)
820
919
  context.stopGraceMs = stopGraceMs
821
- const stopTimeoutMs = Math.max(DEFAULT_STOP_TIMEOUT_MS, stopGraceMs + STOP_TIMEOUT_BUFFER_MS)
920
+ const stopTimeoutMs = Math.max(defaultStopTimeoutMs, stopGraceMs + stopTimeoutBufferMs)
822
921
  ensureStopTimeout(context, stopTimeoutMs)
823
922
 
824
923
  try {
@@ -841,7 +940,7 @@ export function createRunManager(options = {}) {
841
940
  )
842
941
  )
843
942
 
844
- const deadline = Date.now() + DEFAULT_STOP_TIMEOUT_MS + STOP_TIMEOUT_BUFFER_MS
943
+ const deadline = Date.now() + defaultStopTimeoutMs + stopTimeoutBufferMs
845
944
  while (activeRuns.size && Date.now() < deadline) {
846
945
  await sleep(DISPOSE_POLL_INTERVAL_MS)
847
946
  }