@useorgx/openclaw-plugin 0.7.6 → 0.7.11

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 (127) hide show
  1. package/dashboard/dist/assets/{CnitK1MX.js → AqVoI3SF.js} +1 -1
  2. package/dashboard/dist/assets/AqVoI3SF.js.br +0 -0
  3. package/dashboard/dist/assets/AqVoI3SF.js.gz +0 -0
  4. package/dashboard/dist/assets/BC4WvnHJ.js +1 -0
  5. package/dashboard/dist/assets/BC4WvnHJ.js.br +0 -0
  6. package/dashboard/dist/assets/BC4WvnHJ.js.gz +0 -0
  7. package/dashboard/dist/assets/{DOFL9l8s.js → BG5mwTkg.js} +1 -1
  8. package/dashboard/dist/assets/BG5mwTkg.js.br +0 -0
  9. package/dashboard/dist/assets/BG5mwTkg.js.gz +0 -0
  10. package/dashboard/dist/assets/BNh-XYPV.js +1 -0
  11. package/dashboard/dist/assets/BNh-XYPV.js.br +0 -0
  12. package/dashboard/dist/assets/BNh-XYPV.js.gz +0 -0
  13. package/dashboard/dist/assets/{CFwPph5U.js → BepW_590.js} +1 -1
  14. package/dashboard/dist/assets/BepW_590.js.br +0 -0
  15. package/dashboard/dist/assets/BepW_590.js.gz +0 -0
  16. package/dashboard/dist/assets/BerAfzjq.js +1 -0
  17. package/dashboard/dist/assets/BerAfzjq.js.br +0 -0
  18. package/dashboard/dist/assets/BerAfzjq.js.gz +0 -0
  19. package/dashboard/dist/assets/Bp3N-QL5.js +212 -0
  20. package/dashboard/dist/assets/Bp3N-QL5.js.br +0 -0
  21. package/dashboard/dist/assets/Bp3N-QL5.js.gz +0 -0
  22. package/dashboard/dist/assets/C3dZRz9P.css +1 -0
  23. package/dashboard/dist/assets/C3dZRz9P.css.br +0 -0
  24. package/dashboard/dist/assets/C3dZRz9P.css.gz +0 -0
  25. package/dashboard/dist/assets/CD-q5mdP.js +1 -0
  26. package/dashboard/dist/assets/CD-q5mdP.js.br +0 -0
  27. package/dashboard/dist/assets/CD-q5mdP.js.gz +0 -0
  28. package/dashboard/dist/assets/{BgcAY5rE.js → CdvjC9G9.js} +1 -1
  29. package/dashboard/dist/assets/CdvjC9G9.js.br +0 -0
  30. package/dashboard/dist/assets/CdvjC9G9.js.gz +0 -0
  31. package/dashboard/dist/assets/Ck2agw-s.js +1 -0
  32. package/dashboard/dist/assets/Ck2agw-s.js.br +0 -0
  33. package/dashboard/dist/assets/Ck2agw-s.js.gz +0 -0
  34. package/dashboard/dist/assets/{D7DHFX0D.js → D2CH1H6k.js} +1 -1
  35. package/dashboard/dist/assets/D2CH1H6k.js.br +0 -0
  36. package/dashboard/dist/assets/D2CH1H6k.js.gz +0 -0
  37. package/dashboard/dist/assets/D9esz7jd.js +1 -0
  38. package/dashboard/dist/assets/D9esz7jd.js.br +0 -0
  39. package/dashboard/dist/assets/D9esz7jd.js.gz +0 -0
  40. package/dashboard/dist/assets/{77gGFBt6.js → DCP-C7fn.js} +1 -1
  41. package/dashboard/dist/assets/DCP-C7fn.js.br +0 -0
  42. package/dashboard/dist/assets/DCP-C7fn.js.gz +0 -0
  43. package/dashboard/dist/assets/{CSr2ZnTV.js → DJASCd69.js} +1 -1
  44. package/dashboard/dist/assets/DJASCd69.js.br +0 -0
  45. package/dashboard/dist/assets/DJASCd69.js.gz +0 -0
  46. package/dashboard/dist/assets/Dm9AybAp.js +1 -0
  47. package/dashboard/dist/assets/Dm9AybAp.js.br +0 -0
  48. package/dashboard/dist/assets/Dm9AybAp.js.gz +0 -0
  49. package/dashboard/dist/assets/{DxKG5zy8.js → Du1wfrXa.js} +1 -1
  50. package/dashboard/dist/assets/Du1wfrXa.js.br +0 -0
  51. package/dashboard/dist/assets/Du1wfrXa.js.gz +0 -0
  52. package/dashboard/dist/assets/{DpuQm1oF.js → beHYBbh6.js} +1 -1
  53. package/dashboard/dist/assets/beHYBbh6.js.br +0 -0
  54. package/dashboard/dist/assets/beHYBbh6.js.gz +0 -0
  55. package/dashboard/dist/index.html +2 -2
  56. package/dashboard/dist/index.html.br +0 -0
  57. package/dashboard/dist/index.html.gz +0 -0
  58. package/dist/hash-utils.js +2 -1
  59. package/dist/http/helpers/auto-continue-engine.d.ts +36 -0
  60. package/dist/http/helpers/auto-continue-engine.js +83 -17
  61. package/dist/http/helpers/autopilot-runtime.d.ts +1 -0
  62. package/dist/http/helpers/autopilot-runtime.js +31 -3
  63. package/dist/http/helpers/autopilot-slice-utils.d.ts +10 -0
  64. package/dist/http/helpers/autopilot-slice-utils.js +58 -0
  65. package/dist/http/helpers/humanize-slice-failure.d.ts +35 -0
  66. package/dist/http/helpers/humanize-slice-failure.js +137 -0
  67. package/dist/http/helpers/mission-control.d.ts +1 -0
  68. package/dist/http/helpers/mission-control.js +72 -5
  69. package/dist/http/index.js +65 -3
  70. package/dist/http/routes/live-misc.js +12 -4
  71. package/dist/http/routes/live-snapshot.js +10 -4
  72. package/dist/http/routes/mission-control-actions.js +5 -0
  73. package/dist/http/routes/mission-control-read.d.ts +1 -0
  74. package/dist/http/routes/mission-control-read.js +65 -4
  75. package/dist/index.d.ts +8 -1
  76. package/dist/index.js +21 -1
  77. package/dist/mcp-http-handler.js +6 -0
  78. package/dist/openclaw.plugin.json +1 -1
  79. package/dist/tools/core-tools.d.ts +27 -0
  80. package/dist/tools/core-tools.js +89 -0
  81. package/openclaw.plugin.json +1 -1
  82. package/package.json +1 -1
  83. package/dashboard/dist/assets/77gGFBt6.js.br +0 -0
  84. package/dashboard/dist/assets/77gGFBt6.js.gz +0 -0
  85. package/dashboard/dist/assets/BBpTN_SR.js +0 -1
  86. package/dashboard/dist/assets/BBpTN_SR.js.br +0 -0
  87. package/dashboard/dist/assets/BBpTN_SR.js.gz +0 -0
  88. package/dashboard/dist/assets/BVShoyjA.js +0 -1
  89. package/dashboard/dist/assets/BVShoyjA.js.br +0 -0
  90. package/dashboard/dist/assets/BVShoyjA.js.gz +0 -0
  91. package/dashboard/dist/assets/BgcAY5rE.js.br +0 -0
  92. package/dashboard/dist/assets/BgcAY5rE.js.gz +0 -0
  93. package/dashboard/dist/assets/C-PAoJF-.js +0 -1
  94. package/dashboard/dist/assets/C-PAoJF-.js.br +0 -0
  95. package/dashboard/dist/assets/C-PAoJF-.js.gz +0 -0
  96. package/dashboard/dist/assets/C0nA-iUG.js +0 -1
  97. package/dashboard/dist/assets/C0nA-iUG.js.br +0 -0
  98. package/dashboard/dist/assets/C0nA-iUG.js.gz +0 -0
  99. package/dashboard/dist/assets/C6GO-FKy.js +0 -1
  100. package/dashboard/dist/assets/C6GO-FKy.js.br +0 -0
  101. package/dashboard/dist/assets/C6GO-FKy.js.gz +0 -0
  102. package/dashboard/dist/assets/CFwPph5U.js.br +0 -0
  103. package/dashboard/dist/assets/CFwPph5U.js.gz +0 -0
  104. package/dashboard/dist/assets/CPjsbbgZ.js +0 -212
  105. package/dashboard/dist/assets/CPjsbbgZ.js.br +0 -0
  106. package/dashboard/dist/assets/CPjsbbgZ.js.gz +0 -0
  107. package/dashboard/dist/assets/CSr2ZnTV.js.br +0 -0
  108. package/dashboard/dist/assets/CSr2ZnTV.js.gz +0 -0
  109. package/dashboard/dist/assets/CgQDT6yL.js +0 -1
  110. package/dashboard/dist/assets/CgQDT6yL.js.br +0 -0
  111. package/dashboard/dist/assets/CgQDT6yL.js.gz +0 -0
  112. package/dashboard/dist/assets/CnitK1MX.js.br +0 -0
  113. package/dashboard/dist/assets/CnitK1MX.js.gz +0 -0
  114. package/dashboard/dist/assets/D7DHFX0D.js.br +0 -0
  115. package/dashboard/dist/assets/D7DHFX0D.js.gz +0 -0
  116. package/dashboard/dist/assets/DEip7uko.js +0 -1
  117. package/dashboard/dist/assets/DEip7uko.js.br +0 -0
  118. package/dashboard/dist/assets/DEip7uko.js.gz +0 -0
  119. package/dashboard/dist/assets/DHUSLc01.css +0 -1
  120. package/dashboard/dist/assets/DHUSLc01.css.br +0 -0
  121. package/dashboard/dist/assets/DHUSLc01.css.gz +0 -0
  122. package/dashboard/dist/assets/DOFL9l8s.js.br +0 -0
  123. package/dashboard/dist/assets/DOFL9l8s.js.gz +0 -0
  124. package/dashboard/dist/assets/DpuQm1oF.js.br +0 -0
  125. package/dashboard/dist/assets/DpuQm1oF.js.gz +0 -0
  126. package/dashboard/dist/assets/DxKG5zy8.js.br +0 -0
  127. package/dashboard/dist/assets/DxKG5zy8.js.gz +0 -0
@@ -106,8 +106,64 @@ async function resolveSkillPackOverrides(input) {
106
106
  }
107
107
  }
108
108
  function safeErrorMessage(err) {
109
- const raw = err instanceof Error ? err.message : typeof err === "string" ? err : "";
110
- const normalized = raw.trim().toLowerCase();
109
+ const raw = err instanceof Error
110
+ ? err.message
111
+ : typeof err === "string"
112
+ ? err
113
+ : err && typeof err === "object" && "message" in err && typeof err.message === "string"
114
+ ? (err.message ?? "")
115
+ : "";
116
+ const parseStructuredMessage = (value) => {
117
+ const trimmed = value.trim();
118
+ if (!trimmed)
119
+ return null;
120
+ const parseObjectMessage = (parsed) => {
121
+ if (!parsed || typeof parsed !== "object")
122
+ return null;
123
+ const root = parsed;
124
+ const nested = root.error && typeof root.error === "object" ? root.error : null;
125
+ const envelope = nested ?? root;
126
+ return ((typeof envelope.message === "string" && envelope.message.trim()) ||
127
+ (typeof envelope.detail === "string" && envelope.detail.trim()) ||
128
+ (!nested && typeof root.error === "string" && root.error.trim()) ||
129
+ null);
130
+ };
131
+ try {
132
+ const parsed = JSON.parse(trimmed);
133
+ const direct = parseObjectMessage(parsed);
134
+ if (direct)
135
+ return direct;
136
+ }
137
+ catch {
138
+ // Continue and try extracting embedded JSON payloads.
139
+ }
140
+ const firstBrace = trimmed.indexOf("{");
141
+ const lastBrace = trimmed.lastIndexOf("}");
142
+ if (firstBrace >= 0 && lastBrace > firstBrace) {
143
+ const candidate = trimmed.slice(firstBrace, lastBrace + 1);
144
+ try {
145
+ const parsed = JSON.parse(candidate);
146
+ return parseObjectMessage(parsed);
147
+ }
148
+ catch {
149
+ return null;
150
+ }
151
+ }
152
+ return null;
153
+ };
154
+ const stripStructuredNoise = (value) => value
155
+ .replace(/"requestId"\s*:\s*"[^"]*"/gi, "")
156
+ .replace(/"timestamp"\s*:\s*"[^"]*"/gi, "")
157
+ .replace(/"docsUrl"\s*:\s*"[^"]*"/gi, "")
158
+ .replace(/\brequest[_\s-]?id[:=]\s*[\w-]+/gi, "")
159
+ .replace(/\btimestamp[:=]\s*\S+/gi, "")
160
+ .replace(/\bdocsUrl[:=]\s*\S+/gi, "")
161
+ .replace(/[{}]/g, " ")
162
+ .replace(/\s{2,}/g, " ")
163
+ .trim();
164
+ const normalizedMessage = parseStructuredMessage(raw) ?? raw;
165
+ const sanitized = stripStructuredNoise(normalizedMessage);
166
+ const normalized = sanitized.toLowerCase();
111
167
  if (normalized.length > 0) {
112
168
  if (normalized.includes("signal is aborted") ||
113
169
  normalized.includes("aborterror") ||
@@ -121,7 +177,13 @@ function safeErrorMessage(err) {
121
177
  if (normalized.includes("failed to fetch") || normalized.includes("network")) {
122
178
  return "network request failed";
123
179
  }
124
- return raw;
180
+ if (normalized.includes("internal_error") || normalized.includes("internal server error")) {
181
+ return "temporary server issue";
182
+ }
183
+ if (normalized.includes("failed to list decision") || normalized.includes("failed to load decision")) {
184
+ return "decision data temporarily unavailable";
185
+ }
186
+ return sanitized;
125
187
  }
126
188
  return "Unexpected error";
127
189
  }
@@ -1,5 +1,6 @@
1
1
  import { resolveWorkspaceScope, workspaceScopeFromHeaders, } from "../helpers/workspace-scope.js";
2
2
  import { summarizeTaskStatuses } from "../../reporting/rollups.js";
3
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3
4
  function asRecord(input) {
4
5
  if (!input || typeof input !== "object" || Array.isArray(input))
5
6
  return null;
@@ -30,8 +31,15 @@ export function registerLiveMiscRoutes(router, deps) {
30
31
  const projectId = projectIdRaw?.trim() ?? "";
31
32
  if (!projectId)
32
33
  return null;
33
- const ids = await deps.listInitiativeIdsForProject({ projectId });
34
- return new Set(ids);
34
+ try {
35
+ const ids = await deps.listInitiativeIdsForProject({ projectId });
36
+ return new Set(ids);
37
+ }
38
+ catch {
39
+ // Scope discovery is best-effort. Continue with unscoped fallback data
40
+ // instead of hard-failing live surfaces.
41
+ return null;
42
+ }
35
43
  }
36
44
  router.add("POST", "live/activity/headline", async ({ req, res }) => {
37
45
  try {
@@ -447,9 +455,9 @@ export function registerLiveMiscRoutes(router, deps) {
447
455
  let totalActiveAgents = 0;
448
456
  for (const initiative of initiatives) {
449
457
  totalActiveAgents += initiative.activeAgents;
450
- // Try to get task statuses from graph
458
+ // Try to get task statuses from graph (skip local placeholder IDs like "agent:orgx")
451
459
  let taskStatuses = [];
452
- if (deps.buildMissionControlGraph) {
460
+ if (deps.buildMissionControlGraph && UUID_RE.test(initiative.id)) {
453
461
  try {
454
462
  const graphRaw = await deps.buildMissionControlGraph(initiative.id);
455
463
  const graph = asRecord(graphRaw);
@@ -13,7 +13,7 @@ const LIVE_SNAPSHOT_UPSTREAM_TIMEOUT_MS = (() => {
13
13
  const LIVE_SNAPSHOT_NEXT_UP_TIMEOUT_MS = (() => {
14
14
  const raw = Number(process.env.ORGX_LIVE_SNAPSHOT_NEXT_UP_TIMEOUT_MS ?? "");
15
15
  if (!Number.isFinite(raw))
16
- return 1_200;
16
+ return 350;
17
17
  return Math.max(250, Math.min(15_000, Math.floor(raw)));
18
18
  })();
19
19
  async function withSoftTimeout(work, timeoutMs, label) {
@@ -280,9 +280,15 @@ export function registerLiveSnapshotRoutes(router, deps) {
280
280
  const agentContexts = contextStore.agents;
281
281
  const runContexts = contextStore.runs ?? {};
282
282
  const scopedAgentIds = deps.getScopedAgentIds(agentContexts);
283
- const scopedProjectInitiativeIds = projectId && projectId.trim().length > 0
284
- ? new Set(await deps.listInitiativeIdsForProject({ projectId: projectId.trim() }))
285
- : null;
283
+ let scopedProjectInitiativeIds = null;
284
+ if (projectId && projectId.trim().length > 0) {
285
+ try {
286
+ scopedProjectInitiativeIds = new Set(await deps.listInitiativeIdsForProject({ projectId: projectId.trim() }));
287
+ }
288
+ catch (err) {
289
+ degraded.push(`workspace initiative scope unavailable (${deps.safeErrorMessage(err)})`);
290
+ }
291
+ }
286
292
  let outboxStatus;
287
293
  try {
288
294
  const diagnosticsOutbox = await deps.readDiagnosticsOutboxStatus();
@@ -456,6 +456,7 @@ export function registerMissionControlActionsRoutes(router, deps) {
456
456
  ignoreSpawnGuardRateLimit: ignoreSpawnGuardRateLimit === true,
457
457
  scope,
458
458
  });
459
+ deps.clearNextUpQueueCache(initiativeId);
459
460
  const dispatchId = randomUUID();
460
461
  const playDispatchEnvelope = (dispatchMode) => buildDispatchGatewayEnvelope({
461
462
  dispatchId,
@@ -1593,6 +1594,7 @@ export function registerMissionControlActionsRoutes(router, deps) {
1593
1594
  ignoreSpawnGuardRateLimit: ignoreSpawnGuardRateLimit === true,
1594
1595
  scope: startScope,
1595
1596
  });
1597
+ deps.clearNextUpQueueCache(initiativeId);
1596
1598
  const dispatchEnvelope = buildDispatchGatewayEnvelope({
1597
1599
  dispatchMode: "server",
1598
1600
  route: "mission-control.auto-continue.start",
@@ -1643,6 +1645,7 @@ export function registerMissionControlActionsRoutes(router, deps) {
1643
1645
  // best effort
1644
1646
  }
1645
1647
  }
1648
+ deps.clearNextUpQueueCache(initiativeId);
1646
1649
  deps.sendJson(res, 200, { ok: true, run });
1647
1650
  }
1648
1651
  catch (err) {
@@ -1664,10 +1667,12 @@ export function registerMissionControlActionsRoutes(router, deps) {
1664
1667
  return;
1665
1668
  }
1666
1669
  await deps.tickAutoContinueRun(run);
1670
+ deps.clearNextUpQueueCache(initiativeId);
1667
1671
  deps.sendJson(res, 200, { ok: true, initiativeId, run });
1668
1672
  return;
1669
1673
  }
1670
1674
  await deps.tickAllAutoContinue();
1675
+ deps.clearNextUpQueueCache(null);
1671
1676
  deps.sendJson(res, 200, { ok: true });
1672
1677
  }
1673
1678
  catch (err) {
@@ -5,6 +5,7 @@ type AutoContinueRunRecord = {
5
5
  status?: string;
6
6
  startedAt?: string;
7
7
  stoppedAt?: string | null;
8
+ updatedAt?: string | null;
8
9
  tokenBudget?: number | null;
9
10
  maxParallelSlices?: number;
10
11
  parallelMode?: string;
@@ -838,11 +838,72 @@ export function registerMissionControlReadRoutes(router, deps) {
838
838
  const sendRouteException = (res, location, err) => {
839
839
  sendRouteError(res, 500, location, deps.safeErrorMessage(err));
840
840
  };
841
- async function renderAutoContinueStatus(query, res) {
841
+ async function renderAutoContinueStatus(query, res, headerScope) {
842
+ const workspaceScope = resolveWorkspaceScope(query, headerScope, {
843
+ allowProjectScope: false,
844
+ });
845
+ if (workspaceScope.error) {
846
+ sendRouteError(res, 400, "mission-control.read.auto-continue.status.validation", workspaceScope.error);
847
+ return;
848
+ }
849
+ const scopedProjectId = workspaceScope.workspaceId;
842
850
  const initiativeId = query.get("initiative_id") ?? query.get("initiativeId") ?? "";
843
851
  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
+ };
844
879
  if (!id) {
845
- sendRouteError(res, 400, "mission-control.read.auto-continue.status.validation", "Query parameter 'initiative_id' is required.");
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
+ });
846
907
  return;
847
908
  }
848
909
  const run = deps.autoContinueRuns.get(id) ?? null;
@@ -1743,8 +1804,8 @@ export function registerMissionControlReadRoutes(router, deps) {
1743
1804
  items,
1744
1805
  });
1745
1806
  }
1746
- router.add("GET", "mission-control/auto-continue/status", async ({ query, res }) => renderAutoContinueStatus(query, res), "Get auto-continue status for an initiative");
1747
- router.add("HEAD", "mission-control/auto-continue/status", async ({ query, res }) => renderAutoContinueStatus(query, res), "Get auto-continue status for an initiative (HEAD)");
1807
+ router.add("GET", "mission-control/auto-continue/status", async ({ query, res, req }) => renderAutoContinueStatus(query, res, workspaceScopeFromHeaders(req?.headers)), "Get auto-continue status for an initiative");
1808
+ router.add("HEAD", "mission-control/auto-continue/status", async ({ query, res, req }) => renderAutoContinueStatus(query, res, workspaceScopeFromHeaders(req?.headers)), "Get auto-continue status for an initiative (HEAD)");
1748
1809
  router.add("GET", "mission-control/graph", async ({ query, res }) => renderMissionControlGraph(query, res), "Get mission-control dependency graph");
1749
1810
  router.add("HEAD", "mission-control/graph", async ({ query, res }) => renderMissionControlGraph(query, res), "Get mission-control dependency graph (HEAD)");
1750
1811
  router.add("GET", "mission-control/next-up", async ({ query, res, req }) => renderNextUpQueue(query, res, workspaceScopeFromHeaders(req?.headers)), "Get next-up queue");
package/dist/index.d.ts CHANGED
@@ -48,7 +48,14 @@ export interface PluginAPI {
48
48
  }) => void, options?: {
49
49
  commands?: string[];
50
50
  }) => void;
51
- registerHttpHandler: (handler: unknown) => void;
51
+ registerHttpRoute?: (route: {
52
+ path: string;
53
+ auth: "gateway" | "plugin";
54
+ match?: "exact" | "prefix";
55
+ handler: unknown;
56
+ replaceExisting?: boolean;
57
+ }) => void;
58
+ registerHttpHandler?: (handler: unknown) => void;
52
59
  }
53
60
  export interface ToolResult {
54
61
  content: Array<{
package/dist/index.js CHANGED
@@ -1430,7 +1430,27 @@ export default function register(api) {
1430
1430
  return true;
1431
1431
  return await httpHandler(req, res);
1432
1432
  };
1433
- api.registerHttpHandler(compositeHttpHandler);
1433
+ if (typeof api.registerHttpRoute === "function") {
1434
+ api.registerHttpRoute({
1435
+ path: "/orgx",
1436
+ auth: "plugin",
1437
+ match: "prefix",
1438
+ handler: compositeHttpHandler,
1439
+ });
1440
+ api.registerHttpRoute({
1441
+ path: "/workspace-hub",
1442
+ auth: "plugin",
1443
+ match: "prefix",
1444
+ handler: compositeHttpHandler,
1445
+ });
1446
+ }
1447
+ else if (typeof api.registerHttpHandler === "function") {
1448
+ // Backward compatibility for OpenClaw builds before route-based plugin HTTP registration.
1449
+ api.registerHttpHandler(compositeHttpHandler);
1450
+ }
1451
+ else {
1452
+ throw new Error("OpenClaw plugin API does not expose an HTTP registration method.");
1453
+ }
1434
1454
  api.log?.info?.("[orgx] Plugin registered", {
1435
1455
  baseUrl: config.baseUrl,
1436
1456
  hasApiKey: !!config.apiKey,
@@ -38,6 +38,8 @@ export const ORGX_MCP_ALLOWED_TOOLS_BY_SCOPE = {
38
38
  // Stream reassignment is a targeted operational mutation.
39
39
  "orgx_reassign_stream",
40
40
  "orgx_reassign_streams",
41
+ // Session resume (read-only visibility for operations).
42
+ "orgx_agent_sessions",
41
43
  ],
42
44
  orchestration: [
43
45
  ...ORGX_BASE_TOOLS,
@@ -46,6 +48,10 @@ export const ORGX_MCP_ALLOWED_TOOLS_BY_SCOPE = {
46
48
  "orgx_apply_changeset",
47
49
  "orgx_reassign_stream",
48
50
  "orgx_reassign_streams",
51
+ // Session resume tools.
52
+ "orgx_agent_sessions",
53
+ "orgx_resume_agent_session",
54
+ "orgx_clear_agent_session",
49
55
  ],
50
56
  };
51
57
  function isRecord(value) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "openclaw-plugin",
3
3
  "name": "OrgX Integration",
4
- "version": "1.0.2",
4
+ "version": "1.0.4",
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",
@@ -68,5 +68,32 @@ export interface RegisterCoreToolsDeps {
68
68
  auditId?: string;
69
69
  }) => import("../skill-pack-state.js").SkillPackState;
70
70
  randomUUID?: () => string;
71
+ sessionStore?: {
72
+ workstreamSessionStore: Map<string, {
73
+ sessionId: string;
74
+ workstreamId: string;
75
+ initiativeId: string;
76
+ sourceClient: string;
77
+ capturedAt: string;
78
+ fromRunId: string;
79
+ }>;
80
+ getWorkstreamSession: (workstreamId: string) => {
81
+ sessionId: string;
82
+ workstreamId: string;
83
+ initiativeId: string;
84
+ sourceClient: string;
85
+ capturedAt: string;
86
+ fromRunId: string;
87
+ } | null;
88
+ setWorkstreamSession: (workstreamId: string, entry: {
89
+ sessionId: string;
90
+ workstreamId: string;
91
+ initiativeId: string;
92
+ sourceClient: string;
93
+ capturedAt: string;
94
+ fromRunId: string;
95
+ }) => void;
96
+ clearWorkstreamSession: (initiativeId: string) => void;
97
+ };
71
98
  }
72
99
  export declare function registerCoreTools(deps: RegisterCoreToolsDeps): Map<string, RegisteredTool>;
@@ -2266,5 +2266,94 @@ export function registerCoreTools(deps) {
2266
2266
  }
2267
2267
  },
2268
2268
  }, { optional: true });
2269
+ // --- orgx_agent_sessions ---
2270
+ registerMcpTool({
2271
+ name: "orgx_agent_sessions",
2272
+ description: "List active CLI session IDs stored for workstreams. Used for session resume support.",
2273
+ parameters: {
2274
+ type: "object",
2275
+ properties: {
2276
+ initiativeId: {
2277
+ type: "string",
2278
+ description: "Optional initiative ID filter.",
2279
+ },
2280
+ },
2281
+ additionalProperties: false,
2282
+ },
2283
+ async execute(_callId, params = {}) {
2284
+ const store = deps.sessionStore;
2285
+ if (!store) {
2286
+ return text("Session store not available.");
2287
+ }
2288
+ const entries = [];
2289
+ for (const [, entry] of store.workstreamSessionStore.entries()) {
2290
+ if (params.initiativeId && entry.initiativeId !== params.initiativeId)
2291
+ continue;
2292
+ entries.push({ ...entry });
2293
+ }
2294
+ return json("Agent sessions:", {
2295
+ count: entries.length,
2296
+ sessions: entries,
2297
+ });
2298
+ },
2299
+ }, { optional: true });
2300
+ // --- orgx_resume_agent_session ---
2301
+ registerMcpTool({
2302
+ name: "orgx_resume_agent_session",
2303
+ description: "Store or update a CLI session ID for a workstream so the next slice resumes it.",
2304
+ parameters: {
2305
+ type: "object",
2306
+ properties: {
2307
+ workstreamId: { type: "string", description: "Workstream UUID" },
2308
+ sessionId: { type: "string", description: "CLI session UUID to resume" },
2309
+ initiativeId: { type: "string", description: "Initiative UUID" },
2310
+ sourceClient: { type: "string", description: "Source client (codex, claude-code)" },
2311
+ },
2312
+ required: ["workstreamId", "sessionId", "initiativeId"],
2313
+ additionalProperties: false,
2314
+ },
2315
+ async execute(_callId, params = { workstreamId: "", sessionId: "", initiativeId: "" }) {
2316
+ const store = deps.sessionStore;
2317
+ if (!store) {
2318
+ return text("Session store not available.");
2319
+ }
2320
+ if (!params.workstreamId || !params.sessionId || !params.initiativeId) {
2321
+ return text("Missing required parameters: workstreamId, sessionId, initiativeId.");
2322
+ }
2323
+ store.setWorkstreamSession(params.workstreamId, {
2324
+ sessionId: params.sessionId,
2325
+ workstreamId: params.workstreamId,
2326
+ initiativeId: params.initiativeId,
2327
+ sourceClient: params.sourceClient ?? "unknown",
2328
+ capturedAt: new Date().toISOString(),
2329
+ fromRunId: "manual",
2330
+ });
2331
+ return text(`Session ${params.sessionId} stored for workstream ${params.workstreamId}.`);
2332
+ },
2333
+ }, { optional: true });
2334
+ // --- orgx_clear_agent_session ---
2335
+ registerMcpTool({
2336
+ name: "orgx_clear_agent_session",
2337
+ description: "Clear stored CLI session IDs for an initiative (forces fresh sessions on next dispatch).",
2338
+ parameters: {
2339
+ type: "object",
2340
+ properties: {
2341
+ initiativeId: { type: "string", description: "Initiative UUID" },
2342
+ },
2343
+ required: ["initiativeId"],
2344
+ additionalProperties: false,
2345
+ },
2346
+ async execute(_callId, params = { initiativeId: "" }) {
2347
+ const store = deps.sessionStore;
2348
+ if (!store) {
2349
+ return text("Session store not available.");
2350
+ }
2351
+ if (!params.initiativeId) {
2352
+ return text("Missing required parameter: initiativeId.");
2353
+ }
2354
+ store.clearWorkstreamSession(params.initiativeId);
2355
+ return text(`Sessions cleared for initiative ${params.initiativeId}.`);
2356
+ },
2357
+ }, { optional: true });
2269
2358
  return mcpToolRegistry;
2270
2359
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "openclaw-plugin",
3
3
  "name": "OrgX Integration",
4
- "version": "1.0.2",
4
+ "version": "1.0.4",
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.6",
3
+ "version": "0.7.11",
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",
@@ -1 +0,0 @@
1
- import{r as l,a as c}from"./cNrhgGc1.js";import{b as g}from"./CPjsbbgZ.js";function f({authToken:s=null,embedMode:o=!1,enabled:n=!0}={}){var a;const i=l.useMemo(()=>["usage-control-plane",{authToken:s,embedMode:o}],[s,o]),e=c({queryKey:i,enabled:n,queryFn:async()=>{const t=await fetch("/orgx/api/usage/control-plane/summary",{headers:g({authToken:s,embedMode:o})}),r=await t.json().catch(()=>null);if(!t.ok){const u=(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 (${t.status})`;throw new Error(u)}if(!r||typeof r!="object"||!("generatedAt"in r))throw new Error("Usage summary response is missing required fields.");return r},refetchInterval:6e4});return{summary:e.data??null,isLoading:e.isLoading,isFetching:e.isFetching,error:((a=e.error)==null?void 0:a.message)??null,refetch:e.refetch}}export{f as u};