@useorgx/openclaw-plugin 0.4.9 → 0.7.2
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 +77 -11
- package/dashboard/dist/assets/6mILZQ2a.js +1 -0
- package/dashboard/dist/assets/6mILZQ2a.js.br +0 -0
- package/dashboard/dist/assets/6mILZQ2a.js.gz +0 -0
- package/dashboard/dist/assets/8dksYiq4.js +2 -0
- package/dashboard/dist/assets/8dksYiq4.js.br +0 -0
- package/dashboard/dist/assets/8dksYiq4.js.gz +0 -0
- package/dashboard/dist/assets/B5zYRHc3.js +1 -0
- package/dashboard/dist/assets/B5zYRHc3.js.br +0 -0
- package/dashboard/dist/assets/B5zYRHc3.js.gz +0 -0
- package/dashboard/dist/assets/B6wPWJ35.js +1 -0
- package/dashboard/dist/assets/B6wPWJ35.js.br +0 -0
- package/dashboard/dist/assets/B6wPWJ35.js.gz +0 -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/BWEwjt1W.js +1 -0
- package/dashboard/dist/assets/BWEwjt1W.js.br +0 -0
- package/dashboard/dist/assets/BWEwjt1W.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/BzRbDCAD.css +1 -0
- package/dashboard/dist/assets/BzRbDCAD.css.br +0 -0
- package/dashboard/dist/assets/BzRbDCAD.css.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/C8uM3AX8.js +1 -0
- package/dashboard/dist/assets/C8uM3AX8.js.br +0 -0
- package/dashboard/dist/assets/C8uM3AX8.js.gz +0 -0
- package/dashboard/dist/assets/C9jy61eu.js +212 -0
- package/dashboard/dist/assets/C9jy61eu.js.br +0 -0
- package/dashboard/dist/assets/C9jy61eu.js.gz +0 -0
- package/dashboard/dist/assets/CC63EwFD.js +1 -0
- package/dashboard/dist/assets/CC63EwFD.js.br +0 -0
- package/dashboard/dist/assets/CC63EwFD.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/CZaT3ob_.js +1 -0
- package/dashboard/dist/assets/CZaT3ob_.js.br +0 -0
- package/dashboard/dist/assets/CZaT3ob_.js.gz +0 -0
- package/dashboard/dist/assets/CgaottFX.js +1 -0
- package/dashboard/dist/assets/CgaottFX.js.br +0 -0
- package/dashboard/dist/assets/CgaottFX.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/CzCxAZlW.js +1 -0
- package/dashboard/dist/assets/CzCxAZlW.js.br +0 -0
- package/dashboard/dist/assets/CzCxAZlW.js.gz +0 -0
- package/dashboard/dist/assets/D3iMTYEj.js +1 -0
- package/dashboard/dist/assets/D3iMTYEj.js.br +0 -0
- package/dashboard/dist/assets/D3iMTYEj.js.gz +0 -0
- package/dashboard/dist/assets/D8JNX8kq.js +2 -0
- package/dashboard/dist/assets/D8JNX8kq.js.br +0 -0
- package/dashboard/dist/assets/D8JNX8kq.js.gz +0 -0
- package/dashboard/dist/assets/DnA8dpj6.js +1 -0
- package/dashboard/dist/assets/DnA8dpj6.js.br +0 -0
- package/dashboard/dist/assets/DnA8dpj6.js.gz +0 -0
- package/dashboard/dist/assets/IUexzymk.js +1 -0
- package/dashboard/dist/assets/IUexzymk.js.br +0 -0
- package/dashboard/dist/assets/IUexzymk.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/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/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/rttbDbEx.js +1 -0
- package/dashboard/dist/assets/rttbDbEx.js.br +0 -0
- package/dashboard/dist/assets/rttbDbEx.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/practice-exercise-schema.d.ts +216 -0
- package/dist/contracts/practice-exercise-schema.js +314 -0
- 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 +199 -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 +247 -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/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 +3145 -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 +328 -25
- package/dist/http/helpers/autopilot-slice-utils.d.ts +18 -0
- package/dist/http/helpers/autopilot-slice-utils.js +514 -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 +104 -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 +877 -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 +1420 -105
- package/dist/http/routes/agent-suite.d.ts +9 -0
- package/dist/http/routes/agent-suite.js +294 -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 +232 -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 +49 -2
- package/dist/http/routes/live-snapshot.js +653 -23
- package/dist/http/routes/live-terminal.d.ts +11 -0
- package/dist/http/routes/live-terminal.js +154 -0
- package/dist/http/routes/live-triage.d.ts +61 -0
- package/dist/http/routes/live-triage.js +192 -0
- package/dist/http/routes/mission-control-actions.d.ts +49 -1
- package/dist/http/routes/mission-control-actions.js +1246 -84
- package/dist/http/routes/mission-control-read.d.ts +48 -3
- package/dist/http/routes/mission-control-read.js +1658 -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.d.ts +3 -0
- package/dist/mcp-http-handler.js +34 -60
- 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 +36 -5
- package/dist/reporting/rollups.d.ts +41 -0
- package/dist/reporting/rollups.js +113 -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 +20 -6
- 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
|
@@ -18,6 +18,28 @@ export function registerSyncService(deps) {
|
|
|
18
18
|
stop: async () => {
|
|
19
19
|
deps.setSyncServiceRunning(false);
|
|
20
20
|
deps.clearSyncTimer();
|
|
21
|
+
if (deps.stopTrackedAgentRuns) {
|
|
22
|
+
try {
|
|
23
|
+
const result = await deps.stopTrackedAgentRuns();
|
|
24
|
+
deps.api.log?.info?.("[orgx] Stopped tracked agent runs on plugin stop", result);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
deps.api.log?.info?.("[orgx] Failed stopping tracked agent runs on plugin stop", {
|
|
28
|
+
error: err instanceof Error ? err.message : String(err),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (deps.stopGatewayWatchdog) {
|
|
33
|
+
try {
|
|
34
|
+
const result = await deps.stopGatewayWatchdog();
|
|
35
|
+
deps.api.log?.info?.("[orgx] Gateway watchdog teardown on plugin stop", result);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
deps.api.log?.info?.("[orgx] Failed stopping watchdog on plugin stop", {
|
|
39
|
+
error: err instanceof Error ? err.message : String(err),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
21
43
|
},
|
|
22
44
|
});
|
|
23
45
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface RandomizationArm {
|
|
2
|
+
id: string;
|
|
3
|
+
weight: number;
|
|
4
|
+
}
|
|
5
|
+
export interface RandomizationRequest {
|
|
6
|
+
experimentId: string;
|
|
7
|
+
subjectKey: string;
|
|
8
|
+
channel: string;
|
|
9
|
+
arms: RandomizationArm[];
|
|
10
|
+
seed?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface RandomizationResult {
|
|
13
|
+
experimentId: string;
|
|
14
|
+
subjectKey: string;
|
|
15
|
+
channel: string;
|
|
16
|
+
assignmentKey: string;
|
|
17
|
+
exposureKey: string;
|
|
18
|
+
bucket: number;
|
|
19
|
+
armId: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function randomizeExperimentAssignment(request: RandomizationRequest): RandomizationResult;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { stableHash } from "../hash-utils.js";
|
|
2
|
+
const MAX_UINT53 = 0x1fffffffffffff;
|
|
3
|
+
export function randomizeExperimentAssignment(request) {
|
|
4
|
+
const experimentId = sanitizeIdentifier(request.experimentId, "experimentId");
|
|
5
|
+
const subjectKey = sanitizeIdentifier(request.subjectKey, "subjectKey");
|
|
6
|
+
const channel = sanitizeIdentifier(request.channel, "channel");
|
|
7
|
+
const normalizedArms = normalizeArms(request.arms);
|
|
8
|
+
const seed = typeof request.seed === "string" && request.seed.trim().length > 0 ? request.seed.trim() : "v1";
|
|
9
|
+
const assignmentKey = stableHash(`exp:${experimentId}:subject:${subjectKey}:seed:${seed}`);
|
|
10
|
+
const bucket = bucketFromHash(assignmentKey);
|
|
11
|
+
const armId = pickWeightedArm(bucket, normalizedArms);
|
|
12
|
+
return {
|
|
13
|
+
experimentId,
|
|
14
|
+
subjectKey,
|
|
15
|
+
channel,
|
|
16
|
+
assignmentKey,
|
|
17
|
+
exposureKey: stableHash(`exp:${experimentId}:subject:${subjectKey}:arm:${armId}:seed:${seed}`),
|
|
18
|
+
bucket,
|
|
19
|
+
armId,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function normalizeArms(arms) {
|
|
23
|
+
if (!Array.isArray(arms) || arms.length === 0) {
|
|
24
|
+
throw new Error("arms must include at least one entry");
|
|
25
|
+
}
|
|
26
|
+
const sanitized = arms.map((arm, index) => {
|
|
27
|
+
const id = sanitizeIdentifier(arm?.id, `arms[${index}].id`);
|
|
28
|
+
const weight = Number.isFinite(arm?.weight) ? Number(arm.weight) : Number.NaN;
|
|
29
|
+
if (!Number.isFinite(weight) || weight <= 0) {
|
|
30
|
+
throw new Error(`arms[${index}].weight must be > 0`);
|
|
31
|
+
}
|
|
32
|
+
return { id, weight };
|
|
33
|
+
});
|
|
34
|
+
const totalWeight = sanitized.reduce((sum, arm) => sum + arm.weight, 0);
|
|
35
|
+
if (totalWeight <= 0) {
|
|
36
|
+
throw new Error("arms total weight must be > 0");
|
|
37
|
+
}
|
|
38
|
+
return sanitized.map((arm) => ({ id: arm.id, weight: arm.weight / totalWeight }));
|
|
39
|
+
}
|
|
40
|
+
function pickWeightedArm(bucket, arms) {
|
|
41
|
+
let cursor = 0;
|
|
42
|
+
for (const arm of arms) {
|
|
43
|
+
cursor += arm.weight;
|
|
44
|
+
if (bucket < cursor) {
|
|
45
|
+
return arm.id;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return arms[arms.length - 1].id;
|
|
49
|
+
}
|
|
50
|
+
function sanitizeIdentifier(value, field) {
|
|
51
|
+
if (typeof value !== "string") {
|
|
52
|
+
throw new Error(`${field} must be a string`);
|
|
53
|
+
}
|
|
54
|
+
const trimmed = value.trim();
|
|
55
|
+
if (trimmed.length === 0) {
|
|
56
|
+
throw new Error(`${field} cannot be empty`);
|
|
57
|
+
}
|
|
58
|
+
return trimmed;
|
|
59
|
+
}
|
|
60
|
+
function bucketFromHash(hash) {
|
|
61
|
+
const first53Bits = hash.slice(0, 14);
|
|
62
|
+
return parseInt(first53Bits, 16) / MAX_UINT53;
|
|
63
|
+
}
|
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
import type { SkillPack } from "./contracts/types.js";
|
|
2
2
|
import type { OrgxSkillPackOverrides } from "./agent-suite.js";
|
|
3
|
+
export type SkillPackPolicy = {
|
|
4
|
+
frozen: boolean;
|
|
5
|
+
pinnedChecksum: string | null;
|
|
6
|
+
};
|
|
7
|
+
export type SkillPackPolicyDiff = {
|
|
8
|
+
field: "policy.frozen" | "policy.pinnedChecksum";
|
|
9
|
+
before: boolean | string | null;
|
|
10
|
+
after: boolean | string | null;
|
|
11
|
+
};
|
|
12
|
+
export type SkillPackPolicyAuditEntry = {
|
|
13
|
+
id: string;
|
|
14
|
+
changedAt: string;
|
|
15
|
+
changedBy: string;
|
|
16
|
+
action: "policy.update" | "policy.rollback";
|
|
17
|
+
reason: string | null;
|
|
18
|
+
rollbackOfAuditId: string | null;
|
|
19
|
+
diff: SkillPackPolicyDiff[];
|
|
20
|
+
beforePolicy: SkillPackPolicy;
|
|
21
|
+
afterPolicy: SkillPackPolicy;
|
|
22
|
+
};
|
|
3
23
|
export type SkillPackState = {
|
|
4
24
|
version: 1;
|
|
5
25
|
updatedAt: string;
|
|
6
26
|
lastCheckedAt: string | null;
|
|
7
27
|
lastError: string | null;
|
|
8
28
|
etag: string | null;
|
|
9
|
-
policy:
|
|
10
|
-
frozen: boolean;
|
|
11
|
-
pinnedChecksum: string | null;
|
|
12
|
-
};
|
|
29
|
+
policy: SkillPackPolicy;
|
|
13
30
|
pack: {
|
|
14
31
|
name: string;
|
|
15
32
|
version: string;
|
|
@@ -23,6 +40,9 @@ export type SkillPackState = {
|
|
|
23
40
|
updated_at: string | null;
|
|
24
41
|
} | null;
|
|
25
42
|
overrides: OrgxSkillPackOverrides | null;
|
|
43
|
+
audit: {
|
|
44
|
+
entries: SkillPackPolicyAuditEntry[];
|
|
45
|
+
};
|
|
26
46
|
};
|
|
27
47
|
export declare function readSkillPackState(input?: {
|
|
28
48
|
openclawDir?: string;
|
|
@@ -36,11 +56,22 @@ export declare function updateSkillPackPolicy(input: {
|
|
|
36
56
|
pinnedChecksum?: string | null;
|
|
37
57
|
pinToCurrent?: boolean;
|
|
38
58
|
clearPin?: boolean;
|
|
59
|
+
changedBy?: string;
|
|
60
|
+
reason?: string;
|
|
61
|
+
}): SkillPackState;
|
|
62
|
+
export declare function rollbackSkillPackPolicy(input?: {
|
|
63
|
+
openclawDir?: string;
|
|
64
|
+
auditId?: string;
|
|
65
|
+
changedBy?: string;
|
|
66
|
+
reason?: string;
|
|
39
67
|
}): SkillPackState;
|
|
40
68
|
export declare function toOrgxSkillPackOverrides(input: {
|
|
41
69
|
pack: SkillPack;
|
|
42
70
|
etag: string | null;
|
|
43
|
-
}):
|
|
71
|
+
}): {
|
|
72
|
+
overrides: OrgxSkillPackOverrides;
|
|
73
|
+
validationErrors: string[];
|
|
74
|
+
};
|
|
44
75
|
export declare function refreshSkillPackState(input: {
|
|
45
76
|
getSkillPack: (args: {
|
|
46
77
|
name?: string;
|
package/dist/skill-pack-state.js
CHANGED
|
@@ -2,8 +2,10 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { writeFileAtomicSync } from "./fs-utils.js";
|
|
4
4
|
import { getOpenClawDir } from "./paths.js";
|
|
5
|
+
import { validateOpenClawSkillPackManifest } from "./contracts/skill-pack-schema.js";
|
|
5
6
|
const STORE_VERSION = 1;
|
|
6
7
|
const STATE_FILENAME = "orgx-skill-pack-state.json";
|
|
8
|
+
const AUDIT_HISTORY_LIMIT = 50;
|
|
7
9
|
function nowIso() {
|
|
8
10
|
return new Date().toISOString();
|
|
9
11
|
}
|
|
@@ -16,6 +18,94 @@ function coerceString(value) {
|
|
|
16
18
|
function statePath(openclawDir) {
|
|
17
19
|
return join(openclawDir, STATE_FILENAME);
|
|
18
20
|
}
|
|
21
|
+
function clonePolicy(input) {
|
|
22
|
+
return {
|
|
23
|
+
frozen: Boolean(input.frozen),
|
|
24
|
+
pinnedChecksum: coerceString(input.pinnedChecksum),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function normalizeChangedBy(input) {
|
|
28
|
+
if (typeof input !== "string")
|
|
29
|
+
return "unknown";
|
|
30
|
+
const value = input.trim();
|
|
31
|
+
return value.length > 0 ? value : "unknown";
|
|
32
|
+
}
|
|
33
|
+
function normalizeReason(input) {
|
|
34
|
+
return typeof input === "string" && input.trim().length > 0 ? input.trim() : null;
|
|
35
|
+
}
|
|
36
|
+
function nextAuditId() {
|
|
37
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
38
|
+
}
|
|
39
|
+
function computePolicyDiff(before, after) {
|
|
40
|
+
const diff = [];
|
|
41
|
+
if (before.frozen !== after.frozen) {
|
|
42
|
+
diff.push({
|
|
43
|
+
field: "policy.frozen",
|
|
44
|
+
before: before.frozen,
|
|
45
|
+
after: after.frozen,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (before.pinnedChecksum !== after.pinnedChecksum) {
|
|
49
|
+
diff.push({
|
|
50
|
+
field: "policy.pinnedChecksum",
|
|
51
|
+
before: before.pinnedChecksum,
|
|
52
|
+
after: after.pinnedChecksum,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return diff;
|
|
56
|
+
}
|
|
57
|
+
function appendPolicyAuditEntry(entries, entry) {
|
|
58
|
+
return [entry, ...entries].slice(0, AUDIT_HISTORY_LIMIT);
|
|
59
|
+
}
|
|
60
|
+
function parseAuditEntries(raw) {
|
|
61
|
+
if (!Array.isArray(raw))
|
|
62
|
+
return [];
|
|
63
|
+
const entries = [];
|
|
64
|
+
for (const candidate of raw) {
|
|
65
|
+
if (!isRecord(candidate))
|
|
66
|
+
continue;
|
|
67
|
+
const beforePolicyRaw = isRecord(candidate.beforePolicy) ? candidate.beforePolicy : null;
|
|
68
|
+
const afterPolicyRaw = isRecord(candidate.afterPolicy) ? candidate.afterPolicy : null;
|
|
69
|
+
if (!beforePolicyRaw || !afterPolicyRaw)
|
|
70
|
+
continue;
|
|
71
|
+
const diffRaw = Array.isArray(candidate.diff) ? candidate.diff : [];
|
|
72
|
+
const diff = [];
|
|
73
|
+
for (const diffEntry of diffRaw) {
|
|
74
|
+
if (!isRecord(diffEntry))
|
|
75
|
+
continue;
|
|
76
|
+
const field = diffEntry.field;
|
|
77
|
+
if (field !== "policy.frozen" && field !== "policy.pinnedChecksum")
|
|
78
|
+
continue;
|
|
79
|
+
diff.push({
|
|
80
|
+
field,
|
|
81
|
+
before: typeof diffEntry.before === "boolean" || diffEntry.before === null
|
|
82
|
+
? diffEntry.before
|
|
83
|
+
: coerceString(diffEntry.before),
|
|
84
|
+
after: typeof diffEntry.after === "boolean" || diffEntry.after === null
|
|
85
|
+
? diffEntry.after
|
|
86
|
+
: coerceString(diffEntry.after),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
entries.push({
|
|
90
|
+
id: coerceString(candidate.id) ?? nextAuditId(),
|
|
91
|
+
changedAt: coerceString(candidate.changedAt) ?? nowIso(),
|
|
92
|
+
changedBy: normalizeChangedBy(candidate.changedBy),
|
|
93
|
+
action: candidate.action === "policy.rollback" ? "policy.rollback" : "policy.update",
|
|
94
|
+
reason: normalizeReason(candidate.reason),
|
|
95
|
+
rollbackOfAuditId: coerceString(candidate.rollbackOfAuditId),
|
|
96
|
+
diff,
|
|
97
|
+
beforePolicy: {
|
|
98
|
+
frozen: Boolean(beforePolicyRaw.frozen),
|
|
99
|
+
pinnedChecksum: coerceString(beforePolicyRaw.pinnedChecksum),
|
|
100
|
+
},
|
|
101
|
+
afterPolicy: {
|
|
102
|
+
frozen: Boolean(afterPolicyRaw.frozen),
|
|
103
|
+
pinnedChecksum: coerceString(afterPolicyRaw.pinnedChecksum),
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return entries.slice(0, AUDIT_HISTORY_LIMIT);
|
|
108
|
+
}
|
|
19
109
|
export function readSkillPackState(input) {
|
|
20
110
|
const openclawDir = input?.openclawDir ?? getOpenClawDir();
|
|
21
111
|
const path = statePath(openclawDir);
|
|
@@ -29,6 +119,7 @@ export function readSkillPackState(input) {
|
|
|
29
119
|
pack: null,
|
|
30
120
|
remote: null,
|
|
31
121
|
overrides: null,
|
|
122
|
+
audit: { entries: [] },
|
|
32
123
|
};
|
|
33
124
|
try {
|
|
34
125
|
if (!existsSync(path))
|
|
@@ -43,6 +134,7 @@ export function readSkillPackState(input) {
|
|
|
43
134
|
const pack = isRecord(parsed.pack) ? parsed.pack : null;
|
|
44
135
|
const remote = isRecord(parsed.remote) ? parsed.remote : null;
|
|
45
136
|
const overrides = isRecord(parsed.overrides) ? parsed.overrides : null;
|
|
137
|
+
const audit = isRecord(parsed.audit) ? parsed.audit : null;
|
|
46
138
|
return {
|
|
47
139
|
version: STORE_VERSION,
|
|
48
140
|
updatedAt: coerceString(parsed.updatedAt) ?? nowIso(),
|
|
@@ -72,6 +164,9 @@ export function readSkillPackState(input) {
|
|
|
72
164
|
overrides: overrides
|
|
73
165
|
? overrides
|
|
74
166
|
: null,
|
|
167
|
+
audit: {
|
|
168
|
+
entries: parseAuditEntries(audit?.entries),
|
|
169
|
+
},
|
|
75
170
|
};
|
|
76
171
|
}
|
|
77
172
|
catch {
|
|
@@ -88,7 +183,12 @@ export function writeSkillPackState(state, input) {
|
|
|
88
183
|
}
|
|
89
184
|
export function updateSkillPackPolicy(input) {
|
|
90
185
|
const prev = readSkillPackState({ openclawDir: input.openclawDir });
|
|
186
|
+
const beforePolicy = clonePolicy(prev.policy);
|
|
91
187
|
const nextPolicy = { ...prev.policy };
|
|
188
|
+
const activeChecksum = prev.pack?.checksum ?? null;
|
|
189
|
+
const remoteChecksum = prev.remote?.checksum ?? null;
|
|
190
|
+
const hasInactiveRemoteCandidate = Boolean(remoteChecksum && remoteChecksum !== activeChecksum);
|
|
191
|
+
const blockedByActivationValidation = hasInactiveRemoteCandidate && hasActivationValidationFailure(prev.lastError);
|
|
92
192
|
if (typeof input.frozen === "boolean") {
|
|
93
193
|
nextPolicy.frozen = input.frozen;
|
|
94
194
|
}
|
|
@@ -96,10 +196,20 @@ export function updateSkillPackPolicy(input) {
|
|
|
96
196
|
nextPolicy.pinnedChecksum = null;
|
|
97
197
|
}
|
|
98
198
|
else if (input.pinToCurrent) {
|
|
199
|
+
if (blockedByActivationValidation) {
|
|
200
|
+
throw new Error("Cannot pin_to_current: remote config failed eval/manifest checks and is not active.");
|
|
201
|
+
}
|
|
99
202
|
nextPolicy.pinnedChecksum = prev.pack?.checksum ?? prev.remote?.checksum ?? null;
|
|
100
203
|
}
|
|
101
204
|
else if (typeof input.pinnedChecksum === "string") {
|
|
102
|
-
|
|
205
|
+
const requestedChecksum = input.pinnedChecksum.trim() || null;
|
|
206
|
+
if (requestedChecksum &&
|
|
207
|
+
remoteChecksum &&
|
|
208
|
+
requestedChecksum === remoteChecksum &&
|
|
209
|
+
blockedByActivationValidation) {
|
|
210
|
+
throw new Error("Cannot pin checksum to remote config: eval/manifest checks are failing for that candidate.");
|
|
211
|
+
}
|
|
212
|
+
nextPolicy.pinnedChecksum = requestedChecksum;
|
|
103
213
|
}
|
|
104
214
|
else if (input.pinnedChecksum === null) {
|
|
105
215
|
nextPolicy.pinnedChecksum = null;
|
|
@@ -109,48 +219,155 @@ export function updateSkillPackPolicy(input) {
|
|
|
109
219
|
updatedAt: nowIso(),
|
|
110
220
|
policy: nextPolicy,
|
|
111
221
|
};
|
|
222
|
+
const diff = computePolicyDiff(beforePolicy, next.policy);
|
|
223
|
+
if (diff.length > 0) {
|
|
224
|
+
const entry = {
|
|
225
|
+
id: nextAuditId(),
|
|
226
|
+
changedAt: next.updatedAt,
|
|
227
|
+
changedBy: normalizeChangedBy(input.changedBy),
|
|
228
|
+
action: "policy.update",
|
|
229
|
+
reason: normalizeReason(input.reason),
|
|
230
|
+
rollbackOfAuditId: null,
|
|
231
|
+
diff,
|
|
232
|
+
beforePolicy,
|
|
233
|
+
afterPolicy: clonePolicy(next.policy),
|
|
234
|
+
};
|
|
235
|
+
next.audit = {
|
|
236
|
+
entries: appendPolicyAuditEntry(prev.audit.entries, entry),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
112
239
|
writeSkillPackState(next, { openclawDir: input.openclawDir });
|
|
113
240
|
return next;
|
|
114
241
|
}
|
|
242
|
+
export function rollbackSkillPackPolicy(input) {
|
|
243
|
+
const prev = readSkillPackState({ openclawDir: input?.openclawDir });
|
|
244
|
+
const normalizedAuditId = typeof input?.auditId === "string" && input.auditId.trim().length > 0
|
|
245
|
+
? input.auditId.trim()
|
|
246
|
+
: null;
|
|
247
|
+
const target = normalizedAuditId
|
|
248
|
+
? prev.audit.entries.find((entry) => entry.id === normalizedAuditId) ?? null
|
|
249
|
+
: prev.audit.entries[0] ?? null;
|
|
250
|
+
if (!target) {
|
|
251
|
+
throw new Error("No policy audit entry available for rollback");
|
|
252
|
+
}
|
|
253
|
+
const beforePolicy = clonePolicy(prev.policy);
|
|
254
|
+
const afterPolicy = clonePolicy(target.beforePolicy);
|
|
255
|
+
const diff = computePolicyDiff(beforePolicy, afterPolicy);
|
|
256
|
+
if (diff.length === 0) {
|
|
257
|
+
return prev;
|
|
258
|
+
}
|
|
259
|
+
const changedAt = nowIso();
|
|
260
|
+
const rollbackEntry = {
|
|
261
|
+
id: nextAuditId(),
|
|
262
|
+
changedAt,
|
|
263
|
+
changedBy: normalizeChangedBy(input?.changedBy),
|
|
264
|
+
action: "policy.rollback",
|
|
265
|
+
reason: normalizeReason(input?.reason) ?? `Rollback to audit ${target.id}`,
|
|
266
|
+
rollbackOfAuditId: target.id,
|
|
267
|
+
diff,
|
|
268
|
+
beforePolicy,
|
|
269
|
+
afterPolicy,
|
|
270
|
+
};
|
|
271
|
+
const next = {
|
|
272
|
+
...prev,
|
|
273
|
+
updatedAt: changedAt,
|
|
274
|
+
policy: afterPolicy,
|
|
275
|
+
audit: {
|
|
276
|
+
entries: appendPolicyAuditEntry(prev.audit.entries, rollbackEntry),
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
writeSkillPackState(next, { openclawDir: input?.openclawDir });
|
|
280
|
+
return next;
|
|
281
|
+
}
|
|
115
282
|
function asRecord(value) {
|
|
116
283
|
return isRecord(value) ? value : null;
|
|
117
284
|
}
|
|
118
|
-
function
|
|
119
|
-
|
|
285
|
+
function asBoolean(value) {
|
|
286
|
+
return typeof value === "boolean" ? value : null;
|
|
287
|
+
}
|
|
288
|
+
function asFiniteNumber(value) {
|
|
289
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
290
|
+
}
|
|
291
|
+
function normalizeStatus(value) {
|
|
292
|
+
if (typeof value !== "string")
|
|
293
|
+
return null;
|
|
294
|
+
const normalized = value.trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
295
|
+
return normalized.length > 0 ? normalized : null;
|
|
296
|
+
}
|
|
297
|
+
function hasActivationValidationFailure(lastError) {
|
|
298
|
+
if (!lastError)
|
|
299
|
+
return false;
|
|
300
|
+
const normalized = lastError.toLowerCase();
|
|
301
|
+
return (normalized.includes("eval framework checks did not pass") ||
|
|
302
|
+
normalized.includes("eval gate blocked activation") ||
|
|
303
|
+
normalized.includes("manifest validation errors"));
|
|
304
|
+
}
|
|
305
|
+
function evalGateErrorForPack(pack) {
|
|
306
|
+
const manifest = asRecord(pack.manifest);
|
|
307
|
+
if (!manifest) {
|
|
308
|
+
return "SkillPack eval framework checks did not pass: missing manifest object";
|
|
309
|
+
}
|
|
120
310
|
const candidates = [
|
|
121
|
-
asRecord(
|
|
122
|
-
asRecord(
|
|
123
|
-
asRecord(
|
|
124
|
-
|
|
125
|
-
|
|
311
|
+
{ label: "eval_framework", value: asRecord(manifest.eval_framework) },
|
|
312
|
+
{ label: "evalFramework", value: asRecord(manifest.evalFramework) },
|
|
313
|
+
{ label: "evaluation_result", value: asRecord(manifest.evaluation_result) },
|
|
314
|
+
{ label: "evaluationResult", value: asRecord(manifest.evaluationResult) },
|
|
315
|
+
{ label: "evaluation", value: asRecord(manifest.evaluation) },
|
|
316
|
+
{ label: "quality_gate", value: asRecord(manifest.quality_gate) },
|
|
317
|
+
{ label: "qualityGate", value: asRecord(manifest.qualityGate) },
|
|
318
|
+
];
|
|
126
319
|
for (const candidate of candidates) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
320
|
+
if (!candidate.value)
|
|
321
|
+
continue;
|
|
322
|
+
const passed = asBoolean(candidate.value.passed) ??
|
|
323
|
+
asBoolean(candidate.value.ok) ??
|
|
324
|
+
asBoolean(candidate.value.success) ??
|
|
325
|
+
asBoolean(candidate.value.allowed);
|
|
326
|
+
if (passed != null) {
|
|
327
|
+
return passed
|
|
328
|
+
? null
|
|
329
|
+
: `SkillPack eval framework checks did not pass: ${candidate.label}.passed=false`;
|
|
330
|
+
}
|
|
331
|
+
const status = normalizeStatus(candidate.value.status);
|
|
332
|
+
if (status) {
|
|
333
|
+
const passStatuses = new Set(["pass", "passed", "ok", "success", "approved", "green"]);
|
|
334
|
+
const failStatuses = new Set(["fail", "failed", "rejected", "error", "blocked", "red"]);
|
|
335
|
+
if (passStatuses.has(status))
|
|
336
|
+
return null;
|
|
337
|
+
if (failStatuses.has(status)) {
|
|
338
|
+
return `SkillPack eval framework checks did not pass: ${candidate.label}.status=${status}`;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
const checksTotal = asFiniteNumber(candidate.value.checks_total) ??
|
|
342
|
+
asFiniteNumber(candidate.value.total_checks);
|
|
343
|
+
const checksPassed = asFiniteNumber(candidate.value.checks_passed) ??
|
|
344
|
+
asFiniteNumber(candidate.value.passed_checks);
|
|
345
|
+
if (checksTotal != null && checksPassed != null && checksTotal > 0) {
|
|
346
|
+
return checksPassed >= checksTotal
|
|
347
|
+
? null
|
|
348
|
+
: `SkillPack eval framework checks did not pass: ${candidate.label}.checks=${checksPassed}/${checksTotal}`;
|
|
134
349
|
}
|
|
135
350
|
}
|
|
136
|
-
return
|
|
351
|
+
return "SkillPack eval framework checks did not pass: missing pass signal in manifest";
|
|
137
352
|
}
|
|
138
353
|
export function toOrgxSkillPackOverrides(input) {
|
|
139
|
-
const manifest = asRecord(input.pack.manifest)
|
|
140
|
-
const
|
|
354
|
+
const manifest = asRecord(input.pack.manifest);
|
|
355
|
+
const validation = validateOpenClawSkillPackManifest(manifest ?? {});
|
|
141
356
|
const openclaw_skills = {};
|
|
142
|
-
for (const [k, v] of Object.entries(
|
|
143
|
-
// Domains are normalized to lowercase keys in the manifest.
|
|
357
|
+
for (const [k, v] of Object.entries(validation.openclaw_skills)) {
|
|
144
358
|
openclaw_skills[k] = v;
|
|
145
359
|
}
|
|
146
360
|
return {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
361
|
+
overrides: {
|
|
362
|
+
source: "server",
|
|
363
|
+
name: input.pack.name,
|
|
364
|
+
version: input.pack.version,
|
|
365
|
+
checksum: input.pack.checksum,
|
|
366
|
+
etag: input.etag,
|
|
367
|
+
updated_at: input.pack.updated_at ?? null,
|
|
368
|
+
openclaw_skills,
|
|
369
|
+
},
|
|
370
|
+
validationErrors: validation.errors,
|
|
154
371
|
};
|
|
155
372
|
}
|
|
156
373
|
export async function refreshSkillPackState(input) {
|
|
@@ -201,7 +418,33 @@ export async function refreshSkillPackState(input) {
|
|
|
201
418
|
writeSkillPackState(next, { openclawDir: input.openclawDir });
|
|
202
419
|
return { state: next, changed: false };
|
|
203
420
|
}
|
|
204
|
-
const overrides = toOrgxSkillPackOverrides({
|
|
421
|
+
const { overrides, validationErrors } = toOrgxSkillPackOverrides({
|
|
422
|
+
pack: result.pack,
|
|
423
|
+
etag: result.etag ?? null,
|
|
424
|
+
});
|
|
425
|
+
const evalGateError = evalGateErrorForPack(result.pack);
|
|
426
|
+
const activationErrors = [];
|
|
427
|
+
if (validationErrors.length > 0) {
|
|
428
|
+
activationErrors.push(`SkillPack manifest validation errors: ${validationErrors.join("; ")}`);
|
|
429
|
+
}
|
|
430
|
+
if (evalGateError) {
|
|
431
|
+
activationErrors.push(evalGateError);
|
|
432
|
+
}
|
|
433
|
+
const activationValidationError = activationErrors.length > 0 ? activationErrors.join(" | ") : null;
|
|
434
|
+
// Guardrail: never activate a config that fails eval/manifest validation.
|
|
435
|
+
// Keep it staged in `remote` + `lastError` so operators can inspect/fix it.
|
|
436
|
+
if (activationValidationError) {
|
|
437
|
+
const next = {
|
|
438
|
+
...prev,
|
|
439
|
+
updatedAt: nowIso(),
|
|
440
|
+
lastCheckedAt: nowIso(),
|
|
441
|
+
lastError: activationValidationError,
|
|
442
|
+
etag: result.etag ?? prev.etag,
|
|
443
|
+
remote: remoteMeta,
|
|
444
|
+
};
|
|
445
|
+
writeSkillPackState(next, { openclawDir: input.openclawDir });
|
|
446
|
+
return { state: next, changed: false };
|
|
447
|
+
}
|
|
205
448
|
const next = {
|
|
206
449
|
version: STORE_VERSION,
|
|
207
450
|
updatedAt: nowIso(),
|
|
@@ -217,6 +460,7 @@ export async function refreshSkillPackState(input) {
|
|
|
217
460
|
},
|
|
218
461
|
remote: remoteMeta,
|
|
219
462
|
overrides,
|
|
463
|
+
audit: prev.audit,
|
|
220
464
|
};
|
|
221
465
|
writeSkillPackState(next, { openclawDir: input.openclawDir });
|
|
222
466
|
return { state: next, changed: prev.pack?.checksum !== next.pack?.checksum };
|
|
@@ -225,7 +469,7 @@ export async function refreshSkillPackState(input) {
|
|
|
225
469
|
...prev,
|
|
226
470
|
updatedAt: nowIso(),
|
|
227
471
|
lastCheckedAt: nowIso(),
|
|
228
|
-
lastError:
|
|
472
|
+
lastError: result.ok === false ? result.error : prev.lastError,
|
|
229
473
|
};
|
|
230
474
|
writeSkillPackState(next, { openclawDir: input.openclawDir });
|
|
231
475
|
return { state: next, changed: false };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AgentRunRecord } from "../agent-run-store.js";
|
|
2
|
+
import type { AgentState } from "../types.js";
|
|
3
|
+
export declare function buildLocalAgentMirrorsFromSnapshot(input: {
|
|
4
|
+
agents: AgentState[] | null | undefined;
|
|
5
|
+
}): AgentState[];
|
|
6
|
+
/**
|
|
7
|
+
* Derive live local agent states from active OpenClaw runs so sync can mirror
|
|
8
|
+
* local runtime telemetry into OrgX.
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildLocalSyncAgentsFromRuns(input: {
|
|
11
|
+
runs: Record<string, AgentRunRecord>;
|
|
12
|
+
mirrors?: AgentState[] | null;
|
|
13
|
+
}): AgentState[];
|