windmill-cli 1.678.0 → 1.680.0
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/esm/main.js +1117 -146
- package/package.json +2 -2
package/esm/main.js
CHANGED
|
@@ -11812,7 +11812,7 @@ var init_OpenAPI = __esm(() => {
|
|
|
11812
11812
|
PASSWORD: undefined,
|
|
11813
11813
|
TOKEN: getEnv2("WM_TOKEN"),
|
|
11814
11814
|
USERNAME: undefined,
|
|
11815
|
-
VERSION: "1.
|
|
11815
|
+
VERSION: "1.680.0",
|
|
11816
11816
|
WITH_CREDENTIALS: true,
|
|
11817
11817
|
interceptors: {
|
|
11818
11818
|
request: new Interceptors,
|
|
@@ -12380,6 +12380,7 @@ __export(exports_services_gen, {
|
|
|
12380
12380
|
inviteUser: () => inviteUser,
|
|
12381
12381
|
installFromWorkspace: () => installFromWorkspace,
|
|
12382
12382
|
importQueuedJobs: () => importQueuedJobs,
|
|
12383
|
+
importPgDatabase: () => importPgDatabase,
|
|
12383
12384
|
importInstallation: () => importInstallation,
|
|
12384
12385
|
importCompletedJobs: () => importCompletedJobs,
|
|
12385
12386
|
impersonateServiceAccount: () => impersonateServiceAccount,
|
|
@@ -12522,6 +12523,7 @@ __export(exports_services_gen, {
|
|
|
12522
12523
|
getDependencyMap: () => getDependencyMap,
|
|
12523
12524
|
getDefaultScripts: () => getDefaultScripts,
|
|
12524
12525
|
getDbClock: () => getDbClock,
|
|
12526
|
+
getDatatableFullSchema: () => getDatatableFullSchema,
|
|
12525
12527
|
getCustomTagsForWorkspace: () => getCustomTagsForWorkspace,
|
|
12526
12528
|
getCustomTags: () => getCustomTags,
|
|
12527
12529
|
getCurrentEmail: () => getCurrentEmail,
|
|
@@ -12560,6 +12562,7 @@ __export(exports_services_gen, {
|
|
|
12560
12562
|
fileDownloadParquetAsCsv: () => fileDownloadParquetAsCsv,
|
|
12561
12563
|
fileDownload: () => fileDownload,
|
|
12562
12564
|
exportQueuedJobs: () => exportQueuedJobs,
|
|
12565
|
+
exportPgSchema: () => exportPgSchema,
|
|
12563
12566
|
exportInstanceGroups: () => exportInstanceGroups,
|
|
12564
12567
|
exportInstallation: () => exportInstallation,
|
|
12565
12568
|
exportCompletedJobs: () => exportCompletedJobs,
|
|
@@ -12609,6 +12612,8 @@ __export(exports_services_gen, {
|
|
|
12609
12612
|
editAutoInvite: () => editAutoInvite,
|
|
12610
12613
|
duckdbConnectionSettingsV2: () => duckdbConnectionSettingsV2,
|
|
12611
12614
|
duckdbConnectionSettings: () => duckdbConnectionSettings,
|
|
12615
|
+
dropForkedDatatableDatabases: () => dropForkedDatatableDatabases,
|
|
12616
|
+
dropCustomInstanceDb: () => dropCustomInstanceDb,
|
|
12612
12617
|
downloadOpenapiSpec: () => downloadOpenapiSpec,
|
|
12613
12618
|
discoverMcpOauth: () => discoverMcpOauth,
|
|
12614
12619
|
disconnectTeams: () => disconnectTeams,
|
|
@@ -12687,6 +12692,7 @@ __export(exports_services_gen, {
|
|
|
12687
12692
|
createPostgresTrigger: () => createPostgresTrigger,
|
|
12688
12693
|
createPostgresReplicationSlot: () => createPostgresReplicationSlot,
|
|
12689
12694
|
createPostgresPublication: () => createPostgresPublication,
|
|
12695
|
+
createPgDatabase: () => createPgDatabase,
|
|
12690
12696
|
createNatsTrigger: () => createNatsTrigger,
|
|
12691
12697
|
createNativeTriggerService: () => createNativeTriggerService,
|
|
12692
12698
|
createNativeTrigger: () => createNativeTrigger,
|
|
@@ -13104,6 +13110,14 @@ var backendVersion = () => {
|
|
|
13104
13110
|
body: data2.requestBody,
|
|
13105
13111
|
mediaType: "application/json"
|
|
13106
13112
|
});
|
|
13113
|
+
}, dropCustomInstanceDb = (data2) => {
|
|
13114
|
+
return request(OpenAPI, {
|
|
13115
|
+
method: "POST",
|
|
13116
|
+
url: "/settings/drop_custom_instance_pg_database/{name}",
|
|
13117
|
+
path: {
|
|
13118
|
+
name: data2.name
|
|
13119
|
+
}
|
|
13120
|
+
});
|
|
13107
13121
|
}, getGlobal = (data2) => {
|
|
13108
13122
|
return request(OpenAPI, {
|
|
13109
13123
|
method: "GET",
|
|
@@ -14001,6 +14015,56 @@ var backendVersion = () => {
|
|
|
14001
14015
|
body: data2.requestBody,
|
|
14002
14016
|
mediaType: "application/json"
|
|
14003
14017
|
});
|
|
14018
|
+
}, createPgDatabase = (data2) => {
|
|
14019
|
+
return request(OpenAPI, {
|
|
14020
|
+
method: "POST",
|
|
14021
|
+
url: "/w/{workspace}/workspaces/create_pg_database",
|
|
14022
|
+
path: {
|
|
14023
|
+
workspace: data2.workspace
|
|
14024
|
+
},
|
|
14025
|
+
body: data2.requestBody,
|
|
14026
|
+
mediaType: "application/json"
|
|
14027
|
+
});
|
|
14028
|
+
}, dropForkedDatatableDatabases = (data2) => {
|
|
14029
|
+
return request(OpenAPI, {
|
|
14030
|
+
method: "POST",
|
|
14031
|
+
url: "/w/{workspace}/workspaces/drop_forked_datatable_databases",
|
|
14032
|
+
path: {
|
|
14033
|
+
workspace: data2.workspace
|
|
14034
|
+
},
|
|
14035
|
+
body: data2.requestBody,
|
|
14036
|
+
mediaType: "application/json"
|
|
14037
|
+
});
|
|
14038
|
+
}, importPgDatabase = (data2) => {
|
|
14039
|
+
return request(OpenAPI, {
|
|
14040
|
+
method: "POST",
|
|
14041
|
+
url: "/w/{workspace}/workspaces/import_pg_database",
|
|
14042
|
+
path: {
|
|
14043
|
+
workspace: data2.workspace
|
|
14044
|
+
},
|
|
14045
|
+
body: data2.requestBody,
|
|
14046
|
+
mediaType: "application/json"
|
|
14047
|
+
});
|
|
14048
|
+
}, exportPgSchema = (data2) => {
|
|
14049
|
+
return request(OpenAPI, {
|
|
14050
|
+
method: "POST",
|
|
14051
|
+
url: "/w/{workspace}/workspaces/export_pg_schema",
|
|
14052
|
+
path: {
|
|
14053
|
+
workspace: data2.workspace
|
|
14054
|
+
},
|
|
14055
|
+
body: data2.requestBody,
|
|
14056
|
+
mediaType: "application/json"
|
|
14057
|
+
});
|
|
14058
|
+
}, getDatatableFullSchema = (data2) => {
|
|
14059
|
+
return request(OpenAPI, {
|
|
14060
|
+
method: "POST",
|
|
14061
|
+
url: "/w/{workspace}/workspaces/get_datatable_full_schema",
|
|
14062
|
+
path: {
|
|
14063
|
+
workspace: data2.workspace
|
|
14064
|
+
},
|
|
14065
|
+
body: data2.requestBody,
|
|
14066
|
+
mediaType: "application/json"
|
|
14067
|
+
});
|
|
14004
14068
|
}, getGitSyncEnabled = (data2) => {
|
|
14005
14069
|
return request(OpenAPI, {
|
|
14006
14070
|
method: "GET",
|
|
@@ -25166,13 +25230,91 @@ async function createWorkspaceFork2(opts, workspaceName, workspaceId = undefined
|
|
|
25166
25230
|
if (alreadyExists) {
|
|
25167
25231
|
throw new Error(`This forked workspace '${workspaceId}' (${workspaceName}) already exists. Choose a different id`);
|
|
25168
25232
|
}
|
|
25233
|
+
const forkedDatatables = [];
|
|
25234
|
+
let datatables = [];
|
|
25235
|
+
try {
|
|
25236
|
+
datatables = await listDataTables({
|
|
25237
|
+
workspace: workspace.workspaceId
|
|
25238
|
+
});
|
|
25239
|
+
} catch (e) {
|
|
25240
|
+
info(colors.yellow(`Note: Could not list datatables: ${e.message}`));
|
|
25241
|
+
}
|
|
25242
|
+
if (datatables && datatables.length > 0) {
|
|
25243
|
+
const behavior = opts.datatableBehavior ?? (opts.yes ? "skip" : undefined);
|
|
25244
|
+
if (behavior !== "skip") {
|
|
25245
|
+
info(`
|
|
25246
|
+
Found ${datatables.length} datatable(s):`);
|
|
25247
|
+
for (const dt of datatables) {
|
|
25248
|
+
let dtBehavior;
|
|
25249
|
+
if (behavior === "schema_only" || behavior === "schema_and_data") {
|
|
25250
|
+
dtBehavior = behavior;
|
|
25251
|
+
} else {
|
|
25252
|
+
const { Select: Select2 } = await init_select().then(() => exports_select);
|
|
25253
|
+
dtBehavior = await Select2.prompt({
|
|
25254
|
+
message: `Datatable "${dt.name}" (${dt.resource_type}):`,
|
|
25255
|
+
options: [
|
|
25256
|
+
{ name: "Keep original (no cloning)", value: "keep_original" },
|
|
25257
|
+
{ name: "Clone schema only", value: "schema_only" },
|
|
25258
|
+
{ name: "Clone schema and data", value: "schema_and_data" }
|
|
25259
|
+
]
|
|
25260
|
+
});
|
|
25261
|
+
}
|
|
25262
|
+
if (dtBehavior === "keep_original") {
|
|
25263
|
+
continue;
|
|
25264
|
+
}
|
|
25265
|
+
const newDbName = `${trueWorkspaceId.replace(/-/g, "_")}__${dt.name}`;
|
|
25266
|
+
try {
|
|
25267
|
+
info(colors.blue(` Creating database "${newDbName}" for datatable "${dt.name}"...`));
|
|
25268
|
+
await createPgDatabase({
|
|
25269
|
+
workspace: workspace.workspaceId,
|
|
25270
|
+
requestBody: {
|
|
25271
|
+
source: `datatable://${dt.name}`,
|
|
25272
|
+
target_dbname: newDbName
|
|
25273
|
+
}
|
|
25274
|
+
});
|
|
25275
|
+
info(colors.blue(` Importing ${dtBehavior === "schema_only" ? "schema" : "schema + data"}...`));
|
|
25276
|
+
await importPgDatabase({
|
|
25277
|
+
workspace: workspace.workspaceId,
|
|
25278
|
+
requestBody: {
|
|
25279
|
+
source: `datatable://${dt.name}`,
|
|
25280
|
+
target: `datatable://${dt.name}`,
|
|
25281
|
+
target_dbname_override: newDbName,
|
|
25282
|
+
fork_behavior: dtBehavior
|
|
25283
|
+
}
|
|
25284
|
+
});
|
|
25285
|
+
info(colors.green(` ✓ Datatable "${dt.name}" cloned.`));
|
|
25286
|
+
forkedDatatables.push({ name: dt.name, new_dbname: newDbName });
|
|
25287
|
+
} catch (e) {
|
|
25288
|
+
info(colors.yellow(` ✗ Failed to clone datatable "${dt.name}": ${e.message}`));
|
|
25289
|
+
}
|
|
25290
|
+
}
|
|
25291
|
+
}
|
|
25292
|
+
}
|
|
25293
|
+
const forkColor = opts.color;
|
|
25294
|
+
try {
|
|
25295
|
+
const gitSyncJobIds = await createWorkspaceForkGitBranch({
|
|
25296
|
+
workspace: workspace.workspaceId,
|
|
25297
|
+
requestBody: {
|
|
25298
|
+
id: trueWorkspaceId,
|
|
25299
|
+
name: opts.createWorkspaceName ?? trueWorkspaceId,
|
|
25300
|
+
color: forkColor
|
|
25301
|
+
}
|
|
25302
|
+
});
|
|
25303
|
+
if (gitSyncJobIds && gitSyncJobIds.length > 0) {
|
|
25304
|
+
info(colors.blue(`Git sync branch creation triggered (${gitSyncJobIds.length} job(s)). These will complete asynchronously.`));
|
|
25305
|
+
}
|
|
25306
|
+
} catch (e) {
|
|
25307
|
+
error(colors.red(`Failed to create git branch for fork: ${e.message}`));
|
|
25308
|
+
throw e;
|
|
25309
|
+
}
|
|
25169
25310
|
try {
|
|
25170
25311
|
const result = await createWorkspaceFork({
|
|
25171
25312
|
workspace: workspace.workspaceId,
|
|
25172
25313
|
requestBody: {
|
|
25173
25314
|
id: trueWorkspaceId,
|
|
25174
25315
|
name: opts.createWorkspaceName ?? trueWorkspaceId,
|
|
25175
|
-
color:
|
|
25316
|
+
color: forkColor,
|
|
25317
|
+
forked_datatables: forkedDatatables
|
|
25176
25318
|
}
|
|
25177
25319
|
});
|
|
25178
25320
|
info(colors.green(`✅ ${result}`));
|
|
@@ -25188,8 +25330,8 @@ async function createWorkspaceFork2(opts, workspaceName, workspaceId = undefined
|
|
|
25188
25330
|
When doing operations on the forked workspace, it will use the remote setup in gitBranches for the branch it was forked from.
|
|
25189
25331
|
|
|
25190
25332
|
To merge changes back to the parent workspace, you can:
|
|
25333
|
+
- Use the CLI: ` + colors.white(`git checkout ${newBranchName} && wmill workspace merge`) + `
|
|
25191
25334
|
- Use the Merge UI from the forked workspace home page
|
|
25192
|
-
- Deploy individual items via the Deploy to staging/prod UI
|
|
25193
25335
|
- Use git: ` + colors.white(`git checkout ${clonedBranchName} && git merge ${newBranchName} && wmill sync push`) + `
|
|
25194
25336
|
See: https://www.windmill.dev/docs/advanced/workspace_forks`);
|
|
25195
25337
|
}
|
|
@@ -25255,6 +25397,836 @@ var init_fork = __esm(async () => {
|
|
|
25255
25397
|
]);
|
|
25256
25398
|
});
|
|
25257
25399
|
|
|
25400
|
+
// windmill-utils-internal/src/deploy.ts
|
|
25401
|
+
function folderName(path3) {
|
|
25402
|
+
return path3.replace(/^f\//, "");
|
|
25403
|
+
}
|
|
25404
|
+
function getSubModules(flowModule) {
|
|
25405
|
+
const type = flowModule?.value?.type;
|
|
25406
|
+
if (type === "forloopflow" || type === "whileloopflow") {
|
|
25407
|
+
return [flowModule.value.modules ?? []];
|
|
25408
|
+
} else if (type === "branchall") {
|
|
25409
|
+
return (flowModule.value.branches ?? []).map((branch) => branch.modules ?? []);
|
|
25410
|
+
} else if (type === "branchone") {
|
|
25411
|
+
return [
|
|
25412
|
+
...(flowModule.value.branches ?? []).map((b) => b.modules ?? []),
|
|
25413
|
+
flowModule.value.default ?? []
|
|
25414
|
+
];
|
|
25415
|
+
} else if (type === "aiagent") {
|
|
25416
|
+
if (flowModule.value.tools) {
|
|
25417
|
+
return [
|
|
25418
|
+
flowModule.value.tools.filter((t) => t.value?.type === "script" || t.value?.type === "flow").map((t) => ({
|
|
25419
|
+
id: t.id,
|
|
25420
|
+
value: t.value,
|
|
25421
|
+
summary: t.summary
|
|
25422
|
+
}))
|
|
25423
|
+
];
|
|
25424
|
+
}
|
|
25425
|
+
}
|
|
25426
|
+
return [];
|
|
25427
|
+
}
|
|
25428
|
+
function getAllSubmodules(flowModule) {
|
|
25429
|
+
return getSubModules(flowModule).map((modules) => modules.flatMap((m) => [m, ...getAllSubmodules(m)])).flat();
|
|
25430
|
+
}
|
|
25431
|
+
function getAllModules(flowModules, failureModule) {
|
|
25432
|
+
return [
|
|
25433
|
+
...flowModules,
|
|
25434
|
+
...flowModules.flatMap((x) => getAllSubmodules(x)),
|
|
25435
|
+
...failureModule ? [failureModule] : []
|
|
25436
|
+
];
|
|
25437
|
+
}
|
|
25438
|
+
function toError(e) {
|
|
25439
|
+
const err = e;
|
|
25440
|
+
return err.body || err.message || String(e);
|
|
25441
|
+
}
|
|
25442
|
+
async function checkItemExists(provider, kind, path3, workspace) {
|
|
25443
|
+
if (kind === "flow") {
|
|
25444
|
+
return provider.existsFlowByPath({ workspace, path: path3 });
|
|
25445
|
+
} else if (kind === "script") {
|
|
25446
|
+
return provider.existsScriptByPath({ workspace, path: path3 });
|
|
25447
|
+
} else if (kind === "app" || kind === "raw_app") {
|
|
25448
|
+
return provider.existsApp({ workspace, path: path3 });
|
|
25449
|
+
} else if (kind === "variable") {
|
|
25450
|
+
return provider.existsVariable({ workspace, path: path3 });
|
|
25451
|
+
} else if (kind === "resource") {
|
|
25452
|
+
return provider.existsResource({ workspace, path: path3 });
|
|
25453
|
+
} else if (kind === "resource_type") {
|
|
25454
|
+
return provider.existsResourceType({ workspace, path: path3 });
|
|
25455
|
+
} else if (kind === "folder") {
|
|
25456
|
+
return provider.existsFolder({ workspace, name: folderName(path3) });
|
|
25457
|
+
}
|
|
25458
|
+
throw new Error(`Unknown kind: ${kind}`);
|
|
25459
|
+
}
|
|
25460
|
+
async function deployItem(provider, kind, path3, workspaceFrom, workspaceTo, onBehalfOf) {
|
|
25461
|
+
const preserveOnBehalfOf = onBehalfOf !== undefined;
|
|
25462
|
+
try {
|
|
25463
|
+
const alreadyExists = await checkItemExists(provider, kind, path3, workspaceTo);
|
|
25464
|
+
if (kind === "flow") {
|
|
25465
|
+
const flow = await provider.getFlowByPath({
|
|
25466
|
+
workspace: workspaceFrom,
|
|
25467
|
+
path: path3
|
|
25468
|
+
});
|
|
25469
|
+
getAllModules(flow.value?.modules ?? [], flow.value?.failure_module).forEach((x) => {
|
|
25470
|
+
if (x.value?.type === "script" && x.value.hash != null) {
|
|
25471
|
+
x.value.hash = undefined;
|
|
25472
|
+
}
|
|
25473
|
+
});
|
|
25474
|
+
if (alreadyExists) {
|
|
25475
|
+
await provider.updateFlow({
|
|
25476
|
+
workspace: workspaceTo,
|
|
25477
|
+
path: path3,
|
|
25478
|
+
requestBody: {
|
|
25479
|
+
...flow,
|
|
25480
|
+
preserve_on_behalf_of: preserveOnBehalfOf,
|
|
25481
|
+
on_behalf_of_email: onBehalfOf
|
|
25482
|
+
}
|
|
25483
|
+
});
|
|
25484
|
+
} else {
|
|
25485
|
+
await provider.createFlow({
|
|
25486
|
+
workspace: workspaceTo,
|
|
25487
|
+
requestBody: {
|
|
25488
|
+
...flow,
|
|
25489
|
+
preserve_on_behalf_of: preserveOnBehalfOf,
|
|
25490
|
+
on_behalf_of_email: onBehalfOf
|
|
25491
|
+
}
|
|
25492
|
+
});
|
|
25493
|
+
}
|
|
25494
|
+
} else if (kind === "script") {
|
|
25495
|
+
const script = await provider.getScriptByPath({
|
|
25496
|
+
workspace: workspaceFrom,
|
|
25497
|
+
path: path3
|
|
25498
|
+
});
|
|
25499
|
+
let parentHash;
|
|
25500
|
+
if (alreadyExists) {
|
|
25501
|
+
const existing = await provider.getScriptByPath({
|
|
25502
|
+
workspace: workspaceTo,
|
|
25503
|
+
path: path3
|
|
25504
|
+
});
|
|
25505
|
+
parentHash = existing.hash;
|
|
25506
|
+
}
|
|
25507
|
+
await provider.createScript({
|
|
25508
|
+
workspace: workspaceTo,
|
|
25509
|
+
requestBody: {
|
|
25510
|
+
...script,
|
|
25511
|
+
lock: script.lock,
|
|
25512
|
+
parent_hash: parentHash,
|
|
25513
|
+
preserve_on_behalf_of: preserveOnBehalfOf,
|
|
25514
|
+
on_behalf_of_email: onBehalfOf
|
|
25515
|
+
}
|
|
25516
|
+
});
|
|
25517
|
+
} else if (kind === "app" || kind === "raw_app") {
|
|
25518
|
+
const app = await provider.getAppByPath({
|
|
25519
|
+
workspace: workspaceFrom,
|
|
25520
|
+
path: path3
|
|
25521
|
+
});
|
|
25522
|
+
if (alreadyExists) {
|
|
25523
|
+
if (app.raw_app) {
|
|
25524
|
+
const secret = await provider.getPublicSecretOfLatestVersionOfApp({
|
|
25525
|
+
workspace: workspaceFrom,
|
|
25526
|
+
path: app.path
|
|
25527
|
+
});
|
|
25528
|
+
const js = await provider.getRawAppData({
|
|
25529
|
+
secretWithExtension: `${secret}.js`,
|
|
25530
|
+
workspace: workspaceFrom
|
|
25531
|
+
});
|
|
25532
|
+
const css = await provider.getRawAppData({
|
|
25533
|
+
secretWithExtension: `${secret}.css`,
|
|
25534
|
+
workspace: workspaceFrom
|
|
25535
|
+
});
|
|
25536
|
+
await provider.updateAppRaw({
|
|
25537
|
+
workspace: workspaceTo,
|
|
25538
|
+
path: path3,
|
|
25539
|
+
formData: {
|
|
25540
|
+
app: { ...app, preserve_on_behalf_of: preserveOnBehalfOf },
|
|
25541
|
+
css,
|
|
25542
|
+
js
|
|
25543
|
+
}
|
|
25544
|
+
});
|
|
25545
|
+
} else {
|
|
25546
|
+
await provider.updateApp({
|
|
25547
|
+
workspace: workspaceTo,
|
|
25548
|
+
path: path3,
|
|
25549
|
+
requestBody: {
|
|
25550
|
+
...app,
|
|
25551
|
+
preserve_on_behalf_of: preserveOnBehalfOf
|
|
25552
|
+
}
|
|
25553
|
+
});
|
|
25554
|
+
}
|
|
25555
|
+
} else {
|
|
25556
|
+
if (app.raw_app) {
|
|
25557
|
+
const secret = await provider.getPublicSecretOfLatestVersionOfApp({
|
|
25558
|
+
workspace: workspaceFrom,
|
|
25559
|
+
path: app.path
|
|
25560
|
+
});
|
|
25561
|
+
const js = await provider.getRawAppData({
|
|
25562
|
+
secretWithExtension: `${secret}.js`,
|
|
25563
|
+
workspace: workspaceFrom
|
|
25564
|
+
});
|
|
25565
|
+
const css = await provider.getRawAppData({
|
|
25566
|
+
secretWithExtension: `${secret}.css`,
|
|
25567
|
+
workspace: workspaceFrom
|
|
25568
|
+
});
|
|
25569
|
+
await provider.createAppRaw({
|
|
25570
|
+
workspace: workspaceTo,
|
|
25571
|
+
formData: {
|
|
25572
|
+
app: { ...app, preserve_on_behalf_of: preserveOnBehalfOf },
|
|
25573
|
+
css,
|
|
25574
|
+
js
|
|
25575
|
+
}
|
|
25576
|
+
});
|
|
25577
|
+
} else {
|
|
25578
|
+
await provider.createApp({
|
|
25579
|
+
workspace: workspaceTo,
|
|
25580
|
+
requestBody: {
|
|
25581
|
+
...app,
|
|
25582
|
+
preserve_on_behalf_of: preserveOnBehalfOf
|
|
25583
|
+
}
|
|
25584
|
+
});
|
|
25585
|
+
}
|
|
25586
|
+
}
|
|
25587
|
+
} else if (kind === "variable") {
|
|
25588
|
+
const variable = await provider.getVariable({
|
|
25589
|
+
workspace: workspaceFrom,
|
|
25590
|
+
path: path3,
|
|
25591
|
+
decryptSecret: true
|
|
25592
|
+
});
|
|
25593
|
+
if (alreadyExists) {
|
|
25594
|
+
await provider.updateVariable({
|
|
25595
|
+
workspace: workspaceTo,
|
|
25596
|
+
path: path3,
|
|
25597
|
+
requestBody: {
|
|
25598
|
+
path: path3,
|
|
25599
|
+
value: variable.value ?? "",
|
|
25600
|
+
is_secret: variable.is_secret,
|
|
25601
|
+
description: variable.description ?? ""
|
|
25602
|
+
},
|
|
25603
|
+
alreadyEncrypted: false
|
|
25604
|
+
});
|
|
25605
|
+
} else {
|
|
25606
|
+
await provider.createVariable({
|
|
25607
|
+
workspace: workspaceTo,
|
|
25608
|
+
requestBody: {
|
|
25609
|
+
path: path3,
|
|
25610
|
+
value: variable.value ?? "",
|
|
25611
|
+
is_secret: variable.is_secret,
|
|
25612
|
+
description: variable.description ?? ""
|
|
25613
|
+
}
|
|
25614
|
+
});
|
|
25615
|
+
}
|
|
25616
|
+
} else if (kind === "resource") {
|
|
25617
|
+
const resource = await provider.getResource({
|
|
25618
|
+
workspace: workspaceFrom,
|
|
25619
|
+
path: path3
|
|
25620
|
+
});
|
|
25621
|
+
if (alreadyExists) {
|
|
25622
|
+
await provider.updateResource({
|
|
25623
|
+
workspace: workspaceTo,
|
|
25624
|
+
path: path3,
|
|
25625
|
+
requestBody: {
|
|
25626
|
+
path: path3,
|
|
25627
|
+
value: resource.value ?? "",
|
|
25628
|
+
description: resource.description ?? ""
|
|
25629
|
+
}
|
|
25630
|
+
});
|
|
25631
|
+
} else {
|
|
25632
|
+
await provider.createResource({
|
|
25633
|
+
workspace: workspaceTo,
|
|
25634
|
+
requestBody: {
|
|
25635
|
+
path: path3,
|
|
25636
|
+
value: resource.value ?? "",
|
|
25637
|
+
resource_type: resource.resource_type,
|
|
25638
|
+
description: resource.description ?? ""
|
|
25639
|
+
}
|
|
25640
|
+
});
|
|
25641
|
+
}
|
|
25642
|
+
} else if (kind === "resource_type") {
|
|
25643
|
+
const rt = await provider.getResourceType({
|
|
25644
|
+
workspace: workspaceFrom,
|
|
25645
|
+
path: path3
|
|
25646
|
+
});
|
|
25647
|
+
if (alreadyExists) {
|
|
25648
|
+
await provider.updateResourceType({
|
|
25649
|
+
workspace: workspaceTo,
|
|
25650
|
+
path: path3,
|
|
25651
|
+
requestBody: {
|
|
25652
|
+
schema: rt.schema,
|
|
25653
|
+
description: rt.description ?? ""
|
|
25654
|
+
}
|
|
25655
|
+
});
|
|
25656
|
+
} else {
|
|
25657
|
+
await provider.createResourceType({
|
|
25658
|
+
workspace: workspaceTo,
|
|
25659
|
+
requestBody: {
|
|
25660
|
+
name: rt.name,
|
|
25661
|
+
schema: rt.schema,
|
|
25662
|
+
description: rt.description ?? ""
|
|
25663
|
+
}
|
|
25664
|
+
});
|
|
25665
|
+
}
|
|
25666
|
+
} else if (kind === "folder") {
|
|
25667
|
+
const name = folderName(path3);
|
|
25668
|
+
const folder = await provider.getFolder({
|
|
25669
|
+
workspace: workspaceFrom,
|
|
25670
|
+
name
|
|
25671
|
+
});
|
|
25672
|
+
if (alreadyExists) {
|
|
25673
|
+
await provider.updateFolder({
|
|
25674
|
+
workspace: workspaceTo,
|
|
25675
|
+
name,
|
|
25676
|
+
requestBody: {
|
|
25677
|
+
owners: folder.owners,
|
|
25678
|
+
extra_perms: folder.extra_perms,
|
|
25679
|
+
summary: folder.summary ?? undefined
|
|
25680
|
+
}
|
|
25681
|
+
});
|
|
25682
|
+
} else {
|
|
25683
|
+
await provider.createFolder({
|
|
25684
|
+
workspace: workspaceTo,
|
|
25685
|
+
requestBody: {
|
|
25686
|
+
name,
|
|
25687
|
+
owners: folder.owners,
|
|
25688
|
+
extra_perms: folder.extra_perms,
|
|
25689
|
+
summary: folder.summary ?? undefined
|
|
25690
|
+
}
|
|
25691
|
+
});
|
|
25692
|
+
}
|
|
25693
|
+
} else {
|
|
25694
|
+
throw new Error(`Unknown kind: ${kind}`);
|
|
25695
|
+
}
|
|
25696
|
+
return { success: true };
|
|
25697
|
+
} catch (e) {
|
|
25698
|
+
return { success: false, error: toError(e) };
|
|
25699
|
+
}
|
|
25700
|
+
}
|
|
25701
|
+
async function deleteItemInWorkspace(provider, kind, path3, workspace) {
|
|
25702
|
+
try {
|
|
25703
|
+
if (kind === "script") {
|
|
25704
|
+
await provider.archiveScriptByPath({ workspace, path: path3 });
|
|
25705
|
+
} else if (kind === "flow") {
|
|
25706
|
+
await provider.archiveFlowByPath({
|
|
25707
|
+
workspace,
|
|
25708
|
+
path: path3,
|
|
25709
|
+
requestBody: { archived: true }
|
|
25710
|
+
});
|
|
25711
|
+
} else if (kind === "app" || kind === "raw_app") {
|
|
25712
|
+
await provider.deleteApp({ workspace, path: path3 });
|
|
25713
|
+
} else if (kind === "variable") {
|
|
25714
|
+
await provider.deleteVariable({ workspace, path: path3 });
|
|
25715
|
+
} else if (kind === "resource") {
|
|
25716
|
+
await provider.deleteResource({ workspace, path: path3 });
|
|
25717
|
+
} else if (kind === "resource_type") {
|
|
25718
|
+
await provider.deleteResourceType({ workspace, path: path3 });
|
|
25719
|
+
} else if (kind === "folder") {
|
|
25720
|
+
await provider.deleteFolder({ workspace, name: folderName(path3) });
|
|
25721
|
+
} else {
|
|
25722
|
+
throw new Error(`Deletion not supported for kind: ${kind}`);
|
|
25723
|
+
}
|
|
25724
|
+
return { success: true };
|
|
25725
|
+
} catch (e) {
|
|
25726
|
+
return { success: false, error: toError(e) };
|
|
25727
|
+
}
|
|
25728
|
+
}
|
|
25729
|
+
async function getOnBehalfOf(provider, kind, path3, workspace) {
|
|
25730
|
+
try {
|
|
25731
|
+
if (kind === "flow") {
|
|
25732
|
+
const flow = await provider.getFlowByPath({ workspace, path: path3 });
|
|
25733
|
+
return flow.on_behalf_of_email;
|
|
25734
|
+
} else if (kind === "script") {
|
|
25735
|
+
const script = await provider.getScriptByPath({ workspace, path: path3 });
|
|
25736
|
+
return script.on_behalf_of_email;
|
|
25737
|
+
} else if (kind === "app" || kind === "raw_app") {
|
|
25738
|
+
const app = await provider.getAppByPath({ workspace, path: path3 });
|
|
25739
|
+
return app.policy?.on_behalf_of_email;
|
|
25740
|
+
}
|
|
25741
|
+
} catch {}
|
|
25742
|
+
return;
|
|
25743
|
+
}
|
|
25744
|
+
|
|
25745
|
+
// node_modules/@cliffy/prompt/checkbox.js
|
|
25746
|
+
var exports_checkbox = {};
|
|
25747
|
+
__export(exports_checkbox, {
|
|
25748
|
+
isCheckboxOptionGroup: () => isCheckboxOptionGroup,
|
|
25749
|
+
Checkbox: () => Checkbox
|
|
25750
|
+
});
|
|
25751
|
+
function areSomeChecked(options) {
|
|
25752
|
+
return options.some((option) => isOptionGroup(option) ? areSomeChecked(option.options) : option.checked);
|
|
25753
|
+
}
|
|
25754
|
+
function areAllChecked(options) {
|
|
25755
|
+
return options.every((option) => isOptionGroup(option) ? areAllChecked(option.options) : option.checked);
|
|
25756
|
+
}
|
|
25757
|
+
function flatOptions(options) {
|
|
25758
|
+
return flat(options);
|
|
25759
|
+
function flat(options2, indentLevel = 0, opts = []) {
|
|
25760
|
+
for (const option of options2) {
|
|
25761
|
+
option.indentLevel = indentLevel;
|
|
25762
|
+
if (isOption2(option)) {
|
|
25763
|
+
opts.push(option);
|
|
25764
|
+
}
|
|
25765
|
+
if (isOptionGroup(option)) {
|
|
25766
|
+
flat(option.options, ++indentLevel, opts);
|
|
25767
|
+
}
|
|
25768
|
+
}
|
|
25769
|
+
return opts;
|
|
25770
|
+
}
|
|
25771
|
+
}
|
|
25772
|
+
function isCheckboxOptionGroup(option) {
|
|
25773
|
+
return isOptionGroup(option);
|
|
25774
|
+
}
|
|
25775
|
+
var Checkbox;
|
|
25776
|
+
var init_checkbox = __esm(async () => {
|
|
25777
|
+
init_equal();
|
|
25778
|
+
init_colors();
|
|
25779
|
+
init__figures();
|
|
25780
|
+
await __promiseAll([
|
|
25781
|
+
init__generic_list(),
|
|
25782
|
+
init__generic_prompt()
|
|
25783
|
+
]);
|
|
25784
|
+
Checkbox = class Checkbox extends GenericList {
|
|
25785
|
+
settings;
|
|
25786
|
+
options;
|
|
25787
|
+
listIndex;
|
|
25788
|
+
listOffset;
|
|
25789
|
+
confirmSubmit = false;
|
|
25790
|
+
static prompt(options) {
|
|
25791
|
+
return new this(options).prompt();
|
|
25792
|
+
}
|
|
25793
|
+
static inject(value) {
|
|
25794
|
+
GenericPrompt.inject(value);
|
|
25795
|
+
}
|
|
25796
|
+
constructor(options) {
|
|
25797
|
+
super();
|
|
25798
|
+
this.settings = this.getDefaultSettings(options);
|
|
25799
|
+
this.options = this.settings.options.slice();
|
|
25800
|
+
this.listIndex = this.getListIndex();
|
|
25801
|
+
this.listOffset = this.getPageOffset(this.listIndex);
|
|
25802
|
+
}
|
|
25803
|
+
getDefaultSettings(options) {
|
|
25804
|
+
const settings = super.getDefaultSettings(options);
|
|
25805
|
+
return {
|
|
25806
|
+
confirmSubmit: true,
|
|
25807
|
+
...settings,
|
|
25808
|
+
check: options.check ?? green(Figures.TICK),
|
|
25809
|
+
uncheck: options.uncheck ?? red(Figures.CROSS),
|
|
25810
|
+
partialCheck: options.partialCheck ?? green(Figures.RADIO_ON),
|
|
25811
|
+
minOptions: options.minOptions ?? 0,
|
|
25812
|
+
maxOptions: options.maxOptions ?? Infinity,
|
|
25813
|
+
options: this.mapOptions(options, options.options),
|
|
25814
|
+
keys: {
|
|
25815
|
+
check: [
|
|
25816
|
+
"space"
|
|
25817
|
+
],
|
|
25818
|
+
checkAll: [
|
|
25819
|
+
"a"
|
|
25820
|
+
],
|
|
25821
|
+
...settings.keys ?? {},
|
|
25822
|
+
open: options.keys?.open ?? [
|
|
25823
|
+
"right"
|
|
25824
|
+
],
|
|
25825
|
+
back: options.keys?.back ?? [
|
|
25826
|
+
"left",
|
|
25827
|
+
"escape"
|
|
25828
|
+
]
|
|
25829
|
+
}
|
|
25830
|
+
};
|
|
25831
|
+
}
|
|
25832
|
+
mapOptions(promptOptions, options) {
|
|
25833
|
+
return options.map((option) => typeof option === "string" || typeof option === "number" ? this.mapOption(promptOptions, {
|
|
25834
|
+
value: option
|
|
25835
|
+
}) : isCheckboxOptionGroup(option) ? this.mapOptionGroup(promptOptions, option) : this.mapOption(promptOptions, option));
|
|
25836
|
+
}
|
|
25837
|
+
mapOption(options, option) {
|
|
25838
|
+
if (isOption2(option)) {
|
|
25839
|
+
return {
|
|
25840
|
+
...super.mapOption(options, option),
|
|
25841
|
+
checked: typeof option.checked === "undefined" && options.default && options.default.indexOf(option.value) !== -1 ? true : !!option.checked,
|
|
25842
|
+
icon: typeof option.icon === "undefined" ? true : option.icon
|
|
25843
|
+
};
|
|
25844
|
+
} else {
|
|
25845
|
+
return {
|
|
25846
|
+
...super.mapOption(options, option),
|
|
25847
|
+
checked: false,
|
|
25848
|
+
icon: false
|
|
25849
|
+
};
|
|
25850
|
+
}
|
|
25851
|
+
}
|
|
25852
|
+
mapOptionGroup(promptOptions, option) {
|
|
25853
|
+
const options = this.mapOptions(promptOptions, option.options);
|
|
25854
|
+
const optionGroup = super.mapOptionGroup(promptOptions, option, false);
|
|
25855
|
+
return {
|
|
25856
|
+
...optionGroup,
|
|
25857
|
+
get checked() {
|
|
25858
|
+
return areAllChecked(options);
|
|
25859
|
+
},
|
|
25860
|
+
get disabled() {
|
|
25861
|
+
return optionGroup.disabled || options.every((opt) => opt.disabled);
|
|
25862
|
+
},
|
|
25863
|
+
options,
|
|
25864
|
+
icon: typeof option.icon === "undefined" ? true : option.icon
|
|
25865
|
+
};
|
|
25866
|
+
}
|
|
25867
|
+
match() {
|
|
25868
|
+
super.match();
|
|
25869
|
+
if (this.isSearching()) {
|
|
25870
|
+
this.selectSearch();
|
|
25871
|
+
}
|
|
25872
|
+
}
|
|
25873
|
+
getListItemIcon(option) {
|
|
25874
|
+
return this.getCheckboxIcon(option) + super.getListItemIcon(option);
|
|
25875
|
+
}
|
|
25876
|
+
getCheckboxIcon(option) {
|
|
25877
|
+
if (!option.icon) {
|
|
25878
|
+
return "";
|
|
25879
|
+
}
|
|
25880
|
+
const icon = option.checked ? this.settings.check + " " : isOptionGroup(option) && areSomeChecked(option.options) ? this.settings.partialCheck + " " : this.settings.uncheck + " ";
|
|
25881
|
+
return option.disabled ? dim(icon) : icon;
|
|
25882
|
+
}
|
|
25883
|
+
getValue() {
|
|
25884
|
+
return flatOptions(this.settings.options).filter((option) => option.checked).map((option) => option.value);
|
|
25885
|
+
}
|
|
25886
|
+
async handleEvent(event) {
|
|
25887
|
+
const hasConfirmed = this.confirmSubmit;
|
|
25888
|
+
this.confirmSubmit = false;
|
|
25889
|
+
switch (true) {
|
|
25890
|
+
case (this.isKey(this.settings.keys, "check", event) && !this.isSearchSelected()):
|
|
25891
|
+
this.checkValue();
|
|
25892
|
+
break;
|
|
25893
|
+
case this.isKey(this.settings.keys, "submit", event):
|
|
25894
|
+
await this.submit(hasConfirmed);
|
|
25895
|
+
break;
|
|
25896
|
+
case (event.ctrl && this.isKey(this.settings.keys, "checkAll", event)):
|
|
25897
|
+
this.checkAllOption();
|
|
25898
|
+
break;
|
|
25899
|
+
default:
|
|
25900
|
+
await super.handleEvent(event);
|
|
25901
|
+
}
|
|
25902
|
+
}
|
|
25903
|
+
hint() {
|
|
25904
|
+
if (this.confirmSubmit) {
|
|
25905
|
+
const info2 = this.isBackButton(this.selectedOption) ? ` To leave the current group press ${getFiguresByKeys(this.settings.keys.back ?? []).join(", ")}.` : isOptionGroup(this.selectedOption) ? ` To open the selected group press ${getFiguresByKeys(this.settings.keys.open ?? []).join(", ")}.` : ` To check or uncheck the selected option press ${getFiguresByKeys(this.settings.keys.check ?? []).join(", ")}.`;
|
|
25906
|
+
return this.settings.indent + brightBlue(`Press ${getFiguresByKeys(this.settings.keys.submit ?? [])} again to submit.${info2}`);
|
|
25907
|
+
}
|
|
25908
|
+
return super.hint();
|
|
25909
|
+
}
|
|
25910
|
+
async submit(hasConfirmed) {
|
|
25911
|
+
if (!hasConfirmed && this.settings.confirmSubmit && !this.isSearchSelected()) {
|
|
25912
|
+
this.confirmSubmit = true;
|
|
25913
|
+
return;
|
|
25914
|
+
}
|
|
25915
|
+
await super.submit();
|
|
25916
|
+
}
|
|
25917
|
+
checkValue() {
|
|
25918
|
+
const option = this.options.at(this.listIndex);
|
|
25919
|
+
if (!option) {
|
|
25920
|
+
this.setErrorMessage("No option available to select.");
|
|
25921
|
+
return;
|
|
25922
|
+
} else if (option.disabled) {
|
|
25923
|
+
this.setErrorMessage("This option is disabled and cannot be changed.");
|
|
25924
|
+
return;
|
|
25925
|
+
}
|
|
25926
|
+
this.checkOption(option, !option.checked);
|
|
25927
|
+
}
|
|
25928
|
+
checkOption(option, checked) {
|
|
25929
|
+
if (isOption2(option)) {
|
|
25930
|
+
option.checked = checked;
|
|
25931
|
+
} else {
|
|
25932
|
+
for (const childOption of option.options) {
|
|
25933
|
+
this.checkOption(childOption, checked);
|
|
25934
|
+
}
|
|
25935
|
+
}
|
|
25936
|
+
}
|
|
25937
|
+
checkAllOption() {
|
|
25938
|
+
const checked = this.options.some((option) => option.checked);
|
|
25939
|
+
for (const option of this.options) {
|
|
25940
|
+
this.checkOption(option, !checked);
|
|
25941
|
+
}
|
|
25942
|
+
}
|
|
25943
|
+
validate(value) {
|
|
25944
|
+
const options = flatOptions(this.settings.options);
|
|
25945
|
+
const isValidValue = Array.isArray(value) && value.every((val) => options.findIndex((option) => equal(option.value, val)) !== -1);
|
|
25946
|
+
if (!isValidValue) {
|
|
25947
|
+
return false;
|
|
25948
|
+
}
|
|
25949
|
+
if (value.length < this.settings.minOptions) {
|
|
25950
|
+
return `The minimum number of options is ${this.settings.minOptions} but got ${value.length}.`;
|
|
25951
|
+
}
|
|
25952
|
+
if (value.length > this.settings.maxOptions) {
|
|
25953
|
+
return `The maximum number of options is ${this.settings.maxOptions} but got ${value.length}.`;
|
|
25954
|
+
}
|
|
25955
|
+
return true;
|
|
25956
|
+
}
|
|
25957
|
+
transform(value) {
|
|
25958
|
+
return value;
|
|
25959
|
+
}
|
|
25960
|
+
format(value) {
|
|
25961
|
+
return value.map((val) => this.settings.format?.(val) ?? this.getOptionByValue(val)?.name ?? String(val)).join(", ");
|
|
25962
|
+
}
|
|
25963
|
+
};
|
|
25964
|
+
});
|
|
25965
|
+
|
|
25966
|
+
// src/commands/workspace/merge.ts
|
|
25967
|
+
async function mergeWorkspaces(opts) {
|
|
25968
|
+
const workspace = await tryResolveBranchWorkspace(opts);
|
|
25969
|
+
if (!workspace) {
|
|
25970
|
+
throw new Error("Could not resolve workspace from branch name. Make sure you are in a git repo with gitBranches configured.");
|
|
25971
|
+
}
|
|
25972
|
+
const token = workspace.token;
|
|
25973
|
+
if (!token) {
|
|
25974
|
+
throw new Error("Not logged in. Please run 'wmill workspace add' first.");
|
|
25975
|
+
}
|
|
25976
|
+
const remote = workspace.remote;
|
|
25977
|
+
setClient(token, remote.endsWith("/") ? remote.substring(0, remote.length - 1) : remote);
|
|
25978
|
+
const forkWorkspaceId = workspace.workspaceId;
|
|
25979
|
+
const userWorkspaces = await listUserWorkspaces();
|
|
25980
|
+
const forkEntry = userWorkspaces.workspaces?.find((w) => w.id === forkWorkspaceId);
|
|
25981
|
+
if (!forkEntry?.parent_workspace_id) {
|
|
25982
|
+
throw new Error(`Workspace '${forkWorkspaceId}' is not a fork (no parent_workspace_id). ` + `You can only merge from a forked workspace.`);
|
|
25983
|
+
}
|
|
25984
|
+
const parentWorkspaceId = forkEntry.parent_workspace_id;
|
|
25985
|
+
info(`Fork: ${colors.bold(forkWorkspaceId)} → Parent: ${colors.bold(parentWorkspaceId)}`);
|
|
25986
|
+
info("Comparing workspaces...");
|
|
25987
|
+
const comparison = await compareWorkspaces({
|
|
25988
|
+
workspace: parentWorkspaceId,
|
|
25989
|
+
targetWorkspaceId: forkWorkspaceId
|
|
25990
|
+
});
|
|
25991
|
+
if (comparison.skipped_comparison) {
|
|
25992
|
+
info(colors.yellow("This fork was created before change tracking was available. " + "Use the UI or git-based merge instead."));
|
|
25993
|
+
return;
|
|
25994
|
+
}
|
|
25995
|
+
const summary = comparison.summary;
|
|
25996
|
+
if (summary.total_diffs === 0) {
|
|
25997
|
+
info(colors.green("Everything is up to date. No differences found."));
|
|
25998
|
+
return;
|
|
25999
|
+
}
|
|
26000
|
+
info("");
|
|
26001
|
+
info(colors.bold("Comparison Summary:"));
|
|
26002
|
+
const summaryRows = [];
|
|
26003
|
+
if (summary.scripts_changed > 0)
|
|
26004
|
+
summaryRows.push(["Scripts", String(summary.scripts_changed)]);
|
|
26005
|
+
if (summary.flows_changed > 0)
|
|
26006
|
+
summaryRows.push(["Flows", String(summary.flows_changed)]);
|
|
26007
|
+
if (summary.apps_changed > 0)
|
|
26008
|
+
summaryRows.push(["Apps", String(summary.apps_changed)]);
|
|
26009
|
+
if (summary.resources_changed > 0)
|
|
26010
|
+
summaryRows.push(["Resources", String(summary.resources_changed)]);
|
|
26011
|
+
if (summary.variables_changed > 0)
|
|
26012
|
+
summaryRows.push(["Variables", String(summary.variables_changed)]);
|
|
26013
|
+
if (summary.resource_types_changed > 0)
|
|
26014
|
+
summaryRows.push(["Resource Types", String(summary.resource_types_changed)]);
|
|
26015
|
+
if (summary.folders_changed > 0)
|
|
26016
|
+
summaryRows.push(["Folders", String(summary.folders_changed)]);
|
|
26017
|
+
summaryRows.push(["Total", String(summary.total_diffs)]);
|
|
26018
|
+
if (summary.conflicts > 0)
|
|
26019
|
+
summaryRows.push([
|
|
26020
|
+
colors.red("Conflicts"),
|
|
26021
|
+
colors.red(String(summary.conflicts))
|
|
26022
|
+
]);
|
|
26023
|
+
new Table2().header(["Type", "Changed"]).padding(2).border(true).body(summaryRows).render();
|
|
26024
|
+
const diffs = comparison.diffs.filter((d) => d.has_changes !== false);
|
|
26025
|
+
if (diffs.length === 0) {
|
|
26026
|
+
info(colors.green("No effective changes to deploy."));
|
|
26027
|
+
return;
|
|
26028
|
+
}
|
|
26029
|
+
info("");
|
|
26030
|
+
info(colors.bold("Changed items:"));
|
|
26031
|
+
new Table2().header(["#", "Kind", "Path", "Ahead", "Behind", "Conflict"]).padding(1).border(true).body(diffs.map((d, i) => {
|
|
26032
|
+
const isConflict = d.ahead > 0 && d.behind > 0;
|
|
26033
|
+
return [
|
|
26034
|
+
String(i + 1),
|
|
26035
|
+
d.kind,
|
|
26036
|
+
d.path,
|
|
26037
|
+
d.ahead > 0 ? colors.green(String(d.ahead)) : "0",
|
|
26038
|
+
d.behind > 0 ? colors.yellow(String(d.behind)) : "0",
|
|
26039
|
+
isConflict ? colors.red("YES") : ""
|
|
26040
|
+
];
|
|
26041
|
+
})).render();
|
|
26042
|
+
let direction;
|
|
26043
|
+
if (opts.direction === "to-parent" || opts.direction === "to-fork") {
|
|
26044
|
+
direction = opts.direction;
|
|
26045
|
+
} else if (opts.direction) {
|
|
26046
|
+
throw new Error(`Invalid direction '${opts.direction}'. Use 'to-parent' or 'to-fork'.`);
|
|
26047
|
+
} else if (opts.yes) {
|
|
26048
|
+
direction = "to-parent";
|
|
26049
|
+
} else {
|
|
26050
|
+
const { Select: Select2 } = await init_select().then(() => exports_select);
|
|
26051
|
+
direction = await Select2.prompt({
|
|
26052
|
+
message: "Deploy direction:",
|
|
26053
|
+
options: [
|
|
26054
|
+
{
|
|
26055
|
+
name: `Deploy to parent (${parentWorkspaceId}) ← fork changes`,
|
|
26056
|
+
value: "to-parent"
|
|
26057
|
+
},
|
|
26058
|
+
{
|
|
26059
|
+
name: `Update fork (${forkWorkspaceId}) ← parent changes`,
|
|
26060
|
+
value: "to-fork"
|
|
26061
|
+
}
|
|
26062
|
+
]
|
|
26063
|
+
});
|
|
26064
|
+
}
|
|
26065
|
+
info(`
|
|
26066
|
+
Direction: ${colors.bold(direction === "to-parent" ? `Fork → Parent (${parentWorkspaceId})` : `Parent → Fork (${forkWorkspaceId})`)}`);
|
|
26067
|
+
const selectableDiffs = diffs.filter((d) => {
|
|
26068
|
+
if (direction === "to-parent") {
|
|
26069
|
+
return d.ahead > 0;
|
|
26070
|
+
} else {
|
|
26071
|
+
return d.behind > 0;
|
|
26072
|
+
}
|
|
26073
|
+
});
|
|
26074
|
+
if (selectableDiffs.length === 0) {
|
|
26075
|
+
info(colors.yellow(`No items to deploy in the '${direction}' direction.`));
|
|
26076
|
+
return;
|
|
26077
|
+
}
|
|
26078
|
+
let selectedDiffs = selectableDiffs;
|
|
26079
|
+
if (opts.all) {
|
|
26080
|
+
selectedDiffs = selectableDiffs;
|
|
26081
|
+
} else if (opts.skipConflicts) {
|
|
26082
|
+
selectedDiffs = selectableDiffs.filter((d) => !(d.ahead > 0 && d.behind > 0));
|
|
26083
|
+
} else if (opts.yes && !opts.include && !opts.exclude) {
|
|
26084
|
+
if (direction === "to-fork") {
|
|
26085
|
+
selectedDiffs = selectableDiffs.filter((d) => !(d.ahead > 0 && d.behind > 0));
|
|
26086
|
+
}
|
|
26087
|
+
} else if (!opts.yes) {
|
|
26088
|
+
const { Checkbox: Checkbox2 } = await init_checkbox().then(() => exports_checkbox);
|
|
26089
|
+
const defaultForToFork = direction === "to-fork";
|
|
26090
|
+
const selectedValues = await Checkbox2.prompt({
|
|
26091
|
+
message: `Select items to deploy (${selectableDiffs.length} available):`,
|
|
26092
|
+
options: selectableDiffs.map((d) => {
|
|
26093
|
+
const isConflict = d.ahead > 0 && d.behind > 0;
|
|
26094
|
+
const label = `${d.kind}:${d.path}${isConflict ? colors.red(" [CONFLICT]") : ""}`;
|
|
26095
|
+
return {
|
|
26096
|
+
name: label,
|
|
26097
|
+
value: `${d.kind}:${d.path}`,
|
|
26098
|
+
checked: defaultForToFork ? !isConflict : true
|
|
26099
|
+
};
|
|
26100
|
+
})
|
|
26101
|
+
});
|
|
26102
|
+
selectedDiffs = selectableDiffs.filter((d) => selectedValues.includes(`${d.kind}:${d.path}`));
|
|
26103
|
+
}
|
|
26104
|
+
if (opts.include) {
|
|
26105
|
+
const includeSet = new Set(opts.include.split(",").map((s) => s.trim()));
|
|
26106
|
+
selectedDiffs = selectedDiffs.filter((d) => includeSet.has(`${d.kind}:${d.path}`));
|
|
26107
|
+
}
|
|
26108
|
+
if (opts.exclude) {
|
|
26109
|
+
const excludeSet = new Set(opts.exclude.split(",").map((s) => s.trim()));
|
|
26110
|
+
selectedDiffs = selectedDiffs.filter((d) => !excludeSet.has(`${d.kind}:${d.path}`));
|
|
26111
|
+
}
|
|
26112
|
+
if (selectedDiffs.length === 0) {
|
|
26113
|
+
info(colors.yellow("No items selected for deployment."));
|
|
26114
|
+
return;
|
|
26115
|
+
}
|
|
26116
|
+
const conflicts = selectedDiffs.filter((d) => d.ahead > 0 && d.behind > 0);
|
|
26117
|
+
if (conflicts.length > 0) {
|
|
26118
|
+
info(colors.yellow(`
|
|
26119
|
+
⚠ ${conflicts.length} conflicting item(s) will be deployed (source will overwrite target):`));
|
|
26120
|
+
for (const c of conflicts) {
|
|
26121
|
+
info(colors.yellow(` - ${c.kind}:${c.path}`));
|
|
26122
|
+
}
|
|
26123
|
+
if (!opts.yes) {
|
|
26124
|
+
const { Confirm: Confirm2 } = await init_confirm().then(() => exports_confirm);
|
|
26125
|
+
const proceed = await Confirm2.prompt("Proceed with deploying conflicting items?");
|
|
26126
|
+
if (!proceed) {
|
|
26127
|
+
info("Aborted.");
|
|
26128
|
+
return;
|
|
26129
|
+
}
|
|
26130
|
+
}
|
|
26131
|
+
}
|
|
26132
|
+
info(`
|
|
26133
|
+
Deploying ${colors.bold(String(selectedDiffs.length))} item(s)...`);
|
|
26134
|
+
const sorted = [...selectedDiffs].sort((a, b) => {
|
|
26135
|
+
const aFolder = a.kind === "folder" ? 0 : 1;
|
|
26136
|
+
const bFolder = b.kind === "folder" ? 0 : 1;
|
|
26137
|
+
return aFolder - bFolder;
|
|
26138
|
+
});
|
|
26139
|
+
const workspaceFrom = direction === "to-parent" ? forkWorkspaceId : parentWorkspaceId;
|
|
26140
|
+
const workspaceTo = direction === "to-parent" ? parentWorkspaceId : forkWorkspaceId;
|
|
26141
|
+
let successCount = 0;
|
|
26142
|
+
let failCount = 0;
|
|
26143
|
+
for (const diff2 of sorted) {
|
|
26144
|
+
const label = `${diff2.kind}:${diff2.path}`;
|
|
26145
|
+
const itemDeletedInSource = direction === "to-parent" ? diff2.exists_in_fork === false : diff2.exists_in_source === false;
|
|
26146
|
+
let result;
|
|
26147
|
+
if (itemDeletedInSource) {
|
|
26148
|
+
info(colors.yellow(` ⌫ ${label} (removing from target)`));
|
|
26149
|
+
result = await deleteItemInWorkspace(provider, diff2.kind, diff2.path, workspaceTo);
|
|
26150
|
+
} else {
|
|
26151
|
+
let onBehalfOf;
|
|
26152
|
+
if (opts.preserveOnBehalfOf) {
|
|
26153
|
+
onBehalfOf = await getOnBehalfOf(provider, diff2.kind, diff2.path, workspaceFrom);
|
|
26154
|
+
}
|
|
26155
|
+
result = await deployItem(provider, diff2.kind, diff2.path, workspaceFrom, workspaceTo, onBehalfOf);
|
|
26156
|
+
}
|
|
26157
|
+
if (result.success) {
|
|
26158
|
+
info(colors.green(` ✓ ${label}`));
|
|
26159
|
+
successCount++;
|
|
26160
|
+
} else {
|
|
26161
|
+
info(colors.red(` ✗ ${label}: ${result.error}`));
|
|
26162
|
+
failCount++;
|
|
26163
|
+
}
|
|
26164
|
+
}
|
|
26165
|
+
if (successCount > 0) {
|
|
26166
|
+
try {
|
|
26167
|
+
await resetDiffTally({
|
|
26168
|
+
workspace: parentWorkspaceId,
|
|
26169
|
+
forkWorkspaceId
|
|
26170
|
+
});
|
|
26171
|
+
} catch {}
|
|
26172
|
+
}
|
|
26173
|
+
info("");
|
|
26174
|
+
if (failCount === 0) {
|
|
26175
|
+
info(colors.green(`✅ Successfully deployed ${successCount} item(s) from ${workspaceFrom} to ${workspaceTo}.`));
|
|
26176
|
+
} else {
|
|
26177
|
+
info(colors.yellow(`Deployed ${successCount} item(s), ${colors.red(String(failCount) + " failed")} from ${workspaceFrom} to ${workspaceTo}.`));
|
|
26178
|
+
}
|
|
26179
|
+
}
|
|
26180
|
+
var provider;
|
|
26181
|
+
var init_merge = __esm(async () => {
|
|
26182
|
+
init_colors2();
|
|
26183
|
+
init_mod6();
|
|
26184
|
+
init_log();
|
|
26185
|
+
init_client();
|
|
26186
|
+
init_services_gen();
|
|
26187
|
+
await init_context();
|
|
26188
|
+
provider = {
|
|
26189
|
+
existsFlowByPath,
|
|
26190
|
+
existsScriptByPath,
|
|
26191
|
+
existsApp,
|
|
26192
|
+
existsVariable,
|
|
26193
|
+
existsResource,
|
|
26194
|
+
existsResourceType,
|
|
26195
|
+
existsFolder,
|
|
26196
|
+
getFlowByPath,
|
|
26197
|
+
createFlow,
|
|
26198
|
+
updateFlow,
|
|
26199
|
+
archiveFlowByPath,
|
|
26200
|
+
getScriptByPath,
|
|
26201
|
+
createScript,
|
|
26202
|
+
archiveScriptByPath,
|
|
26203
|
+
getAppByPath,
|
|
26204
|
+
createApp,
|
|
26205
|
+
updateApp,
|
|
26206
|
+
createAppRaw,
|
|
26207
|
+
updateAppRaw,
|
|
26208
|
+
getPublicSecretOfLatestVersionOfApp,
|
|
26209
|
+
getRawAppData,
|
|
26210
|
+
deleteApp,
|
|
26211
|
+
getVariable,
|
|
26212
|
+
createVariable,
|
|
26213
|
+
updateVariable,
|
|
26214
|
+
deleteVariable,
|
|
26215
|
+
getResource,
|
|
26216
|
+
createResource,
|
|
26217
|
+
updateResource,
|
|
26218
|
+
deleteResource,
|
|
26219
|
+
getResourceType,
|
|
26220
|
+
createResourceType,
|
|
26221
|
+
updateResourceType,
|
|
26222
|
+
deleteResourceType,
|
|
26223
|
+
getFolder,
|
|
26224
|
+
createFolder,
|
|
26225
|
+
updateFolder,
|
|
26226
|
+
deleteFolder
|
|
26227
|
+
};
|
|
26228
|
+
});
|
|
26229
|
+
|
|
25258
26230
|
// src/core/conf.ts
|
|
25259
26231
|
var exports_conf = {};
|
|
25260
26232
|
__export(exports_conf, {
|
|
@@ -25943,11 +26915,12 @@ var init_workspace = __esm(async () => {
|
|
|
25943
26915
|
init_confirm(),
|
|
25944
26916
|
init_input(),
|
|
25945
26917
|
init_auth(),
|
|
25946
|
-
init_fork()
|
|
26918
|
+
init_fork(),
|
|
26919
|
+
init_merge()
|
|
25947
26920
|
]);
|
|
25948
26921
|
command = new Command().alias("profile").description("workspace related commands").action(list2).command("switch").complete("workspace", async () => (await allWorkspaces()).map((x) => x.name)).description("Switch to another workspace").arguments("<workspace_name:string:workspace>").action(switchC).command("add").description("Add a workspace").arguments("[workspace_name:string] [workspace_id:string] [remote:string]").option("-c --create", "Create the workspace if it does not exist").option("--create-workspace-name <workspace_name:string>", "Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.").option("--create-username <username:string>", "Specify your own username in the newly created workspace. Ignored if --create is not specified, the workspace already exists or automatic username creation is enabled on the instance.", {
|
|
25949
26922
|
default: "admin"
|
|
25950
|
-
}).action(add).command("remove").description("Remove a workspace").arguments("<workspace_name:string>").action(remove).command("whoami").description("Show the currently active user").action(whoami2).command("list").description("List local workspace profiles").action(list2).command("list-remote").description("List workspaces on the remote server that you have access to").action(listRemote).command("list-forks").description("List forked workspaces on the remote server").action(listForks).command("bind").description("Bind the current Git branch to the active workspace. This adds the branch to gitBranches in wmill.yaml so sync operations use the correct workspace for each branch.").option("--branch, --env <branch:string>", "Specify branch/environment (defaults to current)").action((opts) => bind(opts, true)).command("unbind").description("Remove workspace binding from the current Git branch").option("--branch, --env <branch:string>", "Specify branch/environment (defaults to current)").action((opts) => bind(opts, false)).command("fork").description("Create a forked workspace").arguments("[workspace_name:string] [workspace_id:string]").option("--create-workspace-name <workspace_name:string>", "Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.").action(createWorkspaceFork2).command("delete-fork").description("Delete a forked workspace and git branch").arguments("<fork_name:string>").option("-y --yes", "Skip confirmation prompt").action(deleteWorkspaceFork);
|
|
26923
|
+
}).action(add).command("remove").description("Remove a workspace").arguments("<workspace_name:string>").action(remove).command("whoami").description("Show the currently active user").action(whoami2).command("list").description("List local workspace profiles").action(list2).command("list-remote").description("List workspaces on the remote server that you have access to").action(listRemote).command("list-forks").description("List forked workspaces on the remote server").action(listForks).command("bind").description("Bind the current Git branch to the active workspace. This adds the branch to gitBranches in wmill.yaml so sync operations use the correct workspace for each branch.").option("--branch, --env <branch:string>", "Specify branch/environment (defaults to current)").action((opts) => bind(opts, true)).command("unbind").description("Remove workspace binding from the current Git branch").option("--branch, --env <branch:string>", "Specify branch/environment (defaults to current)").action((opts) => bind(opts, false)).command("fork").description("Create a forked workspace").arguments("[workspace_name:string] [workspace_id:string]").option("--create-workspace-name <workspace_name:string>", "Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.").option("--color <color:string>", "Workspace color (hex code, e.g. #ff0000)").option("--datatable-behavior <behavior:string>", "How to handle datatables: skip, schema_only, or schema_and_data (default: interactive prompt)").option("-y --yes", "Skip interactive prompts (defaults datatable behavior to 'skip')").action(createWorkspaceFork2).command("delete-fork").description("Delete a forked workspace and git branch").arguments("<fork_name:string>").option("-y --yes", "Skip confirmation prompt").action(deleteWorkspaceFork).command("merge").description("Compare and deploy changes between a fork and its parent workspace").option("--direction <direction:string>", "Deploy direction: to-parent or to-fork").option("--all", "Deploy all changed items including conflicts").option("--skip-conflicts", "Skip items modified in both workspaces").option("--include <items:string>", "Comma-separated kind:path items to include (e.g. script:f/test/main,flow:f/my/flow)").option("--exclude <items:string>", "Comma-separated kind:path items to exclude").option("--preserve-on-behalf-of", "Preserve original on_behalf_of/permissioned_as values").option("-y --yes", "Non-interactive mode (deploy without prompts)").action(mergeWorkspaces);
|
|
25951
26924
|
workspace_default = command;
|
|
25952
26925
|
});
|
|
25953
26926
|
|
|
@@ -63469,9 +64442,9 @@ Push aborted: ${lockIssues.length} script(s) missing locks.`));
|
|
|
63469
64442
|
folderNames.add(parts[1]);
|
|
63470
64443
|
}
|
|
63471
64444
|
}
|
|
63472
|
-
for (const
|
|
63473
|
-
const basePath = path8.join("f",
|
|
63474
|
-
const branchPath = getBranchSpecificPath(`f/${
|
|
64445
|
+
for (const folderName2 of folderNames) {
|
|
64446
|
+
const basePath = path8.join("f", folderName2, "folder.meta.yaml");
|
|
64447
|
+
const branchPath = getBranchSpecificPath(`f/${folderName2}/folder.meta.yaml`, specificItems, opts.branch);
|
|
63475
64448
|
let found = false;
|
|
63476
64449
|
if (branchPath) {
|
|
63477
64450
|
try {
|
|
@@ -63486,7 +64459,7 @@ Push aborted: ${lockIssues.length} script(s) missing locks.`));
|
|
|
63486
64459
|
} catch {}
|
|
63487
64460
|
}
|
|
63488
64461
|
if (!found) {
|
|
63489
|
-
missingFolders.push(
|
|
64462
|
+
missingFolders.push(folderName2);
|
|
63490
64463
|
}
|
|
63491
64464
|
}
|
|
63492
64465
|
}
|
|
@@ -67514,12 +68487,12 @@ CREATE SCHEMA IF NOT EXISTS ${schemaName};
|
|
|
67514
68487
|
info(colors.gray("You can configure datatables in Workspace Settings > Windmill Data Tables"));
|
|
67515
68488
|
}
|
|
67516
68489
|
await loadNonDottedPathsSetting();
|
|
67517
|
-
const
|
|
67518
|
-
const appDir = path15.join(process.cwd(),
|
|
68490
|
+
const folderName2 = buildFolderPath(appPath, "raw_app");
|
|
68491
|
+
const appDir = path15.join(process.cwd(), folderName2);
|
|
67519
68492
|
try {
|
|
67520
68493
|
await stat8(appDir);
|
|
67521
68494
|
const overwrite = await Confirm.prompt({
|
|
67522
|
-
message: `Directory '${
|
|
68495
|
+
message: `Directory '${folderName2}' already exists. Overwrite?`,
|
|
67523
68496
|
default: false
|
|
67524
68497
|
});
|
|
67525
68498
|
if (!overwrite) {
|
|
@@ -67593,10 +68566,10 @@ This folder is for SQL migration files that will be applied to datatables during
|
|
|
67593
68566
|
await writeFile9(path15.join(appDir, "sql_to_apply", `000_create_schema_${schemaName}.sql`), createSchemaSQL, "utf-8");
|
|
67594
68567
|
}
|
|
67595
68568
|
info("");
|
|
67596
|
-
info(colors.bold.green(`App created successfully at ${
|
|
68569
|
+
info(colors.bold.green(`App created successfully at ${folderName2}/`));
|
|
67597
68570
|
info("");
|
|
67598
68571
|
info(colors.gray("Directory structure:"));
|
|
67599
|
-
info(colors.gray(` ${
|
|
68572
|
+
info(colors.gray(` ${folderName2}/`));
|
|
67600
68573
|
info(colors.gray(" ├── AGENTS.md ← Read this first!"));
|
|
67601
68574
|
info(colors.gray(" ├── raw_app.yaml"));
|
|
67602
68575
|
info(colors.gray(" ├── DATATABLES.md"));
|
|
@@ -67621,7 +68594,7 @@ This folder is for SQL migration files that will be applied to datatables during
|
|
|
67621
68594
|
info("");
|
|
67622
68595
|
}
|
|
67623
68596
|
info(colors.bold.cyan("Next steps:"));
|
|
67624
|
-
info(colors.gray(` 1. cd ${
|
|
68597
|
+
info(colors.gray(` 1. cd ${folderName2}`));
|
|
67625
68598
|
info(colors.gray(" 2. npm install"));
|
|
67626
68599
|
info(colors.bold.white(" 3. wmill app dev .") + colors.gray(" (start dev server)"));
|
|
67627
68600
|
if (createSchemaSQL) {
|
|
@@ -68717,91 +69690,6 @@ var init_schedule = __esm(async () => {
|
|
|
68717
69690
|
schedule_default = command15;
|
|
68718
69691
|
});
|
|
68719
69692
|
|
|
68720
|
-
// src/commands/worker-groups/worker-groups.ts
|
|
68721
|
-
async function getInstance(opts) {
|
|
68722
|
-
const instances = await allInstances();
|
|
68723
|
-
const instanceName = await getActiveInstance(opts);
|
|
68724
|
-
const instance = instances.find((i) => i.name === instanceName);
|
|
68725
|
-
if (instance) {
|
|
68726
|
-
setClient(instance.token, instance.remote.slice(0, instance.remote.length - 1));
|
|
68727
|
-
}
|
|
68728
|
-
return instance;
|
|
68729
|
-
}
|
|
68730
|
-
function removeWorkerPrefix(name) {
|
|
68731
|
-
if (name.startsWith("worker__")) {
|
|
68732
|
-
return name.substring(8);
|
|
68733
|
-
}
|
|
68734
|
-
return name;
|
|
68735
|
-
}
|
|
68736
|
-
async function displayWorkerGroups(opts) {
|
|
68737
|
-
info("2 actions available, pull and push.");
|
|
68738
|
-
const activeInstance = await getActiveInstance({});
|
|
68739
|
-
if (activeInstance) {
|
|
68740
|
-
info("Active instance: " + activeInstance);
|
|
68741
|
-
const instance = await getInstance({});
|
|
68742
|
-
if (instance) {
|
|
68743
|
-
const wGroups = await listWorkerGroups();
|
|
68744
|
-
new Table2().header(["name", "config"]).padding(2).border(true).body(wGroups.map((x) => [removeWorkerPrefix(x.name), JSON.stringify(x.config, null, 2)])).render();
|
|
68745
|
-
} else {
|
|
68746
|
-
error(`Instance ${activeInstance} not found`);
|
|
68747
|
-
}
|
|
68748
|
-
} else {
|
|
68749
|
-
info("No active instance found");
|
|
68750
|
-
info("Use 'wmill instance add' to add a new instance");
|
|
68751
|
-
}
|
|
68752
|
-
}
|
|
68753
|
-
async function pullWorkerGroups(opts) {
|
|
68754
|
-
await pickInstance(opts, true);
|
|
68755
|
-
const totalChanges = await pullInstanceConfigs(opts, true) ?? 0;
|
|
68756
|
-
if (totalChanges === 0) {
|
|
68757
|
-
info("No changes to apply");
|
|
68758
|
-
return;
|
|
68759
|
-
}
|
|
68760
|
-
let confirm = true;
|
|
68761
|
-
if (opts.yes !== true) {
|
|
68762
|
-
confirm = await Confirm.prompt({
|
|
68763
|
-
message: `Do you want to pul these ${totalChanges} instance-level changes?`,
|
|
68764
|
-
default: true
|
|
68765
|
-
});
|
|
68766
|
-
}
|
|
68767
|
-
if (confirm) {
|
|
68768
|
-
await pullInstanceConfigs(opts, false);
|
|
68769
|
-
}
|
|
68770
|
-
}
|
|
68771
|
-
async function pushWorkerGroups(opts) {
|
|
68772
|
-
await pickInstance(opts, true);
|
|
68773
|
-
const totalChanges = await pushInstanceConfigs(opts, true) ?? 0;
|
|
68774
|
-
if (totalChanges === 0) {
|
|
68775
|
-
info("No changes to apply");
|
|
68776
|
-
return;
|
|
68777
|
-
}
|
|
68778
|
-
let confirm = true;
|
|
68779
|
-
if (opts.yes !== true) {
|
|
68780
|
-
confirm = await Confirm.prompt({
|
|
68781
|
-
message: `Do you want to apply these ${totalChanges} instance-level changes?`,
|
|
68782
|
-
default: true
|
|
68783
|
-
});
|
|
68784
|
-
}
|
|
68785
|
-
if (confirm) {
|
|
68786
|
-
await pushInstanceConfigs(opts, false);
|
|
68787
|
-
}
|
|
68788
|
-
}
|
|
68789
|
-
var command16, worker_groups_default;
|
|
68790
|
-
var init_worker_groups = __esm(async () => {
|
|
68791
|
-
init_mod3();
|
|
68792
|
-
init_mod6();
|
|
68793
|
-
init_log();
|
|
68794
|
-
init_client();
|
|
68795
|
-
init_services_gen();
|
|
68796
|
-
await __promiseAll([
|
|
68797
|
-
init_confirm(),
|
|
68798
|
-
init_instance(),
|
|
68799
|
-
init_settings()
|
|
68800
|
-
]);
|
|
68801
|
-
command16 = new Command().description("display worker groups, pull and push worker groups configs").action(displayWorkerGroups).command("pull").description("Pull worker groups (similar to `wmill instance pull --skip-users --skip-settings --skip-groups`)").option("--instance", "Name of the instance to push to, override the active instance").option("--base-url", "Base url to be passed to the instance settings instead of the local one").option("--yes", "Pull without needing confirmation").action(pullWorkerGroups).command("push").description("Push instance settings, users, configs, group and overwrite remote").option("--instance [instance]", "Name of the instance to push to, override the active instance").option("--base-url [baseUrl]", "If used with --token, will be used as the base url for the instance").option("--yes", "Push without needing confirmation").action(pushWorkerGroups);
|
|
68802
|
-
worker_groups_default = command16;
|
|
68803
|
-
});
|
|
68804
|
-
|
|
68805
69693
|
// src/utils/local_encryption.ts
|
|
68806
69694
|
import crypto3 from "node:crypto";
|
|
68807
69695
|
function encode2(input) {
|
|
@@ -69265,12 +70153,7 @@ async function readLocalConfigs(opts) {
|
|
|
69265
70153
|
return localConfigs;
|
|
69266
70154
|
}
|
|
69267
70155
|
async function pullInstanceConfigs(opts, preview2 = false) {
|
|
69268
|
-
const remoteConfigs =
|
|
69269
|
-
return {
|
|
69270
|
-
...x,
|
|
69271
|
-
name: removeWorkerPrefix(x.name)
|
|
69272
|
-
};
|
|
69273
|
-
});
|
|
70156
|
+
const remoteConfigs = await listWorkerGroups();
|
|
69274
70157
|
if (preview2) {
|
|
69275
70158
|
const localConfigs = await readLocalConfigs(opts);
|
|
69276
70159
|
return compareInstanceObjects(remoteConfigs, localConfigs, "name", "config");
|
|
@@ -69281,12 +70164,7 @@ async function pullInstanceConfigs(opts, preview2 = false) {
|
|
|
69281
70164
|
}
|
|
69282
70165
|
}
|
|
69283
70166
|
async function pushInstanceConfigs(opts, preview2 = false) {
|
|
69284
|
-
const remoteConfigs =
|
|
69285
|
-
return {
|
|
69286
|
-
...x,
|
|
69287
|
-
name: removeWorkerPrefix(x.name)
|
|
69288
|
-
};
|
|
69289
|
-
});
|
|
70167
|
+
const remoteConfigs = await listWorkerGroups();
|
|
69290
70168
|
const localConfigs = await readLocalConfigs(opts);
|
|
69291
70169
|
if (preview2) {
|
|
69292
70170
|
return compareInstanceObjects(localConfigs, remoteConfigs, "name", "config");
|
|
@@ -69299,7 +70177,7 @@ async function pushInstanceConfigs(opts, preview2 = false) {
|
|
|
69299
70177
|
}
|
|
69300
70178
|
try {
|
|
69301
70179
|
await updateConfig({
|
|
69302
|
-
name:
|
|
70180
|
+
name: `worker__${config.name}`,
|
|
69303
70181
|
requestBody: config.config
|
|
69304
70182
|
});
|
|
69305
70183
|
} catch (err) {
|
|
@@ -69311,7 +70189,7 @@ async function pushInstanceConfigs(opts, preview2 = false) {
|
|
|
69311
70189
|
if (!localMatch) {
|
|
69312
70190
|
try {
|
|
69313
70191
|
await deleteConfig({
|
|
69314
|
-
name: removeConfig.name
|
|
70192
|
+
name: `worker__${removeConfig.name}`
|
|
69315
70193
|
});
|
|
69316
70194
|
} catch (err) {
|
|
69317
70195
|
error(`Failed to delete config ${removeConfig.name}: ${err}`);
|
|
@@ -69332,8 +70210,7 @@ var init_settings = __esm(async () => {
|
|
|
69332
70210
|
init_confirm(),
|
|
69333
70211
|
init_instance(),
|
|
69334
70212
|
init_types(),
|
|
69335
|
-
init_utils()
|
|
69336
|
-
init_worker_groups()
|
|
70213
|
+
init_utils()
|
|
69337
70214
|
]);
|
|
69338
70215
|
import_yaml28 = __toESM(require_dist(), 1);
|
|
69339
70216
|
instanceSettingsPath = INSTANCE_SETTINGS_PATH;
|
|
@@ -69841,7 +70718,7 @@ async function whoami3(opts) {
|
|
|
69841
70718
|
error(colors.red(`Failed to retrieve whoami information: ${error2.message}`));
|
|
69842
70719
|
}
|
|
69843
70720
|
}
|
|
69844
|
-
var import_yaml29,
|
|
70721
|
+
var import_yaml29, command16, instance_default;
|
|
69845
70722
|
var init_instance = __esm(async () => {
|
|
69846
70723
|
init_colors2();
|
|
69847
70724
|
init_mod3();
|
|
@@ -69865,7 +70742,7 @@ var init_instance = __esm(async () => {
|
|
|
69865
70742
|
init_workspace()
|
|
69866
70743
|
]);
|
|
69867
70744
|
import_yaml29 = __toESM(require_dist(), 1);
|
|
69868
|
-
|
|
70745
|
+
command16 = new Command().description("sync local with a remote instance or the opposite (push or pull)").action(async () => {
|
|
69869
70746
|
info("4 actions available, add, remove, switch, pull and push. Use -h to display help.");
|
|
69870
70747
|
const activeInstance = await getActiveInstance({});
|
|
69871
70748
|
new Table2().header(["name", "remote", "token"]).padding(2).border(true).body((await allInstances()).map((x) => [
|
|
@@ -69890,8 +70767,8 @@ var init_instance = __esm(async () => {
|
|
|
69890
70767
|
});
|
|
69891
70768
|
await removeInstance(choice);
|
|
69892
70769
|
info(colors.green.underline(`Removed instance ${choice}`));
|
|
69893
|
-
}).command("switch").complete("instance", async () => (await allInstances()).map((x) => x.name)).arguments("<instance:string:instance>").description("Switch the current instance").action(switchI).command("pull").description("Pull instance settings, users, configs, instance groups and overwrite local").option("--yes", "Pull without needing confirmation").option("--dry-run", "Perform a dry run without making changes").option("--skip-users", "Skip pulling users").option("--skip-settings", "Skip pulling settings").option("--skip-configs", "Skip pulling configs (worker groups
|
|
69894
|
-
instance_default =
|
|
70770
|
+
}).command("switch").complete("instance", async () => (await allInstances()).map((x) => x.name)).arguments("<instance:string:instance>").description("Switch the current instance").action(switchI).command("pull").description("Pull instance settings, users, configs, instance groups and overwrite local").option("--yes", "Pull without needing confirmation").option("--dry-run", "Perform a dry run without making changes").option("--skip-users", "Skip pulling users").option("--skip-settings", "Skip pulling settings").option("--skip-configs", "Skip pulling configs (worker groups)").option("--skip-groups", "Skip pulling instance groups").option("--include-workspaces", "Also pull workspaces").option("--folder-per-instance", "Create a folder per instance").option("--instance <instance:string>", "Name of the instance to pull from, override the active instance").option("--prefix <prefix:string>", "Prefix of the local workspaces to pull, used to create the folders when using --include-workspaces").option("--prefix-settings", "Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance").action(instancePull).command("push").description("Push instance settings, users, configs, group and overwrite remote").option("--yes", "Push without needing confirmation").option("--dry-run", "Perform a dry run without making changes").option("--skip-users", "Skip pushing users").option("--skip-settings", "Skip pushing settings").option("--skip-configs", "Skip pushing configs (worker groups)").option("--skip-groups", "Skip pushing instance groups").option("--include-workspaces", "Also push workspaces").option("--folder-per-instance", "Create a folder per instance").option("--instance <instance:string>", "Name of the instance to push to, override the active instance").option("--prefix <prefix:string>", "Prefix of the local workspaces folders to push").option("--prefix-settings", "Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance").action(instancePush).command("whoami").description("Display information about the currently logged-in user").action(whoami3).command("get-config").description("Dump the current instance config (global settings + worker configs) as YAML").option("-o, --output-file <file:string>", "Write YAML to a file instead of stdout").option("--show-secrets", "Include sensitive fields (license key, JWT secret) without prompting").option("--instance <instance:string>", "Name of the instance, override the active instance").action(getConfig2);
|
|
70771
|
+
instance_default = command16;
|
|
69895
70772
|
});
|
|
69896
70773
|
|
|
69897
70774
|
// src/commands/user/user.ts
|
|
@@ -70246,7 +71123,7 @@ async function pushInstanceGroups(opts, preview2 = false) {
|
|
|
70246
71123
|
info(colors.green("Groups pushed to the instance"));
|
|
70247
71124
|
}
|
|
70248
71125
|
}
|
|
70249
|
-
var import_yaml31, INSTANCE_USERS_PATH = "instance_users.yaml", instanceUsersPath, INSTANCE_GROUPS_PATH = "instance_groups.yaml", instanceGroupsPath,
|
|
71126
|
+
var import_yaml31, INSTANCE_USERS_PATH = "instance_users.yaml", instanceUsersPath, INSTANCE_GROUPS_PATH = "instance_groups.yaml", instanceGroupsPath, command17, user_default;
|
|
70250
71127
|
var init_user = __esm(async () => {
|
|
70251
71128
|
init_colors2();
|
|
70252
71129
|
init_mod3();
|
|
@@ -70262,12 +71139,12 @@ var init_user = __esm(async () => {
|
|
|
70262
71139
|
import_yaml31 = __toESM(require_dist(), 1);
|
|
70263
71140
|
instanceUsersPath = INSTANCE_USERS_PATH;
|
|
70264
71141
|
instanceGroupsPath = INSTANCE_GROUPS_PATH;
|
|
70265
|
-
|
|
71142
|
+
command17 = new Command().description("user related commands").action(list10).command("add", "Create a user").arguments("<email:string> [password:string]").option("--superadmin", "Specify to make the new user superadmin.").option("--company <company:string>", "Specify to set the company of the new user.").option("--name <name:string>", "Specify to set the name of the new user.").action(add3).command("remove", "Delete a user").arguments("<email:string>").action(remove2).command("create-token", "Create a new API token for the authenticated user").option("--email <email:string>", "Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.", {
|
|
70266
71143
|
depends: ["password"]
|
|
70267
71144
|
}).option("--password <password:string>", "Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.", {
|
|
70268
71145
|
depends: ["email"]
|
|
70269
71146
|
}).action(createToken2);
|
|
70270
|
-
user_default =
|
|
71147
|
+
user_default = command17;
|
|
70271
71148
|
});
|
|
70272
71149
|
|
|
70273
71150
|
// src/commands/dependencies/dependencies.ts
|
|
@@ -70316,7 +71193,7 @@ async function pushWorkspaceDependencies(workspace, path18, _befObj, newDependen
|
|
|
70316
71193
|
});
|
|
70317
71194
|
info(colors.green(`Successfully pushed ${displayName} for ${language}`));
|
|
70318
71195
|
}
|
|
70319
|
-
var
|
|
71196
|
+
var command18, dependencies_default;
|
|
70320
71197
|
var init_dependencies = __esm(async () => {
|
|
70321
71198
|
init_colors2();
|
|
70322
71199
|
init_mod3();
|
|
@@ -70327,8 +71204,8 @@ var init_dependencies = __esm(async () => {
|
|
|
70327
71204
|
init_context(),
|
|
70328
71205
|
init_metadata()
|
|
70329
71206
|
]);
|
|
70330
|
-
|
|
70331
|
-
dependencies_default =
|
|
71207
|
+
command18 = new Command().alias("deps").description("workspace dependencies related commands").command("push", "Push workspace dependencies from a local file").arguments("<file_path:string>").action(push9);
|
|
71208
|
+
dependencies_default = command18;
|
|
70332
71209
|
});
|
|
70333
71210
|
|
|
70334
71211
|
// src/commands/trigger/trigger.ts
|
|
@@ -70671,7 +71548,7 @@ async function push10(opts, filePath, remotePath) {
|
|
|
70671
71548
|
await pushTrigger(triggerKind, workspace.workspaceId, remotePath, undefined, parseFromFile(filePath));
|
|
70672
71549
|
console.log(colors.bold.underline.green("Trigger pushed"));
|
|
70673
71550
|
}
|
|
70674
|
-
var import_yaml33, triggerTemplates, TRIGGER_SKIP_FIELDS,
|
|
71551
|
+
var import_yaml33, triggerTemplates, TRIGGER_SKIP_FIELDS, command19, trigger_default;
|
|
70675
71552
|
var init_trigger = __esm(async () => {
|
|
70676
71553
|
init_services_gen();
|
|
70677
71554
|
init_mod3();
|
|
@@ -70768,8 +71645,8 @@ var init_trigger = __esm(async () => {
|
|
|
70768
71645
|
}
|
|
70769
71646
|
};
|
|
70770
71647
|
TRIGGER_SKIP_FIELDS = new Set(["workspace_id", "extra_perms", "edited_by", "edited_at"]);
|
|
70771
|
-
|
|
70772
|
-
trigger_default =
|
|
71648
|
+
command19 = new Command().description("trigger related commands").option("--json", "Output as JSON (for piping to jq)").action(list11).command("list", "list all triggers").option("--json", "Output as JSON (for piping to jq)").action(list11).command("get", "get a trigger's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").option("--kind <kind:string>", "Trigger kind (http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, email). Recommended for faster lookup").action(get8).command("new", "create a new trigger locally").arguments("<path:string>").option("--kind <kind:string>", "Trigger kind (required: http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, email)").action(newTrigger).command("push", "push a local trigger spec. This overrides any remote versions.").arguments("<file_path:string> <remote_path:string>").action(push10);
|
|
71649
|
+
trigger_default = command19;
|
|
70773
71650
|
});
|
|
70774
71651
|
|
|
70775
71652
|
// src/types.ts
|
|
@@ -71673,7 +72550,7 @@ async function showVersion(opts, flowPath, version) {
|
|
|
71673
72550
|
console.log(JSON.stringify(flow.value, null, 2));
|
|
71674
72551
|
}
|
|
71675
72552
|
}
|
|
71676
|
-
var import_yaml36, alreadySynced3,
|
|
72553
|
+
var import_yaml36, alreadySynced3, command20, flow_default;
|
|
71677
72554
|
var init_flow = __esm(async () => {
|
|
71678
72555
|
init_colors2();
|
|
71679
72556
|
init_mod3();
|
|
@@ -71698,8 +72575,8 @@ var init_flow = __esm(async () => {
|
|
|
71698
72575
|
]);
|
|
71699
72576
|
import_yaml36 = __toESM(require_dist(), 1);
|
|
71700
72577
|
alreadySynced3 = [];
|
|
71701
|
-
|
|
71702
|
-
flow_default =
|
|
72578
|
+
command20 = new Command().description("flow related commands").option("--show-archived", "Enable archived flows in output").option("--json", "Output as JSON (for piping to jq)").action(list12).command("list", "list all flows").option("--show-archived", "Enable archived flows in output").option("--json", "Output as JSON (for piping to jq)").action(list12).command("get", "get a flow's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get9).command("push", "push a local flow spec. This overrides any remote versions.").arguments("<file_path:string> <remote_path:string>").option("--message <message:string>", "Deployment message").action(push11).command("run", "run a flow by path.").arguments("<path:string>").option("-d --data <data:string>", "Inputs specified as a JSON string or a file using @<filename> or stdin using @-.").option("-s --silent", "Do not ouput anything other then the final output. Useful for scripting.").action(run3).command("preview", "preview a local flow without deploying it. Runs the flow definition from local files and uses local PathScripts by default.").arguments("<flow_path:string>").option("-d --data <data:string>", "Inputs specified as a JSON string or a file using @<filename> or stdin using @-.").option("-s --silent", "Do not output anything other then the final output. Useful for scripting.").option("--remote", "Use deployed workspace scripts for PathScript steps instead of local files.").action(preview2).command("generate-locks", 'DEPRECATED: re-generate flow lock files. Use "wmill generate-metadata" instead.').arguments("[flow:file]").option("--yes", "Skip confirmation prompt").option("--dry-run", "Perform a dry run without making changes").option("-i --includes <patterns:file[]>", "Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string)").option("-e --excludes <patterns:file[]>", "Comma separated patterns to specify which file to NOT take into account.").action(generateLocks).command("new", "create a new empty flow").arguments("<flow_path:string>").option("--summary <summary:string>", "flow summary").option("--description <description:string>", "flow description").action(bootstrap2).command("bootstrap", "create a new empty flow (alias for new)").arguments("<flow_path:string>").option("--summary <summary:string>", "flow summary").option("--description <description:string>", "flow description").action(bootstrap2).command("history", "Show version history for a flow").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(history2).command("show-version", "Show a specific version of a flow").arguments("<path:string> <version:string>").option("--json", "Output as JSON (for piping to jq)").action(showVersion);
|
|
72579
|
+
flow_default = command20;
|
|
71703
72580
|
});
|
|
71704
72581
|
|
|
71705
72582
|
// src/commands/gitsync-settings/converter.ts
|
|
@@ -72638,15 +73515,15 @@ __export(exports_gitsync_settings, {
|
|
|
72638
73515
|
pullGitSyncSettings: () => pullGitSyncSettings,
|
|
72639
73516
|
default: () => gitsync_settings_default
|
|
72640
73517
|
});
|
|
72641
|
-
var
|
|
73518
|
+
var command22, gitsync_settings_default;
|
|
72642
73519
|
var init_gitsync_settings = __esm(async () => {
|
|
72643
73520
|
init_mod3();
|
|
72644
73521
|
await __promiseAll([
|
|
72645
73522
|
init_pull2(),
|
|
72646
73523
|
init_push()
|
|
72647
73524
|
]);
|
|
72648
|
-
|
|
72649
|
-
gitsync_settings_default =
|
|
73525
|
+
command22 = new Command().description("Manage git-sync settings between local wmill.yaml and Windmill backend").command("pull").description("Pull git-sync settings from Windmill backend to local wmill.yaml").option("--repository <repo:string>", "Specify repository path (e.g., u/user/repo)").option("--default", "Write settings to top-level defaults instead of overrides").option("--replace", "Replace existing settings (non-interactive mode)").option("--override", "Add branch-specific override (non-interactive mode)").option("--diff", "Show differences without applying changes").option("--json-output", "Output in JSON format").option("--with-backend-settings <json:string>", "Use provided JSON settings instead of querying backend (for testing)").option("--yes", "Skip interactive prompts and use default behavior").option("--promotion <branch:string>", "Use promotionOverrides from the specified branch instead of regular overrides").action(pullGitSyncSettings).command("push").description("Push git-sync settings from local wmill.yaml to Windmill backend").option("--repository <repo:string>", "Specify repository path (e.g., u/user/repo)").option("--diff", "Show what would be pushed without applying changes").option("--json-output", "Output in JSON format").option("--with-backend-settings <json:string>", "Use provided JSON settings instead of querying backend (for testing)").option("--yes", "Skip interactive prompts and use default behavior").option("--promotion <branch:string>", "Use promotionOverrides from the specified branch instead of regular overrides").action(pushGitSyncSettings);
|
|
73526
|
+
gitsync_settings_default = command22;
|
|
72650
73527
|
});
|
|
72651
73528
|
|
|
72652
73529
|
// src/utils/dependency_tree.ts
|
|
@@ -74194,8 +75071,8 @@ async function pull2(opts) {
|
|
|
74194
75071
|
await pushResourceType(workspace.workspaceId, x.name + ".resource-type.json", undefined, x);
|
|
74195
75072
|
}
|
|
74196
75073
|
}
|
|
74197
|
-
var
|
|
74198
|
-
var hub_default =
|
|
75074
|
+
var command21 = new Command().name("hub").description("Hub related commands. EXPERIMENTAL. INTERNAL USE ONLY.").command("pull").description("pull any supported definitions. EXPERIMENTAL.").action(pull2);
|
|
75075
|
+
var hub_default = command21;
|
|
74199
75076
|
|
|
74200
75077
|
// src/main.ts
|
|
74201
75078
|
await __promiseAll([
|
|
@@ -74204,10 +75081,93 @@ await __promiseAll([
|
|
|
74204
75081
|
init_trigger(),
|
|
74205
75082
|
init_sync(),
|
|
74206
75083
|
init_gitsync_settings(),
|
|
75084
|
+
init_instance()
|
|
75085
|
+
]);
|
|
75086
|
+
|
|
75087
|
+
// src/commands/worker-groups/worker-groups.ts
|
|
75088
|
+
init_mod3();
|
|
75089
|
+
init_mod6();
|
|
75090
|
+
init_log();
|
|
75091
|
+
init_client();
|
|
75092
|
+
init_services_gen();
|
|
75093
|
+
await __promiseAll([
|
|
75094
|
+
init_confirm(),
|
|
74207
75095
|
init_instance(),
|
|
74208
|
-
|
|
74209
|
-
init_lint()
|
|
75096
|
+
init_settings()
|
|
74210
75097
|
]);
|
|
75098
|
+
async function getInstance(opts) {
|
|
75099
|
+
const instances = await allInstances();
|
|
75100
|
+
const instanceName = await getActiveInstance(opts);
|
|
75101
|
+
const instance = instances.find((i) => i.name === instanceName);
|
|
75102
|
+
if (instance) {
|
|
75103
|
+
setClient(instance.token, instance.remote.slice(0, instance.remote.length - 1));
|
|
75104
|
+
}
|
|
75105
|
+
return instance;
|
|
75106
|
+
}
|
|
75107
|
+
function removeWorkerPrefix(name) {
|
|
75108
|
+
if (name.startsWith("worker__")) {
|
|
75109
|
+
return name.substring(8);
|
|
75110
|
+
}
|
|
75111
|
+
return name;
|
|
75112
|
+
}
|
|
75113
|
+
async function displayWorkerGroups(opts) {
|
|
75114
|
+
info("2 actions available, pull and push.");
|
|
75115
|
+
const activeInstance = await getActiveInstance({});
|
|
75116
|
+
if (activeInstance) {
|
|
75117
|
+
info("Active instance: " + activeInstance);
|
|
75118
|
+
const instance = await getInstance({});
|
|
75119
|
+
if (instance) {
|
|
75120
|
+
const wGroups = await listWorkerGroups();
|
|
75121
|
+
new Table2().header(["name", "config"]).padding(2).border(true).body(wGroups.map((x) => [removeWorkerPrefix(x.name), JSON.stringify(x.config, null, 2)])).render();
|
|
75122
|
+
} else {
|
|
75123
|
+
error(`Instance ${activeInstance} not found`);
|
|
75124
|
+
}
|
|
75125
|
+
} else {
|
|
75126
|
+
info("No active instance found");
|
|
75127
|
+
info("Use 'wmill instance add' to add a new instance");
|
|
75128
|
+
}
|
|
75129
|
+
}
|
|
75130
|
+
async function pullWorkerGroups(opts) {
|
|
75131
|
+
await pickInstance(opts, true);
|
|
75132
|
+
const totalChanges = await pullInstanceConfigs(opts, true) ?? 0;
|
|
75133
|
+
if (totalChanges === 0) {
|
|
75134
|
+
info("No changes to apply");
|
|
75135
|
+
return;
|
|
75136
|
+
}
|
|
75137
|
+
let confirm = true;
|
|
75138
|
+
if (opts.yes !== true) {
|
|
75139
|
+
confirm = await Confirm.prompt({
|
|
75140
|
+
message: `Do you want to pul these ${totalChanges} instance-level changes?`,
|
|
75141
|
+
default: true
|
|
75142
|
+
});
|
|
75143
|
+
}
|
|
75144
|
+
if (confirm) {
|
|
75145
|
+
await pullInstanceConfigs(opts, false);
|
|
75146
|
+
}
|
|
75147
|
+
}
|
|
75148
|
+
async function pushWorkerGroups(opts) {
|
|
75149
|
+
await pickInstance(opts, true);
|
|
75150
|
+
const totalChanges = await pushInstanceConfigs(opts, true) ?? 0;
|
|
75151
|
+
if (totalChanges === 0) {
|
|
75152
|
+
info("No changes to apply");
|
|
75153
|
+
return;
|
|
75154
|
+
}
|
|
75155
|
+
let confirm = true;
|
|
75156
|
+
if (opts.yes !== true) {
|
|
75157
|
+
confirm = await Confirm.prompt({
|
|
75158
|
+
message: `Do you want to apply these ${totalChanges} instance-level changes?`,
|
|
75159
|
+
default: true
|
|
75160
|
+
});
|
|
75161
|
+
}
|
|
75162
|
+
if (confirm) {
|
|
75163
|
+
await pushInstanceConfigs(opts, false);
|
|
75164
|
+
}
|
|
75165
|
+
}
|
|
75166
|
+
var command23 = new Command().description("display worker groups, pull and push worker groups configs").action(displayWorkerGroups).command("pull").description("Pull worker groups (similar to `wmill instance pull --skip-users --skip-settings --skip-groups`)").option("--instance", "Name of the instance to push to, override the active instance").option("--base-url", "Base url to be passed to the instance settings instead of the local one").option("--yes", "Pull without needing confirmation").action(pullWorkerGroups).command("push").description("Push worker groups (similar to `wmill instance push --skip-users --skip-settings --skip-groups`)").option("--instance [instance]", "Name of the instance to push to, override the active instance").option("--base-url [baseUrl]", "If used with --token, will be used as the base url for the instance").option("--yes", "Push without needing confirmation").action(pushWorkerGroups);
|
|
75167
|
+
var worker_groups_default = command23;
|
|
75168
|
+
|
|
75169
|
+
// src/main.ts
|
|
75170
|
+
await init_lint();
|
|
74211
75171
|
|
|
74212
75172
|
// src/commands/dev/dev.ts
|
|
74213
75173
|
init_mod3();
|
|
@@ -79080,7 +80040,7 @@ Reference a specific resource using \`$res:\` prefix:
|
|
|
79080
80040
|
|
|
79081
80041
|
## OpenFlow Schema
|
|
79082
80042
|
|
|
79083
|
-
{"OpenFlow":{"type":"object","description":"Top-level flow definition containing metadata, configuration, and the flow structure","properties":{"summary":{"type":"string","description":"Short description of what this flow does"},"description":{"type":"string","description":"Detailed documentation for this flow"},"value":{"$ref":"#/components/schemas/FlowValue"},"schema":{"type":"object","description":"JSON Schema for flow inputs. Use this to define input parameters, their types, defaults, and validation. For resource inputs, set type to 'object' and format to 'resource-<type>' (e.g., 'resource-stripe')"},"on_behalf_of_email":{"type":"string","description":"The flow will be run with the permissions of the user with this email."}},"required":["summary","value"]},"FlowValue":{"type":"object","description":"The flow structure containing modules and optional preprocessor/failure handlers","properties":{"modules":{"type":"array","description":"Array of steps that execute in sequence. Each step can be a script, subflow, loop, or branch","items":{"$ref":"#/components/schemas/FlowModule"}},"failure_module":{"description":"Special module that executes when the flow fails. Receives error object with message, name, stack, and step_id. Must have id 'failure'. Only supports script/rawscript types","$ref":"#/components/schemas/FlowModule"},"preprocessor_module":{"description":"Special module that runs before the first step on external triggers. Must have id 'preprocessor'. Only supports script/rawscript types. Cannot reference other step results","$ref":"#/components/schemas/FlowModule"},"same_worker":{"type":"boolean","description":"If true, all steps run on the same worker for better performance"},"concurrent_limit":{"type":"number","description":"Maximum number of concurrent executions of this flow"},"concurrency_key":{"type":"string","description":"Expression to group concurrent executions (e.g., by user ID)"},"concurrency_time_window_s":{"type":"number","description":"Time window in seconds for concurrent_limit"},"debounce_delay_s":{"type":"integer","description":"Delay in seconds to debounce flow executions"},"debounce_key":{"type":"string","description":"Expression to group debounced executions"},"debounce_args_to_accumulate":{"type":"array","description":"Arguments to accumulate across debounced executions","items":{"type":"string"}},"max_total_debouncing_time":{"type":"integer","description":"Maximum total time in seconds that a job can be debounced"},"max_total_debounces_amount":{"type":"integer","description":"Maximum number of times a job can be debounced"},"skip_expr":{"type":"string","description":"JavaScript expression to conditionally skip the entire flow"},"cache_ttl":{"type":"number","description":"Cache duration in seconds for flow results"},"cache_ignore_s3_path":{"type":"boolean"},"flow_env":{"type":"object","description":"Environment variables available to all steps. Values can be strings, JSON values, or special references: '$var:path' (workspace variable) or '$res:path' (resource).","additionalProperties":{}},"priority":{"type":"number","description":"Execution priority (higher numbers run first)"},"early_return":{"type":"string","description":"JavaScript expression to return early from the flow"},"chat_input_enabled":{"type":"boolean","description":"Whether this flow accepts chat-style input"},"notes":{"type":"array","description":"Sticky notes attached to the flow","items":{"$ref":"#/components/schemas/FlowNote"}},"groups":{"type":"array","description":"Semantic groups of modules for organizational purposes","items":{"$ref":"#/components/schemas/FlowGroup"}}},"required":["modules"]},"Retry":{"type":"object","description":"Retry configuration for failed module executions","properties":{"constant":{"type":"object","description":"Retry with constant delay between attempts","properties":{"attempts":{"type":"integer","description":"Number of retry attempts"},"seconds":{"type":"integer","description":"Seconds to wait between retries"}}},"exponential":{"type":"object","description":"Retry with exponential backoff (delay doubles each time)","properties":{"attempts":{"type":"integer","description":"Number of retry attempts"},"multiplier":{"type":"integer","description":"Multiplier for exponential backoff"},"seconds":{"type":"integer","minimum":1,"description":"Initial delay in seconds"},"random_factor":{"type":"integer","minimum":0,"maximum":100,"description":"Random jitter percentage (0-100) to avoid thundering herd"}}},"retry_if":{"$ref":"#/components/schemas/RetryIf"}}},"FlowNote":{"type":"object","description":"A sticky note attached to a flow for documentation and annotation","properties":{"id":{"type":"string","description":"Unique identifier for the note"},"text":{"type":"string","description":"Content of the note"},"position":{"type":"object","description":"Position of the note in the flow editor","properties":{"x":{"type":"number","description":"X coordinate"},"y":{"type":"number","description":"Y coordinate"}},"required":["x","y"]},"size":{"type":"object","description":"Size of the note in the flow editor","properties":{"width":{"type":"number","description":"Width in pixels"},"height":{"type":"number","description":"Height in pixels"}},"required":["width","height"]},"color":{"type":"string","description":"Color of the note (e.g., \\"yellow\\", \\"#ffff00\\")"},"type":{"type":"string","enum":["free","group"],"description":"Type of note - 'free' for standalone notes, 'group' for notes that group other nodes"},"locked":{"type":"boolean","default":false,"description":"Whether the note is locked and cannot be edited or moved"},"contained_node_ids":{"type":"array","items":{"type":"string"},"description":"For group notes, the IDs of nodes contained within this group"}},"required":["id","text","color","type"]},"FlowGroup":{"type":"object","description":"A semantic group of flow modules for organizational purposes. Does not affect execution \\u2014 modules remain in their original position in the flow. Groups provide naming and collapsibility in the editor. Members are computed dynamically from all nodes on paths between start_id and end_id.","properties":{"summary":{"type":"string","description":"Display name for this group"},"note":{"type":"string","description":"Markdown note shown below the group header"},"autocollapse":{"type":"boolean","default":false,"description":"If true, this group is collapsed by default in the flow editor. UI hint only."},"start_id":{"type":"string","description":"ID of the first flow module in this group (topological entry point)"},"end_id":{"type":"string","description":"ID of the last flow module in this group (topological exit point)"},"color":{"type":"string","description":"Color for the group in the flow editor"}},"required":["start_id","end_id"]},"RetryIf":{"type":"object","description":"Conditional retry based on error or result","properties":{"expr":{"type":"string","description":"JavaScript expression that returns true to retry. Has access to 'result' and 'error' variables"}},"required":["expr"]},"StopAfterIf":{"type":"object","description":"Early termination condition for a module","properties":{"skip_if_stopped":{"type":"boolean","description":"If true, following steps are skipped when this condition triggers"},"expr":{"type":"string","description":"JavaScript expression evaluated after the module runs. Can use 'result' (step's result) or 'flow_input'. Return true to stop"},"error_message":{"type":"string","nullable":true,"description":"Custom error message when stopping with an error. Mutually exclusive with skip_if_stopped. If set to a non-empty string, the flow stops with this error. If empty string, a default error message is used. If null or omitted, no error is raised."}},"required":["expr"]},"FlowModule":{"type":"object","description":"A single step in a flow. Can be a script, subflow, loop, or branch","properties":{"id":{"type":"string","description":"Unique identifier for this step. Used to reference results via 'results.step_id'. Must be a valid identifier (alphanumeric, underscore, hyphen)"},"value":{"$ref":"#/components/schemas/FlowModuleValue"},"stop_after_if":{"description":"Early termination condition evaluated after this step completes","$ref":"#/components/schemas/StopAfterIf"},"stop_after_all_iters_if":{"description":"For loops only - early termination condition evaluated after all iterations complete","$ref":"#/components/schemas/StopAfterIf"},"skip_if":{"type":"object","description":"Conditionally skip this step based on previous results or flow inputs","properties":{"expr":{"type":"string","description":"JavaScript expression that returns true to skip. Can use 'flow_input' or 'results.<step_id>'"}},"required":["expr"]},"sleep":{"description":"Delay before executing this step (in seconds or as expression)","$ref":"#/components/schemas/InputTransform"},"cache_ttl":{"type":"number","description":"Cache duration in seconds for this step's results"},"cache_ignore_s3_path":{"type":"boolean"},"timeout":{"description":"Maximum execution time in seconds (static value or expression)","$ref":"#/components/schemas/InputTransform"},"delete_after_use":{"type":"boolean","description":"If true, this step's result is deleted after use to save memory"},"summary":{"type":"string","description":"Short description of what this step does"},"mock":{"type":"object","description":"Mock configuration for testing without executing the actual step","properties":{"enabled":{"type":"boolean","description":"If true, return mock value instead of executing"},"return_value":{"description":"Value to return when mocked"}}},"suspend":{"type":"object","description":"Configuration for approval/resume steps that wait for user input","properties":{"required_events":{"type":"integer","description":"Number of approvals required before continuing"},"timeout":{"type":"integer","description":"Timeout in seconds before auto-continuing or canceling"},"resume_form":{"type":"object","description":"Form schema for collecting input when resuming","properties":{"schema":{"type":"object","description":"JSON Schema for the resume form"}}},"user_auth_required":{"type":"boolean","description":"If true, only authenticated users can approve"},"user_groups_required":{"description":"Expression or list of groups that can approve","$ref":"#/components/schemas/InputTransform"},"self_approval_disabled":{"type":"boolean","description":"If true, the user who started the flow cannot approve"},"hide_cancel":{"type":"boolean","description":"If true, hide the cancel button on the approval form"},"continue_on_disapprove_timeout":{"type":"boolean","description":"If true, continue flow on timeout instead of canceling"}}},"priority":{"type":"number","description":"Execution priority for this step (higher numbers run first)"},"continue_on_error":{"type":"boolean","description":"If true, flow continues even if this step fails"},"retry":{"description":"Retry configuration if this step fails","$ref":"#/components/schemas/Retry"},"debouncing":{"description":"Debounce configuration for this step (EE only)","type":"object","properties":{"debounce_delay_s":{"type":"integer","description":"Delay in seconds to debounce this step's executions across flow runs"},"debounce_key":{"type":"string","description":"Expression to group debounced executions. Supports $workspace and $args[name]. Default: $workspace/flow/<flow_path>-<step_id>"},"debounce_args_to_accumulate":{"type":"array","description":"Array-type arguments to accumulate across debounced executions","items":{"type":"string"}},"max_total_debouncing_time":{"type":"integer","description":"Maximum total time in seconds before forced execution"},"max_total_debounces_amount":{"type":"integer","description":"Maximum number of debounces before forced execution"}}}},"required":["value","id"]},"InputTransform":{"description":"Maps input parameters for a step. Can be a static value or a JavaScript expression that references previous results or flow inputs","oneOf":[{"$ref":"#/components/schemas/StaticTransform"},{"$ref":"#/components/schemas/JavascriptTransform"},{"$ref":"#/components/schemas/AiTransform"}],"discriminator":{"propertyName":"type","mapping":{"static":"#/components/schemas/StaticTransform","javascript":"#/components/schemas/JavascriptTransform","ai":"#/components/schemas/AiTransform"}}},"StaticTransform":{"type":"object","description":"Static value passed directly to the step. Use for hardcoded values or resource references like '$res:path/to/resource'","properties":{"value":{"description":"The static value. For resources, use format '$res:path/to/resource'"},"type":{"type":"string","enum":["static"]}},"required":["type"]},"JavascriptTransform":{"type":"object","description":"JavaScript expression evaluated at runtime. Can reference previous step results via 'results.step_id' or flow inputs via 'flow_input.property'. Inside loops, use 'flow_input.iter.value' for the current iteration value","properties":{"expr":{"type":"string","description":"JavaScript expression returning the value. Available variables - results (object with all previous step results), flow_input (flow inputs), flow_input.iter (in loops)"},"type":{"type":"string","enum":["javascript"]}},"required":["expr","type"]},"AiTransform":{"type":"object","description":"Value resolved by the AI runtime for this input. The AI engine decides how to satisfy the parameter.","properties":{"type":{"type":"string","enum":["ai"]}},"required":["type"]},"AIProviderKind":{"type":"string","description":"Supported AI provider types","enum":["openai","azure_openai","anthropic","mistral","deepseek","googleai","groq","openrouter","togetherai","customai","aws_bedrock"]},"ProviderConfig":{"type":"object","description":"Complete AI provider configuration with resource reference and model selection","properties":{"kind":{"$ref":"#/components/schemas/AIProviderKind"},"resource":{"type":"string","description":"Resource reference in format '$res:{resource_path}' pointing to provider credentials"},"model":{"type":"string","description":"Model identifier (e.g., 'gpt-4', 'claude-3-opus-20240229', 'gemini-pro')"}},"required":["kind","resource","model"]},"StaticProviderTransform":{"type":"object","description":"Static provider configuration passed directly to the AI agent","properties":{"value":{"$ref":"#/components/schemas/ProviderConfig"},"type":{"type":"string","enum":["static"]}},"required":["type","value"]},"ProviderTransform":{"description":"Provider configuration - can be static (ProviderConfig), JavaScript expression, or AI-determined","oneOf":[{"$ref":"#/components/schemas/StaticProviderTransform"},{"$ref":"#/components/schemas/JavascriptTransform"},{"$ref":"#/components/schemas/AiTransform"}],"discriminator":{"propertyName":"type","mapping":{"static":"#/components/schemas/StaticProviderTransform","javascript":"#/components/schemas/JavascriptTransform","ai":"#/components/schemas/AiTransform"}}},"MemoryOff":{"type":"object","description":"No conversation memory/context","properties":{"kind":{"type":"string","enum":["off"]}},"required":["kind"]},"MemoryAuto":{"type":"object","description":"Automatic context management","properties":{"kind":{"type":"string","enum":["auto"]},"context_length":{"type":"integer","description":"Maximum number of messages to retain in context"},"memory_id":{"type":"string","description":"Identifier for persistent memory across agent invocations"}},"required":["kind"]},"MemoryMessage":{"type":"object","description":"A single message in conversation history","properties":{"role":{"type":"string","enum":["user","assistant","system"]},"content":{"type":"string"}},"required":["role","content"]},"MemoryManual":{"type":"object","description":"Explicit message history","properties":{"kind":{"type":"string","enum":["manual"]},"messages":{"type":"array","items":{"$ref":"#/components/schemas/MemoryMessage"}}},"required":["kind","messages"]},"MemoryConfig":{"description":"Conversation memory configuration","oneOf":[{"$ref":"#/components/schemas/MemoryOff"},{"$ref":"#/components/schemas/MemoryAuto"},{"$ref":"#/components/schemas/MemoryManual"}],"discriminator":{"propertyName":"kind","mapping":{"off":"#/components/schemas/MemoryOff","auto":"#/components/schemas/MemoryAuto","manual":"#/components/schemas/MemoryManual"}}},"StaticMemoryTransform":{"type":"object","description":"Static memory configuration passed directly to the AI agent","properties":{"value":{"$ref":"#/components/schemas/MemoryConfig"},"type":{"type":"string","enum":["static"]}},"required":["type","value"]},"MemoryTransform":{"description":"Memory configuration - can be static (MemoryConfig), JavaScript expression, or AI-determined","oneOf":[{"$ref":"#/components/schemas/StaticMemoryTransform"},{"$ref":"#/components/schemas/JavascriptTransform"},{"$ref":"#/components/schemas/AiTransform"}],"discriminator":{"propertyName":"type","mapping":{"static":"#/components/schemas/StaticMemoryTransform","javascript":"#/components/schemas/JavascriptTransform","ai":"#/components/schemas/AiTransform"}}},"FlowModuleValue":{"description":"The actual implementation of a flow step. Can be a script (inline or referenced), subflow, loop, branch, or special module type","oneOf":[{"$ref":"#/components/schemas/RawScript"},{"$ref":"#/components/schemas/PathScript"},{"$ref":"#/components/schemas/PathFlow"},{"$ref":"#/components/schemas/ForloopFlow"},{"$ref":"#/components/schemas/WhileloopFlow"},{"$ref":"#/components/schemas/BranchOne"},{"$ref":"#/components/schemas/BranchAll"},{"$ref":"#/components/schemas/Identity"},{"$ref":"#/components/schemas/AiAgent"}],"discriminator":{"propertyName":"type","mapping":{"rawscript":"#/components/schemas/RawScript","script":"#/components/schemas/PathScript","flow":"#/components/schemas/PathFlow","forloopflow":"#/components/schemas/ForloopFlow","whileloopflow":"#/components/schemas/WhileloopFlow","branchone":"#/components/schemas/BranchOne","branchall":"#/components/schemas/BranchAll","identity":"#/components/schemas/Identity","aiagent":"#/components/schemas/AiAgent"}}},"RawScript":{"type":"object","description":"Inline script with code defined directly in the flow. Use 'bun' as default language if unspecified. The script receives arguments from input_transforms","properties":{"input_transforms":{"type":"object","description":"Map of parameter names to their values (static or JavaScript expressions). These become the script's input arguments","additionalProperties":{"$ref":"#/components/schemas/InputTransform"}},"content":{"type":"string","description":"The script source code. Should export a 'main' function"},"language":{"type":"string","description":"Programming language for this script","enum":["deno","bun","python3","go","bash","powershell","postgresql","mysql","bigquery","snowflake","mssql","oracledb","graphql","nativets","php","rust","ansible","csharp","nu","java","ruby","rlang","duckdb"]},"path":{"type":"string","description":"Optional path for saving this script"},"lock":{"type":"string","description":"Lock file content for dependencies"},"type":{"type":"string","enum":["rawscript"]},"tag":{"type":"string","description":"Worker group tag for execution routing"},"concurrent_limit":{"type":"number","description":"Maximum concurrent executions of this script"},"concurrency_time_window_s":{"type":"number","description":"Time window for concurrent_limit"},"custom_concurrency_key":{"type":"string","description":"Custom key for grouping concurrent executions"},"is_trigger":{"type":"boolean","description":"If true, this script is a trigger that can start the flow"},"assets":{"type":"array","description":"External resources this script accesses (S3 objects, resources, etc.)","items":{"type":"object","required":["path","kind"],"properties":{"path":{"type":"string","description":"Path to the asset"},"kind":{"type":"string","description":"Type of asset","enum":["s3object","resource","ducklake","datatable","volume"]},"access_type":{"type":"string","nullable":true,"description":"Access level for this asset","enum":["r","w","rw"]},"alt_access_type":{"type":"string","nullable":true,"description":"Alternative access level","enum":["r","w","rw"]}}}}},"required":["type","content","language","input_transforms"]},"PathScript":{"type":"object","description":"Reference to an existing script by path. Use this when calling a previously saved script instead of writing inline code","properties":{"input_transforms":{"type":"object","description":"Map of parameter names to their values (static or JavaScript expressions). These become the script's input arguments","additionalProperties":{"$ref":"#/components/schemas/InputTransform"}},"path":{"type":"string","description":"Path to the script in the workspace (e.g., 'f/scripts/send_email')"},"hash":{"type":"string","description":"Optional specific version hash of the script to use"},"type":{"type":"string","enum":["script"]},"tag_override":{"type":"string","description":"Override the script's default worker group tag"},"is_trigger":{"type":"boolean","description":"If true, this script is a trigger that can start the flow"}},"required":["type","path","input_transforms"]},"PathFlow":{"type":"object","description":"Reference to an existing flow by path. Use this to call another flow as a subflow","properties":{"input_transforms":{"type":"object","description":"Map of parameter names to their values (static or JavaScript expressions). These become the subflow's input arguments","additionalProperties":{"$ref":"#/components/schemas/InputTransform"}},"path":{"type":"string","description":"Path to the flow in the workspace (e.g., 'f/flows/process_user')"},"type":{"type":"string","enum":["flow"]}},"required":["type","path","input_transforms"]},"ForloopFlow":{"type":"object","description":"Executes nested modules in a loop over an iterator. Inside the loop, use 'flow_input.iter.value' to access the current iteration value, and 'flow_input.iter.index' for the index. Supports parallel execution for better performance on I/O-bound operations","properties":{"modules":{"type":"array","description":"Steps to execute for each iteration. These can reference the iteration value via 'flow_input.iter.value'","items":{"$ref":"#/components/schemas/FlowModule"}},"iterator":{"description":"JavaScript expression that returns an array to iterate over. Can reference 'results.step_id' or 'flow_input'","$ref":"#/components/schemas/InputTransform"},"skip_failures":{"type":"boolean","description":"If true, iteration failures don't stop the loop. Failed iterations return null"},"type":{"type":"string","enum":["forloopflow"]},"parallel":{"type":"boolean","description":"If true, iterations run concurrently (faster for I/O-bound operations). Use with parallelism to control concurrency"},"parallelism":{"description":"Maximum number of concurrent iterations when parallel=true. Limits resource usage. Can be static number or expression","$ref":"#/components/schemas/InputTransform"},"squash":{"type":"boolean"}},"required":["modules","iterator","skip_failures","type"]},"WhileloopFlow":{"type":"object","description":"Executes nested modules repeatedly while a condition is true. The loop checks the condition after each iteration. Use stop_after_if on modules to control loop termination","properties":{"modules":{"type":"array","description":"Steps to execute in each iteration. Use stop_after_if to control when the loop ends","items":{"$ref":"#/components/schemas/FlowModule"}},"skip_failures":{"type":"boolean","description":"If true, iteration failures don't stop the loop. Failed iterations return null"},"type":{"type":"string","enum":["whileloopflow"]},"parallel":{"type":"boolean","description":"If true, iterations run concurrently (use with caution in while loops)"},"parallelism":{"description":"Maximum number of concurrent iterations when parallel=true","$ref":"#/components/schemas/InputTransform"},"squash":{"type":"boolean"}},"required":["modules","skip_failures","type"]},"BranchOne":{"type":"object","description":"Conditional branching where only the first matching branch executes. Branches are evaluated in order, and the first one with a true expression runs. If no branches match, the default branch executes","properties":{"branches":{"type":"array","description":"Array of branches to evaluate in order. The first branch with expr evaluating to true executes","items":{"type":"object","properties":{"summary":{"type":"string","description":"Short description of this branch condition"},"expr":{"type":"string","description":"JavaScript expression that returns boolean. Can use 'results.step_id' or 'flow_input'. First true expr wins"},"modules":{"type":"array","description":"Steps to execute if this branch's expr is true","items":{"$ref":"#/components/schemas/FlowModule"}}},"required":["modules","expr"]}},"default":{"type":"array","description":"Steps to execute if no branch expressions match","items":{"$ref":"#/components/schemas/FlowModule"}},"type":{"type":"string","enum":["branchone"]}},"required":["branches","default","type"]},"BranchAll":{"type":"object","description":"Parallel branching where all branches execute simultaneously. Unlike BranchOne, all branches run regardless of conditions. Useful for executing independent tasks concurrently","properties":{"branches":{"type":"array","description":"Array of branches that all execute (either in parallel or sequentially)","items":{"type":"object","properties":{"summary":{"type":"string","description":"Short description of this branch's purpose"},"skip_failure":{"type":"boolean","description":"If true, failure in this branch doesn't fail the entire flow"},"modules":{"type":"array","description":"Steps to execute in this branch","items":{"$ref":"#/components/schemas/FlowModule"}}},"required":["modules"]}},"type":{"type":"string","enum":["branchall"]},"parallel":{"type":"boolean","description":"If true, all branches execute concurrently. If false, they execute sequentially"}},"required":["branches","type"]},"AgentTool":{"type":"object","description":"A tool available to an AI agent. Can be a flow module or an external MCP (Model Context Protocol) tool","properties":{"id":{"type":"string","description":"Unique identifier for this tool. Cannot contain spaces - use underscores instead (e.g., 'get_user_data' not 'get user data')"},"summary":{"type":"string","description":"Short description of what this tool does (shown to the AI)"},"value":{"$ref":"#/components/schemas/ToolValue"}},"required":["id","value"]},"ToolValue":{"description":"The implementation of a tool. Can be a flow module (script/flow) or an MCP tool reference","oneOf":[{"$ref":"#/components/schemas/FlowModuleTool"},{"$ref":"#/components/schemas/McpToolValue"},{"$ref":"#/components/schemas/WebsearchToolValue"}],"discriminator":{"propertyName":"tool_type","mapping":{"flowmodule":"#/components/schemas/FlowModuleTool","mcp":"#/components/schemas/McpToolValue","websearch":"#/components/schemas/WebsearchToolValue"}}},"FlowModuleTool":{"description":"A tool implemented as a flow module (script, flow, etc.). The AI can call this like any other flow module","allOf":[{"type":"object","properties":{"tool_type":{"type":"string","enum":["flowmodule"]}},"required":["tool_type"]},{"$ref":"#/components/schemas/FlowModuleValue"}]},"WebsearchToolValue":{"type":"object","description":"A tool implemented as a websearch tool. The AI can call this like any other websearch tool","properties":{"tool_type":{"type":"string","enum":["websearch"]}},"required":["tool_type"]},"McpToolValue":{"type":"object","description":"Reference to an external MCP (Model Context Protocol) tool. The AI can call tools from MCP servers","properties":{"tool_type":{"type":"string","enum":["mcp"]},"resource_path":{"type":"string","description":"Path to the MCP resource/server configuration"},"include_tools":{"type":"array","description":"Whitelist of specific tools to include from this MCP server","items":{"type":"string"}},"exclude_tools":{"type":"array","description":"Blacklist of tools to exclude from this MCP server","items":{"type":"string"}}},"required":["tool_type","resource_path"]},"AiAgent":{"type":"object","description":"AI agent step that can use tools to accomplish tasks. The agent receives inputs and can call any of its configured tools to complete the task","properties":{"input_transforms":{"type":"object","description":"Input parameters for the AI agent mapped to their values","properties":{"provider":{"$ref":"#/components/schemas/ProviderTransform"},"output_type":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"Output format type.\\nValid values: 'text' (default) - plain text response, 'image' - image generation\\n"},"user_message":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"The user's prompt/message to the AI agent. Supports variable interpolation with flow.input syntax."},"system_prompt":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"System instructions that guide the AI's behavior, persona, and response style. Optional."},"streaming":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"Boolean. If true, stream the AI response incrementally.\\nStreaming events include: token_delta, tool_call, tool_call_arguments, tool_execution, tool_result\\n"},"memory":{"$ref":"#/components/schemas/MemoryTransform"},"output_schema":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"JSON Schema object defining structured output format. Used when you need the AI to return data in a specific shape.\\nSupports standard JSON Schema properties: type, properties, required, items, enum, pattern, minLength, maxLength, minimum, maximum, etc.\\nExample: { type: 'object', properties: { name: { type: 'string' }, age: { type: 'integer' } }, required: ['name'] }\\n"},"user_attachments":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"Array of file references (images or PDFs) for the AI agent.\\nFormat: Array<{ bucket: string, key: string }> - S3 object references\\nExample: [{ bucket: 'my-bucket', key: 'documents/report.pdf' }]\\n"},"max_completion_tokens":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"Integer. Maximum number of tokens the AI will generate in its response.\\nRange: 1 to 4,294,967,295. Typical values: 256-4096 for most use cases.\\n"},"temperature":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"Float. Controls randomness/creativity of responses.\\nRange: 0.0 to 2.0 (provider-dependent)\\n- 0.0 = deterministic, focused responses\\n- 0.7 = balanced (common default)\\n- 1.0+ = more creative/random\\n"}},"required":["provider","user_message","output_type"]},"tools":{"type":"array","description":"Array of tools the agent can use. The agent decides which tools to call based on the task","items":{"$ref":"#/components/schemas/AgentTool"}},"type":{"type":"string","enum":["aiagent"]},"parallel":{"type":"boolean","description":"If true, the agent can execute multiple tool calls in parallel"}},"required":["tools","type","input_transforms"]},"Identity":{"type":"object","description":"Pass-through module that returns its input unchanged. Useful for flow structure or as a placeholder","properties":{"type":{"type":"string","enum":["identity"]},"flow":{"type":"boolean","description":"If true, marks this as a flow identity (special handling)"}},"required":["type"]},"FlowStatus":{"type":"object","properties":{"step":{"type":"integer"},"modules":{"type":"array","items":{"$ref":"#/components/schemas/FlowStatusModule"}},"user_states":{"additionalProperties":true},"preprocessor_module":{"allOf":[{"$ref":"#/components/schemas/FlowStatusModule"}]},"failure_module":{"allOf":[{"$ref":"#/components/schemas/FlowStatusModule"},{"type":"object","properties":{"parent_module":{"type":"string"}}}]},"retry":{"type":"object","properties":{"fail_count":{"type":"integer"},"failed_jobs":{"type":"array","items":{"type":"string","format":"uuid"}}}}},"required":["step","modules","failure_module"]},"FlowStatusModule":{"type":"object","properties":{"type":{"type":"string","enum":["WaitingForPriorSteps","WaitingForEvents","WaitingForExecutor","InProgress","Success","Failure"]},"id":{"type":"string"},"job":{"type":"string","format":"uuid"},"count":{"type":"integer"},"progress":{"type":"integer"},"iterator":{"type":"object","properties":{"index":{"type":"integer"},"itered":{"type":"array","items":{}},"itered_len":{"type":"integer"},"args":{}}},"flow_jobs":{"type":"array","items":{"type":"string"}},"flow_jobs_success":{"type":"array","items":{"type":"boolean"}},"flow_jobs_duration":{"type":"object","properties":{"started_at":{"type":"array","items":{"type":"string"}},"duration_ms":{"type":"array","items":{"type":"integer"}}}},"branch_chosen":{"type":"object","properties":{"type":{"type":"string","enum":["branch","default"]},"branch":{"type":"integer"}},"required":["type"]},"branchall":{"type":"object","properties":{"branch":{"type":"integer"},"len":{"type":"integer"}},"required":["branch","len"]},"approvers":{"type":"array","items":{"type":"object","properties":{"resume_id":{"type":"integer"},"approver":{"type":"string"}},"required":["resume_id","approver"]}},"failed_retries":{"type":"array","items":{"type":"string","format":"uuid"}},"skipped":{"type":"boolean"},"agent_actions":{"type":"array","items":{"type":"object","oneOf":[{"type":"object","properties":{"job_id":{"type":"string","format":"uuid"},"function_name":{"type":"string"},"type":{"type":"string","enum":["tool_call"]},"module_id":{"type":"string"}},"required":["job_id","function_name","type","module_id"]},{"type":"object","properties":{"call_id":{"type":"string","format":"uuid"},"function_name":{"type":"string"},"resource_path":{"type":"string"},"type":{"type":"string","enum":["mcp_tool_call"]},"arguments":{"type":"object"}},"required":["call_id","function_name","resource_path","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["web_search"]}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["message"]}},"required":["content","type"]}]}},"agent_actions_success":{"type":"array","items":{"type":"boolean"}}},"required":["type"]}}`,
|
|
80043
|
+
{"OpenFlow":{"type":"object","description":"Top-level flow definition containing metadata, configuration, and the flow structure","properties":{"summary":{"type":"string","description":"Short description of what this flow does"},"description":{"type":"string","description":"Detailed documentation for this flow"},"value":{"$ref":"#/components/schemas/FlowValue"},"schema":{"type":"object","description":"JSON Schema for flow inputs. Use this to define input parameters, their types, defaults, and validation. For resource inputs, set type to 'object' and format to 'resource-<type>' (e.g., 'resource-stripe')"},"on_behalf_of_email":{"type":"string","description":"The flow will be run with the permissions of the user with this email."}},"required":["summary","value"]},"FlowValue":{"type":"object","description":"The flow structure containing modules and optional preprocessor/failure handlers","properties":{"modules":{"type":"array","description":"Array of steps that execute in sequence. Each step can be a script, subflow, loop, or branch","items":{"$ref":"#/components/schemas/FlowModule"}},"failure_module":{"description":"Special module that executes when the flow fails. Receives error object with message, name, stack, and step_id. Must have id 'failure'. Only supports script/rawscript types","$ref":"#/components/schemas/FlowModule"},"preprocessor_module":{"description":"Special module that runs before the first step on external triggers. Must have id 'preprocessor'. Only supports script/rawscript types. Cannot reference other step results","$ref":"#/components/schemas/FlowModule"},"same_worker":{"type":"boolean","description":"If true, all steps run on the same worker for better performance"},"concurrent_limit":{"type":"number","description":"Maximum number of concurrent executions of this flow"},"concurrency_key":{"type":"string","description":"Expression to group concurrent executions (e.g., by user ID)"},"concurrency_time_window_s":{"type":"number","description":"Time window in seconds for concurrent_limit"},"debounce_delay_s":{"type":"integer","description":"Delay in seconds to debounce flow executions"},"debounce_key":{"type":"string","description":"Expression to group debounced executions"},"debounce_args_to_accumulate":{"type":"array","description":"Arguments to accumulate across debounced executions","items":{"type":"string"}},"max_total_debouncing_time":{"type":"integer","description":"Maximum total time in seconds that a job can be debounced"},"max_total_debounces_amount":{"type":"integer","description":"Maximum number of times a job can be debounced"},"skip_expr":{"type":"string","description":"JavaScript expression to conditionally skip the entire flow"},"cache_ttl":{"type":"number","description":"Cache duration in seconds for flow results"},"cache_ignore_s3_path":{"type":"boolean"},"delete_after_secs":{"type":"integer","description":"If set, delete the flow job's args, result and logs after this many seconds following job completion"},"flow_env":{"type":"object","description":"Environment variables available to all steps. Values can be strings, JSON values, or special references: '$var:path' (workspace variable) or '$res:path' (resource).","additionalProperties":{}},"priority":{"type":"number","description":"Execution priority (higher numbers run first)"},"early_return":{"type":"string","description":"JavaScript expression to return early from the flow"},"chat_input_enabled":{"type":"boolean","description":"Whether this flow accepts chat-style input"},"notes":{"type":"array","description":"Sticky notes attached to the flow","items":{"$ref":"#/components/schemas/FlowNote"}},"groups":{"type":"array","description":"Semantic groups of modules for organizational purposes","items":{"$ref":"#/components/schemas/FlowGroup"}}},"required":["modules"]},"Retry":{"type":"object","description":"Retry configuration for failed module executions","properties":{"constant":{"type":"object","description":"Retry with constant delay between attempts","properties":{"attempts":{"type":"integer","description":"Number of retry attempts"},"seconds":{"type":"integer","description":"Seconds to wait between retries"}}},"exponential":{"type":"object","description":"Retry with exponential backoff (delay doubles each time)","properties":{"attempts":{"type":"integer","description":"Number of retry attempts"},"multiplier":{"type":"integer","description":"Multiplier for exponential backoff"},"seconds":{"type":"integer","minimum":1,"description":"Initial delay in seconds"},"random_factor":{"type":"integer","minimum":0,"maximum":100,"description":"Random jitter percentage (0-100) to avoid thundering herd"}}},"retry_if":{"$ref":"#/components/schemas/RetryIf"}}},"FlowNote":{"type":"object","description":"A sticky note attached to a flow for documentation and annotation","properties":{"id":{"type":"string","description":"Unique identifier for the note"},"text":{"type":"string","description":"Content of the note"},"position":{"type":"object","description":"Position of the note in the flow editor","properties":{"x":{"type":"number","description":"X coordinate"},"y":{"type":"number","description":"Y coordinate"}},"required":["x","y"]},"size":{"type":"object","description":"Size of the note in the flow editor","properties":{"width":{"type":"number","description":"Width in pixels"},"height":{"type":"number","description":"Height in pixels"}},"required":["width","height"]},"color":{"type":"string","description":"Color of the note (e.g., \\"yellow\\", \\"#ffff00\\")"},"type":{"type":"string","enum":["free","group"],"description":"Type of note - 'free' for standalone notes, 'group' for notes that group other nodes"},"locked":{"type":"boolean","default":false,"description":"Whether the note is locked and cannot be edited or moved"},"contained_node_ids":{"type":"array","items":{"type":"string"},"description":"For group notes, the IDs of nodes contained within this group"}},"required":["id","text","color","type"]},"FlowGroup":{"type":"object","description":"A semantic group of flow modules for organizational purposes. Does not affect execution \\u2014 modules remain in their original position in the flow. Groups provide naming and collapsibility in the editor. Members are computed dynamically from all nodes on paths between start_id and end_id.","properties":{"summary":{"type":"string","description":"Display name for this group"},"note":{"type":"string","description":"Markdown note shown below the group header"},"autocollapse":{"type":"boolean","default":false,"description":"If true, this group is collapsed by default in the flow editor. UI hint only."},"start_id":{"type":"string","description":"ID of the first flow module in this group (topological entry point)"},"end_id":{"type":"string","description":"ID of the last flow module in this group (topological exit point)"},"color":{"type":"string","description":"Color for the group in the flow editor"}},"required":["start_id","end_id"]},"RetryIf":{"type":"object","description":"Conditional retry based on error or result","properties":{"expr":{"type":"string","description":"JavaScript expression that returns true to retry. Has access to 'result' and 'error' variables"}},"required":["expr"]},"StopAfterIf":{"type":"object","description":"Early termination condition for a module","properties":{"skip_if_stopped":{"type":"boolean","description":"If true, following steps are skipped when this condition triggers"},"expr":{"type":"string","description":"JavaScript expression evaluated after the module runs. Can use 'result' (step's result) or 'flow_input'. Return true to stop"},"error_message":{"type":"string","nullable":true,"description":"Custom error message when stopping with an error. Mutually exclusive with skip_if_stopped. If set to a non-empty string, the flow stops with this error. If empty string, a default error message is used. If null or omitted, no error is raised."}},"required":["expr"]},"FlowModule":{"type":"object","description":"A single step in a flow. Can be a script, subflow, loop, or branch","properties":{"id":{"type":"string","description":"Unique identifier for this step. Used to reference results via 'results.step_id'. Must be a valid identifier (alphanumeric, underscore, hyphen)"},"value":{"$ref":"#/components/schemas/FlowModuleValue"},"stop_after_if":{"description":"Early termination condition evaluated after this step completes","$ref":"#/components/schemas/StopAfterIf"},"stop_after_all_iters_if":{"description":"For loops only - early termination condition evaluated after all iterations complete","$ref":"#/components/schemas/StopAfterIf"},"skip_if":{"type":"object","description":"Conditionally skip this step based on previous results or flow inputs","properties":{"expr":{"type":"string","description":"JavaScript expression that returns true to skip. Can use 'flow_input' or 'results.<step_id>'"}},"required":["expr"]},"sleep":{"description":"Delay before executing this step (in seconds or as expression)","$ref":"#/components/schemas/InputTransform"},"cache_ttl":{"type":"number","description":"Cache duration in seconds for this step's results"},"cache_ignore_s3_path":{"type":"boolean"},"timeout":{"description":"Maximum execution time in seconds (static value or expression)","$ref":"#/components/schemas/InputTransform"},"delete_after_secs":{"type":"integer","description":"If set, delete the step's args, result and logs after this many seconds following job completion"},"summary":{"type":"string","description":"Short description of what this step does"},"mock":{"type":"object","description":"Mock configuration for testing without executing the actual step","properties":{"enabled":{"type":"boolean","description":"If true, return mock value instead of executing"},"return_value":{"description":"Value to return when mocked"}}},"suspend":{"type":"object","description":"Configuration for approval/resume steps that wait for user input","properties":{"required_events":{"type":"integer","description":"Number of approvals required before continuing"},"timeout":{"type":"integer","description":"Timeout in seconds before auto-continuing or canceling"},"resume_form":{"type":"object","description":"Form schema for collecting input when resuming","properties":{"schema":{"type":"object","description":"JSON Schema for the resume form"}}},"user_auth_required":{"type":"boolean","description":"If true, only authenticated users can approve"},"user_groups_required":{"description":"Expression or list of groups that can approve","$ref":"#/components/schemas/InputTransform"},"self_approval_disabled":{"type":"boolean","description":"If true, the user who started the flow cannot approve"},"hide_cancel":{"type":"boolean","description":"If true, hide the cancel button on the approval form"},"continue_on_disapprove_timeout":{"type":"boolean","description":"If true, continue flow on timeout instead of canceling"}}},"priority":{"type":"number","description":"Execution priority for this step (higher numbers run first)"},"continue_on_error":{"type":"boolean","description":"If true, flow continues even if this step fails"},"retry":{"description":"Retry configuration if this step fails","$ref":"#/components/schemas/Retry"},"debouncing":{"description":"Debounce configuration for this step (EE only)","type":"object","properties":{"debounce_delay_s":{"type":"integer","description":"Delay in seconds to debounce this step's executions across flow runs"},"debounce_key":{"type":"string","description":"Expression to group debounced executions. Supports $workspace and $args[name]. Default: $workspace/flow/<flow_path>-<step_id>"},"debounce_args_to_accumulate":{"type":"array","description":"Array-type arguments to accumulate across debounced executions","items":{"type":"string"}},"max_total_debouncing_time":{"type":"integer","description":"Maximum total time in seconds before forced execution"},"max_total_debounces_amount":{"type":"integer","description":"Maximum number of debounces before forced execution"}}}},"required":["value","id"]},"InputTransform":{"description":"Maps input parameters for a step. Can be a static value or a JavaScript expression that references previous results or flow inputs","oneOf":[{"$ref":"#/components/schemas/StaticTransform"},{"$ref":"#/components/schemas/JavascriptTransform"},{"$ref":"#/components/schemas/AiTransform"}],"discriminator":{"propertyName":"type","mapping":{"static":"#/components/schemas/StaticTransform","javascript":"#/components/schemas/JavascriptTransform","ai":"#/components/schemas/AiTransform"}}},"StaticTransform":{"type":"object","description":"Static value passed directly to the step. Use for hardcoded values or resource references like '$res:path/to/resource'","properties":{"value":{"description":"The static value. For resources, use format '$res:path/to/resource'"},"type":{"type":"string","enum":["static"]}},"required":["type"]},"JavascriptTransform":{"type":"object","description":"JavaScript expression evaluated at runtime. Can reference previous step results via 'results.step_id' or flow inputs via 'flow_input.property'. Inside loops, use 'flow_input.iter.value' for the current iteration value","properties":{"expr":{"type":"string","description":"JavaScript expression returning the value. Available variables - results (object with all previous step results), flow_input (flow inputs), flow_input.iter (in loops)"},"type":{"type":"string","enum":["javascript"]}},"required":["expr","type"]},"AiTransform":{"type":"object","description":"Value resolved by the AI runtime for this input. The AI engine decides how to satisfy the parameter.","properties":{"type":{"type":"string","enum":["ai"]}},"required":["type"]},"AIProviderKind":{"type":"string","description":"Supported AI provider types","enum":["openai","azure_openai","anthropic","mistral","deepseek","googleai","groq","openrouter","togetherai","customai","aws_bedrock"]},"ProviderConfig":{"type":"object","description":"Complete AI provider configuration with resource reference and model selection","properties":{"kind":{"$ref":"#/components/schemas/AIProviderKind"},"resource":{"type":"string","description":"Resource reference in format '$res:{resource_path}' pointing to provider credentials"},"model":{"type":"string","description":"Model identifier (e.g., 'gpt-4', 'claude-3-opus-20240229', 'gemini-pro')"}},"required":["kind","resource","model"]},"StaticProviderTransform":{"type":"object","description":"Static provider configuration passed directly to the AI agent","properties":{"value":{"$ref":"#/components/schemas/ProviderConfig"},"type":{"type":"string","enum":["static"]}},"required":["type","value"]},"ProviderTransform":{"description":"Provider configuration - can be static (ProviderConfig), JavaScript expression, or AI-determined","oneOf":[{"$ref":"#/components/schemas/StaticProviderTransform"},{"$ref":"#/components/schemas/JavascriptTransform"},{"$ref":"#/components/schemas/AiTransform"}],"discriminator":{"propertyName":"type","mapping":{"static":"#/components/schemas/StaticProviderTransform","javascript":"#/components/schemas/JavascriptTransform","ai":"#/components/schemas/AiTransform"}}},"MemoryOff":{"type":"object","description":"No conversation memory/context","properties":{"kind":{"type":"string","enum":["off"]}},"required":["kind"]},"MemoryAuto":{"type":"object","description":"Automatic context management","properties":{"kind":{"type":"string","enum":["auto"]},"context_length":{"type":"integer","description":"Maximum number of messages to retain in context"},"memory_id":{"type":"string","description":"Identifier for persistent memory across agent invocations"}},"required":["kind"]},"MemoryMessage":{"type":"object","description":"A single message in conversation history","properties":{"role":{"type":"string","enum":["user","assistant","system"]},"content":{"type":"string"}},"required":["role","content"]},"MemoryManual":{"type":"object","description":"Explicit message history","properties":{"kind":{"type":"string","enum":["manual"]},"messages":{"type":"array","items":{"$ref":"#/components/schemas/MemoryMessage"}}},"required":["kind","messages"]},"MemoryConfig":{"description":"Conversation memory configuration","oneOf":[{"$ref":"#/components/schemas/MemoryOff"},{"$ref":"#/components/schemas/MemoryAuto"},{"$ref":"#/components/schemas/MemoryManual"}],"discriminator":{"propertyName":"kind","mapping":{"off":"#/components/schemas/MemoryOff","auto":"#/components/schemas/MemoryAuto","manual":"#/components/schemas/MemoryManual"}}},"StaticMemoryTransform":{"type":"object","description":"Static memory configuration passed directly to the AI agent","properties":{"value":{"$ref":"#/components/schemas/MemoryConfig"},"type":{"type":"string","enum":["static"]}},"required":["type","value"]},"MemoryTransform":{"description":"Memory configuration - can be static (MemoryConfig), JavaScript expression, or AI-determined","oneOf":[{"$ref":"#/components/schemas/StaticMemoryTransform"},{"$ref":"#/components/schemas/JavascriptTransform"},{"$ref":"#/components/schemas/AiTransform"}],"discriminator":{"propertyName":"type","mapping":{"static":"#/components/schemas/StaticMemoryTransform","javascript":"#/components/schemas/JavascriptTransform","ai":"#/components/schemas/AiTransform"}}},"FlowModuleValue":{"description":"The actual implementation of a flow step. Can be a script (inline or referenced), subflow, loop, branch, or special module type","oneOf":[{"$ref":"#/components/schemas/RawScript"},{"$ref":"#/components/schemas/PathScript"},{"$ref":"#/components/schemas/PathFlow"},{"$ref":"#/components/schemas/ForloopFlow"},{"$ref":"#/components/schemas/WhileloopFlow"},{"$ref":"#/components/schemas/BranchOne"},{"$ref":"#/components/schemas/BranchAll"},{"$ref":"#/components/schemas/Identity"},{"$ref":"#/components/schemas/AiAgent"}],"discriminator":{"propertyName":"type","mapping":{"rawscript":"#/components/schemas/RawScript","script":"#/components/schemas/PathScript","flow":"#/components/schemas/PathFlow","forloopflow":"#/components/schemas/ForloopFlow","whileloopflow":"#/components/schemas/WhileloopFlow","branchone":"#/components/schemas/BranchOne","branchall":"#/components/schemas/BranchAll","identity":"#/components/schemas/Identity","aiagent":"#/components/schemas/AiAgent"}}},"RawScript":{"type":"object","description":"Inline script with code defined directly in the flow. Use 'bun' as default language if unspecified. The script receives arguments from input_transforms","properties":{"input_transforms":{"type":"object","description":"Map of parameter names to their values (static or JavaScript expressions). These become the script's input arguments","additionalProperties":{"$ref":"#/components/schemas/InputTransform"}},"content":{"type":"string","description":"The script source code. Should export a 'main' function"},"language":{"type":"string","description":"Programming language for this script","enum":["deno","bun","python3","go","bash","powershell","postgresql","mysql","bigquery","snowflake","mssql","oracledb","graphql","nativets","php","rust","ansible","csharp","nu","java","ruby","rlang","duckdb"]},"path":{"type":"string","description":"Optional path for saving this script"},"lock":{"type":"string","description":"Lock file content for dependencies"},"type":{"type":"string","enum":["rawscript"]},"tag":{"type":"string","description":"Worker group tag for execution routing"},"concurrent_limit":{"type":"number","description":"Maximum concurrent executions of this script"},"concurrency_time_window_s":{"type":"number","description":"Time window for concurrent_limit"},"custom_concurrency_key":{"type":"string","description":"Custom key for grouping concurrent executions"},"is_trigger":{"type":"boolean","description":"If true, this script is a trigger that can start the flow"},"assets":{"type":"array","description":"External resources this script accesses (S3 objects, resources, etc.)","items":{"type":"object","required":["path","kind"],"properties":{"path":{"type":"string","description":"Path to the asset"},"kind":{"type":"string","description":"Type of asset","enum":["s3object","resource","ducklake","datatable","volume"]},"access_type":{"type":"string","nullable":true,"description":"Access level for this asset","enum":["r","w","rw"]},"alt_access_type":{"type":"string","nullable":true,"description":"Alternative access level","enum":["r","w","rw"]}}}}},"required":["type","content","language","input_transforms"]},"PathScript":{"type":"object","description":"Reference to an existing script by path. Use this when calling a previously saved script instead of writing inline code","properties":{"input_transforms":{"type":"object","description":"Map of parameter names to their values (static or JavaScript expressions). These become the script's input arguments","additionalProperties":{"$ref":"#/components/schemas/InputTransform"}},"path":{"type":"string","description":"Path to the script in the workspace (e.g., 'f/scripts/send_email')"},"hash":{"type":"string","description":"Optional specific version hash of the script to use"},"type":{"type":"string","enum":["script"]},"tag_override":{"type":"string","description":"Override the script's default worker group tag"},"is_trigger":{"type":"boolean","description":"If true, this script is a trigger that can start the flow"}},"required":["type","path","input_transforms"]},"PathFlow":{"type":"object","description":"Reference to an existing flow by path. Use this to call another flow as a subflow","properties":{"input_transforms":{"type":"object","description":"Map of parameter names to their values (static or JavaScript expressions). These become the subflow's input arguments","additionalProperties":{"$ref":"#/components/schemas/InputTransform"}},"path":{"type":"string","description":"Path to the flow in the workspace (e.g., 'f/flows/process_user')"},"type":{"type":"string","enum":["flow"]}},"required":["type","path","input_transforms"]},"ForloopFlow":{"type":"object","description":"Executes nested modules in a loop over an iterator. Inside the loop, use 'flow_input.iter.value' to access the current iteration value, and 'flow_input.iter.index' for the index. Supports parallel execution for better performance on I/O-bound operations","properties":{"modules":{"type":"array","description":"Steps to execute for each iteration. These can reference the iteration value via 'flow_input.iter.value'","items":{"$ref":"#/components/schemas/FlowModule"}},"iterator":{"description":"JavaScript expression that returns an array to iterate over. Can reference 'results.step_id' or 'flow_input'","$ref":"#/components/schemas/InputTransform"},"skip_failures":{"type":"boolean","description":"If true, iteration failures don't stop the loop. Failed iterations return null"},"type":{"type":"string","enum":["forloopflow"]},"parallel":{"type":"boolean","description":"If true, iterations run concurrently (faster for I/O-bound operations). Use with parallelism to control concurrency"},"parallelism":{"description":"Maximum number of concurrent iterations when parallel=true. Limits resource usage. Can be static number or expression","$ref":"#/components/schemas/InputTransform"},"squash":{"type":"boolean"}},"required":["modules","iterator","skip_failures","type"]},"WhileloopFlow":{"type":"object","description":"Executes nested modules repeatedly while a condition is true. The loop checks the condition after each iteration. Use stop_after_if on modules to control loop termination","properties":{"modules":{"type":"array","description":"Steps to execute in each iteration. Use stop_after_if to control when the loop ends","items":{"$ref":"#/components/schemas/FlowModule"}},"skip_failures":{"type":"boolean","description":"If true, iteration failures don't stop the loop. Failed iterations return null"},"type":{"type":"string","enum":["whileloopflow"]},"parallel":{"type":"boolean","description":"If true, iterations run concurrently (use with caution in while loops)"},"parallelism":{"description":"Maximum number of concurrent iterations when parallel=true","$ref":"#/components/schemas/InputTransform"},"squash":{"type":"boolean"}},"required":["modules","skip_failures","type"]},"BranchOne":{"type":"object","description":"Conditional branching where only the first matching branch executes. Branches are evaluated in order, and the first one with a true expression runs. If no branches match, the default branch executes","properties":{"branches":{"type":"array","description":"Array of branches to evaluate in order. The first branch with expr evaluating to true executes","items":{"type":"object","properties":{"summary":{"type":"string","description":"Short description of this branch condition"},"expr":{"type":"string","description":"JavaScript expression that returns boolean. Can use 'results.step_id' or 'flow_input'. First true expr wins"},"modules":{"type":"array","description":"Steps to execute if this branch's expr is true","items":{"$ref":"#/components/schemas/FlowModule"}}},"required":["modules","expr"]}},"default":{"type":"array","description":"Steps to execute if no branch expressions match","items":{"$ref":"#/components/schemas/FlowModule"}},"type":{"type":"string","enum":["branchone"]}},"required":["branches","default","type"]},"BranchAll":{"type":"object","description":"Parallel branching where all branches execute simultaneously. Unlike BranchOne, all branches run regardless of conditions. Useful for executing independent tasks concurrently","properties":{"branches":{"type":"array","description":"Array of branches that all execute (either in parallel or sequentially)","items":{"type":"object","properties":{"summary":{"type":"string","description":"Short description of this branch's purpose"},"skip_failure":{"type":"boolean","description":"If true, failure in this branch doesn't fail the entire flow"},"modules":{"type":"array","description":"Steps to execute in this branch","items":{"$ref":"#/components/schemas/FlowModule"}}},"required":["modules"]}},"type":{"type":"string","enum":["branchall"]},"parallel":{"type":"boolean","description":"If true, all branches execute concurrently. If false, they execute sequentially"}},"required":["branches","type"]},"AgentTool":{"type":"object","description":"A tool available to an AI agent. Can be a flow module or an external MCP (Model Context Protocol) tool","properties":{"id":{"type":"string","description":"Unique identifier for this tool. Cannot contain spaces - use underscores instead (e.g., 'get_user_data' not 'get user data')"},"summary":{"type":"string","description":"Short description of what this tool does (shown to the AI)"},"value":{"$ref":"#/components/schemas/ToolValue"}},"required":["id","value"]},"ToolValue":{"description":"The implementation of a tool. Can be a flow module (script/flow) or an MCP tool reference","oneOf":[{"$ref":"#/components/schemas/FlowModuleTool"},{"$ref":"#/components/schemas/McpToolValue"},{"$ref":"#/components/schemas/WebsearchToolValue"}],"discriminator":{"propertyName":"tool_type","mapping":{"flowmodule":"#/components/schemas/FlowModuleTool","mcp":"#/components/schemas/McpToolValue","websearch":"#/components/schemas/WebsearchToolValue"}}},"FlowModuleTool":{"description":"A tool implemented as a flow module (script, flow, etc.). The AI can call this like any other flow module","allOf":[{"type":"object","properties":{"tool_type":{"type":"string","enum":["flowmodule"]}},"required":["tool_type"]},{"$ref":"#/components/schemas/FlowModuleValue"}]},"WebsearchToolValue":{"type":"object","description":"A tool implemented as a websearch tool. The AI can call this like any other websearch tool","properties":{"tool_type":{"type":"string","enum":["websearch"]}},"required":["tool_type"]},"McpToolValue":{"type":"object","description":"Reference to an external MCP (Model Context Protocol) tool. The AI can call tools from MCP servers","properties":{"tool_type":{"type":"string","enum":["mcp"]},"resource_path":{"type":"string","description":"Path to the MCP resource/server configuration"},"include_tools":{"type":"array","description":"Whitelist of specific tools to include from this MCP server","items":{"type":"string"}},"exclude_tools":{"type":"array","description":"Blacklist of tools to exclude from this MCP server","items":{"type":"string"}}},"required":["tool_type","resource_path"]},"AiAgent":{"type":"object","description":"AI agent step that can use tools to accomplish tasks. The agent receives inputs and can call any of its configured tools to complete the task","properties":{"input_transforms":{"type":"object","description":"Input parameters for the AI agent mapped to their values","properties":{"provider":{"$ref":"#/components/schemas/ProviderTransform"},"output_type":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"Output format type.\\nValid values: 'text' (default) - plain text response, 'image' - image generation\\n"},"user_message":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"The user's prompt/message to the AI agent. Supports variable interpolation with flow.input syntax."},"system_prompt":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"System instructions that guide the AI's behavior, persona, and response style. Optional."},"streaming":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"Boolean. If true, stream the AI response incrementally.\\nStreaming events include: token_delta, tool_call, tool_call_arguments, tool_execution, tool_result\\n"},"memory":{"$ref":"#/components/schemas/MemoryTransform"},"output_schema":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"JSON Schema object defining structured output format. Used when you need the AI to return data in a specific shape.\\nSupports standard JSON Schema properties: type, properties, required, items, enum, pattern, minLength, maxLength, minimum, maximum, etc.\\nExample: { type: 'object', properties: { name: { type: 'string' }, age: { type: 'integer' } }, required: ['name'] }\\n"},"user_attachments":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"Array of file references (images or PDFs) for the AI agent.\\nFormat: Array<{ bucket: string, key: string }> - S3 object references\\nExample: [{ bucket: 'my-bucket', key: 'documents/report.pdf' }]\\n"},"max_completion_tokens":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"Integer. Maximum number of tokens the AI will generate in its response.\\nRange: 1 to 4,294,967,295. Typical values: 256-4096 for most use cases.\\n"},"temperature":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"Float. Controls randomness/creativity of responses.\\nRange: 0.0 to 2.0 (provider-dependent)\\n- 0.0 = deterministic, focused responses\\n- 0.7 = balanced (common default)\\n- 1.0+ = more creative/random\\n"}},"required":["provider","user_message","output_type"]},"tools":{"type":"array","description":"Array of tools the agent can use. The agent decides which tools to call based on the task","items":{"$ref":"#/components/schemas/AgentTool"}},"type":{"type":"string","enum":["aiagent"]},"parallel":{"type":"boolean","description":"If true, the agent can execute multiple tool calls in parallel"}},"required":["tools","type","input_transforms"]},"Identity":{"type":"object","description":"Pass-through module that returns its input unchanged. Useful for flow structure or as a placeholder","properties":{"type":{"type":"string","enum":["identity"]},"flow":{"type":"boolean","description":"If true, marks this as a flow identity (special handling)"}},"required":["type"]},"FlowStatus":{"type":"object","properties":{"step":{"type":"integer"},"modules":{"type":"array","items":{"$ref":"#/components/schemas/FlowStatusModule"}},"user_states":{"additionalProperties":true},"preprocessor_module":{"allOf":[{"$ref":"#/components/schemas/FlowStatusModule"}]},"failure_module":{"allOf":[{"$ref":"#/components/schemas/FlowStatusModule"},{"type":"object","properties":{"parent_module":{"type":"string"}}}]},"retry":{"type":"object","properties":{"fail_count":{"type":"integer"},"failed_jobs":{"type":"array","items":{"type":"string","format":"uuid"}}}}},"required":["step","modules","failure_module"]},"FlowStatusModule":{"type":"object","properties":{"type":{"type":"string","enum":["WaitingForPriorSteps","WaitingForEvents","WaitingForExecutor","InProgress","Success","Failure"]},"id":{"type":"string"},"job":{"type":"string","format":"uuid"},"count":{"type":"integer"},"progress":{"type":"integer"},"iterator":{"type":"object","properties":{"index":{"type":"integer"},"itered":{"type":"array","items":{}},"itered_len":{"type":"integer"},"args":{}}},"flow_jobs":{"type":"array","items":{"type":"string"}},"flow_jobs_success":{"type":"array","items":{"type":"boolean"}},"flow_jobs_duration":{"type":"object","properties":{"started_at":{"type":"array","items":{"type":"string"}},"duration_ms":{"type":"array","items":{"type":"integer"}}}},"branch_chosen":{"type":"object","properties":{"type":{"type":"string","enum":["branch","default"]},"branch":{"type":"integer"}},"required":["type"]},"branchall":{"type":"object","properties":{"branch":{"type":"integer"},"len":{"type":"integer"}},"required":["branch","len"]},"approvers":{"type":"array","items":{"type":"object","properties":{"resume_id":{"type":"integer"},"approver":{"type":"string"}},"required":["resume_id","approver"]}},"failed_retries":{"type":"array","items":{"type":"string","format":"uuid"}},"skipped":{"type":"boolean"},"agent_actions":{"type":"array","items":{"type":"object","oneOf":[{"type":"object","properties":{"job_id":{"type":"string","format":"uuid"},"function_name":{"type":"string"},"type":{"type":"string","enum":["tool_call"]},"module_id":{"type":"string"}},"required":["job_id","function_name","type","module_id"]},{"type":"object","properties":{"call_id":{"type":"string","format":"uuid"},"function_name":{"type":"string"},"resource_path":{"type":"string"},"type":{"type":"string","enum":["mcp_tool_call"]},"arguments":{"type":"object"}},"required":["call_id","function_name","resource_path","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["web_search"]}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["message"]}},"required":["content","type"]}]}},"agent_actions_success":{"type":"array","items":{"type":"boolean"}}},"required":["type"]}}`,
|
|
79084
80044
|
"raw-app": `---
|
|
79085
80045
|
name: raw-app
|
|
79086
80046
|
description: MUST use when creating raw apps.
|
|
@@ -79907,7 +80867,7 @@ sync local with a remote instance or the opposite (push or pull)
|
|
|
79907
80867
|
- \`--dry-run\` - Perform a dry run without making changes
|
|
79908
80868
|
- \`--skip-users\` - Skip pulling users
|
|
79909
80869
|
- \`--skip-settings\` - Skip pulling settings
|
|
79910
|
-
- \`--skip-configs\` - Skip pulling configs (worker groups
|
|
80870
|
+
- \`--skip-configs\` - Skip pulling configs (worker groups)
|
|
79911
80871
|
- \`--skip-groups\` - Skip pulling instance groups
|
|
79912
80872
|
- \`--include-workspaces\` - Also pull workspaces
|
|
79913
80873
|
- \`--folder-per-instance\` - Create a folder per instance
|
|
@@ -79919,7 +80879,7 @@ sync local with a remote instance or the opposite (push or pull)
|
|
|
79919
80879
|
- \`--dry-run\` - Perform a dry run without making changes
|
|
79920
80880
|
- \`--skip-users\` - Skip pushing users
|
|
79921
80881
|
- \`--skip-settings\` - Skip pushing settings
|
|
79922
|
-
- \`--skip-configs\` - Skip pushing configs (worker groups
|
|
80882
|
+
- \`--skip-configs\` - Skip pushing configs (worker groups)
|
|
79923
80883
|
- \`--skip-groups\` - Skip pushing instance groups
|
|
79924
80884
|
- \`--include-workspaces\` - Also push workspaces
|
|
79925
80885
|
- \`--folder-per-instance\` - Create a folder per instance
|
|
@@ -80223,7 +81183,7 @@ display worker groups, pull and push worker groups configs
|
|
|
80223
81183
|
- \`--instance\` - Name of the instance to push to, override the active instance
|
|
80224
81184
|
- \`--base-url\` - Base url to be passed to the instance settings instead of the local one
|
|
80225
81185
|
- \`--yes\` - Pull without needing confirmation
|
|
80226
|
-
- \`worker-groups push\` - Push
|
|
81186
|
+
- \`worker-groups push\` - Push worker groups (similar to \`wmill instance push --skip-users --skip-settings --skip-groups\`)
|
|
80227
81187
|
- \`--instance [instance]\` - Name of the instance to push to, override the active instance
|
|
80228
81188
|
- \`--base-url [baseUrl]\` - If used with --token, will be used as the base url for the instance
|
|
80229
81189
|
- \`--yes\` - Push without needing confirmation
|
|
@@ -80260,8 +81220,19 @@ workspace related commands
|
|
|
80260
81220
|
- \`--branch, --env <branch:string>\` - Specify branch/environment (defaults to current)
|
|
80261
81221
|
- \`workspace fork [workspace_name:string] [workspace_id:string]\` - Create a forked workspace
|
|
80262
81222
|
- \`--create-workspace-name <workspace_name:string>\` - Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.
|
|
81223
|
+
- \`--color <color:string>\` - Workspace color (hex code, e.g. #ff0000)
|
|
81224
|
+
- \`--datatable-behavior <behavior:string>\` - How to handle datatables: skip, schema_only, or schema_and_data (default: interactive prompt)
|
|
81225
|
+
- \`-y --yes\` - Skip interactive prompts (defaults datatable behavior to 'skip')
|
|
80263
81226
|
- \`workspace delete-fork <fork_name:string>\` - Delete a forked workspace and git branch
|
|
80264
81227
|
- \`-y --yes\` - Skip confirmation prompt
|
|
81228
|
+
- \`workspace merge\` - Compare and deploy changes between a fork and its parent workspace
|
|
81229
|
+
- \`--direction <direction:string>\` - Deploy direction: to-parent or to-fork
|
|
81230
|
+
- \`--all\` - Deploy all changed items including conflicts
|
|
81231
|
+
- \`--skip-conflicts\` - Skip items modified in both workspaces
|
|
81232
|
+
- \`--include <items:string>\` - Comma-separated kind:path items to include (e.g. script:f/test/main,flow:f/my/flow)
|
|
81233
|
+
- \`--exclude <items:string>\` - Comma-separated kind:path items to exclude
|
|
81234
|
+
- \`--preserve-on-behalf-of\` - Preserve original on_behalf_of/permissioned_as values
|
|
81235
|
+
- \`-y --yes\` - Non-interactive mode (deploy without prompts)
|
|
80265
81236
|
|
|
80266
81237
|
`
|
|
80267
81238
|
};
|
|
@@ -82873,12 +83844,12 @@ var config_default = command35;
|
|
|
82873
83844
|
|
|
82874
83845
|
// src/main.ts
|
|
82875
83846
|
await init_context();
|
|
82876
|
-
var VERSION = "1.
|
|
83847
|
+
var VERSION = "1.680.0";
|
|
82877
83848
|
var command36 = new Command().name("wmill").action(() => info(`Welcome to Windmill CLI ${VERSION}. Use -h for help.`)).description("Windmill CLI").globalOption("--workspace <workspace:string>", "Specify the target workspace. This overrides the default workspace.").globalOption("--debug --verbose", "Show debug/verbose logs").globalOption("--show-diffs", "Show diff informations when syncing (may show sensitive informations)").globalOption("--token <token:string>", "Specify an API token. This will override any stored token.").globalOption("--base-url <baseUrl:string>", "Specify the base URL of the API. If used, --token and --workspace are required and no local remote/workspace already set will be used.").globalOption("--config-dir <configDir:string>", "Specify a custom config directory. Overrides WMILL_CONFIG_DIR environment variable and default ~/.config location.").env("HEADERS <headers:string>", `Specify headers to use for all requests. e.g: "HEADERS='h1: v1, h2: v2'"`).version(VERSION).versionOption(false).command("init", init_default).command("app", app_default).command("flow", flow_default).command("script", script_default).command("workspace", workspace_default).command("resource", resource_default).command("resource-type", resource_type_default).command("user", user_default).command("variable", variable_default).command("hub", hub_default).command("folder", folder_default).command("schedule", schedule_default).command("trigger", trigger_default).command("dev", dev_default2).command("sync", sync_default).command("lint", lint_default).command("gitsync-settings", gitsync_settings_default).command("instance", instance_default).command("worker-groups", worker_groups_default).command("workers", workers_default).command("queues", queues_default).command("dependencies", dependencies_default).command("jobs", jobs_default).command("job", job_default).command("group", group_default).command("audit", audit_default).command("token", token_default).command("generate-metadata", generate_metadata_default).command("docs", docs_default).command("config", config_default).command("version --version", "Show version information").action(async (opts) => {
|
|
82878
83849
|
console.log("CLI version: " + VERSION);
|
|
82879
83850
|
try {
|
|
82880
|
-
const
|
|
82881
|
-
const versions = await
|
|
83851
|
+
const provider2 = new NpmProvider({ package: "windmill-cli" });
|
|
83852
|
+
const versions = await provider2.getVersions("windmill-cli");
|
|
82882
83853
|
if (versions.latest !== VERSION) {
|
|
82883
83854
|
console.log(`CLI is outdated. Latest version ${versions.latest} is available. Run \`wmill upgrade\` to update.`);
|
|
82884
83855
|
} else {
|