windmill-cli 1.670.0 → 1.671.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.
Files changed (2) hide show
  1. package/esm/main.js +206 -28
  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.670.0",
11815
+ VERSION: "1.671.0",
11816
11816
  WITH_CREDENTIALS: true,
11817
11817
  interceptors: {
11818
11818
  request: new Interceptors,
@@ -71178,28 +71178,89 @@ async function run3(opts, path19) {
71178
71178
  path: path19,
71179
71179
  requestBody: input
71180
71180
  });
71181
+ const stepLabels = new Map;
71182
+ try {
71183
+ const initialJob = await getJob({
71184
+ workspace: workspace.workspaceId,
71185
+ id
71186
+ });
71187
+ const rawFlow = initialJob.raw_flow;
71188
+ if (rawFlow?.modules) {
71189
+ for (const mod of rawFlow.modules) {
71190
+ if (mod.id) {
71191
+ const label = mod.summary ? `${mod.id}: ${mod.summary}` : mod.id;
71192
+ stepLabels.set(mod.id, label);
71193
+ }
71194
+ }
71195
+ }
71196
+ } catch {}
71181
71197
  let i = 0;
71198
+ let lastStatus = "";
71182
71199
  while (true) {
71183
71200
  const jobInfo = await getJob({
71184
71201
  workspace: workspace.workspaceId,
71185
71202
  id
71186
71203
  });
71187
- if (jobInfo.flow_status.modules.length <= i) {
71204
+ const isCompleted = jobInfo.type === "CompletedJob";
71205
+ const flowStatus = jobInfo.flow_status;
71206
+ if (flowStatus.modules.length <= i) {
71188
71207
  break;
71189
71208
  }
71190
- const module = jobInfo.flow_status.modules[i];
71191
- if (module.job) {
71192
- if (!opts.silent) {
71193
- info("====== Job " + (i + 1) + " ======");
71209
+ const module = flowStatus.modules[i];
71210
+ if (module.type === "Failure") {
71211
+ if (module.job && !opts.silent) {
71212
+ const label = stepLabels.get(module.id) ?? `Step ${i + 1}`;
71213
+ info("====== " + label + " ======");
71194
71214
  await track_job(workspace.workspaceId, module.job);
71195
71215
  }
71216
+ break;
71217
+ }
71218
+ if (module.job) {
71219
+ const label = stepLabels.get(module.id) ?? `Step ${i + 1}`;
71220
+ const isForLoop = module.flow_jobs !== undefined;
71221
+ if (isForLoop) {
71222
+ let trackedIterations = 0;
71223
+ let forLoopFailed = false;
71224
+ while (true) {
71225
+ const refreshed = await getJob({
71226
+ workspace: workspace.workspaceId,
71227
+ id
71228
+ });
71229
+ const refreshedModule = refreshed.flow_status.modules[i];
71230
+ const flowJobs = refreshedModule.flow_jobs ?? [];
71231
+ while (trackedIterations < flowJobs.length) {
71232
+ if (!opts.silent) {
71233
+ info(`====== ${label} (iteration ${trackedIterations}) ======`);
71234
+ await track_job(workspace.workspaceId, flowJobs[trackedIterations]);
71235
+ }
71236
+ trackedIterations++;
71237
+ }
71238
+ if (refreshedModule.type === "Success" || refreshedModule.type === "Failure") {
71239
+ forLoopFailed = refreshedModule.type === "Failure";
71240
+ break;
71241
+ }
71242
+ await new Promise((resolve8) => setTimeout(resolve8, 200));
71243
+ }
71244
+ if (forLoopFailed)
71245
+ break;
71246
+ } else {
71247
+ if (!opts.silent) {
71248
+ info("====== " + label + " ======");
71249
+ await track_job(workspace.workspaceId, module.job);
71250
+ }
71251
+ }
71196
71252
  } else {
71197
- if (!opts.silent) {
71198
- info(module.type);
71253
+ const status = String(module.type);
71254
+ if (!opts.silent && status !== lastStatus) {
71255
+ info(colors.dim(status));
71256
+ lastStatus = status;
71199
71257
  }
71200
71258
  await new Promise((resolve8, _) => setTimeout(() => resolve8(undefined), 100));
71259
+ if (isCompleted)
71260
+ break;
71201
71261
  continue;
71202
71262
  }
71263
+ lastStatus = "";
71203
71264
  i++;
71204
71265
  }
71205
71266
  const MAX_RETRIES = 600;
@@ -71211,7 +71272,11 @@ async function run3(opts, path19) {
71211
71272
  id
71212
71273
  });
71213
71274
  if (!opts.silent) {
71214
- info(colors.green.underline.bold("Flow ran to completion"));
71275
+ if (jobInfo.success === false) {
71276
+ info(colors.red.underline.bold("Flow failed"));
71277
+ } else {
71278
+ info(colors.green.underline.bold("Flow ran to completion"));
71279
+ }
71215
71280
  info(`
71216
71281
  `);
71217
71282
  }
@@ -79433,7 +79498,7 @@ flow related commands
79433
79498
  - \`flow new <flow_path:string>\` - create a new empty flow
79434
79499
  - \`--summary <summary:string>\` - flow summary
79435
79500
  - \`--description <description:string>\` - flow description
79436
- - \`flow bootstrap <flow_path:string>\` - create a new empty flow (alias for new
79501
+ - \`flow bootstrap <flow_path:string>\` - create a new empty flow (alias for new)
79437
79502
  - \`--summary <summary:string>\` - flow summary
79438
79503
  - \`--description <description:string>\` - flow description
79439
79504
  - \`flow history <path:string>\` - Show version history for a flow
@@ -79586,10 +79651,10 @@ Manage jobs (list, inspect, cancel)
79586
79651
  **Subcommands:**
79587
79652
 
79588
79653
  - \`job list\` - List recent jobs
79589
- - \`job get <id:string>\` - Get job details and result
79654
+ - \`job get <id:string>\` - Get job details. For flows: shows step tree with sub-job IDs
79590
79655
  - \`--json\` - Output as JSON (for piping to jq)
79591
- - \`job result <id:string>\` - Get the result of a completed job (machine-friendly
79592
- - \`job logs <id:string>\` - Get job logs
79656
+ - \`job result <id:string>\` - Get the result of a completed job (machine-friendly)
79657
+ - \`job logs <id:string>\` - Get job logs. For flows: aggregates all step logs
79593
79658
  - \`job cancel <id:string>\` - Cancel a running or queued job
79594
79659
  - \`--reason <reason:string>\` - Reason for cancellation
79595
79660
 
@@ -79696,11 +79761,11 @@ script related commands
79696
79761
  - \`script list\` - list all scripts
79697
79762
  - \`--show-archived\` - Show archived scripts instead of active ones
79698
79763
  - \`--json\` - Output as JSON (for piping to jq)
79699
- - \`script push <path:file>\` - push a local script spec. This overrides any remote versions. Use the script file (.ts, .js, .py, .sh
79764
+ - \`script push <path:file>\` - push a local script spec. This overrides any remote versions. Use the script file (.ts, .js, .py, .sh)
79700
79765
  - \`--message <message:string>\` - Deployment message
79701
79766
  - \`script get <path:file>\` - get a script's details
79702
79767
  - \`--json\` - Output as JSON (for piping to jq)
79703
- - \`script show <path:file>\` - show a script's content (alias for get
79768
+ - \`script show <path:file>\` - show a script's content (alias for get)
79704
79769
  - \`script run <path:file>\` - run a script by path
79705
79770
  - \`-d --data <data:file>\` - Inputs specified as a JSON string or a file using @<filename> or stdin using @-.
79706
79771
  - \`-s --silent\` - Do not output anything other then the final output. Useful for scripting.
@@ -79710,10 +79775,10 @@ script related commands
79710
79775
  - \`script new <path:file> <language:string>\` - create a new script
79711
79776
  - \`--summary <summary:string>\` - script summary
79712
79777
  - \`--description <description:string>\` - script description
79713
- - \`script bootstrap <path:file> <language:string>\` - create a new script (alias for new
79778
+ - \`script bootstrap <path:file> <language:string>\` - create a new script (alias for new)
79714
79779
  - \`--summary <summary:string>\` - script summary
79715
79780
  - \`--description <description:string>\` - script description
79716
- - \`script generate-metadata [script:file]\` - re-generate the metadata file updating the lock and the script schema (for flows, use \`wmill flow generate-locks\`
79781
+ - \`script generate-metadata [script:file]\` - re-generate the metadata file updating the lock and the script schema (for flows, use \`wmill flow generate-locks\`)
79717
79782
  - \`--yes\` - Skip confirmation prompt
79718
79783
  - \`--dry-run\` - Perform a dry run without making changes
79719
79784
  - \`--lock-only\` - re-generate only the lock
@@ -81675,6 +81740,8 @@ async function list13(opts) {
81675
81740
  let successFilter = opts.success;
81676
81741
  if (opts.failed)
81677
81742
  successFilter = false;
81743
+ const showSubJobs = opts.all || opts.parent;
81744
+ const defaultJobKinds = showSubJobs ? "script,flow,singlestepflow,flowscript,flowdependencies" : "script,flow,singlestepflow";
81678
81745
  const limit = Math.min(opts.limit ?? 30, 100);
81679
81746
  const allJobs = await listJobs({
81680
81747
  workspace: workspace.workspaceId,
@@ -81683,9 +81750,11 @@ async function list13(opts) {
81683
81750
  running: opts.running,
81684
81751
  success: successFilter,
81685
81752
  perPage: limit,
81686
- jobKinds: opts.jobKinds ?? "script,flow,singlestepflow",
81753
+ jobKinds: opts.jobKinds ?? defaultJobKinds,
81687
81754
  label: opts.label,
81688
- hasNullParent: opts.all ? undefined : true
81755
+ hasNullParent: showSubJobs ? undefined : true,
81756
+ parentJob: opts.parent,
81757
+ isFlowStep: opts.isFlowStep
81689
81758
  });
81690
81759
  const jobs = allJobs.slice(0, limit);
81691
81760
  if (opts.json) {
@@ -81707,6 +81776,64 @@ async function list13(opts) {
81707
81776
  Showing ${jobs.length} job(s). Use --limit to show more.`);
81708
81777
  }
81709
81778
  }
81779
+ function getModuleStatusIcon(type, success) {
81780
+ switch (type) {
81781
+ case "Success":
81782
+ return colors.green("✓");
81783
+ case "Failure":
81784
+ return colors.red("✗");
81785
+ case "InProgress":
81786
+ return colors.blue("▶");
81787
+ case "WaitingForPriorSteps":
81788
+ return colors.dim("○");
81789
+ case "WaitingForEvents":
81790
+ return colors.yellow("⏳");
81791
+ default:
81792
+ return colors.dim("·");
81793
+ }
81794
+ }
81795
+ function formatFlowSteps(flowStatus, rawFlow) {
81796
+ const modules = flowStatus?.modules ?? [];
81797
+ const rawModules = rawFlow?.modules ?? [];
81798
+ const summaryMap = new Map;
81799
+ for (const mod of rawModules) {
81800
+ if (mod.id && mod.summary) {
81801
+ summaryMap.set(mod.id, mod.summary);
81802
+ }
81803
+ }
81804
+ console.log(colors.bold(`
81805
+ Steps:`));
81806
+ for (const mod of modules) {
81807
+ const icon = getModuleStatusIcon(mod.type);
81808
+ const summary = summaryMap.get(mod.id) ?? "";
81809
+ const label = summary ? `${mod.id}: ${summary}` : mod.id;
81810
+ const jobId = mod.job ? colors.dim(mod.job) : "";
81811
+ const flowJobsDuration = mod.flow_jobs_duration;
81812
+ const flowJobs = mod.flow_jobs;
81813
+ if (flowJobs && flowJobs.length > 0) {
81814
+ const totalMs = flowJobsDuration?.duration_ms ? flowJobsDuration.duration_ms.reduce((a, b) => a + b, 0) : undefined;
81815
+ const durationStr = totalMs != null ? colors.dim(formatDuration(totalMs)) : "";
81816
+ console.log(` ${icon} ${label} ${durationStr}`);
81817
+ const flowJobsSuccess = mod.flow_jobs_success ?? [];
81818
+ const durationMs = flowJobsDuration?.duration_ms ?? [];
81819
+ for (let iter = 0;iter < flowJobs.length; iter++) {
81820
+ const iterSuccess = flowJobsSuccess[iter];
81821
+ const iterIcon = iterSuccess === true ? colors.green("✓") : iterSuccess === false ? colors.red("✗") : colors.dim("·");
81822
+ const iterDur = durationMs[iter] != null ? colors.dim(formatDuration(durationMs[iter])) : "";
81823
+ const iterJobId = colors.dim(flowJobs[iter]);
81824
+ console.log(` ${iterIcon} iteration ${iter} ${iterJobId} ${iterDur}`);
81825
+ }
81826
+ } else {
81827
+ const durationStr = mod.duration_ms != null ? colors.dim(formatDuration(mod.duration_ms)) : "";
81828
+ console.log(` ${icon} ${label} ${jobId} ${durationStr}`);
81829
+ }
81830
+ }
81831
+ const hasJobs = modules.some((m) => m.job);
81832
+ if (hasJobs) {
81833
+ console.log(colors.dim(`
81834
+ Use 'wmill job logs <job-id>' for step logs`));
81835
+ }
81836
+ }
81710
81837
  async function get10(opts, id) {
81711
81838
  if (opts.json)
81712
81839
  setSilent(true);
@@ -81736,8 +81863,13 @@ async function get10(opts, id) {
81736
81863
  if (j.schedule_path) {
81737
81864
  console.log(colors.bold("Schedule:") + " " + j.schedule_path);
81738
81865
  }
81866
+ const isFlow = j.job_kind === "flow" || j.job_kind === "flowpreview";
81867
+ if (isFlow && j.flow_status) {
81868
+ formatFlowSteps(j.flow_status, j.raw_flow);
81869
+ }
81739
81870
  if (j.result !== undefined) {
81740
- console.log(colors.bold("Result:"));
81871
+ console.log(colors.bold(`
81872
+ Result:`));
81741
81873
  console.log(JSON.stringify(j.result, null, 2));
81742
81874
  }
81743
81875
  }
@@ -81762,10 +81894,55 @@ async function logs(opts, id) {
81762
81894
  workspace: workspace.workspaceId,
81763
81895
  id
81764
81896
  });
81765
- const jobKind = job.job_kind;
81766
- if (jobKind === "flow" || jobKind === "flowpreview") {
81767
- info(colors.yellow(`Flow jobs don't have direct logs. Each step runs as a separate job.
81768
- ` + "Use 'wmill job list --all' to see sub-jobs, then 'wmill job logs <sub-job-id>' for individual step logs."));
81897
+ const j = job;
81898
+ const jobKind = j.job_kind;
81899
+ if ((jobKind === "flow" || jobKind === "flowpreview") && j.flow_status?.modules) {
81900
+ const modules = j.flow_status.modules;
81901
+ const rawModules = j.raw_flow?.modules ?? [];
81902
+ const summaryMap = new Map;
81903
+ for (const mod of rawModules) {
81904
+ if (mod.id && mod.summary)
81905
+ summaryMap.set(mod.id, mod.summary);
81906
+ }
81907
+ const stripHint = (text) => text.replace(/^to remove ansi colors.*\n?/gm, "");
81908
+ let hasLogs = false;
81909
+ for (const mod of modules) {
81910
+ const summary = summaryMap.get(mod.id) ?? "";
81911
+ const label = summary ? `${mod.id}: ${summary}` : mod.id;
81912
+ const flowJobs = mod.flow_jobs;
81913
+ if (flowJobs && flowJobs.length > 0) {
81914
+ for (let iter = 0;iter < flowJobs.length; iter++) {
81915
+ try {
81916
+ const stepLogs = await getJobLogs({
81917
+ workspace: workspace.workspaceId,
81918
+ id: flowJobs[iter]
81919
+ });
81920
+ if (stepLogs) {
81921
+ console.log(colors.bold.cyan(`
81922
+ ====== ${label} (iteration ${iter}) ======`));
81923
+ console.log(stripHint(stepLogs));
81924
+ hasLogs = true;
81925
+ }
81926
+ } catch {}
81927
+ }
81928
+ } else if (mod.job) {
81929
+ try {
81930
+ const stepLogs = await getJobLogs({
81931
+ workspace: workspace.workspaceId,
81932
+ id: mod.job
81933
+ });
81934
+ if (stepLogs) {
81935
+ console.log(colors.bold.cyan(`
81936
+ ====== ${label} ======`));
81937
+ console.log(stripHint(stepLogs));
81938
+ hasLogs = true;
81939
+ }
81940
+ } catch {}
81941
+ }
81942
+ }
81943
+ if (!hasLogs) {
81944
+ info("No logs available for this flow's steps.");
81945
+ }
81769
81946
  return;
81770
81947
  }
81771
81948
  } catch {}
@@ -81776,8 +81953,9 @@ async function logs(opts, id) {
81776
81953
  if (jobLogs == null || jobLogs === "") {
81777
81954
  info("No logs available for this job.");
81778
81955
  } else {
81956
+ const stripped = jobLogs.replace(/^to remove ansi colors.*\n?/gm, "");
81779
81957
  console.error("to remove ansi colors, use: | sed 's/\\x1B\\[[0-9;]\\{1,\\}[A-Za-z]//g'");
81780
- console.log(jobLogs);
81958
+ console.log(stripped);
81781
81959
  }
81782
81960
  }
81783
81961
  async function cancel(opts, id) {
@@ -81793,8 +81971,8 @@ async function cancel(opts, id) {
81793
81971
  });
81794
81972
  info(colors.green(`Job ${id} canceled.`));
81795
81973
  }
81796
- var listOptions = (cmd) => cmd.option("--json", "Output as JSON (for piping to jq)").option("--script-path <scriptPath:string>", "Filter by exact script/flow path").option("--created-by <createdBy:string>", "Filter by creator username").option("--running", "Show only running jobs").option("--failed", "Show only failed jobs").option("--success <success:boolean>", "Filter by success status (true/false)").option("--limit <limit:number>", "Number of jobs to return (default 30, max 100)").option("--job-kinds <jobKinds:string>", "Filter by job kinds (default: script,flow,singlestepflow)").option("--label <label:string>", "Filter by job label").option("--all", "Include sub-jobs (flow steps). By default only top-level jobs are shown");
81797
- var command29 = listOptions(new Command().description("Manage jobs (list, inspect, cancel)")).action(list13).command("list", listOptions(new Command().description("List recent jobs"))).action(list13).command("get", "Get job details and result").arguments("<id:string>").option("--json", "Output as JSON (for piping to jq)").action(get10).command("result", "Get the result of a completed job (machine-friendly)").arguments("<id:string>").action(result).command("logs", "Get job logs").arguments("<id:string>").action(logs).command("cancel", "Cancel a running or queued job").arguments("<id:string>").option("--reason <reason:string>", "Reason for cancellation").action(cancel);
81974
+ var listOptions = (cmd) => cmd.option("--json", "Output as JSON (for piping to jq)").option("--script-path <scriptPath:string>", "Filter by exact script/flow path").option("--created-by <createdBy:string>", "Filter by creator username").option("--running", "Show only running jobs").option("--failed", "Show only failed jobs").option("--success <success:boolean>", "Filter by success status (true/false)").option("--limit <limit:number>", "Number of jobs to return (default 30, max 100)").option("--job-kinds <jobKinds:string>", "Filter by job kinds (default: script,flow,singlestepflow)").option("--label <label:string>", "Filter by job label").option("--all", "Include sub-jobs (flow steps). By default only top-level jobs are shown").option("--parent <parent:string>", "Filter by parent job ID (show sub-jobs of a specific flow)").option("--is-flow-step", "Show only flow step jobs");
81975
+ var command29 = listOptions(new Command().description("Manage jobs (list, inspect, cancel)")).action(list13).command("list", listOptions(new Command().description("List recent jobs"))).action(list13).command("get", "Get job details. For flows: shows step tree with sub-job IDs").arguments("<id:string>").option("--json", "Output as JSON (for piping to jq)").action(get10).command("result", "Get the result of a completed job (machine-friendly)").arguments("<id:string>").action(result).command("logs", "Get job logs. For flows: aggregates all step logs").arguments("<id:string>").action(logs).command("cancel", "Cancel a running or queued job").arguments("<id:string>").option("--reason <reason:string>", "Reason for cancellation").action(cancel);
81798
81976
  var job_default = command29;
81799
81977
 
81800
81978
  // src/commands/group/group.ts
@@ -82362,7 +82540,7 @@ var config_default = command35;
82362
82540
 
82363
82541
  // src/main.ts
82364
82542
  await init_context();
82365
- var VERSION = "1.670.0";
82543
+ var VERSION = "1.671.0";
82366
82544
  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) => {
82367
82545
  console.log("CLI version: " + VERSION);
82368
82546
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "windmill-cli",
3
- "version": "1.670.0",
3
+ "version": "1.671.0",
4
4
  "description": "CLI for Windmill",
5
5
  "license": "Apache 2.0",
6
6
  "type": "module",