@useorgx/openclaw-plugin 0.7.20 → 0.7.24

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 (165) hide show
  1. package/dashboard/dist/assets/B6VftyY6.js +1 -0
  2. package/dashboard/dist/assets/B6VftyY6.js.br +0 -0
  3. package/dashboard/dist/assets/B6VftyY6.js.gz +0 -0
  4. package/dashboard/dist/assets/{Dm0CfDGr.js → BANQdlC4.js} +1 -1
  5. package/dashboard/dist/assets/BANQdlC4.js.br +0 -0
  6. package/dashboard/dist/assets/BANQdlC4.js.gz +0 -0
  7. package/dashboard/dist/assets/{_zpQCpjm.js → BPL4CL3c.js} +1 -1
  8. package/dashboard/dist/assets/BPL4CL3c.js.br +0 -0
  9. package/dashboard/dist/assets/BPL4CL3c.js.gz +0 -0
  10. package/dashboard/dist/assets/{DXVs61e1.js → BZCkOZ20.js} +1 -1
  11. package/dashboard/dist/assets/BZCkOZ20.js.br +0 -0
  12. package/dashboard/dist/assets/BZCkOZ20.js.gz +0 -0
  13. package/dashboard/dist/assets/{BYb6DARX.js → B_LdOJUa.js} +1 -1
  14. package/dashboard/dist/assets/B_LdOJUa.js.br +0 -0
  15. package/dashboard/dist/assets/B_LdOJUa.js.gz +0 -0
  16. package/dashboard/dist/assets/Bfp-wdwb.css +1 -0
  17. package/dashboard/dist/assets/Bfp-wdwb.css.br +0 -0
  18. package/dashboard/dist/assets/Bfp-wdwb.css.gz +0 -0
  19. package/dashboard/dist/assets/{DibzNd0I.js → BvFcH_Iy.js} +1 -1
  20. package/dashboard/dist/assets/BvFcH_Iy.js.br +0 -0
  21. package/dashboard/dist/assets/BvFcH_Iy.js.gz +0 -0
  22. package/dashboard/dist/assets/By0MIBj_.js +1 -0
  23. package/dashboard/dist/assets/By0MIBj_.js.br +0 -0
  24. package/dashboard/dist/assets/By0MIBj_.js.gz +0 -0
  25. package/dashboard/dist/assets/C0i7ABUU.js +212 -0
  26. package/dashboard/dist/assets/C0i7ABUU.js.br +0 -0
  27. package/dashboard/dist/assets/C0i7ABUU.js.gz +0 -0
  28. package/dashboard/dist/assets/CFB0MM7j.js +1 -0
  29. package/dashboard/dist/assets/CFB0MM7j.js.br +0 -0
  30. package/dashboard/dist/assets/CFB0MM7j.js.gz +0 -0
  31. package/dashboard/dist/assets/CQSRb1yu.js +1 -0
  32. package/dashboard/dist/assets/CQSRb1yu.js.br +0 -0
  33. package/dashboard/dist/assets/CQSRb1yu.js.gz +0 -0
  34. package/dashboard/dist/assets/{wa4jJQK9.js → CUoQoSm-.js} +1 -1
  35. package/dashboard/dist/assets/CUoQoSm-.js.br +0 -0
  36. package/dashboard/dist/assets/CUoQoSm-.js.gz +0 -0
  37. package/dashboard/dist/assets/Ckd1R1iE.js +1 -0
  38. package/dashboard/dist/assets/Ckd1R1iE.js.br +0 -0
  39. package/dashboard/dist/assets/Ckd1R1iE.js.gz +0 -0
  40. package/dashboard/dist/assets/{BGY6oI8h.js → CqRNb2EL.js} +1 -1
  41. package/dashboard/dist/assets/CqRNb2EL.js.br +0 -0
  42. package/dashboard/dist/assets/CqRNb2EL.js.gz +0 -0
  43. package/dashboard/dist/assets/{DAr4MfFk.js → DClUc9rw.js} +1 -1
  44. package/dashboard/dist/assets/DClUc9rw.js.br +0 -0
  45. package/dashboard/dist/assets/DClUc9rw.js.gz +0 -0
  46. package/dashboard/dist/assets/DF2PMTwT.js +1 -0
  47. package/dashboard/dist/assets/DF2PMTwT.js.br +0 -0
  48. package/dashboard/dist/assets/DF2PMTwT.js.gz +0 -0
  49. package/dashboard/dist/assets/{B014hrCe.js → DJYl7gyA.js} +2 -2
  50. package/dashboard/dist/assets/DJYl7gyA.js.br +0 -0
  51. package/dashboard/dist/assets/DJYl7gyA.js.gz +0 -0
  52. package/dashboard/dist/assets/{BoDhb8_y.js → DZtNMX0t.js} +2 -2
  53. package/dashboard/dist/assets/DZtNMX0t.js.br +0 -0
  54. package/dashboard/dist/assets/DZtNMX0t.js.gz +0 -0
  55. package/dashboard/dist/assets/DlEa8PI0.js +1 -0
  56. package/dashboard/dist/assets/DlEa8PI0.js.br +0 -0
  57. package/dashboard/dist/assets/DlEa8PI0.js.gz +0 -0
  58. package/dashboard/dist/assets/M4QxcXjh.js +1 -0
  59. package/dashboard/dist/assets/M4QxcXjh.js.br +0 -0
  60. package/dashboard/dist/assets/M4QxcXjh.js.gz +0 -0
  61. package/dashboard/dist/assets/{CV0sWMbv.js → MrW1ixGx.js} +1 -1
  62. package/dashboard/dist/assets/MrW1ixGx.js.br +0 -0
  63. package/dashboard/dist/assets/MrW1ixGx.js.gz +0 -0
  64. package/dashboard/dist/index.html +2 -2
  65. package/dashboard/dist/index.html.br +0 -0
  66. package/dashboard/dist/index.html.gz +0 -0
  67. package/dist/activity-store.js +68 -8
  68. package/dist/agent-run-store.js +162 -24
  69. package/dist/cli/orgx.d.ts +3 -0
  70. package/dist/config/resolution.d.ts +7 -0
  71. package/dist/config/resolution.js +13 -5
  72. package/dist/contracts/onboarding-state.d.ts +2 -0
  73. package/dist/contracts/onboarding-state.js +23 -0
  74. package/dist/contracts/shared-types.d.ts +45 -0
  75. package/dist/http/helpers/auto-continue-engine.d.ts +23 -0
  76. package/dist/http/helpers/auto-continue-engine.js +468 -85
  77. package/dist/http/helpers/autopilot-runtime.js +5 -1
  78. package/dist/http/helpers/autopilot-slice-utils.js +25 -1
  79. package/dist/http/helpers/decision-mapper.d.ts +1 -0
  80. package/dist/http/helpers/decision-mapper.js +19 -2
  81. package/dist/http/helpers/dispatch-lifecycle.js +3 -0
  82. package/dist/http/helpers/mission-control.d.ts +1 -0
  83. package/dist/http/helpers/mission-control.js +5 -2
  84. package/dist/http/helpers/slice-run-projections.d.ts +27 -0
  85. package/dist/http/helpers/slice-run-projections.js +198 -10
  86. package/dist/http/helpers/triage-mapper.js +499 -6
  87. package/dist/http/helpers/value-utils.d.ts +1 -0
  88. package/dist/http/helpers/value-utils.js +17 -0
  89. package/dist/http/index.d.ts +1 -0
  90. package/dist/http/index.js +179 -46
  91. package/dist/http/router.js +64 -9
  92. package/dist/http/routes/live-legacy.d.ts +19 -2
  93. package/dist/http/routes/live-legacy.js +110 -27
  94. package/dist/http/routes/live-snapshot.d.ts +16 -2
  95. package/dist/http/routes/live-snapshot.js +169 -25
  96. package/dist/http/routes/live-triage.js +6 -1
  97. package/dist/http/routes/mission-control-actions.d.ts +9 -0
  98. package/dist/http/routes/mission-control-actions.js +185 -7
  99. package/dist/http/routes/mission-control-read.d.ts +13 -0
  100. package/dist/http/routes/mission-control-read.js +100 -219
  101. package/dist/http/routes/onboarding.d.ts +1 -0
  102. package/dist/http/routes/onboarding.js +17 -0
  103. package/dist/index.d.ts +5 -0
  104. package/dist/index.js +199 -123
  105. package/dist/outbox.d.ts +0 -2
  106. package/dist/outbox.js +259 -148
  107. package/dist/reporting/rollups.js +18 -11
  108. package/dist/runtime-instance-store.js +212 -58
  109. package/dist/stores/materialized-snapshot-store.d.ts +18 -0
  110. package/dist/stores/materialized-snapshot-store.js +91 -0
  111. package/dist/stores/sqlite-state.d.ts +6 -0
  112. package/dist/stores/sqlite-state.js +330 -0
  113. package/package.json +5 -1
  114. package/dashboard/dist/assets/B014hrCe.js.br +0 -0
  115. package/dashboard/dist/assets/B014hrCe.js.gz +0 -0
  116. package/dashboard/dist/assets/BCudUvwg.js +0 -1
  117. package/dashboard/dist/assets/BCudUvwg.js.br +0 -0
  118. package/dashboard/dist/assets/BCudUvwg.js.gz +0 -0
  119. package/dashboard/dist/assets/BGY6oI8h.js.br +0 -0
  120. package/dashboard/dist/assets/BGY6oI8h.js.gz +0 -0
  121. package/dashboard/dist/assets/BJI1Iy5v.css +0 -1
  122. package/dashboard/dist/assets/BJI1Iy5v.css.br +0 -0
  123. package/dashboard/dist/assets/BJI1Iy5v.css.gz +0 -0
  124. package/dashboard/dist/assets/BUvcp_7V.js +0 -1
  125. package/dashboard/dist/assets/BUvcp_7V.js.br +0 -0
  126. package/dashboard/dist/assets/BUvcp_7V.js.gz +0 -0
  127. package/dashboard/dist/assets/BV2Tf8S2.js +0 -212
  128. package/dashboard/dist/assets/BV2Tf8S2.js.br +0 -0
  129. package/dashboard/dist/assets/BV2Tf8S2.js.gz +0 -0
  130. package/dashboard/dist/assets/BYb6DARX.js.br +0 -0
  131. package/dashboard/dist/assets/BYb6DARX.js.gz +0 -0
  132. package/dashboard/dist/assets/BoDhb8_y.js.br +0 -0
  133. package/dashboard/dist/assets/BoDhb8_y.js.gz +0 -0
  134. package/dashboard/dist/assets/Bqk_l0k6.js +0 -1
  135. package/dashboard/dist/assets/Bqk_l0k6.js.br +0 -0
  136. package/dashboard/dist/assets/Bqk_l0k6.js.gz +0 -0
  137. package/dashboard/dist/assets/C-MOJWHs.js +0 -1
  138. package/dashboard/dist/assets/C-MOJWHs.js.br +0 -0
  139. package/dashboard/dist/assets/C-MOJWHs.js.gz +0 -0
  140. package/dashboard/dist/assets/CV0sWMbv.js.br +0 -0
  141. package/dashboard/dist/assets/CV0sWMbv.js.gz +0 -0
  142. package/dashboard/dist/assets/CaAkScfa.js +0 -1
  143. package/dashboard/dist/assets/CaAkScfa.js.br +0 -0
  144. package/dashboard/dist/assets/CaAkScfa.js.gz +0 -0
  145. package/dashboard/dist/assets/Ck5KlsPN.js +0 -1
  146. package/dashboard/dist/assets/Ck5KlsPN.js.br +0 -0
  147. package/dashboard/dist/assets/Ck5KlsPN.js.gz +0 -0
  148. package/dashboard/dist/assets/D2G51wQm.js +0 -1
  149. package/dashboard/dist/assets/D2G51wQm.js.br +0 -0
  150. package/dashboard/dist/assets/D2G51wQm.js.gz +0 -0
  151. package/dashboard/dist/assets/DAr4MfFk.js.br +0 -0
  152. package/dashboard/dist/assets/DAr4MfFk.js.gz +0 -0
  153. package/dashboard/dist/assets/DXVs61e1.js.br +0 -0
  154. package/dashboard/dist/assets/DXVs61e1.js.gz +0 -0
  155. package/dashboard/dist/assets/DibzNd0I.js.br +0 -0
  156. package/dashboard/dist/assets/DibzNd0I.js.gz +0 -0
  157. package/dashboard/dist/assets/Dm0CfDGr.js.br +0 -0
  158. package/dashboard/dist/assets/Dm0CfDGr.js.gz +0 -0
  159. package/dashboard/dist/assets/_zpQCpjm.js.br +0 -0
  160. package/dashboard/dist/assets/_zpQCpjm.js.gz +0 -0
  161. package/dashboard/dist/assets/uNGpYMSH.js +0 -1
  162. package/dashboard/dist/assets/uNGpYMSH.js.br +0 -0
  163. package/dashboard/dist/assets/uNGpYMSH.js.gz +0 -0
  164. package/dashboard/dist/assets/wa4jJQK9.js.br +0 -0
  165. package/dashboard/dist/assets/wa4jJQK9.js.gz +0 -0
@@ -9,6 +9,33 @@ const PLAY_QUEUE_LOOKUP_TIMEOUT_MS = (() => {
9
9
  return 350;
10
10
  return Math.max(200, Math.floor(parsed));
11
11
  })();
12
+ function playOutcomeMessage(input) {
13
+ const workstreamLabel = input.workstreamTitle?.trim() || "this workstream";
14
+ switch (input.outcome) {
15
+ case "dispatch_pending":
16
+ return `Dispatching ${workstreamLabel}; waiting for slice start.`;
17
+ case "started":
18
+ return `Started ${workstreamLabel}.`;
19
+ case "fallback_started":
20
+ return `Started ${workstreamLabel} using the fallback runner.`;
21
+ case "slice_completed":
22
+ return `${workstreamLabel} completed before the queue refreshed.`;
23
+ case "slice_blocked":
24
+ return input.startReasonLabel?.trim() || `${workstreamLabel} needs input before it can continue.`;
25
+ case "slice_error":
26
+ return `${workstreamLabel} hit an error before it could keep running.`;
27
+ case "initiative_run_active":
28
+ return "Autopilot is already running for this initiative.";
29
+ case "no_dispatchable_task":
30
+ return input.startReasonLabel?.trim() || `No dispatchable task is available for ${workstreamLabel}.`;
31
+ case "spawn_guard_rate_limited":
32
+ return input.fallbackBlockedReason?.trim() || `${workstreamLabel} is rate limited right now.`;
33
+ case "spawn_guard_blocked":
34
+ return input.fallbackBlockedReason?.trim() || `${workstreamLabel} is blocked by the current execution policy.`;
35
+ default:
36
+ return input.startReasonLabel?.trim() || `Unable to dispatch ${workstreamLabel} right now.`;
37
+ }
38
+ }
12
39
  const IN_PROGRESS_TASK_STATUSES = new Set([
13
40
  "in_progress",
14
41
  "inprogress",
@@ -399,6 +426,23 @@ export function registerMissionControlActionsRoutes(router, deps) {
399
426
  : null;
400
427
  const maxParallelSlices = normalizeMaxParallelSlices(requestedMaxParallelSlicesRaw, queuePreferredParallel ?? 1);
401
428
  const parallelMode = normalizeParallelMode(requestedParallelModeRaw);
429
+ const requestedWorkspaceId = deps.pickString(payload, [
430
+ "workspaceId",
431
+ "workspace_id",
432
+ "command_center_id",
433
+ "projectId",
434
+ "project_id",
435
+ ]) ??
436
+ query.get("workspaceId") ??
437
+ query.get("workspace_id") ??
438
+ query.get("command_center_id") ??
439
+ query.get("projectId") ??
440
+ query.get("project_id") ??
441
+ null;
442
+ const queueWorkstreamTitle = matchedQueueItem?.workstreamTitle ?? null;
443
+ const queueStartReasonCode = matchedQueueItem?.startReasonCode ?? null;
444
+ const queueStartReasonLabel = matchedQueueItem?.startReasonLabel ?? null;
445
+ const queueDispatchableTask = matchedQueueItem?.dispatchableTask ?? null;
402
446
  const existingRun = deps.autoContinueRuns.get(initiativeId) ?? null;
403
447
  const existingActiveRunIds = Array.isArray(existingRun?.activeSliceRunIds)
404
448
  ? (existingRun?.activeSliceRunIds)
@@ -415,6 +459,13 @@ export function registerMissionControlActionsRoutes(router, deps) {
415
459
  const activeWorkstreamTitle = activeSlice?.workstreamTitle ?? null;
416
460
  deps.sendJson(res, 409, {
417
461
  ok: false,
462
+ outcome: "initiative_run_active",
463
+ reasonCode: "initiative_run_active",
464
+ message: playOutcomeMessage({
465
+ outcome: "initiative_run_active",
466
+ workstreamTitle: queueWorkstreamTitle,
467
+ startReasonLabel: queueStartReasonLabel,
468
+ }),
418
469
  code: "auto_continue_already_running",
419
470
  error: activeWorkstreamId || activeWorkstreamTitle
420
471
  ? `Auto-continue is already running for ${activeWorkstreamTitle ?? activeWorkstreamId}. Stop it before launching another Play run.`
@@ -423,12 +474,38 @@ export function registerMissionControlActionsRoutes(router, deps) {
423
474
  activeRunIds: existingActiveRunIds,
424
475
  activeWorkstreamId,
425
476
  activeWorkstreamTitle,
477
+ dispatchableTask: queueDispatchableTask,
426
478
  error_location: "mission-control.next-up.play.concurrent_run",
427
479
  });
428
480
  return;
429
481
  }
482
+ if (matchedQueueItem?.canStartNow === false) {
483
+ const reasonCode = queueStartReasonCode && queueStartReasonCode.trim().length > 0
484
+ ? queueStartReasonCode.trim()
485
+ : "no_dispatchable_task";
486
+ const message = playOutcomeMessage({
487
+ outcome: reasonCode,
488
+ workstreamTitle: queueWorkstreamTitle,
489
+ startReasonLabel: queueStartReasonLabel,
490
+ });
491
+ deps.sendJson(res, 409, {
492
+ ok: false,
493
+ outcome: reasonCode,
494
+ reasonCode,
495
+ message,
496
+ code: reasonCode,
497
+ error: message,
498
+ initiativeId,
499
+ workstreamId,
500
+ agentId,
501
+ dispatchableTask: queueDispatchableTask,
502
+ error_location: "mission-control.next-up.play.preflight",
503
+ });
504
+ return;
505
+ }
430
506
  const run = await deps.startAutoContinueRun({
431
507
  initiativeId,
508
+ workspaceId: requestedWorkspaceId,
432
509
  agentId,
433
510
  agentName: requestedAgentName,
434
511
  tokenBudget,
@@ -477,7 +554,7 @@ export function registerMissionControlActionsRoutes(router, deps) {
477
554
  // Give short-lived workers a brief window to flush output so Play can resolve
478
555
  // in one request/response cycle without requiring extra manual ticks.
479
556
  if (run.activeRunId) {
480
- await new Promise((resolve) => setTimeout(resolve, 140));
557
+ await new Promise((resolve) => setTimeout(resolve, 500));
481
558
  await deps.tickAutoContinueRun(run);
482
559
  }
483
560
  fallbackDispatch = await maybeDispatchFallback();
@@ -508,12 +585,20 @@ export function registerMissionControlActionsRoutes(router, deps) {
508
585
  });
509
586
  deps.sendJson(res, 202, {
510
587
  ok: true,
588
+ outcome: "dispatch_pending",
589
+ reasonCode: "dispatch_pending",
590
+ message: playOutcomeMessage({
591
+ outcome: "dispatch_pending",
592
+ workstreamTitle: queueWorkstreamTitle,
593
+ startReasonLabel: queueStartReasonLabel,
594
+ }),
511
595
  run,
512
596
  initiativeId,
513
597
  workstreamId,
514
598
  agentId,
515
599
  ...playDispatchEnvelope("pending"),
516
600
  sessionId: null,
601
+ dispatchableTask: queueDispatchableTask,
517
602
  slice: {
518
603
  scope,
519
604
  taskIds: matchedQueueItem?.sliceTaskIds ?? [],
@@ -552,12 +637,20 @@ export function registerMissionControlActionsRoutes(router, deps) {
552
637
  : "slice_error";
553
638
  deps.sendJson(res, 200, {
554
639
  ok: true,
640
+ outcome: finalizedDispatchMode,
641
+ reasonCode: finalizedDispatchMode,
642
+ message: playOutcomeMessage({
643
+ outcome: finalizedDispatchMode,
644
+ workstreamTitle: queueWorkstreamTitle,
645
+ startReasonLabel: queueStartReasonLabel,
646
+ }),
555
647
  run,
556
648
  initiativeId,
557
649
  workstreamId,
558
650
  agentId,
559
651
  ...playDispatchEnvelope(finalizedDispatchMode),
560
652
  sessionId: run.lastRunId,
653
+ dispatchableTask: queueDispatchableTask,
561
654
  slice: {
562
655
  scope,
563
656
  taskIds: matchedQueueItem?.sliceTaskIds ?? [],
@@ -575,12 +668,20 @@ export function registerMissionControlActionsRoutes(router, deps) {
575
668
  if (dispatchMode === "none" && run.status === "running" && !run.stopReason) {
576
669
  deps.sendJson(res, 202, {
577
670
  ok: true,
671
+ outcome: "dispatch_pending",
672
+ reasonCode: "dispatch_pending",
673
+ message: playOutcomeMessage({
674
+ outcome: "dispatch_pending",
675
+ workstreamTitle: queueWorkstreamTitle,
676
+ startReasonLabel: queueStartReasonLabel,
677
+ }),
578
678
  run,
579
679
  initiativeId,
580
680
  workstreamId,
581
681
  agentId,
582
682
  ...playDispatchEnvelope("pending"),
583
683
  sessionId: null,
684
+ dispatchableTask: queueDispatchableTask,
584
685
  slice: {
585
686
  scope,
586
687
  taskIds: matchedQueueItem?.sliceTaskIds ?? [],
@@ -597,6 +698,15 @@ export function registerMissionControlActionsRoutes(router, deps) {
597
698
  }
598
699
  if (dispatchMode === "none") {
599
700
  const fallbackBlockedReason = fallbackDispatch?.blockedReason ?? null;
701
+ const reasonCode = fallbackBlockedReason
702
+ ? fallbackDispatch?.retryable
703
+ ? "spawn_guard_rate_limited"
704
+ : "spawn_guard_blocked"
705
+ : run.stopReason === "blocked"
706
+ ? "no_dispatchable_task"
707
+ : run.stopReason === "completed"
708
+ ? "no_dispatchable_task"
709
+ : "dispatch_failed";
600
710
  const reason = fallbackBlockedReason ??
601
711
  (run.stopReason === "blocked"
602
712
  ? "No dispatchable task is ready for this workstream yet."
@@ -605,29 +715,42 @@ export function registerMissionControlActionsRoutes(router, deps) {
605
715
  : "Unable to dispatch this workstream right now.");
606
716
  deps.sendJson(res, fallbackDispatch?.retryable ? 429 : 409, {
607
717
  ok: false,
608
- code: fallbackBlockedReason
609
- ? fallbackDispatch?.retryable
610
- ? "spawn_guard_rate_limited"
611
- : "spawn_guard_blocked"
612
- : undefined,
718
+ outcome: reasonCode,
719
+ reasonCode,
720
+ message: playOutcomeMessage({
721
+ outcome: reasonCode,
722
+ workstreamTitle: queueWorkstreamTitle,
723
+ startReasonLabel: queueStartReasonLabel ?? reason,
724
+ fallbackBlockedReason,
725
+ }),
726
+ code: reasonCode,
613
727
  error: reason,
614
728
  run,
615
729
  initiativeId,
616
730
  workstreamId,
617
731
  agentId,
618
732
  fallbackDispatch,
733
+ dispatchableTask: queueDispatchableTask,
619
734
  error_location: "mission-control.next-up.play.dispatch",
620
735
  });
621
736
  return;
622
737
  }
623
738
  deps.sendJson(res, 200, {
624
739
  ok: true,
740
+ outcome: dispatchMode === "fallback" ? "fallback_started" : "started",
741
+ reasonCode: dispatchMode === "fallback" ? "fallback_started" : "started",
742
+ message: playOutcomeMessage({
743
+ outcome: dispatchMode === "fallback" ? "fallback_started" : "started",
744
+ workstreamTitle: queueWorkstreamTitle,
745
+ startReasonLabel: queueStartReasonLabel,
746
+ }),
625
747
  run,
626
748
  initiativeId,
627
749
  workstreamId,
628
750
  agentId,
629
751
  ...playDispatchEnvelope(dispatchMode),
630
752
  sessionId: run.activeRunId ?? fallbackDispatch?.sessionId ?? null,
753
+ dispatchableTask: queueDispatchableTask,
631
754
  slice: {
632
755
  scope,
633
756
  taskIds: matchedQueueItem?.sliceTaskIds ?? [],
@@ -1566,8 +1689,22 @@ export function registerMissionControlActionsRoutes(router, deps) {
1566
1689
  const startScope = startScopeRaw === "milestone" || startScopeRaw === "workstream"
1567
1690
  ? startScopeRaw
1568
1691
  : "task";
1692
+ const requestedWorkspaceId = deps.pickString(payload, [
1693
+ "workspaceId",
1694
+ "workspace_id",
1695
+ "command_center_id",
1696
+ "projectId",
1697
+ "project_id",
1698
+ ]) ??
1699
+ query.get("workspaceId") ??
1700
+ query.get("workspace_id") ??
1701
+ query.get("command_center_id") ??
1702
+ query.get("projectId") ??
1703
+ query.get("project_id") ??
1704
+ null;
1569
1705
  const run = await deps.startAutoContinueRun({
1570
1706
  initiativeId,
1707
+ workspaceId: requestedWorkspaceId,
1571
1708
  agentId,
1572
1709
  agentName: await deps.resolveAgentDisplayName(agentId, null),
1573
1710
  tokenBudget,
@@ -1586,7 +1723,48 @@ export function registerMissionControlActionsRoutes(router, deps) {
1586
1723
  initiativeId,
1587
1724
  workstreamIds: allowedWorkstreamIds,
1588
1725
  });
1589
- deps.sendJson(res, 200, { ok: true, ...dispatchEnvelope, run });
1726
+ await deps.tickAutoContinueRun(run);
1727
+ const activeRunIds = Array.isArray(run.activeSliceRunIds)
1728
+ ? run.activeSliceRunIds.filter((id) => typeof id === "string" && id.trim().length > 0)
1729
+ : typeof run.activeRunId === "string" && run.activeRunId.trim().length > 0
1730
+ ? [run.activeRunId]
1731
+ : [];
1732
+ if (activeRunIds.length > 0) {
1733
+ await new Promise((resolve) => setTimeout(resolve, 500));
1734
+ await deps.tickAutoContinueRun(run);
1735
+ }
1736
+ const reconciledActiveRunIds = Array.isArray(run.activeSliceRunIds)
1737
+ ? run.activeSliceRunIds.filter((id) => typeof id === "string" && id.trim().length > 0)
1738
+ : typeof run.activeRunId === "string" && run.activeRunId.trim().length > 0
1739
+ ? [run.activeRunId]
1740
+ : [];
1741
+ const outcome = reconciledActiveRunIds.length > 0 || (run.status === "running" && !run.stopReason)
1742
+ ? "started"
1743
+ : run.stopReason === "blocked"
1744
+ ? "blocked"
1745
+ : run.stopReason === "completed"
1746
+ ? "completed"
1747
+ : run.stopReason === "error"
1748
+ ? "error"
1749
+ : "pending";
1750
+ const message = outcome === "started"
1751
+ ? "Autopilot enabled and running."
1752
+ : outcome === "blocked"
1753
+ ? "Autopilot enabled, but it immediately needs your input."
1754
+ : outcome === "completed"
1755
+ ? "Autopilot enabled and immediately completed the available work."
1756
+ : outcome === "error"
1757
+ ? "Autopilot hit an error before it could keep running."
1758
+ : "Autopilot is starting.";
1759
+ deps.sendJson(res, 200, {
1760
+ ok: true,
1761
+ outcome,
1762
+ reasonCode: outcome === "blocked" ? "blocked" : outcome,
1763
+ message,
1764
+ ...dispatchEnvelope,
1765
+ workstreamIds: allowedWorkstreamIds,
1766
+ run,
1767
+ });
1590
1768
  }
1591
1769
  catch (err) {
1592
1770
  sendRouteException(res, "mission-control.auto-continue.start.handler", err);
@@ -39,6 +39,15 @@ type NextUpQueueItem = {
39
39
  sliceTaskCount?: number | null;
40
40
  sliceMilestoneId?: string | null;
41
41
  milestoneBreakdown?: MilestoneBreakdownEntry[];
42
+ canStartNow?: boolean;
43
+ startReasonCode?: string | null;
44
+ startReasonLabel?: string | null;
45
+ dispatchableTask?: {
46
+ id: string;
47
+ title: string;
48
+ scope: "task" | "milestone" | "workstream";
49
+ milestoneId?: string | null;
50
+ } | null;
42
51
  isPinned?: boolean;
43
52
  pinnedRank?: number | null;
44
53
  compositeScore?: number;
@@ -56,6 +65,10 @@ type SliceRunnerAgent = {
56
65
  type NextUpQueue = {
57
66
  items: NextUpQueueItem[];
58
67
  degraded: string[];
68
+ summary?: {
69
+ visibleTotal: number;
70
+ stateCounts: Record<NextUpQueueItem["queueState"], number>;
71
+ };
59
72
  };
60
73
  type MilestoneBreakdownTask = {
61
74
  id: string;