windmill-cli 1.691.0 → 1.692.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.
- package/README.md +1 -0
- package/esm/main.js +1808 -300
- package/package.json +1 -1
package/esm/main.js
CHANGED
|
@@ -16224,6 +16224,14 @@ var execFile5, __dirname2, localXdgOpenPath, platform, arch, pTryEach = async (a
|
|
|
16224
16224
|
}
|
|
16225
16225
|
subprocess.unref();
|
|
16226
16226
|
return subprocess;
|
|
16227
|
+
}, open = (target, options) => {
|
|
16228
|
+
if (typeof target !== "string") {
|
|
16229
|
+
throw new TypeError("Expected a `target`");
|
|
16230
|
+
}
|
|
16231
|
+
return baseOpen({
|
|
16232
|
+
...options,
|
|
16233
|
+
target
|
|
16234
|
+
});
|
|
16227
16235
|
}, openApp = (name, options) => {
|
|
16228
16236
|
if (typeof name !== "string" && !Array.isArray(name)) {
|
|
16229
16237
|
throw new TypeError("Expected a valid `name`");
|
|
@@ -16239,7 +16247,7 @@ var execFile5, __dirname2, localXdgOpenPath, platform, arch, pTryEach = async (a
|
|
|
16239
16247
|
arguments: appArguments
|
|
16240
16248
|
}
|
|
16241
16249
|
});
|
|
16242
|
-
}, apps;
|
|
16250
|
+
}, apps, open_default;
|
|
16243
16251
|
var init_open = __esm(() => {
|
|
16244
16252
|
init_wsl_utils();
|
|
16245
16253
|
init_default_browser();
|
|
@@ -16285,6 +16293,7 @@ var init_open = __esm(() => {
|
|
|
16285
16293
|
}));
|
|
16286
16294
|
defineLazyProperty(apps, "browser", () => "browser");
|
|
16287
16295
|
defineLazyProperty(apps, "browserPrivate", () => "browserPrivate");
|
|
16296
|
+
open_default = open;
|
|
16288
16297
|
});
|
|
16289
16298
|
|
|
16290
16299
|
// node_modules/@cliffy/prompt/secret.js
|
|
@@ -16408,7 +16417,7 @@ async function browserLogin(baseUrl) {
|
|
|
16408
16417
|
const url = `${baseUrl}user/cli?port=${port}`;
|
|
16409
16418
|
info(`Login by going to ${url}`);
|
|
16410
16419
|
try {
|
|
16411
|
-
|
|
16420
|
+
open_default(url).catch((error2) => {
|
|
16412
16421
|
console.error(`Failed to open browser, please navigate to ${url}, error: ${error2}`);
|
|
16413
16422
|
});
|
|
16414
16423
|
info("Opened browser for you");
|
|
@@ -16701,7 +16710,7 @@ var init_OpenAPI = __esm(() => {
|
|
|
16701
16710
|
PASSWORD: undefined,
|
|
16702
16711
|
TOKEN: getEnv3("WM_TOKEN"),
|
|
16703
16712
|
USERNAME: undefined,
|
|
16704
|
-
VERSION: "1.
|
|
16713
|
+
VERSION: "1.692.0",
|
|
16705
16714
|
WITH_CREDENTIALS: true,
|
|
16706
16715
|
interceptors: {
|
|
16707
16716
|
request: new Interceptors,
|
|
@@ -26226,9 +26235,6 @@ function getFolderSuffixes() {
|
|
|
26226
26235
|
function getFolderSuffix(type) {
|
|
26227
26236
|
return getFolderSuffixes()[type];
|
|
26228
26237
|
}
|
|
26229
|
-
function getFolderSuffixWithSep(type) {
|
|
26230
|
-
return getFolderSuffixes()[type] + SEP2;
|
|
26231
|
-
}
|
|
26232
26238
|
function getMetadataFileName(type, format6) {
|
|
26233
26239
|
return METADATA_FILES[type][format6];
|
|
26234
26240
|
}
|
|
@@ -30232,6 +30238,74 @@ return schema
|
|
|
30232
30238
|
rawAppWmillTs_exports = /* @__PURE__ */ __export2({ default: () => rawAppWmillTs_default }, 1);
|
|
30233
30239
|
});
|
|
30234
30240
|
|
|
30241
|
+
// src/utils/port-probe.ts
|
|
30242
|
+
import { createServer as createServer2 } from "node:net";
|
|
30243
|
+
import { execSync as execSync4 } from "node:child_process";
|
|
30244
|
+
function isPortFree(port, host) {
|
|
30245
|
+
return new Promise((resolve6) => {
|
|
30246
|
+
const s = createServer2();
|
|
30247
|
+
s.once("error", (err) => {
|
|
30248
|
+
const code2 = err.code ?? "";
|
|
30249
|
+
resolve6(code2 !== "EADDRINUSE" && code2 !== "EACCES");
|
|
30250
|
+
});
|
|
30251
|
+
s.once("listening", () => s.close(() => resolve6(true)));
|
|
30252
|
+
s.listen(port, host);
|
|
30253
|
+
});
|
|
30254
|
+
}
|
|
30255
|
+
async function isPortFreeOnBothStacks(port) {
|
|
30256
|
+
if (!await isPortFree(port, "0.0.0.0"))
|
|
30257
|
+
return false;
|
|
30258
|
+
if (!await isPortFree(port, "::"))
|
|
30259
|
+
return false;
|
|
30260
|
+
return true;
|
|
30261
|
+
}
|
|
30262
|
+
function findPortHolder(port) {
|
|
30263
|
+
try {
|
|
30264
|
+
const out = execSync4(`lsof -nP -iTCP:${port} -sTCP:LISTEN -F pc 2>/dev/null`, {
|
|
30265
|
+
encoding: "utf-8",
|
|
30266
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
30267
|
+
});
|
|
30268
|
+
let pid;
|
|
30269
|
+
let cmd;
|
|
30270
|
+
for (const line of out.split(`
|
|
30271
|
+
`)) {
|
|
30272
|
+
if (line.startsWith("p"))
|
|
30273
|
+
pid = parseInt(line.slice(1), 10);
|
|
30274
|
+
else if (line.startsWith("c"))
|
|
30275
|
+
cmd = line.slice(1);
|
|
30276
|
+
if (pid && cmd)
|
|
30277
|
+
return { pid, command: cmd };
|
|
30278
|
+
}
|
|
30279
|
+
} catch {}
|
|
30280
|
+
try {
|
|
30281
|
+
const out = execSync4(`ss -ltnp 2>/dev/null | awk '$4 ~ /:${port}$/ { print $NF }'`, {
|
|
30282
|
+
encoding: "utf-8",
|
|
30283
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
30284
|
+
}).trim();
|
|
30285
|
+
const m = out.match(/\("([^"]+)",pid=(\d+)/);
|
|
30286
|
+
if (m)
|
|
30287
|
+
return { pid: parseInt(m[2], 10), command: m[1] };
|
|
30288
|
+
} catch {}
|
|
30289
|
+
return;
|
|
30290
|
+
}
|
|
30291
|
+
async function resolveBindPort(requested, flagLabel, log) {
|
|
30292
|
+
const MAX_SHIFT = 20;
|
|
30293
|
+
for (let port = requested;port < requested + MAX_SHIFT; port++) {
|
|
30294
|
+
if (await isPortFreeOnBothStacks(port)) {
|
|
30295
|
+
if (port !== requested) {
|
|
30296
|
+
const holder = findPortHolder(requested);
|
|
30297
|
+
const holderHint = holder ? ` (held by PID ${holder.pid} \`${holder.command}\`)` : "";
|
|
30298
|
+
log.warn(`Port ${requested} is already in use${holderHint}. Using port ${port} instead.`);
|
|
30299
|
+
log.info(`If you need port ${requested} stable (e.g. a launch.json entry pinned to it), stop the holder and re-run with ${flagLabel} ${requested}.`);
|
|
30300
|
+
}
|
|
30301
|
+
return port;
|
|
30302
|
+
}
|
|
30303
|
+
}
|
|
30304
|
+
throw new Error(`Could not find a free port in the range ${requested}-${requested + MAX_SHIFT - 1}. Stop a holder or pass ${flagLabel} <other>.`);
|
|
30305
|
+
}
|
|
30306
|
+
var BIND_HOST = "0.0.0.0";
|
|
30307
|
+
var init_port_probe = () => {};
|
|
30308
|
+
|
|
30235
30309
|
// node_modules/ws/lib/stream.js
|
|
30236
30310
|
var require_stream = __commonJS((exports, module) => {
|
|
30237
30311
|
var { Duplex } = __require("stream");
|
|
@@ -30296,7 +30370,7 @@ var require_stream = __commonJS((exports, module) => {
|
|
|
30296
30370
|
};
|
|
30297
30371
|
duplex._final = function(callback) {
|
|
30298
30372
|
if (ws.readyState === ws.CONNECTING) {
|
|
30299
|
-
ws.once("open", function
|
|
30373
|
+
ws.once("open", function open2() {
|
|
30300
30374
|
duplex._final(callback);
|
|
30301
30375
|
});
|
|
30302
30376
|
return;
|
|
@@ -30320,7 +30394,7 @@ var require_stream = __commonJS((exports, module) => {
|
|
|
30320
30394
|
};
|
|
30321
30395
|
duplex._write = function(chunk, encoding, callback) {
|
|
30322
30396
|
if (ws.readyState === ws.CONNECTING) {
|
|
30323
|
-
ws.once("open", function
|
|
30397
|
+
ws.once("open", function open2() {
|
|
30324
30398
|
duplex._write(chunk, encoding, callback);
|
|
30325
30399
|
});
|
|
30326
30400
|
return;
|
|
@@ -34923,10 +34997,10 @@ globstar while`, file, fr, pattern, pr, swallowee);
|
|
|
34923
34997
|
}
|
|
34924
34998
|
return filtered.join("/");
|
|
34925
34999
|
}).join("|");
|
|
34926
|
-
const [
|
|
34927
|
-
re = "^" +
|
|
35000
|
+
const [open2, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
|
|
35001
|
+
re = "^" + open2 + re + close + "$";
|
|
34928
35002
|
if (this.partial) {
|
|
34929
|
-
re = "^(?:\\/|" +
|
|
35003
|
+
re = "^(?:\\/|" + open2 + re.slice(1, -1) + close + ")$";
|
|
34930
35004
|
}
|
|
34931
35005
|
if (this.negate)
|
|
34932
35006
|
re = "^(?!" + re + ").+$";
|
|
@@ -61383,7 +61457,7 @@ import { Buffer as Buffer4 } from "node:buffer";
|
|
|
61383
61457
|
import { sep as SEP4 } from "node:path";
|
|
61384
61458
|
import * as path7 from "node:path";
|
|
61385
61459
|
import fs8 from "node:fs";
|
|
61386
|
-
import { execSync as
|
|
61460
|
+
import { execSync as execSync5 } from "node:child_process";
|
|
61387
61461
|
function isRawAppBackendPath2(filePath) {
|
|
61388
61462
|
return isRawAppBackendPath(filePath);
|
|
61389
61463
|
}
|
|
@@ -61484,7 +61558,7 @@ async function handleFile(path8, workspace, alreadySynced, message, opts, rawWor
|
|
|
61484
61558
|
let outputFiles = [];
|
|
61485
61559
|
if (codebase.customBundler) {
|
|
61486
61560
|
info(`Using custom bundler ${codebase.customBundler} for ${path8}`);
|
|
61487
|
-
bundleContent =
|
|
61561
|
+
bundleContent = execSync5(codebase.customBundler + " " + path8, {
|
|
61488
61562
|
maxBuffer: 1024 * 1024 * 50
|
|
61489
61563
|
}).toString();
|
|
61490
61564
|
info("Custom bundler executed for " + path8);
|
|
@@ -62177,7 +62251,7 @@ async function preview(opts, filePath) {
|
|
|
62177
62251
|
if (!opts.silent) {
|
|
62178
62252
|
info(`Using custom bundler ${codebase.customBundler} for preview`);
|
|
62179
62253
|
}
|
|
62180
|
-
bundledContent =
|
|
62254
|
+
bundledContent = execSync5(codebase.customBundler + " " + filePath, {
|
|
62181
62255
|
maxBuffer: 52428800
|
|
62182
62256
|
}).toString();
|
|
62183
62257
|
} else {
|
|
@@ -63321,8 +63395,8 @@ function getLanguageFromExtension(ext2, defaultTs = "bun") {
|
|
|
63321
63395
|
return;
|
|
63322
63396
|
}
|
|
63323
63397
|
function sanitizeForFilesystem(summary) {
|
|
63324
|
-
const name = summary.
|
|
63325
|
-
return WINDOWS_RESERVED.test(name) ? `_${name}` : name;
|
|
63398
|
+
const name = summary.replaceAll(" ", "_").replace(/[/\\:*?"<>|\x00-\x1f\x7f]/g, "").replace(/_+/g, "_").replace(/^[._]+|[._]+$/g, "");
|
|
63399
|
+
return WINDOWS_RESERVED.test(name.toLowerCase()) ? `_${name}` : name;
|
|
63326
63400
|
}
|
|
63327
63401
|
function newPathAssigner(defaultTs, options) {
|
|
63328
63402
|
const resolvedOptions = typeof defaultTs === "object" ? defaultTs : { defaultTs, skipInlineScriptSuffix: options?.skipInlineScriptSuffix };
|
|
@@ -63337,11 +63411,11 @@ function newPathAssigner(defaultTs, options) {
|
|
|
63337
63411
|
original_name = INLINE_SCRIPT_PREFIX;
|
|
63338
63412
|
name = `${INLINE_SCRIPT_PREFIX}_0`;
|
|
63339
63413
|
}
|
|
63340
|
-
while (seen_names.has(name)) {
|
|
63414
|
+
while (seen_names.has(name.toLowerCase())) {
|
|
63341
63415
|
counter++;
|
|
63342
63416
|
name = `${original_name}_${counter}`;
|
|
63343
63417
|
}
|
|
63344
|
-
seen_names.add(name);
|
|
63418
|
+
seen_names.add(name.toLowerCase());
|
|
63345
63419
|
const ext2 = getLanguageExtension(language, tsRuntime);
|
|
63346
63420
|
const suffix = skipInlineScriptSuffix ? "." : ".inline_script.";
|
|
63347
63421
|
return [`${name}${suffix}`, ext2];
|
|
@@ -63359,11 +63433,11 @@ function newRawAppPathAssigner(defaultTs) {
|
|
|
63359
63433
|
original_name = "runnable";
|
|
63360
63434
|
name = `runnable_0`;
|
|
63361
63435
|
}
|
|
63362
|
-
while (seen_names.has(name)) {
|
|
63436
|
+
while (seen_names.has(name.toLowerCase())) {
|
|
63363
63437
|
counter++;
|
|
63364
63438
|
name = `${original_name}_${counter}`;
|
|
63365
63439
|
}
|
|
63366
|
-
seen_names.add(name);
|
|
63440
|
+
seen_names.add(name.toLowerCase());
|
|
63367
63441
|
const ext2 = getLanguageExtension(language, defaultTs);
|
|
63368
63442
|
return [`${name}.`, ext2];
|
|
63369
63443
|
}
|
|
@@ -67552,12 +67626,24 @@ __export(exports_raw_apps, {
|
|
|
67552
67626
|
import { sep as SEP10 } from "node:path";
|
|
67553
67627
|
import path12 from "node:path";
|
|
67554
67628
|
import { readdir as readdir6 } from "node:fs/promises";
|
|
67629
|
+
async function readSiblingLock(backendPath, runnableId, allFiles) {
|
|
67630
|
+
const target = `${runnableId.toLowerCase()}.lock`;
|
|
67631
|
+
const lockFile = allFiles.find((f) => f.toLowerCase() === target);
|
|
67632
|
+
if (!lockFile)
|
|
67633
|
+
return;
|
|
67634
|
+
try {
|
|
67635
|
+
return await readTextFile(path12.join(backendPath, lockFile));
|
|
67636
|
+
} catch {
|
|
67637
|
+
return;
|
|
67638
|
+
}
|
|
67639
|
+
}
|
|
67555
67640
|
async function findRunnableContentFile(backendPath, runnableId, allFiles) {
|
|
67641
|
+
const runnableIdLower = runnableId.toLowerCase();
|
|
67556
67642
|
for (const fileName of allFiles) {
|
|
67557
67643
|
if (fileName.endsWith(".yaml") || fileName.endsWith(".lock")) {
|
|
67558
67644
|
continue;
|
|
67559
67645
|
}
|
|
67560
|
-
if (!fileName.startsWith(
|
|
67646
|
+
if (!fileName.toLowerCase().startsWith(runnableIdLower + ".")) {
|
|
67561
67647
|
continue;
|
|
67562
67648
|
}
|
|
67563
67649
|
const ext2 = fileName.substring(runnableId.length + 1);
|
|
@@ -67599,17 +67685,14 @@ async function loadRunnablesFromBackend(backendPath, defaultTs = "bun") {
|
|
|
67599
67685
|
continue;
|
|
67600
67686
|
}
|
|
67601
67687
|
const runnableId = fileName.replace(".yaml", "");
|
|
67602
|
-
processedIds.add(runnableId);
|
|
67688
|
+
processedIds.add(runnableId.toLowerCase());
|
|
67603
67689
|
const filePath = path12.join(backendPath, fileName);
|
|
67604
67690
|
const runnable = await yamlParseFile(filePath);
|
|
67605
67691
|
if (runnable?.type === "inline") {
|
|
67606
67692
|
const contentFile = await findRunnableContentFile(backendPath, runnableId, allFiles);
|
|
67607
67693
|
if (contentFile) {
|
|
67608
67694
|
const language = getLanguageFromExtension(contentFile.ext, defaultTs);
|
|
67609
|
-
|
|
67610
|
-
try {
|
|
67611
|
-
lock = await readTextFile(path12.join(backendPath, `${runnableId}.lock`));
|
|
67612
|
-
} catch {}
|
|
67695
|
+
const lock = await readSiblingLock(backendPath, runnableId, allFiles);
|
|
67613
67696
|
runnable.inlineScript = {
|
|
67614
67697
|
content: contentFile.content,
|
|
67615
67698
|
language,
|
|
@@ -67630,17 +67713,14 @@ async function loadRunnablesFromBackend(backendPath, defaultTs = "bun") {
|
|
|
67630
67713
|
if (!runnableId) {
|
|
67631
67714
|
continue;
|
|
67632
67715
|
}
|
|
67633
|
-
if (processedIds.has(runnableId)) {
|
|
67716
|
+
if (processedIds.has(runnableId.toLowerCase())) {
|
|
67634
67717
|
continue;
|
|
67635
67718
|
}
|
|
67636
|
-
processedIds.add(runnableId);
|
|
67719
|
+
processedIds.add(runnableId.toLowerCase());
|
|
67637
67720
|
const contentFile = await findRunnableContentFile(backendPath, runnableId, allFiles);
|
|
67638
67721
|
if (contentFile) {
|
|
67639
67722
|
const language = getLanguageFromExtension(contentFile.ext, defaultTs);
|
|
67640
|
-
|
|
67641
|
-
try {
|
|
67642
|
-
lock = await readTextFile(path12.join(backendPath, `${runnableId}.lock`));
|
|
67643
|
-
} catch {}
|
|
67723
|
+
const lock = await readSiblingLock(backendPath, runnableId, allFiles);
|
|
67644
67724
|
runnables[runnableId] = {
|
|
67645
67725
|
type: "inline",
|
|
67646
67726
|
inlineScript: {
|
|
@@ -68602,10 +68682,14 @@ async function dev(opts, appFolder) {
|
|
|
68602
68682
|
const rawApp = await yamlParseFile(rawAppPath);
|
|
68603
68683
|
const appPath = rawApp?.custom_path ?? "u/unknown/newapp";
|
|
68604
68684
|
const esbuild = await import("esbuild");
|
|
68605
|
-
const
|
|
68685
|
+
const host = opts.host ?? DEFAULT_HOST;
|
|
68686
|
+
const probeBothStacks = host === DEFAULT_HOST;
|
|
68687
|
+
const port = opts.port !== undefined ? probeBothStacks ? await resolveBindPort(opts.port, "--port", {
|
|
68688
|
+
info: (m) => info(m),
|
|
68689
|
+
warn: (m) => warn(m)
|
|
68690
|
+
}) : opts.port : await getPorts({
|
|
68606
68691
|
port: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((p) => p + DEFAULT_PORT)
|
|
68607
68692
|
});
|
|
68608
|
-
const host = opts.host ?? DEFAULT_HOST;
|
|
68609
68693
|
const shouldOpen = opts.open ?? true;
|
|
68610
68694
|
const frameworks = detectFrameworks(process16.cwd());
|
|
68611
68695
|
const defaultEntry = frameworks.svelte || frameworks.vue ? "index.ts" : "index.tsx";
|
|
@@ -69708,6 +69792,7 @@ var init_dev = __esm(async () => {
|
|
|
69708
69792
|
init_log();
|
|
69709
69793
|
init_lib_es();
|
|
69710
69794
|
init_get_port();
|
|
69795
|
+
init_port_probe();
|
|
69711
69796
|
init_open();
|
|
69712
69797
|
init_wrapper();
|
|
69713
69798
|
init_services_gen();
|
|
@@ -69874,8 +69959,9 @@ var init_lint2 = __esm(async () => {
|
|
|
69874
69959
|
});
|
|
69875
69960
|
|
|
69876
69961
|
// src/commands/app/new.ts
|
|
69877
|
-
import { stat as stat9, writeFile as writeFile10, mkdir as mkdir7 } from "node:fs/promises";
|
|
69962
|
+
import { stat as stat9, writeFile as writeFile10, mkdir as mkdir7, rm as rm3 } from "node:fs/promises";
|
|
69878
69963
|
import path17 from "node:path";
|
|
69964
|
+
import { execSync as execSync6, exec, execFile as execFile6 } from "node:child_process";
|
|
69879
69965
|
function validateAppPath(appPath) {
|
|
69880
69966
|
if (!appPath.startsWith("u/") && !appPath.startsWith("f/")) {
|
|
69881
69967
|
return {
|
|
@@ -69942,16 +70028,25 @@ async function newApp(opts) {
|
|
|
69942
70028
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
69943
70029
|
warn(colors.yellow(`Could not fetch datatables: ${errorMessage}`));
|
|
69944
70030
|
}
|
|
69945
|
-
|
|
69946
|
-
|
|
69947
|
-
|
|
69948
|
-
|
|
69949
|
-
|
|
69950
|
-
return "Summary cannot be empty";
|
|
69951
|
-
}
|
|
69952
|
-
return true;
|
|
70031
|
+
let summary;
|
|
70032
|
+
if (opts.summary !== undefined) {
|
|
70033
|
+
if (opts.summary.trim().length === 0) {
|
|
70034
|
+
error(colors.red("--summary cannot be empty"));
|
|
70035
|
+
return;
|
|
69953
70036
|
}
|
|
69954
|
-
|
|
70037
|
+
summary = opts.summary;
|
|
70038
|
+
} else {
|
|
70039
|
+
summary = await Input.prompt({
|
|
70040
|
+
message: "App summary (short description):",
|
|
70041
|
+
minLength: 1,
|
|
70042
|
+
validate: (value) => {
|
|
70043
|
+
if (value.trim().length === 0) {
|
|
70044
|
+
return "Summary cannot be empty";
|
|
70045
|
+
}
|
|
70046
|
+
return true;
|
|
70047
|
+
}
|
|
70048
|
+
});
|
|
70049
|
+
}
|
|
69955
70050
|
const buildPathSuggestions = (input) => {
|
|
69956
70051
|
const suggestions = [];
|
|
69957
70052
|
if (input.length < 2) {
|
|
@@ -69968,27 +70063,46 @@ async function newApp(opts) {
|
|
|
69968
70063
|
return suggestions;
|
|
69969
70064
|
};
|
|
69970
70065
|
let appPath;
|
|
69971
|
-
|
|
69972
|
-
|
|
69973
|
-
|
|
69974
|
-
|
|
69975
|
-
|
|
69976
|
-
}
|
|
69977
|
-
|
|
69978
|
-
|
|
69979
|
-
|
|
70066
|
+
if (opts.path !== undefined) {
|
|
70067
|
+
const validation = validateAppPath(opts.path);
|
|
70068
|
+
if (!validation.valid) {
|
|
70069
|
+
error(colors.red(`Invalid --path: ${validation.error}`));
|
|
70070
|
+
return;
|
|
70071
|
+
}
|
|
70072
|
+
appPath = opts.path;
|
|
70073
|
+
} else {
|
|
70074
|
+
while (true) {
|
|
70075
|
+
appPath = await Input.prompt({
|
|
70076
|
+
message: "App path (e.g., f/my_folder/my_app or u/username/my_app):",
|
|
70077
|
+
minLength: 1,
|
|
70078
|
+
suggestions: buildPathSuggestions
|
|
70079
|
+
});
|
|
70080
|
+
const validation = validateAppPath(appPath);
|
|
70081
|
+
if (validation.valid) {
|
|
70082
|
+
break;
|
|
70083
|
+
}
|
|
70084
|
+
error(colors.red(`Invalid path: ${validation.error}`));
|
|
69980
70085
|
}
|
|
69981
|
-
error(colors.red(`Invalid path: ${validation.error}`));
|
|
69982
70086
|
}
|
|
69983
|
-
const
|
|
69984
|
-
|
|
69985
|
-
|
|
69986
|
-
|
|
69987
|
-
|
|
69988
|
-
|
|
69989
|
-
|
|
69990
|
-
|
|
69991
|
-
}
|
|
70087
|
+
const VALID_FRAMEWORKS = ["react19", "react18", "svelte5", "vue"];
|
|
70088
|
+
let framework;
|
|
70089
|
+
if (opts.framework !== undefined) {
|
|
70090
|
+
if (!VALID_FRAMEWORKS.includes(opts.framework)) {
|
|
70091
|
+
error(colors.red(`Invalid --framework: ${opts.framework}. Must be one of: ${VALID_FRAMEWORKS.join(", ")}`));
|
|
70092
|
+
return;
|
|
70093
|
+
}
|
|
70094
|
+
framework = opts.framework;
|
|
70095
|
+
} else {
|
|
70096
|
+
framework = await Select.prompt({
|
|
70097
|
+
message: "Select a framework:",
|
|
70098
|
+
options: [
|
|
70099
|
+
{ name: "React 19 (Recommended)", value: "react19" },
|
|
70100
|
+
{ name: "React 18", value: "react18" },
|
|
70101
|
+
{ name: "Svelte 5", value: "svelte5" },
|
|
70102
|
+
{ name: "Vue 3", value: "vue" }
|
|
70103
|
+
]
|
|
70104
|
+
});
|
|
70105
|
+
}
|
|
69992
70106
|
const template = templates[framework];
|
|
69993
70107
|
if (!template) {
|
|
69994
70108
|
error(colors.red(`Unknown framework: ${framework}`));
|
|
@@ -69997,7 +70111,29 @@ async function newApp(opts) {
|
|
|
69997
70111
|
let dataConfig = {};
|
|
69998
70112
|
let createSchemaSQL;
|
|
69999
70113
|
let schemaName;
|
|
70000
|
-
|
|
70114
|
+
const nonInteractive = opts.summary !== undefined || opts.path !== undefined || opts.framework !== undefined;
|
|
70115
|
+
if (opts.datatable !== undefined) {
|
|
70116
|
+
if (datatables.length > 0 && !datatables.includes(opts.datatable)) {
|
|
70117
|
+
warn(colors.yellow(`--datatable '${opts.datatable}' is not in the workspace's datatable list (${datatables.join(", ")}). Continuing anyway.`));
|
|
70118
|
+
}
|
|
70119
|
+
dataConfig.datatable = opts.datatable;
|
|
70120
|
+
if (opts.schema !== undefined) {
|
|
70121
|
+
if (!/^[a-z_][a-z0-9_]*$/.test(opts.schema)) {
|
|
70122
|
+
error(colors.red(`--schema must start with a letter or underscore and contain only lowercase letters, numbers, and underscores: ${opts.schema}`));
|
|
70123
|
+
return;
|
|
70124
|
+
}
|
|
70125
|
+
schemaName = opts.schema;
|
|
70126
|
+
dataConfig.schema = schemaName;
|
|
70127
|
+
const existingSchemas = datatableSchemas.get(opts.datatable) ?? [];
|
|
70128
|
+
if (!existingSchemas.includes(schemaName)) {
|
|
70129
|
+
createSchemaSQL = `-- Create schema for ${summary}
|
|
70130
|
+
-- This will be executed when you run 'wmill app dev' and confirm in the modal
|
|
70131
|
+
CREATE SCHEMA IF NOT EXISTS ${schemaName};
|
|
70132
|
+
`;
|
|
70133
|
+
}
|
|
70134
|
+
}
|
|
70135
|
+
dataConfig.tables = [];
|
|
70136
|
+
} else if (nonInteractive) {} else if (datatables.length > 0) {
|
|
70001
70137
|
info("");
|
|
70002
70138
|
info(colors.bold.cyan("Data Configuration"));
|
|
70003
70139
|
info(colors.gray("Configure datatables to enable AI to create and query database tables."));
|
|
@@ -70081,17 +70217,29 @@ CREATE SCHEMA IF NOT EXISTS ${schemaName};
|
|
|
70081
70217
|
await loadNonDottedPathsSetting();
|
|
70082
70218
|
const folderName2 = buildFolderPath(appPath, "raw_app");
|
|
70083
70219
|
const appDir = path17.join(process.cwd(), folderName2);
|
|
70220
|
+
let dirExists = false;
|
|
70084
70221
|
try {
|
|
70085
70222
|
await stat9(appDir);
|
|
70086
|
-
|
|
70087
|
-
|
|
70088
|
-
|
|
70089
|
-
|
|
70090
|
-
|
|
70091
|
-
|
|
70223
|
+
dirExists = true;
|
|
70224
|
+
} catch {}
|
|
70225
|
+
if (dirExists) {
|
|
70226
|
+
if (opts.overwrite) {
|
|
70227
|
+
warn(colors.yellow(`Overwriting existing '${folderName2}' (--overwrite)`));
|
|
70228
|
+
} else if (nonInteractive) {
|
|
70229
|
+
error(colors.red(`Directory '${folderName2}' already exists. Pass --overwrite to replace it.`));
|
|
70092
70230
|
return;
|
|
70231
|
+
} else {
|
|
70232
|
+
const overwrite = await Confirm.prompt({
|
|
70233
|
+
message: `Directory '${folderName2}' already exists. Overwrite?`,
|
|
70234
|
+
default: false
|
|
70235
|
+
});
|
|
70236
|
+
if (!overwrite) {
|
|
70237
|
+
info(colors.yellow("Aborted."));
|
|
70238
|
+
return;
|
|
70239
|
+
}
|
|
70093
70240
|
}
|
|
70094
|
-
|
|
70241
|
+
await rm3(appDir, { recursive: true, force: true });
|
|
70242
|
+
}
|
|
70095
70243
|
await mkdir7(appDir, { recursive: true });
|
|
70096
70244
|
await mkdir7(path17.join(appDir, "backend"), { recursive: true });
|
|
70097
70245
|
await mkdir7(path17.join(appDir, "sql_to_apply"), { recursive: true });
|
|
@@ -70196,6 +70344,69 @@ This folder is for SQL migration files that will be applied to datatables during
|
|
|
70196
70344
|
}
|
|
70197
70345
|
info("");
|
|
70198
70346
|
info(colors.gray(" 4. wmill sync push (to deploy when ready)"));
|
|
70347
|
+
let hasClaudeDesktop = false;
|
|
70348
|
+
if (process.platform === "darwin") {
|
|
70349
|
+
try {
|
|
70350
|
+
execSync6("ls /Applications/Claude.app", { stdio: "ignore" });
|
|
70351
|
+
hasClaudeDesktop = true;
|
|
70352
|
+
} catch {}
|
|
70353
|
+
}
|
|
70354
|
+
if (hasClaudeDesktop && !nonInteractive && opts.openInDesktop !== false) {
|
|
70355
|
+
info("");
|
|
70356
|
+
const openInDesktop = await Confirm.prompt({
|
|
70357
|
+
message: "Open in Claude Desktop?",
|
|
70358
|
+
default: true
|
|
70359
|
+
});
|
|
70360
|
+
if (openInDesktop) {
|
|
70361
|
+
try {
|
|
70362
|
+
const absAppDir = path17.resolve(appDir);
|
|
70363
|
+
const claudeDir = path17.join(absAppDir, ".claude");
|
|
70364
|
+
const launchPath = path17.join(claudeDir, "launch.json");
|
|
70365
|
+
if (!await stat9(launchPath).catch(() => null)) {
|
|
70366
|
+
const launchJson = JSON.stringify({
|
|
70367
|
+
version: "0.0.1",
|
|
70368
|
+
configurations: [{
|
|
70369
|
+
name: `windmill: ${appPath}`,
|
|
70370
|
+
runtimeExecutable: "bash",
|
|
70371
|
+
runtimeArgs: ["-c", "wmill app dev --no-open --port ${PORT:-4000}"],
|
|
70372
|
+
port: 4000,
|
|
70373
|
+
autoPort: true
|
|
70374
|
+
}]
|
|
70375
|
+
}, null, 2) + `
|
|
70376
|
+
`;
|
|
70377
|
+
await mkdir7(claudeDir, { recursive: true });
|
|
70378
|
+
await writeFile10(launchPath, launchJson, "utf-8");
|
|
70379
|
+
info(colors.gray(`Seeded ${path17.relative(process.cwd(), launchPath)}`));
|
|
70380
|
+
}
|
|
70381
|
+
const sessionId = crypto.randomUUID();
|
|
70382
|
+
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
70383
|
+
let i = 0;
|
|
70384
|
+
const spinner = setInterval(() => {
|
|
70385
|
+
process.stdout.write(`\r${colors.gray(`${frames[i++ % frames.length]} Creating Claude session...`)}`);
|
|
70386
|
+
}, 80);
|
|
70387
|
+
try {
|
|
70388
|
+
await new Promise((resolve8, reject) => {
|
|
70389
|
+
exec(`claude --session-id "${sessionId}" -p "Say: Your app is ready, click on preview to test it!"`, { cwd: absAppDir }, (error2) => error2 ? reject(error2) : resolve8());
|
|
70390
|
+
});
|
|
70391
|
+
} finally {
|
|
70392
|
+
clearInterval(spinner);
|
|
70393
|
+
process.stdout.write("\r" + " ".repeat(40) + "\r");
|
|
70394
|
+
}
|
|
70395
|
+
const deepLink = `claude://resume?session=${sessionId}&cwd=${encodeURIComponent(absAppDir)}`;
|
|
70396
|
+
execFile6("open", [deepLink], (err) => {
|
|
70397
|
+
if (err) {
|
|
70398
|
+
warn(colors.yellow(`Could not open Claude Desktop deep link (${err.message}). Open it manually: ${deepLink}`));
|
|
70399
|
+
} else {
|
|
70400
|
+
info(colors.bold.green("Opened in Claude Desktop!"));
|
|
70401
|
+
}
|
|
70402
|
+
});
|
|
70403
|
+
} catch (error2) {
|
|
70404
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
70405
|
+
warn(colors.yellow(`Could not open in Claude Desktop: ${errorMessage}`));
|
|
70406
|
+
info(colors.gray("You can manually run: cd " + folderName2 + " && claude"));
|
|
70407
|
+
}
|
|
70408
|
+
}
|
|
70409
|
+
}
|
|
70199
70410
|
}
|
|
70200
70411
|
var import_yaml22, reactIndex = `
|
|
70201
70412
|
import React from 'react'
|
|
@@ -70266,7 +70477,18 @@ const msg = ref('world');
|
|
|
70266
70477
|
import App from './App.vue'
|
|
70267
70478
|
import "./index.css";
|
|
70268
70479
|
|
|
70269
|
-
createApp(App).mount('#root')`, indexCss =
|
|
70480
|
+
createApp(App).mount('#root')`, indexCss = `body {
|
|
70481
|
+
margin: 0;
|
|
70482
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
70483
|
+
background-color: #f5f5f5;
|
|
70484
|
+
color: #1a1a1a;
|
|
70485
|
+
}
|
|
70486
|
+
|
|
70487
|
+
#root {
|
|
70488
|
+
padding: 24px;
|
|
70489
|
+
}
|
|
70490
|
+
|
|
70491
|
+
.myclass {
|
|
70270
70492
|
border: 1px solid gray;
|
|
70271
70493
|
padding: 2px;
|
|
70272
70494
|
}`, templates, command11, new_default;
|
|
@@ -70354,7 +70576,7 @@ var init_new = __esm(async () => {
|
|
|
70354
70576
|
}
|
|
70355
70577
|
}
|
|
70356
70578
|
};
|
|
70357
|
-
command11 = new Command().description("create a new raw app from a template").action(newApp);
|
|
70579
|
+
command11 = new Command().description("create a new raw app from a template").option("--summary <summary:string>", "App summary (short description). Skips the prompt when provided. Triggers non-interactive mode.").option("--path <path:string>", "App path (e.g., f/folder/my_app or u/username/my_app). Skips the prompt when provided. Triggers non-interactive mode.").option("--framework <framework:string>", "Framework template: react19 | react18 | svelte5 | vue. Skips the prompt when provided. Triggers non-interactive mode.").option("--datatable <datatable:string>", "Datatable to wire up. Without this flag in non-interactive mode, no datatable is configured.").option("--schema <schema:string>", "Schema to use with --datatable. Created (CREATE SCHEMA IF NOT EXISTS) if it doesn't already exist.").option("--overwrite", "Overwrite the target directory if it already exists, without prompting.").option("--no-open-in-desktop", "Do not prompt to open the new app in Claude Desktop.").action(newApp);
|
|
70358
70580
|
new_default = command11;
|
|
70359
70581
|
});
|
|
70360
70582
|
|
|
@@ -71820,7 +72042,7 @@ var init_settings = __esm(async () => {
|
|
|
71820
72042
|
});
|
|
71821
72043
|
|
|
71822
72044
|
// src/commands/instance/instance.ts
|
|
71823
|
-
import { writeFile as writeFile15, readdir as readdir9, mkdir as mkdir11, rm as
|
|
72045
|
+
import { writeFile as writeFile15, readdir as readdir9, mkdir as mkdir11, rm as rm4, stat as stat14 } from "node:fs/promises";
|
|
71824
72046
|
import { appendFile } from "node:fs/promises";
|
|
71825
72047
|
import * as path18 from "node:path";
|
|
71826
72048
|
async function allInstances() {
|
|
@@ -72086,7 +72308,7 @@ Pulling workspace ` + remoteWorkspace.id);
|
|
|
72086
72308
|
if (confirmDelete) {
|
|
72087
72309
|
for (const workspace of localWorkspacesToDelete) {
|
|
72088
72310
|
await removeWorkspace(workspace.id, false, {});
|
|
72089
|
-
await
|
|
72311
|
+
await rm4(path18.join(rootDir, workspace.dir), {
|
|
72090
72312
|
recursive: true
|
|
72091
72313
|
});
|
|
72092
72314
|
}
|
|
@@ -74170,6 +74392,10 @@ async function bootstrap2(opts, flowPath) {
|
|
|
74170
74392
|
const metadataFile = getMetadataFileName("flow", "yaml");
|
|
74171
74393
|
const flowYamlPath = `${flowDirFullPath}/${metadataFile}`;
|
|
74172
74394
|
writeFileSync6(flowYamlPath, newFlowDefinitionYaml, { flag: "wx", encoding: "utf-8" });
|
|
74395
|
+
info(colors.green(`Created flow at ${flowDirFullPath}`));
|
|
74396
|
+
info("");
|
|
74397
|
+
info(colors.bold("To preview this flow:"));
|
|
74398
|
+
info(colors.gray(` wmill dev --path ${flowPath}`));
|
|
74173
74399
|
}
|
|
74174
74400
|
async function history2(opts, flowPath) {
|
|
74175
74401
|
if (opts.json)
|
|
@@ -75218,22 +75444,22 @@ var init_gitsync_settings = __esm(async () => {
|
|
|
75218
75444
|
async function uploadScripts(tree, workspace) {
|
|
75219
75445
|
const scriptHashes = {};
|
|
75220
75446
|
const workspaceDeps = [];
|
|
75221
|
-
for (const
|
|
75222
|
-
const content = tree.getContent(
|
|
75223
|
-
const itemType = tree.getItemType(
|
|
75447
|
+
for (const path21 of tree.allPaths()) {
|
|
75448
|
+
const content = tree.getContent(path21);
|
|
75449
|
+
const itemType = tree.getItemType(path21);
|
|
75224
75450
|
if (itemType === "dependencies") {
|
|
75225
75451
|
if (content === undefined)
|
|
75226
75452
|
continue;
|
|
75227
|
-
const info2 = workspaceDependenciesPathToLanguageAndFilename(
|
|
75453
|
+
const info2 = workspaceDependenciesPathToLanguageAndFilename(path21);
|
|
75228
75454
|
if (info2) {
|
|
75229
75455
|
const hash2 = await generateHash(content);
|
|
75230
|
-
workspaceDeps.push({ path:
|
|
75456
|
+
workspaceDeps.push({ path: path21, language: info2.language, name: info2.name, hash: hash2 });
|
|
75231
75457
|
}
|
|
75232
75458
|
} else if (itemType === "script") {
|
|
75233
75459
|
if (!content)
|
|
75234
75460
|
continue;
|
|
75235
75461
|
const hash2 = await generateHash(content);
|
|
75236
|
-
scriptHashes[
|
|
75462
|
+
scriptHashes[path21] = hash2;
|
|
75237
75463
|
}
|
|
75238
75464
|
}
|
|
75239
75465
|
if (Object.keys(scriptHashes).length === 0 && workspaceDeps.length === 0)
|
|
@@ -75245,19 +75471,19 @@ async function uploadScripts(tree, workspace) {
|
|
|
75245
75471
|
workspace_deps: workspaceDeps
|
|
75246
75472
|
}
|
|
75247
75473
|
});
|
|
75248
|
-
for (const
|
|
75249
|
-
const content = tree.getContent(
|
|
75250
|
-
const itemType = tree.getItemType(
|
|
75474
|
+
for (const path21 of mismatched) {
|
|
75475
|
+
const content = tree.getContent(path21);
|
|
75476
|
+
const itemType = tree.getItemType(path21);
|
|
75251
75477
|
if (itemType === "dependencies") {
|
|
75252
75478
|
if (content !== undefined) {
|
|
75253
|
-
tree.setContentHash(
|
|
75479
|
+
tree.setContentHash(path21, "mismatched");
|
|
75254
75480
|
}
|
|
75255
75481
|
} else if (content) {
|
|
75256
75482
|
const hash2 = await storeRawScriptTemp({
|
|
75257
75483
|
workspace: workspace.workspaceId,
|
|
75258
75484
|
requestBody: content
|
|
75259
75485
|
});
|
|
75260
|
-
tree.setContentHash(
|
|
75486
|
+
tree.setContentHash(path21, hash2);
|
|
75261
75487
|
}
|
|
75262
75488
|
}
|
|
75263
75489
|
}
|
|
@@ -75268,12 +75494,12 @@ class DoubleLinkedDependencyTree {
|
|
|
75268
75494
|
setWorkspaceDeps(deps) {
|
|
75269
75495
|
this.workspaceDeps = deps;
|
|
75270
75496
|
}
|
|
75271
|
-
async addNode(
|
|
75497
|
+
async addNode(path21, content, language, metadata, imports, itemType, folder, originalPath, isDirectlyStale, isRawApp) {
|
|
75272
75498
|
const hasWorkspaceDeps = itemType === "script" || itemType === "inline_script";
|
|
75273
75499
|
const filteredDeps = hasWorkspaceDeps ? filterWorkspaceDependencies(this.workspaceDeps, content, language) : {};
|
|
75274
75500
|
const stalenessHash = await generateScriptHash({}, content, metadata);
|
|
75275
|
-
if (!this.nodes.has(
|
|
75276
|
-
this.nodes.set(
|
|
75501
|
+
if (!this.nodes.has(path21)) {
|
|
75502
|
+
this.nodes.set(path21, {
|
|
75277
75503
|
content: "",
|
|
75278
75504
|
stalenessHash: "",
|
|
75279
75505
|
language: "deno",
|
|
@@ -75286,7 +75512,7 @@ class DoubleLinkedDependencyTree {
|
|
|
75286
75512
|
isDirectlyStale: false
|
|
75287
75513
|
});
|
|
75288
75514
|
}
|
|
75289
|
-
const node = this.nodes.get(
|
|
75515
|
+
const node = this.nodes.get(path21);
|
|
75290
75516
|
node.content = content;
|
|
75291
75517
|
node.stalenessHash = stalenessHash;
|
|
75292
75518
|
node.language = language;
|
|
@@ -75333,59 +75559,59 @@ class DoubleLinkedDependencyTree {
|
|
|
75333
75559
|
isDirectlyStale: false
|
|
75334
75560
|
});
|
|
75335
75561
|
}
|
|
75336
|
-
this.nodes.get(importPath).importedBy.add(
|
|
75562
|
+
this.nodes.get(importPath).importedBy.add(path21);
|
|
75337
75563
|
}
|
|
75338
75564
|
}
|
|
75339
|
-
getContent(
|
|
75340
|
-
return this.nodes.get(
|
|
75565
|
+
getContent(path21) {
|
|
75566
|
+
return this.nodes.get(path21)?.content;
|
|
75341
75567
|
}
|
|
75342
|
-
getStalenessHash(
|
|
75343
|
-
return this.nodes.get(
|
|
75568
|
+
getStalenessHash(path21) {
|
|
75569
|
+
return this.nodes.get(path21)?.stalenessHash;
|
|
75344
75570
|
}
|
|
75345
|
-
getContentHash(
|
|
75346
|
-
return this.nodes.get(
|
|
75571
|
+
getContentHash(path21) {
|
|
75572
|
+
return this.nodes.get(path21)?.contentHash;
|
|
75347
75573
|
}
|
|
75348
|
-
setContentHash(
|
|
75349
|
-
const node = this.nodes.get(
|
|
75574
|
+
setContentHash(path21, hash2) {
|
|
75575
|
+
const node = this.nodes.get(path21);
|
|
75350
75576
|
if (node) {
|
|
75351
75577
|
node.contentHash = hash2;
|
|
75352
75578
|
}
|
|
75353
75579
|
}
|
|
75354
|
-
getLanguage(
|
|
75355
|
-
return this.nodes.get(
|
|
75580
|
+
getLanguage(path21) {
|
|
75581
|
+
return this.nodes.get(path21)?.language;
|
|
75356
75582
|
}
|
|
75357
|
-
getMetadata(
|
|
75358
|
-
return this.nodes.get(
|
|
75583
|
+
getMetadata(path21) {
|
|
75584
|
+
return this.nodes.get(path21)?.metadata;
|
|
75359
75585
|
}
|
|
75360
|
-
getStaleReason(
|
|
75361
|
-
return this.nodes.get(
|
|
75586
|
+
getStaleReason(path21) {
|
|
75587
|
+
return this.nodes.get(path21)?.staleReason;
|
|
75362
75588
|
}
|
|
75363
|
-
getItemType(
|
|
75364
|
-
return this.nodes.get(
|
|
75589
|
+
getItemType(path21) {
|
|
75590
|
+
return this.nodes.get(path21)?.itemType;
|
|
75365
75591
|
}
|
|
75366
|
-
getFolder(
|
|
75367
|
-
return this.nodes.get(
|
|
75592
|
+
getFolder(path21) {
|
|
75593
|
+
return this.nodes.get(path21)?.folder;
|
|
75368
75594
|
}
|
|
75369
|
-
getIsRawApp(
|
|
75370
|
-
return this.nodes.get(
|
|
75595
|
+
getIsRawApp(path21) {
|
|
75596
|
+
return this.nodes.get(path21)?.isRawApp;
|
|
75371
75597
|
}
|
|
75372
|
-
getIsDirectlyStale(
|
|
75373
|
-
return this.nodes.get(
|
|
75598
|
+
getIsDirectlyStale(path21) {
|
|
75599
|
+
return this.nodes.get(path21)?.isDirectlyStale ?? false;
|
|
75374
75600
|
}
|
|
75375
|
-
getOriginalPath(
|
|
75376
|
-
return this.nodes.get(
|
|
75601
|
+
getOriginalPath(path21) {
|
|
75602
|
+
return this.nodes.get(path21)?.originalPath;
|
|
75377
75603
|
}
|
|
75378
|
-
getImports(
|
|
75379
|
-
return this.nodes.get(
|
|
75604
|
+
getImports(path21) {
|
|
75605
|
+
return this.nodes.get(path21)?.imports;
|
|
75380
75606
|
}
|
|
75381
|
-
isStale(
|
|
75382
|
-
return this.nodes.get(
|
|
75607
|
+
isStale(path21) {
|
|
75608
|
+
return this.nodes.get(path21)?.staleReason !== undefined;
|
|
75383
75609
|
}
|
|
75384
75610
|
propagateStaleness() {
|
|
75385
75611
|
const directlyStale = new Set;
|
|
75386
|
-
for (const [
|
|
75612
|
+
for (const [path21, node] of this.nodes.entries()) {
|
|
75387
75613
|
if (node.isDirectlyStale) {
|
|
75388
|
-
directlyStale.add(
|
|
75614
|
+
directlyStale.add(path21);
|
|
75389
75615
|
node.staleReason = "content changed";
|
|
75390
75616
|
}
|
|
75391
75617
|
}
|
|
@@ -75437,20 +75663,20 @@ class DoubleLinkedDependencyTree {
|
|
|
75437
75663
|
return this.nodes.keys();
|
|
75438
75664
|
}
|
|
75439
75665
|
*stalePaths() {
|
|
75440
|
-
for (const [
|
|
75666
|
+
for (const [path21, node] of this.nodes.entries()) {
|
|
75441
75667
|
if (node.staleReason) {
|
|
75442
|
-
yield
|
|
75668
|
+
yield path21;
|
|
75443
75669
|
}
|
|
75444
75670
|
}
|
|
75445
75671
|
}
|
|
75446
|
-
has(
|
|
75447
|
-
return this.nodes.has(
|
|
75672
|
+
has(path21) {
|
|
75673
|
+
return this.nodes.has(path21);
|
|
75448
75674
|
}
|
|
75449
75675
|
getMismatchedWorkspaceDeps() {
|
|
75450
75676
|
const result2 = {};
|
|
75451
|
-
for (const [
|
|
75677
|
+
for (const [path21, node] of this.nodes.entries()) {
|
|
75452
75678
|
if (node.itemType === "dependencies" && node.contentHash && node.content !== undefined) {
|
|
75453
|
-
result2[
|
|
75679
|
+
result2[path21] = node.content;
|
|
75454
75680
|
}
|
|
75455
75681
|
}
|
|
75456
75682
|
return result2;
|
|
@@ -75465,11 +75691,11 @@ class DoubleLinkedDependencyTree {
|
|
|
75465
75691
|
return result2;
|
|
75466
75692
|
}
|
|
75467
75693
|
async persistDepsHashes(depsPaths) {
|
|
75468
|
-
for (const
|
|
75469
|
-
const node = this.nodes.get(
|
|
75694
|
+
for (const path21 of depsPaths) {
|
|
75695
|
+
const node = this.nodes.get(path21);
|
|
75470
75696
|
if (node?.itemType === "dependencies" && node.content !== undefined) {
|
|
75471
|
-
const hash2 = await generateHash(node.content +
|
|
75472
|
-
await updateMetadataGlobalLock(
|
|
75697
|
+
const hash2 = await generateHash(node.content + path21);
|
|
75698
|
+
await updateMetadataGlobalLock(path21, hash2);
|
|
75473
75699
|
}
|
|
75474
75700
|
}
|
|
75475
75701
|
}
|
|
@@ -76861,9 +77087,11 @@ await init_lint();
|
|
|
76861
77087
|
init_mod3();
|
|
76862
77088
|
init_log();
|
|
76863
77089
|
init_wrapper();
|
|
76864
|
-
init_get_port();
|
|
76865
77090
|
init_open();
|
|
76866
77091
|
init_script_common();
|
|
77092
|
+
init_extractor();
|
|
77093
|
+
init_path_assigner();
|
|
77094
|
+
init_port_probe();
|
|
76867
77095
|
await __promiseAll([
|
|
76868
77096
|
init_yaml(),
|
|
76869
77097
|
init_utils(),
|
|
@@ -76878,13 +77106,223 @@ await __promiseAll([
|
|
|
76878
77106
|
init_codebase(),
|
|
76879
77107
|
init_local_path_scripts()
|
|
76880
77108
|
]);
|
|
77109
|
+
var import_yaml40 = __toESM(require_dist(), 1);
|
|
76881
77110
|
import { sep as SEP20 } from "node:path";
|
|
76882
77111
|
import * as http3 from "node:http";
|
|
76883
|
-
import
|
|
77112
|
+
import * as https from "node:https";
|
|
77113
|
+
import { access, readdir as readdir10, realpath, stat as stat17, unlink, writeFile as writeFile19 } from "node:fs/promises";
|
|
76884
77114
|
import { watch as watch2 } from "node:fs";
|
|
77115
|
+
import * as path20 from "node:path";
|
|
77116
|
+
import * as fs13 from "node:fs";
|
|
77117
|
+
|
|
77118
|
+
// src/commands/dev/pathscript-restore.ts
|
|
77119
|
+
var TAG_KEY = "_originalPathScript";
|
|
77120
|
+
function walkModules(modules, visitor) {
|
|
77121
|
+
for (const module of modules) {
|
|
77122
|
+
if (!module.value)
|
|
77123
|
+
continue;
|
|
77124
|
+
const val = module.value;
|
|
77125
|
+
if (val.type === "forloopflow" || val.type === "whileloopflow") {
|
|
77126
|
+
walkModules(val.modules, visitor);
|
|
77127
|
+
} else if (val.type === "branchall") {
|
|
77128
|
+
for (const branch of val.branches ?? []) {
|
|
77129
|
+
walkModules(branch.modules, visitor);
|
|
77130
|
+
}
|
|
77131
|
+
} else if (val.type === "branchone") {
|
|
77132
|
+
for (const branch of val.branches ?? []) {
|
|
77133
|
+
walkModules(branch.modules, visitor);
|
|
77134
|
+
}
|
|
77135
|
+
if (val.default) {
|
|
77136
|
+
walkModules(val.default, visitor);
|
|
77137
|
+
}
|
|
77138
|
+
} else if (val.type === "aiagent") {
|
|
77139
|
+
for (const tool of val.tools ?? []) {
|
|
77140
|
+
visitor.onTool(tool);
|
|
77141
|
+
}
|
|
77142
|
+
} else {
|
|
77143
|
+
visitor.onModule(module);
|
|
77144
|
+
}
|
|
77145
|
+
}
|
|
77146
|
+
}
|
|
77147
|
+
function walkFlow(flowValue, visitor) {
|
|
77148
|
+
if (flowValue?.modules)
|
|
77149
|
+
walkModules(flowValue.modules, visitor);
|
|
77150
|
+
if (flowValue?.failure_module)
|
|
77151
|
+
walkModules([flowValue.failure_module], visitor);
|
|
77152
|
+
if (flowValue?.preprocessor_module)
|
|
77153
|
+
walkModules([flowValue.preprocessor_module], visitor);
|
|
77154
|
+
}
|
|
77155
|
+
function snapshotPathScripts(flowValue) {
|
|
77156
|
+
walkFlow(flowValue, {
|
|
77157
|
+
onModule(module) {
|
|
77158
|
+
if (module.value.type === "script") {
|
|
77159
|
+
module[TAG_KEY] = JSON.parse(JSON.stringify(module.value));
|
|
77160
|
+
}
|
|
77161
|
+
},
|
|
77162
|
+
onTool(tool) {
|
|
77163
|
+
const tv = tool.value;
|
|
77164
|
+
if (tv && "tool_type" in tv && tv.tool_type === "flowmodule" && tv.type === "script") {
|
|
77165
|
+
tool[TAG_KEY] = JSON.parse(JSON.stringify(tv));
|
|
77166
|
+
}
|
|
77167
|
+
}
|
|
77168
|
+
});
|
|
77169
|
+
}
|
|
77170
|
+
function tagReplacedPathScripts(flowValue) {
|
|
77171
|
+
walkFlow(flowValue, {
|
|
77172
|
+
onModule(module) {
|
|
77173
|
+
if (module[TAG_KEY] && module.value.type === "rawscript") {
|
|
77174
|
+
module.value[TAG_KEY] = module[TAG_KEY];
|
|
77175
|
+
delete module[TAG_KEY];
|
|
77176
|
+
} else if (module[TAG_KEY]) {
|
|
77177
|
+
delete module[TAG_KEY];
|
|
77178
|
+
}
|
|
77179
|
+
},
|
|
77180
|
+
onTool(tool) {
|
|
77181
|
+
const tv = tool.value;
|
|
77182
|
+
if (tool[TAG_KEY] && tv && "tool_type" in tv && tv.tool_type === "flowmodule" && tv.type === "rawscript") {
|
|
77183
|
+
tv[TAG_KEY] = tool[TAG_KEY];
|
|
77184
|
+
delete tool[TAG_KEY];
|
|
77185
|
+
} else if (tool[TAG_KEY]) {
|
|
77186
|
+
delete tool[TAG_KEY];
|
|
77187
|
+
}
|
|
77188
|
+
}
|
|
77189
|
+
});
|
|
77190
|
+
}
|
|
77191
|
+
function restorePathScripts(flowValue) {
|
|
77192
|
+
walkFlow(flowValue, {
|
|
77193
|
+
onModule(module) {
|
|
77194
|
+
if (module.value[TAG_KEY]) {
|
|
77195
|
+
module.value = module.value[TAG_KEY];
|
|
77196
|
+
}
|
|
77197
|
+
},
|
|
77198
|
+
onTool(tool) {
|
|
77199
|
+
if (tool.value?.[TAG_KEY]) {
|
|
77200
|
+
tool.value = tool.value[TAG_KEY];
|
|
77201
|
+
}
|
|
77202
|
+
}
|
|
77203
|
+
});
|
|
77204
|
+
}
|
|
77205
|
+
|
|
77206
|
+
// src/commands/dev/dev.ts
|
|
76885
77207
|
var PORT = 3001;
|
|
77208
|
+
var FLOW_SUFFIXES = [".flow", "__flow"];
|
|
77209
|
+
var APP_SUFFIXES = [".app", "__app", ".raw_app", "__raw_app"];
|
|
77210
|
+
var INLINE_SCRIPT_EXTS = new Set([
|
|
77211
|
+
...exts.map((e) => path20.extname("x" + e)).filter((e) => e !== ".yml"),
|
|
77212
|
+
".js"
|
|
77213
|
+
]);
|
|
77214
|
+
function stripFolderSuffix(rel, suffixes) {
|
|
77215
|
+
for (const s of suffixes) {
|
|
77216
|
+
if (rel.endsWith(s))
|
|
77217
|
+
return rel.slice(0, -s.length);
|
|
77218
|
+
}
|
|
77219
|
+
return rel;
|
|
77220
|
+
}
|
|
77221
|
+
function isFlowFolderName(name) {
|
|
77222
|
+
return FLOW_SUFFIXES.some((s) => name.endsWith(s));
|
|
77223
|
+
}
|
|
77224
|
+
function normalizeWmPath(p) {
|
|
77225
|
+
return stripFolderSuffix(p.replace(/\/$/, ""), FLOW_SUFFIXES);
|
|
77226
|
+
}
|
|
77227
|
+
function isInsideFlowFolder(cpath) {
|
|
77228
|
+
return cpath.split("/").some(isFlowFolderName);
|
|
77229
|
+
}
|
|
77230
|
+
function findFlowFolderPrefix(cpath) {
|
|
77231
|
+
const segs = cpath.split("/");
|
|
77232
|
+
for (let i = 0;i < segs.length; i++) {
|
|
77233
|
+
if (isFlowFolderName(segs[i])) {
|
|
77234
|
+
return segs.slice(0, i + 1).join("/") + "/";
|
|
77235
|
+
}
|
|
77236
|
+
}
|
|
77237
|
+
return;
|
|
77238
|
+
}
|
|
77239
|
+
async function listWorkspacePaths() {
|
|
77240
|
+
const items = [];
|
|
77241
|
+
async function walk(dir, rel) {
|
|
77242
|
+
let entries;
|
|
77243
|
+
try {
|
|
77244
|
+
entries = await readdir10(dir, { withFileTypes: true });
|
|
77245
|
+
} catch {
|
|
77246
|
+
return;
|
|
77247
|
+
}
|
|
77248
|
+
for (const entry of entries) {
|
|
77249
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules")
|
|
77250
|
+
continue;
|
|
77251
|
+
const childRel = rel ? `${rel}/${entry.name}` : entry.name;
|
|
77252
|
+
const childAbs = path20.join(dir, entry.name);
|
|
77253
|
+
if (entry.isDirectory()) {
|
|
77254
|
+
if (isFlowFolderName(entry.name)) {
|
|
77255
|
+
items.push({
|
|
77256
|
+
path: stripFolderSuffix(childRel, FLOW_SUFFIXES),
|
|
77257
|
+
kind: "flow",
|
|
77258
|
+
_metaPath: path20.join(childAbs, "flow.yaml")
|
|
77259
|
+
});
|
|
77260
|
+
continue;
|
|
77261
|
+
}
|
|
77262
|
+
if (APP_SUFFIXES.some((s) => entry.name.endsWith(s))) {
|
|
77263
|
+
items.push({ path: stripFolderSuffix(childRel, APP_SUFFIXES), kind: "raw_app" });
|
|
77264
|
+
continue;
|
|
77265
|
+
}
|
|
77266
|
+
await walk(childAbs, childRel);
|
|
77267
|
+
} else if (entry.isFile()) {
|
|
77268
|
+
const matchedExt = exts.find((ext2) => entry.name.endsWith(ext2));
|
|
77269
|
+
if (matchedExt) {
|
|
77270
|
+
const noExtAbs = childAbs.slice(0, -matchedExt.length);
|
|
77271
|
+
items.push({
|
|
77272
|
+
path: childRel.slice(0, -matchedExt.length),
|
|
77273
|
+
kind: "script",
|
|
77274
|
+
_metaPath: noExtAbs + ".script.yaml"
|
|
77275
|
+
});
|
|
77276
|
+
}
|
|
77277
|
+
}
|
|
77278
|
+
}
|
|
77279
|
+
}
|
|
77280
|
+
await walk(process.cwd(), "");
|
|
77281
|
+
await Promise.all(items.map(async (item) => {
|
|
77282
|
+
if (!item._metaPath)
|
|
77283
|
+
return;
|
|
77284
|
+
try {
|
|
77285
|
+
const meta = await yamlParseFile(item._metaPath);
|
|
77286
|
+
if (typeof meta?.summary === "string" && meta.summary.length > 0) {
|
|
77287
|
+
item.summary = meta.summary;
|
|
77288
|
+
}
|
|
77289
|
+
} catch {}
|
|
77290
|
+
}));
|
|
77291
|
+
items.sort((a, b) => a.path.localeCompare(b.path));
|
|
77292
|
+
return items.map(({ _metaPath, ...item }) => item);
|
|
77293
|
+
}
|
|
76886
77294
|
async function dev2(opts) {
|
|
77295
|
+
if (!opts.path) {
|
|
77296
|
+
const cwd = process.cwd();
|
|
77297
|
+
const cwdBasename = path20.basename(cwd);
|
|
77298
|
+
await loadNonDottedPathsSetting();
|
|
77299
|
+
if (isFlowFolderName(cwdBasename)) {
|
|
77300
|
+
GLOBAL_CONFIG_OPT.noCdToRoot = true;
|
|
77301
|
+
let searchDir = cwd;
|
|
77302
|
+
let workspaceRoot;
|
|
77303
|
+
while (true) {
|
|
77304
|
+
const wmillYaml = path20.join(searchDir, "wmill.yaml");
|
|
77305
|
+
if (fs13.existsSync(wmillYaml)) {
|
|
77306
|
+
workspaceRoot = searchDir;
|
|
77307
|
+
break;
|
|
77308
|
+
}
|
|
77309
|
+
const parentDir = path20.dirname(searchDir);
|
|
77310
|
+
if (parentDir === searchDir)
|
|
77311
|
+
break;
|
|
77312
|
+
searchDir = parentDir;
|
|
77313
|
+
}
|
|
77314
|
+
if (workspaceRoot) {
|
|
77315
|
+
const relPath = path20.relative(workspaceRoot, cwd).replaceAll("\\", "/");
|
|
77316
|
+
opts.path = stripFolderSuffix(relPath, FLOW_SUFFIXES);
|
|
77317
|
+
info(`Detected flow folder, path: ${opts.path}`);
|
|
77318
|
+
process.chdir(workspaceRoot);
|
|
77319
|
+
}
|
|
77320
|
+
}
|
|
77321
|
+
}
|
|
76887
77322
|
opts = await mergeConfigWithConfigFile(opts);
|
|
77323
|
+
if (opts.path) {
|
|
77324
|
+
opts.path = normalizeWmPath(opts.path);
|
|
77325
|
+
}
|
|
76888
77326
|
const workspace = await resolveWorkspace(opts);
|
|
76889
77327
|
await requireLogin(opts);
|
|
76890
77328
|
info("Started dev mode");
|
|
@@ -76916,39 +77354,50 @@ async function dev2(opts) {
|
|
|
76916
77354
|
});
|
|
76917
77355
|
});
|
|
76918
77356
|
}
|
|
76919
|
-
const flowFolderSuffix = getFolderSuffixWithSep("flow");
|
|
76920
77357
|
const flowMetadataFile = getMetadataFileName("flow", "yaml");
|
|
76921
77358
|
async function loadPaths(pathsToLoad) {
|
|
76922
|
-
const paths = pathsToLoad.filter((
|
|
77359
|
+
const paths = pathsToLoad.filter((p) => exts.some((ext2) => p.endsWith(ext2) || p.endsWith(".flow/" + flowMetadataFile) || p.endsWith("__flow/" + flowMetadataFile)));
|
|
76923
77360
|
if (paths.length == 0) {
|
|
76924
77361
|
return;
|
|
76925
77362
|
}
|
|
76926
77363
|
const nativePath = (await realpath(paths[0])).replace(base + SEP20, "");
|
|
76927
77364
|
const cpath = nativePath.replaceAll("\\", "/");
|
|
76928
|
-
|
|
76929
|
-
|
|
77365
|
+
const insideFlow = isInsideFlowFolder(cpath);
|
|
77366
|
+
if (insideFlow || !ignore(nativePath, false)) {
|
|
77367
|
+
let typ;
|
|
77368
|
+
if (insideFlow) {
|
|
77369
|
+
typ = "flow";
|
|
77370
|
+
} else {
|
|
77371
|
+
typ = getTypeStrFromPath(cpath);
|
|
77372
|
+
}
|
|
76930
77373
|
info("Detected change in " + cpath + " (" + typ + ")");
|
|
76931
77374
|
if (typ == "flow") {
|
|
76932
|
-
|
|
77375
|
+
let localPath = extractFolderPath(cpath, "flow") ?? findFlowFolderPrefix(cpath);
|
|
77376
|
+
if (!localPath)
|
|
77377
|
+
return;
|
|
77378
|
+
const wmFlowPath = stripFolderSuffix(localPath.replace(/\/$/, ""), FLOW_SUFFIXES);
|
|
76933
77379
|
const localFlow = await yamlParseFile(localPath + "flow.yaml");
|
|
76934
|
-
await replaceInlineScripts(localFlow.value.modules, async (
|
|
77380
|
+
await replaceInlineScripts(localFlow.value.modules, async (path21) => await readTextFile(localPath + path21), exports_log, localPath, SEP20, undefined);
|
|
77381
|
+
snapshotPathScripts(localFlow.value);
|
|
76935
77382
|
const localScriptReader = createPreviewLocalScriptReader({
|
|
76936
77383
|
exts,
|
|
76937
77384
|
defaultTs: opts.defaultTs,
|
|
76938
77385
|
codebases
|
|
76939
77386
|
});
|
|
76940
77387
|
await replaceAllPathScriptsWithLocal(localFlow.value, localScriptReader, exports_log);
|
|
77388
|
+
tagReplacedPathScripts(localFlow.value);
|
|
76941
77389
|
currentLastEdit = {
|
|
76942
77390
|
type: "flow",
|
|
76943
77391
|
flow: localFlow,
|
|
76944
|
-
uriPath: localPath
|
|
77392
|
+
uriPath: localPath,
|
|
77393
|
+
path: wmFlowPath
|
|
76945
77394
|
};
|
|
76946
|
-
info("Updated " +
|
|
77395
|
+
info("Updated " + wmFlowPath);
|
|
76947
77396
|
broadcastChanges(currentLastEdit);
|
|
76948
77397
|
} else if (typ == "script") {
|
|
76949
|
-
const content = await readTextFile(cpath);
|
|
76950
77398
|
const splitted = cpath.split(".");
|
|
76951
77399
|
const wmPath = splitted[0];
|
|
77400
|
+
const content = await readTextFile(cpath);
|
|
76952
77401
|
const lang = inferContentTypeFromFilePath(cpath, opts.defaultTs);
|
|
76953
77402
|
const typed = (await parseMetadataFile(removeExtensionToPath(cpath), undefined))?.payload;
|
|
76954
77403
|
currentLastEdit = {
|
|
@@ -76964,29 +77413,164 @@ async function dev2(opts) {
|
|
|
76964
77413
|
}
|
|
76965
77414
|
}
|
|
76966
77415
|
}
|
|
77416
|
+
async function loadWmPath(wmPath) {
|
|
77417
|
+
wmPath = normalizeWmPath(wmPath);
|
|
77418
|
+
let flowDir;
|
|
77419
|
+
let flowYaml;
|
|
77420
|
+
for (const suffix of [".flow", "__flow"]) {
|
|
77421
|
+
const candidate = wmPath + suffix + "/";
|
|
77422
|
+
try {
|
|
77423
|
+
await access(candidate + "flow.yaml");
|
|
77424
|
+
flowDir = candidate;
|
|
77425
|
+
flowYaml = candidate + "flow.yaml";
|
|
77426
|
+
break;
|
|
77427
|
+
} catch {}
|
|
77428
|
+
}
|
|
77429
|
+
try {
|
|
77430
|
+
if (!flowDir || !flowYaml)
|
|
77431
|
+
throw new Error("not a flow");
|
|
77432
|
+
const localFlow = await yamlParseFile(flowYaml);
|
|
77433
|
+
await replaceInlineScripts(localFlow.value.modules, async (p) => await readTextFile(flowDir + p), exports_log, flowDir, SEP20, undefined);
|
|
77434
|
+
snapshotPathScripts(localFlow.value);
|
|
77435
|
+
const localScriptReader = createPreviewLocalScriptReader({
|
|
77436
|
+
exts,
|
|
77437
|
+
defaultTs: opts.defaultTs,
|
|
77438
|
+
codebases
|
|
77439
|
+
});
|
|
77440
|
+
await replaceAllPathScriptsWithLocal(localFlow.value, localScriptReader, exports_log);
|
|
77441
|
+
tagReplacedPathScripts(localFlow.value);
|
|
77442
|
+
const edit = {
|
|
77443
|
+
type: "flow",
|
|
77444
|
+
flow: localFlow,
|
|
77445
|
+
uriPath: flowDir,
|
|
77446
|
+
path: wmPath
|
|
77447
|
+
};
|
|
77448
|
+
currentLastEdit = edit;
|
|
77449
|
+
return edit;
|
|
77450
|
+
} catch {}
|
|
77451
|
+
for (const ext2 of exts) {
|
|
77452
|
+
const filePath = wmPath + ext2;
|
|
77453
|
+
try {
|
|
77454
|
+
await access(filePath);
|
|
77455
|
+
const content = await readTextFile(filePath);
|
|
77456
|
+
const lang = inferContentTypeFromFilePath(filePath, opts.defaultTs);
|
|
77457
|
+
const typed = (await parseMetadataFile(removeExtensionToPath(filePath), undefined))?.payload;
|
|
77458
|
+
const edit = {
|
|
77459
|
+
type: "script",
|
|
77460
|
+
content,
|
|
77461
|
+
path: wmPath,
|
|
77462
|
+
language: lang,
|
|
77463
|
+
tag: typed?.tag,
|
|
77464
|
+
lock: typed?.lock
|
|
77465
|
+
};
|
|
77466
|
+
currentLastEdit = edit;
|
|
77467
|
+
return edit;
|
|
77468
|
+
} catch {
|
|
77469
|
+
continue;
|
|
77470
|
+
}
|
|
77471
|
+
}
|
|
77472
|
+
error(`Could not find file for path: ${wmPath}`);
|
|
77473
|
+
return;
|
|
77474
|
+
}
|
|
77475
|
+
async function handleFlowRoundTrip(data3) {
|
|
77476
|
+
if (!data3.uriPath || !data3.flow?.value)
|
|
77477
|
+
return;
|
|
77478
|
+
let flowDir = data3.uriPath;
|
|
77479
|
+
if (!flowDir.endsWith("/"))
|
|
77480
|
+
flowDir += "/";
|
|
77481
|
+
if (flowDir.includes("://")) {
|
|
77482
|
+
flowDir = new URL(flowDir).pathname;
|
|
77483
|
+
}
|
|
77484
|
+
restorePathScripts(data3.flow.value);
|
|
77485
|
+
const flowYamlPath = flowDir + "flow.yaml";
|
|
77486
|
+
let currentLoadedFlow;
|
|
77487
|
+
let currentLoadedFailureModule;
|
|
77488
|
+
let currentLoadedPreprocessorModule;
|
|
77489
|
+
try {
|
|
77490
|
+
const currentFlow = await yamlParseFile(flowYamlPath);
|
|
77491
|
+
currentLoadedFlow = currentFlow.value?.modules;
|
|
77492
|
+
currentLoadedFailureModule = currentFlow.value?.failure_module;
|
|
77493
|
+
currentLoadedPreprocessorModule = currentFlow.value?.preprocessor_module;
|
|
77494
|
+
} catch {}
|
|
77495
|
+
const inlineScriptMapping = {};
|
|
77496
|
+
extractCurrentMapping(currentLoadedFlow, inlineScriptMapping, currentLoadedFailureModule, currentLoadedPreprocessorModule);
|
|
77497
|
+
const extractOptions = { skipInlineScriptSuffix: getNonDottedPaths() };
|
|
77498
|
+
const pathAssigner = newPathAssigner(opts.defaultTs ?? "bun", extractOptions);
|
|
77499
|
+
const allExtracted = extractInlineScripts(data3.flow.value.modules ?? [], inlineScriptMapping, "/", opts.defaultTs ?? "bun", pathAssigner, extractOptions);
|
|
77500
|
+
if (data3.flow.value.failure_module?.value?.type === "rawscript") {
|
|
77501
|
+
allExtracted.push(...extractInlineScripts([data3.flow.value.failure_module], inlineScriptMapping, "/", opts.defaultTs ?? "bun", pathAssigner, extractOptions));
|
|
77502
|
+
}
|
|
77503
|
+
if (data3.flow.value.preprocessor_module?.value?.type === "rawscript") {
|
|
77504
|
+
allExtracted.push(...extractInlineScripts([data3.flow.value.preprocessor_module], inlineScriptMapping, "/", opts.defaultTs ?? "bun", pathAssigner, extractOptions));
|
|
77505
|
+
}
|
|
77506
|
+
for (const s of allExtracted) {
|
|
77507
|
+
const filePath = flowDir + s.path;
|
|
77508
|
+
if (s.content.startsWith("!inline ")) {
|
|
77509
|
+
try {
|
|
77510
|
+
await stat17(filePath);
|
|
77511
|
+
} catch {
|
|
77512
|
+
await writeFile19(filePath, "", "utf-8");
|
|
77513
|
+
}
|
|
77514
|
+
continue;
|
|
77515
|
+
}
|
|
77516
|
+
let needsWrite = true;
|
|
77517
|
+
try {
|
|
77518
|
+
const existing = await readTextFile(filePath);
|
|
77519
|
+
if (existing === s.content)
|
|
77520
|
+
needsWrite = false;
|
|
77521
|
+
} catch {}
|
|
77522
|
+
if (needsWrite) {
|
|
77523
|
+
await writeFile19(filePath, s.content, "utf-8");
|
|
77524
|
+
info(`Wrote inline script: ${filePath}`);
|
|
77525
|
+
}
|
|
77526
|
+
}
|
|
77527
|
+
const flowYaml = import_yaml40.stringify(data3.flow);
|
|
77528
|
+
let currentYaml;
|
|
77529
|
+
try {
|
|
77530
|
+
currentYaml = await readTextFile(flowYamlPath);
|
|
77531
|
+
} catch {}
|
|
77532
|
+
if (currentYaml?.trimEnd() !== flowYaml.trimEnd()) {
|
|
77533
|
+
await writeFile19(flowYamlPath, flowYaml, "utf-8");
|
|
77534
|
+
info(`Wrote flow: ${flowYamlPath}`);
|
|
77535
|
+
}
|
|
77536
|
+
const extractedPaths = new Set(allExtracted.map((s) => s.path));
|
|
77537
|
+
try {
|
|
77538
|
+
const dirFiles = await readdir10(flowDir);
|
|
77539
|
+
for (const file of dirFiles) {
|
|
77540
|
+
if (file === "flow.yaml" || file === "flow.json" || file.startsWith("."))
|
|
77541
|
+
continue;
|
|
77542
|
+
if (!INLINE_SCRIPT_EXTS.has(path20.extname(file)))
|
|
77543
|
+
continue;
|
|
77544
|
+
if (!extractedPaths.has(file)) {
|
|
77545
|
+
await unlink(flowDir + file);
|
|
77546
|
+
info(`Removed orphaned file: ${flowDir + file}`);
|
|
77547
|
+
}
|
|
77548
|
+
}
|
|
77549
|
+
} catch {}
|
|
77550
|
+
}
|
|
76967
77551
|
const connectedClients = new Set;
|
|
76968
77552
|
function broadcastChanges(lastEdit) {
|
|
77553
|
+
if (opts.path && normalizeWmPath(lastEdit.path) !== opts.path) {
|
|
77554
|
+
return;
|
|
77555
|
+
}
|
|
76969
77556
|
for (const client of connectedClients.values()) {
|
|
76970
77557
|
client.send(JSON.stringify(lastEdit));
|
|
76971
77558
|
}
|
|
76972
77559
|
}
|
|
76973
|
-
|
|
76974
|
-
const server = http3.createServer((_req, res) => {
|
|
76975
|
-
res.writeHead(200);
|
|
76976
|
-
res.end();
|
|
76977
|
-
});
|
|
76978
|
-
const wss = new import_websocket_server.default({ server });
|
|
77560
|
+
function setupDevWs(wss) {
|
|
76979
77561
|
wss.on("connection", (ws) => {
|
|
76980
77562
|
connectedClients.add(ws);
|
|
76981
|
-
console.log("New client connected");
|
|
76982
|
-
ws.
|
|
76983
|
-
|
|
76984
|
-
|
|
77563
|
+
console.log("New dev client connected");
|
|
77564
|
+
if (currentLastEdit && ws.readyState === import_websocket.default.OPEN) {
|
|
77565
|
+
try {
|
|
77566
|
+
ws.send(JSON.stringify(currentLastEdit));
|
|
77567
|
+
} catch (e) {
|
|
77568
|
+
console.error("Failed to push initial state to new client:", e);
|
|
76985
77569
|
}
|
|
76986
|
-
}
|
|
77570
|
+
}
|
|
76987
77571
|
ws.on("close", () => {
|
|
76988
77572
|
connectedClients.delete(ws);
|
|
76989
|
-
console.log("
|
|
77573
|
+
console.log("Dev client disconnected");
|
|
76990
77574
|
});
|
|
76991
77575
|
ws.on("message", (message) => {
|
|
76992
77576
|
let data3;
|
|
@@ -76998,29 +77582,184 @@ async function dev2(opts) {
|
|
|
76998
77582
|
}
|
|
76999
77583
|
if (data3.type === "load") {
|
|
77000
77584
|
loadPaths([data3.path]);
|
|
77585
|
+
} else if (data3.type === "flow") {
|
|
77586
|
+
handleFlowRoundTrip(data3).catch((err) => {
|
|
77587
|
+
error(`Failed to write flow changes: ${err}`);
|
|
77588
|
+
});
|
|
77589
|
+
} else if (data3.type === "loadWmPath") {
|
|
77590
|
+
loadWmPath(data3.path).then((edit) => {
|
|
77591
|
+
if (edit && ws.readyState === import_websocket.default.OPEN) {
|
|
77592
|
+
ws.send(JSON.stringify(edit));
|
|
77593
|
+
}
|
|
77594
|
+
}).catch((err) => {
|
|
77595
|
+
error(`Failed to load path ${data3.path}: ${err}`);
|
|
77596
|
+
});
|
|
77597
|
+
} else if (data3.type === "listPaths") {
|
|
77598
|
+
listWorkspacePaths().then((items) => {
|
|
77599
|
+
if (ws.readyState === import_websocket.default.OPEN) {
|
|
77600
|
+
ws.send(JSON.stringify({ type: "paths", items }));
|
|
77601
|
+
}
|
|
77602
|
+
}).catch((err) => {
|
|
77603
|
+
error(`Failed to list paths: ${err}`);
|
|
77604
|
+
});
|
|
77001
77605
|
}
|
|
77002
77606
|
});
|
|
77003
77607
|
});
|
|
77004
|
-
|
|
77005
|
-
|
|
77006
|
-
|
|
77608
|
+
}
|
|
77609
|
+
function maybeOpenBrowser(url) {
|
|
77610
|
+
if (opts.open === false)
|
|
77611
|
+
return;
|
|
77007
77612
|
try {
|
|
77008
|
-
|
|
77613
|
+
open_default(url).catch((error2) => {
|
|
77009
77614
|
console.error(`Failed to open browser, please navigate to ${url}, error: ${error2}`);
|
|
77010
77615
|
});
|
|
77011
|
-
console.log(
|
|
77616
|
+
console.log(`Opened browser at ${url}`);
|
|
77012
77617
|
} catch (error2) {
|
|
77013
77618
|
console.error(`Failed to open browser, please navigate to ${url}, ${error2}`);
|
|
77014
77619
|
}
|
|
77015
|
-
|
|
77016
|
-
|
|
77017
|
-
|
|
77620
|
+
}
|
|
77621
|
+
async function startProxyServer(requestedPort) {
|
|
77622
|
+
const proxyPort = await resolveBindPort(requestedPort, "--proxy-port", {
|
|
77623
|
+
info: (m) => console.log(m),
|
|
77624
|
+
warn: (m) => console.warn(m)
|
|
77625
|
+
});
|
|
77626
|
+
const remote = new URL(workspace.remote);
|
|
77627
|
+
const isHttps = remote.protocol === "https:";
|
|
77628
|
+
const remoteHost = remote.hostname;
|
|
77629
|
+
const remotePort = remote.port ? parseInt(remote.port) : isHttps ? 443 : 80;
|
|
77630
|
+
const httpModule = isHttps ? https : http3;
|
|
77631
|
+
const devWss = new import_websocket_server.default({ noServer: true });
|
|
77632
|
+
setupDevWs(devWss);
|
|
77633
|
+
const proxyWss = new import_websocket_server.default({ noServer: true });
|
|
77634
|
+
const proxyServer = http3.createServer((clientReq, clientRes) => {
|
|
77635
|
+
const parsedUrl = new URL(clientReq.url ?? "/", `http://localhost`);
|
|
77636
|
+
if (parsedUrl.pathname === "/" || parsedUrl.pathname === "") {
|
|
77637
|
+
let devUrl = `/dev?workspace=${workspace.workspaceId}&local=true&wm_token=${workspace.token}&port=${proxyPort}`;
|
|
77638
|
+
if (opts.path) {
|
|
77639
|
+
devUrl += `&path=${opts.path}`;
|
|
77640
|
+
}
|
|
77641
|
+
clientRes.writeHead(302, { Location: devUrl });
|
|
77642
|
+
clientRes.end();
|
|
77643
|
+
return;
|
|
77644
|
+
}
|
|
77645
|
+
const fwdHeaders = {
|
|
77646
|
+
...clientReq.headers,
|
|
77647
|
+
host: remote.host
|
|
77648
|
+
};
|
|
77649
|
+
delete fwdHeaders["connection"];
|
|
77650
|
+
delete fwdHeaders["keep-alive"];
|
|
77651
|
+
delete fwdHeaders["transfer-encoding"];
|
|
77652
|
+
delete fwdHeaders["accept-encoding"];
|
|
77653
|
+
const proxyOpts = {
|
|
77654
|
+
hostname: remoteHost,
|
|
77655
|
+
port: remotePort,
|
|
77656
|
+
path: clientReq.url,
|
|
77657
|
+
method: clientReq.method,
|
|
77658
|
+
headers: fwdHeaders
|
|
77659
|
+
};
|
|
77660
|
+
const proxyReq = httpModule.request(proxyOpts, (proxyRes) => {
|
|
77661
|
+
const setCookie = proxyRes.headers["set-cookie"];
|
|
77662
|
+
if (setCookie) {
|
|
77663
|
+
proxyRes.headers["set-cookie"] = setCookie.map((cookie) => cookie.replace(/domain=[^;]+/gi, "domain=localhost"));
|
|
77664
|
+
}
|
|
77665
|
+
clientRes.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
|
|
77666
|
+
proxyRes.pipe(clientRes, { end: true });
|
|
77667
|
+
});
|
|
77668
|
+
proxyReq.on("error", (err) => {
|
|
77669
|
+
console.error("Proxy error:", err.message);
|
|
77670
|
+
clientRes.writeHead(502);
|
|
77671
|
+
clientRes.end("Bad Gateway");
|
|
77672
|
+
});
|
|
77673
|
+
clientReq.pipe(proxyReq, { end: true });
|
|
77674
|
+
});
|
|
77675
|
+
proxyServer.on("upgrade", (req, socket, head) => {
|
|
77676
|
+
const pathname = req.url?.split("?")[0] ?? "";
|
|
77677
|
+
if (pathname === "/ws_dev" || pathname === "/ws") {
|
|
77678
|
+
devWss.handleUpgrade(req, socket, head, (ws) => {
|
|
77679
|
+
devWss.emit("connection", ws, req);
|
|
77680
|
+
});
|
|
77681
|
+
return;
|
|
77682
|
+
}
|
|
77683
|
+
if (pathname.startsWith("/ws/") || pathname.startsWith("/ws_mp/") || pathname.startsWith("/ws_debug/")) {
|
|
77684
|
+
const wsProtocol = isHttps ? "wss" : "ws";
|
|
77685
|
+
const remoteWsUrl = `${wsProtocol}://${remote.host}${req.url}`;
|
|
77686
|
+
const remoteWs = new import_websocket.default(remoteWsUrl, {
|
|
77687
|
+
headers: {
|
|
77688
|
+
...req.headers,
|
|
77689
|
+
host: remote.host
|
|
77690
|
+
}
|
|
77691
|
+
});
|
|
77692
|
+
remoteWs.on("open", () => {
|
|
77693
|
+
proxyWss.handleUpgrade(req, socket, head, (clientWs) => {
|
|
77694
|
+
clientWs.on("message", (data3) => {
|
|
77695
|
+
if (remoteWs.readyState === import_websocket.default.OPEN) {
|
|
77696
|
+
remoteWs.send(data3);
|
|
77697
|
+
}
|
|
77698
|
+
});
|
|
77699
|
+
remoteWs.on("message", (data3) => {
|
|
77700
|
+
if (clientWs.readyState === import_websocket.default.OPEN) {
|
|
77701
|
+
clientWs.send(data3);
|
|
77702
|
+
}
|
|
77703
|
+
});
|
|
77704
|
+
clientWs.on("close", () => remoteWs.close());
|
|
77705
|
+
remoteWs.on("close", () => clientWs.close());
|
|
77706
|
+
});
|
|
77707
|
+
});
|
|
77708
|
+
remoteWs.on("error", (err) => {
|
|
77709
|
+
console.error("WebSocket proxy error:", err.message);
|
|
77710
|
+
socket.destroy();
|
|
77711
|
+
});
|
|
77712
|
+
return;
|
|
77713
|
+
}
|
|
77714
|
+
socket.destroy();
|
|
77715
|
+
});
|
|
77716
|
+
return new Promise((resolve8) => {
|
|
77717
|
+
proxyServer.listen(proxyPort, BIND_HOST, () => {
|
|
77718
|
+
console.log(`Dev proxy listening on http://localhost:${proxyPort}`);
|
|
77719
|
+
if (opts.path) {
|
|
77720
|
+
console.log(`Watching ${opts.path} — edits will live-reload in the dev page`);
|
|
77721
|
+
} else {
|
|
77722
|
+
console.log("Open the dev page and pick a flow or script to preview — edits will live-reload");
|
|
77723
|
+
console.log("(pass --path <path> to skip the picker)");
|
|
77724
|
+
}
|
|
77725
|
+
maybeOpenBrowser(`http://localhost:${proxyPort}/`);
|
|
77726
|
+
resolve8();
|
|
77727
|
+
});
|
|
77728
|
+
});
|
|
77729
|
+
}
|
|
77730
|
+
async function startDirectServer() {
|
|
77731
|
+
const server = http3.createServer((_req, res) => {
|
|
77732
|
+
res.writeHead(200);
|
|
77733
|
+
res.end();
|
|
77734
|
+
});
|
|
77735
|
+
const wss = new import_websocket_server.default({ server });
|
|
77736
|
+
setupDevWs(wss);
|
|
77737
|
+
const port = await resolveBindPort(PORT, "wmill dev", {
|
|
77738
|
+
info: (m) => console.log(m),
|
|
77739
|
+
warn: (m) => console.warn(m)
|
|
77740
|
+
});
|
|
77741
|
+
const url = `${workspace.remote}dev?workspace=${workspace.workspaceId}&local=true&wm_token=${workspace.token}` + (port === PORT ? "" : `&port=${port}`) + (opts.path ? `&path=${opts.path}` : "");
|
|
77742
|
+
if (opts.open === false) {
|
|
77743
|
+
console.log(`Go to ${url}`);
|
|
77744
|
+
}
|
|
77745
|
+
maybeOpenBrowser(url);
|
|
77746
|
+
if (opts.path) {
|
|
77747
|
+
console.log(`Watching ${opts.path} — edits will live-reload in the dev page`);
|
|
77748
|
+
} else {
|
|
77749
|
+
console.log("Open the dev page and pick a flow or script to preview — edits will live-reload");
|
|
77750
|
+
}
|
|
77751
|
+
server.listen(port, BIND_HOST, () => {
|
|
77752
|
+
console.log(`Dev WebSocket listening on ws://localhost:${port}/ws`);
|
|
77018
77753
|
});
|
|
77019
77754
|
}
|
|
77020
|
-
|
|
77755
|
+
if (opts.path) {
|
|
77756
|
+
await loadWmPath(opts.path);
|
|
77757
|
+
}
|
|
77758
|
+
const startServer = opts.proxyPort ? () => startProxyServer(opts.proxyPort) : () => startDirectServer();
|
|
77759
|
+
await Promise.all([startServer(), watchChanges()]);
|
|
77021
77760
|
console.log("Stopped dev mode");
|
|
77022
77761
|
}
|
|
77023
|
-
var command24 = new Command().description("
|
|
77762
|
+
var command24 = new Command().description("Watch local file changes and live-reload the dev page for preview. Does NOT deploy to the remote workspace — use wmill sync push for that.").option("--includes <pattern...:string>", "Filter paths given a glob pattern or path").option("--proxy-port <port:number>", "Port for a localhost reverse proxy to the remote Windmill server").option("--path <path:string>", "Watch a specific windmill path (e.g., u/admin/my_script or f/my_flow)").option("--no-open", "Do not open the browser automatically").action(dev2);
|
|
77024
77763
|
var dev_default2 = command24;
|
|
77025
77764
|
|
|
77026
77765
|
// src/main.ts
|
|
@@ -77262,12 +78001,12 @@ await __promiseAll([
|
|
|
77262
78001
|
init_workspace(),
|
|
77263
78002
|
init_resource_type()
|
|
77264
78003
|
]);
|
|
77265
|
-
import { stat as
|
|
78004
|
+
import { stat as stat19, writeFile as writeFile21, rm as rm5 } from "node:fs/promises";
|
|
77266
78005
|
|
|
77267
78006
|
// src/guidance/writer.ts
|
|
77268
78007
|
await init_utils();
|
|
77269
|
-
import { cp, mkdir as mkdir13, readdir as
|
|
77270
|
-
import { join as
|
|
78008
|
+
import { cp, mkdir as mkdir13, readdir as readdir11, stat as stat18, writeFile as writeFile20 } from "node:fs/promises";
|
|
78009
|
+
import { join as join18 } from "node:path";
|
|
77271
78010
|
|
|
77272
78011
|
// src/guidance/core.ts
|
|
77273
78012
|
function generateAgentsMdContent(skillsReference) {
|
|
@@ -77287,11 +78026,12 @@ You MUST use the \`write-script-<language>\` skill to write or modify scripts in
|
|
|
77287
78026
|
## Flow Writing Guide
|
|
77288
78027
|
|
|
77289
78028
|
You MUST use the \`write-flow\` skill to create or modify flows.
|
|
78029
|
+
When a new flow needs to be created, YOU run \`wmill flow new <path>\` yourself (with \`--summary\` and optional \`--description\`) to scaffold the folder and \`flow.yaml\`, then edit \`flow.yaml\` to fill in modules and schema. Do NOT scaffold the folder + yaml by hand and do NOT tell the user to run \`wmill flow new\`. If path or summary are missing from the user's request, ask via \`AskUserQuestion\` (one call, all missing fields) — never invent them. See the \`write-flow\` skill for the procedure.
|
|
77290
78030
|
|
|
77291
78031
|
## Raw App Development
|
|
77292
78032
|
|
|
77293
78033
|
You MUST use the \`raw-app\` skill to create or modify raw apps.
|
|
77294
|
-
|
|
78034
|
+
When a new app needs to be created, YOU run \`wmill app new\` yourself with \`--summary\`, \`--path\`, and \`--framework\` flags (and any other relevant flags). Do NOT ask the user to run it. If you don't have the values for those flags, ask the user via \`AskUserQuestion\` (one call, all missing fields) — never invent them. See the \`raw-app\` skill for the full procedure.
|
|
77295
78035
|
|
|
77296
78036
|
## Triggers
|
|
77297
78037
|
|
|
@@ -77305,6 +78045,10 @@ You MUST use the \`schedules\` skill to configure cron schedules.
|
|
|
77305
78045
|
|
|
77306
78046
|
You MUST use the \`resources\` skill to manage resource types and credentials.
|
|
77307
78047
|
|
|
78048
|
+
## Visual Preview
|
|
78049
|
+
|
|
78050
|
+
You MUST use the \`preview\` skill any time the user wants to see/open/visualize/preview a flow, script, or app in the dev page — and after writing one, when offering visual verification. The skill picks between an MCP-embedded proxy (one named \`launch.json\` entry per target) and direct mode (URL handed to the user) based on what tools you have.
|
|
78051
|
+
|
|
77308
78052
|
## CLI Reference
|
|
77309
78053
|
|
|
77310
78054
|
You MUST use the \`cli-commands\` skill to use the CLI.
|
|
@@ -77357,7 +78101,8 @@ var SKILLS = [
|
|
|
77357
78101
|
{ name: "triggers", description: "MUST use when configuring triggers." },
|
|
77358
78102
|
{ name: "schedules", description: "MUST use when configuring schedules." },
|
|
77359
78103
|
{ name: "resources", description: "MUST use when managing resources." },
|
|
77360
|
-
{ name: "cli-commands", description: "MUST use when using the CLI, including debugging job failures and inspecting run history via `wmill job`." }
|
|
78104
|
+
{ name: "cli-commands", description: "MUST use when using the CLI, including debugging job failures and inspecting run history via `wmill job`." },
|
|
78105
|
+
{ name: "preview", description: "MUST use when opening the Windmill dev page / visual preview of a flow, script, or app. Triggers on words like preview, open, navigate to, visualize, see the flow/app/script, and after writing a flow/script/app for visual verification." }
|
|
77361
78106
|
];
|
|
77362
78107
|
var SKILL_CONTENT = {
|
|
77363
78108
|
"write-script-bash": `---
|
|
@@ -77367,11 +78112,36 @@ description: MUST use when writing Bash scripts.
|
|
|
77367
78112
|
|
|
77368
78113
|
## CLI Commands
|
|
77369
78114
|
|
|
77370
|
-
Place scripts in a folder.
|
|
77371
|
-
|
|
77372
|
-
|
|
78115
|
+
Place scripts in a folder.
|
|
78116
|
+
|
|
78117
|
+
After writing, tell the user which command fits what they want to do:
|
|
78118
|
+
|
|
78119
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
78120
|
+
- \`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.
|
|
78121
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
78122
|
+
- \`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".
|
|
78123
|
+
|
|
78124
|
+
### Preview vs run — choose by intent, not habit
|
|
78125
|
+
|
|
78126
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
78127
|
+
|
|
78128
|
+
Only use \`script run\` when:
|
|
78129
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
78130
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
77373
78131
|
|
|
77374
|
-
|
|
78132
|
+
Only use \`sync push\` when:
|
|
78133
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
78134
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
78135
|
+
|
|
78136
|
+
### After writing — offer to test, don't wait passively
|
|
78137
|
+
|
|
78138
|
+
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.
|
|
78139
|
+
|
|
78140
|
+
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.
|
|
78141
|
+
|
|
78142
|
+
\`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.
|
|
78143
|
+
|
|
78144
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
77375
78145
|
|
|
77376
78146
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
77377
78147
|
|
|
@@ -77432,11 +78202,36 @@ description: MUST use when writing BigQuery queries.
|
|
|
77432
78202
|
|
|
77433
78203
|
## CLI Commands
|
|
77434
78204
|
|
|
77435
|
-
Place scripts in a folder.
|
|
77436
|
-
|
|
77437
|
-
|
|
78205
|
+
Place scripts in a folder.
|
|
78206
|
+
|
|
78207
|
+
After writing, tell the user which command fits what they want to do:
|
|
78208
|
+
|
|
78209
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
78210
|
+
- \`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.
|
|
78211
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
78212
|
+
- \`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".
|
|
78213
|
+
|
|
78214
|
+
### Preview vs run — choose by intent, not habit
|
|
78215
|
+
|
|
78216
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
78217
|
+
|
|
78218
|
+
Only use \`script run\` when:
|
|
78219
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
78220
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
78221
|
+
|
|
78222
|
+
Only use \`sync push\` when:
|
|
78223
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
78224
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
78225
|
+
|
|
78226
|
+
### After writing — offer to test, don't wait passively
|
|
77438
78227
|
|
|
77439
|
-
|
|
78228
|
+
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.
|
|
78229
|
+
|
|
78230
|
+
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.
|
|
78231
|
+
|
|
78232
|
+
\`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.
|
|
78233
|
+
|
|
78234
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
77440
78235
|
|
|
77441
78236
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
77442
78237
|
|
|
@@ -77459,11 +78254,36 @@ description: MUST use when writing Bun/TypeScript scripts.
|
|
|
77459
78254
|
|
|
77460
78255
|
## CLI Commands
|
|
77461
78256
|
|
|
77462
|
-
Place scripts in a folder.
|
|
77463
|
-
|
|
77464
|
-
|
|
78257
|
+
Place scripts in a folder.
|
|
78258
|
+
|
|
78259
|
+
After writing, tell the user which command fits what they want to do:
|
|
78260
|
+
|
|
78261
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
78262
|
+
- \`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.
|
|
78263
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
78264
|
+
- \`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".
|
|
78265
|
+
|
|
78266
|
+
### Preview vs run — choose by intent, not habit
|
|
78267
|
+
|
|
78268
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
78269
|
+
|
|
78270
|
+
Only use \`script run\` when:
|
|
78271
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
78272
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
78273
|
+
|
|
78274
|
+
Only use \`sync push\` when:
|
|
78275
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
78276
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
78277
|
+
|
|
78278
|
+
### After writing — offer to test, don't wait passively
|
|
78279
|
+
|
|
78280
|
+
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.
|
|
77465
78281
|
|
|
77466
|
-
|
|
78282
|
+
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.
|
|
78283
|
+
|
|
78284
|
+
\`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.
|
|
78285
|
+
|
|
78286
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
77467
78287
|
|
|
77468
78288
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
77469
78289
|
|
|
@@ -78126,11 +78946,36 @@ description: MUST use when writing Bun Native scripts.
|
|
|
78126
78946
|
|
|
78127
78947
|
## CLI Commands
|
|
78128
78948
|
|
|
78129
|
-
Place scripts in a folder.
|
|
78130
|
-
|
|
78131
|
-
|
|
78949
|
+
Place scripts in a folder.
|
|
78950
|
+
|
|
78951
|
+
After writing, tell the user which command fits what they want to do:
|
|
78952
|
+
|
|
78953
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
78954
|
+
- \`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.
|
|
78955
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
78956
|
+
- \`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".
|
|
78957
|
+
|
|
78958
|
+
### Preview vs run — choose by intent, not habit
|
|
78959
|
+
|
|
78960
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
78961
|
+
|
|
78962
|
+
Only use \`script run\` when:
|
|
78963
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
78964
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
78965
|
+
|
|
78966
|
+
Only use \`sync push\` when:
|
|
78967
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
78968
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
78969
|
+
|
|
78970
|
+
### After writing — offer to test, don't wait passively
|
|
78971
|
+
|
|
78972
|
+
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.
|
|
78973
|
+
|
|
78974
|
+
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.
|
|
78132
78975
|
|
|
78133
|
-
|
|
78976
|
+
\`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.
|
|
78977
|
+
|
|
78978
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
78134
78979
|
|
|
78135
78980
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
78136
78981
|
|
|
@@ -78791,11 +79636,36 @@ description: MUST use when writing C# scripts.
|
|
|
78791
79636
|
|
|
78792
79637
|
## CLI Commands
|
|
78793
79638
|
|
|
78794
|
-
Place scripts in a folder.
|
|
78795
|
-
|
|
78796
|
-
|
|
79639
|
+
Place scripts in a folder.
|
|
79640
|
+
|
|
79641
|
+
After writing, tell the user which command fits what they want to do:
|
|
79642
|
+
|
|
79643
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
79644
|
+
- \`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.
|
|
79645
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
79646
|
+
- \`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".
|
|
79647
|
+
|
|
79648
|
+
### Preview vs run — choose by intent, not habit
|
|
79649
|
+
|
|
79650
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
79651
|
+
|
|
79652
|
+
Only use \`script run\` when:
|
|
79653
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
79654
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
79655
|
+
|
|
79656
|
+
Only use \`sync push\` when:
|
|
79657
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
79658
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
79659
|
+
|
|
79660
|
+
### After writing — offer to test, don't wait passively
|
|
79661
|
+
|
|
79662
|
+
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.
|
|
79663
|
+
|
|
79664
|
+
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.
|
|
79665
|
+
|
|
79666
|
+
\`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.
|
|
78797
79667
|
|
|
78798
|
-
|
|
79668
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
78799
79669
|
|
|
78800
79670
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
78801
79671
|
|
|
@@ -78848,11 +79718,36 @@ description: MUST use when writing Deno/TypeScript scripts.
|
|
|
78848
79718
|
|
|
78849
79719
|
## CLI Commands
|
|
78850
79720
|
|
|
78851
|
-
Place scripts in a folder.
|
|
78852
|
-
- \`wmill generate-metadata\` - Generate .script.yaml and .lock files
|
|
78853
|
-
- \`wmill sync push\` - Deploy to Windmill
|
|
79721
|
+
Place scripts in a folder.
|
|
78854
79722
|
|
|
78855
|
-
|
|
79723
|
+
After writing, tell the user which command fits what they want to do:
|
|
79724
|
+
|
|
79725
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
79726
|
+
- \`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.
|
|
79727
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
79728
|
+
- \`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".
|
|
79729
|
+
|
|
79730
|
+
### Preview vs run — choose by intent, not habit
|
|
79731
|
+
|
|
79732
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
79733
|
+
|
|
79734
|
+
Only use \`script run\` when:
|
|
79735
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
79736
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
79737
|
+
|
|
79738
|
+
Only use \`sync push\` when:
|
|
79739
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
79740
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
79741
|
+
|
|
79742
|
+
### After writing — offer to test, don't wait passively
|
|
79743
|
+
|
|
79744
|
+
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.
|
|
79745
|
+
|
|
79746
|
+
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.
|
|
79747
|
+
|
|
79748
|
+
\`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.
|
|
79749
|
+
|
|
79750
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
78856
79751
|
|
|
78857
79752
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
78858
79753
|
|
|
@@ -79519,11 +80414,36 @@ description: MUST use when writing DuckDB queries.
|
|
|
79519
80414
|
|
|
79520
80415
|
## CLI Commands
|
|
79521
80416
|
|
|
79522
|
-
Place scripts in a folder.
|
|
79523
|
-
|
|
79524
|
-
|
|
80417
|
+
Place scripts in a folder.
|
|
80418
|
+
|
|
80419
|
+
After writing, tell the user which command fits what they want to do:
|
|
80420
|
+
|
|
80421
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
80422
|
+
- \`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.
|
|
80423
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
80424
|
+
- \`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".
|
|
80425
|
+
|
|
80426
|
+
### Preview vs run — choose by intent, not habit
|
|
80427
|
+
|
|
80428
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
80429
|
+
|
|
80430
|
+
Only use \`script run\` when:
|
|
80431
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
80432
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
80433
|
+
|
|
80434
|
+
Only use \`sync push\` when:
|
|
80435
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
80436
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
80437
|
+
|
|
80438
|
+
### After writing — offer to test, don't wait passively
|
|
79525
80439
|
|
|
79526
|
-
|
|
80440
|
+
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.
|
|
80441
|
+
|
|
80442
|
+
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.
|
|
80443
|
+
|
|
80444
|
+
\`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.
|
|
80445
|
+
|
|
80446
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
79527
80447
|
|
|
79528
80448
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
79529
80449
|
|
|
@@ -79586,11 +80506,36 @@ description: MUST use when writing Go scripts.
|
|
|
79586
80506
|
|
|
79587
80507
|
## CLI Commands
|
|
79588
80508
|
|
|
79589
|
-
Place scripts in a folder.
|
|
79590
|
-
|
|
79591
|
-
|
|
80509
|
+
Place scripts in a folder.
|
|
80510
|
+
|
|
80511
|
+
After writing, tell the user which command fits what they want to do:
|
|
80512
|
+
|
|
80513
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
80514
|
+
- \`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.
|
|
80515
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
80516
|
+
- \`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".
|
|
80517
|
+
|
|
80518
|
+
### Preview vs run — choose by intent, not habit
|
|
80519
|
+
|
|
80520
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
80521
|
+
|
|
80522
|
+
Only use \`script run\` when:
|
|
80523
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
80524
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
79592
80525
|
|
|
79593
|
-
|
|
80526
|
+
Only use \`sync push\` when:
|
|
80527
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
80528
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
80529
|
+
|
|
80530
|
+
### After writing — offer to test, don't wait passively
|
|
80531
|
+
|
|
80532
|
+
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.
|
|
80533
|
+
|
|
80534
|
+
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.
|
|
80535
|
+
|
|
80536
|
+
\`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.
|
|
80537
|
+
|
|
80538
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
79594
80539
|
|
|
79595
80540
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
79596
80541
|
|
|
@@ -79660,11 +80605,36 @@ description: MUST use when writing GraphQL queries.
|
|
|
79660
80605
|
|
|
79661
80606
|
## CLI Commands
|
|
79662
80607
|
|
|
79663
|
-
Place scripts in a folder.
|
|
79664
|
-
|
|
79665
|
-
|
|
80608
|
+
Place scripts in a folder.
|
|
80609
|
+
|
|
80610
|
+
After writing, tell the user which command fits what they want to do:
|
|
80611
|
+
|
|
80612
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
80613
|
+
- \`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.
|
|
80614
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
80615
|
+
- \`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".
|
|
80616
|
+
|
|
80617
|
+
### Preview vs run — choose by intent, not habit
|
|
79666
80618
|
|
|
79667
|
-
Do NOT run
|
|
80619
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
80620
|
+
|
|
80621
|
+
Only use \`script run\` when:
|
|
80622
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
80623
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
80624
|
+
|
|
80625
|
+
Only use \`sync push\` when:
|
|
80626
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
80627
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
80628
|
+
|
|
80629
|
+
### After writing — offer to test, don't wait passively
|
|
80630
|
+
|
|
80631
|
+
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.
|
|
80632
|
+
|
|
80633
|
+
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.
|
|
80634
|
+
|
|
80635
|
+
\`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.
|
|
80636
|
+
|
|
80637
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
79668
80638
|
|
|
79669
80639
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
79670
80640
|
|
|
@@ -79721,11 +80691,36 @@ description: MUST use when writing Java scripts.
|
|
|
79721
80691
|
|
|
79722
80692
|
## CLI Commands
|
|
79723
80693
|
|
|
79724
|
-
Place scripts in a folder.
|
|
79725
|
-
|
|
79726
|
-
|
|
80694
|
+
Place scripts in a folder.
|
|
80695
|
+
|
|
80696
|
+
After writing, tell the user which command fits what they want to do:
|
|
80697
|
+
|
|
80698
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
80699
|
+
- \`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.
|
|
80700
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
80701
|
+
- \`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".
|
|
80702
|
+
|
|
80703
|
+
### Preview vs run — choose by intent, not habit
|
|
80704
|
+
|
|
80705
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
80706
|
+
|
|
80707
|
+
Only use \`script run\` when:
|
|
80708
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
80709
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
80710
|
+
|
|
80711
|
+
Only use \`sync push\` when:
|
|
80712
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
80713
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
80714
|
+
|
|
80715
|
+
### After writing — offer to test, don't wait passively
|
|
80716
|
+
|
|
80717
|
+
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.
|
|
80718
|
+
|
|
80719
|
+
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.
|
|
79727
80720
|
|
|
79728
|
-
|
|
80721
|
+
\`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.
|
|
80722
|
+
|
|
80723
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
79729
80724
|
|
|
79730
80725
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
79731
80726
|
|
|
@@ -79775,11 +80770,36 @@ description: MUST use when writing MS SQL Server queries.
|
|
|
79775
80770
|
|
|
79776
80771
|
## CLI Commands
|
|
79777
80772
|
|
|
79778
|
-
Place scripts in a folder.
|
|
79779
|
-
|
|
79780
|
-
|
|
80773
|
+
Place scripts in a folder.
|
|
80774
|
+
|
|
80775
|
+
After writing, tell the user which command fits what they want to do:
|
|
80776
|
+
|
|
80777
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
80778
|
+
- \`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.
|
|
80779
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
80780
|
+
- \`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".
|
|
80781
|
+
|
|
80782
|
+
### Preview vs run — choose by intent, not habit
|
|
80783
|
+
|
|
80784
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
80785
|
+
|
|
80786
|
+
Only use \`script run\` when:
|
|
80787
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
80788
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
80789
|
+
|
|
80790
|
+
Only use \`sync push\` when:
|
|
80791
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
80792
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
80793
|
+
|
|
80794
|
+
### After writing — offer to test, don't wait passively
|
|
79781
80795
|
|
|
79782
|
-
|
|
80796
|
+
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.
|
|
80797
|
+
|
|
80798
|
+
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.
|
|
80799
|
+
|
|
80800
|
+
\`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.
|
|
80801
|
+
|
|
80802
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
79783
80803
|
|
|
79784
80804
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
79785
80805
|
|
|
@@ -79802,11 +80822,36 @@ description: MUST use when writing MySQL queries.
|
|
|
79802
80822
|
|
|
79803
80823
|
## CLI Commands
|
|
79804
80824
|
|
|
79805
|
-
Place scripts in a folder.
|
|
79806
|
-
|
|
79807
|
-
|
|
80825
|
+
Place scripts in a folder.
|
|
80826
|
+
|
|
80827
|
+
After writing, tell the user which command fits what they want to do:
|
|
80828
|
+
|
|
80829
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
80830
|
+
- \`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.
|
|
80831
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
80832
|
+
- \`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".
|
|
80833
|
+
|
|
80834
|
+
### Preview vs run — choose by intent, not habit
|
|
80835
|
+
|
|
80836
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
80837
|
+
|
|
80838
|
+
Only use \`script run\` when:
|
|
80839
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
80840
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
79808
80841
|
|
|
79809
|
-
|
|
80842
|
+
Only use \`sync push\` when:
|
|
80843
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
80844
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
80845
|
+
|
|
80846
|
+
### After writing — offer to test, don't wait passively
|
|
80847
|
+
|
|
80848
|
+
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.
|
|
80849
|
+
|
|
80850
|
+
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.
|
|
80851
|
+
|
|
80852
|
+
\`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.
|
|
80853
|
+
|
|
80854
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
79810
80855
|
|
|
79811
80856
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
79812
80857
|
|
|
@@ -79829,11 +80874,36 @@ description: MUST use when writing Native TypeScript scripts.
|
|
|
79829
80874
|
|
|
79830
80875
|
## CLI Commands
|
|
79831
80876
|
|
|
79832
|
-
Place scripts in a folder.
|
|
79833
|
-
|
|
79834
|
-
|
|
80877
|
+
Place scripts in a folder.
|
|
80878
|
+
|
|
80879
|
+
After writing, tell the user which command fits what they want to do:
|
|
80880
|
+
|
|
80881
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
80882
|
+
- \`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.
|
|
80883
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
80884
|
+
- \`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".
|
|
80885
|
+
|
|
80886
|
+
### Preview vs run — choose by intent, not habit
|
|
80887
|
+
|
|
80888
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
79835
80889
|
|
|
79836
|
-
|
|
80890
|
+
Only use \`script run\` when:
|
|
80891
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
80892
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
80893
|
+
|
|
80894
|
+
Only use \`sync push\` when:
|
|
80895
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
80896
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
80897
|
+
|
|
80898
|
+
### After writing — offer to test, don't wait passively
|
|
80899
|
+
|
|
80900
|
+
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.
|
|
80901
|
+
|
|
80902
|
+
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.
|
|
80903
|
+
|
|
80904
|
+
\`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.
|
|
80905
|
+
|
|
80906
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
79837
80907
|
|
|
79838
80908
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
79839
80909
|
|
|
@@ -80461,11 +81531,36 @@ description: MUST use when writing PHP scripts.
|
|
|
80461
81531
|
|
|
80462
81532
|
## CLI Commands
|
|
80463
81533
|
|
|
80464
|
-
Place scripts in a folder.
|
|
80465
|
-
|
|
80466
|
-
|
|
81534
|
+
Place scripts in a folder.
|
|
81535
|
+
|
|
81536
|
+
After writing, tell the user which command fits what they want to do:
|
|
81537
|
+
|
|
81538
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
81539
|
+
- \`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.
|
|
81540
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
81541
|
+
- \`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".
|
|
80467
81542
|
|
|
80468
|
-
|
|
81543
|
+
### Preview vs run — choose by intent, not habit
|
|
81544
|
+
|
|
81545
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
81546
|
+
|
|
81547
|
+
Only use \`script run\` when:
|
|
81548
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
81549
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
81550
|
+
|
|
81551
|
+
Only use \`sync push\` when:
|
|
81552
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
81553
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
81554
|
+
|
|
81555
|
+
### After writing — offer to test, don't wait passively
|
|
81556
|
+
|
|
81557
|
+
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.
|
|
81558
|
+
|
|
81559
|
+
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.
|
|
81560
|
+
|
|
81561
|
+
\`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.
|
|
81562
|
+
|
|
81563
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
80469
81564
|
|
|
80470
81565
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
80471
81566
|
|
|
@@ -80534,11 +81629,36 @@ description: MUST use when writing PostgreSQL queries.
|
|
|
80534
81629
|
|
|
80535
81630
|
## CLI Commands
|
|
80536
81631
|
|
|
80537
|
-
Place scripts in a folder.
|
|
80538
|
-
|
|
80539
|
-
|
|
81632
|
+
Place scripts in a folder.
|
|
81633
|
+
|
|
81634
|
+
After writing, tell the user which command fits what they want to do:
|
|
81635
|
+
|
|
81636
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
81637
|
+
- \`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.
|
|
81638
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
81639
|
+
- \`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".
|
|
81640
|
+
|
|
81641
|
+
### Preview vs run — choose by intent, not habit
|
|
81642
|
+
|
|
81643
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
81644
|
+
|
|
81645
|
+
Only use \`script run\` when:
|
|
81646
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
81647
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
81648
|
+
|
|
81649
|
+
Only use \`sync push\` when:
|
|
81650
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
81651
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
81652
|
+
|
|
81653
|
+
### After writing — offer to test, don't wait passively
|
|
81654
|
+
|
|
81655
|
+
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.
|
|
80540
81656
|
|
|
80541
|
-
|
|
81657
|
+
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.
|
|
81658
|
+
|
|
81659
|
+
\`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.
|
|
81660
|
+
|
|
81661
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
80542
81662
|
|
|
80543
81663
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
80544
81664
|
|
|
@@ -80561,11 +81681,36 @@ description: MUST use when writing PowerShell scripts.
|
|
|
80561
81681
|
|
|
80562
81682
|
## CLI Commands
|
|
80563
81683
|
|
|
80564
|
-
Place scripts in a folder.
|
|
80565
|
-
|
|
80566
|
-
|
|
81684
|
+
Place scripts in a folder.
|
|
81685
|
+
|
|
81686
|
+
After writing, tell the user which command fits what they want to do:
|
|
81687
|
+
|
|
81688
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
81689
|
+
- \`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.
|
|
81690
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
81691
|
+
- \`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".
|
|
81692
|
+
|
|
81693
|
+
### Preview vs run — choose by intent, not habit
|
|
81694
|
+
|
|
81695
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
81696
|
+
|
|
81697
|
+
Only use \`script run\` when:
|
|
81698
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
81699
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
81700
|
+
|
|
81701
|
+
Only use \`sync push\` when:
|
|
81702
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
81703
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
80567
81704
|
|
|
80568
|
-
|
|
81705
|
+
### After writing — offer to test, don't wait passively
|
|
81706
|
+
|
|
81707
|
+
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.
|
|
81708
|
+
|
|
81709
|
+
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.
|
|
81710
|
+
|
|
81711
|
+
\`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.
|
|
81712
|
+
|
|
81713
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
80569
81714
|
|
|
80570
81715
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
80571
81716
|
|
|
@@ -80632,11 +81777,36 @@ description: MUST use when writing Python scripts.
|
|
|
80632
81777
|
|
|
80633
81778
|
## CLI Commands
|
|
80634
81779
|
|
|
80635
|
-
Place scripts in a folder.
|
|
80636
|
-
|
|
80637
|
-
|
|
81780
|
+
Place scripts in a folder.
|
|
81781
|
+
|
|
81782
|
+
After writing, tell the user which command fits what they want to do:
|
|
81783
|
+
|
|
81784
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
81785
|
+
- \`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.
|
|
81786
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
81787
|
+
- \`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".
|
|
81788
|
+
|
|
81789
|
+
### Preview vs run — choose by intent, not habit
|
|
81790
|
+
|
|
81791
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
80638
81792
|
|
|
80639
|
-
|
|
81793
|
+
Only use \`script run\` when:
|
|
81794
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
81795
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
81796
|
+
|
|
81797
|
+
Only use \`sync push\` when:
|
|
81798
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
81799
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
81800
|
+
|
|
81801
|
+
### After writing — offer to test, don't wait passively
|
|
81802
|
+
|
|
81803
|
+
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.
|
|
81804
|
+
|
|
81805
|
+
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.
|
|
81806
|
+
|
|
81807
|
+
\`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.
|
|
81808
|
+
|
|
81809
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
80640
81810
|
|
|
80641
81811
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
80642
81812
|
|
|
@@ -81458,11 +82628,36 @@ description: MUST use when writing R scripts.
|
|
|
81458
82628
|
|
|
81459
82629
|
## CLI Commands
|
|
81460
82630
|
|
|
81461
|
-
Place scripts in a folder.
|
|
81462
|
-
|
|
81463
|
-
|
|
82631
|
+
Place scripts in a folder.
|
|
82632
|
+
|
|
82633
|
+
After writing, tell the user which command fits what they want to do:
|
|
82634
|
+
|
|
82635
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
82636
|
+
- \`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.
|
|
82637
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
82638
|
+
- \`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".
|
|
82639
|
+
|
|
82640
|
+
### Preview vs run — choose by intent, not habit
|
|
82641
|
+
|
|
82642
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
82643
|
+
|
|
82644
|
+
Only use \`script run\` when:
|
|
82645
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
82646
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
82647
|
+
|
|
82648
|
+
Only use \`sync push\` when:
|
|
82649
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
82650
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
82651
|
+
|
|
82652
|
+
### After writing — offer to test, don't wait passively
|
|
82653
|
+
|
|
82654
|
+
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.
|
|
82655
|
+
|
|
82656
|
+
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.
|
|
82657
|
+
|
|
82658
|
+
\`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.
|
|
81464
82659
|
|
|
81465
|
-
|
|
82660
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
81466
82661
|
|
|
81467
82662
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
81468
82663
|
|
|
@@ -81559,11 +82754,36 @@ description: MUST use when writing Rust scripts.
|
|
|
81559
82754
|
|
|
81560
82755
|
## CLI Commands
|
|
81561
82756
|
|
|
81562
|
-
Place scripts in a folder.
|
|
81563
|
-
- \`wmill generate-metadata\` - Generate .script.yaml and .lock files
|
|
81564
|
-
- \`wmill sync push\` - Deploy to Windmill
|
|
82757
|
+
Place scripts in a folder.
|
|
81565
82758
|
|
|
81566
|
-
|
|
82759
|
+
After writing, tell the user which command fits what they want to do:
|
|
82760
|
+
|
|
82761
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
82762
|
+
- \`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.
|
|
82763
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
82764
|
+
- \`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".
|
|
82765
|
+
|
|
82766
|
+
### Preview vs run — choose by intent, not habit
|
|
82767
|
+
|
|
82768
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
82769
|
+
|
|
82770
|
+
Only use \`script run\` when:
|
|
82771
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
82772
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
82773
|
+
|
|
82774
|
+
Only use \`sync push\` when:
|
|
82775
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
82776
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
82777
|
+
|
|
82778
|
+
### After writing — offer to test, don't wait passively
|
|
82779
|
+
|
|
82780
|
+
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.
|
|
82781
|
+
|
|
82782
|
+
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.
|
|
82783
|
+
|
|
82784
|
+
\`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.
|
|
82785
|
+
|
|
82786
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
81567
82787
|
|
|
81568
82788
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
81569
82789
|
|
|
@@ -81650,11 +82870,36 @@ description: MUST use when writing Snowflake queries.
|
|
|
81650
82870
|
|
|
81651
82871
|
## CLI Commands
|
|
81652
82872
|
|
|
81653
|
-
Place scripts in a folder.
|
|
81654
|
-
|
|
81655
|
-
|
|
82873
|
+
Place scripts in a folder.
|
|
82874
|
+
|
|
82875
|
+
After writing, tell the user which command fits what they want to do:
|
|
82876
|
+
|
|
82877
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
82878
|
+
- \`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.
|
|
82879
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
82880
|
+
- \`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".
|
|
82881
|
+
|
|
82882
|
+
### Preview vs run — choose by intent, not habit
|
|
82883
|
+
|
|
82884
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
82885
|
+
|
|
82886
|
+
Only use \`script run\` when:
|
|
82887
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
82888
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
82889
|
+
|
|
82890
|
+
Only use \`sync push\` when:
|
|
82891
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
82892
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
82893
|
+
|
|
82894
|
+
### After writing — offer to test, don't wait passively
|
|
81656
82895
|
|
|
81657
|
-
|
|
82896
|
+
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.
|
|
82897
|
+
|
|
82898
|
+
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.
|
|
82899
|
+
|
|
82900
|
+
\`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.
|
|
82901
|
+
|
|
82902
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
81658
82903
|
|
|
81659
82904
|
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
81660
82905
|
|
|
@@ -81677,15 +82922,77 @@ description: MUST use when creating flows.
|
|
|
81677
82922
|
|
|
81678
82923
|
# Windmill Flow Building Guide
|
|
81679
82924
|
|
|
81680
|
-
##
|
|
82925
|
+
## Creating a Flow
|
|
82926
|
+
|
|
82927
|
+
**You — the AI agent — scaffold the flow yourself by running \`wmill flow new <path>\` with the right flags. Do NOT hand-create the folder + \`flow.yaml\`, and do NOT tell the user to "run \`wmill flow new\` and follow the prompts".**
|
|
82928
|
+
|
|
82929
|
+
\`wmill flow new\` creates the folder with the correct suffix (\`{{FLOW_SUFFIX}}\` or \`.flow\` depending on the workspace's \`nonDottedPaths\` setting), writes a minimal \`flow.yaml\` shell, and prints Claude-specific next-step hints. Scaffolding by hand skips all of that and often picks the wrong suffix.
|
|
82930
|
+
|
|
82931
|
+
### Step 1 — Gather path + summary by asking the user
|
|
82932
|
+
|
|
82933
|
+
You need two things:
|
|
82934
|
+
|
|
82935
|
+
1. **path** — the windmill path, e.g. \`f/folder/my_flow\` or \`u/username/my_flow\`.
|
|
82936
|
+
2. **summary** — a short description of the flow.
|
|
82937
|
+
|
|
82938
|
+
If the user's request didn't supply both, ask for both in a single round-trip. Use whichever interactive question facility your runtime provides — a structured multi-choice tool if available, otherwise plain chat — and provide one or two example values for each (with an "Other" / free-form fallback). Do not guess paths or summaries.
|
|
82939
|
+
|
|
82940
|
+
### Step 2 — Run the command yourself
|
|
82941
|
+
|
|
82942
|
+
\`\`\`bash
|
|
82943
|
+
wmill flow new f/folder/my_flow --summary "Short description"
|
|
82944
|
+
\`\`\`
|
|
82945
|
+
|
|
82946
|
+
Add \`--description "..."\` when the user provided a longer explanation worth preserving separately from the summary.
|
|
82947
|
+
|
|
82948
|
+
### Step 3 — Fill in \`flow.yaml\`
|
|
82949
|
+
|
|
82950
|
+
Open the generated \`flow.yaml\` (under the folder the command just created) and replace the empty \`value.modules\` + \`schema\` with the real flow definition.
|
|
81681
82951
|
|
|
81682
|
-
Create a folder ending with \`{{FLOW_SUFFIX}}\` and add a \`flow.yaml\` file with the flow definition.
|
|
81683
82952
|
For rawscript modules, use \`!inline path/to/script.ts\` for the content key. {{INLINE_SCRIPT_NAMING}}
|
|
81684
|
-
After writing, tell the user they can run:
|
|
81685
|
-
- \`wmill generate-metadata\` - Generate lock files for the flow you modified
|
|
81686
|
-
- \`wmill sync push\` - Deploy to Windmill
|
|
81687
82953
|
|
|
81688
|
-
|
|
82954
|
+
Once the flow has real content, **offer** to open the visual preview as a one-sentence next step (e.g. "Want me to open the visual preview?"). Don't auto-open — opening the dev page has side effects (browser window, possibly a \`launch.json\` entry) and the user should consent.
|
|
82955
|
+
|
|
82956
|
+
### Anti-patterns to avoid
|
|
82957
|
+
|
|
82958
|
+
- ❌ Hand-creating the \`{{FLOW_SUFFIX}}\` folder + \`flow.yaml\` instead of running \`wmill flow new\`. You'll miss the suffix-setting resolution, the default shape, and the Claude hints.
|
|
82959
|
+
- ❌ Telling the user to "run \`wmill flow new <path>\`" — you can and should run it yourself.
|
|
82960
|
+
- ❌ Inventing a path/summary instead of asking the user.
|
|
82961
|
+
|
|
82962
|
+
## CLI Commands — running, previewing, deploying
|
|
82963
|
+
|
|
82964
|
+
After writing, tell the user which command fits what they want to do:
|
|
82965
|
+
|
|
82966
|
+
- \`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.
|
|
82967
|
+
- \`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.
|
|
82968
|
+
- \`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.
|
|
82969
|
+
- \`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".
|
|
82970
|
+
|
|
82971
|
+
### Preview vs run — choose by intent, not habit
|
|
82972
|
+
|
|
82973
|
+
If the user says "run the flow", "try it", "test it", "does it work" while there are **local edits to a \`flow.yaml\`**, use \`flow preview\`. Do NOT push the flow to then \`flow run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
82974
|
+
|
|
82975
|
+
Only use \`flow run\` when:
|
|
82976
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
82977
|
+
- There is no local \`flow.yaml\` being edited (you're just invoking an existing flow).
|
|
82978
|
+
|
|
82979
|
+
Only use \`sync push\` when:
|
|
82980
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
82981
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
82982
|
+
|
|
82983
|
+
### After writing — offer to run, don't wait passively
|
|
82984
|
+
|
|
82985
|
+
This is about **programmatic execution** (\`wmill flow preview -d '<args>'\`), which actually runs the flow and has side effects. Visual preview (the \`preview\` skill) is offered separately — see "Visual preview" below.
|
|
82986
|
+
|
|
82987
|
+
If the user hasn't already told you to run/test the flow, offer it as a one-sentence next step (e.g. "Want me to run \`wmill flow preview\` with sample args?"). Do not present a multi-option menu.
|
|
82988
|
+
|
|
82989
|
+
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.
|
|
82990
|
+
|
|
82991
|
+
\`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.
|
|
82992
|
+
|
|
82993
|
+
### Visual preview
|
|
82994
|
+
|
|
82995
|
+
To open the flow visually in the dev page (graph + live reload), use the \`preview\` skill. Always **offer** it as a one-sentence next step (e.g. "Want me to open the visual preview?") rather than opening it automatically — opening the dev page has side effects (browser window, possibly a \`launch.json\` entry under MCP-preview branches) the user should consent to. If the user already asked to see/preview/visualize the flow in their original request, skip the offer and just invoke the skill.
|
|
81689
82996
|
|
|
81690
82997
|
## OpenFlow Schema
|
|
81691
82998
|
|
|
@@ -81994,11 +83301,70 @@ Raw apps let you build custom frontends with React, Svelte, or Vue that connect
|
|
|
81994
83301
|
|
|
81995
83302
|
## Creating a Raw App
|
|
81996
83303
|
|
|
83304
|
+
**You — the AI agent — create the app yourself by running \`wmill app new\` with the right flags. Do NOT tell the user to "run \`wmill app new\` and follow the prompts" or wait for them to do it.** The bare \`wmill app new\` is an interactive wizard that hangs waiting for stdin in any non-TTY context (which includes you). Always pass flags.
|
|
83305
|
+
|
|
83306
|
+
### Step 1 — Gather the three required values by asking the user
|
|
83307
|
+
|
|
83308
|
+
You need three things to run the command:
|
|
83309
|
+
|
|
83310
|
+
1. **summary** — a short description of the app
|
|
83311
|
+
2. **path** — the windmill path, e.g. \`f/folder/my_app\` or \`u/username/my_app\`
|
|
83312
|
+
3. **framework** — one of \`react19\` (recommended), \`react18\`, \`svelte5\`, \`vue\`
|
|
83313
|
+
|
|
83314
|
+
If the user's request did not supply *every* one of these explicitly, ask. Do not guess values, do not invent paths, do not pick a framework on the user's behalf, do not "just use react19 because it's the default".
|
|
83315
|
+
|
|
83316
|
+
Use whichever interactive question facility your runtime provides — a structured multi-choice tool if available, otherwise plain chat — and group all missing fields into a single round-trip so the user answers them at once:
|
|
83317
|
+
|
|
83318
|
+
- For \`framework\` — multiple-choice with the four allowed values; mark \`react19\` as \`(Recommended)\` and put it first.
|
|
83319
|
+
- For \`summary\` and \`path\` — provide one or two example values as multiple-choice options (the user can pick "Other" to type a free-form answer).
|
|
83320
|
+
|
|
83321
|
+
Only proceed once you have concrete values for all three. If the user replies with something ambiguous, ask again rather than guessing.
|
|
83322
|
+
|
|
83323
|
+
### Step 2 — Run the command yourself
|
|
83324
|
+
|
|
83325
|
+
Once you have summary + path + framework, run it:
|
|
83326
|
+
|
|
83327
|
+
\`\`\`bash
|
|
83328
|
+
wmill app new \\
|
|
83329
|
+
--summary "Customer dashboard" \\
|
|
83330
|
+
--path f/sales/dashboard \\
|
|
83331
|
+
--framework react19
|
|
83332
|
+
\`\`\`
|
|
83333
|
+
|
|
83334
|
+
That's the minimum. The datatable wizard and the "Open in Claude Desktop?" prompt are skipped silently because passing any of \`--summary\`/\`--path\`/\`--framework\` puts the command in non-interactive mode.
|
|
83335
|
+
|
|
83336
|
+
### Optional flags
|
|
83337
|
+
|
|
83338
|
+
Layer these in only when the user asked for them:
|
|
83339
|
+
|
|
83340
|
+
| Flag | When to add it |
|
|
83341
|
+
|---|---|
|
|
83342
|
+
| \`--datatable <name>\` | The user wants this app wired to a specific Windmill datatable. Without it, the app is created with no datatable. |
|
|
83343
|
+
| \`--schema <name>\` | Together with \`--datatable\`. Creates the schema with \`CREATE SCHEMA IF NOT EXISTS\` if it doesn't already exist. |
|
|
83344
|
+
| \`--overwrite\` | The target directory already exists and the user said it's OK to replace. Without it, non-interactive mode aborts with an error so you don't clobber existing work. |
|
|
83345
|
+
| \`--no-open-in-desktop\` | Already implied in non-interactive mode; only needed if you're somehow running interactively. |
|
|
83346
|
+
|
|
83347
|
+
### Step 3 — Offer the visual preview
|
|
83348
|
+
|
|
83349
|
+
After \`wmill app new\` and any initial edits to \`App.tsx\` / \`index.tsx\`, **offer** to open the visual preview as a one-sentence next step (e.g. "Want me to open the visual preview?"). Don't auto-open — opening the dev page has side effects (browser window, possibly a \`launch.json\` entry when an embedded preview tool is in play) the user should consent to.
|
|
83350
|
+
|
|
83351
|
+
For apps the preview command runs from the app folder (\`cd <app_path>__raw_app && wmill app dev …\`); the \`preview\` skill picks the proxy vs direct branch based on whether the runtime exposes a tool that can embed a localhost URL. If the user already asked to see/preview/visualize the app in their original request, skip the offer and just invoke the skill.
|
|
83352
|
+
|
|
83353
|
+
### Anti-patterns to avoid
|
|
83354
|
+
|
|
83355
|
+
- ❌ Running \`wmill app new\` with no flags (the prompt will hang).
|
|
83356
|
+
- ❌ Telling the user to "run \`wmill app new\` and follow the prompts" — that's a step backwards from what you can do directly.
|
|
83357
|
+
- ❌ Inventing a path/summary/framework instead of asking the user.
|
|
83358
|
+
- ❌ Defaulting to \`react19\` because the user didn't say — even sensible defaults must be confirmed.
|
|
83359
|
+
- ❌ Passing \`--overwrite\` automatically when the directory exists — confirm with the user first.
|
|
83360
|
+
|
|
83361
|
+
### Interactive (only when a human is at the terminal)
|
|
83362
|
+
|
|
81997
83363
|
\`\`\`bash
|
|
81998
83364
|
wmill app new
|
|
81999
83365
|
\`\`\`
|
|
82000
83366
|
|
|
82001
|
-
This
|
|
83367
|
+
This is the wizard. It only works when run by a human in a real terminal. Don't call it this way from an agent.
|
|
82002
83368
|
|
|
82003
83369
|
## App Structure
|
|
82004
83370
|
|
|
@@ -82222,12 +83588,13 @@ data:
|
|
|
82222
83588
|
|
|
82223
83589
|
## CLI Commands
|
|
82224
83590
|
|
|
82225
|
-
|
|
83591
|
+
\`wmill app new\` is the exception: you run it yourself, with flags, per the "Creating a Raw App" section above.
|
|
83592
|
+
|
|
83593
|
+
For everything else, tell the user which command fits their intent and let them run it — these touch the workspace or local lock files, and the user should consent each time:
|
|
82226
83594
|
|
|
82227
83595
|
| Command | Description |
|
|
82228
83596
|
|---------|-------------|
|
|
82229
|
-
| \`wmill app
|
|
82230
|
-
| \`wmill app dev\` | Start dev server with live reload |
|
|
83597
|
+
| \`wmill app dev\` | Start dev server with live reload (see the \`preview\` skill for the full open-the-app-in-the-IDE-pane procedure). |
|
|
82231
83598
|
| \`wmill app generate-agents\` | Refresh AGENTS.md and DATATABLES.md |
|
|
82232
83599
|
| \`wmill generate-metadata\` | Generate lock files for backend runnables |
|
|
82233
83600
|
| \`wmill sync push\` | Deploy app to Windmill |
|
|
@@ -82616,6 +83983,13 @@ app related commands
|
|
|
82616
83983
|
- \`app lint [app_folder:string]\` - Lint a raw app folder to validate structure and buildability
|
|
82617
83984
|
- \`--fix\` - Attempt to fix common issues (not implemented yet)
|
|
82618
83985
|
- \`app new\` - create a new raw app from a template
|
|
83986
|
+
- \`--summary <summary:string>\` - App summary (short description). Skips the prompt when provided. Triggers non-interactive mode.
|
|
83987
|
+
- \`--path <path:string>\` - App path (e.g., f/folder/my_app or u/username/my_app). Skips the prompt when provided. Triggers non-interactive mode.
|
|
83988
|
+
- \`--framework <framework:string>\` - Framework template: react19 | react18 | svelte5 | vue. Skips the prompt when provided. Triggers non-interactive mode.
|
|
83989
|
+
- \`--datatable <datatable:string>\` - Datatable to wire up. Without this flag in non-interactive mode, no datatable is configured.
|
|
83990
|
+
- \`--schema <schema:string>\` - Schema to use with --datatable. Created (CREATE SCHEMA IF NOT EXISTS) if it doesn't already exist.
|
|
83991
|
+
- \`--overwrite\` - Overwrite the target directory if it already exists, without prompting.
|
|
83992
|
+
- \`--no-open-in-desktop\` - Do not prompt to open the new app in Claude Desktop.
|
|
82619
83993
|
- \`app generate-agents [app_folder:string]\` - regenerate AGENTS.md and DATATABLES.md from remote workspace
|
|
82620
83994
|
- \`app set-permissioned-as <path:string> <email:string>\` - Set the on_behalf_of_email for an app (requires admin or wm_deployers group)
|
|
82621
83995
|
|
|
@@ -82652,10 +84026,13 @@ workspace dependencies related commands
|
|
|
82652
84026
|
|
|
82653
84027
|
### dev
|
|
82654
84028
|
|
|
82655
|
-
|
|
84029
|
+
Watch local file changes and live-reload the dev page for preview. Does NOT deploy to the remote workspace — use wmill sync push for that.
|
|
82656
84030
|
|
|
82657
84031
|
**Options:**
|
|
82658
|
-
- \`--includes <pattern...:string>\` - Filter paths
|
|
84032
|
+
- \`--includes <pattern...:string>\` - Filter paths given a glob pattern or path
|
|
84033
|
+
- \`--proxy-port <port:number>\` - Port for a localhost reverse proxy to the remote Windmill server
|
|
84034
|
+
- \`--path <path:string>\` - Watch a specific windmill path (e.g., u/admin/my_script or f/my_flow)
|
|
84035
|
+
- \`--no-open\` - Do not open the browser automatically
|
|
82659
84036
|
|
|
82660
84037
|
### docs
|
|
82661
84038
|
|
|
@@ -83201,6 +84578,133 @@ workspace related commands
|
|
|
83201
84578
|
- \`--team-name <team_name:string>\` - Slack team name
|
|
83202
84579
|
- \`workspace disconnect-slack\`
|
|
83203
84580
|
|
|
84581
|
+
`,
|
|
84582
|
+
preview: `---
|
|
84583
|
+
name: preview
|
|
84584
|
+
description: MUST use when opening the Windmill dev page / visual preview of a flow, script, or app. Triggers on words like preview, open, navigate to, visualize, see the flow/app/script, and after writing a flow/script/app for visual verification.
|
|
84585
|
+
---
|
|
84586
|
+
|
|
84587
|
+
# Windmill Preview Workflow
|
|
84588
|
+
|
|
84589
|
+
Use this skill any time the user wants to **see**, **open**, **navigate to**, **visualize**, or **preview** a flow, script, or app — and any time you've just finished writing one and want to offer visual verification.
|
|
84590
|
+
|
|
84591
|
+
The Windmill dev page renders the flow graph / script editor, lets the user step through steps, and live-reloads on every save. It runs locally via \`wmill dev\` and is reached on a localhost port.
|
|
84592
|
+
|
|
84593
|
+
## Two independent decisions
|
|
84594
|
+
|
|
84595
|
+
### 1. Mode: proxy or direct?
|
|
84596
|
+
|
|
84597
|
+
\`wmill dev\` runs in two modes; pick by asking what kind of URL whatever will display the preview needs.
|
|
84598
|
+
|
|
84599
|
+
- **Proxy** (\`--proxy-port <port>\`) — exposes the dev page on \`http://localhost:<port>/\`. Use it when the embedder you'll hand the URL to **only accepts localhost URLs** (most in-IDE / in-chat preview embedders do, because they sandbox cross-origin loads).
|
|
84600
|
+
- **Direct** (default) — the user's browser loads the dev page from the remote workspace's HTTPS URL; the local \`wmill dev\` only runs the WebSocket back-channel for live reload. Use it when the URL will be opened in a regular browser tab.
|
|
84601
|
+
|
|
84602
|
+
Default to **direct** unless you have a specific embedder that needs localhost.
|
|
84603
|
+
|
|
84604
|
+
### 2. Who starts the server?
|
|
84605
|
+
|
|
84606
|
+
- **You start it** in the background. Spawn \`wmill dev …\` (or \`wmill app dev …\`) yourself, capture the URL it prints, do whatever's next (open a tab, hand the URL to an embedder).
|
|
84607
|
+
- **The runtime starts it from \`.claude/launch.json\`.** Some runtimes (currently the Claude Desktop / Claude Code MCP preview integration — tools prefixed with \`mcp__Claude_Preview__\`) can read a \`launch.json\` configuration and launch the dev server on demand when you invoke their preview tool. **Only take this path if you actually have such a tool** — otherwise nothing reads the file and \`wmill dev\` never starts.
|
|
84608
|
+
|
|
84609
|
+
The two decisions compose. The common cases:
|
|
84610
|
+
|
|
84611
|
+
| Embedder | Needs localhost? | launch.json runtime? | What to do |
|
|
84612
|
+
|---|---|---|---|
|
|
84613
|
+
| Regular browser tab | No | n/a | Direct mode, you start it, give URL to user |
|
|
84614
|
+
| IDE / chat preview pane that takes any URL | No | No | Direct mode, you start it, point the embedder at the printed URL |
|
|
84615
|
+
| IDE / chat preview pane that only accepts localhost | Yes | No | Proxy mode, you start it, point the embedder at \`http://localhost:<port>/\` |
|
|
84616
|
+
| Claude Desktop / Code MCP preview | Yes | Yes | Proxy mode, write a \`launch.json\` entry, invoke the MCP tool |
|
|
84617
|
+
|
|
84618
|
+
Never start the proxy "just in case" — it adds the localhost hop for no benefit when no embedder needs it.
|
|
84619
|
+
|
|
84620
|
+
## Starting the server yourself
|
|
84621
|
+
|
|
84622
|
+
Use this when no \`launch.json\`-aware runtime is available, regardless of mode.
|
|
84623
|
+
|
|
84624
|
+
For flows / scripts:
|
|
84625
|
+
\`\`\`bash
|
|
84626
|
+
# Direct mode — gives you the remote dev-page URL
|
|
84627
|
+
wmill dev --path <wmill_path> --no-open
|
|
84628
|
+
|
|
84629
|
+
# Proxy mode — gives you a localhost URL that 302s to the remote dev page
|
|
84630
|
+
wmill dev --proxy-port 4000 --path <wmill_path> --no-open
|
|
84631
|
+
\`\`\`
|
|
84632
|
+
|
|
84633
|
+
For apps:
|
|
84634
|
+
\`\`\`bash
|
|
84635
|
+
cd <app_path>__raw_app && wmill app dev --no-open --port 4000
|
|
84636
|
+
\`\`\`
|
|
84637
|
+
|
|
84638
|
+
Each command prints the URL on stdout. Line shapes differ:
|
|
84639
|
+
|
|
84640
|
+
- \`wmill dev --no-open\` (direct) prints \`Go to <url>\` with the full remote URL (workspace, token, path baked in).
|
|
84641
|
+
- \`wmill dev --proxy-port\` prints \`Dev proxy listening on http://localhost:<port>\` — the URL to hand to an embedder is \`http://localhost:<port>/\`.
|
|
84642
|
+
- \`wmill app dev --no-open\` prints \`\uD83D\uDE80 Dev server running at <url>\` — the local app server.
|
|
84643
|
+
|
|
84644
|
+
Capture the URL with a loose match (the first \`https?://…\` token after startup) and either hand it to your embedder or relay it to the user: *"Preview is running — open \`<url>\` in your browser."* Don't construct the URL yourself; you don't have the workspace ID or auth token.
|
|
84645
|
+
|
|
84646
|
+
These commands are long-running — start them in the background, don't block waiting.
|
|
84647
|
+
|
|
84648
|
+
## Letting \`launch.json\` start the server (Claude Desktop / Code MCP only)
|
|
84649
|
+
|
|
84650
|
+
Take this path when **and only when** an \`mcp__Claude_Preview__*\` MCP tool is exposed in your tool list. Skip it otherwise — without an MCP tool reading the file, \`wmill dev\` never starts.
|
|
84651
|
+
|
|
84652
|
+
**Each flow / script / app gets its own named entry** in the user's \`.claude/launch.json\` so multiple previews coexist without colliding — each entry pins a different port + path. Never reuse a generic "windmill" entry for different targets.
|
|
84653
|
+
|
|
84654
|
+
### Step 1 — Reuse or add a per-target entry in \`.claude/launch.json\`
|
|
84655
|
+
|
|
84656
|
+
Convention: name the entry \`windmill: <wmill_path>\` (e.g. \`windmill: f/test/my_flow\`).
|
|
84657
|
+
|
|
84658
|
+
- **Entry already exists** → reuse it; note its \`port\` for the next step.
|
|
84659
|
+
- **Not there** → add one. Pick a port not already taken by another entry (start at 4000 and bump). Shape:
|
|
84660
|
+
|
|
84661
|
+
For flows / scripts:
|
|
84662
|
+
\`\`\`json
|
|
84663
|
+
{
|
|
84664
|
+
"name": "windmill: f/test/my_flow",
|
|
84665
|
+
"runtimeExecutable": "bash",
|
|
84666
|
+
"runtimeArgs": ["-c", "wmill dev --proxy-port \${PORT:-4000} --path f/test/my_flow --no-open"],
|
|
84667
|
+
"port": 4000,
|
|
84668
|
+
"autoPort": true
|
|
84669
|
+
}
|
|
84670
|
+
\`\`\`
|
|
84671
|
+
|
|
84672
|
+
For apps (\`*__raw_app/\`), \`wmill app dev\` is the equivalent — runs from the app folder, no \`--path\`:
|
|
84673
|
+
\`\`\`json
|
|
84674
|
+
{
|
|
84675
|
+
"name": "windmill: f/test/my_app",
|
|
84676
|
+
"runtimeExecutable": "bash",
|
|
84677
|
+
"runtimeArgs": ["-c", "cd f/test/my_app__raw_app && wmill app dev --no-open --port \${PORT:-4001}"],
|
|
84678
|
+
"port": 4001,
|
|
84679
|
+
"autoPort": true
|
|
84680
|
+
}
|
|
84681
|
+
\`\`\`
|
|
84682
|
+
|
|
84683
|
+
If \`.claude/launch.json\` doesn't exist yet, create it with the standard shell \`{ "version": "0.0.1", "configurations": [...] }\`.
|
|
84684
|
+
|
|
84685
|
+
### Step 2 — Invoke the MCP preview tool
|
|
84686
|
+
|
|
84687
|
+
Point it at the entry you just added/found. Use \`http://localhost:<port>/\` as the URL — the proxy's redirect at \`/\` is what appends the workspace ID, the auth token, and the path. Do **NOT** construct a \`/dev?...\` URL yourself.
|
|
84688
|
+
|
|
84689
|
+
The MCP tool launches the configuration on demand, so you don't need to start the \`wmill dev\` process manually.
|
|
84690
|
+
|
|
84691
|
+
## Non-visual alternative
|
|
84692
|
+
|
|
84693
|
+
If the user wants a programmatic test rather than a visual one:
|
|
84694
|
+
- Flow: \`wmill flow preview <path> -d '<args>'\`
|
|
84695
|
+
- Script: \`wmill script preview <path> -d '<args>'\`
|
|
84696
|
+
|
|
84697
|
+
Both print the job result, are safe to run yourself, and don't deploy.
|
|
84698
|
+
|
|
84699
|
+
## Anti-patterns to avoid
|
|
84700
|
+
|
|
84701
|
+
- ❌ Writing a \`.claude/launch.json\` entry when no \`mcp__Claude_Preview__*\` tool is in your tool list. Nothing will read the file; the server never starts. Spawn \`wmill dev\` yourself instead.
|
|
84702
|
+
- ❌ Starting the proxy when no embedder needs a localhost URL. Direct mode is the right choice — the proxy is overhead with no purpose.
|
|
84703
|
+
- ❌ Reusing a single generic \`launch.json\` entry for every preview target. Each flow/script/app gets its own named entry on its own port — that's how multiple sessions coexist without one preview clobbering another.
|
|
84704
|
+
- ❌ Mutating an existing entry's \`--path\` to retarget it. Add a new entry instead.
|
|
84705
|
+
- ❌ Constructing \`http://localhost:<port>/dev?path=<X>\` yourself. The proxy's \`/\` redirect is what appends the workspace ID and auth token; bypassing it gives a broken page. Always use \`http://localhost:<port>/\`.
|
|
84706
|
+
- ❌ Starting \`wmill dev\` in the foreground (you'll hang). Always background.
|
|
84707
|
+
- ❌ Listing both "open in IDE pane" and "open in browser" as a menu — pick one based on context.
|
|
83204
84708
|
`
|
|
83205
84709
|
};
|
|
83206
84710
|
var SCHEMAS = {
|
|
@@ -84228,16 +85732,17 @@ var WMILL_INIT_AI_AGENTS_SOURCE_ENV = "WMILL_INIT_AI_AGENTS_SOURCE";
|
|
|
84228
85732
|
var WMILL_INIT_AI_CLAUDE_SOURCE_ENV = "WMILL_INIT_AI_CLAUDE_SOURCE";
|
|
84229
85733
|
var CLAUDE_MD_DEFAULT = `Instructions are in @AGENTS.md
|
|
84230
85734
|
`;
|
|
85735
|
+
var SKILL_TARGET_ROOTS = [".claude", ".agents"];
|
|
84231
85736
|
async function writeAiGuidanceFiles(options) {
|
|
84232
85737
|
const nonDottedPaths = options.nonDottedPaths ?? true;
|
|
84233
85738
|
const skillMetadata = options.skillsSourcePath ? await readSkillMetadataFromDirectory(options.skillsSourcePath) : getGeneratedSkillMetadata();
|
|
84234
85739
|
const agentsWritten = await writeProjectGuidanceFile({
|
|
84235
|
-
targetPath:
|
|
85740
|
+
targetPath: join18(options.targetDir, "AGENTS.md"),
|
|
84236
85741
|
overwrite: options.overwriteProjectGuidance ?? false,
|
|
84237
85742
|
content: options.agentsSourcePath != null ? await readTextFile(options.agentsSourcePath) : generateAgentsMdContent(buildSkillsReference(skillMetadata))
|
|
84238
85743
|
});
|
|
84239
85744
|
const claudeWritten = await writeProjectGuidanceFile({
|
|
84240
|
-
targetPath:
|
|
85745
|
+
targetPath: join18(options.targetDir, "CLAUDE.md"),
|
|
84241
85746
|
overwrite: options.overwriteProjectGuidance ?? false,
|
|
84242
85747
|
content: options.claudeSourcePath != null ? await readTextFile(options.claudeSourcePath) : CLAUDE_MD_DEFAULT
|
|
84243
85748
|
});
|
|
@@ -84257,17 +85762,17 @@ function buildSkillsReference(skills) {
|
|
|
84257
85762
|
`);
|
|
84258
85763
|
}
|
|
84259
85764
|
async function copySkillsFromSource(targetDir, skillsSourcePath) {
|
|
84260
|
-
const
|
|
84261
|
-
await copyDirectoryContents(skillsSourcePath, skillsDir);
|
|
84262
|
-
return await readSkillMetadataFromDirectory(
|
|
85765
|
+
const skillsDirs = await ensureSkillsDirectories(targetDir);
|
|
85766
|
+
await Promise.all(skillsDirs.map((skillsDir) => copyDirectoryContents(skillsSourcePath, skillsDir)));
|
|
85767
|
+
return await readSkillMetadataFromDirectory(skillsDirs[0]);
|
|
84263
85768
|
}
|
|
84264
85769
|
async function writeGeneratedSkills(targetDir, nonDottedPaths) {
|
|
84265
|
-
const
|
|
84266
|
-
await Promise.all(SKILLS.map(async (skill) => {
|
|
84267
|
-
const skillDir =
|
|
85770
|
+
const skillsDirs = await ensureSkillsDirectories(targetDir);
|
|
85771
|
+
await Promise.all(skillsDirs.flatMap((skillsDir) => SKILLS.map(async (skill) => {
|
|
85772
|
+
const skillDir = join18(skillsDir, skill.name);
|
|
84268
85773
|
await mkdir13(skillDir, { recursive: true });
|
|
84269
|
-
await
|
|
84270
|
-
}));
|
|
85774
|
+
await writeFile20(join18(skillDir, "SKILL.md"), renderGeneratedSkillContent(skill.name, nonDottedPaths), "utf8");
|
|
85775
|
+
})));
|
|
84271
85776
|
return SKILLS.map((skill) => ({
|
|
84272
85777
|
...skill,
|
|
84273
85778
|
directoryName: skill.name
|
|
@@ -84279,15 +85784,15 @@ function getGeneratedSkillMetadata() {
|
|
|
84279
85784
|
directoryName: skill.name
|
|
84280
85785
|
}));
|
|
84281
85786
|
}
|
|
84282
|
-
async function
|
|
84283
|
-
const
|
|
84284
|
-
await mkdir13(skillsDir, { recursive: true });
|
|
84285
|
-
return
|
|
85787
|
+
async function ensureSkillsDirectories(targetDir) {
|
|
85788
|
+
const skillsDirs = SKILL_TARGET_ROOTS.map((root) => join18(targetDir, root, "skills"));
|
|
85789
|
+
await Promise.all(skillsDirs.map((skillsDir) => mkdir13(skillsDir, { recursive: true })));
|
|
85790
|
+
return skillsDirs;
|
|
84286
85791
|
}
|
|
84287
85792
|
async function copyDirectoryContents(sourceDir, targetDir) {
|
|
84288
|
-
const entries = await
|
|
85793
|
+
const entries = await readdir11(sourceDir, { withFileTypes: true });
|
|
84289
85794
|
await Promise.all(entries.map(async (entry) => {
|
|
84290
|
-
await cp(
|
|
85795
|
+
await cp(join18(sourceDir, entry.name), join18(targetDir, entry.name), {
|
|
84291
85796
|
recursive: true,
|
|
84292
85797
|
force: true
|
|
84293
85798
|
});
|
|
@@ -84324,14 +85829,14 @@ ${schemaDocs.join(`
|
|
|
84324
85829
|
`)}`;
|
|
84325
85830
|
}
|
|
84326
85831
|
async function readSkillMetadataFromDirectory(skillsDir) {
|
|
84327
|
-
const entries = await
|
|
85832
|
+
const entries = await readdir11(skillsDir, { withFileTypes: true });
|
|
84328
85833
|
const skills = [];
|
|
84329
85834
|
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
84330
85835
|
if (!entry.isDirectory()) {
|
|
84331
85836
|
continue;
|
|
84332
85837
|
}
|
|
84333
|
-
const skillPath =
|
|
84334
|
-
if (!await
|
|
85838
|
+
const skillPath = join18(skillsDir, entry.name, "SKILL.md");
|
|
85839
|
+
if (!await stat18(skillPath).catch(() => null)) {
|
|
84335
85840
|
continue;
|
|
84336
85841
|
}
|
|
84337
85842
|
const content = await readTextFile(skillPath);
|
|
@@ -84367,10 +85872,10 @@ function parseSkillMetadata(content, fallbackName) {
|
|
|
84367
85872
|
return { name, description, directoryName: fallbackName };
|
|
84368
85873
|
}
|
|
84369
85874
|
async function writeProjectGuidanceFile(options) {
|
|
84370
|
-
if (!options.overwrite && await
|
|
85875
|
+
if (!options.overwrite && await stat18(options.targetPath).catch(() => null)) {
|
|
84371
85876
|
return false;
|
|
84372
85877
|
}
|
|
84373
|
-
await
|
|
85878
|
+
await writeFile20(options.targetPath, options.content, "utf8");
|
|
84374
85879
|
return true;
|
|
84375
85880
|
}
|
|
84376
85881
|
function formatSchemaForMarkdown(schemaYaml, schemaName, filePattern) {
|
|
@@ -84854,7 +86359,7 @@ function formatConfigReferenceJson() {
|
|
|
84854
86359
|
async function initAction(opts) {
|
|
84855
86360
|
let didBindWorkspace = false;
|
|
84856
86361
|
let boundProfile;
|
|
84857
|
-
if (await
|
|
86362
|
+
if (await stat19("wmill.yaml").catch(() => null)) {
|
|
84858
86363
|
info("wmill.yaml already exists, skipping config generation");
|
|
84859
86364
|
} else {
|
|
84860
86365
|
const { isGitRepository: isGitRepository2, getCurrentGitBranch: getCurrentGitBranch2 } = await Promise.resolve().then(() => (init_git(), exports_git));
|
|
@@ -84880,13 +86385,16 @@ async function initAction(opts) {
|
|
|
84880
86385
|
selectedProfile = profiles.length > 0 ? await getActiveWorkspace(opts) : undefined;
|
|
84881
86386
|
} else {
|
|
84882
86387
|
const activeProfile = await getActiveWorkspace(opts);
|
|
86388
|
+
const orderedProfiles = activeProfile ? [
|
|
86389
|
+
...profiles.filter((p) => p.name === activeProfile.name),
|
|
86390
|
+
...profiles.filter((p) => p.name !== activeProfile.name)
|
|
86391
|
+
] : profiles;
|
|
84883
86392
|
const selectedName = await Select.prompt({
|
|
84884
86393
|
message: "Select workspace profile",
|
|
84885
|
-
options:
|
|
84886
|
-
name: `${p.name} (${p.workspaceId} on ${p.remote})`,
|
|
86394
|
+
options: orderedProfiles.map((p) => ({
|
|
86395
|
+
name: `${p.name} (${p.workspaceId} on ${p.remote})${activeProfile?.name === p.name ? " — active" : ""}`,
|
|
84887
86396
|
value: p.name
|
|
84888
|
-
}))
|
|
84889
|
-
default: activeProfile?.name
|
|
86397
|
+
}))
|
|
84890
86398
|
});
|
|
84891
86399
|
selectedProfile = profiles.find((p) => p.name === selectedName);
|
|
84892
86400
|
}
|
|
@@ -84926,7 +86434,7 @@ async function initAction(opts) {
|
|
|
84926
86434
|
boundProfile = activeWorkspace;
|
|
84927
86435
|
}
|
|
84928
86436
|
}
|
|
84929
|
-
await
|
|
86437
|
+
await writeFile21("wmill.yaml", generateCommentedTemplate(branchName, undefined, wsBindings), "utf-8");
|
|
84930
86438
|
info(colors.green("wmill.yaml created with default settings"));
|
|
84931
86439
|
if (wsBindings && wsBindings.length > 0) {
|
|
84932
86440
|
didBindWorkspace = true;
|
|
@@ -84961,8 +86469,8 @@ async function initAction(opts) {
|
|
|
84961
86469
|
});
|
|
84962
86470
|
if (choice === "cancel") {
|
|
84963
86471
|
try {
|
|
84964
|
-
await
|
|
84965
|
-
await
|
|
86472
|
+
await rm5("wmill.yaml");
|
|
86473
|
+
await rm5("wmill-lock.yaml");
|
|
84966
86474
|
} catch {}
|
|
84967
86475
|
info("Init cancelled");
|
|
84968
86476
|
process.exit(0);
|
|
@@ -85012,7 +86520,7 @@ async function initAction(opts) {
|
|
|
85012
86520
|
if (guidanceResult.claudeWritten) {
|
|
85013
86521
|
info(colors.green("Created CLAUDE.md"));
|
|
85014
86522
|
}
|
|
85015
|
-
info(colors.green(`Created .claude/skills/ with ${guidanceResult.skillCount} skills`));
|
|
86523
|
+
info(colors.green(`Created .claude/skills/ and .agents/skills/ with ${guidanceResult.skillCount} skills`));
|
|
85016
86524
|
} catch (error2) {
|
|
85017
86525
|
if (error2 instanceof Error) {
|
|
85018
86526
|
warn(`Could not create guidance files: ${error2.message}`);
|
|
@@ -85047,7 +86555,7 @@ await __promiseAll([
|
|
|
85047
86555
|
init_conf(),
|
|
85048
86556
|
init_utils()
|
|
85049
86557
|
]);
|
|
85050
|
-
import * as
|
|
86558
|
+
import * as fs14 from "node:fs/promises";
|
|
85051
86559
|
async function pullJobs(opts, workspace) {
|
|
85052
86560
|
opts = await mergeConfigWithConfigFile(opts);
|
|
85053
86561
|
const ws = await resolveWorkspace({ ...opts, workspace });
|
|
@@ -85091,7 +86599,7 @@ Warning: Found ${workers.length} active worker(s) on the instance.`));
|
|
|
85091
86599
|
page++;
|
|
85092
86600
|
}
|
|
85093
86601
|
const completedPath = opts.completedOutput || "completed_jobs.json";
|
|
85094
|
-
await
|
|
86602
|
+
await fs14.writeFile(completedPath, JSON.stringify(completedJobs, null, 2));
|
|
85095
86603
|
info(colors.green(`Successfully pulled ${completedJobs.length} completed jobs to ${completedPath}`));
|
|
85096
86604
|
let queuedJobs = [];
|
|
85097
86605
|
page = 1;
|
|
@@ -85109,7 +86617,7 @@ Warning: Found ${workers.length} active worker(s) on the instance.`));
|
|
|
85109
86617
|
page++;
|
|
85110
86618
|
}
|
|
85111
86619
|
const queuedPath = opts.queuedOutput || "queued_jobs.json";
|
|
85112
|
-
await
|
|
86620
|
+
await fs14.writeFile(queuedPath, JSON.stringify(queuedJobs, null, 2));
|
|
85113
86621
|
info(colors.green(`Successfully pulled ${queuedJobs.length} queued jobs to ${queuedPath}`));
|
|
85114
86622
|
const allJobs = [...queuedJobs, ...completedJobs];
|
|
85115
86623
|
if (allJobs.length > 0) {
|
|
@@ -85984,8 +87492,8 @@ async function generateMetadata2(opts, folder) {
|
|
|
85984
87492
|
info("");
|
|
85985
87493
|
if (errors.length > 0) {
|
|
85986
87494
|
info(`Done. Updated ${colors.bold(String(succeeded))}/${total} item(s). ${colors.red(String(errors.length) + " failed")}:`);
|
|
85987
|
-
for (const { path:
|
|
85988
|
-
error(` ${
|
|
87495
|
+
for (const { path: path21, error: error2 } of errors) {
|
|
87496
|
+
error(` ${path21}: ${error2}`);
|
|
85989
87497
|
}
|
|
85990
87498
|
process.exitCode = 1;
|
|
85991
87499
|
} else {
|
|
@@ -86072,8 +87580,8 @@ var docs_default = command34;
|
|
|
86072
87580
|
init_mod3();
|
|
86073
87581
|
init_log();
|
|
86074
87582
|
init_colors2();
|
|
86075
|
-
var
|
|
86076
|
-
import { writeFile as
|
|
87583
|
+
var import_yaml41 = __toESM(require_dist(), 1);
|
|
87584
|
+
import { writeFile as writeFile23 } from "node:fs/promises";
|
|
86077
87585
|
await __promiseAll([
|
|
86078
87586
|
init_conf(),
|
|
86079
87587
|
init_yaml()
|
|
@@ -86127,7 +87635,7 @@ async function migrateAction() {
|
|
|
86127
87635
|
} else {
|
|
86128
87636
|
newConf.workspaces = workspaces;
|
|
86129
87637
|
}
|
|
86130
|
-
await
|
|
87638
|
+
await writeFile23(wmillYamlPath, import_yaml41.stringify(newConf), "utf-8");
|
|
86131
87639
|
info(colors.green(`✅ Migrated '${legacyKey}' to 'workspaces' in ${wmillYamlPath}`));
|
|
86132
87640
|
if (wsNames.length > 0) {
|
|
86133
87641
|
info(` Workspace entries: ${wsNames.join(", ")}`);
|
|
@@ -86141,7 +87649,7 @@ var config_default = command35;
|
|
|
86141
87649
|
|
|
86142
87650
|
// src/main.ts
|
|
86143
87651
|
await init_context();
|
|
86144
|
-
var VERSION = "1.
|
|
87652
|
+
var VERSION = "1.692.0";
|
|
86145
87653
|
async function checkVersionSafe(cmd) {
|
|
86146
87654
|
const mainCommand = cmd.getMainCommand();
|
|
86147
87655
|
const upgradeCommand = mainCommand.getCommand("upgrade");
|