@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.
- package/dashboard/dist/assets/B6VftyY6.js +1 -0
- package/dashboard/dist/assets/B6VftyY6.js.br +0 -0
- package/dashboard/dist/assets/B6VftyY6.js.gz +0 -0
- package/dashboard/dist/assets/{Dm0CfDGr.js → BANQdlC4.js} +1 -1
- package/dashboard/dist/assets/BANQdlC4.js.br +0 -0
- package/dashboard/dist/assets/BANQdlC4.js.gz +0 -0
- package/dashboard/dist/assets/{_zpQCpjm.js → BPL4CL3c.js} +1 -1
- package/dashboard/dist/assets/BPL4CL3c.js.br +0 -0
- package/dashboard/dist/assets/BPL4CL3c.js.gz +0 -0
- package/dashboard/dist/assets/{DXVs61e1.js → BZCkOZ20.js} +1 -1
- package/dashboard/dist/assets/BZCkOZ20.js.br +0 -0
- package/dashboard/dist/assets/BZCkOZ20.js.gz +0 -0
- package/dashboard/dist/assets/{BYb6DARX.js → B_LdOJUa.js} +1 -1
- package/dashboard/dist/assets/B_LdOJUa.js.br +0 -0
- package/dashboard/dist/assets/B_LdOJUa.js.gz +0 -0
- package/dashboard/dist/assets/Bfp-wdwb.css +1 -0
- package/dashboard/dist/assets/Bfp-wdwb.css.br +0 -0
- package/dashboard/dist/assets/Bfp-wdwb.css.gz +0 -0
- package/dashboard/dist/assets/{DibzNd0I.js → BvFcH_Iy.js} +1 -1
- package/dashboard/dist/assets/BvFcH_Iy.js.br +0 -0
- package/dashboard/dist/assets/BvFcH_Iy.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/C0i7ABUU.js +212 -0
- package/dashboard/dist/assets/C0i7ABUU.js.br +0 -0
- package/dashboard/dist/assets/C0i7ABUU.js.gz +0 -0
- package/dashboard/dist/assets/CFB0MM7j.js +1 -0
- package/dashboard/dist/assets/CFB0MM7j.js.br +0 -0
- package/dashboard/dist/assets/CFB0MM7j.js.gz +0 -0
- package/dashboard/dist/assets/CQSRb1yu.js +1 -0
- package/dashboard/dist/assets/CQSRb1yu.js.br +0 -0
- package/dashboard/dist/assets/CQSRb1yu.js.gz +0 -0
- package/dashboard/dist/assets/{wa4jJQK9.js → CUoQoSm-.js} +1 -1
- package/dashboard/dist/assets/CUoQoSm-.js.br +0 -0
- package/dashboard/dist/assets/CUoQoSm-.js.gz +0 -0
- package/dashboard/dist/assets/Ckd1R1iE.js +1 -0
- package/dashboard/dist/assets/Ckd1R1iE.js.br +0 -0
- package/dashboard/dist/assets/Ckd1R1iE.js.gz +0 -0
- package/dashboard/dist/assets/{BGY6oI8h.js → CqRNb2EL.js} +1 -1
- package/dashboard/dist/assets/CqRNb2EL.js.br +0 -0
- package/dashboard/dist/assets/CqRNb2EL.js.gz +0 -0
- package/dashboard/dist/assets/{DAr4MfFk.js → DClUc9rw.js} +1 -1
- package/dashboard/dist/assets/DClUc9rw.js.br +0 -0
- package/dashboard/dist/assets/DClUc9rw.js.gz +0 -0
- package/dashboard/dist/assets/DF2PMTwT.js +1 -0
- package/dashboard/dist/assets/DF2PMTwT.js.br +0 -0
- package/dashboard/dist/assets/DF2PMTwT.js.gz +0 -0
- package/dashboard/dist/assets/{B014hrCe.js → DJYl7gyA.js} +2 -2
- package/dashboard/dist/assets/DJYl7gyA.js.br +0 -0
- package/dashboard/dist/assets/DJYl7gyA.js.gz +0 -0
- package/dashboard/dist/assets/{BoDhb8_y.js → DZtNMX0t.js} +2 -2
- package/dashboard/dist/assets/DZtNMX0t.js.br +0 -0
- package/dashboard/dist/assets/DZtNMX0t.js.gz +0 -0
- package/dashboard/dist/assets/DlEa8PI0.js +1 -0
- package/dashboard/dist/assets/DlEa8PI0.js.br +0 -0
- package/dashboard/dist/assets/DlEa8PI0.js.gz +0 -0
- package/dashboard/dist/assets/M4QxcXjh.js +1 -0
- package/dashboard/dist/assets/M4QxcXjh.js.br +0 -0
- package/dashboard/dist/assets/M4QxcXjh.js.gz +0 -0
- package/dashboard/dist/assets/{CV0sWMbv.js → MrW1ixGx.js} +1 -1
- package/dashboard/dist/assets/MrW1ixGx.js.br +0 -0
- package/dashboard/dist/assets/MrW1ixGx.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/activity-store.js +68 -8
- 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 +45 -0
- package/dist/http/helpers/auto-continue-engine.d.ts +23 -0
- package/dist/http/helpers/auto-continue-engine.js +468 -85
- 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 +499 -6
- package/dist/http/helpers/value-utils.d.ts +1 -0
- package/dist/http/helpers/value-utils.js +17 -0
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +179 -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/live-triage.js +6 -1
- package/dist/http/routes/mission-control-actions.d.ts +9 -0
- package/dist/http/routes/mission-control-actions.js +185 -7
- package/dist/http/routes/mission-control-read.d.ts +13 -0
- package/dist/http/routes/mission-control-read.js +100 -219
- 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 +259 -148
- 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 +330 -0
- package/package.json +5 -1
- package/dashboard/dist/assets/B014hrCe.js.br +0 -0
- package/dashboard/dist/assets/B014hrCe.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/BGY6oI8h.js.br +0 -0
- package/dashboard/dist/assets/BGY6oI8h.js.gz +0 -0
- package/dashboard/dist/assets/BJI1Iy5v.css +0 -1
- package/dashboard/dist/assets/BJI1Iy5v.css.br +0 -0
- package/dashboard/dist/assets/BJI1Iy5v.css.gz +0 -0
- package/dashboard/dist/assets/BUvcp_7V.js +0 -1
- package/dashboard/dist/assets/BUvcp_7V.js.br +0 -0
- package/dashboard/dist/assets/BUvcp_7V.js.gz +0 -0
- package/dashboard/dist/assets/BV2Tf8S2.js +0 -212
- package/dashboard/dist/assets/BV2Tf8S2.js.br +0 -0
- package/dashboard/dist/assets/BV2Tf8S2.js.gz +0 -0
- package/dashboard/dist/assets/BYb6DARX.js.br +0 -0
- package/dashboard/dist/assets/BYb6DARX.js.gz +0 -0
- package/dashboard/dist/assets/BoDhb8_y.js.br +0 -0
- package/dashboard/dist/assets/BoDhb8_y.js.gz +0 -0
- package/dashboard/dist/assets/Bqk_l0k6.js +0 -1
- package/dashboard/dist/assets/Bqk_l0k6.js.br +0 -0
- package/dashboard/dist/assets/Bqk_l0k6.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/CV0sWMbv.js.br +0 -0
- package/dashboard/dist/assets/CV0sWMbv.js.gz +0 -0
- package/dashboard/dist/assets/CaAkScfa.js +0 -1
- package/dashboard/dist/assets/CaAkScfa.js.br +0 -0
- package/dashboard/dist/assets/CaAkScfa.js.gz +0 -0
- package/dashboard/dist/assets/Ck5KlsPN.js +0 -1
- package/dashboard/dist/assets/Ck5KlsPN.js.br +0 -0
- package/dashboard/dist/assets/Ck5KlsPN.js.gz +0 -0
- package/dashboard/dist/assets/D2G51wQm.js +0 -1
- package/dashboard/dist/assets/D2G51wQm.js.br +0 -0
- package/dashboard/dist/assets/D2G51wQm.js.gz +0 -0
- package/dashboard/dist/assets/DAr4MfFk.js.br +0 -0
- package/dashboard/dist/assets/DAr4MfFk.js.gz +0 -0
- package/dashboard/dist/assets/DXVs61e1.js.br +0 -0
- package/dashboard/dist/assets/DXVs61e1.js.gz +0 -0
- package/dashboard/dist/assets/DibzNd0I.js.br +0 -0
- package/dashboard/dist/assets/DibzNd0I.js.gz +0 -0
- package/dashboard/dist/assets/Dm0CfDGr.js.br +0 -0
- package/dashboard/dist/assets/Dm0CfDGr.js.gz +0 -0
- package/dashboard/dist/assets/_zpQCpjm.js.br +0 -0
- package/dashboard/dist/assets/_zpQCpjm.js.gz +0 -0
- package/dashboard/dist/assets/uNGpYMSH.js +0 -1
- package/dashboard/dist/assets/uNGpYMSH.js.br +0 -0
- package/dashboard/dist/assets/uNGpYMSH.js.gz +0 -0
- package/dashboard/dist/assets/wa4jJQK9.js.br +0 -0
- 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
|
|
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
|
|
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
|
|
486
|
-
recommendedAction
|
|
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()];
|
package/dist/http/index.d.ts
CHANGED