@useorgx/openclaw-plugin 0.7.17 → 0.7.20

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 (111) hide show
  1. package/dashboard/dist/assets/{Crj3jKHE.js → B014hrCe.js} +1 -1
  2. package/dashboard/dist/assets/B014hrCe.js.br +0 -0
  3. package/dashboard/dist/assets/B014hrCe.js.gz +0 -0
  4. package/dashboard/dist/assets/{DBRLnKWw.js → BGY6oI8h.js} +1 -1
  5. package/dashboard/dist/assets/BGY6oI8h.js.br +0 -0
  6. package/dashboard/dist/assets/BGY6oI8h.js.gz +0 -0
  7. package/dashboard/dist/assets/BJI1Iy5v.css +1 -0
  8. package/dashboard/dist/assets/BJI1Iy5v.css.br +0 -0
  9. package/dashboard/dist/assets/BJI1Iy5v.css.gz +0 -0
  10. package/dashboard/dist/assets/BUvcp_7V.js +1 -0
  11. package/dashboard/dist/assets/BUvcp_7V.js.br +0 -0
  12. package/dashboard/dist/assets/BUvcp_7V.js.gz +0 -0
  13. package/dashboard/dist/assets/BV2Tf8S2.js +212 -0
  14. package/dashboard/dist/assets/BV2Tf8S2.js.br +0 -0
  15. package/dashboard/dist/assets/BV2Tf8S2.js.gz +0 -0
  16. package/dashboard/dist/assets/{CoDun8X6.js → BYb6DARX.js} +1 -1
  17. package/dashboard/dist/assets/BYb6DARX.js.br +0 -0
  18. package/dashboard/dist/assets/BYb6DARX.js.gz +0 -0
  19. package/dashboard/dist/assets/{DLNTxNX-.js → BoDhb8_y.js} +1 -1
  20. package/dashboard/dist/assets/BoDhb8_y.js.br +0 -0
  21. package/dashboard/dist/assets/BoDhb8_y.js.gz +0 -0
  22. package/dashboard/dist/assets/Bqk_l0k6.js +1 -0
  23. package/dashboard/dist/assets/Bqk_l0k6.js.br +0 -0
  24. package/dashboard/dist/assets/Bqk_l0k6.js.gz +0 -0
  25. package/dashboard/dist/assets/{BDlKSbsp.js → CV0sWMbv.js} +1 -1
  26. package/dashboard/dist/assets/CV0sWMbv.js.br +0 -0
  27. package/dashboard/dist/assets/CV0sWMbv.js.gz +0 -0
  28. package/dashboard/dist/assets/CaAkScfa.js +1 -0
  29. package/dashboard/dist/assets/CaAkScfa.js.br +0 -0
  30. package/dashboard/dist/assets/CaAkScfa.js.gz +0 -0
  31. package/dashboard/dist/assets/{CyUpNSKv.js → Ck5KlsPN.js} +1 -1
  32. package/dashboard/dist/assets/Ck5KlsPN.js.br +0 -0
  33. package/dashboard/dist/assets/Ck5KlsPN.js.gz +0 -0
  34. package/dashboard/dist/assets/{CMir7ekf.js → D2G51wQm.js} +1 -1
  35. package/dashboard/dist/assets/D2G51wQm.js.br +0 -0
  36. package/dashboard/dist/assets/D2G51wQm.js.gz +0 -0
  37. package/dashboard/dist/assets/{D8mvKY2h.js → DAr4MfFk.js} +1 -1
  38. package/dashboard/dist/assets/DAr4MfFk.js.br +0 -0
  39. package/dashboard/dist/assets/DAr4MfFk.js.gz +0 -0
  40. package/dashboard/dist/assets/{DvFumX8R.js → DXVs61e1.js} +1 -1
  41. package/dashboard/dist/assets/DXVs61e1.js.br +0 -0
  42. package/dashboard/dist/assets/DXVs61e1.js.gz +0 -0
  43. package/dashboard/dist/assets/{CWXk6UZl.js → DibzNd0I.js} +1 -1
  44. package/dashboard/dist/assets/DibzNd0I.js.br +0 -0
  45. package/dashboard/dist/assets/DibzNd0I.js.gz +0 -0
  46. package/dashboard/dist/assets/{DdYkuATV.js → Dm0CfDGr.js} +1 -1
  47. package/dashboard/dist/assets/Dm0CfDGr.js.br +0 -0
  48. package/dashboard/dist/assets/Dm0CfDGr.js.gz +0 -0
  49. package/dashboard/dist/assets/_zpQCpjm.js +1 -0
  50. package/dashboard/dist/assets/_zpQCpjm.js.br +0 -0
  51. package/dashboard/dist/assets/_zpQCpjm.js.gz +0 -0
  52. package/dashboard/dist/assets/{B8NuBCcY.js → uNGpYMSH.js} +1 -1
  53. package/dashboard/dist/assets/uNGpYMSH.js.br +0 -0
  54. package/dashboard/dist/assets/uNGpYMSH.js.gz +0 -0
  55. package/dashboard/dist/assets/{B7kFLPiD.js → wa4jJQK9.js} +1 -1
  56. package/dashboard/dist/assets/wa4jJQK9.js.br +0 -0
  57. package/dashboard/dist/assets/wa4jJQK9.js.gz +0 -0
  58. package/dashboard/dist/index.html +2 -2
  59. package/dashboard/dist/index.html.br +0 -0
  60. package/dashboard/dist/index.html.gz +0 -0
  61. package/dist/http/helpers/auto-continue-engine.d.ts +39 -0
  62. package/dist/http/helpers/auto-continue-engine.js +96 -0
  63. package/dist/http/index.js +2 -1
  64. package/dist/http/routes/mission-control-read.d.ts +14 -0
  65. package/dist/http/routes/mission-control-read.js +69 -5
  66. package/dist/outbox.js +9 -2
  67. package/package.json +2 -1
  68. package/dashboard/dist/assets/05zHA1Am.js +0 -1
  69. package/dashboard/dist/assets/05zHA1Am.js.br +0 -0
  70. package/dashboard/dist/assets/05zHA1Am.js.gz +0 -0
  71. package/dashboard/dist/assets/0uYJrBLl.js +0 -1
  72. package/dashboard/dist/assets/0uYJrBLl.js.br +0 -0
  73. package/dashboard/dist/assets/0uYJrBLl.js.gz +0 -0
  74. package/dashboard/dist/assets/8nr6IqT4.js +0 -1
  75. package/dashboard/dist/assets/8nr6IqT4.js.br +0 -0
  76. package/dashboard/dist/assets/8nr6IqT4.js.gz +0 -0
  77. package/dashboard/dist/assets/B7kFLPiD.js.br +0 -0
  78. package/dashboard/dist/assets/B7kFLPiD.js.gz +0 -0
  79. package/dashboard/dist/assets/B8NuBCcY.js.br +0 -0
  80. package/dashboard/dist/assets/B8NuBCcY.js.gz +0 -0
  81. package/dashboard/dist/assets/BDlKSbsp.js.br +0 -0
  82. package/dashboard/dist/assets/BDlKSbsp.js.gz +0 -0
  83. package/dashboard/dist/assets/C8AYbjlq.js +0 -212
  84. package/dashboard/dist/assets/C8AYbjlq.js.br +0 -0
  85. package/dashboard/dist/assets/C8AYbjlq.js.gz +0 -0
  86. package/dashboard/dist/assets/CMir7ekf.js.br +0 -0
  87. package/dashboard/dist/assets/CMir7ekf.js.gz +0 -0
  88. package/dashboard/dist/assets/CWXk6UZl.js.br +0 -0
  89. package/dashboard/dist/assets/CWXk6UZl.js.gz +0 -0
  90. package/dashboard/dist/assets/CoDun8X6.js.br +0 -0
  91. package/dashboard/dist/assets/CoDun8X6.js.gz +0 -0
  92. package/dashboard/dist/assets/Crj3jKHE.js.br +0 -0
  93. package/dashboard/dist/assets/Crj3jKHE.js.gz +0 -0
  94. package/dashboard/dist/assets/CyUpNSKv.js.br +0 -0
  95. package/dashboard/dist/assets/CyUpNSKv.js.gz +0 -0
  96. package/dashboard/dist/assets/D8mvKY2h.js.br +0 -0
  97. package/dashboard/dist/assets/D8mvKY2h.js.gz +0 -0
  98. package/dashboard/dist/assets/DBRLnKWw.js.br +0 -0
  99. package/dashboard/dist/assets/DBRLnKWw.js.gz +0 -0
  100. package/dashboard/dist/assets/DBct8HLW.js +0 -1
  101. package/dashboard/dist/assets/DBct8HLW.js.br +0 -0
  102. package/dashboard/dist/assets/DBct8HLW.js.gz +0 -0
  103. package/dashboard/dist/assets/DLNTxNX-.js.br +0 -0
  104. package/dashboard/dist/assets/DLNTxNX-.js.gz +0 -0
  105. package/dashboard/dist/assets/DdYkuATV.js.br +0 -0
  106. package/dashboard/dist/assets/DdYkuATV.js.gz +0 -0
  107. package/dashboard/dist/assets/DvFumX8R.js.br +0 -0
  108. package/dashboard/dist/assets/DvFumX8R.js.gz +0 -0
  109. package/dashboard/dist/assets/RZkbqlJk.css +0 -1
  110. package/dashboard/dist/assets/RZkbqlJk.css.br +0 -0
  111. package/dashboard/dist/assets/RZkbqlJk.css.gz +0 -0
@@ -10,7 +10,7 @@
10
10
  <meta name="googlebot" content="noindex, nofollow, noarchive, nosnippet, noimageindex" />
11
11
  <meta name="copyright" content="OrgX. All rights reserved." />
12
12
  <title>OrgX Live Dashboard</title>
13
- <script type="module" crossorigin src="/orgx/live/assets/C8AYbjlq.js"></script>
13
+ <script type="module" crossorigin src="/orgx/live/assets/BV2Tf8S2.js"></script>
14
14
  <link rel="modulepreload" crossorigin href="/orgx/live/assets/Dj2k1r16.js">
15
15
  <link rel="modulepreload" crossorigin href="/orgx/live/assets/DMKyYAtD.js">
16
16
  <link rel="modulepreload" crossorigin href="/orgx/live/assets/eeHXe_OQ.js">
@@ -18,7 +18,7 @@
18
18
  <link rel="modulepreload" crossorigin href="/orgx/live/assets/BjK42gtU.js">
19
19
  <link rel="modulepreload" crossorigin href="/orgx/live/assets/BV0BcV1u.js">
20
20
  <link rel="stylesheet" crossorigin href="/orgx/live/assets/qm8xLgv-.css">
21
- <link rel="stylesheet" crossorigin href="/orgx/live/assets/RZkbqlJk.css">
21
+ <link rel="stylesheet" crossorigin href="/orgx/live/assets/BJI1Iy5v.css">
22
22
  </head>
23
23
  <body class="bg-[#080808] text-white antialiased">
24
24
  <div id="root"></div>
Binary file
Binary file
@@ -485,6 +485,45 @@ export declare function createAutoContinueEngine(deps: CreateAutoContinueEngineD
485
485
  activeRunId: string | null;
486
486
  activeTaskTokenEstimate: number | null;
487
487
  }>;
488
+ restoreAutoContinueRun: (initiativeId: string) => Promise<{
489
+ initiativeId: string;
490
+ agentId: string;
491
+ agentName: string | null;
492
+ includeVerification: boolean;
493
+ allowedWorkstreamIds: string[] | null;
494
+ stopAfterSlice: boolean;
495
+ ignoreSpawnGuardRateLimit: boolean;
496
+ maxParallelSlices: number;
497
+ parallelMode: "iwmt";
498
+ scope: SliceScope;
499
+ tokenBudget: number | null;
500
+ tokensUsed: number;
501
+ status: "stopped" | "running" | "stopping";
502
+ stopReason: ("error" | "blocked" | "completed" | "stopped" | "budget_exhausted") | null;
503
+ stopRequested: boolean;
504
+ startedAt: string;
505
+ stoppedAt: string | null;
506
+ updatedAt: string;
507
+ lastError: string | null;
508
+ lastTaskId: string | null;
509
+ lastRunId: string | null;
510
+ activeSliceRunIds: string[];
511
+ activeTaskIds: string[];
512
+ laneByWorkstreamId: Record<string, {
513
+ workstreamId: string;
514
+ state: "idle" | "blocked" | "completed" | "running" | "rate_limited" | "waiting_dependency";
515
+ activeRunId: string | null;
516
+ activeTaskIds: string[];
517
+ blockedReason: string | null;
518
+ waitingOnWorkstreamIds: string[];
519
+ retryAt: string | null;
520
+ updatedAt: string;
521
+ }>;
522
+ blockedWorkstreamIds: string[];
523
+ activeTaskId: string | null;
524
+ activeRunId: string | null;
525
+ activeTaskTokenEstimate: number | null;
526
+ } | null>;
488
527
  skipCurrentWorkstream: (initiativeId: string, workstreamId: string, reason?: string) => Promise<{
489
528
  ok: boolean;
490
529
  skippedWorkstreamId: string;
@@ -733,6 +733,101 @@ export function createAutoContinueEngine(deps) {
733
733
  };
734
734
  const __filename = deps.filename;
735
735
  const autoContinueRuns = new Map();
736
+ /**
737
+ * Rehydrate an AutoContinueRun from persisted initiative metadata.
738
+ * Called when the in-memory Map is empty (e.g. after server restart) to
739
+ * restore the last-known autopilot state so the dashboard toggle stays
740
+ * accurate.
741
+ */
742
+ async function restoreAutoContinueRun(initiativeId) {
743
+ // Already in memory — nothing to restore.
744
+ if (autoContinueRuns.has(initiativeId)) {
745
+ return autoContinueRuns.get(initiativeId) ?? null;
746
+ }
747
+ try {
748
+ const entity = await fetchInitiativeEntity(initiativeId);
749
+ if (!entity)
750
+ return null;
751
+ const meta = entity && typeof entity === "object"
752
+ ? entity.metadata ?? {}
753
+ : {};
754
+ const enabled = meta.auto_continue_enabled;
755
+ const status = meta.auto_continue_status;
756
+ if (!enabled || !status)
757
+ return null;
758
+ // Reconstruct lane objects from persisted array.
759
+ const rawLanes = Array.isArray(meta.auto_continue_lane_states)
760
+ ? meta.auto_continue_lane_states
761
+ : [];
762
+ const laneByWorkstreamId = {};
763
+ for (const raw of rawLanes) {
764
+ const wsId = String(raw.workstream_id ?? "").trim();
765
+ if (!wsId)
766
+ continue;
767
+ laneByWorkstreamId[wsId] = {
768
+ workstreamId: wsId,
769
+ state: raw.state ?? LaneState.IDLE,
770
+ activeRunId: raw.active_run_id ?? null,
771
+ activeTaskIds: Array.isArray(raw.active_task_ids) ? raw.active_task_ids : [],
772
+ blockedReason: raw.blocked_reason ?? null,
773
+ waitingOnWorkstreamIds: Array.isArray(raw.waiting_on_workstream_ids)
774
+ ? raw.waiting_on_workstream_ids
775
+ : [],
776
+ retryAt: raw.retry_at ?? null,
777
+ updatedAt: raw.updated_at ?? new Date().toISOString(),
778
+ };
779
+ }
780
+ const now = new Date().toISOString();
781
+ const run = {
782
+ initiativeId,
783
+ agentId: "",
784
+ agentName: null,
785
+ includeVerification: Boolean(meta.auto_continue_include_verification),
786
+ allowedWorkstreamIds: Array.isArray(meta.auto_continue_workstream_filter)
787
+ ? meta.auto_continue_workstream_filter
788
+ : null,
789
+ stopAfterSlice: false,
790
+ ignoreSpawnGuardRateLimit: Boolean(meta.auto_continue_ignore_spawn_guard_rate_limit),
791
+ maxParallelSlices: normalizeMaxParallelSlices(meta.auto_continue_max_parallel, AUTO_CONTINUE_MAX_PARALLEL_DEFAULT),
792
+ parallelMode: normalizeParallelMode(meta.auto_continue_parallel_mode),
793
+ scope: "task",
794
+ tokenBudget: normalizeTokenBudget(meta.auto_continue_token_budget, defaultAutoContinueTokenBudget()),
795
+ tokensUsed: typeof meta.auto_continue_tokens_used === "number" ? meta.auto_continue_tokens_used : 0,
796
+ status: status,
797
+ stopReason: meta.auto_continue_stop_reason ?? null,
798
+ stopRequested: false,
799
+ startedAt: meta.auto_continue_started_at ?? now,
800
+ stoppedAt: meta.auto_continue_stopped_at ?? null,
801
+ updatedAt: meta.auto_continue_updated_at ?? now,
802
+ lastError: meta.auto_continue_last_error ?? null,
803
+ lastTaskId: meta.auto_continue_last_task_id ?? null,
804
+ lastRunId: meta.auto_continue_last_run_id ?? null,
805
+ activeSliceRunIds: Array.isArray(meta.auto_continue_active_run_ids)
806
+ ? meta.auto_continue_active_run_ids
807
+ : [],
808
+ activeTaskIds: Array.isArray(meta.auto_continue_active_task_ids)
809
+ ? meta.auto_continue_active_task_ids
810
+ : [],
811
+ laneByWorkstreamId,
812
+ blockedWorkstreamIds: Array.isArray(meta.auto_continue_blocked_workstream_ids)
813
+ ? meta.auto_continue_blocked_workstream_ids
814
+ : [],
815
+ activeTaskId: meta.auto_continue_active_task_id ?? null,
816
+ activeRunId: meta.auto_continue_active_run_id ?? null,
817
+ activeTaskTokenEstimate: typeof meta.auto_continue_active_task_token_estimate === "number"
818
+ ? meta.auto_continue_active_task_token_estimate
819
+ : null,
820
+ };
821
+ ensureRunInternals(run);
822
+ syncLegacyRunPointers(run);
823
+ // Insert into in-memory map so subsequent lookups are fast.
824
+ autoContinueRuns.set(initiativeId, run);
825
+ return run;
826
+ }
827
+ catch {
828
+ return null;
829
+ }
830
+ }
736
831
  const localInitiativeStatusOverrides = new Map();
737
832
  const localTaskStatusOverrides = new Map();
738
833
  const localMilestoneStatusOverrides = new Map();
@@ -4470,6 +4565,7 @@ export function createAutoContinueEngine(deps) {
4470
4565
  getAutoContinueLaneForWorkstream,
4471
4566
  scheduleAutoFixForWorkstream,
4472
4567
  startAutoContinueRun,
4568
+ restoreAutoContinueRun,
4473
4569
  skipCurrentWorkstream,
4474
4570
  getCanonicalAutopilotState,
4475
4571
  // Session store (for resume support)
@@ -1846,7 +1846,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
1846
1846
  };
1847
1847
  const codexBinResolver = createCodexBinResolver();
1848
1848
  const resolveCodexBinInfo = () => codexBinResolver.resolveCodexBinInfo();
1849
- const { autoContinueRuns, autoContinueSliceRuns, localInitiativeStatusOverrides, writeRuntimeEvent, autoContinueTickMs: AUTO_CONTINUE_TICK_MS, defaultAutoContinueTokenBudget, defaultAutoContinueMaxParallelSlices, setLocalInitiativeStatusOverride, clearLocalInitiativeStatusOverride, applyLocalInitiativeOverrides, applyLocalInitiativeOverrideToGraph, updateInitiativeAutoContinueState, stopAutoContinueRun, tickAutoContinueRun, tickAllAutoContinue, isInitiativeActiveStatus, runningAutoContinueForWorkstream, getAutoContinueLaneForWorkstream, scheduleAutoFixForWorkstream, startAutoContinueRun, skipCurrentWorkstream, getCanonicalAutopilotState, } = createAutoContinueEngine({
1849
+ const { autoContinueRuns, autoContinueSliceRuns, localInitiativeStatusOverrides, writeRuntimeEvent, autoContinueTickMs: AUTO_CONTINUE_TICK_MS, defaultAutoContinueTokenBudget, defaultAutoContinueMaxParallelSlices, setLocalInitiativeStatusOverride, clearLocalInitiativeStatusOverride, applyLocalInitiativeOverrides, applyLocalInitiativeOverrideToGraph, updateInitiativeAutoContinueState, stopAutoContinueRun, tickAutoContinueRun, tickAllAutoContinue, isInitiativeActiveStatus, runningAutoContinueForWorkstream, getAutoContinueLaneForWorkstream, scheduleAutoFixForWorkstream, startAutoContinueRun, restoreAutoContinueRun, skipCurrentWorkstream, getCanonicalAutopilotState, } = createAutoContinueEngine({
1850
1850
  client,
1851
1851
  filename: __filename,
1852
1852
  safeErrorMessage,
@@ -3042,6 +3042,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3042
3042
  });
3043
3043
  registerMissionControlReadRoutes(apiRouter, {
3044
3044
  autoContinueRuns,
3045
+ restoreAutoContinueRun,
3045
3046
  defaultAutoContinueTokenBudget,
3046
3047
  defaultAutoContinueMaxParallelSlices,
3047
3048
  autoContinueTickMs: AUTO_CONTINUE_TICK_MS,
@@ -38,6 +38,7 @@ type NextUpQueueItem = {
38
38
  sliceTaskIds?: string[];
39
39
  sliceTaskCount?: number | null;
40
40
  sliceMilestoneId?: string | null;
41
+ milestoneBreakdown?: MilestoneBreakdownEntry[];
41
42
  isPinned?: boolean;
42
43
  pinnedRank?: number | null;
43
44
  compositeScore?: number;
@@ -56,8 +57,21 @@ type NextUpQueue = {
56
57
  items: NextUpQueueItem[];
57
58
  degraded: string[];
58
59
  };
60
+ type MilestoneBreakdownTask = {
61
+ id: string;
62
+ title: string;
63
+ status: string;
64
+ };
65
+ type MilestoneBreakdownEntry = {
66
+ id: string;
67
+ title: string;
68
+ tasks: MilestoneBreakdownTask[];
69
+ totalTasks: number;
70
+ doneTasks: number;
71
+ };
59
72
  type RegisterMissionControlReadRoutesDeps<TRes> = {
60
73
  autoContinueRuns: Map<string, AutoContinueRunRecord>;
74
+ restoreAutoContinueRun?: (initiativeId: string) => Promise<AutoContinueRunRecord | null>;
61
75
  defaultAutoContinueTokenBudget: () => number | null;
62
76
  defaultAutoContinueMaxParallelSlices?: () => number;
63
77
  autoContinueTickMs: number;
@@ -619,6 +619,11 @@ function mapCanonicalSlicesToQueueItems(input) {
619
619
  const record = asRecord(entry);
620
620
  if (!record)
621
621
  continue;
622
+ const sliceKind = (asString(record.sliceKind) ?? asString(record.slice_kind) ?? "")
623
+ .trim()
624
+ .toLowerCase();
625
+ if (sliceKind && sliceKind !== "work_slice")
626
+ continue;
622
627
  const initiativeId = asString(record.initiativeId) ?? asString(record.initiative_id);
623
628
  const workstreamId = asString(record.workstreamId) ?? asString(record.workstream_id);
624
629
  if (!initiativeId || !workstreamId)
@@ -742,6 +747,7 @@ async function loadInitiativeGraphIndex(deps, initiativeId) {
742
747
  const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
743
748
  const tasksById = new Map();
744
749
  const milestoneTitleById = new Map();
750
+ const milestoneWorkstream = new Map();
745
751
  for (const nodeEntry of nodes) {
746
752
  const node = asRecord(nodeEntry);
747
753
  if (!node)
@@ -752,6 +758,9 @@ async function loadInitiativeGraphIndex(deps, initiativeId) {
752
758
  continue;
753
759
  if (type === "milestone") {
754
760
  milestoneTitleById.set(id, asString(node.title) ?? id);
761
+ const wsId = asString(node.workstreamId) ?? asString(node.parentId);
762
+ if (wsId)
763
+ milestoneWorkstream.set(id, wsId);
755
764
  continue;
756
765
  }
757
766
  if (type !== "task")
@@ -767,11 +776,63 @@ async function loadInitiativeGraphIndex(deps, initiativeId) {
767
776
  updatedAt: asString(node.updatedAt),
768
777
  });
769
778
  }
779
+ // Build milestonesByWorkstream from milestones + their child tasks
780
+ const milestonesByWorkstream = new Map();
781
+ for (const [msId, wsId] of milestoneWorkstream) {
782
+ const taskIds = [];
783
+ for (const task of tasksById.values()) {
784
+ if (task.milestoneId === msId)
785
+ taskIds.push(task.id);
786
+ }
787
+ const entry = { id: msId, title: milestoneTitleById.get(msId) ?? msId, taskIds };
788
+ const existing = milestonesByWorkstream.get(wsId) ?? [];
789
+ existing.push(entry);
790
+ milestonesByWorkstream.set(wsId, existing);
791
+ }
770
792
  return {
771
793
  tasksById,
772
794
  milestoneTitleById,
795
+ milestonesByWorkstream,
773
796
  };
774
797
  }
798
+ async function enrichWithMilestoneBreakdown(items, deps) {
799
+ if (items.length === 0)
800
+ return items;
801
+ const graphByInitiative = new Map();
802
+ const uniqueInitiatives = dedupeStrings(items.map((i) => i.initiativeId));
803
+ for (const id of uniqueInitiatives) {
804
+ try {
805
+ graphByInitiative.set(id, await loadInitiativeGraphIndex(deps, id));
806
+ }
807
+ catch {
808
+ // graph unavailable — skip enrichment for this initiative
809
+ }
810
+ }
811
+ if (graphByInitiative.size === 0)
812
+ return items;
813
+ for (const item of items) {
814
+ const graph = graphByInitiative.get(item.initiativeId);
815
+ if (!graph)
816
+ continue;
817
+ const milestones = graph.milestonesByWorkstream.get(item.workstreamId) ?? [];
818
+ if (milestones.length === 0)
819
+ continue;
820
+ item.milestoneBreakdown = milestones.map((ms) => {
821
+ const tasks = ms.taskIds.map((tid) => {
822
+ const task = graph.tasksById.get(tid);
823
+ return { id: tid, title: task?.title ?? "Untitled", status: task?.status ?? "pending" };
824
+ });
825
+ return {
826
+ id: ms.id,
827
+ title: ms.title,
828
+ tasks,
829
+ totalTasks: tasks.length,
830
+ doneTasks: tasks.filter((t) => t.status === "done" || t.status === "completed").length,
831
+ };
832
+ });
833
+ }
834
+ return items;
835
+ }
775
836
  export function registerMissionControlReadRoutes(router, deps) {
776
837
  // Handler registrations are process-local. Reset route caches so each newly
777
838
  // constructed handler starts from a clean canonical cache/bypass state.
@@ -803,7 +864,10 @@ export function registerMissionControlReadRoutes(router, deps) {
803
864
  sendRouteError(res, 400, "mission-control.read.auto-continue.status.validation", "initiativeId is required");
804
865
  return;
805
866
  }
806
- const run = deps.autoContinueRuns.get(id) ?? null;
867
+ let run = deps.autoContinueRuns.get(id) ?? null;
868
+ if (!run && deps.restoreAutoContinueRun) {
869
+ run = await deps.restoreAutoContinueRun(id) ?? null;
870
+ }
807
871
  deps.sendJson(res, 200, {
808
872
  ok: true,
809
873
  initiativeId: id,
@@ -953,7 +1017,7 @@ export function registerMissionControlReadRoutes(router, deps) {
953
1017
  if (isCanonicalAllScopeMismatch(canonicalRecord, useAllScope)) {
954
1018
  throw new Error("canonical next-up all-workspaces scope mismatch");
955
1019
  }
956
- const canonicalItems = applyQueueNoiseControls(normalizeQueueItems(canonicalRecord.items).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs });
1020
+ const canonicalItems = await enrichWithMilestoneBreakdown(applyQueueNoiseControls(normalizeQueueItems(canonicalRecord.items).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs }), deps);
957
1021
  const canonicalTotal = Math.max(canonicalItems.length, Math.floor(asNumber(canonicalRecord.total) ?? canonicalItems.length)) ?? canonicalItems.length;
958
1022
  const canonicalPagination = parsePaginationEnvelope(canonicalRecord.pagination, {
959
1023
  offset,
@@ -1081,7 +1145,7 @@ export function registerMissionControlReadRoutes(router, deps) {
1081
1145
  if (isCanonicalAllScopeMismatch(canonicalSlicesRecord, useAllScope)) {
1082
1146
  throw new Error("canonical slices all-workspaces scope mismatch");
1083
1147
  }
1084
- const bridgedItems = applyQueueNoiseControls(mapCanonicalSlicesToQueueItems(canonicalSlicesRecord.items).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs });
1148
+ const bridgedItems = await enrichWithMilestoneBreakdown(applyQueueNoiseControls(mapCanonicalSlicesToQueueItems(canonicalSlicesRecord.items).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs }), deps);
1085
1149
  if (bridgedItems.length > 0) {
1086
1150
  const paged = applySliceSearchAndPagination({
1087
1151
  items: bridgedItems,
@@ -1124,7 +1188,7 @@ export function registerMissionControlReadRoutes(router, deps) {
1124
1188
  initiativeId,
1125
1189
  projectId,
1126
1190
  });
1127
- const items = applyQueueNoiseControls(normalizeQueueItems(queue.items ?? []).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs });
1191
+ const items = await enrichWithMilestoneBreakdown(applyQueueNoiseControls(normalizeQueueItems(queue.items ?? []).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs }), deps);
1128
1192
  const paged = applySliceSearchAndPagination({
1129
1193
  items,
1130
1194
  searchTerm: "",
@@ -1157,7 +1221,7 @@ export function registerMissionControlReadRoutes(router, deps) {
1157
1221
  initiativeId,
1158
1222
  projectId,
1159
1223
  });
1160
- const items = applyQueueNoiseControls(normalizeQueueItems(queue.items ?? []).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs });
1224
+ const items = await enrichWithMilestoneBreakdown(applyQueueNoiseControls(normalizeQueueItems(queue.items ?? []).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs }), deps);
1161
1225
  const paged = applySliceSearchAndPagination({
1162
1226
  items,
1163
1227
  searchTerm: "",
package/dist/outbox.js CHANGED
@@ -114,10 +114,17 @@ async function appendOutboxDeadLetterRecord(sessionId, record) {
114
114
  await hardenPath(targetPath, 0o600);
115
115
  }
116
116
  export async function appendOutboxDeadLetter(sessionId, event, reason, error) {
117
+ let normalizedSessionId;
118
+ try {
119
+ normalizedSessionId = normalizeSessionId(sessionId);
120
+ }
121
+ catch {
122
+ return;
123
+ }
117
124
  const droppedAt = new Date().toISOString();
118
- await appendOutboxDeadLetterRecord(sessionId, {
125
+ await appendOutboxDeadLetterRecord(normalizedSessionId, {
119
126
  droppedAt,
120
- queueId: normalizeSessionId(sessionId),
127
+ queueId: normalizedSessionId,
121
128
  reason,
122
129
  error: error ?? null,
123
130
  event,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useorgx/openclaw-plugin",
3
- "version": "0.7.17",
3
+ "version": "0.7.20",
4
4
  "description": "OrgX plugin for OpenClaw — agent orchestration, quality gates, model routing, and live dashboard",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -54,6 +54,7 @@
54
54
  "verify:conduit-mcp": "node ./scripts/verify-conduit-mcp.mjs",
55
55
  "verify:repo-hygiene": "node ./scripts/verify-repo-hygiene.mjs",
56
56
  "dev:main": "node ./scripts/dev-main-sync.mjs",
57
+ "dev:live": "node ./scripts/live-dev-serve.mjs",
57
58
  "e2e:auto-continue": "node ./scripts/e2e-auto-continue.mjs",
58
59
  "e2e:agent-suite": "npm run build:core && node ./scripts/e2e-agent-suite-kickoff-3x.mjs",
59
60
  "demo:record": "node ./scripts/record-demo.mjs",
@@ -1 +0,0 @@
1
- import{r as a,j as e}from"./Dj2k1r16.js";import{e as l,y as p,E as h,$ as u}from"./C8AYbjlq.js";import{DecisionQueue as b}from"./CMir7ekf.js";import"./DMKyYAtD.js";import"./eeHXe_OQ.js";import"./cX2e-TLi.js";import"./BjK42gtU.js";import"./BV0BcV1u.js";import"./DBRLnKWw.js";import"./D8mvKY2h.js";function D({open:n,onClose:o,decisions:t,onApproveDecision:i,onRejectDecision:m,onApproveAll:d,onBulkDecisionAction:x}){const r=a.useMemo(()=>t.length>0?Math.max(0,...t.map(c=>c.waitingMinutes)):0,[t]),s=a.useMemo(()=>t.length>=20||r>=15?l.red:t.length>0?l.amber:l.textMuted,[t.length,r]);return e.jsx(p,{open:n,onClose:o,maxWidth:"max-w-3xl",children:e.jsxs("div",{className:"flex h-full w-full flex-col",children:[e.jsx("div",{className:"border-b border-subtle px-5 pt-5 pb-4",children:e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("h3",{className:"inline-flex items-center gap-2 text-heading font-semibold text-white",children:[e.jsx(h,{type:"decision",size:14}),e.jsx("span",{className:"truncate",children:"Decisions"}),e.jsx("span",{className:"rounded-full border px-2 py-0.5 text-caption font-semibold",style:{borderColor:`${s}30`,backgroundColor:`${s}14`,color:s},children:t.length})]}),e.jsx("p",{className:"mt-1 text-body leading-relaxed text-secondary",children:"Bulk review and resolve pending decisions."}),t.length>0&&e.jsxs("p",{className:"mt-2 text-caption text-secondary",children:["Oldest: ",e.jsxs("span",{className:"font-semibold text-white",children:[u(r)," ago"]})]})]}),e.jsx("button",{type:"button",onClick:o,className:"rounded-md border border-strong bg-white/[0.03] px-2.5 py-1.5 text-caption text-primary transition-colors hover:bg-white/[0.08]","aria-label":"Close decisions modal",children:"Close"})]})}),e.jsx("div",{className:"min-h-0 flex-1 overflow-hidden p-4",children:e.jsx(b,{decisions:t,onApproveDecision:i,onRejectDecision:m,onApproveAll:d,onBulkDecisionAction:x})})]})})}export{D as BulkDecisionsModal};