@fieldwangai/agentflow 0.1.134 → 0.1.135
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/bin/lib/ui-server.mjs +106 -4
- package/bin/lib/workflow-report.mjs +88 -4
- package/builtin/web-ui/dist/assets/index-BFQVTav-.css +1 -0
- package/builtin/web-ui/dist/assets/index-CmpbCHAj.js +420 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/skills/agentflow-cli/SKILL.md +3 -70
- package/skills/agentflow-cli/agents/openai.yaml +2 -2
- package/skills/agentflow-workflow-report/SKILL.md +77 -0
- package/skills/agentflow-workflow-report/agents/openai.yaml +4 -0
- package/skills/agentflow-workflow-report/references/protocol.md +337 -0
- package/builtin/web-ui/dist/assets/index-CqXKONpd.js +0 -350
- package/builtin/web-ui/dist/assets/index-QDDFbZ_T.css +0 -1
package/bin/lib/ui-server.mjs
CHANGED
|
@@ -177,6 +177,7 @@ import {
|
|
|
177
177
|
import {
|
|
178
178
|
legacyOverallToGlobalState,
|
|
179
179
|
materializeWorkflowGlobalState,
|
|
180
|
+
materializeWorkflowProjections,
|
|
180
181
|
mergeWorkflowArtifactLists,
|
|
181
182
|
mergeWorkflowArtifacts,
|
|
182
183
|
mergeWorkflowGlobalState,
|
|
@@ -3464,6 +3465,23 @@ function prdWorkflowDashboardSummary(record, snapshot = {}, userCtx = {}) {
|
|
|
3464
3465
|
|| snapshot?.title
|
|
3465
3466
|
|| "",
|
|
3466
3467
|
).trim();
|
|
3468
|
+
const timeline = Array.isArray(snapshot?.projections?.timeline)
|
|
3469
|
+
? snapshot.projections.timeline
|
|
3470
|
+
.filter((entry) => entry && typeof entry === "object" && !Array.isArray(entry))
|
|
3471
|
+
.map((entry) => ({
|
|
3472
|
+
key: String(entry.key || [entry.source, entry.kind, entry.id].filter(Boolean).join(":")),
|
|
3473
|
+
kind: String(entry.kind || ""),
|
|
3474
|
+
id: String(entry.id || ""),
|
|
3475
|
+
title: String(entry.title || entry.label || entry.id || ""),
|
|
3476
|
+
date: String(entry.date || ""),
|
|
3477
|
+
source: String(entry.source || ""),
|
|
3478
|
+
dimensions: entry.dimensions && typeof entry.dimensions === "object" && !Array.isArray(entry.dimensions)
|
|
3479
|
+
? entry.dimensions
|
|
3480
|
+
: {},
|
|
3481
|
+
order: Number.isFinite(Number(entry.order)) ? Number(entry.order) : 0,
|
|
3482
|
+
}))
|
|
3483
|
+
.filter((entry) => entry.kind && entry.id)
|
|
3484
|
+
: [];
|
|
3467
3485
|
const updatedAtTimestamp = Math.max(
|
|
3468
3486
|
prdWorkflowDashboardTimestamp(record),
|
|
3469
3487
|
prdWorkflowDashboardTimestamp(snapshot),
|
|
@@ -3481,6 +3499,7 @@ function prdWorkflowDashboardSummary(record, snapshot = {}, userCtx = {}) {
|
|
|
3481
3499
|
platforms,
|
|
3482
3500
|
actionCount: actions.length,
|
|
3483
3501
|
completedActionCount: completedActions,
|
|
3502
|
+
timeline,
|
|
3484
3503
|
latestAction: latestAction
|
|
3485
3504
|
? {
|
|
3486
3505
|
title: String(latestAction.title || latestAction.label || latestAction.action || latestAction.id || "").trim(),
|
|
@@ -3500,6 +3519,72 @@ function prdWorkflowDashboardSummary(record, snapshot = {}, userCtx = {}) {
|
|
|
3500
3519
|
};
|
|
3501
3520
|
}
|
|
3502
3521
|
|
|
3522
|
+
function prdWorkflowDashboardTimeline(workflows = []) {
|
|
3523
|
+
const buckets = new Map();
|
|
3524
|
+
const assignedWorkflowIds = new Set();
|
|
3525
|
+
const rows = [...(Array.isArray(workflows) ? workflows : [])].sort((left, right) => {
|
|
3526
|
+
const leftAt = Date.parse(String(left?.updatedAt || ""));
|
|
3527
|
+
const rightAt = Date.parse(String(right?.updatedAt || ""));
|
|
3528
|
+
if (Number.isFinite(leftAt) && Number.isFinite(rightAt)) return leftAt - rightAt;
|
|
3529
|
+
if (Number.isFinite(leftAt) !== Number.isFinite(rightAt)) return Number.isFinite(leftAt) ? 1 : -1;
|
|
3530
|
+
return String(left?.id || left?.tapdId || "").localeCompare(String(right?.id || right?.tapdId || ""));
|
|
3531
|
+
});
|
|
3532
|
+
for (const workflow of rows) {
|
|
3533
|
+
const workflowId = String(workflow?.id || workflow?.tapdId || "");
|
|
3534
|
+
const seen = new Set();
|
|
3535
|
+
for (const entry of Array.isArray(workflow?.timeline) ? workflow.timeline : []) {
|
|
3536
|
+
const key = String(entry?.key || [entry?.source, entry?.kind, entry?.id].filter(Boolean).join(":"));
|
|
3537
|
+
if (!key || seen.has(key)) continue;
|
|
3538
|
+
seen.add(key);
|
|
3539
|
+
assignedWorkflowIds.add(workflowId);
|
|
3540
|
+
const current = buckets.get(key) || {
|
|
3541
|
+
key,
|
|
3542
|
+
kind: String(entry.kind || ""),
|
|
3543
|
+
id: String(entry.id || ""),
|
|
3544
|
+
title: String(entry.title || entry.id || ""),
|
|
3545
|
+
date: String(entry.date || ""),
|
|
3546
|
+
source: String(entry.source || ""),
|
|
3547
|
+
dimensions: entry.dimensions && typeof entry.dimensions === "object" && !Array.isArray(entry.dimensions)
|
|
3548
|
+
? entry.dimensions
|
|
3549
|
+
: {},
|
|
3550
|
+
order: Number.isFinite(Number(entry.order)) ? Number(entry.order) : 0,
|
|
3551
|
+
workflowCount: 0,
|
|
3552
|
+
completedCount: 0,
|
|
3553
|
+
blockedCount: 0,
|
|
3554
|
+
workflowIds: [],
|
|
3555
|
+
};
|
|
3556
|
+
current.kind = String(entry.kind || current.kind);
|
|
3557
|
+
current.id = String(entry.id || current.id);
|
|
3558
|
+
current.title = String(entry.title || current.title);
|
|
3559
|
+
current.date = String(entry.date || current.date);
|
|
3560
|
+
current.source = String(entry.source || current.source);
|
|
3561
|
+
current.dimensions = entry.dimensions && typeof entry.dimensions === "object" && !Array.isArray(entry.dimensions)
|
|
3562
|
+
? entry.dimensions
|
|
3563
|
+
: current.dimensions;
|
|
3564
|
+
current.order = Number.isFinite(Number(entry.order)) ? Number(entry.order) : current.order;
|
|
3565
|
+
current.workflowCount += 1;
|
|
3566
|
+
if (workflow?.state === "completed") current.completedCount += 1;
|
|
3567
|
+
if (workflow?.state === "blocked") current.blockedCount += 1;
|
|
3568
|
+
current.workflowIds.push(workflowId);
|
|
3569
|
+
buckets.set(key, current);
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
const timeline = Array.from(buckets.values()).sort((left, right) => {
|
|
3573
|
+
const leftAt = Date.parse(String(left.date || ""));
|
|
3574
|
+
const rightAt = Date.parse(String(right.date || ""));
|
|
3575
|
+
const leftValid = Number.isFinite(leftAt);
|
|
3576
|
+
const rightValid = Number.isFinite(rightAt);
|
|
3577
|
+
if (leftValid && rightValid && leftAt !== rightAt) return leftAt - rightAt;
|
|
3578
|
+
if (leftValid !== rightValid) return leftValid ? -1 : 1;
|
|
3579
|
+
if (left.order !== right.order) return left.order - right.order;
|
|
3580
|
+
return left.title.localeCompare(right.title, undefined, { numeric: true, sensitivity: "base" });
|
|
3581
|
+
});
|
|
3582
|
+
return {
|
|
3583
|
+
timeline,
|
|
3584
|
+
unassignedCount: rows.filter((workflow) => !assignedWorkflowIds.has(String(workflow?.id || workflow?.tapdId || ""))).length,
|
|
3585
|
+
};
|
|
3586
|
+
}
|
|
3587
|
+
|
|
3503
3588
|
function workspaceConversationsPath(scopedRoot) {
|
|
3504
3589
|
return path.join(path.resolve(scopedRoot), ".workspace", "agentflow", "conversations.json");
|
|
3505
3590
|
}
|
|
@@ -11083,13 +11168,15 @@ function prdWorkflowMergeRuntimeEvents(scopedRoot, tapdId, snapshot) {
|
|
|
11083
11168
|
const overall = prdWorkflowOverallFromEvents(tapdId, snapshot, runtimeEvents);
|
|
11084
11169
|
const globalState = prdWorkflowGlobalStateFromEvents(tapdId, snapshot, runtimeEvents);
|
|
11085
11170
|
const artifacts = mergeWorkflowArtifacts(snapshot?.artifacts, runtimeEvents);
|
|
11171
|
+
const projections = materializeWorkflowProjections(snapshot, runtimeEvents);
|
|
11086
11172
|
return {
|
|
11087
11173
|
...snapshot,
|
|
11088
11174
|
workflow: globalState.workflow,
|
|
11089
11175
|
overall,
|
|
11090
11176
|
globalState,
|
|
11091
11177
|
artifacts,
|
|
11092
|
-
|
|
11178
|
+
projections,
|
|
11179
|
+
runtimeRevision: workflowRuntimeRevision(globalState, artifacts, runtimeEvents, projections),
|
|
11093
11180
|
runtimeEvents,
|
|
11094
11181
|
events,
|
|
11095
11182
|
sources: {
|
|
@@ -12515,7 +12602,7 @@ export function startUiServer({
|
|
|
12515
12602
|
? getTeamById(requestedTeamId)
|
|
12516
12603
|
: getTeamForUser(userCtx.userId);
|
|
12517
12604
|
if (!team || team.status !== "active") {
|
|
12518
|
-
json(res, 200, { ok: true, view: "team", team: null, workflows: [] });
|
|
12605
|
+
json(res, 200, { ok: true, view: "team", team: null, workflows: [], timeline: [], unassignedCount: 0 });
|
|
12519
12606
|
return;
|
|
12520
12607
|
}
|
|
12521
12608
|
records = listPrdWorkflowCollaborationsForTeam(team.id);
|
|
@@ -12529,9 +12616,17 @@ export function startUiServer({
|
|
|
12529
12616
|
const latestClient = prdWorkflowLatestClientSnapshot(stateRoot, stateRoot, tapdId);
|
|
12530
12617
|
const legacy = prdWorkflowReadCachedSnapshot(stateRoot, tapdId);
|
|
12531
12618
|
const snapshot = project?.snapshot || latestClient || legacy?.snapshot || {};
|
|
12532
|
-
|
|
12619
|
+
const materialized = prdWorkflowMergeRuntimeEvents(stateRoot, tapdId, snapshot);
|
|
12620
|
+
return prdWorkflowDashboardSummary(record, materialized, userCtx);
|
|
12621
|
+
});
|
|
12622
|
+
const dashboardTimeline = prdWorkflowDashboardTimeline(workflows);
|
|
12623
|
+
json(res, 200, {
|
|
12624
|
+
ok: true,
|
|
12625
|
+
view: view === "team" ? "team" : "personal",
|
|
12626
|
+
team: teamSummaryWithUsers(team),
|
|
12627
|
+
workflows,
|
|
12628
|
+
...dashboardTimeline,
|
|
12533
12629
|
});
|
|
12534
|
-
json(res, 200, { ok: true, view: view === "team" ? "team" : "personal", team: teamSummaryWithUsers(team), workflows });
|
|
12535
12630
|
} catch (error) {
|
|
12536
12631
|
json(res, 500, { error: (error && error.message) || String(error) });
|
|
12537
12632
|
}
|
|
@@ -13636,6 +13731,13 @@ export function startUiServer({
|
|
|
13636
13731
|
json(res, workflowScope.status || 400, { error: workflowScope.error });
|
|
13637
13732
|
return;
|
|
13638
13733
|
}
|
|
13734
|
+
if (!workflowScope.collaboration) {
|
|
13735
|
+
const ensured = ensurePrdWorkflowCollaboration({ tapdId, userId: userCtx.userId });
|
|
13736
|
+
if (ensured.error) {
|
|
13737
|
+
json(res, ensured.status || 400, { error: ensured.error });
|
|
13738
|
+
return;
|
|
13739
|
+
}
|
|
13740
|
+
}
|
|
13639
13741
|
const scopedRoot = workflowScope.stateRoot;
|
|
13640
13742
|
prdWorkflowMigrateLegacyState(workflowScope.executionRoot, scopedRoot, tapdId);
|
|
13641
13743
|
const currentSnapshot = prdWorkflowMaterializeSnapshot(
|
|
@@ -21,6 +21,10 @@ function cleanString(value, max = 4000) {
|
|
|
21
21
|
return String(value ?? "").trim().slice(0, max);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
function hasOwn(value, key) {
|
|
25
|
+
return Boolean(value && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, key));
|
|
26
|
+
}
|
|
27
|
+
|
|
24
28
|
function stableValue(value) {
|
|
25
29
|
if (Array.isArray(value)) return value.map((item) => stableValue(item));
|
|
26
30
|
if (value && typeof value === "object") {
|
|
@@ -105,6 +109,67 @@ function normalizeWorkflowArtifact(value, index = 0, defaultScope = "action") {
|
|
|
105
109
|
};
|
|
106
110
|
}
|
|
107
111
|
|
|
112
|
+
export function normalizeWorkflowTimelineProjection(value, index = 0) {
|
|
113
|
+
const raw = plainObject(value);
|
|
114
|
+
const kind = cleanString(raw.kind || raw.type, 80).toLowerCase();
|
|
115
|
+
const id = cleanString(raw.id || raw.key, 240);
|
|
116
|
+
if (!kind || !id) return null;
|
|
117
|
+
const source = cleanString(raw.source || raw.namespace, 120).toLowerCase();
|
|
118
|
+
const date = cleanString(raw.date || raw.targetDate || raw.target_date, 80);
|
|
119
|
+
const dimensions = mergeWorkflowGlobalState({}, plainObject(raw.dimensions || raw.facets));
|
|
120
|
+
const key = cleanString(raw.key || [source, kind, id].filter(Boolean).join(":"), 500);
|
|
121
|
+
return {
|
|
122
|
+
...mergeWorkflowGlobalState({}, raw),
|
|
123
|
+
key: key || `${kind}:${id}`,
|
|
124
|
+
kind,
|
|
125
|
+
id,
|
|
126
|
+
title: cleanString(raw.title || raw.label || id, 500) || id,
|
|
127
|
+
...(source ? { source } : {}),
|
|
128
|
+
...(date ? { date } : {}),
|
|
129
|
+
dimensions,
|
|
130
|
+
order: Number.isFinite(Number(raw.order)) ? Number(raw.order) : index,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function normalizeWorkflowProjectionState(value = {}) {
|
|
135
|
+
const raw = mergeWorkflowGlobalState({}, plainObject(value));
|
|
136
|
+
if (Array.isArray(value?.timeline)) {
|
|
137
|
+
raw.timeline = value.timeline
|
|
138
|
+
.map((item, index) => normalizeWorkflowTimelineProjection(item, index))
|
|
139
|
+
.filter(Boolean)
|
|
140
|
+
.slice(0, 100);
|
|
141
|
+
} else {
|
|
142
|
+
delete raw.timeline;
|
|
143
|
+
}
|
|
144
|
+
return raw;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function materializeWorkflowProjections(snapshot = {}, runtimeEvents = []) {
|
|
148
|
+
const base =
|
|
149
|
+
snapshot.projections ||
|
|
150
|
+
snapshot.workflowProjections ||
|
|
151
|
+
snapshot.workflow_projections ||
|
|
152
|
+
snapshot.raw?.projections ||
|
|
153
|
+
{};
|
|
154
|
+
let projections = normalizeWorkflowProjectionState(base);
|
|
155
|
+
const events = [...(Array.isArray(runtimeEvents) ? runtimeEvents : [])]
|
|
156
|
+
.sort((left, right) => eventTime(left) - eventTime(right));
|
|
157
|
+
for (const event of events) {
|
|
158
|
+
const next = event?.projections || event?.workflowProjections || event?.workflow_projections;
|
|
159
|
+
if (!next || typeof next !== "object" || Array.isArray(next) || !hasOwn(next, "timeline")) continue;
|
|
160
|
+
projections = {
|
|
161
|
+
...projections,
|
|
162
|
+
timeline: Array.isArray(next.timeline)
|
|
163
|
+
? next.timeline
|
|
164
|
+
.map((item, index) => normalizeWorkflowTimelineProjection(item, index))
|
|
165
|
+
.filter(Boolean)
|
|
166
|
+
.slice(0, 100)
|
|
167
|
+
: projections.timeline || [],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return projections;
|
|
171
|
+
}
|
|
172
|
+
|
|
108
173
|
export function mergeWorkflowGlobalState(base, patch) {
|
|
109
174
|
if (!patch || typeof patch !== "object" || Array.isArray(patch)) return plainObject(base);
|
|
110
175
|
const out = { ...plainObject(base) };
|
|
@@ -206,6 +271,22 @@ export function normalizeWorkflowReport(payload = {}) {
|
|
|
206
271
|
.filter((item) => item && typeof item === "object" && !Array.isArray(item))
|
|
207
272
|
.map((item, index) => normalizeWorkflowArtifact(item, index, action ? "action" : "global"));
|
|
208
273
|
|
|
274
|
+
const rawProjections = plainObject(payload.projections || payload.workflowProjections || payload.workflow_projections);
|
|
275
|
+
const hasProjections = Object.keys(rawProjections).length > 0 || hasOwn(payload, "projections");
|
|
276
|
+
if (hasProjections && !hasOwn(rawProjections, "timeline")) {
|
|
277
|
+
return { error: "projections requires timeline" };
|
|
278
|
+
}
|
|
279
|
+
if (hasProjections && !Array.isArray(rawProjections.timeline)) {
|
|
280
|
+
return { error: "projections.timeline must be an array" };
|
|
281
|
+
}
|
|
282
|
+
const invalidTimelineIndex = hasProjections
|
|
283
|
+
? rawProjections.timeline.findIndex((item, index) => !normalizeWorkflowTimelineProjection(item, index))
|
|
284
|
+
: -1;
|
|
285
|
+
if (invalidTimelineIndex >= 0) {
|
|
286
|
+
return { error: `projections.timeline[${invalidTimelineIndex}] requires kind and id` };
|
|
287
|
+
}
|
|
288
|
+
const projections = hasProjections ? normalizeWorkflowProjectionState(rawProjections) : null;
|
|
289
|
+
|
|
209
290
|
const rawGlobalState = plainObject(payload.globalState || payload.global_state);
|
|
210
291
|
const hasGlobalState = Object.keys(rawGlobalState).length > 0;
|
|
211
292
|
const globalStatePatch = plainObject(rawGlobalState.patch);
|
|
@@ -215,8 +296,8 @@ export function normalizeWorkflowReport(payload = {}) {
|
|
|
215
296
|
if (hasGlobalState && !Object.keys(globalStatePatch).length && !globalStateRemove.length) {
|
|
216
297
|
return { error: "globalState requires patch or remove" };
|
|
217
298
|
}
|
|
218
|
-
if (!action && !artifacts.length && !hasGlobalState) {
|
|
219
|
-
return { error: "Workflow report requires action, artifacts, or
|
|
299
|
+
if (!action && !artifacts.length && !hasGlobalState && !hasProjections) {
|
|
300
|
+
return { error: "Workflow report requires action, artifacts, globalState, or projections" };
|
|
220
301
|
}
|
|
221
302
|
|
|
222
303
|
const idempotencyKey = cleanString(
|
|
@@ -257,6 +338,7 @@ export function normalizeWorkflowReport(payload = {}) {
|
|
|
257
338
|
scope: "global",
|
|
258
339
|
}),
|
|
259
340
|
artifacts,
|
|
341
|
+
...(hasProjections ? { projections } : {}),
|
|
260
342
|
...(hasGlobalState ? {
|
|
261
343
|
globalStatePatch,
|
|
262
344
|
globalStateRemove,
|
|
@@ -268,6 +350,7 @@ export function normalizeWorkflowReport(payload = {}) {
|
|
|
268
350
|
workflow,
|
|
269
351
|
action,
|
|
270
352
|
artifacts,
|
|
353
|
+
projections,
|
|
271
354
|
globalState: hasGlobalState ? {
|
|
272
355
|
mode: "merge",
|
|
273
356
|
patch: globalStatePatch,
|
|
@@ -448,7 +531,7 @@ export function mergeWorkflowArtifactLists(left = [], right = [], defaultScope =
|
|
|
448
531
|
return out;
|
|
449
532
|
}
|
|
450
533
|
|
|
451
|
-
export function workflowRuntimeRevision(globalState = {}, artifacts = [], runtimeEvents = []) {
|
|
534
|
+
export function workflowRuntimeRevision(globalState = {}, artifacts = [], runtimeEvents = [], projections = {}) {
|
|
452
535
|
const events = (Array.isArray(runtimeEvents) ? runtimeEvents : []).map((event) => ({
|
|
453
536
|
id: event?.id || "",
|
|
454
537
|
action: event?.action || event?.actionId || "",
|
|
@@ -457,10 +540,11 @@ export function workflowRuntimeRevision(globalState = {}, artifacts = [], runtim
|
|
|
457
540
|
artifacts: event?.artifacts || [],
|
|
458
541
|
globalStatePatch: event?.globalStatePatch || {},
|
|
459
542
|
globalStateRemove: event?.globalStateRemove || [],
|
|
543
|
+
projections: event?.projections || {},
|
|
460
544
|
}));
|
|
461
545
|
const hash = crypto
|
|
462
546
|
.createHash("sha256")
|
|
463
|
-
.update(JSON.stringify(stableValue({ globalState, artifacts, events })))
|
|
547
|
+
.update(JSON.stringify(stableValue({ globalState, artifacts, projections, events })))
|
|
464
548
|
.digest("hex")
|
|
465
549
|
.slice(0, 24);
|
|
466
550
|
return `runtime:${hash}`;
|