@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
|
@@ -76,6 +76,7 @@ function parseDecisionOptions(record) {
|
|
|
76
76
|
id,
|
|
77
77
|
label,
|
|
78
78
|
description: null,
|
|
79
|
+
consequences: null,
|
|
79
80
|
impliedStatus: null,
|
|
80
81
|
actionType: null,
|
|
81
82
|
requiresNote: false,
|
|
@@ -103,6 +104,9 @@ function parseDecisionOptions(record) {
|
|
|
103
104
|
id,
|
|
104
105
|
label,
|
|
105
106
|
description: typeof candidate.description === "string" ? candidate.description : null,
|
|
107
|
+
consequences: (typeof candidate.consequences === "string" && candidate.consequences.trim()) ||
|
|
108
|
+
(typeof candidate.impact === "string" && candidate.impact.trim()) ||
|
|
109
|
+
null,
|
|
106
110
|
impliedStatus: normalizeOptionStatus(candidate.implied_status) ??
|
|
107
111
|
normalizeOptionStatus(candidate.status) ??
|
|
108
112
|
normalizeOptionStatus(candidate.disposition),
|
|
@@ -202,6 +206,15 @@ export function mapDecisionEntity(entity) {
|
|
|
202
206
|
: 0);
|
|
203
207
|
const options = parseDecisionOptions(record);
|
|
204
208
|
const evidenceRefs = parseEvidenceRefs(record);
|
|
209
|
+
const metadataBlocker = asRecord(metadata?.blocker);
|
|
210
|
+
const envelopeBlocker = asRecord(envelope?.blocker);
|
|
211
|
+
const blockerContext = (metadataBlocker
|
|
212
|
+
? pickString(metadataBlocker, ["description", "summary", "required_action", "requiredAction"])
|
|
213
|
+
: null) ??
|
|
214
|
+
(envelopeBlocker
|
|
215
|
+
? pickString(envelopeBlocker, ["description", "summary", "required_action", "requiredAction"])
|
|
216
|
+
: null) ??
|
|
217
|
+
null;
|
|
205
218
|
return {
|
|
206
219
|
id: String(record.id ?? ""),
|
|
207
220
|
title: pickStringFromRecords(containers, ["title", "name"]) ?? "Decision",
|
|
@@ -212,7 +225,7 @@ export function mapDecisionEntity(entity) {
|
|
|
212
225
|
"details",
|
|
213
226
|
"recommended_action",
|
|
214
227
|
"recommendedAction",
|
|
215
|
-
]),
|
|
228
|
+
]) ?? blockerContext,
|
|
216
229
|
status: pickStringFromRecords(containers, ["status", "decision_status"]) ?? "pending",
|
|
217
230
|
priority: pickStringFromRecords(containers, ["priority"]),
|
|
218
231
|
decisionType: pickStringFromRecords(containers, ["decision_type", "decisionType"]),
|
|
@@ -239,7 +252,11 @@ export function mapDecisionEntity(entity) {
|
|
|
239
252
|
recommendedAction: pickStringFromRecords(containers, [
|
|
240
253
|
"recommended_action",
|
|
241
254
|
"recommendedAction",
|
|
242
|
-
])
|
|
255
|
+
]) ??
|
|
256
|
+
(metadataBlocker
|
|
257
|
+
? pickString(metadataBlocker, ["required_action", "requiredAction"])
|
|
258
|
+
: null) ??
|
|
259
|
+
null,
|
|
243
260
|
occurrenceCount: pickNumberFromRecords(containers, ["occurrence_count", "occurrenceCount"]),
|
|
244
261
|
firstSeenAt: toIsoString(pickStringFromRecords(containers, ["first_seen_at", "firstSeenAt"])),
|
|
245
262
|
lastSeenAt: toIsoString(pickStringFromRecords(containers, ["last_seen_at", "lastSeenAt"])),
|
|
@@ -278,6 +278,9 @@ export function createDispatchLifecycle(deps) {
|
|
|
278
278
|
if (typeof record.description === "string" && record.description.trim()) {
|
|
279
279
|
optionPayload.description = record.description.trim();
|
|
280
280
|
}
|
|
281
|
+
if (typeof record.consequences === "string" && record.consequences.trim()) {
|
|
282
|
+
optionPayload.consequences = record.consequences.trim();
|
|
283
|
+
}
|
|
281
284
|
if (typeof record.implied_status === "string" && record.implied_status.trim()) {
|
|
282
285
|
const implied = record.implied_status.trim().toLowerCase();
|
|
283
286
|
if (implied === "approved" ||
|
|
@@ -92,6 +92,7 @@ export declare function isBlockedStatus(status: string): boolean;
|
|
|
92
92
|
export declare function isInProgressStatus(status: string): boolean;
|
|
93
93
|
export declare function deriveInitiativeLifecycleStatus(currentStatus: string, childStatuses: string[]): string;
|
|
94
94
|
export declare function isDispatchableWorkstreamStatus(status: string): boolean;
|
|
95
|
+
export declare function normalizeMissionControlStatus(status: string | null | undefined): string;
|
|
95
96
|
export declare function isDoneStatus(status: string): boolean;
|
|
96
97
|
export declare function listEntitiesSafe(client: OrgXClient, type: MissionControlNodeType, filters: Record<string, unknown>): Promise<{
|
|
97
98
|
items: Entity[];
|
|
@@ -681,7 +681,7 @@ export function deriveInitiativeLifecycleStatus(currentStatus, childStatuses) {
|
|
|
681
681
|
return currentStatus;
|
|
682
682
|
}
|
|
683
683
|
export function isDispatchableWorkstreamStatus(status) {
|
|
684
|
-
const normalized = status
|
|
684
|
+
const normalized = normalizeMissionControlStatus(status);
|
|
685
685
|
if (!normalized)
|
|
686
686
|
return true;
|
|
687
687
|
return !(normalized === "blocked" ||
|
|
@@ -691,8 +691,11 @@ export function isDispatchableWorkstreamStatus(status) {
|
|
|
691
691
|
normalized === "archived" ||
|
|
692
692
|
normalized === "deleted");
|
|
693
693
|
}
|
|
694
|
+
export function normalizeMissionControlStatus(status) {
|
|
695
|
+
return (status ?? "").trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
696
|
+
}
|
|
694
697
|
export function isDoneStatus(status) {
|
|
695
|
-
const normalized = status
|
|
698
|
+
const normalized = normalizeMissionControlStatus(status);
|
|
696
699
|
return (normalized === "done" ||
|
|
697
700
|
normalized === "completed" ||
|
|
698
701
|
normalized === "cancelled" ||
|
|
@@ -16,6 +16,31 @@ export type SliceRunDecisionOption = {
|
|
|
16
16
|
impliedStatus: string | null;
|
|
17
17
|
requiresNote: boolean;
|
|
18
18
|
};
|
|
19
|
+
export type SliceRunPendingDecision = {
|
|
20
|
+
id: string;
|
|
21
|
+
title: string;
|
|
22
|
+
summary: string | null;
|
|
23
|
+
status: string;
|
|
24
|
+
blocking: boolean;
|
|
25
|
+
decisionType: string | null;
|
|
26
|
+
recommendedAction: string | null;
|
|
27
|
+
updatedAt: string | null;
|
|
28
|
+
sourceRunId: string | null;
|
|
29
|
+
sourceClient: string | null;
|
|
30
|
+
evidenceCount: number;
|
|
31
|
+
options: SliceRunDecisionOption[];
|
|
32
|
+
};
|
|
33
|
+
export type SliceRunBlockerSummary = {
|
|
34
|
+
id: string;
|
|
35
|
+
reason: string;
|
|
36
|
+
waitingOn: string | null;
|
|
37
|
+
requiredAction: string | null;
|
|
38
|
+
source: string | null;
|
|
39
|
+
eventType: string | null;
|
|
40
|
+
eventAt: string | null;
|
|
41
|
+
severity: "info" | "warn" | "error";
|
|
42
|
+
decisionIds: string[];
|
|
43
|
+
};
|
|
19
44
|
export type SliceRunProjection = {
|
|
20
45
|
id: string;
|
|
21
46
|
sliceRunId: string;
|
|
@@ -38,6 +63,8 @@ export type SliceRunProjection = {
|
|
|
38
63
|
decisionCount: number;
|
|
39
64
|
blockingDecisionCount: number;
|
|
40
65
|
decisionOptions: SliceRunDecisionOption[];
|
|
66
|
+
pendingDecisions: SliceRunPendingDecision[];
|
|
67
|
+
blockers: SliceRunBlockerSummary[];
|
|
41
68
|
sourceClient: string | null;
|
|
42
69
|
runtimeState: string | null;
|
|
43
70
|
startedAt: string | null;
|
|
@@ -257,6 +257,8 @@ function createProjection(sliceRunId) {
|
|
|
257
257
|
decisionCount: 0,
|
|
258
258
|
blockingDecisionCount: 0,
|
|
259
259
|
decisionOptions: [],
|
|
260
|
+
pendingDecisions: [],
|
|
261
|
+
blockers: [],
|
|
260
262
|
sourceClient: null,
|
|
261
263
|
runtimeState: null,
|
|
262
264
|
startedAt: null,
|
|
@@ -274,6 +276,8 @@ function createProjection(sliceRunId) {
|
|
|
274
276
|
_artifactIds: new Set(),
|
|
275
277
|
_hasExplicitCompletion: false,
|
|
276
278
|
_peakReportedArtifacts: 0,
|
|
279
|
+
_pendingDecisionById: new Map(),
|
|
280
|
+
_blockerByKey: new Map(),
|
|
277
281
|
};
|
|
278
282
|
}
|
|
279
283
|
function upsertProjection(map, sliceRunId) {
|
|
@@ -403,6 +407,19 @@ function maybeAddArtifact(projection, item, metadata) {
|
|
|
403
407
|
function mergeDecisionOptions(projection, optionsRaw) {
|
|
404
408
|
if (!Array.isArray(optionsRaw))
|
|
405
409
|
return;
|
|
410
|
+
const next = parseDecisionOptions(optionsRaw);
|
|
411
|
+
if (next.length === 0)
|
|
412
|
+
return;
|
|
413
|
+
const merged = new Map();
|
|
414
|
+
for (const option of projection.decisionOptions)
|
|
415
|
+
merged.set(option.id, option);
|
|
416
|
+
for (const option of next)
|
|
417
|
+
merged.set(option.id, option);
|
|
418
|
+
projection.decisionOptions = Array.from(merged.values()).slice(0, 8);
|
|
419
|
+
}
|
|
420
|
+
function parseDecisionOptions(optionsRaw) {
|
|
421
|
+
if (!Array.isArray(optionsRaw))
|
|
422
|
+
return [];
|
|
406
423
|
const next = [];
|
|
407
424
|
for (const option of optionsRaw) {
|
|
408
425
|
const record = asRecord(option);
|
|
@@ -420,14 +437,169 @@ function mergeDecisionOptions(projection, optionsRaw) {
|
|
|
420
437
|
requiresNote: metadataBoolean(record, ["requiresNote", "requires_note"]) ?? false,
|
|
421
438
|
});
|
|
422
439
|
}
|
|
423
|
-
|
|
440
|
+
return next;
|
|
441
|
+
}
|
|
442
|
+
function extractDecisionIdsFromMetadata(metadata) {
|
|
443
|
+
if (!metadata)
|
|
444
|
+
return [];
|
|
445
|
+
const ids = new Set();
|
|
446
|
+
for (const id of metadataStringArray(metadata, [
|
|
447
|
+
"decision_id",
|
|
448
|
+
"decisionId",
|
|
449
|
+
"decision_ids",
|
|
450
|
+
"decisionIds",
|
|
451
|
+
"blocking_decision_ids",
|
|
452
|
+
"blockingDecisionIds",
|
|
453
|
+
"non_blocking_decision_ids",
|
|
454
|
+
"nonBlockingDecisionIds",
|
|
455
|
+
])) {
|
|
456
|
+
ids.add(id);
|
|
457
|
+
}
|
|
458
|
+
const decisionsNeededRaw = metadata.decisions_needed ?? metadata.decisionsNeeded;
|
|
459
|
+
if (Array.isArray(decisionsNeededRaw)) {
|
|
460
|
+
for (const item of decisionsNeededRaw) {
|
|
461
|
+
const record = asRecord(item);
|
|
462
|
+
if (!record)
|
|
463
|
+
continue;
|
|
464
|
+
const directId = normalizeText(record.id) ??
|
|
465
|
+
normalizeText(record.decision_id) ??
|
|
466
|
+
normalizeText(record.decisionId);
|
|
467
|
+
if (directId)
|
|
468
|
+
ids.add(directId);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return Array.from(ids);
|
|
472
|
+
}
|
|
473
|
+
function normalizePendingDecisionStatus(value) {
|
|
474
|
+
return (value ?? "pending").trim().toLowerCase() || "pending";
|
|
475
|
+
}
|
|
476
|
+
function isDecisionResolvedStatus(status) {
|
|
477
|
+
return (status === "approved" ||
|
|
478
|
+
status === "declined" ||
|
|
479
|
+
status === "cancelled" ||
|
|
480
|
+
status === "resolved" ||
|
|
481
|
+
status === "closed");
|
|
482
|
+
}
|
|
483
|
+
function upsertPendingDecision(projection, decisionRecord, metadata) {
|
|
484
|
+
const decisionId = normalizeText(decisionRecord.id) ??
|
|
485
|
+
normalizeText(decisionRecord.decision_id) ??
|
|
486
|
+
normalizeText(decisionRecord.entity_id);
|
|
487
|
+
if (!decisionId)
|
|
424
488
|
return;
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
489
|
+
const status = normalizePendingDecisionStatus(normalizeText(decisionRecord.status));
|
|
490
|
+
if (isDecisionResolvedStatus(status)) {
|
|
491
|
+
projection._pendingDecisionById.delete(decisionId);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
const options = parseDecisionOptions(decisionRecord.options ??
|
|
495
|
+
decisionRecord.decision_options ??
|
|
496
|
+
metadata?.options ??
|
|
497
|
+
metadata?.decision_options);
|
|
498
|
+
if (options.length > 0) {
|
|
499
|
+
mergeDecisionOptions(projection, options);
|
|
500
|
+
}
|
|
501
|
+
const evidenceGroup = decisionRecord.evidenceRefs ??
|
|
502
|
+
decisionRecord.evidence_refs ??
|
|
503
|
+
metadata?.evidence_refs ??
|
|
504
|
+
metadata?.decision_evidence;
|
|
505
|
+
const evidenceCount = Array.isArray(evidenceGroup) ? evidenceGroup.length : 0;
|
|
506
|
+
const updatedAt = toIso(normalizeText(decisionRecord.updatedAt)) ??
|
|
507
|
+
toIso(normalizeText(decisionRecord.updated_at)) ??
|
|
508
|
+
toIso(normalizeText(decisionRecord.requestedAt)) ??
|
|
509
|
+
toIso(normalizeText(decisionRecord.requested_at)) ??
|
|
510
|
+
projection.updatedAt;
|
|
511
|
+
projection._pendingDecisionById.set(decisionId, {
|
|
512
|
+
id: decisionId,
|
|
513
|
+
title: normalizeText(decisionRecord.title) ??
|
|
514
|
+
normalizeText(decisionRecord.name) ??
|
|
515
|
+
"Pending decision",
|
|
516
|
+
summary: normalizeText(decisionRecord.context) ??
|
|
517
|
+
normalizeText(decisionRecord.summary) ??
|
|
518
|
+
normalizeText(decisionRecord.description) ??
|
|
519
|
+
normalizeText(metadata?.summary) ??
|
|
520
|
+
null,
|
|
521
|
+
status,
|
|
522
|
+
blocking: metadataBoolean(metadata, ["blocking"]) !== false,
|
|
523
|
+
decisionType: normalizeText(decisionRecord.decisionType) ??
|
|
524
|
+
normalizeText(decisionRecord.decision_type) ??
|
|
525
|
+
normalizeText(metadata?.decision_type) ??
|
|
526
|
+
null,
|
|
527
|
+
recommendedAction: normalizeText(decisionRecord.recommendedAction) ??
|
|
528
|
+
normalizeText(decisionRecord.recommended_action) ??
|
|
529
|
+
normalizeText(metadata?.recommended_action) ??
|
|
530
|
+
null,
|
|
531
|
+
updatedAt,
|
|
532
|
+
sourceRunId: normalizeText(decisionRecord.sourceRunId) ??
|
|
533
|
+
normalizeText(decisionRecord.source_run_id) ??
|
|
534
|
+
normalizeText(metadata?.source_run_id) ??
|
|
535
|
+
normalizeText(metadata?.run_id) ??
|
|
536
|
+
normalizeText(metadata?.correlation_id) ??
|
|
537
|
+
null,
|
|
538
|
+
sourceClient: normalizeText(decisionRecord.sourceClient) ??
|
|
539
|
+
normalizeText(decisionRecord.source_client) ??
|
|
540
|
+
normalizeText(metadata?.source_client) ??
|
|
541
|
+
null,
|
|
542
|
+
evidenceCount,
|
|
543
|
+
options: options.slice(0, 4),
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
function inferBlockerFromActivity(item, metadata, event, atIso) {
|
|
547
|
+
const blocker = asRecord(metadata?.blocker);
|
|
548
|
+
const reason = normalizeText(blocker?.description) ??
|
|
549
|
+
normalizeText(blocker?.summary) ??
|
|
550
|
+
metadataString(metadata, ["error", "reason", "blocked_reason", "blockedReason", "last_error", "lastError"]) ??
|
|
551
|
+
normalizeText(item.summary) ??
|
|
552
|
+
normalizeText(item.description) ??
|
|
553
|
+
null;
|
|
554
|
+
if (!reason)
|
|
555
|
+
return null;
|
|
556
|
+
const waitingOn = normalizeText(blocker?.waiting_on) ??
|
|
557
|
+
normalizeText(blocker?.required_actor) ??
|
|
558
|
+
metadataString(metadata, ["waiting_on", "required_actor", "requiredActor"]) ??
|
|
559
|
+
null;
|
|
560
|
+
const requiredAction = normalizeText(blocker?.required_action) ??
|
|
561
|
+
normalizeText(blocker?.requiredAction) ??
|
|
562
|
+
metadataString(metadata, ["next_step", "nextStep", "recommended_action", "recommendedAction"]) ??
|
|
563
|
+
null;
|
|
564
|
+
const source = metadataString(metadata, ["source", "source_system", "sourceSystem"]) ??
|
|
565
|
+
null;
|
|
566
|
+
const severity = item.type === "run_failed" || event.includes("failed") || event.includes("error")
|
|
567
|
+
? "error"
|
|
568
|
+
: item.type === "blocker_created" || event.includes("blocked")
|
|
569
|
+
? "warn"
|
|
570
|
+
: "info";
|
|
571
|
+
const decisionIds = extractDecisionIdsFromMetadata(metadata);
|
|
572
|
+
return {
|
|
573
|
+
id: normalizeText(item.id) ?? `${event || item.type}:${atIso ?? "unknown"}`,
|
|
574
|
+
reason,
|
|
575
|
+
waitingOn,
|
|
576
|
+
requiredAction,
|
|
577
|
+
source,
|
|
578
|
+
eventType: event || item.type,
|
|
579
|
+
eventAt: atIso,
|
|
580
|
+
severity,
|
|
581
|
+
decisionIds,
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
function upsertBlocker(projection, blocker) {
|
|
585
|
+
const key = [
|
|
586
|
+
blocker.reason.trim().toLowerCase(),
|
|
587
|
+
blocker.waitingOn?.trim().toLowerCase() ?? "",
|
|
588
|
+
blocker.requiredAction?.trim().toLowerCase() ?? "",
|
|
589
|
+
].join("|");
|
|
590
|
+
const existing = projection._blockerByKey.get(key);
|
|
591
|
+
if (!existing) {
|
|
592
|
+
projection._blockerByKey.set(key, blocker);
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
const existingEpoch = toEpoch(existing.eventAt);
|
|
596
|
+
const nextEpoch = toEpoch(blocker.eventAt);
|
|
597
|
+
const keep = nextEpoch >= existingEpoch ? blocker : existing;
|
|
598
|
+
keep.decisionIds = dedupeStrings([
|
|
599
|
+
...(existing.decisionIds ?? []),
|
|
600
|
+
...(blocker.decisionIds ?? []),
|
|
601
|
+
]);
|
|
602
|
+
projection._blockerByKey.set(key, keep);
|
|
431
603
|
}
|
|
432
604
|
function applySessionFallback(projection, session) {
|
|
433
605
|
const status = (session.status ?? "").trim().toLowerCase();
|
|
@@ -500,6 +672,10 @@ export function buildSliceRunProjections(input) {
|
|
|
500
672
|
const projection = upsertProjection(projections, sliceRunId);
|
|
501
673
|
updateProjectionContext(projection, item, metadata);
|
|
502
674
|
const atIso = toIso(item.timestamp);
|
|
675
|
+
const blockerFromEvent = inferBlockerFromActivity(item, metadata, event, atIso);
|
|
676
|
+
if (blockerFromEvent) {
|
|
677
|
+
upsertBlocker(projection, blockerFromEvent);
|
|
678
|
+
}
|
|
503
679
|
if (item.type === "artifact_created") {
|
|
504
680
|
maybeAddArtifact(projection, item, metadata);
|
|
505
681
|
if (projection.status !== "failed" && projection.status !== "archived") {
|
|
@@ -716,14 +892,20 @@ export function buildSliceRunProjections(input) {
|
|
|
716
892
|
if (!projection)
|
|
717
893
|
continue;
|
|
718
894
|
const status = (normalizeText(decisionRecord?.status) ?? "pending").toLowerCase();
|
|
719
|
-
if (
|
|
720
|
-
|
|
895
|
+
if (decisionRecord) {
|
|
896
|
+
upsertPendingDecision(projection, decisionRecord, metadata);
|
|
721
897
|
}
|
|
898
|
+
if (isDecisionResolvedStatus(status))
|
|
899
|
+
continue;
|
|
722
900
|
projection.decisionCount += 1;
|
|
723
901
|
const isBlocking = metadataBoolean(metadata, ["blocking"]) !== false;
|
|
724
902
|
if (isBlocking)
|
|
725
903
|
projection.blockingDecisionCount += 1;
|
|
726
|
-
mergeDecisionOptions(projection, decisionRecord?.options ??
|
|
904
|
+
mergeDecisionOptions(projection, decisionRecord?.options ??
|
|
905
|
+
decisionRecord?.decision_options ??
|
|
906
|
+
metadata?.options ??
|
|
907
|
+
metadata?.decision_options ??
|
|
908
|
+
null);
|
|
727
909
|
const updatedAt = toIso(normalizeText(decisionRecord?.updatedAt)) ??
|
|
728
910
|
toIso(normalizeText(decisionRecord?.requestedAt)) ??
|
|
729
911
|
projection.updatedAt;
|
|
@@ -851,6 +1033,12 @@ export function buildSliceRunProjections(input) {
|
|
|
851
1033
|
decisionCount: projection.decisionCount,
|
|
852
1034
|
blockingDecisionCount: projection.blockingDecisionCount,
|
|
853
1035
|
decisionOptions: projection.decisionOptions,
|
|
1036
|
+
pendingDecisions: Array.from(projection._pendingDecisionById.values())
|
|
1037
|
+
.sort((a, b) => toEpoch(b.updatedAt) - toEpoch(a.updatedAt))
|
|
1038
|
+
.slice(0, 8),
|
|
1039
|
+
blockers: Array.from(projection._blockerByKey.values())
|
|
1040
|
+
.sort((a, b) => toEpoch(b.eventAt) - toEpoch(a.eventAt))
|
|
1041
|
+
.slice(0, 6),
|
|
854
1042
|
sourceClient: projection.sourceClient,
|
|
855
1043
|
runtimeState: projection.runtimeState,
|
|
856
1044
|
startedAt: projection.startedAt,
|