@fieldwangai/agentflow 0.1.102 → 0.1.105
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/lib/prd-workflow-collaboration.mjs +180 -0
- package/bin/lib/ui-server.mjs +574 -95
- package/builtin/web-ui/dist/assets/index-CC1ceU6X.css +1 -0
- package/builtin/web-ui/dist/assets/index-DuSU9kCW.js +348 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/builtin/web-ui/dist/assets/index-BMmmoIiB.js +0 -348
- package/builtin/web-ui/dist/assets/index-DhNqbtUT.css +0 -1
package/bin/lib/ui-server.mjs
CHANGED
|
@@ -148,6 +148,15 @@ import {
|
|
|
148
148
|
workspaceCollaborationAccess,
|
|
149
149
|
workspaceCollaborationSummary,
|
|
150
150
|
} from "./workspace-collaboration.mjs";
|
|
151
|
+
import {
|
|
152
|
+
addPrdWorkflowCollaborationMember,
|
|
153
|
+
ensurePrdWorkflowCollaboration,
|
|
154
|
+
getPrdWorkflowCollaborationById,
|
|
155
|
+
getPrdWorkflowCollaborationForUser,
|
|
156
|
+
prdWorkflowCollaborationAccess,
|
|
157
|
+
prdWorkflowCollaborationSummary,
|
|
158
|
+
removePrdWorkflowCollaborationMember,
|
|
159
|
+
} from "./prd-workflow-collaboration.mjs";
|
|
151
160
|
|
|
152
161
|
const MIME = {
|
|
153
162
|
".html": "text/html; charset=utf-8",
|
|
@@ -165,6 +174,16 @@ const MIME = {
|
|
|
165
174
|
".ico": "image/x-icon",
|
|
166
175
|
};
|
|
167
176
|
|
|
177
|
+
const UI_SERVER_STARTED_AT = new Date().toISOString();
|
|
178
|
+
const UI_SERVER_APP_VERSION = (() => {
|
|
179
|
+
try {
|
|
180
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, "package.json"), "utf-8"));
|
|
181
|
+
return String(pkg?.version || "0.0.0").trim() || "0.0.0";
|
|
182
|
+
} catch {
|
|
183
|
+
return "0.0.0";
|
|
184
|
+
}
|
|
185
|
+
})();
|
|
186
|
+
|
|
168
187
|
function execFileBuffered(command, args, options = {}) {
|
|
169
188
|
return new Promise((resolve, reject) => {
|
|
170
189
|
execFile(command, args, {
|
|
@@ -3194,6 +3213,20 @@ function workspaceCollaborationSummaryWithUsers(record, userId) {
|
|
|
3194
3213
|
};
|
|
3195
3214
|
}
|
|
3196
3215
|
|
|
3216
|
+
function prdWorkflowCollaborationSummaryWithUsers(record, userId) {
|
|
3217
|
+
const summary = prdWorkflowCollaborationSummary(record, userId);
|
|
3218
|
+
if (!summary) return null;
|
|
3219
|
+
const users = readAuthUsers();
|
|
3220
|
+
return {
|
|
3221
|
+
...summary,
|
|
3222
|
+
ownerUsername: String(users[summary.ownerId]?.username || summary.ownerId),
|
|
3223
|
+
members: (summary.members || []).map((member) => ({
|
|
3224
|
+
...member,
|
|
3225
|
+
username: String(users[member.userId]?.username || member.userId),
|
|
3226
|
+
})),
|
|
3227
|
+
};
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3197
3230
|
function workspaceConversationsPath(scopedRoot) {
|
|
3198
3231
|
return path.join(path.resolve(scopedRoot), ".workspace", "agentflow", "conversations.json");
|
|
3199
3232
|
}
|
|
@@ -7215,14 +7248,56 @@ const WORKSPACE_IMPLEMENTATION_REFERENCE_ENABLED = true;
|
|
|
7215
7248
|
const WORKSPACE_IMPLEMENTATION_SUMMARY_ENABLED = false;
|
|
7216
7249
|
const WORKSPACE_NODE_HISTORY_MAX_CHARS = 80000;
|
|
7217
7250
|
|
|
7251
|
+
function resolvePrdWorkflowScope(workspaceRoot, params = {}, userCtx = {}, capability = "read") {
|
|
7252
|
+
const tapdId = String(params.tapdId || params.tapd_id || "").trim();
|
|
7253
|
+
const flowId = String(params.flowId || "").trim();
|
|
7254
|
+
const flowSource = String(params.flowSource || "user").trim() || "user";
|
|
7255
|
+
const archived = params.archived === true || params.archived === "1" || params.flowArchived === true;
|
|
7256
|
+
const collaboration = tapdId
|
|
7257
|
+
? getPrdWorkflowCollaborationForUser(tapdId, userCtx?.userId)
|
|
7258
|
+
: null;
|
|
7259
|
+
const access = prdWorkflowCollaborationAccess(collaboration, userCtx?.userId);
|
|
7260
|
+
if (collaboration && !access.allowed) {
|
|
7261
|
+
return { error: "PRD Workflow collaboration permission denied", status: 403 };
|
|
7262
|
+
}
|
|
7263
|
+
if (capability === "write" && collaboration && !access.writable) {
|
|
7264
|
+
return { error: "PRD Workflow collaboration edit permission denied", status: 403 };
|
|
7265
|
+
}
|
|
7266
|
+
const ownerId = String(collaboration?.ownerId || userCtx?.userId || "").trim();
|
|
7267
|
+
const stateRoot = path.resolve(getAgentflowUserDataRoot(ownerId));
|
|
7268
|
+
let executionRoot = path.resolve(workspaceRoot);
|
|
7269
|
+
if (flowId) {
|
|
7270
|
+
const projectScope = resolveWorkspaceScopeRoot(workspaceRoot, {
|
|
7271
|
+
flowId,
|
|
7272
|
+
flowSource,
|
|
7273
|
+
workspaceId: params.workspaceId || "",
|
|
7274
|
+
archived,
|
|
7275
|
+
}, userCtx);
|
|
7276
|
+
if (projectScope.error) {
|
|
7277
|
+
if (!collaboration || capability !== "read") return projectScope;
|
|
7278
|
+
executionRoot = stateRoot;
|
|
7279
|
+
} else {
|
|
7280
|
+
executionRoot = projectScope.root;
|
|
7281
|
+
}
|
|
7282
|
+
}
|
|
7283
|
+
return {
|
|
7284
|
+
tapdId,
|
|
7285
|
+
executionRoot,
|
|
7286
|
+
stateRoot,
|
|
7287
|
+
ownerId,
|
|
7288
|
+
collaboration,
|
|
7289
|
+
collaborationAccess: access,
|
|
7290
|
+
flowId,
|
|
7291
|
+
flowSource,
|
|
7292
|
+
archived,
|
|
7293
|
+
};
|
|
7294
|
+
}
|
|
7295
|
+
|
|
7218
7296
|
function prdWorkflowKey(userCtx = {}, flowSource = "user", flowId = "", tapdId = "") {
|
|
7219
|
-
const
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
String(flowId || ""),
|
|
7224
|
-
String(tapdId || ""),
|
|
7225
|
-
].join("\t");
|
|
7297
|
+
const id = String(tapdId || "").trim();
|
|
7298
|
+
const collaboration = getPrdWorkflowCollaborationForUser(id, userCtx?.userId);
|
|
7299
|
+
const actorScope = `user:${String(collaboration?.ownerId || userCtx?.userId || "")}`;
|
|
7300
|
+
return [actorScope, id].join("\t");
|
|
7226
7301
|
}
|
|
7227
7302
|
|
|
7228
7303
|
function prdWorkflowBroadcast(key, event = {}) {
|
|
@@ -7240,8 +7315,10 @@ function prdWorkflowCollaborationState(userCtx = {}, flowSource = "user", flowId
|
|
|
7240
7315
|
const key = prdWorkflowKey(userCtx, flowSource, flowId, tapdId);
|
|
7241
7316
|
const active = prdWorkflowActionLocks.get(key) || null;
|
|
7242
7317
|
const subscribers = prdWorkflowSubscribers.get(key);
|
|
7318
|
+
const workflowCollaboration = getPrdWorkflowCollaborationForUser(tapdId, userCtx?.userId);
|
|
7243
7319
|
return {
|
|
7244
7320
|
subscribers: subscribers ? subscribers.size : 0,
|
|
7321
|
+
workflow: prdWorkflowCollaborationSummaryWithUsers(workflowCollaboration, userCtx?.userId),
|
|
7245
7322
|
activeAction: active ? {
|
|
7246
7323
|
action: String(active.action || ""),
|
|
7247
7324
|
tapdId: String(active.tapdId || tapdId || ""),
|
|
@@ -7417,6 +7494,35 @@ function prdWorkflowReviewPaths(scopedRoot, tapdId, reviewId) {
|
|
|
7417
7494
|
};
|
|
7418
7495
|
}
|
|
7419
7496
|
|
|
7497
|
+
function prdWorkflowMigrateLegacyState(legacyRoot, stateRoot, tapdId) {
|
|
7498
|
+
const sourceRoot = path.resolve(legacyRoot || "");
|
|
7499
|
+
const destinationRoot = path.resolve(stateRoot || "");
|
|
7500
|
+
if (!tapdId || sourceRoot === destinationRoot) return;
|
|
7501
|
+
const pairs = [
|
|
7502
|
+
[prdWorkflowStatePath(sourceRoot, tapdId), prdWorkflowStatePath(destinationRoot, tapdId)],
|
|
7503
|
+
[prdWorkflowCachePath(sourceRoot, tapdId), prdWorkflowCachePath(destinationRoot, tapdId)],
|
|
7504
|
+
[prdWorkflowProjectPath(sourceRoot, tapdId), prdWorkflowProjectPath(destinationRoot, tapdId)],
|
|
7505
|
+
[prdWorkflowClientsPath(sourceRoot, tapdId), prdWorkflowClientsPath(destinationRoot, tapdId)],
|
|
7506
|
+
[prdWorkflowEventsPath(sourceRoot, tapdId), prdWorkflowEventsPath(destinationRoot, tapdId)],
|
|
7507
|
+
[prdWorkflowAuditPath(sourceRoot, tapdId), prdWorkflowAuditPath(destinationRoot, tapdId)],
|
|
7508
|
+
];
|
|
7509
|
+
for (const [source, destination] of pairs) {
|
|
7510
|
+
try {
|
|
7511
|
+
if (!fs.existsSync(source) || fs.existsSync(destination)) continue;
|
|
7512
|
+
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
7513
|
+
fs.copyFileSync(source, destination);
|
|
7514
|
+
} catch (_) {}
|
|
7515
|
+
}
|
|
7516
|
+
try {
|
|
7517
|
+
const sourceReviews = prdWorkflowReviewDir(sourceRoot, tapdId);
|
|
7518
|
+
const destinationReviews = prdWorkflowReviewDir(destinationRoot, tapdId);
|
|
7519
|
+
if (fs.existsSync(sourceReviews) && !fs.existsSync(destinationReviews)) {
|
|
7520
|
+
fs.mkdirSync(path.dirname(destinationReviews), { recursive: true });
|
|
7521
|
+
fs.cpSync(sourceReviews, destinationReviews, { recursive: true, errorOnExist: false });
|
|
7522
|
+
}
|
|
7523
|
+
} catch (_) {}
|
|
7524
|
+
}
|
|
7525
|
+
|
|
7420
7526
|
function prdWorkflowPruneReviews(scopedRoot, tapdId, maxReviews = 200) {
|
|
7421
7527
|
try {
|
|
7422
7528
|
const dir = prdWorkflowReviewDir(scopedRoot, tapdId);
|
|
@@ -8681,6 +8787,19 @@ function prdWorkflowAppendRuntimeEvent(scopedRoot, tapdId, event = {}) {
|
|
|
8681
8787
|
let artifactConflict = false;
|
|
8682
8788
|
const events = [...current.events];
|
|
8683
8789
|
if (index >= 0) {
|
|
8790
|
+
const previousImplementationMetadata =
|
|
8791
|
+
events[index]?.implementationMetadata || events[index]?.implementation_metadata;
|
|
8792
|
+
const incomingImplementationMetadata =
|
|
8793
|
+
entry?.implementationMetadata || entry?.implementation_metadata;
|
|
8794
|
+
const mergedImplementationMetadata =
|
|
8795
|
+
incomingImplementationMetadata && typeof incomingImplementationMetadata === "object" && !Array.isArray(incomingImplementationMetadata)
|
|
8796
|
+
? prdWorkflowOverallMerge(
|
|
8797
|
+
previousImplementationMetadata && typeof previousImplementationMetadata === "object" && !Array.isArray(previousImplementationMetadata)
|
|
8798
|
+
? previousImplementationMetadata
|
|
8799
|
+
: {},
|
|
8800
|
+
incomingImplementationMetadata,
|
|
8801
|
+
)
|
|
8802
|
+
: previousImplementationMetadata;
|
|
8684
8803
|
const prevArtifact = prdWorkflowRuntimeEventArtifactSignature(events[index]);
|
|
8685
8804
|
const nextArtifact = prdWorkflowRuntimeEventArtifactSignature(entry);
|
|
8686
8805
|
artifactConflict = Boolean(prevArtifact && nextArtifact && prevArtifact !== nextArtifact &&
|
|
@@ -8703,6 +8822,9 @@ function prdWorkflowAppendRuntimeEvent(scopedRoot, tapdId, event = {}) {
|
|
|
8703
8822
|
startedAt: events[index].startedAt || entry.startedAt,
|
|
8704
8823
|
idempotencyHistory: [...new Set(idempotencyHistory)].slice(-50),
|
|
8705
8824
|
};
|
|
8825
|
+
if (mergedImplementationMetadata && typeof mergedImplementationMetadata === "object" && !Array.isArray(mergedImplementationMetadata)) {
|
|
8826
|
+
events[index].implementationMetadata = mergedImplementationMetadata;
|
|
8827
|
+
}
|
|
8706
8828
|
if (artifactConflict) {
|
|
8707
8829
|
events[index] = {
|
|
8708
8830
|
...events[index],
|
|
@@ -8802,13 +8924,212 @@ function prdWorkflowMergeRuntimeEventList(snapshotEvents = [], runtimeEvents = [
|
|
|
8802
8924
|
return out;
|
|
8803
8925
|
}
|
|
8804
8926
|
|
|
8927
|
+
function prdWorkflowOverallPlainObject(value) {
|
|
8928
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
8929
|
+
}
|
|
8930
|
+
|
|
8931
|
+
function prdWorkflowOverallMerge(base, patch) {
|
|
8932
|
+
if (!patch || typeof patch !== "object" || Array.isArray(patch)) return base;
|
|
8933
|
+
const out = { ...prdWorkflowOverallPlainObject(base) };
|
|
8934
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
8935
|
+
if (value === undefined) continue;
|
|
8936
|
+
if (value === null) {
|
|
8937
|
+
delete out[key];
|
|
8938
|
+
continue;
|
|
8939
|
+
}
|
|
8940
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
8941
|
+
out[key] = prdWorkflowOverallMerge(out[key], value);
|
|
8942
|
+
continue;
|
|
8943
|
+
}
|
|
8944
|
+
out[key] = value;
|
|
8945
|
+
}
|
|
8946
|
+
return out;
|
|
8947
|
+
}
|
|
8948
|
+
|
|
8949
|
+
function prdWorkflowOverallDeletePath(value, rawPath) {
|
|
8950
|
+
const pathParts = String(rawPath || "").split(".").map((part) => part.trim()).filter(Boolean);
|
|
8951
|
+
if (!pathParts.length) return value;
|
|
8952
|
+
const root = prdWorkflowOverallPlainObject(value);
|
|
8953
|
+
let cursor = root;
|
|
8954
|
+
for (const part of pathParts.slice(0, -1)) {
|
|
8955
|
+
if (!cursor[part] || typeof cursor[part] !== "object" || Array.isArray(cursor[part])) return root;
|
|
8956
|
+
cursor = cursor[part];
|
|
8957
|
+
}
|
|
8958
|
+
delete cursor[pathParts[pathParts.length - 1]];
|
|
8959
|
+
return root;
|
|
8960
|
+
}
|
|
8961
|
+
|
|
8962
|
+
function prdWorkflowOverallValueKey(value) {
|
|
8963
|
+
if (typeof value === "string") return value.trim().toLowerCase();
|
|
8964
|
+
try {
|
|
8965
|
+
return JSON.stringify(value);
|
|
8966
|
+
} catch {
|
|
8967
|
+
return String(value);
|
|
8968
|
+
}
|
|
8969
|
+
}
|
|
8970
|
+
|
|
8971
|
+
function prdWorkflowOverallUnique(values = []) {
|
|
8972
|
+
const out = [];
|
|
8973
|
+
const seen = new Set();
|
|
8974
|
+
for (const value of values) {
|
|
8975
|
+
if (value == null || value === "") continue;
|
|
8976
|
+
const key = prdWorkflowOverallValueKey(value);
|
|
8977
|
+
if (!key || seen.has(key)) continue;
|
|
8978
|
+
seen.add(key);
|
|
8979
|
+
out.push(value);
|
|
8980
|
+
}
|
|
8981
|
+
return out;
|
|
8982
|
+
}
|
|
8983
|
+
|
|
8984
|
+
function prdWorkflowOverallFilterValues(filters, key) {
|
|
8985
|
+
if (!filters || typeof filters !== "object" || Array.isArray(filters)) return [];
|
|
8986
|
+
const aliases = {
|
|
8987
|
+
countries: ["countries", "country", "countryFilters", "country_filters"],
|
|
8988
|
+
users: ["users", "user", "uids", "uid", "userFilters", "user_filters"],
|
|
8989
|
+
versions: ["versions", "version", "versionFilters", "version_filters"],
|
|
8990
|
+
};
|
|
8991
|
+
for (const alias of aliases[key] || [key]) {
|
|
8992
|
+
const value = filters[alias];
|
|
8993
|
+
if (Array.isArray(value)) return value;
|
|
8994
|
+
if (value != null && value !== "") return [value];
|
|
8995
|
+
}
|
|
8996
|
+
return [];
|
|
8997
|
+
}
|
|
8998
|
+
|
|
8999
|
+
function prdWorkflowFinalizeOverall(tapdId, value) {
|
|
9000
|
+
const overall = prdWorkflowOverallPlainObject(value);
|
|
9001
|
+
const requirement = {
|
|
9002
|
+
...prdWorkflowOverallPlainObject(overall.requirement),
|
|
9003
|
+
tapdId: String(overall?.requirement?.tapdId || overall?.requirement?.tapd_id || tapdId || ""),
|
|
9004
|
+
};
|
|
9005
|
+
const platforms = {};
|
|
9006
|
+
for (const [rawPlatform, rawValue] of Object.entries(prdWorkflowOverallPlainObject(overall.platforms))) {
|
|
9007
|
+
const platform = String(rawPlatform || "").trim().toLowerCase();
|
|
9008
|
+
if (!platform) continue;
|
|
9009
|
+
const platformValue = prdWorkflowOverallPlainObject(rawValue);
|
|
9010
|
+
const issues = prdWorkflowOverallPlainObject(platformValue.issues);
|
|
9011
|
+
const implementations = Object.values(issues)
|
|
9012
|
+
.map((issue) => prdWorkflowOverallPlainObject(issue).implementation)
|
|
9013
|
+
.filter((item) => item && typeof item === "object" && !Array.isArray(item));
|
|
9014
|
+
const filters = implementations.map((item) => prdWorkflowOverallPlainObject(item.filters));
|
|
9015
|
+
platforms[platform] = {
|
|
9016
|
+
...platformValue,
|
|
9017
|
+
tags: prdWorkflowOverallUnique([
|
|
9018
|
+
...(Array.isArray(platformValue.tags) ? platformValue.tags : []),
|
|
9019
|
+
...implementations.flatMap((item) => Array.isArray(item.tags) ? item.tags : []),
|
|
9020
|
+
]),
|
|
9021
|
+
experiments: prdWorkflowOverallUnique([
|
|
9022
|
+
...(Array.isArray(platformValue.experiments) ? platformValue.experiments : []),
|
|
9023
|
+
...implementations.flatMap((item) => Array.isArray(item.experiments) ? item.experiments : []),
|
|
9024
|
+
]),
|
|
9025
|
+
settings: prdWorkflowOverallUnique([
|
|
9026
|
+
...(Array.isArray(platformValue.settings) ? platformValue.settings : []),
|
|
9027
|
+
...implementations.flatMap((item) => Array.isArray(item.settings) ? item.settings : []),
|
|
9028
|
+
]),
|
|
9029
|
+
filters: {
|
|
9030
|
+
...prdWorkflowOverallPlainObject(platformValue.filters),
|
|
9031
|
+
countries: prdWorkflowOverallUnique([
|
|
9032
|
+
...prdWorkflowOverallFilterValues(platformValue.filters, "countries"),
|
|
9033
|
+
...filters.flatMap((item) => prdWorkflowOverallFilterValues(item, "countries")),
|
|
9034
|
+
]),
|
|
9035
|
+
users: prdWorkflowOverallUnique([
|
|
9036
|
+
...prdWorkflowOverallFilterValues(platformValue.filters, "users"),
|
|
9037
|
+
...filters.flatMap((item) => prdWorkflowOverallFilterValues(item, "users")),
|
|
9038
|
+
]),
|
|
9039
|
+
versions: prdWorkflowOverallUnique([
|
|
9040
|
+
...prdWorkflowOverallFilterValues(platformValue.filters, "versions"),
|
|
9041
|
+
...filters.flatMap((item) => prdWorkflowOverallFilterValues(item, "versions")),
|
|
9042
|
+
]),
|
|
9043
|
+
},
|
|
9044
|
+
rules: prdWorkflowOverallUnique([
|
|
9045
|
+
...(Array.isArray(platformValue.rules) ? platformValue.rules : []),
|
|
9046
|
+
...implementations.flatMap((item) => Array.isArray(item.rules) ? item.rules : []),
|
|
9047
|
+
]),
|
|
9048
|
+
issues,
|
|
9049
|
+
};
|
|
9050
|
+
}
|
|
9051
|
+
return {
|
|
9052
|
+
...overall,
|
|
9053
|
+
requirement,
|
|
9054
|
+
platforms,
|
|
9055
|
+
};
|
|
9056
|
+
}
|
|
9057
|
+
|
|
9058
|
+
function prdWorkflowOverallFromEvents(tapdId, snapshot = {}, runtimeEvents = []) {
|
|
9059
|
+
const rawOverall =
|
|
9060
|
+
snapshot?.overall ||
|
|
9061
|
+
snapshot?.prdOverall ||
|
|
9062
|
+
snapshot?.prd_overall ||
|
|
9063
|
+
snapshot?.raw?.overall ||
|
|
9064
|
+
snapshot?.raw?.prdOverall ||
|
|
9065
|
+
snapshot?.raw?.prd_overall ||
|
|
9066
|
+
snapshot?.raw?.prd?.overall ||
|
|
9067
|
+
{};
|
|
9068
|
+
let overall = prdWorkflowOverallMerge({}, rawOverall);
|
|
9069
|
+
const events = [...(Array.isArray(runtimeEvents) ? runtimeEvents : [])].sort((left, right) => {
|
|
9070
|
+
const leftAt = Date.parse(left?.updatedAt || left?.completedAt || left?.createdAt || left?.observedAt || "");
|
|
9071
|
+
const rightAt = Date.parse(right?.updatedAt || right?.completedAt || right?.createdAt || right?.observedAt || "");
|
|
9072
|
+
if (!Number.isFinite(leftAt) && !Number.isFinite(rightAt)) return 0;
|
|
9073
|
+
if (!Number.isFinite(leftAt)) return -1;
|
|
9074
|
+
if (!Number.isFinite(rightAt)) return 1;
|
|
9075
|
+
return leftAt - rightAt;
|
|
9076
|
+
});
|
|
9077
|
+
for (const event of events) {
|
|
9078
|
+
if (!event || typeof event !== "object" || Array.isArray(event)) continue;
|
|
9079
|
+
const patch = event.overallPatch || event.overall_patch;
|
|
9080
|
+
if (patch && typeof patch === "object" && !Array.isArray(patch)) {
|
|
9081
|
+
overall = prdWorkflowOverallMerge(overall, patch);
|
|
9082
|
+
}
|
|
9083
|
+
const platform = String(event.platform || "").trim().toLowerCase();
|
|
9084
|
+
const issueKey = String(event.issueKey || event.issue_key || event.issue || "").trim();
|
|
9085
|
+
const actor = prdWorkflowOverallPlainObject(event.actor);
|
|
9086
|
+
if ((event.overallOwnerFromActor === true || event.overall_owner_from_actor === true) && platform && (actor.userId || actor.username)) {
|
|
9087
|
+
overall = prdWorkflowOverallMerge(overall, {
|
|
9088
|
+
platforms: {
|
|
9089
|
+
[platform]: {
|
|
9090
|
+
owner: {
|
|
9091
|
+
userId: String(actor.userId || ""),
|
|
9092
|
+
username: String(actor.username || actor.userId || ""),
|
|
9093
|
+
source: "latest-confirmed-plan",
|
|
9094
|
+
planVersion: event.planVersion || event.plan_version || "",
|
|
9095
|
+
updatedAt: event.updatedAt || event.completedAt || "",
|
|
9096
|
+
},
|
|
9097
|
+
},
|
|
9098
|
+
},
|
|
9099
|
+
});
|
|
9100
|
+
}
|
|
9101
|
+
const implementation = event.implementationMetadata || event.implementation_metadata;
|
|
9102
|
+
if (platform && issueKey && implementation && typeof implementation === "object" && !Array.isArray(implementation)) {
|
|
9103
|
+
overall = prdWorkflowOverallMerge(overall, {
|
|
9104
|
+
platforms: {
|
|
9105
|
+
[platform]: {
|
|
9106
|
+
issues: {
|
|
9107
|
+
[issueKey]: {
|
|
9108
|
+
title: String(event.issueTitle || event.issue_title || event.title || ""),
|
|
9109
|
+
implementation,
|
|
9110
|
+
mr: String(event?.changes?.impl_mr || event?.implMr || event?.impl_mr || ""),
|
|
9111
|
+
updatedAt: event.updatedAt || event.completedAt || "",
|
|
9112
|
+
},
|
|
9113
|
+
},
|
|
9114
|
+
},
|
|
9115
|
+
},
|
|
9116
|
+
});
|
|
9117
|
+
}
|
|
9118
|
+
const removePaths = event.overallRemove || event.overall_remove;
|
|
9119
|
+
for (const removePath of Array.isArray(removePaths) ? removePaths : []) {
|
|
9120
|
+
overall = prdWorkflowOverallDeletePath(overall, removePath);
|
|
9121
|
+
}
|
|
9122
|
+
}
|
|
9123
|
+
return prdWorkflowFinalizeOverall(tapdId, overall);
|
|
9124
|
+
}
|
|
9125
|
+
|
|
8805
9126
|
function prdWorkflowMergeRuntimeEvents(scopedRoot, tapdId, snapshot) {
|
|
8806
9127
|
const runtime = prdWorkflowReadRuntimeEvents(scopedRoot, tapdId);
|
|
8807
9128
|
const runtimeEvents = runtime.events;
|
|
8808
|
-
if (!runtimeEvents.length) return snapshot;
|
|
8809
9129
|
const events = prdWorkflowMergeRuntimeEventList(snapshot?.events, runtimeEvents);
|
|
8810
9130
|
return {
|
|
8811
9131
|
...snapshot,
|
|
9132
|
+
overall: prdWorkflowOverallFromEvents(tapdId, snapshot, runtimeEvents),
|
|
8812
9133
|
runtimeEvents,
|
|
8813
9134
|
events,
|
|
8814
9135
|
sources: {
|
|
@@ -9156,6 +9477,9 @@ function prdWorkflowSnapshotFromParsed(scopedRoot, tapdId, parsed = {}, userCtx
|
|
|
9156
9477
|
dependencies: prdWorkflowFirstArray(parsed.dependencies),
|
|
9157
9478
|
optionalGaps,
|
|
9158
9479
|
sources: parsed.sources && typeof parsed.sources === "object" ? parsed.sources : {},
|
|
9480
|
+
overall: prdWorkflowOverallFromEvents(id, {
|
|
9481
|
+
overall: parsed.overall || parsed.prdOverall || parsed.prd_overall || prd.overall || {},
|
|
9482
|
+
}, []),
|
|
9159
9483
|
raw: parsed,
|
|
9160
9484
|
collaboration: prdWorkflowCollaborationState(userCtx, flowSource, flowId, id),
|
|
9161
9485
|
};
|
|
@@ -9570,6 +9894,7 @@ function listWorkspaceScheduleStatuses(root, userCtx = {}) {
|
|
|
9570
9894
|
key,
|
|
9571
9895
|
flowId,
|
|
9572
9896
|
flowSource,
|
|
9897
|
+
workspaceId: String(flow.collaboration?.id || scoped.workspaceId || ""),
|
|
9573
9898
|
scheduleNodeId,
|
|
9574
9899
|
runNodeId: targetRunNodeId,
|
|
9575
9900
|
label: String(instance.label || "Scheduled Run"),
|
|
@@ -10121,6 +10446,15 @@ export function startUiServer({
|
|
|
10121
10446
|
return;
|
|
10122
10447
|
}
|
|
10123
10448
|
|
|
10449
|
+
if (url.pathname === "/api/app-version" && req.method === "GET") {
|
|
10450
|
+
res.setHeader("Cache-Control", "no-store, max-age=0");
|
|
10451
|
+
json(res, 200, {
|
|
10452
|
+
version: UI_SERVER_APP_VERSION,
|
|
10453
|
+
startedAt: UI_SERVER_STARTED_AT,
|
|
10454
|
+
});
|
|
10455
|
+
return;
|
|
10456
|
+
}
|
|
10457
|
+
|
|
10124
10458
|
if (url.pathname === "/api/auth/login" && req.method === "POST") {
|
|
10125
10459
|
let payload;
|
|
10126
10460
|
try {
|
|
@@ -10166,21 +10500,136 @@ export function startUiServer({
|
|
|
10166
10500
|
json(res, 200, { token: getSessionTokenFromRequest(req) || "" });
|
|
10167
10501
|
return;
|
|
10168
10502
|
}
|
|
10503
|
+
if (req.method === "GET" && url.pathname === "/api/prd-workflow/collaboration") {
|
|
10504
|
+
const tapdId = String(url.searchParams.get("tapdId") || "").trim();
|
|
10505
|
+
if (!tapdId) {
|
|
10506
|
+
json(res, 400, { error: "Missing tapdId" });
|
|
10507
|
+
return;
|
|
10508
|
+
}
|
|
10509
|
+
const record = getPrdWorkflowCollaborationForUser(tapdId, userCtx.userId);
|
|
10510
|
+
json(res, 200, {
|
|
10511
|
+
ok: true,
|
|
10512
|
+
collaboration: prdWorkflowCollaborationSummaryWithUsers(record, userCtx.userId),
|
|
10513
|
+
});
|
|
10514
|
+
return;
|
|
10515
|
+
}
|
|
10516
|
+
if (req.method === "POST" && url.pathname === "/api/prd-workflow/collaboration/share") {
|
|
10517
|
+
try {
|
|
10518
|
+
const payload = JSON.parse(await readBody(req));
|
|
10519
|
+
const tapdId = String(payload?.tapdId || payload?.tapd_id || "").trim();
|
|
10520
|
+
if (!tapdId) {
|
|
10521
|
+
json(res, 400, { error: "Missing tapdId" });
|
|
10522
|
+
return;
|
|
10523
|
+
}
|
|
10524
|
+
const existing = getPrdWorkflowCollaborationForUser(tapdId, userCtx.userId);
|
|
10525
|
+
if (existing && prdWorkflowCollaborationAccess(existing, userCtx.userId).role !== "owner") {
|
|
10526
|
+
json(res, 403, { error: "仅 Workflow 所有者可以添加成员" });
|
|
10527
|
+
return;
|
|
10528
|
+
}
|
|
10529
|
+
const ensured = ensurePrdWorkflowCollaboration({ tapdId, userId: userCtx.userId });
|
|
10530
|
+
if (ensured.error) {
|
|
10531
|
+
json(res, ensured.status || 400, { error: ensured.error });
|
|
10532
|
+
return;
|
|
10533
|
+
}
|
|
10534
|
+
const targetUser = findWorkspaceShareUser(payload?.username || payload?.userId);
|
|
10535
|
+
if (!targetUser) {
|
|
10536
|
+
json(res, 404, { error: "未找到该用户名,请确认对方已经登录或注册 AgentFlow" });
|
|
10537
|
+
return;
|
|
10538
|
+
}
|
|
10539
|
+
if (targetUser.userId === userCtx.userId) {
|
|
10540
|
+
json(res, 400, { error: "无需将 Workflow 分享给自己" });
|
|
10541
|
+
return;
|
|
10542
|
+
}
|
|
10543
|
+
const added = addPrdWorkflowCollaborationMember({
|
|
10544
|
+
workflowId: ensured.workflow.id,
|
|
10545
|
+
userId: userCtx.userId,
|
|
10546
|
+
memberUserId: targetUser.userId,
|
|
10547
|
+
role: payload?.role,
|
|
10548
|
+
});
|
|
10549
|
+
if (added.error) {
|
|
10550
|
+
json(res, added.status || 400, { error: added.error });
|
|
10551
|
+
return;
|
|
10552
|
+
}
|
|
10553
|
+
const scope = resolvePrdWorkflowScope(root, { ...payload, tapdId }, userCtx, "write");
|
|
10554
|
+
if (!scope.error) prdWorkflowMigrateLegacyState(scope.executionRoot, scope.stateRoot, tapdId);
|
|
10555
|
+
const record = getPrdWorkflowCollaborationById(ensured.workflow.id);
|
|
10556
|
+
prdWorkflowBroadcast(prdWorkflowKey(userCtx, "", "", tapdId), {
|
|
10557
|
+
type: "member.added",
|
|
10558
|
+
tapdId,
|
|
10559
|
+
memberUserId: targetUser.userId,
|
|
10560
|
+
});
|
|
10561
|
+
json(res, 200, {
|
|
10562
|
+
ok: true,
|
|
10563
|
+
collaboration: prdWorkflowCollaborationSummaryWithUsers(record, userCtx.userId),
|
|
10564
|
+
member: { userId: targetUser.userId, username: targetUser.username, role: "editor" },
|
|
10565
|
+
});
|
|
10566
|
+
} catch (error) {
|
|
10567
|
+
json(res, 400, { error: (error && error.message) || String(error) });
|
|
10568
|
+
}
|
|
10569
|
+
return;
|
|
10570
|
+
}
|
|
10571
|
+
if (req.method === "DELETE" && url.pathname === "/api/prd-workflow/collaboration/share") {
|
|
10572
|
+
try {
|
|
10573
|
+
const payload = JSON.parse(await readBody(req));
|
|
10574
|
+
const tapdId = String(payload?.tapdId || payload?.tapd_id || "").trim();
|
|
10575
|
+
const record = getPrdWorkflowCollaborationForUser(tapdId, userCtx.userId);
|
|
10576
|
+
if (!record) {
|
|
10577
|
+
json(res, 404, { error: "PRD Workflow collaboration not found" });
|
|
10578
|
+
return;
|
|
10579
|
+
}
|
|
10580
|
+
const requestedUser = String(payload?.username || payload?.memberUserId || "").trim();
|
|
10581
|
+
const targetUser = requestedUser ? findWorkspaceShareUser(requestedUser) : null;
|
|
10582
|
+
if (requestedUser && !targetUser) {
|
|
10583
|
+
json(res, 404, { error: "未找到该用户" });
|
|
10584
|
+
return;
|
|
10585
|
+
}
|
|
10586
|
+
const removed = removePrdWorkflowCollaborationMember({
|
|
10587
|
+
workflowId: record.id,
|
|
10588
|
+
userId: userCtx.userId,
|
|
10589
|
+
memberUserId: targetUser?.userId || userCtx.userId,
|
|
10590
|
+
});
|
|
10591
|
+
if (removed.error) {
|
|
10592
|
+
json(res, removed.status || 400, { error: removed.error });
|
|
10593
|
+
return;
|
|
10594
|
+
}
|
|
10595
|
+
const nextRecord = getPrdWorkflowCollaborationById(record.id);
|
|
10596
|
+
prdWorkflowBroadcast(prdWorkflowKey(userCtx, "", "", tapdId), {
|
|
10597
|
+
type: removed.left ? "member.left" : "member.removed",
|
|
10598
|
+
tapdId,
|
|
10599
|
+
memberUserId: removed.removedUserId || "",
|
|
10600
|
+
});
|
|
10601
|
+
json(res, 200, {
|
|
10602
|
+
ok: true,
|
|
10603
|
+
left: removed.left === true,
|
|
10604
|
+
removedUserId: removed.removedUserId || "",
|
|
10605
|
+
collaboration: removed.left
|
|
10606
|
+
? null
|
|
10607
|
+
: prdWorkflowCollaborationSummaryWithUsers(nextRecord, userCtx.userId),
|
|
10608
|
+
});
|
|
10609
|
+
} catch (error) {
|
|
10610
|
+
json(res, 400, { error: (error && error.message) || String(error) });
|
|
10611
|
+
}
|
|
10612
|
+
return;
|
|
10613
|
+
}
|
|
10169
10614
|
if (req.method === "GET" && url.pathname === "/api/prd-workflow/snapshot") {
|
|
10170
10615
|
try {
|
|
10171
10616
|
const tapdId = String(url.searchParams.get("tapdId") || "").trim();
|
|
10172
10617
|
const flowId = String(url.searchParams.get("flowId") || "").trim();
|
|
10173
10618
|
const flowSource = String(url.searchParams.get("flowSource") || "user").trim() || "user";
|
|
10174
10619
|
const archived = url.searchParams.get("archived") === "1";
|
|
10175
|
-
|
|
10176
|
-
|
|
10177
|
-
|
|
10178
|
-
|
|
10179
|
-
|
|
10180
|
-
|
|
10181
|
-
|
|
10182
|
-
|
|
10620
|
+
const workflowScope = resolvePrdWorkflowScope(root, {
|
|
10621
|
+
tapdId,
|
|
10622
|
+
flowId,
|
|
10623
|
+
flowSource,
|
|
10624
|
+
archived,
|
|
10625
|
+
workspaceId: url.searchParams.get("workspaceId") || "",
|
|
10626
|
+
}, userCtx);
|
|
10627
|
+
if (workflowScope.error) {
|
|
10628
|
+
json(res, workflowScope.status || 400, { error: workflowScope.error });
|
|
10629
|
+
return;
|
|
10183
10630
|
}
|
|
10631
|
+
const scopedRoot = workflowScope.stateRoot;
|
|
10632
|
+
prdWorkflowMigrateLegacyState(workflowScope.executionRoot, scopedRoot, tapdId);
|
|
10184
10633
|
const useMock = url.searchParams.get("mock") === "1" || parseBool(process.env.AGENTFLOW_PRD_WORKFLOW_MOCK, false);
|
|
10185
10634
|
const runtimeOnly = url.searchParams.get("runtimeOnly") === "1" ||
|
|
10186
10635
|
url.searchParams.get("runtime_only") === "1" ||
|
|
@@ -10188,8 +10637,8 @@ export function startUiServer({
|
|
|
10188
10637
|
const baseSnapshot = useMock
|
|
10189
10638
|
? prdWorkflowMockSnapshot(scopedRoot, tapdId || "mock-prd")
|
|
10190
10639
|
: runtimeOnly
|
|
10191
|
-
? prdWorkflowMaterializeSnapshot(
|
|
10192
|
-
: await prdWorkflowSnapshot(
|
|
10640
|
+
? prdWorkflowMaterializeSnapshot(workflowScope.executionRoot, scopedRoot, tapdId, userCtx, { flowSource, flowId })
|
|
10641
|
+
: await prdWorkflowSnapshot(workflowScope.executionRoot, scopedRoot, tapdId, userCtx, { flowSource, flowId });
|
|
10193
10642
|
const snapshot = prdWorkflowWithAgentflowTokenDiagnostic(
|
|
10194
10643
|
baseSnapshot,
|
|
10195
10644
|
getSessionTokenFromRequest(req) || "",
|
|
@@ -10218,15 +10667,19 @@ export function startUiServer({
|
|
|
10218
10667
|
const flowId = String(payload.flowId || "").trim();
|
|
10219
10668
|
const flowSource = String(payload.flowSource || "user").trim() || "user";
|
|
10220
10669
|
const archived = payload.archived === true || payload.flowArchived === true;
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10670
|
+
const workflowScope = resolvePrdWorkflowScope(root, {
|
|
10671
|
+
...payload,
|
|
10672
|
+
tapdId,
|
|
10673
|
+
flowId,
|
|
10674
|
+
flowSource,
|
|
10675
|
+
archived,
|
|
10676
|
+
}, userCtx, "write");
|
|
10677
|
+
if (workflowScope.error) {
|
|
10678
|
+
json(res, workflowScope.status || 400, { error: workflowScope.error });
|
|
10679
|
+
return;
|
|
10229
10680
|
}
|
|
10681
|
+
const scopedRoot = workflowScope.stateRoot;
|
|
10682
|
+
prdWorkflowMigrateLegacyState(workflowScope.executionRoot, scopedRoot, tapdId);
|
|
10230
10683
|
const rawSnapshot = payload.snapshot && typeof payload.snapshot === "object" && !Array.isArray(payload.snapshot)
|
|
10231
10684
|
? payload.snapshot
|
|
10232
10685
|
: payload.prd || payload.next ? payload : null;
|
|
@@ -10311,7 +10764,7 @@ export function startUiServer({
|
|
|
10311
10764
|
incomingSnapshot: prdWorkflowCompactRuntimeValue(projectFactSnapshot, 12000),
|
|
10312
10765
|
});
|
|
10313
10766
|
const currentSnapshot = prdWorkflowWithAgentflowTokenDiagnostic(
|
|
10314
|
-
prdWorkflowMaterializeSnapshot(
|
|
10767
|
+
prdWorkflowMaterializeSnapshot(workflowScope.executionRoot, scopedRoot, tapdId, userCtx, { flowSource, flowId }),
|
|
10315
10768
|
getSessionTokenFromRequest(req) || "",
|
|
10316
10769
|
);
|
|
10317
10770
|
json(res, 409, {
|
|
@@ -10351,7 +10804,7 @@ export function startUiServer({
|
|
|
10351
10804
|
persistence: projectFactSource.persistence,
|
|
10352
10805
|
});
|
|
10353
10806
|
}
|
|
10354
|
-
const materialized = prdWorkflowMaterializeSnapshot(
|
|
10807
|
+
const materialized = prdWorkflowMaterializeSnapshot(workflowScope.executionRoot, scopedRoot, tapdId, userCtx, { flowSource, flowId });
|
|
10355
10808
|
const withDiagnostic = prdWorkflowWithAgentflowTokenDiagnostic(materialized, getSessionTokenFromRequest(req) || "");
|
|
10356
10809
|
prdWorkflowBroadcast(prdWorkflowKey(userCtx, flowSource, flowId, tapdId), { type: "snapshot-report", tapdId, snapshot: withDiagnostic });
|
|
10357
10810
|
json(res, 200, { ok: true, snapshot: withDiagnostic });
|
|
@@ -10370,30 +10823,36 @@ export function startUiServer({
|
|
|
10370
10823
|
return;
|
|
10371
10824
|
}
|
|
10372
10825
|
let actionScopedRoot = root;
|
|
10826
|
+
let actionExecutionRoot = root;
|
|
10373
10827
|
let normalizedForCatch = null;
|
|
10374
10828
|
let actionRunId = "";
|
|
10375
10829
|
try {
|
|
10376
10830
|
const flowId = String(payload.flowId || "").trim();
|
|
10377
10831
|
const flowSource = String(payload.flowSource || "user").trim() || "user";
|
|
10378
10832
|
const archived = payload.archived === true || payload.flowArchived === true;
|
|
10379
|
-
let scopedRoot = root;
|
|
10380
|
-
if (flowId) {
|
|
10381
|
-
const scoped = resolveWorkspaceScopeRoot(root, { flowId, flowSource, archived }, userCtx);
|
|
10382
|
-
if (scoped.error) {
|
|
10383
|
-
json(res, 400, { error: scoped.error });
|
|
10384
|
-
return;
|
|
10385
|
-
}
|
|
10386
|
-
scopedRoot = scoped.root;
|
|
10387
|
-
}
|
|
10388
|
-
actionScopedRoot = scopedRoot;
|
|
10389
10833
|
const normalized = normalizePrdWorkflowActionArgs(payload);
|
|
10390
10834
|
normalizedForCatch = normalized;
|
|
10391
10835
|
if (normalized.error) {
|
|
10392
10836
|
json(res, 400, { error: normalized.error });
|
|
10393
10837
|
return;
|
|
10394
10838
|
}
|
|
10839
|
+
const workflowScope = resolvePrdWorkflowScope(root, {
|
|
10840
|
+
...payload,
|
|
10841
|
+
tapdId: normalized.tapdId,
|
|
10842
|
+
flowId,
|
|
10843
|
+
flowSource,
|
|
10844
|
+
archived,
|
|
10845
|
+
}, userCtx, "write");
|
|
10846
|
+
if (workflowScope.error) {
|
|
10847
|
+
json(res, workflowScope.status || 400, { error: workflowScope.error });
|
|
10848
|
+
return;
|
|
10849
|
+
}
|
|
10850
|
+
const scopedRoot = workflowScope.stateRoot;
|
|
10851
|
+
actionScopedRoot = scopedRoot;
|
|
10852
|
+
actionExecutionRoot = workflowScope.executionRoot;
|
|
10853
|
+
prdWorkflowMigrateLegacyState(actionExecutionRoot, scopedRoot, normalized.tapdId);
|
|
10395
10854
|
const idem = String(normalized.idempotencyKey || "").trim();
|
|
10396
|
-
const idemKey = idem ? prdWorkflowKey(userCtx, flowSource, flowId,
|
|
10855
|
+
const idemKey = idem ? `${prdWorkflowKey(userCtx, flowSource, flowId, normalized.tapdId)}\t${idem}` : "";
|
|
10397
10856
|
if (idemKey && prdWorkflowIdempotency.has(idemKey)) {
|
|
10398
10857
|
json(res, 200, { ok: true, alreadyApplied: true, ...prdWorkflowIdempotency.get(idemKey)?.result });
|
|
10399
10858
|
return;
|
|
@@ -10401,7 +10860,7 @@ export function startUiServer({
|
|
|
10401
10860
|
const completedEvent = prdWorkflowFindCompletedIdempotencyEvent(scopedRoot, normalized.tapdId, idem);
|
|
10402
10861
|
if (completedEvent) {
|
|
10403
10862
|
const snapshot = prdWorkflowWithAgentflowTokenDiagnostic(
|
|
10404
|
-
await prdWorkflowSnapshot(
|
|
10863
|
+
await prdWorkflowSnapshot(actionExecutionRoot, scopedRoot, normalized.tapdId, userCtx, { flowSource, flowId }),
|
|
10405
10864
|
getSessionTokenFromRequest(req) || "",
|
|
10406
10865
|
);
|
|
10407
10866
|
const result = {
|
|
@@ -10453,7 +10912,7 @@ export function startUiServer({
|
|
|
10453
10912
|
const expectedRevision = String(payload?.expectedRevision || "").trim();
|
|
10454
10913
|
if (expectedRevision) {
|
|
10455
10914
|
const latestForMarker = prdWorkflowWithAgentflowTokenDiagnostic(
|
|
10456
|
-
await prdWorkflowSnapshot(
|
|
10915
|
+
await prdWorkflowSnapshot(actionExecutionRoot, scopedRoot, normalized.tapdId, userCtx, { flowSource, flowId }),
|
|
10457
10916
|
getSessionTokenFromRequest(req) || "",
|
|
10458
10917
|
);
|
|
10459
10918
|
const latestRevision = String(latestForMarker?.revision || "").trim();
|
|
@@ -10511,7 +10970,7 @@ export function startUiServer({
|
|
|
10511
10970
|
links: markerEvent.links,
|
|
10512
10971
|
});
|
|
10513
10972
|
const snapshot = prdWorkflowWithAgentflowTokenDiagnostic(
|
|
10514
|
-
await prdWorkflowSnapshot(
|
|
10973
|
+
await prdWorkflowSnapshot(actionExecutionRoot, scopedRoot, normalized.tapdId, userCtx, { flowSource, flowId }),
|
|
10515
10974
|
getSessionTokenFromRequest(req) || "",
|
|
10516
10975
|
);
|
|
10517
10976
|
result = {
|
|
@@ -10556,7 +11015,7 @@ export function startUiServer({
|
|
|
10556
11015
|
output,
|
|
10557
11016
|
});
|
|
10558
11017
|
const snapshot = prdWorkflowWithAgentflowTokenDiagnostic(
|
|
10559
|
-
await prdWorkflowSnapshot(
|
|
11018
|
+
await prdWorkflowSnapshot(actionExecutionRoot, scopedRoot, normalized.tapdId, userCtx, { flowSource, flowId }),
|
|
10560
11019
|
getSessionTokenFromRequest(req) || "",
|
|
10561
11020
|
);
|
|
10562
11021
|
result = {
|
|
@@ -10598,7 +11057,7 @@ export function startUiServer({
|
|
|
10598
11057
|
command: output.command,
|
|
10599
11058
|
});
|
|
10600
11059
|
const snapshot = prdWorkflowWithAgentflowTokenDiagnostic(
|
|
10601
|
-
await prdWorkflowSnapshot(
|
|
11060
|
+
await prdWorkflowSnapshot(actionExecutionRoot, scopedRoot, normalized.tapdId, userCtx, { flowSource, flowId }),
|
|
10602
11061
|
getSessionTokenFromRequest(req) || "",
|
|
10603
11062
|
);
|
|
10604
11063
|
result = {
|
|
@@ -10619,7 +11078,7 @@ export function startUiServer({
|
|
|
10619
11078
|
return;
|
|
10620
11079
|
}
|
|
10621
11080
|
const runtimeEventUrl = `${serverPublicBaseUrl(req, host, uiPort)}/api/prd-workflow/event`;
|
|
10622
|
-
const commandResult = await runPrdWorkflowCommand(
|
|
11081
|
+
const commandResult = await runPrdWorkflowCommand(actionExecutionRoot, scopedRoot, normalized.args, userCtx, {
|
|
10623
11082
|
timeout: 300000,
|
|
10624
11083
|
env: {
|
|
10625
11084
|
PRD_FLOW_RUNTIME_EVENT_URL: runtimeEventUrl,
|
|
@@ -10655,7 +11114,7 @@ export function startUiServer({
|
|
|
10655
11114
|
links: Array.isArray(parsed?.links) ? parsed.links : [],
|
|
10656
11115
|
});
|
|
10657
11116
|
const snapshot = prdWorkflowWithAgentflowTokenDiagnostic(
|
|
10658
|
-
await prdWorkflowSnapshot(
|
|
11117
|
+
await prdWorkflowSnapshot(actionExecutionRoot, scopedRoot, normalized.tapdId, userCtx, { flowSource, flowId }),
|
|
10659
11118
|
getSessionTokenFromRequest(req) || "",
|
|
10660
11119
|
);
|
|
10661
11120
|
result = {
|
|
@@ -10711,7 +11170,7 @@ export function startUiServer({
|
|
|
10711
11170
|
if (status === 409 && tapdId) {
|
|
10712
11171
|
try {
|
|
10713
11172
|
latestSnapshot = prdWorkflowWithAgentflowTokenDiagnostic(
|
|
10714
|
-
await prdWorkflowSnapshot(
|
|
11173
|
+
await prdWorkflowSnapshot(actionExecutionRoot, actionScopedRoot, tapdId, userCtx, { flowSource, flowId }),
|
|
10715
11174
|
getSessionTokenFromRequest(req) || "",
|
|
10716
11175
|
);
|
|
10717
11176
|
} catch (_) {}
|
|
@@ -10750,15 +11209,19 @@ export function startUiServer({
|
|
|
10750
11209
|
const flowId = String(url.searchParams.get("flowId") || "").trim();
|
|
10751
11210
|
const flowSource = String(url.searchParams.get("flowSource") || "user").trim() || "user";
|
|
10752
11211
|
const archived = url.searchParams.get("archived") === "1";
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
|
|
10756
|
-
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
11212
|
+
const workflowScope = resolvePrdWorkflowScope(root, {
|
|
11213
|
+
tapdId,
|
|
11214
|
+
flowId,
|
|
11215
|
+
flowSource,
|
|
11216
|
+
archived,
|
|
11217
|
+
workspaceId: url.searchParams.get("workspaceId") || "",
|
|
11218
|
+
}, userCtx);
|
|
11219
|
+
if (workflowScope.error) {
|
|
11220
|
+
json(res, workflowScope.status || 400, { error: workflowScope.error });
|
|
11221
|
+
return;
|
|
10761
11222
|
}
|
|
11223
|
+
const scopedRoot = workflowScope.stateRoot;
|
|
11224
|
+
prdWorkflowMigrateLegacyState(workflowScope.executionRoot, scopedRoot, tapdId);
|
|
10762
11225
|
const event = prdWorkflowFindCompletedIdempotencyEvent(scopedRoot, tapdId, idempotencyKey);
|
|
10763
11226
|
json(res, 200, {
|
|
10764
11227
|
ok: true,
|
|
@@ -10795,15 +11258,19 @@ export function startUiServer({
|
|
|
10795
11258
|
const flowId = String(payload.flowId || "").trim();
|
|
10796
11259
|
const flowSource = String(payload.flowSource || "user").trim() || "user";
|
|
10797
11260
|
const archived = payload.archived === true || payload.flowArchived === true;
|
|
10798
|
-
|
|
10799
|
-
|
|
10800
|
-
|
|
10801
|
-
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
11261
|
+
const workflowScope = resolvePrdWorkflowScope(root, {
|
|
11262
|
+
...payload,
|
|
11263
|
+
tapdId,
|
|
11264
|
+
flowId,
|
|
11265
|
+
flowSource,
|
|
11266
|
+
archived,
|
|
11267
|
+
}, userCtx, "write");
|
|
11268
|
+
if (workflowScope.error) {
|
|
11269
|
+
json(res, workflowScope.status || 400, { error: workflowScope.error });
|
|
11270
|
+
return;
|
|
10806
11271
|
}
|
|
11272
|
+
const scopedRoot = workflowScope.stateRoot;
|
|
11273
|
+
prdWorkflowMigrateLegacyState(workflowScope.executionRoot, scopedRoot, tapdId);
|
|
10807
11274
|
const existing = prdWorkflowFindCompletedIdempotencyEvent(scopedRoot, tapdId, idempotencyKey);
|
|
10808
11275
|
if (existing) {
|
|
10809
11276
|
json(res, 200, { ok: true, found: true, event: existing, result: existing.output || existing.result || null });
|
|
@@ -10854,15 +11321,19 @@ export function startUiServer({
|
|
|
10854
11321
|
const flowId = String(payload.flowId || "").trim();
|
|
10855
11322
|
const flowSource = String(payload.flowSource || "user").trim() || "user";
|
|
10856
11323
|
const archived = payload.archived === true || payload.flowArchived === true;
|
|
10857
|
-
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
10861
|
-
|
|
10862
|
-
|
|
10863
|
-
|
|
10864
|
-
|
|
11324
|
+
const workflowScope = resolvePrdWorkflowScope(root, {
|
|
11325
|
+
...payload,
|
|
11326
|
+
tapdId,
|
|
11327
|
+
flowId,
|
|
11328
|
+
flowSource,
|
|
11329
|
+
archived,
|
|
11330
|
+
}, userCtx, "write");
|
|
11331
|
+
if (workflowScope.error) {
|
|
11332
|
+
json(res, workflowScope.status || 400, { error: workflowScope.error });
|
|
11333
|
+
return;
|
|
10865
11334
|
}
|
|
11335
|
+
const scopedRoot = workflowScope.stateRoot;
|
|
11336
|
+
prdWorkflowMigrateLegacyState(workflowScope.executionRoot, scopedRoot, tapdId);
|
|
10866
11337
|
const eventPayload = payload.event && typeof payload.event === "object" && !Array.isArray(payload.event)
|
|
10867
11338
|
? payload.event
|
|
10868
11339
|
: payload;
|
|
@@ -10870,9 +11341,13 @@ export function startUiServer({
|
|
|
10870
11341
|
...eventPayload,
|
|
10871
11342
|
tapdId,
|
|
10872
11343
|
type: eventPayload.type || "workflow-event",
|
|
11344
|
+
actor: {
|
|
11345
|
+
userId: String(userCtx?.userId || ""),
|
|
11346
|
+
username: String(authUser?.username || userCtx?.userId || ""),
|
|
11347
|
+
},
|
|
10873
11348
|
});
|
|
10874
11349
|
const snapshot = prdWorkflowWithAgentflowTokenDiagnostic(
|
|
10875
|
-
|
|
11350
|
+
prdWorkflowMaterializeSnapshot(workflowScope.executionRoot, scopedRoot, tapdId, userCtx, { flowSource, flowId }),
|
|
10876
11351
|
getSessionTokenFromRequest(req) || "",
|
|
10877
11352
|
);
|
|
10878
11353
|
prdWorkflowBroadcast(prdWorkflowKey(userCtx, flowSource, flowId, tapdId), { type: "runtime-event", tapdId, event, snapshot });
|
|
@@ -10900,21 +11375,21 @@ export function startUiServer({
|
|
|
10900
11375
|
const flowId = String(payload.flowId || "").trim();
|
|
10901
11376
|
const flowSource = String(payload.flowSource || "user").trim() || "user";
|
|
10902
11377
|
const archived = payload.archived === true || payload.flowArchived === true;
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
11378
|
+
const workflowScope = resolvePrdWorkflowScope(root, {
|
|
11379
|
+
...payload,
|
|
11380
|
+
tapdId,
|
|
11381
|
+
flowId,
|
|
11382
|
+
flowSource,
|
|
11383
|
+
archived,
|
|
11384
|
+
}, userCtx, "write");
|
|
11385
|
+
if (workflowScope.error) {
|
|
11386
|
+
json(res, workflowScope.status || 400, { error: workflowScope.error });
|
|
11387
|
+
return;
|
|
10911
11388
|
}
|
|
11389
|
+
const scopedRoot = workflowScope.stateRoot;
|
|
11390
|
+
prdWorkflowMigrateLegacyState(workflowScope.executionRoot, scopedRoot, tapdId);
|
|
10912
11391
|
const review = prdWorkflowCreateReview(scopedRoot, tapdId, payload, serverPublicBaseUrl(req, host, uiPort, payload));
|
|
10913
|
-
const
|
|
10914
|
-
if (flowId) query.set("flowId", flowId);
|
|
10915
|
-
if (flowId && flowSource && flowSource !== "user") query.set("flowSource", flowSource);
|
|
10916
|
-
if (archived) query.set("archived", "1");
|
|
10917
|
-
const reviewUrl = query.toString() ? `${review.url}?${query.toString()}` : review.url;
|
|
11392
|
+
const reviewUrl = review.url;
|
|
10918
11393
|
const durability = review.durability || "temporary";
|
|
10919
11394
|
const reviewSource = review.source && typeof review.source === "object" && !Array.isArray(review.source)
|
|
10920
11395
|
? review.source
|
|
@@ -10949,7 +11424,7 @@ export function startUiServer({
|
|
|
10949
11424
|
reviewId: review.id,
|
|
10950
11425
|
});
|
|
10951
11426
|
const snapshot = prdWorkflowWithAgentflowTokenDiagnostic(
|
|
10952
|
-
await prdWorkflowSnapshot(
|
|
11427
|
+
await prdWorkflowSnapshot(workflowScope.executionRoot, scopedRoot, tapdId, userCtx, { flowSource, flowId }),
|
|
10953
11428
|
getSessionTokenFromRequest(req) || "",
|
|
10954
11429
|
);
|
|
10955
11430
|
prdWorkflowBroadcast(prdWorkflowKey(userCtx, flowSource, flowId, tapdId), { type: "review-link", tapdId, event, snapshot });
|
|
@@ -11002,16 +11477,20 @@ export function startUiServer({
|
|
|
11002
11477
|
const flowId = String(url.searchParams.get("flowId") || "").trim();
|
|
11003
11478
|
const flowSource = String(url.searchParams.get("flowSource") || "user").trim() || "user";
|
|
11004
11479
|
const archived = url.searchParams.get("archived") === "1";
|
|
11005
|
-
|
|
11006
|
-
|
|
11007
|
-
|
|
11008
|
-
|
|
11009
|
-
|
|
11010
|
-
|
|
11011
|
-
|
|
11012
|
-
|
|
11013
|
-
|
|
11480
|
+
const workflowScope = resolvePrdWorkflowScope(root, {
|
|
11481
|
+
tapdId,
|
|
11482
|
+
flowId,
|
|
11483
|
+
flowSource,
|
|
11484
|
+
archived,
|
|
11485
|
+
workspaceId: url.searchParams.get("workspaceId") || "",
|
|
11486
|
+
}, userCtx);
|
|
11487
|
+
if (workflowScope.error) {
|
|
11488
|
+
res.writeHead(workflowScope.status || 400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
11489
|
+
res.end(workflowScope.error);
|
|
11490
|
+
return;
|
|
11014
11491
|
}
|
|
11492
|
+
const scopedRoot = workflowScope.stateRoot;
|
|
11493
|
+
prdWorkflowMigrateLegacyState(workflowScope.executionRoot, scopedRoot, tapdId);
|
|
11015
11494
|
const paths = prdWorkflowReviewPaths(scopedRoot, tapdId, reviewId);
|
|
11016
11495
|
if (!fs.existsSync(paths.markdownPath) || !fs.statSync(paths.markdownPath).isFile()) {
|
|
11017
11496
|
res.writeHead(404);
|