@useorgx/openclaw-plugin 0.7.20 → 0.7.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard/dist/assets/9gFmK3Kr.js +1 -0
- package/dashboard/dist/assets/9gFmK3Kr.js.br +0 -0
- package/dashboard/dist/assets/9gFmK3Kr.js.gz +0 -0
- package/dashboard/dist/assets/{BoDhb8_y.js → BrMXbzQ-.js} +2 -2
- package/dashboard/dist/assets/BrMXbzQ-.js.br +0 -0
- package/dashboard/dist/assets/BrMXbzQ-.js.gz +0 -0
- package/dashboard/dist/assets/By0MIBj_.js +1 -0
- package/dashboard/dist/assets/By0MIBj_.js.br +0 -0
- package/dashboard/dist/assets/By0MIBj_.js.gz +0 -0
- package/dashboard/dist/assets/C1u2SGin.css +1 -0
- package/dashboard/dist/assets/C1u2SGin.css.br +0 -0
- package/dashboard/dist/assets/C1u2SGin.css.gz +0 -0
- package/dashboard/dist/assets/{DAr4MfFk.js → CGJiHCIx.js} +1 -1
- package/dashboard/dist/assets/CGJiHCIx.js.br +0 -0
- package/dashboard/dist/assets/CGJiHCIx.js.gz +0 -0
- package/dashboard/dist/assets/CSd4rSuU.js +212 -0
- package/dashboard/dist/assets/CSd4rSuU.js.br +0 -0
- package/dashboard/dist/assets/CSd4rSuU.js.gz +0 -0
- package/dashboard/dist/assets/{DibzNd0I.js → CZXS5i_5.js} +1 -1
- package/dashboard/dist/assets/CZXS5i_5.js.br +0 -0
- package/dashboard/dist/assets/CZXS5i_5.js.gz +0 -0
- package/dashboard/dist/assets/{wa4jJQK9.js → CbVWL74-.js} +1 -1
- package/dashboard/dist/assets/CbVWL74-.js.br +0 -0
- package/dashboard/dist/assets/CbVWL74-.js.gz +0 -0
- package/dashboard/dist/assets/{Dm0CfDGr.js → D-FuHfT8.js} +1 -1
- package/dashboard/dist/assets/D-FuHfT8.js.br +0 -0
- package/dashboard/dist/assets/D-FuHfT8.js.gz +0 -0
- package/dashboard/dist/assets/{DXVs61e1.js → D0PN5_vY.js} +1 -1
- package/dashboard/dist/assets/D0PN5_vY.js.br +0 -0
- package/dashboard/dist/assets/D0PN5_vY.js.gz +0 -0
- package/dashboard/dist/assets/{_zpQCpjm.js → DDCPrZRt.js} +1 -1
- package/dashboard/dist/assets/DDCPrZRt.js.br +0 -0
- package/dashboard/dist/assets/DDCPrZRt.js.gz +0 -0
- package/dashboard/dist/assets/{BYb6DARX.js → DNQ-iFO2.js} +1 -1
- package/dashboard/dist/assets/DNQ-iFO2.js.br +0 -0
- package/dashboard/dist/assets/DNQ-iFO2.js.gz +0 -0
- package/dashboard/dist/assets/{BGY6oI8h.js → DhPuHPK7.js} +1 -1
- package/dashboard/dist/assets/DhPuHPK7.js.br +0 -0
- package/dashboard/dist/assets/DhPuHPK7.js.gz +0 -0
- package/dashboard/dist/assets/Dhz7qPtn.js +1 -0
- package/dashboard/dist/assets/Dhz7qPtn.js.br +0 -0
- package/dashboard/dist/assets/Dhz7qPtn.js.gz +0 -0
- package/dashboard/dist/assets/LOFrVoPD.js +1 -0
- package/dashboard/dist/assets/LOFrVoPD.js.br +0 -0
- package/dashboard/dist/assets/LOFrVoPD.js.gz +0 -0
- package/dashboard/dist/assets/OlLPtzdz.js +1 -0
- package/dashboard/dist/assets/OlLPtzdz.js.br +0 -0
- package/dashboard/dist/assets/OlLPtzdz.js.gz +0 -0
- package/dashboard/dist/assets/{B014hrCe.js → RN4M9u9W.js} +2 -2
- package/dashboard/dist/assets/RN4M9u9W.js.br +0 -0
- package/dashboard/dist/assets/RN4M9u9W.js.gz +0 -0
- package/dashboard/dist/assets/VCHu272d.js +1 -0
- package/dashboard/dist/assets/VCHu272d.js.br +0 -0
- package/dashboard/dist/assets/VCHu272d.js.gz +0 -0
- package/dashboard/dist/assets/m2smti3F.js +1 -0
- package/dashboard/dist/assets/m2smti3F.js.br +0 -0
- package/dashboard/dist/assets/m2smti3F.js.gz +0 -0
- package/dashboard/dist/assets/{CV0sWMbv.js → nra1yvJX.js} +1 -1
- package/dashboard/dist/assets/nra1yvJX.js.br +0 -0
- package/dashboard/dist/assets/nra1yvJX.js.gz +0 -0
- package/dashboard/dist/assets/qLX6NZ-J.js +1 -0
- package/dashboard/dist/assets/qLX6NZ-J.js.br +0 -0
- package/dashboard/dist/assets/qLX6NZ-J.js.gz +0 -0
- package/dashboard/dist/index.html +2 -2
- package/dashboard/dist/index.html.br +0 -0
- package/dashboard/dist/index.html.gz +0 -0
- package/dist/agent-run-store.js +162 -24
- package/dist/cli/orgx.d.ts +3 -0
- package/dist/config/resolution.d.ts +7 -0
- package/dist/config/resolution.js +13 -5
- package/dist/contracts/onboarding-state.d.ts +2 -0
- package/dist/contracts/onboarding-state.js +23 -0
- package/dist/contracts/shared-types.d.ts +17 -0
- package/dist/http/helpers/auto-continue-engine.d.ts +23 -0
- package/dist/http/helpers/auto-continue-engine.js +233 -53
- package/dist/http/helpers/autopilot-runtime.js +5 -1
- package/dist/http/helpers/autopilot-slice-utils.js +25 -1
- package/dist/http/helpers/decision-mapper.d.ts +1 -0
- package/dist/http/helpers/decision-mapper.js +19 -2
- package/dist/http/helpers/dispatch-lifecycle.js +3 -0
- package/dist/http/helpers/mission-control.d.ts +1 -0
- package/dist/http/helpers/mission-control.js +5 -2
- package/dist/http/helpers/slice-run-projections.d.ts +27 -0
- package/dist/http/helpers/slice-run-projections.js +198 -10
- package/dist/http/helpers/triage-mapper.js +220 -6
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +92 -45
- package/dist/http/router.js +64 -9
- package/dist/http/routes/live-legacy.d.ts +19 -2
- package/dist/http/routes/live-legacy.js +110 -27
- package/dist/http/routes/live-snapshot.d.ts +16 -2
- package/dist/http/routes/live-snapshot.js +169 -25
- package/dist/http/routes/mission-control-actions.js +28 -0
- package/dist/http/routes/mission-control-read.d.ts +4 -0
- package/dist/http/routes/mission-control-read.js +67 -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 +179 -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,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
|
|
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
|
|
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
|
|
486
|
-
recommendedAction
|
|
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,
|
package/dist/http/index.d.ts
CHANGED
package/dist/http/index.js
CHANGED
|
@@ -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
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
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
|
-
|
|
450
|
-
snapshotResponseCache.set(key, {
|
|
451
|
-
expiresAt: now + SNAPSHOT_RESPONSE_CACHE_TTL_MS,
|
|
447
|
+
writeMaterializedSnapshot(key, payload, {
|
|
452
448
|
generation: snapshotCacheGeneration,
|
|
453
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -2962,12 +2973,14 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
|
|
|
2962
2973
|
// best effort prewarm only
|
|
2963
2974
|
});
|
|
2964
2975
|
};
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
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,
|
|
@@ -3511,6 +3524,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
|
|
|
3511
3524
|
outboxReadAllItems: () => outboxAdapter.readAllItems(),
|
|
3512
3525
|
toLocalLiveActivity,
|
|
3513
3526
|
loadLocalTurnDetail,
|
|
3527
|
+
summarizeActivityHeadline,
|
|
3514
3528
|
sendJson,
|
|
3515
3529
|
safeErrorMessage,
|
|
3516
3530
|
sendHtml,
|
|
@@ -3539,6 +3553,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
|
|
|
3539
3553
|
parsePositiveInt,
|
|
3540
3554
|
readSnapshotResponseCache,
|
|
3541
3555
|
writeSnapshotResponseCache,
|
|
3556
|
+
getSnapshotCacheGeneration,
|
|
3542
3557
|
safeErrorMessage,
|
|
3543
3558
|
readAgentContexts,
|
|
3544
3559
|
getScopedAgentIds,
|
|
@@ -3596,6 +3611,8 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
|
|
|
3596
3611
|
listChatThreads: ({ commandCenterId, initiativeId, limit, offset }) => listChatThreads({ commandCenterId, initiativeId, limit, offset }),
|
|
3597
3612
|
getCanonicalAutopilotState,
|
|
3598
3613
|
sendJson,
|
|
3614
|
+
securityHeaders: SECURITY_HEADERS,
|
|
3615
|
+
corsHeaders: CORS_HEADERS,
|
|
3599
3616
|
});
|
|
3600
3617
|
registerRuntimeHookRoutes(apiRouter, {
|
|
3601
3618
|
parseJsonRequest,
|
|
@@ -3679,10 +3696,11 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
|
|
|
3679
3696
|
const keys = [...scopedKeys, ...fallbackKeys];
|
|
3680
3697
|
const seen = new Set();
|
|
3681
3698
|
const mapped = [];
|
|
3682
|
-
const deriveFailureType = (eventNameRaw, actionTypeRaw) => {
|
|
3699
|
+
const deriveFailureType = (eventNameRaw, actionTypeRaw, reasonRaw) => {
|
|
3683
3700
|
const eventName = (eventNameRaw ?? "").trim().toLowerCase();
|
|
3684
3701
|
const actionType = (actionTypeRaw ?? "").trim().toLowerCase();
|
|
3685
|
-
const
|
|
3702
|
+
const reason = (reasonRaw ?? "").trim().toLowerCase();
|
|
3703
|
+
const signature = `${eventName} ${actionType} ${reason}`;
|
|
3686
3704
|
if (!signature.trim())
|
|
3687
3705
|
return null;
|
|
3688
3706
|
if (signature.includes("status_updates_buffered"))
|
|
@@ -3707,6 +3725,18 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
|
|
|
3707
3725
|
return "budget_exhausted";
|
|
3708
3726
|
if (signature.includes("stale_blocked_workstream"))
|
|
3709
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
|
+
}
|
|
3710
3740
|
return null;
|
|
3711
3741
|
};
|
|
3712
3742
|
try {
|
|
@@ -3724,7 +3754,20 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
|
|
|
3724
3754
|
const metadataRecord = activityRecord.metadata && typeof activityRecord.metadata === "object"
|
|
3725
3755
|
? activityRecord.metadata
|
|
3726
3756
|
: {};
|
|
3727
|
-
const
|
|
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);
|
|
3728
3771
|
if (!failureType)
|
|
3729
3772
|
continue;
|
|
3730
3773
|
const runId = pickString(metadataRecord, ["run_id", "source_run_id"]) ?? pickString(activityRecord, ["runId"]);
|
|
@@ -3743,9 +3786,9 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
|
|
|
3743
3786
|
mapped.push({
|
|
3744
3787
|
id: dedupeId,
|
|
3745
3788
|
failureType,
|
|
3746
|
-
reason:
|
|
3747
|
-
|
|
3748
|
-
|
|
3789
|
+
reason: reasonText,
|
|
3790
|
+
provider: pickString(metadataRecord, ["provider"]) ??
|
|
3791
|
+
pickString(blockerRecord ?? {}, ["provider"]),
|
|
3749
3792
|
initiativeId,
|
|
3750
3793
|
initiativeTitle: pickString(metadataRecord, ["initiative_title"]) ??
|
|
3751
3794
|
pickString(activityRecord, ["initiativeTitle"]),
|
|
@@ -3759,8 +3802,12 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
|
|
|
3759
3802
|
domain: pickString(metadataRecord, ["domain", "executor_domain"]),
|
|
3760
3803
|
sourceSystem: pickString(metadataRecord, ["source_system", "source"]) ?? "openclaw",
|
|
3761
3804
|
runId,
|
|
3762
|
-
logPath: pickString(metadataRecord, ["log_path"])
|
|
3763
|
-
|
|
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"]),
|
|
3764
3811
|
metadata: metadataRecord,
|
|
3765
3812
|
timestamp: timestamp ?? undefined,
|
|
3766
3813
|
});
|
package/dist/http/router.js
CHANGED
|
@@ -1,20 +1,75 @@
|
|
|
1
|
-
function
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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;
|