@fieldwangai/agentflow 0.1.125 → 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.
- package/bin/lib/prd-workflow-collaboration.mjs +8 -0
- package/bin/lib/ui-server.mjs +177 -15
- package/builtin/web-ui/dist/assets/{index-BofazScC.js → index-BLmRIy55.js} +79 -79
- package/builtin/web-ui/dist/assets/index-DQA8LAlU.css +1 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/builtin/web-ui/dist/assets/index-BKLuP3ZS.css +0 -1
|
@@ -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);
|
package/bin/lib/ui-server.mjs
CHANGED
|
@@ -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
|
}
|
|
@@ -8141,7 +8259,7 @@ function prdWorkflowReviewRenderFrontmatter(frontmatter) {
|
|
|
8141
8259
|
}
|
|
8142
8260
|
}
|
|
8143
8261
|
flush();
|
|
8144
|
-
return `<details class="frontmatter"
|
|
8262
|
+
return `<details class="frontmatter"><summary>文档元数据</summary><table><colgroup><col class="frontmatter-key-column"><col></colgroup>${rows}</table></details>`;
|
|
8145
8263
|
}
|
|
8146
8264
|
|
|
8147
8265
|
function prdWorkflowReviewRenderTable(lines) {
|
|
@@ -8614,7 +8732,7 @@ function prdWorkflowReviewRenderChangeIntent(change) {
|
|
|
8614
8732
|
function prdWorkflowReviewMarkdownLinesToHtml(lines) {
|
|
8615
8733
|
const html = [];
|
|
8616
8734
|
let paragraph = [];
|
|
8617
|
-
let list =
|
|
8735
|
+
let list = null;
|
|
8618
8736
|
let code = null;
|
|
8619
8737
|
const flushParagraph = () => {
|
|
8620
8738
|
if (!paragraph.length) return;
|
|
@@ -8622,9 +8740,11 @@ function prdWorkflowReviewMarkdownLinesToHtml(lines) {
|
|
|
8622
8740
|
paragraph = [];
|
|
8623
8741
|
};
|
|
8624
8742
|
const flushList = () => {
|
|
8625
|
-
if (!list
|
|
8626
|
-
|
|
8627
|
-
list =
|
|
8743
|
+
if (!list?.items?.length) return;
|
|
8744
|
+
const tag = list.ordered ? "ol" : "ul";
|
|
8745
|
+
const start = list.ordered && list.start !== 1 ? ` start="${list.start}"` : "";
|
|
8746
|
+
html.push(`<${tag}${start}>${list.items.map((item) => `<li>${item}</li>`).join("")}</${tag}>`);
|
|
8747
|
+
list = null;
|
|
8628
8748
|
};
|
|
8629
8749
|
const flushBlocks = () => {
|
|
8630
8750
|
flushParagraph();
|
|
@@ -8713,13 +8833,31 @@ function prdWorkflowReviewMarkdownLinesToHtml(lines) {
|
|
|
8713
8833
|
html.push(`<blockquote>${prdWorkflowReviewInlineMarkdown(quote[1])}</blockquote>`);
|
|
8714
8834
|
continue;
|
|
8715
8835
|
}
|
|
8716
|
-
const
|
|
8717
|
-
if (
|
|
8836
|
+
const listItem = line.match(/^(\s*)([-*]|\d+[.)])\s+(?:\[( |x|X)\]\s+)?(.+)$/);
|
|
8837
|
+
if (listItem) {
|
|
8718
8838
|
flushParagraph();
|
|
8719
|
-
const
|
|
8720
|
-
list.
|
|
8839
|
+
const ordered = /^\d/.test(listItem[2]);
|
|
8840
|
+
if (list && list.ordered !== ordered) flushList();
|
|
8841
|
+
if (!list) {
|
|
8842
|
+
list = {
|
|
8843
|
+
ordered,
|
|
8844
|
+
start: ordered ? Number.parseInt(listItem[2], 10) || 1 : 1,
|
|
8845
|
+
indent: listItem[1].length,
|
|
8846
|
+
items: [],
|
|
8847
|
+
};
|
|
8848
|
+
}
|
|
8849
|
+
const checked = listItem[3]
|
|
8850
|
+
? `<input type="checkbox" disabled${listItem[3].toLowerCase() === "x" ? " checked" : ""}> `
|
|
8851
|
+
: "";
|
|
8852
|
+
list.items.push(`${checked}${prdWorkflowReviewInlineMarkdown(listItem[4])}`);
|
|
8853
|
+
continue;
|
|
8854
|
+
}
|
|
8855
|
+
if (list?.items?.length && /^\s{2,}\S/.test(line)) {
|
|
8856
|
+
const lastIndex = list.items.length - 1;
|
|
8857
|
+
list.items[lastIndex] += ` ${prdWorkflowReviewInlineMarkdown(trimmed)}`;
|
|
8721
8858
|
continue;
|
|
8722
8859
|
}
|
|
8860
|
+
if (list) flushList();
|
|
8723
8861
|
paragraph.push(trimmed);
|
|
8724
8862
|
}
|
|
8725
8863
|
if (code) html.push(`<pre><code>${htmlEscapeAttribute(prdWorkflowReviewNormalizeText(code.lines.join("\n")))}</code></pre>`);
|
|
@@ -9015,18 +9153,20 @@ export function prdWorkflowReviewHtml(title, markdown, meta = {}) {
|
|
|
9015
9153
|
.raw:hover, .theme-toggle:hover { border-color: var(--interactive); color: var(--link); }
|
|
9016
9154
|
.theme-toggle { cursor: pointer; font-family: inherit; }
|
|
9017
9155
|
.lifecycle { margin-top: 10px; display: inline-flex; max-width: 100%; border: 1px solid var(--border); border-radius: 999px; background: var(--button); color: var(--muted); padding: 6px 10px; font-size: 12px; font-weight: 800; line-height: 1.35; overflow-wrap: anywhere; }
|
|
9018
|
-
article { min-width: 0; border:
|
|
9156
|
+
article { min-width: 0; border: 0; border-radius: 14px; background: var(--panel); box-shadow: 0 18px 50px var(--shadow); padding: clamp(20px, 4vw, 34px); }
|
|
9019
9157
|
article > *:first-child { margin-top: 0; }
|
|
9020
9158
|
article > *:last-child { margin-bottom: 0; }
|
|
9021
9159
|
h2, h3, h4, h5, h6 { margin: 1.7em 0 .65em; line-height: 1.25; letter-spacing: 0; color: var(--heading); overflow-wrap: anywhere; }
|
|
9022
9160
|
h2 { padding-bottom: .4rem; border-bottom: 1px solid var(--border-soft); font-size: 1.5rem; }
|
|
9023
9161
|
h3 { font-size: 1.2rem; }
|
|
9024
|
-
p, li, td, th, blockquote { font-size: 15px; line-height: 1.
|
|
9162
|
+
p, li, td, th, blockquote { font-size: 15px; line-height: 1.75; overflow-wrap: anywhere; word-break: break-word; }
|
|
9025
9163
|
p { margin: .75rem 0; color: var(--body); }
|
|
9026
|
-
ul { margin: .
|
|
9027
|
-
|
|
9164
|
+
ul, ol { margin: .75rem 0 1.1rem; padding-left: 1.55rem; }
|
|
9165
|
+
ol { padding-left: 1.8rem; }
|
|
9166
|
+
li { margin: .48rem 0; padding-left: .12rem; color: var(--body); }
|
|
9167
|
+
li::marker { color: var(--interactive); font-weight: 750; }
|
|
9028
9168
|
li input { margin-right: .38rem; transform: translateY(1px); }
|
|
9029
|
-
code { display: inline; max-width: 100%; border: 1px solid var(--border-soft); border-radius:
|
|
9169
|
+
code { display: inline; max-width: 100%; border: 1px solid var(--border-soft); border-radius: 4px; background: color-mix(in srgb, var(--interactive) 8%, transparent); color: var(--code-inline); padding: .06rem .24rem; font-family: "SFMono-Regular", Consolas, monospace; font-size: .9em; white-space: normal; overflow-wrap: anywhere; word-break: break-word; }
|
|
9030
9170
|
pre { max-width: 100%; overflow: auto; border: 1px solid var(--border); border-radius: 10px; background: var(--code-block); padding: 16px; line-height: 1.65; }
|
|
9031
9171
|
pre code { border: 0; background: transparent; color: var(--code-block-text); padding: 0; white-space: pre; overflow-wrap: normal; word-break: normal; }
|
|
9032
9172
|
.planned-code { max-width: 100%; margin: 1rem 0 1.2rem; overflow: hidden; border: 1px solid var(--planned-border); border-radius: 10px; background: var(--code-block); }
|
|
@@ -9108,7 +9248,8 @@ export function prdWorkflowReviewHtml(title, markdown, meta = {}) {
|
|
|
9108
9248
|
.frontmatter { margin: 0 0 1.35rem; border: 1px solid var(--border-soft); border-radius: 10px; background: var(--panel-strong); padding: .75rem .9rem; }
|
|
9109
9249
|
.frontmatter summary { cursor: pointer; color: var(--body); font-weight: 800; }
|
|
9110
9250
|
.frontmatter table { min-width: 0; margin-top: .7rem; }
|
|
9111
|
-
.frontmatter
|
|
9251
|
+
.frontmatter-key-column { width: clamp(10rem, 22%, 16rem); }
|
|
9252
|
+
.frontmatter th { background: var(--panel-soft); color: var(--body); }
|
|
9112
9253
|
.frontmatter-list { margin: 0; padding-left: 1.1rem; }
|
|
9113
9254
|
.action-index { position: sticky; top: 10px; z-index: 4; display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: 1rem 0 1.25rem; border: 1px solid var(--border); border-radius: 12px; background: var(--panel-strong); box-shadow: 0 8px 22px var(--shadow); padding: 10px 12px; }
|
|
9114
9255
|
.action-index__label { margin-right: 2px; color: var(--muted); font-size: 12px; font-weight: 800; }
|
|
@@ -12063,6 +12204,27 @@ export function startUiServer({
|
|
|
12063
12204
|
json(res, 200, { token: getSessionTokenFromRequest(req) || "" });
|
|
12064
12205
|
return;
|
|
12065
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
|
+
}
|
|
12066
12228
|
if (req.method === "GET" && url.pathname === "/api/prd-workflow/share") {
|
|
12067
12229
|
const tapdId = String(url.searchParams.get("tapdId") || "").trim();
|
|
12068
12230
|
const shareToken = String(url.searchParams.get("workflowShare") || "").trim();
|