@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.
Files changed (224) hide show
  1. package/README.md +77 -11
  2. package/dashboard/dist/assets/6mILZQ2a.js +1 -0
  3. package/dashboard/dist/assets/6mILZQ2a.js.br +0 -0
  4. package/dashboard/dist/assets/6mILZQ2a.js.gz +0 -0
  5. package/dashboard/dist/assets/8dksYiq4.js +2 -0
  6. package/dashboard/dist/assets/8dksYiq4.js.br +0 -0
  7. package/dashboard/dist/assets/8dksYiq4.js.gz +0 -0
  8. package/dashboard/dist/assets/B5zYRHc3.js +1 -0
  9. package/dashboard/dist/assets/B5zYRHc3.js.br +0 -0
  10. package/dashboard/dist/assets/B5zYRHc3.js.gz +0 -0
  11. package/dashboard/dist/assets/B6wPWJ35.js +1 -0
  12. package/dashboard/dist/assets/B6wPWJ35.js.br +0 -0
  13. package/dashboard/dist/assets/B6wPWJ35.js.gz +0 -0
  14. package/dashboard/dist/assets/BJgZIVUQ.js +53 -0
  15. package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
  16. package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
  17. package/dashboard/dist/assets/BWEwjt1W.js +1 -0
  18. package/dashboard/dist/assets/BWEwjt1W.js.br +0 -0
  19. package/dashboard/dist/assets/BWEwjt1W.js.gz +0 -0
  20. package/dashboard/dist/assets/BgOYB78t.js +4 -0
  21. package/dashboard/dist/assets/BgOYB78t.js.br +0 -0
  22. package/dashboard/dist/assets/BgOYB78t.js.gz +0 -0
  23. package/dashboard/dist/assets/BzRbDCAD.css +1 -0
  24. package/dashboard/dist/assets/BzRbDCAD.css.br +0 -0
  25. package/dashboard/dist/assets/BzRbDCAD.css.gz +0 -0
  26. package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
  27. package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
  28. package/dashboard/dist/assets/C8uM3AX8.js +1 -0
  29. package/dashboard/dist/assets/C8uM3AX8.js.br +0 -0
  30. package/dashboard/dist/assets/C8uM3AX8.js.gz +0 -0
  31. package/dashboard/dist/assets/C9jy61eu.js +212 -0
  32. package/dashboard/dist/assets/C9jy61eu.js.br +0 -0
  33. package/dashboard/dist/assets/C9jy61eu.js.gz +0 -0
  34. package/dashboard/dist/assets/CC63EwFD.js +1 -0
  35. package/dashboard/dist/assets/CC63EwFD.js.br +0 -0
  36. package/dashboard/dist/assets/CC63EwFD.js.gz +0 -0
  37. package/dashboard/dist/assets/CL_wXqR7.js +1 -0
  38. package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
  39. package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
  40. package/dashboard/dist/assets/CZaT3ob_.js +1 -0
  41. package/dashboard/dist/assets/CZaT3ob_.js.br +0 -0
  42. package/dashboard/dist/assets/CZaT3ob_.js.gz +0 -0
  43. package/dashboard/dist/assets/CgaottFX.js +1 -0
  44. package/dashboard/dist/assets/CgaottFX.js.br +0 -0
  45. package/dashboard/dist/assets/CgaottFX.js.gz +0 -0
  46. package/dashboard/dist/assets/{CpJsfbXo.js → CxQ08qFN.js} +2 -2
  47. package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
  48. package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
  49. package/dashboard/dist/assets/CzCxAZlW.js +1 -0
  50. package/dashboard/dist/assets/CzCxAZlW.js.br +0 -0
  51. package/dashboard/dist/assets/CzCxAZlW.js.gz +0 -0
  52. package/dashboard/dist/assets/D3iMTYEj.js +1 -0
  53. package/dashboard/dist/assets/D3iMTYEj.js.br +0 -0
  54. package/dashboard/dist/assets/D3iMTYEj.js.gz +0 -0
  55. package/dashboard/dist/assets/D8JNX8kq.js +2 -0
  56. package/dashboard/dist/assets/D8JNX8kq.js.br +0 -0
  57. package/dashboard/dist/assets/D8JNX8kq.js.gz +0 -0
  58. package/dashboard/dist/assets/DnA8dpj6.js +1 -0
  59. package/dashboard/dist/assets/DnA8dpj6.js.br +0 -0
  60. package/dashboard/dist/assets/DnA8dpj6.js.gz +0 -0
  61. package/dashboard/dist/assets/IUexzymk.js +1 -0
  62. package/dashboard/dist/assets/IUexzymk.js.br +0 -0
  63. package/dashboard/dist/assets/IUexzymk.js.gz +0 -0
  64. package/dashboard/dist/assets/cNrhgGc1.js +8 -0
  65. package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
  66. package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
  67. package/dashboard/dist/assets/ic2FaMnh.js +1 -0
  68. package/dashboard/dist/assets/ic2FaMnh.js.br +0 -0
  69. package/dashboard/dist/assets/ic2FaMnh.js.gz +0 -0
  70. package/dashboard/dist/assets/qm8xLgv-.css +1 -0
  71. package/dashboard/dist/assets/qm8xLgv-.css.br +0 -0
  72. package/dashboard/dist/assets/qm8xLgv-.css.gz +0 -0
  73. package/dashboard/dist/assets/rttbDbEx.js +1 -0
  74. package/dashboard/dist/assets/rttbDbEx.js.br +0 -0
  75. package/dashboard/dist/assets/rttbDbEx.js.gz +0 -0
  76. package/dashboard/dist/brand/anthropic-mark.svg.br +0 -0
  77. package/dashboard/dist/brand/anthropic-mark.svg.gz +0 -0
  78. package/dashboard/dist/brand/openai-mark.svg.br +0 -0
  79. package/dashboard/dist/brand/openai-mark.svg.gz +0 -0
  80. package/dashboard/dist/brand/openclaw-mark.svg.br +0 -0
  81. package/dashboard/dist/brand/openclaw-mark.svg.gz +0 -0
  82. package/dashboard/dist/brand/xandy-orchestrator.png +0 -0
  83. package/dashboard/dist/index.html +7 -5
  84. package/dashboard/dist/index.html.br +0 -0
  85. package/dashboard/dist/index.html.gz +0 -0
  86. package/dist/activity-actor-fields.js +26 -4
  87. package/dist/activity-store.js +34 -8
  88. package/dist/agent-context-store.js +79 -17
  89. package/dist/agent-run-store.js +44 -3
  90. package/dist/agent-suite.d.ts +9 -0
  91. package/dist/agent-suite.js +149 -9
  92. package/dist/artifacts/artifact-domain-schemas.d.ts +66 -0
  93. package/dist/artifacts/artifact-domain-schemas.js +357 -0
  94. package/dist/artifacts/register-artifact.d.ts +4 -3
  95. package/dist/artifacts/register-artifact.js +170 -57
  96. package/dist/chat-store.d.ts +157 -0
  97. package/dist/chat-store.js +586 -0
  98. package/dist/cli/orgx.js +11 -0
  99. package/dist/contracts/client.d.ts +43 -3
  100. package/dist/contracts/client.js +159 -30
  101. package/dist/contracts/practice-exercise-schema.d.ts +216 -0
  102. package/dist/contracts/practice-exercise-schema.js +314 -0
  103. package/dist/contracts/retro-schema.d.ts +81 -0
  104. package/dist/contracts/retro-schema.js +80 -0
  105. package/dist/contracts/shared-types.d.ts +159 -0
  106. package/dist/contracts/shared-types.js +199 -1
  107. package/dist/contracts/skill-pack-schema.d.ts +192 -0
  108. package/dist/contracts/skill-pack-schema.js +180 -0
  109. package/dist/contracts/types.d.ts +247 -2
  110. package/dist/entities/auto-assignment.js +43 -17
  111. package/dist/event-sanitization.d.ts +11 -0
  112. package/dist/event-sanitization.js +113 -0
  113. package/dist/gateway-watchdog.d.ts +5 -0
  114. package/dist/gateway-watchdog.js +50 -0
  115. package/dist/hooks/post-reporting-event.mjs +1 -5
  116. package/dist/http/helpers/activity-headline.js +13 -132
  117. package/dist/http/helpers/auto-continue-engine.d.ts +198 -10
  118. package/dist/http/helpers/auto-continue-engine.js +3145 -186
  119. package/dist/http/helpers/autopilot-operations.d.ts +19 -0
  120. package/dist/http/helpers/autopilot-operations.js +182 -31
  121. package/dist/http/helpers/autopilot-runtime.d.ts +1 -0
  122. package/dist/http/helpers/autopilot-runtime.js +328 -25
  123. package/dist/http/helpers/autopilot-slice-utils.d.ts +18 -0
  124. package/dist/http/helpers/autopilot-slice-utils.js +514 -93
  125. package/dist/http/helpers/decision-mapper.d.ts +40 -0
  126. package/dist/http/helpers/decision-mapper.js +223 -7
  127. package/dist/http/helpers/dispatch-lifecycle.d.ts +19 -2
  128. package/dist/http/helpers/dispatch-lifecycle.js +242 -37
  129. package/dist/http/helpers/kickoff-context.js +104 -0
  130. package/dist/http/helpers/llm-client.d.ts +47 -0
  131. package/dist/http/helpers/llm-client.js +256 -0
  132. package/dist/http/helpers/mission-control.d.ts +102 -3
  133. package/dist/http/helpers/mission-control.js +498 -9
  134. package/dist/http/helpers/sentinel-catalog.d.ts +23 -0
  135. package/dist/http/helpers/sentinel-catalog.js +193 -0
  136. package/dist/http/helpers/session-classification.d.ts +9 -0
  137. package/dist/http/helpers/session-classification.js +564 -0
  138. package/dist/http/helpers/slice-experience-v2.d.ts +137 -0
  139. package/dist/http/helpers/slice-experience-v2.js +677 -0
  140. package/dist/http/helpers/slice-run-projections.d.ts +72 -0
  141. package/dist/http/helpers/slice-run-projections.js +877 -0
  142. package/dist/http/helpers/triage-mapper.d.ts +43 -0
  143. package/dist/http/helpers/triage-mapper.js +549 -0
  144. package/dist/http/helpers/value-utils.js +7 -2
  145. package/dist/http/helpers/workspace-scope.d.ts +15 -0
  146. package/dist/http/helpers/workspace-scope.js +170 -0
  147. package/dist/http/index.js +1420 -105
  148. package/dist/http/routes/agent-suite.d.ts +9 -0
  149. package/dist/http/routes/agent-suite.js +294 -8
  150. package/dist/http/routes/agents-catalog.js +64 -19
  151. package/dist/http/routes/chat.d.ts +19 -0
  152. package/dist/http/routes/chat.js +522 -0
  153. package/dist/http/routes/decision-actions.d.ts +8 -1
  154. package/dist/http/routes/decision-actions.js +42 -5
  155. package/dist/http/routes/dispatch-gateway-envelope.d.ts +25 -0
  156. package/dist/http/routes/dispatch-gateway-envelope.js +26 -0
  157. package/dist/http/routes/entities.d.ts +16 -0
  158. package/dist/http/routes/entities.js +232 -6
  159. package/dist/http/routes/live-legacy.d.ts +5 -0
  160. package/dist/http/routes/live-legacy.js +23 -509
  161. package/dist/http/routes/live-misc.d.ts +12 -0
  162. package/dist/http/routes/live-misc.js +251 -31
  163. package/dist/http/routes/live-snapshot.d.ts +49 -2
  164. package/dist/http/routes/live-snapshot.js +653 -23
  165. package/dist/http/routes/live-terminal.d.ts +11 -0
  166. package/dist/http/routes/live-terminal.js +154 -0
  167. package/dist/http/routes/live-triage.d.ts +61 -0
  168. package/dist/http/routes/live-triage.js +192 -0
  169. package/dist/http/routes/mission-control-actions.d.ts +49 -1
  170. package/dist/http/routes/mission-control-actions.js +1246 -84
  171. package/dist/http/routes/mission-control-read.d.ts +48 -3
  172. package/dist/http/routes/mission-control-read.js +1658 -20
  173. package/dist/http/routes/realtime-orchestrator.d.ts +10 -0
  174. package/dist/http/routes/realtime-orchestrator.js +74 -0
  175. package/dist/http/routes/run-control.d.ts +5 -2
  176. package/dist/http/routes/run-control.js +10 -0
  177. package/dist/http/routes/sentinels-catalog.d.ts +7 -0
  178. package/dist/http/routes/sentinels-catalog.js +24 -0
  179. package/dist/http/routes/summary.js +10 -3
  180. package/dist/http/routes/usage.d.ts +24 -0
  181. package/dist/http/routes/usage.js +362 -0
  182. package/dist/http/routes/work-artifacts.js +28 -9
  183. package/dist/index.js +165 -27
  184. package/dist/local-openclaw.js +29 -6
  185. package/dist/mcp-client-setup.js +3 -3
  186. package/dist/mcp-http-handler.d.ts +3 -0
  187. package/dist/mcp-http-handler.js +34 -60
  188. package/dist/next-up-queue-store.d.ts +16 -1
  189. package/dist/next-up-queue-store.js +89 -7
  190. package/dist/outbox.d.ts +5 -0
  191. package/dist/outbox.js +113 -9
  192. package/dist/paths.js +36 -5
  193. package/dist/reporting/rollups.d.ts +41 -0
  194. package/dist/reporting/rollups.js +113 -0
  195. package/dist/retro/domain-templates.d.ts +45 -0
  196. package/dist/retro/domain-templates.js +297 -0
  197. package/dist/retro/quality-rubric.d.ts +33 -0
  198. package/dist/retro/quality-rubric.js +213 -0
  199. package/dist/runtime-cleanup.d.ts +18 -0
  200. package/dist/runtime-cleanup.js +87 -0
  201. package/dist/services/background.d.ts +11 -0
  202. package/dist/services/background.js +22 -0
  203. package/dist/services/experiment-randomization.d.ts +21 -0
  204. package/dist/services/experiment-randomization.js +63 -0
  205. package/dist/skill-pack-state.d.ts +36 -5
  206. package/dist/skill-pack-state.js +273 -29
  207. package/dist/sync/local-agent-telemetry.d.ts +13 -0
  208. package/dist/sync/local-agent-telemetry.js +128 -0
  209. package/dist/sync/outbox-replay.js +131 -24
  210. package/dist/team-context-store.d.ts +23 -0
  211. package/dist/team-context-store.js +116 -0
  212. package/dist/telemetry/posthog.js +4 -2
  213. package/dist/tools/core-tools.d.ts +10 -14
  214. package/dist/tools/core-tools.js +1289 -24
  215. package/dist/types.d.ts +2 -0
  216. package/dist/types.js +2 -0
  217. package/dist/worker-supervisor.js +23 -0
  218. package/package.json +20 -6
  219. package/dashboard/dist/assets/B3ziCA02.js +0 -8
  220. package/dashboard/dist/assets/B5NEElEI.css +0 -1
  221. package/dashboard/dist/assets/BhapSNAs.js +0 -215
  222. package/dashboard/dist/assets/iFdvE7lx.js +0 -1
  223. package/dashboard/dist/assets/jRJsmpYM.js +0 -1
  224. 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
- }): OrgxSkillPackOverrides;
71
+ }): {
72
+ overrides: OrgxSkillPackOverrides;
73
+ validationErrors: string[];
74
+ };
44
75
  export declare function refreshSkillPackState(input: {
45
76
  getSkillPack: (args: {
46
77
  name?: string;
@@ -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
- nextPolicy.pinnedChecksum = input.pinnedChecksum.trim() || null;
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 parseOpenclawSkillOverridesFromManifest(manifest) {
119
- const root = manifest ?? {};
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(root.openclaw_skills),
122
- asRecord(root.openclawSkills),
123
- asRecord(asRecord(root.openclaw)?.skills),
124
- ].filter(Boolean);
125
- const out = {};
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
- for (const [k, v] of Object.entries(candidate)) {
128
- if (typeof v !== "string")
129
- continue;
130
- const key = k.trim().toLowerCase();
131
- if (!key)
132
- continue;
133
- out[key] = v;
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 out;
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 rawOverrides = parseOpenclawSkillOverridesFromManifest(manifest);
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(rawOverrides)) {
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
- source: "server",
148
- name: input.pack.name,
149
- version: input.pack.version,
150
- checksum: input.pack.checksum,
151
- etag: input.etag,
152
- updated_at: input.pack.updated_at ?? null,
153
- openclaw_skills,
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({ pack: result.pack, etag: result.etag ?? null });
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: !result.ok ? result.error : prev.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[];