windmill-cli 1.690.0 → 1.691.1

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 +176 -30
  2. package/package.json +1 -1
package/esm/main.js CHANGED
@@ -16701,7 +16701,7 @@ var init_OpenAPI = __esm(() => {
16701
16701
  PASSWORD: undefined,
16702
16702
  TOKEN: getEnv3("WM_TOKEN"),
16703
16703
  USERNAME: undefined,
16704
- VERSION: "1.690.0",
16704
+ VERSION: "1.691.1",
16705
16705
  WITH_CREDENTIALS: true,
16706
16706
  interceptors: {
16707
16707
  request: new Interceptors,
@@ -17637,8 +17637,10 @@ __export(exports_services_gen, {
17637
17637
  countCompletedJobs: () => countCompletedJobs,
17638
17638
  convertUserToGroup: () => convertUserToGroup,
17639
17639
  connectTeams: () => connectTeams,
17640
+ connectSlackInstance: () => connectSlackInstance,
17640
17641
  connectSlackCallbackInstance: () => connectSlackCallbackInstance,
17641
17642
  connectSlackCallback: () => connectSlackCallback,
17643
+ connectSlack: () => connectSlack,
17642
17644
  connectClientCredentials: () => connectClientCredentials,
17643
17645
  connectCallback: () => connectCallback,
17644
17646
  computeObjectStorageUsage: () => computeObjectStorageUsage,
@@ -18833,6 +18835,16 @@ var backendVersion = () => {
18833
18835
  body: data3.requestBody,
18834
18836
  mediaType: "application/json"
18835
18837
  });
18838
+ }, connectSlack = (data3) => {
18839
+ return request(OpenAPI, {
18840
+ method: "POST",
18841
+ url: "/w/{workspace}/workspaces/connect_slack",
18842
+ path: {
18843
+ workspace: data3.workspace
18844
+ },
18845
+ body: data3.requestBody,
18846
+ mediaType: "application/json"
18847
+ });
18836
18848
  }, runSlackMessageTestJob = (data3) => {
18837
18849
  return request(OpenAPI, {
18838
18850
  method: "POST",
@@ -19594,6 +19606,13 @@ var backendVersion = () => {
19594
19606
  body: data3.requestBody,
19595
19607
  mediaType: "application/json"
19596
19608
  });
19609
+ }, connectSlackInstance = (data3) => {
19610
+ return request(OpenAPI, {
19611
+ method: "POST",
19612
+ url: "/oauth/connect_slack_instance",
19613
+ body: data3.requestBody,
19614
+ mediaType: "application/json"
19615
+ });
19597
19616
  }, connectCallback = (data3) => {
19598
19617
  return request(OpenAPI, {
19599
19618
  method: "POST",
@@ -26134,6 +26153,36 @@ var init_merge = __esm(async () => {
26134
26153
  };
26135
26154
  });
26136
26155
 
26156
+ // src/commands/workspace/slack.ts
26157
+ async function connectSlack2(opts) {
26158
+ await requireLogin(opts);
26159
+ const workspace = await resolveWorkspace(opts);
26160
+ await connectSlack({
26161
+ workspace: workspace.workspaceId,
26162
+ requestBody: {
26163
+ bot_token: opts.botToken,
26164
+ team_id: opts.teamId,
26165
+ team_name: opts.teamName
26166
+ }
26167
+ });
26168
+ info(colors.bold.underline.green(`Slack connected to workspace ${workspace.workspaceId} (team ${opts.teamName} / ${opts.teamId})`));
26169
+ }
26170
+ async function disconnectSlack2(opts) {
26171
+ await requireLogin(opts);
26172
+ const workspace = await resolveWorkspace(opts);
26173
+ await disconnectSlack({ workspace: workspace.workspaceId });
26174
+ info(colors.bold.underline.green(`Slack disconnected from workspace ${workspace.workspaceId} (slack_team_id / slack_name cleared). ` + `To also remove the bot token variable/resource/folder/group, delete the corresponding files from the local sync folder and run 'wmill sync push'. ` + `To remove the workspace-level OAuth override (if any), set slack_oauth_client_id/_secret to '' in settings.yaml and push.`));
26175
+ }
26176
+ var init_slack = __esm(async () => {
26177
+ init_colors2();
26178
+ init_log();
26179
+ init_services_gen();
26180
+ await __promiseAll([
26181
+ init_auth(),
26182
+ init_context()
26183
+ ]);
26184
+ });
26185
+
26137
26186
  // src/utils/resource_folders.ts
26138
26187
  import { sep as SEP2 } from "node:path";
26139
26188
  import * as fs6 from "node:fs";
@@ -27475,11 +27524,12 @@ var init_workspace = __esm(async () => {
27475
27524
  init_input(),
27476
27525
  init_auth(),
27477
27526
  init_fork(),
27478
- init_merge()
27527
+ init_merge(),
27528
+ init_slack()
27479
27529
  ]);
27480
27530
  command2 = new Command().alias("profile").description("workspace related commands").action(list3).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.", {
27481
27531
  default: "admin"
27482
- }).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(list3).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("Create or update a workspace entry in wmill.yaml from the active profile").option("--workspace <name:string>", "Workspace name (default: current branch or workspaceId)").option("--branch <branch:string>", "Git branch to associate (default: workspace name)").action((opts) => bind(opts, true)).command("unbind").description("Remove baseUrl and workspaceId from a workspace entry").option("--workspace <name:string>", "Workspace to unbind").action((opts) => bind(opts, false)).command("fork").description("Create a forked workspace").arguments("[workspace_name:string] [workspace_id:string]").option("--create-workspace-name <workspace_name:string>", "Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.").option("--color <color:string>", "Workspace color (hex code, e.g. #ff0000)").option("--datatable-behavior <behavior:string>", "How to handle datatables: skip, schema_only, or schema_and_data (default: interactive prompt)").option("-y --yes", "Skip interactive prompts (defaults datatable behavior to 'skip')").action(createWorkspaceFork2).command("delete-fork").description("Delete a forked workspace and git branch").arguments("<fork_name:string>").option("-y --yes", "Skip confirmation prompt").action(deleteWorkspaceFork).command("merge").description("Compare and deploy changes between a fork and its parent workspace").option("--direction <direction:string>", "Deploy direction: to-parent or to-fork").option("--all", "Deploy all changed items including conflicts").option("--skip-conflicts", "Skip items modified in both workspaces").option("--include <items:string>", "Comma-separated kind:path items to include (e.g. script:f/test/main,flow:f/my/flow)").option("--exclude <items:string>", "Comma-separated kind:path items to exclude").option("--preserve-on-behalf-of", "Preserve original on_behalf_of/permissioned_as values").option("-y --yes", "Non-interactive mode (deploy without prompts)").action(mergeWorkspaces);
27532
+ }).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(list3).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("Create or update a workspace entry in wmill.yaml from the active profile").option("--workspace <name:string>", "Workspace name (default: current branch or workspaceId)").option("--branch <branch:string>", "Git branch to associate (default: workspace name)").action((opts) => bind(opts, true)).command("unbind").description("Remove baseUrl and workspaceId from a workspace entry").option("--workspace <name:string>", "Workspace to unbind").action((opts) => bind(opts, false)).command("fork").description("Create a forked workspace").arguments("[workspace_name:string] [workspace_id:string]").option("--create-workspace-name <workspace_name:string>", "Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.").option("--color <color:string>", "Workspace color (hex code, e.g. #ff0000)").option("--datatable-behavior <behavior:string>", "How to handle datatables: skip, schema_only, or schema_and_data (default: interactive prompt)").option("-y --yes", "Skip interactive prompts (defaults datatable behavior to 'skip')").action(createWorkspaceFork2).command("delete-fork").description("Delete a forked workspace and git branch").arguments("<fork_name:string>").option("-y --yes", "Skip confirmation prompt").action(deleteWorkspaceFork).command("merge").description("Compare and deploy changes between a fork and its parent workspace").option("--direction <direction:string>", "Deploy direction: to-parent or to-fork").option("--all", "Deploy all changed items including conflicts").option("--skip-conflicts", "Skip items modified in both workspaces").option("--include <items:string>", "Comma-separated kind:path items to include (e.g. script:f/test/main,flow:f/my/flow)").option("--exclude <items:string>", "Comma-separated kind:path items to exclude").option("--preserve-on-behalf-of", "Preserve original on_behalf_of/permissioned_as values").option("-y --yes", "Non-interactive mode (deploy without prompts)").action(mergeWorkspaces).command("connect-slack").description("Non-interactively connect Slack to the active workspace using a pre-minted bot token (xoxb-...). Produces the same artifacts as the UI OAuth flow: workspace_settings fields, g/slack group, f/slack_bot folder, and the encrypted bot token variable + resource at f/slack_bot/bot_token.").option("--bot-token <bot_token:string>", "Slack bot token (xoxb-...)", { required: true }).option("--team-id <team_id:string>", "Slack team id", { required: true }).option("--team-name <team_name:string>", "Slack team name", { required: true }).action(connectSlack2).command("disconnect-slack").description("Clear slack_team_id / slack_name on the active workspace (marks the workspace as disconnected). Does NOT remove the bot token variable/resource/folder/group — delete those from the local sync folder and run 'wmill sync push' to tear them down. Does NOT remove the workspace-level OAuth override — set slack_oauth_client_id/_secret to '' in settings.yaml and push.").action(disconnectSlack2);
27483
27533
  workspace_default = command2;
27484
27534
  });
27485
27535
 
@@ -61646,12 +61696,21 @@ async function readModulesFromDisk(moduleFolderPath, defaultTs, folderLayout = f
61646
61696
  }
61647
61697
  async function createScript2(bundleContent, workspaceId, body, workspace) {
61648
61698
  const start = performance.now();
61699
+ const skipIfNoop = "skip_if_noop=true";
61649
61700
  if (!bundleContent) {
61650
61701
  try {
61651
- await createScript({
61652
- workspace: workspaceId,
61653
- requestBody: body
61702
+ const url = workspace.remote + "api/w/" + workspaceId + "/scripts/create?" + skipIfNoop;
61703
+ const req = await fetch(url, {
61704
+ method: "POST",
61705
+ headers: {
61706
+ Authorization: `Bearer ${workspace.token}`,
61707
+ "Content-Type": "application/json"
61708
+ },
61709
+ body: JSON.stringify(body)
61654
61710
  });
61711
+ if (req.status != 201) {
61712
+ throw Error(`${req.status} - ${req.statusText} - ${await req.text()}`);
61713
+ }
61655
61714
  } catch (e) {
61656
61715
  throw Error(`Script creation for ${body.path} with parent ${body.parent_hash} was not successful: ${e.body ?? e.message} `);
61657
61716
  }
@@ -61659,7 +61718,7 @@ async function createScript2(bundleContent, workspaceId, body, workspace) {
61659
61718
  const form = new FormData;
61660
61719
  form.append("script", JSON.stringify(body));
61661
61720
  form.append("file", typeof bundleContent == "string" ? bundleContent : bundleContent);
61662
- const url = workspace.remote + "api/w/" + workspace.workspaceId + "/scripts/create_snapshot";
61721
+ const url = workspace.remote + "api/w/" + workspace.workspaceId + "/scripts/create_snapshot?" + skipIfNoop;
61663
61722
  const req = await fetch(url, {
61664
61723
  method: "POST",
61665
61724
  headers: { Authorization: `Bearer ${workspace.token} ` },
@@ -63262,8 +63321,8 @@ function getLanguageFromExtension(ext2, defaultTs = "bun") {
63262
63321
  return;
63263
63322
  }
63264
63323
  function sanitizeForFilesystem(summary) {
63265
- const name = summary.toLowerCase().replaceAll(" ", "_").replace(/[/\\:*?"<>|\x00-\x1f\x7f]/g, "").replace(/_+/g, "_").replace(/^[._]+|[._]+$/g, "");
63266
- return WINDOWS_RESERVED.test(name) ? `_${name}` : name;
63324
+ const name = summary.replaceAll(" ", "_").replace(/[/\\:*?"<>|\x00-\x1f\x7f]/g, "").replace(/_+/g, "_").replace(/^[._]+|[._]+$/g, "");
63325
+ return WINDOWS_RESERVED.test(name.toLowerCase()) ? `_${name}` : name;
63267
63326
  }
63268
63327
  function newPathAssigner(defaultTs, options) {
63269
63328
  const resolvedOptions = typeof defaultTs === "object" ? defaultTs : { defaultTs, skipInlineScriptSuffix: options?.skipInlineScriptSuffix };
@@ -63278,11 +63337,11 @@ function newPathAssigner(defaultTs, options) {
63278
63337
  original_name = INLINE_SCRIPT_PREFIX;
63279
63338
  name = `${INLINE_SCRIPT_PREFIX}_0`;
63280
63339
  }
63281
- while (seen_names.has(name)) {
63340
+ while (seen_names.has(name.toLowerCase())) {
63282
63341
  counter++;
63283
63342
  name = `${original_name}_${counter}`;
63284
63343
  }
63285
- seen_names.add(name);
63344
+ seen_names.add(name.toLowerCase());
63286
63345
  const ext2 = getLanguageExtension(language, tsRuntime);
63287
63346
  const suffix = skipInlineScriptSuffix ? "." : ".inline_script.";
63288
63347
  return [`${name}${suffix}`, ext2];
@@ -63300,11 +63359,11 @@ function newRawAppPathAssigner(defaultTs) {
63300
63359
  original_name = "runnable";
63301
63360
  name = `runnable_0`;
63302
63361
  }
63303
- while (seen_names.has(name)) {
63362
+ while (seen_names.has(name.toLowerCase())) {
63304
63363
  counter++;
63305
63364
  name = `${original_name}_${counter}`;
63306
63365
  }
63307
- seen_names.add(name);
63366
+ seen_names.add(name.toLowerCase());
63308
63367
  const ext2 = getLanguageExtension(language, defaultTs);
63309
63368
  return [`${name}.`, ext2];
63310
63369
  }
@@ -65025,6 +65084,12 @@ async function compareDynFSElement(els1, els2, ignore, json, skips, ignoreMetada
65025
65084
  if (o["is_template"] != null) {
65026
65085
  delete o["is_template"];
65027
65086
  }
65087
+ if (o["no_main_func"] != null) {
65088
+ delete o["no_main_func"];
65089
+ }
65090
+ if (o["auto_kind"] != null) {
65091
+ delete o["auto_kind"];
65092
+ }
65028
65093
  }
65029
65094
  return o;
65030
65095
  } else {
@@ -66875,6 +66940,7 @@ async function updateScriptSchema(scriptContent, language, metadataContent, path
66875
66940
  delete metadataContent.has_preprocessor;
66876
66941
  }
66877
66942
  delete metadataContent.auto_kind;
66943
+ delete metadataContent.no_main_func;
66878
66944
  }
66879
66945
  function extractWorkspaceDepsAnnotation(scriptContent, language) {
66880
66946
  const config = LANG_ANNOTATION_CONFIG[language];
@@ -67486,12 +67552,24 @@ __export(exports_raw_apps, {
67486
67552
  import { sep as SEP10 } from "node:path";
67487
67553
  import path12 from "node:path";
67488
67554
  import { readdir as readdir6 } from "node:fs/promises";
67555
+ async function readSiblingLock(backendPath, runnableId, allFiles) {
67556
+ const target = `${runnableId.toLowerCase()}.lock`;
67557
+ const lockFile = allFiles.find((f) => f.toLowerCase() === target);
67558
+ if (!lockFile)
67559
+ return;
67560
+ try {
67561
+ return await readTextFile(path12.join(backendPath, lockFile));
67562
+ } catch {
67563
+ return;
67564
+ }
67565
+ }
67489
67566
  async function findRunnableContentFile(backendPath, runnableId, allFiles) {
67567
+ const runnableIdLower = runnableId.toLowerCase();
67490
67568
  for (const fileName of allFiles) {
67491
67569
  if (fileName.endsWith(".yaml") || fileName.endsWith(".lock")) {
67492
67570
  continue;
67493
67571
  }
67494
- if (!fileName.startsWith(runnableId + ".")) {
67572
+ if (!fileName.toLowerCase().startsWith(runnableIdLower + ".")) {
67495
67573
  continue;
67496
67574
  }
67497
67575
  const ext2 = fileName.substring(runnableId.length + 1);
@@ -67533,17 +67611,14 @@ async function loadRunnablesFromBackend(backendPath, defaultTs = "bun") {
67533
67611
  continue;
67534
67612
  }
67535
67613
  const runnableId = fileName.replace(".yaml", "");
67536
- processedIds.add(runnableId);
67614
+ processedIds.add(runnableId.toLowerCase());
67537
67615
  const filePath = path12.join(backendPath, fileName);
67538
67616
  const runnable = await yamlParseFile(filePath);
67539
67617
  if (runnable?.type === "inline") {
67540
67618
  const contentFile = await findRunnableContentFile(backendPath, runnableId, allFiles);
67541
67619
  if (contentFile) {
67542
67620
  const language = getLanguageFromExtension(contentFile.ext, defaultTs);
67543
- let lock;
67544
- try {
67545
- lock = await readTextFile(path12.join(backendPath, `${runnableId}.lock`));
67546
- } catch {}
67621
+ const lock = await readSiblingLock(backendPath, runnableId, allFiles);
67547
67622
  runnable.inlineScript = {
67548
67623
  content: contentFile.content,
67549
67624
  language,
@@ -67564,17 +67639,14 @@ async function loadRunnablesFromBackend(backendPath, defaultTs = "bun") {
67564
67639
  if (!runnableId) {
67565
67640
  continue;
67566
67641
  }
67567
- if (processedIds.has(runnableId)) {
67642
+ if (processedIds.has(runnableId.toLowerCase())) {
67568
67643
  continue;
67569
67644
  }
67570
- processedIds.add(runnableId);
67645
+ processedIds.add(runnableId.toLowerCase());
67571
67646
  const contentFile = await findRunnableContentFile(backendPath, runnableId, allFiles);
67572
67647
  if (contentFile) {
67573
67648
  const language = getLanguageFromExtension(contentFile.ext, defaultTs);
67574
- let lock;
67575
- try {
67576
- lock = await readTextFile(path12.join(backendPath, `${runnableId}.lock`));
67577
- } catch {}
67649
+ const lock = await readSiblingLock(backendPath, runnableId, allFiles);
67578
67650
  runnables[runnableId] = {
67579
67651
  type: "inline",
67580
67652
  inlineScript: {
@@ -71162,6 +71234,45 @@ var init_schedule = __esm(async () => {
71162
71234
  schedule_default = command15;
71163
71235
  });
71164
71236
 
71237
+ // src/commands/instance/slack.ts
71238
+ async function resolveInstance(instanceName) {
71239
+ if (instanceName) {
71240
+ const match3 = (await allInstances()).find((i) => i.name === instanceName);
71241
+ if (!match3) {
71242
+ throw new Error(`No local instance profile named ${instanceName}`);
71243
+ }
71244
+ return match3;
71245
+ }
71246
+ const activeName = await getActiveInstance({});
71247
+ if (!activeName) {
71248
+ throw new Error("No active instance. Run 'wmill instance add' or pass --instance.");
71249
+ }
71250
+ const match2 = (await allInstances()).find((i) => i.name === activeName);
71251
+ if (!match2) {
71252
+ throw new Error(`Active instance ${activeName} not found in config`);
71253
+ }
71254
+ return match2;
71255
+ }
71256
+ async function connectSlackInstance2(opts) {
71257
+ const instance = await resolveInstance(opts.instance);
71258
+ setClient(instance.token, instance.remote.substring(0, instance.remote.length - 1));
71259
+ await connectSlackInstance({
71260
+ requestBody: {
71261
+ bot_token: opts.botToken,
71262
+ team_id: opts.teamId,
71263
+ team_name: opts.teamName
71264
+ }
71265
+ });
71266
+ info(colors.bold.underline.green(`Slack connected at instance ${instance.name} (team ${opts.teamName} / ${opts.teamId})`));
71267
+ }
71268
+ var init_slack2 = __esm(async () => {
71269
+ init_colors2();
71270
+ init_log();
71271
+ init_client();
71272
+ init_services_gen();
71273
+ await init_instance();
71274
+ });
71275
+
71165
71276
  // src/utils/local_encryption.ts
71166
71277
  import crypto3 from "node:crypto";
71167
71278
  function encode2(input) {
@@ -71242,6 +71353,10 @@ function migrateToGroupedFormat(settings) {
71242
71353
  result.slack_name = settings.slack_name;
71243
71354
  if (settings.slack_command_script !== undefined)
71244
71355
  result.slack_command_script = settings.slack_command_script;
71356
+ if (settings.slack_oauth_client_id !== undefined)
71357
+ result.slack_oauth_client_id = settings.slack_oauth_client_id;
71358
+ if (settings.slack_oauth_client_secret !== undefined)
71359
+ result.slack_oauth_client_secret = settings.slack_oauth_client_secret;
71245
71360
  if (settings.auto_invite && typeof settings.auto_invite === "object") {
71246
71361
  result.auto_invite = settings.auto_invite;
71247
71362
  } else if (settings.auto_invite_enabled !== undefined) {
@@ -71251,7 +71366,9 @@ function migrateToGroupedFormat(settings) {
71251
71366
  mode: settings.auto_invite_mode ?? "invite"
71252
71367
  };
71253
71368
  }
71254
- if (settings.error_handler && typeof settings.error_handler === "object") {
71369
+ if (settings.error_handler === null) {
71370
+ result.error_handler = null;
71371
+ } else if (settings.error_handler && typeof settings.error_handler === "object") {
71255
71372
  result.error_handler = settings.error_handler;
71256
71373
  } else if (typeof settings.error_handler === "string") {
71257
71374
  result.error_handler = {
@@ -71260,7 +71377,9 @@ function migrateToGroupedFormat(settings) {
71260
71377
  muted_on_cancel: settings.error_handler_muted_on_cancel ?? false
71261
71378
  };
71262
71379
  }
71263
- if (settings.success_handler && typeof settings.success_handler === "object") {
71380
+ if (settings.success_handler === null) {
71381
+ result.success_handler = null;
71382
+ } else if (settings.success_handler && typeof settings.success_handler === "object") {
71264
71383
  result.success_handler = settings.success_handler;
71265
71384
  } else if (typeof settings.success_handler === "string") {
71266
71385
  result.success_handler = {
@@ -71307,7 +71426,9 @@ async function pushWorkspaceSettings(workspace, _path, settings, localSettings)
71307
71426
  datatable: remoteSettings.datatable,
71308
71427
  slack_team_id: remoteSettings.slack_team_id,
71309
71428
  slack_name: remoteSettings.slack_name,
71310
- slack_command_script: remoteSettings.slack_command_script
71429
+ slack_command_script: remoteSettings.slack_command_script,
71430
+ slack_oauth_client_id: remoteSettings.slack_oauth_client_id,
71431
+ slack_oauth_client_secret: remoteSettings.slack_oauth_client_secret
71311
71432
  };
71312
71433
  } catch (err) {
71313
71434
  throw new Error(`Failed to get workspace settings: ${err}`);
@@ -71479,6 +71600,20 @@ async function pushWorkspaceSettings(workspace, _path, settings, localSettings)
71479
71600
  }
71480
71601
  });
71481
71602
  }
71603
+ if (localSettings.slack_oauth_client_id != settings.slack_oauth_client_id || localSettings.slack_oauth_client_secret != settings.slack_oauth_client_secret) {
71604
+ debug(`Updating slack oauth config...`);
71605
+ if (localSettings.slack_oauth_client_id && localSettings.slack_oauth_client_secret) {
71606
+ await setWorkspaceSlackOauthConfig({
71607
+ workspace,
71608
+ requestBody: {
71609
+ slack_oauth_client_id: localSettings.slack_oauth_client_id,
71610
+ slack_oauth_client_secret: localSettings.slack_oauth_client_secret
71611
+ }
71612
+ });
71613
+ } else {
71614
+ await deleteWorkspaceSlackOauthConfig({ workspace });
71615
+ }
71616
+ }
71482
71617
  }
71483
71618
  async function pushWorkspaceKey(workspace, _path, key, localKey) {
71484
71619
  try {
@@ -72208,6 +72343,7 @@ var init_instance = __esm(async () => {
72208
72343
  init_sync(),
72209
72344
  init_types(),
72210
72345
  init_user(),
72346
+ init_slack2(),
72211
72347
  init_workspace(),
72212
72348
  init_settings(),
72213
72349
  init_utils(),
@@ -72239,7 +72375,7 @@ var init_instance = __esm(async () => {
72239
72375
  });
72240
72376
  await removeInstance(choice);
72241
72377
  info(colors.green.underline(`Removed instance ${choice}`));
72242
- }).command("switch").complete("instance", async () => (await allInstances()).map((x) => x.name)).arguments("<instance:string:instance>").description("Switch the current instance").action(switchI).command("pull").description("Pull instance settings, users, configs, instance groups and overwrite local").option("--yes", "Pull without needing confirmation").option("--dry-run", "Perform a dry run without making changes").option("--skip-users", "Skip pulling users").option("--skip-settings", "Skip pulling settings").option("--skip-configs", "Skip pulling configs (worker groups)").option("--skip-groups", "Skip pulling instance groups").option("--include-workspaces", "Also pull workspaces").option("--folder-per-instance", "Create a folder per instance").option("--instance <instance:string>", "Name of the instance to pull from, override the active instance").option("--prefix <prefix:string>", "Prefix of the local workspaces to pull, used to create the folders when using --include-workspaces").option("--prefix-settings", "Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance").action(instancePull).command("push").description("Push instance settings, users, configs, group and overwrite remote").option("--yes", "Push without needing confirmation").option("--dry-run", "Perform a dry run without making changes").option("--skip-users", "Skip pushing users").option("--skip-settings", "Skip pushing settings").option("--skip-configs", "Skip pushing configs (worker groups)").option("--skip-groups", "Skip pushing instance groups").option("--include-workspaces", "Also push workspaces").option("--folder-per-instance", "Create a folder per instance").option("--instance <instance:string>", "Name of the instance to push to, override the active instance").option("--prefix <prefix:string>", "Prefix of the local workspaces folders to push").option("--prefix-settings", "Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance").action(instancePush).command("whoami").description("Display information about the currently logged-in user").action(whoami3).command("get-config").description("Dump the current instance config (global settings + worker configs) as YAML").option("-o, --output-file <file:string>", "Write YAML to a file instead of stdout").option("--show-secrets", "Include sensitive fields (license key, JWT secret) without prompting").option("--instance <instance:string>", "Name of the instance, override the active instance").action(getConfig2);
72378
+ }).command("switch").complete("instance", async () => (await allInstances()).map((x) => x.name)).arguments("<instance:string:instance>").description("Switch the current instance").action(switchI).command("pull").description("Pull instance settings, users, configs, instance groups and overwrite local").option("--yes", "Pull without needing confirmation").option("--dry-run", "Perform a dry run without making changes").option("--skip-users", "Skip pulling users").option("--skip-settings", "Skip pulling settings").option("--skip-configs", "Skip pulling configs (worker groups)").option("--skip-groups", "Skip pulling instance groups").option("--include-workspaces", "Also pull workspaces").option("--folder-per-instance", "Create a folder per instance").option("--instance <instance:string>", "Name of the instance to pull from, override the active instance").option("--prefix <prefix:string>", "Prefix of the local workspaces to pull, used to create the folders when using --include-workspaces").option("--prefix-settings", "Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance").action(instancePull).command("push").description("Push instance settings, users, configs, group and overwrite remote").option("--yes", "Push without needing confirmation").option("--dry-run", "Perform a dry run without making changes").option("--skip-users", "Skip pushing users").option("--skip-settings", "Skip pushing settings").option("--skip-configs", "Skip pushing configs (worker groups)").option("--skip-groups", "Skip pushing instance groups").option("--include-workspaces", "Also push workspaces").option("--folder-per-instance", "Create a folder per instance").option("--instance <instance:string>", "Name of the instance to push to, override the active instance").option("--prefix <prefix:string>", "Prefix of the local workspaces folders to push").option("--prefix-settings", "Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance").action(instancePush).command("whoami").description("Display information about the currently logged-in user").action(whoami3).command("get-config").description("Dump the current instance config (global settings + worker configs) as YAML").option("-o, --output-file <file:string>", "Write YAML to a file instead of stdout").option("--show-secrets", "Include sensitive fields (license key, JWT secret) without prompting").option("--instance <instance:string>", "Name of the instance, override the active instance").action(getConfig2).command("connect-slack").description("Non-interactively connect Slack at the instance level using a pre-minted bot token (xoxb-...). Produces the same artifacts as the UI OAuth flow: global_settings 'slack' row + encrypted f/slack_bot/global_bot_token variable and resource in the admins workspace.").option("--bot-token <bot_token:string>", "Slack bot token (xoxb-...)", { required: true }).option("--team-id <team_id:string>", "Slack team id", { required: true }).option("--team-name <team_name:string>", "Slack team name", { required: true }).option("--instance <instance:string>", "Instance profile to connect against (defaults to the active instance)").action((opts) => connectSlackInstance2(opts));
72243
72379
  instance_default = command16;
72244
72380
  });
72245
72381
 
@@ -82712,6 +82848,11 @@ sync local with a remote instance or the opposite (push or pull)
82712
82848
  - \`-o, --output-file <file:string>\` - Write YAML to a file instead of stdout
82713
82849
  - \`--show-secrets\` - Include sensitive fields (license key, JWT secret) without prompting
82714
82850
  - \`--instance <instance:string>\` - Name of the instance, override the active instance
82851
+ - \`instance connect-slack\`
82852
+ - \`--bot-token <bot_token:string>\` - Slack bot token (xoxb-...)
82853
+ - \`--team-id <team_id:string>\` - Slack team id
82854
+ - \`--team-name <team_name:string>\` - Slack team name
82855
+ - \`--instance <instance:string>\` - Instance profile to connect against (defaults to the active instance)
82715
82856
 
82716
82857
  ### job
82717
82858
 
@@ -83060,6 +83201,11 @@ workspace related commands
83060
83201
  - \`--exclude <items:string>\` - Comma-separated kind:path items to exclude
83061
83202
  - \`--preserve-on-behalf-of\` - Preserve original on_behalf_of/permissioned_as values
83062
83203
  - \`-y --yes\` - Non-interactive mode (deploy without prompts)
83204
+ - \`workspace connect-slack\` - Non-interactively connect Slack to the active workspace using a pre-minted bot token (xoxb-...). Produces the same artifacts as the UI OAuth flow: workspace_settings fields, g/slack group, f/slack_bot folder, and the encrypted bot token variable + resource at f/slack_bot/bot_token.
83205
+ - \`--bot-token <bot_token:string>\` - Slack bot token (xoxb-...)
83206
+ - \`--team-id <team_id:string>\` - Slack team id
83207
+ - \`--team-name <team_name:string>\` - Slack team name
83208
+ - \`workspace disconnect-slack\`
83063
83209
 
83064
83210
  `
83065
83211
  };
@@ -86001,7 +86147,7 @@ var config_default = command35;
86001
86147
 
86002
86148
  // src/main.ts
86003
86149
  await init_context();
86004
- var VERSION = "1.690.0";
86150
+ var VERSION = "1.691.1";
86005
86151
  async function checkVersionSafe(cmd) {
86006
86152
  const mainCommand = cmd.getMainCommand();
86007
86153
  const upgradeCommand = mainCommand.getCommand("upgrade");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "windmill-cli",
3
- "version": "1.690.0",
3
+ "version": "1.691.1",
4
4
  "description": "CLI for Windmill",
5
5
  "license": "Apache 2.0",
6
6
  "type": "module",