windmill-cli 1.696.2 → 1.698.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 +619 -141
  2. package/package.json +1 -1
package/esm/main.js CHANGED
@@ -16752,7 +16752,7 @@ var init_OpenAPI = __esm(() => {
16752
16752
  PASSWORD: undefined,
16753
16753
  TOKEN: getEnv3("WM_TOKEN"),
16754
16754
  USERNAME: undefined,
16755
- VERSION: "1.696.2",
16755
+ VERSION: "1.698.0",
16756
16756
  WITH_CREDENTIALS: true,
16757
16757
  interceptors: {
16758
16758
  request: new Interceptors,
@@ -17216,6 +17216,8 @@ __export(exports_services_gen, {
17216
17216
  loadFilePreview: () => loadFilePreview,
17217
17217
  loadFileMetadata: () => loadFileMetadata,
17218
17218
  loadCsvPreview: () => loadCsvPreview,
17219
+ listWsSpecificVersions: () => listWsSpecificVersions,
17220
+ listWsSpecific: () => listWsSpecific,
17219
17221
  listWorkspacesAsSuperAdmin: () => listWorkspacesAsSuperAdmin,
17220
17222
  listWorkspaces: () => listWorkspaces,
17221
17223
  listWorkspaceInvites: () => listWorkspaceInvites,
@@ -19667,6 +19669,26 @@ var backendVersion = () => {
19667
19669
  body: data3.requestBody,
19668
19670
  mediaType: "application/json"
19669
19671
  });
19672
+ }, listWsSpecific = (data3) => {
19673
+ return request(OpenAPI, {
19674
+ method: "GET",
19675
+ url: "/w/{workspace}/workspaces/list_ws_specific",
19676
+ path: {
19677
+ workspace: data3.workspace
19678
+ }
19679
+ });
19680
+ }, listWsSpecificVersions = (data3) => {
19681
+ return request(OpenAPI, {
19682
+ method: "GET",
19683
+ url: "/w/{workspace}/workspaces/list_ws_specific_versions",
19684
+ path: {
19685
+ workspace: data3.workspace
19686
+ },
19687
+ query: {
19688
+ kind: data3.kind,
19689
+ path: data3.path
19690
+ }
19691
+ });
19670
19692
  }, setPublicAppRateLimit = (data3) => {
19671
19693
  return request(OpenAPI, {
19672
19694
  method: "POST",
@@ -25373,7 +25395,7 @@ Found ${datatables.length} datatable(s):`);
25373
25395
  workspace: workspace.workspaceId,
25374
25396
  requestBody: {
25375
25397
  id: trueWorkspaceId,
25376
- name: opts.createWorkspaceName ?? trueWorkspaceId,
25398
+ name: opts.createWorkspaceName ?? workspaceName ?? trueWorkspaceId,
25377
25399
  color: forkColor
25378
25400
  }
25379
25401
  });
@@ -25389,7 +25411,7 @@ Found ${datatables.length} datatable(s):`);
25389
25411
  workspace: workspace.workspaceId,
25390
25412
  requestBody: {
25391
25413
  id: trueWorkspaceId,
25392
- name: opts.createWorkspaceName ?? trueWorkspaceId,
25414
+ name: opts.createWorkspaceName ?? workspaceName ?? trueWorkspaceId,
25393
25415
  color: forkColor,
25394
25416
  forked_datatables: forkedDatatables
25395
25417
  }
@@ -25475,9 +25497,21 @@ var init_fork = __esm(async () => {
25475
25497
  });
25476
25498
 
25477
25499
  // windmill-utils-internal/src/deploy.ts
25500
+ function isTriggerKind(kind) {
25501
+ return TRIGGER_KINDS.includes(kind);
25502
+ }
25503
+ function isTriggerOrScheduleKind(kind) {
25504
+ return kind === "schedule" || isTriggerKind(kind);
25505
+ }
25478
25506
  function folderName(path2) {
25479
25507
  return path2.replace(/^f\//, "");
25480
25508
  }
25509
+ function stripOperationalStateOnUpdate(payload, alreadyExists) {
25510
+ if (!alreadyExists)
25511
+ return payload;
25512
+ const { mode: _mode, enabled: _enabled, ...rest } = payload;
25513
+ return rest;
25514
+ }
25481
25515
  function getSubModules(flowModule) {
25482
25516
  const type = flowModule?.value?.type;
25483
25517
  if (type === "forloopflow" || type === "whileloopflow") {
@@ -25531,6 +25565,10 @@ async function checkItemExists(provider, kind, path2, workspace) {
25531
25565
  return provider.existsResourceType({ workspace, path: path2 });
25532
25566
  } else if (kind === "folder") {
25533
25567
  return provider.existsFolder({ workspace, name: folderName(path2) });
25568
+ } else if (kind === "schedule") {
25569
+ return provider.existsSchedule({ workspace, path: path2 });
25570
+ } else if (isTriggerKind(kind)) {
25571
+ return provider.existsTriggerByKind(kind, { workspace, path: path2 });
25534
25572
  }
25535
25573
  throw new Error(`Unknown kind: ${kind}`);
25536
25574
  }
@@ -25767,6 +25805,48 @@ async function deployItem(provider, kind, path2, workspaceFrom, workspaceTo, onB
25767
25805
  }
25768
25806
  });
25769
25807
  }
25808
+ } else if (kind === "schedule") {
25809
+ const schedule = await provider.getSchedule({
25810
+ workspace: workspaceFrom,
25811
+ path: path2
25812
+ });
25813
+ const baseBody = stripOperationalStateOnUpdate(schedule, alreadyExists);
25814
+ const requestBody = {
25815
+ ...baseBody,
25816
+ permissioned_as: onBehalfOf,
25817
+ preserve_permissioned_as: preserveOnBehalfOf
25818
+ };
25819
+ if (alreadyExists) {
25820
+ await provider.updateSchedule({
25821
+ workspace: workspaceTo,
25822
+ path: path2,
25823
+ requestBody
25824
+ });
25825
+ } else {
25826
+ await provider.createSchedule({
25827
+ workspace: workspaceTo,
25828
+ requestBody
25829
+ });
25830
+ }
25831
+ } else if (isTriggerKind(kind)) {
25832
+ const triggerBody = await provider.getTriggerForDeploy(kind, {
25833
+ workspace: workspaceFrom,
25834
+ path: path2,
25835
+ onBehalfOf
25836
+ });
25837
+ const requestBody = stripOperationalStateOnUpdate(triggerBody, alreadyExists);
25838
+ if (alreadyExists) {
25839
+ await provider.updateTriggerByKind(kind, {
25840
+ workspace: workspaceTo,
25841
+ path: path2,
25842
+ requestBody
25843
+ });
25844
+ } else {
25845
+ await provider.createTriggerByKind(kind, {
25846
+ workspace: workspaceTo,
25847
+ requestBody
25848
+ });
25849
+ }
25770
25850
  } else {
25771
25851
  throw new Error(`Unknown kind: ${kind}`);
25772
25852
  }
@@ -25795,6 +25875,10 @@ async function deleteItemInWorkspace(provider, kind, path2, workspace) {
25795
25875
  await provider.deleteResourceType({ workspace, path: path2 });
25796
25876
  } else if (kind === "folder") {
25797
25877
  await provider.deleteFolder({ workspace, name: folderName(path2) });
25878
+ } else if (kind === "schedule") {
25879
+ await provider.deleteSchedule({ workspace, path: path2 });
25880
+ } else if (isTriggerKind(kind)) {
25881
+ await provider.deleteTriggerByKind(kind, { workspace, path: path2 });
25798
25882
  } else {
25799
25883
  throw new Error(`Deletion not supported for kind: ${kind}`);
25800
25884
  }
@@ -25814,10 +25898,30 @@ async function getOnBehalfOf(provider, kind, path2, workspace) {
25814
25898
  } else if (kind === "app" || kind === "raw_app") {
25815
25899
  const app = await provider.getAppByPath({ workspace, path: path2 });
25816
25900
  return app.policy?.on_behalf_of_email;
25901
+ } else if (kind === "schedule") {
25902
+ const schedule = await provider.getSchedule({ workspace, path: path2 });
25903
+ return schedule.permissioned_as;
25904
+ } else if (isTriggerKind(kind)) {
25905
+ return await provider.getTriggerPermissionedAs(kind, { workspace, path: path2 });
25817
25906
  }
25818
25907
  } catch {}
25819
25908
  return;
25820
25909
  }
25910
+ var TRIGGER_KINDS;
25911
+ var init_deploy = __esm(() => {
25912
+ TRIGGER_KINDS = [
25913
+ "http_trigger",
25914
+ "websocket_trigger",
25915
+ "kafka_trigger",
25916
+ "nats_trigger",
25917
+ "postgres_trigger",
25918
+ "mqtt_trigger",
25919
+ "sqs_trigger",
25920
+ "gcp_trigger",
25921
+ "azure_trigger",
25922
+ "email_trigger"
25923
+ ];
25924
+ });
25821
25925
 
25822
25926
  // node_modules/@cliffy/prompt/checkbox.js
25823
25927
  var exports_checkbox = {};
@@ -26041,6 +26145,111 @@ var init_checkbox = __esm(async () => {
26041
26145
  });
26042
26146
 
26043
26147
  // src/commands/workspace/merge.ts
26148
+ function triggerService(kind) {
26149
+ switch (kind) {
26150
+ case "http_trigger":
26151
+ return {
26152
+ exists: existsHttpTrigger,
26153
+ get: getHttpTrigger,
26154
+ create: createHttpTrigger,
26155
+ update: updateHttpTrigger,
26156
+ delete: deleteHttpTrigger
26157
+ };
26158
+ case "websocket_trigger":
26159
+ return {
26160
+ exists: existsWebsocketTrigger,
26161
+ get: getWebsocketTrigger,
26162
+ create: createWebsocketTrigger,
26163
+ update: updateWebsocketTrigger,
26164
+ delete: deleteWebsocketTrigger
26165
+ };
26166
+ case "kafka_trigger":
26167
+ return {
26168
+ exists: existsKafkaTrigger,
26169
+ get: getKafkaTrigger,
26170
+ create: createKafkaTrigger,
26171
+ update: updateKafkaTrigger,
26172
+ delete: deleteKafkaTrigger
26173
+ };
26174
+ case "nats_trigger":
26175
+ return {
26176
+ exists: existsNatsTrigger,
26177
+ get: getNatsTrigger,
26178
+ create: createNatsTrigger,
26179
+ update: updateNatsTrigger,
26180
+ delete: deleteNatsTrigger
26181
+ };
26182
+ case "postgres_trigger":
26183
+ return {
26184
+ exists: existsPostgresTrigger,
26185
+ get: getPostgresTrigger,
26186
+ create: createPostgresTrigger,
26187
+ update: updatePostgresTrigger,
26188
+ delete: deletePostgresTrigger
26189
+ };
26190
+ case "mqtt_trigger":
26191
+ return {
26192
+ exists: existsMqttTrigger,
26193
+ get: getMqttTrigger,
26194
+ create: createMqttTrigger,
26195
+ update: updateMqttTrigger,
26196
+ delete: deleteMqttTrigger
26197
+ };
26198
+ case "sqs_trigger":
26199
+ return {
26200
+ exists: existsSqsTrigger,
26201
+ get: getSqsTrigger,
26202
+ create: createSqsTrigger,
26203
+ update: updateSqsTrigger,
26204
+ delete: deleteSqsTrigger
26205
+ };
26206
+ case "gcp_trigger":
26207
+ return {
26208
+ exists: existsGcpTrigger,
26209
+ get: getGcpTrigger,
26210
+ create: createGcpTrigger,
26211
+ update: updateGcpTrigger,
26212
+ delete: deleteGcpTrigger
26213
+ };
26214
+ case "azure_trigger":
26215
+ return {
26216
+ exists: existsAzureTrigger,
26217
+ get: getAzureTrigger,
26218
+ create: createAzureTrigger,
26219
+ update: updateAzureTrigger,
26220
+ delete: deleteAzureTrigger
26221
+ };
26222
+ case "email_trigger":
26223
+ return {
26224
+ exists: existsEmailTrigger,
26225
+ get: getEmailTrigger,
26226
+ create: createEmailTrigger,
26227
+ update: updateEmailTrigger,
26228
+ delete: deleteEmailTrigger
26229
+ };
26230
+ }
26231
+ }
26232
+ function preparePayload(kind, trigger, onBehalfOf) {
26233
+ const preserve = onBehalfOf !== undefined;
26234
+ const base = {
26235
+ ...trigger,
26236
+ permissioned_as: onBehalfOf,
26237
+ preserve_permissioned_as: preserve
26238
+ };
26239
+ if (kind === "gcp_trigger") {
26240
+ base.subscription_id = "";
26241
+ base.subscription_mode = "create_update";
26242
+ if (base.delivery_config) {
26243
+ base.delivery_config = { ...base.delivery_config, audience: "" };
26244
+ }
26245
+ if (base.delivery_type === "push") {
26246
+ base.base_endpoint = OpenAPI.BASE.replace(/\/api\/?$/, "");
26247
+ } else {
26248
+ base.base_endpoint = undefined;
26249
+ }
26250
+ }
26251
+ return base;
26252
+ }
26044
26253
  async function mergeWorkspaces(opts) {
26045
26254
  const workspace = await tryResolveBranchWorkspace(opts);
26046
26255
  if (!workspace) {
@@ -26091,6 +26300,10 @@ async function mergeWorkspaces(opts) {
26091
26300
  summaryRows.push(["Resource Types", String(summary.resource_types_changed)]);
26092
26301
  if (summary.folders_changed > 0)
26093
26302
  summaryRows.push(["Folders", String(summary.folders_changed)]);
26303
+ if (summary.schedules_changed > 0)
26304
+ summaryRows.push(["Schedules", String(summary.schedules_changed)]);
26305
+ if (summary.triggers_changed > 0)
26306
+ summaryRows.push(["Triggers", String(summary.triggers_changed)]);
26094
26307
  summaryRows.push(["Total", String(summary.total_diffs)]);
26095
26308
  if (summary.conflicts > 0)
26096
26309
  summaryRows.push([
@@ -26156,11 +26369,9 @@ Direction: ${colors.bold(direction === "to-parent" ? `Fork → Parent (${parentW
26156
26369
  if (opts.all) {
26157
26370
  selectedDiffs = selectableDiffs;
26158
26371
  } else if (opts.skipConflicts) {
26159
- selectedDiffs = selectableDiffs.filter((d) => !(d.ahead > 0 && d.behind > 0));
26372
+ selectedDiffs = selectableDiffs.filter((d) => !(d.ahead > 0 && d.behind > 0) && (!!opts.include || !isTriggerOrScheduleKind(d.kind)));
26160
26373
  } else if (opts.yes && !opts.include && !opts.exclude) {
26161
- if (direction === "to-fork") {
26162
- selectedDiffs = selectableDiffs.filter((d) => !(d.ahead > 0 && d.behind > 0));
26163
- }
26374
+ selectedDiffs = selectableDiffs.filter((d) => !isTriggerOrScheduleKind(d.kind) && (direction !== "to-fork" || !(d.ahead > 0 && d.behind > 0)));
26164
26375
  } else if (!opts.yes) {
26165
26376
  const { Checkbox: Checkbox2 } = await init_checkbox().then(() => exports_checkbox);
26166
26377
  const defaultForToFork = direction === "to-fork";
@@ -26168,11 +26379,12 @@ Direction: ${colors.bold(direction === "to-parent" ? `Fork → Parent (${parentW
26168
26379
  message: `Select items to deploy (${selectableDiffs.length} available):`,
26169
26380
  options: selectableDiffs.map((d) => {
26170
26381
  const isConflict = d.ahead > 0 && d.behind > 0;
26382
+ const isTriggerOrSchedule = isTriggerOrScheduleKind(d.kind);
26171
26383
  const label = `${d.kind}:${d.path}${isConflict ? colors.red(" [CONFLICT]") : ""}`;
26172
26384
  return {
26173
26385
  name: label,
26174
26386
  value: `${d.kind}:${d.path}`,
26175
- checked: defaultForToFork ? !isConflict : true
26387
+ checked: !isTriggerOrSchedule && (defaultForToFork ? !isConflict : true)
26176
26388
  };
26177
26389
  })
26178
26390
  });
@@ -26261,6 +26473,8 @@ var init_merge = __esm(async () => {
26261
26473
  init_log();
26262
26474
  init_client();
26263
26475
  init_services_gen();
26476
+ init_OpenAPI();
26477
+ init_deploy();
26264
26478
  await init_context();
26265
26479
  provider = {
26266
26480
  existsFlowByPath,
@@ -26300,7 +26514,28 @@ var init_merge = __esm(async () => {
26300
26514
  getFolder,
26301
26515
  createFolder,
26302
26516
  updateFolder,
26303
- deleteFolder
26517
+ deleteFolder,
26518
+ existsTriggerByKind: (kind, p) => triggerService(kind).exists(p),
26519
+ getTriggerForDeploy: async (kind, p) => {
26520
+ const trigger = await triggerService(kind).get({
26521
+ workspace: p.workspace,
26522
+ path: p.path
26523
+ });
26524
+ return preparePayload(kind, trigger, p.onBehalfOf);
26525
+ },
26526
+ createTriggerByKind: (kind, p) => triggerService(kind).create(p),
26527
+ updateTriggerByKind: (kind, p) => triggerService(kind).update(p),
26528
+ deleteTriggerByKind: (kind, p) => triggerService(kind).delete(p),
26529
+ getTriggerValue: (kind, p) => triggerService(kind).get(p),
26530
+ getTriggerPermissionedAs: async (kind, p) => {
26531
+ const trigger = await triggerService(kind).get(p);
26532
+ return trigger?.permissioned_as;
26533
+ },
26534
+ existsSchedule,
26535
+ getSchedule,
26536
+ createSchedule,
26537
+ updateSchedule,
26538
+ deleteSchedule
26304
26539
  };
26305
26540
  });
26306
26541
 
@@ -61342,33 +61577,34 @@ async function resolveWsNameForGitBranch(branchName) {
61342
61577
  const match2 = findWorkspaceByGitBranch(config.workspaces, branchName);
61343
61578
  return match2 ? match2[0] : branchName;
61344
61579
  }
61345
- function getWorkspaceSpecificTypes() {
61346
- return {
61347
- variable: ".variable.yaml",
61348
- resource: ".resource.yaml",
61349
- schedule: ".schedule.yaml",
61350
- ...Object.fromEntries(TRIGGER_TYPES.map((t) => [`${t}_trigger`, `.${t}_trigger.yaml`]))
61351
- };
61580
+ function getWorkspaceSpecificTypeKinds() {
61581
+ return [
61582
+ "variable",
61583
+ "resource",
61584
+ "schedule",
61585
+ ...TRIGGER_TYPES.map((t) => `${t}_trigger`)
61586
+ ];
61352
61587
  }
61353
61588
  function isTriggerFile(path7) {
61354
- return TRIGGER_TYPES.some((type) => path7.endsWith(`.${type}_trigger.yaml`));
61589
+ return TRIGGER_TYPES.some((type) => path7.endsWith(`.${type}_trigger.yaml`) || path7.endsWith(`.${type}_trigger.json`));
61355
61590
  }
61356
61591
  function isScheduleFile(path7) {
61357
- return path7.endsWith(".schedule.yaml");
61592
+ return path7.endsWith(".schedule.yaml") || path7.endsWith(".schedule.json");
61358
61593
  }
61359
61594
  function getFileTypeSuffix(path7) {
61360
- for (const [_, suffix] of Object.entries(getWorkspaceSpecificTypes())) {
61361
- if (path7.endsWith(suffix)) {
61362
- return suffix;
61363
- }
61595
+ for (const kind of getWorkspaceSpecificTypeKinds()) {
61596
+ if (path7.endsWith(`.${kind}.yaml`))
61597
+ return `.${kind}.yaml`;
61598
+ if (path7.endsWith(`.${kind}.json`))
61599
+ return `.${kind}.json`;
61364
61600
  }
61365
- const resourceFileMatch = path7.match(/(\\.resource\\.file\\..+)$/);
61601
+ const resourceFileMatch = path7.match(/(\.resource\.file\..+)$/);
61366
61602
  if (resourceFileMatch) {
61367
61603
  return resourceFileMatch[1];
61368
61604
  }
61369
61605
  return null;
61370
61606
  }
61371
- function buildYamlTypePattern() {
61607
+ function buildItemTypePattern() {
61372
61608
  const basicTypes = ["variable", "resource", "schedule"];
61373
61609
  const triggerTypes = TRIGGER_TYPES.map((t) => `${t}_trigger`);
61374
61610
  return `((${basicTypes.join("|")})|(${triggerTypes.join("|")}))`;
@@ -61436,10 +61672,14 @@ function getSpecificItemsForCurrentBranch(config, workspaceNameOverride) {
61436
61672
  function matchesPatterns(path7, patterns) {
61437
61673
  return patterns.some((pattern) => minimatch(path7, pattern));
61438
61674
  }
61675
+ function normalizeJsonToYaml(path7) {
61676
+ return path7.endsWith(".json") ? path7.slice(0, -".json".length) + ".yaml" : path7;
61677
+ }
61439
61678
  function isItemTypeConfigured(path7, specificItems) {
61440
61679
  if (!specificItems) {
61441
61680
  return false;
61442
61681
  }
61682
+ path7 = normalizeJsonToYaml(path7);
61443
61683
  if (path7.endsWith(".variable.yaml")) {
61444
61684
  return specificItems.variables !== undefined;
61445
61685
  }
@@ -61467,6 +61707,7 @@ function isSpecificItem(path7, specificItems) {
61467
61707
  if (!specificItems) {
61468
61708
  return false;
61469
61709
  }
61710
+ path7 = normalizeJsonToYaml(path7);
61470
61711
  if (path7.endsWith(".variable.yaml")) {
61471
61712
  return specificItems.variables ? matchesPatterns(path7, specificItems.variables) : false;
61472
61713
  }
@@ -61510,12 +61751,13 @@ function toWorkspaceSpecificPath(basePath, workspaceName) {
61510
61751
  if (sanitizedName !== workspaceName) {
61511
61752
  console.warn(`Warning: Workspace name "${workspaceName}" contains filesystem-unsafe characters (/ \\ : * ? " < > | .) and was sanitized to "${sanitizedName}". This may cause collisions with other similarly named branches.`);
61512
61753
  }
61513
- if (basePath.endsWith("/folder.meta.yaml")) {
61514
- const pathWithoutMeta = basePath.substring(0, basePath.length - "/folder.meta.yaml".length);
61515
- return `${pathWithoutMeta}/folder.${sanitizedName}.meta.yaml`;
61754
+ const folderMetaMatch = basePath.match(/^(.*)\/folder\.meta\.(yaml|json)$/);
61755
+ if (folderMetaMatch) {
61756
+ return `${folderMetaMatch[1]}/folder.${sanitizedName}.meta.${folderMetaMatch[2]}`;
61516
61757
  }
61517
- if (basePath === "settings.yaml") {
61518
- return `settings.${sanitizedName}.yaml`;
61758
+ const settingsMatch = basePath.match(/^settings\.(yaml|json)$/);
61759
+ if (settingsMatch) {
61760
+ return `settings.${sanitizedName}.${settingsMatch[1]}`;
61519
61761
  }
61520
61762
  const resourceFileMatch = basePath.match(/^(.+?)(\.resource\.file\..+)$/);
61521
61763
  let extension;
@@ -61536,13 +61778,15 @@ function toWorkspaceSpecificPath(basePath, workspaceName) {
61536
61778
  function fromWorkspaceSpecificPath(workspaceSpecificPath, workspaceName) {
61537
61779
  const sanitizedName = workspaceName.replace(/[\/\\:*?"<>|.]/g, "_");
61538
61780
  const escapedName = sanitizedName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
61539
- const folderPattern = new RegExp(`/folder\\.${escapedName}\\.meta\\.yaml$`);
61540
- if (folderPattern.test(workspaceSpecificPath)) {
61541
- return workspaceSpecificPath.replace(folderPattern, "/folder.meta.yaml");
61781
+ const folderPattern = new RegExp(`/folder\\.${escapedName}\\.meta\\.(yaml|json)$`);
61782
+ const folderMatch = workspaceSpecificPath.match(folderPattern);
61783
+ if (folderMatch) {
61784
+ return workspaceSpecificPath.replace(folderPattern, `/folder.meta.${folderMatch[1]}`);
61542
61785
  }
61543
- const settingsPattern = new RegExp(`^settings\\.${escapedName}\\.yaml$`);
61544
- if (settingsPattern.test(workspaceSpecificPath)) {
61545
- return "settings.yaml";
61786
+ const settingsPattern = new RegExp(`^settings\\.${escapedName}\\.(yaml|json)$`);
61787
+ const settingsMatch = workspaceSpecificPath.match(settingsPattern);
61788
+ if (settingsMatch) {
61789
+ return `settings.${settingsMatch[1]}`;
61546
61790
  }
61547
61791
  const resourceFilePattern = new RegExp(`\\.${escapedName}(\\.resource\\.file\\..+)$`);
61548
61792
  const resourceFileMatch = workspaceSpecificPath.match(resourceFilePattern);
@@ -61551,12 +61795,12 @@ function fromWorkspaceSpecificPath(workspaceSpecificPath, workspaceName) {
61551
61795
  const pathWithoutBranchAndExtension2 = workspaceSpecificPath.substring(0, workspaceSpecificPath.length - `.${sanitizedName}${extension2}`.length);
61552
61796
  return `${pathWithoutBranchAndExtension2}${extension2}`;
61553
61797
  }
61554
- const yamlPattern = new RegExp(`\\.${escapedName}(\\.${buildYamlTypePattern()}\\.yaml)$`);
61555
- const yamlMatch = workspaceSpecificPath.match(yamlPattern);
61556
- if (!yamlMatch) {
61798
+ const typedPattern = new RegExp(`\\.${escapedName}(\\.${buildItemTypePattern()}\\.(yaml|json))$`);
61799
+ const typedMatch = workspaceSpecificPath.match(typedPattern);
61800
+ if (!typedMatch) {
61557
61801
  return workspaceSpecificPath;
61558
61802
  }
61559
- const extension = yamlMatch[1];
61803
+ const extension = typedMatch[1];
61560
61804
  const pathWithoutBranchAndExtension = workspaceSpecificPath.substring(0, workspaceSpecificPath.length - `.${sanitizedName}${extension}`.length);
61561
61805
  return `${pathWithoutBranchAndExtension}${extension}`;
61562
61806
  }
@@ -61592,14 +61836,14 @@ function isCurrentWorkspaceFile(path7, workspaceNameOverride) {
61592
61836
  const escapedName = sanitizedName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
61593
61837
  let pattern = workspacePatternCache.get(currentWorkspace);
61594
61838
  if (!pattern) {
61595
- pattern = new RegExp(`\\.${escapedName}\\.${buildYamlTypePattern()}\\.yaml$|` + `\\.${escapedName}\\.resource\\.file\\..+$|` + `/folder\\.${escapedName}\\.meta\\.yaml$|` + `^settings\\.${escapedName}\\.yaml$`);
61839
+ pattern = new RegExp(`\\.${escapedName}\\.${buildItemTypePattern()}\\.(yaml|json)$|` + `\\.${escapedName}\\.resource\\.file\\..+$|` + `/folder\\.${escapedName}\\.meta\\.(yaml|json)$|` + `^settings\\.${escapedName}\\.(yaml|json)$`);
61596
61840
  workspacePatternCache.set(currentWorkspace, pattern);
61597
61841
  }
61598
61842
  return pattern.test(path7);
61599
61843
  }
61600
61844
  function isWorkspaceSpecificFile(path7) {
61601
- const yamlTypePattern = buildYamlTypePattern();
61602
- return new RegExp(`\\.[^.]+\\.${yamlTypePattern}\\.yaml$|` + `\\.[^.]+\\.resource\\.file\\..+$|` + `/folder\\.[^.]+\\.meta\\.yaml$|` + `^settings\\.[^.]+\\.yaml$`).test(path7);
61845
+ const typePattern = buildItemTypePattern();
61846
+ return new RegExp(`\\.[^.]+\\.${typePattern}\\.(yaml|json)$|` + `\\.[^.]+\\.resource\\.file\\..+$|` + `/folder\\.[^.]+\\.meta\\.(yaml|json)$|` + `^settings\\.[^.]+\\.(yaml|json)$`).test(path7);
61603
61847
  }
61604
61848
  var workspacePatternCache;
61605
61849
  var init_specific_items = __esm(async () => {
@@ -62265,6 +62509,7 @@ async function readModulesFromDisk(moduleFolderPath, defaultTs, folderLayout = f
62265
62509
  async function createScript2(bundleContent, workspaceId, body, workspace) {
62266
62510
  const start = performance.now();
62267
62511
  const skipIfNoop = "skip_if_noop=true";
62512
+ const extraHeaders = getHeaders2();
62268
62513
  if (!bundleContent) {
62269
62514
  try {
62270
62515
  const url = workspace.remote + "api/w/" + workspaceId + "/scripts/create?" + skipIfNoop;
@@ -62272,10 +62517,12 @@ async function createScript2(bundleContent, workspaceId, body, workspace) {
62272
62517
  method: "POST",
62273
62518
  headers: {
62274
62519
  Authorization: `Bearer ${workspace.token}`,
62275
- "Content-Type": "application/json"
62520
+ "Content-Type": "application/json",
62521
+ ...extraHeaders
62276
62522
  },
62277
62523
  body: JSON.stringify(body)
62278
62524
  });
62525
+ await detectAuthGatewayChallenge(req, url);
62279
62526
  if (req.status != 201) {
62280
62527
  throw Error(`${req.status} - ${req.statusText} - ${await req.text()}`);
62281
62528
  }
@@ -62289,9 +62536,13 @@ async function createScript2(bundleContent, workspaceId, body, workspace) {
62289
62536
  const url = workspace.remote + "api/w/" + workspace.workspaceId + "/scripts/create_snapshot?" + skipIfNoop;
62290
62537
  const req = await fetch(url, {
62291
62538
  method: "POST",
62292
- headers: { Authorization: `Bearer ${workspace.token} ` },
62539
+ headers: {
62540
+ Authorization: `Bearer ${workspace.token} `,
62541
+ ...extraHeaders
62542
+ },
62293
62543
  body: form
62294
62544
  });
62545
+ await detectAuthGatewayChallenge(req, url);
62295
62546
  if (req.status != 201) {
62296
62547
  throw Error(`Script snapshot creation was not successful: ${req.status} - ${req.statusText} - ${await req.text()} `);
62297
62548
  }
@@ -62836,11 +63087,16 @@ async function preview(opts, filePath) {
62836
63087
  form.append("preview", JSON.stringify(previewPayload));
62837
63088
  form.append("file", typeof bundledContent === "string" ? new Blob([bundledContent], { type: "application/javascript" }) : bundledContent);
62838
63089
  const url = workspace.remote + "api/w/" + workspace.workspaceId + "/jobs/run/preview_bundle";
63090
+ const extraHeaders = getHeaders2();
62839
63091
  const response = await fetch(url, {
62840
63092
  method: "POST",
62841
- headers: { Authorization: `Bearer ${workspace.token}` },
63093
+ headers: {
63094
+ Authorization: `Bearer ${workspace.token}`,
63095
+ ...extraHeaders
63096
+ },
62842
63097
  body: form
62843
63098
  });
63099
+ await detectAuthGatewayChallenge(response, url);
62844
63100
  if (!response.ok) {
62845
63101
  throw new Error(`Preview failed: ${response.status} - ${response.statusText} - ${await response.text()}`);
62846
63102
  }
@@ -62948,6 +63204,7 @@ var init_script = __esm(async () => {
62948
63204
  init_mod3();
62949
63205
  init_mod6();
62950
63206
  init_log();
63207
+ init_http_guards();
62951
63208
  init_services_gen();
62952
63209
  init_git();
62953
63210
  init_script_bootstrap();
@@ -63815,7 +64072,7 @@ async function readFilesetDirectory(dirPath) {
63815
64072
  await walk(dirPath, "");
63816
64073
  return result;
63817
64074
  }
63818
- async function pushResource(workspace, remotePath, resource, localResource, originalLocalPath) {
64075
+ async function pushResource(workspace, remotePath, resource, localResource, originalLocalPath, wsSpecific) {
63819
64076
  remotePath = removeType(remotePath, "resource");
63820
64077
  try {
63821
64078
  resource = await getResource({
@@ -63852,7 +64109,7 @@ async function pushResource(workspace, remotePath, resource, localResource, orig
63852
64109
  await updateResource({
63853
64110
  workspace,
63854
64111
  path: remotePath.replaceAll(SEP6, "/"),
63855
- requestBody: { ...localResource }
64112
+ requestBody: { ...localResource, ...wsSpecific !== undefined ? { ws_specific: wsSpecific } : {} }
63856
64113
  });
63857
64114
  } else {
63858
64115
  await resolveInlineContent();
@@ -63864,7 +64121,8 @@ async function pushResource(workspace, remotePath, resource, localResource, orig
63864
64121
  workspace,
63865
64122
  requestBody: {
63866
64123
  path: remotePath.replaceAll(SEP6, "/"),
63867
- ...localResource
64124
+ ...localResource,
64125
+ ...wsSpecific !== undefined ? { ws_specific: wsSpecific } : {}
63868
64126
  }
63869
64127
  });
63870
64128
  }
@@ -64736,6 +64994,7 @@ async function rehashOnly(opts, folder, rehashFilter) {
64736
64994
  }
64737
64995
  const stubWorkspace = {};
64738
64996
  const rehashOpts = { ...opts, rehashOnly: true };
64997
+ const queue = [];
64739
64998
  if (!rehashFilter?.skipScripts) {
64740
64999
  for (const e of scriptPaths) {
64741
65000
  const remotePath = scriptPathToRemotePath(e);
@@ -64745,12 +65004,7 @@ async function rehashOnly(opts, folder, rehashFilter) {
64745
65004
  if (skipIfExisting(remotePath) || skipIfExisting(remotePath, "__script_hash"))
64746
65005
  continue;
64747
65006
  }
64748
- try {
64749
- await generateScriptMetadataInternal(e, stubWorkspace, rehashOpts, false, true, {}, codebases, false);
64750
- counts.scripts++;
64751
- } catch (err) {
64752
- warn(`Skipping ${e}: ${err instanceof Error ? err.message : err}`);
64753
- }
65007
+ queue.push({ kind: "script", scriptPath: e });
64754
65008
  }
64755
65009
  }
64756
65010
  if (!rehashFilter?.skipFlows) {
@@ -64762,12 +65016,7 @@ async function rehashOnly(opts, folder, rehashFilter) {
64762
65016
  if (skipIfExisting(folderNormalized, "__flow_hash"))
64763
65017
  continue;
64764
65018
  }
64765
- try {
64766
- await generateFlowLockInternal(f, false, stubWorkspace, rehashOpts, false, true);
64767
- counts.flows++;
64768
- } catch (err) {
64769
- warn(`Skipping ${f}: ${err instanceof Error ? err.message : err}`);
64770
- }
65019
+ queue.push({ kind: "flow", folder: f });
64771
65020
  }
64772
65021
  }
64773
65022
  if (!rehashFilter?.skipApps) {
@@ -64779,13 +65028,47 @@ async function rehashOnly(opts, folder, rehashFilter) {
64779
65028
  if (skipIfExisting(folderNormalized, "__app_hash"))
64780
65029
  continue;
64781
65030
  }
64782
- try {
64783
- await generateAppLocksInternal(appFolder, rawApp, false, stubWorkspace, rehashOpts, false, true);
64784
- counts.apps++;
64785
- } catch (err) {
64786
- warn(`Skipping ${appFolder}: ${err instanceof Error ? err.message : err}`);
65031
+ queue.push({ kind: "app", folder: appFolder, rawApp });
65032
+ }
65033
+ }
65034
+ let parallelism = Number(opts.parallel ?? 1);
65035
+ if (!Number.isFinite(parallelism) || parallelism <= 0)
65036
+ parallelism = 1;
65037
+ if (parallelism > 1) {
65038
+ info(`Parallelizing ${parallelism} items at a time`);
65039
+ }
65040
+ await beginLockfileBatch();
65041
+ try {
65042
+ const pool = new Set;
65043
+ while (queue.length > 0 || pool.size > 0) {
65044
+ while (pool.size < parallelism && queue.length > 0) {
65045
+ const task = queue.shift();
65046
+ const p = (async () => {
65047
+ try {
65048
+ if (task.kind === "script") {
65049
+ await generateScriptMetadataInternal(task.scriptPath, stubWorkspace, rehashOpts, false, true, {}, codebases, false);
65050
+ counts.scripts++;
65051
+ } else if (task.kind === "flow") {
65052
+ await generateFlowLockInternal(task.folder, false, stubWorkspace, rehashOpts, false, true);
65053
+ counts.flows++;
65054
+ } else {
65055
+ await generateAppLocksInternal(task.folder, task.rawApp, false, stubWorkspace, rehashOpts, false, true);
65056
+ counts.apps++;
65057
+ }
65058
+ } catch (err) {
65059
+ const label = task.kind === "script" ? task.scriptPath : task.folder;
65060
+ warn(`Skipping ${label}: ${err instanceof Error ? err.message : err}`);
65061
+ }
65062
+ })();
65063
+ pool.add(p);
65064
+ p.then(() => pool.delete(p));
65065
+ }
65066
+ if (pool.size > 0) {
65067
+ await Promise.race(pool);
64787
65068
  }
64788
65069
  }
65070
+ } finally {
65071
+ await flushLockfileBatch();
64789
65072
  }
64790
65073
  if (counts.scripts + counts.flows + counts.apps > 0 || !rehashFilter?.missingOnly) {
64791
65074
  info(`Rehashed ${colors.bold(String(counts.scripts))} script(s), ` + `${colors.bold(String(counts.flows))} flow(s), ` + `${colors.bold(String(counts.apps))} app(s) from disk.`);
@@ -64948,47 +65231,75 @@ async function generateMetadata2(opts, folder) {
64948
65231
  return colors.dim(colors.white(`[${n}/${total}]`.padEnd(maxWidth, " ")));
64949
65232
  };
64950
65233
  const errors = [];
64951
- for (const item of scripts) {
64952
- current++;
64953
- info(`${formatProgress(current)} script ${item.path}`);
64954
- try {
64955
- await generateScriptMetadataInternal(item.path, workspace, opts, false, true, mismatchedWorkspaceDeps, codebases, false, tree);
64956
- } catch (e) {
64957
- const msg = e instanceof Error ? e.message : String(e);
64958
- errors.push({ path: item.path, error: msg });
64959
- error(` Failed: ${msg}`);
64960
- }
64961
- }
64962
- for (const item of flows) {
64963
- current++;
64964
- try {
64965
- const result = await generateFlowLockInternal(item.folder.replaceAll("/", SEP8), false, workspace, opts, false, true, tree);
64966
- const flowResult = result;
64967
- const scriptsInfo = flowResult?.updatedScripts?.length ? colors.dim(colors.white(`: ${flowResult.updatedScripts.join(", ")}`)) : "";
64968
- info(`${formatProgress(current)} flow ${item.path}${scriptsInfo}`);
64969
- } catch (e) {
64970
- const msg = e instanceof Error ? e.message : String(e);
64971
- errors.push({ path: item.path, error: msg });
64972
- info(`${formatProgress(current)} flow ${item.path}`);
64973
- error(` Failed: ${msg}`);
64974
- }
64975
- }
64976
- for (const item of apps2) {
64977
- current++;
64978
- try {
64979
- const result = await generateAppLocksInternal(item.folder.replaceAll("/", SEP8), item.isRawApp, false, workspace, opts, false, true, tree);
64980
- const appResult = result;
64981
- const scriptsInfo = appResult?.updatedScripts?.length ? colors.dim(colors.white(`: ${appResult.updatedScripts.join(", ")}`)) : "";
64982
- info(`${formatProgress(current)} app ${item.path}${scriptsInfo}`);
64983
- } catch (e) {
64984
- const msg = e instanceof Error ? e.message : String(e);
64985
- errors.push({ path: item.path, error: msg });
64986
- info(`${formatProgress(current)} app ${item.path}`);
64987
- error(` Failed: ${msg}`);
65234
+ let parallelism = Number(opts.parallel ?? 1);
65235
+ if (!Number.isFinite(parallelism) || parallelism <= 0)
65236
+ parallelism = 1;
65237
+ if (parallelism > 1) {
65238
+ info(`Parallelizing ${parallelism} items at a time`);
65239
+ }
65240
+ const queue = [
65241
+ ...scripts.map((item) => ({ kind: "script", item })),
65242
+ ...flows.map((item) => ({ kind: "flow", item })),
65243
+ ...apps2.map((item) => ({ kind: "app", item }))
65244
+ ];
65245
+ await beginLockfileBatch();
65246
+ try {
65247
+ const pool = new Set;
65248
+ while (queue.length > 0 || pool.size > 0) {
65249
+ while (pool.size < parallelism && queue.length > 0) {
65250
+ const task = queue.shift();
65251
+ const taskNumber = ++current;
65252
+ const p = (async () => {
65253
+ if (task.kind === "script") {
65254
+ const item = task.item;
65255
+ info(`${formatProgress(taskNumber)} script ${item.path}`);
65256
+ try {
65257
+ await generateScriptMetadataInternal(item.path, workspace, opts, false, true, mismatchedWorkspaceDeps, codebases, false, tree);
65258
+ } catch (e) {
65259
+ const msg = e instanceof Error ? e.message : String(e);
65260
+ errors.push({ path: item.path, error: msg });
65261
+ error(` Failed: ${msg}`);
65262
+ }
65263
+ } else if (task.kind === "flow") {
65264
+ const item = task.item;
65265
+ try {
65266
+ const result = await generateFlowLockInternal(item.folder.replaceAll("/", SEP8), false, workspace, opts, false, true, tree);
65267
+ const flowResult = result;
65268
+ const scriptsInfo = flowResult?.updatedScripts?.length ? colors.dim(colors.white(`: ${flowResult.updatedScripts.join(", ")}`)) : "";
65269
+ info(`${formatProgress(taskNumber)} flow ${item.path}${scriptsInfo}`);
65270
+ } catch (e) {
65271
+ const msg = e instanceof Error ? e.message : String(e);
65272
+ errors.push({ path: item.path, error: msg });
65273
+ info(`${formatProgress(taskNumber)} flow ${item.path}`);
65274
+ error(` Failed: ${msg}`);
65275
+ }
65276
+ } else {
65277
+ const item = task.item;
65278
+ try {
65279
+ const result = await generateAppLocksInternal(item.folder.replaceAll("/", SEP8), item.isRawApp, false, workspace, opts, false, true, tree);
65280
+ const appResult = result;
65281
+ const scriptsInfo = appResult?.updatedScripts?.length ? colors.dim(colors.white(`: ${appResult.updatedScripts.join(", ")}`)) : "";
65282
+ info(`${formatProgress(taskNumber)} app ${item.path}${scriptsInfo}`);
65283
+ } catch (e) {
65284
+ const msg = e instanceof Error ? e.message : String(e);
65285
+ errors.push({ path: item.path, error: msg });
65286
+ info(`${formatProgress(taskNumber)} app ${item.path}`);
65287
+ error(` Failed: ${msg}`);
65288
+ }
65289
+ }
65290
+ })();
65291
+ pool.add(p);
65292
+ p.then(() => pool.delete(p));
65293
+ }
65294
+ if (pool.size > 0) {
65295
+ await Promise.race(pool);
65296
+ }
64988
65297
  }
65298
+ const allStaleDeps = staleItems.filter((i) => i.type === "dependencies");
65299
+ await tree.persistDepsHashes(allStaleDeps.map((d) => d.path));
65300
+ } finally {
65301
+ await flushLockfileBatch();
64989
65302
  }
64990
- const allStaleDeps = staleItems.filter((i) => i.type === "dependencies");
64991
- await tree.persistDepsHashes(allStaleDeps.map((d) => d.path));
64992
65303
  const succeeded = total - errors.length;
64993
65304
  info("");
64994
65305
  if (errors.length > 0) {
@@ -65030,13 +65341,14 @@ var init_generate_metadata = __esm(async () => {
65030
65341
  init_codebase(),
65031
65342
  init_dependency_tree()
65032
65343
  ]);
65033
- command7 = 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).command("rehash", new Command().description("Trust on-disk content; rewrite wmill-lock.yaml hashes without backend " + "trips or yaml/lock rewrites. Useful for bootstrapping missing lockfile " + "entries or recovering from older-CLI hash drift.").arguments("[folder:string]").option("--skip-scripts", "Skip processing scripts").option("--skip-flows", "Skip processing flows").option("--skip-apps", "Skip processing apps").option("-i --includes <patterns:file[]>", "Comma separated patterns to specify which files to include").option("-e --excludes <patterns:file[]>", "Comma separated patterns to specify which files to exclude").action(rehashCommand));
65344
+ command7 = 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("--parallel <n:number>", "Number of items to process in parallel").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).command("rehash", new Command().description("Trust on-disk content; rewrite wmill-lock.yaml hashes without backend " + "trips or yaml/lock rewrites. Useful for bootstrapping missing lockfile " + "entries or recovering from older-CLI hash drift.").arguments("[folder:string]").option("--skip-scripts", "Skip processing scripts").option("--skip-flows", "Skip processing flows").option("--skip-apps", "Skip processing apps").option("--parallel <n:number>", "Number of items to process in parallel").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(rehashCommand));
65034
65345
  generate_metadata_default = command7;
65035
65346
  });
65036
65347
 
65037
65348
  // src/commands/sync/sync.ts
65038
65349
  var exports_sync = {};
65039
65350
  __export(exports_sync, {
65351
+ yamlSortedEntries: () => yamlSortedEntries,
65040
65352
  yamlOptions: () => yamlOptions,
65041
65353
  resolveWsNameForConfigFromFlags: () => resolveWsNameForConfigFromFlags,
65042
65354
  readDirRecursiveWithIgnore: () => readDirRecursiveWithIgnore2,
@@ -65051,11 +65363,74 @@ __export(exports_sync, {
65051
65363
  extractFieldsForRawApps: () => extractFieldsForRawApps,
65052
65364
  elementsToMap: () => elementsToMap,
65053
65365
  default: () => sync_default,
65366
+ computeWsSpecificFlagOnlyPushes: () => computeWsSpecificFlagOnlyPushes,
65054
65367
  FSFSElement: () => FSFSElement
65055
65368
  });
65056
65369
  import { writeFile as writeFile7, readdir as readdir4, stat as stat7, rm, copyFile, mkdir as mkdir5 } from "node:fs/promises";
65057
65370
  import * as path11 from "node:path";
65058
65371
  import { sep as SEP9 } from "node:path";
65372
+ function configKeyForItemKind(kind) {
65373
+ switch (kind) {
65374
+ case "resource":
65375
+ return "resources";
65376
+ case "variable":
65377
+ return "variables";
65378
+ }
65379
+ return null;
65380
+ }
65381
+ async function mergeWsSpecificFromServer(workspaceId, specificItems) {
65382
+ let wsSpecificItems;
65383
+ try {
65384
+ wsSpecificItems = await listWsSpecific({ workspace: workspaceId });
65385
+ } catch (err) {
65386
+ const isApiError = err && typeof err === "object" && "name" in err && err.name === "ApiError";
65387
+ const status = isApiError ? err.status : undefined;
65388
+ if (status === 404) {
65389
+ debug("listWsSpecific endpoint not available on server, skipping");
65390
+ } else {
65391
+ const msg = err instanceof Error ? err.message : String(err);
65392
+ warn(`Could not fetch ws_specific items from server (${status ?? "no status"}): ${msg}. ` + `Sync will proceed without server-side ws_specific items.`);
65393
+ }
65394
+ return { merged: specificItems, serverItems: null };
65395
+ }
65396
+ if (wsSpecificItems.length === 0) {
65397
+ return { merged: specificItems, serverItems: wsSpecificItems };
65398
+ }
65399
+ const merged = specificItems ? { ...specificItems } : {};
65400
+ for (const item of wsSpecificItems) {
65401
+ const configKey = configKeyForItemKind(item.item_kind);
65402
+ if (!configKey)
65403
+ continue;
65404
+ if (!merged[configKey]) {
65405
+ merged[configKey] = [];
65406
+ }
65407
+ merged[configKey].push(`${item.path}.${item.item_kind}.yaml`);
65408
+ }
65409
+ return { merged, serverItems: wsSpecificItems };
65410
+ }
65411
+ function computeWsSpecificFlagOnlyPushes(localMap, localSpecificItems, serverItems) {
65412
+ if (!localSpecificItems || serverItems === null)
65413
+ return [];
65414
+ const serverSet = new Set(serverItems.map((i) => `${i.item_kind}:${i.path}`));
65415
+ const out = [];
65416
+ for (const filePath of Object.keys(localMap)) {
65417
+ let kind;
65418
+ try {
65419
+ kind = getTypeStrFromPath(filePath);
65420
+ } catch {
65421
+ continue;
65422
+ }
65423
+ if (configKeyForItemKind(kind) === null)
65424
+ continue;
65425
+ if (!isSpecificItem(filePath, localSpecificItems))
65426
+ continue;
65427
+ const serverPath = removeType(filePath, kind);
65428
+ if (serverSet.has(`${kind}:${serverPath}`))
65429
+ continue;
65430
+ out.push({ kind, serverPath, filePath });
65431
+ }
65432
+ return out;
65433
+ }
65059
65434
  function resolveWsNameFromBranch(opts, branchName) {
65060
65435
  const match2 = findWorkspaceByGitBranch(opts.workspaces, branchName);
65061
65436
  return match2 ? match2[0] : branchName;
@@ -65256,6 +65631,14 @@ function prioritizeName(name) {
65256
65631
  return "azz";
65257
65632
  return name;
65258
65633
  }
65634
+ function yamlSortedEntries(rec) {
65635
+ const entries = Object.entries(rec);
65636
+ if (Array.isArray(rec)) {
65637
+ return entries;
65638
+ }
65639
+ entries.sort(([a], [b]) => prioritizeName(a).localeCompare(prioritizeName(b)));
65640
+ return entries;
65641
+ }
65259
65642
  function extractFields(fields) {
65260
65643
  Object.entries(fields).forEach(([k, v]) => {
65261
65644
  if (typeof v == "object") {
@@ -65379,7 +65762,7 @@ function extractInlineScriptsForApps(key, rec, pathAssigner, toId, removeSchema)
65379
65762
  return [];
65380
65763
  }
65381
65764
  if (typeof rec == "object") {
65382
- return Object.entries(rec).flatMap(([k, v]) => {
65765
+ return yamlSortedEntries(rec).flatMap(([k, v]) => {
65383
65766
  if (k == "inlineScript" && v != null && typeof v == "object") {
65384
65767
  rec["type"] = undefined;
65385
65768
  const o = v;
@@ -65446,7 +65829,7 @@ async function findFilesetResourceFile(changePath) {
65446
65829
  }
65447
65830
  throw new Error(`No resource metadata file found for fileset resource: ${changePath}`);
65448
65831
  }
65449
- async function pushFilesetParentResource(childPath, workspaceId, alreadySynced, cachedWsName) {
65832
+ async function pushFilesetParentResource(childPath, workspaceId, alreadySynced, cachedWsName, specificItems) {
65450
65833
  let resourceFilePath;
65451
65834
  try {
65452
65835
  resourceFilePath = await findFilesetResourceFile(childPath);
@@ -65459,10 +65842,14 @@ async function pushFilesetParentResource(childPath, workspaceId, alreadySynced,
65459
65842
  alreadySynced.push(resourceFilePath);
65460
65843
  const newObj = parseFromPath(resourceFilePath, await readTextFile(resourceFilePath));
65461
65844
  let serverPath = resourceFilePath;
65845
+ let wsSpecific = false;
65462
65846
  if (cachedWsName && isWorkspaceSpecificFile(resourceFilePath)) {
65463
65847
  serverPath = fromWorkspaceSpecificPath(resourceFilePath, cachedWsName);
65848
+ wsSpecific = true;
65849
+ } else if (specificItems && isSpecificItem(childPath, specificItems)) {
65850
+ wsSpecific = true;
65464
65851
  }
65465
- await pushResource(workspaceId, serverPath, undefined, newObj, resourceFilePath);
65852
+ await pushResource(workspaceId, serverPath, undefined, newObj, resourceFilePath, wsSpecific ? true : undefined);
65466
65853
  return { status: "pushed", resourceFilePath };
65467
65854
  }
65468
65855
  function ZipFSElement(zip, useYaml, defaultTs, resourceTypeToFormatExtension, resourceTypeToIsFileset, ignoreCodebaseChanges, stripOnBehalfOf) {
@@ -66518,8 +66905,11 @@ async function pull(opts) {
66518
66905
  wsNameForConfig = inferWsNameFromProfile(opts, workspace);
66519
66906
  }
66520
66907
  const effectiveOpts = await resolveEffectiveSyncOptions(workspace, opts, opts.promotion, wsNameForConfig);
66521
- const specificItems = getSpecificItemsForCurrentBranch(opts, wsNameForConfig);
66522
- const wsNameForFiles = wsNameForConfig ? resolveWsNameForFiles(opts, wsNameForConfig) : undefined;
66908
+ let specificItems = getSpecificItemsForCurrentBranch(opts, wsNameForConfig);
66909
+ let wsNameForFiles = wsNameForConfig ? resolveWsNameForFiles(opts, wsNameForConfig) : workspace.workspaceId;
66910
+ const localSpecificItems = specificItems;
66911
+ const wsSpecificMerge = await mergeWsSpecificFromServer(workspace.workspaceId, specificItems);
66912
+ specificItems = wsSpecificMerge.merged;
66523
66913
  opts = mergeCliWithEffectiveOptions(originalCliOpts, effectiveOpts);
66524
66914
  const codebases = await listSyncCodebases(opts);
66525
66915
  info(colors.gray("Computing the files to update locally to match remote (taking wmill.yaml into account)"));
@@ -66538,6 +66928,17 @@ async function pull(opts) {
66538
66928
  const local = !opts.stateful ? await FSFSElement(process.cwd(), codebases, true) : await FSFSElement(path11.join(process.cwd(), ".wmill"), [], true);
66539
66929
  const { changes, localMap } = await compareDynFSElement(remote, local, await ignoreF(opts), opts.json ?? false, opts, false, codebases, true, specificItems, wsNameForFiles, true);
66540
66930
  info(`remote (${workspace.name}) -> local: ${changes.length} changes to apply`);
66931
+ if (wsSpecificMerge.serverItems && wsSpecificMerge.serverItems.length > 0) {
66932
+ const changedPaths = new Set(changes.map((c) => c.path));
66933
+ for (const item of wsSpecificMerge.serverItems) {
66934
+ const filePath = `${item.path}.${item.item_kind}.yaml`;
66935
+ if (!changedPaths.has(filePath))
66936
+ continue;
66937
+ if (!isSpecificItem(filePath, localSpecificItems)) {
66938
+ warn(`${item.item_kind} ${item.path} is workspace-specific on the remote ` + `but not flagged in wmill.yaml's specificItems — consider adding it.`);
66939
+ }
66940
+ }
66941
+ }
66541
66942
  if (opts.dryRun && opts.jsonOutput) {
66542
66943
  const result = {
66543
66944
  success: true,
@@ -66761,6 +67162,8 @@ function prettyChanges(changes, specificItems, branchOverride, folderDefaultAnno
66761
67162
  showDiff(change.before, change.after);
66762
67163
  }
66763
67164
  }
67165
+ } else if (change.name === "ws_specific_flag") {
67166
+ info(colors.cyan(`~ ${change.kind} ${displayPath} ` + (change.wsSpecific ? "(mark as workspace-specific)" : "(unmark as workspace-specific)")));
66764
67167
  }
66765
67168
  }
66766
67169
  }
@@ -66800,8 +67203,12 @@ async function push4(opts) {
66800
67203
  wsNameForConfig = inferWsNameFromProfile(opts, workspace);
66801
67204
  }
66802
67205
  const effectiveOpts = await resolveEffectiveSyncOptions(workspace, opts, opts.promotion, wsNameForConfig);
66803
- const specificItems = getSpecificItemsForCurrentBranch(opts, wsNameForConfig);
66804
- const wsNameForFiles = wsNameForConfig ? resolveWsNameForFiles(opts, wsNameForConfig) : undefined;
67206
+ let specificItems = getSpecificItemsForCurrentBranch(opts, wsNameForConfig);
67207
+ let wsNameForFiles = wsNameForConfig ? resolveWsNameForFiles(opts, wsNameForConfig) : workspace.workspaceId;
67208
+ const localSpecificItems = specificItems;
67209
+ const wsSpecificMerge = await mergeWsSpecificFromServer(workspace.workspaceId, specificItems);
67210
+ specificItems = wsSpecificMerge.merged;
67211
+ const serverWsSpecificItems = wsSpecificMerge.serverItems;
66805
67212
  opts = mergeCliWithEffectiveOptions(originalCliOpts, effectiveOpts);
66806
67213
  if (opts.lint) {
66807
67214
  info("Running lint validation before push...");
@@ -66853,7 +67260,18 @@ Push aborted: ${lockIssues.length} script(s) missing locks.`));
66853
67260
  } catch {}
66854
67261
  const remote = ZipFSElement(await downloadZip(workspace, opts.plainSecrets, opts.skipVariables, opts.skipResources, opts.skipResourceTypes, opts.skipSecrets, opts.includeSchedules, opts.includeTriggers, opts.includeUsers, opts.includeGroups, opts.includeSettings, opts.includeKey, opts.skipWorkspaceDependencies, opts.defaultTs), !opts.json, opts.defaultTs ?? "bun", resourceTypeToFormatExtension, resourceTypeToIsFileset, false, parseSyncBehavior(opts.syncBehavior) >= 1);
66855
67262
  const local = await FSFSElement(path11.join(process.cwd(), ""), codebases, false);
66856
- const { changes } = await compareDynFSElement(local, remote, await ignoreF(opts), opts.json ?? false, opts, true, codebases, false, specificItems, wsNameForFiles, false);
67263
+ const { changes, localMap } = await compareDynFSElement(local, remote, await ignoreF(opts), opts.json ?? false, opts, true, codebases, false, specificItems, wsNameForFiles, false);
67264
+ const wsSpecificFlagOnly = computeWsSpecificFlagOnlyPushes(localMap, localSpecificItems, serverWsSpecificItems);
67265
+ for (const item of wsSpecificFlagOnly) {
67266
+ if (changes.some((c) => c.path === item.filePath))
67267
+ continue;
67268
+ changes.push({
67269
+ name: "ws_specific_flag",
67270
+ path: item.filePath,
67271
+ kind: item.kind,
67272
+ wsSpecific: true
67273
+ });
67274
+ }
66857
67275
  const rawWorkspaceDependencies = await getRawWorkspaceDependencies(true);
66858
67276
  const tracker = await buildTracker(changes);
66859
67277
  const autoRegenerate = !!opts.autoMetadata;
@@ -67108,7 +67526,7 @@ Run 'wmill folder add-missing' to create them locally, then push again.`;
67108
67526
  userIsAdminOrDeployer,
67109
67527
  userEmail: user.email
67110
67528
  };
67111
- await preCheckPermissionedAs(changes, user.email, userIsAdminOrDeployer, opts.acceptOverridingPermissionedAsWithSelf ?? false, !!process.stdin.isTTY);
67529
+ await preCheckPermissionedAs(changes.filter((c) => c.name !== "ws_specific_flag"), user.email, userIsAdminOrDeployer, opts.acceptOverridingPermissionedAsWithSelf ?? false, !!process.stdin.isTTY);
67112
67530
  } else if (folderDefaultAnnotations && folderDefaultAnnotations.size > 0) {
67113
67531
  warn(colors.yellow(`This workspace has folder default_permissioned_as rules that affect ${folderDefaultAnnotations.size} item(s) being pushed, but syncBehavior is not set in wmill.yaml. Add 'syncBehavior: v1' to enable ownership preservation on update and on_behalf_of stripping on pull.`));
67114
67532
  }
@@ -67209,10 +67627,14 @@ Run 'wmill folder add-missing' to create them locally, then push again.`;
67209
67627
  const newObj2 = parseFromPath(resourceFilePath, await readTextFile(resourceFilePath));
67210
67628
  let serverPath = resourceFilePath;
67211
67629
  const currentBranch = cachedWsNameForPush;
67630
+ let isFileResWsSpecific = false;
67212
67631
  if (currentBranch && isWorkspaceSpecificFile(resourceFilePath)) {
67213
67632
  serverPath = fromWorkspaceSpecificPath(resourceFilePath, currentBranch);
67633
+ isFileResWsSpecific = true;
67634
+ } else if (specificItems && isSpecificItem(change.path, specificItems)) {
67635
+ isFileResWsSpecific = true;
67214
67636
  }
67215
- await pushResource(workspace.workspaceId, serverPath, undefined, newObj2, resourceFilePath);
67637
+ await pushResource(workspace.workspaceId, serverPath, undefined, newObj2, resourceFilePath, isFileResWsSpecific ? true : undefined);
67216
67638
  if (stateTarget) {
67217
67639
  await writeFile7(stateTarget, change.after, "utf-8");
67218
67640
  }
@@ -67220,7 +67642,7 @@ Run 'wmill folder add-missing' to create them locally, then push again.`;
67220
67642
  }
67221
67643
  }
67222
67644
  if (isFilesetResource(change.path)) {
67223
- const result = await pushFilesetParentResource(change.path, workspace.workspaceId, alreadySynced, cachedWsNameForPush);
67645
+ const result = await pushFilesetParentResource(change.path, workspace.workspaceId, alreadySynced, cachedWsNameForPush, specificItems);
67224
67646
  if (result.status === "parent-missing") {
67225
67647
  throw new Error(`No resource metadata file found for fileset resource: ${change.path}`);
67226
67648
  }
@@ -67234,16 +67656,17 @@ Run 'wmill folder add-missing' to create them locally, then push again.`;
67234
67656
  const oldObj = parseFromPath(change.path, change.before);
67235
67657
  const newObj = parseFromPath(change.path, change.after);
67236
67658
  let originalWorkspaceSpecificPath;
67237
- if (specificItems && isSpecificItem(change.path, specificItems)) {
67659
+ const isWsSpecific = specificItems && isSpecificItem(change.path, specificItems);
67660
+ if (isWsSpecific) {
67238
67661
  originalWorkspaceSpecificPath = getWorkspaceSpecificPath(change.path, specificItems, wsNameForFiles);
67239
67662
  }
67240
- await pushObj(workspace.workspaceId, change.path, oldObj, newObj, opts.plainSecrets ?? false, alreadySynced, opts.message, originalWorkspaceSpecificPath, permissionedAsContext);
67663
+ await pushObj(workspace.workspaceId, change.path, oldObj, newObj, opts.plainSecrets ?? false, alreadySynced, opts.message, originalWorkspaceSpecificPath, permissionedAsContext, isWsSpecific ? true : undefined);
67241
67664
  if (stateTarget) {
67242
67665
  await writeFile7(stateTarget, change.after, "utf-8");
67243
67666
  }
67244
67667
  } else if (change.name === "added") {
67245
67668
  if (isFilesetResource(change.path)) {
67246
- await pushFilesetParentResource(change.path, workspace.workspaceId, alreadySynced, cachedWsNameForPush);
67669
+ await pushFilesetParentResource(change.path, workspace.workspaceId, alreadySynced, cachedWsNameForPush, specificItems);
67247
67670
  continue;
67248
67671
  }
67249
67672
  if (change.path.endsWith(".script.json") || change.path.endsWith(".script.yaml") || change.path.endsWith(".lock") || isFileResource(change.path)) {
@@ -67260,13 +67683,14 @@ Run 'wmill folder add-missing' to create them locally, then push again.`;
67260
67683
  }
67261
67684
  const obj = parseFromPath(change.path, change.content);
67262
67685
  let localFilePath = change.path;
67263
- if (specificItems && isSpecificItem(change.path, specificItems)) {
67686
+ const isAddedWsSpecific = specificItems && isSpecificItem(change.path, specificItems);
67687
+ if (isAddedWsSpecific) {
67264
67688
  const workspaceSpecificPath = getWorkspaceSpecificPath(change.path, specificItems, wsNameForFiles);
67265
67689
  if (workspaceSpecificPath) {
67266
67690
  localFilePath = workspaceSpecificPath;
67267
67691
  }
67268
67692
  }
67269
- await pushObj(workspace.workspaceId, change.path, undefined, obj, opts.plainSecrets ?? false, [], opts.message, localFilePath, permissionedAsContext);
67693
+ await pushObj(workspace.workspaceId, change.path, undefined, obj, opts.plainSecrets ?? false, [], opts.message, localFilePath, permissionedAsContext, isAddedWsSpecific ? true : undefined);
67270
67694
  if (stateTarget) {
67271
67695
  await writeFile7(stateTarget, change.content, "utf-8");
67272
67696
  }
@@ -67279,7 +67703,7 @@ Run 'wmill folder add-missing' to create them locally, then push again.`;
67279
67703
  continue;
67280
67704
  }
67281
67705
  if (isFilesetResource(change.path)) {
67282
- await pushFilesetParentResource(change.path, workspace.workspaceId, alreadySynced, cachedWsNameForPush);
67706
+ await pushFilesetParentResource(change.path, workspace.workspaceId, alreadySynced, cachedWsNameForPush, specificItems);
67283
67707
  continue;
67284
67708
  }
67285
67709
  const typ = getTypeStrFromPath(change.path);
@@ -67548,6 +67972,23 @@ Run 'wmill folder add-missing' to create them locally, then push again.`;
67548
67972
  await rm(stateTarget);
67549
67973
  } catch {}
67550
67974
  }
67975
+ } else if (change.name === "ws_specific_flag") {
67976
+ const target = change.path.replaceAll(SEP9, "/");
67977
+ if (change.kind === "resource") {
67978
+ await updateResource({
67979
+ workspace: workspace.workspaceId,
67980
+ path: removeType(target, "resource"),
67981
+ requestBody: { ws_specific: change.wsSpecific }
67982
+ });
67983
+ } else if (change.kind === "variable") {
67984
+ await updateVariable({
67985
+ workspace: workspace.workspaceId,
67986
+ path: removeType(target, "variable"),
67987
+ requestBody: { ws_specific: change.wsSpecific }
67988
+ });
67989
+ } else {
67990
+ warn(`ws_specific_flag change for unsupported kind '${change.kind}' at ${change.path} — skipping`);
67991
+ }
67551
67992
  }
67552
67993
  }
67553
67994
  })();
@@ -68576,7 +69017,20 @@ function normalizeLockPath(p) {
68576
69017
  n = n.slice(2);
68577
69018
  return n;
68578
69019
  }
69020
+ async function beginLockfileBatch() {
69021
+ if (inMemoryLock)
69022
+ return;
69023
+ inMemoryLock = await readLockfile();
69024
+ }
69025
+ async function flushLockfileBatch() {
69026
+ if (!inMemoryLock)
69027
+ return;
69028
+ await writeFile8(WMILL_LOCKFILE, import_yaml13.stringify(inMemoryLock, yamlOptions), "utf-8");
69029
+ inMemoryLock = null;
69030
+ }
68579
69031
  async function readLockfile() {
69032
+ if (inMemoryLock)
69033
+ return inMemoryLock;
68580
69034
  let parsed;
68581
69035
  try {
68582
69036
  parsed = await yamlParseFile(WMILL_LOCKFILE);
@@ -68669,7 +69123,9 @@ async function clearGlobalLock(path13) {
68669
69123
  }
68670
69124
  });
68671
69125
  }
68672
- await writeFile8(WMILL_LOCKFILE, import_yaml13.stringify(conf, yamlOptions), "utf-8");
69126
+ if (!inMemoryLock) {
69127
+ await writeFile8(WMILL_LOCKFILE, import_yaml13.stringify(conf, yamlOptions), "utf-8");
69128
+ }
68673
69129
  }
68674
69130
  }
68675
69131
  async function updateMetadataGlobalLock(path13, hash2, subpath) {
@@ -68692,9 +69148,11 @@ async function updateMetadataGlobalLock(path13, hash2, subpath) {
68692
69148
  conf.locks[path13] = hash2;
68693
69149
  }
68694
69150
  }
68695
- await writeFile8(WMILL_LOCKFILE, import_yaml13.stringify(conf, yamlOptions), "utf-8");
69151
+ if (!inMemoryLock) {
69152
+ await writeFile8(WMILL_LOCKFILE, import_yaml13.stringify(conf, yamlOptions), "utf-8");
69153
+ }
68696
69154
  }
68697
- var import_yaml13, _require, _parserCache, LockfileGenerationError, UnknownLockVersionError, MalformedLockfileError, LANG_ANNOTATION_CONFIG, lockCache, WMILL_LOCKFILE = "wmill-lock.yaml", CURRENT_LOCK_VERSION = "v2", KNOWN_LOCK_VERSIONS, SCRIPT_TOP_HASH = "__script_hash";
69155
+ var import_yaml13, _require, _parserCache, LockfileGenerationError, UnknownLockVersionError, MalformedLockfileError, LANG_ANNOTATION_CONFIG, lockCache, WMILL_LOCKFILE = "wmill-lock.yaml", CURRENT_LOCK_VERSION = "v2", KNOWN_LOCK_VERSIONS, SCRIPT_TOP_HASH = "__script_hash", inMemoryLock = null;
68698
69156
  var init_metadata = __esm(async () => {
68699
69157
  init_colors2();
68700
69158
  init_log();
@@ -69243,7 +69701,7 @@ async function traverseAndProcessInlineScripts(obj, processor, currentPath = [])
69243
69701
  ])));
69244
69702
  }
69245
69703
  const result = {};
69246
- for (const [key, value] of Object.entries(obj)) {
69704
+ for (const [key, value] of yamlSortedEntries(obj)) {
69247
69705
  if (key === "inlineScript" && typeof value === "object") {
69248
69706
  result[key] = await processor(value, {
69249
69707
  path: currentPath,
@@ -70592,12 +71050,15 @@ async function getJobStatus(workspace, jobId) {
70592
71050
  }
70593
71051
  async function streamJobWithSSE(workspace, jobId, reqId, ws, baseUrl2, token) {
70594
71052
  const sseUrl = `${baseUrl2}api/w/${workspace}/jobs_u/getupdate_sse/${jobId}?fast=true`;
71053
+ const extraHeaders = getHeaders2();
70595
71054
  const response = await fetch(sseUrl, {
70596
71055
  headers: {
70597
71056
  Accept: "text/event-stream",
70598
- Authorization: `Bearer ${token}`
71057
+ Authorization: `Bearer ${token}`,
71058
+ ...extraHeaders
70599
71059
  }
70600
71060
  });
71061
+ await detectAuthGatewayChallenge(response, sseUrl);
70601
71062
  if (!response.ok) {
70602
71063
  throw new Error(`SSE request failed: ${response.status} ${response.statusText}`);
70603
71064
  }
@@ -70684,13 +71145,20 @@ var DEFAULT_PORT = 4000, DEFAULT_HOST = "localhost", createHTML = (jsPath, cssPa
70684
71145
  <meta charset="UTF-8">
70685
71146
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
70686
71147
  <title>Windmill App Dev Preview</title>
70687
- <link rel="stylesheet" href="${cssPath}">
70688
71148
  <style>
70689
- * {
70690
- margin: 0;
70691
- padding: 0;
70692
- box-sizing: border-box;
71149
+ /* Declared before the user stylesheet so Tailwind's layers (theme, base,
71150
+ components, utilities) are appended after wmill-shell and win the
71151
+ cascade. Unlayered styles would override Tailwind utilities. */
71152
+ @layer wmill-shell {
71153
+ * {
71154
+ margin: 0;
71155
+ padding: 0;
71156
+ box-sizing: border-box;
71157
+ }
70693
71158
  }
71159
+ </style>
71160
+ <link rel="stylesheet" href="${cssPath}">
71161
+ <style>
70694
71162
  body {
70695
71163
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
70696
71164
  'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
@@ -70949,6 +71417,7 @@ var init_dev = __esm(async () => {
70949
71417
  init_get_port();
70950
71418
  init_port_probe();
70951
71419
  init_open();
71420
+ init_http_guards();
70952
71421
  init_wrapper();
70953
71422
  init_services_gen();
70954
71423
  init_job_polling();
@@ -72297,7 +72766,7 @@ async function get6(opts, path19) {
72297
72766
  console.log(colors.bold("Account:") + " " + (v.account ?? "-"));
72298
72767
  }
72299
72768
  }
72300
- async function pushVariable(workspace, remotePath, variable, localVariable, plainSecrets) {
72769
+ async function pushVariable(workspace, remotePath, variable, localVariable, plainSecrets, wsSpecific) {
72301
72770
  remotePath = removeType(remotePath, "variable");
72302
72771
  debug(`Processing local variable ${remotePath}`);
72303
72772
  try {
@@ -72323,7 +72792,8 @@ async function pushVariable(workspace, remotePath, variable, localVariable, plai
72323
72792
  alreadyEncrypted: !plainSecrets,
72324
72793
  requestBody: {
72325
72794
  ...localVariable,
72326
- is_secret: localVariable.is_secret && !variable.is_secret ? true : undefined
72795
+ is_secret: localVariable.is_secret && !variable.is_secret ? true : undefined,
72796
+ ...wsSpecific !== undefined ? { ws_specific: wsSpecific } : {}
72327
72797
  }
72328
72798
  });
72329
72799
  } else {
@@ -72333,7 +72803,8 @@ async function pushVariable(workspace, remotePath, variable, localVariable, plai
72333
72803
  alreadyEncrypted: !plainSecrets,
72334
72804
  requestBody: {
72335
72805
  path: remotePath.replaceAll(SEP16, "/"),
72336
- ...localVariable
72806
+ ...localVariable,
72807
+ ...wsSpecific !== undefined ? { ws_specific: wsSpecific } : {}
72337
72808
  }
72338
72809
  });
72339
72810
  }
@@ -74750,7 +75221,7 @@ function showConflict(path21, local, remote) {
74750
75221
  info(`
74751
75222
  `);
74752
75223
  }
74753
- async function pushObj(workspace, p, befObj, newObj, plainSecrets, alreadySynced3, message, originalLocalPath, permissionedAsContext) {
75224
+ async function pushObj(workspace, p, befObj, newObj, plainSecrets, alreadySynced3, message, originalLocalPath, permissionedAsContext, wsSpecific) {
74754
75225
  const typeEnding = getTypeStrFromPath(p);
74755
75226
  if (typeEnding === "app") {
74756
75227
  const appName = extractResourceName(p, "app");
@@ -74767,7 +75238,7 @@ async function pushObj(workspace, p, befObj, newObj, plainSecrets, alreadySynced
74767
75238
  } else if (typeEnding === "folder") {
74768
75239
  await pushFolder(workspace, p, befObj, newObj);
74769
75240
  } else if (typeEnding === "variable") {
74770
- await pushVariable(workspace, p, befObj, newObj, plainSecrets);
75241
+ await pushVariable(workspace, p, befObj, newObj, plainSecrets, wsSpecific);
74771
75242
  } else if (typeEnding === "flow") {
74772
75243
  const flowName = extractResourceName(p, "flow");
74773
75244
  if (!flowName) {
@@ -74777,7 +75248,7 @@ async function pushObj(workspace, p, befObj, newObj, plainSecrets, alreadySynced
74777
75248
  } else if (typeEnding === "resource") {
74778
75249
  if (!alreadySynced3.includes(p)) {
74779
75250
  alreadySynced3.push(p);
74780
- await pushResource(workspace, p, befObj, newObj, originalLocalPath || p);
75251
+ await pushResource(workspace, p, befObj, newObj, originalLocalPath || p, wsSpecific);
74781
75252
  }
74782
75253
  } else if (typeEnding === "resource-type") {
74783
75254
  await pushResourceType(workspace, p, befObj, newObj);
@@ -85719,6 +86190,7 @@ Generate metadata (locks, schemas) for all scripts, flows, and apps
85719
86190
  - \`--skip-flows\` - Skip processing flows
85720
86191
  - \`--skip-apps\` - Skip processing apps
85721
86192
  - \`--strict-folder-boundaries\` - Only update items inside the specified folder (requires folder argument)
86193
+ - \`--parallel <n:number>\` - Number of items to process in parallel
85722
86194
  - \`-i --includes <patterns:file[]>\` - Comma separated patterns to specify which files to include
85723
86195
  - \`-e --excludes <patterns:file[]>\` - Comma separated patterns to specify which files to exclude
85724
86196
 
@@ -85728,6 +86200,7 @@ Generate metadata (locks, schemas) for all scripts, flows, and apps
85728
86200
  - \`--skip-scripts\` - Skip processing scripts
85729
86201
  - \`--skip-flows\` - Skip processing flows
85730
86202
  - \`--skip-apps\` - Skip processing apps
86203
+ - \`--parallel <n:number>\` - Number of items to process in parallel
85731
86204
  - \`-i --includes <patterns:file[]>\` - Comma separated patterns to specify which files to include
85732
86205
  - \`-e --excludes <patterns:file[]>\` - Comma separated patterns to specify which files to exclude
85733
86206
 
@@ -88945,9 +89418,11 @@ await init_generate_metadata();
88945
89418
  init_mod3();
88946
89419
  init_colors2();
88947
89420
  init_log();
89421
+ init_http_guards();
88948
89422
  await __promiseAll([
88949
89423
  init_auth(),
88950
- init_context()
89424
+ init_context(),
89425
+ init_utils()
88951
89426
  ]);
88952
89427
  async function docs(opts, query) {
88953
89428
  await requireLogin(opts);
@@ -88956,19 +89431,22 @@ async function docs(opts, query) {
88956
89431
  console.log(colors.bold(`
88957
89432
  Searching Windmill docs...
88958
89433
  `));
89434
+ const extraHeaders = getHeaders2();
88959
89435
  let res;
88960
89436
  try {
88961
89437
  res = await fetch(url, {
88962
89438
  method: "POST",
88963
89439
  headers: {
88964
89440
  "Content-Type": "application/json",
88965
- Authorization: `Bearer ${workspace.token}`
89441
+ Authorization: `Bearer ${workspace.token}`,
89442
+ ...extraHeaders
88966
89443
  },
88967
89444
  body: JSON.stringify({ query })
88968
89445
  });
88969
89446
  } catch (e) {
88970
89447
  throw new Error(`Network error connecting to ${workspace.remote}: ${e}`);
88971
89448
  }
89449
+ await detectAuthGatewayChallenge(res, url);
88972
89450
  if (res.status === 403) {
88973
89451
  info("Windmill documentation search is an Enterprise Edition feature. Please upgrade to use this command.");
88974
89452
  return;
@@ -89087,7 +89565,7 @@ var config_default = command35;
89087
89565
 
89088
89566
  // src/main.ts
89089
89567
  await init_context();
89090
- var VERSION = "1.696.2";
89568
+ var VERSION = "1.698.0";
89091
89569
  async function checkVersionSafe(cmd) {
89092
89570
  const mainCommand = cmd.getMainCommand();
89093
89571
  const upgradeCommand = mainCommand.getCommand("upgrade");