@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.
- package/README.md +35 -0
- package/dashboard/dist/assets/BJgZIVUQ.js +53 -0
- package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
- package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
- package/dashboard/dist/assets/BXWDRGm-.js +1 -0
- package/dashboard/dist/assets/BXWDRGm-.js.br +0 -0
- package/dashboard/dist/assets/BXWDRGm-.js.gz +0 -0
- package/dashboard/dist/assets/BgOYB78t.js +4 -0
- package/dashboard/dist/assets/BgOYB78t.js.br +0 -0
- package/dashboard/dist/assets/BgOYB78t.js.gz +0 -0
- package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
- package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
- package/dashboard/dist/assets/CE38zU4U.js +1 -0
- package/dashboard/dist/assets/CE38zU4U.js.br +0 -0
- package/dashboard/dist/assets/CE38zU4U.js.gz +0 -0
- package/dashboard/dist/assets/CFGKRAzG.js +1 -0
- package/dashboard/dist/assets/CFGKRAzG.js.br +0 -0
- package/dashboard/dist/assets/CFGKRAzG.js.gz +0 -0
- package/dashboard/dist/assets/CGGR2GZh.js +1 -0
- package/dashboard/dist/assets/CGGR2GZh.js.br +0 -0
- package/dashboard/dist/assets/CGGR2GZh.js.gz +0 -0
- package/dashboard/dist/assets/CL_wXqR7.js +1 -0
- package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
- package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
- package/dashboard/dist/assets/CPFiTmlw.js +8 -0
- package/dashboard/dist/assets/CPFiTmlw.js.br +0 -0
- package/dashboard/dist/assets/CPFiTmlw.js.gz +0 -0
- package/dashboard/dist/assets/CZZTvkQZ.js +1 -0
- package/dashboard/dist/assets/CZZTvkQZ.js.br +0 -0
- package/dashboard/dist/assets/CZZTvkQZ.js.gz +0 -0
- package/dashboard/dist/assets/{CpJsfbXo.js → CxQ08qFN.js} +2 -2
- package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
- package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
- package/dashboard/dist/assets/D-bf6hEI.js +213 -0
- package/dashboard/dist/assets/D-bf6hEI.js.br +0 -0
- package/dashboard/dist/assets/D-bf6hEI.js.gz +0 -0
- package/dashboard/dist/assets/DG6y9wJI.js +2 -0
- package/dashboard/dist/assets/DG6y9wJI.js.br +0 -0
- package/dashboard/dist/assets/DG6y9wJI.js.gz +0 -0
- package/dashboard/dist/assets/DNxKz-GV.js +1 -0
- package/dashboard/dist/assets/DNxKz-GV.js.br +0 -0
- package/dashboard/dist/assets/DNxKz-GV.js.gz +0 -0
- package/dashboard/dist/assets/DW_rKUic.js +11 -0
- package/dashboard/dist/assets/DW_rKUic.js.br +0 -0
- package/dashboard/dist/assets/DW_rKUic.js.gz +0 -0
- package/dashboard/dist/assets/DbNoijHm.js +1 -0
- package/dashboard/dist/assets/DbNoijHm.js.br +0 -0
- package/dashboard/dist/assets/DbNoijHm.js.gz +0 -0
- package/dashboard/dist/assets/DjcdE6jC.js +2 -0
- package/dashboard/dist/assets/DjcdE6jC.js.br +0 -0
- package/dashboard/dist/assets/DjcdE6jC.js.gz +0 -0
- package/dashboard/dist/assets/FZYuCDnt.js +1 -0
- package/dashboard/dist/assets/FZYuCDnt.js.br +0 -0
- package/dashboard/dist/assets/FZYuCDnt.js.gz +0 -0
- package/dashboard/dist/assets/PAUiij_z.js +1 -0
- package/dashboard/dist/assets/PAUiij_z.js.br +0 -0
- package/dashboard/dist/assets/PAUiij_z.js.gz +0 -0
- package/dashboard/dist/assets/cNrhgGc1.js +8 -0
- package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
- package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
- package/dashboard/dist/assets/h5biQs2I.css +1 -0
- package/dashboard/dist/assets/h5biQs2I.css.br +0 -0
- package/dashboard/dist/assets/h5biQs2I.css.gz +0 -0
- package/dashboard/dist/assets/ic2FaMnh.js +1 -0
- package/dashboard/dist/assets/ic2FaMnh.js.br +0 -0
- package/dashboard/dist/assets/ic2FaMnh.js.gz +0 -0
- package/dashboard/dist/assets/nByHNHoW.js +1 -0
- package/dashboard/dist/assets/nByHNHoW.js.br +0 -0
- package/dashboard/dist/assets/nByHNHoW.js.gz +0 -0
- package/dashboard/dist/assets/qm8xLgv-.css +1 -0
- package/dashboard/dist/assets/qm8xLgv-.css.br +0 -0
- package/dashboard/dist/assets/qm8xLgv-.css.gz +0 -0
- package/dashboard/dist/assets/tS9mbYZi.js +1 -0
- package/dashboard/dist/assets/tS9mbYZi.js.br +0 -0
- package/dashboard/dist/assets/tS9mbYZi.js.gz +0 -0
- package/dashboard/dist/brand/anthropic-mark.svg.br +0 -0
- package/dashboard/dist/brand/anthropic-mark.svg.gz +0 -0
- package/dashboard/dist/brand/openai-mark.svg.br +0 -0
- package/dashboard/dist/brand/openai-mark.svg.gz +0 -0
- package/dashboard/dist/brand/openclaw-mark.svg.br +0 -0
- package/dashboard/dist/brand/openclaw-mark.svg.gz +0 -0
- package/dashboard/dist/brand/xandy-orchestrator.png +0 -0
- package/dashboard/dist/index.html +7 -5
- package/dashboard/dist/index.html.br +0 -0
- package/dashboard/dist/index.html.gz +0 -0
- package/dist/activity-actor-fields.js +26 -4
- package/dist/activity-store.js +34 -8
- package/dist/agent-context-store.js +79 -17
- package/dist/agent-run-store.js +44 -3
- package/dist/agent-suite.d.ts +9 -0
- package/dist/agent-suite.js +149 -9
- package/dist/artifacts/artifact-domain-schemas.d.ts +66 -0
- package/dist/artifacts/artifact-domain-schemas.js +357 -0
- package/dist/artifacts/register-artifact.d.ts +4 -3
- package/dist/artifacts/register-artifact.js +170 -57
- package/dist/chat-store.d.ts +157 -0
- package/dist/chat-store.js +586 -0
- package/dist/cli/orgx.js +11 -0
- package/dist/contracts/client.d.ts +43 -3
- package/dist/contracts/client.js +159 -30
- package/dist/contracts/retro-schema.d.ts +81 -0
- package/dist/contracts/retro-schema.js +80 -0
- package/dist/contracts/shared-types.d.ts +159 -0
- package/dist/contracts/shared-types.js +177 -1
- package/dist/contracts/skill-pack-schema.d.ts +192 -0
- package/dist/contracts/skill-pack-schema.js +180 -0
- package/dist/contracts/types.d.ts +227 -2
- package/dist/entities/auto-assignment.js +43 -17
- package/dist/event-sanitization.d.ts +11 -0
- package/dist/event-sanitization.js +113 -0
- package/dist/fs-utils.js +13 -1
- package/dist/gateway-watchdog.d.ts +5 -0
- package/dist/gateway-watchdog.js +50 -0
- package/dist/hooks/post-reporting-event.mjs +1 -5
- package/dist/http/helpers/activity-headline.js +13 -132
- package/dist/http/helpers/auto-continue-engine.d.ts +198 -10
- package/dist/http/helpers/auto-continue-engine.js +2531 -186
- package/dist/http/helpers/autopilot-operations.d.ts +19 -0
- package/dist/http/helpers/autopilot-operations.js +182 -31
- package/dist/http/helpers/autopilot-runtime.d.ts +1 -0
- package/dist/http/helpers/autopilot-runtime.js +308 -20
- package/dist/http/helpers/autopilot-slice-utils.d.ts +18 -0
- package/dist/http/helpers/autopilot-slice-utils.js +516 -93
- package/dist/http/helpers/decision-mapper.d.ts +40 -0
- package/dist/http/helpers/decision-mapper.js +223 -7
- package/dist/http/helpers/dispatch-lifecycle.d.ts +19 -2
- package/dist/http/helpers/dispatch-lifecycle.js +242 -37
- package/dist/http/helpers/kickoff-context.js +74 -0
- package/dist/http/helpers/llm-client.d.ts +47 -0
- package/dist/http/helpers/llm-client.js +256 -0
- package/dist/http/helpers/mission-control.d.ts +102 -3
- package/dist/http/helpers/mission-control.js +498 -9
- package/dist/http/helpers/sentinel-catalog.d.ts +23 -0
- package/dist/http/helpers/sentinel-catalog.js +193 -0
- package/dist/http/helpers/session-classification.d.ts +9 -0
- package/dist/http/helpers/session-classification.js +564 -0
- package/dist/http/helpers/slice-experience-v2.d.ts +137 -0
- package/dist/http/helpers/slice-experience-v2.js +677 -0
- package/dist/http/helpers/slice-run-projections.d.ts +72 -0
- package/dist/http/helpers/slice-run-projections.js +860 -0
- package/dist/http/helpers/triage-mapper.d.ts +43 -0
- package/dist/http/helpers/triage-mapper.js +549 -0
- package/dist/http/helpers/value-utils.js +7 -2
- package/dist/http/helpers/workspace-scope.d.ts +15 -0
- package/dist/http/helpers/workspace-scope.js +170 -0
- package/dist/http/index.js +1354 -97
- package/dist/http/routes/agent-suite.d.ts +9 -0
- package/dist/http/routes/agent-suite.js +207 -8
- package/dist/http/routes/agents-catalog.js +64 -19
- package/dist/http/routes/chat.d.ts +19 -0
- package/dist/http/routes/chat.js +522 -0
- package/dist/http/routes/decision-actions.d.ts +8 -1
- package/dist/http/routes/decision-actions.js +42 -5
- package/dist/http/routes/dispatch-gateway-envelope.d.ts +25 -0
- package/dist/http/routes/dispatch-gateway-envelope.js +26 -0
- package/dist/http/routes/entities.d.ts +16 -0
- package/dist/http/routes/entities.js +294 -6
- package/dist/http/routes/live-legacy.d.ts +5 -0
- package/dist/http/routes/live-legacy.js +23 -509
- package/dist/http/routes/live-misc.d.ts +12 -0
- package/dist/http/routes/live-misc.js +251 -31
- package/dist/http/routes/live-snapshot.d.ts +48 -2
- package/dist/http/routes/live-snapshot.js +638 -19
- package/dist/http/routes/live-terminal.d.ts +11 -0
- package/dist/http/routes/live-terminal.js +261 -0
- package/dist/http/routes/live-triage.d.ts +61 -0
- package/dist/http/routes/live-triage.js +248 -0
- package/dist/http/routes/mission-control-actions.d.ts +49 -1
- package/dist/http/routes/mission-control-actions.js +1334 -84
- package/dist/http/routes/mission-control-read.d.ts +48 -3
- package/dist/http/routes/mission-control-read.js +1593 -20
- package/dist/http/routes/realtime-orchestrator.d.ts +10 -0
- package/dist/http/routes/realtime-orchestrator.js +74 -0
- package/dist/http/routes/run-control.d.ts +5 -2
- package/dist/http/routes/run-control.js +10 -0
- package/dist/http/routes/sentinels-catalog.d.ts +7 -0
- package/dist/http/routes/sentinels-catalog.js +24 -0
- package/dist/http/routes/summary.js +10 -3
- package/dist/http/routes/usage.d.ts +24 -0
- package/dist/http/routes/usage.js +362 -0
- package/dist/http/routes/work-artifacts.js +28 -9
- package/dist/index.js +165 -27
- package/dist/local-openclaw.js +29 -6
- package/dist/mcp-client-setup.js +3 -3
- package/dist/mcp-http-handler.js +33 -59
- package/dist/next-up-queue-store.d.ts +16 -1
- package/dist/next-up-queue-store.js +89 -7
- package/dist/outbox.d.ts +5 -0
- package/dist/outbox.js +113 -9
- package/dist/paths.js +24 -5
- package/dist/reporting/rollups.d.ts +53 -0
- package/dist/reporting/rollups.js +148 -0
- package/dist/retro/domain-templates.d.ts +45 -0
- package/dist/retro/domain-templates.js +297 -0
- package/dist/retro/quality-rubric.d.ts +33 -0
- package/dist/retro/quality-rubric.js +213 -0
- package/dist/runtime-cleanup.d.ts +18 -0
- package/dist/runtime-cleanup.js +87 -0
- package/dist/services/background.d.ts +11 -0
- package/dist/services/background.js +22 -0
- package/dist/services/experiment-randomization.d.ts +21 -0
- package/dist/services/experiment-randomization.js +63 -0
- package/dist/skill-pack-state.d.ts +36 -5
- package/dist/skill-pack-state.js +273 -29
- package/dist/sync/local-agent-telemetry.d.ts +13 -0
- package/dist/sync/local-agent-telemetry.js +128 -0
- package/dist/sync/outbox-replay.js +131 -24
- package/dist/team-context-store.d.ts +23 -0
- package/dist/team-context-store.js +116 -0
- package/dist/telemetry/posthog.js +4 -2
- package/dist/tools/core-tools.d.ts +10 -14
- package/dist/tools/core-tools.js +1289 -24
- package/dist/types.d.ts +2 -0
- package/dist/types.js +2 -0
- package/dist/worker-supervisor.js +23 -0
- package/package.json +14 -4
- package/dashboard/dist/assets/B3ziCA02.js +0 -8
- package/dashboard/dist/assets/B5NEElEI.css +0 -1
- package/dashboard/dist/assets/BhapSNAs.js +0 -215
- package/dashboard/dist/assets/iFdvE7lx.js +0 -1
- package/dashboard/dist/assets/jRJsmpYM.js +0 -1
- 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
|
-
|
|
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
|
|
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[];
|