@tiangong-lca/cli 0.0.2 → 0.0.4
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/README.md +131 -309
- package/dist/src/cli.js +158 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/lib/dataset-command.js +122 -0
- package/dist/src/lib/dataset-command.js.map +1 -0
- package/dist/src/lib/flow-fetch-rows.js +235 -0
- package/dist/src/lib/flow-fetch-rows.js.map +1 -0
- package/dist/src/lib/flow-materialize-decisions.js +421 -0
- package/dist/src/lib/flow-materialize-decisions.js.map +1 -0
- package/dist/src/lib/flow-publish-version.js +23 -19
- package/dist/src/lib/flow-publish-version.js.map +1 -1
- package/dist/src/lib/remote.js +2 -2
- package/dist/src/lib/remote.js.map +1 -1
- package/dist/src/lib/supabase-client.js +5 -2
- package/dist/src/lib/supabase-client.js.map +1 -1
- package/dist/src/lib/supabase-json-ordered-write.js +42 -21
- package/dist/src/lib/supabase-json-ordered-write.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { writeJsonArtifact } from './artifacts.js';
|
|
4
|
+
import { CliError } from './errors.js';
|
|
5
|
+
import { extractFlowRecord, loadRowsFromFile, } from './flow-governance.js';
|
|
6
|
+
function normalizeToken(value) {
|
|
7
|
+
if (value === undefined || value === null) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
const trimmed = String(value).trim();
|
|
11
|
+
return trimmed ? trimmed : null;
|
|
12
|
+
}
|
|
13
|
+
function assertInputFile(inputFile, requiredCode, missingCode) {
|
|
14
|
+
const normalized = normalizeToken(inputFile);
|
|
15
|
+
if (!normalized) {
|
|
16
|
+
throw new CliError('Missing required input file value.', {
|
|
17
|
+
code: requiredCode,
|
|
18
|
+
exitCode: 2,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
const resolved = path.resolve(normalized);
|
|
22
|
+
if (!existsSync(resolved)) {
|
|
23
|
+
throw new CliError(`Input file not found: ${resolved}`, {
|
|
24
|
+
code: missingCode,
|
|
25
|
+
exitCode: 2,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return resolved;
|
|
29
|
+
}
|
|
30
|
+
function assertOutDir(outDir) {
|
|
31
|
+
const normalized = normalizeToken(outDir);
|
|
32
|
+
if (!normalized) {
|
|
33
|
+
throw new CliError('Missing required --out-dir value.', {
|
|
34
|
+
code: 'FLOW_MATERIALIZE_DECISIONS_OUT_DIR_REQUIRED',
|
|
35
|
+
exitCode: 2,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return path.resolve(normalized);
|
|
39
|
+
}
|
|
40
|
+
function parseFlowRefString(value, code) {
|
|
41
|
+
const trimmed = value.trim();
|
|
42
|
+
const [id, version, rest] = trimmed.split('@');
|
|
43
|
+
if (!id || !version || rest !== undefined) {
|
|
44
|
+
throw new CliError(`Expected flow ref to use id@version format, received: ${value}`, {
|
|
45
|
+
code,
|
|
46
|
+
exitCode: 2,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
id,
|
|
51
|
+
version,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function parseFlowRefLike(value, code) {
|
|
55
|
+
if (typeof value === 'string') {
|
|
56
|
+
return parseFlowRefString(value, code);
|
|
57
|
+
}
|
|
58
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
59
|
+
const record = value;
|
|
60
|
+
const id = normalizeToken(record.id);
|
|
61
|
+
const version = normalizeToken(record.version);
|
|
62
|
+
if (!id || !version) {
|
|
63
|
+
throw new CliError('Expected flow ref objects to contain id and version.', {
|
|
64
|
+
code,
|
|
65
|
+
exitCode: 2,
|
|
66
|
+
details: value,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
id,
|
|
71
|
+
version,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (value === undefined || value === null) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
throw new CliError('Expected flow ref values to be id@version strings or { id, version } objects.', {
|
|
78
|
+
code,
|
|
79
|
+
exitCode: 2,
|
|
80
|
+
details: value,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function parseFlowRefArray(row, keys, code) {
|
|
84
|
+
const refs = [];
|
|
85
|
+
keys.forEach((key) => {
|
|
86
|
+
const value = row[key];
|
|
87
|
+
if (!Array.isArray(value)) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
value.forEach((item) => {
|
|
91
|
+
const ref = parseFlowRefLike(item, code);
|
|
92
|
+
if (ref) {
|
|
93
|
+
refs.push(ref);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
return refs;
|
|
98
|
+
}
|
|
99
|
+
function uniqueFlowRefs(refs) {
|
|
100
|
+
const seen = new Set();
|
|
101
|
+
const unique = [];
|
|
102
|
+
refs.forEach((ref) => {
|
|
103
|
+
const key = `${ref.id}@${ref.version}`;
|
|
104
|
+
if (seen.has(key)) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
seen.add(key);
|
|
108
|
+
unique.push(ref);
|
|
109
|
+
});
|
|
110
|
+
return unique;
|
|
111
|
+
}
|
|
112
|
+
function parseDecisionRow(row, index) {
|
|
113
|
+
const clusterId = normalizeToken(row.cluster_id ?? row.clusterId);
|
|
114
|
+
if (!clusterId) {
|
|
115
|
+
throw new CliError(`Decision row ${index + 1} is missing cluster_id.`, {
|
|
116
|
+
code: 'FLOW_MATERIALIZE_DECISIONS_CLUSTER_ID_REQUIRED',
|
|
117
|
+
exitCode: 2,
|
|
118
|
+
details: row,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
const rawDecision = normalizeToken(row.decision ?? row.approved_decision ?? row.outcome);
|
|
122
|
+
if (rawDecision !== 'merge_keep_one' &&
|
|
123
|
+
rawDecision !== 'keep_distinct' &&
|
|
124
|
+
rawDecision !== 'blocked_missing_db_flow') {
|
|
125
|
+
throw new CliError(`Decision row ${clusterId} must use one of merge_keep_one, keep_distinct, or blocked_missing_db_flow.`, {
|
|
126
|
+
code: 'FLOW_MATERIALIZE_DECISIONS_INVALID_DECISION',
|
|
127
|
+
exitCode: 2,
|
|
128
|
+
details: row,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const canonicalRef = parseFlowRefLike(row.canonical_flow ??
|
|
132
|
+
row.canonical_ref ??
|
|
133
|
+
row.keep ??
|
|
134
|
+
row.keep_ref ??
|
|
135
|
+
row.keep_flow ??
|
|
136
|
+
row.canonical_flow_key, 'FLOW_MATERIALIZE_DECISIONS_INVALID_CANONICAL_REF');
|
|
137
|
+
const memberRefs = uniqueFlowRefs([
|
|
138
|
+
...parseFlowRefArray(row, [
|
|
139
|
+
'flow_refs',
|
|
140
|
+
'cluster_members',
|
|
141
|
+
'members',
|
|
142
|
+
'flows',
|
|
143
|
+
'flow_keys',
|
|
144
|
+
'member_keys',
|
|
145
|
+
'drop_refs',
|
|
146
|
+
'drops',
|
|
147
|
+
'rewrite_sources',
|
|
148
|
+
], 'FLOW_MATERIALIZE_DECISIONS_INVALID_MEMBER_REF'),
|
|
149
|
+
...(canonicalRef ? [canonicalRef] : []),
|
|
150
|
+
]);
|
|
151
|
+
if (rawDecision === 'merge_keep_one' && !canonicalRef) {
|
|
152
|
+
throw new CliError(`Decision row ${clusterId} is missing canonical flow information.`, {
|
|
153
|
+
code: 'FLOW_MATERIALIZE_DECISIONS_CANONICAL_REQUIRED',
|
|
154
|
+
exitCode: 2,
|
|
155
|
+
details: row,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (rawDecision === 'merge_keep_one' && memberRefs.length < 2) {
|
|
159
|
+
throw new CliError(`Decision row ${clusterId} needs at least two cluster members for merge_keep_one.`, {
|
|
160
|
+
code: 'FLOW_MATERIALIZE_DECISIONS_MEMBERS_REQUIRED',
|
|
161
|
+
exitCode: 2,
|
|
162
|
+
details: row,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
clusterId,
|
|
167
|
+
decision: rawDecision,
|
|
168
|
+
reason: normalizeToken(row.reason ?? row.notes ?? row.message),
|
|
169
|
+
canonicalRef,
|
|
170
|
+
memberRefs,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function buildFlowIndex(rows) {
|
|
174
|
+
const index = new Map();
|
|
175
|
+
rows.forEach((row, rowIndex) => {
|
|
176
|
+
const record = extractFlowRecord(row);
|
|
177
|
+
const key = `${record.id}@${record.version}`;
|
|
178
|
+
if (index.has(key)) {
|
|
179
|
+
throw new CliError(`Duplicate flow row detected for ${key}.`, {
|
|
180
|
+
code: 'FLOW_MATERIALIZE_DECISIONS_DUPLICATE_FLOW_ROW',
|
|
181
|
+
exitCode: 2,
|
|
182
|
+
details: {
|
|
183
|
+
flow_key: key,
|
|
184
|
+
first_index: [...index.keys()].indexOf(key),
|
|
185
|
+
duplicate_index: rowIndex,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
index.set(key, {
|
|
190
|
+
key,
|
|
191
|
+
row,
|
|
192
|
+
record,
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
return index;
|
|
196
|
+
}
|
|
197
|
+
function summarizeFlow(record) {
|
|
198
|
+
return {
|
|
199
|
+
id: record.id,
|
|
200
|
+
version: record.version,
|
|
201
|
+
name: record.name,
|
|
202
|
+
flow_type: record.flowType,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function buildOutputFiles(outDir) {
|
|
206
|
+
return {
|
|
207
|
+
canonical_map: path.join(outDir, 'flow-dedup-canonical-map.json'),
|
|
208
|
+
rewrite_plan: path.join(outDir, 'flow-dedup-rewrite-plan.json'),
|
|
209
|
+
semantic_merge_seed: path.join(outDir, 'manual-semantic-merge-seed.current.json'),
|
|
210
|
+
summary: path.join(outDir, 'decision-summary.json'),
|
|
211
|
+
blocked_clusters: path.join(outDir, 'blocked-clusters.json'),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function incrementCount(record, key) {
|
|
215
|
+
record[key] = (record[key] ?? 0) + 1;
|
|
216
|
+
}
|
|
217
|
+
function sortedObject(entries) {
|
|
218
|
+
return Object.fromEntries(entries.sort(([left], [right]) => left.localeCompare(right)));
|
|
219
|
+
}
|
|
220
|
+
export async function runFlowMaterializeDecisions(options) {
|
|
221
|
+
const decisionFile = assertInputFile(options.decisionFile, 'FLOW_MATERIALIZE_DECISIONS_DECISION_FILE_REQUIRED', 'FLOW_MATERIALIZE_DECISIONS_DECISION_FILE_NOT_FOUND');
|
|
222
|
+
const flowRowsFile = assertInputFile(options.flowRowsFile, 'FLOW_MATERIALIZE_DECISIONS_FLOW_ROWS_FILE_REQUIRED', 'FLOW_MATERIALIZE_DECISIONS_FLOW_ROWS_FILE_NOT_FOUND');
|
|
223
|
+
const outDir = assertOutDir(options.outDir);
|
|
224
|
+
const generatedAt = (options.now ?? new Date()).toISOString();
|
|
225
|
+
const files = buildOutputFiles(outDir);
|
|
226
|
+
const decisions = loadRowsFromFile(decisionFile).map((row, index) => parseDecisionRow(row, index));
|
|
227
|
+
const flowIndex = buildFlowIndex(loadRowsFromFile(flowRowsFile));
|
|
228
|
+
const canonicalClusters = [];
|
|
229
|
+
const canonicalMapEntries = [];
|
|
230
|
+
const rewriteActions = [];
|
|
231
|
+
const seedAliasEntries = [];
|
|
232
|
+
const blockedClusters = [];
|
|
233
|
+
const decisionCounts = {
|
|
234
|
+
merge_keep_one: 0,
|
|
235
|
+
keep_distinct: 0,
|
|
236
|
+
blocked_missing_db_flow: 0,
|
|
237
|
+
};
|
|
238
|
+
const blockedReasonCounts = {};
|
|
239
|
+
decisions.forEach((decision) => {
|
|
240
|
+
decisionCounts[decision.decision] += 1;
|
|
241
|
+
if (decision.decision === 'keep_distinct') {
|
|
242
|
+
blockedClusters.push({
|
|
243
|
+
cluster_id: decision.clusterId,
|
|
244
|
+
decision: decision.decision,
|
|
245
|
+
blocker_code: 'decision_keep_distinct',
|
|
246
|
+
reason: decision.reason,
|
|
247
|
+
canonical_flow: decision.canonicalRef,
|
|
248
|
+
cluster_members: decision.memberRefs,
|
|
249
|
+
missing_flow_keys: [],
|
|
250
|
+
});
|
|
251
|
+
incrementCount(blockedReasonCounts, 'decision_keep_distinct');
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (decision.decision === 'blocked_missing_db_flow') {
|
|
255
|
+
blockedClusters.push({
|
|
256
|
+
cluster_id: decision.clusterId,
|
|
257
|
+
decision: decision.decision,
|
|
258
|
+
blocker_code: 'blocked_missing_db_flow',
|
|
259
|
+
reason: decision.reason,
|
|
260
|
+
canonical_flow: decision.canonicalRef,
|
|
261
|
+
cluster_members: decision.memberRefs,
|
|
262
|
+
missing_flow_keys: [],
|
|
263
|
+
});
|
|
264
|
+
incrementCount(blockedReasonCounts, 'blocked_missing_db_flow');
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const canonicalRef = decision.canonicalRef;
|
|
268
|
+
const canonicalKey = `${canonicalRef.id}@${canonicalRef.version}`;
|
|
269
|
+
const missingFlowKeys = decision.memberRefs
|
|
270
|
+
.map((ref) => `${ref.id}@${ref.version}`)
|
|
271
|
+
.filter((key) => !flowIndex.has(key));
|
|
272
|
+
if (!flowIndex.has(canonicalKey)) {
|
|
273
|
+
blockedClusters.push({
|
|
274
|
+
cluster_id: decision.clusterId,
|
|
275
|
+
decision: decision.decision,
|
|
276
|
+
blocker_code: 'merge_canonical_flow_missing',
|
|
277
|
+
reason: decision.reason,
|
|
278
|
+
canonical_flow: canonicalRef,
|
|
279
|
+
cluster_members: decision.memberRefs,
|
|
280
|
+
missing_flow_keys: [...new Set([canonicalKey, ...missingFlowKeys])],
|
|
281
|
+
});
|
|
282
|
+
incrementCount(blockedReasonCounts, 'merge_canonical_flow_missing');
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (missingFlowKeys.length > 0) {
|
|
286
|
+
blockedClusters.push({
|
|
287
|
+
cluster_id: decision.clusterId,
|
|
288
|
+
decision: decision.decision,
|
|
289
|
+
blocker_code: 'flow_row_missing',
|
|
290
|
+
reason: decision.reason,
|
|
291
|
+
canonical_flow: canonicalRef,
|
|
292
|
+
cluster_members: decision.memberRefs,
|
|
293
|
+
missing_flow_keys: [...new Set(missingFlowKeys)].sort(),
|
|
294
|
+
});
|
|
295
|
+
incrementCount(blockedReasonCounts, 'flow_row_missing');
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const canonicalFlow = flowIndex.get(canonicalKey);
|
|
299
|
+
const mergeReason = decision.reason ?? 'approved_merge_keep_one';
|
|
300
|
+
const mergedFlows = decision.memberRefs
|
|
301
|
+
.map((ref) => flowIndex.get(`${ref.id}@${ref.version}`))
|
|
302
|
+
.sort((left, right) => left.key.localeCompare(right.key))
|
|
303
|
+
.map((entry) => ({
|
|
304
|
+
...summarizeFlow(entry.record),
|
|
305
|
+
relation: entry.key === canonicalKey
|
|
306
|
+
? 'canonical_self'
|
|
307
|
+
: 'rewrite_to_canonical',
|
|
308
|
+
}));
|
|
309
|
+
canonicalClusters.push({
|
|
310
|
+
cluster_id: decision.clusterId,
|
|
311
|
+
decision: 'merge_keep_one',
|
|
312
|
+
reason: decision.reason,
|
|
313
|
+
canonical_flow: summarizeFlow(canonicalFlow.record),
|
|
314
|
+
merged_flows: mergedFlows,
|
|
315
|
+
});
|
|
316
|
+
mergedFlows.forEach((flow) => {
|
|
317
|
+
canonicalMapEntries.push([
|
|
318
|
+
`${flow.id}@${flow.version}`,
|
|
319
|
+
{
|
|
320
|
+
id: canonicalFlow.record.id,
|
|
321
|
+
version: canonicalFlow.record.version,
|
|
322
|
+
cluster_id: decision.clusterId,
|
|
323
|
+
relation: flow.relation,
|
|
324
|
+
reason: mergeReason,
|
|
325
|
+
},
|
|
326
|
+
]);
|
|
327
|
+
if (flow.relation === 'rewrite_to_canonical') {
|
|
328
|
+
rewriteActions.push({
|
|
329
|
+
cluster_id: decision.clusterId,
|
|
330
|
+
action: 'rewrite_to_canonical',
|
|
331
|
+
reason: mergeReason,
|
|
332
|
+
source_flow_id: flow.id,
|
|
333
|
+
source_flow_version: flow.version,
|
|
334
|
+
source_flow_name: flow.name,
|
|
335
|
+
source_flow_type: flow.flow_type,
|
|
336
|
+
target_flow_id: canonicalFlow.record.id,
|
|
337
|
+
target_flow_version: canonicalFlow.record.version,
|
|
338
|
+
target_flow_name: canonicalFlow.record.name,
|
|
339
|
+
target_flow_type: canonicalFlow.record.flowType,
|
|
340
|
+
});
|
|
341
|
+
seedAliasEntries.push([
|
|
342
|
+
`${flow.id}@${flow.version}`,
|
|
343
|
+
{
|
|
344
|
+
id: canonicalFlow.record.id,
|
|
345
|
+
version: canonicalFlow.record.version,
|
|
346
|
+
cluster_id: decision.clusterId,
|
|
347
|
+
relation: 'rewrite_to_canonical',
|
|
348
|
+
reason: mergeReason,
|
|
349
|
+
},
|
|
350
|
+
]);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
const canonicalMapByFlowKey = sortedObject(canonicalMapEntries);
|
|
355
|
+
const semanticMergeSeed = sortedObject(seedAliasEntries.map(([key, value]) => [
|
|
356
|
+
key,
|
|
357
|
+
{
|
|
358
|
+
id: value.id,
|
|
359
|
+
version: value.version,
|
|
360
|
+
reason: value.reason,
|
|
361
|
+
cluster_id: value.cluster_id,
|
|
362
|
+
},
|
|
363
|
+
]));
|
|
364
|
+
const report = {
|
|
365
|
+
schema_version: 1,
|
|
366
|
+
generated_at_utc: generatedAt,
|
|
367
|
+
status: blockedClusters.length > 0
|
|
368
|
+
? 'completed_local_flow_decision_materialization_with_blocked_clusters'
|
|
369
|
+
: 'completed_local_flow_decision_materialization',
|
|
370
|
+
decision_file: decisionFile,
|
|
371
|
+
flow_rows_file: flowRowsFile,
|
|
372
|
+
out_dir: outDir,
|
|
373
|
+
counts: {
|
|
374
|
+
input_decisions: decisions.length,
|
|
375
|
+
materialized_clusters: canonicalClusters.length,
|
|
376
|
+
blocked_clusters: blockedClusters.length,
|
|
377
|
+
canonical_map_entries: Object.keys(canonicalMapByFlowKey).length,
|
|
378
|
+
rewrite_actions: rewriteActions.length,
|
|
379
|
+
seed_alias_entries: Object.keys(semanticMergeSeed).length,
|
|
380
|
+
decision_counts: decisionCounts,
|
|
381
|
+
blocked_reason_counts: blockedReasonCounts,
|
|
382
|
+
},
|
|
383
|
+
files,
|
|
384
|
+
};
|
|
385
|
+
writeJsonArtifact(files.canonical_map, {
|
|
386
|
+
schema_version: 1,
|
|
387
|
+
generated_at_utc: generatedAt,
|
|
388
|
+
clusters: canonicalClusters.sort((left, right) => left.cluster_id.localeCompare(right.cluster_id)),
|
|
389
|
+
by_flow_key: canonicalMapByFlowKey,
|
|
390
|
+
});
|
|
391
|
+
writeJsonArtifact(files.rewrite_plan, {
|
|
392
|
+
schema_version: 1,
|
|
393
|
+
generated_at_utc: generatedAt,
|
|
394
|
+
actions: rewriteActions.sort((left, right) => {
|
|
395
|
+
const clusterOrder = left.cluster_id.localeCompare(right.cluster_id);
|
|
396
|
+
if (clusterOrder !== 0) {
|
|
397
|
+
return clusterOrder;
|
|
398
|
+
}
|
|
399
|
+
const leftKey = `${left.source_flow_id}@${left.source_flow_version}`;
|
|
400
|
+
const rightKey = `${right.source_flow_id}@${right.source_flow_version}`;
|
|
401
|
+
return leftKey.localeCompare(rightKey);
|
|
402
|
+
}),
|
|
403
|
+
});
|
|
404
|
+
writeJsonArtifact(files.semantic_merge_seed, semanticMergeSeed);
|
|
405
|
+
writeJsonArtifact(files.blocked_clusters, {
|
|
406
|
+
schema_version: 1,
|
|
407
|
+
generated_at_utc: generatedAt,
|
|
408
|
+
clusters: blockedClusters.sort((left, right) => left.cluster_id.localeCompare(right.cluster_id)),
|
|
409
|
+
});
|
|
410
|
+
writeJsonArtifact(files.summary, report);
|
|
411
|
+
return report;
|
|
412
|
+
}
|
|
413
|
+
export const __testInternals = {
|
|
414
|
+
parseDecisionRow,
|
|
415
|
+
parseFlowRefLike,
|
|
416
|
+
parseFlowRefString,
|
|
417
|
+
uniqueFlowRefs,
|
|
418
|
+
buildFlowIndex,
|
|
419
|
+
buildOutputFiles,
|
|
420
|
+
};
|
|
421
|
+
//# sourceMappingURL=flow-materialize-decisions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-materialize-decisions.js","sourceRoot":"","sources":["../../../src/lib/flow-materialize-decisions.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport { writeJsonArtifact } from './artifacts.js';\nimport { CliError } from './errors.js';\nimport {\n extractFlowRecord,\n loadRowsFromFile,\n type FlowRecord,\n type JsonRecord,\n} from './flow-governance.js';\n\ntype FlowRef = {\n id: string;\n version: string;\n};\n\ntype SupportedDecision = 'merge_keep_one' | 'keep_distinct' | 'blocked_missing_db_flow';\n\ntype NormalizedDecision = {\n clusterId: string;\n decision: SupportedDecision;\n reason: string | null;\n canonicalRef: FlowRef | null;\n memberRefs: FlowRef[];\n};\n\ntype IndexedFlowRow = {\n key: string;\n row: JsonRecord;\n record: FlowRecord;\n};\n\ntype CanonicalFlowSummary = {\n id: string;\n version: string;\n name: string;\n flow_type: string;\n};\n\ntype CanonicalMapCluster = {\n cluster_id: string;\n decision: 'merge_keep_one';\n reason: string | null;\n canonical_flow: CanonicalFlowSummary;\n merged_flows: Array<\n CanonicalFlowSummary & {\n relation: 'canonical_self' | 'rewrite_to_canonical';\n }\n >;\n};\n\ntype CanonicalMapEntry = {\n id: string;\n version: string;\n cluster_id: string;\n relation: 'canonical_self' | 'rewrite_to_canonical';\n reason: string;\n};\n\ntype RewritePlanAction = {\n cluster_id: string;\n action: 'rewrite_to_canonical';\n reason: string;\n source_flow_id: string;\n source_flow_version: string;\n source_flow_name: string;\n source_flow_type: string;\n target_flow_id: string;\n target_flow_version: string;\n target_flow_name: string;\n target_flow_type: string;\n};\n\ntype BlockedCluster = {\n cluster_id: string;\n decision: SupportedDecision;\n blocker_code:\n | 'decision_keep_distinct'\n | 'blocked_missing_db_flow'\n | 'merge_canonical_flow_missing'\n | 'flow_row_missing';\n reason: string | null;\n canonical_flow: FlowRef | null;\n cluster_members: FlowRef[];\n missing_flow_keys: string[];\n};\n\ntype FlowMaterializeDecisionsFiles = {\n canonical_map: string;\n rewrite_plan: string;\n semantic_merge_seed: string;\n summary: string;\n blocked_clusters: string;\n};\n\ntype FlowMaterializeDecisionCounts = {\n input_decisions: number;\n materialized_clusters: number;\n blocked_clusters: number;\n canonical_map_entries: number;\n rewrite_actions: number;\n seed_alias_entries: number;\n decision_counts: Record<SupportedDecision, number>;\n blocked_reason_counts: Record<string, number>;\n};\n\nexport type FlowMaterializeDecisionsReport = {\n schema_version: 1;\n generated_at_utc: string;\n status:\n | 'completed_local_flow_decision_materialization'\n | 'completed_local_flow_decision_materialization_with_blocked_clusters';\n decision_file: string;\n flow_rows_file: string;\n out_dir: string;\n counts: FlowMaterializeDecisionCounts;\n files: FlowMaterializeDecisionsFiles;\n};\n\nexport type RunFlowMaterializeDecisionsOptions = {\n decisionFile: string;\n flowRowsFile: string;\n outDir: string;\n now?: Date;\n};\n\nfunction normalizeToken(value: unknown): string | null {\n if (value === undefined || value === null) {\n return null;\n }\n\n const trimmed = String(value).trim();\n return trimmed ? trimmed : null;\n}\n\nfunction assertInputFile(inputFile: string, requiredCode: string, missingCode: string): string {\n const normalized = normalizeToken(inputFile);\n if (!normalized) {\n throw new CliError('Missing required input file value.', {\n code: requiredCode,\n exitCode: 2,\n });\n }\n\n const resolved = path.resolve(normalized);\n if (!existsSync(resolved)) {\n throw new CliError(`Input file not found: ${resolved}`, {\n code: missingCode,\n exitCode: 2,\n });\n }\n\n return resolved;\n}\n\nfunction assertOutDir(outDir: string): string {\n const normalized = normalizeToken(outDir);\n if (!normalized) {\n throw new CliError('Missing required --out-dir value.', {\n code: 'FLOW_MATERIALIZE_DECISIONS_OUT_DIR_REQUIRED',\n exitCode: 2,\n });\n }\n\n return path.resolve(normalized);\n}\n\nfunction parseFlowRefString(value: string, code: string): FlowRef {\n const trimmed = value.trim();\n const [id, version, rest] = trimmed.split('@');\n if (!id || !version || rest !== undefined) {\n throw new CliError(`Expected flow ref to use id@version format, received: ${value}`, {\n code,\n exitCode: 2,\n });\n }\n\n return {\n id,\n version,\n };\n}\n\nfunction parseFlowRefLike(value: unknown, code: string): FlowRef | null {\n if (typeof value === 'string') {\n return parseFlowRefString(value, code);\n }\n\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n const record = value as JsonRecord;\n const id = normalizeToken(record.id);\n const version = normalizeToken(record.version);\n if (!id || !version) {\n throw new CliError('Expected flow ref objects to contain id and version.', {\n code,\n exitCode: 2,\n details: value,\n });\n }\n return {\n id,\n version,\n };\n }\n\n if (value === undefined || value === null) {\n return null;\n }\n\n throw new CliError(\n 'Expected flow ref values to be id@version strings or { id, version } objects.',\n {\n code,\n exitCode: 2,\n details: value,\n },\n );\n}\n\nfunction parseFlowRefArray(row: JsonRecord, keys: string[], code: string): FlowRef[] {\n const refs: FlowRef[] = [];\n keys.forEach((key) => {\n const value = row[key];\n if (!Array.isArray(value)) {\n return;\n }\n value.forEach((item) => {\n const ref = parseFlowRefLike(item, code);\n if (ref) {\n refs.push(ref);\n }\n });\n });\n return refs;\n}\n\nfunction uniqueFlowRefs(refs: FlowRef[]): FlowRef[] {\n const seen = new Set<string>();\n const unique: FlowRef[] = [];\n refs.forEach((ref) => {\n const key = `${ref.id}@${ref.version}`;\n if (seen.has(key)) {\n return;\n }\n seen.add(key);\n unique.push(ref);\n });\n return unique;\n}\n\nfunction parseDecisionRow(row: JsonRecord, index: number): NormalizedDecision {\n const clusterId = normalizeToken(row.cluster_id ?? row.clusterId);\n if (!clusterId) {\n throw new CliError(`Decision row ${index + 1} is missing cluster_id.`, {\n code: 'FLOW_MATERIALIZE_DECISIONS_CLUSTER_ID_REQUIRED',\n exitCode: 2,\n details: row,\n });\n }\n\n const rawDecision = normalizeToken(row.decision ?? row.approved_decision ?? row.outcome);\n if (\n rawDecision !== 'merge_keep_one' &&\n rawDecision !== 'keep_distinct' &&\n rawDecision !== 'blocked_missing_db_flow'\n ) {\n throw new CliError(\n `Decision row ${clusterId} must use one of merge_keep_one, keep_distinct, or blocked_missing_db_flow.`,\n {\n code: 'FLOW_MATERIALIZE_DECISIONS_INVALID_DECISION',\n exitCode: 2,\n details: row,\n },\n );\n }\n\n const canonicalRef = parseFlowRefLike(\n row.canonical_flow ??\n row.canonical_ref ??\n row.keep ??\n row.keep_ref ??\n row.keep_flow ??\n row.canonical_flow_key,\n 'FLOW_MATERIALIZE_DECISIONS_INVALID_CANONICAL_REF',\n );\n const memberRefs = uniqueFlowRefs([\n ...parseFlowRefArray(\n row,\n [\n 'flow_refs',\n 'cluster_members',\n 'members',\n 'flows',\n 'flow_keys',\n 'member_keys',\n 'drop_refs',\n 'drops',\n 'rewrite_sources',\n ],\n 'FLOW_MATERIALIZE_DECISIONS_INVALID_MEMBER_REF',\n ),\n ...(canonicalRef ? [canonicalRef] : []),\n ]);\n\n if (rawDecision === 'merge_keep_one' && !canonicalRef) {\n throw new CliError(`Decision row ${clusterId} is missing canonical flow information.`, {\n code: 'FLOW_MATERIALIZE_DECISIONS_CANONICAL_REQUIRED',\n exitCode: 2,\n details: row,\n });\n }\n\n if (rawDecision === 'merge_keep_one' && memberRefs.length < 2) {\n throw new CliError(\n `Decision row ${clusterId} needs at least two cluster members for merge_keep_one.`,\n {\n code: 'FLOW_MATERIALIZE_DECISIONS_MEMBERS_REQUIRED',\n exitCode: 2,\n details: row,\n },\n );\n }\n\n return {\n clusterId,\n decision: rawDecision,\n reason: normalizeToken(row.reason ?? row.notes ?? row.message),\n canonicalRef,\n memberRefs,\n };\n}\n\nfunction buildFlowIndex(rows: JsonRecord[]): Map<string, IndexedFlowRow> {\n const index = new Map<string, IndexedFlowRow>();\n rows.forEach((row, rowIndex) => {\n const record = extractFlowRecord(row);\n const key = `${record.id}@${record.version}`;\n if (index.has(key)) {\n throw new CliError(`Duplicate flow row detected for ${key}.`, {\n code: 'FLOW_MATERIALIZE_DECISIONS_DUPLICATE_FLOW_ROW',\n exitCode: 2,\n details: {\n flow_key: key,\n first_index: [...index.keys()].indexOf(key),\n duplicate_index: rowIndex,\n },\n });\n }\n index.set(key, {\n key,\n row,\n record,\n });\n });\n return index;\n}\n\nfunction summarizeFlow(record: FlowRecord): CanonicalFlowSummary {\n return {\n id: record.id,\n version: record.version,\n name: record.name,\n flow_type: record.flowType,\n };\n}\n\nfunction buildOutputFiles(outDir: string): FlowMaterializeDecisionsFiles {\n return {\n canonical_map: path.join(outDir, 'flow-dedup-canonical-map.json'),\n rewrite_plan: path.join(outDir, 'flow-dedup-rewrite-plan.json'),\n semantic_merge_seed: path.join(outDir, 'manual-semantic-merge-seed.current.json'),\n summary: path.join(outDir, 'decision-summary.json'),\n blocked_clusters: path.join(outDir, 'blocked-clusters.json'),\n };\n}\n\nfunction incrementCount(record: Record<string, number>, key: string): void {\n record[key] = (record[key] ?? 0) + 1;\n}\n\nfunction sortedObject<T>(entries: Array<[string, T]>): Record<string, T> {\n return Object.fromEntries(entries.sort(([left], [right]) => left.localeCompare(right)));\n}\n\nexport async function runFlowMaterializeDecisions(\n options: RunFlowMaterializeDecisionsOptions,\n): Promise<FlowMaterializeDecisionsReport> {\n const decisionFile = assertInputFile(\n options.decisionFile,\n 'FLOW_MATERIALIZE_DECISIONS_DECISION_FILE_REQUIRED',\n 'FLOW_MATERIALIZE_DECISIONS_DECISION_FILE_NOT_FOUND',\n );\n const flowRowsFile = assertInputFile(\n options.flowRowsFile,\n 'FLOW_MATERIALIZE_DECISIONS_FLOW_ROWS_FILE_REQUIRED',\n 'FLOW_MATERIALIZE_DECISIONS_FLOW_ROWS_FILE_NOT_FOUND',\n );\n const outDir = assertOutDir(options.outDir);\n const generatedAt = (options.now ?? new Date()).toISOString();\n const files = buildOutputFiles(outDir);\n\n const decisions = loadRowsFromFile(decisionFile).map((row, index) =>\n parseDecisionRow(row, index),\n );\n const flowIndex = buildFlowIndex(loadRowsFromFile(flowRowsFile));\n\n const canonicalClusters: CanonicalMapCluster[] = [];\n const canonicalMapEntries: Array<[string, CanonicalMapEntry]> = [];\n const rewriteActions: RewritePlanAction[] = [];\n const seedAliasEntries: Array<[string, CanonicalMapEntry]> = [];\n const blockedClusters: BlockedCluster[] = [];\n const decisionCounts: FlowMaterializeDecisionCounts['decision_counts'] = {\n merge_keep_one: 0,\n keep_distinct: 0,\n blocked_missing_db_flow: 0,\n };\n const blockedReasonCounts: Record<string, number> = {};\n\n decisions.forEach((decision) => {\n decisionCounts[decision.decision] += 1;\n\n if (decision.decision === 'keep_distinct') {\n blockedClusters.push({\n cluster_id: decision.clusterId,\n decision: decision.decision,\n blocker_code: 'decision_keep_distinct',\n reason: decision.reason,\n canonical_flow: decision.canonicalRef,\n cluster_members: decision.memberRefs,\n missing_flow_keys: [],\n });\n incrementCount(blockedReasonCounts, 'decision_keep_distinct');\n return;\n }\n\n if (decision.decision === 'blocked_missing_db_flow') {\n blockedClusters.push({\n cluster_id: decision.clusterId,\n decision: decision.decision,\n blocker_code: 'blocked_missing_db_flow',\n reason: decision.reason,\n canonical_flow: decision.canonicalRef,\n cluster_members: decision.memberRefs,\n missing_flow_keys: [],\n });\n incrementCount(blockedReasonCounts, 'blocked_missing_db_flow');\n return;\n }\n\n const canonicalRef = decision.canonicalRef as FlowRef;\n const canonicalKey = `${canonicalRef.id}@${canonicalRef.version}`;\n const missingFlowKeys = decision.memberRefs\n .map((ref) => `${ref.id}@${ref.version}`)\n .filter((key) => !flowIndex.has(key));\n\n if (!flowIndex.has(canonicalKey)) {\n blockedClusters.push({\n cluster_id: decision.clusterId,\n decision: decision.decision,\n blocker_code: 'merge_canonical_flow_missing',\n reason: decision.reason,\n canonical_flow: canonicalRef,\n cluster_members: decision.memberRefs,\n missing_flow_keys: [...new Set([canonicalKey, ...missingFlowKeys])],\n });\n incrementCount(blockedReasonCounts, 'merge_canonical_flow_missing');\n return;\n }\n\n if (missingFlowKeys.length > 0) {\n blockedClusters.push({\n cluster_id: decision.clusterId,\n decision: decision.decision,\n blocker_code: 'flow_row_missing',\n reason: decision.reason,\n canonical_flow: canonicalRef,\n cluster_members: decision.memberRefs,\n missing_flow_keys: [...new Set(missingFlowKeys)].sort(),\n });\n incrementCount(blockedReasonCounts, 'flow_row_missing');\n return;\n }\n\n const canonicalFlow = flowIndex.get(canonicalKey) as IndexedFlowRow;\n const mergeReason = decision.reason ?? 'approved_merge_keep_one';\n const mergedFlows = decision.memberRefs\n .map((ref) => flowIndex.get(`${ref.id}@${ref.version}`) as IndexedFlowRow)\n .sort((left, right) => left.key.localeCompare(right.key))\n .map((entry) => ({\n ...summarizeFlow(entry.record),\n relation:\n entry.key === canonicalKey\n ? ('canonical_self' as const)\n : ('rewrite_to_canonical' as const),\n }));\n\n canonicalClusters.push({\n cluster_id: decision.clusterId,\n decision: 'merge_keep_one',\n reason: decision.reason,\n canonical_flow: summarizeFlow(canonicalFlow.record),\n merged_flows: mergedFlows,\n });\n\n mergedFlows.forEach((flow) => {\n canonicalMapEntries.push([\n `${flow.id}@${flow.version}`,\n {\n id: canonicalFlow.record.id,\n version: canonicalFlow.record.version,\n cluster_id: decision.clusterId,\n relation: flow.relation,\n reason: mergeReason,\n },\n ]);\n\n if (flow.relation === 'rewrite_to_canonical') {\n rewriteActions.push({\n cluster_id: decision.clusterId,\n action: 'rewrite_to_canonical',\n reason: mergeReason,\n source_flow_id: flow.id,\n source_flow_version: flow.version,\n source_flow_name: flow.name,\n source_flow_type: flow.flow_type,\n target_flow_id: canonicalFlow.record.id,\n target_flow_version: canonicalFlow.record.version,\n target_flow_name: canonicalFlow.record.name,\n target_flow_type: canonicalFlow.record.flowType,\n });\n seedAliasEntries.push([\n `${flow.id}@${flow.version}`,\n {\n id: canonicalFlow.record.id,\n version: canonicalFlow.record.version,\n cluster_id: decision.clusterId,\n relation: 'rewrite_to_canonical',\n reason: mergeReason,\n },\n ]);\n }\n });\n });\n\n const canonicalMapByFlowKey = sortedObject(canonicalMapEntries);\n const semanticMergeSeed = sortedObject(\n seedAliasEntries.map(([key, value]) => [\n key,\n {\n id: value.id,\n version: value.version,\n reason: value.reason,\n cluster_id: value.cluster_id,\n },\n ]),\n );\n const report: FlowMaterializeDecisionsReport = {\n schema_version: 1,\n generated_at_utc: generatedAt,\n status:\n blockedClusters.length > 0\n ? 'completed_local_flow_decision_materialization_with_blocked_clusters'\n : 'completed_local_flow_decision_materialization',\n decision_file: decisionFile,\n flow_rows_file: flowRowsFile,\n out_dir: outDir,\n counts: {\n input_decisions: decisions.length,\n materialized_clusters: canonicalClusters.length,\n blocked_clusters: blockedClusters.length,\n canonical_map_entries: Object.keys(canonicalMapByFlowKey).length,\n rewrite_actions: rewriteActions.length,\n seed_alias_entries: Object.keys(semanticMergeSeed).length,\n decision_counts: decisionCounts,\n blocked_reason_counts: blockedReasonCounts,\n },\n files,\n };\n\n writeJsonArtifact(files.canonical_map, {\n schema_version: 1,\n generated_at_utc: generatedAt,\n clusters: canonicalClusters.sort((left, right) =>\n left.cluster_id.localeCompare(right.cluster_id),\n ),\n by_flow_key: canonicalMapByFlowKey,\n });\n writeJsonArtifact(files.rewrite_plan, {\n schema_version: 1,\n generated_at_utc: generatedAt,\n actions: rewriteActions.sort((left, right) => {\n const clusterOrder = left.cluster_id.localeCompare(right.cluster_id);\n if (clusterOrder !== 0) {\n return clusterOrder;\n }\n const leftKey = `${left.source_flow_id}@${left.source_flow_version}`;\n const rightKey = `${right.source_flow_id}@${right.source_flow_version}`;\n return leftKey.localeCompare(rightKey);\n }),\n });\n writeJsonArtifact(files.semantic_merge_seed, semanticMergeSeed);\n writeJsonArtifact(files.blocked_clusters, {\n schema_version: 1,\n generated_at_utc: generatedAt,\n clusters: blockedClusters.sort((left, right) =>\n left.cluster_id.localeCompare(right.cluster_id),\n ),\n });\n writeJsonArtifact(files.summary, report);\n\n return report;\n}\n\nexport const __testInternals = {\n parseDecisionRow,\n parseFlowRefLike,\n parseFlowRefString,\n uniqueFlowRefs,\n buildFlowIndex,\n buildOutputFiles,\n};\n"]}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { writeJsonArtifact, writeJsonLinesArtifact } from './artifacts.js';
|
|
4
|
+
import { createDatasetCommandClient } from './dataset-command.js';
|
|
5
|
+
import { readRuntimeEnv } from './env.js';
|
|
4
6
|
import { CliError } from './errors.js';
|
|
5
7
|
import { coerceText, deepGet, isRecord, loadRowsFromFile, } from './flow-governance.js';
|
|
6
|
-
import { createSupabaseDataClient, requireSupabaseRestRuntime, runSupabaseArrayQuery,
|
|
8
|
+
import { createSupabaseDataClient, requireSupabaseRestRuntime, runSupabaseArrayQuery, } from './supabase-client.js';
|
|
7
9
|
import { createSupabaseDataRuntime } from './supabase-session.js';
|
|
8
10
|
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
9
11
|
const DEFAULT_MAX_WORKERS = 4;
|
|
@@ -266,21 +268,19 @@ function build_error_reasons(stage, error) {
|
|
|
266
268
|
];
|
|
267
269
|
}
|
|
268
270
|
async function insert_flow_version(options) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
+
await options.commandClient.create({
|
|
272
|
+
table: 'flows',
|
|
271
273
|
id: options.rowId,
|
|
272
|
-
|
|
273
|
-
})
|
|
274
|
+
jsonOrdered: options.payload,
|
|
275
|
+
});
|
|
274
276
|
}
|
|
275
277
|
async function update_flow_version(options) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
.
|
|
279
|
-
.
|
|
280
|
-
|
|
281
|
-
})
|
|
282
|
-
.eq('id', options.rowId)
|
|
283
|
-
.eq('version', options.version), url);
|
|
278
|
+
await options.commandClient.saveDraft({
|
|
279
|
+
table: 'flows',
|
|
280
|
+
id: options.rowId,
|
|
281
|
+
version: options.version,
|
|
282
|
+
jsonOrdered: options.payload,
|
|
283
|
+
});
|
|
284
284
|
}
|
|
285
285
|
async function sync_one_row(options) {
|
|
286
286
|
try {
|
|
@@ -329,8 +329,7 @@ async function sync_one_row(options) {
|
|
|
329
329
|
}
|
|
330
330
|
if (ownBefore) {
|
|
331
331
|
await update_flow_version({
|
|
332
|
-
|
|
333
|
-
restBaseUrl: options.restBaseUrl,
|
|
332
|
+
commandClient: options.commandClient,
|
|
334
333
|
rowId,
|
|
335
334
|
version,
|
|
336
335
|
payload,
|
|
@@ -352,8 +351,7 @@ async function sync_one_row(options) {
|
|
|
352
351
|
}
|
|
353
352
|
try {
|
|
354
353
|
await insert_flow_version({
|
|
355
|
-
|
|
356
|
-
restBaseUrl: options.restBaseUrl,
|
|
354
|
+
commandClient: options.commandClient,
|
|
357
355
|
rowId,
|
|
358
356
|
payload,
|
|
359
357
|
});
|
|
@@ -377,8 +375,7 @@ async function sync_one_row(options) {
|
|
|
377
375
|
if (ownAfter) {
|
|
378
376
|
try {
|
|
379
377
|
await update_flow_version({
|
|
380
|
-
|
|
381
|
-
restBaseUrl: options.restBaseUrl,
|
|
378
|
+
commandClient: options.commandClient,
|
|
382
379
|
rowId,
|
|
383
380
|
version,
|
|
384
381
|
payload,
|
|
@@ -459,6 +456,12 @@ export async function runFlowPublishVersion(options) {
|
|
|
459
456
|
now,
|
|
460
457
|
});
|
|
461
458
|
const { client, restBaseUrl } = createSupabaseDataClient(runtime, fetchImpl, timeoutMs);
|
|
459
|
+
const commandClient = createDatasetCommandClient({
|
|
460
|
+
runtime,
|
|
461
|
+
fetchImpl,
|
|
462
|
+
timeoutMs,
|
|
463
|
+
region: readRuntimeEnv(options.env ?? process.env).region,
|
|
464
|
+
});
|
|
462
465
|
const targetUserIdOverride = normalize_token(options.targetUserId ?? null);
|
|
463
466
|
const files = build_output_files(outDir);
|
|
464
467
|
let rows = loadRowsFromFile(inputFile);
|
|
@@ -475,6 +478,7 @@ export async function runFlowPublishVersion(options) {
|
|
|
475
478
|
row,
|
|
476
479
|
mode,
|
|
477
480
|
client,
|
|
481
|
+
commandClient,
|
|
478
482
|
restBaseUrl,
|
|
479
483
|
targetUserIdOverride,
|
|
480
484
|
}));
|