windmill-cli 1.662.0 → 1.664.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 +736 -205
- package/package.json +3 -2
package/esm/main.js
CHANGED
|
@@ -11785,7 +11785,7 @@ var init_OpenAPI = __esm(() => {
|
|
|
11785
11785
|
PASSWORD: undefined,
|
|
11786
11786
|
TOKEN: getEnv2("WM_TOKEN"),
|
|
11787
11787
|
USERNAME: undefined,
|
|
11788
|
-
VERSION: "1.
|
|
11788
|
+
VERSION: "1.664.0",
|
|
11789
11789
|
WITH_CREDENTIALS: true,
|
|
11790
11790
|
interceptors: {
|
|
11791
11791
|
request: new Interceptors,
|
|
@@ -12114,6 +12114,7 @@ __export(exports_services_gen, {
|
|
|
12114
12114
|
testCriticalChannels: () => testCriticalChannels,
|
|
12115
12115
|
syncNativeTriggers: () => syncNativeTriggers,
|
|
12116
12116
|
submitOnboardingData: () => submitOnboardingData,
|
|
12117
|
+
storeRawScriptTemp: () => storeRawScriptTemp,
|
|
12117
12118
|
startMcpOauthPopup: () => startMcpOauthPopup,
|
|
12118
12119
|
star: () => star,
|
|
12119
12120
|
signS3Objects: () => signS3Objects,
|
|
@@ -12180,6 +12181,7 @@ __export(exports_services_gen, {
|
|
|
12180
12181
|
resumeSuspendedJobPost: () => resumeSuspendedJobPost,
|
|
12181
12182
|
resumeSuspendedJobGet: () => resumeSuspendedJobGet,
|
|
12182
12183
|
resumeSuspendedFlowAsOwner: () => resumeSuspendedFlowAsOwner,
|
|
12184
|
+
resumeSuspended: () => resumeSuspended,
|
|
12183
12185
|
resultById: () => resultById,
|
|
12184
12186
|
restartFlowAtStep: () => restartFlowAtStep,
|
|
12185
12187
|
resolveNpmPackageVersion: () => resolveNpmPackageVersion,
|
|
@@ -12480,6 +12482,7 @@ __export(exports_services_gen, {
|
|
|
12480
12482
|
getCriticalAlerts: () => getCriticalAlerts,
|
|
12481
12483
|
getCountsOfRunningJobsPerTag: () => getCountsOfRunningJobsPerTag,
|
|
12482
12484
|
getCountsOfJobsWaitingPerTag: () => getCountsOfJobsWaitingPerTag,
|
|
12485
|
+
getCopilotSettingsState: () => getCopilotSettingsState,
|
|
12483
12486
|
getCopilotInfo: () => getCopilotInfo,
|
|
12484
12487
|
getConfig: () => getConfig,
|
|
12485
12488
|
getConcurrencyKey: () => getConcurrencyKey,
|
|
@@ -12494,6 +12497,7 @@ __export(exports_services_gen, {
|
|
|
12494
12497
|
getCapture: () => getCapture,
|
|
12495
12498
|
getAuditLog: () => getAuditLog,
|
|
12496
12499
|
getArgsFromHistoryOrSavedInput: () => getArgsFromHistoryOrSavedInput,
|
|
12500
|
+
getApprovalInfo: () => getApprovalInfo,
|
|
12497
12501
|
getAppLiteByPath: () => getAppLiteByPath,
|
|
12498
12502
|
getAppLatestVersion: () => getAppLatestVersion,
|
|
12499
12503
|
getAppHistoryByPath: () => getAppHistoryByPath,
|
|
@@ -12563,6 +12567,7 @@ __export(exports_services_gen, {
|
|
|
12563
12567
|
disconnectTeams: () => disconnectTeams,
|
|
12564
12568
|
disconnectSlack: () => disconnectSlack,
|
|
12565
12569
|
disconnectAccount: () => disconnectAccount,
|
|
12570
|
+
diffRawScriptsWithDeployed: () => diffRawScriptsWithDeployed,
|
|
12566
12571
|
deleteWorkspaceSlackOauthConfig: () => deleteWorkspaceSlackOauthConfig,
|
|
12567
12572
|
deleteWorkspaceDependencies: () => deleteWorkspaceDependencies,
|
|
12568
12573
|
deleteWorkspace: () => deleteWorkspace,
|
|
@@ -13748,6 +13753,14 @@ var backendVersion = () => {
|
|
|
13748
13753
|
body: data2.requestBody,
|
|
13749
13754
|
mediaType: "application/json"
|
|
13750
13755
|
});
|
|
13756
|
+
}, getCopilotSettingsState = (data2) => {
|
|
13757
|
+
return request(OpenAPI, {
|
|
13758
|
+
method: "GET",
|
|
13759
|
+
url: "/w/{workspace}/workspaces/get_copilot_settings_state",
|
|
13760
|
+
path: {
|
|
13761
|
+
workspace: data2.workspace
|
|
13762
|
+
}
|
|
13763
|
+
});
|
|
13751
13764
|
}, getCopilotInfo = (data2) => {
|
|
13752
13765
|
return request(OpenAPI, {
|
|
13753
13766
|
method: "GET",
|
|
@@ -15125,6 +15138,26 @@ var backendVersion = () => {
|
|
|
15125
15138
|
hash: data2.hash
|
|
15126
15139
|
}
|
|
15127
15140
|
});
|
|
15141
|
+
}, storeRawScriptTemp = (data2) => {
|
|
15142
|
+
return request(OpenAPI, {
|
|
15143
|
+
method: "POST",
|
|
15144
|
+
url: "/w/{workspace}/scripts/raw_temp/store",
|
|
15145
|
+
path: {
|
|
15146
|
+
workspace: data2.workspace
|
|
15147
|
+
},
|
|
15148
|
+
body: data2.requestBody,
|
|
15149
|
+
mediaType: "application/json"
|
|
15150
|
+
});
|
|
15151
|
+
}, diffRawScriptsWithDeployed = (data2) => {
|
|
15152
|
+
return request(OpenAPI, {
|
|
15153
|
+
method: "POST",
|
|
15154
|
+
url: "/w/{workspace}/scripts/raw_temp/diff",
|
|
15155
|
+
path: {
|
|
15156
|
+
workspace: data2.workspace
|
|
15157
|
+
},
|
|
15158
|
+
body: data2.requestBody,
|
|
15159
|
+
mediaType: "application/json"
|
|
15160
|
+
});
|
|
15128
15161
|
}, listSelectedJobGroups = (data2) => {
|
|
15129
15162
|
return request(OpenAPI, {
|
|
15130
15163
|
method: "POST",
|
|
@@ -16771,6 +16804,29 @@ var backendVersion = () => {
|
|
|
16771
16804
|
cancel_button_text: data2.cancelButtonText
|
|
16772
16805
|
}
|
|
16773
16806
|
});
|
|
16807
|
+
}, resumeSuspended = (data2) => {
|
|
16808
|
+
return request(OpenAPI, {
|
|
16809
|
+
method: "POST",
|
|
16810
|
+
url: "/w/{workspace}/jobs_u/flow/resume_suspended/{job_id}",
|
|
16811
|
+
path: {
|
|
16812
|
+
workspace: data2.workspace,
|
|
16813
|
+
job_id: data2.jobId
|
|
16814
|
+
},
|
|
16815
|
+
body: data2.requestBody,
|
|
16816
|
+
mediaType: "application/json"
|
|
16817
|
+
});
|
|
16818
|
+
}, getApprovalInfo = (data2) => {
|
|
16819
|
+
return request(OpenAPI, {
|
|
16820
|
+
method: "GET",
|
|
16821
|
+
url: "/w/{workspace}/jobs_u/flow/approval_info/{job_id}",
|
|
16822
|
+
path: {
|
|
16823
|
+
workspace: data2.workspace,
|
|
16824
|
+
job_id: data2.jobId
|
|
16825
|
+
},
|
|
16826
|
+
query: {
|
|
16827
|
+
token: data2.token
|
|
16828
|
+
}
|
|
16829
|
+
});
|
|
16774
16830
|
}, resumeSuspendedJobGet = (data2) => {
|
|
16775
16831
|
return request(OpenAPI, {
|
|
16776
16832
|
method: "GET",
|
|
@@ -24269,6 +24325,15 @@ function isAppPath(p) {
|
|
|
24269
24325
|
function isRawAppPath(p) {
|
|
24270
24326
|
return normalizeSep(p).includes(getFolderSuffixes().raw_app + "/");
|
|
24271
24327
|
}
|
|
24328
|
+
function isFolderResourcePathAnyFormat(p) {
|
|
24329
|
+
const n = normalizeSep(p);
|
|
24330
|
+
for (const suffixes of [DOTTED_SUFFIXES, NON_DOTTED_SUFFIXES]) {
|
|
24331
|
+
if (n.includes(suffixes.flow + "/") || n.includes(suffixes.app + "/") || n.includes(suffixes.raw_app + "/")) {
|
|
24332
|
+
return true;
|
|
24333
|
+
}
|
|
24334
|
+
}
|
|
24335
|
+
return false;
|
|
24336
|
+
}
|
|
24272
24337
|
function isRawAppBackendPath(filePath) {
|
|
24273
24338
|
const suffixes = getFolderSuffixes();
|
|
24274
24339
|
const normalizedPath = filePath.replaceAll(SEP2, "/");
|
|
@@ -58861,7 +58926,7 @@ var init_tar = __esm(() => {
|
|
|
58861
58926
|
});
|
|
58862
58927
|
|
|
58863
58928
|
// src/commands/script/script.ts
|
|
58864
|
-
import { readFile as readFile5, writeFile as writeFile4, stat as stat3 } from "node:fs/promises";
|
|
58929
|
+
import { readFile as readFile5, writeFile as writeFile4, stat as stat3, mkdir as mkdir3 } from "node:fs/promises";
|
|
58865
58930
|
import { Buffer as Buffer4 } from "node:buffer";
|
|
58866
58931
|
import { sep as SEP4 } from "node:path";
|
|
58867
58932
|
import * as path5 from "node:path";
|
|
@@ -58891,7 +58956,7 @@ async function push(opts, filePath) {
|
|
|
58891
58956
|
}
|
|
58892
58957
|
await requireLogin(opts);
|
|
58893
58958
|
const codebases = await listSyncCodebases(opts);
|
|
58894
|
-
await handleFile(filePath, workspace, [], undefined, opts, await getRawWorkspaceDependencies(), codebases);
|
|
58959
|
+
await handleFile(filePath, workspace, [], undefined, opts, await getRawWorkspaceDependencies(true), codebases);
|
|
58895
58960
|
info(colors.bold.underline.green(`Script ${filePath} pushed`));
|
|
58896
58961
|
}
|
|
58897
58962
|
async function findResourceFile(path6) {
|
|
@@ -59437,12 +59502,13 @@ async function bootstrap(opts, scriptPath, language) {
|
|
|
59437
59502
|
if (!validatePath(scriptPath)) {
|
|
59438
59503
|
return;
|
|
59439
59504
|
}
|
|
59440
|
-
const
|
|
59505
|
+
const resolvedLanguage = languageAliases[language] ?? language;
|
|
59506
|
+
const scriptInitialCode = scriptBootstrapCode[resolvedLanguage];
|
|
59441
59507
|
if (scriptInitialCode === undefined) {
|
|
59442
59508
|
throw new Error("Language unknown");
|
|
59443
59509
|
}
|
|
59444
59510
|
const config = await readConfigFile();
|
|
59445
|
-
const extension = filePathExtensionFromContentType(
|
|
59511
|
+
const extension = filePathExtensionFromContentType(resolvedLanguage, config.defaultTs);
|
|
59446
59512
|
const scriptCodeFileFullPath = scriptPath + extension;
|
|
59447
59513
|
const scriptMetadataFileFullPath = scriptPath + ".script.yaml";
|
|
59448
59514
|
try {
|
|
@@ -59467,6 +59533,8 @@ async function bootstrap(opts, scriptPath, language) {
|
|
|
59467
59533
|
scriptMetadata.description = opts.description;
|
|
59468
59534
|
}
|
|
59469
59535
|
const scriptInitialMetadataYaml = import_yaml5.stringify(scriptMetadata, yamlOptions);
|
|
59536
|
+
const parentDir = path5.dirname(scriptCodeFileFullPath);
|
|
59537
|
+
await mkdir3(parentDir, { recursive: true });
|
|
59470
59538
|
await writeFile4(scriptCodeFileFullPath, scriptInitialCode, {
|
|
59471
59539
|
flag: "wx",
|
|
59472
59540
|
encoding: "utf-8"
|
|
@@ -59489,7 +59557,7 @@ async function generateMetadata(opts, scriptPath) {
|
|
|
59489
59557
|
await requireLogin(opts);
|
|
59490
59558
|
opts = await mergeConfigWithConfigFile(opts);
|
|
59491
59559
|
const codebases = await listSyncCodebases(opts);
|
|
59492
|
-
const rawWorkspaceDependencies = await getRawWorkspaceDependencies();
|
|
59560
|
+
const rawWorkspaceDependencies = await getRawWorkspaceDependencies(true);
|
|
59493
59561
|
if (scriptPath) {
|
|
59494
59562
|
await generateScriptMetadataInternal(scriptPath, workspace, opts, false, false, rawWorkspaceDependencies, codebases, false);
|
|
59495
59563
|
} else {
|
|
@@ -59682,7 +59750,7 @@ async function preview(opts, filePath) {
|
|
|
59682
59750
|
}
|
|
59683
59751
|
}
|
|
59684
59752
|
}
|
|
59685
|
-
var import_yaml5, exts, command3, script_default;
|
|
59753
|
+
var import_yaml5, exts, languageAliases, command3, script_default;
|
|
59686
59754
|
var init_script = __esm(async () => {
|
|
59687
59755
|
init_colors2();
|
|
59688
59756
|
init_mod3();
|
|
@@ -59734,6 +59802,9 @@ var init_script = __esm(async () => {
|
|
|
59734
59802
|
".java",
|
|
59735
59803
|
".rb"
|
|
59736
59804
|
];
|
|
59805
|
+
languageAliases = {
|
|
59806
|
+
python: "python3"
|
|
59807
|
+
};
|
|
59737
59808
|
command3 = new Command().description("script related commands").option("--show-archived", "Enable archived scripts in output").option("--json", "Output as JSON (for piping to jq)").action(list2).command("list", "list all scripts").option("--show-archived", "Enable archived scripts in output").option("--json", "Output as JSON (for piping to jq)").action(list2).command("push", "push a local script spec. This overrides any remote versions. Use the script file (.ts, .js, .py, .sh)").arguments("<path:file>").action(push).command("get", "get a script's details").arguments("<path:file>").option("--json", "Output as JSON (for piping to jq)").action(get).command("show", "show a script's content (alias for get)").arguments("<path:file>").action(show).command("run", "run a script by path").arguments("<path:file>").option("-d --data <data:file>", "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.").action(run2).command("preview", "preview a local script without deploying it. Supports both regular and codebase scripts.").arguments("<path:file>").option("-d --data <data:file>", "Inputs specified as a JSON string or a file using @<filename> or stdin using @-.").option("-s --silent", "Do not output anything other than the final output. Useful for scripting.").action(preview).command("new", "create a new script").arguments("<path:file> <language:string>").option("--summary <summary:string>", "script summary").option("--description <description:string>", "script description").action(bootstrap).command("bootstrap", "create a new script (alias for new)").arguments("<path:file> <language:string>").option("--summary <summary:string>", "script summary").option("--description <description:string>", "script description").action(bootstrap).command("generate-metadata", "re-generate the metadata file updating the lock and the script schema (for flows, use `wmill flow generate-locks`)").arguments("[script:file]").option("--yes", "Skip confirmation prompt").option("--dry-run", "Perform a dry run without making changes").option("--lock-only", "re-generate only the lock").option("--schema-only", "re-generate only script schema").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(generateMetadata);
|
|
59738
59809
|
script_default = command3;
|
|
59739
59810
|
});
|
|
@@ -60772,6 +60843,33 @@ function collectPathScriptPaths(flowValue) {
|
|
|
60772
60843
|
return [...paths];
|
|
60773
60844
|
}
|
|
60774
60845
|
|
|
60846
|
+
// src/utils/relative_imports.ts
|
|
60847
|
+
async function extractRelativeImports(code2, scriptPath, language) {
|
|
60848
|
+
try {
|
|
60849
|
+
switch (language) {
|
|
60850
|
+
case "bun":
|
|
60851
|
+
case "nativets":
|
|
60852
|
+
case "deno": {
|
|
60853
|
+
const { parse_ts_relative_imports } = await loadParser("windmill-parser-wasm-ts");
|
|
60854
|
+
return parse_ts_relative_imports(code2, scriptPath);
|
|
60855
|
+
}
|
|
60856
|
+
case "python3": {
|
|
60857
|
+
const { parse_py_relative_imports } = await loadParser("windmill-parser-wasm-py-imports");
|
|
60858
|
+
return parse_py_relative_imports(code2, scriptPath);
|
|
60859
|
+
}
|
|
60860
|
+
default:
|
|
60861
|
+
return [];
|
|
60862
|
+
}
|
|
60863
|
+
} catch (e) {
|
|
60864
|
+
warn(`Failed to parse relative imports for ${scriptPath}: ${e}. Dependency tracking for relative imports will be disabled.`);
|
|
60865
|
+
return [];
|
|
60866
|
+
}
|
|
60867
|
+
}
|
|
60868
|
+
var init_relative_imports = __esm(async () => {
|
|
60869
|
+
init_log();
|
|
60870
|
+
await init_metadata();
|
|
60871
|
+
});
|
|
60872
|
+
|
|
60775
60873
|
// src/commands/flow/flow_metadata.ts
|
|
60776
60874
|
import * as path7 from "node:path";
|
|
60777
60875
|
import { sep as SEP7 } from "node:path";
|
|
@@ -60787,7 +60885,7 @@ async function generateFlowHash(rawWorkspaceDependencies, folder, defaultTs) {
|
|
|
60787
60885
|
}
|
|
60788
60886
|
return { ...hashes, [TOP_HASH]: await generateHash(JSON.stringify(hashes)) };
|
|
60789
60887
|
}
|
|
60790
|
-
async function generateFlowLockInternal(folder, dryRun, workspace, opts, justUpdateMetadataLock, noStaleMessage) {
|
|
60888
|
+
async function generateFlowLockInternal(folder, dryRun, workspace, opts, justUpdateMetadataLock, noStaleMessage, legacyBehaviour, tree) {
|
|
60791
60889
|
if (folder.endsWith(SEP7)) {
|
|
60792
60890
|
folder = folder.substring(0, folder.length - 1);
|
|
60793
60891
|
}
|
|
@@ -60795,24 +60893,65 @@ async function generateFlowLockInternal(folder, dryRun, workspace, opts, justUpd
|
|
|
60795
60893
|
if (!justUpdateMetadataLock && !noStaleMessage) {
|
|
60796
60894
|
info(`Generating lock for flow ${folder} at ${remote_path}`);
|
|
60797
60895
|
}
|
|
60798
|
-
const rawWorkspaceDependencies = await getRawWorkspaceDependencies();
|
|
60799
60896
|
const flowValue = await yamlParseFile(folder + SEP7 + "flow.yaml");
|
|
60800
|
-
const
|
|
60801
|
-
|
|
60897
|
+
const folderNormalized = folder.replaceAll(SEP7, "/");
|
|
60898
|
+
const inlineScriptsForTree = extractInlineScripts(structuredClone(flowValue.value.modules), {}, SEP7, opts.defaultTs).filter((s) => !s.is_lock);
|
|
60899
|
+
let filteredDeps = {};
|
|
60802
60900
|
const conf = await readLockfile();
|
|
60803
|
-
if (
|
|
60804
|
-
if (
|
|
60805
|
-
|
|
60901
|
+
if (!legacyBehaviour && tree) {
|
|
60902
|
+
if (dryRun) {
|
|
60903
|
+
const inlineScriptPaths = [];
|
|
60904
|
+
for (const script of inlineScriptsForTree) {
|
|
60905
|
+
let content = script.content;
|
|
60906
|
+
if (content.startsWith("!inline ")) {
|
|
60907
|
+
const filePath = folder + SEP7 + content.replace("!inline ", "");
|
|
60908
|
+
try {
|
|
60909
|
+
content = await readFile7(filePath, "utf-8");
|
|
60910
|
+
} catch {
|
|
60911
|
+
continue;
|
|
60912
|
+
}
|
|
60913
|
+
}
|
|
60914
|
+
const treePath = folderNormalized + "/" + path7.basename(script.path, path7.extname(script.path));
|
|
60915
|
+
const language = script.language;
|
|
60916
|
+
const imports = await extractRelativeImports(content, treePath, language);
|
|
60917
|
+
await tree.addNode(treePath, content, language, "", imports, "inline_script", folderNormalized, folder, false);
|
|
60918
|
+
inlineScriptPaths.push(treePath);
|
|
60919
|
+
}
|
|
60920
|
+
const hashes = await generateFlowHash({}, folder, opts.defaultTs);
|
|
60921
|
+
const isDirectlyStale = !await checkifMetadataUptodate(folder, hashes[TOP_HASH], conf, TOP_HASH);
|
|
60922
|
+
await tree.addNode(folderNormalized, "", "bun", "", inlineScriptPaths, "flow", folderNormalized, folder, isDirectlyStale);
|
|
60923
|
+
return;
|
|
60924
|
+
}
|
|
60925
|
+
filteredDeps = await filterWorkspaceDependenciesForFlow(flowValue.value, tree.getMismatchedWorkspaceDeps(), folder);
|
|
60926
|
+
} else {
|
|
60927
|
+
const rawWorkspaceDependencies = await getRawWorkspaceDependencies(true);
|
|
60928
|
+
filteredDeps = await filterWorkspaceDependenciesForFlow(flowValue.value, rawWorkspaceDependencies, folder);
|
|
60929
|
+
const hashes = await generateFlowHash(filteredDeps, folder, opts.defaultTs);
|
|
60930
|
+
const isDirectlyStale = !await checkifMetadataUptodate(folder, hashes[TOP_HASH], conf, TOP_HASH);
|
|
60931
|
+
if (!isDirectlyStale) {
|
|
60932
|
+
if (!noStaleMessage) {
|
|
60933
|
+
info(colors.green(`Flow ${remote_path} metadata is up-to-date, skipping`));
|
|
60934
|
+
}
|
|
60935
|
+
return;
|
|
60936
|
+
} else if (dryRun) {
|
|
60937
|
+
return remote_path;
|
|
60806
60938
|
}
|
|
60807
|
-
return;
|
|
60808
|
-
} else if (dryRun) {
|
|
60809
|
-
return remote_path;
|
|
60810
60939
|
}
|
|
60811
60940
|
if (Object.keys(filteredDeps).length > 0 && !noStaleMessage) {
|
|
60812
60941
|
info((await blueColor())(`Found workspace dependencies (${workspaceDependenciesLanguages.map((l) => l.filename).join("/")}) for ${folder}, using them`));
|
|
60813
60942
|
}
|
|
60814
60943
|
let changedScripts = [];
|
|
60944
|
+
const fileToTreePath = new Map;
|
|
60945
|
+
for (const script of inlineScriptsForTree) {
|
|
60946
|
+
const c = script.content;
|
|
60947
|
+
if (c.startsWith("!inline ")) {
|
|
60948
|
+
const fileName = c.replace("!inline ", "");
|
|
60949
|
+
const treePath = folderNormalized + "/" + path7.basename(script.path, path7.extname(script.path));
|
|
60950
|
+
fileToTreePath.set(fileName, treePath);
|
|
60951
|
+
}
|
|
60952
|
+
}
|
|
60815
60953
|
if (!justUpdateMetadataLock) {
|
|
60954
|
+
const hashes = await generateFlowHash(filteredDeps, folder, opts.defaultTs);
|
|
60816
60955
|
for (const [path8, hash2] of Object.entries(hashes)) {
|
|
60817
60956
|
if (path8 == TOP_HASH) {
|
|
60818
60957
|
continue;
|
|
@@ -60825,14 +60964,21 @@ async function generateFlowLockInternal(folder, dryRun, workspace, opts, justUpd
|
|
|
60825
60964
|
info(`Recomputing locks of ${changedScripts.join(", ")} in ${folder}`);
|
|
60826
60965
|
}
|
|
60827
60966
|
const fileReader = async (path8) => await readFile7(folder + SEP7 + path8, "utf-8");
|
|
60828
|
-
|
|
60967
|
+
const locksToRemove = tree && !legacyBehaviour ? Object.keys(hashes).filter((k) => {
|
|
60968
|
+
if (k === TOP_HASH)
|
|
60969
|
+
return false;
|
|
60970
|
+
const treePath = fileToTreePath.get(k) ?? folderNormalized + "/" + path7.basename(k, path7.extname(k));
|
|
60971
|
+
return tree.isStale(treePath);
|
|
60972
|
+
}) : changedScripts;
|
|
60973
|
+
await replaceInlineScripts(flowValue.value.modules, fileReader, exports_log, folder + SEP7, SEP7, locksToRemove);
|
|
60829
60974
|
if (flowValue.value.failure_module) {
|
|
60830
|
-
await replaceInlineScripts([flowValue.value.failure_module], fileReader, exports_log, folder + SEP7, SEP7,
|
|
60975
|
+
await replaceInlineScripts([flowValue.value.failure_module], fileReader, exports_log, folder + SEP7, SEP7, locksToRemove);
|
|
60831
60976
|
}
|
|
60832
60977
|
if (flowValue.value.preprocessor_module) {
|
|
60833
|
-
await replaceInlineScripts([flowValue.value.preprocessor_module], fileReader, exports_log, folder + SEP7, SEP7,
|
|
60978
|
+
await replaceInlineScripts([flowValue.value.preprocessor_module], fileReader, exports_log, folder + SEP7, SEP7, locksToRemove);
|
|
60834
60979
|
}
|
|
60835
|
-
|
|
60980
|
+
const tempScriptRefs = tree?.getTempScriptRefs(folderNormalized);
|
|
60981
|
+
flowValue.value = await updateFlow2(workspace, flowValue.value, remote_path, filteredDeps, tempScriptRefs);
|
|
60836
60982
|
const lockAssigner = newPathAssigner(opts.defaultTs ?? "bun", {
|
|
60837
60983
|
skipInlineScriptSuffix: getNonDottedPaths()
|
|
60838
60984
|
});
|
|
@@ -60848,15 +60994,22 @@ async function generateFlowLockInternal(folder, dryRun, workspace, opts, justUpd
|
|
|
60848
60994
|
});
|
|
60849
60995
|
writeIfChanged(process.cwd() + SEP7 + folder + SEP7 + "flow.yaml", import_yaml8.stringify(flowValue));
|
|
60850
60996
|
}
|
|
60851
|
-
|
|
60997
|
+
const depsForHash = tree && !legacyBehaviour ? {} : filteredDeps;
|
|
60998
|
+
const finalHashes = await generateFlowHash(depsForHash, folder, opts.defaultTs);
|
|
60852
60999
|
await clearGlobalLock(folder);
|
|
60853
|
-
for (const [path8, hash2] of Object.entries(
|
|
61000
|
+
for (const [path8, hash2] of Object.entries(finalHashes)) {
|
|
60854
61001
|
await updateMetadataGlobalLock(folder, hash2, path8);
|
|
60855
61002
|
}
|
|
60856
61003
|
if (!noStaleMessage) {
|
|
60857
61004
|
info(colors.green(`Flow ${remote_path} lockfiles updated`));
|
|
60858
61005
|
}
|
|
60859
|
-
const
|
|
61006
|
+
const relocked = tree && !legacyBehaviour ? Object.keys(finalHashes).filter((k) => {
|
|
61007
|
+
if (k === TOP_HASH)
|
|
61008
|
+
return false;
|
|
61009
|
+
const treePath = fileToTreePath.get(k) ?? folderNormalized + "/" + path7.basename(k, path7.extname(k));
|
|
61010
|
+
return tree.isStale(treePath);
|
|
61011
|
+
}) : changedScripts;
|
|
61012
|
+
const updatedScripts = relocked.map((p) => {
|
|
60860
61013
|
const parts = p.split(SEP7);
|
|
60861
61014
|
return parts[parts.length - 1].replace(/\.[^.]+$/, "");
|
|
60862
61015
|
});
|
|
@@ -60875,7 +61028,7 @@ async function filterWorkspaceDependenciesForFlow(flowValue, rawWorkspaceDepende
|
|
|
60875
61028
|
const scripts = inlineScripts.filter((s) => !s.is_lock).map((s) => ({ content: s.content, language: s.language }));
|
|
60876
61029
|
return await filterWorkspaceDependenciesForScripts(scripts, rawWorkspaceDependencies, folder, SEP7);
|
|
60877
61030
|
}
|
|
60878
|
-
async function updateFlow2(workspace, flow_value, remotePath, rawWorkspaceDependencies) {
|
|
61031
|
+
async function updateFlow2(workspace, flow_value, remotePath, rawWorkspaceDependencies, tempScriptRefs) {
|
|
60879
61032
|
let rawResponse;
|
|
60880
61033
|
if (Object.keys(rawWorkspaceDependencies).length > 0) {
|
|
60881
61034
|
info(colors.blue("Using raw workspace dependencies for flow dependencies"));
|
|
@@ -60891,7 +61044,8 @@ async function updateFlow2(workspace, flow_value, remotePath, rawWorkspaceDepend
|
|
|
60891
61044
|
flow_value,
|
|
60892
61045
|
path: remotePath,
|
|
60893
61046
|
use_local_lockfiles: true,
|
|
60894
|
-
raw_workspace_dependencies: rawWorkspaceDependencies
|
|
61047
|
+
raw_workspace_dependencies: rawWorkspaceDependencies,
|
|
61048
|
+
...tempScriptRefs && Object.keys(tempScriptRefs).length > 0 ? { temp_script_refs: tempScriptRefs } : {}
|
|
60895
61049
|
})
|
|
60896
61050
|
});
|
|
60897
61051
|
} else {
|
|
@@ -60905,7 +61059,8 @@ async function updateFlow2(workspace, flow_value, remotePath, rawWorkspaceDepend
|
|
|
60905
61059
|
},
|
|
60906
61060
|
body: JSON.stringify({
|
|
60907
61061
|
flow_value,
|
|
60908
|
-
path: remotePath
|
|
61062
|
+
path: remotePath,
|
|
61063
|
+
...tempScriptRefs && Object.keys(tempScriptRefs).length > 0 ? { temp_script_refs: tempScriptRefs } : {}
|
|
60909
61064
|
})
|
|
60910
61065
|
});
|
|
60911
61066
|
}
|
|
@@ -60942,7 +61097,8 @@ var init_flow_metadata = __esm(async () => {
|
|
|
60942
61097
|
init_metadata(),
|
|
60943
61098
|
init_utils(),
|
|
60944
61099
|
init_script(),
|
|
60945
|
-
init_sync()
|
|
61100
|
+
init_sync(),
|
|
61101
|
+
init_relative_imports()
|
|
60946
61102
|
]);
|
|
60947
61103
|
import_yaml8 = __toESM(require_dist(), 1);
|
|
60948
61104
|
});
|
|
@@ -60965,7 +61121,7 @@ __export(exports_sync, {
|
|
|
60965
61121
|
default: () => sync_default,
|
|
60966
61122
|
FSFSElement: () => FSFSElement
|
|
60967
61123
|
});
|
|
60968
|
-
import { readFile as readFile8, writeFile as writeFile6, readdir as readdir4, stat as stat6, rm, copyFile, mkdir as
|
|
61124
|
+
import { readFile as readFile8, writeFile as writeFile6, readdir as readdir4, stat as stat6, rm, copyFile, mkdir as mkdir4 } from "node:fs/promises";
|
|
60969
61125
|
import * as path8 from "node:path";
|
|
60970
61126
|
import { sep as SEP8 } from "node:path";
|
|
60971
61127
|
function mergeCliWithEffectiveOptions(cliOpts, effectiveOpts) {
|
|
@@ -62268,7 +62424,7 @@ async function pull(opts) {
|
|
|
62268
62424
|
throw error2;
|
|
62269
62425
|
}
|
|
62270
62426
|
if (opts.stateful) {
|
|
62271
|
-
await
|
|
62427
|
+
await mkdir4(path8.join(process.cwd(), ".wmill"), { recursive: true });
|
|
62272
62428
|
}
|
|
62273
62429
|
const workspace = await resolveWorkspace(opts, opts.branch);
|
|
62274
62430
|
await requireLogin(opts);
|
|
@@ -62367,13 +62523,13 @@ Both local and remote have been modified.`));
|
|
|
62367
62523
|
}
|
|
62368
62524
|
await writeFile6(target, change.after, "utf-8");
|
|
62369
62525
|
if (opts.stateful) {
|
|
62370
|
-
await
|
|
62526
|
+
await mkdir4(path8.dirname(stateTarget), { recursive: true });
|
|
62371
62527
|
await copyFile(target, stateTarget);
|
|
62372
62528
|
}
|
|
62373
62529
|
} else if (change.name === "added") {
|
|
62374
|
-
await
|
|
62530
|
+
await mkdir4(path8.dirname(target), { recursive: true });
|
|
62375
62531
|
if (opts.stateful) {
|
|
62376
|
-
await
|
|
62532
|
+
await mkdir4(path8.dirname(stateTarget), { recursive: true });
|
|
62377
62533
|
info(`Adding ${getTypeStrFromPath(change.path)} ${targetPath}${targetPath !== change.path ? colors.gray(` (branch-specific override for ${change.path})`) : ""}`);
|
|
62378
62534
|
}
|
|
62379
62535
|
await writeFile6(target, change.content, "utf-8");
|
|
@@ -62412,7 +62568,7 @@ Both local and remote have been modified.`));
|
|
|
62412
62568
|
info("All local changes pulled, now updating wmill-lock.yaml");
|
|
62413
62569
|
await readLockfile();
|
|
62414
62570
|
const tracker = await buildTracker(changes);
|
|
62415
|
-
const rawWorkspaceDependencies = await getRawWorkspaceDependencies();
|
|
62571
|
+
const rawWorkspaceDependencies = await getRawWorkspaceDependencies(true);
|
|
62416
62572
|
for (const change of tracker.scripts) {
|
|
62417
62573
|
await generateScriptMetadataInternal(change, workspace, opts, false, true, rawWorkspaceDependencies, codebases, true);
|
|
62418
62574
|
}
|
|
@@ -62557,7 +62713,7 @@ Push aborted: ${lockIssues.length} script(s) missing locks.`));
|
|
|
62557
62713
|
const remote = ZipFSElement(await downloadZip(workspace, opts.plainSecrets, opts.skipVariables, opts.skipResources, opts.skipResourceTypes, opts.skipSecrets, opts.includeSchedules, opts.includeTriggers, opts.includeUsers, opts.includeGroups, opts.includeSettings, opts.includeKey, opts.skipWorkspaceDependencies, opts.defaultTs), !opts.json, opts.defaultTs ?? "bun", resourceTypeToFormatExtension, resourceTypeToIsFileset, false);
|
|
62558
62714
|
const local = await FSFSElement(path8.join(process.cwd(), ""), codebases, false);
|
|
62559
62715
|
const changes = await compareDynFSElement(local, remote, await ignoreF(opts), opts.json ?? false, opts, true, codebases, false, specificItems, opts.branch, false);
|
|
62560
|
-
const rawWorkspaceDependencies = await getRawWorkspaceDependencies();
|
|
62716
|
+
const rawWorkspaceDependencies = await getRawWorkspaceDependencies(true);
|
|
62561
62717
|
const tracker = await buildTracker(changes);
|
|
62562
62718
|
const staleScripts = [];
|
|
62563
62719
|
const staleFlows = [];
|
|
@@ -62752,7 +62908,7 @@ ${folderList}
|
|
|
62752
62908
|
continue;
|
|
62753
62909
|
}
|
|
62754
62910
|
if (stateTarget) {
|
|
62755
|
-
await
|
|
62911
|
+
await mkdir4(path8.dirname(stateTarget), { recursive: true });
|
|
62756
62912
|
info(`Editing ${getTypeStrFromPath(change.path)} ${change.path}`);
|
|
62757
62913
|
}
|
|
62758
62914
|
if (isFileResource(change.path)) {
|
|
@@ -62809,7 +62965,7 @@ ${folderList}
|
|
|
62809
62965
|
continue;
|
|
62810
62966
|
}
|
|
62811
62967
|
if (stateTarget) {
|
|
62812
|
-
await
|
|
62968
|
+
await mkdir4(path8.dirname(stateTarget), { recursive: true });
|
|
62813
62969
|
info(`Adding ${getTypeStrFromPath(change.path)} ${change.path}`);
|
|
62814
62970
|
}
|
|
62815
62971
|
const obj = parseFromPath(change.path, change.content);
|
|
@@ -63351,30 +63507,6 @@ var init_parse_schema = __esm(() => {
|
|
|
63351
63507
|
});
|
|
63352
63508
|
|
|
63353
63509
|
// src/utils/metadata.ts
|
|
63354
|
-
var exports_metadata = {};
|
|
63355
|
-
__export(exports_metadata, {
|
|
63356
|
-
workspaceDependenciesPathToLanguageAndFilename: () => workspaceDependenciesPathToLanguageAndFilename,
|
|
63357
|
-
updateScriptSchema: () => updateScriptSchema,
|
|
63358
|
-
updateMetadataGlobalLock: () => updateMetadataGlobalLock,
|
|
63359
|
-
replaceLock: () => replaceLock,
|
|
63360
|
-
readLockfile: () => readLockfile,
|
|
63361
|
-
parseMetadataFileIfExists: () => parseMetadataFileIfExists,
|
|
63362
|
-
parseMetadataFile: () => parseMetadataFile,
|
|
63363
|
-
normalizeLockPath: () => normalizeLockPath,
|
|
63364
|
-
inferSchema: () => inferSchema,
|
|
63365
|
-
getRawWorkspaceDependencies: () => getRawWorkspaceDependencies,
|
|
63366
|
-
generateScriptMetadataInternal: () => generateScriptMetadataInternal,
|
|
63367
|
-
generateScriptHash: () => generateScriptHash,
|
|
63368
|
-
filterWorkspaceDependenciesForScripts: () => filterWorkspaceDependenciesForScripts,
|
|
63369
|
-
filterWorkspaceDependencies: () => filterWorkspaceDependencies,
|
|
63370
|
-
extractWorkspaceDepsAnnotation: () => extractWorkspaceDepsAnnotation,
|
|
63371
|
-
computeLockCacheKey: () => computeLockCacheKey,
|
|
63372
|
-
clearLockCache: () => clearLockCache,
|
|
63373
|
-
clearGlobalLock: () => clearGlobalLock,
|
|
63374
|
-
checkifMetadataUptodate: () => checkifMetadataUptodate,
|
|
63375
|
-
blueColor: () => blueColor,
|
|
63376
|
-
LockfileGenerationError: () => LockfileGenerationError
|
|
63377
|
-
});
|
|
63378
63510
|
import { sep as SEP9 } from "node:path";
|
|
63379
63511
|
import { readFile as readFile9, writeFile as writeFile7, stat as stat7, rm as rm2, readdir as readdir5 } from "node:fs/promises";
|
|
63380
63512
|
import { readFileSync as readFileSync3, existsSync as existsSync4, readdirSync, statSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
@@ -63393,7 +63525,7 @@ function loadParser(pkgName) {
|
|
|
63393
63525
|
}
|
|
63394
63526
|
return p;
|
|
63395
63527
|
}
|
|
63396
|
-
async function getRawWorkspaceDependencies() {
|
|
63528
|
+
async function getRawWorkspaceDependencies(legacyBehaviour) {
|
|
63397
63529
|
const rawWorkspaceDeps = {};
|
|
63398
63530
|
try {
|
|
63399
63531
|
const entries = await readdir5("dependencies", { withFileTypes: true });
|
|
@@ -63404,9 +63536,13 @@ async function getRawWorkspaceDependencies() {
|
|
|
63404
63536
|
const content = await readFile9(filePath, "utf-8");
|
|
63405
63537
|
for (const lang of workspaceDependenciesLanguages) {
|
|
63406
63538
|
if (entry.name.endsWith(lang.filename)) {
|
|
63407
|
-
|
|
63408
|
-
|
|
63409
|
-
|
|
63539
|
+
if (legacyBehaviour) {
|
|
63540
|
+
const contentHash = await generateHash(content + filePath);
|
|
63541
|
+
const isUpToDate = await checkifMetadataUptodate(filePath, contentHash, undefined);
|
|
63542
|
+
if (!isUpToDate) {
|
|
63543
|
+
rawWorkspaceDeps[filePath] = content;
|
|
63544
|
+
}
|
|
63545
|
+
} else {
|
|
63410
63546
|
rawWorkspaceDeps[filePath] = content;
|
|
63411
63547
|
}
|
|
63412
63548
|
break;
|
|
@@ -63463,7 +63599,7 @@ async function blueColor() {
|
|
|
63463
63599
|
const isWin2 = await getIsWin();
|
|
63464
63600
|
return isWin2 ? colors.black : colors.blue;
|
|
63465
63601
|
}
|
|
63466
|
-
async function generateScriptMetadataInternal(scriptPath, workspace, opts, dryRun, noStaleMessage, rawWorkspaceDependencies, codebases, justUpdateMetadataLock) {
|
|
63602
|
+
async function generateScriptMetadataInternal(scriptPath, workspace, opts, dryRun, noStaleMessage, rawWorkspaceDependencies, codebases, justUpdateMetadataLock, legacyBehaviour, tree) {
|
|
63467
63603
|
const isFolderLayout = isModuleEntryPoint(scriptPath);
|
|
63468
63604
|
const remotePath = isFolderLayout ? getScriptBasePathFromModulePath(scriptPath).replaceAll(SEP9, "/") : scriptPath.substring(0, scriptPath.indexOf(".")).replaceAll(SEP9, "/");
|
|
63469
63605
|
const language = inferContentTypeFromFilePath(scriptPath, opts.defaultTs);
|
|
@@ -63473,10 +63609,11 @@ async function generateScriptMetadataInternal(scriptPath, workspace, opts, dryRu
|
|
|
63473
63609
|
const filteredRawWorkspaceDependencies = filterWorkspaceDependencies(rawWorkspaceDependencies, scriptContent, language);
|
|
63474
63610
|
const moduleFolderPath = isFolderLayout ? path9.dirname(scriptPath) : scriptPath.substring(0, scriptPath.indexOf(".")) + getModuleFolderSuffix();
|
|
63475
63611
|
const hasModules = existsSync4(moduleFolderPath) && statSync(moduleFolderPath).isDirectory();
|
|
63476
|
-
|
|
63612
|
+
const depsForHash = !legacyBehaviour && tree ? {} : filteredRawWorkspaceDependencies;
|
|
63613
|
+
let hash2 = await generateScriptHash(depsForHash, scriptContent, metadataContent);
|
|
63477
63614
|
let moduleHashes = {};
|
|
63478
63615
|
if (hasModules) {
|
|
63479
|
-
moduleHashes = await computeModuleHashes(moduleFolderPath, opts.defaultTs, rawWorkspaceDependencies, isFolderLayout);
|
|
63616
|
+
moduleHashes = await computeModuleHashes(moduleFolderPath, opts.defaultTs, !legacyBehaviour && tree ? {} : rawWorkspaceDependencies, isFolderLayout);
|
|
63480
63617
|
}
|
|
63481
63618
|
const hasModuleHashes = Object.keys(moduleHashes).length > 0;
|
|
63482
63619
|
let checkHash = hash2;
|
|
@@ -63487,25 +63624,34 @@ async function generateScriptMetadataInternal(scriptPath, workspace, opts, dryRu
|
|
|
63487
63624
|
checkSubpath = SCRIPT_TOP_HASH;
|
|
63488
63625
|
}
|
|
63489
63626
|
const conf = await readLockfile();
|
|
63490
|
-
|
|
63491
|
-
|
|
63492
|
-
|
|
63627
|
+
const isDirectlyStale = !await checkifMetadataUptodate(remotePath, checkHash, conf, checkSubpath);
|
|
63628
|
+
if (!legacyBehaviour && tree) {
|
|
63629
|
+
if (dryRun) {
|
|
63630
|
+
const imports = await extractRelativeImports(scriptContent, remotePath, language);
|
|
63631
|
+
await tree.addNode(remotePath, scriptContent, language, metadataContent, imports, "script", remotePath, scriptPath, isDirectlyStale);
|
|
63632
|
+
return;
|
|
63493
63633
|
}
|
|
63494
|
-
|
|
63495
|
-
|
|
63496
|
-
|
|
63497
|
-
|
|
63498
|
-
const changed = [];
|
|
63499
|
-
for (const [modulePath, moduleHash] of Object.entries(moduleHashes)) {
|
|
63500
|
-
if (!await checkifMetadataUptodate(remotePath, moduleHash, conf, modulePath)) {
|
|
63501
|
-
changed.push(modulePath);
|
|
63502
|
-
}
|
|
63634
|
+
} else {
|
|
63635
|
+
if (await checkifMetadataUptodate(remotePath, checkHash, conf, checkSubpath)) {
|
|
63636
|
+
if (!noStaleMessage) {
|
|
63637
|
+
info(colors.green(`Script ${remotePath} metadata is up-to-date, skipping`));
|
|
63503
63638
|
}
|
|
63504
|
-
|
|
63505
|
-
|
|
63639
|
+
return;
|
|
63640
|
+
} else if (dryRun) {
|
|
63641
|
+
let detail = `${remotePath} (${language})`;
|
|
63642
|
+
if (hasModuleHashes) {
|
|
63643
|
+
const changed = [];
|
|
63644
|
+
for (const [modulePath, moduleHash] of Object.entries(moduleHashes)) {
|
|
63645
|
+
if (!await checkifMetadataUptodate(remotePath, moduleHash, conf, modulePath)) {
|
|
63646
|
+
changed.push(modulePath);
|
|
63647
|
+
}
|
|
63648
|
+
}
|
|
63649
|
+
if (changed.length > 0) {
|
|
63650
|
+
detail += ` [changed modules: ${changed.join(", ")}]`;
|
|
63651
|
+
}
|
|
63506
63652
|
}
|
|
63653
|
+
return detail;
|
|
63507
63654
|
}
|
|
63508
|
-
return detail;
|
|
63509
63655
|
}
|
|
63510
63656
|
if (!justUpdateMetadataLock && !noStaleMessage) {
|
|
63511
63657
|
info(colors.gray(`Generating metadata for ${scriptPath}`));
|
|
@@ -63517,8 +63663,9 @@ async function generateScriptMetadataInternal(scriptPath, workspace, opts, dryRu
|
|
|
63517
63663
|
if (!opts.schemaOnly && !justUpdateMetadataLock) {
|
|
63518
63664
|
const hasCodebase = findCodebase(scriptPath, codebases) != null;
|
|
63519
63665
|
if (!hasCodebase) {
|
|
63666
|
+
const tempScriptRefs = tree?.getTempScriptRefs(remotePath);
|
|
63520
63667
|
const lockPathOverride = isFolderLayout ? path9.dirname(scriptPath) + "/script.lock" : undefined;
|
|
63521
|
-
await updateScriptLock(workspace, scriptContent, language, remotePath, metadataParsedContent, filteredRawWorkspaceDependencies, lockPathOverride);
|
|
63668
|
+
await updateScriptLock(workspace, scriptContent, language, remotePath, metadataParsedContent, filteredRawWorkspaceDependencies, tempScriptRefs, lockPathOverride);
|
|
63522
63669
|
} else {
|
|
63523
63670
|
metadataParsedContent.lock = "";
|
|
63524
63671
|
}
|
|
@@ -63564,7 +63711,7 @@ async function generateScriptMetadataInternal(scriptPath, workspace, opts, dryRu
|
|
|
63564
63711
|
}
|
|
63565
63712
|
}
|
|
63566
63713
|
const metadataContentUsedForHash = newMetadataContent;
|
|
63567
|
-
hash2 = await generateScriptHash(
|
|
63714
|
+
hash2 = await generateScriptHash(depsForHash, scriptContent, metadataContentUsedForHash);
|
|
63568
63715
|
if (hasModuleHashes) {
|
|
63569
63716
|
const sortedEntries = Object.entries(moduleHashes).sort(([a], [b]) => a.localeCompare(b));
|
|
63570
63717
|
const metaHash = await generateHash(hash2 + JSON.stringify(sortedEntries));
|
|
@@ -63650,21 +63797,20 @@ function extractWorkspaceDepsAnnotation(scriptContent, language) {
|
|
|
63650
63797
|
const inline = inlineStr.trim().length > 0 ? inlineStr : null;
|
|
63651
63798
|
return { mode, external, inline };
|
|
63652
63799
|
}
|
|
63653
|
-
async function computeLockCacheKey(scriptContent, language, rawWorkspaceDependencies) {
|
|
63800
|
+
async function computeLockCacheKey(scriptContent, language, rawWorkspaceDependencies, tempScriptRefs) {
|
|
63654
63801
|
const annotation = extractWorkspaceDepsAnnotation(scriptContent, language);
|
|
63655
63802
|
const annotationStr = annotation ? `${annotation.mode}|${annotation.external.join(",")}|${annotation.inline ?? ""}` : "none";
|
|
63656
63803
|
const sortedDepsKeys = Object.keys(rawWorkspaceDependencies).sort();
|
|
63657
63804
|
const depsStr = sortedDepsKeys.map((k) => `${k}=${rawWorkspaceDependencies[k]}`).join(";");
|
|
63658
|
-
|
|
63805
|
+
const tempRefsStr = tempScriptRefs ? Object.keys(tempScriptRefs).sort().map((k) => `${k}=${tempScriptRefs[k]}`).join(";") : "";
|
|
63806
|
+
return await generateHash(`${language}|${annotationStr}|${depsStr}|${tempRefsStr}`);
|
|
63659
63807
|
}
|
|
63660
|
-
function
|
|
63661
|
-
lockCache.clear();
|
|
63662
|
-
}
|
|
63663
|
-
async function fetchScriptLock(workspace, scriptContent, language, remotePath, rawWorkspaceDependencies) {
|
|
63808
|
+
async function fetchScriptLock(workspace, scriptContent, language, remotePath, rawWorkspaceDependencies, tempScriptRefs) {
|
|
63664
63809
|
const hasRawDeps = Object.keys(rawWorkspaceDependencies).length > 0;
|
|
63665
|
-
const
|
|
63810
|
+
const hasTempRefs = tempScriptRefs && Object.keys(tempScriptRefs).length > 0;
|
|
63811
|
+
const cacheKey = hasRawDeps || hasTempRefs ? await computeLockCacheKey(scriptContent, language, rawWorkspaceDependencies, tempScriptRefs) : undefined;
|
|
63666
63812
|
if (cacheKey && lockCache.has(cacheKey)) {
|
|
63667
|
-
|
|
63813
|
+
debug(`Using cached lockfile for ${remotePath}`);
|
|
63668
63814
|
return lockCache.get(cacheKey);
|
|
63669
63815
|
}
|
|
63670
63816
|
const extraHeaders = getHeaders2();
|
|
@@ -63684,7 +63830,8 @@ async function fetchScriptLock(workspace, scriptContent, language, remotePath, r
|
|
|
63684
63830
|
}
|
|
63685
63831
|
],
|
|
63686
63832
|
raw_workspace_dependencies: Object.keys(rawWorkspaceDependencies).length > 0 ? rawWorkspaceDependencies : null,
|
|
63687
|
-
entrypoint: remotePath
|
|
63833
|
+
entrypoint: remotePath,
|
|
63834
|
+
temp_script_refs: tempScriptRefs && Object.keys(tempScriptRefs).length > 0 ? tempScriptRefs : null
|
|
63688
63835
|
})
|
|
63689
63836
|
});
|
|
63690
63837
|
let responseText = "reading response failed";
|
|
@@ -63709,15 +63856,15 @@ async function fetchScriptLock(workspace, scriptContent, language, remotePath, r
|
|
|
63709
63856
|
throw new LockfileGenerationError(`Failed to generate lockfile:${rawResponse.statusText}, ${responseText}, ${e}`);
|
|
63710
63857
|
}
|
|
63711
63858
|
}
|
|
63712
|
-
async function updateScriptLock(workspace, scriptContent, language, remotePath, metadataContent, rawWorkspaceDependencies, lockPathOverride) {
|
|
63859
|
+
async function updateScriptLock(workspace, scriptContent, language, remotePath, metadataContent, rawWorkspaceDependencies, tempScriptRefs, lockPathOverride) {
|
|
63713
63860
|
if (!(workspaceDependenciesLanguages.some((l) => l.language == language) && language !== "powershell" || language == "deno" || language == "rust" || language == "ansible")) {
|
|
63714
63861
|
return;
|
|
63715
63862
|
}
|
|
63716
63863
|
if (Object.keys(rawWorkspaceDependencies).length > 0) {
|
|
63717
63864
|
const dependencyPaths = Object.keys(rawWorkspaceDependencies).join(", ");
|
|
63718
|
-
|
|
63865
|
+
debug(`Generating script lock for ${remotePath} with raw workspace dependencies: ${dependencyPaths}`);
|
|
63719
63866
|
}
|
|
63720
|
-
const lock = await fetchScriptLock(workspace, scriptContent, language, remotePath, rawWorkspaceDependencies);
|
|
63867
|
+
const lock = await fetchScriptLock(workspace, scriptContent, language, remotePath, rawWorkspaceDependencies, tempScriptRefs);
|
|
63721
63868
|
const lockPath = lockPathOverride ?? remotePath + ".script.lock";
|
|
63722
63869
|
if (lock != "") {
|
|
63723
63870
|
await writeFile7(lockPath, lock, "utf-8");
|
|
@@ -63756,7 +63903,7 @@ async function updateModuleLocks(workspace, dirPath, relPrefix, scriptRemotePath
|
|
|
63756
63903
|
}
|
|
63757
63904
|
const moduleContent = readFileSync3(fullPath, "utf-8");
|
|
63758
63905
|
const moduleRemotePath = scriptRemotePath + "/" + relPath;
|
|
63759
|
-
|
|
63906
|
+
debug(`Generating lock for module ${relPath}`);
|
|
63760
63907
|
try {
|
|
63761
63908
|
const lock = await fetchScriptLock(workspace, moduleContent, modLanguage, moduleRemotePath, rawWorkspaceDependencies);
|
|
63762
63909
|
const baseName = entry.name.replace(/\.[^.]+$/, "");
|
|
@@ -64157,7 +64304,8 @@ var init_metadata = __esm(async () => {
|
|
|
64157
64304
|
await __promiseAll([
|
|
64158
64305
|
init_sync(),
|
|
64159
64306
|
init_utils(),
|
|
64160
|
-
init_utils()
|
|
64307
|
+
init_utils(),
|
|
64308
|
+
init_relative_imports()
|
|
64161
64309
|
]);
|
|
64162
64310
|
import_yaml12 = __toESM(require_dist(), 1);
|
|
64163
64311
|
_require = createRequire2(import.meta.url);
|
|
@@ -64469,7 +64617,7 @@ __export(exports_app_metadata, {
|
|
|
64469
64617
|
APP_BACKEND_FOLDER: () => APP_BACKEND_FOLDER
|
|
64470
64618
|
});
|
|
64471
64619
|
import path11 from "node:path";
|
|
64472
|
-
import { readFile as readFile11, mkdir as
|
|
64620
|
+
import { readFile as readFile11, mkdir as mkdir5 } from "node:fs/promises";
|
|
64473
64621
|
import { sep as SEP11 } from "node:path";
|
|
64474
64622
|
async function generateAppHash(rawReqs, folder, rawApp, defaultTs) {
|
|
64475
64623
|
const runnablesFolder = rawApp ? path11.join(folder, APP_BACKEND_FOLDER) : folder;
|
|
@@ -64495,7 +64643,7 @@ async function generateAppHash(rawReqs, folder, rawApp, defaultTs) {
|
|
|
64495
64643
|
}
|
|
64496
64644
|
return { ...hashes, [TOP_HASH2]: await generateHash(JSON.stringify(hashes)) };
|
|
64497
64645
|
}
|
|
64498
|
-
async function generateAppLocksInternal(appFolder, rawApp, dryRun, workspace, opts, justUpdateMetadataLock, noStaleMessage) {
|
|
64646
|
+
async function generateAppLocksInternal(appFolder, rawApp, dryRun, workspace, opts, justUpdateMetadataLock, noStaleMessage, legacyBehaviour, tree) {
|
|
64499
64647
|
if (appFolder.endsWith(SEP11)) {
|
|
64500
64648
|
appFolder = appFolder.substring(0, appFolder.length - 1);
|
|
64501
64649
|
}
|
|
@@ -64503,26 +64651,69 @@ async function generateAppLocksInternal(appFolder, rawApp, dryRun, workspace, op
|
|
|
64503
64651
|
if (!justUpdateMetadataLock && !noStaleMessage) {
|
|
64504
64652
|
info(`Generating locks for app ${appFolder} at ${remote_path}`);
|
|
64505
64653
|
}
|
|
64506
|
-
const rawWorkspaceDependencies = await getRawWorkspaceDependencies();
|
|
64507
64654
|
const appFilePath = path11.join(appFolder, rawApp ? "raw_app.yaml" : "app.yaml");
|
|
64508
64655
|
const appFile = await yamlParseFile(appFilePath);
|
|
64509
64656
|
const appValue = rawApp ? appFile.runnables : appFile.value;
|
|
64510
|
-
const
|
|
64511
|
-
let
|
|
64512
|
-
const conf = await
|
|
64513
|
-
if (
|
|
64514
|
-
if (
|
|
64515
|
-
|
|
64657
|
+
const folderNormalized = appFolder.replaceAll(SEP11, "/");
|
|
64658
|
+
let filteredDeps = {};
|
|
64659
|
+
const conf = await readLockfile();
|
|
64660
|
+
if (!legacyBehaviour && tree) {
|
|
64661
|
+
if (dryRun) {
|
|
64662
|
+
const hashes = await generateAppHash({}, appFolder, rawApp, opts.defaultTs);
|
|
64663
|
+
const isDirectlyStale = !await checkifMetadataUptodate(appFolder, hashes[TOP_HASH2], conf, TOP_HASH2);
|
|
64664
|
+
let treeAppValue = structuredClone(appValue);
|
|
64665
|
+
if (rawApp) {
|
|
64666
|
+
const runnablesPath = path11.join(appFolder, APP_BACKEND_FOLDER);
|
|
64667
|
+
const runnablesFromFiles = await loadRunnablesFromBackend(runnablesPath);
|
|
64668
|
+
if (Object.keys(runnablesFromFiles).length > 0) {
|
|
64669
|
+
treeAppValue = runnablesFromFiles;
|
|
64670
|
+
}
|
|
64671
|
+
}
|
|
64672
|
+
const inlineScriptPaths = [];
|
|
64673
|
+
await traverseAndProcessInlineScripts(treeAppValue, async (inlineScript, context) => {
|
|
64674
|
+
if (!inlineScript.content || !inlineScript.language) {
|
|
64675
|
+
return inlineScript;
|
|
64676
|
+
}
|
|
64677
|
+
let content = inlineScript.content;
|
|
64678
|
+
if (typeof content === "string" && content.startsWith("!inline ")) {
|
|
64679
|
+
const filePath = appFolder + SEP11 + content.replace("!inline ", "");
|
|
64680
|
+
try {
|
|
64681
|
+
content = await readFile11(filePath, "utf-8");
|
|
64682
|
+
} catch {
|
|
64683
|
+
return inlineScript;
|
|
64684
|
+
}
|
|
64685
|
+
}
|
|
64686
|
+
const treePath = folderNormalized + "/" + context.path.join("/");
|
|
64687
|
+
const language = inlineScript.language;
|
|
64688
|
+
const imports = await extractRelativeImports(content, treePath, language);
|
|
64689
|
+
await tree.addNode(treePath, content, language, "", imports, "inline_script", folderNormalized, appFolder, false);
|
|
64690
|
+
inlineScriptPaths.push(treePath);
|
|
64691
|
+
return inlineScript;
|
|
64692
|
+
});
|
|
64693
|
+
await tree.addNode(folderNormalized, "", "bun", "", inlineScriptPaths, "app", folderNormalized, appFolder, isDirectlyStale, rawApp);
|
|
64694
|
+
return;
|
|
64695
|
+
}
|
|
64696
|
+
filteredDeps = await filterWorkspaceDependenciesForApp(appValue, tree.getMismatchedWorkspaceDeps(), appFolder);
|
|
64697
|
+
} else {
|
|
64698
|
+
const rawWorkspaceDependencies = await getRawWorkspaceDependencies(true);
|
|
64699
|
+
filteredDeps = await filterWorkspaceDependenciesForApp(appValue, rawWorkspaceDependencies, appFolder);
|
|
64700
|
+
const hashes = await generateAppHash(filteredDeps, appFolder, rawApp, opts.defaultTs);
|
|
64701
|
+
const isDirectlyStale = !await checkifMetadataUptodate(appFolder, hashes[TOP_HASH2], conf, TOP_HASH2);
|
|
64702
|
+
if (!isDirectlyStale) {
|
|
64703
|
+
if (!noStaleMessage) {
|
|
64704
|
+
info(colors.green(`App ${remote_path} metadata is up-to-date, skipping`));
|
|
64705
|
+
}
|
|
64706
|
+
return;
|
|
64707
|
+
} else if (dryRun) {
|
|
64708
|
+
return remote_path;
|
|
64516
64709
|
}
|
|
64517
|
-
return;
|
|
64518
|
-
} else if (dryRun) {
|
|
64519
|
-
return remote_path;
|
|
64520
64710
|
}
|
|
64521
64711
|
if (Object.keys(filteredDeps).length > 0 && !noStaleMessage) {
|
|
64522
64712
|
info((await blueColor())(`Found workspace dependencies (${workspaceDependenciesLanguages.map((l) => l.filename).join("/")}) for ${appFolder}, using them`));
|
|
64523
64713
|
}
|
|
64524
64714
|
let updatedScripts = [];
|
|
64525
64715
|
if (!justUpdateMetadataLock) {
|
|
64716
|
+
const hashes = await generateAppHash(filteredDeps, appFolder, rawApp, opts.defaultTs);
|
|
64526
64717
|
const changedScripts = [];
|
|
64527
64718
|
for (const [scriptPath, hash2] of Object.entries(hashes)) {
|
|
64528
64719
|
if (scriptPath == TOP_HASH2) {
|
|
@@ -64532,7 +64723,8 @@ async function generateAppLocksInternal(appFolder, rawApp, dryRun, workspace, op
|
|
|
64532
64723
|
changedScripts.push(scriptPath);
|
|
64533
64724
|
}
|
|
64534
64725
|
}
|
|
64535
|
-
|
|
64726
|
+
const tempScriptRefs = tree?.getTempScriptRefs(folderNormalized);
|
|
64727
|
+
if (changedScripts.length > 0 || tree && !legacyBehaviour) {
|
|
64536
64728
|
if (!noStaleMessage) {
|
|
64537
64729
|
info(`Recomputing locks of ${changedScripts.join(", ")} in ${appFolder}`);
|
|
64538
64730
|
}
|
|
@@ -64544,11 +64736,11 @@ async function generateAppLocksInternal(appFolder, rawApp, dryRun, workspace, op
|
|
|
64544
64736
|
runnables = rawAppFile.runnables;
|
|
64545
64737
|
}
|
|
64546
64738
|
replaceInlineScripts2(runnables, runnablesPath + SEP11, false);
|
|
64547
|
-
updatedScripts = await updateRawAppRunnables(workspace, runnables, remote_path, appFolder, filteredDeps, opts.defaultTs, noStaleMessage);
|
|
64739
|
+
updatedScripts = await updateRawAppRunnables(workspace, runnables, remote_path, appFolder, filteredDeps, opts.defaultTs, noStaleMessage, tempScriptRefs);
|
|
64548
64740
|
} else {
|
|
64549
64741
|
const normalAppFile = appFile;
|
|
64550
64742
|
replaceInlineScripts2(normalAppFile.value, appFolder + SEP11, false);
|
|
64551
|
-
const result = await updateAppInlineScripts(workspace, normalAppFile.value, remote_path, appFolder, filteredDeps, opts.defaultTs, noStaleMessage);
|
|
64743
|
+
const result = await updateAppInlineScripts(workspace, normalAppFile.value, remote_path, appFolder, filteredDeps, opts.defaultTs, noStaleMessage, tempScriptRefs);
|
|
64552
64744
|
normalAppFile.value = result.value;
|
|
64553
64745
|
updatedScripts = result.updatedScripts;
|
|
64554
64746
|
writeIfChanged(appFilePath, import_yaml17.stringify(appFile, yamlOptions));
|
|
@@ -64557,9 +64749,10 @@ async function generateAppLocksInternal(appFolder, rawApp, dryRun, workspace, op
|
|
|
64557
64749
|
info(colors.gray(`No scripts changed in ${appFolder}`));
|
|
64558
64750
|
}
|
|
64559
64751
|
}
|
|
64560
|
-
|
|
64752
|
+
const depsForHash = tree && !legacyBehaviour ? {} : filteredDeps;
|
|
64753
|
+
const finalHashes = await generateAppHash(depsForHash, appFolder, rawApp, opts.defaultTs);
|
|
64561
64754
|
await clearGlobalLock(appFolder);
|
|
64562
|
-
for (const [scriptPath, hash2] of Object.entries(
|
|
64755
|
+
for (const [scriptPath, hash2] of Object.entries(finalHashes)) {
|
|
64563
64756
|
await updateMetadataGlobalLock(appFolder, hash2, scriptPath);
|
|
64564
64757
|
}
|
|
64565
64758
|
if (!noStaleMessage) {
|
|
@@ -64607,11 +64800,11 @@ async function traverseAndProcessInlineScripts(obj, processor, currentPath = [])
|
|
|
64607
64800
|
}
|
|
64608
64801
|
return result;
|
|
64609
64802
|
}
|
|
64610
|
-
async function updateRawAppRunnables(workspace, runnables, remotePath, appFolder, rawDeps, defaultTs = "bun", noStaleMessage) {
|
|
64803
|
+
async function updateRawAppRunnables(workspace, runnables, remotePath, appFolder, rawDeps, defaultTs = "bun", noStaleMessage, tempScriptRefs) {
|
|
64611
64804
|
const updatedRunnables = [];
|
|
64612
64805
|
const runnablesFolder = path11.join(appFolder, APP_BACKEND_FOLDER);
|
|
64613
64806
|
try {
|
|
64614
|
-
await
|
|
64807
|
+
await mkdir5(runnablesFolder, { recursive: true });
|
|
64615
64808
|
} catch {}
|
|
64616
64809
|
const pathAssigner = newRawAppPathAssigner(defaultTs);
|
|
64617
64810
|
for (const [runnableId, runnable] of Object.entries(runnables)) {
|
|
@@ -64649,7 +64842,7 @@ async function updateRawAppRunnables(workspace, runnables, remotePath, appFolder
|
|
|
64649
64842
|
info(colors.gray(`Generating lock for runnable ${runnableId} (${language})`));
|
|
64650
64843
|
}
|
|
64651
64844
|
try {
|
|
64652
|
-
const lock = await generateInlineScriptLock(workspace, content, language, `${remotePath}/${runnableId}`, rawDeps);
|
|
64845
|
+
const lock = await generateInlineScriptLock(workspace, content, language, `${remotePath}/${runnableId}`, rawDeps, tempScriptRefs);
|
|
64653
64846
|
const [basePathO, ext2] = pathAssigner.assignPath(runnable.name ?? runnableId, language);
|
|
64654
64847
|
const basePath = basePathO.replaceAll(SEP11, "/");
|
|
64655
64848
|
const contentPath = path11.join(runnablesFolder, `${basePath}${ext2}`);
|
|
@@ -64676,7 +64869,7 @@ async function updateRawAppRunnables(workspace, runnables, remotePath, appFolder
|
|
|
64676
64869
|
}
|
|
64677
64870
|
return updatedRunnables;
|
|
64678
64871
|
}
|
|
64679
|
-
async function updateAppInlineScripts(workspace, appValue, remotePath, appFolder, rawDeps, defaultTs = "bun", noStaleMessage) {
|
|
64872
|
+
async function updateAppInlineScripts(workspace, appValue, remotePath, appFolder, rawDeps, defaultTs = "bun", noStaleMessage, tempScriptRefs) {
|
|
64680
64873
|
const pathAssigner = newPathAssigner(defaultTs, { skipInlineScriptSuffix: getNonDottedPaths() });
|
|
64681
64874
|
const updatedScripts = [];
|
|
64682
64875
|
const processor = async (inlineScript, context) => {
|
|
@@ -64697,7 +64890,7 @@ async function updateAppInlineScripts(workspace, appValue, remotePath, appFolder
|
|
|
64697
64890
|
if (!noStaleMessage) {
|
|
64698
64891
|
info(colors.gray(`Generating lock for inline script "${scriptName}" at ${context.path.join(".")} (${language})`));
|
|
64699
64892
|
}
|
|
64700
|
-
lock = await generateInlineScriptLock(workspace, content, language, scriptPath, rawDeps);
|
|
64893
|
+
lock = await generateInlineScriptLock(workspace, content, language, scriptPath, rawDeps, tempScriptRefs);
|
|
64701
64894
|
}
|
|
64702
64895
|
const [basePathO, ext2] = pathAssigner.assignPath(scriptName, language);
|
|
64703
64896
|
const basePath = basePathO.replaceAll(SEP11, "/");
|
|
@@ -64728,7 +64921,7 @@ async function updateAppInlineScripts(workspace, appValue, remotePath, appFolder
|
|
|
64728
64921
|
const updatedValue = await traverseAndProcessInlineScripts(appValue, processor);
|
|
64729
64922
|
return { value: updatedValue, updatedScripts };
|
|
64730
64923
|
}
|
|
64731
|
-
async function generateInlineScriptLock(workspace, content, language, scriptPath, rawWorkspaceDependencies) {
|
|
64924
|
+
async function generateInlineScriptLock(workspace, content, language, scriptPath, rawWorkspaceDependencies, tempScriptRefs) {
|
|
64732
64925
|
const filteredDeps = rawWorkspaceDependencies ? filterWorkspaceDependencies(rawWorkspaceDependencies, content, language) : undefined;
|
|
64733
64926
|
const extraHeaders = getHeaders2();
|
|
64734
64927
|
const rawResponse = await fetch(`${workspace.remote}api/w/${workspace.workspaceId}/jobs/run/dependencies`, {
|
|
@@ -64747,7 +64940,8 @@ async function generateInlineScriptLock(workspace, content, language, scriptPath
|
|
|
64747
64940
|
}
|
|
64748
64941
|
],
|
|
64749
64942
|
raw_workspace_dependencies: filteredDeps && Object.keys(filteredDeps).length > 0 ? filteredDeps : null,
|
|
64750
|
-
entrypoint: scriptPath
|
|
64943
|
+
entrypoint: scriptPath,
|
|
64944
|
+
...tempScriptRefs && Object.keys(tempScriptRefs).length > 0 ? { temp_script_refs: tempScriptRefs } : {}
|
|
64751
64945
|
})
|
|
64752
64946
|
});
|
|
64753
64947
|
if (!rawResponse.ok) {
|
|
@@ -64905,7 +65099,8 @@ var init_app_metadata = __esm(async () => {
|
|
|
64905
65099
|
init_app(),
|
|
64906
65100
|
init_conf(),
|
|
64907
65101
|
init_context(),
|
|
64908
|
-
init_auth()
|
|
65102
|
+
init_auth(),
|
|
65103
|
+
init_relative_imports()
|
|
64909
65104
|
]);
|
|
64910
65105
|
import_yaml17 = __toESM(require_dist(), 1);
|
|
64911
65106
|
});
|
|
@@ -66349,7 +66544,7 @@ var init_lint2 = __esm(async () => {
|
|
|
66349
66544
|
});
|
|
66350
66545
|
|
|
66351
66546
|
// src/commands/app/new.ts
|
|
66352
|
-
import { stat as stat8, writeFile as writeFile9, mkdir as
|
|
66547
|
+
import { stat as stat8, writeFile as writeFile9, mkdir as mkdir6 } from "node:fs/promises";
|
|
66353
66548
|
import path15 from "node:path";
|
|
66354
66549
|
function validateAppPath(appPath) {
|
|
66355
66550
|
if (!appPath.startsWith("u/") && !appPath.startsWith("f/")) {
|
|
@@ -66567,9 +66762,9 @@ CREATE SCHEMA IF NOT EXISTS ${schemaName};
|
|
|
66567
66762
|
return;
|
|
66568
66763
|
}
|
|
66569
66764
|
} catch {}
|
|
66570
|
-
await
|
|
66571
|
-
await
|
|
66572
|
-
await
|
|
66765
|
+
await mkdir6(appDir, { recursive: true });
|
|
66766
|
+
await mkdir6(path15.join(appDir, "backend"), { recursive: true });
|
|
66767
|
+
await mkdir6(path15.join(appDir, "sql_to_apply"), { recursive: true });
|
|
66573
66768
|
const rawAppConfig = {
|
|
66574
66769
|
summary
|
|
66575
66770
|
};
|
|
@@ -67043,7 +67238,7 @@ var init_app = __esm(async () => {
|
|
|
67043
67238
|
});
|
|
67044
67239
|
|
|
67045
67240
|
// src/commands/folder/folder.ts
|
|
67046
|
-
import { stat as stat9, readdir as readdir7, writeFile as writeFile10, mkdir as
|
|
67241
|
+
import { stat as stat9, readdir as readdir7, writeFile as writeFile10, mkdir as mkdir7 } from "node:fs/promises";
|
|
67047
67242
|
import { sep as SEP14 } from "node:path";
|
|
67048
67243
|
async function list5(opts) {
|
|
67049
67244
|
const workspace = await resolveWorkspace(opts);
|
|
@@ -67077,7 +67272,7 @@ async function newFolder(opts, name) {
|
|
|
67077
67272
|
owners: [],
|
|
67078
67273
|
extra_perms: {}
|
|
67079
67274
|
};
|
|
67080
|
-
await
|
|
67275
|
+
await mkdir7(dirPath, { recursive: true });
|
|
67081
67276
|
await writeFile10(filePath, import_yaml23.stringify(template), {
|
|
67082
67277
|
flag: "wx",
|
|
67083
67278
|
encoding: "utf-8"
|
|
@@ -68322,7 +68517,7 @@ var init_settings = __esm(async () => {
|
|
|
68322
68517
|
});
|
|
68323
68518
|
|
|
68324
68519
|
// src/commands/instance/instance.ts
|
|
68325
|
-
import { readFile as readFile13, writeFile as writeFile15, readdir as readdir8, mkdir as
|
|
68520
|
+
import { readFile as readFile13, writeFile as writeFile15, readdir as readdir8, mkdir as mkdir8, rm as rm3, stat as stat13 } from "node:fs/promises";
|
|
68326
68521
|
import { appendFile } from "node:fs/promises";
|
|
68327
68522
|
import * as path17 from "node:path";
|
|
68328
68523
|
async function allInstances() {
|
|
@@ -68501,7 +68696,7 @@ async function instancePull(opts) {
|
|
|
68501
68696
|
if (confirm) {
|
|
68502
68697
|
if (uChanges > 0) {
|
|
68503
68698
|
if (opts.folderPerInstance && opts.prefixSettings) {
|
|
68504
|
-
await
|
|
68699
|
+
await mkdir8(path17.join(rootDir, opts.prefix), {
|
|
68505
68700
|
recursive: true
|
|
68506
68701
|
});
|
|
68507
68702
|
}
|
|
@@ -68535,7 +68730,7 @@ Pulling all workspaces`);
|
|
|
68535
68730
|
info(`
|
|
68536
68731
|
Pulling workspace ` + remoteWorkspace.id);
|
|
68537
68732
|
const workspaceName = opts?.folderPerInstance ? instance.prefix + "/" + remoteWorkspace.id : instance.prefix + "_" + remoteWorkspace.id;
|
|
68538
|
-
await
|
|
68733
|
+
await mkdir8(path17.join(rootDir, workspaceName), {
|
|
68539
68734
|
recursive: true
|
|
68540
68735
|
});
|
|
68541
68736
|
process.chdir(path17.join(rootDir, workspaceName));
|
|
@@ -68719,7 +68914,7 @@ Pushing workspace ` + localWorkspace.id);
|
|
|
68719
68914
|
async function getLocalWorkspaces(rootDir, localPrefix, folderPerInstance) {
|
|
68720
68915
|
const localWorkspaces = [];
|
|
68721
68916
|
if (!await stat13(localPrefix).catch(() => null)) {
|
|
68722
|
-
await
|
|
68917
|
+
await mkdir8(localPrefix);
|
|
68723
68918
|
}
|
|
68724
68919
|
if (folderPerInstance) {
|
|
68725
68920
|
const prefixEntries = await readdir8(rootDir + "/" + localPrefix, { withFileTypes: true });
|
|
@@ -69393,7 +69588,8 @@ async function pushNativeTrigger(workspace, filePath, _remoteTrigger, localTrigg
|
|
|
69393
69588
|
script_path: result.script_path,
|
|
69394
69589
|
is_flow: result.is_flow,
|
|
69395
69590
|
service_config: result.service_config,
|
|
69396
|
-
error: result.error
|
|
69591
|
+
error: result.error,
|
|
69592
|
+
summary: result.summary
|
|
69397
69593
|
};
|
|
69398
69594
|
debug(`Native trigger ${serviceName}/${externalId} exists on remote`);
|
|
69399
69595
|
} catch {
|
|
@@ -69402,18 +69598,21 @@ async function pushNativeTrigger(workspace, filePath, _remoteTrigger, localTrigg
|
|
|
69402
69598
|
const triggerData = {
|
|
69403
69599
|
script_path: localTrigger.script_path,
|
|
69404
69600
|
is_flow: localTrigger.is_flow,
|
|
69405
|
-
service_config: localTrigger.service_config
|
|
69601
|
+
service_config: localTrigger.service_config,
|
|
69602
|
+
summary: localTrigger.summary
|
|
69406
69603
|
};
|
|
69407
69604
|
if (remoteTrigger) {
|
|
69408
69605
|
const localCompare = {
|
|
69409
69606
|
script_path: localTrigger.script_path,
|
|
69410
69607
|
is_flow: localTrigger.is_flow,
|
|
69411
|
-
service_config: localTrigger.service_config
|
|
69608
|
+
service_config: localTrigger.service_config,
|
|
69609
|
+
summary: localTrigger.summary
|
|
69412
69610
|
};
|
|
69413
69611
|
const remoteCompare = {
|
|
69414
69612
|
script_path: remoteTrigger.script_path,
|
|
69415
69613
|
is_flow: remoteTrigger.is_flow,
|
|
69416
|
-
service_config: remoteTrigger.service_config
|
|
69614
|
+
service_config: remoteTrigger.service_config,
|
|
69615
|
+
summary: remoteTrigger.summary
|
|
69417
69616
|
};
|
|
69418
69617
|
if (isSuperset(localCompare, remoteCompare)) {
|
|
69419
69618
|
debug(`Native trigger ${serviceName}/${externalId} is up to date`);
|
|
@@ -70353,6 +70552,10 @@ async function generateLocks(opts, folder) {
|
|
|
70353
70552
|
}
|
|
70354
70553
|
}
|
|
70355
70554
|
if (hasAny) {
|
|
70555
|
+
if (opts.dryRun) {
|
|
70556
|
+
info(colors.gray("Dry run complete."));
|
|
70557
|
+
return;
|
|
70558
|
+
}
|
|
70356
70559
|
if (!opts.yes && !await Confirm.prompt({
|
|
70357
70560
|
message: "Update the locks of the inline scripts of the above flows?",
|
|
70358
70561
|
default: true
|
|
@@ -70408,7 +70611,7 @@ var init_flow = __esm(async () => {
|
|
|
70408
70611
|
]);
|
|
70409
70612
|
import_yaml36 = __toESM(require_dist(), 1);
|
|
70410
70613
|
alreadySynced3 = [];
|
|
70411
|
-
command21 = new Command().description("flow related commands").option("--show-archived", "Enable archived flows in output").option("--json", "Output as JSON (for piping to jq)").action(list11).command("list", "list all flows").option("--show-archived", "Enable archived flows in output").option("--json", "Output as JSON (for piping to jq)").action(list11).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>").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", "re-generate the lock files of all inline scripts of all updated flows").arguments("[flow:file]").option("--yes", "Skip confirmation prompt").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);
|
|
70614
|
+
command21 = new Command().description("flow related commands").option("--show-archived", "Enable archived flows in output").option("--json", "Output as JSON (for piping to jq)").action(list11).command("list", "list all flows").option("--show-archived", "Enable archived flows in output").option("--json", "Output as JSON (for piping to jq)").action(list11).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>").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", "re-generate the lock files of all inline scripts of all updated flows").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);
|
|
70412
70615
|
flow_default = command21;
|
|
70413
70616
|
});
|
|
70414
70617
|
|
|
@@ -71359,6 +71562,277 @@ var init_gitsync_settings = __esm(async () => {
|
|
|
71359
71562
|
gitsync_settings_default = command23;
|
|
71360
71563
|
});
|
|
71361
71564
|
|
|
71565
|
+
// src/utils/dependency_tree.ts
|
|
71566
|
+
async function uploadScripts(tree, workspace) {
|
|
71567
|
+
const scriptHashes = {};
|
|
71568
|
+
const workspaceDeps = [];
|
|
71569
|
+
for (const path19 of tree.allPaths()) {
|
|
71570
|
+
const content = tree.getContent(path19);
|
|
71571
|
+
const itemType = tree.getItemType(path19);
|
|
71572
|
+
if (itemType === "dependencies") {
|
|
71573
|
+
if (content === undefined)
|
|
71574
|
+
continue;
|
|
71575
|
+
const info2 = workspaceDependenciesPathToLanguageAndFilename(path19);
|
|
71576
|
+
if (info2) {
|
|
71577
|
+
const hash2 = await generateHash(content);
|
|
71578
|
+
workspaceDeps.push({ path: path19, language: info2.language, name: info2.name, hash: hash2 });
|
|
71579
|
+
}
|
|
71580
|
+
} else if (itemType === "script") {
|
|
71581
|
+
if (!content)
|
|
71582
|
+
continue;
|
|
71583
|
+
const hash2 = await generateHash(content);
|
|
71584
|
+
scriptHashes[path19] = hash2;
|
|
71585
|
+
}
|
|
71586
|
+
}
|
|
71587
|
+
if (Object.keys(scriptHashes).length === 0 && workspaceDeps.length === 0)
|
|
71588
|
+
return;
|
|
71589
|
+
const mismatched = await diffRawScriptsWithDeployed({
|
|
71590
|
+
workspace: workspace.workspaceId,
|
|
71591
|
+
requestBody: {
|
|
71592
|
+
scripts: scriptHashes,
|
|
71593
|
+
workspace_deps: workspaceDeps
|
|
71594
|
+
}
|
|
71595
|
+
});
|
|
71596
|
+
for (const path19 of mismatched) {
|
|
71597
|
+
const content = tree.getContent(path19);
|
|
71598
|
+
const itemType = tree.getItemType(path19);
|
|
71599
|
+
if (itemType === "dependencies") {
|
|
71600
|
+
if (content !== undefined) {
|
|
71601
|
+
tree.setContentHash(path19, "mismatched");
|
|
71602
|
+
}
|
|
71603
|
+
} else if (content) {
|
|
71604
|
+
const hash2 = await storeRawScriptTemp({
|
|
71605
|
+
workspace: workspace.workspaceId,
|
|
71606
|
+
requestBody: content
|
|
71607
|
+
});
|
|
71608
|
+
tree.setContentHash(path19, hash2);
|
|
71609
|
+
}
|
|
71610
|
+
}
|
|
71611
|
+
}
|
|
71612
|
+
|
|
71613
|
+
class DoubleLinkedDependencyTree {
|
|
71614
|
+
nodes = new Map;
|
|
71615
|
+
workspaceDeps = {};
|
|
71616
|
+
setWorkspaceDeps(deps) {
|
|
71617
|
+
this.workspaceDeps = deps;
|
|
71618
|
+
}
|
|
71619
|
+
async addNode(path19, content, language, metadata, imports, itemType, folder, originalPath, isDirectlyStale, isRawApp) {
|
|
71620
|
+
const hasWorkspaceDeps = itemType === "script" || itemType === "inline_script";
|
|
71621
|
+
const filteredDeps = hasWorkspaceDeps ? filterWorkspaceDependencies(this.workspaceDeps, content, language) : {};
|
|
71622
|
+
const stalenessHash = await generateScriptHash({}, content, metadata);
|
|
71623
|
+
if (!this.nodes.has(path19)) {
|
|
71624
|
+
this.nodes.set(path19, {
|
|
71625
|
+
content: "",
|
|
71626
|
+
stalenessHash: "",
|
|
71627
|
+
language: "deno",
|
|
71628
|
+
metadata: "",
|
|
71629
|
+
imports: new Set,
|
|
71630
|
+
importedBy: new Set,
|
|
71631
|
+
itemType: "script",
|
|
71632
|
+
folder: "",
|
|
71633
|
+
originalPath: "",
|
|
71634
|
+
isDirectlyStale: false
|
|
71635
|
+
});
|
|
71636
|
+
}
|
|
71637
|
+
const node = this.nodes.get(path19);
|
|
71638
|
+
node.content = content;
|
|
71639
|
+
node.stalenessHash = stalenessHash;
|
|
71640
|
+
node.language = language;
|
|
71641
|
+
node.metadata = metadata;
|
|
71642
|
+
node.itemType = itemType;
|
|
71643
|
+
node.folder = folder;
|
|
71644
|
+
node.originalPath = originalPath;
|
|
71645
|
+
node.isDirectlyStale = isDirectlyStale;
|
|
71646
|
+
node.isRawApp = isRawApp;
|
|
71647
|
+
const filteredDepsPaths = Object.keys(filteredDeps);
|
|
71648
|
+
for (const depsPath of filteredDepsPaths) {
|
|
71649
|
+
if (!this.nodes.has(depsPath)) {
|
|
71650
|
+
const depsInfo = workspaceDependenciesPathToLanguageAndFilename(depsPath);
|
|
71651
|
+
const contentHash = await generateHash(filteredDeps[depsPath] + depsPath);
|
|
71652
|
+
const isUpToDate = await checkifMetadataUptodate(depsPath, contentHash, undefined);
|
|
71653
|
+
this.nodes.set(depsPath, {
|
|
71654
|
+
content: filteredDeps[depsPath],
|
|
71655
|
+
stalenessHash: "",
|
|
71656
|
+
language: depsInfo?.language ?? "deno",
|
|
71657
|
+
metadata: "",
|
|
71658
|
+
imports: new Set,
|
|
71659
|
+
importedBy: new Set,
|
|
71660
|
+
itemType: "dependencies",
|
|
71661
|
+
folder: "",
|
|
71662
|
+
originalPath: depsPath,
|
|
71663
|
+
isDirectlyStale: !isUpToDate
|
|
71664
|
+
});
|
|
71665
|
+
}
|
|
71666
|
+
}
|
|
71667
|
+
const allImports = [...imports, ...filteredDepsPaths];
|
|
71668
|
+
for (const importPath of allImports) {
|
|
71669
|
+
node.imports.add(importPath);
|
|
71670
|
+
if (!this.nodes.has(importPath)) {
|
|
71671
|
+
this.nodes.set(importPath, {
|
|
71672
|
+
content: "",
|
|
71673
|
+
stalenessHash: "",
|
|
71674
|
+
language: "deno",
|
|
71675
|
+
metadata: "",
|
|
71676
|
+
imports: new Set,
|
|
71677
|
+
importedBy: new Set,
|
|
71678
|
+
itemType: "script",
|
|
71679
|
+
folder: "",
|
|
71680
|
+
originalPath: "",
|
|
71681
|
+
isDirectlyStale: false
|
|
71682
|
+
});
|
|
71683
|
+
}
|
|
71684
|
+
this.nodes.get(importPath).importedBy.add(path19);
|
|
71685
|
+
}
|
|
71686
|
+
}
|
|
71687
|
+
getContent(path19) {
|
|
71688
|
+
return this.nodes.get(path19)?.content;
|
|
71689
|
+
}
|
|
71690
|
+
getStalenessHash(path19) {
|
|
71691
|
+
return this.nodes.get(path19)?.stalenessHash;
|
|
71692
|
+
}
|
|
71693
|
+
getContentHash(path19) {
|
|
71694
|
+
return this.nodes.get(path19)?.contentHash;
|
|
71695
|
+
}
|
|
71696
|
+
setContentHash(path19, hash2) {
|
|
71697
|
+
const node = this.nodes.get(path19);
|
|
71698
|
+
if (node) {
|
|
71699
|
+
node.contentHash = hash2;
|
|
71700
|
+
}
|
|
71701
|
+
}
|
|
71702
|
+
getLanguage(path19) {
|
|
71703
|
+
return this.nodes.get(path19)?.language;
|
|
71704
|
+
}
|
|
71705
|
+
getMetadata(path19) {
|
|
71706
|
+
return this.nodes.get(path19)?.metadata;
|
|
71707
|
+
}
|
|
71708
|
+
getStaleReason(path19) {
|
|
71709
|
+
return this.nodes.get(path19)?.staleReason;
|
|
71710
|
+
}
|
|
71711
|
+
getItemType(path19) {
|
|
71712
|
+
return this.nodes.get(path19)?.itemType;
|
|
71713
|
+
}
|
|
71714
|
+
getFolder(path19) {
|
|
71715
|
+
return this.nodes.get(path19)?.folder;
|
|
71716
|
+
}
|
|
71717
|
+
getIsRawApp(path19) {
|
|
71718
|
+
return this.nodes.get(path19)?.isRawApp;
|
|
71719
|
+
}
|
|
71720
|
+
getIsDirectlyStale(path19) {
|
|
71721
|
+
return this.nodes.get(path19)?.isDirectlyStale ?? false;
|
|
71722
|
+
}
|
|
71723
|
+
getOriginalPath(path19) {
|
|
71724
|
+
return this.nodes.get(path19)?.originalPath;
|
|
71725
|
+
}
|
|
71726
|
+
getImports(path19) {
|
|
71727
|
+
return this.nodes.get(path19)?.imports;
|
|
71728
|
+
}
|
|
71729
|
+
isStale(path19) {
|
|
71730
|
+
return this.nodes.get(path19)?.staleReason !== undefined;
|
|
71731
|
+
}
|
|
71732
|
+
propagateStaleness() {
|
|
71733
|
+
const directlyStale = new Set;
|
|
71734
|
+
for (const [path19, node] of this.nodes.entries()) {
|
|
71735
|
+
if (node.isDirectlyStale) {
|
|
71736
|
+
directlyStale.add(path19);
|
|
71737
|
+
node.staleReason = "content changed";
|
|
71738
|
+
}
|
|
71739
|
+
}
|
|
71740
|
+
const allStale = new Set(directlyStale);
|
|
71741
|
+
const queue = [...directlyStale];
|
|
71742
|
+
const visited = new Set;
|
|
71743
|
+
while (queue.length > 0) {
|
|
71744
|
+
const scriptPath = queue.shift();
|
|
71745
|
+
if (visited.has(scriptPath))
|
|
71746
|
+
continue;
|
|
71747
|
+
visited.add(scriptPath);
|
|
71748
|
+
const node = this.nodes.get(scriptPath);
|
|
71749
|
+
if (!node)
|
|
71750
|
+
continue;
|
|
71751
|
+
for (const importer of node.importedBy) {
|
|
71752
|
+
if (!allStale.has(importer)) {
|
|
71753
|
+
allStale.add(importer);
|
|
71754
|
+
queue.push(importer);
|
|
71755
|
+
const importerNode = this.nodes.get(importer);
|
|
71756
|
+
if (importerNode)
|
|
71757
|
+
importerNode.staleReason = `depends on ${scriptPath}`;
|
|
71758
|
+
}
|
|
71759
|
+
}
|
|
71760
|
+
}
|
|
71761
|
+
}
|
|
71762
|
+
traverseTransitive(scriptPath, callback) {
|
|
71763
|
+
const queue = [scriptPath];
|
|
71764
|
+
const visited = new Set;
|
|
71765
|
+
while (queue.length > 0) {
|
|
71766
|
+
const current = queue.shift();
|
|
71767
|
+
if (visited.has(current))
|
|
71768
|
+
continue;
|
|
71769
|
+
visited.add(current);
|
|
71770
|
+
const node = this.nodes.get(current);
|
|
71771
|
+
if (!node)
|
|
71772
|
+
continue;
|
|
71773
|
+
for (const importPath of node.imports) {
|
|
71774
|
+
const importNode = this.nodes.get(importPath);
|
|
71775
|
+
if (importNode) {
|
|
71776
|
+
const stop = callback(importPath, importNode);
|
|
71777
|
+
if (!stop) {
|
|
71778
|
+
queue.push(importPath);
|
|
71779
|
+
}
|
|
71780
|
+
}
|
|
71781
|
+
}
|
|
71782
|
+
}
|
|
71783
|
+
}
|
|
71784
|
+
allPaths() {
|
|
71785
|
+
return this.nodes.keys();
|
|
71786
|
+
}
|
|
71787
|
+
*stalePaths() {
|
|
71788
|
+
for (const [path19, node] of this.nodes.entries()) {
|
|
71789
|
+
if (node.staleReason) {
|
|
71790
|
+
yield path19;
|
|
71791
|
+
}
|
|
71792
|
+
}
|
|
71793
|
+
}
|
|
71794
|
+
has(path19) {
|
|
71795
|
+
return this.nodes.has(path19);
|
|
71796
|
+
}
|
|
71797
|
+
getMismatchedWorkspaceDeps() {
|
|
71798
|
+
const result = {};
|
|
71799
|
+
for (const [path19, node] of this.nodes.entries()) {
|
|
71800
|
+
if (node.itemType === "dependencies" && node.contentHash && node.content !== undefined) {
|
|
71801
|
+
result[path19] = node.content;
|
|
71802
|
+
}
|
|
71803
|
+
}
|
|
71804
|
+
return result;
|
|
71805
|
+
}
|
|
71806
|
+
getTempScriptRefs(scriptPath) {
|
|
71807
|
+
const result = {};
|
|
71808
|
+
this.traverseTransitive(scriptPath, (_path, node) => {
|
|
71809
|
+
if (node.contentHash) {
|
|
71810
|
+
result[_path] = node.contentHash;
|
|
71811
|
+
}
|
|
71812
|
+
});
|
|
71813
|
+
return result;
|
|
71814
|
+
}
|
|
71815
|
+
async persistDepsHashes(depsPaths) {
|
|
71816
|
+
for (const path19 of depsPaths) {
|
|
71817
|
+
const node = this.nodes.get(path19);
|
|
71818
|
+
if (node?.itemType === "dependencies" && node.content !== undefined) {
|
|
71819
|
+
const hash2 = await generateHash(node.content + path19);
|
|
71820
|
+
await updateMetadataGlobalLock(path19, hash2);
|
|
71821
|
+
}
|
|
71822
|
+
}
|
|
71823
|
+
}
|
|
71824
|
+
get size() {
|
|
71825
|
+
return this.nodes.size;
|
|
71826
|
+
}
|
|
71827
|
+
}
|
|
71828
|
+
var init_dependency_tree = __esm(async () => {
|
|
71829
|
+
init_services_gen();
|
|
71830
|
+
await __promiseAll([
|
|
71831
|
+
init_metadata(),
|
|
71832
|
+
init_utils()
|
|
71833
|
+
]);
|
|
71834
|
+
});
|
|
71835
|
+
|
|
71362
71836
|
// src/main.ts
|
|
71363
71837
|
init_mod3();
|
|
71364
71838
|
|
|
@@ -73051,7 +73525,7 @@ await __promiseAll([
|
|
|
73051
73525
|
init_resource_type()
|
|
73052
73526
|
]);
|
|
73053
73527
|
var import_yaml40 = __toESM(require_dist(), 1);
|
|
73054
|
-
import { stat as stat16, writeFile as writeFile19, rm as rm4, mkdir as
|
|
73528
|
+
import { stat as stat16, writeFile as writeFile19, rm as rm4, mkdir as mkdir9 } from "node:fs/promises";
|
|
73055
73529
|
|
|
73056
73530
|
// src/guidance/skills.ts
|
|
73057
73531
|
var SKILLS = [
|
|
@@ -73786,7 +74260,7 @@ workflow<T>(fn: (...args: any[]) => Promise<T>): void
|
|
|
73786
74260
|
* await step("notify", () => sendEmail(urls.approvalPage));
|
|
73787
74261
|
* const { value, approver } = await waitForApproval({ timeout: 3600 });
|
|
73788
74262
|
*/
|
|
73789
|
-
waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
|
74263
|
+
waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
|
73790
74264
|
|
|
73791
74265
|
/**
|
|
73792
74266
|
* Process items in parallel with optional concurrency control.
|
|
@@ -74449,7 +74923,7 @@ workflow<T>(fn: (...args: any[]) => Promise<T>): void
|
|
|
74449
74923
|
* await step("notify", () => sendEmail(urls.approvalPage));
|
|
74450
74924
|
* const { value, approver } = await waitForApproval({ timeout: 3600 });
|
|
74451
74925
|
*/
|
|
74452
|
-
waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
|
74926
|
+
waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
|
74453
74927
|
|
|
74454
74928
|
/**
|
|
74455
74929
|
* Process items in parallel with optional concurrency control.
|
|
@@ -75175,7 +75649,7 @@ workflow<T>(fn: (...args: any[]) => Promise<T>): void
|
|
|
75175
75649
|
* await step("notify", () => sendEmail(urls.approvalPage));
|
|
75176
75650
|
* const { value, approver } = await waitForApproval({ timeout: 3600 });
|
|
75177
75651
|
*/
|
|
75178
|
-
waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
|
75652
|
+
waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
|
75179
75653
|
|
|
75180
75654
|
/**
|
|
75181
75655
|
* Process items in parallel with optional concurrency control.
|
|
@@ -76115,7 +76589,7 @@ workflow<T>(fn: (...args: any[]) => Promise<T>): void
|
|
|
76115
76589
|
* await step("notify", () => sendEmail(urls.approvalPage));
|
|
76116
76590
|
* const { value, approver } = await waitForApproval({ timeout: 3600 });
|
|
76117
76591
|
*/
|
|
76118
|
-
waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
|
76592
|
+
waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
|
76119
76593
|
|
|
76120
76594
|
/**
|
|
76121
76595
|
* Process items in parallel with optional concurrency control.
|
|
@@ -77124,12 +77598,17 @@ async def sleep(seconds: int)
|
|
|
77124
77598
|
#
|
|
77125
77599
|
# Returns a dict with \`\`value\`\` (form data), \`\`approver\`\`, and \`\`approved\`\`.
|
|
77126
77600
|
#
|
|
77601
|
+
# Args:
|
|
77602
|
+
# timeout: Approval timeout in seconds (default 1800).
|
|
77603
|
+
# form: Optional form schema for the approval page.
|
|
77604
|
+
# self_approval: Whether the user who triggered the flow can approve it (default True).
|
|
77605
|
+
#
|
|
77127
77606
|
# Example::
|
|
77128
77607
|
#
|
|
77129
77608
|
# urls = await step("urls", lambda: get_resume_urls())
|
|
77130
77609
|
# await step("notify", lambda: send_email(urls["approvalPage"]))
|
|
77131
77610
|
# result = await wait_for_approval(timeout=3600)
|
|
77132
|
-
async def wait_for_approval(timeout: int = 1800, form: dict | None = None) -> dict
|
|
77611
|
+
async def wait_for_approval(timeout: int = 1800, form: dict | None = None, self_approval: bool = True) -> dict
|
|
77133
77612
|
|
|
77134
77613
|
# Process items in parallel with optional concurrency control.
|
|
77135
77614
|
#
|
|
@@ -77400,7 +77879,7 @@ Reference a specific resource using \`$res:\` prefix:
|
|
|
77400
77879
|
|
|
77401
77880
|
## OpenFlow Schema
|
|
77402
77881
|
|
|
77403
|
-
{"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":"number","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":"number","description":"Maximum total time in seconds that a job can be debounced"},"max_total_debounces_amount":{"type":"number","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"}}},"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"]},"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","description":"Custom error message shown when stopping"}},"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"}},"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","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_images":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"Array of image references for vision-capable models.\\nFormat: Array<{ bucket: string, key: string }> - S3 object references\\nExample: [{ bucket: 'my-bucket', key: 'images/photo.jpg' }]\\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"]}}`,
|
|
77882
|
+
{"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","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_images":{"allOf":[{"$ref":"#/components/schemas/InputTransform"}],"description":"Array of image references for vision-capable models.\\nFormat: Array<{ bucket: string, key: string }> - S3 object references\\nExample: [{ bucket: 'my-bucket', key: 'images/photo.jpg' }]\\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"]}}`,
|
|
77404
77883
|
"raw-app": `---
|
|
77405
77884
|
name: raw-app
|
|
77406
77885
|
description: MUST use when creating raw apps.
|
|
@@ -78091,6 +78570,7 @@ flow related commands
|
|
|
78091
78570
|
- \`--remote\` - Use deployed workspace scripts for PathScript steps instead of local files.
|
|
78092
78571
|
- \`flow generate-locks [flow:file]\` - re-generate the lock files of all inline scripts of all updated flows
|
|
78093
78572
|
- \`--yes\` - Skip confirmation prompt
|
|
78573
|
+
- \`--dry-run\` - Perform a dry run without making changes
|
|
78094
78574
|
- \`-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)
|
|
78095
78575
|
- \`-e --excludes <patterns:file[]>\` - Comma separated patterns to specify which file to NOT take into account.
|
|
78096
78576
|
- \`flow new <flow_path:string>\` - create a new empty flow
|
|
@@ -78133,6 +78613,7 @@ Generate metadata (locks, schemas) for all scripts, flows, and apps
|
|
|
78133
78613
|
- \`--skip-scripts\` - Skip processing scripts
|
|
78134
78614
|
- \`--skip-flows\` - Skip processing flows
|
|
78135
78615
|
- \`--skip-apps\` - Skip processing apps
|
|
78616
|
+
- \`--strict-folder-boundaries\` - Only update items inside the specified folder (requires folder argument)
|
|
78136
78617
|
- \`-i --includes <patterns:file[]>\` - Comma separated patterns to specify which files to include
|
|
78137
78618
|
- \`-e --excludes <patterns:file[]>\` - Comma separated patterns to specify which files to exclude
|
|
78138
78619
|
|
|
@@ -79590,10 +80071,10 @@ Current Git branch: ${colors.bold(currentBranch)}`));
|
|
|
79590
80071
|
info(colors.green("Created CLAUDE.md"));
|
|
79591
80072
|
}
|
|
79592
80073
|
try {
|
|
79593
|
-
await
|
|
80074
|
+
await mkdir9(".claude/skills", { recursive: true });
|
|
79594
80075
|
await Promise.all(SKILLS.map(async (skill) => {
|
|
79595
80076
|
const skillDir = `.claude/skills/${skill.name}`;
|
|
79596
|
-
await
|
|
80077
|
+
await mkdir9(skillDir, { recursive: true });
|
|
79597
80078
|
let skillContent = SKILL_CONTENT[skill.name];
|
|
79598
80079
|
if (skillContent) {
|
|
79599
80080
|
if (nonDottedPaths) {
|
|
@@ -79826,7 +80307,8 @@ await __promiseAll([
|
|
|
79826
80307
|
init_app_metadata(),
|
|
79827
80308
|
init_sync(),
|
|
79828
80309
|
init_script(),
|
|
79829
|
-
init_codebase()
|
|
80310
|
+
init_codebase(),
|
|
80311
|
+
init_dependency_tree()
|
|
79830
80312
|
]);
|
|
79831
80313
|
import { sep as SEP21 } from "node:path";
|
|
79832
80314
|
async function generateMetadata2(opts, folder) {
|
|
@@ -79836,10 +80318,9 @@ async function generateMetadata2(opts, folder) {
|
|
|
79836
80318
|
const workspace = await resolveWorkspace(opts);
|
|
79837
80319
|
await requireLogin(opts);
|
|
79838
80320
|
opts = await mergeConfigWithConfigFile(opts);
|
|
79839
|
-
const rawWorkspaceDependencies = await getRawWorkspaceDependencies();
|
|
80321
|
+
const rawWorkspaceDependencies = await getRawWorkspaceDependencies(false);
|
|
79840
80322
|
const codebases = await listSyncCodebases(opts);
|
|
79841
80323
|
const ignore = await ignoreF(opts);
|
|
79842
|
-
const staleItems = [];
|
|
79843
80324
|
const skipScripts = opts.skipScripts ?? false;
|
|
79844
80325
|
const skipFlows = opts.skipFlows ?? opts.schemaOnly ?? false;
|
|
79845
80326
|
const skipApps = opts.skipApps ?? opts.schemaOnly ?? false;
|
|
@@ -79854,27 +80335,23 @@ async function generateMetadata2(opts, folder) {
|
|
|
79854
80335
|
info(colors.yellow("Nothing to check (all types skipped)"));
|
|
79855
80336
|
return;
|
|
79856
80337
|
}
|
|
79857
|
-
info(
|
|
80338
|
+
info(`Checking ${checking.join(", ")}...`);
|
|
80339
|
+
const tree = new DoubleLinkedDependencyTree;
|
|
80340
|
+
tree.setWorkspaceDeps(rawWorkspaceDependencies);
|
|
79858
80341
|
if (!skipScripts) {
|
|
79859
80342
|
const scriptElems = await elementsToMap(await FSFSElement(process.cwd(), codebases, false), (p, isD) => {
|
|
79860
|
-
return !isD && !exts.some((ext2) => p.endsWith(ext2)) || ignore(p, isD) ||
|
|
80343
|
+
return !isD && !exts.some((ext2) => p.endsWith(ext2)) || ignore(p, isD) || isFolderResourcePathAnyFormat(p) || isScriptModulePath(p) && !isModuleEntryPoint(p);
|
|
79861
80344
|
}, false, {});
|
|
79862
80345
|
for (const e of Object.keys(scriptElems)) {
|
|
79863
|
-
|
|
79864
|
-
if (candidate) {
|
|
79865
|
-
staleItems.push({ type: "script", path: candidate, folder: e });
|
|
79866
|
-
}
|
|
80346
|
+
await generateScriptMetadataInternal(e, workspace, opts, true, true, rawWorkspaceDependencies, codebases, false, false, tree);
|
|
79867
80347
|
}
|
|
79868
80348
|
}
|
|
79869
80349
|
if (!skipFlows) {
|
|
79870
80350
|
const flowElems = Object.keys(await elementsToMap(await FSFSElement(process.cwd(), [], true), (p, isD) => {
|
|
79871
80351
|
return ignore(p, isD) || !isD && !p.endsWith(SEP21 + "flow.yaml") && !p.endsWith(SEP21 + "flow.json");
|
|
79872
80352
|
}, false, {})).map((x) => x.substring(0, x.lastIndexOf(SEP21)));
|
|
79873
|
-
for (const
|
|
79874
|
-
|
|
79875
|
-
if (candidate) {
|
|
79876
|
-
staleItems.push({ type: "flow", path: candidate, folder: folder2 });
|
|
79877
|
-
}
|
|
80353
|
+
for (const flowFolder of flowElems) {
|
|
80354
|
+
await generateFlowLockInternal(flowFolder, true, workspace, opts, false, true, false, tree);
|
|
79878
80355
|
}
|
|
79879
80356
|
}
|
|
79880
80357
|
if (!skipApps) {
|
|
@@ -79884,16 +80361,37 @@ async function generateMetadata2(opts, folder) {
|
|
|
79884
80361
|
const rawAppFolders = getAppFolders(elems, "raw_app.yaml");
|
|
79885
80362
|
const appFolders = getAppFolders(elems, "app.yaml");
|
|
79886
80363
|
for (const appFolder of rawAppFolders) {
|
|
79887
|
-
|
|
79888
|
-
if (candidate) {
|
|
79889
|
-
staleItems.push({ type: "app", path: candidate, folder: appFolder, isRawApp: true });
|
|
79890
|
-
}
|
|
80364
|
+
await generateAppLocksInternal(appFolder, true, true, workspace, opts, false, true, false, tree);
|
|
79891
80365
|
}
|
|
79892
80366
|
for (const appFolder of appFolders) {
|
|
79893
|
-
|
|
79894
|
-
|
|
79895
|
-
|
|
79896
|
-
|
|
80367
|
+
await generateAppLocksInternal(appFolder, false, true, workspace, opts, false, true, false, tree);
|
|
80368
|
+
}
|
|
80369
|
+
}
|
|
80370
|
+
tree.propagateStaleness();
|
|
80371
|
+
try {
|
|
80372
|
+
await uploadScripts(tree, workspace);
|
|
80373
|
+
} catch (e) {
|
|
80374
|
+
warn(colors.yellow(`Failed to upload scripts to temp storage (backend may be too old): ${e}. ` + `Locks will be generated using deployed script versions only — locally modified ` + `relative imports may not be reflected.`));
|
|
80375
|
+
}
|
|
80376
|
+
const staleItems = [];
|
|
80377
|
+
const seenFolders = new Set;
|
|
80378
|
+
for (const p of tree.allPaths()) {
|
|
80379
|
+
const staleReason = tree.getStaleReason(p);
|
|
80380
|
+
if (!staleReason)
|
|
80381
|
+
continue;
|
|
80382
|
+
const itemType = tree.getItemType(p);
|
|
80383
|
+
const itemFolder = tree.getFolder(p);
|
|
80384
|
+
if (itemType === "dependencies") {
|
|
80385
|
+
staleItems.push({ type: itemType, path: p, folder: itemFolder, staleReason });
|
|
80386
|
+
} else if (itemType === "inline_script") {
|
|
80387
|
+
continue;
|
|
80388
|
+
} else if (itemType === "script") {
|
|
80389
|
+
const originalPath = tree.getOriginalPath(p);
|
|
80390
|
+
staleItems.push({ type: itemType, path: originalPath, folder: itemFolder, staleReason });
|
|
80391
|
+
} else if (!seenFolders.has(itemFolder)) {
|
|
80392
|
+
seenFolders.add(itemFolder);
|
|
80393
|
+
const originalPath = tree.getOriginalPath(p);
|
|
80394
|
+
staleItems.push({ type: itemType, path: originalPath, folder: itemFolder, isRawApp: tree.getIsRawApp(p), staleReason });
|
|
79897
80395
|
}
|
|
79898
80396
|
}
|
|
79899
80397
|
let filteredItems = staleItems;
|
|
@@ -79902,10 +80400,43 @@ async function generateMetadata2(opts, folder) {
|
|
|
79902
80400
|
if (folder.endsWith("/")) {
|
|
79903
80401
|
folder = folder.substring(0, folder.length - 1);
|
|
79904
80402
|
}
|
|
79905
|
-
|
|
80403
|
+
const folderNoExt = folder.replace(/\.[^/.]+$/, "");
|
|
80404
|
+
const isInsideFolder = (item) => {
|
|
79906
80405
|
const normalizedFolder = item.folder.replaceAll("\\", "/");
|
|
79907
|
-
|
|
79908
|
-
|
|
80406
|
+
const normalizedPath = item.path.replaceAll("\\", "/");
|
|
80407
|
+
return normalizedFolder === folder || normalizedFolder.startsWith(folder + "/") || normalizedPath === folder || normalizedPath === folderNoExt;
|
|
80408
|
+
};
|
|
80409
|
+
const isPathInFolder = (p) => p.startsWith(folder + "/") || p === folder || p === folderNoExt;
|
|
80410
|
+
const touchesFolder = (treePath) => {
|
|
80411
|
+
if (isPathInFolder(treePath))
|
|
80412
|
+
return true;
|
|
80413
|
+
let found = false;
|
|
80414
|
+
tree.traverseTransitive(treePath, (importPath) => {
|
|
80415
|
+
if (isPathInFolder(importPath)) {
|
|
80416
|
+
found = true;
|
|
80417
|
+
return true;
|
|
80418
|
+
}
|
|
80419
|
+
});
|
|
80420
|
+
return found;
|
|
80421
|
+
};
|
|
80422
|
+
const isRelevant = (item) => {
|
|
80423
|
+
if (isInsideFolder(item))
|
|
80424
|
+
return true;
|
|
80425
|
+
if (item.type === "dependencies")
|
|
80426
|
+
return true;
|
|
80427
|
+
const treePath = (item.type === "script" ? item.path.replace(/\.[^/.]+$/, "") : item.folder).replaceAll("\\", "/");
|
|
80428
|
+
return touchesFolder(treePath);
|
|
80429
|
+
};
|
|
80430
|
+
if (opts.strictFolderBoundaries) {
|
|
80431
|
+
filteredItems = staleItems.filter(isInsideFolder);
|
|
80432
|
+
const excludedStale = staleItems.filter((item) => !isInsideFolder(item) && isRelevant(item) && item.type !== "dependencies");
|
|
80433
|
+
for (const item of excludedStale) {
|
|
80434
|
+
const normalizedPath = item.path.replaceAll("\\", "/");
|
|
80435
|
+
warn(colors.yellow(`Warning: ${normalizedPath} depends on something inside "${folder}" but is outside it — skipped due to --strict-folder-boundaries. Next generate-metadata will not detect it as stale.`));
|
|
80436
|
+
}
|
|
80437
|
+
} else {
|
|
80438
|
+
filteredItems = staleItems.filter(isRelevant);
|
|
80439
|
+
}
|
|
79909
80440
|
}
|
|
79910
80441
|
if (filteredItems.length === 0) {
|
|
79911
80442
|
info(colors.green("All metadata up-to-date"));
|
|
@@ -79914,26 +80445,22 @@ async function generateMetadata2(opts, folder) {
|
|
|
79914
80445
|
const scripts = filteredItems.filter((i) => i.type === "script");
|
|
79915
80446
|
const flows = filteredItems.filter((i) => i.type === "flow");
|
|
79916
80447
|
const apps2 = filteredItems.filter((i) => i.type === "app");
|
|
80448
|
+
const deps = filteredItems.filter((i) => i.type === "dependencies");
|
|
79917
80449
|
info("");
|
|
79918
|
-
info(`Found ${filteredItems.length} item(s) with stale metadata:`);
|
|
79919
|
-
|
|
79920
|
-
|
|
79921
|
-
|
|
79922
|
-
|
|
79923
|
-
|
|
79924
|
-
|
|
79925
|
-
|
|
79926
|
-
info(colors.gray(` Flows (${flows.length}):`));
|
|
79927
|
-
for (const item of flows) {
|
|
79928
|
-
info(colors.yellow(` ${item.path}`));
|
|
79929
|
-
}
|
|
79930
|
-
}
|
|
79931
|
-
if (apps2.length > 0) {
|
|
79932
|
-
info(colors.gray(` Apps (${apps2.length}):`));
|
|
79933
|
-
for (const item of apps2) {
|
|
79934
|
-
info(colors.yellow(` ${item.path}`));
|
|
80450
|
+
info(`Found ${colors.bold(String(filteredItems.length))} item(s) with stale metadata:`);
|
|
80451
|
+
const printItems = (label, items) => {
|
|
80452
|
+
if (items.length === 0)
|
|
80453
|
+
return;
|
|
80454
|
+
info(` ${label} (${items.length}):`);
|
|
80455
|
+
for (const item of items) {
|
|
80456
|
+
const reason = item.staleReason ? colors.dim(colors.white(` — ${item.staleReason}`)) : "";
|
|
80457
|
+
info(` ~ ${item.path}` + reason);
|
|
79935
80458
|
}
|
|
79936
|
-
}
|
|
80459
|
+
};
|
|
80460
|
+
printItems("Workspace dependencies", deps);
|
|
80461
|
+
printItems("Scripts", scripts);
|
|
80462
|
+
printItems("Flows", flows);
|
|
80463
|
+
printItems("Apps", apps2);
|
|
79937
80464
|
if (opts.dryRun) {
|
|
79938
80465
|
return;
|
|
79939
80466
|
}
|
|
@@ -79945,34 +80472,38 @@ async function generateMetadata2(opts, folder) {
|
|
|
79945
80472
|
return;
|
|
79946
80473
|
}
|
|
79947
80474
|
info("");
|
|
79948
|
-
const
|
|
80475
|
+
const mismatchedWorkspaceDeps = tree.getMismatchedWorkspaceDeps();
|
|
80476
|
+
const total = filteredItems.length - deps.length;
|
|
79949
80477
|
const maxWidth = `[${total}/${total}]`.length;
|
|
79950
80478
|
let current = 0;
|
|
79951
80479
|
const formatProgress = (n) => {
|
|
79952
|
-
|
|
79953
|
-
return colors.gray(bracket.padEnd(maxWidth, " "));
|
|
80480
|
+
return colors.dim(colors.white(`[${n}/${total}]`.padEnd(maxWidth, " ")));
|
|
79954
80481
|
};
|
|
79955
80482
|
for (const item of scripts) {
|
|
79956
80483
|
current++;
|
|
79957
|
-
info(`${formatProgress(current)} script ${
|
|
79958
|
-
await generateScriptMetadataInternal(item.
|
|
80484
|
+
info(`${formatProgress(current)} script ${item.path}`);
|
|
80485
|
+
await generateScriptMetadataInternal(item.path, workspace, opts, false, true, mismatchedWorkspaceDeps, codebases, false, false, tree);
|
|
79959
80486
|
}
|
|
79960
80487
|
for (const item of flows) {
|
|
79961
80488
|
current++;
|
|
79962
|
-
const result = await generateFlowLockInternal(item.folder, false, workspace, opts, false, true);
|
|
79963
|
-
const
|
|
79964
|
-
|
|
80489
|
+
const result = await generateFlowLockInternal(item.folder.replaceAll("/", SEP21), false, workspace, opts, false, true, false, tree);
|
|
80490
|
+
const flowResult = result;
|
|
80491
|
+
const scriptsInfo = flowResult?.updatedScripts?.length ? colors.dim(colors.white(`: ${flowResult.updatedScripts.join(", ")}`)) : "";
|
|
80492
|
+
info(`${formatProgress(current)} flow ${item.path}${scriptsInfo}`);
|
|
79965
80493
|
}
|
|
79966
80494
|
for (const item of apps2) {
|
|
79967
80495
|
current++;
|
|
79968
|
-
const result = await generateAppLocksInternal(item.folder, item.isRawApp, false, workspace, opts, false, true);
|
|
79969
|
-
const
|
|
79970
|
-
|
|
80496
|
+
const result = await generateAppLocksInternal(item.folder.replaceAll("/", SEP21), item.isRawApp, false, workspace, opts, false, true, false, tree);
|
|
80497
|
+
const appResult = result;
|
|
80498
|
+
const scriptsInfo = appResult?.updatedScripts?.length ? colors.dim(colors.white(`: ${appResult.updatedScripts.join(", ")}`)) : "";
|
|
80499
|
+
info(`${formatProgress(current)} app ${item.path}${scriptsInfo}`);
|
|
79971
80500
|
}
|
|
80501
|
+
const allStaleDeps = staleItems.filter((i) => i.type === "dependencies");
|
|
80502
|
+
await tree.persistDepsHashes(allStaleDeps.map((d) => d.path));
|
|
79972
80503
|
info("");
|
|
79973
|
-
info(
|
|
80504
|
+
info(`Done. Updated ${colors.bold(String(total))} item(s).`);
|
|
79974
80505
|
}
|
|
79975
|
-
var command29 = new Command().description("Generate metadata (locks, schemas) for all scripts, flows, and apps").arguments("[folder:string]").option("--yes", "Skip confirmation prompt").option("--dry-run", "Show what would be updated without making changes").option("--lock-only", "Re-generate only the lock files").option("--schema-only", "Re-generate only script schemas (skips flows and apps)").option("--skip-scripts", "Skip processing scripts").option("--skip-flows", "Skip processing flows").option("--skip-apps", "Skip processing apps").option("-i --includes <patterns:file[]>", "Comma separated patterns to specify which files to include").option("-e --excludes <patterns:file[]>", "Comma separated patterns to specify which files to exclude").action(generateMetadata2);
|
|
80506
|
+
var command29 = new Command().description("Generate metadata (locks, schemas) for all scripts, flows, and apps").arguments("[folder:string]").option("--yes", "Skip confirmation prompt").option("--dry-run", "Show what would be updated without making changes").option("--lock-only", "Re-generate only the lock files").option("--schema-only", "Re-generate only script schemas (skips flows and apps)").option("--skip-scripts", "Skip processing scripts").option("--skip-flows", "Skip processing flows").option("--skip-apps", "Skip processing apps").option("--strict-folder-boundaries", "Only update items inside the specified folder (requires folder argument)").option("-i --includes <patterns:file[]>", "Comma separated patterns to specify which files to include").option("-e --excludes <patterns:file[]>", "Comma separated patterns to specify which files to exclude").action(generateMetadata2);
|
|
79976
80507
|
var generate_metadata_default = command29;
|
|
79977
80508
|
|
|
79978
80509
|
// src/commands/docs/docs.ts
|
|
@@ -80050,7 +80581,7 @@ var docs_default = command30;
|
|
|
80050
80581
|
|
|
80051
80582
|
// src/main.ts
|
|
80052
80583
|
await init_context();
|
|
80053
|
-
var VERSION = "1.
|
|
80584
|
+
var VERSION = "1.664.0";
|
|
80054
80585
|
var command31 = 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("generate-metadata", generate_metadata_default).command("docs", docs_default).command("version --version", "Show version information").action(async (opts) => {
|
|
80055
80586
|
console.log("CLI version: " + VERSION);
|
|
80056
80587
|
try {
|