@useorgx/openclaw-plugin 0.7.11 → 0.7.16

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 (198) hide show
  1. package/README.md +94 -122
  2. package/dashboard/dist/assets/8pbG6uLK.js +1 -0
  3. package/dashboard/dist/assets/8pbG6uLK.js.br +0 -0
  4. package/dashboard/dist/assets/8pbG6uLK.js.gz +0 -0
  5. package/dashboard/dist/assets/B1LENRC8.js +212 -0
  6. package/dashboard/dist/assets/B1LENRC8.js.br +0 -0
  7. package/dashboard/dist/assets/B1LENRC8.js.gz +0 -0
  8. package/dashboard/dist/assets/{tcEHYcbW.js → BCudUvwg.js} +1 -1
  9. package/dashboard/dist/assets/BCudUvwg.js.br +0 -0
  10. package/dashboard/dist/assets/BCudUvwg.js.gz +0 -0
  11. package/dashboard/dist/assets/{Du1wfrXa.js → BM75sh1f.js} +2 -2
  12. package/dashboard/dist/assets/BM75sh1f.js.br +0 -0
  13. package/dashboard/dist/assets/BM75sh1f.js.gz +0 -0
  14. package/dashboard/dist/assets/BV0BcV1u.js +53 -0
  15. package/dashboard/dist/assets/BV0BcV1u.js.br +0 -0
  16. package/dashboard/dist/assets/BV0BcV1u.js.gz +0 -0
  17. package/dashboard/dist/assets/BYVYH9CH.js +1 -0
  18. package/dashboard/dist/assets/BYVYH9CH.js.br +0 -0
  19. package/dashboard/dist/assets/BYVYH9CH.js.gz +0 -0
  20. package/dashboard/dist/assets/BjK42gtU.js +1 -0
  21. package/dashboard/dist/assets/BjK42gtU.js.br +0 -0
  22. package/dashboard/dist/assets/BjK42gtU.js.gz +0 -0
  23. package/dashboard/dist/assets/BkMrrjAv.js +1 -0
  24. package/dashboard/dist/assets/BkMrrjAv.js.br +0 -0
  25. package/dashboard/dist/assets/BkMrrjAv.js.gz +0 -0
  26. package/dashboard/dist/assets/BpF7v1Dk.js +1 -0
  27. package/dashboard/dist/assets/BpF7v1Dk.js.br +0 -0
  28. package/dashboard/dist/assets/BpF7v1Dk.js.gz +0 -0
  29. package/dashboard/dist/assets/{AqVoI3SF.js → Bv_86bUY.js} +1 -1
  30. package/dashboard/dist/assets/Bv_86bUY.js.br +0 -0
  31. package/dashboard/dist/assets/Bv_86bUY.js.gz +0 -0
  32. package/dashboard/dist/assets/C-MOJWHs.js +1 -0
  33. package/dashboard/dist/assets/C-MOJWHs.js.br +0 -0
  34. package/dashboard/dist/assets/C-MOJWHs.js.gz +0 -0
  35. package/dashboard/dist/assets/C3PrI8L7.js +1 -0
  36. package/dashboard/dist/assets/C3PrI8L7.js.br +0 -0
  37. package/dashboard/dist/assets/C3PrI8L7.js.gz +0 -0
  38. package/dashboard/dist/assets/{CD-q5mdP.js → C6AqbA9J.js} +1 -1
  39. package/dashboard/dist/assets/C6AqbA9J.js.br +0 -0
  40. package/dashboard/dist/assets/C6AqbA9J.js.gz +0 -0
  41. package/dashboard/dist/assets/CSlBSRyv.js +1 -0
  42. package/dashboard/dist/assets/CSlBSRyv.js.br +0 -0
  43. package/dashboard/dist/assets/CSlBSRyv.js.gz +0 -0
  44. package/dashboard/dist/assets/{beHYBbh6.js → CUXb_4F3.js} +2 -2
  45. package/dashboard/dist/assets/CUXb_4F3.js.br +0 -0
  46. package/dashboard/dist/assets/CUXb_4F3.js.gz +0 -0
  47. package/dashboard/dist/assets/Cn8sRTkO.js +1 -0
  48. package/dashboard/dist/assets/Cn8sRTkO.js.br +0 -0
  49. package/dashboard/dist/assets/Cn8sRTkO.js.gz +0 -0
  50. package/dashboard/dist/assets/D5IgXoTj.js +1 -0
  51. package/dashboard/dist/assets/D5IgXoTj.js.br +0 -0
  52. package/dashboard/dist/assets/D5IgXoTj.js.gz +0 -0
  53. package/dashboard/dist/assets/DMKyYAtD.js +1 -0
  54. package/dashboard/dist/assets/DMKyYAtD.js.br +0 -0
  55. package/dashboard/dist/assets/DMKyYAtD.js.gz +0 -0
  56. package/dashboard/dist/assets/{DCP-C7fn.js → DXzpQUC0.js} +1 -1
  57. package/dashboard/dist/assets/DXzpQUC0.js.br +0 -0
  58. package/dashboard/dist/assets/DXzpQUC0.js.gz +0 -0
  59. package/dashboard/dist/assets/Dj2k1r16.js +8 -0
  60. package/dashboard/dist/assets/Dj2k1r16.js.br +0 -0
  61. package/dashboard/dist/assets/Dj2k1r16.js.gz +0 -0
  62. package/dashboard/dist/assets/JDPvhd68.js +1 -0
  63. package/dashboard/dist/assets/JDPvhd68.js.br +0 -0
  64. package/dashboard/dist/assets/JDPvhd68.js.gz +0 -0
  65. package/dashboard/dist/assets/R6N_VVqm.js +1 -0
  66. package/dashboard/dist/assets/R6N_VVqm.js.br +0 -0
  67. package/dashboard/dist/assets/R6N_VVqm.js.gz +0 -0
  68. package/dashboard/dist/assets/cEP7N1dn.js +1 -0
  69. package/dashboard/dist/assets/cEP7N1dn.js.br +0 -0
  70. package/dashboard/dist/assets/cEP7N1dn.js.gz +0 -0
  71. package/dashboard/dist/assets/cX2e-TLi.js +1 -0
  72. package/dashboard/dist/assets/cX2e-TLi.js.br +0 -0
  73. package/dashboard/dist/assets/cX2e-TLi.js.gz +0 -0
  74. package/dashboard/dist/assets/eeHXe_OQ.js +9 -0
  75. package/dashboard/dist/assets/eeHXe_OQ.js.br +0 -0
  76. package/dashboard/dist/assets/eeHXe_OQ.js.gz +0 -0
  77. package/dashboard/dist/assets/iLnvdWmW.css +1 -0
  78. package/dashboard/dist/assets/iLnvdWmW.css.br +0 -0
  79. package/dashboard/dist/assets/iLnvdWmW.css.gz +0 -0
  80. package/dashboard/dist/assets/konqMbVI.js +1 -0
  81. package/dashboard/dist/assets/konqMbVI.js.br +0 -0
  82. package/dashboard/dist/assets/konqMbVI.js.gz +0 -0
  83. package/dashboard/dist/assets/wc6cgXzV.js +1 -0
  84. package/dashboard/dist/assets/wc6cgXzV.js.br +0 -0
  85. package/dashboard/dist/assets/wc6cgXzV.js.gz +0 -0
  86. package/dashboard/dist/brand/control-tower.png +0 -0
  87. package/dashboard/dist/brand/design-codex.png +0 -0
  88. package/dashboard/dist/brand/engineering-autopilot.png +0 -0
  89. package/dashboard/dist/brand/launch-captain.png +0 -0
  90. package/dashboard/dist/brand/orgx-logo.png +0 -0
  91. package/dashboard/dist/brand/pipeline-intelligence.png +0 -0
  92. package/dashboard/dist/brand/product-orchestrator.png +0 -0
  93. package/dashboard/dist/brand/xandy-orchestrator.png +0 -0
  94. package/dashboard/dist/index.html +8 -6
  95. package/dashboard/dist/index.html.br +0 -0
  96. package/dashboard/dist/index.html.gz +0 -0
  97. package/dist/hash-utils.d.ts +1 -0
  98. package/dist/hash-utils.js +4 -0
  99. package/dist/http/helpers/auto-continue-engine.d.ts +15 -0
  100. package/dist/http/helpers/auto-continue-engine.js +289 -67
  101. package/dist/http/helpers/autopilot-slice-utils.js +112 -66
  102. package/dist/http/helpers/hash-utils.d.ts +1 -1
  103. package/dist/http/helpers/hash-utils.js +1 -1
  104. package/dist/http/helpers/mission-control.d.ts +3 -0
  105. package/dist/http/helpers/mission-control.js +43 -9
  106. package/dist/http/helpers/queue-constants.d.ts +37 -0
  107. package/dist/http/helpers/queue-constants.js +34 -0
  108. package/dist/http/helpers/slice-experience-v2.js +2 -5
  109. package/dist/http/helpers/slice-run-projections.js +2 -5
  110. package/dist/http/helpers/value-utils.d.ts +1 -1
  111. package/dist/http/helpers/value-utils.js +5 -2
  112. package/dist/http/helpers/workspace-scope.js +4 -3
  113. package/dist/http/index.js +104 -61
  114. package/dist/http/routes/chat.d.ts +1 -1
  115. package/dist/http/routes/chat.js +3 -23
  116. package/dist/http/routes/entities.js +60 -2
  117. package/dist/http/routes/entity-dynamic.js +49 -9
  118. package/dist/http/routes/live-snapshot.d.ts +10 -1
  119. package/dist/http/routes/live-snapshot.js +15 -26
  120. package/dist/http/routes/mission-control-actions.d.ts +6 -0
  121. package/dist/http/routes/mission-control-actions.js +35 -18
  122. package/dist/http/routes/mission-control-read.js +4 -107
  123. package/dist/lib/type-coercion.d.ts +10 -0
  124. package/dist/lib/type-coercion.js +82 -0
  125. package/dist/mcp-http-handler.js +14 -2
  126. package/dist/openclaw.plugin.json +1 -1
  127. package/dist/services/experiment-randomization.js +9 -2
  128. package/openclaw.plugin.json +1 -1
  129. package/package.json +3 -2
  130. package/dashboard/dist/assets/AqVoI3SF.js.br +0 -0
  131. package/dashboard/dist/assets/AqVoI3SF.js.gz +0 -0
  132. package/dashboard/dist/assets/BC4WvnHJ.js +0 -1
  133. package/dashboard/dist/assets/BC4WvnHJ.js.br +0 -0
  134. package/dashboard/dist/assets/BC4WvnHJ.js.gz +0 -0
  135. package/dashboard/dist/assets/BG5mwTkg.js +0 -1
  136. package/dashboard/dist/assets/BG5mwTkg.js.br +0 -0
  137. package/dashboard/dist/assets/BG5mwTkg.js.gz +0 -0
  138. package/dashboard/dist/assets/BJgZIVUQ.js +0 -53
  139. package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
  140. package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
  141. package/dashboard/dist/assets/BNh-XYPV.js +0 -1
  142. package/dashboard/dist/assets/BNh-XYPV.js.br +0 -0
  143. package/dashboard/dist/assets/BNh-XYPV.js.gz +0 -0
  144. package/dashboard/dist/assets/BTAEErUY.js +0 -1
  145. package/dashboard/dist/assets/BTAEErUY.js.br +0 -0
  146. package/dashboard/dist/assets/BTAEErUY.js.gz +0 -0
  147. package/dashboard/dist/assets/BepW_590.js +0 -1
  148. package/dashboard/dist/assets/BepW_590.js.br +0 -0
  149. package/dashboard/dist/assets/BepW_590.js.gz +0 -0
  150. package/dashboard/dist/assets/BerAfzjq.js +0 -1
  151. package/dashboard/dist/assets/BerAfzjq.js.br +0 -0
  152. package/dashboard/dist/assets/BerAfzjq.js.gz +0 -0
  153. package/dashboard/dist/assets/Bp3N-QL5.js +0 -212
  154. package/dashboard/dist/assets/Bp3N-QL5.js.br +0 -0
  155. package/dashboard/dist/assets/Bp3N-QL5.js.gz +0 -0
  156. package/dashboard/dist/assets/C-KIc3Wc.js +0 -1
  157. package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
  158. package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
  159. package/dashboard/dist/assets/C3dZRz9P.css +0 -1
  160. package/dashboard/dist/assets/C3dZRz9P.css.br +0 -0
  161. package/dashboard/dist/assets/C3dZRz9P.css.gz +0 -0
  162. package/dashboard/dist/assets/CD-q5mdP.js.br +0 -0
  163. package/dashboard/dist/assets/CD-q5mdP.js.gz +0 -0
  164. package/dashboard/dist/assets/CL_wXqR7.js +0 -1
  165. package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
  166. package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
  167. package/dashboard/dist/assets/CdvjC9G9.js +0 -1
  168. package/dashboard/dist/assets/CdvjC9G9.js.br +0 -0
  169. package/dashboard/dist/assets/CdvjC9G9.js.gz +0 -0
  170. package/dashboard/dist/assets/Ck2agw-s.js +0 -1
  171. package/dashboard/dist/assets/Ck2agw-s.js.br +0 -0
  172. package/dashboard/dist/assets/Ck2agw-s.js.gz +0 -0
  173. package/dashboard/dist/assets/CxQ08qFN.js +0 -9
  174. package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
  175. package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
  176. package/dashboard/dist/assets/D2CH1H6k.js +0 -1
  177. package/dashboard/dist/assets/D2CH1H6k.js.br +0 -0
  178. package/dashboard/dist/assets/D2CH1H6k.js.gz +0 -0
  179. package/dashboard/dist/assets/D9esz7jd.js +0 -1
  180. package/dashboard/dist/assets/D9esz7jd.js.br +0 -0
  181. package/dashboard/dist/assets/D9esz7jd.js.gz +0 -0
  182. package/dashboard/dist/assets/DCP-C7fn.js.br +0 -0
  183. package/dashboard/dist/assets/DCP-C7fn.js.gz +0 -0
  184. package/dashboard/dist/assets/DJASCd69.js +0 -1
  185. package/dashboard/dist/assets/DJASCd69.js.br +0 -0
  186. package/dashboard/dist/assets/DJASCd69.js.gz +0 -0
  187. package/dashboard/dist/assets/Dm9AybAp.js +0 -1
  188. package/dashboard/dist/assets/Dm9AybAp.js.br +0 -0
  189. package/dashboard/dist/assets/Dm9AybAp.js.gz +0 -0
  190. package/dashboard/dist/assets/Du1wfrXa.js.br +0 -0
  191. package/dashboard/dist/assets/Du1wfrXa.js.gz +0 -0
  192. package/dashboard/dist/assets/beHYBbh6.js.br +0 -0
  193. package/dashboard/dist/assets/beHYBbh6.js.gz +0 -0
  194. package/dashboard/dist/assets/cNrhgGc1.js +0 -8
  195. package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
  196. package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
  197. package/dashboard/dist/assets/tcEHYcbW.js.br +0 -0
  198. package/dashboard/dist/assets/tcEHYcbW.js.gz +0 -0
@@ -1,5 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { resolveWorkspaceScope as resolveCanonicalWorkspaceScope } from "../helpers/workspace-scope.js";
3
+ import { asRecord, asString, asStringArray } from "../../lib/type-coercion.js";
3
4
  import { buildDispatchGatewayEnvelope } from "./dispatch-gateway-envelope.js";
4
5
  const PLAY_QUEUE_LOOKUP_TIMEOUT_MS = (() => {
5
6
  const raw = process.env.ORGX_PLAY_QUEUE_LOOKUP_TIMEOUT_MS;
@@ -194,24 +195,7 @@ function shouldResetTaskStatus(status, states) {
194
195
  }
195
196
  return false;
196
197
  }
197
- function asRecord(value) {
198
- if (!value || typeof value !== "object" || Array.isArray(value))
199
- return null;
200
- return value;
201
- }
202
- function asString(value) {
203
- if (typeof value !== "string")
204
- return null;
205
- const trimmed = value.trim();
206
- return trimmed.length > 0 ? trimmed : null;
207
- }
208
- function asStringArray(value) {
209
- if (!Array.isArray(value))
210
- return [];
211
- return value
212
- .map((entry) => asString(entry))
213
- .filter((entry) => Boolean(entry));
214
- }
198
+ // asRecord, asString, asStringArray imported from ../../lib/type-coercion.js
215
199
  function parseCycleGraphNodes(graph) {
216
200
  const root = asRecord(graph);
217
201
  const rawNodes = Array.isArray(root?.nodes) ? root.nodes : [];
@@ -1652,6 +1636,39 @@ export function registerMissionControlActionsRoutes(router, deps) {
1652
1636
  sendRouteException(res, "mission-control.auto-continue.stop.handler", err);
1653
1637
  }
1654
1638
  }, "Mission-control auto-continue stop");
1639
+ router.add("POST", "mission-control/auto-continue/skip", async ({ req, query, res }) => {
1640
+ try {
1641
+ const payload = await deps.parseJsonRequest(req);
1642
+ const initiativeId = (deps.pickString(payload, ["initiativeId", "initiative_id"]) ??
1643
+ query.get("initiativeId") ??
1644
+ query.get("initiative_id") ??
1645
+ "")
1646
+ .trim();
1647
+ if (!initiativeId) {
1648
+ sendRouteError(res, 400, "mission-control.auto-continue.skip.validation", "initiativeId is required");
1649
+ return;
1650
+ }
1651
+ const workstreamId = (deps.pickString(payload, ["workstreamId", "workstream_id"]) ??
1652
+ query.get("workstreamId") ??
1653
+ query.get("workstream_id") ??
1654
+ "")
1655
+ .trim();
1656
+ if (!workstreamId) {
1657
+ sendRouteError(res, 400, "mission-control.auto-continue.skip.validation", "workstreamId is required");
1658
+ return;
1659
+ }
1660
+ const reason = (deps.pickString(payload, ["reason"]) ??
1661
+ query.get("reason") ??
1662
+ "")
1663
+ .trim() || undefined;
1664
+ const result = await deps.skipCurrentWorkstream(initiativeId, workstreamId, reason);
1665
+ deps.clearNextUpQueueCache(initiativeId);
1666
+ deps.sendJson(res, result.ok ? 200 : 404, result);
1667
+ }
1668
+ catch (err) {
1669
+ sendRouteException(res, "mission-control.auto-continue.skip.handler", err);
1670
+ }
1671
+ }, "Mission-control auto-continue skip");
1655
1672
  router.add("POST", "mission-control/auto-continue/tick", async ({ req, query, res }) => {
1656
1673
  try {
1657
1674
  const payload = await deps.parseJsonRequest(req);
@@ -1,34 +1,7 @@
1
1
  import { listBuiltInSentinels } from "../helpers/sentinel-catalog.js";
2
2
  import { resolveWorkspaceScope, workspaceScopeFromHeaders, } from "../helpers/workspace-scope.js";
3
- function asRecord(value) {
4
- if (!value || typeof value !== "object" || Array.isArray(value))
5
- return null;
6
- return value;
7
- }
8
- function asString(value) {
9
- if (typeof value !== "string")
10
- return null;
11
- const trimmed = value.trim();
12
- return trimmed.length > 0 ? trimmed : null;
13
- }
14
- function asArray(value) {
15
- if (Array.isArray(value))
16
- return value;
17
- if (typeof value !== "string")
18
- return [];
19
- const trimmed = value.trim();
20
- try {
21
- const parsed = JSON.parse(trimmed);
22
- if (Array.isArray(parsed))
23
- return parsed;
24
- if (parsed && typeof parsed === "object")
25
- return [parsed];
26
- return [];
27
- }
28
- catch {
29
- return [];
30
- }
31
- }
3
+ import { asRecord, asString, asNumber, asArray, asStringArray, } from "../../lib/type-coercion.js";
4
+ // asRecord, asString, asArray, asNumber, asStringArray imported from ../../lib/type-coercion.js
32
5
  function normalizeRunnerValue(value) {
33
6
  const raw = asString(value);
34
7
  if (!raw)
@@ -105,29 +78,7 @@ function mergeRunnerAgents(...groups) {
105
78
  }
106
79
  return output;
107
80
  }
108
- function asNumber(value) {
109
- if (typeof value === "number" && Number.isFinite(value))
110
- return value;
111
- if (typeof value === "string" && value.trim().length > 0) {
112
- const parsed = Number(value);
113
- if (Number.isFinite(parsed))
114
- return parsed;
115
- }
116
- return null;
117
- }
118
- function asStringArray(value) {
119
- const entries = asArray(value);
120
- if (entries.length === 0)
121
- return [];
122
- const values = [];
123
- for (const entry of entries) {
124
- const normalized = asString(entry);
125
- if (!normalized)
126
- continue;
127
- values.push(normalized);
128
- }
129
- return dedupeStrings(values);
130
- }
81
+ // asNumber, asStringArray imported from ../../lib/type-coercion.js
131
82
  function isCanonicalAllScopeMismatch(canonicalRecord, useAllScope) {
132
83
  if (!useAllScope)
133
84
  return false;
@@ -846,64 +797,10 @@ export function registerMissionControlReadRoutes(router, deps) {
846
797
  sendRouteError(res, 400, "mission-control.read.auto-continue.status.validation", workspaceScope.error);
847
798
  return;
848
799
  }
849
- const scopedProjectId = workspaceScope.workspaceId;
850
800
  const initiativeId = query.get("initiative_id") ?? query.get("initiativeId") ?? "";
851
801
  const id = initiativeId.trim();
852
- let scopedInitiatives = null;
853
- if (scopedProjectId) {
854
- try {
855
- const ids = await deps.listInitiativeIdsForProject({ projectId: scopedProjectId });
856
- scopedInitiatives = new Set(ids);
857
- }
858
- catch {
859
- // best effort: if scope lookup is unavailable, fall back to unscoped run resolution.
860
- scopedInitiatives = null;
861
- }
862
- }
863
- const statusRank = (value) => {
864
- const normalized = (value ?? "").trim().toLowerCase();
865
- if (normalized === "running")
866
- return 0;
867
- if (normalized === "stopping")
868
- return 1;
869
- if (normalized === "blocked")
870
- return 2;
871
- if (normalized === "stopped")
872
- return 3;
873
- return 4;
874
- };
875
- const updatedEpoch = (value) => {
876
- const parsed = Date.parse(value ?? "");
877
- return Number.isFinite(parsed) ? parsed : 0;
878
- };
879
802
  if (!id) {
880
- const scopedRuns = Array.from(deps.autoContinueRuns.values()).filter((run) => {
881
- const runInitiativeId = (run.initiativeId ?? "").trim();
882
- if (!runInitiativeId)
883
- return false;
884
- if (scopedInitiatives && !scopedInitiatives.has(runInitiativeId))
885
- return false;
886
- return true;
887
- });
888
- scopedRuns.sort((left, right) => {
889
- const statusDelta = statusRank(left.status) - statusRank(right.status);
890
- if (statusDelta !== 0)
891
- return statusDelta;
892
- return updatedEpoch(right.updatedAt) - updatedEpoch(left.updatedAt);
893
- });
894
- const run = scopedRuns[0] ?? null;
895
- deps.sendJson(res, 200, {
896
- ok: true,
897
- initiativeId: run?.initiativeId ?? null,
898
- run,
899
- defaults: {
900
- tokenBudget: deps.defaultAutoContinueTokenBudget(),
901
- maxParallelSlices: typeof deps.defaultAutoContinueMaxParallelSlices === "function"
902
- ? deps.defaultAutoContinueMaxParallelSlices()
903
- : 1,
904
- tickMs: deps.autoContinueTickMs,
905
- },
906
- });
803
+ sendRouteError(res, 400, "mission-control.read.auto-continue.status.validation", "initiativeId is required");
907
804
  return;
908
805
  }
909
806
  const run = deps.autoContinueRuns.get(id) ?? null;
@@ -0,0 +1,10 @@
1
+ /** Safely cast unknown to a Record, or null if not a plain object. */
2
+ export declare function asRecord(value: unknown): Record<string, unknown> | null;
3
+ /** Safely cast unknown to a trimmed non-empty string, or null. */
4
+ export declare function asString(value: unknown): string | null;
5
+ /** Safely cast unknown to a finite number, or null. */
6
+ export declare function asNumber(value: unknown): number | null;
7
+ /** Safely cast unknown to an array. Attempts JSON parse for string values. */
8
+ export declare function asArray(value: unknown): unknown[];
9
+ /** Extract a deduplicated string array from unknown. */
10
+ export declare function asStringArray(value: unknown): string[];
@@ -0,0 +1,82 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Shared type-coercion helpers for safe parsing of unknown API data.
3
+ // Previously duplicated across 20+ files.
4
+ // ---------------------------------------------------------------------------
5
+ /** Safely cast unknown to a Record, or null if not a plain object. */
6
+ export function asRecord(value) {
7
+ if (!value || typeof value !== "object" || Array.isArray(value))
8
+ return null;
9
+ const proto = Object.getPrototypeOf(value);
10
+ if (proto !== Object.prototype && proto !== null)
11
+ return null;
12
+ return value;
13
+ }
14
+ /** Safely cast unknown to a trimmed non-empty string, or null. */
15
+ export function asString(value) {
16
+ if (typeof value !== "string")
17
+ return null;
18
+ const trimmed = value.trim();
19
+ return trimmed.length > 0 ? trimmed : null;
20
+ }
21
+ /** Safely cast unknown to a finite number, or null. */
22
+ export function asNumber(value) {
23
+ if (typeof value === "number" && Number.isFinite(value))
24
+ return value;
25
+ if (typeof value === "string" && value.trim().length > 0) {
26
+ const parsed = Number(value);
27
+ if (Number.isFinite(parsed))
28
+ return parsed;
29
+ }
30
+ return null;
31
+ }
32
+ /** Safely cast unknown to an array. Attempts JSON parse for string values. */
33
+ export function asArray(value) {
34
+ if (Array.isArray(value))
35
+ return value;
36
+ if (asRecord(value))
37
+ return [value];
38
+ if (typeof value !== "string")
39
+ return [];
40
+ const trimmed = value.trim();
41
+ try {
42
+ const parsed = JSON.parse(trimmed);
43
+ if (Array.isArray(parsed))
44
+ return parsed;
45
+ if (asRecord(parsed))
46
+ return [parsed];
47
+ return [];
48
+ }
49
+ catch {
50
+ return [];
51
+ }
52
+ }
53
+ /** Extract a deduplicated string array from unknown. */
54
+ export function asStringArray(value) {
55
+ const entries = asArray(value);
56
+ if (entries.length === 0) {
57
+ const scalar = asString(value);
58
+ if (!scalar)
59
+ return [];
60
+ const fallbackEntries = scalar.includes(",") ? scalar.split(",") : [scalar];
61
+ const seenFallback = new Set();
62
+ const fallbackValues = [];
63
+ for (const entry of fallbackEntries) {
64
+ const normalized = asString(entry);
65
+ if (!normalized || seenFallback.has(normalized))
66
+ continue;
67
+ seenFallback.add(normalized);
68
+ fallbackValues.push(normalized);
69
+ }
70
+ return fallbackValues;
71
+ }
72
+ const seen = new Set();
73
+ const values = [];
74
+ for (const entry of entries) {
75
+ const normalized = asString(entry);
76
+ if (!normalized || seen.has(normalized))
77
+ continue;
78
+ seen.add(normalized);
79
+ values.push(normalized);
80
+ }
81
+ return values;
82
+ }
@@ -136,6 +136,13 @@ async function readRequestBodyBuffer(req) {
136
136
  return Buffer.from("", "utf8");
137
137
  return await new Promise((resolve) => {
138
138
  const chunks = [];
139
+ let settled = false;
140
+ const settle = () => {
141
+ if (settled)
142
+ return;
143
+ settled = true;
144
+ resolve(Buffer.concat(chunks));
145
+ };
139
146
  const onData = (chunk) => {
140
147
  if (typeof chunk === "string") {
141
148
  chunks.push(Buffer.from(chunk, "utf8"));
@@ -147,9 +154,14 @@ async function readRequestBodyBuffer(req) {
147
154
  chunks.push(Buffer.from(chunk));
148
155
  }
149
156
  };
150
- const onEnd = () => resolve(Buffer.concat(chunks));
151
- const onError = () => resolve(Buffer.concat(chunks));
157
+ const onEnd = () => settle();
158
+ const onError = () => settle();
152
159
  req.on?.("data", onData);
160
+ if (typeof req.once === "function") {
161
+ req.once("end", onEnd);
162
+ req.once("error", onError);
163
+ return;
164
+ }
153
165
  req.on?.("end", onEnd);
154
166
  req.on?.("error", onError);
155
167
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "openclaw-plugin",
3
3
  "name": "OrgX Integration",
4
- "version": "1.0.4",
4
+ "version": "1.0.7",
5
5
  "description": "Connects Clawdbot to OrgX for agent orchestration, quality gates, and model routing",
6
6
  "entry": "./index.js",
7
7
  "author": "OrgX Team",
@@ -23,8 +23,13 @@ function normalizeArms(arms) {
23
23
  if (!Array.isArray(arms) || arms.length === 0) {
24
24
  throw new Error("arms must include at least one entry");
25
25
  }
26
+ const seenIds = new Set();
26
27
  const sanitized = arms.map((arm, index) => {
27
28
  const id = sanitizeIdentifier(arm?.id, `arms[${index}].id`);
29
+ if (seenIds.has(id)) {
30
+ throw new Error(`arms[${index}].id must be unique`);
31
+ }
32
+ seenIds.add(id);
28
33
  const weight = Number.isFinite(arm?.weight) ? Number(arm.weight) : Number.NaN;
29
34
  if (!Number.isFinite(weight) || weight <= 0) {
30
35
  throw new Error(`arms[${index}].weight must be > 0`);
@@ -58,6 +63,8 @@ function sanitizeIdentifier(value, field) {
58
63
  return trimmed;
59
64
  }
60
65
  function bucketFromHash(hash) {
61
- const first53Bits = hash.slice(0, 14);
62
- return parseInt(first53Bits, 16) / MAX_UINT53;
66
+ // Keep only 53 high-order bits from the 56-bit hex prefix.
67
+ const first56Bits = parseInt(hash.slice(0, 14), 16);
68
+ const first53Bits = Math.floor(first56Bits / 8);
69
+ return first53Bits / (MAX_UINT53 + 1);
63
70
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "openclaw-plugin",
3
3
  "name": "OrgX Integration",
4
- "version": "1.0.4",
4
+ "version": "1.0.7",
5
5
  "description": "Connects Clawdbot to OrgX for agent orchestration, quality gates, and model routing",
6
6
  "entry": "./dist/index.js",
7
7
  "author": "OrgX Team",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useorgx/openclaw-plugin",
3
- "version": "0.7.11",
3
+ "version": "0.7.16",
4
4
  "description": "OrgX plugin for OpenClaw — agent orchestration, quality gates, model routing, and live dashboard",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -52,6 +52,7 @@
52
52
  "verify:iwmt-cascade": "npm run build:core && node ./scripts/verify-iwmt-cascade-e2e.mjs",
53
53
  "verify:live-ui:p0": "node ./scripts/agent-browser-live-ui-p0-audit.mjs",
54
54
  "verify:conduit-mcp": "node ./scripts/verify-conduit-mcp.mjs",
55
+ "verify:repo-hygiene": "node ./scripts/verify-repo-hygiene.mjs",
55
56
  "dev:main": "node ./scripts/dev-main-sync.mjs",
56
57
  "e2e:auto-continue": "node ./scripts/e2e-auto-continue.mjs",
57
58
  "e2e:agent-suite": "npm run build:core && node ./scripts/e2e-agent-suite-kickoff-3x.mjs",
@@ -94,7 +95,7 @@
94
95
  },
95
96
  "repository": {
96
97
  "type": "git",
97
- "url": "https://github.com/useorgx/openclaw-plugin.git"
98
+ "url": "git+https://github.com/useorgx/openclaw-plugin.git"
98
99
  },
99
100
  "homepage": "https://useorgx.com",
100
101
  "bugs": {
@@ -1 +0,0 @@
1
- import{r as c,a as g}from"./cNrhgGc1.js";import{b as m,h as n}from"./Bp3N-QL5.js";function p({authToken:s=null,embedMode:a=!1,enabled:i=!0}={}){var t;const u=c.useMemo(()=>["usage-control-plane",{authToken:s,embedMode:a}],[s,a]),e=g({queryKey:u,enabled:i,queryFn:async()=>{const o=await fetch("/orgx/api/usage/control-plane/summary",{headers:m({authToken:s,embedMode:a})}),r=await o.json().catch(()=>null);if(!o.ok){const l=(r&&typeof r=="object"&&"error"in r&&typeof r.error=="string"?r.error:null)??(r&&typeof r=="object"&&"message"in r&&typeof r.message=="string"?r.message:null)??`Failed to load usage summary (${o.status})`;throw new Error(n(l))}if(!r||typeof r!="object"||!("generatedAt"in r))throw new Error(n("Usage summary response is missing required fields."));return r},refetchInterval:6e4});return{summary:e.data??null,isLoading:e.isLoading,isFetching:e.isFetching,error:((t=e.error)==null?void 0:t.message)??null,refetch:e.refetch}}export{p as u};
@@ -1 +0,0 @@
1
- import{r as o,j as e}from"./cNrhgGc1.js";import{e as l,y as p,E as h,_ as u}from"./Bp3N-QL5.js";import{DecisionQueue as b}from"./Dm9AybAp.js";import"./C-KIc3Wc.js";import"./BJgZIVUQ.js";import"./CxQ08qFN.js";import"./CD-q5mdP.js";import"./AqVoI3SF.js";function C({open:n,onClose:a,decisions:t,onApproveDecision:i,onRejectDecision:d,onApproveAll:m,onBulkDecisionAction:x}){const r=o.useMemo(()=>t.length>0?Math.max(0,...t.map(c=>c.waitingMinutes)):0,[t]),s=o.useMemo(()=>t.length>=20||r>=15?l.red:t.length>0?l.amber:l.textMuted,[t.length,r]);return e.jsx(p,{open:n,onClose:a,maxWidth:"max-w-3xl",children:e.jsxs("div",{className:"flex h-full w-full flex-col",children:[e.jsx("div",{className:"border-b border-subtle px-5 pt-5 pb-4",children:e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("h3",{className:"inline-flex items-center gap-2 text-heading font-semibold text-white",children:[e.jsx(h,{type:"decision",size:14}),e.jsx("span",{className:"truncate",children:"Decisions"}),e.jsx("span",{className:"rounded-full border px-2 py-0.5 text-caption font-semibold",style:{borderColor:`${s}30`,backgroundColor:`${s}14`,color:s},children:t.length})]}),e.jsx("p",{className:"mt-1 text-body leading-relaxed text-secondary",children:"Bulk review and resolve pending decisions."}),t.length>0&&e.jsxs("p",{className:"mt-2 text-caption text-secondary",children:["Oldest: ",e.jsxs("span",{className:"font-semibold text-white",children:[u(r)," ago"]})]})]}),e.jsx("button",{type:"button",onClick:a,className:"rounded-md border border-strong bg-white/[0.03] px-2.5 py-1.5 text-caption text-primary transition-colors hover:bg-white/[0.08]","aria-label":"Close decisions modal",children:"Close"})]})}),e.jsx("div",{className:"min-h-0 flex-1 overflow-hidden p-4",children:e.jsx(b,{decisions:t,onApproveDecision:i,onRejectDecision:d,onApproveAll:m,onBulkDecisionAction:x})})]})})}export{C as BulkDecisionsModal};