@useorgx/openclaw-plugin 0.7.18 → 0.7.23
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/dashboard/dist/assets/9gFmK3Kr.js +1 -0
- package/dashboard/dist/assets/9gFmK3Kr.js.br +0 -0
- package/dashboard/dist/assets/9gFmK3Kr.js.gz +0 -0
- package/dashboard/dist/assets/{DS79hzMu.js → BrMXbzQ-.js} +2 -2
- package/dashboard/dist/assets/BrMXbzQ-.js.br +0 -0
- package/dashboard/dist/assets/BrMXbzQ-.js.gz +0 -0
- package/dashboard/dist/assets/By0MIBj_.js +1 -0
- package/dashboard/dist/assets/By0MIBj_.js.br +0 -0
- package/dashboard/dist/assets/By0MIBj_.js.gz +0 -0
- package/dashboard/dist/assets/C1u2SGin.css +1 -0
- package/dashboard/dist/assets/C1u2SGin.css.br +0 -0
- package/dashboard/dist/assets/C1u2SGin.css.gz +0 -0
- package/dashboard/dist/assets/{467jKHFJ.js → CGJiHCIx.js} +1 -1
- package/dashboard/dist/assets/CGJiHCIx.js.br +0 -0
- package/dashboard/dist/assets/CGJiHCIx.js.gz +0 -0
- package/dashboard/dist/assets/CSd4rSuU.js +212 -0
- package/dashboard/dist/assets/CSd4rSuU.js.br +0 -0
- package/dashboard/dist/assets/CSd4rSuU.js.gz +0 -0
- package/dashboard/dist/assets/{5Ihga-4X.js → CZXS5i_5.js} +1 -1
- package/dashboard/dist/assets/CZXS5i_5.js.br +0 -0
- package/dashboard/dist/assets/CZXS5i_5.js.gz +0 -0
- package/dashboard/dist/assets/{a6qcPiWt.js → CbVWL74-.js} +1 -1
- package/dashboard/dist/assets/CbVWL74-.js.br +0 -0
- package/dashboard/dist/assets/CbVWL74-.js.gz +0 -0
- package/dashboard/dist/assets/{qDJ6rqcs.js → D-FuHfT8.js} +1 -1
- package/dashboard/dist/assets/D-FuHfT8.js.br +0 -0
- package/dashboard/dist/assets/D-FuHfT8.js.gz +0 -0
- package/dashboard/dist/assets/{BcJmNILk.js → D0PN5_vY.js} +1 -1
- package/dashboard/dist/assets/D0PN5_vY.js.br +0 -0
- package/dashboard/dist/assets/D0PN5_vY.js.gz +0 -0
- package/dashboard/dist/assets/DDCPrZRt.js +1 -0
- package/dashboard/dist/assets/DDCPrZRt.js.br +0 -0
- package/dashboard/dist/assets/DDCPrZRt.js.gz +0 -0
- package/dashboard/dist/assets/{B71dt9yu.js → DNQ-iFO2.js} +1 -1
- package/dashboard/dist/assets/DNQ-iFO2.js.br +0 -0
- package/dashboard/dist/assets/DNQ-iFO2.js.gz +0 -0
- package/dashboard/dist/assets/{PVi0vr9a.js → DhPuHPK7.js} +1 -1
- package/dashboard/dist/assets/DhPuHPK7.js.br +0 -0
- package/dashboard/dist/assets/DhPuHPK7.js.gz +0 -0
- package/dashboard/dist/assets/Dhz7qPtn.js +1 -0
- package/dashboard/dist/assets/Dhz7qPtn.js.br +0 -0
- package/dashboard/dist/assets/Dhz7qPtn.js.gz +0 -0
- package/dashboard/dist/assets/LOFrVoPD.js +1 -0
- package/dashboard/dist/assets/LOFrVoPD.js.br +0 -0
- package/dashboard/dist/assets/LOFrVoPD.js.gz +0 -0
- package/dashboard/dist/assets/OlLPtzdz.js +1 -0
- package/dashboard/dist/assets/OlLPtzdz.js.br +0 -0
- package/dashboard/dist/assets/OlLPtzdz.js.gz +0 -0
- package/dashboard/dist/assets/{sdoPH_Z1.js → RN4M9u9W.js} +2 -2
- package/dashboard/dist/assets/RN4M9u9W.js.br +0 -0
- package/dashboard/dist/assets/RN4M9u9W.js.gz +0 -0
- package/dashboard/dist/assets/VCHu272d.js +1 -0
- package/dashboard/dist/assets/VCHu272d.js.br +0 -0
- package/dashboard/dist/assets/VCHu272d.js.gz +0 -0
- package/dashboard/dist/assets/m2smti3F.js +1 -0
- package/dashboard/dist/assets/m2smti3F.js.br +0 -0
- package/dashboard/dist/assets/m2smti3F.js.gz +0 -0
- package/dashboard/dist/assets/{C3_j_W9V.js → nra1yvJX.js} +1 -1
- package/dashboard/dist/assets/nra1yvJX.js.br +0 -0
- package/dashboard/dist/assets/nra1yvJX.js.gz +0 -0
- package/dashboard/dist/assets/qLX6NZ-J.js +1 -0
- package/dashboard/dist/assets/qLX6NZ-J.js.br +0 -0
- package/dashboard/dist/assets/qLX6NZ-J.js.gz +0 -0
- package/dashboard/dist/index.html +2 -2
- package/dashboard/dist/index.html.br +0 -0
- package/dashboard/dist/index.html.gz +0 -0
- package/dist/agent-run-store.js +162 -24
- package/dist/cli/orgx.d.ts +3 -0
- package/dist/config/resolution.d.ts +7 -0
- package/dist/config/resolution.js +13 -5
- package/dist/contracts/onboarding-state.d.ts +2 -0
- package/dist/contracts/onboarding-state.js +23 -0
- package/dist/contracts/shared-types.d.ts +17 -0
- package/dist/http/helpers/auto-continue-engine.d.ts +62 -0
- package/dist/http/helpers/auto-continue-engine.js +329 -53
- package/dist/http/helpers/autopilot-runtime.js +5 -1
- package/dist/http/helpers/autopilot-slice-utils.js +25 -1
- package/dist/http/helpers/decision-mapper.d.ts +1 -0
- package/dist/http/helpers/decision-mapper.js +19 -2
- package/dist/http/helpers/dispatch-lifecycle.js +3 -0
- package/dist/http/helpers/mission-control.d.ts +1 -0
- package/dist/http/helpers/mission-control.js +5 -2
- package/dist/http/helpers/slice-run-projections.d.ts +27 -0
- package/dist/http/helpers/slice-run-projections.js +198 -10
- package/dist/http/helpers/triage-mapper.js +220 -6
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +94 -46
- package/dist/http/router.js +64 -9
- package/dist/http/routes/live-legacy.d.ts +19 -2
- package/dist/http/routes/live-legacy.js +110 -27
- package/dist/http/routes/live-snapshot.d.ts +16 -2
- package/dist/http/routes/live-snapshot.js +169 -25
- package/dist/http/routes/mission-control-actions.js +28 -0
- package/dist/http/routes/mission-control-read.d.ts +18 -0
- package/dist/http/routes/mission-control-read.js +130 -218
- package/dist/http/routes/onboarding.d.ts +1 -0
- package/dist/http/routes/onboarding.js +17 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +199 -123
- package/dist/outbox.d.ts +0 -2
- package/dist/outbox.js +268 -150
- package/dist/reporting/rollups.js +18 -11
- package/dist/runtime-instance-store.js +212 -58
- package/dist/stores/materialized-snapshot-store.d.ts +18 -0
- package/dist/stores/materialized-snapshot-store.js +91 -0
- package/dist/stores/sqlite-state.d.ts +6 -0
- package/dist/stores/sqlite-state.js +179 -0
- package/package.json +6 -1
- package/dashboard/dist/assets/467jKHFJ.js.br +0 -0
- package/dashboard/dist/assets/467jKHFJ.js.gz +0 -0
- package/dashboard/dist/assets/5Ihga-4X.js.br +0 -0
- package/dashboard/dist/assets/5Ihga-4X.js.gz +0 -0
- package/dashboard/dist/assets/B71dt9yu.js.br +0 -0
- package/dashboard/dist/assets/B71dt9yu.js.gz +0 -0
- package/dashboard/dist/assets/BCudUvwg.js +0 -1
- package/dashboard/dist/assets/BCudUvwg.js.br +0 -0
- package/dashboard/dist/assets/BCudUvwg.js.gz +0 -0
- package/dashboard/dist/assets/BEnI6kNR.js +0 -1
- package/dashboard/dist/assets/BEnI6kNR.js.br +0 -0
- package/dashboard/dist/assets/BEnI6kNR.js.gz +0 -0
- package/dashboard/dist/assets/BcJmNILk.js.br +0 -0
- package/dashboard/dist/assets/BcJmNILk.js.gz +0 -0
- package/dashboard/dist/assets/C-MOJWHs.js +0 -1
- package/dashboard/dist/assets/C-MOJWHs.js.br +0 -0
- package/dashboard/dist/assets/C-MOJWHs.js.gz +0 -0
- package/dashboard/dist/assets/C-XuWXGi.js +0 -1
- package/dashboard/dist/assets/C-XuWXGi.js.br +0 -0
- package/dashboard/dist/assets/C-XuWXGi.js.gz +0 -0
- package/dashboard/dist/assets/C3_j_W9V.js.br +0 -0
- package/dashboard/dist/assets/C3_j_W9V.js.gz +0 -0
- package/dashboard/dist/assets/C9-UYhBb.js +0 -1
- package/dashboard/dist/assets/C9-UYhBb.js.br +0 -0
- package/dashboard/dist/assets/C9-UYhBb.js.gz +0 -0
- package/dashboard/dist/assets/C9yV06GS.js +0 -1
- package/dashboard/dist/assets/C9yV06GS.js.br +0 -0
- package/dashboard/dist/assets/C9yV06GS.js.gz +0 -0
- package/dashboard/dist/assets/CReugbyT.js +0 -1
- package/dashboard/dist/assets/CReugbyT.js.br +0 -0
- package/dashboard/dist/assets/CReugbyT.js.gz +0 -0
- package/dashboard/dist/assets/CSDhTbKy.js +0 -1
- package/dashboard/dist/assets/CSDhTbKy.js.br +0 -0
- package/dashboard/dist/assets/CSDhTbKy.js.gz +0 -0
- package/dashboard/dist/assets/CfMS9yIf.js +0 -1
- package/dashboard/dist/assets/CfMS9yIf.js.br +0 -0
- package/dashboard/dist/assets/CfMS9yIf.js.gz +0 -0
- package/dashboard/dist/assets/D2Kqcmv9.js +0 -212
- package/dashboard/dist/assets/D2Kqcmv9.js.br +0 -0
- package/dashboard/dist/assets/D2Kqcmv9.js.gz +0 -0
- package/dashboard/dist/assets/DS79hzMu.js.br +0 -0
- package/dashboard/dist/assets/DS79hzMu.js.gz +0 -0
- package/dashboard/dist/assets/PVi0vr9a.js.br +0 -0
- package/dashboard/dist/assets/PVi0vr9a.js.gz +0 -0
- package/dashboard/dist/assets/RZkbqlJk.css +0 -1
- package/dashboard/dist/assets/RZkbqlJk.css.br +0 -0
- package/dashboard/dist/assets/RZkbqlJk.css.gz +0 -0
- package/dashboard/dist/assets/a6qcPiWt.js.br +0 -0
- package/dashboard/dist/assets/a6qcPiWt.js.gz +0 -0
- package/dashboard/dist/assets/qDJ6rqcs.js.br +0 -0
- package/dashboard/dist/assets/qDJ6rqcs.js.gz +0 -0
- package/dashboard/dist/assets/sdoPH_Z1.js.br +0 -0
- package/dashboard/dist/assets/sdoPH_Z1.js.gz +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { listBuiltInSentinels } from "../helpers/sentinel-catalog.js";
|
|
2
2
|
import { resolveWorkspaceScope, workspaceScopeFromHeaders, } from "../helpers/workspace-scope.js";
|
|
3
|
+
import { isDoneStatus, normalizeMissionControlStatus, } from "../helpers/mission-control.js";
|
|
3
4
|
import { asRecord, asString, asNumber, asArray, asStringArray, } from "../../lib/type-coercion.js";
|
|
4
5
|
// asRecord, asString, asArray, asNumber, asStringArray imported from ../../lib/type-coercion.js
|
|
5
6
|
function normalizeRunnerValue(value) {
|
|
@@ -313,7 +314,7 @@ async function requestCanonicalWithLegacyFallback(deps, input) {
|
|
|
313
314
|
return await withSoftTimeout(deps.rawRequest("GET", input.legacyPath), Math.min(input.timeoutMs, 1_500), `${input.label} (legacy fallback)`);
|
|
314
315
|
}
|
|
315
316
|
function normalizeQueueState(value) {
|
|
316
|
-
const normalized =
|
|
317
|
+
const normalized = normalizeMissionControlStatus(asString(value));
|
|
317
318
|
if (normalized === "running" || normalized === "in_progress") {
|
|
318
319
|
return "running";
|
|
319
320
|
}
|
|
@@ -336,19 +337,6 @@ function normalizeQueueState(value) {
|
|
|
336
337
|
return "completed";
|
|
337
338
|
return "idle";
|
|
338
339
|
}
|
|
339
|
-
function normalizeStatus(value) {
|
|
340
|
-
return (value ?? "").trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
341
|
-
}
|
|
342
|
-
function isDoneStatus(value) {
|
|
343
|
-
const normalized = normalizeStatus(value);
|
|
344
|
-
return (normalized === "done" ||
|
|
345
|
-
normalized === "completed" ||
|
|
346
|
-
normalized === "resolved" ||
|
|
347
|
-
normalized === "cancelled" ||
|
|
348
|
-
normalized === "canceled" ||
|
|
349
|
-
normalized === "archived" ||
|
|
350
|
-
normalized === "closed");
|
|
351
|
-
}
|
|
352
340
|
function queueStateRank(state) {
|
|
353
341
|
if (state === "running")
|
|
354
342
|
return 0;
|
|
@@ -476,7 +464,7 @@ function normalizeQueueItems(input) {
|
|
|
476
464
|
? runnerSourceHint ?? "inferred"
|
|
477
465
|
: "fallback";
|
|
478
466
|
const queueState = normalizeQueueState(record.queueState ?? record.queue_state);
|
|
479
|
-
const normalizedSliceScope =
|
|
467
|
+
const normalizedSliceScope = normalizeMissionControlStatus(asString(record.sliceScope) ?? asString(record.slice_scope));
|
|
480
468
|
const sliceScope = normalizedSliceScope === "task" ||
|
|
481
469
|
normalizedSliceScope === "milestone" ||
|
|
482
470
|
normalizedSliceScope === "workstream"
|
|
@@ -561,6 +549,34 @@ function normalizeQueueItems(input) {
|
|
|
561
549
|
return left.workstreamTitle.localeCompare(right.workstreamTitle);
|
|
562
550
|
});
|
|
563
551
|
}
|
|
552
|
+
function summarizeQueueItems(items) {
|
|
553
|
+
const stateCounts = {
|
|
554
|
+
queued: 0,
|
|
555
|
+
running: 0,
|
|
556
|
+
blocked: 0,
|
|
557
|
+
idle: 0,
|
|
558
|
+
completed: 0,
|
|
559
|
+
};
|
|
560
|
+
for (const item of items) {
|
|
561
|
+
stateCounts[item.queueState] += 1;
|
|
562
|
+
}
|
|
563
|
+
return {
|
|
564
|
+
visibleTotal: items.filter((item) => item.queueState !== "running" && item.queueState !== "completed").length,
|
|
565
|
+
stateCounts,
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function dedupeQueueItemsByLineage(items) {
|
|
569
|
+
const seen = new Set();
|
|
570
|
+
const deduped = [];
|
|
571
|
+
for (const item of items) {
|
|
572
|
+
const key = `${item.initiativeId}:${item.workstreamId}`;
|
|
573
|
+
if (seen.has(key))
|
|
574
|
+
continue;
|
|
575
|
+
seen.add(key);
|
|
576
|
+
deduped.push(item);
|
|
577
|
+
}
|
|
578
|
+
return deduped;
|
|
579
|
+
}
|
|
564
580
|
function isHighSeverityQueueItem(item) {
|
|
565
581
|
if (item.scoringTier === "urgent")
|
|
566
582
|
return true;
|
|
@@ -613,135 +629,13 @@ function applyQueueNoiseControls(items, options) {
|
|
|
613
629
|
}
|
|
614
630
|
return deduped;
|
|
615
631
|
}
|
|
616
|
-
function mapCanonicalSlicesToQueueItems(input) {
|
|
617
|
-
const queueLike = [];
|
|
618
|
-
for (const entry of input) {
|
|
619
|
-
const record = asRecord(entry);
|
|
620
|
-
if (!record)
|
|
621
|
-
continue;
|
|
622
|
-
const initiativeId = asString(record.initiativeId) ?? asString(record.initiative_id);
|
|
623
|
-
const workstreamId = asString(record.workstreamId) ?? asString(record.workstream_id);
|
|
624
|
-
if (!initiativeId || !workstreamId)
|
|
625
|
-
continue;
|
|
626
|
-
const dispatch = asRecord(record.dispatch) ?? {};
|
|
627
|
-
const lineage = asRecord(record.lineage) ?? {};
|
|
628
|
-
const taskId = asString(record.taskId) ?? asString(record.task_id);
|
|
629
|
-
const sliceTaskIds = dedupeStrings([
|
|
630
|
-
...asStringArray(record.sliceTaskIds),
|
|
631
|
-
...asStringArray(record.slice_task_ids),
|
|
632
|
-
...asStringArray(lineage.taskIds),
|
|
633
|
-
...asStringArray(lineage.task_ids),
|
|
634
|
-
...(taskId ? [taskId] : []),
|
|
635
|
-
]);
|
|
636
|
-
const rawStatus = asString(record.status) ?? "active";
|
|
637
|
-
const normalizedStatus = normalizeStatus(rawStatus);
|
|
638
|
-
const runnable = Boolean(dispatch.runnable);
|
|
639
|
-
let queueState;
|
|
640
|
-
if (isDoneStatus(rawStatus)) {
|
|
641
|
-
queueState = "completed";
|
|
642
|
-
}
|
|
643
|
-
else if (normalizedStatus === "running" || normalizedStatus === "in_progress") {
|
|
644
|
-
queueState = "running";
|
|
645
|
-
}
|
|
646
|
-
else if (normalizedStatus === "blocked" ||
|
|
647
|
-
normalizedStatus === "waiting_dependency" ||
|
|
648
|
-
normalizedStatus === "needs_decision" ||
|
|
649
|
-
normalizedStatus === "waiting_on_decision" ||
|
|
650
|
-
normalizedStatus === "paused" ||
|
|
651
|
-
!runnable) {
|
|
652
|
-
queueState = "blocked";
|
|
653
|
-
}
|
|
654
|
-
else if (normalizedStatus === "idle" ||
|
|
655
|
-
normalizedStatus === "not_started" ||
|
|
656
|
-
normalizedStatus === "draft") {
|
|
657
|
-
queueState = "idle";
|
|
658
|
-
}
|
|
659
|
-
else {
|
|
660
|
-
queueState = "queued";
|
|
661
|
-
}
|
|
662
|
-
const runnerAgentIdRaw = normalizeRunnerValue(record.runnerAgentId) ?? normalizeRunnerValue(record.runner_agent_id);
|
|
663
|
-
const runnerAgentNameRaw = normalizeRunnerValue(record.runnerAgentName) ?? normalizeRunnerValue(record.runner_agent_name);
|
|
664
|
-
const runnerAgents = mergeRunnerAgents(normalizeRunnerAgents(record.runnerAgents), normalizeRunnerAgents(record.runner_agents), runnerAgentIdRaw || runnerAgentNameRaw
|
|
665
|
-
? [
|
|
666
|
-
{
|
|
667
|
-
id: runnerAgentIdRaw ?? runnerAgentNameRaw ?? "Unassigned",
|
|
668
|
-
name: runnerAgentNameRaw ?? runnerAgentIdRaw ?? "Unassigned",
|
|
669
|
-
},
|
|
670
|
-
]
|
|
671
|
-
: []);
|
|
672
|
-
const runnerSourceHint = normalizeRunnerSource(record.runnerSource) ?? normalizeRunnerSource(record.runner_source);
|
|
673
|
-
const runnerSource = runnerAgents.length > 0 ? runnerSourceHint ?? "inferred" : "fallback";
|
|
674
|
-
const suggestedScope = normalizeStatus(asString(dispatch.suggestedScope) ??
|
|
675
|
-
asString(dispatch.suggested_scope) ??
|
|
676
|
-
asString(record.level));
|
|
677
|
-
const sliceScope = suggestedScope === "task" ||
|
|
678
|
-
suggestedScope === "milestone" ||
|
|
679
|
-
suggestedScope === "workstream"
|
|
680
|
-
? suggestedScope
|
|
681
|
-
: null;
|
|
682
|
-
const order = asRecord(record.order) ?? {};
|
|
683
|
-
const manualRank = asNumber(order.manualRank ?? order.manual_rank);
|
|
684
|
-
const iwmt = asRecord(record.iwmt);
|
|
685
|
-
const objective = asRecord(record.objective);
|
|
686
|
-
queueLike.push({
|
|
687
|
-
initiativeId,
|
|
688
|
-
initiativeTitle: asString(record.initiativeTitle) ??
|
|
689
|
-
asString(record.initiative_title) ??
|
|
690
|
-
initiativeId,
|
|
691
|
-
initiativeStatus: asString(record.initiativeStatus) ??
|
|
692
|
-
asString(record.initiative_status) ??
|
|
693
|
-
"active",
|
|
694
|
-
initiativePriority: asString(record.initiativePriority) ?? asString(record.initiative_priority),
|
|
695
|
-
initiativePriorityNum: asNumber(record.initiativePriorityNum ?? record.initiative_priority_num),
|
|
696
|
-
workstreamId,
|
|
697
|
-
workstreamTitle: asString(record.workstreamTitle) ??
|
|
698
|
-
asString(record.workstream_title) ??
|
|
699
|
-
asString(record.title) ??
|
|
700
|
-
workstreamId,
|
|
701
|
-
workstreamStatus: asString(record.workstreamStatus) ??
|
|
702
|
-
asString(record.workstream_status) ??
|
|
703
|
-
rawStatus,
|
|
704
|
-
nextTaskId: taskId ?? sliceTaskIds[0] ?? null,
|
|
705
|
-
nextTaskTitle: asString(record.nextTaskTitle) ?? asString(record.next_task_title),
|
|
706
|
-
nextTaskPriority: asNumber(record.priorityNum ??
|
|
707
|
-
record.priority_num ??
|
|
708
|
-
record.nextTaskPriority ??
|
|
709
|
-
record.next_task_priority),
|
|
710
|
-
nextTaskDueAt: asString(record.dueAt) ??
|
|
711
|
-
asString(record.due_at) ??
|
|
712
|
-
asString(record.nextTaskDueAt) ??
|
|
713
|
-
asString(record.next_task_due_at),
|
|
714
|
-
nextTaskMilestoneId: asString(record.milestoneId) ?? asString(record.milestone_id),
|
|
715
|
-
runnerAgentId: runnerAgentIdRaw,
|
|
716
|
-
runnerAgentName: runnerAgentNameRaw,
|
|
717
|
-
runnerAgents,
|
|
718
|
-
runnerSource,
|
|
719
|
-
queueState,
|
|
720
|
-
blockReason: asString(dispatch.blockReason) ??
|
|
721
|
-
asString(dispatch.block_reason) ??
|
|
722
|
-
null,
|
|
723
|
-
sliceScope,
|
|
724
|
-
sliceTaskIds,
|
|
725
|
-
sliceTaskCount: sliceTaskIds.length,
|
|
726
|
-
sliceMilestoneId: asString(record.milestoneId) ?? asString(record.milestone_id),
|
|
727
|
-
isPinned: typeof manualRank === "number",
|
|
728
|
-
pinnedRank: manualRank,
|
|
729
|
-
compositeScore: asNumber(iwmt?.mixScore ?? objective?.objectiveScore),
|
|
730
|
-
objectiveScore: asNumber(objective?.objectiveScore) ?? undefined,
|
|
731
|
-
roiPerToken: asNumber(iwmt?.roiPerToken) ?? undefined,
|
|
732
|
-
expectedTokens: asNumber(iwmt?.expectedTokens) ?? undefined,
|
|
733
|
-
expectedValueUsd: asNumber(iwmt?.expectedValueUsd) ?? undefined,
|
|
734
|
-
updatedAt: asString(record.updatedAt) ?? asString(record.updated_at) ?? null,
|
|
735
|
-
});
|
|
736
|
-
}
|
|
737
|
-
return normalizeQueueItems(queueLike);
|
|
738
|
-
}
|
|
739
632
|
async function loadInitiativeGraphIndex(deps, initiativeId) {
|
|
740
633
|
const graphRaw = deps.applyLocalInitiativeOverrideToGraph(await deps.buildMissionControlGraph(initiativeId));
|
|
741
634
|
const graph = asRecord(graphRaw);
|
|
742
635
|
const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
743
636
|
const tasksById = new Map();
|
|
744
637
|
const milestoneTitleById = new Map();
|
|
638
|
+
const milestoneWorkstream = new Map();
|
|
745
639
|
for (const nodeEntry of nodes) {
|
|
746
640
|
const node = asRecord(nodeEntry);
|
|
747
641
|
if (!node)
|
|
@@ -752,6 +646,9 @@ async function loadInitiativeGraphIndex(deps, initiativeId) {
|
|
|
752
646
|
continue;
|
|
753
647
|
if (type === "milestone") {
|
|
754
648
|
milestoneTitleById.set(id, asString(node.title) ?? id);
|
|
649
|
+
const wsId = asString(node.workstreamId) ?? asString(node.parentId);
|
|
650
|
+
if (wsId)
|
|
651
|
+
milestoneWorkstream.set(id, wsId);
|
|
755
652
|
continue;
|
|
756
653
|
}
|
|
757
654
|
if (type !== "task")
|
|
@@ -767,11 +664,63 @@ async function loadInitiativeGraphIndex(deps, initiativeId) {
|
|
|
767
664
|
updatedAt: asString(node.updatedAt),
|
|
768
665
|
});
|
|
769
666
|
}
|
|
667
|
+
// Build milestonesByWorkstream from milestones + their child tasks
|
|
668
|
+
const milestonesByWorkstream = new Map();
|
|
669
|
+
for (const [msId, wsId] of milestoneWorkstream) {
|
|
670
|
+
const taskIds = [];
|
|
671
|
+
for (const task of tasksById.values()) {
|
|
672
|
+
if (task.milestoneId === msId)
|
|
673
|
+
taskIds.push(task.id);
|
|
674
|
+
}
|
|
675
|
+
const entry = { id: msId, title: milestoneTitleById.get(msId) ?? msId, taskIds };
|
|
676
|
+
const existing = milestonesByWorkstream.get(wsId) ?? [];
|
|
677
|
+
existing.push(entry);
|
|
678
|
+
milestonesByWorkstream.set(wsId, existing);
|
|
679
|
+
}
|
|
770
680
|
return {
|
|
771
681
|
tasksById,
|
|
772
682
|
milestoneTitleById,
|
|
683
|
+
milestonesByWorkstream,
|
|
773
684
|
};
|
|
774
685
|
}
|
|
686
|
+
async function enrichWithMilestoneBreakdown(items, deps) {
|
|
687
|
+
if (items.length === 0)
|
|
688
|
+
return items;
|
|
689
|
+
const graphByInitiative = new Map();
|
|
690
|
+
const uniqueInitiatives = dedupeStrings(items.map((i) => i.initiativeId));
|
|
691
|
+
for (const id of uniqueInitiatives) {
|
|
692
|
+
try {
|
|
693
|
+
graphByInitiative.set(id, await loadInitiativeGraphIndex(deps, id));
|
|
694
|
+
}
|
|
695
|
+
catch {
|
|
696
|
+
// graph unavailable — skip enrichment for this initiative
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
if (graphByInitiative.size === 0)
|
|
700
|
+
return items;
|
|
701
|
+
for (const item of items) {
|
|
702
|
+
const graph = graphByInitiative.get(item.initiativeId);
|
|
703
|
+
if (!graph)
|
|
704
|
+
continue;
|
|
705
|
+
const milestones = graph.milestonesByWorkstream.get(item.workstreamId) ?? [];
|
|
706
|
+
if (milestones.length === 0)
|
|
707
|
+
continue;
|
|
708
|
+
item.milestoneBreakdown = milestones.map((ms) => {
|
|
709
|
+
const tasks = ms.taskIds.map((tid) => {
|
|
710
|
+
const task = graph.tasksById.get(tid);
|
|
711
|
+
return { id: tid, title: task?.title ?? "Untitled", status: task?.status ?? "pending" };
|
|
712
|
+
});
|
|
713
|
+
return {
|
|
714
|
+
id: ms.id,
|
|
715
|
+
title: ms.title,
|
|
716
|
+
tasks,
|
|
717
|
+
totalTasks: tasks.length,
|
|
718
|
+
doneTasks: tasks.filter((t) => t.status === "done" || t.status === "completed").length,
|
|
719
|
+
};
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
return items;
|
|
723
|
+
}
|
|
775
724
|
export function registerMissionControlReadRoutes(router, deps) {
|
|
776
725
|
// Handler registrations are process-local. Reset route caches so each newly
|
|
777
726
|
// constructed handler starts from a clean canonical cache/bypass state.
|
|
@@ -803,7 +752,10 @@ export function registerMissionControlReadRoutes(router, deps) {
|
|
|
803
752
|
sendRouteError(res, 400, "mission-control.read.auto-continue.status.validation", "initiativeId is required");
|
|
804
753
|
return;
|
|
805
754
|
}
|
|
806
|
-
|
|
755
|
+
let run = deps.autoContinueRuns.get(id) ?? null;
|
|
756
|
+
if (!run && deps.restoreAutoContinueRun) {
|
|
757
|
+
run = await deps.restoreAutoContinueRun(id) ?? null;
|
|
758
|
+
}
|
|
807
759
|
deps.sendJson(res, 200, {
|
|
808
760
|
ok: true,
|
|
809
761
|
initiativeId: id,
|
|
@@ -953,13 +905,42 @@ export function registerMissionControlReadRoutes(router, deps) {
|
|
|
953
905
|
if (isCanonicalAllScopeMismatch(canonicalRecord, useAllScope)) {
|
|
954
906
|
throw new Error("canonical next-up all-workspaces scope mismatch");
|
|
955
907
|
}
|
|
956
|
-
const canonicalItems = applyQueueNoiseControls(normalizeQueueItems(canonicalRecord.items).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs });
|
|
908
|
+
const canonicalItems = await enrichWithMilestoneBreakdown(applyQueueNoiseControls(normalizeQueueItems(canonicalRecord.items).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs }), deps);
|
|
957
909
|
const canonicalTotal = Math.max(canonicalItems.length, Math.floor(asNumber(canonicalRecord.total) ?? canonicalItems.length)) ?? canonicalItems.length;
|
|
958
910
|
const canonicalPagination = parsePaginationEnvelope(canonicalRecord.pagination, {
|
|
959
911
|
offset,
|
|
960
912
|
limit: pageSize,
|
|
961
913
|
total: canonicalTotal,
|
|
962
914
|
});
|
|
915
|
+
let canonicalSummaryItems = canonicalItems;
|
|
916
|
+
const summaryPageSize = Math.max(pageSize, Math.min(canonicalTotal, 200));
|
|
917
|
+
if (canonicalTotal > canonicalItems.length) {
|
|
918
|
+
const summaryItems = [];
|
|
919
|
+
for (let summaryOffset = 0; summaryOffset < canonicalTotal; summaryOffset += summaryPageSize) {
|
|
920
|
+
const summaryParams = new URLSearchParams(params);
|
|
921
|
+
summaryParams.set("offset", String(summaryOffset));
|
|
922
|
+
summaryParams.set("limit", String(summaryPageSize));
|
|
923
|
+
const summaryPage = await requestCanonicalWithLegacyFallback(deps, {
|
|
924
|
+
timeoutMs: CANONICAL_NEXT_UP_TIMEOUT_MS,
|
|
925
|
+
label: "canonical next-up summary",
|
|
926
|
+
modernPath: `/api/client/mission-control/next-up?${summaryParams.toString()}`,
|
|
927
|
+
legacyPath: `/api/mission-control/next-up?${summaryParams.toString()}`,
|
|
928
|
+
});
|
|
929
|
+
const summaryRecord = asRecord(summaryPage);
|
|
930
|
+
if (!summaryRecord || !Array.isArray(summaryRecord.items)) {
|
|
931
|
+
throw new Error("invalid canonical next-up summary payload");
|
|
932
|
+
}
|
|
933
|
+
const normalizedSummaryItems = applyQueueNoiseControls(normalizeQueueItems(summaryRecord.items).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs });
|
|
934
|
+
summaryItems.push(...normalizedSummaryItems);
|
|
935
|
+
if (normalizedSummaryItems.length < summaryPageSize) {
|
|
936
|
+
break;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
canonicalSummaryItems =
|
|
940
|
+
summaryItems.length > 0
|
|
941
|
+
? dedupeQueueItemsByLineage(summaryItems)
|
|
942
|
+
: canonicalItems;
|
|
943
|
+
}
|
|
963
944
|
const shouldRepaginateCanonically = canonicalItems.length > pageSize ||
|
|
964
945
|
canonicalPagination.offset !== offset ||
|
|
965
946
|
canonicalPagination.limit !== pageSize;
|
|
@@ -972,11 +953,13 @@ export function registerMissionControlReadRoutes(router, deps) {
|
|
|
972
953
|
})
|
|
973
954
|
: null;
|
|
974
955
|
const degraded = dedupeStrings(asStringArray(canonicalRecord.degraded));
|
|
956
|
+
const canonicalSummary = summarizeQueueItems(canonicalSummaryItems);
|
|
975
957
|
const responsePayload = {
|
|
976
958
|
ok: true,
|
|
977
959
|
generatedAt: asString(canonicalRecord.generatedAt) ?? new Date().toISOString(),
|
|
978
960
|
total: paged ? paged.filtered.length : canonicalPagination.total,
|
|
979
961
|
items: paged ? paged.paged : canonicalItems,
|
|
962
|
+
summary: canonicalSummary,
|
|
980
963
|
pagination: paged ? paged.pagination : canonicalPagination,
|
|
981
964
|
source: "canonical",
|
|
982
965
|
degraded,
|
|
@@ -1045,86 +1028,13 @@ export function registerMissionControlReadRoutes(router, deps) {
|
|
|
1045
1028
|
return;
|
|
1046
1029
|
}
|
|
1047
1030
|
canonicalFallbackReason = `canonical next-up unavailable (${deps.safeErrorMessage(err)})`;
|
|
1048
|
-
if (projectId || useAllScope) {
|
|
1049
|
-
try {
|
|
1050
|
-
const bridgeParams = new URLSearchParams();
|
|
1051
|
-
if (initiativeId)
|
|
1052
|
-
bridgeParams.set("initiative_id", initiativeId);
|
|
1053
|
-
if (projectId) {
|
|
1054
|
-
bridgeParams.set("workspace_id", projectId);
|
|
1055
|
-
bridgeParams.set("command_center_id", projectId);
|
|
1056
|
-
}
|
|
1057
|
-
else if (useAllScope) {
|
|
1058
|
-
bridgeParams.set("workspace_id", "all");
|
|
1059
|
-
bridgeParams.set("command_center_id", "all");
|
|
1060
|
-
}
|
|
1061
|
-
bridgeParams.set("level", "workstream");
|
|
1062
|
-
bridgeParams.set("offset", String(Math.max(0, offset)));
|
|
1063
|
-
bridgeParams.set("limit", String(Math.min(300, Math.max(pageSize, offset + pageSize))));
|
|
1064
|
-
bridgeParams.set("include_completed", includeCompleted ? "1" : "0");
|
|
1065
|
-
bridgeParams.set("noise_threshold", noiseThreshold);
|
|
1066
|
-
bridgeParams.set("dedup_window", String(dedupWindowMs));
|
|
1067
|
-
bridgeParams.set("mix_policy", requestedMixPolicy ?? "iwmt_v1");
|
|
1068
|
-
if (requestedOrderMode) {
|
|
1069
|
-
bridgeParams.set("order_mode", requestedOrderMode);
|
|
1070
|
-
}
|
|
1071
|
-
const canonicalSlices = await requestCanonicalWithLegacyFallback(deps, {
|
|
1072
|
-
timeoutMs: CANONICAL_SLICES_TIMEOUT_MS,
|
|
1073
|
-
label: "canonical slices bridge",
|
|
1074
|
-
modernPath: `/api/client/mission-control/slices?${bridgeParams.toString()}`,
|
|
1075
|
-
legacyPath: `/api/mission-control/slices?${bridgeParams.toString()}`,
|
|
1076
|
-
});
|
|
1077
|
-
const canonicalSlicesRecord = asRecord(canonicalSlices);
|
|
1078
|
-
if (!canonicalSlicesRecord || !Array.isArray(canonicalSlicesRecord.items)) {
|
|
1079
|
-
throw new Error("invalid canonical slices payload");
|
|
1080
|
-
}
|
|
1081
|
-
if (isCanonicalAllScopeMismatch(canonicalSlicesRecord, useAllScope)) {
|
|
1082
|
-
throw new Error("canonical slices all-workspaces scope mismatch");
|
|
1083
|
-
}
|
|
1084
|
-
const bridgedItems = applyQueueNoiseControls(mapCanonicalSlicesToQueueItems(canonicalSlicesRecord.items).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs });
|
|
1085
|
-
if (bridgedItems.length > 0) {
|
|
1086
|
-
const paged = applySliceSearchAndPagination({
|
|
1087
|
-
items: bridgedItems,
|
|
1088
|
-
searchTerm: "",
|
|
1089
|
-
offset,
|
|
1090
|
-
limit: pageSize,
|
|
1091
|
-
});
|
|
1092
|
-
const degraded = dedupeStrings([
|
|
1093
|
-
...(Array.isArray(canonicalSlicesRecord.degraded)
|
|
1094
|
-
? canonicalSlicesRecord.degraded
|
|
1095
|
-
: []),
|
|
1096
|
-
...(canonicalFallbackReason ? [canonicalFallbackReason] : []),
|
|
1097
|
-
"Next Up derived from canonical slices.",
|
|
1098
|
-
]);
|
|
1099
|
-
const responsePayload = {
|
|
1100
|
-
ok: true,
|
|
1101
|
-
generatedAt: asString(canonicalSlicesRecord.generatedAt) ??
|
|
1102
|
-
new Date().toISOString(),
|
|
1103
|
-
total: paged.filtered.length,
|
|
1104
|
-
items: paged.paged,
|
|
1105
|
-
pagination: paged.pagination,
|
|
1106
|
-
source: "canonical_slices_bridge",
|
|
1107
|
-
degraded,
|
|
1108
|
-
};
|
|
1109
|
-
writeCanonicalReadCache(nextUpCanonicalCacheKey, responsePayload);
|
|
1110
|
-
deps.sendJson(res, 200, responsePayload);
|
|
1111
|
-
return;
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
catch (bridgeErr) {
|
|
1115
|
-
canonicalFallbackReason = dedupeStrings([
|
|
1116
|
-
canonicalFallbackReason ?? "",
|
|
1117
|
-
`canonical slices bridge unavailable (${deps.safeErrorMessage(bridgeErr)})`,
|
|
1118
|
-
]).join(" | ");
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
1031
|
// Continue to local fallback.
|
|
1122
1032
|
try {
|
|
1123
1033
|
const queue = await deps.buildNextUpQueue({
|
|
1124
1034
|
initiativeId,
|
|
1125
1035
|
projectId,
|
|
1126
1036
|
});
|
|
1127
|
-
const items = applyQueueNoiseControls(normalizeQueueItems(queue.items ?? []).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs });
|
|
1037
|
+
const items = await enrichWithMilestoneBreakdown(applyQueueNoiseControls(normalizeQueueItems(queue.items ?? []).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs }), deps);
|
|
1128
1038
|
const paged = applySliceSearchAndPagination({
|
|
1129
1039
|
items,
|
|
1130
1040
|
searchTerm: "",
|
|
@@ -1140,6 +1050,7 @@ export function registerMissionControlReadRoutes(router, deps) {
|
|
|
1140
1050
|
generatedAt: new Date().toISOString(),
|
|
1141
1051
|
total: paged.filtered.length,
|
|
1142
1052
|
items: paged.paged,
|
|
1053
|
+
summary: summarizeQueueItems(items),
|
|
1143
1054
|
pagination: paged.pagination,
|
|
1144
1055
|
source: "local_fallback",
|
|
1145
1056
|
degraded,
|
|
@@ -1157,7 +1068,7 @@ export function registerMissionControlReadRoutes(router, deps) {
|
|
|
1157
1068
|
initiativeId,
|
|
1158
1069
|
projectId,
|
|
1159
1070
|
});
|
|
1160
|
-
const items = applyQueueNoiseControls(normalizeQueueItems(queue.items ?? []).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs });
|
|
1071
|
+
const items = await enrichWithMilestoneBreakdown(applyQueueNoiseControls(normalizeQueueItems(queue.items ?? []).filter((item) => includeCompleted ? true : item.queueState !== "completed"), { noiseThreshold, dedupWindowMs }), deps);
|
|
1161
1072
|
const paged = applySliceSearchAndPagination({
|
|
1162
1073
|
items,
|
|
1163
1074
|
searchTerm: "",
|
|
@@ -1173,6 +1084,7 @@ export function registerMissionControlReadRoutes(router, deps) {
|
|
|
1173
1084
|
generatedAt: new Date().toISOString(),
|
|
1174
1085
|
total: paged.filtered.length,
|
|
1175
1086
|
items: paged.paged,
|
|
1087
|
+
summary: summarizeQueueItems(items),
|
|
1176
1088
|
pagination: paged.pagination,
|
|
1177
1089
|
source: "local",
|
|
1178
1090
|
degraded: dedupeStrings(degraded),
|
|
@@ -1544,7 +1456,7 @@ export function registerMissionControlReadRoutes(router, deps) {
|
|
|
1544
1456
|
const taskBuckets = new Map();
|
|
1545
1457
|
for (const taskId of selectedTaskIds) {
|
|
1546
1458
|
const task = graphIndex?.tasksById.get(taskId) ?? null;
|
|
1547
|
-
if (!includeCompleted && isDoneStatus(task?.status ??
|
|
1459
|
+
if (!includeCompleted && isDoneStatus(task?.status ?? ""))
|
|
1548
1460
|
continue;
|
|
1549
1461
|
const milestoneId = task?.milestoneId ??
|
|
1550
1462
|
item.sliceMilestoneId ??
|
|
@@ -1623,7 +1535,7 @@ export function registerMissionControlReadRoutes(router, deps) {
|
|
|
1623
1535
|
]);
|
|
1624
1536
|
for (const taskId of selectedTaskIds) {
|
|
1625
1537
|
const task = graphIndex?.tasksById.get(taskId) ?? null;
|
|
1626
|
-
if (!includeCompleted && isDoneStatus(task?.status ??
|
|
1538
|
+
if (!includeCompleted && isDoneStatus(task?.status ?? ""))
|
|
1627
1539
|
continue;
|
|
1628
1540
|
const taskTitle = task?.title ??
|
|
1629
1541
|
(taskId === item.nextTaskId ? item.nextTaskTitle : null) ??
|
|
@@ -1644,7 +1556,7 @@ export function registerMissionControlReadRoutes(router, deps) {
|
|
|
1644
1556
|
: null,
|
|
1645
1557
|
taskId,
|
|
1646
1558
|
taskTitle,
|
|
1647
|
-
queueState: isDoneStatus(task?.status ??
|
|
1559
|
+
queueState: isDoneStatus(task?.status ?? "") ? "completed" : item.queueState,
|
|
1648
1560
|
sourceWorkstreamIds: [item.workstreamId],
|
|
1649
1561
|
runnerAgentId: (item.runnerAgents ?? [])[0]?.id ?? item.runnerAgentId ?? null,
|
|
1650
1562
|
runnerAgentName: (item.runnerAgents ?? [])[0]?.name ?? item.runnerAgentName ?? "Unassigned",
|
|
@@ -18,6 +18,7 @@ type OnboardingControllerLike = {
|
|
|
18
18
|
apiKey: string;
|
|
19
19
|
userId?: string;
|
|
20
20
|
}) => Promise<OnboardingState>;
|
|
21
|
+
cancelPairing?: () => Promise<OnboardingState>;
|
|
21
22
|
disconnect: () => Promise<OnboardingState>;
|
|
22
23
|
};
|
|
23
24
|
type RegisterOnboardingRoutesDeps<TReq, TRes> = {
|
|
@@ -83,6 +83,23 @@ export function registerOnboardingRoutes(router, deps) {
|
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
}, "Submit manual OrgX API key");
|
|
86
|
+
router.add("POST", "onboarding/cancel", async ({ res }) => {
|
|
87
|
+
try {
|
|
88
|
+
const state = deps.onboarding.cancelPairing
|
|
89
|
+
? await deps.onboarding.cancelPairing()
|
|
90
|
+
: await deps.onboarding.getStatus();
|
|
91
|
+
deps.sendJson(res, 200, {
|
|
92
|
+
ok: true,
|
|
93
|
+
data: deps.getOnboardingState(state),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
deps.sendJson(res, 500, {
|
|
98
|
+
ok: false,
|
|
99
|
+
error: deps.safeErrorMessage(err),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}, "Cancel onboarding pairing flow");
|
|
86
103
|
router.add("POST", "onboarding/disconnect", async ({ res }) => {
|
|
87
104
|
try {
|
|
88
105
|
const state = await deps.onboarding.disconnect();
|