@fieldwangai/agentflow 0.1.93 → 0.1.95

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.
@@ -2713,15 +2713,42 @@ function displayShareOutputUrl(shareId, baseUrl = "") {
2713
2713
  }
2714
2714
  }
2715
2715
 
2716
+ function normalizePublicBaseUrl(baseUrl = "") {
2717
+ const raw = String(baseUrl || "").trim();
2718
+ if (!raw) return "";
2719
+ try {
2720
+ const url = new URL(raw);
2721
+ if (url.hostname === "0.0.0.0" || url.hostname === "::" || url.hostname === "[::]") {
2722
+ url.hostname = "127.0.0.1";
2723
+ }
2724
+ return url.origin;
2725
+ } catch {
2726
+ return "";
2727
+ }
2728
+ }
2729
+
2716
2730
  function requestPublicBaseUrl(req) {
2717
2731
  const origin = String(req?.headers?.origin || "").trim();
2718
- if (/^https?:\/\//i.test(origin)) return origin;
2732
+ if (/^https?:\/\//i.test(origin)) return normalizePublicBaseUrl(origin);
2719
2733
  const forwardedHost = String(req?.headers?.["x-forwarded-host"] || "").split(",")[0].trim();
2720
2734
  const host = forwardedHost || String(req?.headers?.host || "").trim();
2721
2735
  if (!host) return "";
2722
2736
  const forwardedProto = String(req?.headers?.["x-forwarded-proto"] || "").split(",")[0].trim();
2723
2737
  const proto = /^https?$/i.test(forwardedProto) ? forwardedProto.toLowerCase() : "http";
2724
- return `${proto}://${host}`;
2738
+ return normalizePublicBaseUrl(`${proto}://${host}`);
2739
+ }
2740
+
2741
+ function configuredPublicBaseUrl(payload = null) {
2742
+ const envBase = normalizePublicBaseUrl(process.env.AGENTFLOW_PUBLIC_BASE_URL || process.env.AGENTFLOW_SHARE_BASE_URL || "");
2743
+ if (envBase) return envBase;
2744
+ const payloadBase = payload && typeof payload === "object" && !Array.isArray(payload)
2745
+ ? normalizePublicBaseUrl(payload.publicBaseUrl || payload.public_base_url || payload.reviewBaseUrl || payload.review_base_url || "")
2746
+ : "";
2747
+ return payloadBase;
2748
+ }
2749
+
2750
+ function serverPublicBaseUrl(req, host, port, payload = null) {
2751
+ return configuredPublicBaseUrl(payload) || requestPublicBaseUrl(req) || normalizePublicBaseUrl(`http://${host}:${port}`);
2725
2752
  }
2726
2753
 
2727
2754
  function normalizeRunEnvKey(key) {
@@ -7046,6 +7073,11 @@ function prdWorkflowEventsPath(scopedRoot, tapdId) {
7046
7073
  return path.join(rootDir, ".workspace", "prd-flow", "workflow-state", `${prdWorkflowSafeStateId(tapdId)}.events.json`);
7047
7074
  }
7048
7075
 
7076
+ function prdWorkflowAuditPath(scopedRoot, tapdId) {
7077
+ const rootDir = scopedRoot || process.cwd();
7078
+ return path.join(rootDir, ".workspace", "prd-flow", "workflow-state", `${prdWorkflowSafeStateId(tapdId)}.audit.jsonl`);
7079
+ }
7080
+
7049
7081
  function prdWorkflowReviewDir(scopedRoot, tapdId) {
7050
7082
  const rootDir = path.resolve(scopedRoot || process.cwd());
7051
7083
  return path.join(rootDir, ".workspace", "prd-flow", "reviews", prdWorkflowSafeStateId(tapdId));
@@ -7116,13 +7148,48 @@ function prdWorkflowReviewSplitFrontmatter(markdown) {
7116
7148
 
7117
7149
  function prdWorkflowReviewRenderFrontmatter(frontmatter) {
7118
7150
  if (!String(frontmatter || "").trim()) return "";
7119
- const rows = String(frontmatter || "").split(/\r?\n/)
7120
- .map((line) => {
7121
- const match = line.match(/^([^:]+):\s*(.*)$/);
7122
- if (!match) return `<tr><td colspan="2">${prdWorkflowReviewInlineMarkdown(line)}</td></tr>`;
7123
- return `<tr><th>${htmlEscapeAttribute(match[1].trim())}</th><td>${prdWorkflowReviewInlineMarkdown(match[2].trim())}</td></tr>`;
7124
- })
7125
- .join("");
7151
+ const rows = [];
7152
+ const lines = String(frontmatter || "").split(/\r?\n/);
7153
+ let current = null;
7154
+ const flush = () => {
7155
+ if (!current) return;
7156
+ let valueHtml = "";
7157
+ if (current.items.length) {
7158
+ valueHtml = `<ul class="frontmatter-list">${current.items.map((item) => `<li>${prdWorkflowReviewInlineMarkdown(item)}</li>`).join("")}</ul>`;
7159
+ } else {
7160
+ valueHtml = prdWorkflowReviewInlineMarkdown(current.value);
7161
+ }
7162
+ rows.push(`<tr><th>${htmlEscapeAttribute(current.key)}</th><td>${valueHtml}</td></tr>`);
7163
+ current = null;
7164
+ };
7165
+ for (const rawLine of lines) {
7166
+ const line = String(rawLine || "");
7167
+ const keyValue = line.match(/^([^:\s][^:]*):\s*(.*)$/);
7168
+ if (keyValue) {
7169
+ flush();
7170
+ const key = keyValue[1].trim();
7171
+ const value = keyValue[2].trim();
7172
+ const inlineList = value.match(/^\[(.*)\]$/);
7173
+ current = {
7174
+ key,
7175
+ value: inlineList ? "" : value,
7176
+ items: inlineList
7177
+ ? inlineList[1].split(",").map((item) => item.trim()).filter(Boolean)
7178
+ : [],
7179
+ };
7180
+ continue;
7181
+ }
7182
+ const listItem = line.match(/^\s*-\s+(.+)$/);
7183
+ if (listItem && current) {
7184
+ current.items.push(listItem[1].trim());
7185
+ continue;
7186
+ }
7187
+ if (line.trim()) {
7188
+ flush();
7189
+ rows.push(`<tr><td colspan="2">${prdWorkflowReviewInlineMarkdown(line.trim())}</td></tr>`);
7190
+ }
7191
+ }
7192
+ flush();
7126
7193
  return `<details class="frontmatter" open><summary>文档元数据</summary><table>${rows}</table></details>`;
7127
7194
  }
7128
7195
 
@@ -7233,6 +7300,13 @@ function prdWorkflowReviewHtml(title, markdown, meta = {}) {
7233
7300
  meta.issueKey ? `issue ${meta.issueKey}` : "",
7234
7301
  meta.createdAt || "",
7235
7302
  ].filter(Boolean).join(" · "));
7303
+ const durability = String(meta.durability || "").trim().toLowerCase();
7304
+ const lifecycle = [
7305
+ durability === "temporary" ? "Temporary review link" : durability === "durable" ? "Durable preview" : "",
7306
+ meta.expiresAt ? `Expires ${meta.expiresAt}` : "",
7307
+ meta.persistence ? `persistence ${meta.persistence}` : "",
7308
+ ].filter(Boolean).join(" · ");
7309
+ const escapedLifecycle = htmlEscapeAttribute(lifecycle);
7236
7310
  const renderedMarkdown = prdWorkflowReviewMarkdownToHtml(markdown || "");
7237
7311
  const rawHref = htmlEscapeAttribute(meta.rawHref || "?raw=1");
7238
7312
  return `<!doctype html>
@@ -7294,6 +7368,7 @@ function prdWorkflowReviewHtml(title, markdown, meta = {}) {
7294
7368
  .toolbar { flex: 0 0 auto; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; }
7295
7369
  .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; }
7296
7370
  .theme-toggle { cursor: pointer; font-family: inherit; }
7371
+ .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; }
7297
7372
  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); }
7298
7373
  article > *:first-child { margin-top: 0; }
7299
7374
  article > *:last-child { margin-bottom: 0; }
@@ -7319,6 +7394,7 @@ function prdWorkflowReviewHtml(title, markdown, meta = {}) {
7319
7394
  .frontmatter summary { cursor: pointer; color: var(--body); font-weight: 800; }
7320
7395
  .frontmatter table { min-width: 0; margin-top: .7rem; }
7321
7396
  .frontmatter th { width: min(34%, 12rem); background: var(--panel-soft); color: var(--body); }
7397
+ .frontmatter-list { margin: 0; padding-left: 1.1rem; }
7322
7398
  @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; } }
7323
7399
  </style>
7324
7400
  </head>
@@ -7328,6 +7404,7 @@ function prdWorkflowReviewHtml(title, markdown, meta = {}) {
7328
7404
  <div>
7329
7405
  <h1>${escapedTitle}</h1>
7330
7406
  ${escapedMeta ? `<p class="meta">${escapedMeta}</p>` : ""}
7407
+ ${escapedLifecycle ? `<p class="lifecycle">${escapedLifecycle}</p>` : ""}
7331
7408
  </div>
7332
7409
  <div class="toolbar">
7333
7410
  <button class="theme-toggle" type="button" data-theme-toggle>明亮模式</button>
@@ -7396,6 +7473,19 @@ function prdWorkflowCreateReview(scopedRoot, tapdId, payload = {}, urlBase = "")
7396
7473
  fs.writeFileSync(paths.markdownPath, content.trimEnd() + "\n", "utf-8");
7397
7474
  fs.writeFileSync(paths.metaPath, JSON.stringify(meta, null, 2) + "\n", "utf-8");
7398
7475
  prdWorkflowPruneReviews(scopedRoot, tapdId);
7476
+ prdWorkflowAppendAudit(scopedRoot, tapdId, {
7477
+ type: "review-created",
7478
+ reviewId: paths.id,
7479
+ title,
7480
+ stage: meta.stage,
7481
+ action: meta.action,
7482
+ issueKey: meta.issueKey,
7483
+ durability,
7484
+ persistence: "runtime",
7485
+ sourceKind: String(meta.source?.kind || ""),
7486
+ expiresAt,
7487
+ contentBytes: Buffer.byteLength(content, "utf-8"),
7488
+ });
7399
7489
  const url = `${String(urlBase || "").replace(/\/+$/, "")}/api/prd-workflow/review/${encodeURIComponent(prdWorkflowSafeStateId(tapdId))}/${encodeURIComponent(paths.id)}`;
7400
7490
  return { ...meta, url, markdownPath: paths.markdownPath };
7401
7491
  }
@@ -7445,6 +7535,19 @@ function prdWorkflowWriteJsonFile(filePath, data) {
7445
7535
  return data;
7446
7536
  }
7447
7537
 
7538
+ function prdWorkflowAppendAudit(scopedRoot, tapdId, event = {}) {
7539
+ try {
7540
+ const p = prdWorkflowAuditPath(scopedRoot, tapdId);
7541
+ fs.mkdirSync(path.dirname(p), { recursive: true });
7542
+ const entry = {
7543
+ at: new Date().toISOString(),
7544
+ tapdId: String(tapdId || ""),
7545
+ ...event,
7546
+ };
7547
+ fs.appendFileSync(p, JSON.stringify(entry) + "\n", "utf-8");
7548
+ } catch (_) {}
7549
+ }
7550
+
7448
7551
  function prdWorkflowReadProjectState(scopedRoot, tapdId) {
7449
7552
  return prdWorkflowReadJsonFile(prdWorkflowProjectPath(scopedRoot, tapdId), {
7450
7553
  version: 1,
@@ -7685,12 +7788,25 @@ function prdWorkflowMergedClientIssues(clientRows = []) {
7685
7788
  return out;
7686
7789
  }
7687
7790
 
7791
+ function prdWorkflowArrayCount(value) {
7792
+ return Array.isArray(value) ? value.length : 0;
7793
+ }
7794
+
7795
+ function prdWorkflowSnapshotActionCount(snapshot = {}) {
7796
+ return prdWorkflowArrayCount(snapshot?.actions) +
7797
+ prdWorkflowArrayCount(snapshot?.workflowActions) +
7798
+ prdWorkflowArrayCount(snapshot?.workflow_actions) +
7799
+ prdWorkflowArrayCount(snapshot?.timeline) +
7800
+ prdWorkflowArrayCount(snapshot?.history);
7801
+ }
7802
+
7688
7803
  function prdWorkflowMaterializeSnapshot(root, scopedRoot, tapdId, userCtx = {}, opts = {}) {
7689
7804
  const flowSource = String(opts.flowSource || "user").trim() || "user";
7690
7805
  const flowId = String(opts.flowId || "").trim();
7691
7806
  const project = prdWorkflowReadProjectStateWithFallback(root, scopedRoot, tapdId);
7692
7807
  const legacy = prdWorkflowReadCachedSnapshotWithFallback(root, scopedRoot, tapdId);
7693
7808
  const latestClient = prdWorkflowLatestClientSnapshot(root, scopedRoot, tapdId);
7809
+ const baseSource = project?.snapshot ? "project" : latestClient ? "client-observations" : legacy?.snapshot ? "legacy-cache" : "empty";
7694
7810
  const base = (
7695
7811
  project?.snapshot ||
7696
7812
  latestClient ||
@@ -7716,6 +7832,45 @@ function prdWorkflowMaterializeSnapshot(root, scopedRoot, tapdId, userCtx = {},
7716
7832
  }));
7717
7833
  const clientRows = prdWorkflowClientObservationRows(root, scopedRoot, tapdId);
7718
7834
  const clientIssues = prdWorkflowMergedClientIssues(clientRows);
7835
+ const runtimeState = prdWorkflowReadRuntimeEvents(scopedRoot, tapdId);
7836
+ const projectionAudit = [
7837
+ {
7838
+ step: "select-base",
7839
+ source: baseSource,
7840
+ reason: project?.snapshot
7841
+ ? "project materialized snapshot is available"
7842
+ : latestClient
7843
+ ? "no project snapshot; latest client current observation is used as display base"
7844
+ : legacy?.snapshot
7845
+ ? "no project/client snapshot; legacy projection cache is used"
7846
+ : "no stored workflow projection exists",
7847
+ projectSnapshot: Boolean(project?.snapshot),
7848
+ latestClientSnapshot: Boolean(latestClient),
7849
+ legacySnapshot: Boolean(legacy?.snapshot),
7850
+ clientObservationCount: clientRows.length,
7851
+ runtimeEventCount: runtimeState.events.length,
7852
+ baseActionCount: prdWorkflowSnapshotActionCount(base),
7853
+ latestClientRevision: String(latestClient?.revision || ""),
7854
+ projectRevision: String(project?.snapshot?.revision || ""),
7855
+ },
7856
+ {
7857
+ step: "merge-client-issues",
7858
+ source: "clients",
7859
+ applied: !project?.snapshot && clientIssues.length > 0,
7860
+ issueCount: clientIssues.length,
7861
+ reason: project?.snapshot
7862
+ ? "project snapshot owns issue projection"
7863
+ : clientIssues.length
7864
+ ? "merged issue views from client observations"
7865
+ : "no client issue projection available",
7866
+ },
7867
+ {
7868
+ step: "merge-runtime-events",
7869
+ source: "runtime-events",
7870
+ eventCount: runtimeState.events.length,
7871
+ reason: "runtime events are merged after base selection and must not replace durable facts",
7872
+ },
7873
+ ];
7719
7874
  const materialized = prdWorkflowMergeRuntimeEvents(scopedRoot, tapdId, {
7720
7875
  ...base,
7721
7876
  issues: project?.snapshot ? base.issues : clientIssues.length ? clientIssues : base.issues,
@@ -7731,6 +7886,32 @@ function prdWorkflowMaterializeSnapshot(root, scopedRoot, tapdId, userCtx = {},
7731
7886
  clientsUpdatedAt: prdWorkflowReadClientStateWithFallback(root, scopedRoot, tapdId).updatedAt || "",
7732
7887
  checkedAt: new Date().toISOString(),
7733
7888
  },
7889
+ projectionAudit,
7890
+ });
7891
+ materialized.projectionAudit = [
7892
+ ...projectionAudit,
7893
+ {
7894
+ step: "result",
7895
+ source: "materialized",
7896
+ phase: String(materialized.phase || ""),
7897
+ pointer: String(materialized.pointer || ""),
7898
+ actionCount: prdWorkflowSnapshotActionCount(materialized) + prdWorkflowArrayCount(materialized.runtimeEvents) + prdWorkflowArrayCount(materialized.runtime_events),
7899
+ revision: String(materialized.revision || ""),
7900
+ },
7901
+ ];
7902
+ prdWorkflowAppendAudit(scopedRoot, tapdId, {
7903
+ type: "projection-materialized",
7904
+ flowSource,
7905
+ flowId,
7906
+ baseSource,
7907
+ projectSnapshot: Boolean(project?.snapshot),
7908
+ latestClientSnapshot: Boolean(latestClient),
7909
+ legacySnapshot: Boolean(legacy?.snapshot),
7910
+ clientObservationCount: clientRows.length,
7911
+ runtimeEventCount: runtimeState.events.length,
7912
+ baseActionCount: prdWorkflowSnapshotActionCount(base),
7913
+ resultActionCount: prdWorkflowSnapshotActionCount(materialized) + prdWorkflowArrayCount(materialized.runtimeEvents) + prdWorkflowArrayCount(materialized.runtime_events),
7914
+ revision: String(materialized.revision || ""),
7734
7915
  });
7735
7916
  if (!project?.snapshot && latestClient) {
7736
7917
  materialized.optionalGaps = [
@@ -7992,13 +8173,15 @@ function prdWorkflowAppendRuntimeEvent(scopedRoot, tapdId, event = {}) {
7992
8173
  if (String(item?.idempotencyKey || "").trim() === entryIdem) return true;
7993
8174
  return Array.isArray(item?.idempotencyHistory) && item.idempotencyHistory.includes(entryIdem);
7994
8175
  });
8176
+ const updatedExisting = index >= 0;
8177
+ let artifactConflict = false;
7995
8178
  const events = [...current.events];
7996
8179
  if (index >= 0) {
7997
8180
  const prevArtifact = prdWorkflowRuntimeEventArtifactSignature(events[index]);
7998
8181
  const nextArtifact = prdWorkflowRuntimeEventArtifactSignature(entry);
7999
- const artifactConflict = prevArtifact && nextArtifact && prevArtifact !== nextArtifact &&
8182
+ artifactConflict = Boolean(prevArtifact && nextArtifact && prevArtifact !== nextArtifact &&
8000
8183
  prdWorkflowRuntimeEventShouldConflictOnArtifact(events[index]) &&
8001
- prdWorkflowRuntimeEventShouldConflictOnArtifact(entry);
8184
+ prdWorkflowRuntimeEventShouldConflictOnArtifact(entry));
8002
8185
  const idempotencyHistory = [
8003
8186
  ...(events[index].idempotencyKey ? [events[index].idempotencyKey] : []),
8004
8187
  ...(entry.idempotencyKey ? [entry.idempotencyKey] : []),
@@ -8033,6 +8216,26 @@ function prdWorkflowAppendRuntimeEvent(scopedRoot, tapdId, event = {}) {
8033
8216
  events.push(entry);
8034
8217
  }
8035
8218
  prdWorkflowWriteRuntimeEvents(scopedRoot, tapdId, events);
8219
+ prdWorkflowAppendAudit(scopedRoot, tapdId, {
8220
+ type: "runtime-event-stored",
8221
+ eventId: entry.id,
8222
+ eventType: entry.type,
8223
+ source: entry.source,
8224
+ scope: entry.scope || "",
8225
+ issueKey: entry.issueKey || entry.issue_key || entry.issue || "",
8226
+ platform: entry.platform || "",
8227
+ stage: entry.stage || entry.stageKey || entry.stage_key || "",
8228
+ action: entry.action || entry.actionId || entry.action_id || "",
8229
+ status: entry.status || "",
8230
+ truth: entry.truth || "",
8231
+ authority: entry.authority || "",
8232
+ persistence: entry.persistence || "",
8233
+ idempotencyKey: entry.idempotencyKey || "",
8234
+ updatedExisting,
8235
+ artifactConflict,
8236
+ eventCount: events.length,
8237
+ note: "runtime event stored as append-only workflow event; projection may merge it into the visible timeline",
8238
+ });
8036
8239
  return entry;
8037
8240
  } catch {
8038
8241
  return null;
@@ -9488,6 +9691,23 @@ export function startUiServer({
9488
9691
  };
9489
9692
  const storedObservationSnapshot = prdWorkflowStoredObservationSnapshot(normalizedSnapshot, reportSource);
9490
9693
  prdWorkflowWriteClientObservation(scopedRoot, tapdId, reportMeta, storedObservationSnapshot);
9694
+ prdWorkflowAppendAudit(scopedRoot, tapdId, {
9695
+ type: "client-observation-stored",
9696
+ flowSource,
9697
+ flowId,
9698
+ clientId: reportMeta.clientId,
9699
+ userId: reportMeta.userId,
9700
+ observedAt: reportMeta.observedAt,
9701
+ reportedAt: reportMeta.reportedAt,
9702
+ phase: String(storedObservationSnapshot?.phase || ""),
9703
+ pointer: String(storedObservationSnapshot?.pointer || ""),
9704
+ revision: String(storedObservationSnapshot?.revision || ""),
9705
+ actionCount: prdWorkflowSnapshotActionCount(storedObservationSnapshot),
9706
+ truth: "observation",
9707
+ authority: "client",
9708
+ persistence: "runtime",
9709
+ note: "ordinary current snapshot stored as client observation; it must not overwrite project state",
9710
+ });
9491
9711
 
9492
9712
  const projectFactSource = reportMeta.scope === "project"
9493
9713
  ? prdWorkflowProjectFactSource(payload, rawSnapshot)
@@ -9546,6 +9766,20 @@ export function startUiServer({
9546
9766
  observedAt: reportMeta.observedAt,
9547
9767
  },
9548
9768
  });
9769
+ prdWorkflowAppendAudit(scopedRoot, tapdId, {
9770
+ type: "project-fact-stored",
9771
+ flowSource,
9772
+ flowId,
9773
+ clientId: reportMeta.clientId,
9774
+ observedAt: reportMeta.observedAt,
9775
+ phase: String(projectFactSnapshot?.phase || ""),
9776
+ pointer: String(projectFactSnapshot?.pointer || ""),
9777
+ revision: String(projectFactSnapshot?.revision || ""),
9778
+ actionCount: prdWorkflowSnapshotActionCount(projectFactSnapshot),
9779
+ truth: projectFactSource.truth,
9780
+ authority: projectFactSource.authority,
9781
+ persistence: projectFactSource.persistence,
9782
+ });
9549
9783
  }
9550
9784
  const materialized = prdWorkflowMaterializeSnapshot(root, scopedRoot, tapdId, userCtx, { flowSource, flowId });
9551
9785
  const withDiagnostic = prdWorkflowWithAgentflowTokenDiagnostic(materialized, getSessionTokenFromRequest(req) || "");
@@ -9814,7 +10048,7 @@ export function startUiServer({
9814
10048
  json(res, 200, result);
9815
10049
  return;
9816
10050
  }
9817
- const runtimeEventUrl = `http://${host}:${uiPort}/api/prd-workflow/event`;
10051
+ const runtimeEventUrl = `${serverPublicBaseUrl(req, host, uiPort)}/api/prd-workflow/event`;
9818
10052
  const commandResult = await runPrdWorkflowCommand(root, scopedRoot, normalized.args, userCtx, {
9819
10053
  timeout: 300000,
9820
10054
  env: {
@@ -10105,7 +10339,7 @@ export function startUiServer({
10105
10339
  }
10106
10340
  scopedRoot = scoped.root;
10107
10341
  }
10108
- const review = prdWorkflowCreateReview(scopedRoot, tapdId, payload, `http://${host}:${uiPort}`);
10342
+ const review = prdWorkflowCreateReview(scopedRoot, tapdId, payload, serverPublicBaseUrl(req, host, uiPort, payload));
10109
10343
  const query = new URLSearchParams();
10110
10344
  if (flowId) query.set("flowId", flowId);
10111
10345
  if (flowSource) query.set("flowSource", flowSource);