@fieldwangai/agentflow 0.1.94 → 0.1.96
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 +236 -18
- package/builtin/web-ui/dist/assets/index-9buaezau.js +346 -0
- package/builtin/web-ui/dist/assets/index-DKaacU6h.css +1 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/builtin/web-ui/dist/assets/index-CYwUDlvT.js +0 -346
- package/builtin/web-ui/dist/assets/index-DV-QkHHi.css +0 -1
package/bin/lib/ui-server.mjs
CHANGED
|
@@ -4347,13 +4347,17 @@ function workspaceCachedOutputValueExists(value, scopedRoot = "") {
|
|
|
4347
4347
|
}
|
|
4348
4348
|
|
|
4349
4349
|
function workspaceUpstreamText(graph, nodeId, outputs, scopedRoot = "") {
|
|
4350
|
+
const contentEdge = workspaceContentInputEdge(graph, nodeId);
|
|
4351
|
+
if (!contentEdge) return "";
|
|
4352
|
+
return workspaceOutputSlotValueForEdge(graph, outputs, contentEdge, scopedRoot);
|
|
4353
|
+
}
|
|
4354
|
+
|
|
4355
|
+
function workspaceContentInputEdge(graph, nodeId) {
|
|
4350
4356
|
const edges = Array.isArray(graph?.edges) ? graph.edges : [];
|
|
4351
4357
|
const incoming = edges
|
|
4352
4358
|
.filter((edge) => String(edge?.target || "") === String(nodeId))
|
|
4353
4359
|
.filter((edge) => !isWorkspaceSemanticInputSlot(workspaceTargetSlotForEdge(graph, edge)));
|
|
4354
|
-
|
|
4355
|
-
if (!contentEdge) return "";
|
|
4356
|
-
return workspaceOutputSlotValueForEdge(graph, outputs, contentEdge, scopedRoot);
|
|
4360
|
+
return incoming.find((edge) => String(edge?.targetHandle || "") === "input-1") || incoming[0] || null;
|
|
4357
4361
|
}
|
|
4358
4362
|
|
|
4359
4363
|
function workspaceHandleIndex(handle, prefix) {
|
|
@@ -6089,6 +6093,11 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
6089
6093
|
}
|
|
6090
6094
|
|
|
6091
6095
|
if (workspaceDisplayKind(defId)) {
|
|
6096
|
+
if (!workspaceContentInputEdge(graph, nodeId)) {
|
|
6097
|
+
emit({ type: "status", nodeId, line: "Display unchanged: no content input edge" });
|
|
6098
|
+
emit({ type: "node-done", nodeId, definitionId: defId, unchanged: true });
|
|
6099
|
+
continue;
|
|
6100
|
+
}
|
|
6092
6101
|
const content = workspaceUpstreamText(graph, nodeId, outputs, scopedRoot);
|
|
6093
6102
|
graph.instances[nodeId] = workspaceWriteDisplayContent(instance, content);
|
|
6094
6103
|
const updatedDisplays = publishNodeOutput(nodeId, content);
|
|
@@ -7073,6 +7082,11 @@ function prdWorkflowEventsPath(scopedRoot, tapdId) {
|
|
|
7073
7082
|
return path.join(rootDir, ".workspace", "prd-flow", "workflow-state", `${prdWorkflowSafeStateId(tapdId)}.events.json`);
|
|
7074
7083
|
}
|
|
7075
7084
|
|
|
7085
|
+
function prdWorkflowAuditPath(scopedRoot, tapdId) {
|
|
7086
|
+
const rootDir = scopedRoot || process.cwd();
|
|
7087
|
+
return path.join(rootDir, ".workspace", "prd-flow", "workflow-state", `${prdWorkflowSafeStateId(tapdId)}.audit.jsonl`);
|
|
7088
|
+
}
|
|
7089
|
+
|
|
7076
7090
|
function prdWorkflowReviewDir(scopedRoot, tapdId) {
|
|
7077
7091
|
const rootDir = path.resolve(scopedRoot || process.cwd());
|
|
7078
7092
|
return path.join(rootDir, ".workspace", "prd-flow", "reviews", prdWorkflowSafeStateId(tapdId));
|
|
@@ -7143,13 +7157,48 @@ function prdWorkflowReviewSplitFrontmatter(markdown) {
|
|
|
7143
7157
|
|
|
7144
7158
|
function prdWorkflowReviewRenderFrontmatter(frontmatter) {
|
|
7145
7159
|
if (!String(frontmatter || "").trim()) return "";
|
|
7146
|
-
const rows =
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
.
|
|
7160
|
+
const rows = [];
|
|
7161
|
+
const lines = String(frontmatter || "").split(/\r?\n/);
|
|
7162
|
+
let current = null;
|
|
7163
|
+
const flush = () => {
|
|
7164
|
+
if (!current) return;
|
|
7165
|
+
let valueHtml = "";
|
|
7166
|
+
if (current.items.length) {
|
|
7167
|
+
valueHtml = `<ul class="frontmatter-list">${current.items.map((item) => `<li>${prdWorkflowReviewInlineMarkdown(item)}</li>`).join("")}</ul>`;
|
|
7168
|
+
} else {
|
|
7169
|
+
valueHtml = prdWorkflowReviewInlineMarkdown(current.value);
|
|
7170
|
+
}
|
|
7171
|
+
rows.push(`<tr><th>${htmlEscapeAttribute(current.key)}</th><td>${valueHtml}</td></tr>`);
|
|
7172
|
+
current = null;
|
|
7173
|
+
};
|
|
7174
|
+
for (const rawLine of lines) {
|
|
7175
|
+
const line = String(rawLine || "");
|
|
7176
|
+
const keyValue = line.match(/^([^:\s][^:]*):\s*(.*)$/);
|
|
7177
|
+
if (keyValue) {
|
|
7178
|
+
flush();
|
|
7179
|
+
const key = keyValue[1].trim();
|
|
7180
|
+
const value = keyValue[2].trim();
|
|
7181
|
+
const inlineList = value.match(/^\[(.*)\]$/);
|
|
7182
|
+
current = {
|
|
7183
|
+
key,
|
|
7184
|
+
value: inlineList ? "" : value,
|
|
7185
|
+
items: inlineList
|
|
7186
|
+
? inlineList[1].split(",").map((item) => item.trim()).filter(Boolean)
|
|
7187
|
+
: [],
|
|
7188
|
+
};
|
|
7189
|
+
continue;
|
|
7190
|
+
}
|
|
7191
|
+
const listItem = line.match(/^\s*-\s+(.+)$/);
|
|
7192
|
+
if (listItem && current) {
|
|
7193
|
+
current.items.push(listItem[1].trim());
|
|
7194
|
+
continue;
|
|
7195
|
+
}
|
|
7196
|
+
if (line.trim()) {
|
|
7197
|
+
flush();
|
|
7198
|
+
rows.push(`<tr><td colspan="2">${prdWorkflowReviewInlineMarkdown(line.trim())}</td></tr>`);
|
|
7199
|
+
}
|
|
7200
|
+
}
|
|
7201
|
+
flush();
|
|
7153
7202
|
return `<details class="frontmatter" open><summary>文档元数据</summary><table>${rows}</table></details>`;
|
|
7154
7203
|
}
|
|
7155
7204
|
|
|
@@ -7260,6 +7309,13 @@ function prdWorkflowReviewHtml(title, markdown, meta = {}) {
|
|
|
7260
7309
|
meta.issueKey ? `issue ${meta.issueKey}` : "",
|
|
7261
7310
|
meta.createdAt || "",
|
|
7262
7311
|
].filter(Boolean).join(" · "));
|
|
7312
|
+
const durability = String(meta.durability || "").trim().toLowerCase();
|
|
7313
|
+
const lifecycle = [
|
|
7314
|
+
durability === "temporary" ? "Temporary review link" : durability === "durable" ? "Durable preview" : "",
|
|
7315
|
+
meta.expiresAt ? `Expires ${meta.expiresAt}` : "",
|
|
7316
|
+
meta.persistence ? `persistence ${meta.persistence}` : "",
|
|
7317
|
+
].filter(Boolean).join(" · ");
|
|
7318
|
+
const escapedLifecycle = htmlEscapeAttribute(lifecycle);
|
|
7263
7319
|
const renderedMarkdown = prdWorkflowReviewMarkdownToHtml(markdown || "");
|
|
7264
7320
|
const rawHref = htmlEscapeAttribute(meta.rawHref || "?raw=1");
|
|
7265
7321
|
return `<!doctype html>
|
|
@@ -7321,6 +7377,7 @@ function prdWorkflowReviewHtml(title, markdown, meta = {}) {
|
|
|
7321
7377
|
.toolbar { flex: 0 0 auto; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; }
|
|
7322
7378
|
.raw, .theme-toggle { border: 1px solid rgba(124,58,237,.34); border-radius: 999px; color: var(--button-text); background: var(--button); padding: 9px 14px; text-decoration: none; font-size: 13px; font-weight: 800; line-height: 1.2; }
|
|
7323
7379
|
.theme-toggle { cursor: pointer; font-family: inherit; }
|
|
7380
|
+
.lifecycle { margin-top: 10px; display: inline-flex; max-width: 100%; border: 1px solid rgba(124,58,237,.30); border-radius: 999px; background: rgba(124,58,237,.12); color: var(--button-text); padding: 6px 10px; font-size: 12px; font-weight: 800; line-height: 1.35; overflow-wrap: anywhere; }
|
|
7324
7381
|
article { min-width: 0; border: 1px solid var(--border); border-radius: 14px; background: var(--panel); box-shadow: 0 28px 80px var(--shadow); padding: clamp(20px, 4vw, 34px); }
|
|
7325
7382
|
article > *:first-child { margin-top: 0; }
|
|
7326
7383
|
article > *:last-child { margin-bottom: 0; }
|
|
@@ -7346,6 +7403,7 @@ function prdWorkflowReviewHtml(title, markdown, meta = {}) {
|
|
|
7346
7403
|
.frontmatter summary { cursor: pointer; color: var(--body); font-weight: 800; }
|
|
7347
7404
|
.frontmatter table { min-width: 0; margin-top: .7rem; }
|
|
7348
7405
|
.frontmatter th { width: min(34%, 12rem); background: var(--panel-soft); color: var(--body); }
|
|
7406
|
+
.frontmatter-list { margin: 0; padding-left: 1.1rem; }
|
|
7349
7407
|
@media (max-width: 720px) { main { padding: 28px 14px 48px; } header { display: block; } .toolbar { justify-content: flex-start; margin-top: 14px; } article { padding: 18px; } th, td { padding: .58rem .65rem; } }
|
|
7350
7408
|
</style>
|
|
7351
7409
|
</head>
|
|
@@ -7355,6 +7413,7 @@ function prdWorkflowReviewHtml(title, markdown, meta = {}) {
|
|
|
7355
7413
|
<div>
|
|
7356
7414
|
<h1>${escapedTitle}</h1>
|
|
7357
7415
|
${escapedMeta ? `<p class="meta">${escapedMeta}</p>` : ""}
|
|
7416
|
+
${escapedLifecycle ? `<p class="lifecycle">${escapedLifecycle}</p>` : ""}
|
|
7358
7417
|
</div>
|
|
7359
7418
|
<div class="toolbar">
|
|
7360
7419
|
<button class="theme-toggle" type="button" data-theme-toggle>明亮模式</button>
|
|
@@ -7386,13 +7445,15 @@ function prdWorkflowReviewHtml(title, markdown, meta = {}) {
|
|
|
7386
7445
|
function prdWorkflowCreateReview(scopedRoot, tapdId, payload = {}, urlBase = "") {
|
|
7387
7446
|
const content = String(payload.markdown || payload.content || payload.rawOutput || "").slice(0, 500000);
|
|
7388
7447
|
if (!content.trim()) throw new Error("Missing review markdown");
|
|
7389
|
-
const requestedReviewId = String(payload.reviewId || payload.review_id || "").trim();
|
|
7390
|
-
const reviewId = requestedReviewId
|
|
7391
|
-
? prdWorkflowSafeStateId(requestedReviewId)
|
|
7392
|
-
: `review_${Date.now().toString(36)}_${crypto.randomBytes(4).toString("hex")}`;
|
|
7393
|
-
const paths = prdWorkflowReviewPaths(scopedRoot, tapdId, reviewId);
|
|
7394
7448
|
const title = String(payload.title || payload.label || "PRD Workflow Review").trim().slice(0, 160) || "PRD Workflow Review";
|
|
7395
7449
|
const durability = String(payload.durability || (payload.durable === true || payload.permanent === true ? "durable" : "temporary")).trim().toLowerCase() || "temporary";
|
|
7450
|
+
const requestedReviewId = String(payload.reviewId || payload.review_id || "").trim();
|
|
7451
|
+
const reviewId = durability === "temporary"
|
|
7452
|
+
? `r-${crypto.randomBytes(5).toString("hex")}`
|
|
7453
|
+
: requestedReviewId
|
|
7454
|
+
? prdWorkflowSafeStateId(requestedReviewId)
|
|
7455
|
+
: `review_${Date.now().toString(36)}_${crypto.randomBytes(4).toString("hex")}`;
|
|
7456
|
+
const paths = prdWorkflowReviewPaths(scopedRoot, tapdId, reviewId);
|
|
7396
7457
|
const ttlDaysRaw = Number(payload.ttlDays || payload.ttl_days || (durability === "temporary" ? 7 : 0));
|
|
7397
7458
|
const ttlDays = Number.isFinite(ttlDaysRaw) && ttlDaysRaw > 0 ? ttlDaysRaw : 0;
|
|
7398
7459
|
const createdAt = new Date();
|
|
@@ -7423,6 +7484,19 @@ function prdWorkflowCreateReview(scopedRoot, tapdId, payload = {}, urlBase = "")
|
|
|
7423
7484
|
fs.writeFileSync(paths.markdownPath, content.trimEnd() + "\n", "utf-8");
|
|
7424
7485
|
fs.writeFileSync(paths.metaPath, JSON.stringify(meta, null, 2) + "\n", "utf-8");
|
|
7425
7486
|
prdWorkflowPruneReviews(scopedRoot, tapdId);
|
|
7487
|
+
prdWorkflowAppendAudit(scopedRoot, tapdId, {
|
|
7488
|
+
type: "review-created",
|
|
7489
|
+
reviewId: paths.id,
|
|
7490
|
+
title,
|
|
7491
|
+
stage: meta.stage,
|
|
7492
|
+
action: meta.action,
|
|
7493
|
+
issueKey: meta.issueKey,
|
|
7494
|
+
durability,
|
|
7495
|
+
persistence: "runtime",
|
|
7496
|
+
sourceKind: String(meta.source?.kind || ""),
|
|
7497
|
+
expiresAt,
|
|
7498
|
+
contentBytes: Buffer.byteLength(content, "utf-8"),
|
|
7499
|
+
});
|
|
7426
7500
|
const url = `${String(urlBase || "").replace(/\/+$/, "")}/api/prd-workflow/review/${encodeURIComponent(prdWorkflowSafeStateId(tapdId))}/${encodeURIComponent(paths.id)}`;
|
|
7427
7501
|
return { ...meta, url, markdownPath: paths.markdownPath };
|
|
7428
7502
|
}
|
|
@@ -7472,6 +7546,19 @@ function prdWorkflowWriteJsonFile(filePath, data) {
|
|
|
7472
7546
|
return data;
|
|
7473
7547
|
}
|
|
7474
7548
|
|
|
7549
|
+
function prdWorkflowAppendAudit(scopedRoot, tapdId, event = {}) {
|
|
7550
|
+
try {
|
|
7551
|
+
const p = prdWorkflowAuditPath(scopedRoot, tapdId);
|
|
7552
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
7553
|
+
const entry = {
|
|
7554
|
+
at: new Date().toISOString(),
|
|
7555
|
+
tapdId: String(tapdId || ""),
|
|
7556
|
+
...event,
|
|
7557
|
+
};
|
|
7558
|
+
fs.appendFileSync(p, JSON.stringify(entry) + "\n", "utf-8");
|
|
7559
|
+
} catch (_) {}
|
|
7560
|
+
}
|
|
7561
|
+
|
|
7475
7562
|
function prdWorkflowReadProjectState(scopedRoot, tapdId) {
|
|
7476
7563
|
return prdWorkflowReadJsonFile(prdWorkflowProjectPath(scopedRoot, tapdId), {
|
|
7477
7564
|
version: 1,
|
|
@@ -7712,12 +7799,25 @@ function prdWorkflowMergedClientIssues(clientRows = []) {
|
|
|
7712
7799
|
return out;
|
|
7713
7800
|
}
|
|
7714
7801
|
|
|
7802
|
+
function prdWorkflowArrayCount(value) {
|
|
7803
|
+
return Array.isArray(value) ? value.length : 0;
|
|
7804
|
+
}
|
|
7805
|
+
|
|
7806
|
+
function prdWorkflowSnapshotActionCount(snapshot = {}) {
|
|
7807
|
+
return prdWorkflowArrayCount(snapshot?.actions) +
|
|
7808
|
+
prdWorkflowArrayCount(snapshot?.workflowActions) +
|
|
7809
|
+
prdWorkflowArrayCount(snapshot?.workflow_actions) +
|
|
7810
|
+
prdWorkflowArrayCount(snapshot?.timeline) +
|
|
7811
|
+
prdWorkflowArrayCount(snapshot?.history);
|
|
7812
|
+
}
|
|
7813
|
+
|
|
7715
7814
|
function prdWorkflowMaterializeSnapshot(root, scopedRoot, tapdId, userCtx = {}, opts = {}) {
|
|
7716
7815
|
const flowSource = String(opts.flowSource || "user").trim() || "user";
|
|
7717
7816
|
const flowId = String(opts.flowId || "").trim();
|
|
7718
7817
|
const project = prdWorkflowReadProjectStateWithFallback(root, scopedRoot, tapdId);
|
|
7719
7818
|
const legacy = prdWorkflowReadCachedSnapshotWithFallback(root, scopedRoot, tapdId);
|
|
7720
7819
|
const latestClient = prdWorkflowLatestClientSnapshot(root, scopedRoot, tapdId);
|
|
7820
|
+
const baseSource = project?.snapshot ? "project" : latestClient ? "client-observations" : legacy?.snapshot ? "legacy-cache" : "empty";
|
|
7721
7821
|
const base = (
|
|
7722
7822
|
project?.snapshot ||
|
|
7723
7823
|
latestClient ||
|
|
@@ -7743,6 +7843,45 @@ function prdWorkflowMaterializeSnapshot(root, scopedRoot, tapdId, userCtx = {},
|
|
|
7743
7843
|
}));
|
|
7744
7844
|
const clientRows = prdWorkflowClientObservationRows(root, scopedRoot, tapdId);
|
|
7745
7845
|
const clientIssues = prdWorkflowMergedClientIssues(clientRows);
|
|
7846
|
+
const runtimeState = prdWorkflowReadRuntimeEvents(scopedRoot, tapdId);
|
|
7847
|
+
const projectionAudit = [
|
|
7848
|
+
{
|
|
7849
|
+
step: "select-base",
|
|
7850
|
+
source: baseSource,
|
|
7851
|
+
reason: project?.snapshot
|
|
7852
|
+
? "project materialized snapshot is available"
|
|
7853
|
+
: latestClient
|
|
7854
|
+
? "no project snapshot; latest client current observation is used as display base"
|
|
7855
|
+
: legacy?.snapshot
|
|
7856
|
+
? "no project/client snapshot; legacy projection cache is used"
|
|
7857
|
+
: "no stored workflow projection exists",
|
|
7858
|
+
projectSnapshot: Boolean(project?.snapshot),
|
|
7859
|
+
latestClientSnapshot: Boolean(latestClient),
|
|
7860
|
+
legacySnapshot: Boolean(legacy?.snapshot),
|
|
7861
|
+
clientObservationCount: clientRows.length,
|
|
7862
|
+
runtimeEventCount: runtimeState.events.length,
|
|
7863
|
+
baseActionCount: prdWorkflowSnapshotActionCount(base),
|
|
7864
|
+
latestClientRevision: String(latestClient?.revision || ""),
|
|
7865
|
+
projectRevision: String(project?.snapshot?.revision || ""),
|
|
7866
|
+
},
|
|
7867
|
+
{
|
|
7868
|
+
step: "merge-client-issues",
|
|
7869
|
+
source: "clients",
|
|
7870
|
+
applied: !project?.snapshot && clientIssues.length > 0,
|
|
7871
|
+
issueCount: clientIssues.length,
|
|
7872
|
+
reason: project?.snapshot
|
|
7873
|
+
? "project snapshot owns issue projection"
|
|
7874
|
+
: clientIssues.length
|
|
7875
|
+
? "merged issue views from client observations"
|
|
7876
|
+
: "no client issue projection available",
|
|
7877
|
+
},
|
|
7878
|
+
{
|
|
7879
|
+
step: "merge-runtime-events",
|
|
7880
|
+
source: "runtime-events",
|
|
7881
|
+
eventCount: runtimeState.events.length,
|
|
7882
|
+
reason: "runtime events are merged after base selection and must not replace durable facts",
|
|
7883
|
+
},
|
|
7884
|
+
];
|
|
7746
7885
|
const materialized = prdWorkflowMergeRuntimeEvents(scopedRoot, tapdId, {
|
|
7747
7886
|
...base,
|
|
7748
7887
|
issues: project?.snapshot ? base.issues : clientIssues.length ? clientIssues : base.issues,
|
|
@@ -7758,6 +7897,32 @@ function prdWorkflowMaterializeSnapshot(root, scopedRoot, tapdId, userCtx = {},
|
|
|
7758
7897
|
clientsUpdatedAt: prdWorkflowReadClientStateWithFallback(root, scopedRoot, tapdId).updatedAt || "",
|
|
7759
7898
|
checkedAt: new Date().toISOString(),
|
|
7760
7899
|
},
|
|
7900
|
+
projectionAudit,
|
|
7901
|
+
});
|
|
7902
|
+
materialized.projectionAudit = [
|
|
7903
|
+
...projectionAudit,
|
|
7904
|
+
{
|
|
7905
|
+
step: "result",
|
|
7906
|
+
source: "materialized",
|
|
7907
|
+
phase: String(materialized.phase || ""),
|
|
7908
|
+
pointer: String(materialized.pointer || ""),
|
|
7909
|
+
actionCount: prdWorkflowSnapshotActionCount(materialized) + prdWorkflowArrayCount(materialized.runtimeEvents) + prdWorkflowArrayCount(materialized.runtime_events),
|
|
7910
|
+
revision: String(materialized.revision || ""),
|
|
7911
|
+
},
|
|
7912
|
+
];
|
|
7913
|
+
prdWorkflowAppendAudit(scopedRoot, tapdId, {
|
|
7914
|
+
type: "projection-materialized",
|
|
7915
|
+
flowSource,
|
|
7916
|
+
flowId,
|
|
7917
|
+
baseSource,
|
|
7918
|
+
projectSnapshot: Boolean(project?.snapshot),
|
|
7919
|
+
latestClientSnapshot: Boolean(latestClient),
|
|
7920
|
+
legacySnapshot: Boolean(legacy?.snapshot),
|
|
7921
|
+
clientObservationCount: clientRows.length,
|
|
7922
|
+
runtimeEventCount: runtimeState.events.length,
|
|
7923
|
+
baseActionCount: prdWorkflowSnapshotActionCount(base),
|
|
7924
|
+
resultActionCount: prdWorkflowSnapshotActionCount(materialized) + prdWorkflowArrayCount(materialized.runtimeEvents) + prdWorkflowArrayCount(materialized.runtime_events),
|
|
7925
|
+
revision: String(materialized.revision || ""),
|
|
7761
7926
|
});
|
|
7762
7927
|
if (!project?.snapshot && latestClient) {
|
|
7763
7928
|
materialized.optionalGaps = [
|
|
@@ -8019,13 +8184,15 @@ function prdWorkflowAppendRuntimeEvent(scopedRoot, tapdId, event = {}) {
|
|
|
8019
8184
|
if (String(item?.idempotencyKey || "").trim() === entryIdem) return true;
|
|
8020
8185
|
return Array.isArray(item?.idempotencyHistory) && item.idempotencyHistory.includes(entryIdem);
|
|
8021
8186
|
});
|
|
8187
|
+
const updatedExisting = index >= 0;
|
|
8188
|
+
let artifactConflict = false;
|
|
8022
8189
|
const events = [...current.events];
|
|
8023
8190
|
if (index >= 0) {
|
|
8024
8191
|
const prevArtifact = prdWorkflowRuntimeEventArtifactSignature(events[index]);
|
|
8025
8192
|
const nextArtifact = prdWorkflowRuntimeEventArtifactSignature(entry);
|
|
8026
|
-
|
|
8193
|
+
artifactConflict = Boolean(prevArtifact && nextArtifact && prevArtifact !== nextArtifact &&
|
|
8027
8194
|
prdWorkflowRuntimeEventShouldConflictOnArtifact(events[index]) &&
|
|
8028
|
-
prdWorkflowRuntimeEventShouldConflictOnArtifact(entry);
|
|
8195
|
+
prdWorkflowRuntimeEventShouldConflictOnArtifact(entry));
|
|
8029
8196
|
const idempotencyHistory = [
|
|
8030
8197
|
...(events[index].idempotencyKey ? [events[index].idempotencyKey] : []),
|
|
8031
8198
|
...(entry.idempotencyKey ? [entry.idempotencyKey] : []),
|
|
@@ -8060,6 +8227,26 @@ function prdWorkflowAppendRuntimeEvent(scopedRoot, tapdId, event = {}) {
|
|
|
8060
8227
|
events.push(entry);
|
|
8061
8228
|
}
|
|
8062
8229
|
prdWorkflowWriteRuntimeEvents(scopedRoot, tapdId, events);
|
|
8230
|
+
prdWorkflowAppendAudit(scopedRoot, tapdId, {
|
|
8231
|
+
type: "runtime-event-stored",
|
|
8232
|
+
eventId: entry.id,
|
|
8233
|
+
eventType: entry.type,
|
|
8234
|
+
source: entry.source,
|
|
8235
|
+
scope: entry.scope || "",
|
|
8236
|
+
issueKey: entry.issueKey || entry.issue_key || entry.issue || "",
|
|
8237
|
+
platform: entry.platform || "",
|
|
8238
|
+
stage: entry.stage || entry.stageKey || entry.stage_key || "",
|
|
8239
|
+
action: entry.action || entry.actionId || entry.action_id || "",
|
|
8240
|
+
status: entry.status || "",
|
|
8241
|
+
truth: entry.truth || "",
|
|
8242
|
+
authority: entry.authority || "",
|
|
8243
|
+
persistence: entry.persistence || "",
|
|
8244
|
+
idempotencyKey: entry.idempotencyKey || "",
|
|
8245
|
+
updatedExisting,
|
|
8246
|
+
artifactConflict,
|
|
8247
|
+
eventCount: events.length,
|
|
8248
|
+
note: "runtime event stored as append-only workflow event; projection may merge it into the visible timeline",
|
|
8249
|
+
});
|
|
8063
8250
|
return entry;
|
|
8064
8251
|
} catch {
|
|
8065
8252
|
return null;
|
|
@@ -9515,6 +9702,23 @@ export function startUiServer({
|
|
|
9515
9702
|
};
|
|
9516
9703
|
const storedObservationSnapshot = prdWorkflowStoredObservationSnapshot(normalizedSnapshot, reportSource);
|
|
9517
9704
|
prdWorkflowWriteClientObservation(scopedRoot, tapdId, reportMeta, storedObservationSnapshot);
|
|
9705
|
+
prdWorkflowAppendAudit(scopedRoot, tapdId, {
|
|
9706
|
+
type: "client-observation-stored",
|
|
9707
|
+
flowSource,
|
|
9708
|
+
flowId,
|
|
9709
|
+
clientId: reportMeta.clientId,
|
|
9710
|
+
userId: reportMeta.userId,
|
|
9711
|
+
observedAt: reportMeta.observedAt,
|
|
9712
|
+
reportedAt: reportMeta.reportedAt,
|
|
9713
|
+
phase: String(storedObservationSnapshot?.phase || ""),
|
|
9714
|
+
pointer: String(storedObservationSnapshot?.pointer || ""),
|
|
9715
|
+
revision: String(storedObservationSnapshot?.revision || ""),
|
|
9716
|
+
actionCount: prdWorkflowSnapshotActionCount(storedObservationSnapshot),
|
|
9717
|
+
truth: "observation",
|
|
9718
|
+
authority: "client",
|
|
9719
|
+
persistence: "runtime",
|
|
9720
|
+
note: "ordinary current snapshot stored as client observation; it must not overwrite project state",
|
|
9721
|
+
});
|
|
9518
9722
|
|
|
9519
9723
|
const projectFactSource = reportMeta.scope === "project"
|
|
9520
9724
|
? prdWorkflowProjectFactSource(payload, rawSnapshot)
|
|
@@ -9573,6 +9777,20 @@ export function startUiServer({
|
|
|
9573
9777
|
observedAt: reportMeta.observedAt,
|
|
9574
9778
|
},
|
|
9575
9779
|
});
|
|
9780
|
+
prdWorkflowAppendAudit(scopedRoot, tapdId, {
|
|
9781
|
+
type: "project-fact-stored",
|
|
9782
|
+
flowSource,
|
|
9783
|
+
flowId,
|
|
9784
|
+
clientId: reportMeta.clientId,
|
|
9785
|
+
observedAt: reportMeta.observedAt,
|
|
9786
|
+
phase: String(projectFactSnapshot?.phase || ""),
|
|
9787
|
+
pointer: String(projectFactSnapshot?.pointer || ""),
|
|
9788
|
+
revision: String(projectFactSnapshot?.revision || ""),
|
|
9789
|
+
actionCount: prdWorkflowSnapshotActionCount(projectFactSnapshot),
|
|
9790
|
+
truth: projectFactSource.truth,
|
|
9791
|
+
authority: projectFactSource.authority,
|
|
9792
|
+
persistence: projectFactSource.persistence,
|
|
9793
|
+
});
|
|
9576
9794
|
}
|
|
9577
9795
|
const materialized = prdWorkflowMaterializeSnapshot(root, scopedRoot, tapdId, userCtx, { flowSource, flowId });
|
|
9578
9796
|
const withDiagnostic = prdWorkflowWithAgentflowTokenDiagnostic(materialized, getSessionTokenFromRequest(req) || "");
|
|
@@ -10135,7 +10353,7 @@ export function startUiServer({
|
|
|
10135
10353
|
const review = prdWorkflowCreateReview(scopedRoot, tapdId, payload, serverPublicBaseUrl(req, host, uiPort, payload));
|
|
10136
10354
|
const query = new URLSearchParams();
|
|
10137
10355
|
if (flowId) query.set("flowId", flowId);
|
|
10138
|
-
if (flowSource) query.set("flowSource", flowSource);
|
|
10356
|
+
if (flowId && flowSource && flowSource !== "user") query.set("flowSource", flowSource);
|
|
10139
10357
|
if (archived) query.set("archived", "1");
|
|
10140
10358
|
const reviewUrl = query.toString() ? `${review.url}?${query.toString()}` : review.url;
|
|
10141
10359
|
const durability = review.durability || "temporary";
|