windmill-cli 1.728.1 → 1.730.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 +595 -71
  2. package/package.json +1 -1
package/esm/main.js CHANGED
@@ -16772,7 +16772,7 @@ var init_OpenAPI = __esm(() => {
16772
16772
  PASSWORD: undefined,
16773
16773
  TOKEN: getEnv3("WM_TOKEN"),
16774
16774
  USERNAME: undefined,
16775
- VERSION: "1.728.1",
16775
+ VERSION: "1.730.0",
16776
16776
  WITH_CREDENTIALS: true,
16777
16777
  interceptors: {
16778
16778
  request: new Interceptors,
@@ -17227,6 +17227,7 @@ __export(exports_services_gen, {
17227
17227
  migrateSecretsToAwsSm: () => migrateSecretsToAwsSm,
17228
17228
  migrateSecretsFromAzureKv: () => migrateSecretsFromAzureKv,
17229
17229
  migrateSecretsFromAwsSm: () => migrateSecretsFromAwsSm,
17230
+ migrateLegacyDraft: () => migrateLegacyDraft,
17230
17231
  mcpOauthCallback: () => mcpOauthCallback,
17231
17232
  logout: () => logout,
17232
17233
  loginWithOauth: () => loginWithOauth,
@@ -17281,6 +17282,7 @@ __export(exports_services_gen, {
17281
17282
  listPostgresTriggers: () => listPostgresTriggers,
17282
17283
  listPostgresReplicationSlot: () => listPostgresReplicationSlot,
17283
17284
  listPostgresPublication: () => listPostgresPublication,
17285
+ listPipelineFolders: () => listPipelineFolders,
17284
17286
  listPendingInvites: () => listPendingInvites,
17285
17287
  listPathAutocompletePaths: () => listPathAutocompletePaths,
17286
17288
  listOauthLogins: () => listOauthLogins,
@@ -17325,6 +17327,7 @@ __export(exports_services_gen, {
17325
17327
  listEmailTriggers: () => listEmailTriggers,
17326
17328
  listDucklakes: () => listDucklakes,
17327
17329
  listDrafts: () => listDrafts,
17330
+ listDispatchEvents: () => listDispatchEvents,
17328
17331
  listDeploymentRequestEligibleDeployers: () => listDeploymentRequestEligibleDeployers,
17329
17332
  listDedicatedWithDeps: () => listDedicatedWithDeps,
17330
17333
  listDataTables: () => listDataTables,
@@ -17351,6 +17354,7 @@ __export(exports_services_gen, {
17351
17354
  listAuditLogs: () => listAuditLogs,
17352
17355
  listAssetsByUsage: () => listAssetsByUsage,
17353
17356
  listAssets: () => listAssets,
17357
+ listAssetDispatchEdges: () => listAssetDispatchEdges,
17354
17358
  listApps: () => listApps,
17355
17359
  listAppPathsFromWorkspaceRunnable: () => listAppPathsFromWorkspaceRunnable,
17356
17360
  listAllWorkspaceDependencies: () => listAllWorkspaceDependencies,
@@ -17440,6 +17444,7 @@ __export(exports_services_gen, {
17440
17444
  getPostgresVersion: () => getPostgresVersion,
17441
17445
  getPostgresTrigger: () => getPostgresTrigger,
17442
17446
  getPostgresPublication: () => getPostgresPublication,
17447
+ getOwnDraft: () => getOwnDraft,
17443
17448
  getOpenDeploymentRequest: () => getOpenDeploymentRequest,
17444
17449
  getOpenApiYaml: () => getOpenApiYaml,
17445
17450
  getOidcToken: () => getOidcToken,
@@ -17545,6 +17550,7 @@ __export(exports_services_gen, {
17545
17550
  getAzureTrigger: () => getAzureTrigger,
17546
17551
  getAuditLogsS3Status: () => getAuditLogsS3Status,
17547
17552
  getAuditLog: () => getAuditLog,
17553
+ getAssetsGraph: () => getAssetsGraph,
17548
17554
  getArgsFromHistoryOrSavedInput: () => getArgsFromHistoryOrSavedInput,
17549
17555
  getApprovalInfo: () => getApprovalInfo,
17550
17556
  getAppLiteByPath: () => getAppLiteByPath,
@@ -19831,8 +19837,9 @@ var backendVersion = () => {
19831
19837
  }, connectClientCredentials = (data3) => {
19832
19838
  return request(OpenAPI, {
19833
19839
  method: "POST",
19834
- url: "/oauth/connect_client_credentials/{client}",
19840
+ url: "/w/{workspace}/oauth/connect_client_credentials/{client}",
19835
19841
  path: {
19842
+ workspace: data3.workspace,
19836
19843
  client: data3.client
19837
19844
  },
19838
19845
  body: data3.requestBody,
@@ -20328,6 +20335,9 @@ var backendVersion = () => {
20328
20335
  url: "/w/{workspace}/drafts/list",
20329
20336
  path: {
20330
20337
  workspace: data3.workspace
20338
+ },
20339
+ query: {
20340
+ all_users: data3.allUsers
20331
20341
  }
20332
20342
  });
20333
20343
  }, getDraftForUser = (data3) => {
@@ -20346,6 +20356,16 @@ var backendVersion = () => {
20346
20356
  404: "no draft for that owner at that path"
20347
20357
  }
20348
20358
  });
20359
+ }, getOwnDraft = (data3) => {
20360
+ return request(OpenAPI, {
20361
+ method: "GET",
20362
+ url: "/w/{workspace}/drafts/get_own/{kind}/{path}",
20363
+ path: {
20364
+ workspace: data3.workspace,
20365
+ kind: data3.kind,
20366
+ path: data3.path
20367
+ }
20368
+ });
20349
20369
  }, updateDraft = (data3) => {
20350
20370
  return request(OpenAPI, {
20351
20371
  method: "POST",
@@ -20358,6 +20378,18 @@ var backendVersion = () => {
20358
20378
  body: data3.requestBody,
20359
20379
  mediaType: "application/json"
20360
20380
  });
20381
+ }, migrateLegacyDraft = (data3) => {
20382
+ return request(OpenAPI, {
20383
+ method: "POST",
20384
+ url: "/w/{workspace}/drafts/migrate_legacy/{kind}/{path}",
20385
+ path: {
20386
+ workspace: data3.workspace,
20387
+ kind: data3.kind,
20388
+ path: data3.path
20389
+ },
20390
+ body: data3.requestBody,
20391
+ mediaType: "application/json"
20392
+ });
20361
20393
  }, createScript = (data3) => {
20362
20394
  return request(OpenAPI, {
20363
20395
  method: "POST",
@@ -22283,6 +22315,27 @@ var backendVersion = () => {
22283
22315
  id: data3.id
22284
22316
  }
22285
22317
  });
22318
+ }, listDispatchEvents = (data3) => {
22319
+ return request(OpenAPI, {
22320
+ method: "GET",
22321
+ url: "/w/{workspace}/jobs_u/dispatch_events/{id}",
22322
+ path: {
22323
+ workspace: data3.workspace,
22324
+ id: data3.id
22325
+ }
22326
+ });
22327
+ }, listAssetDispatchEdges = (data3) => {
22328
+ return request(OpenAPI, {
22329
+ method: "GET",
22330
+ url: "/w/{workspace}/jobs/asset_dispatch_edges",
22331
+ path: {
22332
+ workspace: data3.workspace
22333
+ },
22334
+ query: {
22335
+ path_start: data3.pathStart,
22336
+ created_after: data3.createdAfter
22337
+ }
22338
+ });
22286
22339
  }, deleteCompletedJob = (data3) => {
22287
22340
  return request(OpenAPI, {
22288
22341
  method: "POST",
@@ -25158,6 +25211,26 @@ var backendVersion = () => {
25158
25211
  workspace: data3.workspace
25159
25212
  }
25160
25213
  });
25214
+ }, getAssetsGraph = (data3) => {
25215
+ return request(OpenAPI, {
25216
+ method: "GET",
25217
+ url: "/w/{workspace}/assets/graph",
25218
+ path: {
25219
+ workspace: data3.workspace
25220
+ },
25221
+ query: {
25222
+ asset_kinds: data3.assetKinds,
25223
+ folder: data3.folder
25224
+ }
25225
+ });
25226
+ }, listPipelineFolders = (data3) => {
25227
+ return request(OpenAPI, {
25228
+ method: "GET",
25229
+ url: "/w/{workspace}/assets/pipelines",
25230
+ path: {
25231
+ workspace: data3.workspace
25232
+ }
25233
+ });
25161
25234
  }, listVolumes = (data3) => {
25162
25235
  return request(OpenAPI, {
25163
25236
  method: "GET",
@@ -25347,7 +25420,7 @@ var init_auth = __esm(async () => {
25347
25420
  });
25348
25421
 
25349
25422
  // src/core/constants.ts
25350
- var WM_FORK_PREFIX = "wm-fork", VERSION = "1.728.1";
25423
+ var WM_FORK_PREFIX = "wm-fork", VERSION = "1.730.0";
25351
25424
 
25352
25425
  // src/utils/git.ts
25353
25426
  var exports_git = {};
@@ -37271,7 +37344,14 @@ function inferContentTypeFromFilePath(contentPath, defaultTs) {
37271
37344
  } else if (contentPath.endsWith(".r")) {
37272
37345
  return "rlang";
37273
37346
  } else {
37274
- throw new Error("Invalid language: " + contentPath.substring(contentPath.lastIndexOf(".")));
37347
+ const ext = contentPath.substring(contentPath.lastIndexOf("."));
37348
+ let hint = "";
37349
+ if (ext === ".sql") {
37350
+ hint = `
37351
+ Bare .sql is ambiguous — use a dialect extension: .pg.sql (postgresql), .my.sql (mysql), .bq.sql (bigquery), .sf.sql (snowflake), .ms.sql (mssql), .odb.sql (oracledb), .duckdb.sql (duckdb)`;
37352
+ }
37353
+ throw new Error(`Cannot infer script language from extension '${ext}' (file ${contentPath}).` + hint + `
37354
+ Supported extensions: .ts (bun/deno), .py, .go, .sh, .ps1, .php, .rs, .cs, .nu, .java, .rb, .r, .gql, .playbook.yml, .pg.sql, .my.sql, .bq.sql, .sf.sql, .ms.sql, .odb.sql, .duckdb.sql`);
37275
37355
  }
37276
37356
  }
37277
37357
  var workspaceDependenciesLanguages;
@@ -64059,7 +64139,7 @@ var init_generate_metadata = __esm(async () => {
64059
64139
  init_codebase(),
64060
64140
  init_dependency_tree()
64061
64141
  ]);
64062
- command4 = 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(generateMetadata).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));
64142
+ command4 = new Command().description("Regenerate stale local locks and script schemas and refresh wmill-lock.yaml content hashes (scripts, flows, apps). Writes local files only, not a deploy. Run it after edits that add or remove imports or change a script's arguments, so the lock, the auto-generated UI schema, and wmill-lock.yaml stay in sync.").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(generateMetadata).command("rehash", new Command().description("Refresh wmill-lock.yaml content hashes from the on-disk .lock and .script.yaml without re-resolving dependencies or hitting the backend. Use when those files are already correct and only the hashes need updating: bootstrapping missing entries or recovering from 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));
64063
64143
  generate_metadata_default = command4;
64064
64144
  });
64065
64145
 
@@ -78567,6 +78647,20 @@ Local previews exist for every entity type and don't deploy:
78567
78647
 
78568
78648
  Argument shapes and per-language details live in the \`write-script-<lang>\`, \`write-flow\`, and \`raw-app\` skills.
78569
78649
 
78650
+ ## Keeping metadata in sync
78651
+
78652
+ After editing a script, flow inline script, or app runnable, its generated metadata can go stale. \`wmill-lock.yaml\` stores a content hash per item, so a change that **adds or removes an import** or **changes a script's arguments** invalidates that hash and leaves the \`.lock\` (resolved dependencies) and \`.script.yaml\` (the input schema that drives the auto-generated args UI) out of date. \`wmill generate-metadata\` regenerates them and refreshes the hashes. Leaving them stale produces spurious diffs in git-sync and CI.
78653
+
78654
+ This only writes local files — it is **not** a deploy — but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default **offer it and run it once the user agrees**, rather than running it silently after every edit. YOU run the command (never tell the user to run it); the choice is only whether to confirm first.
78655
+
78656
+ After running it, diff the regenerated lockfiles (e.g. \`git diff\` the \`.lock\` / \`.script.lock\` files): if any dependency versions changed, tell the user what bumped (e.g. \`requests 2.31.0 → 2.32.0\`) so they can catch an unwanted change before deploying. Do this even under \`Metadata: auto\` — it is information, not a confirmation gate. Pin a version in code to keep it fixed.
78657
+
78658
+ With no path argument it regenerates only the items whose metadata is actually stale (content hash drifted), workspace-wide — not everything. The set can be larger than the file you edited for two reasons: imports propagate (editing a script that others import marks every importer stale too, so their locks regenerate against the new code — by design, since a lock must reflect the imported code), and any pre-existing drift is swept in. If it touches items you didn't expect, run \`wmill generate-metadata --dry-run\` first — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) and changes nothing, so you can see why each is in scope. To narrow it, pass a folder or file path (\`wmill generate-metadata f/foo\`); add \`--strict-folder-boundaries\` to touch only items literally inside that folder (it warns about stale importers outside the folder that it skipped — they resurface as stale on the next unscoped run).
78659
+
78660
+ **Save the preference so you don't ask every session.** If the user wants metadata regenerated automatically after edits (or always confirmed first), record it in the **project-specific instructions** section of \`AGENTS.md\` (user-owned — never overwritten by \`wmill refresh prompts\`), e.g. a line like \`Metadata: auto (run wmill generate-metadata after edits)\` or \`Metadata: ask first\`. Read that line first on later sessions and follow it.
78661
+
78662
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
78663
+
78570
78664
  ## Deploying
78571
78665
 
78572
78666
  There are two ways local changes reach the workspace. Pick based on how the repo is wired, not habit.
@@ -78693,7 +78787,7 @@ After writing, tell the user which command fits what they want to do:
78693
78787
 
78694
78788
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
78695
78789
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
78696
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
78790
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
78697
78791
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
78698
78792
 
78699
78793
  ### Preview vs run — choose by intent, not habit
@@ -78708,13 +78802,23 @@ Only use \`sync push\` when:
78708
78802
  - The user explicitly asks to deploy, publish, push, or ship.
78709
78803
  - The preview has already validated the change and the user wants it in the workspace.
78710
78804
 
78805
+ ### Keep metadata in sync after editing
78806
+
78807
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
78808
+
78809
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
78810
+
78811
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
78812
+
78813
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
78814
+
78711
78815
  ### After writing — offer to test, don't wait passively
78712
78816
 
78713
78817
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
78714
78818
 
78715
78819
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
78716
78820
 
78717
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
78821
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
78718
78822
 
78719
78823
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
78720
78824
 
@@ -78783,7 +78887,7 @@ After writing, tell the user which command fits what they want to do:
78783
78887
 
78784
78888
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
78785
78889
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
78786
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
78890
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
78787
78891
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
78788
78892
 
78789
78893
  ### Preview vs run — choose by intent, not habit
@@ -78798,13 +78902,23 @@ Only use \`sync push\` when:
78798
78902
  - The user explicitly asks to deploy, publish, push, or ship.
78799
78903
  - The preview has already validated the change and the user wants it in the workspace.
78800
78904
 
78905
+ ### Keep metadata in sync after editing
78906
+
78907
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
78908
+
78909
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
78910
+
78911
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
78912
+
78913
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
78914
+
78801
78915
  ### After writing — offer to test, don't wait passively
78802
78916
 
78803
78917
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
78804
78918
 
78805
78919
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
78806
78920
 
78807
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
78921
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
78808
78922
 
78809
78923
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
78810
78924
 
@@ -78866,7 +78980,7 @@ After writing, tell the user which command fits what they want to do:
78866
78980
 
78867
78981
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
78868
78982
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
78869
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
78983
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
78870
78984
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
78871
78985
 
78872
78986
  ### Preview vs run — choose by intent, not habit
@@ -78881,13 +78995,23 @@ Only use \`sync push\` when:
78881
78995
  - The user explicitly asks to deploy, publish, push, or ship.
78882
78996
  - The preview has already validated the change and the user wants it in the workspace.
78883
78997
 
78998
+ ### Keep metadata in sync after editing
78999
+
79000
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
79001
+
79002
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
79003
+
79004
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
79005
+
79006
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
79007
+
78884
79008
  ### After writing — offer to test, don't wait passively
78885
79009
 
78886
79010
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
78887
79011
 
78888
79012
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
78889
79013
 
78890
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
79014
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
78891
79015
 
78892
79016
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
78893
79017
 
@@ -79558,7 +79682,7 @@ datatable(name: string = "main"): DatatableSqlTemplateFunction
79558
79682
 
79559
79683
  /**
79560
79684
  * Create a SQL template function for DuckDB/ducklake queries
79561
- * @param name - DuckDB database name (default: "main")
79685
+ * @param name - DuckDB database name, optionally with a schema as \`name:schema\` (default: "main")
79562
79686
  * @returns SQL template function for building parameterized queries
79563
79687
  * @example
79564
79688
  * let sql = wmill.ducklake()
@@ -79568,6 +79692,9 @@ datatable(name: string = "main"): DatatableSqlTemplateFunction
79568
79692
  * SELECT * FROM friends
79569
79693
  * WHERE name = \${name} AND age = \${age}
79570
79694
  * \`.fetch()
79695
+ * @example
79696
+ * // Target a specific schema within the ducklake
79697
+ * let sql = wmill.ducklake("my_lake:analytics")
79571
79698
  */
79572
79699
  ducklake(name: string = "main"): SqlTemplateFunction
79573
79700
  `,
@@ -79584,7 +79711,7 @@ After writing, tell the user which command fits what they want to do:
79584
79711
 
79585
79712
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
79586
79713
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
79587
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
79714
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
79588
79715
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
79589
79716
 
79590
79717
  ### Preview vs run — choose by intent, not habit
@@ -79599,13 +79726,23 @@ Only use \`sync push\` when:
79599
79726
  - The user explicitly asks to deploy, publish, push, or ship.
79600
79727
  - The preview has already validated the change and the user wants it in the workspace.
79601
79728
 
79729
+ ### Keep metadata in sync after editing
79730
+
79731
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
79732
+
79733
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
79734
+
79735
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
79736
+
79737
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
79738
+
79602
79739
  ### After writing — offer to test, don't wait passively
79603
79740
 
79604
79741
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
79605
79742
 
79606
79743
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
79607
79744
 
79608
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
79745
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
79609
79746
 
79610
79747
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
79611
79748
 
@@ -80276,7 +80413,7 @@ datatable(name: string = "main"): DatatableSqlTemplateFunction
80276
80413
 
80277
80414
  /**
80278
80415
  * Create a SQL template function for DuckDB/ducklake queries
80279
- * @param name - DuckDB database name (default: "main")
80416
+ * @param name - DuckDB database name, optionally with a schema as \`name:schema\` (default: "main")
80280
80417
  * @returns SQL template function for building parameterized queries
80281
80418
  * @example
80282
80419
  * let sql = wmill.ducklake()
@@ -80286,6 +80423,9 @@ datatable(name: string = "main"): DatatableSqlTemplateFunction
80286
80423
  * SELECT * FROM friends
80287
80424
  * WHERE name = \${name} AND age = \${age}
80288
80425
  * \`.fetch()
80426
+ * @example
80427
+ * // Target a specific schema within the ducklake
80428
+ * let sql = wmill.ducklake("my_lake:analytics")
80289
80429
  */
80290
80430
  ducklake(name: string = "main"): SqlTemplateFunction
80291
80431
  `,
@@ -80302,7 +80442,7 @@ After writing, tell the user which command fits what they want to do:
80302
80442
 
80303
80443
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
80304
80444
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
80305
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
80445
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
80306
80446
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
80307
80447
 
80308
80448
  ### Preview vs run — choose by intent, not habit
@@ -80317,13 +80457,23 @@ Only use \`sync push\` when:
80317
80457
  - The user explicitly asks to deploy, publish, push, or ship.
80318
80458
  - The preview has already validated the change and the user wants it in the workspace.
80319
80459
 
80460
+ ### Keep metadata in sync after editing
80461
+
80462
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
80463
+
80464
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
80465
+
80466
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
80467
+
80468
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
80469
+
80320
80470
  ### After writing — offer to test, don't wait passively
80321
80471
 
80322
80472
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
80323
80473
 
80324
80474
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
80325
80475
 
80326
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
80476
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
80327
80477
 
80328
80478
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
80329
80479
 
@@ -80384,7 +80534,7 @@ After writing, tell the user which command fits what they want to do:
80384
80534
 
80385
80535
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
80386
80536
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
80387
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
80537
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
80388
80538
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
80389
80539
 
80390
80540
  ### Preview vs run — choose by intent, not habit
@@ -80399,13 +80549,23 @@ Only use \`sync push\` when:
80399
80549
  - The user explicitly asks to deploy, publish, push, or ship.
80400
80550
  - The preview has already validated the change and the user wants it in the workspace.
80401
80551
 
80552
+ ### Keep metadata in sync after editing
80553
+
80554
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
80555
+
80556
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
80557
+
80558
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
80559
+
80560
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
80561
+
80402
80562
  ### After writing — offer to test, don't wait passively
80403
80563
 
80404
80564
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
80405
80565
 
80406
80566
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
80407
80567
 
80408
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
80568
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
80409
80569
 
80410
80570
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
80411
80571
 
@@ -81076,7 +81236,7 @@ datatable(name: string = "main"): DatatableSqlTemplateFunction
81076
81236
 
81077
81237
  /**
81078
81238
  * Create a SQL template function for DuckDB/ducklake queries
81079
- * @param name - DuckDB database name (default: "main")
81239
+ * @param name - DuckDB database name, optionally with a schema as \`name:schema\` (default: "main")
81080
81240
  * @returns SQL template function for building parameterized queries
81081
81241
  * @example
81082
81242
  * let sql = wmill.ducklake()
@@ -81086,6 +81246,9 @@ datatable(name: string = "main"): DatatableSqlTemplateFunction
81086
81246
  * SELECT * FROM friends
81087
81247
  * WHERE name = \${name} AND age = \${age}
81088
81248
  * \`.fetch()
81249
+ * @example
81250
+ * // Target a specific schema within the ducklake
81251
+ * let sql = wmill.ducklake("my_lake:analytics")
81089
81252
  */
81090
81253
  ducklake(name: string = "main"): SqlTemplateFunction
81091
81254
  `,
@@ -81102,7 +81265,7 @@ After writing, tell the user which command fits what they want to do:
81102
81265
 
81103
81266
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
81104
81267
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
81105
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
81268
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
81106
81269
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
81107
81270
 
81108
81271
  ### Preview vs run — choose by intent, not habit
@@ -81117,13 +81280,23 @@ Only use \`sync push\` when:
81117
81280
  - The user explicitly asks to deploy, publish, push, or ship.
81118
81281
  - The preview has already validated the change and the user wants it in the workspace.
81119
81282
 
81283
+ ### Keep metadata in sync after editing
81284
+
81285
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
81286
+
81287
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
81288
+
81289
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
81290
+
81291
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
81292
+
81120
81293
  ### After writing — offer to test, don't wait passively
81121
81294
 
81122
81295
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
81123
81296
 
81124
81297
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
81125
81298
 
81126
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
81299
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
81127
81300
 
81128
81301
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
81129
81302
 
@@ -81218,7 +81391,7 @@ After writing, tell the user which command fits what they want to do:
81218
81391
 
81219
81392
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
81220
81393
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
81221
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
81394
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
81222
81395
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
81223
81396
 
81224
81397
  ### Preview vs run — choose by intent, not habit
@@ -81233,13 +81406,23 @@ Only use \`sync push\` when:
81233
81406
  - The user explicitly asks to deploy, publish, push, or ship.
81234
81407
  - The preview has already validated the change and the user wants it in the workspace.
81235
81408
 
81409
+ ### Keep metadata in sync after editing
81410
+
81411
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
81412
+
81413
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
81414
+
81415
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
81416
+
81417
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
81418
+
81236
81419
  ### After writing — offer to test, don't wait passively
81237
81420
 
81238
81421
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
81239
81422
 
81240
81423
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
81241
81424
 
81242
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
81425
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
81243
81426
 
81244
81427
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
81245
81428
 
@@ -81317,7 +81500,7 @@ After writing, tell the user which command fits what they want to do:
81317
81500
 
81318
81501
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
81319
81502
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
81320
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
81503
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
81321
81504
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
81322
81505
 
81323
81506
  ### Preview vs run — choose by intent, not habit
@@ -81332,13 +81515,23 @@ Only use \`sync push\` when:
81332
81515
  - The user explicitly asks to deploy, publish, push, or ship.
81333
81516
  - The preview has already validated the change and the user wants it in the workspace.
81334
81517
 
81518
+ ### Keep metadata in sync after editing
81519
+
81520
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
81521
+
81522
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
81523
+
81524
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
81525
+
81526
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
81527
+
81335
81528
  ### After writing — offer to test, don't wait passively
81336
81529
 
81337
81530
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
81338
81531
 
81339
81532
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
81340
81533
 
81341
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
81534
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
81342
81535
 
81343
81536
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
81344
81537
 
@@ -81403,7 +81596,7 @@ After writing, tell the user which command fits what they want to do:
81403
81596
 
81404
81597
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
81405
81598
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
81406
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
81599
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
81407
81600
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
81408
81601
 
81409
81602
  ### Preview vs run — choose by intent, not habit
@@ -81418,13 +81611,23 @@ Only use \`sync push\` when:
81418
81611
  - The user explicitly asks to deploy, publish, push, or ship.
81419
81612
  - The preview has already validated the change and the user wants it in the workspace.
81420
81613
 
81614
+ ### Keep metadata in sync after editing
81615
+
81616
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
81617
+
81618
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
81619
+
81620
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
81621
+
81622
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
81623
+
81421
81624
  ### After writing — offer to test, don't wait passively
81422
81625
 
81423
81626
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
81424
81627
 
81425
81628
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
81426
81629
 
81427
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
81630
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
81428
81631
 
81429
81632
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
81430
81633
 
@@ -81482,7 +81685,7 @@ After writing, tell the user which command fits what they want to do:
81482
81685
 
81483
81686
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
81484
81687
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
81485
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
81688
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
81486
81689
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
81487
81690
 
81488
81691
  ### Preview vs run — choose by intent, not habit
@@ -81497,13 +81700,23 @@ Only use \`sync push\` when:
81497
81700
  - The user explicitly asks to deploy, publish, push, or ship.
81498
81701
  - The preview has already validated the change and the user wants it in the workspace.
81499
81702
 
81703
+ ### Keep metadata in sync after editing
81704
+
81705
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
81706
+
81707
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
81708
+
81709
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
81710
+
81711
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
81712
+
81500
81713
  ### After writing — offer to test, don't wait passively
81501
81714
 
81502
81715
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
81503
81716
 
81504
81717
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
81505
81718
 
81506
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
81719
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
81507
81720
 
81508
81721
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
81509
81722
 
@@ -81564,7 +81777,7 @@ After writing, tell the user which command fits what they want to do:
81564
81777
 
81565
81778
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
81566
81779
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
81567
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
81780
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
81568
81781
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
81569
81782
 
81570
81783
  ### Preview vs run — choose by intent, not habit
@@ -81579,13 +81792,23 @@ Only use \`sync push\` when:
81579
81792
  - The user explicitly asks to deploy, publish, push, or ship.
81580
81793
  - The preview has already validated the change and the user wants it in the workspace.
81581
81794
 
81795
+ ### Keep metadata in sync after editing
81796
+
81797
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
81798
+
81799
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
81800
+
81801
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
81802
+
81803
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
81804
+
81582
81805
  ### After writing — offer to test, don't wait passively
81583
81806
 
81584
81807
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
81585
81808
 
81586
81809
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
81587
81810
 
81588
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
81811
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
81589
81812
 
81590
81813
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
81591
81814
 
@@ -81647,7 +81870,7 @@ After writing, tell the user which command fits what they want to do:
81647
81870
 
81648
81871
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
81649
81872
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
81650
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
81873
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
81651
81874
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
81652
81875
 
81653
81876
  ### Preview vs run — choose by intent, not habit
@@ -81662,13 +81885,23 @@ Only use \`sync push\` when:
81662
81885
  - The user explicitly asks to deploy, publish, push, or ship.
81663
81886
  - The preview has already validated the change and the user wants it in the workspace.
81664
81887
 
81888
+ ### Keep metadata in sync after editing
81889
+
81890
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
81891
+
81892
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
81893
+
81894
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
81895
+
81896
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
81897
+
81665
81898
  ### After writing — offer to test, don't wait passively
81666
81899
 
81667
81900
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
81668
81901
 
81669
81902
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
81670
81903
 
81671
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
81904
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
81672
81905
 
81673
81906
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
81674
81907
 
@@ -81745,7 +81978,7 @@ After writing, tell the user which command fits what they want to do:
81745
81978
 
81746
81979
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
81747
81980
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
81748
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
81981
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
81749
81982
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
81750
81983
 
81751
81984
  ### Preview vs run — choose by intent, not habit
@@ -81760,13 +81993,23 @@ Only use \`sync push\` when:
81760
81993
  - The user explicitly asks to deploy, publish, push, or ship.
81761
81994
  - The preview has already validated the change and the user wants it in the workspace.
81762
81995
 
81996
+ ### Keep metadata in sync after editing
81997
+
81998
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
81999
+
82000
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
82001
+
82002
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
82003
+
82004
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
82005
+
81763
82006
  ### After writing — offer to test, don't wait passively
81764
82007
 
81765
82008
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
81766
82009
 
81767
82010
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
81768
82011
 
81769
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
82012
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
81770
82013
 
81771
82014
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
81772
82015
 
@@ -81826,7 +82069,7 @@ After writing, tell the user which command fits what they want to do:
81826
82069
 
81827
82070
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
81828
82071
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
81829
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
82072
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
81830
82073
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
81831
82074
 
81832
82075
  ### Preview vs run — choose by intent, not habit
@@ -81841,13 +82084,23 @@ Only use \`sync push\` when:
81841
82084
  - The user explicitly asks to deploy, publish, push, or ship.
81842
82085
  - The preview has already validated the change and the user wants it in the workspace.
81843
82086
 
82087
+ ### Keep metadata in sync after editing
82088
+
82089
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
82090
+
82091
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
82092
+
82093
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
82094
+
82095
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
82096
+
81844
82097
  ### After writing — offer to test, don't wait passively
81845
82098
 
81846
82099
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
81847
82100
 
81848
82101
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
81849
82102
 
81850
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
82103
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
81851
82104
 
81852
82105
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
81853
82106
 
@@ -81922,7 +82175,7 @@ After writing, tell the user which command fits what they want to do:
81922
82175
 
81923
82176
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
81924
82177
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
81925
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
82178
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
81926
82179
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
81927
82180
 
81928
82181
  ### Preview vs run — choose by intent, not habit
@@ -81937,13 +82190,23 @@ Only use \`sync push\` when:
81937
82190
  - The user explicitly asks to deploy, publish, push, or ship.
81938
82191
  - The preview has already validated the change and the user wants it in the workspace.
81939
82192
 
82193
+ ### Keep metadata in sync after editing
82194
+
82195
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
82196
+
82197
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
82198
+
82199
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
82200
+
82201
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
82202
+
81940
82203
  ### After writing — offer to test, don't wait passively
81941
82204
 
81942
82205
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
81943
82206
 
81944
82207
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
81945
82208
 
81946
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
82209
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
81947
82210
 
81948
82211
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
81949
82212
 
@@ -82788,7 +83051,7 @@ After writing, tell the user which command fits what they want to do:
82788
83051
 
82789
83052
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
82790
83053
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
82791
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
83054
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
82792
83055
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
82793
83056
 
82794
83057
  ### Preview vs run — choose by intent, not habit
@@ -82803,13 +83066,23 @@ Only use \`sync push\` when:
82803
83066
  - The user explicitly asks to deploy, publish, push, or ship.
82804
83067
  - The preview has already validated the change and the user wants it in the workspace.
82805
83068
 
83069
+ ### Keep metadata in sync after editing
83070
+
83071
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
83072
+
83073
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
83074
+
83075
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
83076
+
83077
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
83078
+
82806
83079
  ### After writing — offer to test, don't wait passively
82807
83080
 
82808
83081
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
82809
83082
 
82810
83083
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
82811
83084
 
82812
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
83085
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
82813
83086
 
82814
83087
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
82815
83088
 
@@ -82914,7 +83187,7 @@ After writing, tell the user which command fits what they want to do:
82914
83187
 
82915
83188
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
82916
83189
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
82917
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
83190
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
82918
83191
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
82919
83192
 
82920
83193
  ### Preview vs run — choose by intent, not habit
@@ -82929,13 +83202,23 @@ Only use \`sync push\` when:
82929
83202
  - The user explicitly asks to deploy, publish, push, or ship.
82930
83203
  - The preview has already validated the change and the user wants it in the workspace.
82931
83204
 
83205
+ ### Keep metadata in sync after editing
83206
+
83207
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
83208
+
83209
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
83210
+
83211
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
83212
+
83213
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
83214
+
82932
83215
  ### After writing — offer to test, don't wait passively
82933
83216
 
82934
83217
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
82935
83218
 
82936
83219
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
82937
83220
 
82938
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
83221
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
82939
83222
 
82940
83223
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
82941
83224
 
@@ -83030,7 +83313,7 @@ After writing, tell the user which command fits what they want to do:
83030
83313
 
83031
83314
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
83032
83315
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
83033
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
83316
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
83034
83317
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
83035
83318
 
83036
83319
  ### Preview vs run — choose by intent, not habit
@@ -83045,13 +83328,23 @@ Only use \`sync push\` when:
83045
83328
  - The user explicitly asks to deploy, publish, push, or ship.
83046
83329
  - The preview has already validated the change and the user wants it in the workspace.
83047
83330
 
83331
+ ### Keep metadata in sync after editing
83332
+
83333
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
83334
+
83335
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
83336
+
83337
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
83338
+
83339
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
83340
+
83048
83341
  ### After writing — offer to test, don't wait passively
83049
83342
 
83050
83343
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
83051
83344
 
83052
83345
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
83053
83346
 
83054
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
83347
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
83055
83348
 
83056
83349
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
83057
83350
 
@@ -83146,11 +83439,11 @@ Once the flow has real content, **offer** to open the visual preview as a one-se
83146
83439
 
83147
83440
  ## CLI Commands — running, previewing, deploying
83148
83441
 
83149
- After writing, act on the user's intent instead of just listing commands. Run the safe, non-deploying command yourself when it fits (\`wmill flow preview\` — see "After writing — offer to run, don't wait passively" below); only *name* the commands that deploy or rewrite files (\`wmill sync push\`, \`wmill generate-metadata\`) so the user can approve them. The options:
83442
+ After writing, act on the user's intent instead of just listing commands. Run \`wmill flow preview\` yourself when it fits (see "After writing — offer to run, don't wait passively" below). \`wmill generate-metadata\` regenerates local lock/hash files (not a deploy) but re-resolves deps — offer it and run on agreement, unless the project's \`AGENTS.md\` opts into running metadata automatically. Only *name* \`wmill sync push\` (the deploy) so the user can approve it. The options:
83150
83443
 
83151
83444
  - \`wmill flow preview <flow_path>\` — **default when iterating on a local flow.** Runs the local \`flow.yaml\` against local inline scripts without deploying. Add \`--remote\` to use deployed workspace scripts for PathScript steps instead of local files. Add \`--step <step_id>\` to run only one module in isolation (see "Single-step vs whole-flow preview" below).
83152
83445
  - \`wmill flow run <path>\` — runs the flow **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
83153
- - \`wmill generate-metadata\` — regenerate stale \`.lock\` and \`.script.yaml\` files. By default it scans **scripts, flows, and apps** across the workspace; pass \`--skip-flows --skip-apps\` (or run from a subdirectory) to limit the scope when you only care about the flow you edited.
83446
+ - \`wmill generate-metadata\` — regenerate stale local \`.lock\` files for the flow and its inline scripts and refresh their content hashes in \`wmill-lock.yaml\`. Writes local files only (not a deploy). Run it after editing inline scripts whose imports or arguments changed, so \`wmill-lock.yaml\` doesn't drift and add noise to git-sync/CI. By default it scans **scripts, flows, and apps** across the workspace but only regenerates stale ones; pass the flow's folder as an argument (or run from that subdirectory) to limit the scope to the flow you edited. Note a flow (or script) that imports a changed shared script is pulled in too — run \`wmill generate-metadata --dry-run\` to see exactly what is stale and why (\`content changed\` vs \`depends on <path>\`) before applying.
83154
83447
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
83155
83448
 
83156
83449
  ### Preview vs run — choose by intent, not habit
@@ -83179,7 +83472,7 @@ If the user hasn't already told you to run/test the flow, offer it as a one-sent
83179
83472
 
83180
83473
  If the user already asked to test/run/try the flow in their original request, skip the offer and just execute \`wmill flow preview <path> -d '<args>'\` directly — pick plausible args from the flow's input schema.
83181
83474
 
83182
- \`wmill flow preview\` is safe to run yourself (it does not deploy). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
83475
+ \`wmill flow preview\` is safe to run yourself (it does not deploy). \`wmill generate-metadata\` does not deploy either (it only writes local lock/hash files) but re-resolves deps offer it and run on agreement, unless the project's \`AGENTS.md\` opts into automatic metadata. After running it, check the regenerated \`.lock\` diff and tell the user which inline-script dependency versions changed, so they can catch an unwanted bump before deploying. Only \`wmill sync push\` deploys; run it only when the user explicitly asks.
83183
83476
 
83184
83477
  ### Visual preview
83185
83478
 
@@ -83612,10 +83905,11 @@ The runnable ID is the filename without extension. For example, \`get_user.ts\`
83612
83905
  | C# | \`.cs\` | \`myFunc.cs\` |
83613
83906
  | Java | \`.java\` | \`myFunc.java\` |
83614
83907
 
83615
- After creating a runnable, offer to generate its lock files as a one-sentence next step (e.g. "Want me to generate the lock files?") and run it yourself once they agree don't just name the command and wait. If the user already asked you to finish/lock the app, run it directly. It writes local lock files (not a deploy), so offer rather than running silently:
83908
+ After creating or editing a backend runnable especially when its imports or arguments changed its local lock and \`wmill-lock.yaml\` go stale. Offer to run \`wmill generate-metadata\` and run it once the user agrees (or automatically if the project's \`AGENTS.md\` opts into that) YOU run it, don't just name it and wait. It writes local files only (not a deploy), and keeping the lock current avoids noise in git-sync/CI:
83616
83909
  \`\`\`bash
83617
83910
  wmill generate-metadata
83618
83911
  \`\`\`
83912
+ After it runs, check the regenerated \`.lock\` diff and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying.
83619
83913
 
83620
83914
  ### Optional YAML configuration
83621
83915
 
@@ -83705,7 +83999,7 @@ data:
83705
83999
 
83706
84000
  Two commands you run yourself, not the user:
83707
84001
  - \`wmill app new\` — run it with flags, per the "Creating a Raw App" section above.
83708
- - \`wmill generate-metadata\` — generates local lock files; offer it and run it on consent, per "After creating a runnable" above (it writes local lock files, not a deploy).
84002
+ - \`wmill generate-metadata\` — (re)generates local lock files and refreshes \`wmill-lock.yaml\` content hashes; writes local files only (not a deploy). After adding or editing a runnable, offer it and run it on agreement or automatically if the project's \`AGENTS.md\` opts into that (see "After creating a runnable" above).
83709
84003
 
83710
84004
  For the rest, tell the user which command fits their intent and let them run it — these deploy to the workspace, overwrite local files, or launch a long-running server, so the user should consent each time:
83711
84005
 
@@ -84245,7 +84539,7 @@ After writing, tell the user which command fits what they want to do:
84245
84539
 
84246
84540
  - \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
84247
84541
  - \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
84248
- - \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
84542
+ - \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
84249
84543
  - \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
84250
84544
 
84251
84545
  ### Preview vs run — choose by intent, not habit
@@ -84260,13 +84554,23 @@ Only use \`sync push\` when:
84260
84554
  - The user explicitly asks to deploy, publish, push, or ship.
84261
84555
  - The preview has already validated the change and the user wants it in the workspace.
84262
84556
 
84557
+ ### Keep metadata in sync after editing
84558
+
84559
+ \`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
84560
+
84561
+ This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
84562
+
84563
+ With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
84564
+
84565
+ If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
84566
+
84263
84567
  ### After writing — offer to test, don't wait passively
84264
84568
 
84265
84569
  If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
84266
84570
 
84267
84571
  If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
84268
84572
 
84269
- \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
84573
+ \`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
84270
84574
 
84271
84575
  For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
84272
84576
 
@@ -84756,6 +85060,9 @@ datatable related commands
84756
85060
  - \`datatable run <sql:string>\` - run a SQL query on a datatable
84757
85061
  - \`-n --name <name:string>\` - Datatable name (default: main)
84758
85062
  - \`-s --silent\` - Output only the final result as JSON. Useful for scripting.
85063
+ - \`datatable create [name:string]\` - register a datatable database in the workspace (default: instance-backed 'main') so scripts can use datatable://<name>
85064
+ - \`--resource <resource:string>\` - Back the datatable with an existing postgresql resource path instead of the instance database
85065
+ - \`--force\` - Allow adding to a workspace that already has datatables (fork metadata on existing ones is not preserved)
84759
85066
  - \`datatable serve\` - Serve all datatables as a Postgres-wire endpoint (psql, DBeaver, pgAdmin); the client picks the datatable via the database name in its connection string
84760
85067
  - \`--port <port:number>\` - Port to listen on (default: first free port in 5433-5500)
84761
85068
  - \`--host <host:string>\` - Bind address (default: 127.0.0.1)
@@ -84868,7 +85175,7 @@ folder related commands
84868
85175
 
84869
85176
  ### generate-metadata
84870
85177
 
84871
- Generate metadata (locks, schemas) for all scripts, flows, and apps
85178
+ Regenerate stale local locks and script schemas and refresh wmill-lock.yaml content hashes (scripts, flows, apps). Writes local files only, not a deploy. Run it after edits that add or remove imports or change a script's arguments, so the lock, the auto-generated UI schema, and wmill-lock.yaml stay in sync.
84872
85179
 
84873
85180
  **Arguments:** \`[folder:string]\`
84874
85181
 
@@ -84887,7 +85194,7 @@ Generate metadata (locks, schemas) for all scripts, flows, and apps
84887
85194
 
84888
85195
  **Subcommands:**
84889
85196
 
84890
- - \`generate-metadata rehash [folder:string]\`
85197
+ - \`generate-metadata rehash [folder:string]\` - Refresh wmill-lock.yaml content hashes from the on-disk .lock and .script.yaml without re-resolving dependencies or hitting the backend. Use when those files are already correct and only the hashes need updating: bootstrapping missing entries or recovering from hash drift.
84891
85198
  - \`--skip-scripts\` - Skip processing scripts
84892
85199
  - \`--skip-flows\` - Skip processing flows
84893
85200
  - \`--skip-apps\` - Skip processing apps
@@ -84995,7 +85302,7 @@ sync local with a remote instance or the opposite (push or pull)
84995
85302
  - \`-o, --output-file <file:string>\` - Write YAML to a file instead of stdout
84996
85303
  - \`--show-secrets\` - Include sensitive fields (license key, JWT secret) without prompting
84997
85304
  - \`--instance <instance:string>\` - Name of the instance, override the active instance
84998
- - \`instance connect-slack\`
85305
+ - \`instance connect-slack\` - 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.
84999
85306
  - \`--bot-token <bot_token:string>\` - Slack bot token (xoxb-...)
85000
85307
  - \`--team-id <team_id:string>\` - Slack team id
85001
85308
  - \`--team-name <team_name:string>\` - Slack team name
@@ -85049,6 +85356,8 @@ Validate Windmill flow, schedule, and trigger YAML files in a directory
85049
85356
 
85050
85357
  ### object-storage
85051
85358
 
85359
+ Object storage (S3) related commands. Operates on the workspace's default object storage; use --storage to target a configured secondary storage.
85360
+
85052
85361
  **Alias:** \`s3\`
85053
85362
 
85054
85363
  **Subcommands:**
@@ -85083,8 +85392,21 @@ Validate Windmill flow, schedule, and trigger YAML files in a directory
85083
85392
  - \`--csv-separator <csvSeparator:string>\` - CSV column separator (default ,)
85084
85393
  - \`--csv-header\` - Treat the first CSV row as a header
85085
85394
 
85395
+ ### pipeline
85396
+
85397
+ inspect asset-driven pipelines (scripts marked \`// pipeline\`, wired by \`// on <spec>\` annotations)
85398
+
85399
+ **Subcommands:**
85400
+
85401
+ - \`pipeline list\` - list pipeline folders in the workspace
85402
+ - \`--json\` - Output as JSON (for piping to jq)
85403
+ - \`pipeline show <folder:string>\` - render a pipeline folder's DAG (sources, lineage, subscriptions) in the terminal
85404
+ - \`--json\` - Output the raw asset graph as JSON
85405
+
85086
85406
  ### protection-rules
85087
85407
 
85408
+ Sync workspace protection rules between protection-rules.yaml and Windmill. The file is keyed by workspace name; keys must match wmill.yaml 'workspaces'.
85409
+
85088
85410
  **Subcommands:**
85089
85411
 
85090
85412
  - \`protection-rules pull [workspace:string]\` - Pull protection rules from Windmill into protection-rules.yaml for a workspace
@@ -85425,7 +85747,7 @@ workspace related commands
85425
85747
  - \`--bot-token <bot_token:string>\` - Slack bot token (xoxb-...)
85426
85748
  - \`--team-id <team_id:string>\` - Slack team id
85427
85749
  - \`--team-name <team_name:string>\` - Slack team name
85428
- - \`workspace disconnect-slack\`
85750
+ - \`workspace disconnect-slack\` - 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.
85429
85751
 
85430
85752
 
85431
85753
 
@@ -93960,15 +94282,216 @@ async function run4(opts, sql) {
93960
94282
  const name = opts.name ?? DEFAULT_DATATABLE_NAME2;
93961
94283
  await runCatalogQuery(opts, "datatable", name, sql);
93962
94284
  }
94285
+ async function create3(opts, name) {
94286
+ const workspace = await resolveWorkspace(opts);
94287
+ await requireLogin(opts);
94288
+ const dtName = name ?? DEFAULT_DATATABLE_NAME2;
94289
+ const existing = await listDataTables({
94290
+ workspace: workspace.workspaceId
94291
+ });
94292
+ if (existing.some((d3) => d3.name === dtName)) {
94293
+ throw new Error(`Datatable '${dtName}' already exists in this workspace`);
94294
+ }
94295
+ if (existing.length > 0 && !opts.force) {
94296
+ throw new Error(`Workspace already has datatable(s): ${existing.map((d3) => d3.name).join(", ")}. Re-run with --force to add '${dtName}' ` + "(note: fork metadata on existing datatables is not preserved)");
94297
+ }
94298
+ const datatables = {};
94299
+ for (const d3 of existing) {
94300
+ datatables[d3.name] = {
94301
+ database: {
94302
+ resource_type: d3.resource_type,
94303
+ resource_path: d3.resource_path ?? undefined
94304
+ }
94305
+ };
94306
+ }
94307
+ datatables[dtName] = opts.resource ? { database: { resource_type: "postgresql", resource_path: opts.resource } } : { database: { resource_type: "instance", resource_path: "datatable_db" } };
94308
+ await editDataTableConfig({
94309
+ workspace: workspace.workspaceId,
94310
+ requestBody: { settings: { datatables } }
94311
+ });
94312
+ info(`Datatable '${dtName}' created (${opts.resource ? `postgresql resource ${opts.resource}` : "instance-backed"}). Scripts can now use datatable://${dtName}.`);
94313
+ }
93963
94314
  async function serve2(opts) {
93964
94315
  await serve(opts);
93965
94316
  }
93966
94317
  async function psql2(opts) {
93967
94318
  await psql(opts);
93968
94319
  }
93969
- var command40 = new Command().description("datatable related commands").command("list", "list all datatables in the workspace").option("--json", "Output as JSON (for piping to jq)").action(list17).command("run", "run a SQL query on a datatable").arguments("<sql:string>").option("-n --name <name:string>", "Datatable name (default: main)").option("-s --silent", "Output only the final result as JSON. Useful for scripting.").action(run4).command("serve", "Serve all datatables as a Postgres-wire endpoint (psql, DBeaver, pgAdmin); the client picks the datatable via the database name in its connection string").option("--port <port:number>", "Port to listen on (default: first free port in 5433-5500)").option("--host <host:string>", "Bind address (default: 127.0.0.1)").option("--password <password:string>", "Password for Postgres clients (default: generate a random password at startup)").action(serve2).command("psql", "Start a serve listener and launch psql connected to it").option("-n --name <name:string>", "Datatable to connect psql to (default: main)").option("--port <port:number>", "Port the proxy listens on (default: first free port in 5433-5500)").option("--host <host:string>", "Bind address for the proxy (default: 127.0.0.1)").option("--password <password:string>", "Password for the temporary Postgres proxy (default: generate a random password at startup)").action(psql2);
94320
+ var command40 = new Command().description("datatable related commands").command("list", "list all datatables in the workspace").option("--json", "Output as JSON (for piping to jq)").action(list17).command("run", "run a SQL query on a datatable").arguments("<sql:string>").option("-n --name <name:string>", "Datatable name (default: main)").option("-s --silent", "Output only the final result as JSON. Useful for scripting.").action(run4).command("create", "register a datatable database in the workspace (default: instance-backed 'main') so scripts can use datatable://<name>").arguments("[name:string]").option("--resource <resource:string>", "Back the datatable with an existing postgresql resource path instead of the instance database").option("--force", "Allow adding to a workspace that already has datatables (fork metadata on existing ones is not preserved)").action(create3).command("serve", "Serve all datatables as a Postgres-wire endpoint (psql, DBeaver, pgAdmin); the client picks the datatable via the database name in its connection string").option("--port <port:number>", "Port to listen on (default: first free port in 5433-5500)").option("--host <host:string>", "Bind address (default: 127.0.0.1)").option("--password <password:string>", "Password for Postgres clients (default: generate a random password at startup)").action(serve2).command("psql", "Start a serve listener and launch psql connected to it").option("-n --name <name:string>", "Datatable to connect psql to (default: main)").option("--port <port:number>", "Port the proxy listens on (default: first free port in 5433-5500)").option("--host <host:string>", "Bind address for the proxy (default: 127.0.0.1)").option("--password <password:string>", "Password for the temporary Postgres proxy (default: generate a random password at startup)").action(psql2);
93970
94321
  var datatable_default = command40;
93971
94322
 
94323
+ // src/commands/pipeline/pipeline.ts
94324
+ init_mod3();
94325
+ init_mod6();
94326
+ init_colors2();
94327
+ init_gen();
94328
+ init_services_gen();
94329
+ init_log();
94330
+ await __promiseAll([
94331
+ init_auth(),
94332
+ init_context()
94333
+ ]);
94334
+ async function apiGet(path23) {
94335
+ const response = await fetch(`${OpenAPI.BASE}${path23}`, {
94336
+ headers: { Authorization: `Bearer ${OpenAPI.TOKEN}` }
94337
+ });
94338
+ if (!response.ok) {
94339
+ const body = await response.text();
94340
+ throw new Error(`GET ${path23} -> ${response.status}: ${body}`);
94341
+ }
94342
+ return await response.json();
94343
+ }
94344
+ async function list18(opts) {
94345
+ if (opts.json)
94346
+ setSilent(true);
94347
+ const workspace = await resolveWorkspace(opts);
94348
+ await requireLogin(opts);
94349
+ const items = await apiGet(`/w/${workspace.workspaceId}/assets/pipelines`);
94350
+ if (opts.json) {
94351
+ console.log(JSON.stringify(items));
94352
+ } else if (items.length === 0) {
94353
+ info("No pipelines in this workspace. Mark scripts with a `// pipeline` comment (plus `// on <spec>` triggers) and push them into a folder.");
94354
+ } else {
94355
+ new Table2().header(["Folder", "Scripts"]).padding(2).border(true).body(items.map((p3) => [`f/${p3.folder}`, String(p3.script_count)])).render();
94356
+ }
94357
+ }
94358
+ var ASSET_KINDS = "s3object,ducklake,datatable,volume";
94359
+ function assetUri(kind, path23) {
94360
+ const prefix = kind === "s3object" ? "s3" : kind;
94361
+ return `${prefix}://${path23}`;
94362
+ }
94363
+ function shortName(scriptPath) {
94364
+ return scriptPath.split("/").pop() ?? scriptPath;
94365
+ }
94366
+ function pushTo(map, key, val) {
94367
+ (map.get(key) ?? map.set(key, []).get(key)).push(val);
94368
+ }
94369
+ async function show2(opts, folder) {
94370
+ if (opts.json)
94371
+ setSilent(true);
94372
+ const workspace = await resolveWorkspace(opts);
94373
+ await requireLogin(opts);
94374
+ const f3 = folder.replace(/^f\//, "").replace(/\/$/, "");
94375
+ const graph = await apiGet(`/w/${workspace.workspaceId}/assets/graph?folder=${encodeURIComponent(f3)}&asset_kinds=${ASSET_KINDS}`);
94376
+ if (opts.json) {
94377
+ console.log(JSON.stringify(graph));
94378
+ return;
94379
+ }
94380
+ if (graph.runnables.length === 0) {
94381
+ info(`No pipeline scripts in f/${f3}. Mark scripts with a \`// pipeline\` comment and push them.`);
94382
+ return;
94383
+ }
94384
+ const writesByScript = new Map;
94385
+ for (const e2 of graph.edges) {
94386
+ if (e2.access_type === "w" || e2.access_type === "rw") {
94387
+ const uri = assetUri(e2.asset_kind, e2.asset_path);
94388
+ pushTo(writesByScript, e2.runnable_path, uri);
94389
+ }
94390
+ }
94391
+ const subsByAsset = new Map;
94392
+ const subsByScript = new Map;
94393
+ const nativeByScript = new Map;
94394
+ for (const t2 of graph.triggers) {
94395
+ if (t2.trigger_kind === "asset") {
94396
+ const at = t2;
94397
+ const uri = assetUri(at.asset_kind, at.asset_path);
94398
+ pushTo(subsByAsset, uri, t2.runnable_path);
94399
+ pushTo(subsByScript, t2.runnable_path, uri);
94400
+ } else {
94401
+ const nt = t2;
94402
+ pushTo(nativeByScript, t2.runnable_path, {
94403
+ kind: nt.trigger_kind,
94404
+ path: nt.path,
94405
+ missing: nt.missing
94406
+ });
94407
+ }
94408
+ }
94409
+ function triggerBadges(script) {
94410
+ const out = [];
94411
+ for (const t2 of nativeByScript.get(script) ?? []) {
94412
+ if (t2.kind === "data_upload") {
94413
+ out.push(colors.magenta("[data upload]"));
94414
+ } else if (t2.missing) {
94415
+ out.push(colors.red(`[${t2.kind} ✗ missing]`));
94416
+ } else {
94417
+ out.push(colors.yellow(`[${t2.kind}${t2.path ? ` ${t2.path}` : ""}]`));
94418
+ }
94419
+ }
94420
+ return out.length > 0 ? " " + out.join(" ") : "";
94421
+ }
94422
+ const printed = new Set;
94423
+ const lines = [];
94424
+ function printScript(script, prefix, extraOn) {
94425
+ const alsoOn = extraOn && extraOn.length > 0 ? colors.dim(` (also on: ${extraOn.join(", ")})`) : "";
94426
+ if (printed.has(script)) {
94427
+ lines.push(`${prefix}${colors.bold(shortName(script))}${colors.dim(" ↻ shown above")}`);
94428
+ return;
94429
+ }
94430
+ printed.add(script);
94431
+ lines.push(`${prefix}${colors.bold(shortName(script))}${triggerBadges(script)}${alsoOn}`);
94432
+ const childPrefix = prefix.replace(/├─ $/, "│ ").replace(/└─ $/, " ");
94433
+ const writes = [...writesByScript.get(script) ?? []].sort();
94434
+ writes.forEach((uri, i) => {
94435
+ const lastAsset = i === writes.length - 1;
94436
+ const assetBranch = lastAsset ? "└─▶ " : "├─▶ ";
94437
+ lines.push(`${childPrefix}${assetBranch}${colors.cyan(uri)}`);
94438
+ const assetChildPrefix = childPrefix + (lastAsset ? " " : "│ ");
94439
+ const subs = [...subsByAsset.get(uri) ?? []].sort();
94440
+ subs.forEach((sub, j2) => {
94441
+ const branch = j2 === subs.length - 1 ? "└─ " : "├─ ";
94442
+ const otherOn = (subsByScript.get(sub) ?? []).filter((u2) => u2 !== uri);
94443
+ printScript(sub, assetChildPrefix + branch, otherOn);
94444
+ });
94445
+ });
94446
+ }
94447
+ const roots = graph.runnables.map((r2) => r2.path).filter((p3) => !subsByScript.get(p3)?.length).sort();
94448
+ const MARKER_KINDS = ["data_upload", "webhook", "email"];
94449
+ await Promise.all(roots.map(async (p3) => {
94450
+ const r2 = graph.runnables.find((x3) => x3.path === p3);
94451
+ if (r2?.usage_kind !== "script")
94452
+ return;
94453
+ try {
94454
+ const script = await getScriptByPath({
94455
+ workspace: workspace.workspaceId,
94456
+ path: p3
94457
+ });
94458
+ const existing = nativeByScript.get(p3) ?? [];
94459
+ for (const line of (script.content ?? "").split(`
94460
+ `)) {
94461
+ const m3 = line.match(/^\s*(?:\/\/|--|#)\s*on\s+(\w+)\s*$/);
94462
+ if (!m3)
94463
+ continue;
94464
+ const kind = m3[1];
94465
+ if (!MARKER_KINDS.includes(kind))
94466
+ continue;
94467
+ if (!existing.some((t2) => t2.kind === kind)) {
94468
+ existing.push({ kind });
94469
+ }
94470
+ }
94471
+ if (existing.length > 0)
94472
+ nativeByScript.set(p3, existing);
94473
+ } catch {}
94474
+ }));
94475
+ const scriptCount = graph.runnables.length;
94476
+ const assetCount = graph.assets.length;
94477
+ info(colors.bold(`Pipeline f/${f3}`) + colors.dim(` — ${scriptCount} script${scriptCount === 1 ? "" : "s"} · ${assetCount} asset${assetCount === 1 ? "" : "s"}`));
94478
+ lines.push("");
94479
+ for (const root of roots) {
94480
+ printScript(root, "");
94481
+ lines.push("");
94482
+ }
94483
+ for (const r2 of graph.runnables) {
94484
+ if (!printed.has(r2.path)) {
94485
+ printScript(r2.path, "");
94486
+ lines.push("");
94487
+ }
94488
+ }
94489
+ console.log(lines.join(`
94490
+ `));
94491
+ }
94492
+ var command41 = new Command().description("inspect asset-driven pipelines (scripts marked `// pipeline`, wired by `// on <spec>` annotations)").command("list", "list pipeline folders in the workspace").option("--json", "Output as JSON (for piping to jq)").action(list18).command("show", "render a pipeline folder's DAG (sources, lineage, subscriptions) in the terminal").arguments("<folder:string>").option("--json", "Output the raw asset graph as JSON").action(show2);
94493
+ var pipeline_default = command41;
94494
+
93972
94495
  // src/commands/ducklake/ducklake.ts
93973
94496
  init_mod3();
93974
94497
  init_mod6();
@@ -93979,7 +94502,7 @@ await __promiseAll([
93979
94502
  init_context()
93980
94503
  ]);
93981
94504
  var DEFAULT_DUCKLAKE_NAME = "main";
93982
- async function list18(opts) {
94505
+ async function list19(opts) {
93983
94506
  if (opts.json)
93984
94507
  setSilent(true);
93985
94508
  const workspace = await resolveWorkspace(opts);
@@ -93997,8 +94520,8 @@ async function run5(opts, sql) {
93997
94520
  const name = opts.name ?? DEFAULT_DUCKLAKE_NAME;
93998
94521
  await runCatalogQuery(opts, "ducklake", name, sql);
93999
94522
  }
94000
- var command41 = new Command().description("ducklake related commands").command("list", "list all ducklakes in the workspace").option("--json", "Output as JSON (for piping to jq)").action(list18).command("run", "run a SQL query on a ducklake").arguments("<sql:string>").option("-n --name <name:string>", "Ducklake name (default: main)").option("-s --silent", "Output only the final result as JSON. Useful for scripting.").action(run5);
94001
- var ducklake_default = command41;
94523
+ var command42 = new Command().description("ducklake related commands").command("list", "list all ducklakes in the workspace").option("--json", "Output as JSON (for piping to jq)").action(list19).command("run", "run a SQL query on a ducklake").arguments("<sql:string>").option("-n --name <name:string>", "Ducklake name (default: main)").option("-s --silent", "Output only the final result as JSON. Useful for scripting.").action(run5);
94524
+ var ducklake_default = command42;
94002
94525
 
94003
94526
  // src/commands/object-storage/object-storage.ts
94004
94527
  init_mod3();
@@ -94199,8 +94722,8 @@ async function preview3(opts, fileKey) {
94199
94722
  `);
94200
94723
  }
94201
94724
  }
94202
- var command42 = new Command().alias("s3").description("Object storage (S3) related commands. Operates on the workspace's default object storage; use --storage to target a configured secondary storage.").action(listStorages).command("list", "List configured object storages for the workspace (default + secondary).").option("--json", "Output as JSON (for piping to jq)").action(listStorages).command("files", "List files in an object storage. Optionally filter by prefix.").alias("ls").arguments("[prefix:string]").option("--json", "Output as JSON (for piping to jq)").option("--max-keys <maxKeys:number>", "Page size (default 100)").option("--marker <marker:string>", "Pagination marker from a previous response").option("--storage <storage:string>", "Secondary storage name (omit for the workspace default)").action(listFiles).command("upload", "Upload a local file to object storage at the given file key.").arguments("<local_path:string> <file_key:string>").option("--storage <storage:string>", "Secondary storage name").option("--content-type <contentType:string>", "Content-Type header to set on the object").option("--content-disposition <contentDisposition:string>", "Content-Disposition header to set on the object").action(upload).command("download", "Download an object to a local file (or stdout). Default output path is the basename of the file key in the current directory.").arguments("<file_key:string> [output_path:string]").option("--storage <storage:string>", "Secondary storage name").option("--stdout", "Write file contents to stdout instead of a file").action(download).command("delete", "Delete an object from object storage. Prompts for confirmation unless --yes is set.").arguments("<file_key:string>").option("--storage <storage:string>", "Secondary storage name").option("--yes", "Skip the confirmation prompt").action(del).command("move", "Move an object within the same storage (rename or relocate by key).").arguments("<src_file_key:string> <dest_file_key:string>").option("--storage <storage:string>", "Secondary storage name").action(move).command("info", "Show metadata (size, mime, last-modified) for an object.").arguments("<file_key:string>").option("--json", "Output as JSON (for piping to jq)").option("--storage <storage:string>", "Secondary storage name").action(info2).command("preview", "Preview the contents of an object (text/CSV). Use --bytes-from / --bytes-length to peek at a slice of binary files.").arguments("<file_key:string>").option("--storage <storage:string>", "Secondary storage name").option("--mime <mime:string>", "Override the detected mime type (e.g. text/csv)").option("--bytes-from <bytesFrom:number>", "Start offset in bytes").option("--bytes-length <bytesLength:number>", "Number of bytes to read").option("--csv-separator <csvSeparator:string>", "CSV column separator (default ,)").option("--csv-header", "Treat the first CSV row as a header").action(preview3);
94203
- var object_storage_default = command42;
94725
+ var command43 = new Command().alias("s3").description("Object storage (S3) related commands. Operates on the workspace's default object storage; use --storage to target a configured secondary storage.").action(listStorages).command("list", "List configured object storages for the workspace (default + secondary).").option("--json", "Output as JSON (for piping to jq)").action(listStorages).command("files", "List files in an object storage. Optionally filter by prefix.").alias("ls").arguments("[prefix:string]").option("--json", "Output as JSON (for piping to jq)").option("--max-keys <maxKeys:number>", "Page size (default 100)").option("--marker <marker:string>", "Pagination marker from a previous response").option("--storage <storage:string>", "Secondary storage name (omit for the workspace default)").action(listFiles).command("upload", "Upload a local file to object storage at the given file key.").arguments("<local_path:string> <file_key:string>").option("--storage <storage:string>", "Secondary storage name").option("--content-type <contentType:string>", "Content-Type header to set on the object").option("--content-disposition <contentDisposition:string>", "Content-Disposition header to set on the object").action(upload).command("download", "Download an object to a local file (or stdout). Default output path is the basename of the file key in the current directory.").arguments("<file_key:string> [output_path:string]").option("--storage <storage:string>", "Secondary storage name").option("--stdout", "Write file contents to stdout instead of a file").action(download).command("delete", "Delete an object from object storage. Prompts for confirmation unless --yes is set.").arguments("<file_key:string>").option("--storage <storage:string>", "Secondary storage name").option("--yes", "Skip the confirmation prompt").action(del).command("move", "Move an object within the same storage (rename or relocate by key).").arguments("<src_file_key:string> <dest_file_key:string>").option("--storage <storage:string>", "Secondary storage name").action(move).command("info", "Show metadata (size, mime, last-modified) for an object.").arguments("<file_key:string>").option("--json", "Output as JSON (for piping to jq)").option("--storage <storage:string>", "Secondary storage name").action(info2).command("preview", "Preview the contents of an object (text/CSV). Use --bytes-from / --bytes-length to peek at a slice of binary files.").arguments("<file_key:string>").option("--storage <storage:string>", "Secondary storage name").option("--mime <mime:string>", "Override the detected mime type (e.g. text/csv)").option("--bytes-from <bytesFrom:number>", "Start offset in bytes").option("--bytes-length <bytesLength:number>", "Number of bytes to read").option("--csv-separator <csvSeparator:string>", "CSV column separator (default ,)").option("--csv-header", "Treat the first CSV row as a header").action(preview3);
94726
+ var object_storage_default = command43;
94204
94727
 
94205
94728
  // src/main.ts
94206
94729
  await init_context();
@@ -94220,7 +94743,7 @@ async function checkVersionSafe(cmd) {
94220
94743
  }
94221
94744
  mainCommand.version(`${currentVersion} (New version available: ${latestVersion}. Run '${mainCommand.getName()} upgrade' to upgrade to the latest version!)`);
94222
94745
  }
94223
- var command43 = new Command().name("wmill").action(() => info(`Welcome to Windmill CLI ${VERSION}. Use -h for help.`)).description("Windmill CLI").globalOption("--workspace <workspace:string>", "Specify the target workspace. This overrides the default workspace.").globalOption("--debug --verbose", "Show debug/verbose logs").globalOption("--show-diffs", "Show diff informations when syncing (may show sensitive informations)").globalOption("--token <token:string>", "Specify an API token. This will override any stored token.").globalOption("--base-url <baseUrl:string>", "Specify the base URL of the API. If used, --token and --workspace are required and no local remote/workspace already set will be used.").globalOption("--config-dir <configDir:string>", "Specify a custom config directory. Overrides WMILL_CONFIG_DIR environment variable and default ~/.config location.").env("HEADERS <headers:string>", `Specify headers to use for all requests. e.g: "HEADERS='h1: v1, h2: v2'"`).version(VERSION).versionOption(false).helpOption("-h, --help", "Show this help.", {
94746
+ var command44 = new Command().name("wmill").action(() => info(`Welcome to Windmill CLI ${VERSION}. Use -h for help.`)).description("Windmill CLI").globalOption("--workspace <workspace:string>", "Specify the target workspace. This overrides the default workspace.").globalOption("--debug --verbose", "Show debug/verbose logs").globalOption("--show-diffs", "Show diff informations when syncing (may show sensitive informations)").globalOption("--token <token:string>", "Specify an API token. This will override any stored token.").globalOption("--base-url <baseUrl:string>", "Specify the base URL of the API. If used, --token and --workspace are required and no local remote/workspace already set will be used.").globalOption("--config-dir <configDir:string>", "Specify a custom config directory. Overrides WMILL_CONFIG_DIR environment variable and default ~/.config location.").env("HEADERS <headers:string>", `Specify headers to use for all requests. e.g: "HEADERS='h1: v1, h2: v2'"`).version(VERSION).versionOption(false).helpOption("-h, --help", "Show this help.", {
94224
94747
  action: async function() {
94225
94748
  const self2 = this;
94226
94749
  const long = self2.getRawArgs().includes(`--${self2.getHelpOption()?.name}`);
@@ -94232,7 +94755,7 @@ var command43 = new Command().name("wmill").action(() => info(`Welcome to Windmi
94232
94755
  self2.showHelp({ long });
94233
94756
  self2.exit();
94234
94757
  }
94235
- }).command("init", init_default).command("refresh", refresh_default).command("app", app_default).command("flow", flow_default).command("script", script_default).command("workspace", workspace_default).command("resource", resource_default).command("resource-type", resource_type_default).command("user", user_default).command("variable", variable_default).command("hub", hub_default).command("folder", folder_default).command("schedule", schedule_default).command("trigger", trigger_default).command("dev", dev_default2).command("sync", sync_default).command("lint", lint_default).command("gitsync-settings", gitsync_settings_default).command("protection-rules", protection_rules_default).command("instance", instance_default).command("worker-groups", worker_groups_default).command("workers", workers_default).command("queues", queues_default).command("dependencies", dependencies_default).command("jobs", jobs_default).command("job", job_default).command("group", group_default).command("audit", audit_default).command("token", token_default).command("generate-metadata", generate_metadata_default).command("docs", docs_default).command("config", config_default).command("datatable", datatable_default).command("ducklake", ducklake_default).command("object-storage", object_storage_default).command("version --version", "Show version information").action(async (opts) => {
94758
+ }).command("init", init_default).command("refresh", refresh_default).command("app", app_default).command("flow", flow_default).command("script", script_default).command("workspace", workspace_default).command("resource", resource_default).command("resource-type", resource_type_default).command("user", user_default).command("variable", variable_default).command("hub", hub_default).command("folder", folder_default).command("schedule", schedule_default).command("trigger", trigger_default).command("dev", dev_default2).command("sync", sync_default).command("lint", lint_default).command("gitsync-settings", gitsync_settings_default).command("protection-rules", protection_rules_default).command("instance", instance_default).command("worker-groups", worker_groups_default).command("workers", workers_default).command("queues", queues_default).command("dependencies", dependencies_default).command("jobs", jobs_default).command("job", job_default).command("group", group_default).command("audit", audit_default).command("token", token_default).command("generate-metadata", generate_metadata_default).command("docs", docs_default).command("config", config_default).command("datatable", datatable_default).command("pipeline", pipeline_default).command("ducklake", ducklake_default).command("object-storage", object_storage_default).command("version --version", "Show version information").action(async (opts) => {
94236
94759
  console.log("CLI version: " + VERSION);
94237
94760
  try {
94238
94761
  const provider2 = new NpmProvider({ package: "windmill-cli" });
@@ -94262,20 +94785,20 @@ var command43 = new Command().name("wmill").action(() => info(`Welcome to Windmi
94262
94785
  error(e2);
94263
94786
  info("Try running with sudo and otherwise check the result of the command: npm uninstall windmill-cli && npm install -g windmill-cli");
94264
94787
  })).command("completions", new Command().description("Generate shell completions.").command("bash", new Command().description("Generate bash completions.").action(() => {
94265
- process.stdout.write(generateShellCompletions(command43, "bash") + `
94788
+ process.stdout.write(generateShellCompletions(command44, "bash") + `
94266
94789
  `);
94267
94790
  })).command("zsh", new Command().description("Generate zsh completions.").action(() => {
94268
- process.stdout.write(generateShellCompletions(command43, "zsh") + `
94791
+ process.stdout.write(generateShellCompletions(command44, "zsh") + `
94269
94792
  `);
94270
94793
  })).command("fish", new Command().description("Generate fish completions.").action(() => {
94271
- process.stdout.write(generateShellCompletions(command43, "fish") + `
94794
+ process.stdout.write(generateShellCompletions(command44, "fish") + `
94272
94795
  `);
94273
94796
  })));
94274
94797
  async function main2() {
94275
94798
  try {
94276
94799
  const args = process.argv.slice(2);
94277
94800
  if (args.length === 0) {
94278
- command43.showHelp();
94801
+ command44.showHelp();
94279
94802
  }
94280
94803
  const LOG_LEVEL = args.includes("--verbose") || args.includes("--debug") ? "DEBUG" : "INFO";
94281
94804
  setShowDiffs(args.includes("--show-diffs"));
@@ -94295,7 +94818,7 @@ async function main2() {
94295
94818
  const { warnIfTsconfigStale: warnIfTsconfigStale2 } = await init_tsconfig().then(() => exports_tsconfig);
94296
94819
  await warnIfTsconfigStale2().catch(() => {});
94297
94820
  }
94298
- await command43.parse(args);
94821
+ await command44.parse(args);
94299
94822
  } catch (e2) {
94300
94823
  if (e2 && typeof e2 === "object" && "name" in e2 && e2.name === "ApiError") {
94301
94824
  const body = e2.body;
@@ -94331,7 +94854,7 @@ if (isMain()) {
94331
94854
  process.stdin.destroy();
94332
94855
  });
94333
94856
  }
94334
- var main_default = command43;
94857
+ var main_default = command44;
94335
94858
  export {
94336
94859
  add as workspaceAdd,
94337
94860
  workspace_default as workspace,
@@ -94347,6 +94870,7 @@ export {
94347
94870
  push4 as push,
94348
94871
  pull,
94349
94872
  protection_rules_default as protectionRules,
94873
+ pipeline_default as pipeline,
94350
94874
  object_storage_default as objectStorage,
94351
94875
  lint_default as lint,
94352
94876
  job_default as job,