@useorgx/openclaw-plugin 0.7.15 → 0.7.17

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 (126) hide show
  1. package/dashboard/dist/assets/{CFZ4Swr5.js → 05zHA1Am.js} +1 -1
  2. package/dashboard/dist/assets/05zHA1Am.js.br +0 -0
  3. package/dashboard/dist/assets/05zHA1Am.js.gz +0 -0
  4. package/dashboard/dist/assets/0uYJrBLl.js +1 -0
  5. package/dashboard/dist/assets/0uYJrBLl.js.br +0 -0
  6. package/dashboard/dist/assets/0uYJrBLl.js.gz +0 -0
  7. package/dashboard/dist/assets/8nr6IqT4.js +1 -0
  8. package/dashboard/dist/assets/8nr6IqT4.js.br +0 -0
  9. package/dashboard/dist/assets/8nr6IqT4.js.gz +0 -0
  10. package/dashboard/dist/assets/{3VwNyxUf.js → B7kFLPiD.js} +1 -1
  11. package/dashboard/dist/assets/B7kFLPiD.js.br +0 -0
  12. package/dashboard/dist/assets/B7kFLPiD.js.gz +0 -0
  13. package/dashboard/dist/assets/{3TtV4moZ.js → B8NuBCcY.js} +1 -1
  14. package/dashboard/dist/assets/B8NuBCcY.js.br +0 -0
  15. package/dashboard/dist/assets/B8NuBCcY.js.gz +0 -0
  16. package/dashboard/dist/assets/{CnPC783_.js → BDlKSbsp.js} +1 -1
  17. package/dashboard/dist/assets/BDlKSbsp.js.br +0 -0
  18. package/dashboard/dist/assets/BDlKSbsp.js.gz +0 -0
  19. package/dashboard/dist/assets/C8AYbjlq.js +212 -0
  20. package/dashboard/dist/assets/C8AYbjlq.js.br +0 -0
  21. package/dashboard/dist/assets/C8AYbjlq.js.gz +0 -0
  22. package/dashboard/dist/assets/CMir7ekf.js +1 -0
  23. package/dashboard/dist/assets/CMir7ekf.js.br +0 -0
  24. package/dashboard/dist/assets/CMir7ekf.js.gz +0 -0
  25. package/dashboard/dist/assets/{CKrH5fYO.js → CWXk6UZl.js} +1 -1
  26. package/dashboard/dist/assets/CWXk6UZl.js.br +0 -0
  27. package/dashboard/dist/assets/CWXk6UZl.js.gz +0 -0
  28. package/dashboard/dist/assets/{Ctw95IkC.js → CoDun8X6.js} +1 -1
  29. package/dashboard/dist/assets/CoDun8X6.js.br +0 -0
  30. package/dashboard/dist/assets/CoDun8X6.js.gz +0 -0
  31. package/dashboard/dist/assets/{7DhYqBrM.js → Crj3jKHE.js} +1 -1
  32. package/dashboard/dist/assets/Crj3jKHE.js.br +0 -0
  33. package/dashboard/dist/assets/Crj3jKHE.js.gz +0 -0
  34. package/dashboard/dist/assets/{T2NFtzAv.js → CyUpNSKv.js} +1 -1
  35. package/dashboard/dist/assets/CyUpNSKv.js.br +0 -0
  36. package/dashboard/dist/assets/CyUpNSKv.js.gz +0 -0
  37. package/dashboard/dist/assets/{C9fvfXmS.js → D8mvKY2h.js} +1 -1
  38. package/dashboard/dist/assets/D8mvKY2h.js.br +0 -0
  39. package/dashboard/dist/assets/D8mvKY2h.js.gz +0 -0
  40. package/dashboard/dist/assets/{C91KLKit.js → DBRLnKWw.js} +1 -1
  41. package/dashboard/dist/assets/DBRLnKWw.js.br +0 -0
  42. package/dashboard/dist/assets/DBRLnKWw.js.gz +0 -0
  43. package/dashboard/dist/assets/DBct8HLW.js +1 -0
  44. package/dashboard/dist/assets/DBct8HLW.js.br +0 -0
  45. package/dashboard/dist/assets/DBct8HLW.js.gz +0 -0
  46. package/dashboard/dist/assets/{gZr_xKlA.js → DLNTxNX-.js} +1 -1
  47. package/dashboard/dist/assets/DLNTxNX-.js.br +0 -0
  48. package/dashboard/dist/assets/DLNTxNX-.js.gz +0 -0
  49. package/dashboard/dist/assets/DMKyYAtD.js +1 -0
  50. package/dashboard/dist/assets/DMKyYAtD.js.br +0 -0
  51. package/dashboard/dist/assets/DMKyYAtD.js.gz +0 -0
  52. package/dashboard/dist/assets/{CJjEAGFN.js → DdYkuATV.js} +1 -1
  53. package/dashboard/dist/assets/DdYkuATV.js.br +0 -0
  54. package/dashboard/dist/assets/DdYkuATV.js.gz +0 -0
  55. package/dashboard/dist/assets/{CGj8kRhg.js → DvFumX8R.js} +1 -1
  56. package/dashboard/dist/assets/DvFumX8R.js.br +0 -0
  57. package/dashboard/dist/assets/DvFumX8R.js.gz +0 -0
  58. package/dashboard/dist/assets/RZkbqlJk.css +1 -0
  59. package/dashboard/dist/assets/RZkbqlJk.css.br +0 -0
  60. package/dashboard/dist/assets/RZkbqlJk.css.gz +0 -0
  61. package/dashboard/dist/index.html +3 -3
  62. package/dashboard/dist/index.html.br +0 -0
  63. package/dashboard/dist/index.html.gz +0 -0
  64. package/dist/http/helpers/auto-continue-engine.d.ts +15 -0
  65. package/dist/http/helpers/auto-continue-engine.js +165 -0
  66. package/dist/http/helpers/mission-control.d.ts +3 -0
  67. package/dist/http/helpers/mission-control.js +38 -7
  68. package/dist/http/helpers/value-utils.d.ts +1 -1
  69. package/dist/http/helpers/value-utils.js +5 -2
  70. package/dist/http/index.js +3 -1
  71. package/dist/http/routes/chat.d.ts +1 -1
  72. package/dist/http/routes/chat.js +2 -2
  73. package/dist/http/routes/entities.js +60 -2
  74. package/dist/http/routes/entity-dynamic.js +49 -9
  75. package/dist/http/routes/live-snapshot.d.ts +10 -1
  76. package/dist/http/routes/live-snapshot.js +11 -3
  77. package/dist/http/routes/mission-control-actions.d.ts +6 -0
  78. package/dist/http/routes/mission-control-actions.js +33 -0
  79. package/package.json +1 -1
  80. package/dashboard/dist/assets/0RUEVzJa.js +0 -1
  81. package/dashboard/dist/assets/0RUEVzJa.js.br +0 -0
  82. package/dashboard/dist/assets/0RUEVzJa.js.gz +0 -0
  83. package/dashboard/dist/assets/3TtV4moZ.js.br +0 -0
  84. package/dashboard/dist/assets/3TtV4moZ.js.gz +0 -0
  85. package/dashboard/dist/assets/3VwNyxUf.js.br +0 -0
  86. package/dashboard/dist/assets/3VwNyxUf.js.gz +0 -0
  87. package/dashboard/dist/assets/7DhYqBrM.js.br +0 -0
  88. package/dashboard/dist/assets/7DhYqBrM.js.gz +0 -0
  89. package/dashboard/dist/assets/BVvffj0x.js +0 -1
  90. package/dashboard/dist/assets/BVvffj0x.js.br +0 -0
  91. package/dashboard/dist/assets/BVvffj0x.js.gz +0 -0
  92. package/dashboard/dist/assets/BiOgVMED.js +0 -1
  93. package/dashboard/dist/assets/BiOgVMED.js.br +0 -0
  94. package/dashboard/dist/assets/BiOgVMED.js.gz +0 -0
  95. package/dashboard/dist/assets/C91KLKit.js.br +0 -0
  96. package/dashboard/dist/assets/C91KLKit.js.gz +0 -0
  97. package/dashboard/dist/assets/C9fvfXmS.js.br +0 -0
  98. package/dashboard/dist/assets/C9fvfXmS.js.gz +0 -0
  99. package/dashboard/dist/assets/CFZ4Swr5.js.br +0 -0
  100. package/dashboard/dist/assets/CFZ4Swr5.js.gz +0 -0
  101. package/dashboard/dist/assets/CGj8kRhg.js.br +0 -0
  102. package/dashboard/dist/assets/CGj8kRhg.js.gz +0 -0
  103. package/dashboard/dist/assets/CJjEAGFN.js.br +0 -0
  104. package/dashboard/dist/assets/CJjEAGFN.js.gz +0 -0
  105. package/dashboard/dist/assets/CKrH5fYO.js.br +0 -0
  106. package/dashboard/dist/assets/CKrH5fYO.js.gz +0 -0
  107. package/dashboard/dist/assets/CMTTPXch.js +0 -1
  108. package/dashboard/dist/assets/CMTTPXch.js.br +0 -0
  109. package/dashboard/dist/assets/CMTTPXch.js.gz +0 -0
  110. package/dashboard/dist/assets/CnPC783_.js.br +0 -0
  111. package/dashboard/dist/assets/CnPC783_.js.gz +0 -0
  112. package/dashboard/dist/assets/Ctw95IkC.js.br +0 -0
  113. package/dashboard/dist/assets/Ctw95IkC.js.gz +0 -0
  114. package/dashboard/dist/assets/DHz-aQPw.js +0 -1
  115. package/dashboard/dist/assets/DHz-aQPw.js.br +0 -0
  116. package/dashboard/dist/assets/DHz-aQPw.js.gz +0 -0
  117. package/dashboard/dist/assets/DNX2foSJ.css +0 -1
  118. package/dashboard/dist/assets/DNX2foSJ.css.br +0 -0
  119. package/dashboard/dist/assets/DNX2foSJ.css.gz +0 -0
  120. package/dashboard/dist/assets/DxUw4FMR.js +0 -212
  121. package/dashboard/dist/assets/DxUw4FMR.js.br +0 -0
  122. package/dashboard/dist/assets/DxUw4FMR.js.gz +0 -0
  123. package/dashboard/dist/assets/T2NFtzAv.js.br +0 -0
  124. package/dashboard/dist/assets/T2NFtzAv.js.gz +0 -0
  125. package/dashboard/dist/assets/gZr_xKlA.js.br +0 -0
  126. package/dashboard/dist/assets/gZr_xKlA.js.gz +0 -0
@@ -48,7 +48,7 @@ export function toIsoString(value) {
48
48
  return null;
49
49
  return new Date(parsed).toISOString();
50
50
  }
51
- export function parsePositiveInt(raw, fallback) {
51
+ export function parsePositiveInt(raw, fallback, max = Number.POSITIVE_INFINITY) {
52
52
  if (!raw)
53
53
  return fallback;
54
54
  const normalized = raw.trim();
@@ -59,7 +59,10 @@ export function parsePositiveInt(raw, fallback) {
59
59
  return fallback;
60
60
  // Offset-like parameters may intentionally allow zero when fallback is zero.
61
61
  const minimum = fallback <= 0 ? 0 : 1;
62
- return Math.max(minimum, Math.floor(parsed));
62
+ const clamped = Math.max(minimum, Math.floor(parsed));
63
+ if (!Number.isFinite(max))
64
+ return clamped;
65
+ return Math.min(clamped, Math.max(minimum, Math.floor(max)));
63
66
  }
64
67
  export function parseBooleanQuery(raw) {
65
68
  if (!raw)
@@ -1846,7 +1846,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
1846
1846
  };
1847
1847
  const codexBinResolver = createCodexBinResolver();
1848
1848
  const resolveCodexBinInfo = () => codexBinResolver.resolveCodexBinInfo();
1849
- const { autoContinueRuns, autoContinueSliceRuns, localInitiativeStatusOverrides, writeRuntimeEvent, autoContinueTickMs: AUTO_CONTINUE_TICK_MS, defaultAutoContinueTokenBudget, defaultAutoContinueMaxParallelSlices, setLocalInitiativeStatusOverride, clearLocalInitiativeStatusOverride, applyLocalInitiativeOverrides, applyLocalInitiativeOverrideToGraph, updateInitiativeAutoContinueState, stopAutoContinueRun, tickAutoContinueRun, tickAllAutoContinue, isInitiativeActiveStatus, runningAutoContinueForWorkstream, getAutoContinueLaneForWorkstream, scheduleAutoFixForWorkstream, startAutoContinueRun, } = createAutoContinueEngine({
1849
+ const { autoContinueRuns, autoContinueSliceRuns, localInitiativeStatusOverrides, writeRuntimeEvent, autoContinueTickMs: AUTO_CONTINUE_TICK_MS, defaultAutoContinueTokenBudget, defaultAutoContinueMaxParallelSlices, setLocalInitiativeStatusOverride, clearLocalInitiativeStatusOverride, applyLocalInitiativeOverrides, applyLocalInitiativeOverrideToGraph, updateInitiativeAutoContinueState, stopAutoContinueRun, tickAutoContinueRun, tickAllAutoContinue, isInitiativeActiveStatus, runningAutoContinueForWorkstream, getAutoContinueLaneForWorkstream, scheduleAutoFixForWorkstream, startAutoContinueRun, skipCurrentWorkstream, getCanonicalAutopilotState, } = createAutoContinueEngine({
1850
1850
  client,
1851
1851
  filename: __filename,
1852
1852
  safeErrorMessage,
@@ -3417,6 +3417,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3417
3417
  dispatchFallbackWorkstreamTurn,
3418
3418
  tickAutoContinueRun,
3419
3419
  stopAutoContinueRun,
3420
+ skipCurrentWorkstream,
3420
3421
  updateInitiativeAutoContinueState,
3421
3422
  tickAllAutoContinue,
3422
3423
  scheduleAutoFixForWorkstream,
@@ -3592,6 +3593,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3592
3593
  },
3593
3594
  runAction: (runId, action, input) => client.runAction(runId, action, input),
3594
3595
  listChatThreads: ({ commandCenterId, initiativeId, limit, offset }) => listChatThreads({ commandCenterId, initiativeId, limit, offset }),
3596
+ getCanonicalAutopilotState,
3595
3597
  sendJson,
3596
3598
  });
3597
3599
  registerRuntimeHookRoutes(apiRouter, {
@@ -3,7 +3,7 @@ type JsonRecord = Record<string, unknown>;
3
3
  type RegisterChatRoutesDeps<TReq, TRes> = {
4
4
  parseJsonRequest: (req: TReq) => Promise<JsonRecord>;
5
5
  pickString: (input: Record<string, unknown>, keys: string[]) => string | null;
6
- parsePositiveInt: (raw: string | null, fallback: number) => number;
6
+ parsePositiveInt: (raw: string | null, fallback: number, max?: number) => number;
7
7
  emitActivitySafe?: (input: {
8
8
  initiativeId: string | null;
9
9
  sourceClient?: string;
@@ -161,8 +161,8 @@ export function registerChatRoutes(router, deps) {
161
161
  const initiativeId = query.get("initiative_id") ?? query.get("initiative");
162
162
  const searchQuery = query.get("query") ?? query.get("q");
163
163
  const status = query.get("status");
164
- const limit = deps.parsePositiveInt(query.get("limit"), 60);
165
- const offset = deps.parsePositiveInt(query.get("offset"), 0);
164
+ const limit = deps.parsePositiveInt(query.get("limit"), 60, 200);
165
+ const offset = deps.parsePositiveInt(query.get("offset"), 0, 10000);
166
166
  sendThreadList(deps, res, {
167
167
  commandCenterId: commandCenterId?.trim() ?? null,
168
168
  initiativeId: initiativeId?.trim() ?? null,
@@ -1,4 +1,5 @@
1
1
  import { resolveWorkspaceScope, workspaceScopeFromHeaders, } from "../helpers/workspace-scope.js";
2
+ import { deriveInitiativeLifecycleStatus } from "../helpers/mission-control.js";
2
3
  const WORKSTREAM_REASSIGNMENT_FIELDS = [
3
4
  "domain",
4
5
  "role",
@@ -38,6 +39,59 @@ function toObjectArray(input) {
38
39
  return [];
39
40
  return input.filter((item) => Boolean(item) && typeof item === "object");
40
41
  }
42
+ async function reconcileInitiativeStatusesFromWorkstreams(deps, rows, input) {
43
+ if (rows.length === 0)
44
+ return rows;
45
+ const initiativeIds = new Set(rows
46
+ .map((row) => deps.pickString(row, ["id"]))
47
+ .filter((value) => Boolean(value)));
48
+ if (initiativeIds.size === 0)
49
+ return rows;
50
+ const scopedInitiativeId = input.initiativeId?.trim() ?? "";
51
+ const scopedWorkspaceId = input.workspaceId?.trim() ?? "";
52
+ if (!scopedInitiativeId && !scopedWorkspaceId) {
53
+ // Avoid unscoped global workstream scans.
54
+ return rows;
55
+ }
56
+ const filters = { limit: 2000 };
57
+ if (scopedInitiativeId) {
58
+ filters.initiative_id = scopedInitiativeId;
59
+ }
60
+ if (scopedWorkspaceId) {
61
+ filters.workspace_id = scopedWorkspaceId;
62
+ filters.command_center_id = scopedWorkspaceId;
63
+ }
64
+ const response = await deps.client.listEntities("workstream", filters);
65
+ const workstreamRows = toObjectArray(response && typeof response === "object"
66
+ ? response.data
67
+ : []);
68
+ const childStatusesByInitiative = new Map();
69
+ for (const workstreamRow of workstreamRows) {
70
+ const initiativeId = deps.pickString(workstreamRow, ["initiative_id", "initiativeId"]);
71
+ if (!initiativeId || !initiativeIds.has(initiativeId))
72
+ continue;
73
+ const status = deps.pickString(workstreamRow, ["status"]) ?? "todo";
74
+ const statuses = childStatusesByInitiative.get(initiativeId) ?? [];
75
+ statuses.push(status);
76
+ childStatusesByInitiative.set(initiativeId, statuses);
77
+ }
78
+ return rows.map((row) => {
79
+ const initiativeId = deps.pickString(row, ["id"]);
80
+ const status = deps.pickString(row, ["status"]);
81
+ if (!initiativeId || !status)
82
+ return row;
83
+ const childStatuses = childStatusesByInitiative.get(initiativeId) ?? [];
84
+ if (childStatuses.length === 0)
85
+ return row;
86
+ const normalized = deriveInitiativeLifecycleStatus(status, childStatuses);
87
+ if (normalized === status)
88
+ return row;
89
+ return {
90
+ ...row,
91
+ status: normalized,
92
+ };
93
+ });
94
+ }
41
95
  export function registerEntitiesRoutes(router, deps) {
42
96
  router.add("POST", "entities", async ({ req, res }) => {
43
97
  try {
@@ -305,13 +359,17 @@ export function registerEntitiesRoutes(router, deps) {
305
359
  return rowScope.trim() === workspaceScopeId;
306
360
  })
307
361
  : searchedRows;
362
+ const reconciledRows = await reconcileInitiativeStatusesFromWorkstreams(deps, rows, {
363
+ initiativeId: id,
364
+ workspaceId: workspaceScopeId,
365
+ }).catch(() => rows);
308
366
  deps.sendJson(res, 200, {
309
367
  ...payload,
310
- data: deps.applyLocalInitiativeOverrides(rows),
368
+ data: deps.applyLocalInitiativeOverrides(reconciledRows),
311
369
  pagination: payload.pagination && typeof payload.pagination === "object"
312
370
  ? {
313
371
  ...payload.pagination,
314
- total: rows.length,
372
+ total: reconciledRows.length,
315
373
  }
316
374
  : payload.pagination,
317
375
  });
@@ -1,3 +1,51 @@
1
+ function resolveEntityActionStatus(entityType, entityAction) {
2
+ const normalizedType = entityType.trim().toLowerCase();
3
+ const normalizedAction = entityAction.trim().toLowerCase();
4
+ const defaultStatusMap = {
5
+ start: "in_progress",
6
+ complete: "done",
7
+ block: "blocked",
8
+ unblock: "in_progress",
9
+ pause: "paused",
10
+ resume: "active",
11
+ };
12
+ const statusMapByEntityType = {
13
+ initiative: {
14
+ start: "active",
15
+ complete: "completed",
16
+ block: "blocked",
17
+ unblock: "active",
18
+ pause: "paused",
19
+ resume: "active",
20
+ },
21
+ workstream: {
22
+ start: "active",
23
+ complete: "completed",
24
+ block: "blocked",
25
+ unblock: "active",
26
+ pause: "paused",
27
+ resume: "active",
28
+ },
29
+ milestone: {
30
+ start: "in_progress",
31
+ complete: "completed",
32
+ block: "at_risk",
33
+ unblock: "in_progress",
34
+ pause: "planned",
35
+ resume: "in_progress",
36
+ },
37
+ task: {
38
+ start: "in_progress",
39
+ complete: "done",
40
+ block: "blocked",
41
+ unblock: "in_progress",
42
+ pause: "todo",
43
+ resume: "in_progress",
44
+ },
45
+ };
46
+ const map = statusMapByEntityType[normalizedType] ?? defaultStatusMap;
47
+ return map[normalizedAction] ?? null;
48
+ }
1
49
  export function registerEntityDynamicRoutes(router, deps) {
2
50
  router.add("*", "entities/*", async ({ req, res, path }) => {
3
51
  const method = (req.method ?? "GET").toUpperCase();
@@ -137,15 +185,7 @@ export function registerEntityDynamicRoutes(router, deps) {
137
185
  }
138
186
  return;
139
187
  }
140
- const statusMap = {
141
- start: "in_progress",
142
- complete: "done",
143
- block: "blocked",
144
- unblock: "in_progress",
145
- pause: "paused",
146
- resume: "active",
147
- };
148
- const newStatus = statusMap[entityAction];
188
+ const newStatus = resolveEntityActionStatus(entityType, entityAction);
149
189
  if (!newStatus) {
150
190
  deps.sendJson(res, 400, {
151
191
  error: `Unknown entity action: ${entityAction}`,
@@ -14,7 +14,7 @@ type SnapshotPersistState = {
14
14
  lastPersistAt: number;
15
15
  };
16
16
  type LiveSnapshotRoutesDeps<TReq, TRes> = {
17
- parsePositiveInt: (raw: string | null, fallback: number) => number;
17
+ parsePositiveInt: (raw: string | null, fallback: number, max?: number) => number;
18
18
  readSnapshotResponseCache: (key: string) => Record<string, unknown> | null;
19
19
  writeSnapshotResponseCache: (key: string, payload: Record<string, unknown>) => void;
20
20
  safeErrorMessage: (err: unknown) => string;
@@ -131,6 +131,15 @@ type LiveSnapshotRoutesDeps<TReq, TRes> = {
131
131
  total: number;
132
132
  updatedAt: string;
133
133
  };
134
+ getCanonicalAutopilotState?: (initiativeId: string) => {
135
+ state: "idle" | "running" | "blocked" | "stopping";
136
+ reason: string | null;
137
+ activeRunId: string | null;
138
+ activeWorkstreamId: string | null;
139
+ activeWorkstreamTitle: string | null;
140
+ queueHeadTitle: string | null;
141
+ lastTransitionAt: string;
142
+ } | null;
134
143
  sendJson: (res: TRes, status: number, payload: unknown) => void;
135
144
  };
136
145
  export declare function registerLiveSnapshotRoutes<TReq, TRes>(router: Router<Record<string, never>, TReq, TRes>, deps: LiveSnapshotRoutesDeps<TReq, TRes>): void;
@@ -231,9 +231,9 @@ export function registerLiveSnapshotRoutes(router, deps) {
231
231
  };
232
232
  const headerScopeFromRequest = (req) => workspaceScopeFromHeaders(req?.headers);
233
233
  function parseSnapshotQuery(query, headerScope) {
234
- const sessionsLimit = deps.parsePositiveInt(query.get("sessionsLimit") ?? query.get("sessions_limit"), 320);
235
- const activityLimit = deps.parsePositiveInt(query.get("activityLimit") ?? query.get("activity_limit"), 600);
236
- const decisionsLimit = deps.parsePositiveInt(query.get("decisionsLimit") ?? query.get("decisions_limit"), 120);
234
+ const sessionsLimit = deps.parsePositiveInt(query.get("sessionsLimit") ?? query.get("sessions_limit"), 320, 1000);
235
+ const activityLimit = deps.parsePositiveInt(query.get("activityLimit") ?? query.get("activity_limit"), 600, 2000);
236
+ const decisionsLimit = deps.parsePositiveInt(query.get("decisionsLimit") ?? query.get("decisions_limit"), 120, 500);
237
237
  const initiative = query.get("initiative");
238
238
  const scope = resolveWorkspaceScope(query, headerScope, {
239
239
  allowProjectScope: false,
@@ -523,6 +523,14 @@ export function registerLiveSnapshotRoutes(router, deps) {
523
523
  projectId,
524
524
  degraded: degraded.length > 0 ? degraded : undefined,
525
525
  };
526
+ if (typeof deps.getCanonicalAutopilotState === "function" && initiative) {
527
+ try {
528
+ payload.autopilot = deps.getCanonicalAutopilotState(initiative) ?? null;
529
+ }
530
+ catch {
531
+ // best effort
532
+ }
533
+ }
526
534
  if (typeof deps.listChatThreads === "function") {
527
535
  try {
528
536
  const listed = deps.listChatThreads({
@@ -66,6 +66,12 @@ type RegisterMissionControlActionsRoutesDeps<TReq, TRes> = {
66
66
  }>;
67
67
  tickAutoContinueRun: (run: any) => Promise<void>;
68
68
  stopAutoContinueRun: (input: any) => Promise<void>;
69
+ skipCurrentWorkstream: (initiativeId: string, workstreamId: string, reason?: string) => Promise<{
70
+ ok: boolean;
71
+ skippedWorkstreamId: string;
72
+ nextWorkstreamId?: string;
73
+ nextWorkstreamTitle?: string;
74
+ }>;
69
75
  updateInitiativeAutoContinueState: (input: any) => Promise<void>;
70
76
  tickAllAutoContinue: () => Promise<void>;
71
77
  scheduleAutoFixForWorkstream: (input: {
@@ -1636,6 +1636,39 @@ export function registerMissionControlActionsRoutes(router, deps) {
1636
1636
  sendRouteException(res, "mission-control.auto-continue.stop.handler", err);
1637
1637
  }
1638
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");
1639
1672
  router.add("POST", "mission-control/auto-continue/tick", async ({ req, query, res }) => {
1640
1673
  try {
1641
1674
  const payload = await deps.parseJsonRequest(req);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useorgx/openclaw-plugin",
3
- "version": "0.7.15",
3
+ "version": "0.7.17",
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",