@fieldwangai/agentflow 0.1.115 → 0.1.117

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.
@@ -3133,6 +3133,48 @@ function hydrateWorkspaceGraphForRuntime(workspaceRoot, scoped = {}, graph = {},
3133
3133
  return hydrateWorkspaceSlotMetaFromDefinitions(workspaceRoot, scoped, withMarketplaceRuntime, userCtx);
3134
3134
  }
3135
3135
 
3136
+ function adminWorkspaceOwnerSummary(ownerId = "") {
3137
+ const id = String(ownerId || "").trim();
3138
+ if (!id) return null;
3139
+ const users = readAuthUsers();
3140
+ const knownUserIds = new Set([
3141
+ ...Object.keys(users || {}),
3142
+ ...listAgentflowUserIds(),
3143
+ ].map((value) => String(value || "").trim()).filter(Boolean));
3144
+ if (!knownUserIds.has(id)) return null;
3145
+ return {
3146
+ userId: id,
3147
+ username: String(users?.[id]?.username || id),
3148
+ };
3149
+ }
3150
+
3151
+ function adminWorkspaceRequestedUserContext(userCtx = {}) {
3152
+ const ownerId = String(userCtx.adminOwnerId || "").trim();
3153
+ if (!ownerId) return { userCtx };
3154
+ if (userCtx.isAdmin !== true) {
3155
+ return { error: "Admin permission required", status: 403 };
3156
+ }
3157
+ const owner = adminWorkspaceOwnerSummary(ownerId);
3158
+ if (!owner) return { error: "Workspace owner not found", status: 404 };
3159
+ return {
3160
+ owner,
3161
+ userCtx: {
3162
+ ...userCtx,
3163
+ userId: owner.userId,
3164
+ adminOwnerId: "",
3165
+ },
3166
+ };
3167
+ }
3168
+
3169
+ function workspaceScopedUserContext(scoped = {}, userCtx = {}) {
3170
+ if (!scoped.adminReadonly || !scoped.ownerUserId) return userCtx;
3171
+ return {
3172
+ ...userCtx,
3173
+ userId: scoped.ownerUserId,
3174
+ adminOwnerId: "",
3175
+ };
3176
+ }
3177
+
3136
3178
  function resolveWorkspaceScopeRoot(workspaceRoot, params = {}, opts = {}) {
3137
3179
  const flowId = params.flowId != null ? String(params.flowId).trim() : "";
3138
3180
  if (!flowId) return { root: path.resolve(workspaceRoot), flowId: "", flowSource: "", archived: false };
@@ -3143,6 +3185,46 @@ function resolveWorkspaceScopeRoot(workspaceRoot, params = {}, opts = {}) {
3143
3185
  if (!isValidFlowSourceRead(flowSource)) {
3144
3186
  return { root: "", error: "Invalid flowSource" };
3145
3187
  }
3188
+ const adminOwnerId = String(params.adminOwnerId || opts.adminOwnerId || "").trim();
3189
+ if (adminOwnerId) {
3190
+ if (opts.isAdmin !== true) {
3191
+ return { root: "", error: "Admin permission required", status: 403 };
3192
+ }
3193
+ if (flowSource !== "user") {
3194
+ return { root: "", error: "Admin read-only review only supports user projects", status: 400 };
3195
+ }
3196
+ const owner = adminWorkspaceOwnerSummary(adminOwnerId);
3197
+ if (!owner) {
3198
+ return { root: "", error: "Workspace owner not found", status: 404 };
3199
+ }
3200
+ const targetFlow = listFlowsJson(workspaceRoot, { userId: owner.userId })
3201
+ .find((flow) => (
3202
+ flow.id === flowId
3203
+ && (flow.source || "user") === "user"
3204
+ && Boolean(flow.archived) === archived
3205
+ ));
3206
+ if (!targetFlow?.path) {
3207
+ return { root: "", error: "Pipeline workspace not found", status: 404 };
3208
+ }
3209
+ return {
3210
+ root: path.resolve(targetFlow.path),
3211
+ flowId,
3212
+ flowSource: "user",
3213
+ requestedFlowSource: flowSource,
3214
+ workspaceId: "",
3215
+ archived,
3216
+ collaboration: null,
3217
+ collaborationAccess: {
3218
+ allowed: true,
3219
+ writable: false,
3220
+ runnable: false,
3221
+ role: "admin-viewer",
3222
+ },
3223
+ adminReadonly: true,
3224
+ ownerUserId: owner.userId,
3225
+ ownerUsername: owner.username,
3226
+ };
3227
+ }
3146
3228
  const workspaceId = String(params.workspaceId || "").trim();
3147
3229
  let collaboration = getWorkspaceCollaborationForProject({
3148
3230
  workspaceId,
@@ -7472,6 +7554,17 @@ function resolvePrdWorkflowScope(workspaceRoot, params = {}, userCtx = {}, capab
7472
7554
  const flowId = String(params.flowId || "").trim();
7473
7555
  const flowSource = String(params.flowSource || "user").trim() || "user";
7474
7556
  const archived = params.archived === true || params.archived === "1" || params.flowArchived === true;
7557
+ const adminOwnerId = String(params.adminOwnerId || userCtx.adminOwnerId || "").trim();
7558
+ if (adminOwnerId && userCtx.isAdmin !== true) {
7559
+ return { error: "Admin permission required", status: 403 };
7560
+ }
7561
+ const adminOwner = adminOwnerId ? adminWorkspaceOwnerSummary(adminOwnerId) : null;
7562
+ if (adminOwnerId && !adminOwner) {
7563
+ return { error: "Workspace owner not found", status: 404 };
7564
+ }
7565
+ if (adminOwner && capability !== "read") {
7566
+ return { error: "Admin Workspace review is read-only", status: 403 };
7567
+ }
7475
7568
  const shareToken = String(params.workflowShare || params.workflow_share || "").trim();
7476
7569
  const linkCollaboration = shareToken ? getPrdWorkflowCollaborationByShareToken(shareToken) : null;
7477
7570
  if (shareToken && (!linkCollaboration || linkCollaboration.tapdId !== tapdId)) {
@@ -7480,8 +7573,10 @@ function resolvePrdWorkflowScope(workspaceRoot, params = {}, userCtx = {}, capab
7480
7573
  const memberCollaboration = tapdId
7481
7574
  ? getPrdWorkflowCollaborationForUser(tapdId, userCtx?.userId)
7482
7575
  : null;
7483
- const collaboration = linkCollaboration || memberCollaboration;
7484
- const access = linkCollaboration
7576
+ const collaboration = adminOwner ? null : (linkCollaboration || memberCollaboration);
7577
+ const access = adminOwner
7578
+ ? { allowed: true, writable: false, role: "admin-viewer", via: "admin-review" }
7579
+ : linkCollaboration
7485
7580
  ? { allowed: true, writable: false, role: "viewer", via: "share-link" }
7486
7581
  : prdWorkflowCollaborationAccess(collaboration, userCtx?.userId);
7487
7582
  if (collaboration && !access.allowed) {
@@ -7490,7 +7585,7 @@ function resolvePrdWorkflowScope(workspaceRoot, params = {}, userCtx = {}, capab
7490
7585
  if (capability === "write" && (linkCollaboration || (collaboration && !access.writable))) {
7491
7586
  return { error: "PRD Workflow collaboration edit permission denied", status: 403 };
7492
7587
  }
7493
- const ownerId = String(collaboration?.ownerId || userCtx?.userId || "").trim();
7588
+ const ownerId = String(adminOwner?.userId || collaboration?.ownerId || userCtx?.userId || "").trim();
7494
7589
  const stateRoot = path.resolve(getAgentflowUserDataRoot(ownerId));
7495
7590
  let executionRoot = path.resolve(workspaceRoot);
7496
7591
  if (flowId) {
@@ -7498,6 +7593,7 @@ function resolvePrdWorkflowScope(workspaceRoot, params = {}, userCtx = {}, capab
7498
7593
  flowId,
7499
7594
  flowSource,
7500
7595
  workspaceId: params.workspaceId || "",
7596
+ adminOwnerId,
7501
7597
  archived,
7502
7598
  }, userCtx);
7503
7599
  if (projectScope.error) {
@@ -7516,6 +7612,7 @@ function resolvePrdWorkflowScope(workspaceRoot, params = {}, userCtx = {}, capab
7516
7612
  collaborationAccess: access,
7517
7613
  shareToken,
7518
7614
  sharedByLink: Boolean(linkCollaboration),
7615
+ adminReadonly: Boolean(adminOwner),
7519
7616
  flowId,
7520
7617
  flowSource,
7521
7618
  archived,
@@ -7526,7 +7623,8 @@ function prdWorkflowKey(userCtx = {}, flowSource = "user", flowId = "", tapdId =
7526
7623
  const id = String(tapdId || "").trim();
7527
7624
  const collaboration = getPrdWorkflowCollaborationByShareToken(shareToken)
7528
7625
  || getPrdWorkflowCollaborationForUser(id, userCtx?.userId);
7529
- const actorScope = `user:${String(collaboration?.ownerId || userCtx?.userId || "")}`;
7626
+ const adminOwnerId = userCtx?.isAdmin === true ? String(userCtx?.adminOwnerId || "").trim() : "";
7627
+ const actorScope = `user:${String(collaboration?.ownerId || adminOwnerId || userCtx?.userId || "")}`;
7530
7628
  return [actorScope, id].join("\t");
7531
7629
  }
7532
7630
 
@@ -7678,6 +7776,32 @@ function prdWorkflowReviewIdFromRequest(tapdId, payload = {}, durability = "temp
7678
7776
  return prdWorkflowSafeStateId(["review", tapdId, stageHead, digest].filter(Boolean).join("-")).slice(0, 64);
7679
7777
  }
7680
7778
 
7779
+ function prdWorkflowReviewArtifactKey(tapdId, payload = {}, durability = "temporary") {
7780
+ const explicit = String(payload.artifactKey || payload.artifact_key || "").trim();
7781
+ if (explicit) return explicit.slice(0, 500);
7782
+ const issueKey = prdWorkflowSafeStateId(
7783
+ payload.issueKey || payload.issue_key || payload.issue || "global",
7784
+ ).toLowerCase();
7785
+ const platform = prdWorkflowSafeStateId(payload.platform || "all").toLowerCase();
7786
+ const stage = prdWorkflowSafeStateId(
7787
+ payload.stage
7788
+ || payload.stageKey
7789
+ || payload.stage_key
7790
+ || payload.action
7791
+ || payload.actionId
7792
+ || payload.action_id
7793
+ || "review",
7794
+ ).toLowerCase();
7795
+ return [
7796
+ "prd-review",
7797
+ prdWorkflowSafeStateId(tapdId).toLowerCase(),
7798
+ issueKey,
7799
+ platform,
7800
+ stage,
7801
+ String(durability || "temporary").trim().toLowerCase() || "temporary",
7802
+ ].join(":").slice(0, 500);
7803
+ }
7804
+
7681
7805
  function prdWorkflowStatePath(scopedRoot, tapdId) {
7682
7806
  const rootDir = scopedRoot || process.cwd();
7683
7807
  return path.join(rootDir, ".workspace", "prd-flow", "workflow-state", `${prdWorkflowSafeStateId(tapdId)}.json`);
@@ -9131,18 +9255,27 @@ function prdWorkflowNormalizeRuntimeEvent(tapdId, event = {}) {
9131
9255
 
9132
9256
  function prdWorkflowMergeRuntimeEventArrays(left, right) {
9133
9257
  const out = [];
9134
- const seen = new Set();
9258
+ const seen = new Map();
9135
9259
  for (const value of [...(Array.isArray(left) ? left : []), ...(Array.isArray(right) ? right : [])]) {
9136
9260
  if (value == null) continue;
9137
- let key = "";
9261
+ const explicitKey = value && typeof value === "object" && !Array.isArray(value)
9262
+ ? String(value.key || value.artifactKey || value.artifact_key || "").trim()
9263
+ : "";
9264
+ let key = explicitKey ? `key:${explicitKey}` : "";
9138
9265
  try {
9139
- key = typeof value === "string" ? value : JSON.stringify(value);
9266
+ if (!key) key = typeof value === "string" ? value : JSON.stringify(value);
9140
9267
  } catch {
9141
9268
  key = String(value);
9142
9269
  }
9143
- if (seen.has(key)) continue;
9144
- seen.add(key);
9145
- out.push(value);
9270
+ const index = seen.get(key);
9271
+ if (index == null) {
9272
+ seen.set(key, out.length);
9273
+ out.push(value);
9274
+ continue;
9275
+ }
9276
+ if (explicitKey) {
9277
+ out[index] = value;
9278
+ }
9146
9279
  }
9147
9280
  return out;
9148
9281
  }
@@ -10958,7 +11091,11 @@ export function startUiServer({
10958
11091
  }
10959
11092
 
10960
11093
  const authUser = getAuthUserFromRequest(req);
10961
- const userCtx = authUser ? { userId: authUser.userId, isAdmin: Boolean(authUser.isAdmin) } : {};
11094
+ const userCtx = authUser ? {
11095
+ userId: authUser.userId,
11096
+ isAdmin: Boolean(authUser.isAdmin),
11097
+ adminOwnerId: String(url.searchParams.get("adminOwnerId") || "").trim(),
11098
+ } : {};
10962
11099
  if (req.method === "GET" && url.pathname === "/api/auth/session-token") {
10963
11100
  if (!authUser?.userId) {
10964
11101
  json(res, 401, { error: "Unauthorized" });
@@ -12195,10 +12332,15 @@ export function startUiServer({
12195
12332
  const shortUrl = shortLink?.shortUrl || "";
12196
12333
  const displayUrl = shortUrl || reviewUrl;
12197
12334
  const durability = review.durability || "temporary";
12335
+ const artifactKey = prdWorkflowReviewArtifactKey(tapdId, payload, durability);
12198
12336
  const reviewSource = review.source && typeof review.source === "object" && !Array.isArray(review.source)
12199
12337
  ? review.source
12200
12338
  : { kind: durability === "durable" ? "ai-doc" : "local-draft", durability };
12339
+ const idempotencyKey = String(
12340
+ payload.idempotencyKey || payload.idempotency_key || "",
12341
+ ).trim();
12201
12342
  const artifact = {
12343
+ key: artifactKey,
12202
12344
  label: payload.artifactLabel || "Markdown Review",
12203
12345
  kind: durability === "temporary" ? "temporary-review" : "review",
12204
12346
  persistence: "runtime",
@@ -12222,12 +12364,15 @@ export function startUiServer({
12222
12364
  detail: "已生成临时 Markdown review 链接",
12223
12365
  status: "current",
12224
12366
  issueKey: payload.issueKey || payload.issue_key || "",
12367
+ idempotencyKey,
12225
12368
  durability,
12226
12369
  sourceArtifact: reviewSource,
12227
12370
  expiresAt: review.expiresAt || "",
12228
12371
  artifacts: [artifact],
12229
12372
  links: [{
12373
+ key: artifactKey,
12230
12374
  label: "Markdown Review",
12375
+ kind: artifact.kind,
12231
12376
  url: displayUrl,
12232
12377
  canonicalUrl: reviewUrl,
12233
12378
  shortUrl,
@@ -12647,6 +12792,36 @@ export function startUiServer({
12647
12792
  return;
12648
12793
  }
12649
12794
 
12795
+ if (req.method === "GET" && url.pathname === "/api/admin/user-workspaces") {
12796
+ if (!authUser?.isAdmin) {
12797
+ json(res, 403, { error: "Admin permission required" });
12798
+ return;
12799
+ }
12800
+ const owner = adminWorkspaceOwnerSummary(url.searchParams.get("userId") || "");
12801
+ if (!owner) {
12802
+ json(res, 404, { error: "Workspace owner not found" });
12803
+ return;
12804
+ }
12805
+ try {
12806
+ const workspaces = listFlowsJson(root, { userId: owner.userId })
12807
+ .filter((flow) => (flow.source || "user") === "user")
12808
+ .map((flow) => ({
12809
+ id: String(flow.id || ""),
12810
+ source: "user",
12811
+ archived: flow.archived === true,
12812
+ description: String(flow.description || ""),
12813
+ ownerUserId: owner.userId,
12814
+ ownerUsername: owner.username,
12815
+ adminReadonly: true,
12816
+ }))
12817
+ .sort((a, b) => Number(a.archived) - Number(b.archived) || a.id.localeCompare(b.id));
12818
+ json(res, 200, { owner, workspaces });
12819
+ } catch (e) {
12820
+ json(res, 500, { error: (e && e.message) || String(e) });
12821
+ }
12822
+ return;
12823
+ }
12824
+
12650
12825
  if (req.method === "GET" && url.pathname === "/api/admin/run-detail") {
12651
12826
  if (!authUser?.isAdmin) {
12652
12827
  json(res, 403, { error: "Admin permission required" });
@@ -13022,12 +13197,17 @@ export function startUiServer({
13022
13197
  flowId,
13023
13198
  flowSource,
13024
13199
  workspaceId: payload.workspaceId || "",
13200
+ adminOwnerId: payload.adminOwnerId || "",
13025
13201
  archived,
13026
13202
  }, userCtx);
13027
13203
  if (scoped.error) {
13028
13204
  json(res, scoped.status || 400, { error: scoped.error });
13029
13205
  return;
13030
13206
  }
13207
+ if (scoped.adminReadonly) {
13208
+ json(res, 403, { error: "Admin Workspace review is read-only" });
13209
+ return;
13210
+ }
13031
13211
  const ensured = ensureWorkspaceCollaboration({
13032
13212
  flowId,
13033
13213
  flowSource,
@@ -13139,7 +13319,12 @@ export function startUiServer({
13139
13319
  json(res, scoped.status || 400, { error: scoped.error });
13140
13320
  return;
13141
13321
  }
13142
- const key = workspaceCollaborationEventKey(userCtx, scoped.flowSource, scoped.flowId, scoped.archived);
13322
+ const key = workspaceCollaborationEventKey(
13323
+ workspaceScopedUserContext(scoped, userCtx),
13324
+ scoped.flowSource,
13325
+ scoped.flowId,
13326
+ scoped.archived,
13327
+ );
13143
13328
  let subscribers = workspaceCollaborationSubscribers.get(key);
13144
13329
  if (!subscribers) {
13145
13330
  subscribers = new Set();
@@ -13256,7 +13441,8 @@ export function startUiServer({
13256
13441
  return;
13257
13442
  }
13258
13443
  const { path: graphPath, graph } = readWorkspaceGraph(scoped.root);
13259
- const hydratedGraph = hydrateWorkspaceGraphForRuntime(root, scoped, graph, userCtx);
13444
+ const scopedUserCtx = workspaceScopedUserContext(scoped, userCtx);
13445
+ const hydratedGraph = hydrateWorkspaceGraphForRuntime(root, scoped, graph, scopedUserCtx);
13260
13446
  const collaborationAccess = scoped.collaborationAccess || workspaceCollaborationAccess(null, userCtx.userId);
13261
13447
  json(res, 200, {
13262
13448
  ok: true,
@@ -13270,9 +13456,15 @@ export function startUiServer({
13270
13456
  flowSource: scoped.flowSource,
13271
13457
  archived: scoped.archived,
13272
13458
  writable: !(scoped.archived || isReadonlyBuiltinFlowSource(scoped.flowSource))
13459
+ && scoped.adminReadonly !== true
13273
13460
  && collaborationAccess.writable !== false,
13274
13461
  collaboration: workspaceCollaborationSummaryWithUsers(scoped.collaboration, userCtx.userId),
13275
- workspaceSchedules: listWorkspaceScheduleStatusesForFlow(userCtx, scoped.flowSource || "user", scoped.flowId || ""),
13462
+ adminReview: scoped.adminReadonly ? {
13463
+ readonly: true,
13464
+ ownerUserId: scoped.ownerUserId,
13465
+ ownerUsername: scoped.ownerUsername,
13466
+ } : null,
13467
+ workspaceSchedules: listWorkspaceScheduleStatusesForFlow(scopedUserCtx, scoped.flowSource || "user", scoped.flowId || ""),
13276
13468
  });
13277
13469
  } catch (e) {
13278
13470
  json(res, 500, { error: (e && e.message) || String(e) });
@@ -13293,12 +13485,17 @@ export function startUiServer({
13293
13485
  flowId: payload.flowId || "",
13294
13486
  flowSource: payload.flowSource || "user",
13295
13487
  workspaceId: payload.workspaceId || "",
13488
+ adminOwnerId: payload.adminOwnerId || "",
13296
13489
  archived: payload.archived === true || payload.flowArchived === true,
13297
13490
  }, userCtx);
13298
13491
  if (scoped.error) {
13299
13492
  json(res, 400, { error: scoped.error });
13300
13493
  return;
13301
13494
  }
13495
+ if (scoped.adminReadonly) {
13496
+ json(res, 403, { error: "Admin Workspace review is read-only" });
13497
+ return;
13498
+ }
13302
13499
  const { graph } = readWorkspaceGraph(scoped.root);
13303
13500
  const nodeIds = normalizeDisplayShareNodeIds(payload.nodeIds, graph);
13304
13501
  if (nodeIds.length === 0) {
@@ -13338,6 +13535,7 @@ export function startUiServer({
13338
13535
  flowId: payload.flowId || "",
13339
13536
  flowSource: payload.flowSource || "user",
13340
13537
  workspaceId: payload.workspaceId || "",
13538
+ adminOwnerId: payload.adminOwnerId || "",
13341
13539
  archived: payload.archived === true || payload.flowArchived === true,
13342
13540
  }, userCtx);
13343
13541
  if (scoped.error) {
@@ -13451,8 +13649,21 @@ export function startUiServer({
13451
13649
  json(res, 400, { error: "Missing flowId" });
13452
13650
  return;
13453
13651
  }
13652
+ const scoped = resolveWorkspaceScopeRoot(root, {
13653
+ flowId,
13654
+ flowSource,
13655
+ archived: url.searchParams.get("archived") === "1",
13656
+ }, userCtx);
13657
+ if (scoped.error) {
13658
+ json(res, scoped.status || 400, { error: scoped.error });
13659
+ return;
13660
+ }
13454
13661
  json(res, 200, {
13455
- schedules: listWorkspaceScheduleStatusesForFlow(userCtx, flowSource, flowId),
13662
+ schedules: listWorkspaceScheduleStatusesForFlow(
13663
+ workspaceScopedUserContext(scoped, userCtx),
13664
+ flowSource,
13665
+ flowId,
13666
+ ),
13456
13667
  });
13457
13668
  } catch (e) {
13458
13669
  json(res, 500, { error: (e && e.message) || String(e) });
@@ -13473,12 +13684,17 @@ export function startUiServer({
13473
13684
  flowId: payload.flowId || "",
13474
13685
  flowSource: payload.flowSource || "user",
13475
13686
  workspaceId: payload.workspaceId || "",
13687
+ adminOwnerId: payload.adminOwnerId || "",
13476
13688
  archived: payload.archived === true || payload.flowArchived === true,
13477
13689
  }, userCtx);
13478
13690
  if (scoped.error) {
13479
13691
  json(res, 400, { error: scoped.error });
13480
13692
  return;
13481
13693
  }
13694
+ if (scoped.collaborationAccess?.runnable === false) {
13695
+ json(res, 403, { error: "Workspace run permission denied" });
13696
+ return;
13697
+ }
13482
13698
  const flowId = String(payload.flowId || "").trim();
13483
13699
  if (!flowId) {
13484
13700
  json(res, 400, { error: "Missing flowId" });
@@ -13521,6 +13737,7 @@ export function startUiServer({
13521
13737
  flowId: payload.flowId || "",
13522
13738
  flowSource: payload.flowSource || "user",
13523
13739
  workspaceId: payload.workspaceId || "",
13740
+ adminOwnerId: payload.adminOwnerId || "",
13524
13741
  archived: payload.archived === true || payload.flowArchived === true,
13525
13742
  }, userCtx);
13526
13743
  if (scoped.error) {
@@ -13585,6 +13802,7 @@ export function startUiServer({
13585
13802
  flowId: payload.flowId || "",
13586
13803
  flowSource: payload.flowSource || "user",
13587
13804
  workspaceId: payload.workspaceId || "",
13805
+ adminOwnerId: payload.adminOwnerId || "",
13588
13806
  archived: payload.archived === true || payload.flowArchived === true,
13589
13807
  }, userCtx);
13590
13808
  if (scoped.error) {
@@ -13868,9 +14086,10 @@ export function startUiServer({
13868
14086
  json(res, scoped.status || 400, { error: scoped.error });
13869
14087
  return;
13870
14088
  }
14089
+ const scopedUserCtx = workspaceScopedUserContext(scoped, userCtx);
13871
14090
  json(res, 200, {
13872
14091
  runs: listWorkspaceRunLogs({
13873
- userId: flowSource === "workspace" ? "" : userCtx.userId || "",
14092
+ userId: flowSource === "workspace" ? "" : scopedUserCtx.userId || "",
13874
14093
  flowId,
13875
14094
  flowSource,
13876
14095
  scheduleNodeId,
@@ -13902,8 +14121,9 @@ export function startUiServer({
13902
14121
  json(res, scoped.status || 400, { error: scoped.error });
13903
14122
  return;
13904
14123
  }
14124
+ const scopedUserCtx = workspaceScopedUserContext(scoped, userCtx);
13905
14125
  const run = listWorkspaceRunLogs({
13906
- userId: flowSource === "workspace" ? "" : userCtx.userId || "",
14126
+ userId: flowSource === "workspace" ? "" : scopedUserCtx.userId || "",
13907
14127
  flowId,
13908
14128
  flowSource,
13909
14129
  limit: 200,
@@ -13939,7 +14159,7 @@ export function startUiServer({
13939
14159
  json(res, scoped.status || 400, { error: scoped.error });
13940
14160
  return;
13941
14161
  }
13942
- const scopeKey = workspaceRunKey(userCtx, flowSource, flowId);
14162
+ const scopeKey = workspaceRunKey(workspaceScopedUserContext(scoped, userCtx), flowSource, flowId);
13943
14163
  const entries = workspaceActiveRunsForScope(scopeKey).map(([, entry]) => entry);
13944
14164
  const entry = entries[0] || null;
13945
14165
  json(res, 200, {
@@ -13980,6 +14200,7 @@ export function startUiServer({
13980
14200
  const scoped = resolveWorkspaceScopeRoot(root, {
13981
14201
  flowId,
13982
14202
  flowSource,
14203
+ adminOwnerId: payload.adminOwnerId || "",
13983
14204
  archived: payload.archived === true || payload.flowArchived === true,
13984
14205
  }, userCtx);
13985
14206
  if (scoped.error) {
@@ -14124,6 +14345,7 @@ export function startUiServer({
14124
14345
  const scoped = resolveWorkspaceScopeRoot(root, {
14125
14346
  flowId: payload.flowId || "",
14126
14347
  flowSource: payload.flowSource || "user",
14348
+ adminOwnerId: payload.adminOwnerId || "",
14127
14349
  archived: payload.archived === true || payload.flowArchived === true,
14128
14350
  }, userCtx);
14129
14351
  if (scoped.error) {
@@ -14185,6 +14407,7 @@ export function startUiServer({
14185
14407
  const scoped = resolveWorkspaceScopeRoot(root, {
14186
14408
  flowId: payload.flowId || "",
14187
14409
  flowSource: payload.flowSource || "user",
14410
+ adminOwnerId: payload.adminOwnerId || "",
14188
14411
  archived: payload.archived === true || payload.flowArchived === true,
14189
14412
  }, userCtx);
14190
14413
  if (scoped.error) {
@@ -14259,6 +14482,7 @@ export function startUiServer({
14259
14482
  const scoped = resolveWorkspaceScopeRoot(root, {
14260
14483
  flowId: parsed.fields.flowId || "",
14261
14484
  flowSource: parsed.fields.flowSource || "user",
14485
+ adminOwnerId: parsed.fields.adminOwnerId || "",
14262
14486
  archived: parsed.fields.archived === "1" || parsed.fields.archived === "true" || parsed.fields.flowArchived === "true",
14263
14487
  }, userCtx);
14264
14488
  if (scoped.error) {
@@ -14304,6 +14528,7 @@ export function startUiServer({
14304
14528
  const scoped = resolveWorkspaceScopeRoot(root, {
14305
14529
  flowId: payload.flowId || "",
14306
14530
  flowSource: payload.flowSource || "user",
14531
+ adminOwnerId: payload.adminOwnerId || "",
14307
14532
  archived: payload.archived === true || payload.flowArchived === true,
14308
14533
  }, userCtx);
14309
14534
  if (scoped.error) {
@@ -14344,6 +14569,7 @@ export function startUiServer({
14344
14569
  const scoped = resolveWorkspaceScopeRoot(root, {
14345
14570
  flowId: payload.flowId || "",
14346
14571
  flowSource: payload.flowSource || "user",
14572
+ adminOwnerId: payload.adminOwnerId || "",
14347
14573
  archived: payload.archived === true || payload.flowArchived === true,
14348
14574
  }, userCtx);
14349
14575
  if (scoped.error) {
@@ -14394,6 +14620,7 @@ export function startUiServer({
14394
14620
  const scoped = resolveWorkspaceScopeRoot(root, {
14395
14621
  flowId: req.method === "POST" ? (payload.flowId || "") : (url.searchParams.get("flowId") || ""),
14396
14622
  flowSource: req.method === "POST" ? (payload.flowSource || "user") : (url.searchParams.get("flowSource") || "user"),
14623
+ adminOwnerId: req.method === "POST" ? (payload.adminOwnerId || "") : "",
14397
14624
  archived: req.method === "POST"
14398
14625
  ? (payload.archived === true || payload.flowArchived === true)
14399
14626
  : (url.searchParams.get("archived") === "1" || url.searchParams.get("flowArchived") === "1"),
@@ -14435,6 +14662,7 @@ export function startUiServer({
14435
14662
  const scoped = resolveWorkspaceScopeRoot(root, {
14436
14663
  flowId: payload.flowId || "",
14437
14664
  flowSource: payload.flowSource || "user",
14665
+ adminOwnerId: payload.adminOwnerId || "",
14438
14666
  archived: payload.archived === true || payload.flowArchived === true,
14439
14667
  }, userCtx);
14440
14668
  if (scoped.error) {
@@ -14525,6 +14753,7 @@ export function startUiServer({
14525
14753
  const scoped = resolveWorkspaceScopeRoot(root, {
14526
14754
  flowId: payload.flowId || "",
14527
14755
  flowSource: payload.flowSource || "user",
14756
+ adminOwnerId: payload.adminOwnerId || "",
14528
14757
  archived: payload.archived === true || payload.flowArchived === true,
14529
14758
  }, userCtx);
14530
14759
  if (scoped.error) {
@@ -15168,9 +15397,18 @@ export function startUiServer({
15168
15397
  }
15169
15398
  const nodesArchived = url.searchParams.get("archived") === "1";
15170
15399
  try {
15400
+ const requestedContext = adminWorkspaceRequestedUserContext(userCtx);
15401
+ if (requestedContext.error) {
15402
+ json(res, requestedContext.status || 403, { error: requestedContext.error });
15403
+ return;
15404
+ }
15171
15405
  const { setLanguage } = await import("./i18n.mjs");
15172
15406
  setLanguage(lang);
15173
- json(res, 200, listNodesJson(root, flowId || "", flowId ? flowSource : "", { archived: nodesArchived, ...userCtx, marketplaceScope }));
15407
+ json(res, 200, listNodesJson(root, flowId || "", flowId ? flowSource : "", {
15408
+ archived: nodesArchived,
15409
+ ...requestedContext.userCtx,
15410
+ marketplaceScope,
15411
+ }));
15174
15412
  } catch (e) {
15175
15413
  json(res, 500, { error: (e && e.message) || String(e) });
15176
15414
  }
@@ -15191,7 +15429,15 @@ export function startUiServer({
15191
15429
  }
15192
15430
  const archived = url.searchParams.get("archived") === "1";
15193
15431
  try {
15194
- const detail = readNodeDetailJson(root, nodeId, flowId, flowId ? (flowSource || "user") : "", { archived, ...userCtx });
15432
+ const requestedContext = adminWorkspaceRequestedUserContext(userCtx);
15433
+ if (requestedContext.error) {
15434
+ json(res, requestedContext.status || 403, { error: requestedContext.error });
15435
+ return;
15436
+ }
15437
+ const detail = readNodeDetailJson(root, nodeId, flowId, flowId ? (flowSource || "user") : "", {
15438
+ archived,
15439
+ ...requestedContext.userCtx,
15440
+ });
15195
15441
  if (detail.error) {
15196
15442
  json(res, 404, { error: detail.error });
15197
15443
  return;
@@ -15438,7 +15684,12 @@ export function startUiServer({
15438
15684
  json(res, collaborationDenied.status, { error: collaborationDenied.error });
15439
15685
  return;
15440
15686
  }
15441
- const result = readFlowJson(root, flowId, flowSource, { archived: flowArchived, ...userCtx });
15687
+ const requestedContext = adminWorkspaceRequestedUserContext(userCtx);
15688
+ if (requestedContext.error) {
15689
+ json(res, requestedContext.status || 403, { error: requestedContext.error });
15690
+ return;
15691
+ }
15692
+ const result = readFlowJson(root, flowId, flowSource, { archived: flowArchived, ...requestedContext.userCtx });
15442
15693
  if (result.error) {
15443
15694
  json(res, 404, result);
15444
15695
  return;