windmill-cli 1.623.0 → 1.624.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.
@@ -32,7 +32,7 @@ export const OpenAPI = {
32
32
  PASSWORD: undefined,
33
33
  TOKEN: getEnv("WM_TOKEN"),
34
34
  USERNAME: undefined,
35
- VERSION: '1.623.0',
35
+ VERSION: '1.624.0',
36
36
  WITH_CREDENTIALS: true,
37
37
  interceptors: {
38
38
  request: new Interceptors(),
@@ -12395,10 +12395,16 @@ export const clearIndex = (data) => {
12395
12395
  });
12396
12396
  };
12397
12397
  /**
12398
- * List all assets in the workspace
12398
+ * List all assets in the workspace with cursor pagination
12399
12399
  * @param data The data for the request.
12400
12400
  * @param data.workspace
12401
- * @returns unknown all assets in the workspace
12401
+ * @param data.perPage Number of items per page (max 1000, default 50)
12402
+ * @param data.cursorCreatedAt Cursor timestamp for pagination (created_at of last item from previous page)
12403
+ * @param data.cursorId Cursor ID for pagination (id of last item from previous page)
12404
+ * @param data.assetPath Filter by asset path (case-insensitive partial match)
12405
+ * @param data.usagePath Filter by usage path (case-insensitive partial match)
12406
+ * @param data.assetKinds Filter by asset kinds (multiple values allowed)
12407
+ * @returns unknown paginated assets in the workspace
12402
12408
  * @throws ApiError
12403
12409
  */
12404
12410
  export const listAssets = (data) => {
@@ -12407,6 +12413,14 @@ export const listAssets = (data) => {
12407
12413
  url: '/w/{workspace}/assets/list',
12408
12414
  path: {
12409
12415
  workspace: data.workspace
12416
+ },
12417
+ query: {
12418
+ per_page: data.perPage,
12419
+ cursor_created_at: data.cursorCreatedAt,
12420
+ cursor_id: data.cursorId,
12421
+ asset_path: data.assetPath,
12422
+ usage_path: data.usagePath,
12423
+ asset_kinds: data.assetKinds
12410
12424
  }
12411
12425
  });
12412
12426
  };
@@ -190,6 +190,7 @@ const createHTML = (jsPath, cssPath) => `
190
190
  // SQL Migration Modal handling
191
191
  let pendingSqlMigration = null;
192
192
  let sqlWebSocket = null;
193
+ let closeModalTimeout = null;
193
194
 
194
195
  function initSqlWebSocket() {
195
196
  const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
@@ -211,12 +212,19 @@ const createHTML = (jsPath, cssPath) => `
211
212
  }
212
213
 
213
214
  function showSqlModal(data) {
215
+ // Cancel any pending close from a previous migration's success
216
+ if (closeModalTimeout) {
217
+ clearTimeout(closeModalTimeout);
218
+ closeModalTimeout = null;
219
+ }
214
220
  pendingSqlMigration = data;
215
221
  document.getElementById('sql-file-name').textContent = data.fileName;
216
222
  document.getElementById('sql-datatable').textContent = data.datatable || 'Not configured';
217
223
  document.getElementById('sql-content').textContent = data.sql;
218
224
  document.getElementById('sql-result').innerHTML = '';
225
+ document.getElementById('sql-result').className = 'sql-result';
219
226
  document.getElementById('apply-sql-btn').disabled = !data.datatable;
227
+ document.getElementById('apply-sql-btn').textContent = 'Apply SQL';
220
228
  document.getElementById('sql-modal-overlay').classList.add('visible');
221
229
  }
222
230
 
@@ -257,7 +265,11 @@ const createHTML = (jsPath, cssPath) => `
257
265
  resultDiv.className = 'sql-result success';
258
266
  resultDiv.innerHTML = '<strong>Success!</strong> SQL applied and file deleted.';
259
267
  // Auto-close after success (don't send skip since server already handled it)
260
- setTimeout(() => closeSqlModal(false), 1500);
268
+ // Save timeout ID so it can be cancelled if a new migration arrives
269
+ closeModalTimeout = setTimeout(() => {
270
+ closeModalTimeout = null;
271
+ closeSqlModal(false);
272
+ }, 1500);
261
273
  }
262
274
  }
263
275
 
@@ -1044,7 +1044,7 @@ export async function* readDirRecursiveWithIgnore(ignore, root) {
1044
1044
  }
1045
1045
  }
1046
1046
  }
1047
- export async function elementsToMap(els, ignore, json, skips, specificItems, branchOverride) {
1047
+ export async function elementsToMap(els, ignore, json, skips, specificItems, branchOverride, isRemote) {
1048
1048
  const map = {};
1049
1049
  const processedBasePaths = new Set();
1050
1050
  // Cache git branch at the start to avoid repeated execSync calls per file
@@ -1209,7 +1209,8 @@ export async function elementsToMap(els, ignore, json, skips, specificItems, bra
1209
1209
  continue;
1210
1210
  }
1211
1211
  // Skip base file if it's configured as branch-specific (expect branch version)
1212
- if (isSpecificItem(path, specificItems)) {
1212
+ // Only for LOCAL files - remote workspace only has base paths
1213
+ if (!isRemote && isSpecificItem(path, specificItems)) {
1213
1214
  continue;
1214
1215
  }
1215
1216
  map[path] = content;
@@ -1218,13 +1219,13 @@ export async function elementsToMap(els, ignore, json, skips, specificItems, bra
1218
1219
  }
1219
1220
  return map;
1220
1221
  }
1221
- async function compareDynFSElement(els1, els2, ignore, json, skips, ignoreMetadataDeletion, codebases, ignoreCodebaseChanges, specificItems, branchOverride) {
1222
+ async function compareDynFSElement(els1, els2, ignore, json, skips, ignoreMetadataDeletion, codebases, ignoreCodebaseChanges, specificItems, branchOverride, isEls1Remote) {
1222
1223
  const [m1, m2] = els2
1223
1224
  ? await Promise.all([
1224
- elementsToMap(els1, ignore, json, skips, specificItems, branchOverride),
1225
- elementsToMap(els2, ignore, json, skips, specificItems, branchOverride),
1225
+ elementsToMap(els1, ignore, json, skips, specificItems, branchOverride, isEls1Remote),
1226
+ elementsToMap(els2, ignore, json, skips, specificItems, branchOverride, !isEls1Remote),
1226
1227
  ])
1227
- : [await elementsToMap(els1, ignore, json, skips, specificItems, branchOverride), {}];
1228
+ : [await elementsToMap(els1, ignore, json, skips, specificItems, branchOverride, isEls1Remote), {}];
1228
1229
  const changes = [];
1229
1230
  function parseYaml(k, v) {
1230
1231
  if (k.endsWith(".script.yaml")) {
@@ -1633,7 +1634,7 @@ export async function pull(opts) {
1633
1634
  const local = !opts.stateful
1634
1635
  ? await FSFSElement(dntShim.Deno.cwd(), codebases, true)
1635
1636
  : await FSFSElement(path.join(dntShim.Deno.cwd(), ".wmill"), [], true);
1636
- const changes = await compareDynFSElement(remote, local, await ignoreF(opts), opts.json ?? false, opts, false, codebases, true, specificItems, opts.branch);
1637
+ const changes = await compareDynFSElement(remote, local, await ignoreF(opts), opts.json ?? false, opts, false, codebases, true, specificItems, opts.branch, true);
1637
1638
  log.info(`remote (${workspace.name}) -> local: ${changes.length} changes to apply`);
1638
1639
  // Handle JSON output for dry-run
1639
1640
  if (opts.dryRun && opts.jsonOutput) {
@@ -1943,7 +1944,7 @@ export async function push(opts) {
1943
1944
  }
1944
1945
  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, false);
1945
1946
  const local = await FSFSElement(path.join(dntShim.Deno.cwd(), ""), codebases, false);
1946
- const changes = await compareDynFSElement(local, remote, await ignoreF(opts), opts.json ?? false, opts, true, codebases, false, specificItems, opts.branch);
1947
+ const changes = await compareDynFSElement(local, remote, await ignoreF(opts), opts.json ?? false, opts, true, codebases, false, specificItems, opts.branch, false);
1947
1948
  const rawWorkspaceDependencies = await getRawWorkspaceDependencies();
1948
1949
  const tracker = await buildTracker(changes);
1949
1950
  const staleScripts = [];
package/esm/src/main.js CHANGED
@@ -46,7 +46,7 @@ export { flow, app, script, workspace, resource, resourceType, user, variable, h
46
46
  // console.error(JSON.stringify(event.error, null, 4));
47
47
  // }
48
48
  // });
49
- export const VERSION = "1.623.0";
49
+ export const VERSION = "1.624.0";
50
50
  // Re-exported from constants.ts to maintain backwards compatibility
51
51
  export { WM_FORK_PREFIX } from "./core/constants.js";
52
52
  const command = new Command()
@@ -1,4 +1,18 @@
1
1
  import { newPathAssigner } from "../path-utils/path-assigner.js";
2
+ function extractRawscriptInline(id, summary, rawscript, mapping, separator, assigner) {
3
+ const [basePath, ext] = assigner.assignPath(summary ?? id, rawscript.language);
4
+ const path = mapping[id] ?? basePath + ext;
5
+ const content = rawscript.content;
6
+ const r = [{ path: path, content: content }];
7
+ rawscript.content = "!inline " + path.replaceAll(separator, "/");
8
+ const lock = rawscript.lock;
9
+ if (lock && lock != "") {
10
+ const lockPath = basePath + "lock";
11
+ rawscript.lock = "!inline " + lockPath.replaceAll(separator, "/");
12
+ r.push({ path: lockPath, content: lock });
13
+ }
14
+ return r;
15
+ }
2
16
  /**
3
17
  * Extracts inline scripts from flow modules, converting them to separate files
4
18
  * and replacing the original content with file references.
@@ -16,18 +30,7 @@ export function extractInlineScripts(modules, mapping = {}, separator = "/", def
16
30
  const assigner = pathAssigner ?? newPathAssigner(defaultTs ?? "bun", { skipInlineScriptSuffix: options?.skipInlineScriptSuffix });
17
31
  return modules.flatMap((m) => {
18
32
  if (m.value.type == "rawscript") {
19
- const [basePath, ext] = assigner.assignPath(m.summary, m.value.language);
20
- const path = mapping[m.id] ?? basePath + ext;
21
- const content = m.value.content;
22
- const r = [{ path: path, content: content }];
23
- m.value.content = "!inline " + path.replaceAll(separator, "/");
24
- const lock = m.value.lock;
25
- if (lock && lock != "") {
26
- const lockPath = basePath + "lock";
27
- m.value.lock = "!inline " + lockPath.replaceAll(separator, "/");
28
- r.push({ path: lockPath, content: lock });
29
- }
30
- return r;
33
+ return extractRawscriptInline(m.id, m.summary, m.value, mapping, separator, assigner);
31
34
  }
32
35
  else if (m.value.type == "forloopflow") {
33
36
  return extractInlineScripts(m.value.modules, mapping, separator, defaultTs, assigner);
@@ -44,6 +47,16 @@ export function extractInlineScripts(modules, mapping = {}, separator = "/", def
44
47
  ...extractInlineScripts(m.value.default, mapping, separator, defaultTs, assigner),
45
48
  ];
46
49
  }
50
+ else if (m.value.type == "aiagent") {
51
+ return (m.value.tools ?? []).flatMap((tool) => {
52
+ const toolValue = tool.value;
53
+ // Only process flowmodule tools with rawscript type
54
+ if (!toolValue || toolValue.tool_type !== 'flowmodule' || toolValue.type !== 'rawscript') {
55
+ return [];
56
+ }
57
+ return extractRawscriptInline(tool.id, tool.summary, toolValue, mapping, separator, assigner);
58
+ });
59
+ }
47
60
  else {
48
61
  return [];
49
62
  }
@@ -81,6 +94,15 @@ export function extractCurrentMapping(modules, mapping = {}) {
81
94
  m.value.branches.forEach((b) => extractCurrentMapping(b.modules, mapping));
82
95
  extractCurrentMapping(m.value.default, mapping);
83
96
  }
97
+ else if (m.value.type === "aiagent") {
98
+ (m.value.tools ?? []).forEach((tool) => {
99
+ const toolValue = tool.value;
100
+ if (!toolValue || toolValue.tool_type !== 'flowmodule' || toolValue.type !== 'rawscript' || !toolValue.content || !toolValue.content.startsWith("!inline")) {
101
+ return;
102
+ }
103
+ mapping[tool.id] = toolValue.content.trim().split(" ")[1];
104
+ });
105
+ }
84
106
  });
85
107
  return mapping;
86
108
  }
@@ -1,3 +1,39 @@
1
+ async function replaceRawscriptInline(id, rawscript, fileReader, logger, separator, removeLocks) {
2
+ if (!rawscript.content || !rawscript.content.startsWith("!inline")) {
3
+ return;
4
+ }
5
+ const path = rawscript.content.split(" ")[1];
6
+ const pathSuffix = path.split(".").slice(1).join(".");
7
+ const newPath = id + "." + pathSuffix;
8
+ try {
9
+ rawscript.content = await fileReader(path);
10
+ }
11
+ catch {
12
+ logger.error(`Script file ${path} not found`);
13
+ try {
14
+ rawscript.content = await fileReader(newPath);
15
+ }
16
+ catch {
17
+ logger.error(`Script file ${newPath} not found`);
18
+ }
19
+ }
20
+ const lock = rawscript.lock;
21
+ if (removeLocks && removeLocks.includes(path)) {
22
+ rawscript.lock = undefined;
23
+ }
24
+ else if (lock &&
25
+ typeof lock === "string" &&
26
+ lock.trimStart().startsWith("!inline ")) {
27
+ const lockPath = lock.split(" ")[1];
28
+ try {
29
+ rawscript.lock = await fileReader(lockPath.replaceAll("/", separator));
30
+ }
31
+ catch {
32
+ logger.error(`Lock file ${lockPath} not found, treating as empty`);
33
+ rawscript.lock = "";
34
+ }
35
+ }
36
+ }
1
37
  /**
2
38
  * Replaces inline script references with actual file content from the filesystem.
3
39
  * This function recursively processes all flow modules and their nested structures.
@@ -17,63 +53,8 @@ export async function replaceInlineScripts(modules, fileReader, logger = {
17
53
  if (!module.value) {
18
54
  throw new Error(`Module value is undefined for module ${module.id}`);
19
55
  }
20
- if (module.value.type === "rawscript" && module.value.content && module.value.content.startsWith("!inline")) {
21
- const path = module.value.content.split(" ")[1];
22
- // const pathPrefix = path.split(".")[0];
23
- const pathSuffix = path.split(".").slice(1).join(".");
24
- // new path is the module id with the same suffix
25
- const newPath = module.id + "." + pathSuffix;
26
- try {
27
- module.value.content = await fileReader(path);
28
- }
29
- catch {
30
- logger.error(`Script file ${path} not found`);
31
- // try new path
32
- try {
33
- module.value.content = await fileReader(newPath);
34
- }
35
- catch {
36
- logger.error(`Script file ${newPath} not found`);
37
- }
38
- }
39
- // rename the file if the prefix is different from the module id (fix old naming)
40
- // if (pathPrefix != module.id && renamer) {
41
- // logger.info(`Renaming ${path} to ${module.id}.${pathSuffix}`);
42
- // try {
43
- // renamer(localPath + path, localPath + module.id + "." + pathSuffix);
44
- // } catch {
45
- // logger.info(`Failed to rename ${path} to ${module.id}.${pathSuffix}`);
46
- // }
47
- // }
48
- const lock = module.value.lock;
49
- if (removeLocks && removeLocks.includes(path)) {
50
- module.value.lock = undefined;
51
- // delete the file if the prefix is different from the module id (fix old naming)
52
- // if (lock && lock != "") {
53
- // const path = lock.split(" ")[1];
54
- // const pathPrefix = path.split(".")[0];
55
- // if (pathPrefix != module.id && deleter) {
56
- // logger.info(`Deleting ${path}`);
57
- // try {
58
- // deleter(localPath + path);
59
- // } catch {
60
- // logger.error(`Failed to delete ${path}`);
61
- // }
62
- // }
63
- // }
64
- }
65
- else if (lock &&
66
- typeof lock == "string" &&
67
- lock.trimStart().startsWith("!inline ")) {
68
- const path = lock.split(" ")[1];
69
- try {
70
- module.value.lock = await fileReader(path.replaceAll("/", separator));
71
- }
72
- catch {
73
- logger.error(`Lock file ${path} not found, treating as empty`);
74
- module.value.lock = "";
75
- }
76
- }
56
+ if (module.value.type === "rawscript") {
57
+ await replaceRawscriptInline(module.id, module.value, fileReader, logger, separator, removeLocks);
77
58
  }
78
59
  else if (module.value.type === "forloopflow" || module.value.type === "whileloopflow") {
79
60
  await replaceInlineScripts(module.value.modules, fileReader, logger, localPath, separator, removeLocks);
@@ -89,5 +70,16 @@ export async function replaceInlineScripts(modules, fileReader, logger = {
89
70
  }));
90
71
  await replaceInlineScripts(module.value.default, fileReader, logger, localPath, separator, removeLocks);
91
72
  }
73
+ else if (module.value.type === "aiagent") {
74
+ await Promise.all((module.value.tools ?? []).map(async (tool) => {
75
+ const toolValue = tool.value;
76
+ if (!toolValue ||
77
+ toolValue.tool_type !== "flowmodule" ||
78
+ toolValue.type !== "rawscript") {
79
+ return;
80
+ }
81
+ await replaceRawscriptInline(tool.id, toolValue, fileReader, logger, separator, removeLocks);
82
+ }));
83
+ }
92
84
  }));
93
85
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "windmill-cli",
3
- "version": "1.623.0",
3
+ "version": "1.624.0",
4
4
  "description": "CLI for Windmill",
5
5
  "repository": {
6
6
  "type": "git",
@@ -6078,10 +6078,16 @@ export declare const countSearchLogsIndex: (data: CountSearchLogsIndexData) => C
6078
6078
  */
6079
6079
  export declare const clearIndex: (data: ClearIndexData) => CancelablePromise<ClearIndexResponse>;
6080
6080
  /**
6081
- * List all assets in the workspace
6081
+ * List all assets in the workspace with cursor pagination
6082
6082
  * @param data The data for the request.
6083
6083
  * @param data.workspace
6084
- * @returns unknown all assets in the workspace
6084
+ * @param data.perPage Number of items per page (max 1000, default 50)
6085
+ * @param data.cursorCreatedAt Cursor timestamp for pagination (created_at of last item from previous page)
6086
+ * @param data.cursorId Cursor ID for pagination (id of last item from previous page)
6087
+ * @param data.assetPath Filter by asset path (case-insensitive partial match)
6088
+ * @param data.usagePath Filter by usage path (case-insensitive partial match)
6089
+ * @param data.assetKinds Filter by asset kinds (multiple values allowed)
6090
+ * @returns unknown paginated assets in the workspace
6085
6091
  * @throws ApiError
6086
6092
  */
6087
6093
  export declare const listAssets: (data: ListAssetsData) => CancelablePromise<ListAssetsResponse>;