@fieldwangai/agentflow 0.1.126 → 0.1.127

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.
@@ -105,6 +105,14 @@ export function getPrdWorkflowCollaborationForUser(tapdId, userId) {
105
105
  return records.find((record) => record.ownerId === actorId) || records[0] || null;
106
106
  }
107
107
 
108
+ export function listPrdWorkflowCollaborationsForUser(userId) {
109
+ const actorId = normalizeUserId(userId);
110
+ if (!actorId) return [];
111
+ return Object.values(readRegistry().workflows)
112
+ .filter((record) => prdWorkflowCollaborationAccess(record, actorId).allowed)
113
+ .sort((left, right) => String(right?.updatedAt || "").localeCompare(String(left?.updatedAt || "")));
114
+ }
115
+
108
116
  export function ensurePrdWorkflowCollaboration({ tapdId, userId }) {
109
117
  const ownerId = normalizeUserId(userId);
110
118
  const normalizedTapdId = normalizeTapdId(tapdId);
@@ -156,6 +156,7 @@ import {
156
156
  getPrdWorkflowCollaborationByShareToken,
157
157
  getPrdWorkflowCollaborationForUser,
158
158
  ensurePrdWorkflowShareLink,
159
+ listPrdWorkflowCollaborationsForUser,
159
160
  prdWorkflowCollaborationAccess,
160
161
  prdWorkflowCollaborationSummary,
161
162
  removePrdWorkflowCollaborationMember,
@@ -3349,6 +3350,123 @@ function prdWorkflowShareLinkSummary(record, shareToken, publicBaseUrl, userId =
3349
3350
  };
3350
3351
  }
3351
3352
 
3353
+ function prdWorkflowDashboardActions(snapshot = {}) {
3354
+ const rows = new Map();
3355
+ for (const field of ["actions", "workflowActions", "workflow_actions", "timeline", "history"]) {
3356
+ for (const item of Array.isArray(snapshot?.[field]) ? snapshot[field] : []) {
3357
+ if (!item || typeof item !== "object" || Array.isArray(item)) continue;
3358
+ const key = String(
3359
+ item.stageKey
3360
+ || item.stage_key
3361
+ || item.actionId
3362
+ || item.action_id
3363
+ || item.id
3364
+ || item.action
3365
+ || "",
3366
+ ).trim();
3367
+ if (!key) continue;
3368
+ rows.set(key, { ...(rows.get(key) || {}), ...item });
3369
+ }
3370
+ }
3371
+ return Array.from(rows.values());
3372
+ }
3373
+
3374
+ function prdWorkflowDashboardTimestamp(item = {}) {
3375
+ for (const value of [
3376
+ item.updatedAt,
3377
+ item.updated_at,
3378
+ item.observedAt,
3379
+ item.observed_at,
3380
+ item.completedAt,
3381
+ item.completed_at,
3382
+ item.stageEnteredAt,
3383
+ item.stage_entered_at,
3384
+ item.actionAt,
3385
+ item.action_at,
3386
+ item.startedAt,
3387
+ item.started_at,
3388
+ item.reportedAt,
3389
+ item.reported_at,
3390
+ item.createdAt,
3391
+ item.created_at,
3392
+ item.at,
3393
+ ]) {
3394
+ const timestamp = Date.parse(String(value || ""));
3395
+ if (Number.isFinite(timestamp)) return timestamp;
3396
+ }
3397
+ return 0;
3398
+ }
3399
+
3400
+ function prdWorkflowDashboardSummary(record, snapshot = {}, userCtx = {}) {
3401
+ const tapdId = String(record?.tapdId || snapshot?.tapdId || snapshot?.tapd_id || "").trim();
3402
+ const collaboration = prdWorkflowCollaborationSummaryWithUsers(record, userCtx?.userId) || {};
3403
+ const actions = prdWorkflowDashboardActions(snapshot);
3404
+ const doneStatuses = new Set(["done", "complete", "success", "completed", "passed", "observed"]);
3405
+ const completedActions = actions.filter((item) => (
3406
+ doneStatuses.has(String(item?.status || "").trim().toLowerCase())
3407
+ )).length;
3408
+ const latestAction = [...actions].sort((left, right) => (
3409
+ prdWorkflowDashboardTimestamp(right) - prdWorkflowDashboardTimestamp(left)
3410
+ ))[0] || null;
3411
+ const issues = Array.isArray(snapshot?.issues)
3412
+ ? snapshot.issues
3413
+ : Array.isArray(snapshot?.raw?.prd?.issues)
3414
+ ? snapshot.raw.prd.issues
3415
+ : [];
3416
+ const platforms = Array.from(new Set(issues
3417
+ .map((issue) => String(issue?.platform || "").trim().toLowerCase())
3418
+ .filter(Boolean)));
3419
+ const phase = String(snapshot?.phase || "").trim();
3420
+ const phaseKey = phase.toLowerCase();
3421
+ const state = /blocked|failed|error|conflict/.test(phaseKey)
3422
+ ? "blocked"
3423
+ : /done|completed|released|closed/.test(phaseKey) || (actions.length > 0 && completedActions === actions.length)
3424
+ ? "completed"
3425
+ : "active";
3426
+ const requirement = snapshot?.overall?.requirement && typeof snapshot.overall.requirement === "object"
3427
+ ? snapshot.overall.requirement
3428
+ : {};
3429
+ const title = String(
3430
+ requirement.title
3431
+ || requirement.name
3432
+ || snapshot?.prd?.title
3433
+ || snapshot?.raw?.prd?.title
3434
+ || snapshot?.title
3435
+ || "",
3436
+ ).trim();
3437
+ const updatedAtTimestamp = Math.max(
3438
+ prdWorkflowDashboardTimestamp(record),
3439
+ prdWorkflowDashboardTimestamp(snapshot),
3440
+ prdWorkflowDashboardTimestamp(latestAction || {}),
3441
+ );
3442
+ return {
3443
+ id: String(record?.id || ""),
3444
+ tapdId,
3445
+ title,
3446
+ phase,
3447
+ state,
3448
+ pointer: String(snapshot?.pointer || "").trim(),
3449
+ revision: String(snapshot?.revision || "").trim(),
3450
+ issueCount: issues.length,
3451
+ platforms,
3452
+ actionCount: actions.length,
3453
+ completedActionCount: completedActions,
3454
+ latestAction: latestAction
3455
+ ? {
3456
+ title: String(latestAction.title || latestAction.label || latestAction.action || latestAction.id || "").trim(),
3457
+ status: String(latestAction.status || "").trim(),
3458
+ at: prdWorkflowDashboardTimestamp(latestAction) ? new Date(prdWorkflowDashboardTimestamp(latestAction)).toISOString() : "",
3459
+ }
3460
+ : null,
3461
+ role: String(collaboration.role || ""),
3462
+ ownerId: String(collaboration.ownerId || ""),
3463
+ ownerUsername: String(collaboration.ownerUsername || collaboration.ownerId || ""),
3464
+ memberCount: Number(collaboration.memberCount || 0),
3465
+ shareActive: collaboration.shareActive === true,
3466
+ updatedAt: updatedAtTimestamp ? new Date(updatedAtTimestamp).toISOString() : String(record?.updatedAt || ""),
3467
+ };
3468
+ }
3469
+
3352
3470
  function workspaceConversationsPath(scopedRoot) {
3353
3471
  return path.join(path.resolve(scopedRoot), ".workspace", "agentflow", "conversations.json");
3354
3472
  }
@@ -12086,6 +12204,27 @@ export function startUiServer({
12086
12204
  json(res, 200, { token: getSessionTokenFromRequest(req) || "" });
12087
12205
  return;
12088
12206
  }
12207
+ if (req.method === "GET" && url.pathname === "/api/prd-workflows") {
12208
+ if (!authUser?.userId) {
12209
+ json(res, 401, { error: "Unauthorized" });
12210
+ return;
12211
+ }
12212
+ try {
12213
+ const workflows = listPrdWorkflowCollaborationsForUser(userCtx.userId).map((record) => {
12214
+ const stateRoot = path.resolve(getAgentflowUserDataRoot(record.ownerId));
12215
+ const tapdId = String(record.tapdId || "").trim();
12216
+ const project = prdWorkflowReadProjectState(stateRoot, tapdId);
12217
+ const latestClient = prdWorkflowLatestClientSnapshot(stateRoot, stateRoot, tapdId);
12218
+ const legacy = prdWorkflowReadCachedSnapshot(stateRoot, tapdId);
12219
+ const snapshot = project?.snapshot || latestClient || legacy?.snapshot || {};
12220
+ return prdWorkflowDashboardSummary(record, snapshot, userCtx);
12221
+ });
12222
+ json(res, 200, { ok: true, workflows });
12223
+ } catch (error) {
12224
+ json(res, 500, { error: (error && error.message) || String(error) });
12225
+ }
12226
+ return;
12227
+ }
12089
12228
  if (req.method === "GET" && url.pathname === "/api/prd-workflow/share") {
12090
12229
  const tapdId = String(url.searchParams.get("tapdId") || "").trim();
12091
12230
  const shareToken = String(url.searchParams.get("workflowShare") || "").trim();