windmill-cli 1.666.0 → 1.668.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 +1718 -252
  2. package/package.json +1 -1
package/esm/main.js CHANGED
@@ -4244,6 +4244,7 @@ var exports_log = {};
4244
4244
  __export(exports_log, {
4245
4245
  warn: () => warn,
4246
4246
  setup: () => setup,
4247
+ setSilent: () => setSilent,
4247
4248
  info: () => info,
4248
4249
  error: () => error,
4249
4250
  debug: () => debug
@@ -4251,20 +4252,27 @@ __export(exports_log, {
4251
4252
  function setup(level) {
4252
4253
  logLevel = level;
4253
4254
  }
4255
+ function setSilent(silent) {
4256
+ silentMode = silent;
4257
+ }
4254
4258
  function debug(msg) {
4255
4259
  if (levels[logLevel] <= levels.DEBUG)
4256
4260
  console.log(`\x1B[90m${String(msg)}\x1B[39m`);
4257
4261
  }
4258
4262
  function info(msg) {
4263
+ if (silentMode)
4264
+ return;
4259
4265
  console.log(`\x1B[34m${String(msg)}\x1B[39m`);
4260
4266
  }
4261
4267
  function warn(msg) {
4268
+ if (silentMode)
4269
+ return;
4262
4270
  console.log(`\x1B[33m${String(msg)}\x1B[39m`);
4263
4271
  }
4264
4272
  function error(msg) {
4265
- console.log(`\x1B[31m${String(msg)}\x1B[39m`);
4273
+ console.error(`\x1B[31m${String(msg)}\x1B[39m`);
4266
4274
  }
4267
- var logLevel = "INFO", levels;
4275
+ var logLevel = "INFO", silentMode = false, levels;
4268
4276
  var init_log = __esm(() => {
4269
4277
  levels = { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3 };
4270
4278
  });
@@ -11618,21 +11626,40 @@ var require_dist = __commonJS((exports) => {
11618
11626
  import { readFile } from "node:fs/promises";
11619
11627
  async function yamlParseFile(path, options = {}) {
11620
11628
  try {
11621
- return import_yaml.parse(await readFile(path, "utf-8"), options);
11629
+ return import_yaml.parse(await readFile(path, "utf-8"), {
11630
+ ...options,
11631
+ customTags: [...WINDMILL_CUSTOM_TAGS, ...options.customTags ?? []]
11632
+ });
11622
11633
  } catch (e) {
11623
11634
  throw new Error(`Error parsing yaml ${path}`, { cause: e });
11624
11635
  }
11625
11636
  }
11626
11637
  function yamlParseContent(path, content, options = {}) {
11627
11638
  try {
11628
- return import_yaml.parse(content, options);
11639
+ return import_yaml.parse(content, {
11640
+ ...options,
11641
+ customTags: [...WINDMILL_CUSTOM_TAGS, ...options.customTags ?? []]
11642
+ });
11629
11643
  } catch (e) {
11630
11644
  throw new Error(`Error parsing yaml ${path}`, { cause: e });
11631
11645
  }
11632
11646
  }
11633
- var import_yaml;
11647
+ var import_yaml, inlineTag, inlineFilesetTag, WINDMILL_CUSTOM_TAGS;
11634
11648
  var init_yaml = __esm(() => {
11635
11649
  import_yaml = __toESM(require_dist(), 1);
11650
+ inlineTag = {
11651
+ tag: "!inline",
11652
+ resolve(value) {
11653
+ return "!inline " + value;
11654
+ }
11655
+ };
11656
+ inlineFilesetTag = {
11657
+ tag: "!inline_fileset",
11658
+ resolve(value) {
11659
+ return "!inline_fileset " + value;
11660
+ }
11661
+ };
11662
+ WINDMILL_CUSTOM_TAGS = [inlineTag, inlineFilesetTag];
11636
11663
  });
11637
11664
 
11638
11665
  // gen/core/ApiError.ts
@@ -11785,7 +11812,7 @@ var init_OpenAPI = __esm(() => {
11785
11812
  PASSWORD: undefined,
11786
11813
  TOKEN: getEnv2("WM_TOKEN"),
11787
11814
  USERNAME: undefined,
11788
- VERSION: "1.666.0",
11815
+ VERSION: "1.668.0",
11789
11816
  WITH_CREDENTIALS: true,
11790
11817
  interceptors: {
11791
11818
  request: new Interceptors,
@@ -12344,6 +12371,7 @@ __export(exports_services_gen, {
12344
12371
  importQueuedJobs: () => importQueuedJobs,
12345
12372
  importInstallation: () => importInstallation,
12346
12373
  importCompletedJobs: () => importCompletedJobs,
12374
+ impersonateServiceAccount: () => impersonateServiceAccount,
12347
12375
  globalWhoami: () => globalWhoami,
12348
12376
  globalUsersOverwrite: () => globalUsersOverwrite,
12349
12377
  globalUsersExport: () => globalUsersExport,
@@ -12521,6 +12549,7 @@ __export(exports_services_gen, {
12521
12549
  exportInstanceGroups: () => exportInstanceGroups,
12522
12550
  exportInstallation: () => exportInstallation,
12523
12551
  exportCompletedJobs: () => exportCompletedJobs,
12552
+ exitImpersonation: () => exitImpersonation,
12524
12553
  existsWorkspace: () => existsWorkspace,
12525
12554
  existsWorkersWithTags: () => existsWorkersWithTags,
12526
12555
  existsWebsocketTrigger: () => existsWebsocketTrigger,
@@ -12635,6 +12664,7 @@ __export(exports_services_gen, {
12635
12664
  createToken: () => createToken,
12636
12665
  createTemplateScript: () => createTemplateScript,
12637
12666
  createSqsTrigger: () => createSqsTrigger,
12667
+ createServiceAccount: () => createServiceAccount,
12638
12668
  createScript: () => createScript,
12639
12669
  createSchedule: () => createSchedule,
12640
12670
  createResourceType: () => createResourceType,
@@ -13374,6 +13404,36 @@ var backendVersion = () => {
13374
13404
  body: data2.requestBody,
13375
13405
  mediaType: "application/json"
13376
13406
  });
13407
+ }, createServiceAccount = (data2) => {
13408
+ return request(OpenAPI, {
13409
+ method: "POST",
13410
+ url: "/w/{workspace}/workspaces/create_service_account",
13411
+ path: {
13412
+ workspace: data2.workspace
13413
+ },
13414
+ body: data2.requestBody,
13415
+ mediaType: "application/json"
13416
+ });
13417
+ }, impersonateServiceAccount = (data2) => {
13418
+ return request(OpenAPI, {
13419
+ method: "POST",
13420
+ url: "/w/{workspace}/users/impersonate_service_account",
13421
+ path: {
13422
+ workspace: data2.workspace
13423
+ },
13424
+ body: data2.requestBody,
13425
+ mediaType: "application/json"
13426
+ });
13427
+ }, exitImpersonation = (data2) => {
13428
+ return request(OpenAPI, {
13429
+ method: "POST",
13430
+ url: "/w/{workspace}/users/exit_impersonation",
13431
+ path: {
13432
+ workspace: data2.workspace
13433
+ },
13434
+ body: data2.requestBody,
13435
+ mediaType: "application/json"
13436
+ });
13377
13437
  }, deleteInvite = (data2) => {
13378
13438
  return request(OpenAPI, {
13379
13439
  method: "POST",
@@ -19451,6 +19511,10 @@ var init_gen = __esm(() => {
19451
19511
  });
19452
19512
 
19453
19513
  // src/core/client.ts
19514
+ var exports_client = {};
19515
+ __export(exports_client, {
19516
+ setClient: () => setClient
19517
+ });
19454
19518
  function setClient(token, baseUrl2) {
19455
19519
  if (baseUrl2 === undefined) {
19456
19520
  baseUrl2 = process.env["BASE_INTERNAL_URL"] ?? process.env["BASE_URL"] ?? "http://localhost:8000";
@@ -24449,6 +24513,12 @@ function isRawAppMetadataFile(p) {
24449
24513
  function isRawAppFolderMetadataFile(p) {
24450
24514
  return p.endsWith(getMetadataPathSuffix("raw_app", "yaml")) || p.endsWith(getMetadataPathSuffix("raw_app", "json"));
24451
24515
  }
24516
+ function isAppFolderMetadataFile(p) {
24517
+ return p.endsWith(getMetadataPathSuffix("app", "yaml")) || p.endsWith(getMetadataPathSuffix("app", "json"));
24518
+ }
24519
+ function isFlowFolderMetadataFile(p) {
24520
+ return p.endsWith(getMetadataPathSuffix("flow", "yaml")) || p.endsWith(getMetadataPathSuffix("flow", "json"));
24521
+ }
24452
24522
  function getModuleFolderSuffix() {
24453
24523
  return MODULE_SUFFIX;
24454
24524
  }
@@ -24704,6 +24774,9 @@ function toCamel(s) {
24704
24774
  function capitalize(str) {
24705
24775
  return str.charAt(0).toUpperCase() + str.slice(1);
24706
24776
  }
24777
+ function formatTimestamp(ts) {
24778
+ return new Date(ts).toISOString().replace("T", " ").substring(0, 19);
24779
+ }
24707
24780
  var isWin = undefined;
24708
24781
  var init_utils = __esm(async () => {
24709
24782
  init_colors2();
@@ -24972,28 +25045,46 @@ async function createWorkspaceFork2(opts, workspaceName, workspaceId = undefined
24972
25045
  }
24973
25046
  const newBranchName = `${WM_FORK_PREFIX}/${clonedBranchName}/${workspaceId}`;
24974
25047
  info(`Created forked workspace ${trueWorkspaceId}. To start contributing to your fork, create and push edits to the branch \`${newBranchName}\` by using the command:
24975
-
25048
+
24976
25049
  ` + colors.white(`git checkout -b ${newBranchName}`) + `
24977
-
24978
- When doing operations on the forked workspace, it will use the remote setup in gitBranches for the branch it was forked from.`);
25050
+
25051
+ When doing operations on the forked workspace, it will use the remote setup in gitBranches for the branch it was forked from.
25052
+
25053
+ To merge changes back to the parent workspace, you can:
25054
+ - Use the Merge UI from the forked workspace home page
25055
+ - Deploy individual items via the Deploy to staging/prod UI
25056
+ - Use git: ` + colors.white(`git checkout ${clonedBranchName} && git merge ${newBranchName} && wmill sync push`) + `
25057
+ See: https://www.windmill.dev/docs/advanced/workspace_forks`);
24979
25058
  }
24980
25059
  async function deleteWorkspaceFork(opts, name) {
25060
+ let forkWorkspaceId;
25061
+ let token;
25062
+ let remote;
25063
+ let hasLocalProfile = false;
24981
25064
  const orgWorkspaces = await allWorkspaces(opts.configDir);
24982
25065
  const idxOf = orgWorkspaces.findIndex((x) => x.name === name);
24983
- if (idxOf === -1) {
24984
- info(colors.red.bold(`! Workspace profile ${name} does not exist locally`));
24985
- info("available workspace profiles:");
24986
- await list(opts);
24987
- return;
24988
- }
24989
- const workspace = orgWorkspaces[idxOf];
24990
- if (!workspace.workspaceId.startsWith(WM_FORK_PREFIX)) {
24991
- throw new Error(`You can only delete forked workspaces where the workspace id starts with \`${WM_FORK_PREFIX}.\` Failed while attempting to delete \`${workspace.workspaceId}\``);
25066
+ if (idxOf !== -1) {
25067
+ const workspace = orgWorkspaces[idxOf];
25068
+ if (!workspace.workspaceId.startsWith(WM_FORK_PREFIX)) {
25069
+ throw new Error(`You can only delete forked workspaces where the workspace id starts with \`${WM_FORK_PREFIX}.\` Failed while attempting to delete \`${workspace.workspaceId}\``);
25070
+ }
25071
+ forkWorkspaceId = workspace.workspaceId;
25072
+ token = workspace.token;
25073
+ remote = workspace.remote;
25074
+ hasLocalProfile = true;
25075
+ } else {
25076
+ const parentWorkspace = await tryResolveBranchWorkspace(opts);
25077
+ if (!parentWorkspace) {
25078
+ throw new Error("Could not resolve parent workspace. Make sure you are in a git repo with gitBranches configured in wmill.yaml, or create a local workspace profile for the fork.");
25079
+ }
25080
+ forkWorkspaceId = name.startsWith(`${WM_FORK_PREFIX}-`) ? name : `${WM_FORK_PREFIX}-${name}`;
25081
+ token = parentWorkspace.token;
25082
+ remote = parentWorkspace.remote;
24992
25083
  }
24993
25084
  if (!opts.yes) {
24994
25085
  const { Select: Select2 } = await init_select().then(() => exports_select);
24995
25086
  const choice = await Select2.prompt({
24996
- message: `Are you sure you want to delete the forked workspace with id: \`${workspace.workspaceId}\`? This action will delete the workspace `,
25087
+ message: `Are you sure you want to delete the forked workspace \`${forkWorkspaceId}\`?`,
24997
25088
  options: [
24998
25089
  { name: "Yes", value: "confirm" },
24999
25090
  { name: "No", value: "cancel" }
@@ -25004,14 +25095,15 @@ async function deleteWorkspaceFork(opts, name) {
25004
25095
  return;
25005
25096
  }
25006
25097
  }
25007
- const remote = workspace.remote;
25008
- setClient(workspace.token, remote.endsWith("/") ? remote.substring(0, remote.length - 1) : remote);
25098
+ setClient(token, remote.endsWith("/") ? remote.substring(0, remote.length - 1) : remote);
25009
25099
  const result = await deleteWorkspace({
25010
- workspace: workspace.workspaceId
25100
+ workspace: forkWorkspaceId
25011
25101
  });
25012
- info(colors.green(`✅ Forked workspace '${workspace.workspaceId}' deleted successfully!
25102
+ info(colors.green(`✅ Forked workspace '${forkWorkspaceId}' deleted successfully!
25013
25103
  ${result}`));
25014
- await removeWorkspace(name, false, opts);
25104
+ if (hasLocalProfile) {
25105
+ await removeWorkspace(name, false, opts);
25106
+ }
25015
25107
  }
25016
25108
  var init_fork = __esm(async () => {
25017
25109
  init_colors2();
@@ -25090,11 +25182,14 @@ function findWmillYaml() {
25090
25182
  function getWmillYamlPath() {
25091
25183
  return findWmillYaml();
25092
25184
  }
25093
- async function readConfigFile() {
25185
+ async function readConfigFile(opts) {
25186
+ const warnIfMissing = opts?.warnIfMissing ?? true;
25094
25187
  try {
25095
25188
  const wmillYamlPath = findWmillYaml();
25096
25189
  if (!wmillYamlPath) {
25097
- warn("No wmill.yaml found. Use 'wmill init' to bootstrap it.");
25190
+ if (warnIfMissing) {
25191
+ warn("No wmill.yaml found. Use 'wmill init' to bootstrap it.");
25192
+ }
25098
25193
  return {};
25099
25194
  }
25100
25195
  const conf = await yamlParseFile(wmillYamlPath);
@@ -25324,7 +25419,7 @@ var exports_workspace = {};
25324
25419
  __export(exports_workspace, {
25325
25420
  setActiveWorkspace: () => setActiveWorkspace,
25326
25421
  removeWorkspace: () => removeWorkspace,
25327
- list: () => list,
25422
+ list: () => list2,
25328
25423
  getWorkspaceByName: () => getWorkspaceByName,
25329
25424
  getActiveWorkspaceOrFallback: () => getActiveWorkspaceOrFallback,
25330
25425
  getActiveWorkspace: () => getActiveWorkspace,
@@ -25378,7 +25473,7 @@ async function getWorkspaceByName(workspaceName, configDirOverride) {
25378
25473
  }
25379
25474
  return;
25380
25475
  }
25381
- async function list(opts) {
25476
+ async function list2(opts) {
25382
25477
  const workspaces = await allWorkspaces(opts.configDir);
25383
25478
  const activeName = await getActiveWorkspaceName(opts);
25384
25479
  new Table2().header(["name", "remote", "workspace id"]).padding(2).border(true).body(workspaces.map((x) => {
@@ -25481,8 +25576,12 @@ async function add(opts, workspaceName, workspaceId, remote) {
25481
25576
  info(colors.red.bold(`! Workspace at id ${workspaceId} on ${remote} does not exist. Re-run with --create to create it. Aborting.`));
25482
25577
  info("On that instance and with those credentials, the workspaces that you can access are:");
25483
25578
  const workspaces = await listWorkspaces();
25484
- for (const workspace of workspaces) {
25485
- info(`- ${workspace.id} (name: ${workspace.name})`);
25579
+ if (workspaces.length === 0) {
25580
+ info(" (none)");
25581
+ } else {
25582
+ for (const workspace of workspaces) {
25583
+ info(`- ${workspace.id} (name: ${workspace.name})`);
25584
+ }
25486
25585
  }
25487
25586
  process10.exit(1);
25488
25587
  }
@@ -25550,7 +25649,7 @@ async function removeWorkspace(name, silent, opts) {
25550
25649
  if (!silent) {
25551
25650
  info(colors.red.bold(`! Workspace profile ${name} does not exist locally`));
25552
25651
  info("available workspace profiles:");
25553
- await list(opts);
25652
+ await list2(opts);
25554
25653
  }
25555
25654
  return;
25556
25655
  }
@@ -25573,21 +25672,67 @@ async function whoami2(_opts) {
25573
25672
  const whoamiInfo = await globalWhoami();
25574
25673
  info(JSON.stringify(whoamiInfo, null, 2));
25575
25674
  const activeName = await getActiveWorkspaceName(_opts);
25576
- info("Active: " + colors.green.bold(activeName || "none"));
25675
+ const { getCurrentGitBranch: getCurrentGitBranch2, getOriginalBranchForWorkspaceForks: getOriginalBranchForWorkspaceForks2 } = await Promise.resolve().then(() => (init_git(), exports_git));
25676
+ const branch = getCurrentGitBranch2();
25677
+ const originalBranch = branch ? getOriginalBranchForWorkspaceForks2(branch) : null;
25678
+ if (originalBranch) {
25679
+ const { resolveWorkspace } = await init_context().then(() => exports_context);
25680
+ try {
25681
+ const ws = await resolveWorkspace(_opts);
25682
+ info("Active: " + colors.green.bold(`${activeName || "none"}`) + ` (fork workspace: ${ws.workspaceId})`);
25683
+ } catch {
25684
+ info("Active: " + colors.green.bold(activeName || "none") + " (fork branch)");
25685
+ }
25686
+ } else {
25687
+ info("Active: " + colors.green.bold(activeName || "none"));
25688
+ }
25577
25689
  }
25578
25690
  async function listRemote(_opts) {
25691
+ let remote;
25692
+ if (_opts.baseUrl && _opts.token && !_opts.workspace) {
25693
+ const { setClient: setClient2 } = await Promise.resolve().then(() => (init_client(), exports_client));
25694
+ remote = new URL(_opts.baseUrl).toString();
25695
+ setClient2(_opts.token, remote.replace(/\/$/, ""));
25696
+ } else {
25697
+ const { resolveWorkspace } = await init_context().then(() => exports_context);
25698
+ const workspace = await resolveWorkspace(_opts);
25699
+ await requireLogin(_opts);
25700
+ remote = workspace.remote;
25701
+ }
25702
+ const userWorkspaces = await listUserWorkspaces();
25703
+ const hasForks = userWorkspaces.workspaces.some((x) => x.parent_workspace_id);
25704
+ const headers = hasForks ? ["id", "name", "username", "fork of", "disabled"] : ["id", "name", "username", "disabled"];
25705
+ new Table2().header(headers).padding(2).border(true).body(userWorkspaces.workspaces.map((x) => {
25706
+ const row = [
25707
+ x.id,
25708
+ x.name,
25709
+ x.username
25710
+ ];
25711
+ if (hasForks)
25712
+ row.push(x.parent_workspace_id ?? "-");
25713
+ row.push(x.disabled ? colors.red("true") : "false");
25714
+ return row;
25715
+ })).render();
25716
+ info(`Remote: ${colors.bold(remote)}`);
25717
+ info(`Logged in as: ${colors.green.bold(userWorkspaces.email)}`);
25718
+ }
25719
+ async function listForks(_opts) {
25579
25720
  const { resolveWorkspace } = await init_context().then(() => exports_context);
25580
25721
  const workspace = await resolveWorkspace(_opts);
25581
25722
  await requireLogin(_opts);
25582
25723
  const userWorkspaces = await listUserWorkspaces();
25583
- new Table2().header(["id", "name", "username", "disabled"]).padding(2).border(true).body(userWorkspaces.workspaces.map((x) => [
25724
+ const forks = userWorkspaces.workspaces.filter((w) => w.parent_workspace_id);
25725
+ if (forks.length === 0) {
25726
+ info("No forked workspaces found.");
25727
+ return;
25728
+ }
25729
+ new Table2().header(["id", "name", "fork of", "username"]).padding(2).border(true).body(forks.map((x) => [
25584
25730
  x.id,
25585
25731
  x.name,
25586
- x.username,
25587
- x.disabled ? colors.red("true") : "false"
25732
+ x.parent_workspace_id ?? "",
25733
+ x.username
25588
25734
  ])).render();
25589
25735
  info(`Remote: ${colors.bold(workspace.remote)}`);
25590
- info(`Logged in as: ${colors.green.bold(userWorkspaces.email)}`);
25591
25736
  }
25592
25737
  async function getActiveWorkspaceOrFallback(opts) {
25593
25738
  let activeWorkspace = await getActiveWorkspace(opts);
@@ -25663,9 +25808,9 @@ var init_workspace = __esm(async () => {
25663
25808
  init_auth(),
25664
25809
  init_fork()
25665
25810
  ]);
25666
- command = new Command().alias("profile").description("workspace related commands").action(list).command("switch").complete("workspace", async () => (await allWorkspaces()).map((x) => x.name)).description("Switch to another workspace").arguments("<workspace_name:string:workspace>").action(switchC).command("add").description("Add a workspace").arguments("[workspace_name:string] [workspace_id:string] [remote:string]").option("-c --create", "Create the workspace if it does not exist").option("--create-workspace-name <workspace_name:string>", "Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.").option("--create-username <username:string>", "Specify your own username in the newly created workspace. Ignored if --create is not specified, the workspace already exists or automatic username creation is enabled on the instance.", {
25811
+ command = new Command().alias("profile").description("workspace related commands").action(list2).command("switch").complete("workspace", async () => (await allWorkspaces()).map((x) => x.name)).description("Switch to another workspace").arguments("<workspace_name:string:workspace>").action(switchC).command("add").description("Add a workspace").arguments("[workspace_name:string] [workspace_id:string] [remote:string]").option("-c --create", "Create the workspace if it does not exist").option("--create-workspace-name <workspace_name:string>", "Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.").option("--create-username <username:string>", "Specify your own username in the newly created workspace. Ignored if --create is not specified, the workspace already exists or automatic username creation is enabled on the instance.", {
25667
25812
  default: "admin"
25668
- }).action(add).command("remove").description("Remove a workspace").arguments("<workspace_name:string>").action(remove).command("whoami").description("Show the currently active user").action(whoami2).command("list").description("List local workspace profiles").action(list).command("list-remote").description("List workspaces on the remote server that you have access to").action(listRemote).command("bind").description("Bind the current Git branch to the active workspace").option("--branch, --env <branch:string>", "Specify branch/environment (defaults to current)").action((opts) => bind(opts, true)).command("unbind").description("Remove workspace binding from the current Git branch").option("--branch, --env <branch:string>", "Specify branch/environment (defaults to current)").action((opts) => bind(opts, false)).command("fork").description("Create a forked workspace").arguments("[workspace_name:string] [workspace_id:string]").option("--create-workspace-name <workspace_name:string>", "Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.").action(createWorkspaceFork2).command("delete-fork").description("Delete a forked workspace and git branch").arguments("<fork_name:string>").option("-y --yes", "Skip confirmation prompt").action(deleteWorkspaceFork);
25813
+ }).action(add).command("remove").description("Remove a workspace").arguments("<workspace_name:string>").action(remove).command("whoami").description("Show the currently active user").action(whoami2).command("list").description("List local workspace profiles").action(list2).command("list-remote").description("List workspaces on the remote server that you have access to").action(listRemote).command("list-forks").description("List forked workspaces on the remote server").action(listForks).command("bind").description("Bind the current Git branch to the active workspace. This adds the branch to gitBranches in wmill.yaml so sync operations use the correct workspace for each branch.").option("--branch, --env <branch:string>", "Specify branch/environment (defaults to current)").action((opts) => bind(opts, true)).command("unbind").description("Remove workspace binding from the current Git branch").option("--branch, --env <branch:string>", "Specify branch/environment (defaults to current)").action((opts) => bind(opts, false)).command("fork").description("Create a forked workspace").arguments("[workspace_name:string] [workspace_id:string]").option("--create-workspace-name <workspace_name:string>", "Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.").action(createWorkspaceFork2).command("delete-fork").description("Delete a forked workspace and git branch").arguments("<fork_name:string>").option("-y --yes", "Skip confirmation prompt").action(deleteWorkspaceFork);
25669
25814
  workspace_default = command;
25670
25815
  });
25671
25816
 
@@ -25864,7 +26009,7 @@ async function tryResolveBranchWorkspace(opts, branchOverride) {
25864
26009
  currentBranch = rawBranch;
25865
26010
  }
25866
26011
  }
25867
- const config = await readConfigFile();
26012
+ const config = await readConfigFile({ warnIfMissing: false });
25868
26013
  const branchConfig = config.gitBranches?.[currentBranch];
25869
26014
  if (!branchConfig?.baseUrl || !branchConfig?.workspaceId) {
25870
26015
  return;
@@ -25956,10 +26101,10 @@ async function resolveWorkspace(opts, branchOverride) {
25956
26101
  const res = await tryResolveWorkspace(opts);
25957
26102
  if (!res.isError) {
25958
26103
  const workspace = res.value;
25959
- if (branchOverride || !branch || !branch.startsWith(WM_FORK_PREFIX)) {
26104
+ if (branchOverride || opts.workspace || !branch || !branch.startsWith(WM_FORK_PREFIX)) {
25960
26105
  return workspace;
25961
26106
  } else {
25962
- info(`Found an active workspace \`${workspace.name}\` but the branch name indicates this is a forked workspace. Ignoring active workspace and trying to resolve the correct workspace from the branch name \`${branch}\``);
26107
+ info(`Found an active workspace \`${workspace.name}\` but the branch name indicates this is a forked workspace. Ignoring active workspace and trying to resolve the correct workspace from the branch name \`${branch}\`. Use --workspace to override.`);
25963
26108
  }
25964
26109
  } else if (opts.workspace) {
25965
26110
  const workspaces = await allWorkspaces(opts.configDir);
@@ -28134,15 +28279,15 @@ var require_constants2 = __commonJS((exports, module) => {
28134
28279
  var require_buffer_util = __commonJS((exports, module) => {
28135
28280
  var { EMPTY_BUFFER } = require_constants2();
28136
28281
  var FastBuffer = Buffer[Symbol.species];
28137
- function concat(list2, totalLength) {
28138
- if (list2.length === 0)
28282
+ function concat(list3, totalLength) {
28283
+ if (list3.length === 0)
28139
28284
  return EMPTY_BUFFER;
28140
- if (list2.length === 1)
28141
- return list2[0];
28285
+ if (list3.length === 1)
28286
+ return list3[0];
28142
28287
  const target = Buffer.allocUnsafe(totalLength);
28143
28288
  let offset = 0;
28144
- for (let i = 0;i < list2.length; i++) {
28145
- const buf = list2[i];
28289
+ for (let i = 0;i < list3.length; i++) {
28290
+ const buf = list3[i];
28146
28291
  target.set(buf, offset);
28147
28292
  offset += buf.length;
28148
28293
  }
@@ -29394,14 +29539,14 @@ var require_sender = __commonJS((exports, module) => {
29394
29539
  this._bufferedBytes += params[3][kByteLength];
29395
29540
  this._queue.push(params);
29396
29541
  }
29397
- sendFrame(list2, cb) {
29398
- if (list2.length === 2) {
29542
+ sendFrame(list3, cb) {
29543
+ if (list3.length === 2) {
29399
29544
  this._socket.cork();
29400
- this._socket.write(list2[0]);
29401
- this._socket.write(list2[1], cb);
29545
+ this._socket.write(list3[0]);
29546
+ this._socket.write(list3[1], cb);
29402
29547
  this._socket.uncork();
29403
29548
  } else {
29404
- this._socket.write(list2[0], cb);
29549
+ this._socket.write(list3[0], cb);
29405
29550
  }
29406
29551
  }
29407
29552
  }
@@ -32732,7 +32877,7 @@ var minimatch = (p, pattern, options = {}) => {
32732
32877
  defaults: (options) => orig.defaults(ext(def, options)),
32733
32878
  makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)),
32734
32879
  braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)),
32735
- match: (list2, pattern, options = {}) => orig.match(list2, pattern, ext(def, options)),
32880
+ match: (list3, pattern, options = {}) => orig.match(list3, pattern, ext(def, options)),
32736
32881
  sep: orig.sep,
32737
32882
  GLOBSTAR
32738
32883
  });
@@ -32742,13 +32887,13 @@ var minimatch = (p, pattern, options = {}) => {
32742
32887
  return [pattern];
32743
32888
  }
32744
32889
  return expand(pattern, { max: options.braceExpandMax });
32745
- }, makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe(), match = (list2, pattern, options = {}) => {
32890
+ }, makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe(), match = (list3, pattern, options = {}) => {
32746
32891
  const mm = new Minimatch(pattern, options);
32747
- list2 = list2.filter((f) => mm.match(f));
32748
- if (mm.options.nonull && !list2.length) {
32749
- list2.push(pattern);
32892
+ list3 = list3.filter((f) => mm.match(f));
32893
+ if (mm.options.nonull && !list3.length) {
32894
+ list3.push(pattern);
32750
32895
  }
32751
- return list2;
32896
+ return list3;
32752
32897
  }, globMagic, regExpEscape2 = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
32753
32898
  var init_esm2 = __esm(() => {
32754
32899
  init_esm();
@@ -34595,20 +34740,20 @@ var require__stream_readable = __commonJS((exports, module) => {
34595
34740
  }
34596
34741
  return ret;
34597
34742
  }
34598
- function fromListPartial(n, list2, hasStrings) {
34743
+ function fromListPartial(n, list3, hasStrings) {
34599
34744
  var ret;
34600
- if (n < list2.head.data.length) {
34601
- ret = list2.head.data.slice(0, n);
34602
- list2.head.data = list2.head.data.slice(n);
34603
- } else if (n === list2.head.data.length) {
34604
- ret = list2.shift();
34745
+ if (n < list3.head.data.length) {
34746
+ ret = list3.head.data.slice(0, n);
34747
+ list3.head.data = list3.head.data.slice(n);
34748
+ } else if (n === list3.head.data.length) {
34749
+ ret = list3.shift();
34605
34750
  } else {
34606
- ret = hasStrings ? copyFromBufferString(n, list2) : copyFromBuffer(n, list2);
34751
+ ret = hasStrings ? copyFromBufferString(n, list3) : copyFromBuffer(n, list3);
34607
34752
  }
34608
34753
  return ret;
34609
34754
  }
34610
- function copyFromBufferString(n, list2) {
34611
- var p = list2.head;
34755
+ function copyFromBufferString(n, list3) {
34756
+ var p = list3.head;
34612
34757
  var c = 1;
34613
34758
  var ret = p.data;
34614
34759
  n -= ret.length;
@@ -34624,23 +34769,23 @@ var require__stream_readable = __commonJS((exports, module) => {
34624
34769
  if (nb === str.length) {
34625
34770
  ++c;
34626
34771
  if (p.next)
34627
- list2.head = p.next;
34772
+ list3.head = p.next;
34628
34773
  else
34629
- list2.head = list2.tail = null;
34774
+ list3.head = list3.tail = null;
34630
34775
  } else {
34631
- list2.head = p;
34776
+ list3.head = p;
34632
34777
  p.data = str.slice(nb);
34633
34778
  }
34634
34779
  break;
34635
34780
  }
34636
34781
  ++c;
34637
34782
  }
34638
- list2.length -= c;
34783
+ list3.length -= c;
34639
34784
  return ret;
34640
34785
  }
34641
- function copyFromBuffer(n, list2) {
34786
+ function copyFromBuffer(n, list3) {
34642
34787
  var ret = Buffer4.allocUnsafe(n);
34643
- var p = list2.head;
34788
+ var p = list3.head;
34644
34789
  var c = 1;
34645
34790
  p.data.copy(ret);
34646
34791
  n -= p.data.length;
@@ -34653,18 +34798,18 @@ var require__stream_readable = __commonJS((exports, module) => {
34653
34798
  if (nb === buf.length) {
34654
34799
  ++c;
34655
34800
  if (p.next)
34656
- list2.head = p.next;
34801
+ list3.head = p.next;
34657
34802
  else
34658
- list2.head = list2.tail = null;
34803
+ list3.head = list3.tail = null;
34659
34804
  } else {
34660
- list2.head = p;
34805
+ list3.head = p;
34661
34806
  p.data = buf.slice(nb);
34662
34807
  }
34663
34808
  break;
34664
34809
  }
34665
34810
  ++c;
34666
34811
  }
34667
- list2.length -= c;
34812
+ list3.length -= c;
34668
34813
  return ret;
34669
34814
  }
34670
34815
  function endReadable(stream) {
@@ -56161,12 +56306,16 @@ function getBranchSpecificTypes() {
56161
56306
  return {
56162
56307
  variable: ".variable.yaml",
56163
56308
  resource: ".resource.yaml",
56309
+ schedule: ".schedule.yaml",
56164
56310
  ...Object.fromEntries(TRIGGER_TYPES.map((t) => [`${t}_trigger`, `.${t}_trigger.yaml`]))
56165
56311
  };
56166
56312
  }
56167
56313
  function isTriggerFile(path5) {
56168
56314
  return TRIGGER_TYPES.some((type) => path5.endsWith(`.${type}_trigger.yaml`));
56169
56315
  }
56316
+ function isScheduleFile(path5) {
56317
+ return path5.endsWith(".schedule.yaml");
56318
+ }
56170
56319
  function getFileTypeSuffix(path5) {
56171
56320
  for (const [_, suffix] of Object.entries(getBranchSpecificTypes())) {
56172
56321
  if (path5.endsWith(suffix)) {
@@ -56180,7 +56329,7 @@ function getFileTypeSuffix(path5) {
56180
56329
  return null;
56181
56330
  }
56182
56331
  function buildYamlTypePattern() {
56183
- const basicTypes = ["variable", "resource"];
56332
+ const basicTypes = ["variable", "resource", "schedule"];
56184
56333
  const triggerTypes = TRIGGER_TYPES.map((t) => `${t}_trigger`);
56185
56334
  return `((${basicTypes.join("|")})|(${triggerTypes.join("|")}))`;
56186
56335
  }
@@ -56212,6 +56361,9 @@ function getSpecificItemsForCurrentBranch(config, branchOverride) {
56212
56361
  if (commonItems?.triggers) {
56213
56362
  merged.triggers = [...commonItems.triggers];
56214
56363
  }
56364
+ if (commonItems?.schedules) {
56365
+ merged.schedules = [...commonItems.schedules];
56366
+ }
56215
56367
  if (commonItems?.folders) {
56216
56368
  merged.folders = [...commonItems.folders];
56217
56369
  }
@@ -56227,6 +56379,9 @@ function getSpecificItemsForCurrentBranch(config, branchOverride) {
56227
56379
  if (branchItems?.triggers) {
56228
56380
  merged.triggers = [...merged.triggers || [], ...branchItems.triggers];
56229
56381
  }
56382
+ if (branchItems?.schedules) {
56383
+ merged.schedules = [...merged.schedules || [], ...branchItems.schedules];
56384
+ }
56230
56385
  if (branchItems?.folders) {
56231
56386
  merged.folders = [...merged.folders || [], ...branchItems.folders];
56232
56387
  }
@@ -56251,6 +56406,9 @@ function isItemTypeConfigured(path5, specificItems) {
56251
56406
  if (isTriggerFile(path5)) {
56252
56407
  return specificItems.triggers !== undefined;
56253
56408
  }
56409
+ if (isScheduleFile(path5)) {
56410
+ return specificItems.schedules !== undefined;
56411
+ }
56254
56412
  if (path5.endsWith("/folder.meta.yaml")) {
56255
56413
  return specificItems.folders !== undefined;
56256
56414
  }
@@ -56275,6 +56433,9 @@ function isSpecificItem(path5, specificItems) {
56275
56433
  if (isTriggerFile(path5)) {
56276
56434
  return specificItems.triggers ? matchesPatterns(path5, specificItems.triggers) : false;
56277
56435
  }
56436
+ if (isScheduleFile(path5)) {
56437
+ return specificItems.schedules ? matchesPatterns(path5, specificItems.schedules) : false;
56438
+ }
56278
56439
  if (path5.endsWith("/folder.meta.yaml")) {
56279
56440
  if (specificItems.folders) {
56280
56441
  const folderPath = path5.slice(0, -"/folder.meta.yaml".length);
@@ -59357,7 +59518,9 @@ function removeExtensionToPath(path6) {
59357
59518
  }
59358
59519
  throw new Error("Invalid extension: " + path6);
59359
59520
  }
59360
- async function list2(opts) {
59521
+ async function list3(opts) {
59522
+ if (opts.json)
59523
+ setSilent(true);
59361
59524
  const workspace = await resolveWorkspace(opts);
59362
59525
  await requireLogin(opts);
59363
59526
  let page = 0;
@@ -59405,14 +59568,40 @@ async function resolve6(input) {
59405
59568
  }
59406
59569
  }
59407
59570
  async function run2(opts, path6) {
59571
+ if (opts.silent) {
59572
+ setSilent(true);
59573
+ }
59408
59574
  const workspace = await resolveWorkspace(opts);
59409
59575
  await requireLogin(opts);
59410
59576
  const input = opts.data ? await resolve6(opts.data) : {};
59411
- const id = await runScriptByPath({
59412
- workspace: workspace.workspaceId,
59413
- path: path6,
59414
- requestBody: input
59415
- });
59577
+ let id;
59578
+ try {
59579
+ id = await runScriptByPath({
59580
+ workspace: workspace.workspaceId,
59581
+ path: path6,
59582
+ requestBody: input
59583
+ });
59584
+ } catch (e) {
59585
+ if (e?.status === 404) {
59586
+ try {
59587
+ const script = await getScriptByPath({
59588
+ workspace: workspace.workspaceId,
59589
+ path: path6
59590
+ });
59591
+ if (script.lock_error_logs) {
59592
+ throw new Error(`Script '${path6}' has a deployment error and cannot be run:
59593
+ ${script.lock_error_logs}`);
59594
+ }
59595
+ } catch (lookupErr) {
59596
+ if (lookupErr?.message?.includes("deployment error"))
59597
+ throw lookupErr;
59598
+ if (lookupErr?.status && lookupErr.status !== 404)
59599
+ throw lookupErr;
59600
+ }
59601
+ throw new Error(`Script '${path6}' not found. Run 'wmill script list' to see available scripts.`);
59602
+ }
59603
+ throw e;
59604
+ }
59416
59605
  if (!opts.silent) {
59417
59606
  await track_job(workspace.workspaceId, id);
59418
59607
  }
@@ -59423,7 +59612,7 @@ async function run2(opts, path6) {
59423
59612
  id
59424
59613
  })).result ?? {};
59425
59614
  if (opts.silent) {
59426
- console.log(result);
59615
+ console.log(JSON.stringify(result));
59427
59616
  } else {
59428
59617
  info(JSON.stringify(result, null, 2));
59429
59618
  }
@@ -59541,7 +59730,8 @@ async function bootstrap(opts, scriptPath, language) {
59541
59730
  const resolvedLanguage = languageAliases[language] ?? language;
59542
59731
  const scriptInitialCode = scriptBootstrapCode[resolvedLanguage];
59543
59732
  if (scriptInitialCode === undefined) {
59544
- throw new Error("Language unknown");
59733
+ const validLanguages = Object.keys(scriptBootstrapCode).sort().join(", ");
59734
+ throw new Error(`Unknown language '${language}'. Valid languages: ${validLanguages}`);
59545
59735
  }
59546
59736
  const config = await readConfigFile();
59547
59737
  const extension = filePathExtensionFromContentType(resolvedLanguage, config.defaultTs);
@@ -59631,6 +59821,9 @@ async function generateMetadata(opts, scriptPath) {
59631
59821
  }
59632
59822
  }
59633
59823
  async function preview(opts, filePath) {
59824
+ if (opts.silent) {
59825
+ setSilent(true);
59826
+ }
59634
59827
  opts = await mergeConfigWithConfigFile(opts);
59635
59828
  const workspace = await resolveWorkspace(opts);
59636
59829
  await requireLogin(opts);
@@ -59786,6 +59979,30 @@ async function preview(opts, filePath) {
59786
59979
  }
59787
59980
  }
59788
59981
  }
59982
+ async function history(opts, scriptPath) {
59983
+ if (opts.json)
59984
+ setSilent(true);
59985
+ opts = await mergeConfigWithConfigFile(opts);
59986
+ const workspace = await resolveWorkspace(opts);
59987
+ await requireLogin(opts);
59988
+ const versions = await getScriptHistoryByPath({
59989
+ workspace: workspace.workspaceId,
59990
+ path: scriptPath
59991
+ });
59992
+ if (opts.json) {
59993
+ console.log(JSON.stringify(versions));
59994
+ } else {
59995
+ if (versions.length === 0) {
59996
+ info("No version history found for " + scriptPath);
59997
+ return;
59998
+ }
59999
+ new Table2().header(["#", "Hash", "Deployment Message"]).padding(2).border(true).body(versions.map((v, i) => [
60000
+ String(versions.length - i),
60001
+ v.script_hash,
60002
+ v.deployment_msg ?? "-"
60003
+ ])).render();
60004
+ }
60005
+ }
59789
60006
  var import_yaml5, exts, languageAliases, command3, script_default;
59790
60007
  var init_script = __esm(async () => {
59791
60008
  init_colors2();
@@ -59841,7 +60058,7 @@ var init_script = __esm(async () => {
59841
60058
  languageAliases = {
59842
60059
  python: "python3"
59843
60060
  };
59844
- 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);
60061
+ 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);
59845
60062
  script_default = command3;
59846
60063
  });
59847
60064
 
@@ -60457,7 +60674,9 @@ async function push2(opts, filePath, remotePath) {
60457
60674
  await pushResource(workspace.workspaceId, remotePath, undefined, parseFromFile(filePath), filePath);
60458
60675
  info(colors.bold.underline.green(`Resource ${remotePath} pushed`));
60459
60676
  }
60460
- async function list3(opts) {
60677
+ async function list4(opts) {
60678
+ if (opts.json)
60679
+ setSilent(true);
60461
60680
  const workspace = await resolveWorkspace(opts);
60462
60681
  await requireLogin(opts);
60463
60682
  let page = 0;
@@ -60536,7 +60755,7 @@ var init_resource = __esm(async () => {
60536
60755
  init_specific_items()
60537
60756
  ]);
60538
60757
  import_yaml7 = __toESM(require_dist(), 1);
60539
- command5 = new Command().description("resource related commands").option("--json", "Output as JSON (for piping to jq)").action(list3).command("list", "list all resources").option("--json", "Output as JSON (for piping to jq)").action(list3).command("get", "get a resource's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get2).command("new", "create a new resource locally").arguments("<path:string>").action(newResource).command("push", "push a local resource spec. This overrides any remote versions.").arguments("<file_path:string> <remote_path:string>").action(push2);
60758
+ command5 = new Command().description("resource related commands").option("--json", "Output as JSON (for piping to jq)").action(list4).command("list", "list all resources").option("--json", "Output as JSON (for piping to jq)").action(list4).command("get", "get a resource's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get2).command("new", "create a new resource locally").arguments("<path:string>").action(newResource).command("push", "push a local resource spec. This overrides any remote versions.").arguments("<file_path:string> <remote_path:string>").action(push2);
60540
60759
  resource_default = command5;
60541
60760
  });
60542
60761
 
@@ -60557,6 +60776,10 @@ function getLanguageFromExtension(ext2, defaultTs = "bun") {
60557
60776
  }
60558
60777
  return;
60559
60778
  }
60779
+ function sanitizeForFilesystem(summary) {
60780
+ const name = summary.toLowerCase().replaceAll(" ", "_").replace(/[/\\:*?"<>|\x00-\x1f\x7f]/g, "").replace(/_+/g, "_").replace(/^[._]+|[._]+$/g, "");
60781
+ return WINDOWS_RESERVED.test(name) ? `_${name}` : name;
60782
+ }
60560
60783
  function newPathAssigner(defaultTs, options) {
60561
60784
  const resolvedOptions = typeof defaultTs === "object" ? defaultTs : { defaultTs, skipInlineScriptSuffix: options?.skipInlineScriptSuffix };
60562
60785
  const { defaultTs: tsRuntime, skipInlineScriptSuffix } = resolvedOptions;
@@ -60564,7 +60787,7 @@ function newPathAssigner(defaultTs, options) {
60564
60787
  const seen_names = new Set;
60565
60788
  function assignPath(summary, language) {
60566
60789
  let name;
60567
- name = summary?.toLowerCase()?.replaceAll(" ", "_") ?? "";
60790
+ name = summary ? sanitizeForFilesystem(summary) : "";
60568
60791
  let original_name = name;
60569
60792
  if (name == "") {
60570
60793
  original_name = INLINE_SCRIPT_PREFIX;
@@ -60586,7 +60809,7 @@ function newRawAppPathAssigner(defaultTs) {
60586
60809
  const seen_names = new Set;
60587
60810
  function assignPath(summary, language) {
60588
60811
  let name;
60589
- name = summary?.toLowerCase()?.replaceAll(" ", "_") ?? "";
60812
+ name = summary ? sanitizeForFilesystem(summary) : "";
60590
60813
  let original_name = name;
60591
60814
  if (name == "") {
60592
60815
  original_name = "runnable";
@@ -60602,7 +60825,7 @@ function newRawAppPathAssigner(defaultTs) {
60602
60825
  }
60603
60826
  return { assignPath };
60604
60827
  }
60605
- var INLINE_SCRIPT_PREFIX = "inline_script", LANGUAGE_EXTENSIONS, EXTENSION_TO_LANGUAGE;
60828
+ var INLINE_SCRIPT_PREFIX = "inline_script", LANGUAGE_EXTENSIONS, EXTENSION_TO_LANGUAGE, WINDOWS_RESERVED;
60606
60829
  var init_path_assigner = __esm(() => {
60607
60830
  LANGUAGE_EXTENSIONS = {
60608
60831
  python3: "py",
@@ -60656,19 +60879,23 @@ var init_path_assigner = __esm(() => {
60656
60879
  rb: "ruby",
60657
60880
  ts: "bun"
60658
60881
  };
60882
+ WINDOWS_RESERVED = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/;
60659
60883
  });
60660
60884
 
60661
60885
  // windmill-utils-internal/src/inline-scripts/extractor.ts
60662
60886
  function extractRawscriptInline(id, summary, rawscript, mapping, separator, assigner) {
60663
60887
  const [basePath, ext2] = assigner.assignPath(summary ?? id, rawscript.language);
60664
- const path7 = mapping[id] ?? basePath + ext2;
60888
+ const mappedPath = mapping[id];
60889
+ const path7 = mappedPath ?? basePath + ext2;
60665
60890
  const language = rawscript.language;
60666
60891
  const content = rawscript.content;
60667
60892
  const r = [{ path: path7, content, language, is_lock: false }];
60668
60893
  rawscript.content = "!inline " + path7.replaceAll(separator, "/");
60669
60894
  const lock = rawscript.lock;
60670
60895
  if (lock && lock != "") {
60671
- const lockPath = basePath + "lock";
60896
+ const dotIdx = mappedPath ? mappedPath.lastIndexOf(".") : -1;
60897
+ const lockBasePath = mappedPath ? dotIdx > 0 ? mappedPath.substring(0, dotIdx + 1) : mappedPath + "." : basePath;
60898
+ const lockPath = lockBasePath + "lock";
60672
60899
  rawscript.lock = "!inline " + lockPath.replaceAll(separator, "/");
60673
60900
  r.push({ path: lockPath, content: lock, language, is_lock: true });
60674
60901
  }
@@ -60703,6 +60930,43 @@ function extractInlineScripts(modules, mapping = {}, separator = "/", defaultTs,
60703
60930
  }
60704
60931
  });
60705
60932
  }
60933
+ function extractCurrentMapping(modules, mapping = {}, failureModule, preprocessorModule) {
60934
+ if (failureModule) {
60935
+ extractCurrentMapping([failureModule], mapping);
60936
+ }
60937
+ if (preprocessorModule) {
60938
+ extractCurrentMapping([preprocessorModule], mapping);
60939
+ }
60940
+ if (!modules || !Array.isArray(modules)) {
60941
+ return mapping;
60942
+ }
60943
+ modules.forEach((m) => {
60944
+ if (!m?.value?.type) {
60945
+ return;
60946
+ }
60947
+ if (m.value.type === "rawscript") {
60948
+ if (m.value.content && m.value.content.startsWith("!inline ")) {
60949
+ mapping[m.id] = m.value.content.trim().split(" ")[1];
60950
+ }
60951
+ } else if (m.value.type === "forloopflow" || m.value.type === "whileloopflow") {
60952
+ extractCurrentMapping(m.value.modules, mapping);
60953
+ } else if (m.value.type === "branchall") {
60954
+ m.value.branches.forEach((b) => extractCurrentMapping(b.modules, mapping));
60955
+ } else if (m.value.type === "branchone") {
60956
+ m.value.branches.forEach((b) => extractCurrentMapping(b.modules, mapping));
60957
+ extractCurrentMapping(m.value.default, mapping);
60958
+ } else if (m.value.type === "aiagent") {
60959
+ (m.value.tools ?? []).forEach((tool) => {
60960
+ const toolValue = tool.value;
60961
+ if (!toolValue || toolValue.tool_type !== "flowmodule" || toolValue.type !== "rawscript" || !toolValue.content || !toolValue.content.startsWith("!inline ")) {
60962
+ return;
60963
+ }
60964
+ mapping[tool.id] = toolValue.content.trim().split(" ")[1];
60965
+ });
60966
+ }
60967
+ });
60968
+ return mapping;
60969
+ }
60706
60970
  var init_extractor = __esm(() => {
60707
60971
  init_path_assigner();
60708
60972
  });
@@ -61000,6 +61264,7 @@ async function generateFlowLockInternal(folder, dryRun, workspace, opts, justUpd
61000
61264
  info(`Recomputing locks of ${changedScripts.join(", ")} in ${folder}`);
61001
61265
  }
61002
61266
  const fileReader = async (path8) => await readFile7(folder + SEP7 + path8, "utf-8");
61267
+ const currentMapping = extractCurrentMapping(flowValue.value.modules, {}, flowValue.value.failure_module, flowValue.value.preprocessor_module);
61003
61268
  const locksToRemove = tree && !legacyBehaviour ? Object.keys(hashes).filter((k) => {
61004
61269
  if (k === TOP_HASH)
61005
61270
  return false;
@@ -61018,12 +61283,12 @@ async function generateFlowLockInternal(folder, dryRun, workspace, opts, justUpd
61018
61283
  const lockAssigner = newPathAssigner(opts.defaultTs ?? "bun", {
61019
61284
  skipInlineScriptSuffix: getNonDottedPaths()
61020
61285
  });
61021
- const inlineScripts = extractInlineScripts(flowValue.value.modules, {}, SEP7, opts.defaultTs, lockAssigner);
61286
+ const inlineScripts = extractInlineScripts(flowValue.value.modules, currentMapping, SEP7, opts.defaultTs, lockAssigner);
61022
61287
  if (flowValue.value.failure_module) {
61023
- inlineScripts.push(...extractInlineScripts([flowValue.value.failure_module], {}, SEP7, opts.defaultTs, lockAssigner));
61288
+ inlineScripts.push(...extractInlineScripts([flowValue.value.failure_module], currentMapping, SEP7, opts.defaultTs, lockAssigner));
61024
61289
  }
61025
61290
  if (flowValue.value.preprocessor_module) {
61026
- inlineScripts.push(...extractInlineScripts([flowValue.value.preprocessor_module], {}, SEP7, opts.defaultTs, lockAssigner));
61291
+ inlineScripts.push(...extractInlineScripts([flowValue.value.preprocessor_module], currentMapping, SEP7, opts.defaultTs, lockAssigner));
61027
61292
  }
61028
61293
  inlineScripts.forEach((s) => {
61029
61294
  writeIfChanged(process.cwd() + SEP7 + folder + SEP7 + s.path, s.content);
@@ -62448,8 +62713,13 @@ async function pushParentScriptForModule(modulePath, workspace, alreadySynced, m
62448
62713
  }
62449
62714
  }
62450
62715
  async function pull(opts) {
62716
+ if (opts.jsonOutput)
62717
+ setSilent(true);
62451
62718
  const originalCliOpts = { ...opts };
62452
62719
  opts = await mergeConfigWithConfigFile(opts);
62720
+ if (originalCliOpts.includeSecrets) {
62721
+ opts.skipSecrets = false;
62722
+ }
62453
62723
  try {
62454
62724
  await validateBranchConfiguration(opts, opts.branch);
62455
62725
  } catch (error2) {
@@ -62682,8 +62952,13 @@ function removeSuffix(str, suffix) {
62682
62952
  return str.slice(0, str.length - suffix.length);
62683
62953
  }
62684
62954
  async function push3(opts) {
62955
+ if (opts.jsonOutput)
62956
+ setSilent(true);
62685
62957
  const originalCliOpts = { ...opts };
62686
62958
  opts = await mergeConfigWithConfigFile(opts);
62959
+ if (originalCliOpts.includeSecrets) {
62960
+ opts.skipSecrets = false;
62961
+ }
62687
62962
  try {
62688
62963
  await validateBranchConfiguration(opts, opts.branch);
62689
62964
  } catch (error2) {
@@ -62751,55 +63026,104 @@ Push aborted: ${lockIssues.length} script(s) missing locks.`));
62751
63026
  const changes = await compareDynFSElement(local, remote, await ignoreF(opts), opts.json ?? false, opts, true, codebases, false, specificItems, opts.branch, false);
62752
63027
  const rawWorkspaceDependencies = await getRawWorkspaceDependencies(true);
62753
63028
  const tracker = await buildTracker(changes);
63029
+ const autoRegenerate = !!opts.autoMetadata;
62754
63030
  const staleScripts = [];
62755
63031
  const staleFlows = [];
62756
63032
  const staleApps = [];
62757
63033
  for (const change of tracker.scripts) {
62758
- const stale = await generateScriptMetadataInternal(change, workspace, opts, true, true, rawWorkspaceDependencies, codebases, false);
63034
+ const stale = await generateScriptMetadataInternal(change, workspace, opts, !autoRegenerate, true, rawWorkspaceDependencies, codebases, false);
62759
63035
  if (stale) {
62760
63036
  staleScripts.push(stale);
62761
63037
  }
62762
63038
  }
62763
63039
  if (staleScripts.length > 0) {
62764
63040
  info("");
62765
- warn("Stale scripts metadata found, you may want to update them using 'wmill script generate-metadata' before pushing:");
63041
+ if (autoRegenerate) {
63042
+ info("Auto-regenerated metadata for stale scripts:");
63043
+ } else {
63044
+ warn("Stale scripts metadata found, you may want to update them using 'wmill script generate-metadata' before pushing:");
63045
+ }
62766
63046
  for (const stale of staleScripts) {
62767
- warn(stale);
63047
+ if (autoRegenerate) {
63048
+ info(` ${stale}`);
63049
+ } else {
63050
+ warn(stale);
63051
+ }
62768
63052
  }
62769
63053
  info("");
62770
63054
  }
62771
63055
  for (const change of tracker.flows) {
62772
- const stale = await generateFlowLockInternal(change, true, workspace, opts, false, true);
63056
+ const stale = await generateFlowLockInternal(change, !autoRegenerate, workspace, opts, false, true);
62773
63057
  if (stale) {
62774
63058
  staleFlows.push(stale);
62775
63059
  }
62776
63060
  }
62777
63061
  if (staleFlows.length > 0) {
62778
- warn("Stale flows locks found, you may want to update them using 'wmill flow generate-locks' before pushing:");
63062
+ if (autoRegenerate) {
63063
+ info("Auto-regenerated locks for stale flows:");
63064
+ } else {
63065
+ warn("Stale flows locks found, you may want to update them using 'wmill flow generate-locks' before pushing:");
63066
+ }
62779
63067
  for (const stale of staleFlows) {
62780
- warn(stale);
63068
+ if (autoRegenerate) {
63069
+ info(` ${stale}`);
63070
+ } else {
63071
+ warn(stale);
63072
+ }
62781
63073
  }
62782
63074
  info("");
62783
63075
  }
62784
63076
  for (const change of tracker.apps) {
62785
- const stale = await generateAppLocksInternal(change, false, true, workspace, opts, true, true);
63077
+ const stale = await generateAppLocksInternal(change, false, !autoRegenerate, workspace, opts, true, true);
62786
63078
  if (stale) {
62787
63079
  staleApps.push(stale);
62788
63080
  }
62789
63081
  }
62790
63082
  for (const change of tracker.rawApps) {
62791
- const stale = await generateAppLocksInternal(change, true, true, workspace, opts, true, true);
63083
+ const stale = await generateAppLocksInternal(change, true, !autoRegenerate, workspace, opts, true, true);
62792
63084
  if (stale) {
62793
63085
  staleApps.push(stale);
62794
63086
  }
62795
63087
  }
62796
63088
  if (staleApps.length > 0) {
62797
- warn("Stale apps locks found, you may want to update them using 'wmill app generate-locks' before pushing:");
63089
+ if (autoRegenerate) {
63090
+ info("Auto-regenerated locks for stale apps:");
63091
+ } else {
63092
+ warn("Stale apps locks found, you may want to update them using 'wmill app generate-locks' before pushing:");
63093
+ }
62798
63094
  for (const stale of staleApps) {
62799
- warn(stale);
63095
+ if (autoRegenerate) {
63096
+ info(` ${stale}`);
63097
+ } else {
63098
+ warn(stale);
63099
+ }
62800
63100
  }
62801
63101
  info("");
62802
63102
  }
63103
+ {
63104
+ const skippedWarnings = [];
63105
+ let scheduleCount = 0;
63106
+ let triggerCount = 0;
63107
+ for await (const entry of readDirRecursiveWithIgnore2(() => false, local)) {
63108
+ if (entry.isDirectory)
63109
+ continue;
63110
+ if (!opts.includeSchedules && entry.path.endsWith(".schedule.yaml"))
63111
+ scheduleCount++;
63112
+ if (!opts.includeTriggers && entry.path.endsWith("_trigger.yaml"))
63113
+ triggerCount++;
63114
+ }
63115
+ if (scheduleCount > 0) {
63116
+ skippedWarnings.push(`Skipping ${scheduleCount} schedule file(s). Use --include-schedules or set includeSchedules: true in wmill.yaml`);
63117
+ }
63118
+ if (triggerCount > 0) {
63119
+ skippedWarnings.push(`Skipping ${triggerCount} trigger file(s). Use --include-triggers or set includeTriggers: true in wmill.yaml`);
63120
+ }
63121
+ for (const warning of skippedWarnings) {
63122
+ warn(warning);
63123
+ }
63124
+ if (skippedWarnings.length > 0)
63125
+ info("");
63126
+ }
62803
63127
  await fetchRemoteVersion(workspace);
62804
63128
  info(`remote (${workspace.name}) <- local: ${changes.length} changes to apply`);
62805
63129
  const missingFolders = [];
@@ -63070,16 +63394,60 @@ ${folderList}
63070
63394
  });
63071
63395
  break;
63072
63396
  case "flow":
63073
- await deleteFlowByPath({
63074
- workspace: workspaceId,
63075
- path: removeSuffix(target, getDeleteSuffix("flow", "json"))
63076
- });
63397
+ if (isFlowFolderMetadataFile(target)) {
63398
+ await deleteFlowByPath({
63399
+ workspace: workspaceId,
63400
+ path: removeSuffix(target, getDeleteSuffix("flow", "json"))
63401
+ });
63402
+ } else {
63403
+ const flowFolder = extractFolderPath(target, "flow");
63404
+ let flowFolderExists = false;
63405
+ if (flowFolder) {
63406
+ try {
63407
+ await stat6(flowFolder);
63408
+ flowFolderExists = true;
63409
+ } catch {}
63410
+ }
63411
+ if (flowFolderExists) {
63412
+ await pushObj(workspaceId, target, undefined, undefined, opts.plainSecrets ?? false, alreadySynced, opts.message);
63413
+ } else {
63414
+ const remotePath = extractResourceName(target, "flow");
63415
+ if (remotePath) {
63416
+ await deleteFlowByPath({
63417
+ workspace: workspaceId,
63418
+ path: remotePath
63419
+ });
63420
+ }
63421
+ }
63422
+ }
63077
63423
  break;
63078
63424
  case "app":
63079
- await deleteApp({
63080
- workspace: workspaceId,
63081
- path: removeSuffix(target, getDeleteSuffix("app", "json"))
63082
- });
63425
+ if (isAppFolderMetadataFile(target)) {
63426
+ await deleteApp({
63427
+ workspace: workspaceId,
63428
+ path: removeSuffix(target, getDeleteSuffix("app", "json"))
63429
+ });
63430
+ } else {
63431
+ const appFolder = extractFolderPath(target, "app");
63432
+ let appFolderExists = false;
63433
+ if (appFolder) {
63434
+ try {
63435
+ await stat6(appFolder);
63436
+ appFolderExists = true;
63437
+ } catch {}
63438
+ }
63439
+ if (appFolderExists) {
63440
+ await pushObj(workspaceId, target, undefined, undefined, opts.plainSecrets ?? false, alreadySynced, opts.message);
63441
+ } else {
63442
+ const remotePath = extractResourceName(target, "app");
63443
+ if (remotePath) {
63444
+ await deleteApp({
63445
+ workspace: workspaceId,
63446
+ path: remotePath
63447
+ });
63448
+ }
63449
+ }
63450
+ }
63083
63451
  break;
63084
63452
  case "raw_app":
63085
63453
  if (isRawAppFolderMetadataFile(target)) {
@@ -63337,7 +63705,7 @@ var init_sync = __esm(async () => {
63337
63705
  aliasDuplicateObjects: false,
63338
63706
  singleQuote: true
63339
63707
  };
63340
- command6 = new Command().description("sync local with a remote workspaces or the opposite (push or pull)").action(() => info("2 actions available, pull and push. Use -h to display help.")).command("pull").description("Pull any remote changes and apply them locally.").option("--yes", "Pull without needing confirmation").option("--dry-run", "Show changes that would be pulled without actually pushing").option("--plain-secrets", "Pull secrets as plain text").option("--json", "Use JSON instead of YAML").option("--skip-variables", "Skip syncing variables (including secrets)").option("--skip-secrets", "Skip syncing only secrets variables").option("--skip-resources", "Skip syncing resources").option("--skip-resource-types", "Skip syncing resource types").option("--skip-scripts", "Skip syncing scripts").option("--skip-flows", "Skip syncing flows").option("--skip-apps", "Skip syncing apps").option("--skip-folders", "Skip syncing folders").option("--skip-workspace-dependencies", "Skip syncing workspace dependencies").option("--include-schedules", "Include syncing schedules").option("--include-triggers", "Include syncing triggers").option("--include-users", "Include syncing users").option("--include-groups", "Include syncing groups").option("--include-settings", "Include syncing workspace settings").option("--include-key", "Include workspace encryption key").option("--skip-branch-validation", "Skip git branch validation and prompts").option("--json-output", "Output results in JSON format").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). Overrides wmill.yaml includes").option("-e --excludes <patterns:file[]>", "Comma separated patterns to specify which file to NOT take into account. Overrides wmill.yaml excludes").option("--extra-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). Useful to still take wmill.yaml into account and act as a second pattern to satisfy").option("--repository <repo:string>", "Specify repository path (e.g., u/user/repo) when multiple repositories exist").option("--promotion <branch:string>", "Use promotionOverrides from the specified branch instead of regular overrides").option("--branch, --env <branch:string>", "Override the current git branch/environment (works even outside a git repository)").action(pull).command("push").description("Push any local changes and apply them remotely.").option("--yes", "Push without needing confirmation").option("--dry-run", "Show changes that would be pushed without actually pushing").option("--plain-secrets", "Push secrets as plain text").option("--json", "Use JSON instead of YAML").option("--skip-variables", "Skip syncing variables (including secrets)").option("--skip-secrets", "Skip syncing only secrets variables").option("--skip-resources", "Skip syncing resources").option("--skip-resource-types", "Skip syncing resource types").option("--skip-scripts", "Skip syncing scripts").option("--skip-flows", "Skip syncing flows").option("--skip-apps", "Skip syncing apps").option("--skip-folders", "Skip syncing folders").option("--skip-workspace-dependencies", "Skip syncing workspace dependencies").option("--include-schedules", "Include syncing schedules").option("--include-triggers", "Include syncing triggers").option("--include-users", "Include syncing users").option("--include-groups", "Include syncing groups").option("--include-settings", "Include syncing workspace settings").option("--include-key", "Include workspace encryption key").option("--skip-branch-validation", "Skip git branch validation and prompts").option("--json-output", "Output results in JSON format").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.").option("--extra-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). Useful to still take wmill.yaml into account and act as a second pattern to satisfy").option("--message <message:string>", "Include a message that will be added to all scripts/flows/apps updated during this push").option("--parallel <number>", "Number of changes to process in parallel").option("--repository <repo:string>", "Specify repository path (e.g., u/user/repo) when multiple repositories exist").option("--branch, --env <branch:string>", "Override the current git branch/environment (works even outside a git repository)").option("--lint", "Run lint validation before pushing").option("--locks-required", "Fail if scripts or flow inline scripts that need locks have no locks").action(push3);
63708
+ command6 = new Command().description("sync local with a remote workspaces or the opposite (push or pull)").action(() => info("2 actions available, pull and push. Use -h to display help.")).command("pull").description("Pull any remote changes and apply them locally.").option("--yes", "Pull without needing confirmation").option("--dry-run", "Show changes that would be pulled without actually pushing").option("--plain-secrets", "Pull secrets as plain text").option("--json", "Use JSON instead of YAML").option("--skip-variables", "Skip syncing variables (including secrets)").option("--skip-secrets", "Skip syncing only secrets variables").option("--include-secrets", "Include secrets in sync (overrides skipSecrets in wmill.yaml)").option("--skip-resources", "Skip syncing resources").option("--skip-resource-types", "Skip syncing resource types").option("--skip-scripts", "Skip syncing scripts").option("--skip-flows", "Skip syncing flows").option("--skip-apps", "Skip syncing apps").option("--skip-folders", "Skip syncing folders").option("--skip-workspace-dependencies", "Skip syncing workspace dependencies").option("--include-schedules", "Include syncing schedules").option("--include-triggers", "Include syncing triggers").option("--include-users", "Include syncing users").option("--include-groups", "Include syncing groups").option("--include-settings", "Include syncing workspace settings").option("--include-key", "Include workspace encryption key").option("--skip-branch-validation", "Skip git branch validation and prompts").option("--json-output", "Output results in JSON format").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). Overrides wmill.yaml includes").option("-e --excludes <patterns:file[]>", "Comma separated patterns to specify which file to NOT take into account. Overrides wmill.yaml excludes").option("--extra-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). Useful to still take wmill.yaml into account and act as a second pattern to satisfy").option("--repository <repo:string>", "Specify repository path (e.g., u/user/repo) when multiple repositories exist").option("--promotion <branch:string>", "Use promotionOverrides from the specified branch instead of regular overrides").option("--branch, --env <branch:string>", "Override the current git branch/environment (works even outside a git repository)").action(pull).command("push").description("Push any local changes and apply them remotely.").option("--yes", "Push without needing confirmation").option("--dry-run", "Show changes that would be pushed without actually pushing").option("--plain-secrets", "Push secrets as plain text").option("--json", "Use JSON instead of YAML").option("--skip-variables", "Skip syncing variables (including secrets)").option("--skip-secrets", "Skip syncing only secrets variables").option("--include-secrets", "Include secrets in sync (overrides skipSecrets in wmill.yaml)").option("--skip-resources", "Skip syncing resources").option("--skip-resource-types", "Skip syncing resource types").option("--skip-scripts", "Skip syncing scripts").option("--skip-flows", "Skip syncing flows").option("--skip-apps", "Skip syncing apps").option("--skip-folders", "Skip syncing folders").option("--skip-workspace-dependencies", "Skip syncing workspace dependencies").option("--include-schedules", "Include syncing schedules").option("--include-triggers", "Include syncing triggers").option("--include-users", "Include syncing users").option("--include-groups", "Include syncing groups").option("--include-settings", "Include syncing workspace settings").option("--include-key", "Include workspace encryption key").option("--skip-branch-validation", "Skip git branch validation and prompts").option("--json-output", "Output results in JSON format").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.").option("--extra-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). Useful to still take wmill.yaml into account and act as a second pattern to satisfy").option("--message <message:string>", "Include a message that will be added to all scripts/flows/apps updated during this push").option("--parallel <number>", "Number of changes to process in parallel").option("--repository <repo:string>", "Specify repository path (e.g., u/user/repo) when multiple repositories exist").option("--branch, --env <branch:string>", "Override the current git branch/environment (works even outside a git repository)").option("--lint", "Run lint validation before pushing").option("--locks-required", "Fail if scripts or flow inline scripts that need locks have no locks").option("--auto-metadata", "Automatically regenerate stale metadata (locks and schemas) before pushing").action(push3);
63341
63709
  sync_default = command6;
63342
63710
  });
63343
63711
 
@@ -64364,6 +64732,13 @@ var init_metadata = __esm(async () => {
64364
64732
  });
64365
64733
 
64366
64734
  // src/commands/app/raw_apps.ts
64735
+ var exports_raw_apps = {};
64736
+ __export(exports_raw_apps, {
64737
+ writeRunnableToBackend: () => writeRunnableToBackend,
64738
+ pushRawApp: () => pushRawApp,
64739
+ loadRunnablesFromBackend: () => loadRunnablesFromBackend,
64740
+ generatingPolicy: () => generatingPolicy
64741
+ });
64367
64742
  import { sep as SEP10 } from "node:path";
64368
64743
  import path10 from "node:path";
64369
64744
  import { readFile as readFile10, readdir as readdir6 } from "node:fs/promises";
@@ -67066,6 +67441,7 @@ var init_new = __esm(async () => {
67066
67441
 
67067
67442
  // src/commands/app/app.ts
67068
67443
  import { sep as SEP13 } from "node:path";
67444
+ import { stat as stat9 } from "node:fs/promises";
67069
67445
  function respecializeFields(fields) {
67070
67446
  Object.entries(fields).forEach(([k, v]) => {
67071
67447
  if (typeof v == "object") {
@@ -67195,7 +67571,7 @@ async function generatingPolicy2(app, path16, publicApp) {
67195
67571
  throw e;
67196
67572
  }
67197
67573
  }
67198
- async function list4(opts) {
67574
+ async function list5(opts) {
67199
67575
  const workspace = await resolveWorkspace(opts);
67200
67576
  await requireLogin(opts);
67201
67577
  let page = 0;
@@ -67241,8 +67617,24 @@ async function push4(opts, filePath, remotePath) {
67241
67617
  }
67242
67618
  const workspace = await resolveWorkspace(opts);
67243
67619
  await requireLogin(opts);
67244
- await pushApp(workspace.workspaceId, remotePath, filePath);
67245
- info(colors.bold.underline.green("App pushed"));
67620
+ const normalizedPath = filePath.endsWith(SEP13) ? filePath.slice(0, -1) : filePath;
67621
+ const isRawApp = normalizedPath.endsWith("__raw_app") || normalizedPath.endsWith(".raw_app");
67622
+ let hasRawAppYaml = false;
67623
+ if (!isRawApp) {
67624
+ try {
67625
+ const rawAppPath = (filePath.endsWith(SEP13) ? filePath : filePath + SEP13) + "raw_app.yaml";
67626
+ await stat9(rawAppPath);
67627
+ hasRawAppYaml = true;
67628
+ } catch {}
67629
+ }
67630
+ if (isRawApp || hasRawAppYaml) {
67631
+ const { pushRawApp: pushRawApp2 } = await init_raw_apps().then(() => exports_raw_apps);
67632
+ await pushRawApp2(workspace.workspaceId, remotePath, filePath);
67633
+ info(colors.bold.underline.green("Raw app pushed"));
67634
+ } else {
67635
+ await pushApp(workspace.workspaceId, remotePath, filePath);
67636
+ info(colors.bold.underline.green("App pushed"));
67637
+ }
67246
67638
  }
67247
67639
  var alreadySynced2, command11, app_default;
67248
67640
  var init_app = __esm(async () => {
@@ -67265,7 +67657,7 @@ var init_app = __esm(async () => {
67265
67657
  init_generate_agents()
67266
67658
  ]);
67267
67659
  alreadySynced2 = [];
67268
- command11 = new Command().description("app related commands").option("--json", "Output as JSON (for piping to jq)").action(list4).command("list", "list all apps").option("--json", "Output as JSON (for piping to jq)").action(list4).command("get", "get an app's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get3).command("push", "push a local app ").arguments("<file_path:string> <remote_path:string>").action(push4).command("dev", dev_default).command("lint", lint_default2).command("new", new_default).command("generate-agents", generate_agents_default).command("generate-locks", "re-generate the lockfiles for app runnables inline scripts that have changed").arguments("[app_folder:string]").option("--yes", "Skip confirmation prompt").option("--dry-run", "Perform a dry run without making changes").option("--default-ts <runtime:string>", "Default TypeScript runtime (bun or deno)").action(async (opts, appFolder) => {
67660
+ command11 = new Command().description("app related commands").option("--json", "Output as JSON (for piping to jq)").action(list5).command("list", "list all apps").option("--json", "Output as JSON (for piping to jq)").action(list5).command("get", "get an app's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get3).command("push", "push a local app ").arguments("<file_path:string> <remote_path:string>").action(push4).command("dev", dev_default).command("lint", lint_default2).command("new", new_default).command("generate-agents", generate_agents_default).command("generate-locks", "re-generate the lockfiles for app runnables inline scripts that have changed").arguments("[app_folder:string]").option("--yes", "Skip confirmation prompt").option("--dry-run", "Perform a dry run without making changes").option("--default-ts <runtime:string>", "Default TypeScript runtime (bun or deno)").action(async (opts, appFolder) => {
67269
67661
  warn(colors.yellow('This command is deprecated. Use "wmill generate-metadata" instead.'));
67270
67662
  const { generateLocksCommand: generateLocksCommand2 } = await init_app_metadata().then(() => exports_app_metadata);
67271
67663
  await generateLocksCommand2(opts, appFolder);
@@ -67274,9 +67666,11 @@ var init_app = __esm(async () => {
67274
67666
  });
67275
67667
 
67276
67668
  // src/commands/folder/folder.ts
67277
- import { stat as stat9, readdir as readdir7, writeFile as writeFile10, mkdir as mkdir7 } from "node:fs/promises";
67669
+ import { stat as stat10, readdir as readdir7, writeFile as writeFile10, mkdir as mkdir7 } from "node:fs/promises";
67278
67670
  import { sep as SEP14 } from "node:path";
67279
- async function list5(opts) {
67671
+ async function list6(opts) {
67672
+ if (opts.json)
67673
+ setSilent(true);
67280
67674
  const workspace = await resolveWorkspace(opts);
67281
67675
  await requireLogin(opts);
67282
67676
  const folders = await listFolders({
@@ -67296,7 +67690,7 @@ async function newFolder(opts, name) {
67296
67690
  const dirPath = `f${SEP14}${name}`;
67297
67691
  const filePath = `${dirPath}${SEP14}folder.meta.yaml`;
67298
67692
  try {
67299
- await stat9(filePath);
67693
+ await stat10(filePath);
67300
67694
  throw new Error("File already exists: " + filePath);
67301
67695
  } catch (e) {
67302
67696
  if (e.message?.startsWith("File already exists"))
@@ -67384,7 +67778,7 @@ async function push5(opts, name) {
67384
67778
  await requireLogin(opts);
67385
67779
  const metaPath = `f${SEP14}${name}${SEP14}folder.meta.yaml`;
67386
67780
  try {
67387
- await stat9(metaPath);
67781
+ await stat10(metaPath);
67388
67782
  } catch {
67389
67783
  throw new Error(`Could not find ${metaPath}. Does the folder exist locally?`);
67390
67784
  }
@@ -67395,7 +67789,7 @@ async function push5(opts, name) {
67395
67789
  async function addMissing(opts) {
67396
67790
  const fDir = `f`;
67397
67791
  try {
67398
- await stat9(fDir);
67792
+ await stat10(fDir);
67399
67793
  } catch {
67400
67794
  info("No 'f/' directory found. Nothing to do.");
67401
67795
  return;
@@ -67407,7 +67801,7 @@ async function addMissing(opts) {
67407
67801
  continue;
67408
67802
  const metaPath = `${fDir}${SEP14}${entry.name}${SEP14}folder.meta.yaml`;
67409
67803
  try {
67410
- await stat9(metaPath);
67804
+ await stat10(metaPath);
67411
67805
  } catch {
67412
67806
  missing.push(entry.name);
67413
67807
  }
@@ -67446,7 +67840,7 @@ var init_folder = __esm(async () => {
67446
67840
  init_types()
67447
67841
  ]);
67448
67842
  import_yaml23 = __toESM(require_dist(), 1);
67449
- command12 = new Command().description("folder related commands").option("--json", "Output as JSON (for piping to jq)").action(list5).command("list", "list all folders").option("--json", "Output as JSON (for piping to jq)").action(list5).command("get", "get a folder's details").arguments("<name:string>").option("--json", "Output as JSON (for piping to jq)").action(get4).command("new", "create a new folder locally").arguments("<name:string>").option("--summary <summary:string>", "folder summary").action(newFolder).command("push", "push a local folder to the remote by name. This overrides any remote versions.").arguments("<name:string>").action(push5).command("add-missing", "create default folder.meta.yaml for all subdirectories of f/ that are missing one").option("-y, --yes", "skip confirmation prompt").action(addMissing);
67843
+ command12 = new Command().description("folder related commands").option("--json", "Output as JSON (for piping to jq)").action(list6).command("list", "list all folders").option("--json", "Output as JSON (for piping to jq)").action(list6).command("get", "get a folder's details").arguments("<name:string>").option("--json", "Output as JSON (for piping to jq)").action(get4).command("new", "create a new folder locally").arguments("<name:string>").option("--summary <summary:string>", "folder summary").action(newFolder).command("push", "push a local folder to the remote by name. This overrides any remote versions.").arguments("<name:string>").action(push5).command("add-missing", "create default folder.meta.yaml for all subdirectories of f/ that are missing one").option("-y, --yes", "skip confirmation prompt").action(addMissing);
67450
67844
  folder_default = command12;
67451
67845
  });
67452
67846
 
@@ -67487,7 +67881,7 @@ function compileResourceTypeToTsType(schema) {
67487
67881
 
67488
67882
  // src/commands/resource-type/resource-type.ts
67489
67883
  import { writeFileSync as writeFileSync4 } from "node:fs";
67490
- import { stat as stat10, writeFile as writeFile11 } from "node:fs/promises";
67884
+ import { stat as stat11, writeFile as writeFile11 } from "node:fs/promises";
67491
67885
  import path16 from "node:path";
67492
67886
  import process16 from "node:process";
67493
67887
  async function pushResourceType(workspace, remotePath, resource, localResource) {
@@ -67521,7 +67915,7 @@ async function pushResourceType(workspace, remotePath, resource, localResource)
67521
67915
  }
67522
67916
  }
67523
67917
  async function push6(opts, filePath, name) {
67524
- const fstat = await stat10(filePath);
67918
+ const fstat = await stat11(filePath);
67525
67919
  if (!fstat.isFile()) {
67526
67920
  throw new Error("file path must refer to a file.");
67527
67921
  }
@@ -67531,7 +67925,9 @@ async function push6(opts, filePath, name) {
67531
67925
  await pushResourceType(workspace.workspaceId, name, undefined, parseFromFile(filePath));
67532
67926
  info(colors.bold.underline.green("Resource pushed"));
67533
67927
  }
67534
- async function list6(opts) {
67928
+ async function list7(opts) {
67929
+ if (opts.json)
67930
+ setSilent(true);
67535
67931
  const workspace = await resolveWorkspace(opts);
67536
67932
  await requireLogin(opts);
67537
67933
  const res = await listResourceType({
@@ -67552,7 +67948,7 @@ async function list6(opts) {
67552
67948
  async function newResourceType(opts, name) {
67553
67949
  const filePath = name + ".resource-type.yaml";
67554
67950
  try {
67555
- await stat10(filePath);
67951
+ await stat11(filePath);
67556
67952
  throw new Error("File already exists: " + filePath);
67557
67953
  } catch (e) {
67558
67954
  if (e.message?.startsWith("File already exists"))
@@ -67620,14 +68016,16 @@ var init_resource_type = __esm(async () => {
67620
68016
  init_utils()
67621
68017
  ]);
67622
68018
  import_yaml24 = __toESM(require_dist(), 1);
67623
- command13 = new Command().description("resource type related commands").option("--json", "Output as JSON (for piping to jq)").action(list6).command("list", "list all resource types").option("--schema", "Show schema in the output").option("--json", "Output as JSON (for piping to jq)").action(list6).command("get", "get a resource type's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get5).command("new", "create a new resource type locally").arguments("<name:string>").action(newResourceType).command("push", "push a local resource spec. This overrides any remote versions.").arguments("<file_path:string> <name:string>").action(push6).command("generate-namespace", "Create a TypeScript definition file with the RT namespace generated from the resource types").action(generateRTNamespace);
68019
+ command13 = new Command().description("resource type related commands").option("--json", "Output as JSON (for piping to jq)").action(list7).command("list", "list all resource types").option("--schema", "Show schema in the output").option("--json", "Output as JSON (for piping to jq)").action(list7).command("get", "get a resource type's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get5).command("new", "create a new resource type locally").arguments("<name:string>").action(newResourceType).command("push", "push a local resource spec. This overrides any remote versions.").arguments("<file_path:string> <name:string>").action(push6).command("generate-namespace", "Create a TypeScript definition file with the RT namespace generated from the resource types").action(generateRTNamespace);
67624
68020
  resource_type_default = command13;
67625
68021
  });
67626
68022
 
67627
68023
  // src/commands/variable/variable.ts
67628
- import { stat as stat11, writeFile as writeFile12 } from "node:fs/promises";
68024
+ import { stat as stat12, writeFile as writeFile12 } from "node:fs/promises";
67629
68025
  import { sep as SEP15 } from "node:path";
67630
- async function list7(opts) {
68026
+ async function list8(opts) {
68027
+ if (opts.json)
68028
+ setSilent(true);
67631
68029
  const workspace = await resolveWorkspace(opts);
67632
68030
  await requireLogin(opts);
67633
68031
  const variables = await listVariable({
@@ -67650,7 +68048,7 @@ async function newVariable(opts, path17) {
67650
68048
  }
67651
68049
  const filePath = path17 + ".variable.yaml";
67652
68050
  try {
67653
- await stat11(filePath);
68051
+ await stat12(filePath);
67654
68052
  throw new Error("File already exists: " + filePath);
67655
68053
  } catch (e) {
67656
68054
  if (e.message?.startsWith("File already exists"))
@@ -67731,7 +68129,7 @@ async function push7(opts, filePath, remotePath) {
67731
68129
  if (!validatePath(remotePath)) {
67732
68130
  return;
67733
68131
  }
67734
- const fstat = await stat11(filePath);
68132
+ const fstat = await stat12(filePath);
67735
68133
  if (!fstat.isFile()) {
67736
68134
  throw new Error("file path must refer to a file.");
67737
68135
  }
@@ -67779,14 +68177,16 @@ var init_variable = __esm(async () => {
67779
68177
  init_confirm()
67780
68178
  ]);
67781
68179
  import_yaml25 = __toESM(require_dist(), 1);
67782
- command14 = new Command().description("variable related commands").option("--json", "Output as JSON (for piping to jq)").action(list7).command("list", "list all variables").option("--json", "Output as JSON (for piping to jq)").action(list7).command("get", "get a variable's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get6).command("new", "create a new variable locally").arguments("<path:string>").action(newVariable).command("push", "Push a local variable spec. This overrides any remote versions.").arguments("<file_path:string> <remote_path:string>").option("--plain-secrets", "Push secrets as plain text").action(push7).command("add", "Create a new variable on the remote. This will update the variable if it already exists.").arguments("<value:string> <remote_path:string>").option("--plain-secrets", "Push secrets as plain text").option("--public", "Legacy option, use --plain-secrets instead").action(add2);
68180
+ command14 = new Command().description("variable related commands").option("--json", "Output as JSON (for piping to jq)").action(list8).command("list", "list all variables").option("--json", "Output as JSON (for piping to jq)").action(list8).command("get", "get a variable's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get6).command("new", "create a new variable locally").arguments("<path:string>").action(newVariable).command("push", "Push a local variable spec. This overrides any remote versions.").arguments("<file_path:string> <remote_path:string>").option("--plain-secrets", "Push secrets as plain text").action(push7).command("add", "Create a new variable on the remote. This will update the variable if it already exists.").arguments("<value:string> <remote_path:string>").option("--plain-secrets", "Push secrets as plain text").option("--public", "Legacy option, use --plain-secrets instead").action(add2);
67783
68181
  variable_default = command14;
67784
68182
  });
67785
68183
 
67786
68184
  // src/commands/schedule/schedule.ts
67787
- import { stat as stat12, writeFile as writeFile13 } from "node:fs/promises";
68185
+ import { stat as stat13, writeFile as writeFile13 } from "node:fs/promises";
67788
68186
  import { sep as SEP16 } from "node:path";
67789
- async function list8(opts) {
68187
+ async function list9(opts) {
68188
+ if (opts.json)
68189
+ setSilent(true);
67790
68190
  const workspace = await resolveWorkspace(opts);
67791
68191
  await requireLogin(opts);
67792
68192
  const schedules = await listSchedules({
@@ -67804,14 +68204,14 @@ async function newSchedule(opts, path17) {
67804
68204
  }
67805
68205
  const filePath = path17 + ".schedule.yaml";
67806
68206
  try {
67807
- await stat12(filePath);
68207
+ await stat13(filePath);
67808
68208
  throw new Error("File already exists: " + filePath);
67809
68209
  } catch (e) {
67810
68210
  if (e.message?.startsWith("File already exists"))
67811
68211
  throw e;
67812
68212
  }
67813
68213
  const template = {
67814
- schedule: "0 */6 * * *",
68214
+ schedule: "0 0 */6 * * *",
67815
68215
  on_failure: "",
67816
68216
  script_path: "",
67817
68217
  args: {},
@@ -67897,13 +68297,35 @@ async function pushSchedule(workspace, path17, schedule, localSchedule) {
67897
68297
  }
67898
68298
  }
67899
68299
  }
68300
+ async function enable(opts, path17) {
68301
+ opts = await mergeConfigWithConfigFile(opts);
68302
+ const workspace = await resolveWorkspace(opts);
68303
+ await requireLogin(opts);
68304
+ await setScheduleEnabled({
68305
+ workspace: workspace.workspaceId,
68306
+ path: path17,
68307
+ requestBody: { enabled: true }
68308
+ });
68309
+ info(colors.green(`Schedule ${path17} enabled.`));
68310
+ }
68311
+ async function disable(opts, path17) {
68312
+ opts = await mergeConfigWithConfigFile(opts);
68313
+ const workspace = await resolveWorkspace(opts);
68314
+ await requireLogin(opts);
68315
+ await setScheduleEnabled({
68316
+ workspace: workspace.workspaceId,
68317
+ path: path17,
68318
+ requestBody: { enabled: false }
68319
+ });
68320
+ info(colors.yellow(`Schedule ${path17} disabled.`));
68321
+ }
67900
68322
  async function push8(opts, filePath, remotePath) {
67901
68323
  const workspace = await resolveWorkspace(opts);
67902
68324
  await requireLogin(opts);
67903
68325
  if (!validatePath(remotePath)) {
67904
68326
  return;
67905
68327
  }
67906
- const fstat = await stat12(filePath);
68328
+ const fstat = await stat13(filePath);
67907
68329
  if (!fstat.isFile()) {
67908
68330
  throw new Error("file path must refer to a file.");
67909
68331
  }
@@ -67921,10 +68343,11 @@ var init_schedule = __esm(async () => {
67921
68343
  await __promiseAll([
67922
68344
  init_auth(),
67923
68345
  init_context(),
68346
+ init_conf(),
67924
68347
  init_types()
67925
68348
  ]);
67926
68349
  import_yaml26 = __toESM(require_dist(), 1);
67927
- command15 = new Command().description("schedule related commands").option("--json", "Output as JSON (for piping to jq)").action(list8).command("list", "list all schedules").option("--json", "Output as JSON (for piping to jq)").action(list8).command("get", "get a schedule's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get7).command("new", "create a new schedule locally").arguments("<path:string>").action(newSchedule).command("push", "push a local schedule spec. This overrides any remote versions.").arguments("<file_path:string> <remote_path:string>").action(push8);
68350
+ command15 = new Command().description("schedule related commands").option("--json", "Output as JSON (for piping to jq)").action(list9).command("list", "list all schedules").option("--json", "Output as JSON (for piping to jq)").action(list9).command("get", "get a schedule's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get7).command("new", "create a new schedule locally").arguments("<path:string>").action(newSchedule).command("push", "push a local schedule spec. This overrides any remote versions.").arguments("<file_path:string> <remote_path:string>").action(push8).command("enable", "Enable a schedule").arguments("<path:string>").action(enable).command("disable", "Disable a schedule").arguments("<path:string>").action(disable);
67928
68351
  schedule_default = command15;
67929
68352
  });
67930
68353
 
@@ -68553,7 +68976,7 @@ var init_settings = __esm(async () => {
68553
68976
  });
68554
68977
 
68555
68978
  // src/commands/instance/instance.ts
68556
- import { readFile as readFile13, writeFile as writeFile15, readdir as readdir8, mkdir as mkdir8, rm as rm3, stat as stat13 } from "node:fs/promises";
68979
+ import { readFile as readFile13, writeFile as writeFile15, readdir as readdir8, mkdir as mkdir8, rm as rm3, stat as stat14 } from "node:fs/promises";
68557
68980
  import { appendFile } from "node:fs/promises";
68558
68981
  import * as path17 from "node:path";
68559
68982
  async function allInstances() {
@@ -68663,6 +69086,21 @@ async function pickInstance(opts, allowNew) {
68663
69086
  prefix: opts.prefix ?? "custom"
68664
69087
  };
68665
69088
  }
69089
+ if (instances.length < 1) {
69090
+ try {
69091
+ const ws = await getActiveWorkspace({});
69092
+ if (ws?.remote && ws?.token) {
69093
+ const remote = ws.remote.endsWith("/") ? ws.remote.slice(0, -1) : ws.remote;
69094
+ setClient(ws.token, remote);
69095
+ return {
69096
+ name: ws.name,
69097
+ remote: ws.remote,
69098
+ token: ws.token,
69099
+ prefix: ws.name
69100
+ };
69101
+ }
69102
+ } catch {}
69103
+ }
68666
69104
  if (!allowNew && instances.length < 1) {
68667
69105
  throw new Error("No instance found, please add one first");
68668
69106
  }
@@ -68949,7 +69387,7 @@ Pushing workspace ` + localWorkspace.id);
68949
69387
  }
68950
69388
  async function getLocalWorkspaces(rootDir, localPrefix, folderPerInstance) {
68951
69389
  const localWorkspaces = [];
68952
- if (!await stat13(localPrefix).catch(() => null)) {
69390
+ if (!await stat14(localPrefix).catch(() => null)) {
68953
69391
  await mkdir8(localPrefix);
68954
69392
  }
68955
69393
  if (folderPerInstance) {
@@ -69004,6 +69442,21 @@ async function getActiveInstance(opts) {
69004
69442
  async function getConfig2(opts) {
69005
69443
  await pickInstance(opts, false);
69006
69444
  const config = await getInstanceConfig();
69445
+ const hasSecrets = config?.global_settings?.license_key || config?.global_settings?.jwt_secret;
69446
+ let showSecrets = opts.showSecrets ?? false;
69447
+ if (!showSecrets && hasSecrets && process.stdout.isTTY && !opts.outputFile) {
69448
+ warn("Config contains sensitive fields (license_key, jwt_secret). They are masked by default.");
69449
+ warn("Use --show-secrets to include them, or press Y to show them now.");
69450
+ showSecrets = await Confirm.prompt({ message: "Show secrets?", default: false });
69451
+ } else if (!process.stdout.isTTY || opts.outputFile) {
69452
+ showSecrets = true;
69453
+ }
69454
+ if (!showSecrets && config?.global_settings) {
69455
+ if (config.global_settings.license_key)
69456
+ config.global_settings.license_key = "***";
69457
+ if (config.global_settings.jwt_secret)
69458
+ config.global_settings.jwt_secret = "***";
69459
+ }
69007
69460
  const yaml = import_yaml29.stringify(config);
69008
69461
  if (opts.outputFile) {
69009
69462
  await writeFile15(opts.outputFile, yaml, "utf-8");
@@ -69071,7 +69524,7 @@ var init_instance = __esm(async () => {
69071
69524
  });
69072
69525
  await removeInstance(choice);
69073
69526
  info(colors.green.underline(`Removed instance ${choice}`));
69074
- }).command("switch").complete("instance", async () => (await allInstances()).map((x) => x.name)).arguments("<instance:string:instance>").description("Switch the current instance").action(switchI).command("pull").description("Pull instance settings, users, configs, instance groups and overwrite local").option("--yes", "Pull without needing confirmation").option("--dry-run", "Perform a dry run without making changes").option("--skip-users", "Skip pulling users").option("--skip-settings", "Skip pulling settings").option("--skip-configs", "Skip pulling configs (worker groups and SMTP)").option("--skip-groups", "Skip pulling instance groups").option("--include-workspaces", "Also pull workspaces").option("--folder-per-instance", "Create a folder per instance").option("--instance <instance:string>", "Name of the instance to pull from, override the active instance").option("--prefix <prefix:string>", "Prefix of the local workspaces to pull, used to create the folders when using --include-workspaces").option("--prefix-settings", "Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance").action(instancePull).command("push").description("Push instance settings, users, configs, group and overwrite remote").option("--yes", "Push without needing confirmation").option("--dry-run", "Perform a dry run without making changes").option("--skip-users", "Skip pushing users").option("--skip-settings", "Skip pushing settings").option("--skip-configs", "Skip pushing configs (worker groups and SMTP)").option("--skip-groups", "Skip pushing instance groups").option("--include-workspaces", "Also push workspaces").option("--folder-per-instance", "Create a folder per instance").option("--instance <instance:string>", "Name of the instance to push to, override the active instance").option("--prefix <prefix:string>", "Prefix of the local workspaces folders to push").option("--prefix-settings", "Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance").action(instancePush).command("whoami").description("Display information about the currently logged-in user").action(whoami3).command("get-config").description("Dump the current instance config (global settings + worker configs) as YAML").option("-o, --output-file <file:string>", "Write YAML to a file instead of stdout").option("--instance <instance:string>", "Name of the instance, override the active instance").action(getConfig2);
69527
+ }).command("switch").complete("instance", async () => (await allInstances()).map((x) => x.name)).arguments("<instance:string:instance>").description("Switch the current instance").action(switchI).command("pull").description("Pull instance settings, users, configs, instance groups and overwrite local").option("--yes", "Pull without needing confirmation").option("--dry-run", "Perform a dry run without making changes").option("--skip-users", "Skip pulling users").option("--skip-settings", "Skip pulling settings").option("--skip-configs", "Skip pulling configs (worker groups and SMTP)").option("--skip-groups", "Skip pulling instance groups").option("--include-workspaces", "Also pull workspaces").option("--folder-per-instance", "Create a folder per instance").option("--instance <instance:string>", "Name of the instance to pull from, override the active instance").option("--prefix <prefix:string>", "Prefix of the local workspaces to pull, used to create the folders when using --include-workspaces").option("--prefix-settings", "Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance").action(instancePull).command("push").description("Push instance settings, users, configs, group and overwrite remote").option("--yes", "Push without needing confirmation").option("--dry-run", "Perform a dry run without making changes").option("--skip-users", "Skip pushing users").option("--skip-settings", "Skip pushing settings").option("--skip-configs", "Skip pushing configs (worker groups and SMTP)").option("--skip-groups", "Skip pushing instance groups").option("--include-workspaces", "Also push workspaces").option("--folder-per-instance", "Create a folder per instance").option("--instance <instance:string>", "Name of the instance to push to, override the active instance").option("--prefix <prefix:string>", "Prefix of the local workspaces folders to push").option("--prefix-settings", "Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance").action(instancePush).command("whoami").description("Display information about the currently logged-in user").action(whoami3).command("get-config").description("Dump the current instance config (global settings + worker configs) as YAML").option("-o, --output-file <file:string>", "Write YAML to a file instead of stdout").option("--show-secrets", "Include sensitive fields (license key, JWT secret) without prompting").option("--instance <instance:string>", "Name of the instance, override the active instance").action(getConfig2);
69075
69528
  instance_default = command17;
69076
69529
  });
69077
69530
 
@@ -69087,7 +69540,7 @@ function checkInstanceGroupsPath(opts) {
69087
69540
  instanceGroupsPath = `${opts.prefix}/${INSTANCE_GROUPS_PATH}`;
69088
69541
  }
69089
69542
  }
69090
- async function list9(opts) {
69543
+ async function list10(opts) {
69091
69544
  await requireLogin(opts);
69092
69545
  const perPage = 10;
69093
69546
  let page = 0;
@@ -69443,7 +69896,7 @@ var init_user = __esm(async () => {
69443
69896
  import_yaml31 = __toESM(require_dist(), 1);
69444
69897
  instanceUsersPath = INSTANCE_USERS_PATH;
69445
69898
  instanceGroupsPath = INSTANCE_GROUPS_PATH;
69446
- command18 = new Command().description("user related commands").action(list9).command("add", "Create a user").arguments("<email:string> [password:string]").option("--superadmin", "Specify to make the new user superadmin.").option("--company <company:string>", "Specify to set the company of the new user.").option("--name <name:string>", "Specify to set the name of the new user.").action(add3).command("remove", "Delete a user").arguments("<email:string>").action(remove2).command("create-token").option("--email <email:string>", "Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.", {
69899
+ command18 = new Command().description("user related commands").action(list10).command("add", "Create a user").arguments("<email:string> [password:string]").option("--superadmin", "Specify to make the new user superadmin.").option("--company <company:string>", "Specify to set the company of the new user.").option("--name <name:string>", "Specify to set the name of the new user.").action(add3).command("remove", "Delete a user").arguments("<email:string>").action(remove2).command("create-token", "Create a new API token for the authenticated user").option("--email <email:string>", "Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.", {
69447
69900
  depends: ["password"]
69448
69901
  }).option("--password <password:string>", "Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.", {
69449
69902
  depends: ["email"]
@@ -69518,7 +69971,7 @@ var init_dependencies = __esm(async () => {
69518
69971
  });
69519
69972
 
69520
69973
  // src/commands/trigger/trigger.ts
69521
- import { stat as stat14, writeFile as writeFile17 } from "node:fs/promises";
69974
+ import { stat as stat15, writeFile as writeFile17 } from "node:fs/promises";
69522
69975
  import { sep as SEP17 } from "node:path";
69523
69976
  async function getTrigger(triggerType, workspace, path18) {
69524
69977
  const triggerFunctions = {
@@ -69693,7 +70146,7 @@ async function newTrigger(opts, path18) {
69693
70146
  const kind = opts.kind;
69694
70147
  const filePath = `${path18}.${kind}_trigger.yaml`;
69695
70148
  try {
69696
- await stat14(filePath);
70149
+ await stat15(filePath);
69697
70150
  throw new Error("File already exists: " + filePath);
69698
70151
  } catch (e) {
69699
70152
  if (e.message?.startsWith("File already exists"))
@@ -69742,7 +70195,7 @@ async function get8(opts, path18) {
69742
70195
  } else {
69743
70196
  console.log(colors.bold("Path:") + " " + trigger.path);
69744
70197
  console.log(colors.bold("Kind:") + " " + kind);
69745
- console.log(colors.bold("Enabled:") + " " + (trigger.enabled ?? "-"));
70198
+ console.log(colors.bold("Enabled:") + " " + (trigger.enabled ?? trigger.mode ?? "-"));
69746
70199
  console.log(colors.bold("Script Path:") + " " + (trigger.script_path ?? ""));
69747
70200
  console.log(colors.bold("Is Flow:") + " " + (trigger.is_flow ? "true" : "false"));
69748
70201
  }
@@ -69761,7 +70214,9 @@ async function listOrEmpty(fn) {
69761
70214
  return [];
69762
70215
  }
69763
70216
  }
69764
- async function list10(opts) {
70217
+ async function list11(opts) {
70218
+ if (opts.json)
70219
+ setSilent(true);
69765
70220
  const workspace = await resolveWorkspace(opts);
69766
70221
  await requireLogin(opts);
69767
70222
  const ws = workspace.workspaceId;
@@ -69827,7 +70282,7 @@ async function push10(opts, filePath, remotePath) {
69827
70282
  if (!validatePath(remotePath)) {
69828
70283
  return;
69829
70284
  }
69830
- const fstat = await stat14(filePath);
70285
+ const fstat = await stat15(filePath);
69831
70286
  if (!fstat.isFile()) {
69832
70287
  throw new Error("file path must refer to a file.");
69833
70288
  }
@@ -69861,12 +70316,21 @@ var init_trigger = __esm(async () => {
69861
70316
  route_path: "",
69862
70317
  http_method: "get",
69863
70318
  is_async: false,
69864
- requires_auth: true
70319
+ requires_auth: true,
70320
+ request_type: "sync",
70321
+ authentication_method: "none",
70322
+ is_static_website: false,
70323
+ workspaced_route: false,
70324
+ wrap_body: false,
70325
+ raw_string: false
69865
70326
  },
69866
70327
  websocket: {
69867
70328
  script_path: "",
69868
70329
  is_flow: false,
69869
70330
  url: "",
70331
+ filters: [],
70332
+ can_return_message: false,
70333
+ can_return_error_result: false,
69870
70334
  enabled: false
69871
70335
  },
69872
70336
  kafka: {
@@ -69875,6 +70339,7 @@ var init_trigger = __esm(async () => {
69875
70339
  kafka_resource_path: "",
69876
70340
  group_id: "",
69877
70341
  topics: [],
70342
+ filters: [],
69878
70343
  enabled: false
69879
70344
  },
69880
70345
  nats: {
@@ -69882,6 +70347,7 @@ var init_trigger = __esm(async () => {
69882
70347
  is_flow: false,
69883
70348
  nats_resource_path: "",
69884
70349
  subjects: [],
70350
+ use_jetstream: false,
69885
70351
  enabled: false
69886
70352
  },
69887
70353
  postgres: {
@@ -69896,23 +70362,25 @@ var init_trigger = __esm(async () => {
69896
70362
  script_path: "",
69897
70363
  is_flow: false,
69898
70364
  mqtt_resource_path: "",
69899
- topics: [],
69900
- subscribe_qos: 0,
70365
+ subscribe_topics: [],
69901
70366
  enabled: false
69902
70367
  },
69903
70368
  sqs: {
69904
70369
  script_path: "",
69905
70370
  is_flow: false,
69906
- sqs_resource_path: "",
69907
70371
  queue_url: "",
70372
+ aws_resource_path: "",
70373
+ aws_auth_resource_type: "credentials",
69908
70374
  enabled: false
69909
70375
  },
69910
70376
  gcp: {
69911
70377
  script_path: "",
69912
70378
  is_flow: false,
69913
70379
  gcp_resource_path: "",
69914
- subscription_id: "",
69915
70380
  topic_id: "",
70381
+ subscription_id: "",
70382
+ delivery_type: "pull",
70383
+ subscription_mode: "create_update",
69916
70384
  enabled: false
69917
70385
  },
69918
70386
  email: {
@@ -69921,7 +70389,7 @@ var init_trigger = __esm(async () => {
69921
70389
  enabled: false
69922
70390
  }
69923
70391
  };
69924
- command20 = new Command().description("trigger related commands").option("--json", "Output as JSON (for piping to jq)").action(list10).command("list", "list all triggers").option("--json", "Output as JSON (for piping to jq)").action(list10).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);
70392
+ 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);
69925
70393
  trigger_default = command20;
69926
70394
  });
69927
70395
 
@@ -69982,9 +70450,15 @@ async function pushObj(workspace, p, befObj, newObj, plainSecrets, alreadySynced
69982
70450
  const typeEnding = getTypeStrFromPath(p);
69983
70451
  if (typeEnding === "app") {
69984
70452
  const appName = extractResourceName(p, "app");
70453
+ if (!appName) {
70454
+ throw new Error(`Could not extract app name from path: ${p}`);
70455
+ }
69985
70456
  await pushApp(workspace, appName, buildFolderPath(appName, "app"), message);
69986
70457
  } else if (typeEnding === "raw_app") {
69987
70458
  const rawAppName = extractResourceName(p, "raw_app");
70459
+ if (!rawAppName) {
70460
+ throw new Error(`Could not extract raw app name from path: ${p}`);
70461
+ }
69988
70462
  await pushRawApp(workspace, rawAppName, buildFolderPath(rawAppName, "raw_app"), message);
69989
70463
  } else if (typeEnding === "folder") {
69990
70464
  await pushFolder(workspace, p, befObj, newObj);
@@ -69992,6 +70466,9 @@ async function pushObj(workspace, p, befObj, newObj, plainSecrets, alreadySynced
69992
70466
  await pushVariable(workspace, p, befObj, newObj, plainSecrets);
69993
70467
  } else if (typeEnding === "flow") {
69994
70468
  const flowName = extractResourceName(p, "flow");
70469
+ if (!flowName) {
70470
+ throw new Error(`Could not extract flow name from path: ${p}`);
70471
+ }
69995
70472
  await pushFlow(workspace, flowName, buildFolderPath(flowName, "flow"), message);
69996
70473
  } else if (typeEnding === "resource") {
69997
70474
  if (!alreadySynced3.includes(p)) {
@@ -70092,10 +70569,13 @@ function getTypeStrFromPath(p) {
70092
70569
  }
70093
70570
  function removeType(str, type) {
70094
70571
  const normalizedStr = path18.normalize(str).replaceAll(SEP18, "/");
70095
- if (!normalizedStr.endsWith("." + type + ".yaml") && !normalizedStr.endsWith("." + type + ".json")) {
70096
- throw new Error(str + " does not end with ." + type + ".(yaml|json)");
70572
+ if (normalizedStr.endsWith("." + type + ".yaml") || normalizedStr.endsWith("." + type + ".json")) {
70573
+ return normalizedStr.slice(0, normalizedStr.length - type.length - 6);
70097
70574
  }
70098
- return normalizedStr.slice(0, normalizedStr.length - type.length - 6);
70575
+ if (normalizedStr.includes("." + type)) {
70576
+ debug(`Path '${str}' contains '.${type}' but doesn't end with '.${type}.(yaml|json)' — treating as clean path`);
70577
+ }
70578
+ return normalizedStr;
70099
70579
  }
70100
70580
  function extractNativeTriggerInfo(p) {
70101
70581
  const normalizedPath = path18.normalize(p).replaceAll(SEP18, "/");
@@ -70175,14 +70655,13 @@ function defaultFlowDefinition() {
70175
70655
  order: [],
70176
70656
  properties: {},
70177
70657
  required: []
70178
- },
70179
- ws_error_handler_muted: false
70658
+ }
70180
70659
  };
70181
70660
  }
70182
70661
 
70183
70662
  // src/utils/local_path_scripts.ts
70184
70663
  import { execFileSync as execFileSync2 } from "node:child_process";
70185
- import { readFile as readFile14, stat as stat15 } from "node:fs/promises";
70664
+ import { readFile as readFile14, stat as stat16 } from "node:fs/promises";
70186
70665
  async function readOptionalLock(scriptPath) {
70187
70666
  try {
70188
70667
  return await readFile14(scriptPath + ".script.lock", "utf-8");
@@ -70246,7 +70725,7 @@ async function resolvePreviewLocalScriptState(scriptPath, opts) {
70246
70725
  const filePath = scriptPath + ext2;
70247
70726
  let fileStat;
70248
70727
  try {
70249
- fileStat = await stat15(filePath);
70728
+ fileStat = await stat16(filePath);
70250
70729
  } catch {
70251
70730
  continue;
70252
70731
  }
@@ -70406,7 +70885,9 @@ async function push11(opts, filePath, remotePath) {
70406
70885
  await pushFlow(workspace.workspaceId, remotePath, filePath);
70407
70886
  info(colors.bold.underline.green("Flow pushed"));
70408
70887
  }
70409
- async function list11(opts) {
70888
+ async function list12(opts) {
70889
+ if (opts.json)
70890
+ setSilent(true);
70410
70891
  const workspace = await resolveWorkspace(opts);
70411
70892
  await requireLogin(opts);
70412
70893
  let page = 0;
@@ -70447,9 +70928,21 @@ async function get9(opts, path19) {
70447
70928
  console.log(colors.bold("Description:") + " " + (f.description ?? ""));
70448
70929
  console.log(colors.bold("Edited by:") + " " + (f.edited_by ?? ""));
70449
70930
  console.log(colors.bold("Edited at:") + " " + (f.edited_at ?? ""));
70931
+ const modules = f.value?.modules;
70932
+ if (modules && Array.isArray(modules) && modules.length > 0) {
70933
+ console.log(colors.bold("Steps:"));
70934
+ for (const mod of modules) {
70935
+ const type = mod.value?.type ?? "unknown";
70936
+ const detail = mod.value?.language ?? mod.value?.path ?? "";
70937
+ console.log(` ${mod.id}: ${type}${detail ? " (" + detail + ")" : ""}`);
70938
+ }
70939
+ }
70450
70940
  }
70451
70941
  }
70452
70942
  async function run3(opts, path19) {
70943
+ if (opts.silent) {
70944
+ setSilent(true);
70945
+ }
70453
70946
  const workspace = await resolveWorkspace(opts);
70454
70947
  await requireLogin(opts);
70455
70948
  const input = opts.data ? await resolve6(opts.data) : {};
@@ -70491,9 +70984,16 @@ async function run3(opts, path19) {
70491
70984
  workspace: workspace.workspaceId,
70492
70985
  id
70493
70986
  });
70494
- info(JSON.stringify(jobInfo.result ?? {}, null, 2));
70987
+ if (opts.silent) {
70988
+ console.log(JSON.stringify(jobInfo.result ?? {}));
70989
+ } else {
70990
+ info(JSON.stringify(jobInfo.result ?? {}, null, 2));
70991
+ }
70495
70992
  }
70496
70993
  async function preview2(opts, flowPath) {
70994
+ if (opts.silent) {
70995
+ setSilent(true);
70996
+ }
70497
70997
  const useLocalPathScripts = !opts.remote;
70498
70998
  if (useLocalPathScripts) {
70499
70999
  opts = await mergeConfigWithConfigFile(opts);
@@ -70501,11 +71001,12 @@ async function preview2(opts, flowPath) {
70501
71001
  const workspace = await resolveWorkspace(opts);
70502
71002
  await requireLogin(opts);
70503
71003
  const codebases = useLocalPathScripts ? listSyncCodebases(opts) : [];
70504
- if (!flowPath.endsWith(".flow") && !flowPath.endsWith(".flow" + SEP19)) {
71004
+ const isFlowDir = flowPath.endsWith(".flow") || flowPath.endsWith(".flow" + SEP19) || flowPath.endsWith("__flow") || flowPath.endsWith("__flow" + SEP19);
71005
+ if (!isFlowDir) {
70505
71006
  if (flowPath.endsWith("flow.yaml") || flowPath.endsWith("flow.json")) {
70506
71007
  flowPath = flowPath.substring(0, flowPath.lastIndexOf(SEP19));
70507
71008
  } else {
70508
- throw new Error("Flow path must be a .flow directory or a flow.yaml file");
71009
+ throw new Error("Flow path must be a .flow/__flow directory or a flow.yaml file");
70509
71010
  }
70510
71011
  }
70511
71012
  if (!flowPath.endsWith(SEP19)) {
@@ -70561,7 +71062,7 @@ async function preview2(opts, flowPath) {
70561
71062
  throw e;
70562
71063
  }
70563
71064
  if (opts.silent) {
70564
- console.log(JSON.stringify(result, null, 2));
71065
+ console.log(JSON.stringify(result));
70565
71066
  } else {
70566
71067
  info(colors.bold.underline.green("Flow preview completed"));
70567
71068
  info(JSON.stringify(result, null, 2));
@@ -70607,11 +71108,12 @@ async function generateLocks(opts, folder) {
70607
71108
  }
70608
71109
  }
70609
71110
  }
70610
- function bootstrap2(opts, flowPath) {
71111
+ async function bootstrap2(opts, flowPath) {
70611
71112
  if (!validatePath(flowPath)) {
70612
71113
  return;
70613
71114
  }
70614
- const flowDirFullPath = `${flowPath}.flow`;
71115
+ await loadNonDottedPathsSetting();
71116
+ const flowDirFullPath = buildFolderPath(flowPath, "flow");
70615
71117
  mkdirSync4(flowDirFullPath, { recursive: false });
70616
71118
  const newFlowDefinition = defaultFlowDefinition();
70617
71119
  if (opts.summary !== undefined) {
@@ -70621,9 +71123,57 @@ function bootstrap2(opts, flowPath) {
70621
71123
  newFlowDefinition.description = opts.description;
70622
71124
  }
70623
71125
  const newFlowDefinitionYaml = import_yaml36.stringify(newFlowDefinition);
70624
- const flowYamlPath = `${flowDirFullPath}/flow.yaml`;
71126
+ const metadataFile = getMetadataFileName("flow", "yaml");
71127
+ const flowYamlPath = `${flowDirFullPath}/${metadataFile}`;
70625
71128
  writeFileSync5(flowYamlPath, newFlowDefinitionYaml, { flag: "wx", encoding: "utf-8" });
70626
71129
  }
71130
+ async function history2(opts, flowPath) {
71131
+ if (opts.json)
71132
+ setSilent(true);
71133
+ opts = await mergeConfigWithConfigFile(opts);
71134
+ const workspace = await resolveWorkspace(opts);
71135
+ await requireLogin(opts);
71136
+ const versions = await getFlowHistory({
71137
+ workspace: workspace.workspaceId,
71138
+ path: flowPath
71139
+ });
71140
+ if (opts.json) {
71141
+ console.log(JSON.stringify(versions));
71142
+ } else {
71143
+ if (versions.length === 0) {
71144
+ info("No version history found for " + flowPath);
71145
+ return;
71146
+ }
71147
+ new Table2().header(["Version", "Created At", "Deployment Message"]).padding(2).border(true).body(versions.map((v) => [
71148
+ String(v.id),
71149
+ new Date(v.created_at).toISOString().replace("T", " ").substring(0, 19),
71150
+ v.deployment_msg ?? "-"
71151
+ ])).render();
71152
+ }
71153
+ }
71154
+ async function showVersion(opts, flowPath, version) {
71155
+ if (opts.json)
71156
+ setSilent(true);
71157
+ opts = await mergeConfigWithConfigFile(opts);
71158
+ const workspace = await resolveWorkspace(opts);
71159
+ await requireLogin(opts);
71160
+ const flow = await getFlowVersion({
71161
+ workspace: workspace.workspaceId,
71162
+ path: flowPath,
71163
+ version: parseInt(version, 10)
71164
+ });
71165
+ if (opts.json) {
71166
+ console.log(JSON.stringify(flow));
71167
+ } else {
71168
+ console.log(colors.bold("Path:") + " " + flow.path);
71169
+ console.log(colors.bold("Summary:") + " " + (flow.summary ?? "-"));
71170
+ console.log(colors.bold("Description:") + " " + (flow.description ?? "-"));
71171
+ console.log(colors.bold("Schema:"));
71172
+ console.log(JSON.stringify(flow.schema, null, 2));
71173
+ console.log(colors.bold("Value:"));
71174
+ console.log(JSON.stringify(flow.value, null, 2));
71175
+ }
71176
+ }
70627
71177
  var import_yaml36, alreadySynced3, command21, flow_default;
70628
71178
  var init_flow = __esm(async () => {
70629
71179
  init_colors2();
@@ -70632,6 +71182,7 @@ var init_flow = __esm(async () => {
70632
71182
  init_log();
70633
71183
  init_yaml();
70634
71184
  init_services_gen();
71185
+ init_resource_folders();
70635
71186
  await __promiseAll([
70636
71187
  init_types(),
70637
71188
  init_confirm(),
@@ -70647,7 +71198,7 @@ var init_flow = __esm(async () => {
70647
71198
  ]);
70648
71199
  import_yaml36 = __toESM(require_dist(), 1);
70649
71200
  alreadySynced3 = [];
70650
- 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);
71201
+ 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);
70651
71202
  flow_default = command21;
70652
71203
  });
70653
71204
 
@@ -71831,22 +72382,22 @@ class DoubleLinkedDependencyTree {
71831
72382
  return this.nodes.has(path19);
71832
72383
  }
71833
72384
  getMismatchedWorkspaceDeps() {
71834
- const result = {};
72385
+ const result2 = {};
71835
72386
  for (const [path19, node] of this.nodes.entries()) {
71836
72387
  if (node.itemType === "dependencies" && node.contentHash && node.content !== undefined) {
71837
- result[path19] = node.content;
72388
+ result2[path19] = node.content;
71838
72389
  }
71839
72390
  }
71840
- return result;
72391
+ return result2;
71841
72392
  }
71842
72393
  getTempScriptRefs(scriptPath) {
71843
- const result = {};
72394
+ const result2 = {};
71844
72395
  this.traverseTransitive(scriptPath, (_path, node) => {
71845
72396
  if (node.contentHash) {
71846
- result[_path] = node.contentHash;
72397
+ result2[_path] = node.contentHash;
71847
72398
  }
71848
72399
  });
71849
- return result;
72400
+ return result2;
71850
72401
  }
71851
72402
  async persistDepsHashes(depsPaths) {
71852
72403
  for (const path19 of depsPaths) {
@@ -73113,8 +73664,8 @@ async function pull2(opts) {
73113
73664
  throw new Error("Couldn't fetch resource types from hub " + hubBaseUrl + ": " + await res1.text());
73114
73665
  }
73115
73666
  }
73116
- let list12 = await res1.json();
73117
- if (list12 && list12.length === 0 && hubBaseUrl !== DEFAULT_HUB_BASE_URL) {
73667
+ let list13 = await res1.json();
73668
+ if (list13 && list13.length === 0 && hubBaseUrl !== DEFAULT_HUB_BASE_URL) {
73118
73669
  info("No resource types found in private hub, fetching from public hub");
73119
73670
  delete headers["X-api-secret"];
73120
73671
  const res2 = await fetch(DEFAULT_HUB_BASE_URL + "/resource_types/list", {
@@ -73123,12 +73674,12 @@ async function pull2(opts) {
73123
73674
  if (!res2.ok) {
73124
73675
  throw new Error("Couldn't fetch resource types from public hub: " + await res2.text());
73125
73676
  }
73126
- list12 = await res2.json();
73677
+ list13 = await res2.json();
73127
73678
  }
73128
73679
  const resourceTypes = await listResourceType({
73129
73680
  workspace: workspace.workspaceId
73130
73681
  });
73131
- for (const x of list12) {
73682
+ for (const x of list13) {
73132
73683
  try {
73133
73684
  x.schema = JSON.parse(x.schema);
73134
73685
  } catch (e) {
@@ -73320,7 +73871,7 @@ async function dev2(opts) {
73320
73871
  await Promise.all([startApp(), watchChanges()]);
73321
73872
  console.log("Stopped dev mode");
73322
73873
  }
73323
- var command24 = new Command().description("Launch a dev server that will spawn a webserver with HMR").option("--includes <pattern...:string>", "Filter paths givena glob pattern or path").action(dev2);
73874
+ var command24 = new Command().description("Launch a dev server that watches for local file changes and auto-pushes them to the remote workspace. Provides live reload for scripts and flows during development.").option("--includes <pattern...:string>", "Filter paths givena glob pattern or path").action(dev2);
73324
73875
  var dev_default2 = command24;
73325
73876
 
73326
73877
  // src/main.ts
@@ -73560,8 +74111,7 @@ await __promiseAll([
73560
74111
  init_workspace(),
73561
74112
  init_resource_type()
73562
74113
  ]);
73563
- var import_yaml40 = __toESM(require_dist(), 1);
73564
- import { stat as stat16, writeFile as writeFile19, rm as rm4, mkdir as mkdir9 } from "node:fs/promises";
74114
+ import { stat as stat17, writeFile as writeFile19, rm as rm4, mkdir as mkdir9 } from "node:fs/promises";
73565
74115
 
73566
74116
  // src/guidance/skills.ts
73567
74117
  var SKILLS = [
@@ -78555,6 +79105,23 @@ app related commands
78555
79105
  - \`--dry-run\` - Perform a dry run without making changes
78556
79106
  - \`--default-ts <runtime:string>\` - Default TypeScript runtime (bun or deno)
78557
79107
 
79108
+ ### audit
79109
+
79110
+ View audit logs (requires admin)
79111
+
79112
+ **Subcommands:**
79113
+
79114
+ - \`audit list\` - List audit log entries
79115
+ - \`audit get <id:string>\` - Get a specific audit log entry
79116
+ - \`--json\` - Output as JSON (for piping to jq)
79117
+
79118
+ ### config
79119
+
79120
+ Show all available wmill.yaml configuration options
79121
+
79122
+ **Options:**
79123
+ - \`--json\` - Output as JSON for programmatic consumption
79124
+
78558
79125
  ### dependencies
78559
79126
 
78560
79127
  workspace dependencies related commands
@@ -78567,14 +79134,14 @@ workspace dependencies related commands
78567
79134
 
78568
79135
  ### dev
78569
79136
 
78570
- Launch a dev server that will spawn a webserver with HMR
79137
+ Launch a dev server that watches for local file changes and auto-pushes them to the remote workspace. Provides live reload for scripts and flows during development.
78571
79138
 
78572
79139
  **Options:**
78573
79140
  - \`--includes <pattern...:string>\` - Filter paths givena glob pattern or path
78574
79141
 
78575
79142
  ### docs
78576
79143
 
78577
- Search Windmill documentation. Requires Enterprise Edition.
79144
+ Search Windmill documentation.
78578
79145
 
78579
79146
  **Arguments:** \`<query:string>\`
78580
79147
 
@@ -78615,6 +79182,10 @@ flow related commands
78615
79182
  - \`flow bootstrap <flow_path:string>\` - create a new empty flow (alias for new
78616
79183
  - \`--summary <summary:string>\` - flow summary
78617
79184
  - \`--description <description:string>\` - flow description
79185
+ - \`flow history <path:string>\` - Show version history for a flow
79186
+ - \`--json\` - Output as JSON (for piping to jq)
79187
+ - \`flow show-version <path:string> <version:string>\` - Show a specific version of a flow
79188
+ - \`--json\` - Output as JSON (for piping to jq)
78618
79189
 
78619
79190
  ### folder
78620
79191
 
@@ -78677,6 +79248,25 @@ Manage git-sync settings between local wmill.yaml and Windmill backend
78677
79248
  - \`--yes\` - Skip interactive prompts and use default behavior
78678
79249
  - \`--promotion <branch:string>\` - Use promotionOverrides from the specified branch instead of regular overrides
78679
79250
 
79251
+ ### group
79252
+
79253
+ Manage workspace groups
79254
+
79255
+ **Options:**
79256
+ - \`--json\` - Output as JSON (for piping to jq)
79257
+
79258
+ **Subcommands:**
79259
+
79260
+ - \`group list\` - List all groups in the workspace
79261
+ - \`--json\` - Output as JSON (for piping to jq)
79262
+ - \`group get <name:string>\` - Get group details and members
79263
+ - \`--json\` - Output as JSON (for piping to jq)
79264
+ - \`group create <name:string>\` - Create a new group
79265
+ - \`--summary <summary:string>\` - Group summary/description
79266
+ - \`group delete <name:string>\` - Delete a group
79267
+ - \`group add-user <name:string> <username:string>\` - Add a user to a group
79268
+ - \`group remove-user <name:string> <username:string>\` - Remove a user from a group
79269
+
78680
79270
  ### hub
78681
79271
 
78682
79272
  Hub related commands. EXPERIMENTAL. INTERNAL USE ONLY.
@@ -78732,8 +79322,23 @@ sync local with a remote instance or the opposite (push or pull)
78732
79322
  - \`instance whoami\` - Display information about the currently logged-in user
78733
79323
  - \`instance get-config\` - Dump the current instance config (global settings + worker configs) as YAML
78734
79324
  - \`-o, --output-file <file:string>\` - Write YAML to a file instead of stdout
79325
+ - \`--show-secrets\` - Include sensitive fields (license key, JWT secret) without prompting
78735
79326
  - \`--instance <instance:string>\` - Name of the instance, override the active instance
78736
79327
 
79328
+ ### job
79329
+
79330
+ Manage jobs (list, inspect, cancel)
79331
+
79332
+ **Subcommands:**
79333
+
79334
+ - \`job list\` - List recent jobs
79335
+ - \`job get <id:string>\` - Get job details and result
79336
+ - \`--json\` - Output as JSON (for piping to jq)
79337
+ - \`job result <id:string>\` - Get the result of a completed job (machine-friendly
79338
+ - \`job logs <id:string>\` - Get job logs
79339
+ - \`job cancel <id:string>\` - Cancel a running or queued job
79340
+ - \`--reason <reason:string>\` - Reason for cancellation
79341
+
78737
79342
  ### jobs
78738
79343
 
78739
79344
  Pull completed and queued jobs from workspace
@@ -78820,6 +79425,8 @@ schedule related commands
78820
79425
  - \`--json\` - Output as JSON (for piping to jq)
78821
79426
  - \`schedule new <path:string>\` - create a new schedule locally
78822
79427
  - \`schedule push <file_path:string> <remote_path:string>\` - push a local schedule spec. This overrides any remote versions.
79428
+ - \`schedule enable <path:string>\` - Enable a schedule
79429
+ - \`schedule disable <path:string>\` - Disable a schedule
78823
79430
 
78824
79431
  ### script
78825
79432
 
@@ -78857,6 +79464,8 @@ script related commands
78857
79464
  - \`--schema-only\` - re-generate only script schema
78858
79465
  - \`-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)
78859
79466
  - \`-e --excludes <patterns:file[]>\` - Comma separated patterns to specify which file to NOT take into account.
79467
+ - \`script history <path:string>\` - show version history for a script
79468
+ - \`--json\` - Output as JSON (for piping to jq)
78860
79469
 
78861
79470
  ### sync
78862
79471
 
@@ -78871,6 +79480,7 @@ sync local with a remote workspaces or the opposite (push or pull)
78871
79480
  - \`--json\` - Use JSON instead of YAML
78872
79481
  - \`--skip-variables\` - Skip syncing variables (including secrets)
78873
79482
  - \`--skip-secrets\` - Skip syncing only secrets variables
79483
+ - \`--include-secrets\` - Include secrets in sync (overrides skipSecrets in wmill.yaml)
78874
79484
  - \`--skip-resources\` - Skip syncing resources
78875
79485
  - \`--skip-resource-types\` - Skip syncing resource types
78876
79486
  - \`--skip-scripts\` - Skip syncing scripts
@@ -78900,6 +79510,7 @@ sync local with a remote workspaces or the opposite (push or pull)
78900
79510
  - \`--json\` - Use JSON instead of YAML
78901
79511
  - \`--skip-variables\` - Skip syncing variables (including secrets)
78902
79512
  - \`--skip-secrets\` - Skip syncing only secrets variables
79513
+ - \`--include-secrets\` - Include secrets in sync (overrides skipSecrets in wmill.yaml)
78903
79514
  - \`--skip-resources\` - Skip syncing resources
78904
79515
  - \`--skip-resource-types\` - Skip syncing resource types
78905
79516
  - \`--skip-scripts\` - Skip syncing scripts
@@ -78925,6 +79536,23 @@ sync local with a remote workspaces or the opposite (push or pull)
78925
79536
  - \`--branch, --env <branch:string>\` - Override the current git branch/environment (works even outside a git repository)
78926
79537
  - \`--lint\` - Run lint validation before pushing
78927
79538
  - \`--locks-required\` - Fail if scripts or flow inline scripts that need locks have no locks
79539
+ - \`--auto-metadata\` - Automatically regenerate stale metadata (locks and schemas) before pushing
79540
+
79541
+ ### token
79542
+
79543
+ Manage API tokens
79544
+
79545
+ **Options:**
79546
+ - \`--json\` - Output as JSON (for piping to jq)
79547
+
79548
+ **Subcommands:**
79549
+
79550
+ - \`token list\` - List API tokens
79551
+ - \`--json\` - Output as JSON (for piping to jq)
79552
+ - \`token create\` - Create a new API token
79553
+ - \`--label <label:string>\` - Token label
79554
+ - \`--expiration <expiration:string>\` - Token expiration (ISO 8601 timestamp)
79555
+ - \`token delete <token_prefix:string>\` - Delete a token by its prefix
78928
79556
 
78929
79557
  ### trigger
78930
79558
 
@@ -78955,7 +79583,7 @@ user related commands
78955
79583
  - \`--company <company:string>\` - Specify to set the company of the new user.
78956
79584
  - \`--name <name:string>\` - Specify to set the name of the new user.
78957
79585
  - \`user remove <email:string>\` - Delete a user
78958
- - \`user create-token\`
79586
+ - \`user create-token\` - Create a new API token for the authenticated user
78959
79587
  - \`--email <email:string>\` - Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.
78960
79588
  - \`--password <password:string>\` - Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.
78961
79589
 
@@ -79023,7 +79651,8 @@ workspace related commands
79023
79651
  - \`workspace whoami\` - Show the currently active user
79024
79652
  - \`workspace list\` - List local workspace profiles
79025
79653
  - \`workspace list-remote\` - List workspaces on the remote server that you have access to
79026
- - \`workspace bind\` - Bind the current Git branch to the active workspace
79654
+ - \`workspace list-forks\` - List forked workspaces on the remote server
79655
+ - \`workspace bind\` - Bind the current Git branch to the active workspace. This adds the branch to gitBranches in wmill.yaml so sync operations use the correct workspace for each branch.
79027
79656
  - \`--branch, --env <branch:string>\` - Specify branch/environment (defaults to current)
79028
79657
  - \`workspace unbind\` - Remove workspace binding from the current Git branch
79029
79658
  - \`--branch, --env <branch:string>\` - Specify branch/environment (defaults to current)
@@ -79950,6 +80579,406 @@ ${skillsReference}
79950
80579
  `;
79951
80580
  }
79952
80581
 
80582
+ // src/commands/init/template.ts
80583
+ var NON_SCHEMA_KEYS = new Set([
80584
+ "name",
80585
+ "default",
80586
+ "section",
80587
+ "sectionNote",
80588
+ "commented",
80589
+ "templateValue",
80590
+ "example",
80591
+ "inlineComment",
80592
+ "groupNote"
80593
+ ]);
80594
+ var SPECIFIC_ITEMS_SCHEMA = {
80595
+ type: "object",
80596
+ description: "Sync only specific items",
80597
+ properties: {
80598
+ variables: { type: "array", items: { type: "string" }, description: "Specific variable paths to sync" },
80599
+ resources: { type: "array", items: { type: "string" }, description: "Specific resource paths to sync" },
80600
+ triggers: { type: "array", items: { type: "string" }, description: "Specific trigger paths to sync" },
80601
+ folders: { type: "array", items: { type: "string" }, description: "Specific folder paths to sync" },
80602
+ settings: { type: "boolean", description: "Whether to sync settings" }
80603
+ },
80604
+ additionalProperties: false
80605
+ };
80606
+ var BRANCH_CONFIG_SCHEMA = {
80607
+ type: "object",
80608
+ properties: {
80609
+ baseUrl: { type: "string", description: "Windmill instance URL for this branch" },
80610
+ workspaceId: { type: "string", description: "Workspace ID to sync with for this branch" },
80611
+ overrides: { type: "object", description: "Override any top-level sync option for this branch" },
80612
+ promotionOverrides: { type: "object", description: "Overrides applied when using --promotion flag" },
80613
+ specificItems: SPECIFIC_ITEMS_SCHEMA
80614
+ },
80615
+ additionalProperties: false
80616
+ };
80617
+ var CONFIG_REFERENCE = [
80618
+ { name: "defaultTs", type: "string", enum: ["bun", "deno"], default: "bun", description: "Default TypeScript runtime for new scripts" },
80619
+ {
80620
+ name: "includes",
80621
+ type: "array",
80622
+ items: { type: "string" },
80623
+ default: '["f/**"]',
80624
+ description: "Glob patterns for files to include in sync",
80625
+ templateValue: `
80626
+ - "f/**"`
80627
+ },
80628
+ {
80629
+ name: "extraIncludes",
80630
+ type: "array",
80631
+ items: { type: "string" },
80632
+ default: "[]",
80633
+ description: "Additional glob patterns merged with includes (useful in branch overrides)",
80634
+ commented: true
80635
+ },
80636
+ { name: "excludes", type: "array", items: { type: "string" }, default: "[]", description: "Glob patterns for files to exclude from sync" },
80637
+ {
80638
+ name: "skipVariables",
80639
+ type: "boolean",
80640
+ default: "false",
80641
+ description: "Skip syncing variables",
80642
+ section: "What to sync",
80643
+ sectionNote: '"skip" options default to false (synced), "include" options default to false (not synced)'
80644
+ },
80645
+ { name: "skipResources", type: "boolean", default: "false", description: "Skip syncing resources" },
80646
+ { name: "skipResourceTypes", type: "boolean", default: "false", description: "Skip syncing resource types" },
80647
+ {
80648
+ name: "skipSecrets",
80649
+ type: "boolean",
80650
+ default: "true",
80651
+ description: "Skip syncing secrets (true by default for security)",
80652
+ inlineComment: "true by default — secrets are not synced for security"
80653
+ },
80654
+ { name: "skipScripts", type: "boolean", default: "false", description: "Skip syncing scripts" },
80655
+ { name: "skipFlows", type: "boolean", default: "false", description: "Skip syncing flows" },
80656
+ { name: "skipApps", type: "boolean", default: "false", description: "Skip syncing apps" },
80657
+ { name: "skipFolders", type: "boolean", default: "false", description: "Skip syncing folders" },
80658
+ { name: "skipWorkspaceDependencies", type: "boolean", default: "false", description: "Skip syncing workspace dependencies" },
80659
+ {
80660
+ name: "includeSchedules",
80661
+ type: "boolean",
80662
+ default: "false",
80663
+ description: "Include schedules in sync",
80664
+ commented: true,
80665
+ templateValue: "true",
80666
+ groupNote: "Uncomment to include these (excluded by default):"
80667
+ },
80668
+ {
80669
+ name: "includeTriggers",
80670
+ type: "boolean",
80671
+ default: "false",
80672
+ description: "Include triggers (http, websocket, kafka, etc.) in sync",
80673
+ commented: true,
80674
+ templateValue: "true"
80675
+ },
80676
+ {
80677
+ name: "includeUsers",
80678
+ type: "boolean",
80679
+ default: "false",
80680
+ description: "Include workspace users in sync",
80681
+ commented: true,
80682
+ templateValue: "true"
80683
+ },
80684
+ {
80685
+ name: "includeGroups",
80686
+ type: "boolean",
80687
+ default: "false",
80688
+ description: "Include workspace groups in sync",
80689
+ commented: true,
80690
+ templateValue: "true"
80691
+ },
80692
+ {
80693
+ name: "includeSettings",
80694
+ type: "boolean",
80695
+ default: "false",
80696
+ description: "Include workspace settings in sync",
80697
+ commented: true,
80698
+ templateValue: "true"
80699
+ },
80700
+ {
80701
+ name: "includeKey",
80702
+ type: "boolean",
80703
+ default: "false",
80704
+ description: "Include encryption key in sync",
80705
+ commented: true,
80706
+ templateValue: "true"
80707
+ },
80708
+ {
80709
+ name: "parallel",
80710
+ type: "integer",
80711
+ default: "(unset)",
80712
+ description: "Number of parallel operations during sync",
80713
+ section: "Sync behavior",
80714
+ commented: true,
80715
+ templateValue: "4"
80716
+ },
80717
+ {
80718
+ name: "locksRequired",
80719
+ type: "boolean",
80720
+ default: "false",
80721
+ description: "Require lock files for all scripts",
80722
+ commented: true,
80723
+ templateValue: "true"
80724
+ },
80725
+ {
80726
+ name: "lint",
80727
+ type: "boolean",
80728
+ default: "false",
80729
+ description: "Run linting before push",
80730
+ commented: true,
80731
+ templateValue: "true"
80732
+ },
80733
+ {
80734
+ name: "plainSecrets",
80735
+ type: "boolean",
80736
+ default: "false",
80737
+ description: "Handle secrets as plain text (not recommended)",
80738
+ commented: true
80739
+ },
80740
+ {
80741
+ name: "message",
80742
+ type: "string",
80743
+ default: "(unset)",
80744
+ description: "Default commit message for sync operations",
80745
+ commented: true,
80746
+ templateValue: '"my commit message"'
80747
+ },
80748
+ {
80749
+ name: "promotion",
80750
+ type: "string",
80751
+ default: "(unset)",
80752
+ description: "Branch name to use promotion overrides from during sync",
80753
+ commented: true,
80754
+ templateValue: "staging"
80755
+ },
80756
+ {
80757
+ name: "skipBranchValidation",
80758
+ type: "boolean",
80759
+ default: "false",
80760
+ description: "Skip validation that current git branch matches a configured branch",
80761
+ commented: true
80762
+ },
80763
+ { name: "nonDottedPaths", type: "boolean", default: "true", description: "Use __flow/__app/__raw_app suffixes instead of .flow/.app/.raw_app" },
80764
+ {
80765
+ name: "codebases",
80766
+ type: "array",
80767
+ default: "[]",
80768
+ description: "Codebase bundling configurations for shared libraries",
80769
+ items: {
80770
+ type: "object",
80771
+ properties: {
80772
+ relative_path: { type: "string", description: "Path to the codebase directory" },
80773
+ includes: { type: "array", items: { type: "string" }, description: "Glob patterns for files to include in bundle" },
80774
+ excludes: { type: "array", items: { type: "string" }, description: "Glob patterns for files to exclude from bundle" },
80775
+ format: { type: "string", enum: ["cjs", "esm"], description: "Bundle output format" },
80776
+ external: { type: "array", items: { type: "string" }, description: "Dependencies to leave unbundled (externals)" },
80777
+ assets: { type: "array", items: { type: "object", properties: { from: { type: "string" }, to: { type: "string" } }, required: ["from", "to"] }, description: "Static files to copy into the bundle" },
80778
+ customBundler: { type: "string", description: "Path to a custom bundler script (replaces esbuild)" },
80779
+ inject: { type: "array", items: { type: "string" }, description: "Files to inject into every entry point" },
80780
+ define: { type: "object", additionalProperties: { type: "string" }, description: "Compile-time constant definitions" },
80781
+ banner: { type: "object", additionalProperties: { type: "string" }, description: "Text to prepend to output files by type" },
80782
+ loader: { type: "object", additionalProperties: { type: "string" }, description: "esbuild loader overrides by extension" }
80783
+ },
80784
+ required: ["relative_path"],
80785
+ additionalProperties: false
80786
+ },
80787
+ section: "Codebase bundling (shared libraries)",
80788
+ sectionNote: `Bundle TypeScript/JavaScript codebases that scripts import from.
80789
+ Each entry is bundled and uploaded so scripts can import shared code.`,
80790
+ example: [
80791
+ "# codebases:",
80792
+ "# - relative_path: ./shared # path to the codebase",
80793
+ '# includes: ["**/*.ts"] # files to include in bundle',
80794
+ '# excludes: ["node_modules/**"] # files to exclude',
80795
+ '# format: esm # bundle format: "cjs" or "esm"',
80796
+ '# external: ["pg", "axios"] # dependencies to leave unbundled',
80797
+ "# assets: # static files to copy into bundle",
80798
+ "# - from: ./static",
80799
+ "# to: ./dist",
80800
+ "# # customBundler: ./build.ts # custom bundler script (replaces esbuild)",
80801
+ '# # inject: ["./polyfills.ts"] # files to inject into every entry point',
80802
+ "# # define: # compile-time constants",
80803
+ `# # API_URL: '"https://api.example.com"'`,
80804
+ "# # banner: # text prepended to output files",
80805
+ '# # js: "/* bundled by windmill */"',
80806
+ "# # loader: # esbuild loader overrides",
80807
+ '# # ".png": "dataurl"'
80808
+ ].join(`
80809
+ `)
80810
+ },
80811
+ {
80812
+ name: "gitBranches",
80813
+ type: "object",
80814
+ default: "{}",
80815
+ description: "Map git branches to workspaces and per-branch sync overrides",
80816
+ properties: { commonSpecificItems: SPECIFIC_ITEMS_SCHEMA },
80817
+ additionalProperties: BRANCH_CONFIG_SCHEMA,
80818
+ section: "Git branch / environment bindings",
80819
+ sectionNote: `Map git branches to Windmill workspaces and override settings per branch.
80820
+ Use "environments" as an alias if you prefer environment-based terminology.`,
80821
+ templateValue: `
80822
+ {{BRANCH}}:
80823
+ overrides: {}`,
80824
+ example: [
80825
+ "{{BASEURL_LINE}}",
80826
+ "{{WORKSPACE_ID_LINE}}",
80827
+ " # promotionOverrides: # overrides applied during --promotion",
80828
+ " # skipSecrets: false",
80829
+ " # specificItems: # only sync these specific items",
80830
+ ' # variables: ["f/my_folder/my_var"]',
80831
+ ' # resources: ["f/my_folder/my_res"]',
80832
+ ' # triggers: ["f/my_folder/my_trigger"]',
80833
+ ' # folders: ["my_folder"]',
80834
+ " # settings: true",
80835
+ "",
80836
+ " # Example: staging branch bound to a different workspace",
80837
+ " # staging:",
80838
+ " # baseUrl: https://staging.windmill.dev",
80839
+ " # workspaceId: staging-workspace",
80840
+ " # overrides:",
80841
+ " # skipSecrets: false",
80842
+ " # includeSchedules: true",
80843
+ "",
80844
+ " # Items shared across ALL branches",
80845
+ " # commonSpecificItems:",
80846
+ ' # variables: ["f/shared/api_key"]',
80847
+ ' # resources: ["f/shared/db_conn"]',
80848
+ ' # folders: ["shared"]'
80849
+ ].join(`
80850
+ `)
80851
+ },
80852
+ {
80853
+ name: "environments",
80854
+ type: "object",
80855
+ default: "{}",
80856
+ description: "Alias for gitBranches — use if you prefer environment-based terminology",
80857
+ properties: { commonSpecificItems: SPECIFIC_ITEMS_SCHEMA },
80858
+ additionalProperties: BRANCH_CONFIG_SCHEMA,
80859
+ commented: true
80860
+ }
80861
+ ];
80862
+ function yamlKey(s) {
80863
+ if (/^[a-zA-Z0-9_/.@-]+$/.test(s) && !/^(true|false|yes|no|on|off|null|~)$/i.test(s) && !/^\d+(\.\d+)?$/.test(s)) {
80864
+ return s;
80865
+ }
80866
+ return `"${s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
80867
+ }
80868
+ function generateCommentedTemplate(branchName, binding) {
80869
+ const branch = yamlKey(branchName ?? "main");
80870
+ const lines = [
80871
+ "# yaml-language-server: $schema=wmill.schema.json",
80872
+ "# wmill.yaml — Windmill CLI configuration",
80873
+ '# Full reference: run "wmill config"',
80874
+ ""
80875
+ ];
80876
+ for (const opt of CONFIG_REFERENCE) {
80877
+ if (opt.section) {
80878
+ const ruler = "-".repeat(Math.max(0, 65 - opt.section.length));
80879
+ lines.push(`# --- ${opt.section} ${ruler}`);
80880
+ if (opt.sectionNote) {
80881
+ for (const noteLine of opt.sectionNote.split(`
80882
+ `)) {
80883
+ lines.push(`# ${noteLine}`);
80884
+ }
80885
+ }
80886
+ lines.push("");
80887
+ }
80888
+ if (opt.groupNote) {
80889
+ lines.push(`# ${opt.groupNote}`);
80890
+ }
80891
+ const value = opt.templateValue ?? opt.default;
80892
+ const resolvedValue = value.replace("{{BRANCH}}", branch);
80893
+ if (opt.commented) {
80894
+ lines.push(`# ${opt.description}`);
80895
+ lines.push(`# ${opt.name}: ${resolvedValue}`);
80896
+ } else {
80897
+ lines.push(`# ${opt.description}`);
80898
+ if (opt.inlineComment) {
80899
+ const base = `${opt.name}: ${resolvedValue}`;
80900
+ const pad = " ".repeat(Math.max(1, 32 - base.length));
80901
+ lines.push(`${base}${pad}# ${opt.inlineComment}`);
80902
+ } else {
80903
+ lines.push(`${opt.name}: ${resolvedValue}`);
80904
+ }
80905
+ }
80906
+ if (opt.example) {
80907
+ let resolvedExample = opt.example.replace(/\{\{BRANCH\}\}/g, branch);
80908
+ if (binding) {
80909
+ resolvedExample = resolvedExample.replace("{{BASEURL_LINE}}", ` baseUrl: ${binding.baseUrl}`).replace("{{WORKSPACE_ID_LINE}}", ` workspaceId: ${binding.workspaceId}`);
80910
+ } else {
80911
+ resolvedExample = resolvedExample.replace("{{BASEURL_LINE}}", " # baseUrl: https://app.windmill.dev # Windmill instance URL for this branch").replace("{{WORKSPACE_ID_LINE}}", " # workspaceId: my-workspace # workspace to sync with");
80912
+ }
80913
+ for (const exLine of resolvedExample.split(`
80914
+ `)) {
80915
+ lines.push(exLine);
80916
+ }
80917
+ }
80918
+ lines.push("");
80919
+ }
80920
+ return lines.join(`
80921
+ `);
80922
+ }
80923
+ function expandSchema(prefix, schema, rows) {
80924
+ if (schema.properties) {
80925
+ for (const [key, prop] of Object.entries(schema.properties)) {
80926
+ const name = prefix ? `${prefix}.${key}` : key;
80927
+ rows.push({ name, description: prop.description ?? "", default: "" });
80928
+ if (prop.properties && prop.type === "object") {
80929
+ expandSchema(name, prop, rows);
80930
+ }
80931
+ }
80932
+ }
80933
+ }
80934
+ function formatConfigReference() {
80935
+ const nameWidth = 48;
80936
+ const descWidth = 70;
80937
+ const header = [
80938
+ "OPTION".padEnd(nameWidth),
80939
+ "DESCRIPTION".padEnd(descWidth),
80940
+ "DEFAULT"
80941
+ ].join(" ");
80942
+ const separator = "-".repeat(header.length + 10);
80943
+ const allRows = [];
80944
+ for (const opt of CONFIG_REFERENCE) {
80945
+ allRows.push({ name: opt.name, description: opt.description, default: opt.default });
80946
+ if (opt.items?.properties) {
80947
+ expandSchema(`${opt.name}[]`, opt.items, allRows);
80948
+ }
80949
+ if (opt.additionalProperties && typeof opt.additionalProperties === "object" && opt.additionalProperties.properties) {
80950
+ expandSchema(`${opt.name}.<branch>`, opt.additionalProperties, allRows);
80951
+ }
80952
+ if (opt.properties) {
80953
+ expandSchema(opt.name, opt, allRows);
80954
+ }
80955
+ }
80956
+ const rows = allRows.map((r) => [r.name.padEnd(nameWidth), r.description.padEnd(descWidth), r.default].join(" "));
80957
+ return [
80958
+ "wmill.yaml — Configuration Reference",
80959
+ "",
80960
+ "Full documentation: https://www.windmill.dev/docs/advanced/cli",
80961
+ "",
80962
+ separator,
80963
+ header,
80964
+ separator,
80965
+ ...rows,
80966
+ separator,
80967
+ "",
80968
+ 'Run "wmill init" to generate a wmill.yaml with commented examples.'
80969
+ ].join(`
80970
+ `);
80971
+ }
80972
+ function formatConfigReferenceJson() {
80973
+ const clean = CONFIG_REFERENCE.map((opt) => ({
80974
+ name: opt.name,
80975
+ type: opt.type,
80976
+ default: opt.default,
80977
+ description: opt.description
80978
+ }));
80979
+ return JSON.stringify(clean, null, 2);
80980
+ }
80981
+
79953
80982
  // src/commands/init/init.ts
79954
80983
  function formatSchemaForMarkdown(schemaYaml, schemaName, filePattern) {
79955
80984
  return `## ${schemaName} (\`${filePattern}\`)
@@ -79961,39 +80990,25 @@ ${schemaYaml.trim()}
79961
80990
  \`\`\``;
79962
80991
  }
79963
80992
  async function initAction(opts) {
79964
- if (await stat16("wmill.yaml").catch(() => null)) {
80993
+ if (await stat17("wmill.yaml").catch(() => null)) {
79965
80994
  error(colors.red("wmill.yaml already exists"));
79966
80995
  } else {
79967
- const { DEFAULT_SYNC_OPTIONS: DEFAULT_SYNC_OPTIONS2 } = await init_conf().then(() => exports_conf);
79968
- const initialConfig = { ...DEFAULT_SYNC_OPTIONS2 };
79969
80996
  const { isGitRepository: isGitRepository2, getCurrentGitBranch: getCurrentGitBranch2 } = await Promise.resolve().then(() => (init_git(), exports_git));
80997
+ let branchName;
80998
+ let binding;
79970
80999
  if (isGitRepository2()) {
79971
- const currentBranch = getCurrentGitBranch2();
79972
- if (currentBranch) {
79973
- initialConfig.gitBranches = {
79974
- [currentBranch]: { overrides: {} }
79975
- };
79976
- } else {
79977
- initialConfig.gitBranches = {};
79978
- }
79979
- } else {
79980
- initialConfig.gitBranches = {};
81000
+ branchName = getCurrentGitBranch2() ?? undefined;
79981
81001
  }
79982
- initialConfig.nonDottedPaths = true;
79983
- await writeFile19("wmill.yaml", import_yaml40.stringify(initialConfig), "utf-8");
79984
- info(colors.green("wmill.yaml created with default settings"));
79985
- await readLockfile();
79986
- if (isGitRepository2()) {
81002
+ if (isGitRepository2() && branchName) {
79987
81003
  const activeWorkspace = await getActiveWorkspaceOrFallback(opts);
79988
- const currentBranch = getCurrentGitBranch2();
79989
- if (activeWorkspace && currentBranch) {
81004
+ if (activeWorkspace) {
79990
81005
  const shouldBind = opts.bindProfile === true;
79991
81006
  const shouldPrompt = opts.bindProfile === undefined && !!process.stdin.isTTY && !opts.useDefault;
79992
- const shouldSkip = opts.bindProfile != true && (opts.useDefault || !!!process.stdin.isTTY);
81007
+ const shouldSkip = opts.bindProfile != true && (opts.useDefault || !process.stdin.isTTY);
79993
81008
  if (!shouldSkip) {
79994
81009
  if (shouldBind || shouldPrompt) {
79995
81010
  info(colors.yellow(`
79996
- Current Git branch: ${colors.bold(currentBranch)}`));
81011
+ Current Git branch: ${colors.bold(branchName)}`));
79997
81012
  info(colors.yellow(`Active workspace profile: ${colors.bold(activeWorkspace.name)}`));
79998
81013
  info(colors.yellow(` ${activeWorkspace.workspaceId} on ${activeWorkspace.remote}`));
79999
81014
  }
@@ -80001,22 +81016,21 @@ Current Git branch: ${colors.bold(currentBranch)}`));
80001
81016
  message: "Bind workspace profile to current Git branch?",
80002
81017
  default: true
80003
81018
  })) {
80004
- const currentConfig = await init_conf().then(() => exports_conf).then((m) => m.readConfigFile());
80005
- if (!currentConfig.gitBranches) {
80006
- currentConfig.gitBranches = {};
80007
- }
80008
- if (!currentConfig.gitBranches[currentBranch]) {
80009
- currentConfig.gitBranches[currentBranch] = { overrides: {} };
80010
- }
80011
- info(`binding branch ${currentBranch} to workspace ${activeWorkspace.name} on ${activeWorkspace.remote}`);
80012
- currentConfig.gitBranches[currentBranch].baseUrl = activeWorkspace.remote;
80013
- currentConfig.gitBranches[currentBranch].workspaceId = activeWorkspace.workspaceId;
80014
- await writeFile19("wmill.yaml", import_yaml40.stringify(currentConfig), "utf-8");
80015
- info(colors.green(`✓ Bound branch '${currentBranch}' to workspace '${activeWorkspace.name}'`));
81019
+ info(`binding branch ${branchName} to workspace ${activeWorkspace.name} on ${activeWorkspace.remote}`);
81020
+ binding = {
81021
+ baseUrl: activeWorkspace.remote,
81022
+ workspaceId: activeWorkspace.workspaceId
81023
+ };
80016
81024
  }
80017
81025
  }
80018
81026
  }
80019
81027
  }
81028
+ await writeFile19("wmill.yaml", generateCommentedTemplate(branchName, binding), "utf-8");
81029
+ info(colors.green("wmill.yaml created with default settings"));
81030
+ if (binding) {
81031
+ info(colors.green(`✓ Bound branch '${branchName}' to workspace`));
81032
+ }
81033
+ await readLockfile();
80020
81034
  if (!opts.useDefault) {
80021
81035
  try {
80022
81036
  const { requireLogin: requireLogin2 } = await init_auth().then(() => exports_auth);
@@ -80097,11 +81111,11 @@ Current Git branch: ${colors.bold(currentBranch)}`));
80097
81111
  const skills_base_dir = ".claude/skills";
80098
81112
  const skillsReference = SKILLS.map((s) => `- \`${skills_base_dir}/${s.name}/SKILL.md\` - ${s.description}`).join(`
80099
81113
  `);
80100
- if (!await stat16("AGENTS.md").catch(() => null)) {
81114
+ if (!await stat17("AGENTS.md").catch(() => null)) {
80101
81115
  await writeFile19("AGENTS.md", generateAgentsMdContent(skillsReference), "utf-8");
80102
81116
  info(colors.green("Created AGENTS.md"));
80103
81117
  }
80104
- if (!await stat16("CLAUDE.md").catch(() => null)) {
81118
+ if (!await stat17("CLAUDE.md").catch(() => null)) {
80105
81119
  await writeFile19("CLAUDE.md", `Instructions are in @AGENTS.md
80106
81120
  `, "utf-8");
80107
81121
  info(colors.green("Created CLAUDE.md"));
@@ -80328,6 +81342,400 @@ var push12 = new Command().description("Push completed and queued jobs to worksp
80328
81342
  var command28 = new Command().description("Manage jobs (import/export)").command("pull", pull3).command("push", push12);
80329
81343
  var jobs_default = command28;
80330
81344
 
81345
+ // src/commands/job/job.ts
81346
+ init_mod3();
81347
+ init_mod6();
81348
+ init_colors2();
81349
+ init_log();
81350
+ init_services_gen();
81351
+ await __promiseAll([
81352
+ init_auth(),
81353
+ init_context(),
81354
+ init_conf(),
81355
+ init_utils()
81356
+ ]);
81357
+ function formatDuration(ms) {
81358
+ if (ms < 1000)
81359
+ return `${ms}ms`;
81360
+ const seconds = Math.floor(ms / 1000);
81361
+ if (seconds < 60)
81362
+ return `${seconds}s`;
81363
+ const minutes = Math.floor(seconds / 60);
81364
+ const remainingSeconds = seconds % 60;
81365
+ if (minutes < 60)
81366
+ return `${minutes}m${remainingSeconds}s`;
81367
+ const hours = Math.floor(minutes / 60);
81368
+ const remainingMinutes = minutes % 60;
81369
+ return `${hours}h${remainingMinutes}m`;
81370
+ }
81371
+ function getJobStatus2(job) {
81372
+ if (job.type === "QueuedJob") {
81373
+ if (job.canceled)
81374
+ return colors.red("canceled");
81375
+ if (job.running)
81376
+ return colors.blue("running");
81377
+ return colors.yellow("queued");
81378
+ }
81379
+ if (job.canceled)
81380
+ return colors.red("canceled");
81381
+ if (job.success)
81382
+ return colors.green("success");
81383
+ return colors.red("failure");
81384
+ }
81385
+ function getJobStatusPlain(job) {
81386
+ if (job.type === "QueuedJob") {
81387
+ if (job.canceled)
81388
+ return "canceled";
81389
+ if (job.running)
81390
+ return "running";
81391
+ return "queued";
81392
+ }
81393
+ if (job.canceled)
81394
+ return "canceled";
81395
+ if (job.success)
81396
+ return "success";
81397
+ return "failure";
81398
+ }
81399
+ async function list13(opts) {
81400
+ if (opts.json)
81401
+ setSilent(true);
81402
+ opts = await mergeConfigWithConfigFile(opts);
81403
+ const workspace = await resolveWorkspace(opts);
81404
+ await requireLogin(opts);
81405
+ let successFilter = opts.success;
81406
+ if (opts.failed)
81407
+ successFilter = false;
81408
+ const jobs = await listJobs({
81409
+ workspace: workspace.workspaceId,
81410
+ scriptPathExact: opts.scriptPath,
81411
+ createdBy: opts.createdBy,
81412
+ running: opts.running,
81413
+ success: successFilter,
81414
+ perPage: Math.min(opts.limit ?? 30, 100),
81415
+ jobKinds: opts.jobKinds ?? "script,flow,singlestepflow",
81416
+ label: opts.label,
81417
+ hasNullParent: opts.all ? undefined : true
81418
+ });
81419
+ if (opts.json) {
81420
+ console.log(JSON.stringify(jobs));
81421
+ } else {
81422
+ if (jobs.length === 0) {
81423
+ info("No jobs found.");
81424
+ return;
81425
+ }
81426
+ new Table2().header(["ID", "Status", "Script/Flow", "Created By", "Duration", "Created At"]).padding(2).border(true).body(jobs.map((j) => [
81427
+ j.id.substring(0, 8),
81428
+ getJobStatus2(j),
81429
+ j.script_path ?? j.raw_code?.substring(0, 30) ?? "-",
81430
+ j.created_by ?? j.email ?? "-",
81431
+ j.duration_ms != null ? formatDuration(j.duration_ms) : j.running ? "running" : "-",
81432
+ j.created_at ? formatTimestamp(j.created_at) : "-"
81433
+ ])).render();
81434
+ info(`
81435
+ Showing ${jobs.length} job(s). Use --limit to show more.`);
81436
+ }
81437
+ }
81438
+ async function get10(opts, id) {
81439
+ if (opts.json)
81440
+ setSilent(true);
81441
+ opts = await mergeConfigWithConfigFile(opts);
81442
+ const workspace = await resolveWorkspace(opts);
81443
+ await requireLogin(opts);
81444
+ const job = await getJob({
81445
+ workspace: workspace.workspaceId,
81446
+ id
81447
+ });
81448
+ if (opts.json) {
81449
+ console.log(JSON.stringify(job));
81450
+ } else {
81451
+ const j = job;
81452
+ console.log(colors.bold("ID:") + " " + j.id);
81453
+ console.log(colors.bold("Status:") + " " + getJobStatusPlain(j));
81454
+ console.log(colors.bold("Kind:") + " " + j.job_kind);
81455
+ console.log(colors.bold("Script Path:") + " " + (j.script_path ?? "-"));
81456
+ console.log(colors.bold("Created By:") + " " + (j.created_by ?? "-"));
81457
+ console.log(colors.bold("Created At:") + " " + (j.created_at ? formatTimestamp(j.created_at) : "-"));
81458
+ if (j.started_at) {
81459
+ console.log(colors.bold("Started At:") + " " + formatTimestamp(j.started_at));
81460
+ }
81461
+ if (j.duration_ms != null) {
81462
+ console.log(colors.bold("Duration:") + " " + formatDuration(j.duration_ms));
81463
+ }
81464
+ if (j.schedule_path) {
81465
+ console.log(colors.bold("Schedule:") + " " + j.schedule_path);
81466
+ }
81467
+ if (j.result !== undefined) {
81468
+ console.log(colors.bold("Result:"));
81469
+ console.log(JSON.stringify(j.result, null, 2));
81470
+ }
81471
+ }
81472
+ }
81473
+ async function result(opts, id) {
81474
+ setSilent(true);
81475
+ opts = await mergeConfigWithConfigFile(opts);
81476
+ const workspace = await resolveWorkspace(opts);
81477
+ await requireLogin(opts);
81478
+ const jobResult = await getCompletedJobResult({
81479
+ workspace: workspace.workspaceId,
81480
+ id
81481
+ });
81482
+ console.log(JSON.stringify(jobResult));
81483
+ }
81484
+ async function logs(opts, id) {
81485
+ opts = await mergeConfigWithConfigFile(opts);
81486
+ const workspace = await resolveWorkspace(opts);
81487
+ await requireLogin(opts);
81488
+ const jobLogs = await getJobLogs({
81489
+ workspace: workspace.workspaceId,
81490
+ id
81491
+ });
81492
+ console.log(jobLogs);
81493
+ }
81494
+ async function cancel(opts, id) {
81495
+ opts = await mergeConfigWithConfigFile(opts);
81496
+ const workspace = await resolveWorkspace(opts);
81497
+ await requireLogin(opts);
81498
+ await cancelQueuedJob({
81499
+ workspace: workspace.workspaceId,
81500
+ id,
81501
+ requestBody: {
81502
+ reason: opts.reason ?? "Canceled via CLI"
81503
+ }
81504
+ });
81505
+ info(colors.green(`Job ${id} canceled.`));
81506
+ }
81507
+ 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");
81508
+ 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);
81509
+ var job_default = command29;
81510
+
81511
+ // src/commands/group/group.ts
81512
+ init_mod3();
81513
+ init_mod6();
81514
+ init_colors2();
81515
+ init_log();
81516
+ init_services_gen();
81517
+ await __promiseAll([
81518
+ init_auth(),
81519
+ init_context(),
81520
+ init_conf()
81521
+ ]);
81522
+ async function list14(opts) {
81523
+ if (opts.json)
81524
+ setSilent(true);
81525
+ opts = await mergeConfigWithConfigFile(opts);
81526
+ const workspace = await resolveWorkspace(opts);
81527
+ await requireLogin(opts);
81528
+ const groups = await listGroups({
81529
+ workspace: workspace.workspaceId
81530
+ });
81531
+ if (opts.json) {
81532
+ console.log(JSON.stringify(groups));
81533
+ } else {
81534
+ if (groups.length === 0) {
81535
+ info("No groups found.");
81536
+ return;
81537
+ }
81538
+ new Table2().header(["Name", "Summary", "Members"]).padding(2).border(true).body(groups.map((g) => [
81539
+ g.name,
81540
+ g.summary ?? "-",
81541
+ String(g.members?.length ?? 0)
81542
+ ])).render();
81543
+ }
81544
+ }
81545
+ async function get11(opts, name) {
81546
+ if (opts.json)
81547
+ setSilent(true);
81548
+ opts = await mergeConfigWithConfigFile(opts);
81549
+ const workspace = await resolveWorkspace(opts);
81550
+ await requireLogin(opts);
81551
+ const group = await getGroup({
81552
+ workspace: workspace.workspaceId,
81553
+ name
81554
+ });
81555
+ if (opts.json) {
81556
+ console.log(JSON.stringify(group));
81557
+ } else {
81558
+ console.log(colors.bold("Name:") + " " + group.name);
81559
+ console.log(colors.bold("Summary:") + " " + (group.summary ?? "-"));
81560
+ console.log(colors.bold("Members:") + " " + (group.members && group.members.length > 0 ? group.members.join(", ") : "(none)"));
81561
+ }
81562
+ }
81563
+ async function create(opts, name) {
81564
+ opts = await mergeConfigWithConfigFile(opts);
81565
+ const workspace = await resolveWorkspace(opts);
81566
+ await requireLogin(opts);
81567
+ await createGroup({
81568
+ workspace: workspace.workspaceId,
81569
+ requestBody: {
81570
+ name,
81571
+ summary: opts.summary
81572
+ }
81573
+ });
81574
+ info(colors.green(`Group '${name}' created.`));
81575
+ }
81576
+ async function deleteGroup2(opts, name) {
81577
+ opts = await mergeConfigWithConfigFile(opts);
81578
+ const workspace = await resolveWorkspace(opts);
81579
+ await requireLogin(opts);
81580
+ await deleteGroup({
81581
+ workspace: workspace.workspaceId,
81582
+ name
81583
+ });
81584
+ info(colors.green(`Group '${name}' deleted.`));
81585
+ }
81586
+ async function addUser2(opts, name, username) {
81587
+ opts = await mergeConfigWithConfigFile(opts);
81588
+ const workspace = await resolveWorkspace(opts);
81589
+ await requireLogin(opts);
81590
+ await addUserToGroup({
81591
+ workspace: workspace.workspaceId,
81592
+ name,
81593
+ requestBody: { username }
81594
+ });
81595
+ info(colors.green(`User '${username}' added to group '${name}'.`));
81596
+ }
81597
+ async function removeUser(opts, name, username) {
81598
+ opts = await mergeConfigWithConfigFile(opts);
81599
+ const workspace = await resolveWorkspace(opts);
81600
+ await requireLogin(opts);
81601
+ await removeUserToGroup({
81602
+ workspace: workspace.workspaceId,
81603
+ name,
81604
+ requestBody: { username }
81605
+ });
81606
+ info(colors.green(`User '${username}' removed from group '${name}'.`));
81607
+ }
81608
+ var command30 = new Command().description("Manage workspace groups").option("--json", "Output as JSON (for piping to jq)").action(list14).command("list", "List all groups in the workspace").option("--json", "Output as JSON (for piping to jq)").action(list14).command("get", "Get group details and members").arguments("<name:string>").option("--json", "Output as JSON (for piping to jq)").action(get11).command("create", "Create a new group").arguments("<name:string>").option("--summary <summary:string>", "Group summary/description").action(create).command("delete", "Delete a group").arguments("<name:string>").action(deleteGroup2).command("add-user", "Add a user to a group").arguments("<name:string> <username:string>").action(addUser2).command("remove-user", "Remove a user from a group").arguments("<name:string> <username:string>").action(removeUser);
81609
+ var group_default = command30;
81610
+
81611
+ // src/commands/audit/audit.ts
81612
+ init_mod3();
81613
+ init_mod6();
81614
+ init_colors2();
81615
+ init_log();
81616
+ init_services_gen();
81617
+ await __promiseAll([
81618
+ init_auth(),
81619
+ init_context(),
81620
+ init_conf(),
81621
+ init_utils()
81622
+ ]);
81623
+ async function list15(opts) {
81624
+ if (opts.json)
81625
+ setSilent(true);
81626
+ opts = await mergeConfigWithConfigFile(opts);
81627
+ const workspace = await resolveWorkspace(opts);
81628
+ await requireLogin(opts);
81629
+ const logs2 = await listAuditLogs({
81630
+ workspace: workspace.workspaceId,
81631
+ username: opts.username,
81632
+ operation: opts.operation,
81633
+ actionKind: opts.actionKind,
81634
+ before: opts.before,
81635
+ after: opts.after,
81636
+ perPage: opts.limit ?? 30
81637
+ });
81638
+ if (opts.json) {
81639
+ console.log(JSON.stringify(logs2));
81640
+ } else {
81641
+ if (logs2.length === 0) {
81642
+ info("No audit logs found.");
81643
+ return;
81644
+ }
81645
+ new Table2().header(["ID", "Timestamp", "Username", "Operation", "Action", "Resource"]).padding(2).border(true).body(logs2.map((l) => [
81646
+ String(l.id),
81647
+ formatTimestamp(l.timestamp),
81648
+ l.username,
81649
+ l.operation,
81650
+ l.action_kind,
81651
+ l.resource ?? "-"
81652
+ ])).render();
81653
+ }
81654
+ }
81655
+ async function get12(opts, id) {
81656
+ if (opts.json)
81657
+ setSilent(true);
81658
+ opts = await mergeConfigWithConfigFile(opts);
81659
+ const workspace = await resolveWorkspace(opts);
81660
+ await requireLogin(opts);
81661
+ const auditLog = await getAuditLog({
81662
+ workspace: workspace.workspaceId,
81663
+ id: parseInt(id, 10)
81664
+ });
81665
+ if (opts.json) {
81666
+ console.log(JSON.stringify(auditLog));
81667
+ } else {
81668
+ console.log(colors.bold("ID:") + " " + auditLog.id);
81669
+ console.log(colors.bold("Timestamp:") + " " + formatTimestamp(auditLog.timestamp));
81670
+ console.log(colors.bold("Username:") + " " + auditLog.username);
81671
+ console.log(colors.bold("Operation:") + " " + auditLog.operation);
81672
+ console.log(colors.bold("Action Kind:") + " " + auditLog.action_kind);
81673
+ console.log(colors.bold("Resource:") + " " + (auditLog.resource ?? "-"));
81674
+ if (auditLog.parameters && Object.keys(auditLog.parameters).length > 0) {
81675
+ console.log(colors.bold("Parameters:"));
81676
+ console.log(JSON.stringify(auditLog.parameters, null, 2));
81677
+ }
81678
+ }
81679
+ }
81680
+ var auditListOptions = (cmd) => cmd.option("--json", "Output as JSON (for piping to jq)").option("--username <username:string>", "Filter by username").option("--operation <operation:string>", "Filter by operation (exact or prefix)").option("--action-kind <actionKind:string>", "Filter by action kind (Create, Update, Delete, Execute)").option("--before <before:string>", "Filter events before this timestamp").option("--after <after:string>", "Filter events after this timestamp").option("--limit <limit:number>", "Number of entries to return (default 30, max 100)");
81681
+ var command31 = auditListOptions(new Command().description("View audit logs (requires admin)")).action(list15).command("list", auditListOptions(new Command().description("List audit log entries"))).action(list15).command("get", "Get a specific audit log entry").arguments("<id:string>").option("--json", "Output as JSON (for piping to jq)").action(get12);
81682
+ var audit_default = command31;
81683
+
81684
+ // src/commands/token/token.ts
81685
+ init_mod3();
81686
+ init_mod6();
81687
+ init_colors2();
81688
+ init_log();
81689
+ init_services_gen();
81690
+ await __promiseAll([
81691
+ init_auth(),
81692
+ init_conf(),
81693
+ init_utils()
81694
+ ]);
81695
+ async function list16(opts) {
81696
+ if (opts.json)
81697
+ setSilent(true);
81698
+ opts = await mergeConfigWithConfigFile(opts);
81699
+ await requireLogin(opts);
81700
+ const tokens = await listTokens({
81701
+ excludeEphemeral: true
81702
+ });
81703
+ if (opts.json) {
81704
+ console.log(JSON.stringify(tokens));
81705
+ } else {
81706
+ if (tokens.length === 0) {
81707
+ info("No tokens found.");
81708
+ return;
81709
+ }
81710
+ new Table2().header(["Prefix", "Label", "Created At", "Last Used", "Expiration"]).padding(2).border(true).body(tokens.map((t) => [
81711
+ t.token_prefix,
81712
+ t.label ?? "-",
81713
+ formatTimestamp(t.created_at),
81714
+ formatTimestamp(t.last_used_at),
81715
+ t.expiration ? formatTimestamp(t.expiration) : "never"
81716
+ ])).render();
81717
+ }
81718
+ }
81719
+ async function create2(opts) {
81720
+ opts = await mergeConfigWithConfigFile(opts);
81721
+ await requireLogin(opts);
81722
+ const token = await createToken({
81723
+ requestBody: {
81724
+ label: opts.label,
81725
+ expiration: opts.expiration
81726
+ }
81727
+ });
81728
+ console.log(token);
81729
+ }
81730
+ async function deleteToken2(opts, tokenPrefix) {
81731
+ opts = await mergeConfigWithConfigFile(opts);
81732
+ await requireLogin(opts);
81733
+ await deleteToken({ tokenPrefix });
81734
+ info(colors.green(`Token with prefix '${tokenPrefix}' deleted.`));
81735
+ }
81736
+ var command32 = new Command().description("Manage API tokens").option("--json", "Output as JSON (for piping to jq)").action(list16).command("list", "List API tokens").option("--json", "Output as JSON (for piping to jq)").action(list16).command("create", "Create a new API token").option("--label <label:string>", "Token label").option("--expiration <expiration:string>", "Token expiration (ISO 8601 timestamp)").action(create2).command("delete", "Delete a token by its prefix").arguments("<token_prefix:string>").action(deleteToken2);
81737
+ var token_default = command32;
81738
+
80331
81739
  // src/commands/generate-metadata/generate-metadata.ts
80332
81740
  init_mod3();
80333
81741
  init_colors2();
@@ -80515,32 +81923,62 @@ async function generateMetadata2(opts, folder) {
80515
81923
  const formatProgress = (n) => {
80516
81924
  return colors.dim(colors.white(`[${n}/${total}]`.padEnd(maxWidth, " ")));
80517
81925
  };
81926
+ const errors = [];
80518
81927
  for (const item of scripts) {
80519
81928
  current++;
80520
81929
  info(`${formatProgress(current)} script ${item.path}`);
80521
- await generateScriptMetadataInternal(item.path, workspace, opts, false, true, mismatchedWorkspaceDeps, codebases, false, false, tree);
81930
+ try {
81931
+ await generateScriptMetadataInternal(item.path, workspace, opts, false, true, mismatchedWorkspaceDeps, codebases, false, false, tree);
81932
+ } catch (e) {
81933
+ const msg = e instanceof Error ? e.message : String(e);
81934
+ errors.push({ path: item.path, error: msg });
81935
+ error(` Failed: ${msg}`);
81936
+ }
80522
81937
  }
80523
81938
  for (const item of flows) {
80524
81939
  current++;
80525
- const result = await generateFlowLockInternal(item.folder.replaceAll("/", SEP21), false, workspace, opts, false, true, false, tree);
80526
- const flowResult = result;
80527
- const scriptsInfo = flowResult?.updatedScripts?.length ? colors.dim(colors.white(`: ${flowResult.updatedScripts.join(", ")}`)) : "";
80528
- info(`${formatProgress(current)} flow ${item.path}${scriptsInfo}`);
81940
+ try {
81941
+ const result2 = await generateFlowLockInternal(item.folder.replaceAll("/", SEP21), false, workspace, opts, false, true, false, tree);
81942
+ const flowResult = result2;
81943
+ const scriptsInfo = flowResult?.updatedScripts?.length ? colors.dim(colors.white(`: ${flowResult.updatedScripts.join(", ")}`)) : "";
81944
+ info(`${formatProgress(current)} flow ${item.path}${scriptsInfo}`);
81945
+ } catch (e) {
81946
+ const msg = e instanceof Error ? e.message : String(e);
81947
+ errors.push({ path: item.path, error: msg });
81948
+ info(`${formatProgress(current)} flow ${item.path}`);
81949
+ error(` Failed: ${msg}`);
81950
+ }
80529
81951
  }
80530
81952
  for (const item of apps2) {
80531
81953
  current++;
80532
- const result = await generateAppLocksInternal(item.folder.replaceAll("/", SEP21), item.isRawApp, false, workspace, opts, false, true, false, tree);
80533
- const appResult = result;
80534
- const scriptsInfo = appResult?.updatedScripts?.length ? colors.dim(colors.white(`: ${appResult.updatedScripts.join(", ")}`)) : "";
80535
- info(`${formatProgress(current)} app ${item.path}${scriptsInfo}`);
81954
+ try {
81955
+ const result2 = await generateAppLocksInternal(item.folder.replaceAll("/", SEP21), item.isRawApp, false, workspace, opts, false, true, false, tree);
81956
+ const appResult = result2;
81957
+ const scriptsInfo = appResult?.updatedScripts?.length ? colors.dim(colors.white(`: ${appResult.updatedScripts.join(", ")}`)) : "";
81958
+ info(`${formatProgress(current)} app ${item.path}${scriptsInfo}`);
81959
+ } catch (e) {
81960
+ const msg = e instanceof Error ? e.message : String(e);
81961
+ errors.push({ path: item.path, error: msg });
81962
+ info(`${formatProgress(current)} app ${item.path}`);
81963
+ error(` Failed: ${msg}`);
81964
+ }
80536
81965
  }
80537
81966
  const allStaleDeps = staleItems.filter((i) => i.type === "dependencies");
80538
81967
  await tree.persistDepsHashes(allStaleDeps.map((d) => d.path));
81968
+ const succeeded = total - errors.length;
80539
81969
  info("");
80540
- info(`Done. Updated ${colors.bold(String(total))} item(s).`);
81970
+ if (errors.length > 0) {
81971
+ info(`Done. Updated ${colors.bold(String(succeeded))}/${total} item(s). ${colors.red(String(errors.length) + " failed")}:`);
81972
+ for (const { path: path19, error: error2 } of errors) {
81973
+ error(` ${path19}: ${error2}`);
81974
+ }
81975
+ process.exitCode = 1;
81976
+ } else {
81977
+ info(`Done. Updated ${colors.bold(String(total))} item(s).`);
81978
+ }
80541
81979
  }
80542
- 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);
80543
- var generate_metadata_default = command29;
81980
+ var command33 = 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);
81981
+ var generate_metadata_default = command33;
80544
81982
 
80545
81983
  // src/commands/docs/docs.ts
80546
81984
  init_mod3();
@@ -80612,13 +82050,26 @@ ${await res.text()}`);
80612
82050
  console.log();
80613
82051
  }
80614
82052
  }
80615
- var command30 = new Command().name("docs").description("Search Windmill documentation. Requires Enterprise Edition.").arguments("<query:string>").option("--json", "Output results as JSON.").action(docs);
80616
- var docs_default = command30;
82053
+ var command34 = new Command().name("docs").description("Search Windmill documentation.").arguments("<query:string>").option("--json", "Output results as JSON.").action(docs);
82054
+ var docs_default = command34;
82055
+
82056
+ // src/commands/config/config.ts
82057
+ init_mod3();
82058
+ init_log();
82059
+ async function configAction(opts) {
82060
+ if (opts.json) {
82061
+ console.log(formatConfigReferenceJson());
82062
+ } else {
82063
+ info(formatConfigReference());
82064
+ }
82065
+ }
82066
+ var command35 = new Command().name("config").description("Show all available wmill.yaml configuration options").option("--json", "Output as JSON for programmatic consumption").action(configAction);
82067
+ var config_default = command35;
80617
82068
 
80618
82069
  // src/main.ts
80619
82070
  await init_context();
80620
- var VERSION = "1.666.0";
80621
- 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) => {
82071
+ var VERSION = "1.668.0";
82072
+ 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) => {
80622
82073
  console.log("CLI version: " + VERSION);
80623
82074
  try {
80624
82075
  const provider = new NpmProvider({ package: "windmill-cli" });
@@ -80648,20 +82099,20 @@ var command31 = new Command().name("wmill").action(() => info(`Welcome to Windmi
80648
82099
  error(e);
80649
82100
  info("Try running with sudo and otherwise check the result of the command: npm uninstall windmill-cli && npm install -g windmill-cli");
80650
82101
  })).command("completions", new Command().description("Generate shell completions.").command("bash", new Command().description("Generate bash completions.").action(() => {
80651
- process.stdout.write(generateShellCompletions(command31, "bash") + `
82102
+ process.stdout.write(generateShellCompletions(command36, "bash") + `
80652
82103
  `);
80653
82104
  })).command("zsh", new Command().description("Generate zsh completions.").action(() => {
80654
- process.stdout.write(generateShellCompletions(command31, "zsh") + `
82105
+ process.stdout.write(generateShellCompletions(command36, "zsh") + `
80655
82106
  `);
80656
82107
  })).command("fish", new Command().description("Generate fish completions.").action(() => {
80657
- process.stdout.write(generateShellCompletions(command31, "fish") + `
82108
+ process.stdout.write(generateShellCompletions(command36, "fish") + `
80658
82109
  `);
80659
82110
  })));
80660
82111
  async function main2() {
80661
82112
  try {
80662
82113
  const args = process.argv.slice(2);
80663
82114
  if (args.length === 0) {
80664
- command31.showHelp();
82115
+ command36.showHelp();
80665
82116
  }
80666
82117
  const LOG_LEVEL = args.includes("--verbose") || args.includes("--debug") ? "DEBUG" : "INFO";
80667
82118
  setShowDiffs(args.includes("--show-diffs"));
@@ -80671,12 +82122,22 @@ async function main2() {
80671
82122
  if (extraHeaders) {
80672
82123
  OpenAPI.HEADERS = extraHeaders;
80673
82124
  }
80674
- await command31.parse(args);
82125
+ await command36.parse(args);
80675
82126
  } catch (e) {
80676
82127
  if (e && typeof e === "object" && "name" in e && e.name === "ApiError") {
80677
- console.log("Server failed. " + e.statusText + ": " + e.body);
82128
+ const body = e.body;
82129
+ const bodyStr = typeof body === "object" && body !== null ? JSON.stringify(body) : body;
82130
+ error("Server failed. " + e.statusText + ": " + bodyStr);
82131
+ } else if (e instanceof Error) {
82132
+ error(e.message);
82133
+ } else if (e !== undefined && e !== null) {
82134
+ error(String(e));
82135
+ }
82136
+ const isDebug = process.argv.includes("--verbose") || process.argv.includes("--debug");
82137
+ if (isDebug) {
82138
+ throw e;
80678
82139
  }
80679
- throw e;
82140
+ process.exitCode = 1;
80680
82141
  }
80681
82142
  }
80682
82143
  function isMain() {
@@ -80696,13 +82157,14 @@ if (isMain()) {
80696
82157
  process.stdin.destroy();
80697
82158
  });
80698
82159
  }
80699
- var main_default = command31;
82160
+ var main_default = command36;
80700
82161
  export {
80701
82162
  add as workspaceAdd,
80702
82163
  workspace_default as workspace,
80703
82164
  variable_default as variable,
80704
82165
  user_default as user,
80705
82166
  trigger_default as trigger,
82167
+ token_default as token,
80706
82168
  sync_default as sync,
80707
82169
  script_default as script,
80708
82170
  schedule_default as schedule,
@@ -80711,15 +82173,19 @@ export {
80711
82173
  push3 as push,
80712
82174
  pull,
80713
82175
  lint_default as lint,
82176
+ job_default as job,
80714
82177
  instance_default as instance,
80715
82178
  pull2 as hubPull,
80716
82179
  hub_default as hub,
82180
+ group_default as group,
80717
82181
  gitsync_settings_default as gitsyncSettings,
80718
82182
  folder_default as folder,
80719
82183
  flow_default as flow,
80720
82184
  docs_default as docs,
80721
82185
  dev_default2 as dev,
80722
82186
  main_default as default,
82187
+ config_default as config,
82188
+ audit_default as audit,
80723
82189
  app_default as app,
80724
82190
  WM_FORK_PREFIX,
80725
82191
  VERSION