@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
@@ -12,9 +12,16 @@ type EntityClientLike = {
12
12
  createEntity: (type: string, data: Record<string, unknown>) => Promise<Entity>;
13
13
  updateEntity: (type: string, id: string, updates: Record<string, unknown>) => Promise<Entity>;
14
14
  listEntities: (type: string, input: {
15
+ id?: string;
16
+ ids?: string[] | string;
17
+ search?: string;
15
18
  status?: string;
16
19
  initiative_id?: string;
20
+ project_id?: string;
21
+ workspace_id?: string;
22
+ command_center_id?: string;
17
23
  limit?: number;
24
+ offset?: number;
18
25
  }) => Promise<unknown>;
19
26
  };
20
27
  type RegisterEntitiesRoutesDeps<TReq, TRes> = {
@@ -40,6 +47,15 @@ type RegisterEntitiesRoutesDeps<TReq, TRes> = {
40
47
  progress?: number | null;
41
48
  }>;
42
49
  getSnapshot: () => OrgSnapshot | null;
50
+ scheduleWorkstreamReassignment?: (input: {
51
+ initiativeId: string;
52
+ workstreamId: string;
53
+ status: string | null;
54
+ event: string;
55
+ }) => Promise<{
56
+ requestId?: string | null;
57
+ dueAt?: string | null;
58
+ } | null>;
43
59
  sendJson: (res: TRes, status: number, payload: unknown) => void;
44
60
  safeErrorMessage: (err: unknown) => string;
45
61
  };
@@ -1,3 +1,44 @@
1
+ import { resolveWorkspaceScope, workspaceScopeFromHeaders, } from "../helpers/workspace-scope.js";
2
+ import { cascadeProgressFromChildren, deriveLifecycleState, } from "../../reporting/rollups.js";
3
+ const WORKSTREAM_REASSIGNMENT_FIELDS = [
4
+ "domain",
5
+ "role",
6
+ "assigned_agents",
7
+ "assignedAgents",
8
+ "assigned_agent_ids",
9
+ "assignedAgentIds",
10
+ "assigned_agent_names",
11
+ "assignedAgentNames",
12
+ ];
13
+ function hasOwn(input, key) {
14
+ return Object.prototype.hasOwnProperty.call(input, key);
15
+ }
16
+ function hasMeaningfulReassignmentValue(value) {
17
+ if (typeof value === "string")
18
+ return value.trim().length > 0;
19
+ if (Array.isArray(value))
20
+ return value.length > 0;
21
+ return value !== null && value !== undefined;
22
+ }
23
+ function includesWorkstreamReassignmentMutation(payload) {
24
+ return WORKSTREAM_REASSIGNMENT_FIELDS.some((field) => hasOwn(payload, field) && hasMeaningfulReassignmentValue(payload[field]));
25
+ }
26
+ function isActiveOrReadyStatus(status) {
27
+ const normalized = (status ?? "").trim().toLowerCase();
28
+ if (!normalized)
29
+ return false;
30
+ return (normalized === "active" ||
31
+ normalized === "ready" ||
32
+ normalized === "in_progress" ||
33
+ normalized === "running" ||
34
+ normalized === "queued" ||
35
+ normalized === "pending");
36
+ }
37
+ function toObjectArray(input) {
38
+ if (!Array.isArray(input))
39
+ return [];
40
+ return input.filter((item) => Boolean(item) && typeof item === "object");
41
+ }
1
42
  export function registerEntitiesRoutes(router, deps) {
2
43
  router.add("POST", "entities", async ({ req, res }) => {
3
44
  try {
@@ -59,10 +100,164 @@ export function registerEntitiesRoutes(router, deps) {
59
100
  const normalizedType = type.trim().toLowerCase();
60
101
  const normalizedUpdates = deps.normalizeEntityMutationPayload(updates);
61
102
  const entity = await deps.client.updateEntity(type, id, normalizedUpdates);
103
+ let reassignment = null;
104
+ let initiativeReassignment = null;
105
+ if (normalizedType === "workstream" &&
106
+ deps.scheduleWorkstreamReassignment &&
107
+ includesWorkstreamReassignmentMutation(normalizedUpdates)) {
108
+ const entityRecord = entity && typeof entity === "object"
109
+ ? entity
110
+ : {};
111
+ const initiativeId = deps.pickString(entityRecord, ["initiative_id", "initiativeId"]) ??
112
+ deps.pickString(normalizedUpdates, ["initiative_id", "initiativeId"]) ??
113
+ null;
114
+ const workstreamStatus = deps.pickString(entityRecord, ["status"]) ??
115
+ deps.pickString(normalizedUpdates, ["status"]) ??
116
+ null;
117
+ if (!initiativeId) {
118
+ reassignment = { scheduled: false, reason: "missing_initiative" };
119
+ }
120
+ else if (!isActiveOrReadyStatus(workstreamStatus)) {
121
+ reassignment = { scheduled: false, reason: "workstream_not_active_or_ready" };
122
+ }
123
+ else {
124
+ try {
125
+ const scheduled = await deps.scheduleWorkstreamReassignment({
126
+ initiativeId,
127
+ workstreamId: id,
128
+ status: workstreamStatus,
129
+ event: "workstream_reassigned",
130
+ });
131
+ reassignment = {
132
+ scheduled: true,
133
+ requestId: scheduled && typeof scheduled === "object"
134
+ ? (deps.pickString(scheduled, ["requestId"]) ?? null)
135
+ : null,
136
+ dueAt: scheduled && typeof scheduled === "object"
137
+ ? (deps.pickString(scheduled, ["dueAt"]) ?? null)
138
+ : null,
139
+ };
140
+ }
141
+ catch (reassignmentErr) {
142
+ reassignment = {
143
+ scheduled: false,
144
+ reason: `schedule_failed:${deps.safeErrorMessage(reassignmentErr)}`,
145
+ };
146
+ }
147
+ }
148
+ }
149
+ if (normalizedType === "initiative" &&
150
+ deps.scheduleWorkstreamReassignment &&
151
+ includesWorkstreamReassignmentMutation(normalizedUpdates)) {
152
+ const workstreams = await deps.client.listEntities("workstream", {
153
+ initiative_id: id,
154
+ limit: 200,
155
+ });
156
+ const workstreamRows = toObjectArray(workstreams && typeof workstreams === "object"
157
+ ? workstreams.data
158
+ : []);
159
+ const failures = [];
160
+ let requested = 0;
161
+ let scheduled = 0;
162
+ let skipped = 0;
163
+ for (const row of workstreamRows) {
164
+ const workstreamId = deps.pickString(row, ["id"]);
165
+ if (!workstreamId) {
166
+ skipped += 1;
167
+ continue;
168
+ }
169
+ const workstreamStatus = deps.pickString(row, ["status"]);
170
+ requested += 1;
171
+ if (!isActiveOrReadyStatus(workstreamStatus)) {
172
+ skipped += 1;
173
+ continue;
174
+ }
175
+ try {
176
+ await deps.scheduleWorkstreamReassignment({
177
+ initiativeId: id,
178
+ workstreamId,
179
+ status: workstreamStatus,
180
+ event: "initiative_reassigned",
181
+ });
182
+ scheduled += 1;
183
+ }
184
+ catch (reassignmentErr) {
185
+ failures.push(`${workstreamId}:${deps.safeErrorMessage(reassignmentErr)}`);
186
+ }
187
+ }
188
+ initiativeReassignment = {
189
+ triggered: true,
190
+ requested,
191
+ scheduled,
192
+ skipped,
193
+ failures,
194
+ };
195
+ }
62
196
  if (normalizedType === "initiative") {
63
197
  deps.clearLocalInitiativeStatusOverride(id);
64
198
  }
65
- deps.sendJson(res, 200, { ok: true, entity });
199
+ // Post-status-transition hook: when a task status changes to
200
+ // completed/done, recompute cascaded progress for parent entities.
201
+ let cascadedProgress = null;
202
+ if (normalizedType === "task" && requestedStatus) {
203
+ const normalizedRequestedStatus = requestedStatus.trim().toLowerCase();
204
+ const isTerminal = normalizedRequestedStatus === "done" ||
205
+ normalizedRequestedStatus === "completed" ||
206
+ normalizedRequestedStatus === "cancelled" ||
207
+ normalizedRequestedStatus === "archived";
208
+ if (isTerminal) {
209
+ // Look up sibling tasks for the parent workstream/milestone/initiative
210
+ const entityRecord = entity && typeof entity === "object"
211
+ ? entity
212
+ : {};
213
+ const parentWorkstreamId = deps.pickString(entityRecord, ["workstream_id", "workstreamId"]) ??
214
+ deps.pickString(normalizedUpdates, ["workstream_id", "workstreamId"]);
215
+ const parentInitiativeId = deps.pickString(entityRecord, ["initiative_id", "initiativeId"]) ??
216
+ deps.pickString(normalizedUpdates, ["initiative_id", "initiativeId"]);
217
+ // Fetch sibling tasks to compute cascaded progress
218
+ const parentScope = parentWorkstreamId
219
+ ? { initiative_id: parentInitiativeId ?? undefined }
220
+ : parentInitiativeId
221
+ ? { initiative_id: parentInitiativeId }
222
+ : null;
223
+ if (parentScope) {
224
+ try {
225
+ const siblingResult = await deps.client.listEntities("task", {
226
+ ...parentScope,
227
+ limit: 500,
228
+ });
229
+ const siblingRows = toObjectArray(siblingResult && typeof siblingResult === "object"
230
+ ? siblingResult.data
231
+ : []);
232
+ const siblingStatuses = siblingRows
233
+ .filter((row) => {
234
+ if (!parentWorkstreamId)
235
+ return true;
236
+ const rowWsId = deps.pickString(row, ["workstream_id", "workstreamId"]);
237
+ return rowWsId === parentWorkstreamId;
238
+ })
239
+ .map((row) => deps.pickString(row, ["status"]) ?? "unknown");
240
+ const parentProgress = cascadeProgressFromChildren(siblingStatuses);
241
+ const parentLifecycleState = deriveLifecycleState(parentWorkstreamId ? "active" : (parentInitiativeId ? "active" : "active"), siblingStatuses);
242
+ cascadedProgress = {
243
+ parentProgress,
244
+ parentLifecycleState,
245
+ taskStatuses: siblingStatuses,
246
+ };
247
+ }
248
+ catch {
249
+ // Non-critical: cascade progress is best-effort
250
+ }
251
+ }
252
+ }
253
+ }
254
+ deps.sendJson(res, 200, {
255
+ ok: true,
256
+ entity,
257
+ reassignment,
258
+ initiative_reassignment: initiativeReassignment,
259
+ ...(cascadedProgress ? { cascaded_progress: cascadedProgress } : {}),
260
+ });
66
261
  }
67
262
  catch (err) {
68
263
  if (type?.trim().toLowerCase() === "initiative" &&
@@ -87,7 +282,7 @@ export function registerEntitiesRoutes(router, deps) {
87
282
  });
88
283
  }
89
284
  }, "Update entity");
90
- async function renderEntityList(query, res) {
285
+ async function renderEntityList(query, res, headerScope) {
91
286
  const type = query.get("type");
92
287
  if (!type) {
93
288
  deps.sendJson(res, 400, {
@@ -95,23 +290,92 @@ export function registerEntitiesRoutes(router, deps) {
95
290
  });
96
291
  return;
97
292
  }
293
+ const workspaceScope = resolveWorkspaceScope(query, headerScope, {
294
+ allowProjectScope: false,
295
+ });
296
+ if (workspaceScope.error) {
297
+ deps.sendJson(res, 400, { error: workspaceScope.error });
298
+ return;
299
+ }
98
300
  const status = query.get("status") ?? undefined;
301
+ const id = query.get("id") ?? undefined;
302
+ const ids = query
303
+ .get("ids")
304
+ ?.split(",")
305
+ .map((value) => value.trim())
306
+ .filter((value) => value.length > 0);
307
+ const search = query.get("search")?.trim() || undefined;
99
308
  const initiativeId = query.get("initiative_id") ?? undefined;
309
+ const workspaceId = workspaceScope.workspaceId ?? undefined;
100
310
  const limit = query.get("limit") ? Number(query.get("limit")) : undefined;
311
+ const offset = query.get("offset") ? Number(query.get("offset")) : undefined;
101
312
  try {
102
313
  const data = await deps.client.listEntities(type, {
314
+ id,
315
+ ids,
316
+ search,
103
317
  status,
104
318
  initiative_id: initiativeId,
319
+ workspace_id: workspaceId,
320
+ command_center_id: workspaceId,
105
321
  limit: Number.isFinite(limit) ? limit : undefined,
322
+ offset: Number.isFinite(offset) ? offset : undefined,
106
323
  });
107
324
  if (type.trim().toLowerCase() === "initiative") {
108
325
  const payload = data;
109
- const rows = Array.isArray(payload.data)
326
+ const rawRows = Array.isArray(payload.data)
110
327
  ? payload.data.filter((row) => Boolean(row && typeof row === "object"))
111
328
  : [];
329
+ const filteredById = rawRows.filter((row) => {
330
+ const rowId = deps.pickString(row, ["id"])?.trim();
331
+ if (!rowId)
332
+ return false;
333
+ if (id && rowId !== id.trim())
334
+ return false;
335
+ if (ids && ids.length > 0 && !ids.includes(rowId))
336
+ return false;
337
+ return true;
338
+ });
339
+ const searchTokens = typeof search === "string" && search.length > 0
340
+ ? Array.from(new Set(search
341
+ .toLowerCase()
342
+ .split(/\s+/)
343
+ .map((token) => token.trim())
344
+ .filter((token) => token.length > 0)))
345
+ : [];
346
+ const searchedRows = searchTokens.length > 0
347
+ ? filteredById.filter((row) => {
348
+ const haystack = [
349
+ deps.pickString(row, ["title", "name"]) ?? "",
350
+ deps.pickString(row, ["summary", "description"]) ?? "",
351
+ deps.pickString(row, ["status"]) ?? "",
352
+ ]
353
+ .join(" ")
354
+ .toLowerCase();
355
+ return searchTokens.every((token) => haystack.includes(token));
356
+ })
357
+ : filteredById;
358
+ const workspaceScopeId = (workspaceId ?? "").trim();
359
+ const rows = workspaceScopeId.length > 0
360
+ ? searchedRows.filter((row) => {
361
+ const rowScope = deps.pickString(row, [
362
+ "workspace_id",
363
+ "workspaceId",
364
+ "command_center_id",
365
+ "commandCenterId",
366
+ ]) ?? "";
367
+ return rowScope.trim() === workspaceScopeId;
368
+ })
369
+ : searchedRows;
112
370
  deps.sendJson(res, 200, {
113
371
  ...payload,
114
372
  data: deps.applyLocalInitiativeOverrides(rows),
373
+ pagination: payload.pagination && typeof payload.pagination === "object"
374
+ ? {
375
+ ...payload.pagination,
376
+ total: rows.length,
377
+ }
378
+ : payload.pagination,
115
379
  });
116
380
  return;
117
381
  }
@@ -131,7 +395,22 @@ export function registerEntitiesRoutes(router, deps) {
131
395
  created_at: null,
132
396
  updated_at: null,
133
397
  }))
134
- .filter((item) => (initiativeId ? item.id === initiativeId : true));
398
+ .filter((item) => (initiativeId ? item.id === initiativeId : true))
399
+ .filter((item) => (id ? item.id === id : true))
400
+ .filter((item) => ids && ids.length > 0 ? ids.includes(item.id) : true)
401
+ .filter((item) => {
402
+ if (!search)
403
+ return true;
404
+ const searchTokens = search
405
+ .toLowerCase()
406
+ .split(/\s+/)
407
+ .map((token) => token.trim())
408
+ .filter((token) => token.length > 0);
409
+ if (searchTokens.length === 0)
410
+ return true;
411
+ const haystack = `${item.title} ${item.summary ?? ""} ${item.status ?? ""}`.toLowerCase();
412
+ return searchTokens.every((token) => haystack.includes(token));
413
+ });
135
414
  deps.sendJson(res, 200, {
136
415
  data: deps.applyLocalInitiativeOverrides(snapshotInitiatives),
137
416
  localFallback: true,
@@ -139,13 +418,22 @@ export function registerEntitiesRoutes(router, deps) {
139
418
  });
140
419
  return;
141
420
  }
421
+ if (type.trim().toLowerCase() === "command_center") {
422
+ deps.sendJson(res, 200, {
423
+ data: [],
424
+ pagination: { total: 0, has_more: false },
425
+ localFallback: true,
426
+ warning: deps.safeErrorMessage(err),
427
+ });
428
+ return;
429
+ }
142
430
  deps.sendJson(res, 500, {
143
431
  error: deps.safeErrorMessage(err),
144
432
  });
145
433
  }
146
434
  }
147
- router.add("GET", "entities", async ({ query, res }) => renderEntityList(query, res), "List entities");
148
- router.add("HEAD", "entities", async ({ query, res }) => renderEntityList(query, res), "List entities (HEAD)");
435
+ router.add("GET", "entities", async ({ query, res, req }) => renderEntityList(query, res, workspaceScopeFromHeaders(req?.headers)), "List entities");
436
+ router.add("HEAD", "entities", async ({ query, res, req }) => renderEntityList(query, res, workspaceScopeFromHeaders(req?.headers)), "List entities (HEAD)");
149
437
  router.add("*", "entities", ({ res }) => {
150
438
  deps.sendJson(res, 405, { error: "Method not allowed" });
151
439
  }, "Reject unsupported methods for entities");
@@ -37,13 +37,18 @@ type RouteResLike = {
37
37
  type RegisterLiveLegacyRoutesDeps<TRes extends RouteResLike> = {
38
38
  getLiveSessions: (input: {
39
39
  initiative: string | null;
40
+ projectId: string | null;
40
41
  limit: number | undefined;
41
42
  }) => Promise<LiveSessionsResponse>;
42
43
  getLiveActivity: (input: {
43
44
  run: string | null;
44
45
  since: string | null;
46
+ projectId: string | null;
45
47
  limit: number | undefined;
46
48
  }) => Promise<LiveActivityResponse>;
49
+ listInitiativeIdsForProject: (input: {
50
+ projectId: string;
51
+ }) => Promise<string[]>;
47
52
  listRuntimeInstances: (input: {
48
53
  limit: number;
49
54
  }) => RuntimeInstanceRecord[];