@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.
Files changed (161) hide show
  1. package/dashboard/dist/assets/9gFmK3Kr.js +1 -0
  2. package/dashboard/dist/assets/9gFmK3Kr.js.br +0 -0
  3. package/dashboard/dist/assets/9gFmK3Kr.js.gz +0 -0
  4. package/dashboard/dist/assets/{DS79hzMu.js → BrMXbzQ-.js} +2 -2
  5. package/dashboard/dist/assets/BrMXbzQ-.js.br +0 -0
  6. package/dashboard/dist/assets/BrMXbzQ-.js.gz +0 -0
  7. package/dashboard/dist/assets/By0MIBj_.js +1 -0
  8. package/dashboard/dist/assets/By0MIBj_.js.br +0 -0
  9. package/dashboard/dist/assets/By0MIBj_.js.gz +0 -0
  10. package/dashboard/dist/assets/C1u2SGin.css +1 -0
  11. package/dashboard/dist/assets/C1u2SGin.css.br +0 -0
  12. package/dashboard/dist/assets/C1u2SGin.css.gz +0 -0
  13. package/dashboard/dist/assets/{467jKHFJ.js → CGJiHCIx.js} +1 -1
  14. package/dashboard/dist/assets/CGJiHCIx.js.br +0 -0
  15. package/dashboard/dist/assets/CGJiHCIx.js.gz +0 -0
  16. package/dashboard/dist/assets/CSd4rSuU.js +212 -0
  17. package/dashboard/dist/assets/CSd4rSuU.js.br +0 -0
  18. package/dashboard/dist/assets/CSd4rSuU.js.gz +0 -0
  19. package/dashboard/dist/assets/{5Ihga-4X.js → CZXS5i_5.js} +1 -1
  20. package/dashboard/dist/assets/CZXS5i_5.js.br +0 -0
  21. package/dashboard/dist/assets/CZXS5i_5.js.gz +0 -0
  22. package/dashboard/dist/assets/{a6qcPiWt.js → CbVWL74-.js} +1 -1
  23. package/dashboard/dist/assets/CbVWL74-.js.br +0 -0
  24. package/dashboard/dist/assets/CbVWL74-.js.gz +0 -0
  25. package/dashboard/dist/assets/{qDJ6rqcs.js → D-FuHfT8.js} +1 -1
  26. package/dashboard/dist/assets/D-FuHfT8.js.br +0 -0
  27. package/dashboard/dist/assets/D-FuHfT8.js.gz +0 -0
  28. package/dashboard/dist/assets/{BcJmNILk.js → D0PN5_vY.js} +1 -1
  29. package/dashboard/dist/assets/D0PN5_vY.js.br +0 -0
  30. package/dashboard/dist/assets/D0PN5_vY.js.gz +0 -0
  31. package/dashboard/dist/assets/DDCPrZRt.js +1 -0
  32. package/dashboard/dist/assets/DDCPrZRt.js.br +0 -0
  33. package/dashboard/dist/assets/DDCPrZRt.js.gz +0 -0
  34. package/dashboard/dist/assets/{B71dt9yu.js → DNQ-iFO2.js} +1 -1
  35. package/dashboard/dist/assets/DNQ-iFO2.js.br +0 -0
  36. package/dashboard/dist/assets/DNQ-iFO2.js.gz +0 -0
  37. package/dashboard/dist/assets/{PVi0vr9a.js → DhPuHPK7.js} +1 -1
  38. package/dashboard/dist/assets/DhPuHPK7.js.br +0 -0
  39. package/dashboard/dist/assets/DhPuHPK7.js.gz +0 -0
  40. package/dashboard/dist/assets/Dhz7qPtn.js +1 -0
  41. package/dashboard/dist/assets/Dhz7qPtn.js.br +0 -0
  42. package/dashboard/dist/assets/Dhz7qPtn.js.gz +0 -0
  43. package/dashboard/dist/assets/LOFrVoPD.js +1 -0
  44. package/dashboard/dist/assets/LOFrVoPD.js.br +0 -0
  45. package/dashboard/dist/assets/LOFrVoPD.js.gz +0 -0
  46. package/dashboard/dist/assets/OlLPtzdz.js +1 -0
  47. package/dashboard/dist/assets/OlLPtzdz.js.br +0 -0
  48. package/dashboard/dist/assets/OlLPtzdz.js.gz +0 -0
  49. package/dashboard/dist/assets/{sdoPH_Z1.js → RN4M9u9W.js} +2 -2
  50. package/dashboard/dist/assets/RN4M9u9W.js.br +0 -0
  51. package/dashboard/dist/assets/RN4M9u9W.js.gz +0 -0
  52. package/dashboard/dist/assets/VCHu272d.js +1 -0
  53. package/dashboard/dist/assets/VCHu272d.js.br +0 -0
  54. package/dashboard/dist/assets/VCHu272d.js.gz +0 -0
  55. package/dashboard/dist/assets/m2smti3F.js +1 -0
  56. package/dashboard/dist/assets/m2smti3F.js.br +0 -0
  57. package/dashboard/dist/assets/m2smti3F.js.gz +0 -0
  58. package/dashboard/dist/assets/{C3_j_W9V.js → nra1yvJX.js} +1 -1
  59. package/dashboard/dist/assets/nra1yvJX.js.br +0 -0
  60. package/dashboard/dist/assets/nra1yvJX.js.gz +0 -0
  61. package/dashboard/dist/assets/qLX6NZ-J.js +1 -0
  62. package/dashboard/dist/assets/qLX6NZ-J.js.br +0 -0
  63. package/dashboard/dist/assets/qLX6NZ-J.js.gz +0 -0
  64. package/dashboard/dist/index.html +2 -2
  65. package/dashboard/dist/index.html.br +0 -0
  66. package/dashboard/dist/index.html.gz +0 -0
  67. package/dist/agent-run-store.js +162 -24
  68. package/dist/cli/orgx.d.ts +3 -0
  69. package/dist/config/resolution.d.ts +7 -0
  70. package/dist/config/resolution.js +13 -5
  71. package/dist/contracts/onboarding-state.d.ts +2 -0
  72. package/dist/contracts/onboarding-state.js +23 -0
  73. package/dist/contracts/shared-types.d.ts +17 -0
  74. package/dist/http/helpers/auto-continue-engine.d.ts +62 -0
  75. package/dist/http/helpers/auto-continue-engine.js +329 -53
  76. package/dist/http/helpers/autopilot-runtime.js +5 -1
  77. package/dist/http/helpers/autopilot-slice-utils.js +25 -1
  78. package/dist/http/helpers/decision-mapper.d.ts +1 -0
  79. package/dist/http/helpers/decision-mapper.js +19 -2
  80. package/dist/http/helpers/dispatch-lifecycle.js +3 -0
  81. package/dist/http/helpers/mission-control.d.ts +1 -0
  82. package/dist/http/helpers/mission-control.js +5 -2
  83. package/dist/http/helpers/slice-run-projections.d.ts +27 -0
  84. package/dist/http/helpers/slice-run-projections.js +198 -10
  85. package/dist/http/helpers/triage-mapper.js +220 -6
  86. package/dist/http/index.d.ts +1 -0
  87. package/dist/http/index.js +94 -46
  88. package/dist/http/router.js +64 -9
  89. package/dist/http/routes/live-legacy.d.ts +19 -2
  90. package/dist/http/routes/live-legacy.js +110 -27
  91. package/dist/http/routes/live-snapshot.d.ts +16 -2
  92. package/dist/http/routes/live-snapshot.js +169 -25
  93. package/dist/http/routes/mission-control-actions.js +28 -0
  94. package/dist/http/routes/mission-control-read.d.ts +18 -0
  95. package/dist/http/routes/mission-control-read.js +130 -218
  96. package/dist/http/routes/onboarding.d.ts +1 -0
  97. package/dist/http/routes/onboarding.js +17 -0
  98. package/dist/index.d.ts +5 -0
  99. package/dist/index.js +199 -123
  100. package/dist/outbox.d.ts +0 -2
  101. package/dist/outbox.js +268 -150
  102. package/dist/reporting/rollups.js +18 -11
  103. package/dist/runtime-instance-store.js +212 -58
  104. package/dist/stores/materialized-snapshot-store.d.ts +18 -0
  105. package/dist/stores/materialized-snapshot-store.js +91 -0
  106. package/dist/stores/sqlite-state.d.ts +6 -0
  107. package/dist/stores/sqlite-state.js +179 -0
  108. package/package.json +6 -1
  109. package/dashboard/dist/assets/467jKHFJ.js.br +0 -0
  110. package/dashboard/dist/assets/467jKHFJ.js.gz +0 -0
  111. package/dashboard/dist/assets/5Ihga-4X.js.br +0 -0
  112. package/dashboard/dist/assets/5Ihga-4X.js.gz +0 -0
  113. package/dashboard/dist/assets/B71dt9yu.js.br +0 -0
  114. package/dashboard/dist/assets/B71dt9yu.js.gz +0 -0
  115. package/dashboard/dist/assets/BCudUvwg.js +0 -1
  116. package/dashboard/dist/assets/BCudUvwg.js.br +0 -0
  117. package/dashboard/dist/assets/BCudUvwg.js.gz +0 -0
  118. package/dashboard/dist/assets/BEnI6kNR.js +0 -1
  119. package/dashboard/dist/assets/BEnI6kNR.js.br +0 -0
  120. package/dashboard/dist/assets/BEnI6kNR.js.gz +0 -0
  121. package/dashboard/dist/assets/BcJmNILk.js.br +0 -0
  122. package/dashboard/dist/assets/BcJmNILk.js.gz +0 -0
  123. package/dashboard/dist/assets/C-MOJWHs.js +0 -1
  124. package/dashboard/dist/assets/C-MOJWHs.js.br +0 -0
  125. package/dashboard/dist/assets/C-MOJWHs.js.gz +0 -0
  126. package/dashboard/dist/assets/C-XuWXGi.js +0 -1
  127. package/dashboard/dist/assets/C-XuWXGi.js.br +0 -0
  128. package/dashboard/dist/assets/C-XuWXGi.js.gz +0 -0
  129. package/dashboard/dist/assets/C3_j_W9V.js.br +0 -0
  130. package/dashboard/dist/assets/C3_j_W9V.js.gz +0 -0
  131. package/dashboard/dist/assets/C9-UYhBb.js +0 -1
  132. package/dashboard/dist/assets/C9-UYhBb.js.br +0 -0
  133. package/dashboard/dist/assets/C9-UYhBb.js.gz +0 -0
  134. package/dashboard/dist/assets/C9yV06GS.js +0 -1
  135. package/dashboard/dist/assets/C9yV06GS.js.br +0 -0
  136. package/dashboard/dist/assets/C9yV06GS.js.gz +0 -0
  137. package/dashboard/dist/assets/CReugbyT.js +0 -1
  138. package/dashboard/dist/assets/CReugbyT.js.br +0 -0
  139. package/dashboard/dist/assets/CReugbyT.js.gz +0 -0
  140. package/dashboard/dist/assets/CSDhTbKy.js +0 -1
  141. package/dashboard/dist/assets/CSDhTbKy.js.br +0 -0
  142. package/dashboard/dist/assets/CSDhTbKy.js.gz +0 -0
  143. package/dashboard/dist/assets/CfMS9yIf.js +0 -1
  144. package/dashboard/dist/assets/CfMS9yIf.js.br +0 -0
  145. package/dashboard/dist/assets/CfMS9yIf.js.gz +0 -0
  146. package/dashboard/dist/assets/D2Kqcmv9.js +0 -212
  147. package/dashboard/dist/assets/D2Kqcmv9.js.br +0 -0
  148. package/dashboard/dist/assets/D2Kqcmv9.js.gz +0 -0
  149. package/dashboard/dist/assets/DS79hzMu.js.br +0 -0
  150. package/dashboard/dist/assets/DS79hzMu.js.gz +0 -0
  151. package/dashboard/dist/assets/PVi0vr9a.js.br +0 -0
  152. package/dashboard/dist/assets/PVi0vr9a.js.gz +0 -0
  153. package/dashboard/dist/assets/RZkbqlJk.css +0 -1
  154. package/dashboard/dist/assets/RZkbqlJk.css.br +0 -0
  155. package/dashboard/dist/assets/RZkbqlJk.css.gz +0 -0
  156. package/dashboard/dist/assets/a6qcPiWt.js.br +0 -0
  157. package/dashboard/dist/assets/a6qcPiWt.js.gz +0 -0
  158. package/dashboard/dist/assets/qDJ6rqcs.js.br +0 -0
  159. package/dashboard/dist/assets/qDJ6rqcs.js.gz +0 -0
  160. package/dashboard/dist/assets/sdoPH_Z1.js.br +0 -0
  161. package/dashboard/dist/assets/sdoPH_Z1.js.gz +0 -0
@@ -5,6 +5,136 @@
5
5
  * `LiveTriageItem` objects with proof bundles and recommended actions.
6
6
  */
7
7
  import { callLlmJson } from "./llm-client.js";
8
+ function asRecord(value) {
9
+ if (!value || typeof value !== "object" || Array.isArray(value))
10
+ return null;
11
+ return value;
12
+ }
13
+ function pickString(record, keys) {
14
+ if (!record)
15
+ return null;
16
+ for (const key of keys) {
17
+ const value = record[key];
18
+ if (typeof value !== "string")
19
+ continue;
20
+ const normalized = value.trim();
21
+ if (normalized.length > 0)
22
+ return normalized;
23
+ }
24
+ return null;
25
+ }
26
+ function pickStringArray(record, keys) {
27
+ if (!record)
28
+ return [];
29
+ const values = [];
30
+ for (const key of keys) {
31
+ const candidate = record[key];
32
+ if (!Array.isArray(candidate))
33
+ continue;
34
+ for (const entry of candidate) {
35
+ if (typeof entry !== "string")
36
+ continue;
37
+ const normalized = entry.trim();
38
+ if (normalized.length > 0)
39
+ values.push(normalized);
40
+ }
41
+ if (values.length > 0)
42
+ break;
43
+ }
44
+ return values;
45
+ }
46
+ function countArray(record, keys) {
47
+ if (!record)
48
+ return 0;
49
+ for (const key of keys) {
50
+ const candidate = record[key];
51
+ if (Array.isArray(candidate))
52
+ return candidate.length;
53
+ }
54
+ return 0;
55
+ }
56
+ function deriveInterventionContext(input) {
57
+ const metadata = asRecord(input.metadata);
58
+ const result = asRecord(metadata?.result);
59
+ const blocker = asRecord(metadata?.blocker) ?? asRecord(result?.blocker);
60
+ const blockerReason = pickString(blocker, ["description", "summary"]) ??
61
+ pickString(result, ["blocked_reason", "blockedReason", "error"]) ??
62
+ pickString(metadata, ["blocked_reason", "blockedReason", "error", "reason"]) ??
63
+ (typeof input.reason === "string" && input.reason.trim().length > 0 ? input.reason.trim() : null);
64
+ const waitingOn = pickString(blocker, ["waiting_on", "required_actor", "requiredActor"]) ??
65
+ pickString(result, ["waiting_on", "required_actor", "requiredActor"]) ??
66
+ pickString(metadata, ["waiting_on", "required_actor", "requiredActor"]);
67
+ const nextActions = [
68
+ ...pickStringArray(result, ["next_actions", "nextActions"]),
69
+ ...pickStringArray(metadata, ["next_actions", "nextActions"]),
70
+ ];
71
+ const requiredAction = pickString(blocker, ["required_action", "requiredAction"]) ??
72
+ pickString(result, ["required_action", "requiredAction"]) ??
73
+ pickString(metadata, ["required_action", "requiredAction"]) ??
74
+ (nextActions[0] ?? null);
75
+ const requiredActor = pickString(blocker, ["required_actor", "requiredActor"]) ??
76
+ pickString(result, ["required_actor", "requiredActor"]) ??
77
+ pickString(metadata, ["required_actor", "requiredActor"]);
78
+ const suggestedActions = [
79
+ ...pickStringArray(blocker, ["suggested_actions", "suggestedActions"]),
80
+ ...pickStringArray(result, ["suggested_actions", "suggestedActions"]),
81
+ ...pickStringArray(metadata, ["suggested_actions", "suggestedActions"]),
82
+ ];
83
+ const decisionIds = [
84
+ ...pickStringArray(result, ["decision_ids", "decisionIds"]),
85
+ ...pickStringArray(metadata, ["decision_ids", "decisionIds"]),
86
+ ];
87
+ const retryable = typeof blocker?.retryable === "boolean"
88
+ ? blocker.retryable
89
+ : typeof result?.retryable === "boolean"
90
+ ? result.retryable
91
+ : typeof metadata?.retryable === "boolean"
92
+ ? metadata.retryable
93
+ : null;
94
+ const errorCode = pickString(blocker, ["error_code", "errorCode"]) ??
95
+ pickString(result, ["error_code", "errorCode"]) ??
96
+ pickString(metadata, ["error_code", "errorCode"]);
97
+ const errorCategory = pickString(blocker, ["error_category", "errorCategory"]) ??
98
+ pickString(result, ["error_category", "errorCategory"]) ??
99
+ pickString(metadata, ["error_category", "errorCategory"]);
100
+ const taskUpdateCount = countArray(result, ["task_updates", "taskUpdates"]) ||
101
+ countArray(metadata, ["task_updates", "taskUpdates"]);
102
+ const milestoneUpdateCount = countArray(result, ["milestone_updates", "milestoneUpdates"]) ||
103
+ countArray(metadata, ["milestone_updates", "milestoneUpdates"]);
104
+ const context = {
105
+ blockerReason,
106
+ waitingOn,
107
+ requiredAction,
108
+ requiredActor,
109
+ retryable,
110
+ errorCode,
111
+ errorCategory,
112
+ suggestedActions: suggestedActions.length > 0 ? Array.from(new Set(suggestedActions)) : [],
113
+ nextActions: nextActions.length > 0 ? Array.from(new Set(nextActions)) : [],
114
+ decisionIds: decisionIds.length > 0 ? Array.from(new Set(decisionIds)) : [],
115
+ taskUpdateCount: taskUpdateCount > 0 ? taskUpdateCount : undefined,
116
+ milestoneUpdateCount: milestoneUpdateCount > 0 ? milestoneUpdateCount : undefined,
117
+ };
118
+ const hasValue = [
119
+ context.blockerReason,
120
+ context.waitingOn,
121
+ context.requiredAction,
122
+ context.requiredActor,
123
+ context.errorCode,
124
+ context.errorCategory,
125
+ context.retryable,
126
+ context.taskUpdateCount,
127
+ context.milestoneUpdateCount,
128
+ context.suggestedActions?.length,
129
+ context.nextActions?.length,
130
+ context.decisionIds?.length,
131
+ ].some((entry) => {
132
+ if (typeof entry === "number")
133
+ return entry > 0;
134
+ return entry != null && String(entry).trim().length > 0;
135
+ });
136
+ return hasValue ? context : null;
137
+ }
8
138
  const FAILURE_MAPPINGS = {
9
139
  credential_missing: {
10
140
  kind: "blocked_intervention",
@@ -288,12 +418,16 @@ export async function mapFailureToTriageItem(input) {
288
418
  metadata: input.metadata,
289
419
  };
290
420
  const now = input.timestamp ?? new Date().toISOString();
421
+ const intervention = deriveInterventionContext({
422
+ reason: input.reason ?? null,
423
+ metadata: input.metadata,
424
+ });
291
425
  const proofBundle = {
292
426
  artifactRefs: [],
293
427
  fileChanges: [],
294
428
  prRefs: [],
295
429
  logRefs: input.logPath ? [input.logPath] : [],
296
- decisionRefs: [],
430
+ decisionRefs: intervention?.decisionIds ?? [],
297
431
  };
298
432
  if (input.outputPath) {
299
433
  proofBundle.artifactRefs.push(input.outputPath);
@@ -380,6 +514,25 @@ export async function mapFailureToTriageItem(input) {
380
514
  },
381
515
  ];
382
516
  }
517
+ const summaryDetails = [];
518
+ if (intervention?.waitingOn)
519
+ summaryDetails.push(`Waiting on ${intervention.waitingOn}.`);
520
+ if (intervention?.requiredAction)
521
+ summaryDetails.push(`Required action: ${intervention.requiredAction}.`);
522
+ if (intervention?.errorCode)
523
+ summaryDetails.push(`Error code: ${intervention.errorCode}.`);
524
+ if (intervention?.taskUpdateCount && intervention.taskUpdateCount > 0) {
525
+ summaryDetails.push(`${intervention.taskUpdateCount} task update${intervention.taskUpdateCount === 1 ? "" : "s"} pending apply.`);
526
+ }
527
+ if (intervention?.milestoneUpdateCount && intervention.milestoneUpdateCount > 0) {
528
+ summaryDetails.push(`${intervention.milestoneUpdateCount} milestone update${intervention.milestoneUpdateCount === 1 ? "" : "s"} pending apply.`);
529
+ }
530
+ if (summaryDetails.length > 0) {
531
+ summary = `${summary} ${summaryDetails.join(" ")}`.trim();
532
+ }
533
+ if (intervention?.requiredAction) {
534
+ recommendedAction = intervention.requiredAction;
535
+ }
383
536
  return {
384
537
  id: input.id,
385
538
  kind,
@@ -407,6 +560,7 @@ export async function mapFailureToTriageItem(input) {
407
560
  blocking: kind === "blocked_intervention" || kind === "decision_required",
408
561
  recommendedAction,
409
562
  agentId: input.agentId ?? null,
563
+ intervention,
410
564
  impact,
411
565
  proofBundle,
412
566
  actionContract,
@@ -426,7 +580,38 @@ export function mapDecisionToTriageItem(decision) {
426
580
  const now = new Date().toISOString();
427
581
  const decisionType = decision.decisionType ?? "decision_required";
428
582
  const mapping = FAILURE_MAPPINGS[decisionType];
429
- const actions = [
583
+ const metadata = decision.metadata && typeof decision.metadata === "object" && !Array.isArray(decision.metadata)
584
+ ? decision.metadata
585
+ : null;
586
+ const intervention = deriveInterventionContext({
587
+ reason: decision.context ?? null,
588
+ metadata: metadata ?? undefined,
589
+ });
590
+ const blocking = metadata?.blocking !== false;
591
+ const options = Array.isArray(decision.options) ? decision.options : [];
592
+ const optionActions = options
593
+ .map((option) => {
594
+ const implied = (option.impliedStatus ?? "").toLowerCase();
595
+ const action = implied === "declined" || implied === "cancelled" ? "reject" : "approve";
596
+ const optionConsequences = typeof option.consequences === "string" && option.consequences.trim().length > 0
597
+ ? option.consequences.trim()
598
+ : null;
599
+ const consequences = optionConsequences ??
600
+ (action === "approve"
601
+ ? "Will continue execution using this option."
602
+ : "Will decline this direction and keep the run blocked.");
603
+ return {
604
+ action,
605
+ label: option.label,
606
+ description: option.description ?? (action === "approve" ? "Approve this option" : "Reject with this rationale"),
607
+ consequences,
608
+ requiresNote: option.requiresNote === true,
609
+ available: true,
610
+ optionId: option.id,
611
+ };
612
+ })
613
+ .slice(0, 4);
614
+ const fallbackActions = [
430
615
  {
431
616
  action: "approve",
432
617
  label: "Approve",
@@ -434,6 +619,7 @@ export function mapDecisionToTriageItem(decision) {
434
619
  consequences: "Will proceed with the recommended action.",
435
620
  requiresNote: false,
436
621
  available: true,
622
+ optionId: null,
437
623
  },
438
624
  {
439
625
  action: "reject",
@@ -442,7 +628,20 @@ export function mapDecisionToTriageItem(decision) {
442
628
  consequences: "Agent will pause and await new instructions.",
443
629
  requiresNote: true,
444
630
  available: true,
631
+ optionId: null,
445
632
  },
633
+ ];
634
+ const optionActionsWithCoverage = [...optionActions];
635
+ if (optionActionsWithCoverage.length > 0) {
636
+ if (!optionActionsWithCoverage.some((action) => action.action === "approve")) {
637
+ optionActionsWithCoverage.unshift(fallbackActions[0]);
638
+ }
639
+ if (!optionActionsWithCoverage.some((action) => action.action === "reject")) {
640
+ optionActionsWithCoverage.push(fallbackActions[1]);
641
+ }
642
+ }
643
+ const actions = [
644
+ ...(optionActionsWithCoverage.length > 0 ? optionActionsWithCoverage.slice(0, 4) : fallbackActions),
446
645
  {
447
646
  action: "snooze",
448
647
  label: "Snooze",
@@ -450,6 +649,7 @@ export function mapDecisionToTriageItem(decision) {
450
649
  consequences: "Item reappears after snooze period.",
451
650
  requiresNote: false,
452
651
  available: true,
652
+ optionId: null,
453
653
  },
454
654
  ];
455
655
  const proofBundle = {
@@ -457,20 +657,33 @@ export function mapDecisionToTriageItem(decision) {
457
657
  fileChanges: [],
458
658
  prRefs: [],
459
659
  logRefs: [],
460
- decisionRefs: [decision.id],
660
+ decisionRefs: Array.from(new Set([decision.id, ...(intervention?.decisionIds ?? [])].filter(Boolean))),
461
661
  };
462
662
  if (decision.evidenceRefs) {
463
663
  for (const ref of decision.evidenceRefs) {
464
664
  if (ref.sourceUrl)
465
665
  proofBundle.artifactRefs.push(ref.sourceUrl);
666
+ if (ref.sourcePointer)
667
+ proofBundle.logRefs.push(ref.sourcePointer);
466
668
  }
467
669
  }
670
+ const summaryBase = (typeof decision.context === "string" && decision.context.trim()) ||
671
+ intervention?.blockerReason ||
672
+ decision.title;
673
+ const summarySuffix = [
674
+ intervention?.waitingOn ? `Waiting on ${intervention.waitingOn}.` : null,
675
+ intervention?.requiredAction ? `Required action: ${intervention.requiredAction}.` : null,
676
+ ]
677
+ .filter((entry) => Boolean(entry))
678
+ .join(" ");
679
+ const summary = summarySuffix.length > 0 ? `${summaryBase} ${summarySuffix}` : summaryBase;
680
+ const recommendedAction = decision.recommendedAction ?? intervention?.requiredAction ?? null;
468
681
  return {
469
682
  id: `triage-decision-${decision.id}`,
470
683
  kind: mapping?.kind ?? "decision_required",
471
684
  status: decision.status === "pending" ? "open" : decision.status === "resolved" ? "resolved" : "open",
472
685
  title: decision.title,
473
- summary: decision.context ?? decision.title,
686
+ summary,
474
687
  initiativeId: decision.initiativeId ?? null,
475
688
  initiativeTitle: null,
476
689
  workstreamId: decision.workstreamId ?? null,
@@ -482,9 +695,10 @@ export function mapDecisionToTriageItem(decision) {
482
695
  dedupeKey: decision.dedupeKey ?? null,
483
696
  occurrenceCount: decision.occurrenceCount ?? 1,
484
697
  severity: decision.priority === "urgent" ? "critical" : decision.priority === "high" ? "high" : "medium",
485
- blocking: true,
486
- recommendedAction: decision.recommendedAction ?? null,
698
+ blocking,
699
+ recommendedAction,
487
700
  agentId: decision.agentId ?? null,
701
+ intervention,
488
702
  impact: {
489
703
  initiativeCount: decision.initiativeId ? 1 : 0,
490
704
  workstreamCount: decision.workstreamId ? 1 : 0,
@@ -70,6 +70,7 @@ interface OnboardingController {
70
70
  apiKey: string;
71
71
  userId?: string;
72
72
  }) => Promise<OnboardingState>;
73
+ cancelPairing?: () => Promise<OnboardingState>;
73
74
  disconnect: () => Promise<OnboardingState>;
74
75
  }
75
76
  interface DiagnosticsProvider {
@@ -41,6 +41,7 @@ import { listRuntimeInstances, resolveRuntimeHookToken, upsertRuntimeInstanceFro
41
41
  import { parseJsonSafe } from "../json-utils.js";
42
42
  import { readSkillPackState, refreshSkillPackState, rollbackSkillPackPolicy, updateSkillPackPolicy, } from "../skill-pack-state.js";
43
43
  import { posthogCapture } from "../telemetry/posthog.js";
44
+ import { clearMaterializedSnapshotMemory, readMaterializedSnapshot, writeMaterializedSnapshot, } from "../stores/materialized-snapshot-store.js";
44
45
  import { createRouter } from "./router.js";
45
46
  import { summarizeActivityHeadline } from "./helpers/activity-headline.js";
46
47
  import { createAutoContinueEngine, } from "./helpers/auto-continue-engine.js";
@@ -271,7 +272,6 @@ async function mapWithConcurrency(items, concurrency, mapper) {
271
272
  const ACTIVITY_WARM_THROTTLE_MS = 30_000;
272
273
  const activityWarmByKey = new Map();
273
274
  const SNAPSHOT_RESPONSE_CACHE_TTL_MS = 800;
274
- const SNAPSHOT_RESPONSE_CACHE_MAX_ENTRIES = 16;
275
275
  const SNAPSHOT_ACTIVITY_PERSIST_MIN_INTERVAL_MS = 15_000;
276
276
  const SNAPSHOT_ACTIVITY_FINGERPRINT_DEPTH = 8;
277
277
  const NEXT_UP_QUEUE_CACHE_TTL_MS = readPositiveIntEnv("ORGX_NEXT_UP_QUEUE_CACHE_TTL_MS", 30_000, { min: 250, max: 120_000 });
@@ -292,7 +292,6 @@ const LIVE_WORKSPACE_INITIATIVE_STATUSES = [
292
292
  let lastSnapshotActivityPersistAt = 0;
293
293
  let lastSnapshotActivityFingerprint = "";
294
294
  let snapshotCacheGeneration = 0;
295
- const snapshotResponseCache = new Map();
296
295
  const ACTIVITY_DECISION_EVENT_HINTS = new Set([
297
296
  "decision_buffered",
298
297
  "auto_continue_spawn_guard_blocked",
@@ -435,39 +434,24 @@ function snapshotActivityFingerprint(items) {
435
434
  .join(";");
436
435
  return `${items.length}:${sample}`;
437
436
  }
438
- function readSnapshotResponseCache(key) {
439
- const entry = snapshotResponseCache.get(key);
440
- if (!entry)
441
- return null;
442
- if (entry.generation !== snapshotCacheGeneration || entry.expiresAt <= Date.now()) {
443
- snapshotResponseCache.delete(key);
444
- return null;
445
- }
446
- return entry.payload;
437
+ function getSnapshotCacheGeneration() {
438
+ return snapshotCacheGeneration;
439
+ }
440
+ function readSnapshotResponseCache(key, options) {
441
+ return readMaterializedSnapshot(key, {
442
+ allowStale: options?.allowStale,
443
+ generation: snapshotCacheGeneration,
444
+ });
447
445
  }
448
446
  function writeSnapshotResponseCache(key, payload) {
449
- const now = Date.now();
450
- snapshotResponseCache.set(key, {
451
- expiresAt: now + SNAPSHOT_RESPONSE_CACHE_TTL_MS,
447
+ writeMaterializedSnapshot(key, payload, {
452
448
  generation: snapshotCacheGeneration,
453
- payload,
449
+ ttlMs: SNAPSHOT_RESPONSE_CACHE_TTL_MS,
454
450
  });
455
- if (snapshotResponseCache.size <= SNAPSHOT_RESPONSE_CACHE_MAX_ENTRIES)
456
- return;
457
- for (const [cachedKey, entry] of snapshotResponseCache.entries()) {
458
- if (entry.expiresAt <= now)
459
- snapshotResponseCache.delete(cachedKey);
460
- }
461
- while (snapshotResponseCache.size > SNAPSHOT_RESPONSE_CACHE_MAX_ENTRIES) {
462
- const oldestKey = snapshotResponseCache.keys().next().value;
463
- if (!oldestKey)
464
- break;
465
- snapshotResponseCache.delete(oldestKey);
466
- }
467
451
  }
468
452
  function clearSnapshotResponseCache() {
469
453
  snapshotCacheGeneration += 1;
470
- snapshotResponseCache.clear();
454
+ clearMaterializedSnapshotMemory();
471
455
  }
472
456
  function isUserScopedApiKey(apiKey) {
473
457
  return apiKey.trim().toLowerCase().startsWith("oxk_");
@@ -1751,9 +1735,36 @@ async function parseJsonRequest(req) {
1751
1735
  }
1752
1736
  return parseJsonBody(streamed);
1753
1737
  }
1754
- // =============================================================================
1755
- // Factory
1756
- // =============================================================================
1738
+ let activeHttpRuntimeLifecycle = null;
1739
+ function createHttpRuntimeLifecycle(input) {
1740
+ let nextUpPrewarmTimer = null;
1741
+ let autoContinueTimer = null;
1742
+ const stop = () => {
1743
+ if (nextUpPrewarmTimer) {
1744
+ clearTimeout(nextUpPrewarmTimer);
1745
+ nextUpPrewarmTimer = null;
1746
+ }
1747
+ if (autoContinueTimer) {
1748
+ clearInterval(autoContinueTimer);
1749
+ autoContinueTimer = null;
1750
+ }
1751
+ };
1752
+ return {
1753
+ start() {
1754
+ stop();
1755
+ nextUpPrewarmTimer = setTimeout(() => {
1756
+ nextUpPrewarmTimer = null;
1757
+ input.prewarmNextUpQueue();
1758
+ }, 75);
1759
+ nextUpPrewarmTimer.unref?.();
1760
+ autoContinueTimer = setInterval(() => {
1761
+ void input.tickAllAutoContinue();
1762
+ }, input.autoContinueTickMs);
1763
+ autoContinueTimer.unref?.();
1764
+ },
1765
+ stop,
1766
+ };
1767
+ }
1757
1768
  export function createHttpHandler(config, client, getSnapshot, onboarding, diagnostics, adapters) {
1758
1769
  const dashboardEnabled = config.dashboardEnabled ??
1759
1770
  true;
@@ -1846,7 +1857,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
1846
1857
  };
1847
1858
  const codexBinResolver = createCodexBinResolver();
1848
1859
  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({
1860
+ 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
1861
  client,
1851
1862
  filename: __filename,
1852
1863
  safeErrorMessage,
@@ -2962,12 +2973,14 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
2962
2973
  // best effort prewarm only
2963
2974
  });
2964
2975
  };
2965
- const nextUpPrewarmTimer = setTimeout(prewarmNextUpQueue, 75);
2966
- nextUpPrewarmTimer.unref?.();
2967
- const autoContinueTimer = setInterval(() => {
2968
- void tickAllAutoContinue();
2969
- }, AUTO_CONTINUE_TICK_MS);
2970
- autoContinueTimer.unref?.();
2976
+ activeHttpRuntimeLifecycle?.stop();
2977
+ const runtimeLifecycle = createHttpRuntimeLifecycle({
2978
+ prewarmNextUpQueue,
2979
+ tickAllAutoContinue,
2980
+ autoContinueTickMs: AUTO_CONTINUE_TICK_MS,
2981
+ });
2982
+ runtimeLifecycle.start();
2983
+ activeHttpRuntimeLifecycle = runtimeLifecycle;
2971
2984
  const apiRouter = createRouter();
2972
2985
  registerOnboardingRoutes(apiRouter, {
2973
2986
  onboarding,
@@ -3042,6 +3055,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3042
3055
  });
3043
3056
  registerMissionControlReadRoutes(apiRouter, {
3044
3057
  autoContinueRuns,
3058
+ restoreAutoContinueRun,
3045
3059
  defaultAutoContinueTokenBudget,
3046
3060
  defaultAutoContinueMaxParallelSlices,
3047
3061
  autoContinueTickMs: AUTO_CONTINUE_TICK_MS,
@@ -3510,6 +3524,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3510
3524
  outboxReadAllItems: () => outboxAdapter.readAllItems(),
3511
3525
  toLocalLiveActivity,
3512
3526
  loadLocalTurnDetail,
3527
+ summarizeActivityHeadline,
3513
3528
  sendJson,
3514
3529
  safeErrorMessage,
3515
3530
  sendHtml,
@@ -3538,6 +3553,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3538
3553
  parsePositiveInt,
3539
3554
  readSnapshotResponseCache,
3540
3555
  writeSnapshotResponseCache,
3556
+ getSnapshotCacheGeneration,
3541
3557
  safeErrorMessage,
3542
3558
  readAgentContexts,
3543
3559
  getScopedAgentIds,
@@ -3595,6 +3611,8 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3595
3611
  listChatThreads: ({ commandCenterId, initiativeId, limit, offset }) => listChatThreads({ commandCenterId, initiativeId, limit, offset }),
3596
3612
  getCanonicalAutopilotState,
3597
3613
  sendJson,
3614
+ securityHeaders: SECURITY_HEADERS,
3615
+ corsHeaders: CORS_HEADERS,
3598
3616
  });
3599
3617
  registerRuntimeHookRoutes(apiRouter, {
3600
3618
  parseJsonRequest,
@@ -3678,10 +3696,11 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3678
3696
  const keys = [...scopedKeys, ...fallbackKeys];
3679
3697
  const seen = new Set();
3680
3698
  const mapped = [];
3681
- const deriveFailureType = (eventNameRaw, actionTypeRaw) => {
3699
+ const deriveFailureType = (eventNameRaw, actionTypeRaw, reasonRaw) => {
3682
3700
  const eventName = (eventNameRaw ?? "").trim().toLowerCase();
3683
3701
  const actionType = (actionTypeRaw ?? "").trim().toLowerCase();
3684
- const signature = `${eventName} ${actionType}`;
3702
+ const reason = (reasonRaw ?? "").trim().toLowerCase();
3703
+ const signature = `${eventName} ${actionType} ${reason}`;
3685
3704
  if (!signature.trim())
3686
3705
  return null;
3687
3706
  if (signature.includes("status_updates_buffered"))
@@ -3706,6 +3725,18 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3706
3725
  return "budget_exhausted";
3707
3726
  if (signature.includes("stale_blocked_workstream"))
3708
3727
  return "stale_blocked_workstream";
3728
+ if (signature.includes("credit") ||
3729
+ signature.includes("insufficient_quota") ||
3730
+ signature.includes("insufficient credit") ||
3731
+ signature.includes("payment required")) {
3732
+ return "budget_exhausted";
3733
+ }
3734
+ if (signature.includes("run_failed") ||
3735
+ signature.includes("autopilot_slice_result") ||
3736
+ signature.includes("autopilot_slice_finished") ||
3737
+ signature.includes("failed")) {
3738
+ return "worker_exit_no_output";
3739
+ }
3709
3740
  return null;
3710
3741
  };
3711
3742
  try {
@@ -3723,7 +3754,20 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3723
3754
  const metadataRecord = activityRecord.metadata && typeof activityRecord.metadata === "object"
3724
3755
  ? activityRecord.metadata
3725
3756
  : {};
3726
- const failureType = deriveFailureType(pickString(metadataRecord, ["event", "event_name"]), pickString(metadataRecord, ["action_type", "actionType"]));
3757
+ const resultRecord = metadataRecord.result && typeof metadataRecord.result === "object"
3758
+ ? metadataRecord.result
3759
+ : null;
3760
+ const blockerRecord = metadataRecord.blocker && typeof metadataRecord.blocker === "object"
3761
+ ? metadataRecord.blocker
3762
+ : resultRecord && resultRecord.blocker && typeof resultRecord.blocker === "object"
3763
+ ? resultRecord.blocker
3764
+ : null;
3765
+ const reasonText = pickString(blockerRecord ?? {}, ["description", "summary"]) ??
3766
+ pickString(resultRecord ?? {}, ["error", "reason", "blocked_reason", "blockedReason", "summary"]) ??
3767
+ pickString(metadataRecord, ["error", "reason", "message", "blocked_reason", "blockedReason"]) ??
3768
+ pickString(activityRecord, ["description", "summary", "title"]);
3769
+ const failureType = deriveFailureType(pickString(metadataRecord, ["event", "event_name"]), pickString(metadataRecord, ["action_type", "actionType"]) ??
3770
+ pickString(activityRecord, ["type"]), reasonText);
3727
3771
  if (!failureType)
3728
3772
  continue;
3729
3773
  const runId = pickString(metadataRecord, ["run_id", "source_run_id"]) ?? pickString(activityRecord, ["runId"]);
@@ -3742,9 +3786,9 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3742
3786
  mapped.push({
3743
3787
  id: dedupeId,
3744
3788
  failureType,
3745
- reason: pickString(metadataRecord, ["error", "reason", "message"]) ??
3746
- pickString(activityRecord, ["description", "summary", "title"]),
3747
- provider: pickString(metadataRecord, ["provider"]),
3789
+ reason: reasonText,
3790
+ provider: pickString(metadataRecord, ["provider"]) ??
3791
+ pickString(blockerRecord ?? {}, ["provider"]),
3748
3792
  initiativeId,
3749
3793
  initiativeTitle: pickString(metadataRecord, ["initiative_title"]) ??
3750
3794
  pickString(activityRecord, ["initiativeTitle"]),
@@ -3758,8 +3802,12 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3758
3802
  domain: pickString(metadataRecord, ["domain", "executor_domain"]),
3759
3803
  sourceSystem: pickString(metadataRecord, ["source_system", "source"]) ?? "openclaw",
3760
3804
  runId,
3761
- logPath: pickString(metadataRecord, ["log_path"]),
3762
- outputPath: pickString(metadataRecord, ["output_path"]),
3805
+ logPath: pickString(metadataRecord, ["log_path"]) ??
3806
+ pickString(resultRecord ?? {}, ["log_path"]) ??
3807
+ pickString(blockerRecord ?? {}, ["log_path"]),
3808
+ outputPath: pickString(metadataRecord, ["output_path"]) ??
3809
+ pickString(resultRecord ?? {}, ["output_path"]) ??
3810
+ pickString(blockerRecord ?? {}, ["output_path"]),
3763
3811
  metadata: metadataRecord,
3764
3812
  timestamp: timestamp ?? undefined,
3765
3813
  });
@@ -1,20 +1,75 @@
1
- function isPatternMatch(pattern, path) {
2
- if (pattern.endsWith("/*")) {
3
- return path.startsWith(pattern.slice(0, -1));
1
+ function normalizePrefixBase(pattern) {
2
+ return pattern.endsWith("/*") ? pattern.slice(0, -1) : null;
3
+ }
4
+ function getOrCreateBucket(map, key) {
5
+ const existing = map.get(key);
6
+ if (existing)
7
+ return existing;
8
+ const created = [];
9
+ map.set(key, created);
10
+ return created;
11
+ }
12
+ function getOrCreateMethodBuckets(map, method) {
13
+ const existing = map.get(method);
14
+ if (existing)
15
+ return existing;
16
+ const created = new Map();
17
+ map.set(method, created);
18
+ return created;
19
+ }
20
+ function collectPathPrefixBases(path) {
21
+ const bases = new Set();
22
+ let slashIndex = path.indexOf("/");
23
+ while (slashIndex !== -1) {
24
+ bases.add(path.slice(0, slashIndex + 1));
25
+ slashIndex = path.indexOf("/", slashIndex + 1);
4
26
  }
5
- return pattern === path;
27
+ bases.add(`${path}/`);
28
+ return Array.from(bases);
6
29
  }
7
30
  export function createRouter() {
8
31
  const entries = [];
32
+ const exactRoutes = new Map();
33
+ const prefixRoutes = new Map();
9
34
  function add(method, pattern, handler, description) {
10
- entries.push({ method, pattern, handler, description });
35
+ const route = {
36
+ method,
37
+ pattern,
38
+ handler,
39
+ description,
40
+ order: entries.length,
41
+ prefixBase: normalizePrefixBase(pattern),
42
+ };
43
+ entries.push(route);
44
+ if (route.prefixBase) {
45
+ getOrCreateBucket(getOrCreateMethodBuckets(prefixRoutes, method), route.prefixBase).push(route);
46
+ return;
47
+ }
48
+ getOrCreateBucket(getOrCreateMethodBuckets(exactRoutes, method), pattern).push(route);
49
+ }
50
+ function pickEarlierRoute(current, candidate) {
51
+ if (!current)
52
+ return candidate;
53
+ return candidate.order < current.order ? candidate : current;
54
+ }
55
+ function matchFromBuckets(routeBuckets, method, key, current) {
56
+ const methodBuckets = routeBuckets.get(method);
57
+ const wildcardBuckets = routeBuckets.get("*");
58
+ for (const candidate of methodBuckets?.get(key) ?? []) {
59
+ current = pickEarlierRoute(current, candidate);
60
+ }
61
+ for (const candidate of wildcardBuckets?.get(key) ?? []) {
62
+ current = pickEarlierRoute(current, candidate);
63
+ }
64
+ return current;
11
65
  }
12
66
  function match(method, path) {
13
67
  const normalizedMethod = method.toUpperCase();
14
- return entries.find((route) => {
15
- const methodMatches = route.method === "*" || route.method === normalizedMethod;
16
- return methodMatches && isPatternMatch(route.pattern, path);
17
- });
68
+ let matched = matchFromBuckets(exactRoutes, normalizedMethod, path, undefined);
69
+ for (const base of collectPathPrefixBases(path)) {
70
+ matched = matchFromBuckets(prefixRoutes, normalizedMethod, base, matched);
71
+ }
72
+ return matched;
18
73
  }
19
74
  function routes() {
20
75
  return entries;