windmill-cli 1.722.0 → 1.723.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/esm/main.js +2069 -1863
- package/package.json +1 -1
package/esm/main.js
CHANGED
|
@@ -16772,7 +16772,7 @@ var init_OpenAPI = __esm(() => {
|
|
|
16772
16772
|
PASSWORD: undefined,
|
|
16773
16773
|
TOKEN: getEnv3("WM_TOKEN"),
|
|
16774
16774
|
USERNAME: undefined,
|
|
16775
|
-
VERSION: "1.
|
|
16775
|
+
VERSION: "1.723.0",
|
|
16776
16776
|
WITH_CREDENTIALS: true,
|
|
16777
16777
|
interceptors: {
|
|
16778
16778
|
request: new Interceptors,
|
|
@@ -25304,16 +25304,18 @@ var init_auth = __esm(async () => {
|
|
|
25304
25304
|
});
|
|
25305
25305
|
|
|
25306
25306
|
// src/core/constants.ts
|
|
25307
|
-
var WM_FORK_PREFIX = "wm-fork", VERSION = "1.
|
|
25307
|
+
var WM_FORK_PREFIX = "wm-fork", VERSION = "1.723.0";
|
|
25308
25308
|
|
|
25309
25309
|
// src/utils/git.ts
|
|
25310
25310
|
var exports_git = {};
|
|
25311
25311
|
__export(exports_git, {
|
|
25312
|
+
renameCurrentGitBranch: () => renameCurrentGitBranch,
|
|
25312
25313
|
isGitRepository: () => isGitRepository,
|
|
25313
25314
|
isForkWorkspace: () => isForkWorkspace,
|
|
25314
25315
|
gitSyncIncludePattern: () => gitSyncIncludePattern,
|
|
25315
25316
|
gitSyncDeployPush: () => gitSyncDeployPush,
|
|
25316
25317
|
gitSyncCommitMessage: () => gitSyncCommitMessage,
|
|
25318
|
+
gitBranchExists: () => gitBranchExists,
|
|
25317
25319
|
getWorkspaceIdForWorkspaceForkFromBranchName: () => getWorkspaceIdForWorkspaceForkFromBranchName,
|
|
25318
25320
|
getOriginalBranchForWorkspaceForks: () => getOriginalBranchForWorkspaceForks,
|
|
25319
25321
|
getCurrentGitBranch: () => getCurrentGitBranch,
|
|
@@ -25337,6 +25339,19 @@ function getCurrentGitBranch() {
|
|
|
25337
25339
|
return null;
|
|
25338
25340
|
}
|
|
25339
25341
|
}
|
|
25342
|
+
function gitBranchExists(branchName) {
|
|
25343
|
+
const r = spawnSync("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branchName}`], { stdio: "pipe" });
|
|
25344
|
+
return r.status === 0;
|
|
25345
|
+
}
|
|
25346
|
+
function renameCurrentGitBranch(newName) {
|
|
25347
|
+
const r = spawnSync("git", ["branch", "-m", newName], {
|
|
25348
|
+
encoding: "utf8",
|
|
25349
|
+
stdio: "pipe"
|
|
25350
|
+
});
|
|
25351
|
+
if ((r.status ?? 1) !== 0) {
|
|
25352
|
+
throw new Error(`git branch -m ${newName} failed (exit ${r.status}): ${r.stderr ?? ""}`);
|
|
25353
|
+
}
|
|
25354
|
+
}
|
|
25340
25355
|
function getOriginalBranchForWorkspaceForks(branchName) {
|
|
25341
25356
|
if (!branchName || !branchName.startsWith(WM_FORK_PREFIX)) {
|
|
25342
25357
|
return null;
|
|
@@ -25578,1898 +25593,2027 @@ var init_git = __esm(() => {
|
|
|
25578
25593
|
FORK_WORKSPACE_PREFIX = `${WM_FORK_PREFIX}-`;
|
|
25579
25594
|
});
|
|
25580
25595
|
|
|
25581
|
-
// src/
|
|
25582
|
-
|
|
25583
|
-
|
|
25584
|
-
|
|
25585
|
-
|
|
25586
|
-
|
|
25587
|
-
if (!
|
|
25588
|
-
|
|
25589
|
-
|
|
25590
|
-
info(`You are forking workspace (${workspace.workspaceId})`);
|
|
25591
|
-
const currentBranch = getCurrentGitBranch();
|
|
25592
|
-
if (!currentBranch) {
|
|
25593
|
-
throw new Error("Could not get git branch name");
|
|
25594
|
-
}
|
|
25595
|
-
const originalBranchIfForked = getOriginalBranchForWorkspaceForks(currentBranch);
|
|
25596
|
-
let clonedBranchName;
|
|
25597
|
-
if (originalBranchIfForked) {
|
|
25598
|
-
info(`You are creating a fork of a fork. The branch will be linked to the original branch this was forked from, i.e. \`${originalBranchIfForked}\`, for all settings and overrides.`);
|
|
25599
|
-
clonedBranchName = originalBranchIfForked;
|
|
25600
|
-
} else {
|
|
25601
|
-
clonedBranchName = currentBranch;
|
|
25602
|
-
}
|
|
25603
|
-
if (!clonedBranchName) {
|
|
25604
|
-
throw new Error("Failed to get current branch name, aborting operation");
|
|
25596
|
+
// src/utils/resource_folders.ts
|
|
25597
|
+
import { sep as SEP2 } from "node:path";
|
|
25598
|
+
import * as fs6 from "node:fs";
|
|
25599
|
+
import * as path2 from "node:path";
|
|
25600
|
+
import process9 from "node:process";
|
|
25601
|
+
function setNonDottedPaths(value) {
|
|
25602
|
+
if (value && !_nonDottedPathsLogged) {
|
|
25603
|
+
debug("Using non-dotted paths (__flow, __app, __raw_app)");
|
|
25604
|
+
_nonDottedPathsLogged = true;
|
|
25605
25605
|
}
|
|
25606
|
-
|
|
25607
|
-
|
|
25608
|
-
|
|
25606
|
+
_nonDottedPaths = value;
|
|
25607
|
+
}
|
|
25608
|
+
function getNonDottedPaths() {
|
|
25609
|
+
return _nonDottedPaths;
|
|
25610
|
+
}
|
|
25611
|
+
async function loadNonDottedPathsSetting() {
|
|
25612
|
+
let currentDir = process9.cwd();
|
|
25613
|
+
while (true) {
|
|
25614
|
+
const wmillYamlPath = path2.join(currentDir, "wmill.yaml");
|
|
25615
|
+
if (fs6.existsSync(wmillYamlPath)) {
|
|
25616
|
+
try {
|
|
25617
|
+
const config = await yamlParseFile(wmillYamlPath);
|
|
25618
|
+
setNonDottedPaths(config?.nonDottedPaths ?? false);
|
|
25619
|
+
debug(`Found wmill.yaml at ${wmillYamlPath}, nonDottedPaths=${config?.nonDottedPaths ?? false}`);
|
|
25620
|
+
} catch (e) {
|
|
25621
|
+
debug(`Failed to parse wmill.yaml at ${wmillYamlPath}: ${e}`);
|
|
25622
|
+
}
|
|
25623
|
+
return;
|
|
25624
|
+
}
|
|
25625
|
+
const parentDir = path2.dirname(currentDir);
|
|
25626
|
+
if (parentDir === currentDir) {
|
|
25627
|
+
debug("No wmill.yaml found, using default dotted paths");
|
|
25628
|
+
return;
|
|
25629
|
+
}
|
|
25630
|
+
currentDir = parentDir;
|
|
25609
25631
|
}
|
|
25610
|
-
|
|
25611
|
-
|
|
25612
|
-
|
|
25632
|
+
}
|
|
25633
|
+
function getFolderSuffixes() {
|
|
25634
|
+
return _nonDottedPaths ? NON_DOTTED_SUFFIXES : DOTTED_SUFFIXES;
|
|
25635
|
+
}
|
|
25636
|
+
function getFolderSuffix(type) {
|
|
25637
|
+
return getFolderSuffixes()[type];
|
|
25638
|
+
}
|
|
25639
|
+
function getMetadataFileName(type, format6) {
|
|
25640
|
+
return METADATA_FILES[type][format6];
|
|
25641
|
+
}
|
|
25642
|
+
function getMetadataPathSuffix(type, format6) {
|
|
25643
|
+
return getFolderSuffixes()[type] + "/" + METADATA_FILES[type][format6];
|
|
25644
|
+
}
|
|
25645
|
+
function hasWrongFormatSuffix(dirName) {
|
|
25646
|
+
const wrongSuffixes = _nonDottedPaths ? DOTTED_SUFFIXES : NON_DOTTED_SUFFIXES;
|
|
25647
|
+
for (const [type, suffix] of Object.entries(wrongSuffixes)) {
|
|
25648
|
+
if (dirName.endsWith(suffix)) {
|
|
25649
|
+
return type;
|
|
25613
25650
|
}
|
|
25614
25651
|
}
|
|
25615
|
-
|
|
25616
|
-
|
|
25617
|
-
|
|
25618
|
-
|
|
25619
|
-
|
|
25620
|
-
|
|
25652
|
+
return null;
|
|
25653
|
+
}
|
|
25654
|
+
function normalizeSep(p) {
|
|
25655
|
+
return p.replaceAll("\\", "/");
|
|
25656
|
+
}
|
|
25657
|
+
function isFlowPath(p) {
|
|
25658
|
+
return normalizeSep(p).includes(getFolderSuffixes().flow + "/");
|
|
25659
|
+
}
|
|
25660
|
+
function isAppPath(p) {
|
|
25661
|
+
return normalizeSep(p).includes(getFolderSuffixes().app + "/");
|
|
25662
|
+
}
|
|
25663
|
+
function isRawAppPath(p) {
|
|
25664
|
+
return normalizeSep(p).includes(getFolderSuffixes().raw_app + "/");
|
|
25665
|
+
}
|
|
25666
|
+
function isFolderResourcePathAnyFormat(p) {
|
|
25667
|
+
const n = normalizeSep(p);
|
|
25668
|
+
for (const suffixes of [DOTTED_SUFFIXES, NON_DOTTED_SUFFIXES]) {
|
|
25669
|
+
if (n.includes(suffixes.flow + "/") || n.includes(suffixes.app + "/") || n.includes(suffixes.raw_app + "/")) {
|
|
25670
|
+
return true;
|
|
25671
|
+
}
|
|
25621
25672
|
}
|
|
25622
|
-
|
|
25623
|
-
|
|
25624
|
-
|
|
25673
|
+
return false;
|
|
25674
|
+
}
|
|
25675
|
+
function isAppInlineScriptPath(filePath) {
|
|
25676
|
+
const suffixes = getFolderSuffixes();
|
|
25677
|
+
const normalizedPath = filePath.replaceAll(SEP2, "/");
|
|
25678
|
+
const escapedSuffix = suffixes.app.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
25679
|
+
const pattern = new RegExp(`${escapedSuffix}/`);
|
|
25680
|
+
return pattern.test(normalizedPath);
|
|
25681
|
+
}
|
|
25682
|
+
function isFlowInlineScriptPath(filePath) {
|
|
25683
|
+
const suffixes = getFolderSuffixes();
|
|
25684
|
+
const normalizedPath = filePath.replaceAll(SEP2, "/");
|
|
25685
|
+
const escapedSuffix = suffixes.flow.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
25686
|
+
const pattern = new RegExp(`${escapedSuffix}/`);
|
|
25687
|
+
return pattern.test(normalizedPath);
|
|
25688
|
+
}
|
|
25689
|
+
function extractResourceName(p, type) {
|
|
25690
|
+
const normalized = normalizeSep(p);
|
|
25691
|
+
const suffix = getFolderSuffixes()[type] + "/";
|
|
25692
|
+
const index = normalized.indexOf(suffix);
|
|
25693
|
+
if (index === -1)
|
|
25694
|
+
return null;
|
|
25695
|
+
return normalized.substring(0, index);
|
|
25696
|
+
}
|
|
25697
|
+
function extractFolderPath(p, type) {
|
|
25698
|
+
const normalized = normalizeSep(p);
|
|
25699
|
+
const suffix = getFolderSuffixes()[type] + "/";
|
|
25700
|
+
const index = normalized.indexOf(suffix);
|
|
25701
|
+
if (index === -1)
|
|
25702
|
+
return null;
|
|
25703
|
+
return normalized.substring(0, index) + suffix;
|
|
25704
|
+
}
|
|
25705
|
+
function buildFolderPath(resourceName, type) {
|
|
25706
|
+
return resourceName + getFolderSuffixes()[type];
|
|
25707
|
+
}
|
|
25708
|
+
function hasFolderSuffix(dirName, type) {
|
|
25709
|
+
return dirName.endsWith(getFolderSuffixes()[type]);
|
|
25710
|
+
}
|
|
25711
|
+
function extractNameFromFolder(folderName, type) {
|
|
25712
|
+
const suffix = getFolderSuffixes()[type];
|
|
25713
|
+
if (folderName.endsWith(suffix)) {
|
|
25714
|
+
return folderName.substring(0, folderName.length - suffix.length);
|
|
25625
25715
|
}
|
|
25626
|
-
|
|
25627
|
-
|
|
25628
|
-
|
|
25629
|
-
|
|
25630
|
-
|
|
25631
|
-
try {
|
|
25632
|
-
alreadyExists = await existsWorkspace({
|
|
25633
|
-
requestBody: { id: trueWorkspaceId }
|
|
25634
|
-
});
|
|
25635
|
-
} catch (e) {
|
|
25636
|
-
info(colors.red.bold("! Credentials or instance is invalid. Aborting."));
|
|
25637
|
-
throw e;
|
|
25716
|
+
return folderName;
|
|
25717
|
+
}
|
|
25718
|
+
function isFlowMetadataFile(p) {
|
|
25719
|
+
if (p.endsWith(DOTTED_SUFFIXES.flow + ".json") || p.endsWith(DOTTED_SUFFIXES.flow + ".yaml")) {
|
|
25720
|
+
return true;
|
|
25638
25721
|
}
|
|
25639
|
-
if (
|
|
25640
|
-
|
|
25722
|
+
if (_nonDottedPaths) {
|
|
25723
|
+
return p.endsWith(NON_DOTTED_SUFFIXES.flow + ".json") || p.endsWith(NON_DOTTED_SUFFIXES.flow + ".yaml");
|
|
25641
25724
|
}
|
|
25642
|
-
|
|
25643
|
-
|
|
25644
|
-
|
|
25645
|
-
|
|
25646
|
-
|
|
25647
|
-
});
|
|
25648
|
-
} catch (e) {
|
|
25649
|
-
info(colors.yellow(`Note: Could not list datatables: ${e.message}`));
|
|
25725
|
+
return false;
|
|
25726
|
+
}
|
|
25727
|
+
function isAppMetadataFile(p) {
|
|
25728
|
+
if (p.endsWith(DOTTED_SUFFIXES.app + ".json") || p.endsWith(DOTTED_SUFFIXES.app + ".yaml")) {
|
|
25729
|
+
return true;
|
|
25650
25730
|
}
|
|
25651
|
-
if (
|
|
25652
|
-
|
|
25653
|
-
if (behavior !== "skip") {
|
|
25654
|
-
info(`
|
|
25655
|
-
Found ${datatables.length} datatable(s):`);
|
|
25656
|
-
for (const dt of datatables) {
|
|
25657
|
-
let dtBehavior;
|
|
25658
|
-
if (behavior === "schema_only" || behavior === "schema_and_data") {
|
|
25659
|
-
dtBehavior = behavior;
|
|
25660
|
-
} else {
|
|
25661
|
-
const { Select: Select2 } = await init_select().then(() => exports_select);
|
|
25662
|
-
dtBehavior = await Select2.prompt({
|
|
25663
|
-
message: `Datatable "${dt.name}" (${dt.resource_type}):`,
|
|
25664
|
-
options: [
|
|
25665
|
-
{ name: "Keep original (no cloning)", value: "keep_original" },
|
|
25666
|
-
{ name: "Clone schema only", value: "schema_only" },
|
|
25667
|
-
{ name: "Clone schema and data", value: "schema_and_data" }
|
|
25668
|
-
]
|
|
25669
|
-
});
|
|
25670
|
-
}
|
|
25671
|
-
if (dtBehavior === "keep_original") {
|
|
25672
|
-
continue;
|
|
25673
|
-
}
|
|
25674
|
-
const newDbName = `${trueWorkspaceId.replace(/-/g, "_")}__${dt.name}`;
|
|
25675
|
-
try {
|
|
25676
|
-
info(colors.blue(` Creating database "${newDbName}" for datatable "${dt.name}"...`));
|
|
25677
|
-
await createPgDatabase({
|
|
25678
|
-
workspace: workspace.workspaceId,
|
|
25679
|
-
requestBody: {
|
|
25680
|
-
source: `datatable://${dt.name}`,
|
|
25681
|
-
target_dbname: newDbName
|
|
25682
|
-
}
|
|
25683
|
-
});
|
|
25684
|
-
info(colors.blue(` Importing ${dtBehavior === "schema_only" ? "schema" : "schema + data"}...`));
|
|
25685
|
-
await importPgDatabase({
|
|
25686
|
-
workspace: workspace.workspaceId,
|
|
25687
|
-
requestBody: {
|
|
25688
|
-
source: `datatable://${dt.name}`,
|
|
25689
|
-
target: `datatable://${dt.name}`,
|
|
25690
|
-
target_dbname_override: newDbName,
|
|
25691
|
-
fork_behavior: dtBehavior
|
|
25692
|
-
}
|
|
25693
|
-
});
|
|
25694
|
-
info(colors.green(` ✓ Datatable "${dt.name}" cloned.`));
|
|
25695
|
-
forkedDatatables.push({ name: dt.name, new_dbname: newDbName });
|
|
25696
|
-
} catch (e) {
|
|
25697
|
-
info(colors.yellow(` ✗ Failed to clone datatable "${dt.name}": ${e.message}`));
|
|
25698
|
-
}
|
|
25699
|
-
}
|
|
25700
|
-
}
|
|
25731
|
+
if (_nonDottedPaths) {
|
|
25732
|
+
return p.endsWith(NON_DOTTED_SUFFIXES.app + ".json") || p.endsWith(NON_DOTTED_SUFFIXES.app + ".yaml");
|
|
25701
25733
|
}
|
|
25702
|
-
|
|
25703
|
-
|
|
25704
|
-
|
|
25705
|
-
|
|
25706
|
-
|
|
25707
|
-
id: trueWorkspaceId,
|
|
25708
|
-
name: opts.createWorkspaceName ?? workspaceName ?? trueWorkspaceId,
|
|
25709
|
-
color: forkColor
|
|
25710
|
-
}
|
|
25711
|
-
});
|
|
25712
|
-
if (gitSyncJobIds && gitSyncJobIds.length > 0) {
|
|
25713
|
-
info(colors.blue(`Git sync branch creation triggered (${gitSyncJobIds.length} job(s)). These will complete asynchronously.`));
|
|
25714
|
-
}
|
|
25715
|
-
} catch (e) {
|
|
25716
|
-
error(colors.red(`Failed to create git branch for fork: ${e.message}`));
|
|
25717
|
-
throw e;
|
|
25734
|
+
return false;
|
|
25735
|
+
}
|
|
25736
|
+
function isRawAppMetadataFile(p) {
|
|
25737
|
+
if (p.endsWith(DOTTED_SUFFIXES.raw_app + ".json") || p.endsWith(DOTTED_SUFFIXES.raw_app + ".yaml")) {
|
|
25738
|
+
return true;
|
|
25718
25739
|
}
|
|
25719
|
-
|
|
25720
|
-
|
|
25721
|
-
workspace: workspace.workspaceId,
|
|
25722
|
-
requestBody: {
|
|
25723
|
-
id: trueWorkspaceId,
|
|
25724
|
-
name: opts.createWorkspaceName ?? workspaceName ?? trueWorkspaceId,
|
|
25725
|
-
color: forkColor,
|
|
25726
|
-
forked_datatables: forkedDatatables
|
|
25727
|
-
}
|
|
25728
|
-
});
|
|
25729
|
-
info(colors.green(`✅ ${result}`));
|
|
25730
|
-
} catch (error2) {
|
|
25731
|
-
error(colors.red(`Failed to create forked workspace: ${error2.message}`));
|
|
25732
|
-
throw error2;
|
|
25740
|
+
if (_nonDottedPaths) {
|
|
25741
|
+
return p.endsWith(NON_DOTTED_SUFFIXES.raw_app + ".json") || p.endsWith(NON_DOTTED_SUFFIXES.raw_app + ".yaml");
|
|
25733
25742
|
}
|
|
25734
|
-
|
|
25735
|
-
info(`Created forked workspace ${trueWorkspaceId}. To start contributing to your fork, create and push edits to the branch \`${newBranchName}\` by using the command:
|
|
25736
|
-
|
|
25737
|
-
` + colors.white(`git checkout -b ${newBranchName}`) + `
|
|
25738
|
-
|
|
25739
|
-
When doing operations on the forked workspace, it will use the remote setup in the workspaces section for the branch it was forked from.
|
|
25740
|
-
|
|
25741
|
-
To merge changes back to the parent workspace, you can:
|
|
25742
|
-
- Use the CLI: ` + colors.white(`git checkout ${newBranchName} && wmill workspace merge`) + `
|
|
25743
|
-
- Use the Merge UI from the forked workspace home page
|
|
25744
|
-
- Use git: ` + colors.white(`git checkout ${clonedBranchName} && git merge ${newBranchName} && wmill sync push`) + `
|
|
25745
|
-
See: https://www.windmill.dev/docs/advanced/workspace_forks`);
|
|
25743
|
+
return false;
|
|
25746
25744
|
}
|
|
25747
|
-
|
|
25748
|
-
|
|
25749
|
-
|
|
25750
|
-
|
|
25751
|
-
|
|
25752
|
-
|
|
25753
|
-
|
|
25754
|
-
|
|
25755
|
-
|
|
25756
|
-
|
|
25757
|
-
|
|
25758
|
-
|
|
25759
|
-
|
|
25760
|
-
|
|
25761
|
-
|
|
25762
|
-
|
|
25763
|
-
|
|
25764
|
-
|
|
25765
|
-
|
|
25766
|
-
|
|
25767
|
-
|
|
25768
|
-
|
|
25769
|
-
|
|
25770
|
-
|
|
25771
|
-
|
|
25772
|
-
|
|
25773
|
-
|
|
25774
|
-
|
|
25775
|
-
|
|
25776
|
-
|
|
25777
|
-
|
|
25778
|
-
|
|
25779
|
-
|
|
25780
|
-
|
|
25781
|
-
|
|
25782
|
-
|
|
25783
|
-
|
|
25784
|
-
|
|
25745
|
+
function isRawAppFolderMetadataFile(p) {
|
|
25746
|
+
return p.endsWith(getMetadataPathSuffix("raw_app", "yaml")) || p.endsWith(getMetadataPathSuffix("raw_app", "json"));
|
|
25747
|
+
}
|
|
25748
|
+
function isAppFolderMetadataFile(p) {
|
|
25749
|
+
return p.endsWith(getMetadataPathSuffix("app", "yaml")) || p.endsWith(getMetadataPathSuffix("app", "json"));
|
|
25750
|
+
}
|
|
25751
|
+
function isFlowFolderMetadataFile(p) {
|
|
25752
|
+
return p.endsWith(getMetadataPathSuffix("flow", "yaml")) || p.endsWith(getMetadataPathSuffix("flow", "json"));
|
|
25753
|
+
}
|
|
25754
|
+
function getModuleFolderSuffix() {
|
|
25755
|
+
return MODULE_SUFFIX;
|
|
25756
|
+
}
|
|
25757
|
+
function isScriptModulePath(p) {
|
|
25758
|
+
return normalizeSep(p).includes(MODULE_SUFFIX + "/");
|
|
25759
|
+
}
|
|
25760
|
+
function isModuleEntryPoint(p) {
|
|
25761
|
+
const norm = normalizeSep(p);
|
|
25762
|
+
const suffix = MODULE_SUFFIX + "/";
|
|
25763
|
+
const idx = norm.indexOf(suffix);
|
|
25764
|
+
if (idx === -1)
|
|
25765
|
+
return false;
|
|
25766
|
+
const rest = norm.slice(idx + suffix.length);
|
|
25767
|
+
return rest.startsWith("script.") && !rest.includes("/");
|
|
25768
|
+
}
|
|
25769
|
+
function getScriptBasePathFromModulePath(p) {
|
|
25770
|
+
const norm = normalizeSep(p);
|
|
25771
|
+
const suffix = MODULE_SUFFIX + "/";
|
|
25772
|
+
const idx = norm.indexOf(suffix);
|
|
25773
|
+
if (idx === -1)
|
|
25774
|
+
return;
|
|
25775
|
+
return norm.slice(0, idx);
|
|
25776
|
+
}
|
|
25777
|
+
function scriptPathToRemotePath(p) {
|
|
25778
|
+
return (isModuleEntryPoint(p) ? getScriptBasePathFromModulePath(p) : p.substring(0, p.indexOf("."))).replaceAll(SEP2, "/");
|
|
25779
|
+
}
|
|
25780
|
+
function getDeleteSuffix(type, format6) {
|
|
25781
|
+
return getFolderSuffixes()[type] + "/" + METADATA_FILES[type][format6];
|
|
25782
|
+
}
|
|
25783
|
+
function transformJsonPathToDir(p, type) {
|
|
25784
|
+
const apiSuffix = DOTTED_SUFFIXES[type] + ".json";
|
|
25785
|
+
if (p.endsWith(apiSuffix)) {
|
|
25786
|
+
const basePath = p.substring(0, p.length - apiSuffix.length);
|
|
25787
|
+
return basePath + getFolderSuffixes()[type];
|
|
25785
25788
|
}
|
|
25786
|
-
|
|
25787
|
-
|
|
25788
|
-
|
|
25789
|
-
});
|
|
25790
|
-
info(colors.green(`✅ Forked workspace '${forkWorkspaceId}' deleted successfully!
|
|
25791
|
-
${result}`));
|
|
25792
|
-
if (hasLocalProfile) {
|
|
25793
|
-
await removeWorkspace(name, false, opts);
|
|
25789
|
+
const userSuffix = getFolderSuffixes()[type] + ".json";
|
|
25790
|
+
if (p.endsWith(userSuffix)) {
|
|
25791
|
+
return p.substring(0, p.length - 5);
|
|
25794
25792
|
}
|
|
25793
|
+
return p;
|
|
25795
25794
|
}
|
|
25796
|
-
var
|
|
25797
|
-
|
|
25795
|
+
var DOTTED_SUFFIXES, NON_DOTTED_SUFFIXES, _nonDottedPaths = false, _nonDottedPathsLogged = false, METADATA_FILES, MODULE_SUFFIX = "__mod";
|
|
25796
|
+
var init_resource_folders = __esm(async () => {
|
|
25798
25797
|
init_log();
|
|
25799
|
-
|
|
25800
|
-
|
|
25801
|
-
|
|
25802
|
-
|
|
25803
|
-
|
|
25804
|
-
|
|
25805
|
-
|
|
25806
|
-
|
|
25798
|
+
await init_yaml();
|
|
25799
|
+
DOTTED_SUFFIXES = {
|
|
25800
|
+
flow: ".flow",
|
|
25801
|
+
app: ".app",
|
|
25802
|
+
raw_app: ".raw_app"
|
|
25803
|
+
};
|
|
25804
|
+
NON_DOTTED_SUFFIXES = {
|
|
25805
|
+
flow: "__flow",
|
|
25806
|
+
app: "__app",
|
|
25807
|
+
raw_app: "__raw_app"
|
|
25808
|
+
};
|
|
25809
|
+
METADATA_FILES = {
|
|
25810
|
+
flow: { yaml: "flow.yaml", json: "flow.json" },
|
|
25811
|
+
app: { yaml: "app.yaml", json: "app.json" },
|
|
25812
|
+
raw_app: { yaml: "raw_app.yaml", json: "raw_app.json" }
|
|
25813
|
+
};
|
|
25807
25814
|
});
|
|
25808
25815
|
|
|
25809
|
-
//
|
|
25810
|
-
|
|
25811
|
-
|
|
25812
|
-
|
|
25813
|
-
|
|
25814
|
-
|
|
25816
|
+
// src/core/conf.ts
|
|
25817
|
+
var exports_conf = {};
|
|
25818
|
+
__export(exports_conf, {
|
|
25819
|
+
validateBranchConfiguration: () => validateBranchConfiguration,
|
|
25820
|
+
showDiffs: () => showDiffs,
|
|
25821
|
+
setShowDiffs: () => setShowDiffs,
|
|
25822
|
+
readConfigFile: () => readConfigFile,
|
|
25823
|
+
parseSyncBehavior: () => parseSyncBehavior,
|
|
25824
|
+
mergeConfigWithConfigFile: () => mergeConfigWithConfigFile,
|
|
25825
|
+
getWorkspaceNames: () => getWorkspaceNames,
|
|
25826
|
+
getWmillYamlPath: () => getWmillYamlPath,
|
|
25827
|
+
getEffectiveWorkspaceId: () => getEffectiveWorkspaceId,
|
|
25828
|
+
getEffectiveSettings: () => getEffectiveSettings,
|
|
25829
|
+
getEffectiveGitBranch: () => getEffectiveGitBranch,
|
|
25830
|
+
findWorkspaceByGitBranch: () => findWorkspaceByGitBranch,
|
|
25831
|
+
convertGitBranchesToWorkspaces: () => convertGitBranchesToWorkspaces,
|
|
25832
|
+
SUPPORTED_SYNC_BEHAVIOR_VERSION: () => SUPPORTED_SYNC_BEHAVIOR_VERSION,
|
|
25833
|
+
GLOBAL_CONFIG_OPT: () => GLOBAL_CONFIG_OPT,
|
|
25834
|
+
DEFAULT_SYNC_OPTIONS: () => DEFAULT_SYNC_OPTIONS
|
|
25835
|
+
});
|
|
25836
|
+
import { join as join7, dirname as dirname6, resolve as resolve5, relative as relative4 } from "node:path";
|
|
25837
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
25838
|
+
import { writeFile } from "node:fs/promises";
|
|
25839
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
25840
|
+
function setShowDiffs(value) {
|
|
25841
|
+
showDiffs = value;
|
|
25815
25842
|
}
|
|
25816
|
-
function
|
|
25817
|
-
|
|
25843
|
+
function parseSyncBehavior(value) {
|
|
25844
|
+
if (!value && value !== 0)
|
|
25845
|
+
return 0;
|
|
25846
|
+
const s = String(value);
|
|
25847
|
+
const match = s.match(/^v(\d+)$/);
|
|
25848
|
+
return match ? parseInt(match[1], 10) : 0;
|
|
25818
25849
|
}
|
|
25819
|
-
function
|
|
25820
|
-
|
|
25821
|
-
|
|
25822
|
-
|
|
25823
|
-
|
|
25850
|
+
function getGitRepoRoot() {
|
|
25851
|
+
try {
|
|
25852
|
+
const result = execSync2("git rev-parse --show-toplevel", {
|
|
25853
|
+
encoding: "utf8",
|
|
25854
|
+
stdio: "pipe"
|
|
25855
|
+
});
|
|
25856
|
+
return result.trim();
|
|
25857
|
+
} catch (error2) {
|
|
25858
|
+
return null;
|
|
25859
|
+
}
|
|
25824
25860
|
}
|
|
25825
|
-
function
|
|
25826
|
-
const
|
|
25827
|
-
|
|
25828
|
-
|
|
25829
|
-
|
|
25830
|
-
|
|
25831
|
-
|
|
25832
|
-
|
|
25833
|
-
|
|
25834
|
-
|
|
25835
|
-
|
|
25836
|
-
} else if (type === "aiagent") {
|
|
25837
|
-
if (flowModule.value.tools) {
|
|
25838
|
-
return [
|
|
25839
|
-
flowModule.value.tools.filter((t) => t.value?.type === "script" || t.value?.type === "flow").map((t) => ({
|
|
25840
|
-
id: t.id,
|
|
25841
|
-
value: t.value,
|
|
25842
|
-
summary: t.summary
|
|
25843
|
-
}))
|
|
25844
|
-
];
|
|
25861
|
+
function findWmillYaml() {
|
|
25862
|
+
const startDir = resolve5(process.cwd());
|
|
25863
|
+
const isInGitRepo = isGitRepository();
|
|
25864
|
+
const gitRoot = isInGitRepo ? getGitRepoRoot() : null;
|
|
25865
|
+
let currentDir = startDir;
|
|
25866
|
+
let foundPath = null;
|
|
25867
|
+
while (true) {
|
|
25868
|
+
const wmillYamlPath = join7(currentDir, "wmill.yaml");
|
|
25869
|
+
if (existsSync2(wmillYamlPath)) {
|
|
25870
|
+
foundPath = wmillYamlPath;
|
|
25871
|
+
break;
|
|
25845
25872
|
}
|
|
25873
|
+
if (gitRoot && resolve5(currentDir) === resolve5(gitRoot)) {
|
|
25874
|
+
break;
|
|
25875
|
+
}
|
|
25876
|
+
const parentDir = dirname6(currentDir);
|
|
25877
|
+
if (parentDir === currentDir) {
|
|
25878
|
+
break;
|
|
25879
|
+
}
|
|
25880
|
+
currentDir = parentDir;
|
|
25846
25881
|
}
|
|
25847
|
-
|
|
25882
|
+
if (!GLOBAL_CONFIG_OPT.noCdToRoot && foundPath && resolve5(dirname6(foundPath)) !== resolve5(startDir)) {
|
|
25883
|
+
const configDir = dirname6(foundPath);
|
|
25884
|
+
const relativePath = relative4(startDir, foundPath);
|
|
25885
|
+
warn(`⚠️ wmill.yaml found in parent directory: ${relativePath}`);
|
|
25886
|
+
process.chdir(configDir);
|
|
25887
|
+
info(`\uD83D\uDCC1 Changed working directory to: ${configDir}`);
|
|
25888
|
+
}
|
|
25889
|
+
return foundPath;
|
|
25848
25890
|
}
|
|
25849
|
-
function
|
|
25850
|
-
return
|
|
25891
|
+
function getWmillYamlPath() {
|
|
25892
|
+
return findWmillYaml();
|
|
25851
25893
|
}
|
|
25852
|
-
function
|
|
25853
|
-
|
|
25854
|
-
...flowModules,
|
|
25855
|
-
...flowModules.flatMap((x) => getAllSubmodules(x)),
|
|
25856
|
-
...failureModule ? [failureModule] : []
|
|
25857
|
-
];
|
|
25858
|
-
}
|
|
25859
|
-
function toError(e) {
|
|
25860
|
-
const err = e;
|
|
25861
|
-
return err.body || err.message || String(e);
|
|
25862
|
-
}
|
|
25863
|
-
async function checkItemExists(provider, kind, path2, workspace) {
|
|
25864
|
-
if (kind === "flow") {
|
|
25865
|
-
return provider.existsFlowByPath({ workspace, path: path2 });
|
|
25866
|
-
} else if (kind === "script") {
|
|
25867
|
-
return provider.existsScriptByPath({ workspace, path: path2 });
|
|
25868
|
-
} else if (kind === "app" || kind === "raw_app") {
|
|
25869
|
-
return provider.existsApp({ workspace, path: path2 });
|
|
25870
|
-
} else if (kind === "variable") {
|
|
25871
|
-
return provider.existsVariable({ workspace, path: path2 });
|
|
25872
|
-
} else if (kind === "resource") {
|
|
25873
|
-
return provider.existsResource({ workspace, path: path2 });
|
|
25874
|
-
} else if (kind === "resource_type") {
|
|
25875
|
-
return provider.existsResourceType({ workspace, path: path2 });
|
|
25876
|
-
} else if (kind === "folder") {
|
|
25877
|
-
return provider.existsFolder({ workspace, name: folderName(path2) });
|
|
25878
|
-
} else if (kind === "schedule") {
|
|
25879
|
-
return provider.existsSchedule({ workspace, path: path2 });
|
|
25880
|
-
} else if (isTriggerKind(kind)) {
|
|
25881
|
-
return provider.existsTriggerByKind(kind, { workspace, path: path2 });
|
|
25882
|
-
}
|
|
25883
|
-
throw new Error(`Unknown kind: ${kind}`);
|
|
25884
|
-
}
|
|
25885
|
-
async function deployItem(provider, kind, path2, workspaceFrom, workspaceTo, onBehalfOf) {
|
|
25886
|
-
const preserveOnBehalfOf = onBehalfOf !== undefined;
|
|
25887
|
-
try {
|
|
25888
|
-
const alreadyExists = await checkItemExists(provider, kind, path2, workspaceTo);
|
|
25889
|
-
if (kind === "flow") {
|
|
25890
|
-
const flow = await provider.getFlowByPath({
|
|
25891
|
-
workspace: workspaceFrom,
|
|
25892
|
-
path: path2
|
|
25893
|
-
});
|
|
25894
|
-
getAllModules(flow.value?.modules ?? [], flow.value?.failure_module).forEach((x) => {
|
|
25895
|
-
if (x.value?.type === "script" && x.value.hash != null) {
|
|
25896
|
-
x.value.hash = undefined;
|
|
25897
|
-
}
|
|
25898
|
-
});
|
|
25899
|
-
if (alreadyExists) {
|
|
25900
|
-
await provider.updateFlow({
|
|
25901
|
-
workspace: workspaceTo,
|
|
25902
|
-
path: path2,
|
|
25903
|
-
requestBody: {
|
|
25904
|
-
...flow,
|
|
25905
|
-
preserve_on_behalf_of: preserveOnBehalfOf,
|
|
25906
|
-
on_behalf_of_email: onBehalfOf
|
|
25907
|
-
}
|
|
25908
|
-
});
|
|
25909
|
-
} else {
|
|
25910
|
-
await provider.createFlow({
|
|
25911
|
-
workspace: workspaceTo,
|
|
25912
|
-
requestBody: {
|
|
25913
|
-
...flow,
|
|
25914
|
-
preserve_on_behalf_of: preserveOnBehalfOf,
|
|
25915
|
-
on_behalf_of_email: onBehalfOf
|
|
25916
|
-
}
|
|
25917
|
-
});
|
|
25918
|
-
}
|
|
25919
|
-
} else if (kind === "script") {
|
|
25920
|
-
const script = await provider.getScriptByPath({
|
|
25921
|
-
workspace: workspaceFrom,
|
|
25922
|
-
path: path2
|
|
25923
|
-
});
|
|
25924
|
-
let parentHash;
|
|
25925
|
-
if (alreadyExists) {
|
|
25926
|
-
const existing = await provider.getScriptByPath({
|
|
25927
|
-
workspace: workspaceTo,
|
|
25928
|
-
path: path2
|
|
25929
|
-
});
|
|
25930
|
-
parentHash = existing.hash;
|
|
25931
|
-
}
|
|
25932
|
-
await provider.createScript({
|
|
25933
|
-
workspace: workspaceTo,
|
|
25934
|
-
requestBody: {
|
|
25935
|
-
...script,
|
|
25936
|
-
lock: script.lock,
|
|
25937
|
-
parent_hash: parentHash,
|
|
25938
|
-
preserve_on_behalf_of: preserveOnBehalfOf,
|
|
25939
|
-
on_behalf_of_email: onBehalfOf
|
|
25940
|
-
}
|
|
25941
|
-
});
|
|
25942
|
-
} else if (kind === "app" || kind === "raw_app") {
|
|
25943
|
-
const app = await provider.getAppByPath({
|
|
25944
|
-
workspace: workspaceFrom,
|
|
25945
|
-
path: path2
|
|
25946
|
-
});
|
|
25947
|
-
if (alreadyExists) {
|
|
25948
|
-
if (app.raw_app) {
|
|
25949
|
-
const secret = await provider.getPublicSecretOfLatestVersionOfApp({
|
|
25950
|
-
workspace: workspaceFrom,
|
|
25951
|
-
path: app.path
|
|
25952
|
-
});
|
|
25953
|
-
const js = await provider.getRawAppData({
|
|
25954
|
-
secretWithExtension: `${secret}.js`,
|
|
25955
|
-
workspace: workspaceFrom
|
|
25956
|
-
});
|
|
25957
|
-
const css = await provider.getRawAppData({
|
|
25958
|
-
secretWithExtension: `${secret}.css`,
|
|
25959
|
-
workspace: workspaceFrom
|
|
25960
|
-
});
|
|
25961
|
-
await provider.updateAppRaw({
|
|
25962
|
-
workspace: workspaceTo,
|
|
25963
|
-
path: path2,
|
|
25964
|
-
formData: {
|
|
25965
|
-
app: { ...app, preserve_on_behalf_of: preserveOnBehalfOf },
|
|
25966
|
-
css,
|
|
25967
|
-
js
|
|
25968
|
-
}
|
|
25969
|
-
});
|
|
25970
|
-
} else {
|
|
25971
|
-
await provider.updateApp({
|
|
25972
|
-
workspace: workspaceTo,
|
|
25973
|
-
path: path2,
|
|
25974
|
-
requestBody: {
|
|
25975
|
-
...app,
|
|
25976
|
-
preserve_on_behalf_of: preserveOnBehalfOf
|
|
25977
|
-
}
|
|
25978
|
-
});
|
|
25979
|
-
}
|
|
25980
|
-
} else {
|
|
25981
|
-
if (app.raw_app) {
|
|
25982
|
-
const secret = await provider.getPublicSecretOfLatestVersionOfApp({
|
|
25983
|
-
workspace: workspaceFrom,
|
|
25984
|
-
path: app.path
|
|
25985
|
-
});
|
|
25986
|
-
const js = await provider.getRawAppData({
|
|
25987
|
-
secretWithExtension: `${secret}.js`,
|
|
25988
|
-
workspace: workspaceFrom
|
|
25989
|
-
});
|
|
25990
|
-
const css = await provider.getRawAppData({
|
|
25991
|
-
secretWithExtension: `${secret}.css`,
|
|
25992
|
-
workspace: workspaceFrom
|
|
25993
|
-
});
|
|
25994
|
-
await provider.createAppRaw({
|
|
25995
|
-
workspace: workspaceTo,
|
|
25996
|
-
formData: {
|
|
25997
|
-
app: { ...app, preserve_on_behalf_of: preserveOnBehalfOf },
|
|
25998
|
-
css,
|
|
25999
|
-
js
|
|
26000
|
-
}
|
|
26001
|
-
});
|
|
26002
|
-
} else {
|
|
26003
|
-
await provider.createApp({
|
|
26004
|
-
workspace: workspaceTo,
|
|
26005
|
-
requestBody: {
|
|
26006
|
-
...app,
|
|
26007
|
-
preserve_on_behalf_of: preserveOnBehalfOf
|
|
26008
|
-
}
|
|
26009
|
-
});
|
|
26010
|
-
}
|
|
26011
|
-
}
|
|
26012
|
-
} else if (kind === "variable") {
|
|
26013
|
-
const variable = await provider.getVariable({
|
|
26014
|
-
workspace: workspaceFrom,
|
|
26015
|
-
path: path2,
|
|
26016
|
-
decryptSecret: true
|
|
26017
|
-
});
|
|
26018
|
-
if (alreadyExists) {
|
|
26019
|
-
await provider.updateVariable({
|
|
26020
|
-
workspace: workspaceTo,
|
|
26021
|
-
path: path2,
|
|
26022
|
-
requestBody: {
|
|
26023
|
-
path: path2,
|
|
26024
|
-
value: variable.value ?? "",
|
|
26025
|
-
is_secret: variable.is_secret,
|
|
26026
|
-
description: variable.description ?? ""
|
|
26027
|
-
},
|
|
26028
|
-
alreadyEncrypted: false
|
|
26029
|
-
});
|
|
26030
|
-
} else {
|
|
26031
|
-
await provider.createVariable({
|
|
26032
|
-
workspace: workspaceTo,
|
|
26033
|
-
requestBody: {
|
|
26034
|
-
path: path2,
|
|
26035
|
-
value: variable.value ?? "",
|
|
26036
|
-
is_secret: variable.is_secret,
|
|
26037
|
-
description: variable.description ?? ""
|
|
26038
|
-
}
|
|
26039
|
-
});
|
|
26040
|
-
}
|
|
26041
|
-
} else if (kind === "resource") {
|
|
26042
|
-
const resource = await provider.getResource({
|
|
26043
|
-
workspace: workspaceFrom,
|
|
26044
|
-
path: path2
|
|
26045
|
-
});
|
|
26046
|
-
if (alreadyExists) {
|
|
26047
|
-
await provider.updateResource({
|
|
26048
|
-
workspace: workspaceTo,
|
|
26049
|
-
path: path2,
|
|
26050
|
-
requestBody: {
|
|
26051
|
-
path: path2,
|
|
26052
|
-
value: resource.value ?? "",
|
|
26053
|
-
description: resource.description ?? ""
|
|
26054
|
-
}
|
|
26055
|
-
});
|
|
26056
|
-
} else {
|
|
26057
|
-
await provider.createResource({
|
|
26058
|
-
workspace: workspaceTo,
|
|
26059
|
-
requestBody: {
|
|
26060
|
-
path: path2,
|
|
26061
|
-
value: resource.value ?? "",
|
|
26062
|
-
resource_type: resource.resource_type,
|
|
26063
|
-
description: resource.description ?? ""
|
|
26064
|
-
}
|
|
26065
|
-
});
|
|
26066
|
-
}
|
|
26067
|
-
} else if (kind === "resource_type") {
|
|
26068
|
-
const rt = await provider.getResourceType({
|
|
26069
|
-
workspace: workspaceFrom,
|
|
26070
|
-
path: path2
|
|
26071
|
-
});
|
|
26072
|
-
if (alreadyExists) {
|
|
26073
|
-
await provider.updateResourceType({
|
|
26074
|
-
workspace: workspaceTo,
|
|
26075
|
-
path: path2,
|
|
26076
|
-
requestBody: {
|
|
26077
|
-
schema: rt.schema,
|
|
26078
|
-
description: rt.description ?? ""
|
|
26079
|
-
}
|
|
26080
|
-
});
|
|
26081
|
-
} else {
|
|
26082
|
-
await provider.createResourceType({
|
|
26083
|
-
workspace: workspaceTo,
|
|
26084
|
-
requestBody: {
|
|
26085
|
-
name: rt.name,
|
|
26086
|
-
schema: rt.schema,
|
|
26087
|
-
description: rt.description ?? ""
|
|
26088
|
-
}
|
|
26089
|
-
});
|
|
26090
|
-
}
|
|
26091
|
-
} else if (kind === "folder") {
|
|
26092
|
-
const name = folderName(path2);
|
|
26093
|
-
const folder = await provider.getFolder({
|
|
26094
|
-
workspace: workspaceFrom,
|
|
26095
|
-
name
|
|
26096
|
-
});
|
|
26097
|
-
if (alreadyExists) {
|
|
26098
|
-
await provider.updateFolder({
|
|
26099
|
-
workspace: workspaceTo,
|
|
26100
|
-
name,
|
|
26101
|
-
requestBody: {
|
|
26102
|
-
owners: folder.owners,
|
|
26103
|
-
extra_perms: folder.extra_perms,
|
|
26104
|
-
summary: folder.summary ?? undefined
|
|
26105
|
-
}
|
|
26106
|
-
});
|
|
26107
|
-
} else {
|
|
26108
|
-
await provider.createFolder({
|
|
26109
|
-
workspace: workspaceTo,
|
|
26110
|
-
requestBody: {
|
|
26111
|
-
name,
|
|
26112
|
-
owners: folder.owners,
|
|
26113
|
-
extra_perms: folder.extra_perms,
|
|
26114
|
-
summary: folder.summary ?? undefined
|
|
26115
|
-
}
|
|
26116
|
-
});
|
|
26117
|
-
}
|
|
26118
|
-
} else if (kind === "schedule") {
|
|
26119
|
-
const schedule = await provider.getSchedule({
|
|
26120
|
-
workspace: workspaceFrom,
|
|
26121
|
-
path: path2
|
|
26122
|
-
});
|
|
26123
|
-
const baseBody = stripOperationalStateOnUpdate(schedule, alreadyExists);
|
|
26124
|
-
const requestBody = {
|
|
26125
|
-
...baseBody,
|
|
26126
|
-
permissioned_as: onBehalfOf,
|
|
26127
|
-
preserve_permissioned_as: preserveOnBehalfOf
|
|
26128
|
-
};
|
|
26129
|
-
if (alreadyExists) {
|
|
26130
|
-
await provider.updateSchedule({
|
|
26131
|
-
workspace: workspaceTo,
|
|
26132
|
-
path: path2,
|
|
26133
|
-
requestBody
|
|
26134
|
-
});
|
|
26135
|
-
} else {
|
|
26136
|
-
await provider.createSchedule({
|
|
26137
|
-
workspace: workspaceTo,
|
|
26138
|
-
requestBody
|
|
26139
|
-
});
|
|
26140
|
-
}
|
|
26141
|
-
} else if (isTriggerKind(kind)) {
|
|
26142
|
-
const triggerBody = await provider.getTriggerForDeploy(kind, {
|
|
26143
|
-
workspace: workspaceFrom,
|
|
26144
|
-
path: path2,
|
|
26145
|
-
onBehalfOf
|
|
26146
|
-
});
|
|
26147
|
-
const requestBody = stripOperationalStateOnUpdate(triggerBody, alreadyExists);
|
|
26148
|
-
if (alreadyExists) {
|
|
26149
|
-
await provider.updateTriggerByKind(kind, {
|
|
26150
|
-
workspace: workspaceTo,
|
|
26151
|
-
path: path2,
|
|
26152
|
-
requestBody
|
|
26153
|
-
});
|
|
26154
|
-
} else {
|
|
26155
|
-
await provider.createTriggerByKind(kind, {
|
|
26156
|
-
workspace: workspaceTo,
|
|
26157
|
-
requestBody
|
|
26158
|
-
});
|
|
26159
|
-
}
|
|
26160
|
-
} else {
|
|
26161
|
-
throw new Error(`Unknown kind: ${kind}`);
|
|
26162
|
-
}
|
|
26163
|
-
return { success: true };
|
|
26164
|
-
} catch (e) {
|
|
26165
|
-
return { success: false, error: toError(e) };
|
|
26166
|
-
}
|
|
26167
|
-
}
|
|
26168
|
-
async function deleteItemInWorkspace(provider, kind, path2, workspace) {
|
|
26169
|
-
try {
|
|
26170
|
-
if (kind === "script") {
|
|
26171
|
-
await provider.archiveScriptByPath({ workspace, path: path2 });
|
|
26172
|
-
} else if (kind === "flow") {
|
|
26173
|
-
await provider.archiveFlowByPath({
|
|
26174
|
-
workspace,
|
|
26175
|
-
path: path2,
|
|
26176
|
-
requestBody: { archived: true }
|
|
26177
|
-
});
|
|
26178
|
-
} else if (kind === "app" || kind === "raw_app") {
|
|
26179
|
-
await provider.deleteApp({ workspace, path: path2 });
|
|
26180
|
-
} else if (kind === "variable") {
|
|
26181
|
-
await provider.deleteVariable({ workspace, path: path2 });
|
|
26182
|
-
} else if (kind === "resource") {
|
|
26183
|
-
await provider.deleteResource({ workspace, path: path2 });
|
|
26184
|
-
} else if (kind === "resource_type") {
|
|
26185
|
-
await provider.deleteResourceType({ workspace, path: path2 });
|
|
26186
|
-
} else if (kind === "folder") {
|
|
26187
|
-
await provider.deleteFolder({ workspace, name: folderName(path2) });
|
|
26188
|
-
} else if (kind === "schedule") {
|
|
26189
|
-
await provider.deleteSchedule({ workspace, path: path2 });
|
|
26190
|
-
} else if (isTriggerKind(kind)) {
|
|
26191
|
-
await provider.deleteTriggerByKind(kind, { workspace, path: path2 });
|
|
26192
|
-
} else {
|
|
26193
|
-
throw new Error(`Deletion not supported for kind: ${kind}`);
|
|
26194
|
-
}
|
|
26195
|
-
return { success: true };
|
|
26196
|
-
} catch (e) {
|
|
26197
|
-
return { success: false, error: toError(e) };
|
|
26198
|
-
}
|
|
26199
|
-
}
|
|
26200
|
-
async function getOnBehalfOf(provider, kind, path2, workspace) {
|
|
25894
|
+
async function readConfigFile(opts) {
|
|
25895
|
+
const warnIfMissing = opts?.warnIfMissing ?? true;
|
|
26201
25896
|
try {
|
|
26202
|
-
|
|
26203
|
-
|
|
26204
|
-
|
|
26205
|
-
|
|
26206
|
-
const script = await provider.getScriptByPath({ workspace, path: path2 });
|
|
26207
|
-
return script.on_behalf_of_email;
|
|
26208
|
-
} else if (kind === "app" || kind === "raw_app") {
|
|
26209
|
-
const app = await provider.getAppByPath({ workspace, path: path2 });
|
|
26210
|
-
return app.policy?.on_behalf_of_email;
|
|
26211
|
-
} else if (kind === "schedule") {
|
|
26212
|
-
const schedule = await provider.getSchedule({ workspace, path: path2 });
|
|
26213
|
-
return schedule.permissioned_as;
|
|
26214
|
-
} else if (isTriggerKind(kind)) {
|
|
26215
|
-
return await provider.getTriggerPermissionedAs(kind, { workspace, path: path2 });
|
|
26216
|
-
}
|
|
26217
|
-
} catch {}
|
|
26218
|
-
return;
|
|
26219
|
-
}
|
|
26220
|
-
var TRIGGER_KINDS;
|
|
26221
|
-
var init_deploy = __esm(() => {
|
|
26222
|
-
TRIGGER_KINDS = [
|
|
26223
|
-
"http_trigger",
|
|
26224
|
-
"websocket_trigger",
|
|
26225
|
-
"kafka_trigger",
|
|
26226
|
-
"nats_trigger",
|
|
26227
|
-
"postgres_trigger",
|
|
26228
|
-
"mqtt_trigger",
|
|
26229
|
-
"sqs_trigger",
|
|
26230
|
-
"gcp_trigger",
|
|
26231
|
-
"azure_trigger",
|
|
26232
|
-
"email_trigger"
|
|
26233
|
-
];
|
|
26234
|
-
});
|
|
26235
|
-
|
|
26236
|
-
// node_modules/@cliffy/prompt/checkbox.js
|
|
26237
|
-
var exports_checkbox = {};
|
|
26238
|
-
__export(exports_checkbox, {
|
|
26239
|
-
isCheckboxOptionGroup: () => isCheckboxOptionGroup,
|
|
26240
|
-
Checkbox: () => Checkbox
|
|
26241
|
-
});
|
|
26242
|
-
function areSomeChecked(options) {
|
|
26243
|
-
return options.some((option) => isOptionGroup(option) ? areSomeChecked(option.options) : option.checked);
|
|
26244
|
-
}
|
|
26245
|
-
function areAllChecked(options) {
|
|
26246
|
-
return options.every((option) => isOptionGroup(option) ? areAllChecked(option.options) : option.checked);
|
|
26247
|
-
}
|
|
26248
|
-
function flatOptions(options) {
|
|
26249
|
-
return flat(options);
|
|
26250
|
-
function flat(options2, indentLevel = 0, opts = []) {
|
|
26251
|
-
for (const option of options2) {
|
|
26252
|
-
option.indentLevel = indentLevel;
|
|
26253
|
-
if (isOption2(option)) {
|
|
26254
|
-
opts.push(option);
|
|
26255
|
-
}
|
|
26256
|
-
if (isOptionGroup(option)) {
|
|
26257
|
-
flat(option.options, ++indentLevel, opts);
|
|
25897
|
+
const wmillYamlPath = findWmillYaml();
|
|
25898
|
+
if (!wmillYamlPath) {
|
|
25899
|
+
if (warnIfMissing) {
|
|
25900
|
+
warn("No wmill.yaml found. Use 'wmill init' to bootstrap it.");
|
|
26258
25901
|
}
|
|
25902
|
+
return {};
|
|
26259
25903
|
}
|
|
26260
|
-
|
|
26261
|
-
|
|
26262
|
-
|
|
26263
|
-
|
|
26264
|
-
|
|
26265
|
-
|
|
26266
|
-
|
|
26267
|
-
|
|
26268
|
-
init_equal();
|
|
26269
|
-
init_colors();
|
|
26270
|
-
init__figures();
|
|
26271
|
-
await __promiseAll([
|
|
26272
|
-
init__generic_list(),
|
|
26273
|
-
init__generic_prompt()
|
|
26274
|
-
]);
|
|
26275
|
-
Checkbox = class Checkbox extends GenericList {
|
|
26276
|
-
settings;
|
|
26277
|
-
options;
|
|
26278
|
-
listIndex;
|
|
26279
|
-
listOffset;
|
|
26280
|
-
confirmSubmit = false;
|
|
26281
|
-
static prompt(options) {
|
|
26282
|
-
return new this(options).prompt();
|
|
26283
|
-
}
|
|
26284
|
-
static inject(value) {
|
|
26285
|
-
GenericPrompt.inject(value);
|
|
26286
|
-
}
|
|
26287
|
-
constructor(options) {
|
|
26288
|
-
super();
|
|
26289
|
-
this.settings = this.getDefaultSettings(options);
|
|
26290
|
-
this.options = this.settings.options.slice();
|
|
26291
|
-
this.listIndex = this.getListIndex();
|
|
26292
|
-
this.listOffset = this.getPageOffset(this.listIndex);
|
|
26293
|
-
}
|
|
26294
|
-
getDefaultSettings(options) {
|
|
26295
|
-
const settings = super.getDefaultSettings(options);
|
|
26296
|
-
return {
|
|
26297
|
-
confirmSubmit: true,
|
|
26298
|
-
...settings,
|
|
26299
|
-
check: options.check ?? green(Figures.TICK),
|
|
26300
|
-
uncheck: options.uncheck ?? red(Figures.CROSS),
|
|
26301
|
-
partialCheck: options.partialCheck ?? green(Figures.RADIO_ON),
|
|
26302
|
-
minOptions: options.minOptions ?? 0,
|
|
26303
|
-
maxOptions: options.maxOptions ?? Infinity,
|
|
26304
|
-
options: this.mapOptions(options, options.options),
|
|
26305
|
-
keys: {
|
|
26306
|
-
check: [
|
|
26307
|
-
"space"
|
|
26308
|
-
],
|
|
26309
|
-
checkAll: [
|
|
26310
|
-
"a"
|
|
26311
|
-
],
|
|
26312
|
-
...settings.keys ?? {},
|
|
26313
|
-
open: options.keys?.open ?? [
|
|
26314
|
-
"right"
|
|
26315
|
-
],
|
|
26316
|
-
back: options.keys?.back ?? [
|
|
26317
|
-
"left",
|
|
26318
|
-
"escape"
|
|
26319
|
-
]
|
|
26320
|
-
}
|
|
26321
|
-
};
|
|
26322
|
-
}
|
|
26323
|
-
mapOptions(promptOptions, options) {
|
|
26324
|
-
return options.map((option) => typeof option === "string" || typeof option === "number" ? this.mapOption(promptOptions, {
|
|
26325
|
-
value: option
|
|
26326
|
-
}) : isCheckboxOptionGroup(option) ? this.mapOptionGroup(promptOptions, option) : this.mapOption(promptOptions, option));
|
|
26327
|
-
}
|
|
26328
|
-
mapOption(options, option) {
|
|
26329
|
-
if (isOption2(option)) {
|
|
26330
|
-
return {
|
|
26331
|
-
...super.mapOption(options, option),
|
|
26332
|
-
checked: typeof option.checked === "undefined" && options.default && options.default.indexOf(option.value) !== -1 ? true : !!option.checked,
|
|
26333
|
-
icon: typeof option.icon === "undefined" ? true : option.icon
|
|
26334
|
-
};
|
|
25904
|
+
const conf = await yamlParseFile(wmillYamlPath);
|
|
25905
|
+
if (conf && "overrides" in conf) {
|
|
25906
|
+
const overrides = conf.overrides;
|
|
25907
|
+
const hasSettings = overrides && typeof overrides === "object" && Object.keys(overrides).length > 0;
|
|
25908
|
+
if (hasSettings) {
|
|
25909
|
+
throw new Error(`❌ The 'overrides' field is no longer supported.
|
|
25910
|
+
` + ` The configuration system now uses workspace-based configuration.
|
|
25911
|
+
` + " Please delete your wmill.yaml and run 'wmill init' to recreate it with the new format.");
|
|
26335
25912
|
} else {
|
|
26336
|
-
|
|
26337
|
-
...super.mapOption(options, option),
|
|
26338
|
-
checked: false,
|
|
26339
|
-
icon: false
|
|
26340
|
-
};
|
|
26341
|
-
}
|
|
26342
|
-
}
|
|
26343
|
-
mapOptionGroup(promptOptions, option) {
|
|
26344
|
-
const options = this.mapOptions(promptOptions, option.options);
|
|
26345
|
-
const optionGroup = super.mapOptionGroup(promptOptions, option, false);
|
|
26346
|
-
return {
|
|
26347
|
-
...optionGroup,
|
|
26348
|
-
get checked() {
|
|
26349
|
-
return areAllChecked(options);
|
|
26350
|
-
},
|
|
26351
|
-
get disabled() {
|
|
26352
|
-
return optionGroup.disabled || options.every((opt) => opt.disabled);
|
|
26353
|
-
},
|
|
26354
|
-
options,
|
|
26355
|
-
icon: typeof option.icon === "undefined" ? true : option.icon
|
|
26356
|
-
};
|
|
26357
|
-
}
|
|
26358
|
-
match() {
|
|
26359
|
-
super.match();
|
|
26360
|
-
if (this.isSearching()) {
|
|
26361
|
-
this.selectSearch();
|
|
26362
|
-
}
|
|
26363
|
-
}
|
|
26364
|
-
getListItemIcon(option) {
|
|
26365
|
-
return this.getCheckboxIcon(option) + super.getListItemIcon(option);
|
|
26366
|
-
}
|
|
26367
|
-
getCheckboxIcon(option) {
|
|
26368
|
-
if (!option.icon) {
|
|
26369
|
-
return "";
|
|
26370
|
-
}
|
|
26371
|
-
const icon = option.checked ? this.settings.check + " " : isOptionGroup(option) && areSomeChecked(option.options) ? this.settings.partialCheck + " " : this.settings.uncheck + " ";
|
|
26372
|
-
return option.disabled ? dim(icon) : icon;
|
|
26373
|
-
}
|
|
26374
|
-
getValue() {
|
|
26375
|
-
return flatOptions(this.settings.options).filter((option) => option.checked).map((option) => option.value);
|
|
26376
|
-
}
|
|
26377
|
-
async handleEvent(event) {
|
|
26378
|
-
const hasConfirmed = this.confirmSubmit;
|
|
26379
|
-
this.confirmSubmit = false;
|
|
26380
|
-
switch (true) {
|
|
26381
|
-
case (this.isKey(this.settings.keys, "check", event) && !this.isSearchSelected()):
|
|
26382
|
-
this.checkValue();
|
|
26383
|
-
break;
|
|
26384
|
-
case this.isKey(this.settings.keys, "submit", event):
|
|
26385
|
-
await this.submit(hasConfirmed);
|
|
26386
|
-
break;
|
|
26387
|
-
case (event.ctrl && this.isKey(this.settings.keys, "checkAll", event)):
|
|
26388
|
-
this.checkAllOption();
|
|
26389
|
-
break;
|
|
26390
|
-
default:
|
|
26391
|
-
await super.handleEvent(event);
|
|
26392
|
-
}
|
|
26393
|
-
}
|
|
26394
|
-
hint() {
|
|
26395
|
-
if (this.confirmSubmit) {
|
|
26396
|
-
const info2 = this.isBackButton(this.selectedOption) ? ` To leave the current group press ${getFiguresByKeys(this.settings.keys.back ?? []).join(", ")}.` : isOptionGroup(this.selectedOption) ? ` To open the selected group press ${getFiguresByKeys(this.settings.keys.open ?? []).join(", ")}.` : ` To check or uncheck the selected option press ${getFiguresByKeys(this.settings.keys.check ?? []).join(", ")}.`;
|
|
26397
|
-
return this.settings.indent + brightBlue(`Press ${getFiguresByKeys(this.settings.keys.submit ?? [])} again to submit.${info2}`);
|
|
26398
|
-
}
|
|
26399
|
-
return super.hint();
|
|
26400
|
-
}
|
|
26401
|
-
async submit(hasConfirmed) {
|
|
26402
|
-
if (!hasConfirmed && this.settings.confirmSubmit && !this.isSearchSelected()) {
|
|
26403
|
-
this.confirmSubmit = true;
|
|
26404
|
-
return;
|
|
25913
|
+
delete conf.overrides;
|
|
26405
25914
|
}
|
|
26406
|
-
await super.submit();
|
|
26407
25915
|
}
|
|
26408
|
-
|
|
26409
|
-
|
|
26410
|
-
|
|
26411
|
-
|
|
26412
|
-
|
|
26413
|
-
|
|
26414
|
-
|
|
26415
|
-
|
|
25916
|
+
if (conf && !conf.workspaces) {
|
|
25917
|
+
let legacyKey = null;
|
|
25918
|
+
let legacyData;
|
|
25919
|
+
if (conf.gitBranches) {
|
|
25920
|
+
legacyKey = "gitBranches";
|
|
25921
|
+
legacyData = conf.gitBranches;
|
|
25922
|
+
} else if (conf.environments) {
|
|
25923
|
+
legacyKey = "environments";
|
|
25924
|
+
legacyData = conf.environments;
|
|
25925
|
+
} else if (conf.git_branches) {
|
|
25926
|
+
legacyKey = "git_branches";
|
|
25927
|
+
legacyData = conf.git_branches;
|
|
26416
25928
|
}
|
|
26417
|
-
|
|
26418
|
-
|
|
26419
|
-
|
|
26420
|
-
|
|
26421
|
-
|
|
26422
|
-
|
|
26423
|
-
for (const childOption of option.options) {
|
|
26424
|
-
this.checkOption(childOption, checked);
|
|
25929
|
+
if (legacyKey && legacyData) {
|
|
25930
|
+
conf.workspaces = convertGitBranchesToWorkspaces(legacyData);
|
|
25931
|
+
if (!legacyConfigWarned) {
|
|
25932
|
+
warn(`⚠️ '${legacyKey}' in wmill.yaml is deprecated. Use 'workspaces' instead.
|
|
25933
|
+
` + ` Run 'wmill config migrate' to update your configuration automatically.`);
|
|
25934
|
+
legacyConfigWarned = true;
|
|
26425
25935
|
}
|
|
26426
25936
|
}
|
|
26427
|
-
}
|
|
26428
|
-
|
|
26429
|
-
|
|
26430
|
-
|
|
26431
|
-
|
|
26432
|
-
}
|
|
26433
|
-
}
|
|
26434
|
-
validate(value) {
|
|
26435
|
-
const options = flatOptions(this.settings.options);
|
|
26436
|
-
const isValidValue = Array.isArray(value) && value.every((val) => options.findIndex((option) => equal(option.value, val)) !== -1);
|
|
26437
|
-
if (!isValidValue) {
|
|
26438
|
-
return false;
|
|
26439
|
-
}
|
|
26440
|
-
if (value.length < this.settings.minOptions) {
|
|
26441
|
-
return `The minimum number of options is ${this.settings.minOptions} but got ${value.length}.`;
|
|
26442
|
-
}
|
|
26443
|
-
if (value.length > this.settings.maxOptions) {
|
|
26444
|
-
return `The maximum number of options is ${this.settings.maxOptions} but got ${value.length}.`;
|
|
25937
|
+
} else if (conf?.workspaces) {
|
|
25938
|
+
for (const legacyKey of ["gitBranches", "environments", "git_branches"]) {
|
|
25939
|
+
if (conf[legacyKey]) {
|
|
25940
|
+
warn(`⚠️ Both 'workspaces' and '${legacyKey}' found in wmill.yaml. Using 'workspaces' and ignoring '${legacyKey}'.`);
|
|
25941
|
+
}
|
|
26445
25942
|
}
|
|
26446
|
-
return true;
|
|
26447
25943
|
}
|
|
26448
|
-
|
|
26449
|
-
|
|
25944
|
+
delete conf?.gitBranches;
|
|
25945
|
+
delete conf?.environments;
|
|
25946
|
+
delete conf?.git_branches;
|
|
25947
|
+
if (conf?.defaultTs == undefined) {
|
|
25948
|
+
warn("No defaultTs defined in your wmill.yaml. Using 'bun' as default.");
|
|
26450
25949
|
}
|
|
26451
|
-
|
|
26452
|
-
|
|
25950
|
+
setNonDottedPaths(conf?.nonDottedPaths ?? false);
|
|
25951
|
+
const syncBehaviorVersion = parseSyncBehavior(conf?.syncBehavior);
|
|
25952
|
+
if (syncBehaviorVersion > SUPPORTED_SYNC_BEHAVIOR_VERSION) {
|
|
25953
|
+
error(`Your wmill.yaml specifies syncBehavior: ${conf.syncBehavior}, but this CLI only supports up to v${SUPPORTED_SYNC_BEHAVIOR_VERSION}. Run 'wmill upgrade' to update.`);
|
|
25954
|
+
process.exit(1);
|
|
26453
25955
|
}
|
|
26454
|
-
|
|
26455
|
-
})
|
|
26456
|
-
|
|
26457
|
-
|
|
26458
|
-
function triggerService(kind) {
|
|
26459
|
-
switch (kind) {
|
|
26460
|
-
case "http_trigger":
|
|
26461
|
-
return {
|
|
26462
|
-
exists: existsHttpTrigger,
|
|
26463
|
-
get: getHttpTrigger,
|
|
26464
|
-
create: createHttpTrigger,
|
|
26465
|
-
update: updateHttpTrigger,
|
|
26466
|
-
delete: deleteHttpTrigger
|
|
26467
|
-
};
|
|
26468
|
-
case "websocket_trigger":
|
|
26469
|
-
return {
|
|
26470
|
-
exists: existsWebsocketTrigger,
|
|
26471
|
-
get: getWebsocketTrigger,
|
|
26472
|
-
create: createWebsocketTrigger,
|
|
26473
|
-
update: updateWebsocketTrigger,
|
|
26474
|
-
delete: deleteWebsocketTrigger
|
|
26475
|
-
};
|
|
26476
|
-
case "kafka_trigger":
|
|
26477
|
-
return {
|
|
26478
|
-
exists: existsKafkaTrigger,
|
|
26479
|
-
get: getKafkaTrigger,
|
|
26480
|
-
create: createKafkaTrigger,
|
|
26481
|
-
update: updateKafkaTrigger,
|
|
26482
|
-
delete: deleteKafkaTrigger
|
|
26483
|
-
};
|
|
26484
|
-
case "nats_trigger":
|
|
26485
|
-
return {
|
|
26486
|
-
exists: existsNatsTrigger,
|
|
26487
|
-
get: getNatsTrigger,
|
|
26488
|
-
create: createNatsTrigger,
|
|
26489
|
-
update: updateNatsTrigger,
|
|
26490
|
-
delete: deleteNatsTrigger
|
|
26491
|
-
};
|
|
26492
|
-
case "postgres_trigger":
|
|
26493
|
-
return {
|
|
26494
|
-
exists: existsPostgresTrigger,
|
|
26495
|
-
get: getPostgresTrigger,
|
|
26496
|
-
create: createPostgresTrigger,
|
|
26497
|
-
update: updatePostgresTrigger,
|
|
26498
|
-
delete: deletePostgresTrigger
|
|
26499
|
-
};
|
|
26500
|
-
case "mqtt_trigger":
|
|
26501
|
-
return {
|
|
26502
|
-
exists: existsMqttTrigger,
|
|
26503
|
-
get: getMqttTrigger,
|
|
26504
|
-
create: createMqttTrigger,
|
|
26505
|
-
update: updateMqttTrigger,
|
|
26506
|
-
delete: deleteMqttTrigger
|
|
26507
|
-
};
|
|
26508
|
-
case "sqs_trigger":
|
|
26509
|
-
return {
|
|
26510
|
-
exists: existsSqsTrigger,
|
|
26511
|
-
get: getSqsTrigger,
|
|
26512
|
-
create: createSqsTrigger,
|
|
26513
|
-
update: updateSqsTrigger,
|
|
26514
|
-
delete: deleteSqsTrigger
|
|
26515
|
-
};
|
|
26516
|
-
case "gcp_trigger":
|
|
26517
|
-
return {
|
|
26518
|
-
exists: existsGcpTrigger,
|
|
26519
|
-
get: getGcpTrigger,
|
|
26520
|
-
create: createGcpTrigger,
|
|
26521
|
-
update: updateGcpTrigger,
|
|
26522
|
-
delete: deleteGcpTrigger
|
|
26523
|
-
};
|
|
26524
|
-
case "azure_trigger":
|
|
26525
|
-
return {
|
|
26526
|
-
exists: existsAzureTrigger,
|
|
26527
|
-
get: getAzureTrigger,
|
|
26528
|
-
create: createAzureTrigger,
|
|
26529
|
-
update: updateAzureTrigger,
|
|
26530
|
-
delete: deleteAzureTrigger
|
|
26531
|
-
};
|
|
26532
|
-
case "email_trigger":
|
|
26533
|
-
return {
|
|
26534
|
-
exists: existsEmailTrigger,
|
|
26535
|
-
get: getEmailTrigger,
|
|
26536
|
-
create: createEmailTrigger,
|
|
26537
|
-
update: updateEmailTrigger,
|
|
26538
|
-
delete: deleteEmailTrigger
|
|
26539
|
-
};
|
|
26540
|
-
}
|
|
26541
|
-
}
|
|
26542
|
-
function preparePayload(kind, trigger, onBehalfOf) {
|
|
26543
|
-
const preserve = onBehalfOf !== undefined;
|
|
26544
|
-
const base = {
|
|
26545
|
-
...trigger,
|
|
26546
|
-
permissioned_as: onBehalfOf,
|
|
26547
|
-
preserve_permissioned_as: preserve
|
|
26548
|
-
};
|
|
26549
|
-
if (kind === "gcp_trigger") {
|
|
26550
|
-
base.subscription_id = "";
|
|
26551
|
-
base.subscription_mode = "create_update";
|
|
26552
|
-
if (base.delivery_config) {
|
|
26553
|
-
base.delivery_config = { ...base.delivery_config, audience: "" };
|
|
25956
|
+
return typeof conf == "object" ? conf : {};
|
|
25957
|
+
} catch (e) {
|
|
25958
|
+
if (e instanceof Error && (e.message.includes("overrides") || e.message.includes("Obsolete configuration format"))) {
|
|
25959
|
+
throw e;
|
|
26554
25960
|
}
|
|
26555
|
-
if (
|
|
26556
|
-
|
|
25961
|
+
if (e instanceof Error && e.message.includes("Error parsing yaml")) {
|
|
25962
|
+
const yamlError = e.cause instanceof Error ? e.cause.message : String(e.cause);
|
|
25963
|
+
throw new Error(`❌ YAML syntax error in wmill.yaml:
|
|
25964
|
+
` + " " + yamlError + `
|
|
25965
|
+
` + " Please fix the YAML syntax in wmill.yaml or delete the file to start fresh.");
|
|
26557
25966
|
} else {
|
|
26558
|
-
|
|
25967
|
+
throw new Error(`❌ Failed to read wmill.yaml:
|
|
25968
|
+
` + " " + (e instanceof Error ? e.message : String(e)) + `
|
|
25969
|
+
` + " Please check file permissions or fix the syntax.");
|
|
26559
25970
|
}
|
|
26560
25971
|
}
|
|
26561
|
-
return base;
|
|
26562
25972
|
}
|
|
26563
|
-
async function
|
|
26564
|
-
const
|
|
26565
|
-
|
|
26566
|
-
|
|
26567
|
-
|
|
26568
|
-
|
|
26569
|
-
if (!token) {
|
|
26570
|
-
throw new Error("Not logged in. Please run 'wmill workspace add' first.");
|
|
26571
|
-
}
|
|
26572
|
-
const remote = workspace.remote;
|
|
26573
|
-
setClient(token, remote.endsWith("/") ? remote.substring(0, remote.length - 1) : remote);
|
|
26574
|
-
const forkWorkspaceId = workspace.workspaceId;
|
|
26575
|
-
const userWorkspaces = await listUserWorkspaces();
|
|
26576
|
-
const forkEntry = userWorkspaces.workspaces?.find((w) => w.id === forkWorkspaceId);
|
|
26577
|
-
if (!forkEntry?.parent_workspace_id) {
|
|
26578
|
-
throw new Error(`Workspace '${forkWorkspaceId}' is not a fork (no parent_workspace_id). ` + `You can only merge from a forked workspace.`);
|
|
26579
|
-
}
|
|
26580
|
-
const parentWorkspaceId = forkEntry.parent_workspace_id;
|
|
26581
|
-
info(`Fork: ${colors.bold(forkWorkspaceId)} → Parent: ${colors.bold(parentWorkspaceId)}`);
|
|
26582
|
-
info("Comparing workspaces...");
|
|
26583
|
-
const comparison = await compareWorkspaces({
|
|
26584
|
-
workspace: parentWorkspaceId,
|
|
26585
|
-
targetWorkspaceId: forkWorkspaceId
|
|
26586
|
-
});
|
|
26587
|
-
if (comparison.skipped_comparison) {
|
|
26588
|
-
info(colors.yellow("This fork was created before change tracking was available. " + "Use the UI or git-based merge instead."));
|
|
25973
|
+
async function mergeConfigWithConfigFile(opts) {
|
|
25974
|
+
const configFile = await readConfigFile();
|
|
25975
|
+
return Object.assign(configFile ?? {}, opts);
|
|
25976
|
+
}
|
|
25977
|
+
async function validateBranchConfiguration(opts, workspaceNameOverride) {
|
|
25978
|
+
if (opts.skipBranchValidation || workspaceNameOverride || !isGitRepository()) {
|
|
26589
25979
|
return;
|
|
26590
25980
|
}
|
|
26591
|
-
const
|
|
26592
|
-
|
|
26593
|
-
|
|
26594
|
-
|
|
25981
|
+
const config = await readConfigFile();
|
|
25982
|
+
const { workspaces } = config;
|
|
25983
|
+
const rawBranch = getCurrentGitBranch();
|
|
25984
|
+
const originalBranchIfForked = getOriginalBranchForWorkspaceForks(rawBranch);
|
|
25985
|
+
let currentBranch;
|
|
25986
|
+
if (originalBranchIfForked) {
|
|
25987
|
+
info(`Workspace fork detected from branch name \`${rawBranch}\`. Validating workspace configuration using original branch \`${originalBranchIfForked}\``);
|
|
25988
|
+
currentBranch = originalBranchIfForked;
|
|
25989
|
+
} else {
|
|
25990
|
+
currentBranch = rawBranch;
|
|
26595
25991
|
}
|
|
26596
|
-
|
|
26597
|
-
|
|
26598
|
-
|
|
26599
|
-
|
|
26600
|
-
summaryRows.push(["Scripts", String(summary.scripts_changed)]);
|
|
26601
|
-
if (summary.flows_changed > 0)
|
|
26602
|
-
summaryRows.push(["Flows", String(summary.flows_changed)]);
|
|
26603
|
-
if (summary.apps_changed > 0)
|
|
26604
|
-
summaryRows.push(["Apps", String(summary.apps_changed)]);
|
|
26605
|
-
if (summary.resources_changed > 0)
|
|
26606
|
-
summaryRows.push(["Resources", String(summary.resources_changed)]);
|
|
26607
|
-
if (summary.variables_changed > 0)
|
|
26608
|
-
summaryRows.push(["Variables", String(summary.variables_changed)]);
|
|
26609
|
-
if (summary.resource_types_changed > 0)
|
|
26610
|
-
summaryRows.push(["Resource Types", String(summary.resource_types_changed)]);
|
|
26611
|
-
if (summary.folders_changed > 0)
|
|
26612
|
-
summaryRows.push(["Folders", String(summary.folders_changed)]);
|
|
26613
|
-
if (summary.schedules_changed > 0)
|
|
26614
|
-
summaryRows.push(["Schedules", String(summary.schedules_changed)]);
|
|
26615
|
-
if (summary.triggers_changed > 0)
|
|
26616
|
-
summaryRows.push(["Triggers", String(summary.triggers_changed)]);
|
|
26617
|
-
summaryRows.push(["Total", String(summary.total_diffs)]);
|
|
26618
|
-
if (summary.conflicts > 0)
|
|
26619
|
-
summaryRows.push([
|
|
26620
|
-
colors.red("Conflicts"),
|
|
26621
|
-
colors.red(String(summary.conflicts))
|
|
26622
|
-
]);
|
|
26623
|
-
new Table2().header(["Type", "Changed"]).padding(2).border(true).body(summaryRows).render();
|
|
26624
|
-
const diffs = comparison.diffs.filter((d) => d.has_changes !== false);
|
|
26625
|
-
if (diffs.length === 0) {
|
|
26626
|
-
info(colors.green("No effective changes to deploy."));
|
|
25992
|
+
if (!workspaces || getWorkspaceNames(workspaces).length === 0) {
|
|
25993
|
+
warn(`⚠️ WARNING: In a Git repository, the 'workspaces' section is recommended in wmill.yaml.
|
|
25994
|
+
` + ` Consider adding a workspaces section to map workspace names to Windmill instances.
|
|
25995
|
+
` + " Run 'wmill init' to recreate the configuration file with proper workspace setup.");
|
|
26627
25996
|
return;
|
|
26628
25997
|
}
|
|
26629
|
-
|
|
26630
|
-
|
|
26631
|
-
|
|
26632
|
-
const
|
|
26633
|
-
|
|
26634
|
-
|
|
26635
|
-
|
|
26636
|
-
d.path,
|
|
26637
|
-
d.ahead > 0 ? colors.green(String(d.ahead)) : "0",
|
|
26638
|
-
d.behind > 0 ? colors.yellow(String(d.behind)) : "0",
|
|
26639
|
-
isConflict ? colors.red("YES") : ""
|
|
26640
|
-
];
|
|
26641
|
-
})).render();
|
|
26642
|
-
let direction;
|
|
26643
|
-
if (opts.direction === "to-parent" || opts.direction === "to-fork") {
|
|
26644
|
-
direction = opts.direction;
|
|
26645
|
-
} else if (opts.direction) {
|
|
26646
|
-
throw new Error(`Invalid direction '${opts.direction}'. Use 'to-parent' or 'to-fork'.`);
|
|
26647
|
-
} else if (opts.yes) {
|
|
26648
|
-
direction = "to-parent";
|
|
26649
|
-
} else {
|
|
26650
|
-
const { Select: Select2 } = await init_select().then(() => exports_select);
|
|
26651
|
-
direction = await Select2.prompt({
|
|
26652
|
-
message: "Deploy direction:",
|
|
26653
|
-
options: [
|
|
26654
|
-
{
|
|
26655
|
-
name: `Deploy to parent (${parentWorkspaceId}) ← fork changes`,
|
|
26656
|
-
value: "to-parent"
|
|
26657
|
-
},
|
|
26658
|
-
{
|
|
26659
|
-
name: `Update fork (${forkWorkspaceId}) ← parent changes`,
|
|
26660
|
-
value: "to-fork"
|
|
26661
|
-
}
|
|
26662
|
-
]
|
|
26663
|
-
});
|
|
26664
|
-
}
|
|
26665
|
-
info(`
|
|
26666
|
-
Direction: ${colors.bold(direction === "to-parent" ? `Fork → Parent (${parentWorkspaceId})` : `Parent → Fork (${forkWorkspaceId})`)}`);
|
|
26667
|
-
const selectableDiffs = diffs.filter((d) => {
|
|
26668
|
-
if (direction === "to-parent") {
|
|
26669
|
-
return d.ahead > 0;
|
|
25998
|
+
const branchToWsNames = new Map;
|
|
25999
|
+
for (const name of getWorkspaceNames(workspaces)) {
|
|
26000
|
+
const entry = workspaces[name];
|
|
26001
|
+
const branch = getEffectiveGitBranch(name, entry);
|
|
26002
|
+
const existing = branchToWsNames.get(branch);
|
|
26003
|
+
if (existing) {
|
|
26004
|
+
existing.push(name);
|
|
26670
26005
|
} else {
|
|
26671
|
-
|
|
26006
|
+
branchToWsNames.set(branch, [name]);
|
|
26672
26007
|
}
|
|
26673
|
-
});
|
|
26674
|
-
if (selectableDiffs.length === 0) {
|
|
26675
|
-
info(colors.yellow(`No items to deploy in the '${direction}' direction.`));
|
|
26676
|
-
return;
|
|
26677
26008
|
}
|
|
26678
|
-
|
|
26679
|
-
|
|
26680
|
-
|
|
26681
|
-
|
|
26682
|
-
|
|
26683
|
-
} else if (opts.yes && !opts.include && !opts.exclude) {
|
|
26684
|
-
selectedDiffs = selectableDiffs.filter((d) => !isTriggerOrScheduleKind(d.kind) && (direction !== "to-fork" || !(d.ahead > 0 && d.behind > 0)));
|
|
26685
|
-
} else if (!opts.yes) {
|
|
26686
|
-
const { Checkbox: Checkbox2 } = await init_checkbox().then(() => exports_checkbox);
|
|
26687
|
-
const defaultForToFork = direction === "to-fork";
|
|
26688
|
-
const selectedValues = await Checkbox2.prompt({
|
|
26689
|
-
message: `Select items to deploy (${selectableDiffs.length} available):`,
|
|
26690
|
-
options: selectableDiffs.map((d) => {
|
|
26691
|
-
const isConflict = d.ahead > 0 && d.behind > 0;
|
|
26692
|
-
const isTriggerOrSchedule = isTriggerOrScheduleKind(d.kind);
|
|
26693
|
-
const label = `${d.kind}:${d.path}${isConflict ? colors.red(" [CONFLICT]") : ""}`;
|
|
26694
|
-
return {
|
|
26695
|
-
name: label,
|
|
26696
|
-
value: `${d.kind}:${d.path}`,
|
|
26697
|
-
checked: !isTriggerOrSchedule && (defaultForToFork ? !isConflict : true)
|
|
26698
|
-
};
|
|
26699
|
-
})
|
|
26700
|
-
});
|
|
26701
|
-
selectedDiffs = selectableDiffs.filter((d) => selectedValues.includes(`${d.kind}:${d.path}`));
|
|
26702
|
-
}
|
|
26703
|
-
if (opts.include) {
|
|
26704
|
-
const includeSet = new Set(opts.include.split(",").map((s) => s.trim()));
|
|
26705
|
-
selectedDiffs = selectedDiffs.filter((d) => includeSet.has(`${d.kind}:${d.path}`));
|
|
26706
|
-
}
|
|
26707
|
-
if (opts.exclude) {
|
|
26708
|
-
const excludeSet = new Set(opts.exclude.split(",").map((s) => s.trim()));
|
|
26709
|
-
selectedDiffs = selectedDiffs.filter((d) => !excludeSet.has(`${d.kind}:${d.path}`));
|
|
26009
|
+
for (const [branch, names] of branchToWsNames) {
|
|
26010
|
+
if (names.length > 1) {
|
|
26011
|
+
warn(`⚠️ WARNING: Multiple workspaces map to git branch '${branch}': ${names.join(", ")}.
|
|
26012
|
+
` + ` Only the first ('${names[0]}') will be used during auto-detection. Use --workspace to select explicitly.`);
|
|
26013
|
+
}
|
|
26710
26014
|
}
|
|
26711
|
-
if (
|
|
26712
|
-
|
|
26713
|
-
|
|
26015
|
+
if (currentBranch && !findWorkspaceByGitBranch(workspaces, currentBranch)) {
|
|
26016
|
+
const wsNames = getWorkspaceNames(workspaces);
|
|
26017
|
+
const availableInfo = wsNames.map((n) => {
|
|
26018
|
+
const entry = workspaces[n];
|
|
26019
|
+
const branch = getEffectiveGitBranch(n, entry);
|
|
26020
|
+
return branch !== n ? `${n} (gitBranch: ${branch})` : n;
|
|
26021
|
+
}).join(", ");
|
|
26022
|
+
if (!!process.stdin.isTTY) {
|
|
26023
|
+
info(`Current Git branch '${currentBranch}' does not match any workspace in the configuration.
|
|
26024
|
+
` + `Available workspaces: ${availableInfo}`);
|
|
26025
|
+
const shouldCreate = opts.yes || await Confirm.prompt({
|
|
26026
|
+
message: `Create empty workspace configuration for branch '${currentBranch}'?`,
|
|
26027
|
+
default: true
|
|
26028
|
+
});
|
|
26029
|
+
if (shouldCreate) {
|
|
26030
|
+
if (/[\/\\:*?"<>|.]/.test(currentBranch)) {
|
|
26031
|
+
const sanitizedBranchName = currentBranch.replace(/[\/\\:*?"<>|.]/g, "_");
|
|
26032
|
+
warn(`⚠️ WARNING: Branch name "${currentBranch}" contains filesystem-unsafe characters (/ \\ : * ? " < > | .).`);
|
|
26033
|
+
warn(` Branch-specific files will be saved with sanitized name: "${sanitizedBranchName}"`);
|
|
26034
|
+
warn(` Example: "file.variable.yaml" → "file.${sanitizedBranchName}.variable.yaml"`);
|
|
26035
|
+
}
|
|
26036
|
+
const currentConfig = await readConfigFile();
|
|
26037
|
+
if (!currentConfig.workspaces) {
|
|
26038
|
+
currentConfig.workspaces = {};
|
|
26039
|
+
}
|
|
26040
|
+
currentConfig.workspaces[currentBranch] = {};
|
|
26041
|
+
await writeFile("wmill.yaml", import_yaml3.stringify(currentConfig), "utf-8");
|
|
26042
|
+
info(`✅ Created empty workspace configuration for '${currentBranch}'`);
|
|
26043
|
+
} else {
|
|
26044
|
+
warn("⚠️ WARNING: Workspace creation cancelled. You can manually add a workspace to the 'workspaces' section in wmill.yaml or use 'wmill gitsync-settings pull' to pull configuration from an existing windmill workspace git-sync configuration.");
|
|
26045
|
+
return;
|
|
26046
|
+
}
|
|
26047
|
+
} else {
|
|
26048
|
+
if (/[\/\\:*?"<>|.]/.test(currentBranch)) {
|
|
26049
|
+
const sanitizedBranchName = currentBranch.replace(/[\/\\:*?"<>|.]/g, "_");
|
|
26050
|
+
warn(`⚠️ WARNING: Branch name "${currentBranch}" contains filesystem-unsafe characters (/ \\ : * ? " < > | .).`);
|
|
26051
|
+
warn(` Branch-specific files will use sanitized name: "${sanitizedBranchName}"`);
|
|
26052
|
+
}
|
|
26053
|
+
warn(`⚠️ WARNING: Current Git branch '${currentBranch}' does not match any workspace in the configuration.
|
|
26054
|
+
` + ` Consider adding a workspace entry for branch '${currentBranch}' in the 'workspaces' section of wmill.yaml.
|
|
26055
|
+
` + ` Available workspaces: ${availableInfo}`);
|
|
26056
|
+
return;
|
|
26057
|
+
}
|
|
26714
26058
|
}
|
|
26715
|
-
|
|
26716
|
-
|
|
26717
|
-
|
|
26718
|
-
|
|
26719
|
-
|
|
26720
|
-
|
|
26059
|
+
}
|
|
26060
|
+
async function getEffectiveSettings(config, promotion, skipBranchValidation, suppressLogs, workspaceNameOverride) {
|
|
26061
|
+
const { workspaces, ...topLevelSettings } = config;
|
|
26062
|
+
const effective = { ...topLevelSettings };
|
|
26063
|
+
let resolvedWsName = null;
|
|
26064
|
+
let resolvedWsEntry = null;
|
|
26065
|
+
let originalBranchIfForked = null;
|
|
26066
|
+
let rawGitBranch = null;
|
|
26067
|
+
if (workspaceNameOverride) {
|
|
26068
|
+
if (workspaces && workspaces[workspaceNameOverride]) {
|
|
26069
|
+
resolvedWsName = workspaceNameOverride;
|
|
26070
|
+
resolvedWsEntry = workspaces[workspaceNameOverride];
|
|
26721
26071
|
}
|
|
26722
|
-
|
|
26723
|
-
|
|
26724
|
-
|
|
26725
|
-
|
|
26726
|
-
|
|
26727
|
-
|
|
26072
|
+
} else if (isGitRepository()) {
|
|
26073
|
+
rawGitBranch = getCurrentGitBranch();
|
|
26074
|
+
originalBranchIfForked = getOriginalBranchForWorkspaceForks(rawGitBranch);
|
|
26075
|
+
const branch = originalBranchIfForked ?? rawGitBranch;
|
|
26076
|
+
if (originalBranchIfForked) {
|
|
26077
|
+
info(`Using overrides from original branch \`${originalBranchIfForked}\``);
|
|
26078
|
+
}
|
|
26079
|
+
if (branch) {
|
|
26080
|
+
const match = findWorkspaceByGitBranch(workspaces, branch);
|
|
26081
|
+
if (match) {
|
|
26082
|
+
[resolvedWsName, resolvedWsEntry] = match;
|
|
26728
26083
|
}
|
|
26729
26084
|
}
|
|
26085
|
+
} else {
|
|
26086
|
+
debug("Not in a Git repository and no workspace override provided, using top-level settings");
|
|
26730
26087
|
}
|
|
26731
|
-
|
|
26732
|
-
|
|
26733
|
-
|
|
26734
|
-
|
|
26735
|
-
|
|
26736
|
-
|
|
26737
|
-
|
|
26738
|
-
|
|
26739
|
-
|
|
26740
|
-
|
|
26741
|
-
|
|
26742
|
-
|
|
26743
|
-
|
|
26744
|
-
|
|
26745
|
-
|
|
26746
|
-
|
|
26747
|
-
info(colors.yellow(` ⌫ ${label} (removing from target)`));
|
|
26748
|
-
result = await deleteItemInWorkspace(provider, diff2.kind, diff2.path, workspaceTo);
|
|
26749
|
-
} else {
|
|
26750
|
-
let onBehalfOf;
|
|
26751
|
-
if (opts.preserveOnBehalfOf) {
|
|
26752
|
-
onBehalfOf = await getOnBehalfOf(provider, diff2.kind, diff2.path, workspaceFrom);
|
|
26088
|
+
if (promotion && workspaces) {
|
|
26089
|
+
const promotionMatch = findWorkspaceByGitBranch(workspaces, promotion);
|
|
26090
|
+
if (promotionMatch) {
|
|
26091
|
+
const [, targetWs] = promotionMatch;
|
|
26092
|
+
if (targetWs.promotionOverrides) {
|
|
26093
|
+
Object.assign(effective, targetWs.promotionOverrides);
|
|
26094
|
+
if (!suppressLogs) {
|
|
26095
|
+
info(`Applied promotion settings from workspace for branch: ${promotion}`);
|
|
26096
|
+
}
|
|
26097
|
+
} else if (targetWs.overrides) {
|
|
26098
|
+
Object.assign(effective, targetWs.overrides);
|
|
26099
|
+
if (!suppressLogs) {
|
|
26100
|
+
info(`Applied settings from workspace for branch: ${promotion} (no promotionOverrides found)`);
|
|
26101
|
+
}
|
|
26102
|
+
} else {
|
|
26103
|
+
debug(`No promotion or regular overrides found for '${promotion}', using top-level settings`);
|
|
26753
26104
|
}
|
|
26754
|
-
result = await deployItem(provider, diff2.kind, diff2.path, workspaceFrom, workspaceTo, onBehalfOf);
|
|
26755
26105
|
}
|
|
26756
|
-
|
|
26757
|
-
|
|
26758
|
-
|
|
26759
|
-
|
|
26760
|
-
info(
|
|
26761
|
-
failCount++;
|
|
26106
|
+
} else if (resolvedWsEntry?.overrides) {
|
|
26107
|
+
Object.assign(effective, resolvedWsEntry.overrides);
|
|
26108
|
+
if (!suppressLogs) {
|
|
26109
|
+
const extraLog = originalBranchIfForked ? ` (because it is the origin of the workspace fork branch \`${rawGitBranch}\`)` : "";
|
|
26110
|
+
info(`Applied settings for workspace '${resolvedWsName}'${extraLog}`);
|
|
26762
26111
|
}
|
|
26112
|
+
} else if (resolvedWsName) {
|
|
26113
|
+
debug(`No overrides found for workspace '${resolvedWsName}', using top-level settings`);
|
|
26763
26114
|
}
|
|
26764
|
-
|
|
26765
|
-
try {
|
|
26766
|
-
await resetDiffTally({
|
|
26767
|
-
workspace: parentWorkspaceId,
|
|
26768
|
-
forkWorkspaceId
|
|
26769
|
-
});
|
|
26770
|
-
} catch {}
|
|
26771
|
-
}
|
|
26772
|
-
info("");
|
|
26773
|
-
if (failCount === 0) {
|
|
26774
|
-
info(colors.green(`✅ Successfully deployed ${successCount} item(s) from ${workspaceFrom} to ${workspaceTo}.`));
|
|
26775
|
-
} else {
|
|
26776
|
-
info(colors.yellow(`Deployed ${successCount} item(s), ${colors.red(String(failCount) + " failed")} from ${workspaceFrom} to ${workspaceTo}.`));
|
|
26777
|
-
}
|
|
26115
|
+
return effective;
|
|
26778
26116
|
}
|
|
26779
|
-
|
|
26780
|
-
|
|
26781
|
-
|
|
26782
|
-
|
|
26783
|
-
|
|
26784
|
-
|
|
26785
|
-
|
|
26786
|
-
|
|
26787
|
-
|
|
26788
|
-
await init_context();
|
|
26789
|
-
provider = {
|
|
26790
|
-
existsFlowByPath,
|
|
26791
|
-
existsScriptByPath,
|
|
26792
|
-
existsApp,
|
|
26793
|
-
existsVariable,
|
|
26794
|
-
existsResource,
|
|
26795
|
-
existsResourceType,
|
|
26796
|
-
existsFolder,
|
|
26797
|
-
getFlowByPath,
|
|
26798
|
-
createFlow,
|
|
26799
|
-
updateFlow,
|
|
26800
|
-
archiveFlowByPath,
|
|
26801
|
-
getScriptByPath,
|
|
26802
|
-
createScript,
|
|
26803
|
-
archiveScriptByPath,
|
|
26804
|
-
getAppByPath,
|
|
26805
|
-
createApp,
|
|
26806
|
-
updateApp,
|
|
26807
|
-
createAppRaw,
|
|
26808
|
-
updateAppRaw,
|
|
26809
|
-
getPublicSecretOfLatestVersionOfApp,
|
|
26810
|
-
getRawAppData,
|
|
26811
|
-
deleteApp,
|
|
26812
|
-
getVariable,
|
|
26813
|
-
createVariable,
|
|
26814
|
-
updateVariable,
|
|
26815
|
-
deleteVariable,
|
|
26816
|
-
getResource,
|
|
26817
|
-
createResource,
|
|
26818
|
-
updateResource,
|
|
26819
|
-
deleteResource,
|
|
26820
|
-
getResourceType,
|
|
26821
|
-
createResourceType,
|
|
26822
|
-
updateResourceType,
|
|
26823
|
-
deleteResourceType,
|
|
26824
|
-
getFolder,
|
|
26825
|
-
createFolder,
|
|
26826
|
-
updateFolder,
|
|
26827
|
-
deleteFolder,
|
|
26828
|
-
existsTriggerByKind: (kind, p) => triggerService(kind).exists(p),
|
|
26829
|
-
getTriggerForDeploy: async (kind, p) => {
|
|
26830
|
-
const trigger = await triggerService(kind).get({
|
|
26831
|
-
workspace: p.workspace,
|
|
26832
|
-
path: p.path
|
|
26833
|
-
});
|
|
26834
|
-
return preparePayload(kind, trigger, p.onBehalfOf);
|
|
26835
|
-
},
|
|
26836
|
-
createTriggerByKind: (kind, p) => triggerService(kind).create(p),
|
|
26837
|
-
updateTriggerByKind: (kind, p) => triggerService(kind).update(p),
|
|
26838
|
-
deleteTriggerByKind: (kind, p) => triggerService(kind).delete(p),
|
|
26839
|
-
getTriggerValue: (kind, p) => triggerService(kind).get(p),
|
|
26840
|
-
getTriggerPermissionedAs: async (kind, p) => {
|
|
26841
|
-
const trigger = await triggerService(kind).get(p);
|
|
26842
|
-
return trigger?.permissioned_as;
|
|
26843
|
-
},
|
|
26844
|
-
existsSchedule,
|
|
26845
|
-
getSchedule,
|
|
26846
|
-
createSchedule,
|
|
26847
|
-
updateSchedule,
|
|
26848
|
-
deleteSchedule
|
|
26849
|
-
};
|
|
26850
|
-
});
|
|
26851
|
-
|
|
26852
|
-
// src/commands/workspace/slack.ts
|
|
26853
|
-
async function connectSlack2(opts) {
|
|
26854
|
-
await requireLogin(opts);
|
|
26855
|
-
const workspace = await resolveWorkspace(opts);
|
|
26856
|
-
await connectSlack({
|
|
26857
|
-
workspace: workspace.workspaceId,
|
|
26858
|
-
requestBody: {
|
|
26859
|
-
bot_token: opts.botToken,
|
|
26860
|
-
team_id: opts.teamId,
|
|
26861
|
-
team_name: opts.teamName
|
|
26117
|
+
function findWorkspaceByGitBranch(workspaces, branchName) {
|
|
26118
|
+
if (!workspaces)
|
|
26119
|
+
return;
|
|
26120
|
+
for (const [name, entry] of Object.entries(workspaces)) {
|
|
26121
|
+
if (RESERVED_WORKSPACE_KEYS.has(name))
|
|
26122
|
+
continue;
|
|
26123
|
+
const effectiveBranch = entry.gitBranch ?? name;
|
|
26124
|
+
if (effectiveBranch === branchName) {
|
|
26125
|
+
return [name, entry];
|
|
26862
26126
|
}
|
|
26863
|
-
}
|
|
26864
|
-
|
|
26127
|
+
}
|
|
26128
|
+
return;
|
|
26865
26129
|
}
|
|
26866
|
-
|
|
26867
|
-
|
|
26868
|
-
const workspace = await resolveWorkspace(opts);
|
|
26869
|
-
await disconnectSlack({ workspace: workspace.workspaceId });
|
|
26870
|
-
info(colors.bold.underline.green(`Slack disconnected from workspace ${workspace.workspaceId} (slack_team_id / slack_name cleared). ` + `To also remove the bot token variable/resource/folder/group, delete the corresponding files from the local sync folder and run 'wmill sync push'. ` + `To remove the workspace-level OAuth override (if any), set slack_oauth_client_id/_secret to '' in settings.yaml and push.`));
|
|
26130
|
+
function getEffectiveWorkspaceId(workspaceName, config) {
|
|
26131
|
+
return config.workspaceId ?? workspaceName;
|
|
26871
26132
|
}
|
|
26872
|
-
|
|
26873
|
-
|
|
26133
|
+
function getEffectiveGitBranch(workspaceName, config) {
|
|
26134
|
+
return config.gitBranch ?? workspaceName;
|
|
26135
|
+
}
|
|
26136
|
+
function getWorkspaceNames(workspaces) {
|
|
26137
|
+
if (!workspaces)
|
|
26138
|
+
return [];
|
|
26139
|
+
return Object.keys(workspaces).filter((k) => !RESERVED_WORKSPACE_KEYS.has(k));
|
|
26140
|
+
}
|
|
26141
|
+
function convertGitBranchesToWorkspaces(gitBranches) {
|
|
26142
|
+
const workspaces = {};
|
|
26143
|
+
for (const [key, value] of Object.entries(gitBranches)) {
|
|
26144
|
+
if (key === "commonSpecificItems") {
|
|
26145
|
+
workspaces.commonSpecificItems = value;
|
|
26146
|
+
continue;
|
|
26147
|
+
}
|
|
26148
|
+
workspaces[key] = { ...value };
|
|
26149
|
+
}
|
|
26150
|
+
return workspaces;
|
|
26151
|
+
}
|
|
26152
|
+
var import_yaml3, showDiffs = false, SUPPORTED_SYNC_BEHAVIOR_VERSION = 1, GLOBAL_CONFIG_OPT, legacyConfigWarned = false, DEFAULT_SYNC_OPTIONS, RESERVED_WORKSPACE_KEYS;
|
|
26153
|
+
var init_conf = __esm(async () => {
|
|
26874
26154
|
init_log();
|
|
26875
|
-
|
|
26155
|
+
init_git();
|
|
26876
26156
|
await __promiseAll([
|
|
26877
|
-
|
|
26878
|
-
|
|
26157
|
+
init_yaml(),
|
|
26158
|
+
init_confirm(),
|
|
26159
|
+
init_resource_folders()
|
|
26879
26160
|
]);
|
|
26161
|
+
import_yaml3 = __toESM(require_dist(), 1);
|
|
26162
|
+
GLOBAL_CONFIG_OPT = { noCdToRoot: false };
|
|
26163
|
+
DEFAULT_SYNC_OPTIONS = {
|
|
26164
|
+
defaultTs: "bun",
|
|
26165
|
+
includes: ["f/**"],
|
|
26166
|
+
excludes: [],
|
|
26167
|
+
codebases: [],
|
|
26168
|
+
skipVariables: false,
|
|
26169
|
+
skipResources: false,
|
|
26170
|
+
skipResourceTypes: false,
|
|
26171
|
+
skipSecrets: true,
|
|
26172
|
+
skipScripts: false,
|
|
26173
|
+
skipFlows: false,
|
|
26174
|
+
skipApps: false,
|
|
26175
|
+
skipFolders: false,
|
|
26176
|
+
includeSchedules: false,
|
|
26177
|
+
includeTriggers: false,
|
|
26178
|
+
includeUsers: false,
|
|
26179
|
+
includeGroups: false,
|
|
26180
|
+
includeSettings: false,
|
|
26181
|
+
includeKey: false,
|
|
26182
|
+
skipWorkspaceDependencies: false,
|
|
26183
|
+
nonDottedPaths: false,
|
|
26184
|
+
syncBehavior: "v1"
|
|
26185
|
+
};
|
|
26186
|
+
RESERVED_WORKSPACE_KEYS = new Set(["commonSpecificItems"]);
|
|
26880
26187
|
});
|
|
26881
26188
|
|
|
26882
|
-
// src/
|
|
26883
|
-
import
|
|
26884
|
-
|
|
26885
|
-
|
|
26886
|
-
|
|
26887
|
-
function setNonDottedPaths(value) {
|
|
26888
|
-
if (value && !_nonDottedPathsLogged) {
|
|
26889
|
-
debug("Using non-dotted paths (__flow, __app, __raw_app)");
|
|
26890
|
-
_nonDottedPathsLogged = true;
|
|
26189
|
+
// src/commands/workspace/fork.ts
|
|
26190
|
+
import process10 from "node:process";
|
|
26191
|
+
async function createWorkspaceFork2(opts, workspaceName, workspaceId = undefined) {
|
|
26192
|
+
if (!isGitRepository()) {
|
|
26193
|
+
throw new Error("You can only create forks within a git repo. Forks are tracked with git and synced to your instance with the git sync workflow.");
|
|
26891
26194
|
}
|
|
26892
|
-
|
|
26893
|
-
|
|
26894
|
-
|
|
26895
|
-
|
|
26896
|
-
}
|
|
26897
|
-
|
|
26898
|
-
|
|
26899
|
-
|
|
26900
|
-
|
|
26901
|
-
|
|
26902
|
-
|
|
26903
|
-
|
|
26904
|
-
setNonDottedPaths(config?.nonDottedPaths ?? false);
|
|
26905
|
-
debug(`Found wmill.yaml at ${wmillYamlPath}, nonDottedPaths=${config?.nonDottedPaths ?? false}`);
|
|
26906
|
-
} catch (e) {
|
|
26907
|
-
debug(`Failed to parse wmill.yaml at ${wmillYamlPath}: ${e}`);
|
|
26908
|
-
}
|
|
26909
|
-
return;
|
|
26195
|
+
const currentBranch = getCurrentGitBranch();
|
|
26196
|
+
if (!currentBranch) {
|
|
26197
|
+
throw new Error("Could not get git branch name");
|
|
26198
|
+
}
|
|
26199
|
+
const config = await readConfigFile({ warnIfMissing: false });
|
|
26200
|
+
const originalBranchIfForked = getOriginalBranchForWorkspaceForks(currentBranch);
|
|
26201
|
+
const isBaseBranch = (branch) => branch === "main" || branch === "master" || findWorkspaceByGitBranch(config.workspaces, branch) !== undefined;
|
|
26202
|
+
let clonedBranchName;
|
|
26203
|
+
let renameCurrent;
|
|
26204
|
+
if (opts.fromBranch) {
|
|
26205
|
+
if (opts.fromBranch === currentBranch) {
|
|
26206
|
+
throw new Error(`--from-branch is for converting a *different* working branch into the fork branch, but you are already on \`${currentBranch}\`. ` + `Omit --from-branch to create a fresh fork branch with \`git checkout -b\`.`);
|
|
26910
26207
|
}
|
|
26911
|
-
|
|
26912
|
-
|
|
26913
|
-
debug("No wmill.yaml found, using default dotted paths");
|
|
26914
|
-
return;
|
|
26208
|
+
if (isBaseBranch(currentBranch)) {
|
|
26209
|
+
throw new Error(`Refusing to rename your current branch \`${currentBranch}\` — it looks like a base branch (mapped to a workspace in wmill.yaml, or main/master). ` + `Check out the disposable working branch you want to convert first.`);
|
|
26915
26210
|
}
|
|
26916
|
-
|
|
26211
|
+
if (getOriginalBranchForWorkspaceForks(currentBranch)) {
|
|
26212
|
+
throw new Error(`Refusing to rename your current branch \`${currentBranch}\` — it is already a fork branch. ` + `To fork a fork, omit --from-branch: \`wmill workspace fork\` bases the new fork on this fork's original branch and creates a fresh fork branch without renaming.`);
|
|
26213
|
+
}
|
|
26214
|
+
if (!findWorkspaceByGitBranch(config.workspaces, opts.fromBranch)) {
|
|
26215
|
+
throw new Error(`Could not find a workspace mapped to branch \`${opts.fromBranch}\` in wmill.yaml's workspaces section. ` + `Pass the base branch your fork should be based on (e.g. the branch bound to the parent workspace).`);
|
|
26216
|
+
}
|
|
26217
|
+
clonedBranchName = opts.fromBranch;
|
|
26218
|
+
renameCurrent = true;
|
|
26219
|
+
} else if (originalBranchIfForked) {
|
|
26220
|
+
info(`You are creating a fork of a fork. The branch will be linked to the original branch this was forked from, i.e. \`${originalBranchIfForked}\`, for all settings and overrides.`);
|
|
26221
|
+
clonedBranchName = originalBranchIfForked;
|
|
26222
|
+
renameCurrent = false;
|
|
26223
|
+
} else if (isBaseBranch(currentBranch)) {
|
|
26224
|
+
clonedBranchName = currentBranch;
|
|
26225
|
+
renameCurrent = false;
|
|
26226
|
+
} else {
|
|
26227
|
+
clonedBranchName = await resolveWorkingBranchBase(config, opts, currentBranch);
|
|
26228
|
+
renameCurrent = true;
|
|
26917
26229
|
}
|
|
26918
|
-
|
|
26919
|
-
|
|
26920
|
-
|
|
26921
|
-
}
|
|
26922
|
-
|
|
26923
|
-
|
|
26924
|
-
}
|
|
26925
|
-
|
|
26926
|
-
|
|
26927
|
-
}
|
|
26928
|
-
|
|
26929
|
-
|
|
26930
|
-
|
|
26931
|
-
|
|
26932
|
-
|
|
26933
|
-
|
|
26934
|
-
|
|
26935
|
-
|
|
26230
|
+
let workspace;
|
|
26231
|
+
if (clonedBranchName === currentBranch) {
|
|
26232
|
+
workspace = await tryResolveBranchWorkspace(opts);
|
|
26233
|
+
} else {
|
|
26234
|
+
const baseMatch = findWorkspaceByGitBranch(config.workspaces, clonedBranchName);
|
|
26235
|
+
workspace = baseMatch ? await tryResolveBranchWorkspace(opts, baseMatch[0]) : await tryResolveBranchWorkspace(opts);
|
|
26236
|
+
}
|
|
26237
|
+
if (!workspace) {
|
|
26238
|
+
throw new Error("Could not resolve workspace from branch name. Make sure you are in a git repo to use workspace forks");
|
|
26239
|
+
}
|
|
26240
|
+
info(`You are forking workspace (${workspace.workspaceId})`);
|
|
26241
|
+
if (opts.workspace) {
|
|
26242
|
+
info(colors.red.bold("! Workspace needs to be specified as positional argument, not as option."));
|
|
26243
|
+
return;
|
|
26244
|
+
}
|
|
26245
|
+
const branchDefaultId = renameCurrent ? branchToForkId(currentBranch) : undefined;
|
|
26246
|
+
const interactive = process10.stdin.isTTY && opts.yes !== true;
|
|
26247
|
+
if (workspaceName === undefined) {
|
|
26248
|
+
if (branchDefaultId && !interactive) {
|
|
26249
|
+
workspaceName = branchDefaultId;
|
|
26250
|
+
info(`Naming the fork after the current branch: \`${workspaceName}\``);
|
|
26251
|
+
} else {
|
|
26252
|
+
workspaceName = await Input.prompt({
|
|
26253
|
+
message: "Name this forked workspace:",
|
|
26254
|
+
default: branchDefaultId
|
|
26255
|
+
});
|
|
26936
26256
|
}
|
|
26937
26257
|
}
|
|
26938
|
-
|
|
26939
|
-
|
|
26940
|
-
|
|
26941
|
-
|
|
26942
|
-
}
|
|
26943
|
-
|
|
26944
|
-
|
|
26945
|
-
|
|
26946
|
-
|
|
26947
|
-
|
|
26948
|
-
}
|
|
26949
|
-
function isRawAppPath(p) {
|
|
26950
|
-
return normalizeSep(p).includes(getFolderSuffixes().raw_app + "/");
|
|
26951
|
-
}
|
|
26952
|
-
function isFolderResourcePathAnyFormat(p) {
|
|
26953
|
-
const n = normalizeSep(p);
|
|
26954
|
-
for (const suffixes of [DOTTED_SUFFIXES, NON_DOTTED_SUFFIXES]) {
|
|
26955
|
-
if (n.includes(suffixes.flow + "/") || n.includes(suffixes.app + "/") || n.includes(suffixes.raw_app + "/")) {
|
|
26956
|
-
return true;
|
|
26258
|
+
if (!workspaceId) {
|
|
26259
|
+
const idDefault = branchToForkId(workspaceName);
|
|
26260
|
+
if (branchDefaultId && !interactive) {
|
|
26261
|
+
workspaceId = idDefault;
|
|
26262
|
+
} else {
|
|
26263
|
+
workspaceId = await Input.prompt({
|
|
26264
|
+
message: `Enter the ID of this forked workspace, it will then be prefixed by ${WM_FORK_PREFIX}. It will also determine the branch name`,
|
|
26265
|
+
default: idDefault,
|
|
26266
|
+
suggestions: [idDefault]
|
|
26267
|
+
});
|
|
26957
26268
|
}
|
|
26958
26269
|
}
|
|
26959
|
-
|
|
26960
|
-
|
|
26961
|
-
|
|
26962
|
-
|
|
26963
|
-
const
|
|
26964
|
-
|
|
26965
|
-
|
|
26966
|
-
|
|
26967
|
-
|
|
26968
|
-
|
|
26969
|
-
|
|
26970
|
-
|
|
26971
|
-
|
|
26972
|
-
|
|
26973
|
-
|
|
26974
|
-
|
|
26975
|
-
|
|
26976
|
-
|
|
26977
|
-
|
|
26978
|
-
|
|
26979
|
-
|
|
26980
|
-
|
|
26981
|
-
|
|
26982
|
-
|
|
26983
|
-
|
|
26984
|
-
|
|
26985
|
-
|
|
26986
|
-
|
|
26987
|
-
|
|
26988
|
-
|
|
26989
|
-
|
|
26990
|
-
|
|
26991
|
-
|
|
26992
|
-
|
|
26993
|
-
}
|
|
26994
|
-
|
|
26995
|
-
|
|
26996
|
-
|
|
26997
|
-
|
|
26998
|
-
|
|
26999
|
-
|
|
27000
|
-
|
|
26270
|
+
const token = workspace.token;
|
|
26271
|
+
if (!token) {
|
|
26272
|
+
throw new Error("Not logged in. Please run 'wmill workspace add' first.");
|
|
26273
|
+
}
|
|
26274
|
+
const remote = workspace.remote;
|
|
26275
|
+
setClient(token, remote.endsWith("/") ? remote.substring(0, remote.length - 1) : remote);
|
|
26276
|
+
info(colors.blue(`Creating forked workspace: ${workspaceName}...`));
|
|
26277
|
+
const trueWorkspaceId = `${WM_FORK_PREFIX}-${workspaceId}`;
|
|
26278
|
+
validateForkWorkspaceId(trueWorkspaceId);
|
|
26279
|
+
let alreadyExists = false;
|
|
26280
|
+
try {
|
|
26281
|
+
alreadyExists = await existsWorkspace({
|
|
26282
|
+
requestBody: { id: trueWorkspaceId }
|
|
26283
|
+
});
|
|
26284
|
+
} catch (e) {
|
|
26285
|
+
info(colors.red.bold("! Credentials or instance is invalid. Aborting."));
|
|
26286
|
+
throw e;
|
|
26287
|
+
}
|
|
26288
|
+
if (alreadyExists) {
|
|
26289
|
+
throw new Error(`This forked workspace '${workspaceId}' (${workspaceName}) already exists, possibly archived (archiving keeps the id reserved). ` + `Permanently delete it with \`wmill workspace delete-fork ${workspaceId}\` to reuse the id, or choose a different id`);
|
|
26290
|
+
}
|
|
26291
|
+
const forkedDatatables = [];
|
|
26292
|
+
let datatables = [];
|
|
26293
|
+
try {
|
|
26294
|
+
datatables = await listDataTables({
|
|
26295
|
+
workspace: workspace.workspaceId
|
|
26296
|
+
});
|
|
26297
|
+
} catch (e) {
|
|
26298
|
+
info(colors.yellow(`Note: Could not list datatables: ${e.message}`));
|
|
26299
|
+
}
|
|
26300
|
+
if (datatables && datatables.length > 0) {
|
|
26301
|
+
const behavior = opts.datatableBehavior ?? (opts.yes ? "skip" : undefined);
|
|
26302
|
+
if (behavior !== "skip") {
|
|
26303
|
+
info(`
|
|
26304
|
+
Found ${datatables.length} datatable(s):`);
|
|
26305
|
+
for (const dt of datatables) {
|
|
26306
|
+
let dtBehavior;
|
|
26307
|
+
if (behavior === "schema_only" || behavior === "schema_and_data") {
|
|
26308
|
+
dtBehavior = behavior;
|
|
26309
|
+
} else {
|
|
26310
|
+
const { Select: Select2 } = await init_select().then(() => exports_select);
|
|
26311
|
+
dtBehavior = await Select2.prompt({
|
|
26312
|
+
message: `Datatable "${dt.name}" (${dt.resource_type}):`,
|
|
26313
|
+
options: [
|
|
26314
|
+
{ name: "Keep original (no cloning)", value: "keep_original" },
|
|
26315
|
+
{ name: "Clone schema only", value: "schema_only" },
|
|
26316
|
+
{ name: "Clone schema and data", value: "schema_and_data" }
|
|
26317
|
+
]
|
|
26318
|
+
});
|
|
26319
|
+
}
|
|
26320
|
+
if (dtBehavior === "keep_original") {
|
|
26321
|
+
continue;
|
|
26322
|
+
}
|
|
26323
|
+
const newDbName = `${trueWorkspaceId.replace(/-/g, "_")}__${dt.name}`;
|
|
26324
|
+
try {
|
|
26325
|
+
info(colors.blue(` Creating database "${newDbName}" for datatable "${dt.name}"...`));
|
|
26326
|
+
await createPgDatabase({
|
|
26327
|
+
workspace: workspace.workspaceId,
|
|
26328
|
+
requestBody: {
|
|
26329
|
+
source: `datatable://${dt.name}`,
|
|
26330
|
+
target_dbname: newDbName
|
|
26331
|
+
}
|
|
26332
|
+
});
|
|
26333
|
+
info(colors.blue(` Importing ${dtBehavior === "schema_only" ? "schema" : "schema + data"}...`));
|
|
26334
|
+
await importPgDatabase({
|
|
26335
|
+
workspace: workspace.workspaceId,
|
|
26336
|
+
requestBody: {
|
|
26337
|
+
source: `datatable://${dt.name}`,
|
|
26338
|
+
target: `datatable://${dt.name}`,
|
|
26339
|
+
target_dbname_override: newDbName,
|
|
26340
|
+
fork_behavior: dtBehavior
|
|
26341
|
+
}
|
|
26342
|
+
});
|
|
26343
|
+
info(colors.green(` ✓ Datatable "${dt.name}" cloned.`));
|
|
26344
|
+
forkedDatatables.push({ name: dt.name, new_dbname: newDbName });
|
|
26345
|
+
} catch (e) {
|
|
26346
|
+
info(colors.yellow(` ✗ Failed to clone datatable "${dt.name}": ${e.message}`));
|
|
26347
|
+
}
|
|
26348
|
+
}
|
|
26349
|
+
}
|
|
27001
26350
|
}
|
|
27002
|
-
|
|
27003
|
-
|
|
27004
|
-
|
|
27005
|
-
|
|
27006
|
-
|
|
26351
|
+
const forkColor = opts.color;
|
|
26352
|
+
try {
|
|
26353
|
+
const gitSyncJobIds = await createWorkspaceForkGitBranch({
|
|
26354
|
+
workspace: workspace.workspaceId,
|
|
26355
|
+
requestBody: {
|
|
26356
|
+
id: trueWorkspaceId,
|
|
26357
|
+
name: opts.createWorkspaceName ?? workspaceName ?? trueWorkspaceId,
|
|
26358
|
+
color: forkColor
|
|
26359
|
+
}
|
|
26360
|
+
});
|
|
26361
|
+
if (gitSyncJobIds && gitSyncJobIds.length > 0) {
|
|
26362
|
+
info(colors.blue(`Git sync branch creation triggered (${gitSyncJobIds.length} job(s)). These will complete asynchronously.`));
|
|
26363
|
+
}
|
|
26364
|
+
} catch (e) {
|
|
26365
|
+
error(colors.red(`Failed to create git branch for fork: ${e.message}`));
|
|
26366
|
+
throw e;
|
|
27007
26367
|
}
|
|
27008
|
-
|
|
27009
|
-
|
|
26368
|
+
try {
|
|
26369
|
+
const result = await createWorkspaceFork({
|
|
26370
|
+
workspace: workspace.workspaceId,
|
|
26371
|
+
requestBody: {
|
|
26372
|
+
id: trueWorkspaceId,
|
|
26373
|
+
name: opts.createWorkspaceName ?? workspaceName ?? trueWorkspaceId,
|
|
26374
|
+
color: forkColor,
|
|
26375
|
+
forked_datatables: forkedDatatables
|
|
26376
|
+
}
|
|
26377
|
+
});
|
|
26378
|
+
info(colors.green(`✅ ${result}`));
|
|
26379
|
+
} catch (error2) {
|
|
26380
|
+
error(colors.red(`Failed to create forked workspace: ${error2.message}`));
|
|
26381
|
+
throw error2;
|
|
27010
26382
|
}
|
|
27011
|
-
|
|
26383
|
+
const newBranchName = `${WM_FORK_PREFIX}/${clonedBranchName}/${workspaceId}`;
|
|
26384
|
+
let onForkBranch = false;
|
|
26385
|
+
if (renameCurrent) {
|
|
26386
|
+
if (currentBranch === newBranchName) {
|
|
26387
|
+
onForkBranch = true;
|
|
26388
|
+
info(colors.green(`Your current branch is already \`${newBranchName}\`.`));
|
|
26389
|
+
} else if (gitBranchExists(newBranchName)) {
|
|
26390
|
+
warn(`Branch \`${newBranchName}\` already exists locally, so the current branch \`${currentBranch}\` was not renamed. Check out the fork branch yourself (e.g. \`git checkout ${newBranchName}\`).`);
|
|
26391
|
+
} else {
|
|
26392
|
+
renameCurrentGitBranch(newBranchName);
|
|
26393
|
+
onForkBranch = true;
|
|
26394
|
+
info(colors.green(`Renamed \`${currentBranch}\` → \`${newBranchName}\`. Your existing commits are now on the fork branch.`));
|
|
26395
|
+
}
|
|
26396
|
+
}
|
|
26397
|
+
const checkoutHint = onForkBranch ? `Created forked workspace ${trueWorkspaceId}. You are on the fork branch \`${newBranchName}\` — push it to sync your fork.` : `Created forked workspace ${trueWorkspaceId}. To start contributing to your fork, create and push edits to the branch \`${newBranchName}\` by using the command:
|
|
26398
|
+
|
|
26399
|
+
` + colors.white(`git checkout -b ${newBranchName}`);
|
|
26400
|
+
info(`${checkoutHint}
|
|
26401
|
+
|
|
26402
|
+
When doing operations on the forked workspace, it will use the remote setup in the workspaces section for the branch it was forked from.
|
|
26403
|
+
|
|
26404
|
+
To merge changes back to the parent workspace, you can:
|
|
26405
|
+
- Use the CLI: ` + colors.white(`git checkout ${newBranchName} && wmill workspace merge`) + `
|
|
26406
|
+
- Use the Merge UI from the forked workspace home page
|
|
26407
|
+
- Use git: ` + colors.white(`git checkout ${clonedBranchName} && git merge ${newBranchName} && wmill sync push`) + `
|
|
26408
|
+
See: https://www.windmill.dev/docs/advanced/workspace_forks`);
|
|
27012
26409
|
}
|
|
27013
|
-
function
|
|
27014
|
-
|
|
27015
|
-
|
|
26410
|
+
async function resolveWorkingBranchBase(config, opts, currentBranch) {
|
|
26411
|
+
const interactive = process10.stdin.isTTY && opts.yes !== true;
|
|
26412
|
+
if (!interactive) {
|
|
26413
|
+
throw new Error(`You are on working branch \`${currentBranch}\`, which is not a base branch. Pass --from-branch <base> to base the fork on a base branch and rename this branch onto the fork branch, or check out a base branch and run \`wmill workspace fork\` to create a fresh fork branch.`);
|
|
27016
26414
|
}
|
|
27017
|
-
|
|
27018
|
-
|
|
26415
|
+
const { Select: Select2 } = await init_select().then(() => exports_select);
|
|
26416
|
+
const proceed = await Select2.prompt({
|
|
26417
|
+
message: `You're on working branch \`${currentBranch}\`, not a base branch. Base a fork on it and rename it onto the fork branch?`,
|
|
26418
|
+
options: [
|
|
26419
|
+
{ name: "Yes, base the fork on this branch and rename it", value: "yes" },
|
|
26420
|
+
{ name: "No, cancel", value: "no" }
|
|
26421
|
+
]
|
|
26422
|
+
});
|
|
26423
|
+
if (proceed !== "yes") {
|
|
26424
|
+
throw new Error("Fork cancelled. Check out a base branch to create a fresh fork branch instead.");
|
|
26425
|
+
}
|
|
26426
|
+
const baseBranches = listConfiguredBaseBranches(config);
|
|
26427
|
+
if (baseBranches.length === 0) {
|
|
26428
|
+
throw new Error(`No base branches are configured in wmill.yaml's workspaces section, so the fork can't be linked to a parent. Add the parent workspace to wmill.yaml, or pass --from-branch <base>.`);
|
|
26429
|
+
}
|
|
26430
|
+
if (baseBranches.length === 1) {
|
|
26431
|
+
info(`Basing the fork on \`${baseBranches[0]}\`.`);
|
|
26432
|
+
return baseBranches[0];
|
|
26433
|
+
}
|
|
26434
|
+
return await Select2.prompt({
|
|
26435
|
+
message: "Which base branch is this fork based on (the parent)?",
|
|
26436
|
+
options: baseBranches.map((b) => ({ name: b, value: b }))
|
|
26437
|
+
});
|
|
26438
|
+
}
|
|
26439
|
+
function branchToForkId(branch) {
|
|
26440
|
+
const slug = branch.replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, MAX_FORK_ID_SLUG).replace(/-+$/g, "");
|
|
26441
|
+
return slug || "fork";
|
|
26442
|
+
}
|
|
26443
|
+
function validateForkWorkspaceId(id) {
|
|
26444
|
+
const reject = (reason) => {
|
|
26445
|
+
throw new Error(`Fork workspace id \`${id}\` is invalid: ${reason}. Choose a shorter or simpler name/id.`);
|
|
26446
|
+
};
|
|
26447
|
+
if (id.length > 50) {
|
|
26448
|
+
reject(`too long (${id.length} chars; max 50 including the \`${WM_FORK_PREFIX}-\` prefix)`);
|
|
26449
|
+
}
|
|
26450
|
+
if (id.endsWith("."))
|
|
26451
|
+
reject("cannot end with '.'");
|
|
26452
|
+
if (id.endsWith(".lock"))
|
|
26453
|
+
reject("cannot end with '.lock'");
|
|
26454
|
+
if (id.includes(".."))
|
|
26455
|
+
reject("cannot contain '..'");
|
|
26456
|
+
if (id.includes("@{"))
|
|
26457
|
+
reject("cannot contain '@{'");
|
|
26458
|
+
if (id.includes("//"))
|
|
26459
|
+
reject("cannot contain '//'");
|
|
26460
|
+
for (const ch of id) {
|
|
26461
|
+
if (":~^?*[\\ ".includes(ch))
|
|
26462
|
+
reject(`contains forbidden character '${ch}'`);
|
|
26463
|
+
const code2 = ch.charCodeAt(0);
|
|
26464
|
+
if (code2 < 32 || code2 === 127)
|
|
26465
|
+
reject("contains a control character");
|
|
26466
|
+
}
|
|
26467
|
+
for (const component of id.split("/")) {
|
|
26468
|
+
if (component.startsWith("."))
|
|
26469
|
+
reject("a path component cannot start with '.'");
|
|
26470
|
+
if (component.endsWith(".lock"))
|
|
26471
|
+
reject("a path component cannot end with '.lock'");
|
|
26472
|
+
}
|
|
26473
|
+
}
|
|
26474
|
+
function listConfiguredBaseBranches(config) {
|
|
26475
|
+
const workspaces = config.workspaces;
|
|
26476
|
+
const branches = new Set;
|
|
26477
|
+
for (const name of getWorkspaceNames(workspaces)) {
|
|
26478
|
+
branches.add(getEffectiveGitBranch(name, workspaces[name]));
|
|
27019
26479
|
}
|
|
27020
|
-
return
|
|
26480
|
+
return [...branches];
|
|
27021
26481
|
}
|
|
27022
|
-
function
|
|
27023
|
-
|
|
27024
|
-
|
|
26482
|
+
async function deleteWorkspaceFork(opts, name) {
|
|
26483
|
+
let forkWorkspaceId;
|
|
26484
|
+
let token;
|
|
26485
|
+
let remote;
|
|
26486
|
+
let hasLocalProfile = false;
|
|
26487
|
+
const orgWorkspaces = await allWorkspaces(opts.configDir);
|
|
26488
|
+
const idxOf = orgWorkspaces.findIndex((x) => x.name === name);
|
|
26489
|
+
if (idxOf !== -1) {
|
|
26490
|
+
const workspace = orgWorkspaces[idxOf];
|
|
26491
|
+
if (!workspace.workspaceId.startsWith(WM_FORK_PREFIX)) {
|
|
26492
|
+
throw new Error(`You can only delete forked workspaces where the workspace id starts with \`${WM_FORK_PREFIX}.\` Failed while attempting to delete \`${workspace.workspaceId}\``);
|
|
26493
|
+
}
|
|
26494
|
+
forkWorkspaceId = workspace.workspaceId;
|
|
26495
|
+
token = workspace.token;
|
|
26496
|
+
remote = workspace.remote;
|
|
26497
|
+
hasLocalProfile = true;
|
|
26498
|
+
} else {
|
|
26499
|
+
const parentWorkspace = await tryResolveBranchWorkspace(opts);
|
|
26500
|
+
if (!parentWorkspace) {
|
|
26501
|
+
throw new Error("Could not resolve parent workspace. Make sure you are in a git repo with 'workspaces' configured in wmill.yaml, or create a local workspace profile for the fork.");
|
|
26502
|
+
}
|
|
26503
|
+
forkWorkspaceId = name.startsWith(`${WM_FORK_PREFIX}-`) ? name : `${WM_FORK_PREFIX}-${name}`;
|
|
26504
|
+
token = parentWorkspace.token;
|
|
26505
|
+
remote = parentWorkspace.remote;
|
|
27025
26506
|
}
|
|
27026
|
-
if (
|
|
27027
|
-
|
|
26507
|
+
if (!opts.yes) {
|
|
26508
|
+
const { Select: Select2 } = await init_select().then(() => exports_select);
|
|
26509
|
+
const choice = await Select2.prompt({
|
|
26510
|
+
message: `Are you sure you want to delete the forked workspace \`${forkWorkspaceId}\`?`,
|
|
26511
|
+
options: [
|
|
26512
|
+
{ name: "Yes", value: "confirm" },
|
|
26513
|
+
{ name: "No", value: "cancel" }
|
|
26514
|
+
]
|
|
26515
|
+
});
|
|
26516
|
+
if (choice === "cancel") {
|
|
26517
|
+
info("Operation cancelled");
|
|
26518
|
+
return;
|
|
26519
|
+
}
|
|
26520
|
+
}
|
|
26521
|
+
setClient(token, remote.endsWith("/") ? remote.substring(0, remote.length - 1) : remote);
|
|
26522
|
+
const result = await deleteWorkspace({
|
|
26523
|
+
workspace: forkWorkspaceId
|
|
26524
|
+
});
|
|
26525
|
+
info(colors.green(`✅ Forked workspace '${forkWorkspaceId}' deleted successfully!
|
|
26526
|
+
${result}`));
|
|
26527
|
+
if (hasLocalProfile) {
|
|
26528
|
+
await removeWorkspace(name, false, opts);
|
|
27028
26529
|
}
|
|
27029
|
-
return false;
|
|
27030
26530
|
}
|
|
27031
|
-
|
|
27032
|
-
|
|
26531
|
+
var MAX_FORK_ID_SLUG = 42;
|
|
26532
|
+
var init_fork = __esm(async () => {
|
|
26533
|
+
init_colors2();
|
|
26534
|
+
init_log();
|
|
26535
|
+
init_client();
|
|
26536
|
+
init_services_gen();
|
|
26537
|
+
init_git();
|
|
26538
|
+
await __promiseAll([
|
|
26539
|
+
init_input(),
|
|
26540
|
+
init_workspace(),
|
|
26541
|
+
init_context(),
|
|
26542
|
+
init_conf()
|
|
26543
|
+
]);
|
|
26544
|
+
});
|
|
26545
|
+
|
|
26546
|
+
// windmill-utils-internal/src/deploy.ts
|
|
26547
|
+
function isTriggerKind(kind) {
|
|
26548
|
+
return TRIGGER_KINDS.includes(kind);
|
|
27033
26549
|
}
|
|
27034
|
-
function
|
|
27035
|
-
return
|
|
26550
|
+
function isTriggerOrScheduleKind(kind) {
|
|
26551
|
+
return kind === "schedule" || isTriggerKind(kind);
|
|
27036
26552
|
}
|
|
27037
|
-
function
|
|
27038
|
-
return
|
|
26553
|
+
function folderName(path3) {
|
|
26554
|
+
return path3.replace(/^f\//, "");
|
|
27039
26555
|
}
|
|
27040
|
-
function
|
|
27041
|
-
|
|
26556
|
+
function stripOperationalStateOnUpdate(payload, alreadyExists) {
|
|
26557
|
+
if (!alreadyExists)
|
|
26558
|
+
return payload;
|
|
26559
|
+
const { mode: _mode, enabled: _enabled, ...rest } = payload;
|
|
26560
|
+
return rest;
|
|
27042
26561
|
}
|
|
27043
|
-
function
|
|
27044
|
-
|
|
26562
|
+
function getSubModules(flowModule) {
|
|
26563
|
+
const type = flowModule?.value?.type;
|
|
26564
|
+
if (type === "forloopflow" || type === "whileloopflow") {
|
|
26565
|
+
return [flowModule.value.modules ?? []];
|
|
26566
|
+
} else if (type === "branchall") {
|
|
26567
|
+
return (flowModule.value.branches ?? []).map((branch) => branch.modules ?? []);
|
|
26568
|
+
} else if (type === "branchone") {
|
|
26569
|
+
return [
|
|
26570
|
+
...(flowModule.value.branches ?? []).map((b) => b.modules ?? []),
|
|
26571
|
+
flowModule.value.default ?? []
|
|
26572
|
+
];
|
|
26573
|
+
} else if (type === "aiagent") {
|
|
26574
|
+
if (flowModule.value.tools) {
|
|
26575
|
+
return [
|
|
26576
|
+
flowModule.value.tools.filter((t) => t.value?.type === "script" || t.value?.type === "flow").map((t) => ({
|
|
26577
|
+
id: t.id,
|
|
26578
|
+
value: t.value,
|
|
26579
|
+
summary: t.summary
|
|
26580
|
+
}))
|
|
26581
|
+
];
|
|
26582
|
+
}
|
|
26583
|
+
}
|
|
26584
|
+
return [];
|
|
27045
26585
|
}
|
|
27046
|
-
function
|
|
27047
|
-
|
|
27048
|
-
const suffix = MODULE_SUFFIX + "/";
|
|
27049
|
-
const idx = norm.indexOf(suffix);
|
|
27050
|
-
if (idx === -1)
|
|
27051
|
-
return false;
|
|
27052
|
-
const rest = norm.slice(idx + suffix.length);
|
|
27053
|
-
return rest.startsWith("script.") && !rest.includes("/");
|
|
26586
|
+
function getAllSubmodules(flowModule) {
|
|
26587
|
+
return getSubModules(flowModule).map((modules) => modules.flatMap((m) => [m, ...getAllSubmodules(m)])).flat();
|
|
27054
26588
|
}
|
|
27055
|
-
function
|
|
27056
|
-
|
|
27057
|
-
|
|
27058
|
-
|
|
27059
|
-
|
|
27060
|
-
|
|
27061
|
-
return norm.slice(0, idx);
|
|
26589
|
+
function getAllModules(flowModules, failureModule) {
|
|
26590
|
+
return [
|
|
26591
|
+
...flowModules,
|
|
26592
|
+
...flowModules.flatMap((x) => getAllSubmodules(x)),
|
|
26593
|
+
...failureModule ? [failureModule] : []
|
|
26594
|
+
];
|
|
27062
26595
|
}
|
|
27063
|
-
function
|
|
27064
|
-
|
|
26596
|
+
function toError(e) {
|
|
26597
|
+
const err = e;
|
|
26598
|
+
return err.body || err.message || String(e);
|
|
27065
26599
|
}
|
|
27066
|
-
function
|
|
27067
|
-
|
|
26600
|
+
async function checkItemExists(provider, kind, path3, workspace) {
|
|
26601
|
+
if (kind === "flow") {
|
|
26602
|
+
return provider.existsFlowByPath({ workspace, path: path3 });
|
|
26603
|
+
} else if (kind === "script") {
|
|
26604
|
+
return provider.existsScriptByPath({ workspace, path: path3 });
|
|
26605
|
+
} else if (kind === "app" || kind === "raw_app") {
|
|
26606
|
+
return provider.existsApp({ workspace, path: path3 });
|
|
26607
|
+
} else if (kind === "variable") {
|
|
26608
|
+
return provider.existsVariable({ workspace, path: path3 });
|
|
26609
|
+
} else if (kind === "resource") {
|
|
26610
|
+
return provider.existsResource({ workspace, path: path3 });
|
|
26611
|
+
} else if (kind === "resource_type") {
|
|
26612
|
+
return provider.existsResourceType({ workspace, path: path3 });
|
|
26613
|
+
} else if (kind === "folder") {
|
|
26614
|
+
return provider.existsFolder({ workspace, name: folderName(path3) });
|
|
26615
|
+
} else if (kind === "schedule") {
|
|
26616
|
+
return provider.existsSchedule({ workspace, path: path3 });
|
|
26617
|
+
} else if (isTriggerKind(kind)) {
|
|
26618
|
+
return provider.existsTriggerByKind(kind, { workspace, path: path3 });
|
|
26619
|
+
}
|
|
26620
|
+
throw new Error(`Unknown kind: ${kind}`);
|
|
27068
26621
|
}
|
|
27069
|
-
function
|
|
27070
|
-
const
|
|
27071
|
-
|
|
27072
|
-
const
|
|
27073
|
-
|
|
26622
|
+
async function deployItem(provider, kind, path3, workspaceFrom, workspaceTo, onBehalfOf) {
|
|
26623
|
+
const preserveOnBehalfOf = onBehalfOf !== undefined;
|
|
26624
|
+
try {
|
|
26625
|
+
const alreadyExists = await checkItemExists(provider, kind, path3, workspaceTo);
|
|
26626
|
+
if (kind === "flow") {
|
|
26627
|
+
const flow = await provider.getFlowByPath({
|
|
26628
|
+
workspace: workspaceFrom,
|
|
26629
|
+
path: path3
|
|
26630
|
+
});
|
|
26631
|
+
getAllModules(flow.value?.modules ?? [], flow.value?.failure_module).forEach((x) => {
|
|
26632
|
+
if (x.value?.type === "script" && x.value.hash != null) {
|
|
26633
|
+
x.value.hash = undefined;
|
|
26634
|
+
}
|
|
26635
|
+
});
|
|
26636
|
+
if (alreadyExists) {
|
|
26637
|
+
await provider.updateFlow({
|
|
26638
|
+
workspace: workspaceTo,
|
|
26639
|
+
path: path3,
|
|
26640
|
+
requestBody: {
|
|
26641
|
+
...flow,
|
|
26642
|
+
preserve_on_behalf_of: preserveOnBehalfOf,
|
|
26643
|
+
on_behalf_of_email: onBehalfOf
|
|
26644
|
+
}
|
|
26645
|
+
});
|
|
26646
|
+
} else {
|
|
26647
|
+
await provider.createFlow({
|
|
26648
|
+
workspace: workspaceTo,
|
|
26649
|
+
requestBody: {
|
|
26650
|
+
...flow,
|
|
26651
|
+
preserve_on_behalf_of: preserveOnBehalfOf,
|
|
26652
|
+
on_behalf_of_email: onBehalfOf
|
|
26653
|
+
}
|
|
26654
|
+
});
|
|
26655
|
+
}
|
|
26656
|
+
} else if (kind === "script") {
|
|
26657
|
+
const script = await provider.getScriptByPath({
|
|
26658
|
+
workspace: workspaceFrom,
|
|
26659
|
+
path: path3
|
|
26660
|
+
});
|
|
26661
|
+
let parentHash;
|
|
26662
|
+
if (alreadyExists) {
|
|
26663
|
+
const existing = await provider.getScriptByPath({
|
|
26664
|
+
workspace: workspaceTo,
|
|
26665
|
+
path: path3
|
|
26666
|
+
});
|
|
26667
|
+
parentHash = existing.hash;
|
|
26668
|
+
}
|
|
26669
|
+
await provider.createScript({
|
|
26670
|
+
workspace: workspaceTo,
|
|
26671
|
+
requestBody: {
|
|
26672
|
+
...script,
|
|
26673
|
+
lock: script.lock,
|
|
26674
|
+
parent_hash: parentHash,
|
|
26675
|
+
preserve_on_behalf_of: preserveOnBehalfOf,
|
|
26676
|
+
on_behalf_of_email: onBehalfOf
|
|
26677
|
+
}
|
|
26678
|
+
});
|
|
26679
|
+
} else if (kind === "app" || kind === "raw_app") {
|
|
26680
|
+
const app = await provider.getAppByPath({
|
|
26681
|
+
workspace: workspaceFrom,
|
|
26682
|
+
path: path3
|
|
26683
|
+
});
|
|
26684
|
+
if (alreadyExists) {
|
|
26685
|
+
if (app.raw_app) {
|
|
26686
|
+
const secret = await provider.getPublicSecretOfLatestVersionOfApp({
|
|
26687
|
+
workspace: workspaceFrom,
|
|
26688
|
+
path: app.path
|
|
26689
|
+
});
|
|
26690
|
+
const js = await provider.getRawAppData({
|
|
26691
|
+
secretWithExtension: `${secret}.js`,
|
|
26692
|
+
workspace: workspaceFrom
|
|
26693
|
+
});
|
|
26694
|
+
const css = await provider.getRawAppData({
|
|
26695
|
+
secretWithExtension: `${secret}.css`,
|
|
26696
|
+
workspace: workspaceFrom
|
|
26697
|
+
});
|
|
26698
|
+
await provider.updateAppRaw({
|
|
26699
|
+
workspace: workspaceTo,
|
|
26700
|
+
path: path3,
|
|
26701
|
+
formData: {
|
|
26702
|
+
app: { ...app, preserve_on_behalf_of: preserveOnBehalfOf },
|
|
26703
|
+
css,
|
|
26704
|
+
js
|
|
26705
|
+
}
|
|
26706
|
+
});
|
|
26707
|
+
} else {
|
|
26708
|
+
await provider.updateApp({
|
|
26709
|
+
workspace: workspaceTo,
|
|
26710
|
+
path: path3,
|
|
26711
|
+
requestBody: {
|
|
26712
|
+
...app,
|
|
26713
|
+
preserve_on_behalf_of: preserveOnBehalfOf
|
|
26714
|
+
}
|
|
26715
|
+
});
|
|
26716
|
+
}
|
|
26717
|
+
} else {
|
|
26718
|
+
if (app.raw_app) {
|
|
26719
|
+
const secret = await provider.getPublicSecretOfLatestVersionOfApp({
|
|
26720
|
+
workspace: workspaceFrom,
|
|
26721
|
+
path: app.path
|
|
26722
|
+
});
|
|
26723
|
+
const js = await provider.getRawAppData({
|
|
26724
|
+
secretWithExtension: `${secret}.js`,
|
|
26725
|
+
workspace: workspaceFrom
|
|
26726
|
+
});
|
|
26727
|
+
const css = await provider.getRawAppData({
|
|
26728
|
+
secretWithExtension: `${secret}.css`,
|
|
26729
|
+
workspace: workspaceFrom
|
|
26730
|
+
});
|
|
26731
|
+
await provider.createAppRaw({
|
|
26732
|
+
workspace: workspaceTo,
|
|
26733
|
+
formData: {
|
|
26734
|
+
app: { ...app, preserve_on_behalf_of: preserveOnBehalfOf },
|
|
26735
|
+
css,
|
|
26736
|
+
js
|
|
26737
|
+
}
|
|
26738
|
+
});
|
|
26739
|
+
} else {
|
|
26740
|
+
await provider.createApp({
|
|
26741
|
+
workspace: workspaceTo,
|
|
26742
|
+
requestBody: {
|
|
26743
|
+
...app,
|
|
26744
|
+
preserve_on_behalf_of: preserveOnBehalfOf
|
|
26745
|
+
}
|
|
26746
|
+
});
|
|
26747
|
+
}
|
|
26748
|
+
}
|
|
26749
|
+
} else if (kind === "variable") {
|
|
26750
|
+
const variable = await provider.getVariable({
|
|
26751
|
+
workspace: workspaceFrom,
|
|
26752
|
+
path: path3,
|
|
26753
|
+
decryptSecret: true
|
|
26754
|
+
});
|
|
26755
|
+
if (alreadyExists) {
|
|
26756
|
+
await provider.updateVariable({
|
|
26757
|
+
workspace: workspaceTo,
|
|
26758
|
+
path: path3,
|
|
26759
|
+
requestBody: {
|
|
26760
|
+
path: path3,
|
|
26761
|
+
value: variable.value ?? "",
|
|
26762
|
+
is_secret: variable.is_secret,
|
|
26763
|
+
description: variable.description ?? ""
|
|
26764
|
+
},
|
|
26765
|
+
alreadyEncrypted: false
|
|
26766
|
+
});
|
|
26767
|
+
} else {
|
|
26768
|
+
await provider.createVariable({
|
|
26769
|
+
workspace: workspaceTo,
|
|
26770
|
+
requestBody: {
|
|
26771
|
+
path: path3,
|
|
26772
|
+
value: variable.value ?? "",
|
|
26773
|
+
is_secret: variable.is_secret,
|
|
26774
|
+
description: variable.description ?? ""
|
|
26775
|
+
}
|
|
26776
|
+
});
|
|
26777
|
+
}
|
|
26778
|
+
} else if (kind === "resource") {
|
|
26779
|
+
const resource = await provider.getResource({
|
|
26780
|
+
workspace: workspaceFrom,
|
|
26781
|
+
path: path3
|
|
26782
|
+
});
|
|
26783
|
+
if (alreadyExists) {
|
|
26784
|
+
await provider.updateResource({
|
|
26785
|
+
workspace: workspaceTo,
|
|
26786
|
+
path: path3,
|
|
26787
|
+
requestBody: {
|
|
26788
|
+
path: path3,
|
|
26789
|
+
value: resource.value ?? "",
|
|
26790
|
+
description: resource.description ?? ""
|
|
26791
|
+
}
|
|
26792
|
+
});
|
|
26793
|
+
} else {
|
|
26794
|
+
await provider.createResource({
|
|
26795
|
+
workspace: workspaceTo,
|
|
26796
|
+
requestBody: {
|
|
26797
|
+
path: path3,
|
|
26798
|
+
value: resource.value ?? "",
|
|
26799
|
+
resource_type: resource.resource_type,
|
|
26800
|
+
description: resource.description ?? ""
|
|
26801
|
+
}
|
|
26802
|
+
});
|
|
26803
|
+
}
|
|
26804
|
+
} else if (kind === "resource_type") {
|
|
26805
|
+
const rt = await provider.getResourceType({
|
|
26806
|
+
workspace: workspaceFrom,
|
|
26807
|
+
path: path3
|
|
26808
|
+
});
|
|
26809
|
+
if (alreadyExists) {
|
|
26810
|
+
await provider.updateResourceType({
|
|
26811
|
+
workspace: workspaceTo,
|
|
26812
|
+
path: path3,
|
|
26813
|
+
requestBody: {
|
|
26814
|
+
schema: rt.schema,
|
|
26815
|
+
description: rt.description ?? ""
|
|
26816
|
+
}
|
|
26817
|
+
});
|
|
26818
|
+
} else {
|
|
26819
|
+
await provider.createResourceType({
|
|
26820
|
+
workspace: workspaceTo,
|
|
26821
|
+
requestBody: {
|
|
26822
|
+
name: rt.name,
|
|
26823
|
+
schema: rt.schema,
|
|
26824
|
+
description: rt.description ?? ""
|
|
26825
|
+
}
|
|
26826
|
+
});
|
|
26827
|
+
}
|
|
26828
|
+
} else if (kind === "folder") {
|
|
26829
|
+
const name = folderName(path3);
|
|
26830
|
+
const folder = await provider.getFolder({
|
|
26831
|
+
workspace: workspaceFrom,
|
|
26832
|
+
name
|
|
26833
|
+
});
|
|
26834
|
+
if (alreadyExists) {
|
|
26835
|
+
await provider.updateFolder({
|
|
26836
|
+
workspace: workspaceTo,
|
|
26837
|
+
name,
|
|
26838
|
+
requestBody: {
|
|
26839
|
+
owners: folder.owners,
|
|
26840
|
+
extra_perms: folder.extra_perms,
|
|
26841
|
+
summary: folder.summary ?? undefined
|
|
26842
|
+
}
|
|
26843
|
+
});
|
|
26844
|
+
} else {
|
|
26845
|
+
await provider.createFolder({
|
|
26846
|
+
workspace: workspaceTo,
|
|
26847
|
+
requestBody: {
|
|
26848
|
+
name,
|
|
26849
|
+
owners: folder.owners,
|
|
26850
|
+
extra_perms: folder.extra_perms,
|
|
26851
|
+
summary: folder.summary ?? undefined
|
|
26852
|
+
}
|
|
26853
|
+
});
|
|
26854
|
+
}
|
|
26855
|
+
} else if (kind === "schedule") {
|
|
26856
|
+
const schedule = await provider.getSchedule({
|
|
26857
|
+
workspace: workspaceFrom,
|
|
26858
|
+
path: path3
|
|
26859
|
+
});
|
|
26860
|
+
const baseBody = stripOperationalStateOnUpdate(schedule, alreadyExists);
|
|
26861
|
+
const requestBody = {
|
|
26862
|
+
...baseBody,
|
|
26863
|
+
permissioned_as: onBehalfOf,
|
|
26864
|
+
preserve_permissioned_as: preserveOnBehalfOf
|
|
26865
|
+
};
|
|
26866
|
+
if (alreadyExists) {
|
|
26867
|
+
await provider.updateSchedule({
|
|
26868
|
+
workspace: workspaceTo,
|
|
26869
|
+
path: path3,
|
|
26870
|
+
requestBody
|
|
26871
|
+
});
|
|
26872
|
+
} else {
|
|
26873
|
+
await provider.createSchedule({
|
|
26874
|
+
workspace: workspaceTo,
|
|
26875
|
+
requestBody
|
|
26876
|
+
});
|
|
26877
|
+
}
|
|
26878
|
+
} else if (isTriggerKind(kind)) {
|
|
26879
|
+
const triggerBody = await provider.getTriggerForDeploy(kind, {
|
|
26880
|
+
workspace: workspaceFrom,
|
|
26881
|
+
path: path3,
|
|
26882
|
+
onBehalfOf
|
|
26883
|
+
});
|
|
26884
|
+
const requestBody = stripOperationalStateOnUpdate(triggerBody, alreadyExists);
|
|
26885
|
+
if (alreadyExists) {
|
|
26886
|
+
await provider.updateTriggerByKind(kind, {
|
|
26887
|
+
workspace: workspaceTo,
|
|
26888
|
+
path: path3,
|
|
26889
|
+
requestBody
|
|
26890
|
+
});
|
|
26891
|
+
} else {
|
|
26892
|
+
await provider.createTriggerByKind(kind, {
|
|
26893
|
+
workspace: workspaceTo,
|
|
26894
|
+
requestBody
|
|
26895
|
+
});
|
|
26896
|
+
}
|
|
26897
|
+
} else {
|
|
26898
|
+
throw new Error(`Unknown kind: ${kind}`);
|
|
26899
|
+
}
|
|
26900
|
+
return { success: true };
|
|
26901
|
+
} catch (e) {
|
|
26902
|
+
return { success: false, error: toError(e) };
|
|
27074
26903
|
}
|
|
27075
|
-
|
|
27076
|
-
|
|
27077
|
-
|
|
26904
|
+
}
|
|
26905
|
+
async function deleteItemInWorkspace(provider, kind, path3, workspace) {
|
|
26906
|
+
try {
|
|
26907
|
+
if (kind === "script") {
|
|
26908
|
+
await provider.archiveScriptByPath({ workspace, path: path3 });
|
|
26909
|
+
} else if (kind === "flow") {
|
|
26910
|
+
await provider.archiveFlowByPath({
|
|
26911
|
+
workspace,
|
|
26912
|
+
path: path3,
|
|
26913
|
+
requestBody: { archived: true }
|
|
26914
|
+
});
|
|
26915
|
+
} else if (kind === "app" || kind === "raw_app") {
|
|
26916
|
+
await provider.deleteApp({ workspace, path: path3 });
|
|
26917
|
+
} else if (kind === "variable") {
|
|
26918
|
+
await provider.deleteVariable({ workspace, path: path3 });
|
|
26919
|
+
} else if (kind === "resource") {
|
|
26920
|
+
await provider.deleteResource({ workspace, path: path3 });
|
|
26921
|
+
} else if (kind === "resource_type") {
|
|
26922
|
+
await provider.deleteResourceType({ workspace, path: path3 });
|
|
26923
|
+
} else if (kind === "folder") {
|
|
26924
|
+
await provider.deleteFolder({ workspace, name: folderName(path3) });
|
|
26925
|
+
} else if (kind === "schedule") {
|
|
26926
|
+
await provider.deleteSchedule({ workspace, path: path3 });
|
|
26927
|
+
} else if (isTriggerKind(kind)) {
|
|
26928
|
+
await provider.deleteTriggerByKind(kind, { workspace, path: path3 });
|
|
26929
|
+
} else {
|
|
26930
|
+
throw new Error(`Deletion not supported for kind: ${kind}`);
|
|
26931
|
+
}
|
|
26932
|
+
return { success: true };
|
|
26933
|
+
} catch (e) {
|
|
26934
|
+
return { success: false, error: toError(e) };
|
|
27078
26935
|
}
|
|
27079
|
-
return p;
|
|
27080
26936
|
}
|
|
27081
|
-
|
|
27082
|
-
|
|
27083
|
-
|
|
27084
|
-
|
|
27085
|
-
|
|
27086
|
-
|
|
27087
|
-
|
|
27088
|
-
|
|
27089
|
-
|
|
27090
|
-
|
|
27091
|
-
|
|
27092
|
-
|
|
27093
|
-
|
|
27094
|
-
|
|
27095
|
-
|
|
27096
|
-
|
|
27097
|
-
|
|
27098
|
-
|
|
27099
|
-
|
|
26937
|
+
async function getOnBehalfOf(provider, kind, path3, workspace) {
|
|
26938
|
+
try {
|
|
26939
|
+
if (kind === "flow") {
|
|
26940
|
+
const flow = await provider.getFlowByPath({ workspace, path: path3 });
|
|
26941
|
+
return flow.on_behalf_of_email;
|
|
26942
|
+
} else if (kind === "script") {
|
|
26943
|
+
const script = await provider.getScriptByPath({ workspace, path: path3 });
|
|
26944
|
+
return script.on_behalf_of_email;
|
|
26945
|
+
} else if (kind === "app" || kind === "raw_app") {
|
|
26946
|
+
const app = await provider.getAppByPath({ workspace, path: path3 });
|
|
26947
|
+
return app.policy?.on_behalf_of_email;
|
|
26948
|
+
} else if (kind === "schedule") {
|
|
26949
|
+
const schedule = await provider.getSchedule({ workspace, path: path3 });
|
|
26950
|
+
return schedule.permissioned_as;
|
|
26951
|
+
} else if (isTriggerKind(kind)) {
|
|
26952
|
+
return await provider.getTriggerPermissionedAs(kind, { workspace, path: path3 });
|
|
26953
|
+
}
|
|
26954
|
+
} catch {}
|
|
26955
|
+
return;
|
|
26956
|
+
}
|
|
26957
|
+
var TRIGGER_KINDS;
|
|
26958
|
+
var init_deploy = __esm(() => {
|
|
26959
|
+
TRIGGER_KINDS = [
|
|
26960
|
+
"http_trigger",
|
|
26961
|
+
"websocket_trigger",
|
|
26962
|
+
"kafka_trigger",
|
|
26963
|
+
"nats_trigger",
|
|
26964
|
+
"postgres_trigger",
|
|
26965
|
+
"mqtt_trigger",
|
|
26966
|
+
"sqs_trigger",
|
|
26967
|
+
"gcp_trigger",
|
|
26968
|
+
"azure_trigger",
|
|
26969
|
+
"email_trigger"
|
|
26970
|
+
];
|
|
27100
26971
|
});
|
|
27101
26972
|
|
|
27102
|
-
//
|
|
27103
|
-
var
|
|
27104
|
-
__export(
|
|
27105
|
-
|
|
27106
|
-
|
|
27107
|
-
setShowDiffs: () => setShowDiffs,
|
|
27108
|
-
readConfigFile: () => readConfigFile,
|
|
27109
|
-
parseSyncBehavior: () => parseSyncBehavior,
|
|
27110
|
-
mergeConfigWithConfigFile: () => mergeConfigWithConfigFile,
|
|
27111
|
-
getWorkspaceNames: () => getWorkspaceNames,
|
|
27112
|
-
getWmillYamlPath: () => getWmillYamlPath,
|
|
27113
|
-
getEffectiveWorkspaceId: () => getEffectiveWorkspaceId,
|
|
27114
|
-
getEffectiveSettings: () => getEffectiveSettings,
|
|
27115
|
-
getEffectiveGitBranch: () => getEffectiveGitBranch,
|
|
27116
|
-
findWorkspaceByGitBranch: () => findWorkspaceByGitBranch,
|
|
27117
|
-
convertGitBranchesToWorkspaces: () => convertGitBranchesToWorkspaces,
|
|
27118
|
-
SUPPORTED_SYNC_BEHAVIOR_VERSION: () => SUPPORTED_SYNC_BEHAVIOR_VERSION,
|
|
27119
|
-
GLOBAL_CONFIG_OPT: () => GLOBAL_CONFIG_OPT,
|
|
27120
|
-
DEFAULT_SYNC_OPTIONS: () => DEFAULT_SYNC_OPTIONS
|
|
26973
|
+
// node_modules/@cliffy/prompt/checkbox.js
|
|
26974
|
+
var exports_checkbox = {};
|
|
26975
|
+
__export(exports_checkbox, {
|
|
26976
|
+
isCheckboxOptionGroup: () => isCheckboxOptionGroup,
|
|
26977
|
+
Checkbox: () => Checkbox
|
|
27121
26978
|
});
|
|
27122
|
-
|
|
27123
|
-
|
|
27124
|
-
import { writeFile } from "node:fs/promises";
|
|
27125
|
-
import { execSync as execSync2 } from "node:child_process";
|
|
27126
|
-
function setShowDiffs(value) {
|
|
27127
|
-
showDiffs = value;
|
|
26979
|
+
function areSomeChecked(options) {
|
|
26980
|
+
return options.some((option) => isOptionGroup(option) ? areSomeChecked(option.options) : option.checked);
|
|
27128
26981
|
}
|
|
27129
|
-
function
|
|
27130
|
-
|
|
27131
|
-
return 0;
|
|
27132
|
-
const s = String(value);
|
|
27133
|
-
const match = s.match(/^v(\d+)$/);
|
|
27134
|
-
return match ? parseInt(match[1], 10) : 0;
|
|
26982
|
+
function areAllChecked(options) {
|
|
26983
|
+
return options.every((option) => isOptionGroup(option) ? areAllChecked(option.options) : option.checked);
|
|
27135
26984
|
}
|
|
27136
|
-
function
|
|
27137
|
-
|
|
27138
|
-
|
|
27139
|
-
|
|
27140
|
-
|
|
27141
|
-
|
|
27142
|
-
|
|
27143
|
-
|
|
27144
|
-
|
|
26985
|
+
function flatOptions(options) {
|
|
26986
|
+
return flat(options);
|
|
26987
|
+
function flat(options2, indentLevel = 0, opts = []) {
|
|
26988
|
+
for (const option of options2) {
|
|
26989
|
+
option.indentLevel = indentLevel;
|
|
26990
|
+
if (isOption2(option)) {
|
|
26991
|
+
opts.push(option);
|
|
26992
|
+
}
|
|
26993
|
+
if (isOptionGroup(option)) {
|
|
26994
|
+
flat(option.options, ++indentLevel, opts);
|
|
26995
|
+
}
|
|
26996
|
+
}
|
|
26997
|
+
return opts;
|
|
27145
26998
|
}
|
|
27146
26999
|
}
|
|
27147
|
-
function
|
|
27148
|
-
|
|
27149
|
-
|
|
27150
|
-
|
|
27151
|
-
|
|
27152
|
-
|
|
27153
|
-
|
|
27154
|
-
|
|
27155
|
-
|
|
27156
|
-
|
|
27157
|
-
|
|
27000
|
+
function isCheckboxOptionGroup(option) {
|
|
27001
|
+
return isOptionGroup(option);
|
|
27002
|
+
}
|
|
27003
|
+
var Checkbox;
|
|
27004
|
+
var init_checkbox = __esm(async () => {
|
|
27005
|
+
init_equal();
|
|
27006
|
+
init_colors();
|
|
27007
|
+
init__figures();
|
|
27008
|
+
await __promiseAll([
|
|
27009
|
+
init__generic_list(),
|
|
27010
|
+
init__generic_prompt()
|
|
27011
|
+
]);
|
|
27012
|
+
Checkbox = class Checkbox extends GenericList {
|
|
27013
|
+
settings;
|
|
27014
|
+
options;
|
|
27015
|
+
listIndex;
|
|
27016
|
+
listOffset;
|
|
27017
|
+
confirmSubmit = false;
|
|
27018
|
+
static prompt(options) {
|
|
27019
|
+
return new this(options).prompt();
|
|
27158
27020
|
}
|
|
27159
|
-
|
|
27160
|
-
|
|
27021
|
+
static inject(value) {
|
|
27022
|
+
GenericPrompt.inject(value);
|
|
27161
27023
|
}
|
|
27162
|
-
|
|
27163
|
-
|
|
27164
|
-
|
|
27024
|
+
constructor(options) {
|
|
27025
|
+
super();
|
|
27026
|
+
this.settings = this.getDefaultSettings(options);
|
|
27027
|
+
this.options = this.settings.options.slice();
|
|
27028
|
+
this.listIndex = this.getListIndex();
|
|
27029
|
+
this.listOffset = this.getPageOffset(this.listIndex);
|
|
27165
27030
|
}
|
|
27166
|
-
|
|
27167
|
-
|
|
27168
|
-
|
|
27169
|
-
|
|
27170
|
-
|
|
27171
|
-
|
|
27172
|
-
|
|
27173
|
-
|
|
27174
|
-
|
|
27175
|
-
|
|
27176
|
-
|
|
27177
|
-
|
|
27178
|
-
|
|
27179
|
-
|
|
27180
|
-
|
|
27181
|
-
|
|
27182
|
-
|
|
27183
|
-
|
|
27184
|
-
|
|
27185
|
-
|
|
27186
|
-
|
|
27187
|
-
|
|
27188
|
-
|
|
27031
|
+
getDefaultSettings(options) {
|
|
27032
|
+
const settings = super.getDefaultSettings(options);
|
|
27033
|
+
return {
|
|
27034
|
+
confirmSubmit: true,
|
|
27035
|
+
...settings,
|
|
27036
|
+
check: options.check ?? green(Figures.TICK),
|
|
27037
|
+
uncheck: options.uncheck ?? red(Figures.CROSS),
|
|
27038
|
+
partialCheck: options.partialCheck ?? green(Figures.RADIO_ON),
|
|
27039
|
+
minOptions: options.minOptions ?? 0,
|
|
27040
|
+
maxOptions: options.maxOptions ?? Infinity,
|
|
27041
|
+
options: this.mapOptions(options, options.options),
|
|
27042
|
+
keys: {
|
|
27043
|
+
check: [
|
|
27044
|
+
"space"
|
|
27045
|
+
],
|
|
27046
|
+
checkAll: [
|
|
27047
|
+
"a"
|
|
27048
|
+
],
|
|
27049
|
+
...settings.keys ?? {},
|
|
27050
|
+
open: options.keys?.open ?? [
|
|
27051
|
+
"right"
|
|
27052
|
+
],
|
|
27053
|
+
back: options.keys?.back ?? [
|
|
27054
|
+
"left",
|
|
27055
|
+
"escape"
|
|
27056
|
+
]
|
|
27057
|
+
}
|
|
27058
|
+
};
|
|
27189
27059
|
}
|
|
27190
|
-
|
|
27191
|
-
|
|
27192
|
-
|
|
27193
|
-
|
|
27194
|
-
|
|
27195
|
-
|
|
27196
|
-
|
|
27197
|
-
|
|
27060
|
+
mapOptions(promptOptions, options) {
|
|
27061
|
+
return options.map((option) => typeof option === "string" || typeof option === "number" ? this.mapOption(promptOptions, {
|
|
27062
|
+
value: option
|
|
27063
|
+
}) : isCheckboxOptionGroup(option) ? this.mapOptionGroup(promptOptions, option) : this.mapOption(promptOptions, option));
|
|
27064
|
+
}
|
|
27065
|
+
mapOption(options, option) {
|
|
27066
|
+
if (isOption2(option)) {
|
|
27067
|
+
return {
|
|
27068
|
+
...super.mapOption(options, option),
|
|
27069
|
+
checked: typeof option.checked === "undefined" && options.default && options.default.indexOf(option.value) !== -1 ? true : !!option.checked,
|
|
27070
|
+
icon: typeof option.icon === "undefined" ? true : option.icon
|
|
27071
|
+
};
|
|
27198
27072
|
} else {
|
|
27199
|
-
|
|
27073
|
+
return {
|
|
27074
|
+
...super.mapOption(options, option),
|
|
27075
|
+
checked: false,
|
|
27076
|
+
icon: false
|
|
27077
|
+
};
|
|
27200
27078
|
}
|
|
27201
27079
|
}
|
|
27202
|
-
|
|
27203
|
-
|
|
27204
|
-
|
|
27205
|
-
|
|
27206
|
-
|
|
27207
|
-
|
|
27208
|
-
|
|
27209
|
-
|
|
27210
|
-
|
|
27211
|
-
|
|
27212
|
-
|
|
27213
|
-
|
|
27080
|
+
mapOptionGroup(promptOptions, option) {
|
|
27081
|
+
const options = this.mapOptions(promptOptions, option.options);
|
|
27082
|
+
const optionGroup = super.mapOptionGroup(promptOptions, option, false);
|
|
27083
|
+
return {
|
|
27084
|
+
...optionGroup,
|
|
27085
|
+
get checked() {
|
|
27086
|
+
return areAllChecked(options);
|
|
27087
|
+
},
|
|
27088
|
+
get disabled() {
|
|
27089
|
+
return optionGroup.disabled || options.every((opt) => opt.disabled);
|
|
27090
|
+
},
|
|
27091
|
+
options,
|
|
27092
|
+
icon: typeof option.icon === "undefined" ? true : option.icon
|
|
27093
|
+
};
|
|
27094
|
+
}
|
|
27095
|
+
match() {
|
|
27096
|
+
super.match();
|
|
27097
|
+
if (this.isSearching()) {
|
|
27098
|
+
this.selectSearch();
|
|
27214
27099
|
}
|
|
27215
|
-
|
|
27216
|
-
|
|
27217
|
-
|
|
27218
|
-
|
|
27219
|
-
|
|
27220
|
-
|
|
27221
|
-
|
|
27100
|
+
}
|
|
27101
|
+
getListItemIcon(option) {
|
|
27102
|
+
return this.getCheckboxIcon(option) + super.getListItemIcon(option);
|
|
27103
|
+
}
|
|
27104
|
+
getCheckboxIcon(option) {
|
|
27105
|
+
if (!option.icon) {
|
|
27106
|
+
return "";
|
|
27222
27107
|
}
|
|
27223
|
-
|
|
27224
|
-
|
|
27225
|
-
|
|
27226
|
-
|
|
27108
|
+
const icon = option.checked ? this.settings.check + " " : isOptionGroup(option) && areSomeChecked(option.options) ? this.settings.partialCheck + " " : this.settings.uncheck + " ";
|
|
27109
|
+
return option.disabled ? dim(icon) : icon;
|
|
27110
|
+
}
|
|
27111
|
+
getValue() {
|
|
27112
|
+
return flatOptions(this.settings.options).filter((option) => option.checked).map((option) => option.value);
|
|
27113
|
+
}
|
|
27114
|
+
async handleEvent(event) {
|
|
27115
|
+
const hasConfirmed = this.confirmSubmit;
|
|
27116
|
+
this.confirmSubmit = false;
|
|
27117
|
+
switch (true) {
|
|
27118
|
+
case (this.isKey(this.settings.keys, "check", event) && !this.isSearchSelected()):
|
|
27119
|
+
this.checkValue();
|
|
27120
|
+
break;
|
|
27121
|
+
case this.isKey(this.settings.keys, "submit", event):
|
|
27122
|
+
await this.submit(hasConfirmed);
|
|
27123
|
+
break;
|
|
27124
|
+
case (event.ctrl && this.isKey(this.settings.keys, "checkAll", event)):
|
|
27125
|
+
this.checkAllOption();
|
|
27126
|
+
break;
|
|
27127
|
+
default:
|
|
27128
|
+
await super.handleEvent(event);
|
|
27129
|
+
}
|
|
27130
|
+
}
|
|
27131
|
+
hint() {
|
|
27132
|
+
if (this.confirmSubmit) {
|
|
27133
|
+
const info2 = this.isBackButton(this.selectedOption) ? ` To leave the current group press ${getFiguresByKeys(this.settings.keys.back ?? []).join(", ")}.` : isOptionGroup(this.selectedOption) ? ` To open the selected group press ${getFiguresByKeys(this.settings.keys.open ?? []).join(", ")}.` : ` To check or uncheck the selected option press ${getFiguresByKeys(this.settings.keys.check ?? []).join(", ")}.`;
|
|
27134
|
+
return this.settings.indent + brightBlue(`Press ${getFiguresByKeys(this.settings.keys.submit ?? [])} again to submit.${info2}`);
|
|
27135
|
+
}
|
|
27136
|
+
return super.hint();
|
|
27137
|
+
}
|
|
27138
|
+
async submit(hasConfirmed) {
|
|
27139
|
+
if (!hasConfirmed && this.settings.confirmSubmit && !this.isSearchSelected()) {
|
|
27140
|
+
this.confirmSubmit = true;
|
|
27141
|
+
return;
|
|
27142
|
+
}
|
|
27143
|
+
await super.submit();
|
|
27144
|
+
}
|
|
27145
|
+
checkValue() {
|
|
27146
|
+
const option = this.options.at(this.listIndex);
|
|
27147
|
+
if (!option) {
|
|
27148
|
+
this.setErrorMessage("No option available to select.");
|
|
27149
|
+
return;
|
|
27150
|
+
} else if (option.disabled) {
|
|
27151
|
+
this.setErrorMessage("This option is disabled and cannot be changed.");
|
|
27152
|
+
return;
|
|
27153
|
+
}
|
|
27154
|
+
this.checkOption(option, !option.checked);
|
|
27155
|
+
}
|
|
27156
|
+
checkOption(option, checked) {
|
|
27157
|
+
if (isOption2(option)) {
|
|
27158
|
+
option.checked = checked;
|
|
27159
|
+
} else {
|
|
27160
|
+
for (const childOption of option.options) {
|
|
27161
|
+
this.checkOption(childOption, checked);
|
|
27227
27162
|
}
|
|
27228
27163
|
}
|
|
27229
27164
|
}
|
|
27230
|
-
|
|
27231
|
-
|
|
27232
|
-
|
|
27233
|
-
|
|
27234
|
-
|
|
27165
|
+
checkAllOption() {
|
|
27166
|
+
const checked = this.options.some((option) => option.checked);
|
|
27167
|
+
for (const option of this.options) {
|
|
27168
|
+
this.checkOption(option, !checked);
|
|
27169
|
+
}
|
|
27235
27170
|
}
|
|
27236
|
-
|
|
27237
|
-
|
|
27238
|
-
|
|
27239
|
-
|
|
27240
|
-
|
|
27171
|
+
validate(value) {
|
|
27172
|
+
const options = flatOptions(this.settings.options);
|
|
27173
|
+
const isValidValue = Array.isArray(value) && value.every((val) => options.findIndex((option) => equal(option.value, val)) !== -1);
|
|
27174
|
+
if (!isValidValue) {
|
|
27175
|
+
return false;
|
|
27176
|
+
}
|
|
27177
|
+
if (value.length < this.settings.minOptions) {
|
|
27178
|
+
return `The minimum number of options is ${this.settings.minOptions} but got ${value.length}.`;
|
|
27179
|
+
}
|
|
27180
|
+
if (value.length > this.settings.maxOptions) {
|
|
27181
|
+
return `The maximum number of options is ${this.settings.maxOptions} but got ${value.length}.`;
|
|
27182
|
+
}
|
|
27183
|
+
return true;
|
|
27241
27184
|
}
|
|
27242
|
-
|
|
27243
|
-
|
|
27244
|
-
if (e instanceof Error && (e.message.includes("overrides") || e.message.includes("Obsolete configuration format"))) {
|
|
27245
|
-
throw e;
|
|
27185
|
+
transform(value) {
|
|
27186
|
+
return value;
|
|
27246
27187
|
}
|
|
27247
|
-
|
|
27248
|
-
|
|
27249
|
-
throw new Error(`❌ YAML syntax error in wmill.yaml:
|
|
27250
|
-
` + " " + yamlError + `
|
|
27251
|
-
` + " Please fix the YAML syntax in wmill.yaml or delete the file to start fresh.");
|
|
27252
|
-
} else {
|
|
27253
|
-
throw new Error(`❌ Failed to read wmill.yaml:
|
|
27254
|
-
` + " " + (e instanceof Error ? e.message : String(e)) + `
|
|
27255
|
-
` + " Please check file permissions or fix the syntax.");
|
|
27188
|
+
format(value) {
|
|
27189
|
+
return value.map((val) => this.settings.format?.(val) ?? this.getOptionByValue(val)?.name ?? String(val)).join(", ");
|
|
27256
27190
|
}
|
|
27191
|
+
};
|
|
27192
|
+
});
|
|
27193
|
+
|
|
27194
|
+
// src/commands/workspace/merge.ts
|
|
27195
|
+
function triggerService(kind) {
|
|
27196
|
+
switch (kind) {
|
|
27197
|
+
case "http_trigger":
|
|
27198
|
+
return {
|
|
27199
|
+
exists: existsHttpTrigger,
|
|
27200
|
+
get: getHttpTrigger,
|
|
27201
|
+
create: createHttpTrigger,
|
|
27202
|
+
update: updateHttpTrigger,
|
|
27203
|
+
delete: deleteHttpTrigger
|
|
27204
|
+
};
|
|
27205
|
+
case "websocket_trigger":
|
|
27206
|
+
return {
|
|
27207
|
+
exists: existsWebsocketTrigger,
|
|
27208
|
+
get: getWebsocketTrigger,
|
|
27209
|
+
create: createWebsocketTrigger,
|
|
27210
|
+
update: updateWebsocketTrigger,
|
|
27211
|
+
delete: deleteWebsocketTrigger
|
|
27212
|
+
};
|
|
27213
|
+
case "kafka_trigger":
|
|
27214
|
+
return {
|
|
27215
|
+
exists: existsKafkaTrigger,
|
|
27216
|
+
get: getKafkaTrigger,
|
|
27217
|
+
create: createKafkaTrigger,
|
|
27218
|
+
update: updateKafkaTrigger,
|
|
27219
|
+
delete: deleteKafkaTrigger
|
|
27220
|
+
};
|
|
27221
|
+
case "nats_trigger":
|
|
27222
|
+
return {
|
|
27223
|
+
exists: existsNatsTrigger,
|
|
27224
|
+
get: getNatsTrigger,
|
|
27225
|
+
create: createNatsTrigger,
|
|
27226
|
+
update: updateNatsTrigger,
|
|
27227
|
+
delete: deleteNatsTrigger
|
|
27228
|
+
};
|
|
27229
|
+
case "postgres_trigger":
|
|
27230
|
+
return {
|
|
27231
|
+
exists: existsPostgresTrigger,
|
|
27232
|
+
get: getPostgresTrigger,
|
|
27233
|
+
create: createPostgresTrigger,
|
|
27234
|
+
update: updatePostgresTrigger,
|
|
27235
|
+
delete: deletePostgresTrigger
|
|
27236
|
+
};
|
|
27237
|
+
case "mqtt_trigger":
|
|
27238
|
+
return {
|
|
27239
|
+
exists: existsMqttTrigger,
|
|
27240
|
+
get: getMqttTrigger,
|
|
27241
|
+
create: createMqttTrigger,
|
|
27242
|
+
update: updateMqttTrigger,
|
|
27243
|
+
delete: deleteMqttTrigger
|
|
27244
|
+
};
|
|
27245
|
+
case "sqs_trigger":
|
|
27246
|
+
return {
|
|
27247
|
+
exists: existsSqsTrigger,
|
|
27248
|
+
get: getSqsTrigger,
|
|
27249
|
+
create: createSqsTrigger,
|
|
27250
|
+
update: updateSqsTrigger,
|
|
27251
|
+
delete: deleteSqsTrigger
|
|
27252
|
+
};
|
|
27253
|
+
case "gcp_trigger":
|
|
27254
|
+
return {
|
|
27255
|
+
exists: existsGcpTrigger,
|
|
27256
|
+
get: getGcpTrigger,
|
|
27257
|
+
create: createGcpTrigger,
|
|
27258
|
+
update: updateGcpTrigger,
|
|
27259
|
+
delete: deleteGcpTrigger
|
|
27260
|
+
};
|
|
27261
|
+
case "azure_trigger":
|
|
27262
|
+
return {
|
|
27263
|
+
exists: existsAzureTrigger,
|
|
27264
|
+
get: getAzureTrigger,
|
|
27265
|
+
create: createAzureTrigger,
|
|
27266
|
+
update: updateAzureTrigger,
|
|
27267
|
+
delete: deleteAzureTrigger
|
|
27268
|
+
};
|
|
27269
|
+
case "email_trigger":
|
|
27270
|
+
return {
|
|
27271
|
+
exists: existsEmailTrigger,
|
|
27272
|
+
get: getEmailTrigger,
|
|
27273
|
+
create: createEmailTrigger,
|
|
27274
|
+
update: updateEmailTrigger,
|
|
27275
|
+
delete: deleteEmailTrigger
|
|
27276
|
+
};
|
|
27257
27277
|
}
|
|
27258
27278
|
}
|
|
27259
|
-
|
|
27260
|
-
const
|
|
27261
|
-
|
|
27279
|
+
function preparePayload(kind, trigger, onBehalfOf) {
|
|
27280
|
+
const preserve = onBehalfOf !== undefined;
|
|
27281
|
+
const base = {
|
|
27282
|
+
...trigger,
|
|
27283
|
+
permissioned_as: onBehalfOf,
|
|
27284
|
+
preserve_permissioned_as: preserve
|
|
27285
|
+
};
|
|
27286
|
+
if (kind === "gcp_trigger") {
|
|
27287
|
+
base.subscription_id = "";
|
|
27288
|
+
base.subscription_mode = "create_update";
|
|
27289
|
+
if (base.delivery_config) {
|
|
27290
|
+
base.delivery_config = { ...base.delivery_config, audience: "" };
|
|
27291
|
+
}
|
|
27292
|
+
if (base.delivery_type === "push") {
|
|
27293
|
+
base.base_endpoint = OpenAPI.BASE.replace(/\/api\/?$/, "");
|
|
27294
|
+
} else {
|
|
27295
|
+
base.base_endpoint = undefined;
|
|
27296
|
+
}
|
|
27297
|
+
}
|
|
27298
|
+
return base;
|
|
27262
27299
|
}
|
|
27263
|
-
async function
|
|
27264
|
-
|
|
27300
|
+
async function mergeWorkspaces(opts) {
|
|
27301
|
+
const workspace = await tryResolveBranchWorkspace(opts);
|
|
27302
|
+
if (!workspace) {
|
|
27303
|
+
throw new Error("Could not resolve workspace from branch name. Make sure you are in a git repo with 'workspaces' configured in wmill.yaml.");
|
|
27304
|
+
}
|
|
27305
|
+
const token = workspace.token;
|
|
27306
|
+
if (!token) {
|
|
27307
|
+
throw new Error("Not logged in. Please run 'wmill workspace add' first.");
|
|
27308
|
+
}
|
|
27309
|
+
const remote = workspace.remote;
|
|
27310
|
+
setClient(token, remote.endsWith("/") ? remote.substring(0, remote.length - 1) : remote);
|
|
27311
|
+
const forkWorkspaceId = workspace.workspaceId;
|
|
27312
|
+
const userWorkspaces = await listUserWorkspaces();
|
|
27313
|
+
const forkEntry = userWorkspaces.workspaces?.find((w) => w.id === forkWorkspaceId);
|
|
27314
|
+
if (!forkEntry?.parent_workspace_id) {
|
|
27315
|
+
throw new Error(`Workspace '${forkWorkspaceId}' is not a fork (no parent_workspace_id). ` + `You can only merge from a forked workspace.`);
|
|
27316
|
+
}
|
|
27317
|
+
const parentWorkspaceId = forkEntry.parent_workspace_id;
|
|
27318
|
+
info(`Fork: ${colors.bold(forkWorkspaceId)} → Parent: ${colors.bold(parentWorkspaceId)}`);
|
|
27319
|
+
info("Comparing workspaces...");
|
|
27320
|
+
const comparison = await compareWorkspaces({
|
|
27321
|
+
workspace: parentWorkspaceId,
|
|
27322
|
+
targetWorkspaceId: forkWorkspaceId
|
|
27323
|
+
});
|
|
27324
|
+
if (comparison.skipped_comparison) {
|
|
27325
|
+
info(colors.yellow("This fork was created before change tracking was available. " + "Use the UI or git-based merge instead."));
|
|
27326
|
+
return;
|
|
27327
|
+
}
|
|
27328
|
+
const summary = comparison.summary;
|
|
27329
|
+
if (summary.total_diffs === 0) {
|
|
27330
|
+
info(colors.green("Everything is up to date. No differences found."));
|
|
27265
27331
|
return;
|
|
27266
27332
|
}
|
|
27267
|
-
|
|
27268
|
-
|
|
27269
|
-
const
|
|
27270
|
-
|
|
27271
|
-
|
|
27272
|
-
if (
|
|
27273
|
-
|
|
27274
|
-
|
|
27275
|
-
|
|
27276
|
-
|
|
27277
|
-
|
|
27278
|
-
if (
|
|
27279
|
-
|
|
27280
|
-
|
|
27281
|
-
|
|
27333
|
+
info("");
|
|
27334
|
+
info(colors.bold("Comparison Summary:"));
|
|
27335
|
+
const summaryRows = [];
|
|
27336
|
+
if (summary.scripts_changed > 0)
|
|
27337
|
+
summaryRows.push(["Scripts", String(summary.scripts_changed)]);
|
|
27338
|
+
if (summary.flows_changed > 0)
|
|
27339
|
+
summaryRows.push(["Flows", String(summary.flows_changed)]);
|
|
27340
|
+
if (summary.apps_changed > 0)
|
|
27341
|
+
summaryRows.push(["Apps", String(summary.apps_changed)]);
|
|
27342
|
+
if (summary.resources_changed > 0)
|
|
27343
|
+
summaryRows.push(["Resources", String(summary.resources_changed)]);
|
|
27344
|
+
if (summary.variables_changed > 0)
|
|
27345
|
+
summaryRows.push(["Variables", String(summary.variables_changed)]);
|
|
27346
|
+
if (summary.resource_types_changed > 0)
|
|
27347
|
+
summaryRows.push(["Resource Types", String(summary.resource_types_changed)]);
|
|
27348
|
+
if (summary.folders_changed > 0)
|
|
27349
|
+
summaryRows.push(["Folders", String(summary.folders_changed)]);
|
|
27350
|
+
if (summary.schedules_changed > 0)
|
|
27351
|
+
summaryRows.push(["Schedules", String(summary.schedules_changed)]);
|
|
27352
|
+
if (summary.triggers_changed > 0)
|
|
27353
|
+
summaryRows.push(["Triggers", String(summary.triggers_changed)]);
|
|
27354
|
+
summaryRows.push(["Total", String(summary.total_diffs)]);
|
|
27355
|
+
if (summary.conflicts > 0)
|
|
27356
|
+
summaryRows.push([
|
|
27357
|
+
colors.red("Conflicts"),
|
|
27358
|
+
colors.red(String(summary.conflicts))
|
|
27359
|
+
]);
|
|
27360
|
+
new Table2().header(["Type", "Changed"]).padding(2).border(true).body(summaryRows).render();
|
|
27361
|
+
const diffs = comparison.diffs.filter((d) => d.has_changes !== false);
|
|
27362
|
+
if (diffs.length === 0) {
|
|
27363
|
+
info(colors.green("No effective changes to deploy."));
|
|
27282
27364
|
return;
|
|
27283
27365
|
}
|
|
27284
|
-
|
|
27285
|
-
|
|
27286
|
-
|
|
27287
|
-
const
|
|
27288
|
-
|
|
27289
|
-
|
|
27290
|
-
|
|
27366
|
+
info("");
|
|
27367
|
+
info(colors.bold("Changed items:"));
|
|
27368
|
+
new Table2().header(["#", "Kind", "Path", "Ahead", "Behind", "Conflict"]).padding(1).border(true).body(diffs.map((d, i) => {
|
|
27369
|
+
const isConflict = d.ahead > 0 && d.behind > 0;
|
|
27370
|
+
return [
|
|
27371
|
+
String(i + 1),
|
|
27372
|
+
d.kind,
|
|
27373
|
+
d.path,
|
|
27374
|
+
d.ahead > 0 ? colors.green(String(d.ahead)) : "0",
|
|
27375
|
+
d.behind > 0 ? colors.yellow(String(d.behind)) : "0",
|
|
27376
|
+
isConflict ? colors.red("YES") : ""
|
|
27377
|
+
];
|
|
27378
|
+
})).render();
|
|
27379
|
+
let direction;
|
|
27380
|
+
if (opts.direction === "to-parent" || opts.direction === "to-fork") {
|
|
27381
|
+
direction = opts.direction;
|
|
27382
|
+
} else if (opts.direction) {
|
|
27383
|
+
throw new Error(`Invalid direction '${opts.direction}'. Use 'to-parent' or 'to-fork'.`);
|
|
27384
|
+
} else if (opts.yes) {
|
|
27385
|
+
direction = "to-parent";
|
|
27386
|
+
} else {
|
|
27387
|
+
const { Select: Select2 } = await init_select().then(() => exports_select);
|
|
27388
|
+
direction = await Select2.prompt({
|
|
27389
|
+
message: "Deploy direction:",
|
|
27390
|
+
options: [
|
|
27391
|
+
{
|
|
27392
|
+
name: `Deploy to parent (${parentWorkspaceId}) ← fork changes`,
|
|
27393
|
+
value: "to-parent"
|
|
27394
|
+
},
|
|
27395
|
+
{
|
|
27396
|
+
name: `Update fork (${forkWorkspaceId}) ← parent changes`,
|
|
27397
|
+
value: "to-fork"
|
|
27398
|
+
}
|
|
27399
|
+
]
|
|
27400
|
+
});
|
|
27401
|
+
}
|
|
27402
|
+
info(`
|
|
27403
|
+
Direction: ${colors.bold(direction === "to-parent" ? `Fork → Parent (${parentWorkspaceId})` : `Parent → Fork (${forkWorkspaceId})`)}`);
|
|
27404
|
+
const selectableDiffs = diffs.filter((d) => {
|
|
27405
|
+
if (direction === "to-parent") {
|
|
27406
|
+
return d.ahead > 0;
|
|
27291
27407
|
} else {
|
|
27292
|
-
|
|
27408
|
+
return d.behind > 0;
|
|
27293
27409
|
}
|
|
27410
|
+
});
|
|
27411
|
+
if (selectableDiffs.length === 0) {
|
|
27412
|
+
info(colors.yellow(`No items to deploy in the '${direction}' direction.`));
|
|
27413
|
+
return;
|
|
27294
27414
|
}
|
|
27295
|
-
|
|
27296
|
-
|
|
27297
|
-
|
|
27298
|
-
|
|
27299
|
-
|
|
27415
|
+
let selectedDiffs = selectableDiffs;
|
|
27416
|
+
if (opts.all) {
|
|
27417
|
+
selectedDiffs = selectableDiffs;
|
|
27418
|
+
} else if (opts.skipConflicts) {
|
|
27419
|
+
selectedDiffs = selectableDiffs.filter((d) => !(d.ahead > 0 && d.behind > 0) && (!!opts.include || !isTriggerOrScheduleKind(d.kind)));
|
|
27420
|
+
} else if (opts.yes && !opts.include && !opts.exclude) {
|
|
27421
|
+
selectedDiffs = selectableDiffs.filter((d) => !isTriggerOrScheduleKind(d.kind) && (direction !== "to-fork" || !(d.ahead > 0 && d.behind > 0)));
|
|
27422
|
+
} else if (!opts.yes) {
|
|
27423
|
+
const { Checkbox: Checkbox2 } = await init_checkbox().then(() => exports_checkbox);
|
|
27424
|
+
const defaultForToFork = direction === "to-fork";
|
|
27425
|
+
const selectedValues = await Checkbox2.prompt({
|
|
27426
|
+
message: `Select items to deploy (${selectableDiffs.length} available):`,
|
|
27427
|
+
options: selectableDiffs.map((d) => {
|
|
27428
|
+
const isConflict = d.ahead > 0 && d.behind > 0;
|
|
27429
|
+
const isTriggerOrSchedule = isTriggerOrScheduleKind(d.kind);
|
|
27430
|
+
const label = `${d.kind}:${d.path}${isConflict ? colors.red(" [CONFLICT]") : ""}`;
|
|
27431
|
+
return {
|
|
27432
|
+
name: label,
|
|
27433
|
+
value: `${d.kind}:${d.path}`,
|
|
27434
|
+
checked: !isTriggerOrSchedule && (defaultForToFork ? !isConflict : true)
|
|
27435
|
+
};
|
|
27436
|
+
})
|
|
27437
|
+
});
|
|
27438
|
+
selectedDiffs = selectableDiffs.filter((d) => selectedValues.includes(`${d.kind}:${d.path}`));
|
|
27300
27439
|
}
|
|
27301
|
-
if (
|
|
27302
|
-
const
|
|
27303
|
-
|
|
27304
|
-
const entry = workspaces[n];
|
|
27305
|
-
const branch = getEffectiveGitBranch(n, entry);
|
|
27306
|
-
return branch !== n ? `${n} (gitBranch: ${branch})` : n;
|
|
27307
|
-
}).join(", ");
|
|
27308
|
-
if (!!process.stdin.isTTY) {
|
|
27309
|
-
info(`Current Git branch '${currentBranch}' does not match any workspace in the configuration.
|
|
27310
|
-
` + `Available workspaces: ${availableInfo}`);
|
|
27311
|
-
const shouldCreate = opts.yes || await Confirm.prompt({
|
|
27312
|
-
message: `Create empty workspace configuration for branch '${currentBranch}'?`,
|
|
27313
|
-
default: true
|
|
27314
|
-
});
|
|
27315
|
-
if (shouldCreate) {
|
|
27316
|
-
if (/[\/\\:*?"<>|.]/.test(currentBranch)) {
|
|
27317
|
-
const sanitizedBranchName = currentBranch.replace(/[\/\\:*?"<>|.]/g, "_");
|
|
27318
|
-
warn(`⚠️ WARNING: Branch name "${currentBranch}" contains filesystem-unsafe characters (/ \\ : * ? " < > | .).`);
|
|
27319
|
-
warn(` Branch-specific files will be saved with sanitized name: "${sanitizedBranchName}"`);
|
|
27320
|
-
warn(` Example: "file.variable.yaml" → "file.${sanitizedBranchName}.variable.yaml"`);
|
|
27321
|
-
}
|
|
27322
|
-
const currentConfig = await readConfigFile();
|
|
27323
|
-
if (!currentConfig.workspaces) {
|
|
27324
|
-
currentConfig.workspaces = {};
|
|
27325
|
-
}
|
|
27326
|
-
currentConfig.workspaces[currentBranch] = {};
|
|
27327
|
-
await writeFile("wmill.yaml", import_yaml3.stringify(currentConfig), "utf-8");
|
|
27328
|
-
info(`✅ Created empty workspace configuration for '${currentBranch}'`);
|
|
27329
|
-
} else {
|
|
27330
|
-
warn("⚠️ WARNING: Workspace creation cancelled. You can manually add a workspace to the 'workspaces' section in wmill.yaml or use 'wmill gitsync-settings pull' to pull configuration from an existing windmill workspace git-sync configuration.");
|
|
27331
|
-
return;
|
|
27332
|
-
}
|
|
27333
|
-
} else {
|
|
27334
|
-
if (/[\/\\:*?"<>|.]/.test(currentBranch)) {
|
|
27335
|
-
const sanitizedBranchName = currentBranch.replace(/[\/\\:*?"<>|.]/g, "_");
|
|
27336
|
-
warn(`⚠️ WARNING: Branch name "${currentBranch}" contains filesystem-unsafe characters (/ \\ : * ? " < > | .).`);
|
|
27337
|
-
warn(` Branch-specific files will use sanitized name: "${sanitizedBranchName}"`);
|
|
27338
|
-
}
|
|
27339
|
-
warn(`⚠️ WARNING: Current Git branch '${currentBranch}' does not match any workspace in the configuration.
|
|
27340
|
-
` + ` Consider adding a workspace entry for branch '${currentBranch}' in the 'workspaces' section of wmill.yaml.
|
|
27341
|
-
` + ` Available workspaces: ${availableInfo}`);
|
|
27342
|
-
return;
|
|
27343
|
-
}
|
|
27440
|
+
if (opts.include) {
|
|
27441
|
+
const includeSet = new Set(opts.include.split(",").map((s) => s.trim()));
|
|
27442
|
+
selectedDiffs = selectedDiffs.filter((d) => includeSet.has(`${d.kind}:${d.path}`));
|
|
27344
27443
|
}
|
|
27345
|
-
|
|
27346
|
-
|
|
27347
|
-
|
|
27348
|
-
|
|
27349
|
-
|
|
27350
|
-
|
|
27351
|
-
|
|
27352
|
-
|
|
27353
|
-
|
|
27354
|
-
|
|
27355
|
-
|
|
27356
|
-
|
|
27357
|
-
|
|
27358
|
-
}
|
|
27359
|
-
rawGitBranch = getCurrentGitBranch();
|
|
27360
|
-
originalBranchIfForked = getOriginalBranchForWorkspaceForks(rawGitBranch);
|
|
27361
|
-
const branch = originalBranchIfForked ?? rawGitBranch;
|
|
27362
|
-
if (originalBranchIfForked) {
|
|
27363
|
-
info(`Using overrides from original branch \`${originalBranchIfForked}\``);
|
|
27444
|
+
if (opts.exclude) {
|
|
27445
|
+
const excludeSet = new Set(opts.exclude.split(",").map((s) => s.trim()));
|
|
27446
|
+
selectedDiffs = selectedDiffs.filter((d) => !excludeSet.has(`${d.kind}:${d.path}`));
|
|
27447
|
+
}
|
|
27448
|
+
if (selectedDiffs.length === 0) {
|
|
27449
|
+
info(colors.yellow("No items selected for deployment."));
|
|
27450
|
+
return;
|
|
27451
|
+
}
|
|
27452
|
+
const conflicts = selectedDiffs.filter((d) => d.ahead > 0 && d.behind > 0);
|
|
27453
|
+
if (conflicts.length > 0) {
|
|
27454
|
+
info(colors.yellow(`
|
|
27455
|
+
⚠ ${conflicts.length} conflicting item(s) will be deployed (source will overwrite target):`));
|
|
27456
|
+
for (const c of conflicts) {
|
|
27457
|
+
info(colors.yellow(` - ${c.kind}:${c.path}`));
|
|
27364
27458
|
}
|
|
27365
|
-
if (
|
|
27366
|
-
const
|
|
27367
|
-
|
|
27368
|
-
|
|
27459
|
+
if (!opts.yes) {
|
|
27460
|
+
const { Confirm: Confirm2 } = await init_confirm().then(() => exports_confirm);
|
|
27461
|
+
const proceed = await Confirm2.prompt("Proceed with deploying conflicting items?");
|
|
27462
|
+
if (!proceed) {
|
|
27463
|
+
info("Aborted.");
|
|
27464
|
+
return;
|
|
27369
27465
|
}
|
|
27370
27466
|
}
|
|
27371
|
-
} else {
|
|
27372
|
-
debug("Not in a Git repository and no workspace override provided, using top-level settings");
|
|
27373
27467
|
}
|
|
27374
|
-
|
|
27375
|
-
|
|
27376
|
-
|
|
27377
|
-
|
|
27378
|
-
|
|
27379
|
-
|
|
27380
|
-
|
|
27381
|
-
|
|
27382
|
-
|
|
27383
|
-
|
|
27384
|
-
|
|
27385
|
-
|
|
27386
|
-
|
|
27387
|
-
|
|
27388
|
-
|
|
27389
|
-
|
|
27468
|
+
info(`
|
|
27469
|
+
Deploying ${colors.bold(String(selectedDiffs.length))} item(s)...`);
|
|
27470
|
+
const sorted = [...selectedDiffs].sort((a, b) => {
|
|
27471
|
+
const aFolder = a.kind === "folder" ? 0 : 1;
|
|
27472
|
+
const bFolder = b.kind === "folder" ? 0 : 1;
|
|
27473
|
+
return aFolder - bFolder;
|
|
27474
|
+
});
|
|
27475
|
+
const workspaceFrom = direction === "to-parent" ? forkWorkspaceId : parentWorkspaceId;
|
|
27476
|
+
const workspaceTo = direction === "to-parent" ? parentWorkspaceId : forkWorkspaceId;
|
|
27477
|
+
let successCount = 0;
|
|
27478
|
+
let failCount = 0;
|
|
27479
|
+
for (const diff2 of sorted) {
|
|
27480
|
+
const label = `${diff2.kind}:${diff2.path}`;
|
|
27481
|
+
const itemDeletedInSource = direction === "to-parent" ? diff2.exists_in_fork === false : diff2.exists_in_source === false;
|
|
27482
|
+
let result;
|
|
27483
|
+
if (itemDeletedInSource) {
|
|
27484
|
+
info(colors.yellow(` ⌫ ${label} (removing from target)`));
|
|
27485
|
+
result = await deleteItemInWorkspace(provider, diff2.kind, diff2.path, workspaceTo);
|
|
27486
|
+
} else {
|
|
27487
|
+
let onBehalfOf;
|
|
27488
|
+
if (opts.preserveOnBehalfOf) {
|
|
27489
|
+
onBehalfOf = await getOnBehalfOf(provider, diff2.kind, diff2.path, workspaceFrom);
|
|
27390
27490
|
}
|
|
27491
|
+
result = await deployItem(provider, diff2.kind, diff2.path, workspaceFrom, workspaceTo, onBehalfOf);
|
|
27391
27492
|
}
|
|
27392
|
-
|
|
27393
|
-
|
|
27394
|
-
|
|
27395
|
-
|
|
27396
|
-
info(`
|
|
27493
|
+
if (result.success) {
|
|
27494
|
+
info(colors.green(` ✓ ${label}`));
|
|
27495
|
+
successCount++;
|
|
27496
|
+
} else {
|
|
27497
|
+
info(colors.red(` ✗ ${label}: ${result.error}`));
|
|
27498
|
+
failCount++;
|
|
27397
27499
|
}
|
|
27398
|
-
} else if (resolvedWsName) {
|
|
27399
|
-
debug(`No overrides found for workspace '${resolvedWsName}', using top-level settings`);
|
|
27400
27500
|
}
|
|
27401
|
-
|
|
27402
|
-
|
|
27403
|
-
|
|
27404
|
-
|
|
27405
|
-
|
|
27406
|
-
|
|
27407
|
-
|
|
27408
|
-
|
|
27409
|
-
|
|
27410
|
-
|
|
27411
|
-
|
|
27412
|
-
|
|
27501
|
+
if (successCount > 0) {
|
|
27502
|
+
try {
|
|
27503
|
+
await resetDiffTally({
|
|
27504
|
+
workspace: parentWorkspaceId,
|
|
27505
|
+
forkWorkspaceId
|
|
27506
|
+
});
|
|
27507
|
+
} catch {}
|
|
27508
|
+
}
|
|
27509
|
+
info("");
|
|
27510
|
+
if (failCount === 0) {
|
|
27511
|
+
info(colors.green(`✅ Successfully deployed ${successCount} item(s) from ${workspaceFrom} to ${workspaceTo}.`));
|
|
27512
|
+
} else {
|
|
27513
|
+
info(colors.yellow(`Deployed ${successCount} item(s), ${colors.red(String(failCount) + " failed")} from ${workspaceFrom} to ${workspaceTo}.`));
|
|
27413
27514
|
}
|
|
27414
|
-
return;
|
|
27415
|
-
}
|
|
27416
|
-
function getEffectiveWorkspaceId(workspaceName, config) {
|
|
27417
|
-
return config.workspaceId ?? workspaceName;
|
|
27418
|
-
}
|
|
27419
|
-
function getEffectiveGitBranch(workspaceName, config) {
|
|
27420
|
-
return config.gitBranch ?? workspaceName;
|
|
27421
|
-
}
|
|
27422
|
-
function getWorkspaceNames(workspaces) {
|
|
27423
|
-
if (!workspaces)
|
|
27424
|
-
return [];
|
|
27425
|
-
return Object.keys(workspaces).filter((k) => !RESERVED_WORKSPACE_KEYS.has(k));
|
|
27426
27515
|
}
|
|
27427
|
-
|
|
27428
|
-
|
|
27429
|
-
|
|
27430
|
-
|
|
27431
|
-
|
|
27432
|
-
|
|
27516
|
+
var provider;
|
|
27517
|
+
var init_merge = __esm(async () => {
|
|
27518
|
+
init_colors2();
|
|
27519
|
+
init_mod6();
|
|
27520
|
+
init_log();
|
|
27521
|
+
init_client();
|
|
27522
|
+
init_services_gen();
|
|
27523
|
+
init_OpenAPI();
|
|
27524
|
+
init_deploy();
|
|
27525
|
+
await init_context();
|
|
27526
|
+
provider = {
|
|
27527
|
+
existsFlowByPath,
|
|
27528
|
+
existsScriptByPath,
|
|
27529
|
+
existsApp,
|
|
27530
|
+
existsVariable,
|
|
27531
|
+
existsResource,
|
|
27532
|
+
existsResourceType,
|
|
27533
|
+
existsFolder,
|
|
27534
|
+
getFlowByPath,
|
|
27535
|
+
createFlow,
|
|
27536
|
+
updateFlow,
|
|
27537
|
+
archiveFlowByPath,
|
|
27538
|
+
getScriptByPath,
|
|
27539
|
+
createScript,
|
|
27540
|
+
archiveScriptByPath,
|
|
27541
|
+
getAppByPath,
|
|
27542
|
+
createApp,
|
|
27543
|
+
updateApp,
|
|
27544
|
+
createAppRaw,
|
|
27545
|
+
updateAppRaw,
|
|
27546
|
+
getPublicSecretOfLatestVersionOfApp,
|
|
27547
|
+
getRawAppData,
|
|
27548
|
+
deleteApp,
|
|
27549
|
+
getVariable,
|
|
27550
|
+
createVariable,
|
|
27551
|
+
updateVariable,
|
|
27552
|
+
deleteVariable,
|
|
27553
|
+
getResource,
|
|
27554
|
+
createResource,
|
|
27555
|
+
updateResource,
|
|
27556
|
+
deleteResource,
|
|
27557
|
+
getResourceType,
|
|
27558
|
+
createResourceType,
|
|
27559
|
+
updateResourceType,
|
|
27560
|
+
deleteResourceType,
|
|
27561
|
+
getFolder,
|
|
27562
|
+
createFolder,
|
|
27563
|
+
updateFolder,
|
|
27564
|
+
deleteFolder,
|
|
27565
|
+
existsTriggerByKind: (kind, p) => triggerService(kind).exists(p),
|
|
27566
|
+
getTriggerForDeploy: async (kind, p) => {
|
|
27567
|
+
const trigger = await triggerService(kind).get({
|
|
27568
|
+
workspace: p.workspace,
|
|
27569
|
+
path: p.path
|
|
27570
|
+
});
|
|
27571
|
+
return preparePayload(kind, trigger, p.onBehalfOf);
|
|
27572
|
+
},
|
|
27573
|
+
createTriggerByKind: (kind, p) => triggerService(kind).create(p),
|
|
27574
|
+
updateTriggerByKind: (kind, p) => triggerService(kind).update(p),
|
|
27575
|
+
deleteTriggerByKind: (kind, p) => triggerService(kind).delete(p),
|
|
27576
|
+
getTriggerValue: (kind, p) => triggerService(kind).get(p),
|
|
27577
|
+
getTriggerPermissionedAs: async (kind, p) => {
|
|
27578
|
+
const trigger = await triggerService(kind).get(p);
|
|
27579
|
+
return trigger?.permissioned_as;
|
|
27580
|
+
},
|
|
27581
|
+
existsSchedule,
|
|
27582
|
+
getSchedule,
|
|
27583
|
+
createSchedule,
|
|
27584
|
+
updateSchedule,
|
|
27585
|
+
deleteSchedule
|
|
27586
|
+
};
|
|
27587
|
+
});
|
|
27588
|
+
|
|
27589
|
+
// src/commands/workspace/slack.ts
|
|
27590
|
+
async function connectSlack2(opts) {
|
|
27591
|
+
await requireLogin(opts);
|
|
27592
|
+
const workspace = await resolveWorkspace(opts);
|
|
27593
|
+
await connectSlack({
|
|
27594
|
+
workspace: workspace.workspaceId,
|
|
27595
|
+
requestBody: {
|
|
27596
|
+
bot_token: opts.botToken,
|
|
27597
|
+
team_id: opts.teamId,
|
|
27598
|
+
team_name: opts.teamName
|
|
27433
27599
|
}
|
|
27434
|
-
|
|
27435
|
-
}
|
|
27436
|
-
return workspaces;
|
|
27600
|
+
});
|
|
27601
|
+
info(colors.bold.underline.green(`Slack connected to workspace ${workspace.workspaceId} (team ${opts.teamName} / ${opts.teamId})`));
|
|
27437
27602
|
}
|
|
27438
|
-
|
|
27439
|
-
|
|
27603
|
+
async function disconnectSlack2(opts) {
|
|
27604
|
+
await requireLogin(opts);
|
|
27605
|
+
const workspace = await resolveWorkspace(opts);
|
|
27606
|
+
await disconnectSlack({ workspace: workspace.workspaceId });
|
|
27607
|
+
info(colors.bold.underline.green(`Slack disconnected from workspace ${workspace.workspaceId} (slack_team_id / slack_name cleared). ` + `To also remove the bot token variable/resource/folder/group, delete the corresponding files from the local sync folder and run 'wmill sync push'. ` + `To remove the workspace-level OAuth override (if any), set slack_oauth_client_id/_secret to '' in settings.yaml and push.`));
|
|
27608
|
+
}
|
|
27609
|
+
var init_slack = __esm(async () => {
|
|
27610
|
+
init_colors2();
|
|
27440
27611
|
init_log();
|
|
27441
|
-
|
|
27612
|
+
init_services_gen();
|
|
27442
27613
|
await __promiseAll([
|
|
27443
|
-
|
|
27444
|
-
|
|
27445
|
-
init_resource_folders()
|
|
27614
|
+
init_auth(),
|
|
27615
|
+
init_context()
|
|
27446
27616
|
]);
|
|
27447
|
-
import_yaml3 = __toESM(require_dist(), 1);
|
|
27448
|
-
GLOBAL_CONFIG_OPT = { noCdToRoot: false };
|
|
27449
|
-
DEFAULT_SYNC_OPTIONS = {
|
|
27450
|
-
defaultTs: "bun",
|
|
27451
|
-
includes: ["f/**"],
|
|
27452
|
-
excludes: [],
|
|
27453
|
-
codebases: [],
|
|
27454
|
-
skipVariables: false,
|
|
27455
|
-
skipResources: false,
|
|
27456
|
-
skipResourceTypes: false,
|
|
27457
|
-
skipSecrets: true,
|
|
27458
|
-
skipScripts: false,
|
|
27459
|
-
skipFlows: false,
|
|
27460
|
-
skipApps: false,
|
|
27461
|
-
skipFolders: false,
|
|
27462
|
-
includeSchedules: false,
|
|
27463
|
-
includeTriggers: false,
|
|
27464
|
-
includeUsers: false,
|
|
27465
|
-
includeGroups: false,
|
|
27466
|
-
includeSettings: false,
|
|
27467
|
-
includeKey: false,
|
|
27468
|
-
skipWorkspaceDependencies: false,
|
|
27469
|
-
nonDottedPaths: false,
|
|
27470
|
-
syncBehavior: "v1"
|
|
27471
|
-
};
|
|
27472
|
-
RESERVED_WORKSPACE_KEYS = new Set(["commonSpecificItems"]);
|
|
27473
27617
|
});
|
|
27474
27618
|
|
|
27475
27619
|
// src/utils/resource_types.ts
|
|
@@ -27517,7 +27661,7 @@ __export(exports_resource_type, {
|
|
|
27517
27661
|
import { writeFileSync } from "node:fs";
|
|
27518
27662
|
import { stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
|
|
27519
27663
|
import path3 from "node:path";
|
|
27520
|
-
import
|
|
27664
|
+
import process11 from "node:process";
|
|
27521
27665
|
async function pushResourceType(workspace, remotePath, resource, localResource) {
|
|
27522
27666
|
remotePath = removeType(remotePath, "resource-type");
|
|
27523
27667
|
try {
|
|
@@ -27637,7 +27781,7 @@ async function generateRTNamespace(opts) {
|
|
|
27637
27781
|
`);
|
|
27638
27782
|
namespaceContent += `
|
|
27639
27783
|
}`;
|
|
27640
|
-
writeFileSync(path3.join(
|
|
27784
|
+
writeFileSync(path3.join(process11.cwd(), "rt.d.ts"), namespaceContent);
|
|
27641
27785
|
info(colors.green("Created rt.d.ts with resource types namespace (RT) for TypeScript."));
|
|
27642
27786
|
}
|
|
27643
27787
|
var import_yaml4, command, resource_type_default;
|
|
@@ -27673,7 +27817,7 @@ __export(exports_workspace, {
|
|
|
27673
27817
|
add: () => add
|
|
27674
27818
|
});
|
|
27675
27819
|
import { writeFile as writeFile3, open as fsOpen } from "node:fs/promises";
|
|
27676
|
-
import
|
|
27820
|
+
import process12 from "node:process";
|
|
27677
27821
|
async function allWorkspaces(configDirOverride) {
|
|
27678
27822
|
try {
|
|
27679
27823
|
const file = await getWorkspaceConfigFilePath(configDirOverride);
|
|
@@ -27785,7 +27929,7 @@ async function add(opts, workspaceName, workspaceId, remote) {
|
|
|
27785
27929
|
}
|
|
27786
27930
|
remote = new URL(remote).toString();
|
|
27787
27931
|
let token = await tryGetLoginInfo(opts);
|
|
27788
|
-
if (!token && !(
|
|
27932
|
+
if (!token && !(process12.stdin.isTTY ?? false)) {
|
|
27789
27933
|
info("Not a TTY, can't login interactively. Pass the token in --token");
|
|
27790
27934
|
return;
|
|
27791
27935
|
}
|
|
@@ -27827,7 +27971,7 @@ async function add(opts, workspaceName, workspaceId, remote) {
|
|
|
27827
27971
|
info(`- ${workspace.id} (name: ${workspace.name})`);
|
|
27828
27972
|
}
|
|
27829
27973
|
}
|
|
27830
|
-
|
|
27974
|
+
process12.exit(1);
|
|
27831
27975
|
}
|
|
27832
27976
|
const added = await addWorkspace({
|
|
27833
27977
|
name: workspaceName,
|
|
@@ -27844,7 +27988,7 @@ async function add(opts, workspaceName, workspaceId, remote) {
|
|
|
27844
27988
|
async function addWorkspace(workspace, opts) {
|
|
27845
27989
|
workspace.remote = new URL(workspace.remote).toString();
|
|
27846
27990
|
const existingWorkspaces = await allWorkspaces(opts.configDir);
|
|
27847
|
-
const isInteractive = (
|
|
27991
|
+
const isInteractive = (process12.stdin.isTTY ?? false) && (process12.stdout.isTTY ?? false) && !opts.force;
|
|
27848
27992
|
const nameConflict = existingWorkspaces.find((w) => w.name === workspace.name);
|
|
27849
27993
|
if (nameConflict) {
|
|
27850
27994
|
if (nameConflict.remote === workspace.remote && nameConflict.workspaceId === workspace.workspaceId) {
|
|
@@ -28020,7 +28164,7 @@ async function bind(opts, doBind) {
|
|
|
28020
28164
|
if (!config.workspaces) {
|
|
28021
28165
|
config.workspaces = {};
|
|
28022
28166
|
}
|
|
28023
|
-
const isInteractive = !!
|
|
28167
|
+
const isInteractive = !!process12.stdin.isTTY;
|
|
28024
28168
|
const inGitRepo = isGitRepository2();
|
|
28025
28169
|
const currentBranch = inGitRepo ? getCurrentGitBranch2() : null;
|
|
28026
28170
|
if (doBind) {
|
|
@@ -28175,7 +28319,7 @@ var init_workspace = __esm(async () => {
|
|
|
28175
28319
|
]);
|
|
28176
28320
|
command2 = new Command().alias("profile").description("workspace related commands").action(list3).command("switch").complete("workspace", async () => (await allWorkspaces()).map((x) => x.name)).description("Switch to another workspace").arguments("<workspace_name:string:workspace>").action(switchC).command("add").description("Add a workspace").arguments("[workspace_name:string] [workspace_id:string] [remote:string]").option("-c --create", "Create the workspace if it does not exist").option("--create-workspace-name <workspace_name:string>", "Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.").option("--create-username <username:string>", "Specify your own username in the newly created workspace. Ignored if --create is not specified, the workspace already exists or automatic username creation is enabled on the instance.", {
|
|
28177
28321
|
default: "admin"
|
|
28178
|
-
}).action(add).command("remove").description("Remove a workspace").arguments("<workspace_name:string>").action(remove).command("whoami").description("Show the currently active user").action(whoami2).command("list").description("List local workspace profiles").action(list3).command("list-remote").description("List workspaces on the remote server that you have access to").option("--as-superadmin", "List ALL workspaces on the instance (requires the token to belong to a superadmin/devops user)").action(listRemote).command("list-forks").description("List forked workspaces on the remote server").action(listForks).command("bind").description("Create or update a workspace entry in wmill.yaml from the active profile").option("--workspace <name:string>", "Workspace name (default: current branch or workspaceId)").option("--branch <branch:string>", "Git branch to associate (default: workspace name)").action((opts) => bind(opts, true)).command("unbind").description("Remove baseUrl and workspaceId from a workspace entry").option("--workspace <name:string>", "Workspace to unbind").action((opts) => bind(opts, false)).command("fork").description("Create a forked workspace").arguments("[workspace_name:string] [workspace_id:string]").option("--create-workspace-name <workspace_name:string>", "Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.").option("--color <color:string>", "Workspace color (hex code, e.g. #ff0000)").option("--datatable-behavior <behavior:string>", "How to handle datatables: skip, schema_only, or schema_and_data (default: interactive prompt)").option("-y --yes", "Skip interactive prompts (defaults datatable behavior to 'skip')").action(createWorkspaceFork2).command("delete-fork").description("Delete a forked workspace and git branch").arguments("<fork_name:string>").option("-y --yes", "Skip confirmation prompt").action(deleteWorkspaceFork).command("merge").description("Compare and deploy changes between a fork and its parent workspace").option("--direction <direction:string>", "Deploy direction: to-parent or to-fork").option("--all", "Deploy all changed items including conflicts").option("--skip-conflicts", "Skip items modified in both workspaces").option("--include <items:string>", "Comma-separated kind:path items to include (e.g. script:f/test/main,flow:f/my/flow)").option("--exclude <items:string>", "Comma-separated kind:path items to exclude").option("--preserve-on-behalf-of", "Preserve original on_behalf_of/permissioned_as values").option("-y --yes", "Non-interactive mode (deploy without prompts)").action(mergeWorkspaces).command("connect-slack").description("Non-interactively connect Slack to the active workspace using a pre-minted bot token (xoxb-...). Produces the same artifacts as the UI OAuth flow: workspace_settings fields, g/slack group, f/slack_bot folder, and the encrypted bot token variable + resource at f/slack_bot/bot_token.").option("--bot-token <bot_token:string>", "Slack bot token (xoxb-...)", { required: true }).option("--team-id <team_id:string>", "Slack team id", { required: true }).option("--team-name <team_name:string>", "Slack team name", { required: true }).action(connectSlack2).command("disconnect-slack").description("Clear slack_team_id / slack_name on the active workspace (marks the workspace as disconnected). Does NOT remove the bot token variable/resource/folder/group — delete those from the local sync folder and run 'wmill sync push' to tear them down. Does NOT remove the workspace-level OAuth override — set slack_oauth_client_id/_secret to '' in settings.yaml and push.").action(disconnectSlack2);
|
|
28322
|
+
}).action(add).command("remove").description("Remove a workspace").arguments("<workspace_name:string>").action(remove).command("whoami").description("Show the currently active user").action(whoami2).command("list").description("List local workspace profiles").action(list3).command("list-remote").description("List workspaces on the remote server that you have access to").option("--as-superadmin", "List ALL workspaces on the instance (requires the token to belong to a superadmin/devops user)").action(listRemote).command("list-forks").description("List forked workspaces on the remote server").action(listForks).command("bind").description("Create or update a workspace entry in wmill.yaml from the active profile").option("--workspace <name:string>", "Workspace name (default: current branch or workspaceId)").option("--branch <branch:string>", "Git branch to associate (default: workspace name)").action((opts) => bind(opts, true)).command("unbind").description("Remove baseUrl and workspaceId from a workspace entry").option("--workspace <name:string>", "Workspace to unbind").action((opts) => bind(opts, false)).command("fork").description("Create a forked workspace").arguments("[workspace_name:string] [workspace_id:string]").option("--create-workspace-name <workspace_name:string>", "Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.").option("--color <color:string>", "Workspace color (hex code, e.g. #ff0000)").option("--datatable-behavior <behavior:string>", "How to handle datatables: skip, schema_only, or schema_and_data (default: interactive prompt)").option("--from-branch <branch:string>", "Non-interactive override for the 'turn my current working branch into the fork' workflow: base the fork on <branch> (its bound workspace is the parent) and rename the current branch onto wm-fork/<branch>/<id>. Usually unneeded — from a working branch `wmill workspace fork` offers this interactively; from a base branch it creates a fresh fork branch.").option("-y --yes", "Skip interactive prompts (defaults datatable behavior to 'skip'). On a non-base branch, requires --from-branch since the base branch can't be prompted for.").action(createWorkspaceFork2).command("delete-fork").description("Delete a forked workspace and git branch").arguments("<fork_name:string>").option("-y --yes", "Skip confirmation prompt").action(deleteWorkspaceFork).command("merge").description("Compare and deploy changes between a fork and its parent workspace").option("--direction <direction:string>", "Deploy direction: to-parent or to-fork").option("--all", "Deploy all changed items including conflicts").option("--skip-conflicts", "Skip items modified in both workspaces").option("--include <items:string>", "Comma-separated kind:path items to include (e.g. script:f/test/main,flow:f/my/flow)").option("--exclude <items:string>", "Comma-separated kind:path items to exclude").option("--preserve-on-behalf-of", "Preserve original on_behalf_of/permissioned_as values").option("-y --yes", "Non-interactive mode (deploy without prompts)").action(mergeWorkspaces).command("connect-slack").description("Non-interactively connect Slack to the active workspace using a pre-minted bot token (xoxb-...). Produces the same artifacts as the UI OAuth flow: workspace_settings fields, g/slack group, f/slack_bot folder, and the encrypted bot token variable + resource at f/slack_bot/bot_token.").option("--bot-token <bot_token:string>", "Slack bot token (xoxb-...)", { required: true }).option("--team-id <team_id:string>", "Slack team id", { required: true }).option("--team-name <team_name:string>", "Slack team name", { required: true }).action(connectSlack2).command("disconnect-slack").description("Clear slack_team_id / slack_name on the active workspace (marks the workspace as disconnected). Does NOT remove the bot token variable/resource/folder/group — delete those from the local sync folder and run 'wmill sync push' to tear them down. Does NOT remove the workspace-level OAuth override — set slack_oauth_client_id/_secret to '' in settings.yaml and push.").action(disconnectSlack2);
|
|
28179
28323
|
workspace_default = command2;
|
|
28180
28324
|
});
|
|
28181
28325
|
|
|
@@ -33798,7 +33942,7 @@ var init_wrapper = __esm(() => {
|
|
|
33798
33942
|
// src/commands/app/bundle.ts
|
|
33799
33943
|
import * as fs7 from "node:fs";
|
|
33800
33944
|
import * as path4 from "node:path";
|
|
33801
|
-
import
|
|
33945
|
+
import process13 from "node:process";
|
|
33802
33946
|
import { spawn } from "node:child_process";
|
|
33803
33947
|
function detectFrameworks(appDir) {
|
|
33804
33948
|
const packageJsonPath = path4.join(appDir, "package.json");
|
|
@@ -33826,7 +33970,7 @@ function createSveltePlugin(appDir) {
|
|
|
33826
33970
|
build.onLoad({ filter: /\.svelte$/ }, async (args) => {
|
|
33827
33971
|
const svelte = await import("svelte/compiler");
|
|
33828
33972
|
const source = await readTextFile(args.path);
|
|
33829
|
-
const filename = path4.relative(
|
|
33973
|
+
const filename = path4.relative(process13.cwd(), args.path);
|
|
33830
33974
|
const convertMessage = ({ message, start, end }) => {
|
|
33831
33975
|
let location;
|
|
33832
33976
|
if (start && end) {
|
|
@@ -33867,7 +34011,7 @@ async function createFrameworkPlugins(appDir) {
|
|
|
33867
34011
|
return plugins;
|
|
33868
34012
|
}
|
|
33869
34013
|
async function ensureNodeModules(appDir) {
|
|
33870
|
-
const targetDir = appDir ??
|
|
34014
|
+
const targetDir = appDir ?? process13.cwd();
|
|
33871
34015
|
const nodeModulesPath = path4.join(targetDir, "node_modules");
|
|
33872
34016
|
if (!fs7.existsSync(nodeModulesPath)) {
|
|
33873
34017
|
info(colors.yellow("\uD83D\uDCE6 node_modules not found, running npm install..."));
|
|
@@ -33888,7 +34032,7 @@ async function ensureNodeModules(appDir) {
|
|
|
33888
34032
|
}
|
|
33889
34033
|
async function createBundle(options = {}) {
|
|
33890
34034
|
const esbuild = await import("esbuild");
|
|
33891
|
-
const appDir = options.entryPoint ? path4.dirname(options.entryPoint) :
|
|
34035
|
+
const appDir = options.entryPoint ? path4.dirname(options.entryPoint) : process13.cwd();
|
|
33892
34036
|
const frameworks = detectFrameworks(appDir);
|
|
33893
34037
|
const defaultEntry = frameworks.svelte || frameworks.vue ? "index.ts" : "index.tsx";
|
|
33894
34038
|
const entryPoint = options.entryPoint ?? defaultEntry;
|
|
@@ -33901,7 +34045,7 @@ async function createBundle(options = {}) {
|
|
|
33901
34045
|
}
|
|
33902
34046
|
await ensureNodeModules(appDir);
|
|
33903
34047
|
const frameworkPlugins = await createFrameworkPlugins(appDir);
|
|
33904
|
-
const distDir = path4.join(
|
|
34048
|
+
const distDir = path4.join(process13.cwd(), outDir);
|
|
33905
34049
|
if (!fs7.existsSync(distDir)) {
|
|
33906
34050
|
fs7.mkdirSync(distDir, { recursive: true });
|
|
33907
34051
|
}
|
|
@@ -33977,8 +34121,8 @@ async function createBundle(options = {}) {
|
|
|
33977
34121
|
throw new Error("Build failed with errors");
|
|
33978
34122
|
}
|
|
33979
34123
|
info(colors.green("✅ Bundle created successfully"));
|
|
33980
|
-
const jsPath = path4.join(
|
|
33981
|
-
const cssPath = path4.join(
|
|
34124
|
+
const jsPath = path4.join(process13.cwd(), outfile);
|
|
34125
|
+
const cssPath = path4.join(process13.cwd(), outDir, "bundle.css");
|
|
33982
34126
|
if (!fs7.existsSync(jsPath)) {
|
|
33983
34127
|
throw new Error(`Expected JS bundle at ${jsPath} but file not found`);
|
|
33984
34128
|
}
|
|
@@ -64780,7 +64924,7 @@ var init_script = __esm(async () => {
|
|
|
64780
64924
|
|
|
64781
64925
|
// src/commands/lint/lint.ts
|
|
64782
64926
|
import { stat as stat5, readdir as readdir2 } from "node:fs/promises";
|
|
64783
|
-
import
|
|
64927
|
+
import process14 from "node:process";
|
|
64784
64928
|
import * as path8 from "node:path";
|
|
64785
64929
|
import { sep as SEP7 } from "node:path";
|
|
64786
64930
|
function normalizePath(p) {
|
|
@@ -65014,8 +65158,8 @@ async function checkRawAppRunnables(backendDir, rawAppYamlPath, defaultTs) {
|
|
|
65014
65158
|
return issues;
|
|
65015
65159
|
}
|
|
65016
65160
|
async function checkMissingLocks(opts, directory) {
|
|
65017
|
-
const initialCwd =
|
|
65018
|
-
const targetDirectory = directory ? path8.resolve(initialCwd, directory) :
|
|
65161
|
+
const initialCwd = process14.cwd();
|
|
65162
|
+
const targetDirectory = directory ? path8.resolve(initialCwd, directory) : process14.cwd();
|
|
65019
65163
|
const { ...syncOpts } = opts;
|
|
65020
65164
|
const mergedOpts = await mergeConfigWithConfigFile(syncOpts);
|
|
65021
65165
|
const ignore = await ignoreF(mergedOpts);
|
|
@@ -65151,11 +65295,11 @@ async function checkMissingLocks(opts, directory) {
|
|
|
65151
65295
|
return issues;
|
|
65152
65296
|
}
|
|
65153
65297
|
async function runLint(opts, directory) {
|
|
65154
|
-
const initialCwd =
|
|
65298
|
+
const initialCwd = process14.cwd();
|
|
65155
65299
|
const explicitTargetDirectory = directory ? path8.resolve(initialCwd, directory) : undefined;
|
|
65156
65300
|
const { json: _json, ...syncOpts } = opts;
|
|
65157
65301
|
const mergedOpts = await mergeConfigWithConfigFile(syncOpts);
|
|
65158
|
-
const targetDirectory = explicitTargetDirectory ??
|
|
65302
|
+
const targetDirectory = explicitTargetDirectory ?? process14.cwd();
|
|
65159
65303
|
const stats = await stat5(targetDirectory).catch(() => null);
|
|
65160
65304
|
if (!stats) {
|
|
65161
65305
|
throw new Error(`Directory not found: ${targetDirectory}`);
|
|
@@ -65270,7 +65414,7 @@ async function lint(opts, directory) {
|
|
|
65270
65414
|
const report = await runLint(opts, directory);
|
|
65271
65415
|
printReport(report, !!opts.json);
|
|
65272
65416
|
if (report.exitCode !== 0) {
|
|
65273
|
-
|
|
65417
|
+
process14.exit(report.exitCode);
|
|
65274
65418
|
}
|
|
65275
65419
|
} catch (error2) {
|
|
65276
65420
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
@@ -65283,17 +65427,17 @@ async function lint(opts, directory) {
|
|
|
65283
65427
|
} else {
|
|
65284
65428
|
error(colors.red(`❌ ${message}`));
|
|
65285
65429
|
}
|
|
65286
|
-
|
|
65430
|
+
process14.exit(1);
|
|
65287
65431
|
}
|
|
65288
65432
|
}
|
|
65289
65433
|
async function lintWatch(opts, directory) {
|
|
65290
65434
|
const { watch } = await import("node:fs");
|
|
65291
|
-
const targetDir = directory ? path8.resolve(
|
|
65435
|
+
const targetDir = directory ? path8.resolve(process14.cwd(), directory) : process14.cwd();
|
|
65292
65436
|
info(colors.blue(`Watching ${targetDir} for changes... (Ctrl+C to stop)`));
|
|
65293
65437
|
async function runAndReport() {
|
|
65294
65438
|
try {
|
|
65295
65439
|
const report = await runLint(opts, directory);
|
|
65296
|
-
|
|
65440
|
+
process14.stdout.write("\x1Bc");
|
|
65297
65441
|
info(colors.gray(`[${new Date().toLocaleTimeString()}] Lint results:
|
|
65298
65442
|
`));
|
|
65299
65443
|
printReport(report, false);
|
|
@@ -70757,7 +70901,7 @@ var init_app_metadata = __esm(async () => {
|
|
|
70757
70901
|
import * as fs10 from "node:fs";
|
|
70758
70902
|
import { writeFile as writeFile9 } from "node:fs/promises";
|
|
70759
70903
|
import path14 from "node:path";
|
|
70760
|
-
import
|
|
70904
|
+
import process15 from "node:process";
|
|
70761
70905
|
function generateDatatablesMarkdown(schemas, localData) {
|
|
70762
70906
|
const defaultDatatable = localData?.datatable;
|
|
70763
70907
|
const defaultSchema = localData?.schema;
|
|
@@ -70905,7 +71049,7 @@ async function regenerateAgentDocs(workspaceId, targetDir, silent = false) {
|
|
|
70905
71049
|
}
|
|
70906
71050
|
}
|
|
70907
71051
|
async function generateAgents(opts, appFolder) {
|
|
70908
|
-
const cwd =
|
|
71052
|
+
const cwd = process15.cwd();
|
|
70909
71053
|
let targetDir = cwd;
|
|
70910
71054
|
if (appFolder) {
|
|
70911
71055
|
targetDir = path14.isAbsolute(appFolder) ? appFolder : path14.join(cwd, appFolder);
|
|
@@ -70916,13 +71060,13 @@ async function generateAgents(opts, appFolder) {
|
|
|
70916
71060
|
if (!hasFolderSuffix(path14.basename(cwd), "raw_app") && !appFolder) {
|
|
70917
71061
|
error(colors.red(`Error: Must be run inside a ${getFolderSuffix("raw_app")} folder or specify one as argument.`));
|
|
70918
71062
|
info(colors.gray("Usage: wmill app generate-agents [app_folder]"));
|
|
70919
|
-
|
|
71063
|
+
process15.exit(1);
|
|
70920
71064
|
}
|
|
70921
71065
|
}
|
|
70922
71066
|
const rawAppPath = path14.join(targetDir, "raw_app.yaml");
|
|
70923
71067
|
if (!fs10.existsSync(rawAppPath)) {
|
|
70924
71068
|
error(colors.red(`Error: raw_app.yaml not found in ${targetDir}`));
|
|
70925
|
-
|
|
71069
|
+
process15.exit(1);
|
|
70926
71070
|
}
|
|
70927
71071
|
const workspace = await resolveWorkspace(opts);
|
|
70928
71072
|
await requireLogin(opts);
|
|
@@ -70950,18 +71094,18 @@ import { sep as SEP13 } from "node:path";
|
|
|
70950
71094
|
import * as http2 from "node:http";
|
|
70951
71095
|
import * as fs11 from "node:fs";
|
|
70952
71096
|
import * as path15 from "node:path";
|
|
70953
|
-
import
|
|
71097
|
+
import process16 from "node:process";
|
|
70954
71098
|
import { writeFileSync as writeFileSync5 } from "node:fs";
|
|
70955
71099
|
async function dev(opts, appFolder) {
|
|
70956
71100
|
GLOBAL_CONFIG_OPT.noCdToRoot = true;
|
|
70957
71101
|
await loadNonDottedPathsSetting();
|
|
70958
|
-
const originalCwd =
|
|
71102
|
+
const originalCwd = process16.cwd();
|
|
70959
71103
|
let targetDir = originalCwd;
|
|
70960
71104
|
if (appFolder) {
|
|
70961
71105
|
targetDir = path15.isAbsolute(appFolder) ? appFolder : path15.join(originalCwd, appFolder);
|
|
70962
71106
|
if (!fs11.existsSync(targetDir)) {
|
|
70963
71107
|
error(colors.red(`Error: Directory not found: ${targetDir}`));
|
|
70964
|
-
|
|
71108
|
+
process16.exit(1);
|
|
70965
71109
|
}
|
|
70966
71110
|
}
|
|
70967
71111
|
const targetDirName = path15.basename(targetDir);
|
|
@@ -70969,13 +71113,13 @@ async function dev(opts, appFolder) {
|
|
|
70969
71113
|
error(colors.red(`Error: The dev command must be run inside a ${getFolderSuffix("raw_app")} folder.
|
|
70970
71114
|
` + `Target directory: ${targetDirName}
|
|
70971
71115
|
` + `Please navigate to a folder ending with '${getFolderSuffix("raw_app")}' or specify one as argument.`));
|
|
70972
|
-
|
|
71116
|
+
process16.exit(1);
|
|
70973
71117
|
}
|
|
70974
71118
|
const rawAppPath = path15.join(targetDir, "raw_app.yaml");
|
|
70975
71119
|
if (!fs11.existsSync(rawAppPath)) {
|
|
70976
71120
|
error(colors.red(`Error: raw_app.yaml not found in ${targetDir}.
|
|
70977
71121
|
` + `The dev command requires a ${getFolderSuffix("raw_app")} folder containing a raw_app.yaml file.`));
|
|
70978
|
-
|
|
71122
|
+
process16.exit(1);
|
|
70979
71123
|
}
|
|
70980
71124
|
const workspace = await resolveWorkspace(opts);
|
|
70981
71125
|
await requireLogin(opts);
|
|
@@ -70988,20 +71132,20 @@ async function dev(opts, appFolder) {
|
|
|
70988
71132
|
const mergedOpts = await mergeConfigWithConfigFile(opts);
|
|
70989
71133
|
const codebases = await listSyncCodebases(mergedOpts);
|
|
70990
71134
|
const { buildPreviewTempScriptRefs: buildPreviewTempScriptRefs2 } = await init_generate_metadata().then(() => exports_generate_metadata);
|
|
70991
|
-
const savedCwd =
|
|
71135
|
+
const savedCwd = process16.cwd();
|
|
70992
71136
|
if (workspaceRoot !== savedCwd) {
|
|
70993
|
-
|
|
71137
|
+
process16.chdir(workspaceRoot);
|
|
70994
71138
|
}
|
|
70995
71139
|
try {
|
|
70996
71140
|
appTempRefs = await buildPreviewTempScriptRefs2(workspace, mergedOpts, codebases, { kind: "app", folder: relAppFolder, rawApp: true });
|
|
70997
71141
|
} finally {
|
|
70998
71142
|
if (workspaceRoot !== savedCwd) {
|
|
70999
|
-
|
|
71143
|
+
process16.chdir(savedCwd);
|
|
71000
71144
|
}
|
|
71001
71145
|
}
|
|
71002
71146
|
}
|
|
71003
71147
|
if (appFolder) {
|
|
71004
|
-
|
|
71148
|
+
process16.chdir(targetDir);
|
|
71005
71149
|
}
|
|
71006
71150
|
const rawApp = await yamlParseFile(rawAppPath);
|
|
71007
71151
|
const appPath = rawApp?.custom_path ?? "u/unknown/newapp";
|
|
@@ -71015,30 +71159,30 @@ async function dev(opts, appFolder) {
|
|
|
71015
71159
|
port: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((p) => p + DEFAULT_PORT)
|
|
71016
71160
|
});
|
|
71017
71161
|
const shouldOpen = opts.open ?? true;
|
|
71018
|
-
const frameworks = detectFrameworks(
|
|
71162
|
+
const frameworks = detectFrameworks(process16.cwd());
|
|
71019
71163
|
const defaultEntry = frameworks.svelte || frameworks.vue ? "index.ts" : "index.tsx";
|
|
71020
71164
|
const entryPoint = opts.entry ?? defaultEntry;
|
|
71021
71165
|
if (!fs11.existsSync(entryPoint)) {
|
|
71022
71166
|
error(colors.red(`Entry point "${entryPoint}" not found. Please specify a valid entry point with --entry.`));
|
|
71023
|
-
|
|
71167
|
+
process16.exit(1);
|
|
71024
71168
|
}
|
|
71025
|
-
const appDir = path15.dirname(entryPoint) ||
|
|
71169
|
+
const appDir = path15.dirname(entryPoint) || process16.cwd();
|
|
71026
71170
|
await ensureNodeModules(appDir);
|
|
71027
71171
|
const inferredSchemas = {};
|
|
71028
71172
|
try {
|
|
71029
|
-
Object.assign(inferredSchemas, await inferAllInlineSchemas(
|
|
71173
|
+
Object.assign(inferredSchemas, await inferAllInlineSchemas(process16.cwd()));
|
|
71030
71174
|
} catch (err) {
|
|
71031
71175
|
warn(colors.yellow(`Could not seed inline schemas at startup: ${err.message}`));
|
|
71032
71176
|
}
|
|
71033
71177
|
const pathRunnableSchemas = {};
|
|
71034
71178
|
try {
|
|
71035
|
-
const initialRunnables = await loadRunnablesFromBackend(path15.join(
|
|
71179
|
+
const initialRunnables = await loadRunnablesFromBackend(path15.join(process16.cwd(), APP_BACKEND_FOLDER));
|
|
71036
71180
|
Object.assign(pathRunnableSchemas, await fetchPathRunnableSchemas(workspaceId, initialRunnables));
|
|
71037
71181
|
} catch (err) {
|
|
71038
71182
|
warn(colors.yellow(`Could not fetch schemas for path-based runnables: ${err.message}`));
|
|
71039
71183
|
}
|
|
71040
71184
|
await genRunnablesTs(inferredSchemas, pathRunnableSchemas);
|
|
71041
|
-
const distDir = path15.join(
|
|
71185
|
+
const distDir = path15.join(process16.cwd(), "dist");
|
|
71042
71186
|
if (!fs11.existsSync(distDir)) {
|
|
71043
71187
|
fs11.mkdirSync(distDir);
|
|
71044
71188
|
}
|
|
@@ -71101,7 +71245,7 @@ data: reload
|
|
|
71101
71245
|
info(colors.blue(`\uD83D\uDC40 Watching for file changes...
|
|
71102
71246
|
`));
|
|
71103
71247
|
await ctx.rebuild();
|
|
71104
|
-
const runnablesPath = path15.join(
|
|
71248
|
+
const runnablesPath = path15.join(process16.cwd(), APP_BACKEND_FOLDER);
|
|
71105
71249
|
let runnablesWatcher;
|
|
71106
71250
|
if (fs11.existsSync(runnablesPath)) {
|
|
71107
71251
|
info(colors.blue(`\uD83D\uDC41️ Watching runnables folder at: ${runnablesPath}
|
|
@@ -71114,7 +71258,7 @@ data: reload
|
|
|
71114
71258
|
return;
|
|
71115
71259
|
const fileStr = typeof filename === "string" ? filename : filename.toString();
|
|
71116
71260
|
const changedPath = path15.join(runnablesPath, fileStr);
|
|
71117
|
-
const relativePath = path15.relative(
|
|
71261
|
+
const relativePath = path15.relative(process16.cwd(), changedPath);
|
|
71118
71262
|
const relativeToRunnables = fileStr;
|
|
71119
71263
|
if (changedPath.endsWith(".lock")) {
|
|
71120
71264
|
return;
|
|
@@ -71127,7 +71271,7 @@ data: reload
|
|
|
71127
71271
|
delete schemaInferenceTimeouts[changedPath];
|
|
71128
71272
|
try {
|
|
71129
71273
|
info(colors.cyan(`\uD83D\uDCDD Inferring schema for: ${relativeToRunnables}`));
|
|
71130
|
-
const result = await inferRunnableSchemaFromFile(
|
|
71274
|
+
const result = await inferRunnableSchemaFromFile(process16.cwd(), relativeToRunnables);
|
|
71131
71275
|
if (result) {
|
|
71132
71276
|
inferredSchemas[result.runnableId] = result.schema;
|
|
71133
71277
|
info(colors.green(` Inferred Schemas: ${JSON.stringify(inferredSchemas, null, 2)}`));
|
|
@@ -71165,7 +71309,7 @@ data: reload
|
|
|
71165
71309
|
return;
|
|
71166
71310
|
}
|
|
71167
71311
|
if (url === "/dist/bundle.js" || url === "/bundle.js") {
|
|
71168
|
-
const jsPath = path15.join(
|
|
71312
|
+
const jsPath = path15.join(process16.cwd(), "dist/bundle.js");
|
|
71169
71313
|
if (fs11.existsSync(jsPath)) {
|
|
71170
71314
|
res.writeHead(200, { "Content-Type": "application/javascript" });
|
|
71171
71315
|
res.end(fs11.readFileSync(jsPath));
|
|
@@ -71176,7 +71320,7 @@ data: reload
|
|
|
71176
71320
|
return;
|
|
71177
71321
|
}
|
|
71178
71322
|
if (url === "/dist/bundle.css" || url === "/bundle.css") {
|
|
71179
|
-
const cssPath = path15.join(
|
|
71323
|
+
const cssPath = path15.join(process16.cwd(), "dist/bundle.css");
|
|
71180
71324
|
if (fs11.existsSync(cssPath)) {
|
|
71181
71325
|
res.writeHead(200, { "Content-Type": "text/css" });
|
|
71182
71326
|
res.end(fs11.readFileSync(cssPath));
|
|
@@ -71187,7 +71331,7 @@ data: reload
|
|
|
71187
71331
|
return;
|
|
71188
71332
|
}
|
|
71189
71333
|
if (url === "/dist/bundle.js.map" || url === "/bundle.js.map") {
|
|
71190
|
-
const mapPath = path15.join(
|
|
71334
|
+
const mapPath = path15.join(process16.cwd(), "dist/bundle.js.map");
|
|
71191
71335
|
if (fs11.existsSync(mapPath)) {
|
|
71192
71336
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
71193
71337
|
res.end(fs11.readFileSync(mapPath));
|
|
@@ -71198,7 +71342,7 @@ data: reload
|
|
|
71198
71342
|
return;
|
|
71199
71343
|
}
|
|
71200
71344
|
if (url === "/dist/bundle.css.map" || url === "/bundle.css.map") {
|
|
71201
|
-
const mapPath = path15.join(
|
|
71345
|
+
const mapPath = path15.join(process16.cwd(), "dist/bundle.css.map");
|
|
71202
71346
|
if (fs11.existsSync(mapPath)) {
|
|
71203
71347
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
71204
71348
|
res.end(fs11.readFileSync(mapPath));
|
|
@@ -71212,12 +71356,12 @@ data: reload
|
|
|
71212
71356
|
res.end(createHTML("/dist/bundle.js", "/dist/bundle.css"));
|
|
71213
71357
|
});
|
|
71214
71358
|
const wss = new import_websocket_server.default({ server });
|
|
71215
|
-
const sqlToApplyPath = path15.join(
|
|
71359
|
+
const sqlToApplyPath = path15.join(process16.cwd(), "sql_to_apply");
|
|
71216
71360
|
const sqlFileQueue = [];
|
|
71217
71361
|
let currentSqlFile = null;
|
|
71218
71362
|
async function getDatatableConfig() {
|
|
71219
71363
|
try {
|
|
71220
|
-
const rawApp2 = await yamlParseFile(path15.join(
|
|
71364
|
+
const rawApp2 = await yamlParseFile(path15.join(process16.cwd(), "raw_app.yaml"));
|
|
71221
71365
|
return rawApp2?.data?.datatable;
|
|
71222
71366
|
} catch {
|
|
71223
71367
|
return;
|
|
@@ -71436,7 +71580,7 @@ data: reload
|
|
|
71436
71580
|
await onSqlFileCompleted(currentSqlFile, true);
|
|
71437
71581
|
}
|
|
71438
71582
|
try {
|
|
71439
|
-
await regenerateAgentDocs(workspaceId,
|
|
71583
|
+
await regenerateAgentDocs(workspaceId, process16.cwd(), true);
|
|
71440
71584
|
info(colors.gray(`[SQL Migration] Refreshed AGENTS.md and DATATABLES.md`));
|
|
71441
71585
|
} catch (regenError) {
|
|
71442
71586
|
warn(colors.yellow(`[SQL Migration] Could not refresh docs: ${regenError.message}`));
|
|
@@ -71535,7 +71679,7 @@ data: reload
|
|
|
71535
71679
|
const url = `http://${host}:${port}`;
|
|
71536
71680
|
info(colors.bold.green(`\uD83D\uDE80 Dev server running at ${url}`));
|
|
71537
71681
|
info(colors.cyan(`\uD83D\uDD0C WebSocket server running at ws://${host}:${port}`));
|
|
71538
|
-
info(colors.gray(`\uD83D\uDCE6 Serving files from: ${
|
|
71682
|
+
info(colors.gray(`\uD83D\uDCE6 Serving files from: ${process16.cwd()}`));
|
|
71539
71683
|
info(colors.gray(`\uD83D\uDD04 Live reload enabled
|
|
71540
71684
|
`));
|
|
71541
71685
|
if (shouldOpen) {
|
|
@@ -71549,7 +71693,7 @@ data: reload
|
|
|
71549
71693
|
}
|
|
71550
71694
|
}
|
|
71551
71695
|
});
|
|
71552
|
-
|
|
71696
|
+
process16.on("SIGINT", async () => {
|
|
71553
71697
|
info(colors.yellow(`
|
|
71554
71698
|
|
|
71555
71699
|
\uD83D\uDED1 Shutting down...`));
|
|
@@ -71562,12 +71706,12 @@ data: reload
|
|
|
71562
71706
|
sqlWatcher.close();
|
|
71563
71707
|
}
|
|
71564
71708
|
await ctx.dispose();
|
|
71565
|
-
|
|
71709
|
+
process16.exit(0);
|
|
71566
71710
|
});
|
|
71567
71711
|
}
|
|
71568
71712
|
async function genRunnablesTs(inlineSchemaOverrides = {}, pathSchemaOverrides = {}) {
|
|
71569
71713
|
info(colors.blue("\uD83D\uDD04 Generating wmill.d.ts..."));
|
|
71570
|
-
const localPath =
|
|
71714
|
+
const localPath = process16.cwd();
|
|
71571
71715
|
const backendPath = path15.join(localPath, APP_BACKEND_FOLDER);
|
|
71572
71716
|
let runnables = await loadRunnablesFromBackend(backendPath);
|
|
71573
71717
|
if (Object.keys(runnables).length === 0) {
|
|
@@ -71580,7 +71724,7 @@ async function genRunnablesTs(inlineSchemaOverrides = {}, pathSchemaOverrides =
|
|
|
71580
71724
|
}
|
|
71581
71725
|
try {
|
|
71582
71726
|
const newWmillTs = buildWmillTs(runnables, inlineSchemaOverrides, pathSchemaOverrides);
|
|
71583
|
-
writeFileSync5(path15.join(
|
|
71727
|
+
writeFileSync5(path15.join(process16.cwd(), "wmill.d.ts"), newWmillTs);
|
|
71584
71728
|
} catch (error2) {
|
|
71585
71729
|
error(colors.red(`Failed to generate wmill.d.ts: ${error2.message}`));
|
|
71586
71730
|
}
|
|
@@ -71649,7 +71793,7 @@ function convertRunnablesToApiFormat(runnables) {
|
|
|
71649
71793
|
}
|
|
71650
71794
|
async function loadRunnables() {
|
|
71651
71795
|
try {
|
|
71652
|
-
const localPath =
|
|
71796
|
+
const localPath = process16.cwd();
|
|
71653
71797
|
const backendPath = path15.join(localPath, APP_BACKEND_FOLDER);
|
|
71654
71798
|
let runnables = await loadRunnablesFromBackend(backendPath);
|
|
71655
71799
|
if (Object.keys(runnables).length === 0) {
|
|
@@ -72158,7 +72302,7 @@ var init_dev = __esm(async () => {
|
|
|
72158
72302
|
// src/commands/app/lint.ts
|
|
72159
72303
|
import * as fs12 from "node:fs";
|
|
72160
72304
|
import * as path16 from "node:path";
|
|
72161
|
-
import
|
|
72305
|
+
import process17 from "node:process";
|
|
72162
72306
|
function validateRawAppYaml(appData) {
|
|
72163
72307
|
const errors = [];
|
|
72164
72308
|
const warnings = [];
|
|
@@ -72254,7 +72398,7 @@ async function lintRawApp(appDir, opts) {
|
|
|
72254
72398
|
}
|
|
72255
72399
|
async function lint2(opts, appFolder) {
|
|
72256
72400
|
await loadNonDottedPathsSetting();
|
|
72257
|
-
const targetDir = appFolder ??
|
|
72401
|
+
const targetDir = appFolder ?? process17.cwd();
|
|
72258
72402
|
info(colors.bold.blue(`
|
|
72259
72403
|
\uD83D\uDD0D Linting raw app: ${targetDir}
|
|
72260
72404
|
`));
|
|
@@ -72275,7 +72419,7 @@ async function lint2(opts, appFolder) {
|
|
|
72275
72419
|
info(colors.red(`
|
|
72276
72420
|
❌ Lint failed
|
|
72277
72421
|
`));
|
|
72278
|
-
|
|
72422
|
+
process17.exit(1);
|
|
72279
72423
|
}
|
|
72280
72424
|
info(colors.green(`
|
|
72281
72425
|
✅ All checks passed
|
|
@@ -73948,7 +74092,7 @@ async function decrypt(combinedCiphertext, keyString) {
|
|
|
73948
74092
|
var init_local_encryption = () => {};
|
|
73949
74093
|
|
|
73950
74094
|
// src/core/settings.ts
|
|
73951
|
-
import
|
|
74095
|
+
import process18 from "node:process";
|
|
73952
74096
|
import { writeFile as writeFile14 } from "node:fs/promises";
|
|
73953
74097
|
function migrateToGroupedFormat(settings) {
|
|
73954
74098
|
const result = { name: settings.name ?? "" };
|
|
@@ -74252,7 +74396,7 @@ async function pushWorkspaceKey(workspace, _path, key, localKey, opts) {
|
|
|
74252
74396
|
}
|
|
74253
74397
|
if (localKey && key !== localKey) {
|
|
74254
74398
|
let reencrypt;
|
|
74255
|
-
const explicitSkip = opts?.skipReencrypt || (
|
|
74399
|
+
const explicitSkip = opts?.skipReencrypt || (process18.env.WMILL_NO_REENCRYPT_ON_KEY_CHANGE ?? "").toLowerCase() === "true";
|
|
74256
74400
|
if (explicitSkip) {
|
|
74257
74401
|
reencrypt = false;
|
|
74258
74402
|
info("Workspace encryption key changed; leaving remote ciphertexts untouched (skip re-encryption requested).");
|
|
@@ -74291,7 +74435,7 @@ async function readInstanceSettings(opts) {
|
|
|
74291
74435
|
return localSettings;
|
|
74292
74436
|
}
|
|
74293
74437
|
async function processInstanceSettings(settings, mode) {
|
|
74294
|
-
const encKey =
|
|
74438
|
+
const encKey = process18.env.WMILL_INSTANCE_LOCAL_ENCRYPTION_KEY;
|
|
74295
74439
|
if (encKey) {
|
|
74296
74440
|
const res = [];
|
|
74297
74441
|
for (const s of settings) {
|
|
@@ -77236,7 +77380,7 @@ class GitSyncSettingsConverter {
|
|
|
77236
77380
|
}
|
|
77237
77381
|
|
|
77238
77382
|
// src/commands/gitsync-settings/legacySettings.ts
|
|
77239
|
-
import
|
|
77383
|
+
import process19 from "node:process";
|
|
77240
77384
|
async function handleLegacyRepositoryMigration(selectedRepo, gitSyncSettings, workspace, opts, operationName = "operation") {
|
|
77241
77385
|
if (selectedRepo.settings) {
|
|
77242
77386
|
return selectedRepo;
|
|
@@ -77246,7 +77390,7 @@ async function handleLegacyRepositoryMigration(selectedRepo, gitSyncSettings, wo
|
|
|
77246
77390
|
}
|
|
77247
77391
|
const workspaceIncludePath = gitSyncSettings.include_path;
|
|
77248
77392
|
const workspaceIncludeType = gitSyncSettings.include_type;
|
|
77249
|
-
if (!!
|
|
77393
|
+
if (!!process19.stdout.isTTY && !opts.yes) {
|
|
77250
77394
|
console.log(colors.yellow(`
|
|
77251
77395
|
⚠️ Legacy git-sync settings detected!`));
|
|
77252
77396
|
console.log(`
|
|
@@ -77352,7 +77496,7 @@ Repository "${selectedRepo.git_repo_resource_path}" has legacy settings format.`
|
|
|
77352
77496
|
console.error(` wmill gitsync-settings push
|
|
77353
77497
|
`);
|
|
77354
77498
|
}
|
|
77355
|
-
|
|
77499
|
+
process19.exit(1);
|
|
77356
77500
|
}
|
|
77357
77501
|
}
|
|
77358
77502
|
var init_legacySettings = __esm(async () => {
|
|
@@ -77808,14 +77952,14 @@ var init_pull2 = __esm(async () => {
|
|
|
77808
77952
|
});
|
|
77809
77953
|
|
|
77810
77954
|
// src/commands/gitsync-settings/push.ts
|
|
77811
|
-
import
|
|
77955
|
+
import process20 from "node:process";
|
|
77812
77956
|
async function pushGitSyncSettings(opts) {
|
|
77813
77957
|
try {
|
|
77814
77958
|
await validateBranchConfiguration({ yes: opts.yes });
|
|
77815
77959
|
} catch (error2) {
|
|
77816
77960
|
if (error2 instanceof Error && error2.message.includes("overrides")) {
|
|
77817
77961
|
error(error2.message);
|
|
77818
|
-
|
|
77962
|
+
process20.exit(1);
|
|
77819
77963
|
}
|
|
77820
77964
|
throw error2;
|
|
77821
77965
|
}
|
|
@@ -77825,7 +77969,7 @@ async function pushGitSyncSettings(opts) {
|
|
|
77825
77969
|
const wmillYamlPath = getWmillYamlPath();
|
|
77826
77970
|
if (!wmillYamlPath) {
|
|
77827
77971
|
error(colors.red("No wmill.yaml file found. Please run 'wmill init' first to create the configuration file."));
|
|
77828
|
-
|
|
77972
|
+
process20.exit(1);
|
|
77829
77973
|
}
|
|
77830
77974
|
const localConfig = await readConfigFile();
|
|
77831
77975
|
let settings;
|
|
@@ -77941,7 +78085,7 @@ async function pushGitSyncSettings(opts) {
|
|
|
77941
78085
|
displayChanges(changes);
|
|
77942
78086
|
}
|
|
77943
78087
|
}
|
|
77944
|
-
if (!opts.yes && !!
|
|
78088
|
+
if (!opts.yes && !!process20.stdin.isTTY) {
|
|
77945
78089
|
const confirmed = await Confirm.prompt({
|
|
77946
78090
|
message: `Do you want to apply these changes to the remote?`,
|
|
77947
78091
|
default: true
|
|
@@ -78060,7 +78204,7 @@ The line below pulls in Windmill's managed CLI guidance (skills, deploy flow,
|
|
|
78060
78204
|
debugging jobs, etc.). Refresh it with \`wmill refresh prompts\`. Remove the
|
|
78061
78205
|
include line if you don't want the managed guidance in this project.
|
|
78062
78206
|
|
|
78063
|
-
${
|
|
78207
|
+
${AGENTS_WMILL_INCLUDE_LINE}
|
|
78064
78208
|
|
|
78065
78209
|
## Project-specific instructions
|
|
78066
78210
|
|
|
@@ -78139,10 +78283,11 @@ There are two ways local changes reach the workspace. Pick based on how the repo
|
|
|
78139
78283
|
Before deploying, check whether this repo has a **GitHub Actions (or other CI) workflow that runs \`wmill sync push\` on push**. That workflow is the signal that pushing a branch will deploy:
|
|
78140
78284
|
|
|
78141
78285
|
- Look for \`.github/workflows/*.yml\` (or other CI configs) that invoke \`wmill sync push\`, \`wmill\` deployment commands, or similar.
|
|
78142
|
-
- Cache the result for the rest of the session — don't re-scan on every deploy.
|
|
78143
78286
|
|
|
78144
78287
|
If such a workflow exists → **use \`git push\`** (Option A). Otherwise → **use \`wmill sync push\`** directly (Option B).
|
|
78145
78288
|
|
|
78289
|
+
**Save the preference so you don't re-detect it every session.** Once you've determined which option this repo uses (or the user tells you), record it in the **project-specific instructions** section of \`AGENTS.md\` (user-owned — never overwritten by \`wmill refresh prompts\`), e.g. a line like \`Deploy mode: git push (CI runs wmill sync push)\` or \`Deploy mode: wmill sync push (no CI wiring)\`. On later sessions, read that line first and skip the scan. Re-detect only if the CI wiring visibly changed.
|
|
78290
|
+
|
|
78146
78291
|
### Option A — \`git push\` (CI is wired to sync)
|
|
78147
78292
|
|
|
78148
78293
|
The CI workflow will pick up the commit and run \`wmill sync push\` on the backend, which is how deployments are intended to happen in this repo. Don't bypass it.
|
|
@@ -78164,6 +78309,19 @@ No CI workflow runs \`wmill sync push\` automatically, so deploy directly from t
|
|
|
78164
78309
|
|
|
78165
78310
|
Only deploy when the user explicitly asks to deploy, publish, push, or ship — not when they say "run", "try", or "test". For testing local edits use the per-entity \`preview\` commands (\`wmill script preview\`, \`wmill flow preview\`) — they don't deploy.
|
|
78166
78311
|
|
|
78312
|
+
## Workspace forks
|
|
78313
|
+
|
|
78314
|
+
A **fork** is an isolated copy of a workspace for parallel or experimental work — make changes (including to datatables, which are cloned per fork) without touching the parent, then merge back after review. Each fork is paired with a git branch named \`wm-fork/<base>/<id>\`. Forks require a git repo.
|
|
78315
|
+
|
|
78316
|
+
Just run \`wmill workspace fork\` — it adapts to where you are:
|
|
78317
|
+
|
|
78318
|
+
- **On a base branch** (e.g. \`main\`, or a branch bound to a workspace): it bases the fork on that branch and prints a \`git checkout -b wm-fork/<base>/<id>\` to start a fresh fork branch.
|
|
78319
|
+
- **On a working branch** (e.g. you've branched and already edited a forked datatable): it offers to base the fork on that branch and rename it onto \`wm-fork/<base>/<id>\` in place, preserving its commits — asking which base branch is the parent if there's more than one.
|
|
78320
|
+
|
|
78321
|
+
For non-interactive runs from a working branch, pass \`--from-branch <base>\` to skip the prompts. The CLI refuses to rename a base branch.
|
|
78322
|
+
|
|
78323
|
+
Merge a fork back into its parent with \`wmill workspace merge\` (or the Merge UI on the fork's home page). Full reference: https://www.windmill.dev/docs/advanced/workspace_forks
|
|
78324
|
+
|
|
78167
78325
|
## Debugging Jobs
|
|
78168
78326
|
|
|
78169
78327
|
When the user reports a script or flow failure, is investigating unexpected output, or asks why something ran the way it did, use the CLI to fetch job details before speculating. See the \`cli-commands\` skill for all flags.
|
|
@@ -78194,7 +78352,7 @@ For Windmill concepts not covered by the skills (triggers, schedules, workers, f
|
|
|
78194
78352
|
- https://www.windmill.dev/llms-full.txt is the entire documentation as a single ~2.3 MB file — only for bulk indexing/RAG, do NOT load it directly into context.
|
|
78195
78353
|
`;
|
|
78196
78354
|
}
|
|
78197
|
-
var
|
|
78355
|
+
var AGENTS_WMILL_FILENAME = "AGENTS.wmill.md", AGENTS_WMILL_INCLUDE_LINE = "@AGENTS.wmill.md", LEGACY_AGENTS_CLI_FILENAME = "AGENTS.cli.md", LEGACY_AGENTS_CLI_INCLUDE_LINE = "@AGENTS.cli.md";
|
|
78198
78356
|
|
|
78199
78357
|
// src/guidance/skills.gen.ts
|
|
78200
78358
|
var SKILLS, SKILL_CONTENT, SCHEMAS, SCHEMA_MAPPINGS;
|
|
@@ -78482,6 +78640,10 @@ import Stripe from "stripe";
|
|
|
78482
78640
|
import { someFunction } from "some-package";
|
|
78483
78641
|
\`\`\`
|
|
78484
78642
|
|
|
78643
|
+
## Prefer \`//native\` when the runtime allows it
|
|
78644
|
+
|
|
78645
|
+
If a script only needs \`fetch\` and the JavaScript standard library — including when it uses \`windmill-client\` — prefer making it a **native** script: add \`//native\` as the first line and write it with the \`write-script-bunnative\` skill. Native scripts run on a lightweight V8 isolate, start faster, and parallelize heavily. \`windmill-client\` works on the native worker (its calls go over \`fetch\`), so needing the Windmill client is **not** a reason to avoid \`//native\`. Use the regular \`bun\` language only when the code (or a dependency) needs Node/Bun runtime APIs — \`node:*\` modules, the filesystem, child processes, or native addons.
|
|
78646
|
+
|
|
78485
78647
|
## Windmill Client
|
|
78486
78648
|
|
|
78487
78649
|
Import the windmill client for platform interactions:
|
|
@@ -78490,7 +78652,9 @@ Import the windmill client for platform interactions:
|
|
|
78490
78652
|
import * as wmill from "windmill-client";
|
|
78491
78653
|
\`\`\`
|
|
78492
78654
|
|
|
78493
|
-
|
|
78655
|
+
**Prefer \`windmill-client\` over raw \`fetch\` for anything that talks to Windmill** — reading resources/variables/states, running scripts and flows, S3 object operations, etc. It handles auth, the workspace, and the base URL for you, so you don't hand-roll URLs or tokens. Reserve \`fetch\` for calling *external* HTTP APIs that aren't Windmill.
|
|
78656
|
+
|
|
78657
|
+
The full \`windmill-client\` API reference (every exported function and its signature) is included in this skill below — consult it for the exact method to use instead of guessing or falling back to \`fetch\`.
|
|
78494
78658
|
|
|
78495
78659
|
## Preprocessor Scripts
|
|
78496
78660
|
|
|
@@ -79203,7 +79367,9 @@ export async function main(url: string) {
|
|
|
79203
79367
|
|
|
79204
79368
|
## Windmill Client
|
|
79205
79369
|
|
|
79206
|
-
\`windmill-client\`
|
|
79370
|
+
\`windmill-client\` works on the native worker (its calls go over \`fetch\`), so use it as the **preferred way to talk to Windmill** — reading resources/variables/states, running scripts and flows, and the S3 helpers below (\`loadS3File\`, \`loadS3FileStream\`, \`writeS3File\`, \`S3Object\`). It handles auth, the workspace, and the base URL for you. Reserve raw \`fetch\` for calling *external* HTTP APIs that aren't Windmill.
|
|
79371
|
+
|
|
79372
|
+
The full \`windmill-client\` API reference (every exported function and its signature) is included in this skill below — consult it for the exact method instead of hand-rolling a \`fetch\` against the Windmill API.
|
|
79207
79373
|
|
|
79208
79374
|
## Preprocessor Scripts
|
|
79209
79375
|
|
|
@@ -80004,7 +80170,9 @@ Import the windmill client for platform interactions:
|
|
|
80004
80170
|
import * as wmill from "windmill-client";
|
|
80005
80171
|
\`\`\`
|
|
80006
80172
|
|
|
80007
|
-
|
|
80173
|
+
**Prefer \`windmill-client\` over raw \`fetch\` for anything that talks to Windmill** — reading resources/variables/states, running scripts and flows, S3 object operations, etc. It handles auth, the workspace, and the base URL for you. Reserve \`fetch\` for calling *external* HTTP APIs that aren't Windmill.
|
|
80174
|
+
|
|
80175
|
+
The full \`windmill-client\` API reference (every exported function and its signature) is included in this skill below — consult it for the exact method instead of guessing or falling back to \`fetch\`.
|
|
80008
80176
|
|
|
80009
80177
|
## Preprocessor Scripts
|
|
80010
80178
|
|
|
@@ -82685,7 +82853,7 @@ Once the flow has real content, **offer** to open the visual preview as a one-se
|
|
|
82685
82853
|
|
|
82686
82854
|
## CLI Commands — running, previewing, deploying
|
|
82687
82855
|
|
|
82688
|
-
After writing,
|
|
82856
|
+
After writing, act on the user's intent instead of just listing commands. Run the safe, non-deploying command yourself when it fits (\`wmill flow preview\` — see "After writing — offer to run, don't wait passively" below); only *name* the commands that deploy or rewrite files (\`wmill sync push\`, \`wmill generate-metadata\`) so the user can approve them. The options:
|
|
82689
82857
|
|
|
82690
82858
|
- \`wmill flow preview <flow_path>\` — **default when iterating on a local flow.** Runs the local \`flow.yaml\` against local inline scripts without deploying. Add \`--remote\` to use deployed workspace scripts for PathScript steps instead of local files. Add \`--step <step_id>\` to run only one module in isolation (see "Single-step vs whole-flow preview" below).
|
|
82691
82859
|
- \`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.
|
|
@@ -83151,7 +83319,7 @@ The runnable ID is the filename without extension. For example, \`get_user.ts\`
|
|
|
83151
83319
|
| C# | \`.cs\` | \`myFunc.cs\` |
|
|
83152
83320
|
| Java | \`.java\` | \`myFunc.java\` |
|
|
83153
83321
|
|
|
83154
|
-
After creating a runnable,
|
|
83322
|
+
After creating a runnable, offer to generate its lock files as a one-sentence next step (e.g. "Want me to generate the lock files?") and run it yourself once they agree — don't just name the command and wait. If the user already asked you to finish/lock the app, run it directly. It writes local lock files (not a deploy), so offer rather than running silently:
|
|
83155
83323
|
\`\`\`bash
|
|
83156
83324
|
wmill generate-metadata
|
|
83157
83325
|
\`\`\`
|
|
@@ -83242,15 +83410,16 @@ data:
|
|
|
83242
83410
|
|
|
83243
83411
|
## CLI Commands
|
|
83244
83412
|
|
|
83245
|
-
|
|
83413
|
+
Two commands you run yourself, not the user:
|
|
83414
|
+
- \`wmill app new\` — run it with flags, per the "Creating a Raw App" section above.
|
|
83415
|
+
- \`wmill generate-metadata\` — generates local lock files; offer it and run it on consent, per "After creating a runnable" above (it writes local lock files, not a deploy).
|
|
83246
83416
|
|
|
83247
|
-
For
|
|
83417
|
+
For the rest, tell the user which command fits their intent and let them run it — these deploy to the workspace, overwrite local files, or launch a long-running server, so the user should consent each time:
|
|
83248
83418
|
|
|
83249
83419
|
| Command | Description |
|
|
83250
83420
|
|---------|-------------|
|
|
83251
83421
|
| \`wmill app dev\` | Start dev server with live reload (see the \`preview\` skill for the full open-the-app-in-the-IDE-pane procedure). |
|
|
83252
83422
|
| \`wmill app generate-agents\` | Refresh AGENTS.md and DATATABLES.md |
|
|
83253
|
-
| \`wmill generate-metadata\` | Generate lock files for backend runnables |
|
|
83254
83423
|
| \`wmill sync push\` | Deploy app to Windmill |
|
|
83255
83424
|
| \`wmill sync pull\` | Pull latest from Windmill |
|
|
83256
83425
|
|
|
@@ -84647,12 +84816,12 @@ List all queues with their metrics
|
|
|
84647
84816
|
|
|
84648
84817
|
### refresh
|
|
84649
84818
|
|
|
84650
|
-
Refresh wmill-managed project files (AGENTS.
|
|
84819
|
+
Refresh wmill-managed project files (AGENTS.wmill.md, skills, tsconfig.wmill.json)
|
|
84651
84820
|
|
|
84652
84821
|
**Subcommands:**
|
|
84653
84822
|
|
|
84654
|
-
- \`refresh prompts\` - Refresh AGENTS.
|
|
84655
|
-
- \`--yes\` - Non-interactive: append the @AGENTS.
|
|
84823
|
+
- \`refresh prompts\` - Refresh AGENTS.wmill.md and managed skills. User-owned AGENTS.md and CLAUDE.md are never overwritten unless you opt in.
|
|
84824
|
+
- \`--yes\` - Non-interactive: append the @AGENTS.wmill.md include to an existing AGENTS.md / CLAUDE.md without prompting. Without it, a non-interactive run leaves an unlinked file untouched.
|
|
84656
84825
|
- \`refresh tsconfig\` - Refresh the wmill-managed tsconfig.wmill.json (and Deno import map for Deno projects)
|
|
84657
84826
|
- \`--yes\` - Non-interactive: wire an existing custom tsconfig.json/deno.json to the managed file without prompting (a previously-generated config is always migrated automatically).
|
|
84658
84827
|
|
|
@@ -84943,7 +85112,8 @@ workspace related commands
|
|
|
84943
85112
|
- \`--create-workspace-name <workspace_name:string>\` - Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.
|
|
84944
85113
|
- \`--color <color:string>\` - Workspace color (hex code, e.g. #ff0000)
|
|
84945
85114
|
- \`--datatable-behavior <behavior:string>\` - How to handle datatables: skip, schema_only, or schema_and_data (default: interactive prompt)
|
|
84946
|
-
-
|
|
85115
|
+
- \`--from-branch <branch:string>\` - Non-interactive override for the 'turn my current working branch into the fork' workflow: base the fork on <branch> (its bound workspace is the parent) and rename the current branch onto wm-fork/<branch>/<id>. Usually unneeded — from a working branch \`wmill workspace fork\` offers this interactively; from a base branch it creates a fresh fork branch.
|
|
85116
|
+
- \`-y --yes\` - Skip interactive prompts (defaults datatable behavior to 'skip'). On a non-base branch, requires --from-branch since the base branch can't be prompted for.
|
|
84947
85117
|
- \`workspace delete-fork <fork_name:string>\` - Delete a forked workspace and git branch
|
|
84948
85118
|
- \`-y --yes\` - Skip confirmation prompt
|
|
84949
85119
|
- \`workspace merge\` - Compare and deploy changes between a fork and its parent workspace
|
|
@@ -86304,9 +86474,15 @@ async function warnIfPromptsStale(opts) {
|
|
|
86304
86474
|
if (opts?.argv && !shouldRunFreshnessCheck(opts.argv))
|
|
86305
86475
|
return;
|
|
86306
86476
|
const cwd = opts?.cwd ?? process.cwd();
|
|
86307
|
-
|
|
86308
|
-
|
|
86309
|
-
|
|
86477
|
+
let fileName = AGENTS_WMILL_FILENAME;
|
|
86478
|
+
let path21 = `${cwd}/${fileName}`;
|
|
86479
|
+
if (!await stat18(path21).catch(() => null)) {
|
|
86480
|
+
fileName = LEGACY_AGENTS_CLI_FILENAME;
|
|
86481
|
+
path21 = `${cwd}/${fileName}`;
|
|
86482
|
+
if (!await stat18(path21).catch(() => null)) {
|
|
86483
|
+
return;
|
|
86484
|
+
}
|
|
86485
|
+
}
|
|
86310
86486
|
let content;
|
|
86311
86487
|
try {
|
|
86312
86488
|
content = await readTextFile(path21);
|
|
@@ -86315,7 +86491,7 @@ async function warnIfPromptsStale(opts) {
|
|
|
86315
86491
|
}
|
|
86316
86492
|
const stored = extractPromptsHash(content);
|
|
86317
86493
|
if (!stored) {
|
|
86318
|
-
emitWarning(
|
|
86494
|
+
emitWarning(`Your ${fileName} predates prompt versioning. Run \`wmill refresh prompts\` to refresh and add a version marker.`);
|
|
86319
86495
|
return;
|
|
86320
86496
|
}
|
|
86321
86497
|
let nonDottedPaths = opts?.nonDottedPaths;
|
|
@@ -86330,7 +86506,7 @@ async function warnIfPromptsStale(opts) {
|
|
|
86330
86506
|
}
|
|
86331
86507
|
const current = currentPromptsHash(nonDottedPaths);
|
|
86332
86508
|
if (stored !== current) {
|
|
86333
|
-
emitWarning(
|
|
86509
|
+
emitWarning(`Your ${fileName} is out of date. Run \`wmill refresh prompts\` to refresh.`);
|
|
86334
86510
|
}
|
|
86335
86511
|
}
|
|
86336
86512
|
function emitWarning(message) {
|
|
@@ -86357,7 +86533,7 @@ import { execSync as execSync6 } from "node:child_process";
|
|
|
86357
86533
|
import { createHash as createHash2 } from "node:crypto";
|
|
86358
86534
|
import { existsSync as existsSync12, readFileSync as readFileSync4, writeFileSync as writeFileSync7 } from "node:fs";
|
|
86359
86535
|
import path21 from "node:path";
|
|
86360
|
-
import
|
|
86536
|
+
import process23 from "node:process";
|
|
86361
86537
|
function buildManagedTsconfig() {
|
|
86362
86538
|
const paths = {};
|
|
86363
86539
|
for (const dir of WORKSPACE_IMPORT_DIRS) {
|
|
@@ -86408,7 +86584,7 @@ async function refreshTsconfig(opts) {
|
|
|
86408
86584
|
const assumeYes = opts?.yes === true;
|
|
86409
86585
|
const mode = {
|
|
86410
86586
|
assumeYes,
|
|
86411
|
-
interactive: !!
|
|
86587
|
+
interactive: !!process23.stdin.isTTY && !assumeYes
|
|
86412
86588
|
};
|
|
86413
86589
|
await refreshManagedTsconfig(defaultTs, mode);
|
|
86414
86590
|
if (defaultTs === "deno") {
|
|
@@ -86423,7 +86599,7 @@ async function refreshManagedTsconfig(defaultTs, mode) {
|
|
|
86423
86599
|
}
|
|
86424
86600
|
const header = MANAGED_NOTICE + TSCONFIG_HASH_PREFIX + currentTsconfigHash() + `
|
|
86425
86601
|
`;
|
|
86426
|
-
writeFileSync7(path21.join(
|
|
86602
|
+
writeFileSync7(path21.join(process23.cwd(), MANAGED_TSCONFIG), header + JSON.stringify(managed, null, 2) + `
|
|
86427
86603
|
`);
|
|
86428
86604
|
info(colors.green(`Refreshed ${MANAGED_TSCONFIG}`));
|
|
86429
86605
|
await ensureUserReferencesManaged({
|
|
@@ -86459,7 +86635,7 @@ async function refreshManagedDenoImportMap(mode) {
|
|
|
86459
86635
|
for (const dir of WORKSPACE_IMPORT_DIRS) {
|
|
86460
86636
|
imports[`/${dir}/`] = `./${dir}/`;
|
|
86461
86637
|
}
|
|
86462
|
-
writeFileSync7(path21.join(
|
|
86638
|
+
writeFileSync7(path21.join(process23.cwd(), MANAGED_IMPORT_MAP), JSON.stringify({ imports }, null, 2) + `
|
|
86463
86639
|
`);
|
|
86464
86640
|
info(colors.green(`Refreshed ${MANAGED_IMPORT_MAP}`));
|
|
86465
86641
|
await ensureUserReferencesManaged({
|
|
@@ -86482,9 +86658,9 @@ async function refreshManagedDenoImportMap(mode) {
|
|
|
86482
86658
|
});
|
|
86483
86659
|
}
|
|
86484
86660
|
async function ensureUserReferencesManaged(opts) {
|
|
86485
|
-
const existing = [opts.file, ...opts.altFiles ?? []].map((f) => path21.join(
|
|
86661
|
+
const existing = [opts.file, ...opts.altFiles ?? []].map((f) => path21.join(process23.cwd(), f)).find((p) => existsSync12(p));
|
|
86486
86662
|
if (!existing) {
|
|
86487
|
-
const userPath = path21.join(
|
|
86663
|
+
const userPath = path21.join(process23.cwd(), opts.file);
|
|
86488
86664
|
writeFileSync7(userPath, JSON.stringify(opts.create, null, 2) + `
|
|
86489
86665
|
`);
|
|
86490
86666
|
info(colors.green(`Created ${opts.file} (references ${opts.token})`));
|
|
@@ -86533,7 +86709,7 @@ async function ensureUserReferencesManaged(opts) {
|
|
|
86533
86709
|
info(colors.green(`Linked ${existingName} → ${opts.token}`));
|
|
86534
86710
|
}
|
|
86535
86711
|
function ensureBunTypesAvailable() {
|
|
86536
|
-
const cwd =
|
|
86712
|
+
const cwd = process23.cwd();
|
|
86537
86713
|
if (existsSync12(path21.join(cwd, "node_modules", "bun-types"))) {
|
|
86538
86714
|
return true;
|
|
86539
86715
|
}
|
|
@@ -86555,7 +86731,7 @@ function ensureBunTypesAvailable() {
|
|
|
86555
86731
|
}
|
|
86556
86732
|
}
|
|
86557
86733
|
async function warnIfTsconfigStale(opts) {
|
|
86558
|
-
const cwd = opts?.cwd ??
|
|
86734
|
+
const cwd = opts?.cwd ?? process23.cwd();
|
|
86559
86735
|
const managedPath = path21.join(cwd, MANAGED_TSCONFIG);
|
|
86560
86736
|
if (!existsSync12(managedPath))
|
|
86561
86737
|
return;
|
|
@@ -86575,7 +86751,7 @@ async function warnIfTsconfigStale(opts) {
|
|
|
86575
86751
|
}
|
|
86576
86752
|
}
|
|
86577
86753
|
function emitTsconfigWarning(message) {
|
|
86578
|
-
|
|
86754
|
+
process23.stderr.write(`${colors.yellow(message)}
|
|
86579
86755
|
`);
|
|
86580
86756
|
}
|
|
86581
86757
|
var WORKSPACE_IMPORT_DIRS, MANAGED_TSCONFIG = "tsconfig.wmill.json", MANAGED_IMPORT_MAP = "import_map.wmill.json", MANAGED_NOTICE, TSCONFIG_HASH_PREFIX = "// wmill-tsconfig-hash: ", TSCONFIG_HASH_REGEX, LEGACY_GENERATED_TSCONFIGS, command30, tsconfig_default;
|
|
@@ -88061,7 +88237,7 @@ async function configureClientForWorkspace(opts, ws, resolver) {
|
|
|
88061
88237
|
// src/commands/protection-rules/utils.ts
|
|
88062
88238
|
init_colors2();
|
|
88063
88239
|
init_log();
|
|
88064
|
-
import
|
|
88240
|
+
import process21 from "node:process";
|
|
88065
88241
|
function outputResult2(opts, result) {
|
|
88066
88242
|
if (opts.jsonOutput) {
|
|
88067
88243
|
console.log(JSON.stringify(result));
|
|
@@ -88073,7 +88249,7 @@ function outputResult2(opts, result) {
|
|
|
88073
88249
|
}
|
|
88074
88250
|
function fail(opts, result) {
|
|
88075
88251
|
outputResult2(opts, { ...result, success: false });
|
|
88076
|
-
|
|
88252
|
+
process21.exit(1);
|
|
88077
88253
|
}
|
|
88078
88254
|
function describeEntry(entry) {
|
|
88079
88255
|
const n = ProtectionRulesConverter.normalizeEntry(entry);
|
|
@@ -88217,7 +88393,7 @@ await __promiseAll([
|
|
|
88217
88393
|
init_confirm(),
|
|
88218
88394
|
init_conf()
|
|
88219
88395
|
]);
|
|
88220
|
-
import
|
|
88396
|
+
import process22 from "node:process";
|
|
88221
88397
|
import { existsSync as existsSync10 } from "node:fs";
|
|
88222
88398
|
async function pushProtectionRules(opts, workspaceArg) {
|
|
88223
88399
|
if (opts.jsonOutput)
|
|
@@ -88298,7 +88474,7 @@ async function pushProtectionRules(opts, workspaceArg) {
|
|
|
88298
88474
|
workspaces: Object.fromEntries(wsPlans.map((w) => [w.ws, structuredPlan(w.plan)]))
|
|
88299
88475
|
}));
|
|
88300
88476
|
if (hadError)
|
|
88301
|
-
|
|
88477
|
+
process22.exit(1);
|
|
88302
88478
|
return;
|
|
88303
88479
|
}
|
|
88304
88480
|
if (!opts.jsonOutput) {
|
|
@@ -88312,7 +88488,7 @@ async function pushProtectionRules(opts, workspaceArg) {
|
|
|
88312
88488
|
error: "One or more workspaces failed (see errors above); the rest are in sync",
|
|
88313
88489
|
partialFailure: true
|
|
88314
88490
|
});
|
|
88315
|
-
|
|
88491
|
+
process22.exit(1);
|
|
88316
88492
|
}
|
|
88317
88493
|
if (!opts.dryRun) {
|
|
88318
88494
|
outputResult2(opts, {
|
|
@@ -88324,7 +88500,7 @@ async function pushProtectionRules(opts, workspaceArg) {
|
|
|
88324
88500
|
}
|
|
88325
88501
|
if (opts.dryRun) {
|
|
88326
88502
|
if (hadError)
|
|
88327
|
-
|
|
88503
|
+
process22.exit(1);
|
|
88328
88504
|
return;
|
|
88329
88505
|
}
|
|
88330
88506
|
for (const w of wsPlans) {
|
|
@@ -88333,7 +88509,7 @@ async function pushProtectionRules(opts, workspaceArg) {
|
|
|
88333
88509
|
}
|
|
88334
88510
|
}
|
|
88335
88511
|
const totalDeletes = changed.reduce((n, w) => n + w.plan.toDelete.length, 0);
|
|
88336
|
-
if (!opts.yes && !!
|
|
88512
|
+
if (!opts.yes && !!process22.stdin.isTTY) {
|
|
88337
88513
|
const confirmed = await Confirm.prompt({
|
|
88338
88514
|
message: totalDeletes > 0 ? `Apply these changes? This DELETES ${totalDeletes} protection rule(s) across ${changed.length} workspace(s).` : `Apply these changes to ${changed.length} workspace(s)?`,
|
|
88339
88515
|
default: totalDeletes === 0
|
|
@@ -88395,7 +88571,7 @@ async function pushProtectionRules(opts, workspaceArg) {
|
|
|
88395
88571
|
partialFailure: true,
|
|
88396
88572
|
...applied
|
|
88397
88573
|
});
|
|
88398
|
-
|
|
88574
|
+
process22.exit(1);
|
|
88399
88575
|
}
|
|
88400
88576
|
outputResult2(opts, {
|
|
88401
88577
|
success: true,
|
|
@@ -89433,7 +89609,7 @@ await __promiseAll([
|
|
|
89433
89609
|
init_workspace(),
|
|
89434
89610
|
init_resource_type()
|
|
89435
89611
|
]);
|
|
89436
|
-
import { stat as stat20, writeFile as writeFile22, rm as
|
|
89612
|
+
import { stat as stat20, writeFile as writeFile22, rm as rm6 } from "node:fs/promises";
|
|
89437
89613
|
|
|
89438
89614
|
// src/commands/init/template.ts
|
|
89439
89615
|
var NON_SCHEMA_KEYS = new Set([
|
|
@@ -89914,7 +90090,7 @@ await __promiseAll([
|
|
|
89914
90090
|
init_utils(),
|
|
89915
90091
|
init_freshness()
|
|
89916
90092
|
]);
|
|
89917
|
-
import { cp, mkdir as mkdir13, readdir as readdir11, stat as stat19, writeFile as writeFile21 } from "node:fs/promises";
|
|
90093
|
+
import { cp, mkdir as mkdir13, readdir as readdir11, rm as rm5, stat as stat19, writeFile as writeFile21 } from "node:fs/promises";
|
|
89918
90094
|
import { join as join20 } from "node:path";
|
|
89919
90095
|
var WMILL_INIT_AI_SKILLS_SOURCE_ENV = "WMILL_INIT_AI_SKILLS_SOURCE";
|
|
89920
90096
|
var WMILL_INIT_AI_AGENTS_SOURCE_ENV = "WMILL_INIT_AI_AGENTS_SOURCE";
|
|
@@ -89928,13 +90104,14 @@ async function writeAiGuidanceFiles(options) {
|
|
|
89928
90104
|
const skillMetadata = options.skillsSourcePath ? await readSkillMetadataFromDirectory(options.skillsSourcePath) : getGeneratedSkillMetadata();
|
|
89929
90105
|
const rawAgentsCliContent = options.agentsSourcePath != null ? await readTextFile(options.agentsSourcePath) : generateAgentsCliMdContent(buildSkillsReference(skillMetadata));
|
|
89930
90106
|
const agentsCliContent = injectPromptsHashMarker(rawAgentsCliContent, currentPromptsHash(nonDottedPaths));
|
|
89931
|
-
const agentsCliPath = join20(options.targetDir,
|
|
90107
|
+
const agentsCliPath = join20(options.targetDir, AGENTS_WMILL_FILENAME);
|
|
89932
90108
|
await writeFile21(agentsCliPath, agentsCliContent, "utf8");
|
|
89933
90109
|
const agentsCliWritten = true;
|
|
90110
|
+
const legacyManagedRemoved = await migrateLegacyManagedFile(options.targetDir);
|
|
89934
90111
|
const resolveMigration = cacheOnce(options.resolveAgentsMdMigration);
|
|
89935
90112
|
const agentsMdResult = await reconcileIncludingFile({
|
|
89936
90113
|
path: join20(options.targetDir, "AGENTS.md"),
|
|
89937
|
-
includeLine:
|
|
90114
|
+
includeLine: AGENTS_WMILL_INCLUDE_LINE,
|
|
89938
90115
|
skeleton: generateAgentsMdSkeleton(),
|
|
89939
90116
|
resolveMigration
|
|
89940
90117
|
});
|
|
@@ -89956,9 +90133,35 @@ async function writeAiGuidanceFiles(options) {
|
|
|
89956
90133
|
agentsMigration: agentsMdResult.migration,
|
|
89957
90134
|
claudeCreated: claudeMdResult.created,
|
|
89958
90135
|
claudeMigration: claudeMdResult.migration,
|
|
89959
|
-
skillCount: skillMetadata.length
|
|
90136
|
+
skillCount: skillMetadata.length,
|
|
90137
|
+
legacyManagedRemoved
|
|
89960
90138
|
};
|
|
89961
90139
|
}
|
|
90140
|
+
async function migrateLegacyManagedFile(targetDir) {
|
|
90141
|
+
for (const fileName of ["AGENTS.md", "CLAUDE.md"]) {
|
|
90142
|
+
const filePath = join20(targetDir, fileName);
|
|
90143
|
+
const existing = await readTextFile(filePath).catch(() => null);
|
|
90144
|
+
if (existing == null)
|
|
90145
|
+
continue;
|
|
90146
|
+
const rewritten = rewriteIncludeToken(existing, LEGACY_AGENTS_CLI_INCLUDE_LINE, AGENTS_WMILL_INCLUDE_LINE);
|
|
90147
|
+
if (rewritten !== existing) {
|
|
90148
|
+
await writeFile21(filePath, rewritten, "utf8");
|
|
90149
|
+
}
|
|
90150
|
+
}
|
|
90151
|
+
const legacyPath = join20(targetDir, LEGACY_AGENTS_CLI_FILENAME);
|
|
90152
|
+
const legacyExists = await stat19(legacyPath).catch(() => null) != null;
|
|
90153
|
+
if (legacyExists) {
|
|
90154
|
+
await rm5(legacyPath, { force: true });
|
|
90155
|
+
}
|
|
90156
|
+
return legacyExists;
|
|
90157
|
+
}
|
|
90158
|
+
function escapeRegExp(value) {
|
|
90159
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
90160
|
+
}
|
|
90161
|
+
function rewriteIncludeToken(content, from, to) {
|
|
90162
|
+
const re = new RegExp(`(?<=^|\\s)${escapeRegExp(from)}(?=\\s|$)`, "gm");
|
|
90163
|
+
return content.replace(re, to);
|
|
90164
|
+
}
|
|
89962
90165
|
function cacheOnce(resolver) {
|
|
89963
90166
|
if (!resolver)
|
|
89964
90167
|
return;
|
|
@@ -90159,10 +90362,13 @@ async function refreshPrompts(opts) {
|
|
|
90159
90362
|
return "skip";
|
|
90160
90363
|
}
|
|
90161
90364
|
});
|
|
90162
|
-
info(colors.green("Refreshed AGENTS.
|
|
90365
|
+
info(colors.green("Refreshed AGENTS.wmill.md"));
|
|
90366
|
+
if (result.legacyManagedRemoved) {
|
|
90367
|
+
info(colors.yellow("Migrated legacy AGENTS.cli.md → AGENTS.wmill.md (removed the old file and rewrote any @AGENTS.cli.md include)."));
|
|
90368
|
+
}
|
|
90163
90369
|
reportReconciliation({
|
|
90164
90370
|
file: "AGENTS.md",
|
|
90165
|
-
includeLine: "@AGENTS.
|
|
90371
|
+
includeLine: "@AGENTS.wmill.md",
|
|
90166
90372
|
created: result.agentsCreated,
|
|
90167
90373
|
migration: result.agentsMigration
|
|
90168
90374
|
});
|
|
@@ -90231,7 +90437,7 @@ async function promptMigration() {
|
|
|
90231
90437
|
async function promptsAction(opts) {
|
|
90232
90438
|
await refreshPrompts({ yes: opts.yes === true });
|
|
90233
90439
|
}
|
|
90234
|
-
var command29 = new Command().description("Refresh AGENTS.
|
|
90440
|
+
var command29 = new Command().description("Refresh AGENTS.wmill.md and managed skills. User-owned AGENTS.md and CLAUDE.md are never overwritten unless you opt in.").option("--yes", "Non-interactive: append the @AGENTS.wmill.md include to an existing AGENTS.md / CLAUDE.md without prompting. Without it, a non-interactive run leaves an unlinked file untouched.").action(promptsAction);
|
|
90235
90441
|
var prompts_default = command29;
|
|
90236
90442
|
|
|
90237
90443
|
// src/commands/init/init.ts
|
|
@@ -90349,8 +90555,8 @@ async function initAction(opts) {
|
|
|
90349
90555
|
});
|
|
90350
90556
|
if (choice === "cancel") {
|
|
90351
90557
|
try {
|
|
90352
|
-
await
|
|
90353
|
-
await
|
|
90558
|
+
await rm6("wmill.yaml");
|
|
90559
|
+
await rm6("wmill-lock.yaml");
|
|
90354
90560
|
} catch {}
|
|
90355
90561
|
info("Init cancelled");
|
|
90356
90562
|
process.exit(0);
|
|
@@ -90403,7 +90609,7 @@ var init_default = command31;
|
|
|
90403
90609
|
// src/commands/refresh/refresh.ts
|
|
90404
90610
|
init_mod3();
|
|
90405
90611
|
await init_tsconfig();
|
|
90406
|
-
var command32 = new Command().description("Refresh wmill-managed project files (AGENTS.
|
|
90612
|
+
var command32 = new Command().description("Refresh wmill-managed project files (AGENTS.wmill.md, skills, tsconfig.wmill.json)").command("prompts", prompts_default).command("tsconfig", tsconfig_default);
|
|
90407
90613
|
var refresh_default = command32;
|
|
90408
90614
|
|
|
90409
90615
|
// src/main.ts
|