windmill-cli 1.668.1 → 1.668.3

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.
Files changed (2) hide show
  1. package/esm/main.js +213 -85
  2. package/package.json +1 -1
package/esm/main.js CHANGED
@@ -11812,7 +11812,7 @@ var init_OpenAPI = __esm(() => {
11812
11812
  PASSWORD: undefined,
11813
11813
  TOKEN: getEnv2("WM_TOKEN"),
11814
11814
  USERNAME: undefined,
11815
- VERSION: "1.668.1",
11815
+ VERSION: "1.668.3",
11816
11816
  WITH_CREDENTIALS: true,
11817
11817
  interceptors: {
11818
11818
  request: new Interceptors,
@@ -24671,6 +24671,7 @@ function getHeaders2() {
24671
24671
  async function digestDir(path3, conf) {
24672
24672
  const hashes = [];
24673
24673
  const entries = await readdir(path3, { withFileTypes: true });
24674
+ entries.sort((a, b) => a.name.localeCompare(b.name));
24674
24675
  for (const e of entries) {
24675
24676
  const npath = path3 + "/" + e.name;
24676
24677
  if (e.isFile()) {
@@ -24777,6 +24778,13 @@ function capitalize(str) {
24777
24778
  function formatTimestamp(ts) {
24778
24779
  return new Date(ts).toISOString().replace("T", " ").substring(0, 19);
24779
24780
  }
24781
+ function validateRequiredArgs(schema) {
24782
+ const required = schema?.required ?? [];
24783
+ if (required.length > 0) {
24784
+ throw new Error(`Missing required arguments: ${required.join(", ")}.
24785
+ Use -d '{"${required[0]}": ...}' to provide input data.`);
24786
+ }
24787
+ }
24780
24788
  var isWin = undefined;
24781
24789
  var init_utils = __esm(async () => {
24782
24790
  init_colors2();
@@ -26159,7 +26167,7 @@ Available workspaces:`);
26159
26167
  opts.__secret_workspace = ws;
26160
26168
  return ws;
26161
26169
  }
26162
- info(colors.red.bold("No workspace given and no default set."));
26170
+ info(colors.red.bold("No workspace given and no default set. Run 'wmill workspace add' to configure one."));
26163
26171
  return process.exit(-1);
26164
26172
  }
26165
26173
  async function fetchVersion(baseUrl2) {
@@ -31089,7 +31097,8 @@ async function ensureNodeModules(appDir) {
31089
31097
  }
31090
31098
  async function createBundle(options = {}) {
31091
31099
  const esbuild = await import("esbuild");
31092
- const frameworks = detectFrameworks(process11.cwd());
31100
+ const appDir = options.entryPoint ? path3.dirname(options.entryPoint) : process11.cwd();
31101
+ const frameworks = detectFrameworks(appDir);
31093
31102
  const defaultEntry = frameworks.svelte || frameworks.vue ? "index.ts" : "index.tsx";
31094
31103
  const entryPoint = options.entryPoint ?? defaultEntry;
31095
31104
  const outDir = options.outDir ?? "dist";
@@ -31099,7 +31108,6 @@ async function createBundle(options = {}) {
31099
31108
  if (!fs7.existsSync(entryPoint)) {
31100
31109
  throw new Error(`Entry point "${entryPoint}" not found. Please ensure the file exists.`);
31101
31110
  }
31102
- const appDir = path3.dirname(entryPoint) || process11.cwd();
31103
31111
  await ensureNodeModules(appDir);
31104
31112
  const frameworkPlugins = await createFrameworkPlugins(appDir);
31105
31113
  const distDir = path3.join(process11.cwd(), outDir);
@@ -59221,13 +59229,16 @@ async function push(opts, filePath) {
59221
59229
  const remotePath = removeExtensionToPath(filePath).replaceAll(SEP4, "/");
59222
59230
  const contentHash = await generateHash(content + remotePath);
59223
59231
  const conf = await readLockfile();
59224
- if (!await checkifMetadataUptodate(remotePath, contentHash, conf)) {
59232
+ const hasLockEntry = conf.locks && (conf.locks[remotePath] !== undefined || conf.locks[`${remotePath}.ts`] !== undefined);
59233
+ if (!hasLockEntry) {
59234
+ warn(colors.yellow(`No metadata generated yet for ${filePath}. Run 'wmill generate-metadata' to generate schema and lock.`));
59235
+ } else if (!await checkifMetadataUptodate(remotePath, contentHash, conf)) {
59225
59236
  warn(colors.yellow(`Metadata for ${filePath} appears stale (content changed since last 'wmill generate-metadata').
59226
59237
  ` + `The schema and lock may not match the current code. Consider running 'wmill generate-metadata' first.`));
59227
59238
  }
59228
59239
  } catch {}
59229
59240
  const codebases = await listSyncCodebases(opts);
59230
- await handleFile(filePath, workspace, [], undefined, opts, await getRawWorkspaceDependencies(true), codebases);
59241
+ await handleFile(filePath, workspace, [], opts.message, opts, await getRawWorkspaceDependencies(true), codebases);
59231
59242
  info(colors.bold.underline.green(`Script ${filePath} pushed`));
59232
59243
  }
59233
59244
  async function findResourceFile(path6) {
@@ -59649,6 +59660,19 @@ async function run2(opts, path6) {
59649
59660
  const workspace = await resolveWorkspace(opts);
59650
59661
  await requireLogin(opts);
59651
59662
  const input = opts.data ? await resolve6(opts.data) : {};
59663
+ if (!opts.data) {
59664
+ try {
59665
+ const script = await getScriptByPath({
59666
+ workspace: workspace.workspaceId,
59667
+ path: path6
59668
+ });
59669
+ validateRequiredArgs(script.schema);
59670
+ } catch (e) {
59671
+ if (e.message?.startsWith("Missing required"))
59672
+ throw e;
59673
+ warn(`Could not fetch schema to validate args: ${e.message}`);
59674
+ }
59675
+ }
59652
59676
  let id;
59653
59677
  try {
59654
59678
  id = await runScriptByPath({
@@ -60083,9 +60107,10 @@ async function history(opts, scriptPath) {
60083
60107
  info("No version history found for " + scriptPath);
60084
60108
  return;
60085
60109
  }
60086
- new Table2().header(["#", "Hash", "Deployment Message"]).padding(2).border(true).body(versions.map((v, i) => [
60110
+ new Table2().header(["#", "Hash", "Created At", "Deployment Message"]).padding(2).border(true).body(versions.map((v, i) => [
60087
60111
  String(versions.length - i),
60088
60112
  v.script_hash,
60113
+ v.created_at ? new Date(v.created_at).toLocaleString() : "-",
60089
60114
  v.deployment_msg ?? "-"
60090
60115
  ])).render();
60091
60116
  }
@@ -60146,7 +60171,7 @@ var init_script = __esm(async () => {
60146
60171
  languageAliases = {
60147
60172
  python: "python3"
60148
60173
  };
60149
- 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(list3).command("list", "list all scripts").option("--show-archived", "Enable archived scripts in output").option("--json", "Output as JSON (for piping to jq)").action(list3).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).command("history", "show version history for a script").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(history);
60174
+ command3 = new Command().description("script related commands").option("--show-archived", "Show archived scripts instead of active ones").option("--json", "Output as JSON (for piping to jq)").action(list3).command("list", "list all scripts").option("--show-archived", "Show archived scripts instead of active ones").option("--json", "Output as JSON (for piping to jq)").action(list3).command("push", "push a local script spec. This overrides any remote versions. Use the script file (.ts, .js, .py, .sh)").arguments("<path:file>").option("--message <message:string>", "Deployment message").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).command("history", "show version history for a script").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(history);
60150
60175
  script_default = command3;
60151
60176
  });
60152
60177
 
@@ -60535,7 +60560,8 @@ async function runLint(opts, directory) {
60535
60560
  if (!stats.isDirectory()) {
60536
60561
  throw new Error(`Path is not a directory: ${targetDirectory}`);
60537
60562
  }
60538
- const ignore = await ignoreF(mergedOpts);
60563
+ const isSubdirectory = explicitTargetDirectory && !await stat4(path6.join(targetDirectory, "wmill.yaml")).catch(() => null);
60564
+ const ignore = isSubdirectory ? (_p, _isDir) => false : await ignoreF(mergedOpts);
60539
60565
  const root = await FSFSElement(targetDirectory, [], false);
60540
60566
  const validator = new import_windmill_yaml_validator.WindmillYamlValidator;
60541
60567
  const warnings = [];
@@ -60548,8 +60574,8 @@ async function runLint(opts, directory) {
60548
60574
  if (entry.isDirectory || entry.ignored) {
60549
60575
  continue;
60550
60576
  }
60551
- scannedFiles += 1;
60552
60577
  const normalizedPath = normalizePath(entry.path);
60578
+ scannedFiles += 1;
60553
60579
  if (!YAML_FILE_REGEX.test(normalizedPath)) {
60554
60580
  continue;
60555
60581
  }
@@ -60633,6 +60659,10 @@ function printReport(report, jsonOutput) {
60633
60659
  }
60634
60660
  }
60635
60661
  async function lint(opts, directory) {
60662
+ if (opts.watch) {
60663
+ await lintWatch(opts, directory);
60664
+ return;
60665
+ }
60636
60666
  try {
60637
60667
  const report = await runLint(opts, directory);
60638
60668
  printReport(report, !!opts.json);
@@ -60653,6 +60683,32 @@ async function lint(opts, directory) {
60653
60683
  process12.exit(1);
60654
60684
  }
60655
60685
  }
60686
+ async function lintWatch(opts, directory) {
60687
+ const { watch } = await import("node:fs");
60688
+ const targetDir = directory ? path6.resolve(process12.cwd(), directory) : process12.cwd();
60689
+ info(colors.blue(`Watching ${targetDir} for changes... (Ctrl+C to stop)`));
60690
+ async function runAndReport() {
60691
+ try {
60692
+ const report = await runLint(opts, directory);
60693
+ process12.stdout.write("\x1Bc");
60694
+ info(colors.gray(`[${new Date().toLocaleTimeString()}] Lint results:
60695
+ `));
60696
+ printReport(report, false);
60697
+ } catch (error2) {
60698
+ error(error2 instanceof Error ? error2.message : String(error2));
60699
+ }
60700
+ }
60701
+ await runAndReport();
60702
+ let debounce = null;
60703
+ watch(targetDir, { recursive: true }, (_event, filename) => {
60704
+ if (!filename || !filename.toString().endsWith(".yaml") && !filename.toString().endsWith(".yml"))
60705
+ return;
60706
+ if (debounce)
60707
+ clearTimeout(debounce);
60708
+ debounce = setTimeout(runAndReport, 300);
60709
+ });
60710
+ await new Promise(() => {});
60711
+ }
60656
60712
  var import_windmill_yaml_validator, YAML_FILE_REGEX, NATIVE_TRIGGER_REGEX, command4, lint_default;
60657
60713
  var init_lint = __esm(async () => {
60658
60714
  init_colors2();
@@ -60669,7 +60725,7 @@ var init_lint = __esm(async () => {
60669
60725
  import_windmill_yaml_validator = __toESM(require_dist3(), 1);
60670
60726
  YAML_FILE_REGEX = /\.ya?ml$/i;
60671
60727
  NATIVE_TRIGGER_REGEX = /\.[^.]+_native_trigger\.ya?ml$/i;
60672
- command4 = new Command().description("Validate Windmill flow, schedule, and trigger YAML files in a directory").arguments("[directory:string]").option("--json", "Output results in JSON format").option("--fail-on-warn", "Exit with code 1 when warnings are emitted").option("--locks-required", "Fail if scripts or flow inline scripts that need locks have no locks").action(lint);
60728
+ command4 = new Command().description("Validate Windmill flow, schedule, and trigger YAML files in a directory").arguments("[directory:string]").option("--json", "Output results in JSON format").option("--fail-on-warn", "Exit with code 1 when warnings are emitted").option("--locks-required", "Fail if scripts or flow inline scripts that need locks have no locks").option("-w, --watch", "Watch for file changes and re-lint automatically").action(lint);
60673
60729
  lint_default = command4;
60674
60730
  });
60675
60731
 
@@ -61063,7 +61119,7 @@ var init_extractor = __esm(() => {
61063
61119
  });
61064
61120
 
61065
61121
  // windmill-utils-internal/src/inline-scripts/replacer.ts
61066
- async function replaceRawscriptInline(id, rawscript, fileReader, logger, separator, removeLocks) {
61122
+ async function replaceRawscriptInline(id, rawscript, fileReader, logger, separator, removeLocks, missingFiles) {
61067
61123
  if (!rawscript.content || !rawscript.content.startsWith("!inline")) {
61068
61124
  return;
61069
61125
  }
@@ -61078,6 +61134,8 @@ async function replaceRawscriptInline(id, rawscript, fileReader, logger, separat
61078
61134
  rawscript.content = await fileReader(newPath);
61079
61135
  } catch {
61080
61136
  logger.error(`Script file ${newPath} not found`);
61137
+ if (missingFiles)
61138
+ missingFiles.push(path7);
61081
61139
  }
61082
61140
  }
61083
61141
  const lock = rawscript.lock;
@@ -61096,34 +61154,36 @@ async function replaceRawscriptInline(id, rawscript, fileReader, logger, separat
61096
61154
  async function replaceInlineScripts(modules, fileReader, logger = {
61097
61155
  info: () => {},
61098
61156
  error: () => {}
61099
- }, localPath, separator = "/", removeLocks) {
61157
+ }, localPath, separator = "/", removeLocks, missingFiles) {
61158
+ const missing = missingFiles ?? [];
61100
61159
  await Promise.all(modules.map(async (module) => {
61101
61160
  if (!module.value) {
61102
61161
  throw new Error(`Module value is undefined for module ${module.id}`);
61103
61162
  }
61104
61163
  if (module.value.type === "rawscript") {
61105
- await replaceRawscriptInline(module.id, module.value, fileReader, logger, separator, removeLocks);
61164
+ await replaceRawscriptInline(module.id, module.value, fileReader, logger, separator, removeLocks, missing);
61106
61165
  } else if (module.value.type === "forloopflow" || module.value.type === "whileloopflow") {
61107
- await replaceInlineScripts(module.value.modules, fileReader, logger, localPath, separator, removeLocks);
61166
+ await replaceInlineScripts(module.value.modules, fileReader, logger, localPath, separator, removeLocks, missing);
61108
61167
  } else if (module.value.type === "branchall") {
61109
61168
  await Promise.all(module.value.branches.map(async (branch) => {
61110
- await replaceInlineScripts(branch.modules, fileReader, logger, localPath, separator, removeLocks);
61169
+ await replaceInlineScripts(branch.modules, fileReader, logger, localPath, separator, removeLocks, missing);
61111
61170
  }));
61112
61171
  } else if (module.value.type === "branchone") {
61113
61172
  await Promise.all(module.value.branches.map(async (branch) => {
61114
- await replaceInlineScripts(branch.modules, fileReader, logger, localPath, separator, removeLocks);
61173
+ await replaceInlineScripts(branch.modules, fileReader, logger, localPath, separator, removeLocks, missing);
61115
61174
  }));
61116
- await replaceInlineScripts(module.value.default, fileReader, logger, localPath, separator, removeLocks);
61175
+ await replaceInlineScripts(module.value.default, fileReader, logger, localPath, separator, removeLocks, missing);
61117
61176
  } else if (module.value.type === "aiagent") {
61118
61177
  await Promise.all((module.value.tools ?? []).map(async (tool) => {
61119
61178
  const toolValue = tool.value;
61120
61179
  if (!toolValue || toolValue.tool_type !== "flowmodule" || toolValue.type !== "rawscript") {
61121
61180
  return;
61122
61181
  }
61123
- await replaceRawscriptInline(tool.id, toolValue, fileReader, logger, separator, removeLocks);
61182
+ await replaceRawscriptInline(tool.id, toolValue, fileReader, logger, separator, removeLocks, missing);
61124
61183
  }));
61125
61184
  }
61126
61185
  }));
61186
+ return missing;
61127
61187
  }
61128
61188
  async function replacePathScriptsWithLocal(modules, scriptReader, logger = {
61129
61189
  info: () => {},
@@ -61909,12 +61969,13 @@ function ZipFSElement(zip, useYaml, defaultTs, resourceTypeToFormatExtension, re
61909
61969
  let inlineScripts;
61910
61970
  try {
61911
61971
  const assigner = newPathAssigner(defaultTs, { skipInlineScriptSuffix: getNonDottedPaths() });
61912
- inlineScripts = extractInlineScripts(flow.value.modules, {}, SEP8, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths() });
61972
+ const inlineMapping = extractCurrentMapping(flow.value.modules, {}, flow.value.failure_module, flow.value.preprocessor_module);
61973
+ inlineScripts = extractInlineScripts(flow.value.modules, inlineMapping, SEP8, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths() });
61913
61974
  if (flow.value.failure_module) {
61914
- inlineScripts.push(...extractInlineScripts([flow.value.failure_module], {}, SEP8, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths() }));
61975
+ inlineScripts.push(...extractInlineScripts([flow.value.failure_module], inlineMapping, SEP8, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths() }));
61915
61976
  }
61916
61977
  if (flow.value.preprocessor_module) {
61917
- inlineScripts.push(...extractInlineScripts([flow.value.preprocessor_module], {}, SEP8, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths() }));
61978
+ inlineScripts.push(...extractInlineScripts([flow.value.preprocessor_module], inlineMapping, SEP8, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths() }));
61918
61979
  }
61919
61980
  } catch (error2) {
61920
61981
  error(`Failed to extract inline scripts for flow at path: ${p}`);
@@ -62516,6 +62577,10 @@ async function compareDynFSElement(els1, els2, ignore, json, skips, ignoreMetada
62516
62577
  continue;
62517
62578
  }
62518
62579
  if (k.startsWith("dependencies/")) {
62580
+ if (!workspaceDependenciesPathToLanguageAndFilename(k)) {
62581
+ warn(`Skipping unrecognized workspace dependencies file: ${k}`);
62582
+ continue;
62583
+ }
62519
62584
  info(`Adding workspace dependencies file: ${k}`);
62520
62585
  }
62521
62586
  changes.push({ name: "added", path: k, content: v });
@@ -66945,7 +67010,11 @@ async function validateBuild(appDir) {
66945
67010
  const warnings = [];
66946
67011
  try {
66947
67012
  info(colors.blue("\uD83D\uDD28 Testing build..."));
67013
+ const frameworks = detectFrameworks(appDir);
67014
+ const entryFile = frameworks.svelte || frameworks.vue ? "index.ts" : "index.tsx";
67015
+ const entryPoint = path14.join(appDir, entryFile);
66948
67016
  await createBundle({
67017
+ entryPoint,
66949
67018
  production: true,
66950
67019
  minify: false
66951
67020
  });
@@ -70019,44 +70088,39 @@ async function push9(opts, filePath) {
70019
70088
  await pushWorkspaceDependencies(workspace.workspaceId, filePath, null, content);
70020
70089
  }
70021
70090
  async function pushWorkspaceDependencies(workspace, path18, _befObj, newDependenciesContent) {
70091
+ const res = workspaceDependenciesPathToLanguageAndFilename(path18);
70092
+ if (!res) {
70093
+ throw new Error(`Unknown workspace dependencies file format: ${path18}. ` + `Valid files: package.json, requirements.in, composer.json, go.mod, modules.json`);
70094
+ }
70095
+ const { language, name } = res;
70096
+ const displayName = name ? `named dependencies "${name}"` : `workspace default dependencies`;
70022
70097
  try {
70023
- const res = workspaceDependenciesPathToLanguageAndFilename(path18);
70024
- if (!res) {
70025
- throw new Error(`Unknown workspace dependencies file format: ${path18}`);
70026
- }
70027
- const { language, name } = res;
70028
- const displayName = name ? `named dependencies "${name}"` : `workspace default dependencies`;
70029
- try {
70030
- const remoteDeps = await getLatestWorkspaceDependencies({
70031
- workspace,
70032
- language,
70033
- name
70034
- });
70035
- if (remoteDeps && remoteDeps.content === newDependenciesContent) {
70036
- info(colors.green(`${displayName} for ${language} are up-to-date, skipping push`));
70037
- return;
70038
- }
70039
- } catch (e) {
70040
- if (e.status !== 404 && !e.message?.includes("not found")) {
70041
- throw e;
70042
- }
70043
- }
70044
- info(colors.yellow(`Pushing ${name ? "named" : "workspace default"} dependencies for ${language}...`));
70045
- await createWorkspaceDependencies({
70098
+ const remoteDeps = await getLatestWorkspaceDependencies({
70046
70099
  workspace,
70047
- requestBody: {
70048
- name,
70049
- content: newDependenciesContent,
70050
- language,
70051
- workspace_id: workspace,
70052
- description: undefined
70053
- }
70100
+ language,
70101
+ name
70054
70102
  });
70055
- info(colors.green(`Successfully pushed ${displayName} for ${language}`));
70056
- } catch (error2) {
70057
- error(colors.red(`Failed to push workspace dependencies: ${error2.message}`));
70058
- throw error2;
70103
+ if (remoteDeps && remoteDeps.content === newDependenciesContent) {
70104
+ info(colors.green(`${displayName} for ${language} are up-to-date, skipping push`));
70105
+ return;
70106
+ }
70107
+ } catch (e) {
70108
+ if (e.status !== 404 && !e.message?.includes("not found")) {
70109
+ throw e;
70110
+ }
70059
70111
  }
70112
+ info(colors.yellow(`Pushing ${name ? "named" : "workspace default"} dependencies for ${language}...`));
70113
+ await createWorkspaceDependencies({
70114
+ workspace,
70115
+ requestBody: {
70116
+ name,
70117
+ content: newDependenciesContent,
70118
+ language,
70119
+ workspace_id: workspace,
70120
+ description: undefined
70121
+ }
70122
+ });
70123
+ info(colors.green(`Successfully pushed ${displayName} for ${language}`));
70060
70124
  }
70061
70125
  var command19, dependencies_default;
70062
70126
  var init_dependencies = __esm(async () => {
@@ -70264,6 +70328,26 @@ async function newTrigger(opts, path18) {
70264
70328
  });
70265
70329
  info(colors.green(`Created ${filePath}`));
70266
70330
  }
70331
+ function printTriggerDetails(trigger, kind) {
70332
+ console.log(colors.bold("Path:") + " " + trigger.path);
70333
+ console.log(colors.bold("Kind:") + " " + kind);
70334
+ console.log(colors.bold("Enabled:") + " " + (trigger.enabled ?? trigger.mode ?? "-"));
70335
+ console.log(colors.bold("Script Path:") + " " + (trigger.script_path ?? ""));
70336
+ console.log(colors.bold("Is Flow:") + " " + (trigger.is_flow ? "true" : "false"));
70337
+ for (const [key, value] of Object.entries(trigger)) {
70338
+ if (["path", "enabled", "mode", "script_path", "is_flow"].includes(key))
70339
+ continue;
70340
+ if (TRIGGER_SKIP_FIELDS.has(key))
70341
+ continue;
70342
+ if (value === undefined || value === null || value === "")
70343
+ continue;
70344
+ const display = Array.isArray(value) ? value.length > 0 ? JSON.stringify(value) : "[]" : typeof value === "object" ? JSON.stringify(value) : String(value);
70345
+ if (display === "[]" || display === "{}")
70346
+ continue;
70347
+ const label = key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
70348
+ console.log(colors.bold(label + ":") + " " + display);
70349
+ }
70350
+ }
70267
70351
  async function get8(opts, path18) {
70268
70352
  if (opts.json)
70269
70353
  setSilent(true);
@@ -70277,11 +70361,7 @@ async function get8(opts, path18) {
70277
70361
  if (opts.json) {
70278
70362
  console.log(JSON.stringify(trigger));
70279
70363
  } else {
70280
- console.log(colors.bold("Path:") + " " + trigger.path);
70281
- console.log(colors.bold("Kind:") + " " + opts.kind);
70282
- console.log(colors.bold("Enabled:") + " " + (trigger.enabled ?? "-"));
70283
- console.log(colors.bold("Script Path:") + " " + (trigger.script_path ?? ""));
70284
- console.log(colors.bold("Is Flow:") + " " + (trigger.is_flow ? "true" : "false"));
70364
+ printTriggerDetails(trigger, opts.kind);
70285
70365
  }
70286
70366
  return;
70287
70367
  }
@@ -70300,11 +70380,7 @@ async function get8(opts, path18) {
70300
70380
  if (opts.json) {
70301
70381
  console.log(JSON.stringify(trigger));
70302
70382
  } else {
70303
- console.log(colors.bold("Path:") + " " + trigger.path);
70304
- console.log(colors.bold("Kind:") + " " + kind);
70305
- console.log(colors.bold("Enabled:") + " " + (trigger.enabled ?? trigger.mode ?? "-"));
70306
- console.log(colors.bold("Script Path:") + " " + (trigger.script_path ?? ""));
70307
- console.log(colors.bold("Is Flow:") + " " + (trigger.is_flow ? "true" : "false"));
70383
+ printTriggerDetails(trigger, kind);
70308
70384
  }
70309
70385
  return;
70310
70386
  }
@@ -70401,7 +70477,7 @@ async function push10(opts, filePath, remotePath) {
70401
70477
  await pushTrigger(triggerKind, workspace.workspaceId, remotePath, undefined, parseFromFile(filePath));
70402
70478
  console.log(colors.bold.underline.green("Trigger pushed"));
70403
70479
  }
70404
- var import_yaml33, triggerTemplates, command20, trigger_default;
70480
+ var import_yaml33, triggerTemplates, TRIGGER_SKIP_FIELDS, command20, trigger_default;
70405
70481
  var init_trigger = __esm(async () => {
70406
70482
  init_services_gen();
70407
70483
  init_mod3();
@@ -70493,9 +70569,11 @@ var init_trigger = __esm(async () => {
70493
70569
  email: {
70494
70570
  script_path: "",
70495
70571
  is_flow: false,
70572
+ local_part: "",
70496
70573
  enabled: false
70497
70574
  }
70498
70575
  };
70576
+ TRIGGER_SKIP_FIELDS = new Set(["workspace_id", "extra_perms", "edited_by", "edited_at"]);
70499
70577
  command20 = new Command().description("trigger related commands").option("--json", "Output as JSON (for piping to jq)").action(list11).command("list", "list all triggers").option("--json", "Output as JSON (for piping to jq)").action(list11).command("get", "get a trigger's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").option("--kind <kind:string>", "Trigger kind (http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, email). Recommended for faster lookup").action(get8).command("new", "create a new trigger locally").arguments("<path:string>").option("--kind <kind:string>", "Trigger kind (required: http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, email)").action(newTrigger).command("push", "push a local trigger spec. This overrides any remote versions.").arguments("<file_path:string> <remote_path:string>").action(push10);
70500
70578
  trigger_default = command20;
70501
70579
  });
@@ -70945,12 +71023,16 @@ async function pushFlow(workspace, remotePath, localPath, message) {
70945
71023
  }
70946
71024
  const localFlow = await yamlParseFile(localPath + "flow.yaml");
70947
71025
  const fileReader = async (path19) => await readFile15(localPath + path19, "utf-8");
70948
- await replaceInlineScripts(localFlow.value.modules, fileReader, exports_log, localPath, SEP19);
71026
+ const missingFiles = [];
71027
+ await replaceInlineScripts(localFlow.value.modules, fileReader, exports_log, localPath, SEP19, undefined, missingFiles);
70949
71028
  if (localFlow.value.failure_module) {
70950
- await replaceInlineScripts([localFlow.value.failure_module], fileReader, exports_log, localPath, SEP19);
71029
+ await replaceInlineScripts([localFlow.value.failure_module], fileReader, exports_log, localPath, SEP19, undefined, missingFiles);
70951
71030
  }
70952
71031
  if (localFlow.value.preprocessor_module) {
70953
- await replaceInlineScripts([localFlow.value.preprocessor_module], fileReader, exports_log, localPath, SEP19);
71032
+ await replaceInlineScripts([localFlow.value.preprocessor_module], fileReader, exports_log, localPath, SEP19, undefined, missingFiles);
71033
+ }
71034
+ if (missingFiles.length > 0) {
71035
+ warn(colors.yellow(`Warning: missing inline script file(s): ${missingFiles.join(", ")}. ` + `The flow will be pushed with unresolved !inline references.`));
70954
71036
  }
70955
71037
  if (flow) {
70956
71038
  if (isSuperset(localFlow, flow)) {
@@ -70989,7 +71071,7 @@ async function push11(opts, filePath, remotePath) {
70989
71071
  }
70990
71072
  const workspace = await resolveWorkspace(opts);
70991
71073
  await requireLogin(opts);
70992
- await pushFlow(workspace.workspaceId, remotePath, filePath);
71074
+ await pushFlow(workspace.workspaceId, remotePath, filePath, opts.message);
70993
71075
  info(colors.bold.underline.green("Flow pushed"));
70994
71076
  }
70995
71077
  async function list12(opts) {
@@ -71039,12 +71121,29 @@ async function get9(opts, path19) {
71039
71121
  console.log(colors.bold("Edited at:") + " " + (f.edited_at ?? ""));
71040
71122
  const modules = f.value?.modules;
71041
71123
  if (modules && Array.isArray(modules) && modules.length > 0) {
71124
+ let printModules = function(mods, indent = " ") {
71125
+ for (const mod of mods) {
71126
+ const type = mod.value?.type ?? "unknown";
71127
+ const detail = mod.value?.language ?? mod.value?.path ?? "";
71128
+ console.log(`${indent}${mod.id}: ${type}${detail ? " (" + detail + ")" : ""}`);
71129
+ if (type === "branchall" || type === "branchone") {
71130
+ for (const branch of mod.value?.branches ?? []) {
71131
+ console.log(`${indent} Branch: ${branch.summary || "(default)"}`);
71132
+ if (branch.modules)
71133
+ printModules(branch.modules, indent + " ");
71134
+ }
71135
+ if (type === "branchone" && mod.value?.default) {
71136
+ console.log(`${indent} Default:`);
71137
+ printModules(mod.value.default, indent + " ");
71138
+ }
71139
+ } else if (type === "forloopflow" || type === "whileloopflow") {
71140
+ if (mod.value?.modules)
71141
+ printModules(mod.value.modules, indent + " ");
71142
+ }
71143
+ }
71144
+ };
71042
71145
  console.log(colors.bold("Steps:"));
71043
- for (const mod of modules) {
71044
- const type = mod.value?.type ?? "unknown";
71045
- const detail = mod.value?.language ?? mod.value?.path ?? "";
71046
- console.log(` ${mod.id}: ${type}${detail ? " (" + detail + ")" : ""}`);
71047
- }
71146
+ printModules(modules);
71048
71147
  }
71049
71148
  }
71050
71149
  }
@@ -71055,6 +71154,19 @@ async function run3(opts, path19) {
71055
71154
  const workspace = await resolveWorkspace(opts);
71056
71155
  await requireLogin(opts);
71057
71156
  const input = opts.data ? await resolve6(opts.data) : {};
71157
+ if (!opts.data) {
71158
+ try {
71159
+ const flow = await getFlowByPath({
71160
+ workspace: workspace.workspaceId,
71161
+ path: path19
71162
+ });
71163
+ validateRequiredArgs(flow.schema);
71164
+ } catch (e) {
71165
+ if (e.message?.startsWith("Missing required"))
71166
+ throw e;
71167
+ warn(`Could not fetch schema to validate args: ${e.message}`);
71168
+ }
71169
+ }
71058
71170
  const id = await runFlowByPath({
71059
71171
  workspace: workspace.workspaceId,
71060
71172
  path: path19,
@@ -71182,7 +71294,16 @@ async function preview2(opts, flowPath) {
71182
71294
  });
71183
71295
  } catch (e) {
71184
71296
  if (e.body) {
71185
- error(`Flow preview failed: ${JSON.stringify(e.body)}`);
71297
+ if (e.body.result !== undefined) {
71298
+ if (opts.silent) {
71299
+ console.log(JSON.stringify(e.body.result));
71300
+ } else {
71301
+ info(colors.yellow.bold("Flow failed, error handler result:"));
71302
+ info(JSON.stringify(e.body.result, null, 2));
71303
+ }
71304
+ process.exitCode = 1;
71305
+ return;
71306
+ }
71186
71307
  }
71187
71308
  throw e;
71188
71309
  }
@@ -71311,6 +71432,7 @@ var init_flow = __esm(async () => {
71311
71432
  await __promiseAll([
71312
71433
  init_types(),
71313
71434
  init_confirm(),
71435
+ init_utils(),
71314
71436
  init_auth(),
71315
71437
  init_context(),
71316
71438
  init_script(),
@@ -71323,7 +71445,7 @@ var init_flow = __esm(async () => {
71323
71445
  ]);
71324
71446
  import_yaml36 = __toESM(require_dist(), 1);
71325
71447
  alreadySynced3 = [];
71326
- 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(list12).command("list", "list all flows").option("--show-archived", "Enable archived flows in output").option("--json", "Output as JSON (for piping to jq)").action(list12).command("get", "get a flow's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get9).command("push", "push a local flow spec. This overrides any remote versions.").arguments("<file_path:string> <remote_path:string>").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).command("history", "Show version history for a flow").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(history2).command("show-version", "Show a specific version of a flow").arguments("<path:string> <version:string>").option("--json", "Output as JSON (for piping to jq)").action(showVersion);
71448
+ 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(list12).command("list", "list all flows").option("--show-archived", "Enable archived flows in output").option("--json", "Output as JSON (for piping to jq)").action(list12).command("get", "get a flow's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get9).command("push", "push a local flow spec. This overrides any remote versions.").arguments("<file_path:string> <remote_path:string>").option("--message <message:string>", "Deployment message").action(push11).command("run", "run a flow by path.").arguments("<path:string>").option("-d --data <data:string>", "Inputs specified as a JSON string or a file using @<filename> or stdin using @-.").option("-s --silent", "Do not ouput anything other then the final output. Useful for scripting.").action(run3).command("preview", "preview a local flow without deploying it. Runs the flow definition from local files and uses local PathScripts by default.").arguments("<flow_path:string>").option("-d --data <data:string>", "Inputs specified as a JSON string or a file using @<filename> or stdin using @-.").option("-s --silent", "Do not output anything other then the final output. Useful for scripting.").option("--remote", "Use deployed workspace scripts for PathScript steps instead of local files.").action(preview2).command("generate-locks", "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).command("history", "Show version history for a flow").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(history2).command("show-version", "Show a specific version of a flow").arguments("<path:string> <version:string>").option("--json", "Output as JSON (for piping to jq)").action(showVersion);
71327
71449
  flow_default = command21;
71328
71450
  });
71329
71451
 
@@ -79289,6 +79411,7 @@ flow related commands
79289
79411
  - \`flow get <path:string>\` - get a flow's details
79290
79412
  - \`--json\` - Output as JSON (for piping to jq)
79291
79413
  - \`flow push <file_path:string> <remote_path:string>\` - push a local flow spec. This overrides any remote versions.
79414
+ - \`--message <message:string>\` - Deployment message
79292
79415
  - \`flow run <path:string>\` - run a flow by path.
79293
79416
  - \`-d --data <data:string>\` - Inputs specified as a JSON string or a file using @<filename> or stdin using @-.
79294
79417
  - \`-s --silent\` - Do not ouput anything other then the final output. Useful for scripting.
@@ -79490,6 +79613,7 @@ Validate Windmill flow, schedule, and trigger YAML files in a directory
79490
79613
  - \`--json\` - Output results in JSON format
79491
79614
  - \`--fail-on-warn\` - Exit with code 1 when warnings are emitted
79492
79615
  - \`--locks-required\` - Fail if scripts or flow inline scripts that need locks have no locks
79616
+ - \`-w, --watch\` - Watch for file changes and re-lint automatically
79493
79617
 
79494
79618
  ### queues
79495
79619
 
@@ -79558,15 +79682,16 @@ schedule related commands
79558
79682
  script related commands
79559
79683
 
79560
79684
  **Options:**
79561
- - \`--show-archived\` - Enable archived scripts in output
79685
+ - \`--show-archived\` - Show archived scripts instead of active ones
79562
79686
  - \`--json\` - Output as JSON (for piping to jq)
79563
79687
 
79564
79688
  **Subcommands:**
79565
79689
 
79566
79690
  - \`script list\` - list all scripts
79567
- - \`--show-archived\` - Enable archived scripts in output
79691
+ - \`--show-archived\` - Show archived scripts instead of active ones
79568
79692
  - \`--json\` - Output as JSON (for piping to jq)
79569
79693
  - \`script push <path:file>\` - push a local script spec. This overrides any remote versions. Use the script file (.ts, .js, .py, .sh
79694
+ - \`--message <message:string>\` - Deployment message
79570
79695
  - \`script get <path:file>\` - get a script's details
79571
79696
  - \`--json\` - Output as JSON (for piping to jq)
79572
79697
  - \`script show <path:file>\` - show a script's content (alias for get
@@ -81116,7 +81241,7 @@ ${schemaYaml.trim()}
81116
81241
  }
81117
81242
  async function initAction(opts) {
81118
81243
  if (await stat17("wmill.yaml").catch(() => null)) {
81119
- error(colors.red("wmill.yaml already exists"));
81244
+ info("wmill.yaml already exists, skipping config generation");
81120
81245
  } else {
81121
81246
  const { isGitRepository: isGitRepository2, getCurrentGitBranch: getCurrentGitBranch2 } = await Promise.resolve().then(() => (init_git(), exports_git));
81122
81247
  let branchName;
@@ -81530,17 +81655,19 @@ async function list13(opts) {
81530
81655
  let successFilter = opts.success;
81531
81656
  if (opts.failed)
81532
81657
  successFilter = false;
81533
- const jobs = await listJobs({
81658
+ const limit = Math.min(opts.limit ?? 30, 100);
81659
+ const allJobs = await listJobs({
81534
81660
  workspace: workspace.workspaceId,
81535
81661
  scriptPathExact: opts.scriptPath,
81536
81662
  createdBy: opts.createdBy,
81537
81663
  running: opts.running,
81538
81664
  success: successFilter,
81539
- perPage: Math.min(opts.limit ?? 30, 100),
81665
+ perPage: limit,
81540
81666
  jobKinds: opts.jobKinds ?? "script,flow,singlestepflow",
81541
81667
  label: opts.label,
81542
81668
  hasNullParent: opts.all ? undefined : true
81543
81669
  });
81670
+ const jobs = allJobs.slice(0, limit);
81544
81671
  if (opts.json) {
81545
81672
  console.log(JSON.stringify(jobs));
81546
81673
  } else {
@@ -82215,7 +82342,7 @@ var config_default = command35;
82215
82342
 
82216
82343
  // src/main.ts
82217
82344
  await init_context();
82218
- var VERSION = "1.668.1";
82345
+ var VERSION = "1.668.3";
82219
82346
  var command36 = new Command().name("wmill").action(() => info(`Welcome to Windmill CLI ${VERSION}. Use -h for help.`)).description("Windmill CLI").globalOption("--workspace <workspace:string>", "Specify the target workspace. This overrides the default workspace.").globalOption("--debug --verbose", "Show debug/verbose logs").globalOption("--show-diffs", "Show diff informations when syncing (may show sensitive informations)").globalOption("--token <token:string>", "Specify an API token. This will override any stored token.").globalOption("--base-url <baseUrl:string>", "Specify the base URL of the API. If used, --token and --workspace are required and no local remote/workspace already set will be used.").globalOption("--config-dir <configDir:string>", "Specify a custom config directory. Overrides WMILL_CONFIG_DIR environment variable and default ~/.config location.").env("HEADERS <headers:string>", `Specify headers to use for all requests. e.g: "HEADERS='h1: v1, h2: v2'"`).version(VERSION).versionOption(false).command("init", init_default).command("app", app_default).command("flow", flow_default).command("script", script_default).command("workspace", workspace_default).command("resource", resource_default).command("resource-type", resource_type_default).command("user", user_default).command("variable", variable_default).command("hub", hub_default).command("folder", folder_default).command("schedule", schedule_default).command("trigger", trigger_default).command("dev", dev_default2).command("sync", sync_default).command("lint", lint_default).command("gitsync-settings", gitsync_settings_default).command("instance", instance_default).command("worker-groups", worker_groups_default).command("workers", workers_default).command("queues", queues_default).command("dependencies", dependencies_default).command("jobs", jobs_default).command("job", job_default).command("group", group_default).command("audit", audit_default).command("token", token_default).command("generate-metadata", generate_metadata_default).command("docs", docs_default).command("config", config_default).command("version --version", "Show version information").action(async (opts) => {
82220
82347
  console.log("CLI version: " + VERSION);
82221
82348
  try {
@@ -82273,7 +82400,8 @@ async function main2() {
82273
82400
  } catch (e) {
82274
82401
  if (e && typeof e === "object" && "name" in e && e.name === "ApiError") {
82275
82402
  const body = e.body;
82276
- const bodyStr = typeof body === "object" && body !== null ? JSON.stringify(body) : body;
82403
+ let bodyStr = typeof body === "object" && body !== null ? JSON.stringify(body) : String(body ?? "");
82404
+ bodyStr = bodyStr.replace(/\s*[@(]\w+\.rs:\d+[:\d]*\)?/g, "");
82277
82405
  error("Server failed. " + e.statusText + ": " + bodyStr);
82278
82406
  } else if (e instanceof Error) {
82279
82407
  error(e.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "windmill-cli",
3
- "version": "1.668.1",
3
+ "version": "1.668.3",
4
4
  "description": "CLI for Windmill",
5
5
  "license": "Apache 2.0",
6
6
  "type": "module",