@useorgx/openclaw-plugin 0.4.9 → 0.7.0
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/README.md +35 -0
- package/dashboard/dist/assets/BJgZIVUQ.js +53 -0
- package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
- package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
- package/dashboard/dist/assets/BXWDRGm-.js +1 -0
- package/dashboard/dist/assets/BXWDRGm-.js.br +0 -0
- package/dashboard/dist/assets/BXWDRGm-.js.gz +0 -0
- package/dashboard/dist/assets/BgOYB78t.js +4 -0
- package/dashboard/dist/assets/BgOYB78t.js.br +0 -0
- package/dashboard/dist/assets/BgOYB78t.js.gz +0 -0
- package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
- package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
- package/dashboard/dist/assets/CE38zU4U.js +1 -0
- package/dashboard/dist/assets/CE38zU4U.js.br +0 -0
- package/dashboard/dist/assets/CE38zU4U.js.gz +0 -0
- package/dashboard/dist/assets/CFGKRAzG.js +1 -0
- package/dashboard/dist/assets/CFGKRAzG.js.br +0 -0
- package/dashboard/dist/assets/CFGKRAzG.js.gz +0 -0
- package/dashboard/dist/assets/CGGR2GZh.js +1 -0
- package/dashboard/dist/assets/CGGR2GZh.js.br +0 -0
- package/dashboard/dist/assets/CGGR2GZh.js.gz +0 -0
- package/dashboard/dist/assets/CL_wXqR7.js +1 -0
- package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
- package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
- package/dashboard/dist/assets/CPFiTmlw.js +8 -0
- package/dashboard/dist/assets/CPFiTmlw.js.br +0 -0
- package/dashboard/dist/assets/CPFiTmlw.js.gz +0 -0
- package/dashboard/dist/assets/CZZTvkQZ.js +1 -0
- package/dashboard/dist/assets/CZZTvkQZ.js.br +0 -0
- package/dashboard/dist/assets/CZZTvkQZ.js.gz +0 -0
- package/dashboard/dist/assets/{CpJsfbXo.js → CxQ08qFN.js} +2 -2
- package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
- package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
- package/dashboard/dist/assets/D-bf6hEI.js +213 -0
- package/dashboard/dist/assets/D-bf6hEI.js.br +0 -0
- package/dashboard/dist/assets/D-bf6hEI.js.gz +0 -0
- package/dashboard/dist/assets/DG6y9wJI.js +2 -0
- package/dashboard/dist/assets/DG6y9wJI.js.br +0 -0
- package/dashboard/dist/assets/DG6y9wJI.js.gz +0 -0
- package/dashboard/dist/assets/DNxKz-GV.js +1 -0
- package/dashboard/dist/assets/DNxKz-GV.js.br +0 -0
- package/dashboard/dist/assets/DNxKz-GV.js.gz +0 -0
- package/dashboard/dist/assets/DW_rKUic.js +11 -0
- package/dashboard/dist/assets/DW_rKUic.js.br +0 -0
- package/dashboard/dist/assets/DW_rKUic.js.gz +0 -0
- package/dashboard/dist/assets/DbNoijHm.js +1 -0
- package/dashboard/dist/assets/DbNoijHm.js.br +0 -0
- package/dashboard/dist/assets/DbNoijHm.js.gz +0 -0
- package/dashboard/dist/assets/DjcdE6jC.js +2 -0
- package/dashboard/dist/assets/DjcdE6jC.js.br +0 -0
- package/dashboard/dist/assets/DjcdE6jC.js.gz +0 -0
- package/dashboard/dist/assets/FZYuCDnt.js +1 -0
- package/dashboard/dist/assets/FZYuCDnt.js.br +0 -0
- package/dashboard/dist/assets/FZYuCDnt.js.gz +0 -0
- package/dashboard/dist/assets/PAUiij_z.js +1 -0
- package/dashboard/dist/assets/PAUiij_z.js.br +0 -0
- package/dashboard/dist/assets/PAUiij_z.js.gz +0 -0
- package/dashboard/dist/assets/cNrhgGc1.js +8 -0
- package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
- package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
- package/dashboard/dist/assets/h5biQs2I.css +1 -0
- package/dashboard/dist/assets/h5biQs2I.css.br +0 -0
- package/dashboard/dist/assets/h5biQs2I.css.gz +0 -0
- package/dashboard/dist/assets/ic2FaMnh.js +1 -0
- package/dashboard/dist/assets/ic2FaMnh.js.br +0 -0
- package/dashboard/dist/assets/ic2FaMnh.js.gz +0 -0
- package/dashboard/dist/assets/nByHNHoW.js +1 -0
- package/dashboard/dist/assets/nByHNHoW.js.br +0 -0
- package/dashboard/dist/assets/nByHNHoW.js.gz +0 -0
- package/dashboard/dist/assets/qm8xLgv-.css +1 -0
- package/dashboard/dist/assets/qm8xLgv-.css.br +0 -0
- package/dashboard/dist/assets/qm8xLgv-.css.gz +0 -0
- package/dashboard/dist/assets/tS9mbYZi.js +1 -0
- package/dashboard/dist/assets/tS9mbYZi.js.br +0 -0
- package/dashboard/dist/assets/tS9mbYZi.js.gz +0 -0
- package/dashboard/dist/brand/anthropic-mark.svg.br +0 -0
- package/dashboard/dist/brand/anthropic-mark.svg.gz +0 -0
- package/dashboard/dist/brand/openai-mark.svg.br +0 -0
- package/dashboard/dist/brand/openai-mark.svg.gz +0 -0
- package/dashboard/dist/brand/openclaw-mark.svg.br +0 -0
- package/dashboard/dist/brand/openclaw-mark.svg.gz +0 -0
- package/dashboard/dist/brand/xandy-orchestrator.png +0 -0
- package/dashboard/dist/index.html +7 -5
- package/dashboard/dist/index.html.br +0 -0
- package/dashboard/dist/index.html.gz +0 -0
- package/dist/activity-actor-fields.js +26 -4
- package/dist/activity-store.js +34 -8
- package/dist/agent-context-store.js +79 -17
- package/dist/agent-run-store.js +44 -3
- package/dist/agent-suite.d.ts +9 -0
- package/dist/agent-suite.js +149 -9
- package/dist/artifacts/artifact-domain-schemas.d.ts +66 -0
- package/dist/artifacts/artifact-domain-schemas.js +357 -0
- package/dist/artifacts/register-artifact.d.ts +4 -3
- package/dist/artifacts/register-artifact.js +170 -57
- package/dist/chat-store.d.ts +157 -0
- package/dist/chat-store.js +586 -0
- package/dist/cli/orgx.js +11 -0
- package/dist/contracts/client.d.ts +43 -3
- package/dist/contracts/client.js +159 -30
- package/dist/contracts/retro-schema.d.ts +81 -0
- package/dist/contracts/retro-schema.js +80 -0
- package/dist/contracts/shared-types.d.ts +159 -0
- package/dist/contracts/shared-types.js +177 -1
- package/dist/contracts/skill-pack-schema.d.ts +192 -0
- package/dist/contracts/skill-pack-schema.js +180 -0
- package/dist/contracts/types.d.ts +227 -2
- package/dist/entities/auto-assignment.js +43 -17
- package/dist/event-sanitization.d.ts +11 -0
- package/dist/event-sanitization.js +113 -0
- package/dist/fs-utils.js +13 -1
- package/dist/gateway-watchdog.d.ts +5 -0
- package/dist/gateway-watchdog.js +50 -0
- package/dist/hooks/post-reporting-event.mjs +1 -5
- package/dist/http/helpers/activity-headline.js +13 -132
- package/dist/http/helpers/auto-continue-engine.d.ts +198 -10
- package/dist/http/helpers/auto-continue-engine.js +2531 -186
- package/dist/http/helpers/autopilot-operations.d.ts +19 -0
- package/dist/http/helpers/autopilot-operations.js +182 -31
- package/dist/http/helpers/autopilot-runtime.d.ts +1 -0
- package/dist/http/helpers/autopilot-runtime.js +308 -20
- package/dist/http/helpers/autopilot-slice-utils.d.ts +18 -0
- package/dist/http/helpers/autopilot-slice-utils.js +516 -93
- package/dist/http/helpers/decision-mapper.d.ts +40 -0
- package/dist/http/helpers/decision-mapper.js +223 -7
- package/dist/http/helpers/dispatch-lifecycle.d.ts +19 -2
- package/dist/http/helpers/dispatch-lifecycle.js +242 -37
- package/dist/http/helpers/kickoff-context.js +74 -0
- package/dist/http/helpers/llm-client.d.ts +47 -0
- package/dist/http/helpers/llm-client.js +256 -0
- package/dist/http/helpers/mission-control.d.ts +102 -3
- package/dist/http/helpers/mission-control.js +498 -9
- package/dist/http/helpers/sentinel-catalog.d.ts +23 -0
- package/dist/http/helpers/sentinel-catalog.js +193 -0
- package/dist/http/helpers/session-classification.d.ts +9 -0
- package/dist/http/helpers/session-classification.js +564 -0
- package/dist/http/helpers/slice-experience-v2.d.ts +137 -0
- package/dist/http/helpers/slice-experience-v2.js +677 -0
- package/dist/http/helpers/slice-run-projections.d.ts +72 -0
- package/dist/http/helpers/slice-run-projections.js +860 -0
- package/dist/http/helpers/triage-mapper.d.ts +43 -0
- package/dist/http/helpers/triage-mapper.js +549 -0
- package/dist/http/helpers/value-utils.js +7 -2
- package/dist/http/helpers/workspace-scope.d.ts +15 -0
- package/dist/http/helpers/workspace-scope.js +170 -0
- package/dist/http/index.js +1354 -97
- package/dist/http/routes/agent-suite.d.ts +9 -0
- package/dist/http/routes/agent-suite.js +207 -8
- package/dist/http/routes/agents-catalog.js +64 -19
- package/dist/http/routes/chat.d.ts +19 -0
- package/dist/http/routes/chat.js +522 -0
- package/dist/http/routes/decision-actions.d.ts +8 -1
- package/dist/http/routes/decision-actions.js +42 -5
- package/dist/http/routes/dispatch-gateway-envelope.d.ts +25 -0
- package/dist/http/routes/dispatch-gateway-envelope.js +26 -0
- package/dist/http/routes/entities.d.ts +16 -0
- package/dist/http/routes/entities.js +294 -6
- package/dist/http/routes/live-legacy.d.ts +5 -0
- package/dist/http/routes/live-legacy.js +23 -509
- package/dist/http/routes/live-misc.d.ts +12 -0
- package/dist/http/routes/live-misc.js +251 -31
- package/dist/http/routes/live-snapshot.d.ts +48 -2
- package/dist/http/routes/live-snapshot.js +638 -19
- package/dist/http/routes/live-terminal.d.ts +11 -0
- package/dist/http/routes/live-terminal.js +261 -0
- package/dist/http/routes/live-triage.d.ts +61 -0
- package/dist/http/routes/live-triage.js +248 -0
- package/dist/http/routes/mission-control-actions.d.ts +49 -1
- package/dist/http/routes/mission-control-actions.js +1334 -84
- package/dist/http/routes/mission-control-read.d.ts +48 -3
- package/dist/http/routes/mission-control-read.js +1593 -20
- package/dist/http/routes/realtime-orchestrator.d.ts +10 -0
- package/dist/http/routes/realtime-orchestrator.js +74 -0
- package/dist/http/routes/run-control.d.ts +5 -2
- package/dist/http/routes/run-control.js +10 -0
- package/dist/http/routes/sentinels-catalog.d.ts +7 -0
- package/dist/http/routes/sentinels-catalog.js +24 -0
- package/dist/http/routes/summary.js +10 -3
- package/dist/http/routes/usage.d.ts +24 -0
- package/dist/http/routes/usage.js +362 -0
- package/dist/http/routes/work-artifacts.js +28 -9
- package/dist/index.js +165 -27
- package/dist/local-openclaw.js +29 -6
- package/dist/mcp-client-setup.js +3 -3
- package/dist/mcp-http-handler.js +33 -59
- package/dist/next-up-queue-store.d.ts +16 -1
- package/dist/next-up-queue-store.js +89 -7
- package/dist/outbox.d.ts +5 -0
- package/dist/outbox.js +113 -9
- package/dist/paths.js +24 -5
- package/dist/reporting/rollups.d.ts +53 -0
- package/dist/reporting/rollups.js +148 -0
- package/dist/retro/domain-templates.d.ts +45 -0
- package/dist/retro/domain-templates.js +297 -0
- package/dist/retro/quality-rubric.d.ts +33 -0
- package/dist/retro/quality-rubric.js +213 -0
- package/dist/runtime-cleanup.d.ts +18 -0
- package/dist/runtime-cleanup.js +87 -0
- package/dist/services/background.d.ts +11 -0
- package/dist/services/background.js +22 -0
- package/dist/services/experiment-randomization.d.ts +21 -0
- package/dist/services/experiment-randomization.js +63 -0
- package/dist/skill-pack-state.d.ts +36 -5
- package/dist/skill-pack-state.js +273 -29
- package/dist/sync/local-agent-telemetry.d.ts +13 -0
- package/dist/sync/local-agent-telemetry.js +128 -0
- package/dist/sync/outbox-replay.js +131 -24
- package/dist/team-context-store.d.ts +23 -0
- package/dist/team-context-store.js +116 -0
- package/dist/telemetry/posthog.js +4 -2
- package/dist/tools/core-tools.d.ts +10 -14
- package/dist/tools/core-tools.js +1289 -24
- package/dist/types.d.ts +2 -0
- package/dist/types.js +2 -0
- package/dist/worker-supervisor.js +23 -0
- package/package.json +14 -4
- package/dashboard/dist/assets/B3ziCA02.js +0 -8
- package/dashboard/dist/assets/B5NEElEI.css +0 -1
- package/dashboard/dist/assets/BhapSNAs.js +0 -215
- package/dashboard/dist/assets/iFdvE7lx.js +0 -1
- package/dashboard/dist/assets/jRJsmpYM.js +0 -1
- package/dashboard/dist/assets/sAhvFnpk.js +0 -4
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const KNOWN_DOMAINS = [
|
|
2
|
+
"engineering",
|
|
3
|
+
"product",
|
|
4
|
+
"design",
|
|
5
|
+
"marketing",
|
|
6
|
+
"sales",
|
|
7
|
+
"operations",
|
|
8
|
+
"orchestration",
|
|
9
|
+
];
|
|
10
|
+
const IDLE_MIRROR_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
11
|
+
function inferDomainFromAgentId(agentId) {
|
|
12
|
+
const normalized = agentId.trim().toLowerCase();
|
|
13
|
+
for (const domain of KNOWN_DOMAINS) {
|
|
14
|
+
if (normalized.includes(domain))
|
|
15
|
+
return domain;
|
|
16
|
+
}
|
|
17
|
+
return "operations";
|
|
18
|
+
}
|
|
19
|
+
function inferNameFromAgentId(agentId) {
|
|
20
|
+
const cleaned = agentId
|
|
21
|
+
.trim()
|
|
22
|
+
.replace(/[_-]+/g, " ")
|
|
23
|
+
.replace(/\s+/g, " ");
|
|
24
|
+
if (!cleaned)
|
|
25
|
+
return "Local Agent";
|
|
26
|
+
return cleaned
|
|
27
|
+
.split(" ")
|
|
28
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
29
|
+
.join(" ");
|
|
30
|
+
}
|
|
31
|
+
function toEpoch(value) {
|
|
32
|
+
const epoch = Date.parse(value);
|
|
33
|
+
return Number.isFinite(epoch) ? epoch : 0;
|
|
34
|
+
}
|
|
35
|
+
function normalizeMirror(input) {
|
|
36
|
+
const id = typeof input.id === "string" ? input.id.trim() : "";
|
|
37
|
+
if (!id)
|
|
38
|
+
return null;
|
|
39
|
+
const status = input.status === "active" || input.status === "throttled" ? input.status : "idle";
|
|
40
|
+
const name = typeof input.name === "string" && input.name.trim().length > 0
|
|
41
|
+
? input.name.trim()
|
|
42
|
+
: inferNameFromAgentId(id);
|
|
43
|
+
const domain = typeof input.domain === "string" && input.domain.trim().length > 0
|
|
44
|
+
? input.domain.trim()
|
|
45
|
+
: inferDomainFromAgentId(id);
|
|
46
|
+
return {
|
|
47
|
+
id,
|
|
48
|
+
name,
|
|
49
|
+
domain,
|
|
50
|
+
status,
|
|
51
|
+
currentTask: input.currentTask,
|
|
52
|
+
lastActive: input.lastActive,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function buildLocalAgentMirrorsFromSnapshot(input) {
|
|
56
|
+
const latestByAgent = new Map();
|
|
57
|
+
for (const source of input.agents ?? []) {
|
|
58
|
+
const normalized = normalizeMirror(source);
|
|
59
|
+
if (!normalized)
|
|
60
|
+
continue;
|
|
61
|
+
const previous = latestByAgent.get(normalized.id);
|
|
62
|
+
if (!previous ||
|
|
63
|
+
toEpoch(normalized.lastActive ?? "") >= toEpoch(previous.lastActive ?? "")) {
|
|
64
|
+
latestByAgent.set(normalized.id, normalized);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return Array.from(latestByAgent.values()).sort((a, b) => a.id.localeCompare(b.id));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Derive live local agent states from active OpenClaw runs so sync can mirror
|
|
71
|
+
* local runtime telemetry into OrgX.
|
|
72
|
+
*/
|
|
73
|
+
export function buildLocalSyncAgentsFromRuns(input) {
|
|
74
|
+
const latestRunningByAgent = new Map();
|
|
75
|
+
const latestStoppedByAgent = new Map();
|
|
76
|
+
const mergedByAgent = new Map();
|
|
77
|
+
const now = Date.now();
|
|
78
|
+
for (const mirror of buildLocalAgentMirrorsFromSnapshot({ agents: input.mirrors })) {
|
|
79
|
+
mergedByAgent.set(mirror.id, mirror);
|
|
80
|
+
}
|
|
81
|
+
for (const run of Object.values(input.runs ?? {})) {
|
|
82
|
+
if (!run)
|
|
83
|
+
continue;
|
|
84
|
+
const agentId = run.agentId?.trim();
|
|
85
|
+
if (!agentId)
|
|
86
|
+
continue;
|
|
87
|
+
const isRunning = run.status === "running";
|
|
88
|
+
const index = isRunning ? latestRunningByAgent : latestStoppedByAgent;
|
|
89
|
+
const runTimestamp = isRunning ? toEpoch(run.startedAt) : toEpoch(run.stoppedAt ?? run.startedAt);
|
|
90
|
+
const previous = index.get(agentId);
|
|
91
|
+
const previousTimestamp = previous
|
|
92
|
+
? toEpoch(previous.status === "running" ? previous.startedAt : previous.stoppedAt ?? previous.startedAt)
|
|
93
|
+
: 0;
|
|
94
|
+
if (!previous || runTimestamp >= previousTimestamp) {
|
|
95
|
+
index.set(agentId, run);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
for (const [agentId, run] of latestRunningByAgent) {
|
|
99
|
+
mergedByAgent.set(agentId, {
|
|
100
|
+
id: agentId,
|
|
101
|
+
name: inferNameFromAgentId(agentId),
|
|
102
|
+
domain: inferDomainFromAgentId(agentId),
|
|
103
|
+
status: "active",
|
|
104
|
+
currentTask: run.taskId ?? undefined,
|
|
105
|
+
lastActive: run.startedAt,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
for (const [agentId, run] of latestStoppedByAgent) {
|
|
109
|
+
if (latestRunningByAgent.has(agentId))
|
|
110
|
+
continue;
|
|
111
|
+
const lastActive = run.stoppedAt ?? run.startedAt;
|
|
112
|
+
const idleAgeMs = now - toEpoch(lastActive);
|
|
113
|
+
if (!Number.isFinite(idleAgeMs) || idleAgeMs < 0 || idleAgeMs > IDLE_MIRROR_MAX_AGE_MS) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const existing = mergedByAgent.get(agentId);
|
|
117
|
+
if (existing && toEpoch(existing.lastActive ?? "") > toEpoch(lastActive))
|
|
118
|
+
continue;
|
|
119
|
+
mergedByAgent.set(agentId, {
|
|
120
|
+
id: agentId,
|
|
121
|
+
name: existing?.name ?? inferNameFromAgentId(agentId),
|
|
122
|
+
domain: existing?.domain ?? inferDomainFromAgentId(agentId),
|
|
123
|
+
status: "idle",
|
|
124
|
+
lastActive,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return Array.from(mergedByAgent.values()).sort((a, b) => a.id.localeCompare(b.id));
|
|
128
|
+
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { registerArtifact } from "../artifacts/register-artifact.js";
|
|
2
|
-
import { readOutbox, readOutboxSummary, replaceOutbox } from "../outbox.js";
|
|
2
|
+
import { appendOutboxDeadLetter, readOutbox, readOutboxSummary, replaceOutbox, } from "../outbox.js";
|
|
3
3
|
import { extractProgressOutboxMessage } from "../reporting/outbox-replay.js";
|
|
4
|
+
import { RETRO_ARTIFACT_SCHEMA_VERSION } from "../contracts/retro-schema.js";
|
|
5
|
+
import { classifyOutboxReplaySkip } from "../event-sanitization.js";
|
|
6
|
+
const OUTBOX_MAX_REPLAY_FAILURES = (() => {
|
|
7
|
+
const raw = Number(process.env.ORGX_OUTBOX_MAX_REPLAY_FAILURES ?? "");
|
|
8
|
+
if (!Number.isFinite(raw))
|
|
9
|
+
return 3;
|
|
10
|
+
return Math.max(1, Math.min(20, Math.floor(raw)));
|
|
11
|
+
})();
|
|
4
12
|
export function createOutboxReplayer(deps) {
|
|
5
13
|
const { client, logger, toErrorMessage, stableHash, resolveReportingContext, pickStringField, pickStringArrayField, toReportingPhase, parseRetroEntityType, isUuid, } = deps;
|
|
6
14
|
async function replayOutboxEvent(event) {
|
|
@@ -19,6 +27,78 @@ export function createOutboxReplayer(deps) {
|
|
|
19
27
|
}
|
|
20
28
|
return { run_id: undefined, correlation_id: undefined };
|
|
21
29
|
}
|
|
30
|
+
function normalizeRetro(payload) {
|
|
31
|
+
const retro = payload.retro && typeof payload.retro === "object" && !Array.isArray(payload.retro)
|
|
32
|
+
? payload.retro
|
|
33
|
+
: null;
|
|
34
|
+
const trimAndClamp = (value, maxLength) => value.trim().slice(0, maxLength);
|
|
35
|
+
const summary = retro && typeof retro.summary === "string"
|
|
36
|
+
? trimAndClamp(retro.summary, 4000)
|
|
37
|
+
: "";
|
|
38
|
+
if (!retro || !summary) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const normalizeStringList = (value) => {
|
|
42
|
+
if (!Array.isArray(value))
|
|
43
|
+
return undefined;
|
|
44
|
+
const normalized = value
|
|
45
|
+
.filter((item) => typeof item === "string")
|
|
46
|
+
.map((item) => trimAndClamp(item, 1000))
|
|
47
|
+
.filter((item) => item.length > 0)
|
|
48
|
+
.slice(0, 25);
|
|
49
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
50
|
+
};
|
|
51
|
+
const pickRetroStringList = (snakeCaseKey, camelCaseKey) => normalizeStringList(retro[snakeCaseKey]) ?? normalizeStringList(retro[camelCaseKey]);
|
|
52
|
+
const followUpsRaw = Array.isArray(retro.follow_ups)
|
|
53
|
+
? retro.follow_ups
|
|
54
|
+
: Array.isArray(retro.followUps)
|
|
55
|
+
? retro.followUps
|
|
56
|
+
: [];
|
|
57
|
+
const followUps = [];
|
|
58
|
+
for (const candidate of followUpsRaw) {
|
|
59
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const title = typeof candidate.title === "string"
|
|
63
|
+
? trimAndClamp(candidate.title, 500)
|
|
64
|
+
: "";
|
|
65
|
+
if (!title) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const priorityRaw = typeof candidate.priority === "string"
|
|
69
|
+
? candidate.priority.trim().toLowerCase()
|
|
70
|
+
: "";
|
|
71
|
+
const priority = priorityRaw === "p0" || priorityRaw === "p1" || priorityRaw === "p2"
|
|
72
|
+
? priorityRaw
|
|
73
|
+
: undefined;
|
|
74
|
+
const reason = typeof candidate.reason === "string"
|
|
75
|
+
? trimAndClamp(candidate.reason, 2000)
|
|
76
|
+
: "";
|
|
77
|
+
const normalizedFollowUp = { title };
|
|
78
|
+
if (priority) {
|
|
79
|
+
normalizedFollowUp.priority = priority;
|
|
80
|
+
}
|
|
81
|
+
if (reason) {
|
|
82
|
+
normalizedFollowUp.reason = reason;
|
|
83
|
+
}
|
|
84
|
+
followUps.push(normalizedFollowUp);
|
|
85
|
+
if (followUps.length >= 25) {
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const signals = retro.signals && typeof retro.signals === "object" && !Array.isArray(retro.signals)
|
|
90
|
+
? retro.signals
|
|
91
|
+
: undefined;
|
|
92
|
+
return {
|
|
93
|
+
schema_version: RETRO_ARTIFACT_SCHEMA_VERSION,
|
|
94
|
+
summary,
|
|
95
|
+
what_went_well: pickRetroStringList("what_went_well", "whatWentWell"),
|
|
96
|
+
what_went_wrong: pickRetroStringList("what_went_wrong", "whatWentWrong"),
|
|
97
|
+
decisions: pickRetroStringList("decisions", "keyDecisions"),
|
|
98
|
+
follow_ups: followUps.length > 0 ? followUps : undefined,
|
|
99
|
+
signals,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
22
102
|
if (event.type === "progress") {
|
|
23
103
|
const message = extractProgressOutboxMessage(payload);
|
|
24
104
|
if (!message) {
|
|
@@ -68,20 +148,6 @@ export function createOutboxReplayer(deps) {
|
|
|
68
148
|
undefined,
|
|
69
149
|
metadata: baseMetadata,
|
|
70
150
|
};
|
|
71
|
-
// Locally-buffered progress events often store a local UUID in run_id. OrgX may reject
|
|
72
|
-
// unknown run IDs on replay; prefer a deterministic non-UUID correlation key instead.
|
|
73
|
-
if (emitPayload.run_id && !emitPayload.correlation_id) {
|
|
74
|
-
const replayCorrelationId = `openclaw_run_${stableHash(emitPayload.run_id).slice(0, 24)}`;
|
|
75
|
-
emitPayload = {
|
|
76
|
-
...emitPayload,
|
|
77
|
-
run_id: undefined,
|
|
78
|
-
correlation_id: replayCorrelationId,
|
|
79
|
-
metadata: {
|
|
80
|
-
...(emitPayload.metadata ?? {}),
|
|
81
|
-
replay_run_id_as_correlation: true,
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
151
|
try {
|
|
86
152
|
await client.emitActivity(emitPayload);
|
|
87
153
|
}
|
|
@@ -92,8 +158,8 @@ export function createOutboxReplayer(deps) {
|
|
|
92
158
|
// create/attach a run deterministically.
|
|
93
159
|
const msg = toErrorMessage(err);
|
|
94
160
|
if (emitPayload.run_id &&
|
|
95
|
-
|
|
96
|
-
|
|
161
|
+
/(?:^|\b)404\b/.test(msg) &&
|
|
162
|
+
/\brun\b/i.test(msg) &&
|
|
97
163
|
/not found/i.test(msg)) {
|
|
98
164
|
const replayCorrelationId = `openclaw_run_${stableHash(emitPayload.run_id).slice(0, 24)}`;
|
|
99
165
|
await client.emitActivity({
|
|
@@ -350,11 +416,8 @@ export function createOutboxReplayer(deps) {
|
|
|
350
416
|
runId: context.value.runId,
|
|
351
417
|
correlationId: context.value.correlationId,
|
|
352
418
|
});
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
: null;
|
|
356
|
-
const summary = retro && typeof retro.summary === "string" ? retro.summary.trim() : "";
|
|
357
|
-
if (!retro || !summary) {
|
|
419
|
+
const normalizedRetro = normalizeRetro(payload);
|
|
420
|
+
if (!normalizedRetro) {
|
|
358
421
|
logger.warn?.("[orgx] Dropping invalid retro outbox event", {
|
|
359
422
|
eventId: event.id,
|
|
360
423
|
});
|
|
@@ -383,7 +446,7 @@ export function createOutboxReplayer(deps) {
|
|
|
383
446
|
idempotency_key: pickStringField(payload, "idempotency_key") ??
|
|
384
447
|
pickStringField(payload, "idempotencyKey") ??
|
|
385
448
|
undefined,
|
|
386
|
-
retro:
|
|
449
|
+
retro: normalizedRetro,
|
|
387
450
|
markdown: pickStringField(payload, "markdown") ?? undefined,
|
|
388
451
|
});
|
|
389
452
|
return;
|
|
@@ -402,6 +465,13 @@ export function createOutboxReplayer(deps) {
|
|
|
402
465
|
const description = pickStringField(payload, "description") ?? undefined;
|
|
403
466
|
const externalUrl = pickStringField(payload, "url") ?? pickStringField(payload, "artifact_url") ?? null;
|
|
404
467
|
const content = pickStringField(payload, "content") ?? pickStringField(payload, "preview_markdown") ?? null;
|
|
468
|
+
const confidenceRaw = payload.confidence_score;
|
|
469
|
+
const confidenceScore = typeof confidenceRaw === "number" &&
|
|
470
|
+
Number.isFinite(confidenceRaw) &&
|
|
471
|
+
confidenceRaw >= 0 &&
|
|
472
|
+
confidenceRaw <= 1
|
|
473
|
+
? confidenceRaw
|
|
474
|
+
: null;
|
|
405
475
|
const allowedEntityType = entityType === "initiative" ||
|
|
406
476
|
entityType === "milestone" ||
|
|
407
477
|
entityType === "task" ||
|
|
@@ -423,6 +493,7 @@ export function createOutboxReplayer(deps) {
|
|
|
423
493
|
entity_id: entityId,
|
|
424
494
|
name: name.trim(),
|
|
425
495
|
artifact_type: artifactType.trim() || "other",
|
|
496
|
+
confidence_score: confidenceScore,
|
|
426
497
|
description,
|
|
427
498
|
external_url: externalUrl,
|
|
428
499
|
preview_markdown: content,
|
|
@@ -430,6 +501,7 @@ export function createOutboxReplayer(deps) {
|
|
|
430
501
|
metadata: {
|
|
431
502
|
source: "outbox_replay",
|
|
432
503
|
outbox_event_id: event.id,
|
|
504
|
+
confidence_score: confidenceScore,
|
|
433
505
|
...(payload.metadata && typeof payload.metadata === "object" && !Array.isArray(payload.metadata)
|
|
434
506
|
? payload.metadata
|
|
435
507
|
: {}),
|
|
@@ -466,16 +538,51 @@ export function createOutboxReplayer(deps) {
|
|
|
466
538
|
}
|
|
467
539
|
const remaining = [];
|
|
468
540
|
for (const event of pending) {
|
|
541
|
+
const skipReason = classifyOutboxReplaySkip(event);
|
|
542
|
+
if (skipReason) {
|
|
543
|
+
await appendOutboxDeadLetter(queue, event, `dropped_before_replay:${skipReason}`, null);
|
|
544
|
+
logger.warn?.("[orgx] Dropping non-replayable outbox event", {
|
|
545
|
+
queue,
|
|
546
|
+
eventId: event.id,
|
|
547
|
+
reason: skipReason,
|
|
548
|
+
});
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
469
551
|
try {
|
|
470
552
|
await replayOutboxEvent(event);
|
|
471
553
|
}
|
|
472
554
|
catch (err) {
|
|
473
555
|
hadReplayFailure = true;
|
|
474
556
|
lastReplayError = toErrorMessage(err);
|
|
475
|
-
|
|
557
|
+
const nextFailures = typeof event.replayFailures === "number" && Number.isFinite(event.replayFailures)
|
|
558
|
+
? Math.max(0, Math.floor(event.replayFailures)) + 1
|
|
559
|
+
: 1;
|
|
560
|
+
if (nextFailures >= OUTBOX_MAX_REPLAY_FAILURES) {
|
|
561
|
+
await appendOutboxDeadLetter(queue, {
|
|
562
|
+
...event,
|
|
563
|
+
replayFailures: nextFailures,
|
|
564
|
+
lastReplayError,
|
|
565
|
+
lastReplayAt: new Date().toISOString(),
|
|
566
|
+
}, "max_replay_failures", lastReplayError);
|
|
567
|
+
logger.warn?.("[orgx] Dead-lettering outbox event after max replay failures", {
|
|
568
|
+
queue,
|
|
569
|
+
eventId: event.id,
|
|
570
|
+
failures: nextFailures,
|
|
571
|
+
maxFailures: OUTBOX_MAX_REPLAY_FAILURES,
|
|
572
|
+
error: lastReplayError,
|
|
573
|
+
});
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
remaining.push({
|
|
577
|
+
...event,
|
|
578
|
+
replayFailures: nextFailures,
|
|
579
|
+
lastReplayError,
|
|
580
|
+
lastReplayAt: new Date().toISOString(),
|
|
581
|
+
});
|
|
476
582
|
logger.warn?.("[orgx] Outbox replay failed", {
|
|
477
583
|
queue,
|
|
478
584
|
eventId: event.id,
|
|
585
|
+
replayFailures: nextFailures,
|
|
479
586
|
error: lastReplayError,
|
|
480
587
|
});
|
|
481
588
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type TeamCompletion = {
|
|
2
|
+
domain: string;
|
|
3
|
+
task_title: string;
|
|
4
|
+
summary: string;
|
|
5
|
+
key_outputs?: string[];
|
|
6
|
+
completed_at: string;
|
|
7
|
+
};
|
|
8
|
+
export type TeamDecision = {
|
|
9
|
+
title: string;
|
|
10
|
+
resolution: string;
|
|
11
|
+
affected_domains?: string[];
|
|
12
|
+
resolved_at: string;
|
|
13
|
+
};
|
|
14
|
+
type PersistedTeamContext = {
|
|
15
|
+
updatedAt: string;
|
|
16
|
+
recent_completions: TeamCompletion[];
|
|
17
|
+
recent_decisions: TeamDecision[];
|
|
18
|
+
};
|
|
19
|
+
export declare function readTeamContext(initiativeId: string): PersistedTeamContext;
|
|
20
|
+
export declare function appendTeamCompletion(initiativeId: string, completion: TeamCompletion): void;
|
|
21
|
+
export declare function appendTeamDecision(initiativeId: string, decision: TeamDecision): void;
|
|
22
|
+
export declare function clearTeamContext(initiativeId?: string): void;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team Context Store — Local cache for cross-agent awareness.
|
|
3
|
+
*
|
|
4
|
+
* Persists recent slice completions and decisions per initiative so the
|
|
5
|
+
* auto-continue engine can provide degraded team context when the server
|
|
6
|
+
* is unreachable (offline fallback for KickoffContext.team_context).
|
|
7
|
+
*
|
|
8
|
+
* Follows the same patterns as agent-context-store.ts: bounded store,
|
|
9
|
+
* atomic writes, corrupt file recovery.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
12
|
+
import { getOrgxPluginConfigDir, getOrgxPluginConfigPath } from "./paths.js";
|
|
13
|
+
import { backupCorruptFileSync, writeJsonFileAtomicSync } from "./fs-utils.js";
|
|
14
|
+
import { clearStoreFileSync, ensureStoreDirSync, parseJsonSafe, } from "./stores/json-store.js";
|
|
15
|
+
const MAX_COMPLETIONS = 20;
|
|
16
|
+
const MAX_DECISIONS = 20;
|
|
17
|
+
const MAX_INITIATIVES = 50;
|
|
18
|
+
function storeDir() {
|
|
19
|
+
return getOrgxPluginConfigDir();
|
|
20
|
+
}
|
|
21
|
+
function storeFile() {
|
|
22
|
+
return getOrgxPluginConfigPath("team-context.json");
|
|
23
|
+
}
|
|
24
|
+
function emptyContext() {
|
|
25
|
+
return { updatedAt: new Date().toISOString(), recent_completions: [], recent_decisions: [] };
|
|
26
|
+
}
|
|
27
|
+
function emptyIndex() {
|
|
28
|
+
return { initiatives: {} };
|
|
29
|
+
}
|
|
30
|
+
function isValidIndex(value) {
|
|
31
|
+
if (!value || typeof value !== "object")
|
|
32
|
+
return false;
|
|
33
|
+
const record = value;
|
|
34
|
+
return record.initiatives !== undefined && typeof record.initiatives === "object";
|
|
35
|
+
}
|
|
36
|
+
function readIndex() {
|
|
37
|
+
const file = storeFile();
|
|
38
|
+
try {
|
|
39
|
+
if (!existsSync(file))
|
|
40
|
+
return emptyIndex();
|
|
41
|
+
const raw = readFileSync(file, "utf8");
|
|
42
|
+
const parsed = parseJsonSafe(raw);
|
|
43
|
+
if (!isValidIndex(parsed)) {
|
|
44
|
+
backupCorruptFileSync(file);
|
|
45
|
+
return emptyIndex();
|
|
46
|
+
}
|
|
47
|
+
return parsed;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return emptyIndex();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function writeIndex(index) {
|
|
54
|
+
ensureStoreDirSync(storeDir());
|
|
55
|
+
// Prune if too many initiatives.
|
|
56
|
+
const keys = Object.keys(index.initiatives);
|
|
57
|
+
if (keys.length > MAX_INITIATIVES) {
|
|
58
|
+
const sorted = keys
|
|
59
|
+
.map((k) => ({ key: k, updatedAt: index.initiatives[k]?.updatedAt ?? "" }))
|
|
60
|
+
.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
61
|
+
const keep = new Set(sorted.slice(0, MAX_INITIATIVES).map((e) => e.key));
|
|
62
|
+
for (const key of keys) {
|
|
63
|
+
if (!keep.has(key))
|
|
64
|
+
delete index.initiatives[key];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
writeJsonFileAtomicSync(storeFile(), index, 0o600);
|
|
68
|
+
}
|
|
69
|
+
export function readTeamContext(initiativeId) {
|
|
70
|
+
const id = initiativeId.trim();
|
|
71
|
+
if (!id)
|
|
72
|
+
return emptyContext();
|
|
73
|
+
const index = readIndex();
|
|
74
|
+
const ctx = index.initiatives[id];
|
|
75
|
+
return ctx ?? emptyContext();
|
|
76
|
+
}
|
|
77
|
+
export function appendTeamCompletion(initiativeId, completion) {
|
|
78
|
+
const id = initiativeId.trim();
|
|
79
|
+
if (!id)
|
|
80
|
+
return;
|
|
81
|
+
const index = readIndex();
|
|
82
|
+
const ctx = index.initiatives[id] ?? emptyContext();
|
|
83
|
+
ctx.recent_completions.push(completion);
|
|
84
|
+
if (ctx.recent_completions.length > MAX_COMPLETIONS) {
|
|
85
|
+
ctx.recent_completions = ctx.recent_completions.slice(-MAX_COMPLETIONS);
|
|
86
|
+
}
|
|
87
|
+
ctx.updatedAt = new Date().toISOString();
|
|
88
|
+
index.initiatives[id] = ctx;
|
|
89
|
+
writeIndex(index);
|
|
90
|
+
}
|
|
91
|
+
export function appendTeamDecision(initiativeId, decision) {
|
|
92
|
+
const id = initiativeId.trim();
|
|
93
|
+
if (!id)
|
|
94
|
+
return;
|
|
95
|
+
const index = readIndex();
|
|
96
|
+
const ctx = index.initiatives[id] ?? emptyContext();
|
|
97
|
+
ctx.recent_decisions.push(decision);
|
|
98
|
+
if (ctx.recent_decisions.length > MAX_DECISIONS) {
|
|
99
|
+
ctx.recent_decisions = ctx.recent_decisions.slice(-MAX_DECISIONS);
|
|
100
|
+
}
|
|
101
|
+
ctx.updatedAt = new Date().toISOString();
|
|
102
|
+
index.initiatives[id] = ctx;
|
|
103
|
+
writeIndex(index);
|
|
104
|
+
}
|
|
105
|
+
export function clearTeamContext(initiativeId) {
|
|
106
|
+
if (!initiativeId) {
|
|
107
|
+
clearStoreFileSync(storeFile());
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const id = initiativeId.trim();
|
|
111
|
+
if (!id)
|
|
112
|
+
return;
|
|
113
|
+
const index = readIndex();
|
|
114
|
+
delete index.initiatives[id];
|
|
115
|
+
writeIndex(index);
|
|
116
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const POSTHOG_DEFAULT_API_KEY = "phc_s4KPgkYEFZgvkMYw4zXG41H5FN6haVwbEWPYHfNjxOc";
|
|
2
1
|
const POSTHOG_DEFAULT_HOST = "https://us.i.posthog.com";
|
|
3
2
|
function isTruthyEnv(value) {
|
|
4
3
|
if (!value)
|
|
@@ -15,6 +14,9 @@ function isTruthyEnv(value) {
|
|
|
15
14
|
}
|
|
16
15
|
}
|
|
17
16
|
export function isOrgxTelemetryDisabled() {
|
|
17
|
+
const explicitEnable = isTruthyEnv(process.env.ORGX_TELEMETRY_ENABLED);
|
|
18
|
+
if (!explicitEnable)
|
|
19
|
+
return true;
|
|
18
20
|
return (isTruthyEnv(process.env.ORGX_TELEMETRY_DISABLED) ||
|
|
19
21
|
isTruthyEnv(process.env.OPENCLAW_TELEMETRY_DISABLED) ||
|
|
20
22
|
isTruthyEnv(process.env.POSTHOG_DISABLED));
|
|
@@ -28,7 +30,7 @@ export function resolvePosthogApiKey() {
|
|
|
28
30
|
const trimmed = fromEnv.trim();
|
|
29
31
|
if (trimmed)
|
|
30
32
|
return trimmed;
|
|
31
|
-
return
|
|
33
|
+
return null;
|
|
32
34
|
}
|
|
33
35
|
export function resolvePosthogHost() {
|
|
34
36
|
const fromEnv = process.env.ORGX_POSTHOG_HOST ??
|
|
@@ -57,20 +57,16 @@ export interface RegisterCoreToolsDeps {
|
|
|
57
57
|
ok: false;
|
|
58
58
|
error: string;
|
|
59
59
|
};
|
|
60
|
-
readSkillPackState: () =>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
checksum?: string | null;
|
|
71
|
-
} | null;
|
|
72
|
-
etag?: string | null;
|
|
73
|
-
};
|
|
60
|
+
readSkillPackState: () => import("../skill-pack-state.js").SkillPackState;
|
|
61
|
+
updateSkillPackPolicy: (input: {
|
|
62
|
+
frozen?: boolean;
|
|
63
|
+
pinnedChecksum?: string | null;
|
|
64
|
+
pinToCurrent?: boolean;
|
|
65
|
+
clearPin?: boolean;
|
|
66
|
+
}) => import("../skill-pack-state.js").SkillPackState;
|
|
67
|
+
rollbackSkillPackPolicy: (input?: {
|
|
68
|
+
auditId?: string;
|
|
69
|
+
}) => import("../skill-pack-state.js").SkillPackState;
|
|
74
70
|
randomUUID?: () => string;
|
|
75
71
|
}
|
|
76
72
|
export declare function registerCoreTools(deps: RegisterCoreToolsDeps): Map<string, RegisteredTool>;
|