@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.
@@ -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
- const contentEdge = incoming.find((edge) => String(edge?.targetHandle || "") === "input-1") || incoming[0];
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 = String(frontmatter || "").split(/\r?\n/)
7147
- .map((line) => {
7148
- const match = line.match(/^([^:]+):\s*(.*)$/);
7149
- if (!match) return `<tr><td colspan="2">${prdWorkflowReviewInlineMarkdown(line)}</td></tr>`;
7150
- return `<tr><th>${htmlEscapeAttribute(match[1].trim())}</th><td>${prdWorkflowReviewInlineMarkdown(match[2].trim())}</td></tr>`;
7151
- })
7152
- .join("");
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
- const artifactConflict = prevArtifact && nextArtifact && prevArtifact !== nextArtifact &&
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";