@useorgx/openclaw-plugin 0.7.20 → 0.7.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/dashboard/dist/assets/B6VftyY6.js +1 -0
  2. package/dashboard/dist/assets/B6VftyY6.js.br +0 -0
  3. package/dashboard/dist/assets/B6VftyY6.js.gz +0 -0
  4. package/dashboard/dist/assets/{Dm0CfDGr.js → BANQdlC4.js} +1 -1
  5. package/dashboard/dist/assets/BANQdlC4.js.br +0 -0
  6. package/dashboard/dist/assets/BANQdlC4.js.gz +0 -0
  7. package/dashboard/dist/assets/{_zpQCpjm.js → BPL4CL3c.js} +1 -1
  8. package/dashboard/dist/assets/BPL4CL3c.js.br +0 -0
  9. package/dashboard/dist/assets/BPL4CL3c.js.gz +0 -0
  10. package/dashboard/dist/assets/{DXVs61e1.js → BZCkOZ20.js} +1 -1
  11. package/dashboard/dist/assets/BZCkOZ20.js.br +0 -0
  12. package/dashboard/dist/assets/BZCkOZ20.js.gz +0 -0
  13. package/dashboard/dist/assets/{BYb6DARX.js → B_LdOJUa.js} +1 -1
  14. package/dashboard/dist/assets/B_LdOJUa.js.br +0 -0
  15. package/dashboard/dist/assets/B_LdOJUa.js.gz +0 -0
  16. package/dashboard/dist/assets/Bfp-wdwb.css +1 -0
  17. package/dashboard/dist/assets/Bfp-wdwb.css.br +0 -0
  18. package/dashboard/dist/assets/Bfp-wdwb.css.gz +0 -0
  19. package/dashboard/dist/assets/{DibzNd0I.js → BvFcH_Iy.js} +1 -1
  20. package/dashboard/dist/assets/BvFcH_Iy.js.br +0 -0
  21. package/dashboard/dist/assets/BvFcH_Iy.js.gz +0 -0
  22. package/dashboard/dist/assets/By0MIBj_.js +1 -0
  23. package/dashboard/dist/assets/By0MIBj_.js.br +0 -0
  24. package/dashboard/dist/assets/By0MIBj_.js.gz +0 -0
  25. package/dashboard/dist/assets/C0i7ABUU.js +212 -0
  26. package/dashboard/dist/assets/C0i7ABUU.js.br +0 -0
  27. package/dashboard/dist/assets/C0i7ABUU.js.gz +0 -0
  28. package/dashboard/dist/assets/CFB0MM7j.js +1 -0
  29. package/dashboard/dist/assets/CFB0MM7j.js.br +0 -0
  30. package/dashboard/dist/assets/CFB0MM7j.js.gz +0 -0
  31. package/dashboard/dist/assets/CQSRb1yu.js +1 -0
  32. package/dashboard/dist/assets/CQSRb1yu.js.br +0 -0
  33. package/dashboard/dist/assets/CQSRb1yu.js.gz +0 -0
  34. package/dashboard/dist/assets/{wa4jJQK9.js → CUoQoSm-.js} +1 -1
  35. package/dashboard/dist/assets/CUoQoSm-.js.br +0 -0
  36. package/dashboard/dist/assets/CUoQoSm-.js.gz +0 -0
  37. package/dashboard/dist/assets/Ckd1R1iE.js +1 -0
  38. package/dashboard/dist/assets/Ckd1R1iE.js.br +0 -0
  39. package/dashboard/dist/assets/Ckd1R1iE.js.gz +0 -0
  40. package/dashboard/dist/assets/{BGY6oI8h.js → CqRNb2EL.js} +1 -1
  41. package/dashboard/dist/assets/CqRNb2EL.js.br +0 -0
  42. package/dashboard/dist/assets/CqRNb2EL.js.gz +0 -0
  43. package/dashboard/dist/assets/{DAr4MfFk.js → DClUc9rw.js} +1 -1
  44. package/dashboard/dist/assets/DClUc9rw.js.br +0 -0
  45. package/dashboard/dist/assets/DClUc9rw.js.gz +0 -0
  46. package/dashboard/dist/assets/DF2PMTwT.js +1 -0
  47. package/dashboard/dist/assets/DF2PMTwT.js.br +0 -0
  48. package/dashboard/dist/assets/DF2PMTwT.js.gz +0 -0
  49. package/dashboard/dist/assets/{B014hrCe.js → DJYl7gyA.js} +2 -2
  50. package/dashboard/dist/assets/DJYl7gyA.js.br +0 -0
  51. package/dashboard/dist/assets/DJYl7gyA.js.gz +0 -0
  52. package/dashboard/dist/assets/{BoDhb8_y.js → DZtNMX0t.js} +2 -2
  53. package/dashboard/dist/assets/DZtNMX0t.js.br +0 -0
  54. package/dashboard/dist/assets/DZtNMX0t.js.gz +0 -0
  55. package/dashboard/dist/assets/DlEa8PI0.js +1 -0
  56. package/dashboard/dist/assets/DlEa8PI0.js.br +0 -0
  57. package/dashboard/dist/assets/DlEa8PI0.js.gz +0 -0
  58. package/dashboard/dist/assets/M4QxcXjh.js +1 -0
  59. package/dashboard/dist/assets/M4QxcXjh.js.br +0 -0
  60. package/dashboard/dist/assets/M4QxcXjh.js.gz +0 -0
  61. package/dashboard/dist/assets/{CV0sWMbv.js → MrW1ixGx.js} +1 -1
  62. package/dashboard/dist/assets/MrW1ixGx.js.br +0 -0
  63. package/dashboard/dist/assets/MrW1ixGx.js.gz +0 -0
  64. package/dashboard/dist/index.html +2 -2
  65. package/dashboard/dist/index.html.br +0 -0
  66. package/dashboard/dist/index.html.gz +0 -0
  67. package/dist/activity-store.js +68 -8
  68. package/dist/agent-run-store.js +162 -24
  69. package/dist/cli/orgx.d.ts +3 -0
  70. package/dist/config/resolution.d.ts +7 -0
  71. package/dist/config/resolution.js +13 -5
  72. package/dist/contracts/onboarding-state.d.ts +2 -0
  73. package/dist/contracts/onboarding-state.js +23 -0
  74. package/dist/contracts/shared-types.d.ts +45 -0
  75. package/dist/http/helpers/auto-continue-engine.d.ts +23 -0
  76. package/dist/http/helpers/auto-continue-engine.js +468 -85
  77. package/dist/http/helpers/autopilot-runtime.js +5 -1
  78. package/dist/http/helpers/autopilot-slice-utils.js +25 -1
  79. package/dist/http/helpers/decision-mapper.d.ts +1 -0
  80. package/dist/http/helpers/decision-mapper.js +19 -2
  81. package/dist/http/helpers/dispatch-lifecycle.js +3 -0
  82. package/dist/http/helpers/mission-control.d.ts +1 -0
  83. package/dist/http/helpers/mission-control.js +5 -2
  84. package/dist/http/helpers/slice-run-projections.d.ts +27 -0
  85. package/dist/http/helpers/slice-run-projections.js +198 -10
  86. package/dist/http/helpers/triage-mapper.js +499 -6
  87. package/dist/http/helpers/value-utils.d.ts +1 -0
  88. package/dist/http/helpers/value-utils.js +17 -0
  89. package/dist/http/index.d.ts +1 -0
  90. package/dist/http/index.js +179 -46
  91. package/dist/http/router.js +64 -9
  92. package/dist/http/routes/live-legacy.d.ts +19 -2
  93. package/dist/http/routes/live-legacy.js +110 -27
  94. package/dist/http/routes/live-snapshot.d.ts +16 -2
  95. package/dist/http/routes/live-snapshot.js +169 -25
  96. package/dist/http/routes/live-triage.js +6 -1
  97. package/dist/http/routes/mission-control-actions.d.ts +9 -0
  98. package/dist/http/routes/mission-control-actions.js +185 -7
  99. package/dist/http/routes/mission-control-read.d.ts +13 -0
  100. package/dist/http/routes/mission-control-read.js +100 -219
  101. package/dist/http/routes/onboarding.d.ts +1 -0
  102. package/dist/http/routes/onboarding.js +17 -0
  103. package/dist/index.d.ts +5 -0
  104. package/dist/index.js +199 -123
  105. package/dist/outbox.d.ts +0 -2
  106. package/dist/outbox.js +259 -148
  107. package/dist/reporting/rollups.js +18 -11
  108. package/dist/runtime-instance-store.js +212 -58
  109. package/dist/stores/materialized-snapshot-store.d.ts +18 -0
  110. package/dist/stores/materialized-snapshot-store.js +91 -0
  111. package/dist/stores/sqlite-state.d.ts +6 -0
  112. package/dist/stores/sqlite-state.js +330 -0
  113. package/package.json +5 -1
  114. package/dashboard/dist/assets/B014hrCe.js.br +0 -0
  115. package/dashboard/dist/assets/B014hrCe.js.gz +0 -0
  116. package/dashboard/dist/assets/BCudUvwg.js +0 -1
  117. package/dashboard/dist/assets/BCudUvwg.js.br +0 -0
  118. package/dashboard/dist/assets/BCudUvwg.js.gz +0 -0
  119. package/dashboard/dist/assets/BGY6oI8h.js.br +0 -0
  120. package/dashboard/dist/assets/BGY6oI8h.js.gz +0 -0
  121. package/dashboard/dist/assets/BJI1Iy5v.css +0 -1
  122. package/dashboard/dist/assets/BJI1Iy5v.css.br +0 -0
  123. package/dashboard/dist/assets/BJI1Iy5v.css.gz +0 -0
  124. package/dashboard/dist/assets/BUvcp_7V.js +0 -1
  125. package/dashboard/dist/assets/BUvcp_7V.js.br +0 -0
  126. package/dashboard/dist/assets/BUvcp_7V.js.gz +0 -0
  127. package/dashboard/dist/assets/BV2Tf8S2.js +0 -212
  128. package/dashboard/dist/assets/BV2Tf8S2.js.br +0 -0
  129. package/dashboard/dist/assets/BV2Tf8S2.js.gz +0 -0
  130. package/dashboard/dist/assets/BYb6DARX.js.br +0 -0
  131. package/dashboard/dist/assets/BYb6DARX.js.gz +0 -0
  132. package/dashboard/dist/assets/BoDhb8_y.js.br +0 -0
  133. package/dashboard/dist/assets/BoDhb8_y.js.gz +0 -0
  134. package/dashboard/dist/assets/Bqk_l0k6.js +0 -1
  135. package/dashboard/dist/assets/Bqk_l0k6.js.br +0 -0
  136. package/dashboard/dist/assets/Bqk_l0k6.js.gz +0 -0
  137. package/dashboard/dist/assets/C-MOJWHs.js +0 -1
  138. package/dashboard/dist/assets/C-MOJWHs.js.br +0 -0
  139. package/dashboard/dist/assets/C-MOJWHs.js.gz +0 -0
  140. package/dashboard/dist/assets/CV0sWMbv.js.br +0 -0
  141. package/dashboard/dist/assets/CV0sWMbv.js.gz +0 -0
  142. package/dashboard/dist/assets/CaAkScfa.js +0 -1
  143. package/dashboard/dist/assets/CaAkScfa.js.br +0 -0
  144. package/dashboard/dist/assets/CaAkScfa.js.gz +0 -0
  145. package/dashboard/dist/assets/Ck5KlsPN.js +0 -1
  146. package/dashboard/dist/assets/Ck5KlsPN.js.br +0 -0
  147. package/dashboard/dist/assets/Ck5KlsPN.js.gz +0 -0
  148. package/dashboard/dist/assets/D2G51wQm.js +0 -1
  149. package/dashboard/dist/assets/D2G51wQm.js.br +0 -0
  150. package/dashboard/dist/assets/D2G51wQm.js.gz +0 -0
  151. package/dashboard/dist/assets/DAr4MfFk.js.br +0 -0
  152. package/dashboard/dist/assets/DAr4MfFk.js.gz +0 -0
  153. package/dashboard/dist/assets/DXVs61e1.js.br +0 -0
  154. package/dashboard/dist/assets/DXVs61e1.js.gz +0 -0
  155. package/dashboard/dist/assets/DibzNd0I.js.br +0 -0
  156. package/dashboard/dist/assets/DibzNd0I.js.gz +0 -0
  157. package/dashboard/dist/assets/Dm0CfDGr.js.br +0 -0
  158. package/dashboard/dist/assets/Dm0CfDGr.js.gz +0 -0
  159. package/dashboard/dist/assets/_zpQCpjm.js.br +0 -0
  160. package/dashboard/dist/assets/_zpQCpjm.js.gz +0 -0
  161. package/dashboard/dist/assets/uNGpYMSH.js +0 -1
  162. package/dashboard/dist/assets/uNGpYMSH.js.br +0 -0
  163. package/dashboard/dist/assets/uNGpYMSH.js.gz +0 -0
  164. package/dashboard/dist/assets/wa4jJQK9.js.br +0 -0
  165. package/dashboard/dist/assets/wa4jJQK9.js.gz +0 -0
@@ -5,6 +5,298 @@
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 pickBoolean(record, keys) {
57
+ if (!record)
58
+ return null;
59
+ for (const key of keys) {
60
+ const candidate = record[key];
61
+ if (typeof candidate === "boolean")
62
+ return candidate;
63
+ if (typeof candidate === "string") {
64
+ const normalized = candidate.trim().toLowerCase();
65
+ if (normalized === "true" || normalized === "yes" || normalized === "1")
66
+ return true;
67
+ if (normalized === "false" || normalized === "no" || normalized === "0")
68
+ return false;
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+ function normalizeDecisionOptionsFromUnknown(...values) {
74
+ const options = [];
75
+ const seen = new Set();
76
+ for (const value of values) {
77
+ if (!Array.isArray(value))
78
+ continue;
79
+ for (const entry of value) {
80
+ if (typeof entry === "string") {
81
+ const label = entry.trim();
82
+ if (!label)
83
+ continue;
84
+ const key = label.toLowerCase();
85
+ if (seen.has(key))
86
+ continue;
87
+ seen.add(key);
88
+ options.push({ label });
89
+ continue;
90
+ }
91
+ const record = asRecord(entry);
92
+ if (!record)
93
+ continue;
94
+ const label = pickString(record, ["label", "title", "name", "question"]) ??
95
+ pickString(record, ["action", "action_type", "actionType"]);
96
+ if (!label)
97
+ continue;
98
+ const id = pickString(record, ["id", "option_id", "optionId"]);
99
+ const description = pickString(record, ["description", "summary"]);
100
+ const consequences = pickString(record, ["consequences", "impact"]);
101
+ const actionType = pickString(record, ["action_type", "actionType", "action"]);
102
+ const impliedStatus = pickString(record, ["implied_status", "impliedStatus", "status"]);
103
+ const requiresNote = pickBoolean(record, ["requires_note", "requiresNote", "note_required"]);
104
+ const recommended = pickBoolean(record, ["recommended", "is_recommended", "isRecommended"]);
105
+ const key = `${(id ?? "").toLowerCase()}|${label.toLowerCase()}`;
106
+ if (seen.has(key))
107
+ continue;
108
+ seen.add(key);
109
+ options.push({
110
+ ...(id ? { id } : {}),
111
+ label,
112
+ ...(description ? { description } : {}),
113
+ ...(consequences ? { consequences } : {}),
114
+ ...(actionType ? { actionType } : {}),
115
+ ...(impliedStatus ? { impliedStatus } : {}),
116
+ ...(typeof requiresNote === "boolean" ? { requiresNote } : {}),
117
+ ...(typeof recommended === "boolean" ? { recommended } : {}),
118
+ });
119
+ }
120
+ }
121
+ return options.slice(0, 8);
122
+ }
123
+ function normalizeEvidenceFromUnknown(...values) {
124
+ const evidence = [];
125
+ const seen = new Set();
126
+ for (const value of values) {
127
+ if (!Array.isArray(value))
128
+ continue;
129
+ for (const entry of value) {
130
+ const record = asRecord(entry);
131
+ if (!record)
132
+ continue;
133
+ const title = pickString(record, ["title", "label", "name"]) ??
134
+ pickString(record, ["source_pointer", "sourcePointer", "source_url", "sourceUrl"]) ??
135
+ "Evidence";
136
+ const summary = pickString(record, ["summary", "description"]);
137
+ const url = pickString(record, ["source_url", "sourceUrl", "url"]);
138
+ const pointer = pickString(record, ["source_pointer", "sourcePointer", "path"]);
139
+ const evidenceType = pickString(record, ["evidence_type", "evidenceType", "type"]);
140
+ const confidenceRaw = record.confidence ?? record.confidence_score;
141
+ const confidence = typeof confidenceRaw === "number" && Number.isFinite(confidenceRaw)
142
+ ? Math.max(0, Math.min(1, confidenceRaw))
143
+ : null;
144
+ const key = `${title.toLowerCase()}|${url ?? ""}|${pointer ?? ""}`;
145
+ if (seen.has(key))
146
+ continue;
147
+ seen.add(key);
148
+ evidence.push({
149
+ title,
150
+ ...(summary ? { summary } : {}),
151
+ ...(url ? { url } : {}),
152
+ ...(pointer ? { pointer } : {}),
153
+ ...(evidenceType ? { evidenceType } : {}),
154
+ ...(confidence !== null ? { confidence } : {}),
155
+ });
156
+ }
157
+ }
158
+ return evidence.slice(0, 8);
159
+ }
160
+ function pickHierarchy(record, keys) {
161
+ if (!record)
162
+ return [];
163
+ for (const key of keys) {
164
+ const candidate = record[key];
165
+ if (!Array.isArray(candidate))
166
+ continue;
167
+ const normalized = candidate
168
+ .filter((entry) => typeof entry === "string")
169
+ .map((entry) => entry.trim())
170
+ .filter(Boolean);
171
+ if (normalized.length > 0)
172
+ return normalized;
173
+ }
174
+ return [];
175
+ }
176
+ function deriveInterventionContext(input) {
177
+ const metadata = asRecord(input.metadata);
178
+ const result = asRecord(metadata?.result);
179
+ const blocker = asRecord(metadata?.blocker) ?? asRecord(result?.blocker);
180
+ const blockerReason = pickString(blocker, ["description", "summary"]) ??
181
+ pickString(result, ["blocked_reason", "blockedReason", "error"]) ??
182
+ pickString(metadata, ["blocked_reason", "blockedReason", "error", "reason"]) ??
183
+ (typeof input.reason === "string" && input.reason.trim().length > 0 ? input.reason.trim() : null);
184
+ const waitingOn = pickString(blocker, ["waiting_on", "required_actor", "requiredActor"]) ??
185
+ pickString(result, ["waiting_on", "required_actor", "requiredActor"]) ??
186
+ pickString(metadata, ["waiting_on", "required_actor", "requiredActor"]);
187
+ const nextActions = [
188
+ ...pickStringArray(result, ["next_actions", "nextActions"]),
189
+ ...pickStringArray(metadata, ["next_actions", "nextActions"]),
190
+ ];
191
+ const requiredAction = pickString(blocker, ["required_action", "requiredAction"]) ??
192
+ pickString(result, ["required_action", "requiredAction"]) ??
193
+ pickString(metadata, ["required_action", "requiredAction"]) ??
194
+ (nextActions[0] ?? null);
195
+ const requiredActor = pickString(blocker, ["required_actor", "requiredActor"]) ??
196
+ pickString(result, ["required_actor", "requiredActor"]) ??
197
+ pickString(metadata, ["required_actor", "requiredActor"]);
198
+ const suggestedActions = [
199
+ ...pickStringArray(blocker, ["suggested_actions", "suggestedActions"]),
200
+ ...pickStringArray(result, ["suggested_actions", "suggestedActions"]),
201
+ ...pickStringArray(metadata, ["suggested_actions", "suggestedActions"]),
202
+ ];
203
+ const decisionIds = [
204
+ ...pickStringArray(result, ["decision_ids", "decisionIds"]),
205
+ ...pickStringArray(metadata, ["decision_ids", "decisionIds"]),
206
+ ];
207
+ const retryable = typeof blocker?.retryable === "boolean"
208
+ ? blocker.retryable
209
+ : typeof result?.retryable === "boolean"
210
+ ? result.retryable
211
+ : typeof metadata?.retryable === "boolean"
212
+ ? metadata.retryable
213
+ : null;
214
+ const errorCode = pickString(blocker, ["error_code", "errorCode"]) ??
215
+ pickString(result, ["error_code", "errorCode"]) ??
216
+ pickString(metadata, ["error_code", "errorCode"]);
217
+ const errorCategory = pickString(blocker, ["error_category", "errorCategory"]) ??
218
+ pickString(result, ["error_category", "errorCategory"]) ??
219
+ pickString(metadata, ["error_category", "errorCategory"]);
220
+ const taskUpdateCount = countArray(result, ["task_updates", "taskUpdates"]) ||
221
+ countArray(metadata, ["task_updates", "taskUpdates"]);
222
+ const milestoneUpdateCount = countArray(result, ["milestone_updates", "milestoneUpdates"]) ||
223
+ countArray(metadata, ["milestone_updates", "milestoneUpdates"]);
224
+ const decisionPrompt = pickString(metadata, ["decision_prompt", "decisionPrompt", "question", "decision_title", "decisionTitle"]) ??
225
+ pickString(result, ["decision_prompt", "decisionPrompt", "question"]);
226
+ const decisionSummary = pickString(metadata, ["decision_summary", "decisionSummary", "summary", "context"]) ??
227
+ pickString(result, ["decision_summary", "decisionSummary", "summary"]);
228
+ const decisionOptions = normalizeDecisionOptionsFromUnknown(metadata?.decision_options, metadata?.decisionOptions, metadata?.options, result?.decision_options, result?.decisionOptions, result?.options);
229
+ const recommendedAction = pickString(metadata, ["recommended_action", "recommendedAction"]) ??
230
+ pickString(result, ["recommended_action", "recommendedAction"]) ??
231
+ requiredAction;
232
+ const scopeHierarchy = [
233
+ ...pickHierarchy(metadata, ["scope_hierarchy", "scopeHierarchy"]),
234
+ ...pickHierarchy(result, ["scope_hierarchy", "scopeHierarchy"]),
235
+ ].filter((entry, index, source) => source.indexOf(entry) === index);
236
+ const currentRunState = pickString(metadata, ["current_run_state", "currentRunState", "runtime_state", "runtimeState", "status"]) ??
237
+ pickString(result, ["current_run_state", "currentRunState", "runtime_state", "runtimeState", "status"]);
238
+ const impactIfDelayed = pickString(metadata, ["impact_if_delayed", "impactIfDelayed"]) ??
239
+ pickString(result, ["impact_if_delayed", "impactIfDelayed"]);
240
+ const evidence = normalizeEvidenceFromUnknown(metadata?.evidence_refs, metadata?.evidenceRefs, result?.evidence_refs, result?.evidenceRefs);
241
+ const artifacts = pickStringArray(metadata, ["artifacts_created", "artifact_titles", "artifactTitles"]);
242
+ const updatesApplied = [
243
+ ...pickStringArray(metadata, ["updates_applied", "updatesApplied"]),
244
+ ...pickStringArray(result, ["updates_applied", "updatesApplied"]),
245
+ ];
246
+ const context = {
247
+ blockerReason,
248
+ waitingOn,
249
+ requiredAction,
250
+ requiredActor,
251
+ retryable,
252
+ errorCode,
253
+ errorCategory,
254
+ suggestedActions: suggestedActions.length > 0 ? Array.from(new Set(suggestedActions)) : [],
255
+ nextActions: nextActions.length > 0 ? Array.from(new Set(nextActions)) : [],
256
+ decisionIds: decisionIds.length > 0 ? Array.from(new Set(decisionIds)) : [],
257
+ taskUpdateCount: taskUpdateCount > 0 ? taskUpdateCount : undefined,
258
+ milestoneUpdateCount: milestoneUpdateCount > 0 ? milestoneUpdateCount : undefined,
259
+ decisionPrompt,
260
+ decisionSummary,
261
+ decisionOptions: decisionOptions.length > 0 ? decisionOptions : undefined,
262
+ recommendedAction,
263
+ scopeHierarchy: scopeHierarchy.length > 0 ? scopeHierarchy : undefined,
264
+ currentRunState,
265
+ impactIfDelayed,
266
+ artifacts: artifacts.length > 0 ? Array.from(new Set(artifacts)) : undefined,
267
+ evidence: evidence.length > 0 ? evidence : undefined,
268
+ updatesApplied: updatesApplied.length > 0 ? Array.from(new Set(updatesApplied)) : undefined,
269
+ };
270
+ const hasValue = [
271
+ context.blockerReason,
272
+ context.waitingOn,
273
+ context.requiredAction,
274
+ context.requiredActor,
275
+ context.errorCode,
276
+ context.errorCategory,
277
+ context.retryable,
278
+ context.taskUpdateCount,
279
+ context.milestoneUpdateCount,
280
+ context.decisionPrompt,
281
+ context.decisionSummary,
282
+ context.recommendedAction,
283
+ context.currentRunState,
284
+ context.impactIfDelayed,
285
+ context.suggestedActions?.length,
286
+ context.nextActions?.length,
287
+ context.decisionIds?.length,
288
+ context.decisionOptions?.length,
289
+ context.scopeHierarchy?.length,
290
+ context.artifacts?.length,
291
+ context.evidence?.length,
292
+ context.updatesApplied?.length,
293
+ ].some((entry) => {
294
+ if (typeof entry === "number")
295
+ return entry > 0;
296
+ return entry != null && String(entry).trim().length > 0;
297
+ });
298
+ return hasValue ? context : null;
299
+ }
8
300
  const FAILURE_MAPPINGS = {
9
301
  credential_missing: {
10
302
  kind: "blocked_intervention",
@@ -180,6 +472,72 @@ const FAILURE_MAPPINGS = {
180
472
  },
181
473
  ],
182
474
  },
475
+ decision_required: {
476
+ kind: "decision_required",
477
+ severity: "high",
478
+ recommendedAction: "Review the options and choose the next move",
479
+ defaultTitle: (ctx) => `Decision required${ctx.workstreamTitle ? `: ${ctx.workstreamTitle}` : ""}`,
480
+ defaultSummary: (ctx) => `${ctx.workstreamTitle ?? "This workstream"} cannot continue until a decision is made. ${ctx.reason ?? "Review the recommendation and choose a direction."}`,
481
+ actions: () => [
482
+ {
483
+ action: "approve",
484
+ label: "Approve path",
485
+ description: "Accept the recommended option and continue",
486
+ consequences: "Autopilot will continue with the approved direction.",
487
+ requiresNote: false,
488
+ available: true,
489
+ },
490
+ {
491
+ action: "reject",
492
+ label: "Reject path",
493
+ description: "Decline this path and provide direction",
494
+ consequences: "The run stays paused until new direction is provided.",
495
+ requiresNote: true,
496
+ available: true,
497
+ },
498
+ {
499
+ action: "snooze",
500
+ label: "Snooze",
501
+ description: "Defer this intervention",
502
+ consequences: "This decision returns to the queue later.",
503
+ requiresNote: false,
504
+ available: true,
505
+ },
506
+ ],
507
+ },
508
+ review_required: {
509
+ kind: "review_required",
510
+ severity: "medium",
511
+ recommendedAction: "Review the update and confirm the next step",
512
+ defaultTitle: (ctx) => `Review required${ctx.workstreamTitle ? `: ${ctx.workstreamTitle}` : ""}`,
513
+ defaultSummary: (ctx) => `${ctx.workstreamTitle ?? "This workstream"} surfaced something that needs judgment before it proceeds. ${ctx.reason ?? "Review the evidence and confirm what should happen next."}`,
514
+ actions: () => [
515
+ {
516
+ action: "approve",
517
+ label: "Approve",
518
+ description: "Confirm the proposed next step",
519
+ consequences: "The run continues with the reviewed direction.",
520
+ requiresNote: false,
521
+ available: true,
522
+ },
523
+ {
524
+ action: "reject",
525
+ label: "Send back",
526
+ description: "Request a different approach",
527
+ consequences: "The run pauses until new direction is provided.",
528
+ requiresNote: true,
529
+ available: true,
530
+ },
531
+ {
532
+ action: "snooze",
533
+ label: "Snooze",
534
+ description: "Return to this later",
535
+ consequences: "The review request will surface again later.",
536
+ requiresNote: false,
537
+ available: true,
538
+ },
539
+ ],
540
+ },
183
541
  budget_exhausted: {
184
542
  kind: "blocked_intervention",
185
543
  severity: "critical",
@@ -288,16 +646,33 @@ export async function mapFailureToTriageItem(input) {
288
646
  metadata: input.metadata,
289
647
  };
290
648
  const now = input.timestamp ?? new Date().toISOString();
649
+ const intervention = deriveInterventionContext({
650
+ reason: input.reason ?? null,
651
+ metadata: input.metadata,
652
+ });
291
653
  const proofBundle = {
292
654
  artifactRefs: [],
293
655
  fileChanges: [],
294
656
  prRefs: [],
295
657
  logRefs: input.logPath ? [input.logPath] : [],
296
- decisionRefs: [],
658
+ decisionRefs: intervention?.decisionIds ?? [],
297
659
  };
298
660
  if (input.outputPath) {
299
661
  proofBundle.artifactRefs.push(input.outputPath);
300
662
  }
663
+ for (const artifact of intervention?.artifacts ?? []) {
664
+ if (!proofBundle.artifactRefs.includes(artifact)) {
665
+ proofBundle.artifactRefs.push(artifact);
666
+ }
667
+ }
668
+ for (const evidence of intervention?.evidence ?? []) {
669
+ if (evidence.url && !proofBundle.artifactRefs.includes(evidence.url)) {
670
+ proofBundle.artifactRefs.push(evidence.url);
671
+ }
672
+ if (evidence.pointer && !proofBundle.logRefs.includes(evidence.pointer)) {
673
+ proofBundle.logRefs.push(evidence.pointer);
674
+ }
675
+ }
301
676
  const impact = {
302
677
  initiativeCount: input.initiativeId ? 1 : 0,
303
678
  workstreamCount: input.workstreamId ? 1 : 0,
@@ -380,6 +755,25 @@ export async function mapFailureToTriageItem(input) {
380
755
  },
381
756
  ];
382
757
  }
758
+ const summaryDetails = [];
759
+ if (intervention?.waitingOn)
760
+ summaryDetails.push(`Waiting on ${intervention.waitingOn}.`);
761
+ if (intervention?.requiredAction)
762
+ summaryDetails.push(`Required action: ${intervention.requiredAction}.`);
763
+ if (intervention?.errorCode)
764
+ summaryDetails.push(`Error code: ${intervention.errorCode}.`);
765
+ if (intervention?.taskUpdateCount && intervention.taskUpdateCount > 0) {
766
+ summaryDetails.push(`${intervention.taskUpdateCount} task update${intervention.taskUpdateCount === 1 ? "" : "s"} pending apply.`);
767
+ }
768
+ if (intervention?.milestoneUpdateCount && intervention.milestoneUpdateCount > 0) {
769
+ summaryDetails.push(`${intervention.milestoneUpdateCount} milestone update${intervention.milestoneUpdateCount === 1 ? "" : "s"} pending apply.`);
770
+ }
771
+ if (summaryDetails.length > 0) {
772
+ summary = `${summary} ${summaryDetails.join(" ")}`.trim();
773
+ }
774
+ if (intervention?.requiredAction) {
775
+ recommendedAction = intervention.requiredAction;
776
+ }
383
777
  return {
384
778
  id: input.id,
385
779
  kind,
@@ -407,6 +801,7 @@ export async function mapFailureToTriageItem(input) {
407
801
  blocking: kind === "blocked_intervention" || kind === "decision_required",
408
802
  recommendedAction,
409
803
  agentId: input.agentId ?? null,
804
+ intervention,
410
805
  impact,
411
806
  proofBundle,
412
807
  actionContract,
@@ -426,7 +821,73 @@ export function mapDecisionToTriageItem(decision) {
426
821
  const now = new Date().toISOString();
427
822
  const decisionType = decision.decisionType ?? "decision_required";
428
823
  const mapping = FAILURE_MAPPINGS[decisionType];
429
- const actions = [
824
+ const metadata = decision.metadata && typeof decision.metadata === "object" && !Array.isArray(decision.metadata)
825
+ ? decision.metadata
826
+ : null;
827
+ const intervention = deriveInterventionContext({
828
+ reason: decision.context ?? null,
829
+ metadata: metadata ?? undefined,
830
+ });
831
+ const blocking = metadata?.blocking !== false;
832
+ const options = Array.isArray(decision.options) ? decision.options : [];
833
+ const enrichedIntervention = intervention || options.length > 0 || decision.context || decision.recommendedAction || decision.evidenceRefs?.length
834
+ ? {
835
+ ...(intervention ?? {}),
836
+ decisionPrompt: intervention?.decisionPrompt ??
837
+ decision.title,
838
+ decisionSummary: intervention?.decisionSummary ??
839
+ decision.context ??
840
+ null,
841
+ decisionOptions: intervention?.decisionOptions && intervention.decisionOptions.length > 0
842
+ ? intervention.decisionOptions
843
+ : options.map((option) => ({
844
+ id: option.id,
845
+ label: option.label,
846
+ description: option.description ?? null,
847
+ consequences: option.consequences ?? null,
848
+ actionType: option.actionType ?? null,
849
+ impliedStatus: option.impliedStatus ?? null,
850
+ requiresNote: option.requiresNote,
851
+ recommended: decision.selectedOptionId != null ? decision.selectedOptionId === option.id : false,
852
+ })),
853
+ recommendedAction: intervention?.recommendedAction ??
854
+ decision.recommendedAction ??
855
+ null,
856
+ evidence: intervention?.evidence && intervention.evidence.length > 0
857
+ ? intervention.evidence
858
+ : (decision.evidenceRefs ?? []).map((ref) => ({
859
+ title: ref.title ?? ref.sourcePointer ?? ref.sourceUrl ?? "Evidence",
860
+ summary: ref.summary ?? null,
861
+ url: ref.sourceUrl ?? null,
862
+ pointer: ref.sourcePointer ?? null,
863
+ evidenceType: ref.evidenceType ?? null,
864
+ confidence: ref.confidence ?? null,
865
+ })),
866
+ }
867
+ : null;
868
+ const optionActions = options
869
+ .map((option) => {
870
+ const implied = (option.impliedStatus ?? "").toLowerCase();
871
+ const action = implied === "declined" || implied === "cancelled" ? "reject" : "approve";
872
+ const optionConsequences = typeof option.consequences === "string" && option.consequences.trim().length > 0
873
+ ? option.consequences.trim()
874
+ : null;
875
+ const consequences = optionConsequences ??
876
+ (action === "approve"
877
+ ? "Will continue execution using this option."
878
+ : "Will decline this direction and keep the run blocked.");
879
+ return {
880
+ action,
881
+ label: option.label,
882
+ description: option.description ?? (action === "approve" ? "Approve this option" : "Reject with this rationale"),
883
+ consequences,
884
+ requiresNote: option.requiresNote === true,
885
+ available: true,
886
+ optionId: option.id,
887
+ };
888
+ })
889
+ .slice(0, 4);
890
+ const fallbackActions = [
430
891
  {
431
892
  action: "approve",
432
893
  label: "Approve",
@@ -434,6 +895,7 @@ export function mapDecisionToTriageItem(decision) {
434
895
  consequences: "Will proceed with the recommended action.",
435
896
  requiresNote: false,
436
897
  available: true,
898
+ optionId: null,
437
899
  },
438
900
  {
439
901
  action: "reject",
@@ -442,7 +904,20 @@ export function mapDecisionToTriageItem(decision) {
442
904
  consequences: "Agent will pause and await new instructions.",
443
905
  requiresNote: true,
444
906
  available: true,
907
+ optionId: null,
445
908
  },
909
+ ];
910
+ const optionActionsWithCoverage = [...optionActions];
911
+ if (optionActionsWithCoverage.length > 0) {
912
+ if (!optionActionsWithCoverage.some((action) => action.action === "approve")) {
913
+ optionActionsWithCoverage.unshift(fallbackActions[0]);
914
+ }
915
+ if (!optionActionsWithCoverage.some((action) => action.action === "reject")) {
916
+ optionActionsWithCoverage.push(fallbackActions[1]);
917
+ }
918
+ }
919
+ const actions = [
920
+ ...(optionActionsWithCoverage.length > 0 ? optionActionsWithCoverage.slice(0, 4) : fallbackActions),
446
921
  {
447
922
  action: "snooze",
448
923
  label: "Snooze",
@@ -450,6 +925,7 @@ export function mapDecisionToTriageItem(decision) {
450
925
  consequences: "Item reappears after snooze period.",
451
926
  requiresNote: false,
452
927
  available: true,
928
+ optionId: null,
453
929
  },
454
930
  ];
455
931
  const proofBundle = {
@@ -457,20 +933,36 @@ export function mapDecisionToTriageItem(decision) {
457
933
  fileChanges: [],
458
934
  prRefs: [],
459
935
  logRefs: [],
460
- decisionRefs: [decision.id],
936
+ decisionRefs: Array.from(new Set([decision.id, ...(enrichedIntervention?.decisionIds ?? [])].filter(Boolean))),
461
937
  };
462
938
  if (decision.evidenceRefs) {
463
939
  for (const ref of decision.evidenceRefs) {
464
940
  if (ref.sourceUrl)
465
941
  proofBundle.artifactRefs.push(ref.sourceUrl);
942
+ if (ref.sourcePointer)
943
+ proofBundle.logRefs.push(ref.sourcePointer);
466
944
  }
467
945
  }
946
+ const summaryBase = (typeof decision.context === "string" && decision.context.trim()) ||
947
+ enrichedIntervention?.blockerReason ||
948
+ decision.title;
949
+ const summarySuffix = [
950
+ enrichedIntervention?.waitingOn ? `Waiting on ${enrichedIntervention.waitingOn}.` : null,
951
+ enrichedIntervention?.requiredAction ? `Required action: ${enrichedIntervention.requiredAction}.` : null,
952
+ ]
953
+ .filter((entry) => Boolean(entry))
954
+ .join(" ");
955
+ const summary = summarySuffix.length > 0 ? `${summaryBase} ${summarySuffix}` : summaryBase;
956
+ const recommendedAction = decision.recommendedAction ??
957
+ enrichedIntervention?.recommendedAction ??
958
+ enrichedIntervention?.requiredAction ??
959
+ null;
468
960
  return {
469
961
  id: `triage-decision-${decision.id}`,
470
962
  kind: mapping?.kind ?? "decision_required",
471
963
  status: decision.status === "pending" ? "open" : decision.status === "resolved" ? "resolved" : "open",
472
964
  title: decision.title,
473
- summary: decision.context ?? decision.title,
965
+ summary,
474
966
  initiativeId: decision.initiativeId ?? null,
475
967
  initiativeTitle: null,
476
968
  workstreamId: decision.workstreamId ?? null,
@@ -482,9 +974,10 @@ export function mapDecisionToTriageItem(decision) {
482
974
  dedupeKey: decision.dedupeKey ?? null,
483
975
  occurrenceCount: decision.occurrenceCount ?? 1,
484
976
  severity: decision.priority === "urgent" ? "critical" : decision.priority === "high" ? "high" : "medium",
485
- blocking: true,
486
- recommendedAction: decision.recommendedAction ?? null,
977
+ blocking,
978
+ recommendedAction,
487
979
  agentId: decision.agentId ?? null,
980
+ intervention: enrichedIntervention,
488
981
  impact: {
489
982
  initiativeCount: decision.initiativeId ? 1 : 0,
490
983
  workstreamCount: decision.workstreamId ? 1 : 0,
@@ -1,5 +1,6 @@
1
1
  export declare function pickString(record: Record<string, unknown>, keys: string[]): string | null;
2
2
  export declare function pickNumber(record: Record<string, unknown>, keys: string[]): number | null;
3
+ export declare function pickBoolean(record: Record<string, unknown> | null, keys: string[]): boolean | null;
3
4
  export declare function pickHeaderString(headers: Record<string, string | string[] | undefined>, keys: string[]): string | null;
4
5
  export declare function toIsoString(value: string | null): string | null;
5
6
  export declare function parsePositiveInt(raw: string | null, fallback: number, max?: number): number;
@@ -23,6 +23,23 @@ export function pickNumber(record, keys) {
23
23
  }
24
24
  return null;
25
25
  }
26
+ export function pickBoolean(record, keys) {
27
+ if (!record)
28
+ return null;
29
+ for (const key of keys) {
30
+ const value = record[key];
31
+ if (typeof value === "boolean")
32
+ return value;
33
+ if (typeof value === "string") {
34
+ const normalized = value.trim().toLowerCase();
35
+ if (normalized === "true" || normalized === "yes" || normalized === "1")
36
+ return true;
37
+ if (normalized === "false" || normalized === "no" || normalized === "0")
38
+ return false;
39
+ }
40
+ }
41
+ return null;
42
+ }
26
43
  export function pickHeaderString(headers, keys) {
27
44
  for (const key of keys) {
28
45
  const candidates = [key, key.toLowerCase(), key.toUpperCase()];
@@ -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 {