@useorgx/openclaw-plugin 0.4.9 → 0.7.0

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 (222) hide show
  1. package/README.md +35 -0
  2. package/dashboard/dist/assets/BJgZIVUQ.js +53 -0
  3. package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
  4. package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
  5. package/dashboard/dist/assets/BXWDRGm-.js +1 -0
  6. package/dashboard/dist/assets/BXWDRGm-.js.br +0 -0
  7. package/dashboard/dist/assets/BXWDRGm-.js.gz +0 -0
  8. package/dashboard/dist/assets/BgOYB78t.js +4 -0
  9. package/dashboard/dist/assets/BgOYB78t.js.br +0 -0
  10. package/dashboard/dist/assets/BgOYB78t.js.gz +0 -0
  11. package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
  12. package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
  13. package/dashboard/dist/assets/CE38zU4U.js +1 -0
  14. package/dashboard/dist/assets/CE38zU4U.js.br +0 -0
  15. package/dashboard/dist/assets/CE38zU4U.js.gz +0 -0
  16. package/dashboard/dist/assets/CFGKRAzG.js +1 -0
  17. package/dashboard/dist/assets/CFGKRAzG.js.br +0 -0
  18. package/dashboard/dist/assets/CFGKRAzG.js.gz +0 -0
  19. package/dashboard/dist/assets/CGGR2GZh.js +1 -0
  20. package/dashboard/dist/assets/CGGR2GZh.js.br +0 -0
  21. package/dashboard/dist/assets/CGGR2GZh.js.gz +0 -0
  22. package/dashboard/dist/assets/CL_wXqR7.js +1 -0
  23. package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
  24. package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
  25. package/dashboard/dist/assets/CPFiTmlw.js +8 -0
  26. package/dashboard/dist/assets/CPFiTmlw.js.br +0 -0
  27. package/dashboard/dist/assets/CPFiTmlw.js.gz +0 -0
  28. package/dashboard/dist/assets/CZZTvkQZ.js +1 -0
  29. package/dashboard/dist/assets/CZZTvkQZ.js.br +0 -0
  30. package/dashboard/dist/assets/CZZTvkQZ.js.gz +0 -0
  31. package/dashboard/dist/assets/{CpJsfbXo.js → CxQ08qFN.js} +2 -2
  32. package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
  33. package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
  34. package/dashboard/dist/assets/D-bf6hEI.js +213 -0
  35. package/dashboard/dist/assets/D-bf6hEI.js.br +0 -0
  36. package/dashboard/dist/assets/D-bf6hEI.js.gz +0 -0
  37. package/dashboard/dist/assets/DG6y9wJI.js +2 -0
  38. package/dashboard/dist/assets/DG6y9wJI.js.br +0 -0
  39. package/dashboard/dist/assets/DG6y9wJI.js.gz +0 -0
  40. package/dashboard/dist/assets/DNxKz-GV.js +1 -0
  41. package/dashboard/dist/assets/DNxKz-GV.js.br +0 -0
  42. package/dashboard/dist/assets/DNxKz-GV.js.gz +0 -0
  43. package/dashboard/dist/assets/DW_rKUic.js +11 -0
  44. package/dashboard/dist/assets/DW_rKUic.js.br +0 -0
  45. package/dashboard/dist/assets/DW_rKUic.js.gz +0 -0
  46. package/dashboard/dist/assets/DbNoijHm.js +1 -0
  47. package/dashboard/dist/assets/DbNoijHm.js.br +0 -0
  48. package/dashboard/dist/assets/DbNoijHm.js.gz +0 -0
  49. package/dashboard/dist/assets/DjcdE6jC.js +2 -0
  50. package/dashboard/dist/assets/DjcdE6jC.js.br +0 -0
  51. package/dashboard/dist/assets/DjcdE6jC.js.gz +0 -0
  52. package/dashboard/dist/assets/FZYuCDnt.js +1 -0
  53. package/dashboard/dist/assets/FZYuCDnt.js.br +0 -0
  54. package/dashboard/dist/assets/FZYuCDnt.js.gz +0 -0
  55. package/dashboard/dist/assets/PAUiij_z.js +1 -0
  56. package/dashboard/dist/assets/PAUiij_z.js.br +0 -0
  57. package/dashboard/dist/assets/PAUiij_z.js.gz +0 -0
  58. package/dashboard/dist/assets/cNrhgGc1.js +8 -0
  59. package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
  60. package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
  61. package/dashboard/dist/assets/h5biQs2I.css +1 -0
  62. package/dashboard/dist/assets/h5biQs2I.css.br +0 -0
  63. package/dashboard/dist/assets/h5biQs2I.css.gz +0 -0
  64. package/dashboard/dist/assets/ic2FaMnh.js +1 -0
  65. package/dashboard/dist/assets/ic2FaMnh.js.br +0 -0
  66. package/dashboard/dist/assets/ic2FaMnh.js.gz +0 -0
  67. package/dashboard/dist/assets/nByHNHoW.js +1 -0
  68. package/dashboard/dist/assets/nByHNHoW.js.br +0 -0
  69. package/dashboard/dist/assets/nByHNHoW.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/tS9mbYZi.js +1 -0
  74. package/dashboard/dist/assets/tS9mbYZi.js.br +0 -0
  75. package/dashboard/dist/assets/tS9mbYZi.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/retro-schema.d.ts +81 -0
  102. package/dist/contracts/retro-schema.js +80 -0
  103. package/dist/contracts/shared-types.d.ts +159 -0
  104. package/dist/contracts/shared-types.js +177 -1
  105. package/dist/contracts/skill-pack-schema.d.ts +192 -0
  106. package/dist/contracts/skill-pack-schema.js +180 -0
  107. package/dist/contracts/types.d.ts +227 -2
  108. package/dist/entities/auto-assignment.js +43 -17
  109. package/dist/event-sanitization.d.ts +11 -0
  110. package/dist/event-sanitization.js +113 -0
  111. package/dist/fs-utils.js +13 -1
  112. package/dist/gateway-watchdog.d.ts +5 -0
  113. package/dist/gateway-watchdog.js +50 -0
  114. package/dist/hooks/post-reporting-event.mjs +1 -5
  115. package/dist/http/helpers/activity-headline.js +13 -132
  116. package/dist/http/helpers/auto-continue-engine.d.ts +198 -10
  117. package/dist/http/helpers/auto-continue-engine.js +2531 -186
  118. package/dist/http/helpers/autopilot-operations.d.ts +19 -0
  119. package/dist/http/helpers/autopilot-operations.js +182 -31
  120. package/dist/http/helpers/autopilot-runtime.d.ts +1 -0
  121. package/dist/http/helpers/autopilot-runtime.js +308 -20
  122. package/dist/http/helpers/autopilot-slice-utils.d.ts +18 -0
  123. package/dist/http/helpers/autopilot-slice-utils.js +516 -93
  124. package/dist/http/helpers/decision-mapper.d.ts +40 -0
  125. package/dist/http/helpers/decision-mapper.js +223 -7
  126. package/dist/http/helpers/dispatch-lifecycle.d.ts +19 -2
  127. package/dist/http/helpers/dispatch-lifecycle.js +242 -37
  128. package/dist/http/helpers/kickoff-context.js +74 -0
  129. package/dist/http/helpers/llm-client.d.ts +47 -0
  130. package/dist/http/helpers/llm-client.js +256 -0
  131. package/dist/http/helpers/mission-control.d.ts +102 -3
  132. package/dist/http/helpers/mission-control.js +498 -9
  133. package/dist/http/helpers/sentinel-catalog.d.ts +23 -0
  134. package/dist/http/helpers/sentinel-catalog.js +193 -0
  135. package/dist/http/helpers/session-classification.d.ts +9 -0
  136. package/dist/http/helpers/session-classification.js +564 -0
  137. package/dist/http/helpers/slice-experience-v2.d.ts +137 -0
  138. package/dist/http/helpers/slice-experience-v2.js +677 -0
  139. package/dist/http/helpers/slice-run-projections.d.ts +72 -0
  140. package/dist/http/helpers/slice-run-projections.js +860 -0
  141. package/dist/http/helpers/triage-mapper.d.ts +43 -0
  142. package/dist/http/helpers/triage-mapper.js +549 -0
  143. package/dist/http/helpers/value-utils.js +7 -2
  144. package/dist/http/helpers/workspace-scope.d.ts +15 -0
  145. package/dist/http/helpers/workspace-scope.js +170 -0
  146. package/dist/http/index.js +1354 -97
  147. package/dist/http/routes/agent-suite.d.ts +9 -0
  148. package/dist/http/routes/agent-suite.js +207 -8
  149. package/dist/http/routes/agents-catalog.js +64 -19
  150. package/dist/http/routes/chat.d.ts +19 -0
  151. package/dist/http/routes/chat.js +522 -0
  152. package/dist/http/routes/decision-actions.d.ts +8 -1
  153. package/dist/http/routes/decision-actions.js +42 -5
  154. package/dist/http/routes/dispatch-gateway-envelope.d.ts +25 -0
  155. package/dist/http/routes/dispatch-gateway-envelope.js +26 -0
  156. package/dist/http/routes/entities.d.ts +16 -0
  157. package/dist/http/routes/entities.js +294 -6
  158. package/dist/http/routes/live-legacy.d.ts +5 -0
  159. package/dist/http/routes/live-legacy.js +23 -509
  160. package/dist/http/routes/live-misc.d.ts +12 -0
  161. package/dist/http/routes/live-misc.js +251 -31
  162. package/dist/http/routes/live-snapshot.d.ts +48 -2
  163. package/dist/http/routes/live-snapshot.js +638 -19
  164. package/dist/http/routes/live-terminal.d.ts +11 -0
  165. package/dist/http/routes/live-terminal.js +261 -0
  166. package/dist/http/routes/live-triage.d.ts +61 -0
  167. package/dist/http/routes/live-triage.js +248 -0
  168. package/dist/http/routes/mission-control-actions.d.ts +49 -1
  169. package/dist/http/routes/mission-control-actions.js +1334 -84
  170. package/dist/http/routes/mission-control-read.d.ts +48 -3
  171. package/dist/http/routes/mission-control-read.js +1593 -20
  172. package/dist/http/routes/realtime-orchestrator.d.ts +10 -0
  173. package/dist/http/routes/realtime-orchestrator.js +74 -0
  174. package/dist/http/routes/run-control.d.ts +5 -2
  175. package/dist/http/routes/run-control.js +10 -0
  176. package/dist/http/routes/sentinels-catalog.d.ts +7 -0
  177. package/dist/http/routes/sentinels-catalog.js +24 -0
  178. package/dist/http/routes/summary.js +10 -3
  179. package/dist/http/routes/usage.d.ts +24 -0
  180. package/dist/http/routes/usage.js +362 -0
  181. package/dist/http/routes/work-artifacts.js +28 -9
  182. package/dist/index.js +165 -27
  183. package/dist/local-openclaw.js +29 -6
  184. package/dist/mcp-client-setup.js +3 -3
  185. package/dist/mcp-http-handler.js +33 -59
  186. package/dist/next-up-queue-store.d.ts +16 -1
  187. package/dist/next-up-queue-store.js +89 -7
  188. package/dist/outbox.d.ts +5 -0
  189. package/dist/outbox.js +113 -9
  190. package/dist/paths.js +24 -5
  191. package/dist/reporting/rollups.d.ts +53 -0
  192. package/dist/reporting/rollups.js +148 -0
  193. package/dist/retro/domain-templates.d.ts +45 -0
  194. package/dist/retro/domain-templates.js +297 -0
  195. package/dist/retro/quality-rubric.d.ts +33 -0
  196. package/dist/retro/quality-rubric.js +213 -0
  197. package/dist/runtime-cleanup.d.ts +18 -0
  198. package/dist/runtime-cleanup.js +87 -0
  199. package/dist/services/background.d.ts +11 -0
  200. package/dist/services/background.js +22 -0
  201. package/dist/services/experiment-randomization.d.ts +21 -0
  202. package/dist/services/experiment-randomization.js +63 -0
  203. package/dist/skill-pack-state.d.ts +36 -5
  204. package/dist/skill-pack-state.js +273 -29
  205. package/dist/sync/local-agent-telemetry.d.ts +13 -0
  206. package/dist/sync/local-agent-telemetry.js +128 -0
  207. package/dist/sync/outbox-replay.js +131 -24
  208. package/dist/team-context-store.d.ts +23 -0
  209. package/dist/team-context-store.js +116 -0
  210. package/dist/telemetry/posthog.js +4 -2
  211. package/dist/tools/core-tools.d.ts +10 -14
  212. package/dist/tools/core-tools.js +1289 -24
  213. package/dist/types.d.ts +2 -0
  214. package/dist/types.js +2 -0
  215. package/dist/worker-supervisor.js +23 -0
  216. package/package.json +14 -4
  217. package/dashboard/dist/assets/B3ziCA02.js +0 -8
  218. package/dashboard/dist/assets/B5NEElEI.css +0 -1
  219. package/dashboard/dist/assets/BhapSNAs.js +0 -215
  220. package/dashboard/dist/assets/iFdvE7lx.js +0 -1
  221. package/dashboard/dist/assets/jRJsmpYM.js +0 -1
  222. package/dashboard/dist/assets/sAhvFnpk.js +0 -4
@@ -1,4 +1,37 @@
1
+ import { resolveWorkspaceScope, workspaceScopeFromHeaders, } from "../helpers/workspace-scope.js";
2
+ function asRecord(input) {
3
+ if (!input || typeof input !== "object" || Array.isArray(input))
4
+ return null;
5
+ return input;
6
+ }
7
+ function pickStringFromRecord(input, keys) {
8
+ if (!input)
9
+ return null;
10
+ for (const key of keys) {
11
+ const value = input[key];
12
+ if (typeof value !== "string")
13
+ continue;
14
+ const normalized = value.trim();
15
+ if (normalized.length > 0)
16
+ return normalized;
17
+ }
18
+ return null;
19
+ }
20
+ function resolveInitiativeIdFromRecord(input) {
21
+ const direct = pickStringFromRecord(input, ["initiativeId", "initiative_id", "initiative"]);
22
+ if (direct)
23
+ return direct;
24
+ const metadata = asRecord(input.metadata);
25
+ return pickStringFromRecord(metadata, ["initiativeId", "initiative_id", "initiative"]);
26
+ }
1
27
  export function registerLiveMiscRoutes(router, deps) {
28
+ async function resolveProjectInitiativeSet(projectIdRaw) {
29
+ const projectId = projectIdRaw?.trim() ?? "";
30
+ if (!projectId)
31
+ return null;
32
+ const ids = await deps.listInitiativeIdsForProject({ projectId });
33
+ return new Set(ids);
34
+ }
2
35
  router.add("POST", "live/activity/headline", async ({ req, res }) => {
3
36
  try {
4
37
  const payload = await deps.parseJsonRequest(req);
@@ -29,20 +62,59 @@ export function registerLiveMiscRoutes(router, deps) {
29
62
  router.add("*", "live/activity/headline", ({ res }) => {
30
63
  deps.sendJson(res, 405, { error: "Use POST /orgx/api/live/activity/headline" });
31
64
  }, "Reject unsupported methods for live/activity/headline");
32
- async function renderLiveAgents(query, res) {
65
+ async function renderLiveAgents(query, res, headerScope) {
66
+ const scope = resolveWorkspaceScope(query, headerScope, {
67
+ allowProjectScope: false,
68
+ });
69
+ if (scope.error) {
70
+ deps.sendJson(res, 400, { error: scope.error });
71
+ return;
72
+ }
73
+ const workspaceId = scope.workspaceId;
33
74
  try {
34
75
  const initiative = query.get("initiative");
76
+ const projectInitiatives = await resolveProjectInitiativeSet(workspaceId);
35
77
  const includeIdleRaw = query.get("include_idle");
36
78
  const includeIdle = includeIdleRaw === null ? undefined : includeIdleRaw !== "false";
37
- const data = await deps.getLiveAgents({
79
+ const data = (await deps.getLiveAgents({
38
80
  initiative,
81
+ projectId: workspaceId,
39
82
  includeIdle,
83
+ }));
84
+ const agents = Array.isArray(data.agents) ? data.agents : [];
85
+ const scopedAgents = agents.filter((entry) => {
86
+ const row = asRecord(entry);
87
+ if (!row)
88
+ return false;
89
+ const initiativeId = resolveInitiativeIdFromRecord(row);
90
+ if (initiative && initiative.trim().length > 0 && initiativeId !== initiative)
91
+ return false;
92
+ if (projectInitiatives && (!initiativeId || !projectInitiatives.has(initiativeId))) {
93
+ return false;
94
+ }
95
+ if (includeIdle === false) {
96
+ const status = pickStringFromRecord(row, ["status"]);
97
+ if (status === "idle")
98
+ return false;
99
+ }
100
+ return true;
101
+ });
102
+ const summary = scopedAgents.reduce((acc, entry) => {
103
+ const row = asRecord(entry);
104
+ const status = pickStringFromRecord(row, ["status"]) ?? "unknown";
105
+ acc[status] = (acc[status] ?? 0) + 1;
106
+ return acc;
107
+ }, {});
108
+ deps.sendJson(res, 200, {
109
+ ...data,
110
+ agents: scopedAgents,
111
+ summary,
40
112
  });
41
- deps.sendJson(res, 200, data);
42
113
  }
43
114
  catch (err) {
44
115
  try {
45
116
  const initiative = query.get("initiative");
117
+ const projectInitiatives = await resolveProjectInitiativeSet(workspaceId);
46
118
  const includeIdleRaw = query.get("include_idle");
47
119
  const includeIdle = includeIdleRaw === null ? undefined : includeIdleRaw !== "false";
48
120
  const localSnapshot = await deps.loadLocalOpenClawSnapshot(240);
@@ -51,6 +123,12 @@ export function registerLiveMiscRoutes(router, deps) {
51
123
  if (initiative && initiative.trim().length > 0) {
52
124
  agents = agents.filter((agent) => agent.initiativeId === initiative);
53
125
  }
126
+ if (projectInitiatives) {
127
+ agents = agents.filter((agent) => {
128
+ const initiativeId = typeof agent.initiativeId === "string" ? agent.initiativeId : "";
129
+ return initiativeId.length > 0 && projectInitiatives.has(initiativeId);
130
+ });
131
+ }
54
132
  if (includeIdle === false) {
55
133
  agents = agents.filter((agent) => agent.status !== "idle");
56
134
  }
@@ -68,50 +146,161 @@ export function registerLiveMiscRoutes(router, deps) {
68
146
  }
69
147
  }
70
148
  }
71
- router.add("GET", "live/agents", async ({ query, res }) => renderLiveAgents(query, res), "Get live agents");
72
- router.add("HEAD", "live/agents", async ({ query, res }) => renderLiveAgents(query, res), "Get live agents (HEAD)");
73
- async function renderLiveInitiatives(query, res) {
149
+ router.add("GET", "live/agents", async ({ query, res, req }) => renderLiveAgents(query, res, workspaceScopeFromHeaders(req?.headers)), "Get live agents");
150
+ router.add("HEAD", "live/agents", async ({ query, res, req }) => renderLiveAgents(query, res, workspaceScopeFromHeaders(req?.headers)), "Get live agents (HEAD)");
151
+ async function renderLiveInitiatives(query, res, headerScope) {
152
+ const scope = resolveWorkspaceScope(query, headerScope, {
153
+ allowProjectScope: false,
154
+ });
155
+ if (scope.error) {
156
+ deps.sendJson(res, 400, { error: scope.error });
157
+ return;
158
+ }
159
+ const workspaceId = scope.workspaceId;
74
160
  try {
75
161
  const id = query.get("id");
76
- const limit = query.get("limit") ? Number(query.get("limit")) : undefined;
162
+ const projectInitiatives = await resolveProjectInitiativeSet(workspaceId);
163
+ const limitRaw = query.get("limit") ? Number(query.get("limit")) : undefined;
164
+ const offsetRaw = query.get("offset") ? Number(query.get("offset")) : undefined;
165
+ const requestedLimit = Number.isFinite(limitRaw)
166
+ ? Math.max(1, Math.floor(Number(limitRaw)))
167
+ : null;
168
+ const requestedOffset = Number.isFinite(offsetRaw)
169
+ ? Math.max(0, Math.floor(Number(offsetRaw)))
170
+ : 0;
77
171
  const data = await deps.getLiveInitiatives({
78
172
  id,
79
- limit: Number.isFinite(limit) ? limit : undefined,
173
+ projectId: workspaceId,
174
+ limit: requestedLimit ?? undefined,
175
+ offset: requestedOffset,
80
176
  });
81
177
  const payload = data;
82
- const initiatives = Array.isArray(payload.initiatives)
83
- ? payload.initiatives.map((entry) => {
84
- if (!entry || typeof entry !== "object")
85
- return entry;
86
- const row = entry;
178
+ const rawInitiatives = Array.isArray(payload.initiatives) ? payload.initiatives : [];
179
+ const applyLocalOverrides = (rows) => rows.map((entry) => {
180
+ if (!entry || typeof entry !== "object")
181
+ return entry;
182
+ const row = entry;
183
+ const initiativeId = deps.pickString(row, ["id"]);
184
+ if (!initiativeId)
185
+ return entry;
186
+ const override = deps.localInitiativeStatusOverrides.get(initiativeId) ?? null;
187
+ if (!override)
188
+ return entry;
189
+ return {
190
+ ...row,
191
+ status: override.status,
192
+ updatedAt: deps.pickString(row, ["updatedAt", "updated_at"]) ?? override.updatedAt,
193
+ };
194
+ });
195
+ let initiatives = Array.isArray(payload.initiatives)
196
+ ? payload.initiatives
197
+ .filter((entry) => {
198
+ const row = asRecord(entry);
199
+ if (!row)
200
+ return false;
87
201
  const initiativeId = deps.pickString(row, ["id"]);
88
202
  if (!initiativeId)
89
- return entry;
90
- const override = deps.localInitiativeStatusOverrides.get(initiativeId) ?? null;
91
- if (!override)
92
- return entry;
93
- return {
94
- ...row,
95
- status: override.status,
96
- updatedAt: deps.pickString(row, ["updatedAt", "updated_at"]) ?? override.updatedAt,
97
- };
203
+ return false;
204
+ if (id && id.trim().length > 0 && initiativeId !== id)
205
+ return false;
206
+ if (projectInitiatives && !projectInitiatives.has(initiativeId))
207
+ return false;
208
+ return true;
98
209
  })
210
+ .map((entry) => entry)
99
211
  : payload.initiatives;
212
+ initiatives = Array.isArray(initiatives) ? applyLocalOverrides(initiatives) : initiatives;
213
+ let fallbackHydratedFromScope = false;
214
+ if (Array.isArray(initiatives) &&
215
+ initiatives.length === 0 &&
216
+ !id &&
217
+ projectInitiatives &&
218
+ projectInitiatives.size > 0) {
219
+ const scopedIds = Array.from(projectInitiatives.values()).slice(requestedOffset, requestedOffset + (requestedLimit ?? 50));
220
+ const hydrated = [];
221
+ for (const initiativeId of scopedIds) {
222
+ try {
223
+ const single = await deps.getLiveInitiatives({
224
+ id: initiativeId,
225
+ projectId: null,
226
+ limit: 1,
227
+ offset: 0,
228
+ });
229
+ const singleRows = Array.isArray(single?.initiatives)
230
+ ? single.initiatives
231
+ : [];
232
+ const match = singleRows.find((entry) => {
233
+ const row = asRecord(entry);
234
+ const rowId = deps.pickString(row ?? {}, ["id"]);
235
+ return rowId === initiativeId;
236
+ });
237
+ if (match)
238
+ hydrated.push(match);
239
+ }
240
+ catch {
241
+ // Ignore per-initiative hydration failures and continue with remaining IDs.
242
+ }
243
+ }
244
+ if (hydrated.length > 0) {
245
+ initiatives = applyLocalOverrides(hydrated);
246
+ fallbackHydratedFromScope = true;
247
+ }
248
+ }
249
+ const remotePagination = asRecord(payload.pagination);
250
+ const remoteHasMoreComputed = typeof remotePagination?.has_more === "boolean"
251
+ ? remotePagination.has_more
252
+ : typeof payload.total === "number"
253
+ ? requestedOffset + rawInitiatives.length < payload.total
254
+ : requestedLimit !== null
255
+ ? rawInitiatives.length >= requestedLimit
256
+ : false;
257
+ const scopedTotal = fallbackHydratedFromScope && projectInitiatives
258
+ ? projectInitiatives.size
259
+ : Array.isArray(initiatives)
260
+ ? initiatives.length
261
+ : 0;
262
+ const scopedHasMore = fallbackHydratedFromScope && projectInitiatives
263
+ ? requestedOffset + (Array.isArray(initiatives) ? initiatives.length : 0) <
264
+ projectInitiatives.size
265
+ : remoteHasMoreComputed;
100
266
  deps.sendJson(res, 200, {
101
267
  ...payload,
102
268
  initiatives,
269
+ total: scopedTotal,
270
+ pagination: {
271
+ ...(remotePagination ?? {}),
272
+ limit: typeof remotePagination?.limit === "number"
273
+ ? remotePagination.limit
274
+ : (requestedLimit ?? rawInitiatives.length),
275
+ offset: typeof remotePagination?.offset === "number"
276
+ ? remotePagination.offset
277
+ : requestedOffset,
278
+ has_more: scopedHasMore,
279
+ },
280
+ ...(fallbackHydratedFromScope
281
+ ? {
282
+ scopedFallback: true,
283
+ scopedFallbackReason: "upstream live initiatives page did not contain requested workspace rows",
284
+ }
285
+ : {}),
103
286
  });
104
287
  }
105
288
  catch (err) {
106
289
  try {
107
290
  const id = query.get("id");
291
+ const projectInitiatives = await resolveProjectInitiativeSet(workspaceId);
108
292
  const limitRaw = query.get("limit") ? Number(query.get("limit")) : undefined;
293
+ const offsetRaw = query.get("offset") ? Number(query.get("offset")) : undefined;
109
294
  const limit = Number.isFinite(limitRaw) ? Math.max(1, Number(limitRaw)) : 100;
295
+ const offset = Number.isFinite(offsetRaw) ? Math.max(0, Number(offsetRaw)) : 0;
110
296
  const local = deps.toLocalLiveInitiatives(await deps.loadLocalOpenClawSnapshot(240));
111
297
  let initiatives = local.initiatives;
112
298
  if (id && id.trim().length > 0) {
113
299
  initiatives = initiatives.filter((item) => item.id === id);
114
300
  }
301
+ if (projectInitiatives) {
302
+ initiatives = initiatives.filter((item) => projectInitiatives.has(item.id));
303
+ }
115
304
  initiatives = initiatives.map((item) => {
116
305
  const override = deps.localInitiativeStatusOverrides.get(item.id) ?? null;
117
306
  if (!override)
@@ -125,7 +314,10 @@ export function registerLiveMiscRoutes(router, deps) {
125
314
  const requestedId = id?.trim() ?? "";
126
315
  if (requestedId.length > 0) {
127
316
  const override = deps.localInitiativeStatusOverrides.get(requestedId) ?? null;
128
- if (override && !initiatives.some((item) => item.id === requestedId)) {
317
+ const allowedByProject = !projectInitiatives || projectInitiatives.has(requestedId);
318
+ if (override &&
319
+ allowedByProject &&
320
+ !initiatives.some((item) => item.id === requestedId)) {
129
321
  initiatives.push({
130
322
  id: requestedId,
131
323
  title: `Initiative ${requestedId.slice(0, 8)}`,
@@ -138,6 +330,8 @@ export function registerLiveMiscRoutes(router, deps) {
138
330
  }
139
331
  else {
140
332
  for (const [initiativeId, override] of deps.localInitiativeStatusOverrides.entries()) {
333
+ if (projectInitiatives && !projectInitiatives.has(initiativeId))
334
+ continue;
141
335
  if (initiatives.some((item) => item.id === initiativeId))
142
336
  continue;
143
337
  initiatives.push({
@@ -150,9 +344,16 @@ export function registerLiveMiscRoutes(router, deps) {
150
344
  });
151
345
  }
152
346
  }
347
+ const total = initiatives.length;
348
+ const page = initiatives.slice(offset, offset + limit);
153
349
  deps.sendJson(res, 200, {
154
- initiatives: initiatives.slice(0, limit),
155
- total: initiatives.length,
350
+ initiatives: page,
351
+ total,
352
+ pagination: {
353
+ limit,
354
+ offset,
355
+ has_more: offset + page.length < total,
356
+ },
156
357
  localFallback: true,
157
358
  warning: deps.safeErrorMessage(err),
158
359
  });
@@ -165,22 +366,41 @@ export function registerLiveMiscRoutes(router, deps) {
165
366
  }
166
367
  }
167
368
  }
168
- router.add("GET", "live/initiatives", async ({ query, res }) => renderLiveInitiatives(query, res), "Get live initiatives");
169
- router.add("HEAD", "live/initiatives", async ({ query, res }) => renderLiveInitiatives(query, res), "Get live initiatives (HEAD)");
170
- async function renderLiveDecisions(query, res) {
369
+ router.add("GET", "live/initiatives", async ({ query, res, req }) => renderLiveInitiatives(query, res, workspaceScopeFromHeaders(req?.headers)), "Get live initiatives");
370
+ router.add("HEAD", "live/initiatives", async ({ query, res, req }) => renderLiveInitiatives(query, res, workspaceScopeFromHeaders(req?.headers)), "Get live initiatives (HEAD)");
371
+ async function renderLiveDecisions(query, res, headerScope) {
372
+ const scope = resolveWorkspaceScope(query, headerScope, {
373
+ allowProjectScope: false,
374
+ });
375
+ if (scope.error) {
376
+ deps.sendJson(res, 400, { error: scope.error });
377
+ return;
378
+ }
379
+ const workspaceId = scope.workspaceId;
171
380
  try {
172
381
  const status = query.get("status") ?? "pending";
382
+ const projectInitiatives = await resolveProjectInitiativeSet(workspaceId);
173
383
  const limit = query.get("limit") ? Number(query.get("limit")) : 100;
174
384
  const data = await deps.getLiveDecisions({
175
385
  status,
386
+ projectId: workspaceId,
176
387
  limit: Number.isFinite(limit) ? limit : 100,
177
388
  });
178
389
  const decisions = data.decisions
179
390
  .map(deps.mapDecisionEntity)
391
+ .filter((entry) => {
392
+ if (!projectInitiatives)
393
+ return true;
394
+ const row = asRecord(entry);
395
+ if (!row)
396
+ return false;
397
+ const initiativeId = resolveInitiativeIdFromRecord(row);
398
+ return Boolean(initiativeId && projectInitiatives.has(initiativeId));
399
+ })
180
400
  .sort((a, b) => b.waitingMinutes - a.waitingMinutes);
181
401
  deps.sendJson(res, 200, {
182
402
  decisions,
183
- total: data.total,
403
+ total: decisions.length,
184
404
  });
185
405
  }
186
406
  catch {
@@ -190,8 +410,8 @@ export function registerLiveMiscRoutes(router, deps) {
190
410
  });
191
411
  }
192
412
  }
193
- router.add("GET", "live/decisions", async ({ query, res }) => renderLiveDecisions(query, res), "Get live decisions");
194
- router.add("HEAD", "live/decisions", async ({ query, res }) => renderLiveDecisions(query, res), "Get live decisions (HEAD)");
413
+ router.add("GET", "live/decisions", async ({ query, res, req }) => renderLiveDecisions(query, res, workspaceScopeFromHeaders(req?.headers)), "Get live decisions");
414
+ router.add("HEAD", "live/decisions", async ({ query, res, req }) => renderLiveDecisions(query, res, workspaceScopeFromHeaders(req?.headers)), "Get live decisions (HEAD)");
195
415
  async function renderHandoffs(res) {
196
416
  try {
197
417
  const data = await deps.getHandoffs();
@@ -1,6 +1,7 @@
1
1
  import type { HandoffSummary, LiveActivityItem, SessionTreeResponse } from "../../types.js";
2
2
  import type { RuntimeInstanceRecord } from "../../runtime-instance-store.js";
3
3
  import type { OutboxSummary } from "../../outbox.js";
4
+ import type { ChatThreadSummary } from "../../chat-store.js";
4
5
  import type { AgentLaunchContext, RunLaunchContext } from "../../agent-context-store.js";
5
6
  import type { Router } from "../router.js";
6
7
  type LocalSnapshot = Awaited<ReturnType<typeof import("../../local-openclaw.js").loadLocalOpenClawSnapshot>>;
@@ -12,7 +13,7 @@ type SnapshotPersistState = {
12
13
  lastFingerprint: string;
13
14
  lastPersistAt: number;
14
15
  };
15
- type LiveSnapshotRoutesDeps<TRes> = {
16
+ type LiveSnapshotRoutesDeps<TReq, TRes> = {
16
17
  parsePositiveInt: (raw: string | null, fallback: number) => number;
17
18
  readSnapshotResponseCache: (key: string) => Record<string, unknown> | null;
18
19
  writeSnapshotResponseCache: (key: string, payload: Record<string, unknown>) => void;
@@ -36,11 +37,13 @@ type LiveSnapshotRoutesDeps<TRes> = {
36
37
  };
37
38
  getLiveSessions: (input: {
38
39
  initiative: string | null;
40
+ projectId: string | null;
39
41
  limit: number;
40
42
  }) => Promise<SessionTreeResponse>;
41
43
  getLiveActivity: (input: {
42
44
  run: string | null;
43
45
  since: string | null;
46
+ projectId: string | null;
44
47
  limit: number;
45
48
  }) => Promise<{
46
49
  activities: LiveActivityItem[];
@@ -50,16 +53,21 @@ type LiveSnapshotRoutesDeps<TRes> = {
50
53
  }>;
51
54
  getLiveDecisions: (input: {
52
55
  status: string;
56
+ projectId: string | null;
53
57
  limit: number;
54
58
  }) => Promise<{
55
59
  decisions: unknown[];
56
60
  }>;
57
61
  getLiveAgents: (input: {
58
62
  initiative: string | null;
63
+ projectId: string | null;
59
64
  includeIdle: boolean | undefined;
60
65
  }) => Promise<{
61
66
  agents?: unknown[];
62
67
  }>;
68
+ listInitiativeIdsForProject: (input: {
69
+ projectId: string;
70
+ }) => Promise<string[]>;
63
71
  mapDecisionEntity: (entry: unknown) => Record<string, unknown> & {
64
72
  waitingMinutes: number;
65
73
  };
@@ -84,7 +92,45 @@ type LiveSnapshotRoutesDeps<TRes> = {
84
92
  snapshotActivityPersistMinIntervalMs: number;
85
93
  readSnapshotPersistState: () => SnapshotPersistState;
86
94
  writeSnapshotPersistState: (state: SnapshotPersistState) => void;
95
+ parseJsonRequest?: (req: TReq) => Promise<Record<string, unknown>>;
96
+ buildNextUpQueue?: (input: {
97
+ initiativeId?: string | null;
98
+ projectId?: string | null;
99
+ }) => Promise<{
100
+ items: Array<Record<string, unknown>>;
101
+ degraded: string[];
102
+ }>;
103
+ bulkDecideDecisions?: (ids: string[], action: "approve" | "reject", input?: {
104
+ note?: string;
105
+ optionId?: string;
106
+ }) => Promise<Array<{
107
+ id?: string;
108
+ ok?: boolean;
109
+ error?: string;
110
+ }>>;
111
+ emitDecisionResolvedActivity?: (input: {
112
+ ids: string[];
113
+ action: "approve" | "reject";
114
+ note?: string | null;
115
+ optionId?: string | null;
116
+ sliceRunId?: string | null;
117
+ initiativeId?: string | null;
118
+ }) => Promise<void>;
119
+ runAction?: (runId: string, action: "pause" | "resume" | "cancel" | "rollback", input?: {
120
+ checkpointId?: string;
121
+ reason?: string;
122
+ }) => Promise<unknown>;
123
+ listChatThreads?: (input: {
124
+ commandCenterId?: string | null;
125
+ initiativeId?: string | null;
126
+ limit?: number;
127
+ offset?: number;
128
+ }) => {
129
+ threads: ChatThreadSummary[];
130
+ total: number;
131
+ updatedAt: string;
132
+ };
87
133
  sendJson: (res: TRes, status: number, payload: unknown) => void;
88
134
  };
89
- export declare function registerLiveSnapshotRoutes<TReq, TRes>(router: Router<Record<string, never>, TReq, TRes>, deps: LiveSnapshotRoutesDeps<TRes>): void;
135
+ export declare function registerLiveSnapshotRoutes<TReq, TRes>(router: Router<Record<string, never>, TReq, TRes>, deps: LiveSnapshotRoutesDeps<TReq, TRes>): void;
90
136
  export {};