flowcat 1.6.3 → 1.7.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/core/config.ts +43 -2
- package/core/constants.ts +1 -0
- package/core/gitignore.ts +1 -1
- package/core/workspace.ts +28 -8
- package/dist/fcat.mjs +449 -14
- package/dist/fweb +0 -0
- package/dist/index.mjs +451 -16
- package/package.json +3 -2
package/core/config.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { access, mkdir } from "node:fs/promises";
|
|
1
|
+
import { access, mkdir, readFile } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { parse as parseEnv } from "dotenv";
|
|
6
|
+
|
|
7
|
+
import { APP_NAME, ENV_FILE } from "./constants";
|
|
6
8
|
import { readJsonFile, writeJsonAtomic } from "./json";
|
|
7
9
|
|
|
8
10
|
export type PluginEntry = {
|
|
@@ -91,7 +93,33 @@ export const resolveAutoCommitEnabled = async (workspaceRoot: string): Promise<b
|
|
|
91
93
|
return globalConfig.autoCommit ?? false;
|
|
92
94
|
};
|
|
93
95
|
|
|
96
|
+
export const resolveWorkspaceEnvPath = (workspaceRoot: string): string => {
|
|
97
|
+
return path.join(workspaceRoot, ENV_FILE);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const resolveGlobalEnvPath = (): string => {
|
|
101
|
+
const configHome = process.env.XDG_CONFIG_HOME ?? path.join(homedir(), ".config");
|
|
102
|
+
return path.join(configHome, APP_NAME, ENV_FILE);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Read and parse an env file, returning empty object if file doesn't exist
|
|
107
|
+
*/
|
|
108
|
+
export const readEnvFile = async (filePath: string): Promise<Record<string, string>> => {
|
|
109
|
+
if (!(await configFileExists(filePath))) {
|
|
110
|
+
return {};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const content = await readFile(filePath, "utf8");
|
|
115
|
+
return parseEnv(content);
|
|
116
|
+
} catch {
|
|
117
|
+
return {};
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
94
121
|
export const resolveGithubToken = async (workspaceRoot: string): Promise<string | null> => {
|
|
122
|
+
// 1. Check environment variables first
|
|
95
123
|
if (process.env.FLOWCAT_GITHUB_TOKEN) {
|
|
96
124
|
return process.env.FLOWCAT_GITHUB_TOKEN;
|
|
97
125
|
}
|
|
@@ -100,6 +128,19 @@ export const resolveGithubToken = async (workspaceRoot: string): Promise<string
|
|
|
100
128
|
return process.env.IL_GITHUB_TOKEN;
|
|
101
129
|
}
|
|
102
130
|
|
|
131
|
+
// 2. Check workspace .env file
|
|
132
|
+
const workspaceEnv = await readEnvFile(resolveWorkspaceEnvPath(workspaceRoot));
|
|
133
|
+
if (workspaceEnv.GITHUB_TOKEN) {
|
|
134
|
+
return workspaceEnv.GITHUB_TOKEN;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 3. Check global .env file
|
|
138
|
+
const globalEnv = await readEnvFile(resolveGlobalEnvPath());
|
|
139
|
+
if (globalEnv.GITHUB_TOKEN) {
|
|
140
|
+
return globalEnv.GITHUB_TOKEN;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 4. Fallback to config.json (for backwards compatibility)
|
|
103
144
|
const workspaceConfig = await readConfigFile(resolveWorkspaceConfigPath(workspaceRoot));
|
|
104
145
|
if (workspaceConfig.github?.token) {
|
|
105
146
|
return workspaceConfig.github.token;
|
package/core/constants.ts
CHANGED
|
@@ -4,5 +4,6 @@ export const LOCK_DIR = ".lock";
|
|
|
4
4
|
export const LOCK_FILE = "store.lock";
|
|
5
5
|
export const TASKS_DIR = "tasks";
|
|
6
6
|
export const PLUGINS_DIR = "plugins";
|
|
7
|
+
export const ENV_FILE = ".env";
|
|
7
8
|
|
|
8
9
|
export const STATUS_ORDER = ["backlog", "active", "paused", "completed", "cancelled"] as const;
|
package/core/gitignore.ts
CHANGED
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import { APP_DIR } from "./constants";
|
|
5
5
|
|
|
6
|
-
const ignoredEntries = [`${APP_DIR}/.lock
|
|
6
|
+
const ignoredEntries = [`${APP_DIR}/.lock/`];
|
|
7
7
|
|
|
8
8
|
export const ensureWorkspaceIgnored = async (repoRoot: string): Promise<boolean> => {
|
|
9
9
|
const gitignorePath = path.join(repoRoot, ".gitignore");
|
package/core/workspace.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { access, mkdir } from "node:fs/promises";
|
|
1
|
+
import { access, mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
5
5
|
import { configFileExists, resolveGlobalConfigPath, resolveWorkspaceConfigPath } from "./config";
|
|
6
|
-
import { APP_DIR, APP_NAME, LOCK_DIR, PLUGINS_DIR, STATUS_ORDER, TASKS_DIR } from "./constants";
|
|
6
|
+
import { APP_DIR, APP_NAME, ENV_FILE, LOCK_DIR, PLUGINS_DIR, STATUS_ORDER, TASKS_DIR } from "./constants";
|
|
7
7
|
import { writeJsonAtomic } from "./json";
|
|
8
8
|
|
|
9
9
|
export type WorkspaceKind = "explicit" | "global" | "repo";
|
|
@@ -106,22 +106,24 @@ export const ensureWorkspaceLayout = async (workspaceRoot: string): Promise<void
|
|
|
106
106
|
),
|
|
107
107
|
);
|
|
108
108
|
|
|
109
|
-
// Create
|
|
110
|
-
await
|
|
109
|
+
// Create package.json for TypeScript plugin development
|
|
110
|
+
await ensureWorkspacePackageJson(workspaceRoot);
|
|
111
|
+
// Create .gitignore for workspace-local files
|
|
112
|
+
await ensureWorkspaceGitignore(workspaceRoot);
|
|
111
113
|
};
|
|
112
114
|
|
|
113
115
|
/**
|
|
114
|
-
* Ensure
|
|
116
|
+
* Ensure workspace has a package.json for TypeScript plugin development
|
|
115
117
|
*/
|
|
116
|
-
export const
|
|
117
|
-
const packageJsonPath = path.join(workspaceRoot,
|
|
118
|
+
export const ensureWorkspacePackageJson = async (workspaceRoot: string): Promise<void> => {
|
|
119
|
+
const packageJsonPath = path.join(workspaceRoot, "package.json");
|
|
118
120
|
|
|
119
121
|
if (await exists(packageJsonPath)) {
|
|
120
122
|
return;
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
const packageJson = {
|
|
124
|
-
name: "flowcat-
|
|
126
|
+
name: "flowcat-workspace",
|
|
125
127
|
type: "module",
|
|
126
128
|
private: true,
|
|
127
129
|
dependencies: {
|
|
@@ -131,3 +133,21 @@ export const ensurePluginsPackageJson = async (workspaceRoot: string): Promise<v
|
|
|
131
133
|
|
|
132
134
|
await writeJsonAtomic(packageJsonPath, packageJson);
|
|
133
135
|
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Ensure workspace has a .gitignore for local files that shouldn't be committed
|
|
139
|
+
*/
|
|
140
|
+
export const ensureWorkspaceGitignore = async (workspaceRoot: string): Promise<void> => {
|
|
141
|
+
const gitignorePath = path.join(workspaceRoot, ".gitignore");
|
|
142
|
+
|
|
143
|
+
if (await exists(gitignorePath)) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const gitignoreContent = `# Flowcat workspace local files
|
|
148
|
+
${ENV_FILE}
|
|
149
|
+
${LOCK_DIR}/
|
|
150
|
+
`;
|
|
151
|
+
|
|
152
|
+
await writeFile(gitignorePath, gitignoreContent, "utf8");
|
|
153
|
+
};
|
package/dist/fcat.mjs
CHANGED
|
@@ -27642,6 +27642,401 @@ var init_chunk_fcedq94e = __esm(async () => {
|
|
|
27642
27642
|
import_react_devtools_core.default.connectToDevTools();
|
|
27643
27643
|
});
|
|
27644
27644
|
|
|
27645
|
+
// ../../node_modules/.bun/dotenv@17.2.3/node_modules/dotenv/package.json
|
|
27646
|
+
var require_package = __commonJS((exports, module2) => {
|
|
27647
|
+
module2.exports = {
|
|
27648
|
+
name: "dotenv",
|
|
27649
|
+
version: "17.2.3",
|
|
27650
|
+
description: "Loads environment variables from .env file",
|
|
27651
|
+
main: "lib/main.js",
|
|
27652
|
+
types: "lib/main.d.ts",
|
|
27653
|
+
exports: {
|
|
27654
|
+
".": {
|
|
27655
|
+
types: "./lib/main.d.ts",
|
|
27656
|
+
require: "./lib/main.js",
|
|
27657
|
+
default: "./lib/main.js"
|
|
27658
|
+
},
|
|
27659
|
+
"./config": "./config.js",
|
|
27660
|
+
"./config.js": "./config.js",
|
|
27661
|
+
"./lib/env-options": "./lib/env-options.js",
|
|
27662
|
+
"./lib/env-options.js": "./lib/env-options.js",
|
|
27663
|
+
"./lib/cli-options": "./lib/cli-options.js",
|
|
27664
|
+
"./lib/cli-options.js": "./lib/cli-options.js",
|
|
27665
|
+
"./package.json": "./package.json"
|
|
27666
|
+
},
|
|
27667
|
+
scripts: {
|
|
27668
|
+
"dts-check": "tsc --project tests/types/tsconfig.json",
|
|
27669
|
+
lint: "standard",
|
|
27670
|
+
pretest: "npm run lint && npm run dts-check",
|
|
27671
|
+
test: "tap run tests/**/*.js --allow-empty-coverage --disable-coverage --timeout=60000",
|
|
27672
|
+
"test:coverage": "tap run tests/**/*.js --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
|
|
27673
|
+
prerelease: "npm test",
|
|
27674
|
+
release: "standard-version"
|
|
27675
|
+
},
|
|
27676
|
+
repository: {
|
|
27677
|
+
type: "git",
|
|
27678
|
+
url: "git://github.com/motdotla/dotenv.git"
|
|
27679
|
+
},
|
|
27680
|
+
homepage: "https://github.com/motdotla/dotenv#readme",
|
|
27681
|
+
funding: "https://dotenvx.com",
|
|
27682
|
+
keywords: [
|
|
27683
|
+
"dotenv",
|
|
27684
|
+
"env",
|
|
27685
|
+
".env",
|
|
27686
|
+
"environment",
|
|
27687
|
+
"variables",
|
|
27688
|
+
"config",
|
|
27689
|
+
"settings"
|
|
27690
|
+
],
|
|
27691
|
+
readmeFilename: "README.md",
|
|
27692
|
+
license: "BSD-2-Clause",
|
|
27693
|
+
devDependencies: {
|
|
27694
|
+
"@types/node": "^18.11.3",
|
|
27695
|
+
decache: "^4.6.2",
|
|
27696
|
+
sinon: "^14.0.1",
|
|
27697
|
+
standard: "^17.0.0",
|
|
27698
|
+
"standard-version": "^9.5.0",
|
|
27699
|
+
tap: "^19.2.0",
|
|
27700
|
+
typescript: "^4.8.4"
|
|
27701
|
+
},
|
|
27702
|
+
engines: {
|
|
27703
|
+
node: ">=12"
|
|
27704
|
+
},
|
|
27705
|
+
browser: {
|
|
27706
|
+
fs: false
|
|
27707
|
+
}
|
|
27708
|
+
};
|
|
27709
|
+
});
|
|
27710
|
+
|
|
27711
|
+
// ../../node_modules/.bun/dotenv@17.2.3/node_modules/dotenv/lib/main.js
|
|
27712
|
+
var require_main = __commonJS((exports, module2) => {
|
|
27713
|
+
var fs2 = __require("fs");
|
|
27714
|
+
var path2 = __require("path");
|
|
27715
|
+
var os2 = __require("os");
|
|
27716
|
+
var crypto = __require("crypto");
|
|
27717
|
+
var packageJson = require_package();
|
|
27718
|
+
var version = packageJson.version;
|
|
27719
|
+
var TIPS = [
|
|
27720
|
+
"\uD83D\uDD10 encrypt with Dotenvx: https://dotenvx.com",
|
|
27721
|
+
"\uD83D\uDD10 prevent committing .env to code: https://dotenvx.com/precommit",
|
|
27722
|
+
"\uD83D\uDD10 prevent building .env in docker: https://dotenvx.com/prebuild",
|
|
27723
|
+
"\uD83D\uDCE1 add observability to secrets: https://dotenvx.com/ops",
|
|
27724
|
+
"\uD83D\uDC65 sync secrets across teammates & machines: https://dotenvx.com/ops",
|
|
27725
|
+
"\uD83D\uDDC2\uFE0F backup and recover secrets: https://dotenvx.com/ops",
|
|
27726
|
+
"\u2705 audit secrets and track compliance: https://dotenvx.com/ops",
|
|
27727
|
+
"\uD83D\uDD04 add secrets lifecycle management: https://dotenvx.com/ops",
|
|
27728
|
+
"\uD83D\uDD11 add access controls to secrets: https://dotenvx.com/ops",
|
|
27729
|
+
"\uD83D\uDEE0\uFE0F run anywhere with `dotenvx run -- yourcommand`",
|
|
27730
|
+
"\u2699\uFE0F specify custom .env file path with { path: '/custom/path/.env' }",
|
|
27731
|
+
"\u2699\uFE0F enable debug logging with { debug: true }",
|
|
27732
|
+
"\u2699\uFE0F override existing env vars with { override: true }",
|
|
27733
|
+
"\u2699\uFE0F suppress all logs with { quiet: true }",
|
|
27734
|
+
"\u2699\uFE0F write to custom object with { processEnv: myObject }",
|
|
27735
|
+
"\u2699\uFE0F load multiple .env files with { path: ['.env.local', '.env'] }"
|
|
27736
|
+
];
|
|
27737
|
+
function _getRandomTip() {
|
|
27738
|
+
return TIPS[Math.floor(Math.random() * TIPS.length)];
|
|
27739
|
+
}
|
|
27740
|
+
function parseBoolean(value) {
|
|
27741
|
+
if (typeof value === "string") {
|
|
27742
|
+
return !["false", "0", "no", "off", ""].includes(value.toLowerCase());
|
|
27743
|
+
}
|
|
27744
|
+
return Boolean(value);
|
|
27745
|
+
}
|
|
27746
|
+
function supportsAnsi() {
|
|
27747
|
+
return process.stdout.isTTY;
|
|
27748
|
+
}
|
|
27749
|
+
function dim2(text) {
|
|
27750
|
+
return supportsAnsi() ? `\x1B[2m${text}\x1B[0m` : text;
|
|
27751
|
+
}
|
|
27752
|
+
var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
|
|
27753
|
+
function parse2(src) {
|
|
27754
|
+
const obj = {};
|
|
27755
|
+
let lines = src.toString();
|
|
27756
|
+
lines = lines.replace(/\r\n?/mg, `
|
|
27757
|
+
`);
|
|
27758
|
+
let match;
|
|
27759
|
+
while ((match = LINE.exec(lines)) != null) {
|
|
27760
|
+
const key = match[1];
|
|
27761
|
+
let value = match[2] || "";
|
|
27762
|
+
value = value.trim();
|
|
27763
|
+
const maybeQuote = value[0];
|
|
27764
|
+
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
|
|
27765
|
+
if (maybeQuote === '"') {
|
|
27766
|
+
value = value.replace(/\\n/g, `
|
|
27767
|
+
`);
|
|
27768
|
+
value = value.replace(/\\r/g, "\r");
|
|
27769
|
+
}
|
|
27770
|
+
obj[key] = value;
|
|
27771
|
+
}
|
|
27772
|
+
return obj;
|
|
27773
|
+
}
|
|
27774
|
+
function _parseVault(options) {
|
|
27775
|
+
options = options || {};
|
|
27776
|
+
const vaultPath = _vaultPath(options);
|
|
27777
|
+
options.path = vaultPath;
|
|
27778
|
+
const result = DotenvModule.configDotenv(options);
|
|
27779
|
+
if (!result.parsed) {
|
|
27780
|
+
const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
|
|
27781
|
+
err.code = "MISSING_DATA";
|
|
27782
|
+
throw err;
|
|
27783
|
+
}
|
|
27784
|
+
const keys = _dotenvKey(options).split(",");
|
|
27785
|
+
const length = keys.length;
|
|
27786
|
+
let decrypted;
|
|
27787
|
+
for (let i = 0;i < length; i++) {
|
|
27788
|
+
try {
|
|
27789
|
+
const key = keys[i].trim();
|
|
27790
|
+
const attrs = _instructions(result, key);
|
|
27791
|
+
decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
|
|
27792
|
+
break;
|
|
27793
|
+
} catch (error) {
|
|
27794
|
+
if (i + 1 >= length) {
|
|
27795
|
+
throw error;
|
|
27796
|
+
}
|
|
27797
|
+
}
|
|
27798
|
+
}
|
|
27799
|
+
return DotenvModule.parse(decrypted);
|
|
27800
|
+
}
|
|
27801
|
+
function _warn(message) {
|
|
27802
|
+
console.error(`[dotenv@${version}][WARN] ${message}`);
|
|
27803
|
+
}
|
|
27804
|
+
function _debug(message) {
|
|
27805
|
+
console.log(`[dotenv@${version}][DEBUG] ${message}`);
|
|
27806
|
+
}
|
|
27807
|
+
function _log(message) {
|
|
27808
|
+
console.log(`[dotenv@${version}] ${message}`);
|
|
27809
|
+
}
|
|
27810
|
+
function _dotenvKey(options) {
|
|
27811
|
+
if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
|
|
27812
|
+
return options.DOTENV_KEY;
|
|
27813
|
+
}
|
|
27814
|
+
if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
|
|
27815
|
+
return process.env.DOTENV_KEY;
|
|
27816
|
+
}
|
|
27817
|
+
return "";
|
|
27818
|
+
}
|
|
27819
|
+
function _instructions(result, dotenvKey) {
|
|
27820
|
+
let uri;
|
|
27821
|
+
try {
|
|
27822
|
+
uri = new URL(dotenvKey);
|
|
27823
|
+
} catch (error) {
|
|
27824
|
+
if (error.code === "ERR_INVALID_URL") {
|
|
27825
|
+
const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
|
|
27826
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
27827
|
+
throw err;
|
|
27828
|
+
}
|
|
27829
|
+
throw error;
|
|
27830
|
+
}
|
|
27831
|
+
const key = uri.password;
|
|
27832
|
+
if (!key) {
|
|
27833
|
+
const err = new Error("INVALID_DOTENV_KEY: Missing key part");
|
|
27834
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
27835
|
+
throw err;
|
|
27836
|
+
}
|
|
27837
|
+
const environment = uri.searchParams.get("environment");
|
|
27838
|
+
if (!environment) {
|
|
27839
|
+
const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
|
|
27840
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
27841
|
+
throw err;
|
|
27842
|
+
}
|
|
27843
|
+
const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
|
|
27844
|
+
const ciphertext = result.parsed[environmentKey];
|
|
27845
|
+
if (!ciphertext) {
|
|
27846
|
+
const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
|
|
27847
|
+
err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
|
|
27848
|
+
throw err;
|
|
27849
|
+
}
|
|
27850
|
+
return { ciphertext, key };
|
|
27851
|
+
}
|
|
27852
|
+
function _vaultPath(options) {
|
|
27853
|
+
let possibleVaultPath = null;
|
|
27854
|
+
if (options && options.path && options.path.length > 0) {
|
|
27855
|
+
if (Array.isArray(options.path)) {
|
|
27856
|
+
for (const filepath of options.path) {
|
|
27857
|
+
if (fs2.existsSync(filepath)) {
|
|
27858
|
+
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
27859
|
+
}
|
|
27860
|
+
}
|
|
27861
|
+
} else {
|
|
27862
|
+
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
|
|
27863
|
+
}
|
|
27864
|
+
} else {
|
|
27865
|
+
possibleVaultPath = path2.resolve(process.cwd(), ".env.vault");
|
|
27866
|
+
}
|
|
27867
|
+
if (fs2.existsSync(possibleVaultPath)) {
|
|
27868
|
+
return possibleVaultPath;
|
|
27869
|
+
}
|
|
27870
|
+
return null;
|
|
27871
|
+
}
|
|
27872
|
+
function _resolveHome(envPath) {
|
|
27873
|
+
return envPath[0] === "~" ? path2.join(os2.homedir(), envPath.slice(1)) : envPath;
|
|
27874
|
+
}
|
|
27875
|
+
function _configVault(options) {
|
|
27876
|
+
const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
|
|
27877
|
+
const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options && options.quiet);
|
|
27878
|
+
if (debug || !quiet) {
|
|
27879
|
+
_log("Loading env from encrypted .env.vault");
|
|
27880
|
+
}
|
|
27881
|
+
const parsed = DotenvModule._parseVault(options);
|
|
27882
|
+
let processEnv = process.env;
|
|
27883
|
+
if (options && options.processEnv != null) {
|
|
27884
|
+
processEnv = options.processEnv;
|
|
27885
|
+
}
|
|
27886
|
+
DotenvModule.populate(processEnv, parsed, options);
|
|
27887
|
+
return { parsed };
|
|
27888
|
+
}
|
|
27889
|
+
function configDotenv(options) {
|
|
27890
|
+
const dotenvPath = path2.resolve(process.cwd(), ".env");
|
|
27891
|
+
let encoding = "utf8";
|
|
27892
|
+
let processEnv = process.env;
|
|
27893
|
+
if (options && options.processEnv != null) {
|
|
27894
|
+
processEnv = options.processEnv;
|
|
27895
|
+
}
|
|
27896
|
+
let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || options && options.debug);
|
|
27897
|
+
let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options && options.quiet);
|
|
27898
|
+
if (options && options.encoding) {
|
|
27899
|
+
encoding = options.encoding;
|
|
27900
|
+
} else {
|
|
27901
|
+
if (debug) {
|
|
27902
|
+
_debug("No encoding is specified. UTF-8 is used by default");
|
|
27903
|
+
}
|
|
27904
|
+
}
|
|
27905
|
+
let optionPaths = [dotenvPath];
|
|
27906
|
+
if (options && options.path) {
|
|
27907
|
+
if (!Array.isArray(options.path)) {
|
|
27908
|
+
optionPaths = [_resolveHome(options.path)];
|
|
27909
|
+
} else {
|
|
27910
|
+
optionPaths = [];
|
|
27911
|
+
for (const filepath of options.path) {
|
|
27912
|
+
optionPaths.push(_resolveHome(filepath));
|
|
27913
|
+
}
|
|
27914
|
+
}
|
|
27915
|
+
}
|
|
27916
|
+
let lastError;
|
|
27917
|
+
const parsedAll = {};
|
|
27918
|
+
for (const path3 of optionPaths) {
|
|
27919
|
+
try {
|
|
27920
|
+
const parsed = DotenvModule.parse(fs2.readFileSync(path3, { encoding }));
|
|
27921
|
+
DotenvModule.populate(parsedAll, parsed, options);
|
|
27922
|
+
} catch (e) {
|
|
27923
|
+
if (debug) {
|
|
27924
|
+
_debug(`Failed to load ${path3} ${e.message}`);
|
|
27925
|
+
}
|
|
27926
|
+
lastError = e;
|
|
27927
|
+
}
|
|
27928
|
+
}
|
|
27929
|
+
const populated = DotenvModule.populate(processEnv, parsedAll, options);
|
|
27930
|
+
debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug);
|
|
27931
|
+
quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet);
|
|
27932
|
+
if (debug || !quiet) {
|
|
27933
|
+
const keysCount = Object.keys(populated).length;
|
|
27934
|
+
const shortPaths = [];
|
|
27935
|
+
for (const filePath of optionPaths) {
|
|
27936
|
+
try {
|
|
27937
|
+
const relative = path2.relative(process.cwd(), filePath);
|
|
27938
|
+
shortPaths.push(relative);
|
|
27939
|
+
} catch (e) {
|
|
27940
|
+
if (debug) {
|
|
27941
|
+
_debug(`Failed to load ${filePath} ${e.message}`);
|
|
27942
|
+
}
|
|
27943
|
+
lastError = e;
|
|
27944
|
+
}
|
|
27945
|
+
}
|
|
27946
|
+
_log(`injecting env (${keysCount}) from ${shortPaths.join(",")} ${dim2(`-- tip: ${_getRandomTip()}`)}`);
|
|
27947
|
+
}
|
|
27948
|
+
if (lastError) {
|
|
27949
|
+
return { parsed: parsedAll, error: lastError };
|
|
27950
|
+
} else {
|
|
27951
|
+
return { parsed: parsedAll };
|
|
27952
|
+
}
|
|
27953
|
+
}
|
|
27954
|
+
function config(options) {
|
|
27955
|
+
if (_dotenvKey(options).length === 0) {
|
|
27956
|
+
return DotenvModule.configDotenv(options);
|
|
27957
|
+
}
|
|
27958
|
+
const vaultPath = _vaultPath(options);
|
|
27959
|
+
if (!vaultPath) {
|
|
27960
|
+
_warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
|
|
27961
|
+
return DotenvModule.configDotenv(options);
|
|
27962
|
+
}
|
|
27963
|
+
return DotenvModule._configVault(options);
|
|
27964
|
+
}
|
|
27965
|
+
function decrypt(encrypted, keyStr) {
|
|
27966
|
+
const key = Buffer.from(keyStr.slice(-64), "hex");
|
|
27967
|
+
let ciphertext = Buffer.from(encrypted, "base64");
|
|
27968
|
+
const nonce = ciphertext.subarray(0, 12);
|
|
27969
|
+
const authTag = ciphertext.subarray(-16);
|
|
27970
|
+
ciphertext = ciphertext.subarray(12, -16);
|
|
27971
|
+
try {
|
|
27972
|
+
const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
|
|
27973
|
+
aesgcm.setAuthTag(authTag);
|
|
27974
|
+
return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
|
|
27975
|
+
} catch (error) {
|
|
27976
|
+
const isRange = error instanceof RangeError;
|
|
27977
|
+
const invalidKeyLength = error.message === "Invalid key length";
|
|
27978
|
+
const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
|
|
27979
|
+
if (isRange || invalidKeyLength) {
|
|
27980
|
+
const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
|
|
27981
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
27982
|
+
throw err;
|
|
27983
|
+
} else if (decryptionFailed) {
|
|
27984
|
+
const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
|
|
27985
|
+
err.code = "DECRYPTION_FAILED";
|
|
27986
|
+
throw err;
|
|
27987
|
+
} else {
|
|
27988
|
+
throw error;
|
|
27989
|
+
}
|
|
27990
|
+
}
|
|
27991
|
+
}
|
|
27992
|
+
function populate(processEnv, parsed, options = {}) {
|
|
27993
|
+
const debug = Boolean(options && options.debug);
|
|
27994
|
+
const override = Boolean(options && options.override);
|
|
27995
|
+
const populated = {};
|
|
27996
|
+
if (typeof parsed !== "object") {
|
|
27997
|
+
const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
|
|
27998
|
+
err.code = "OBJECT_REQUIRED";
|
|
27999
|
+
throw err;
|
|
28000
|
+
}
|
|
28001
|
+
for (const key of Object.keys(parsed)) {
|
|
28002
|
+
if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
|
|
28003
|
+
if (override === true) {
|
|
28004
|
+
processEnv[key] = parsed[key];
|
|
28005
|
+
populated[key] = parsed[key];
|
|
28006
|
+
}
|
|
28007
|
+
if (debug) {
|
|
28008
|
+
if (override === true) {
|
|
28009
|
+
_debug(`"${key}" is already defined and WAS overwritten`);
|
|
28010
|
+
} else {
|
|
28011
|
+
_debug(`"${key}" is already defined and was NOT overwritten`);
|
|
28012
|
+
}
|
|
28013
|
+
}
|
|
28014
|
+
} else {
|
|
28015
|
+
processEnv[key] = parsed[key];
|
|
28016
|
+
populated[key] = parsed[key];
|
|
28017
|
+
}
|
|
28018
|
+
}
|
|
28019
|
+
return populated;
|
|
28020
|
+
}
|
|
28021
|
+
var DotenvModule = {
|
|
28022
|
+
configDotenv,
|
|
28023
|
+
_configVault,
|
|
28024
|
+
_parseVault,
|
|
28025
|
+
config,
|
|
28026
|
+
decrypt,
|
|
28027
|
+
parse: parse2,
|
|
28028
|
+
populate
|
|
28029
|
+
};
|
|
28030
|
+
exports.configDotenv = DotenvModule.configDotenv;
|
|
28031
|
+
exports._configVault = DotenvModule._configVault;
|
|
28032
|
+
exports._parseVault = DotenvModule._parseVault;
|
|
28033
|
+
exports.config = DotenvModule.config;
|
|
28034
|
+
exports.decrypt = DotenvModule.decrypt;
|
|
28035
|
+
exports.parse = DotenvModule.parse;
|
|
28036
|
+
exports.populate = DotenvModule.populate;
|
|
28037
|
+
module2.exports = DotenvModule;
|
|
28038
|
+
});
|
|
28039
|
+
|
|
27645
28040
|
// ../../node_modules/.bun/imurmurhash@0.1.4/node_modules/imurmurhash/imurmurhash.js
|
|
27646
28041
|
var require_imurmurhash = __commonJS((exports, module2) => {
|
|
27647
28042
|
(function() {
|
|
@@ -28670,8 +29065,8 @@ GFS4: `);
|
|
|
28670
29065
|
fs3.createReadStream = createReadStream;
|
|
28671
29066
|
fs3.createWriteStream = createWriteStream;
|
|
28672
29067
|
var fs$readFile = fs3.readFile;
|
|
28673
|
-
fs3.readFile =
|
|
28674
|
-
function
|
|
29068
|
+
fs3.readFile = readFile3;
|
|
29069
|
+
function readFile3(path3, options, cb) {
|
|
28675
29070
|
if (typeof options === "function")
|
|
28676
29071
|
cb = options, options = null;
|
|
28677
29072
|
return go$readFile(path3, options, cb);
|
|
@@ -72268,7 +72663,8 @@ var coerce = {
|
|
|
72268
72663
|
};
|
|
72269
72664
|
var NEVER = INVALID;
|
|
72270
72665
|
// ../../packages/core/src/config.ts
|
|
72271
|
-
|
|
72666
|
+
var import_dotenv = __toESM(require_main(), 1);
|
|
72667
|
+
import { access, mkdir, readFile as readFile2 } from "fs/promises";
|
|
72272
72668
|
import { homedir } from "os";
|
|
72273
72669
|
import path2 from "path";
|
|
72274
72670
|
|
|
@@ -72279,6 +72675,7 @@ var LOCK_DIR = ".lock";
|
|
|
72279
72675
|
var LOCK_FILE = "store.lock";
|
|
72280
72676
|
var TASKS_DIR = "tasks";
|
|
72281
72677
|
var PLUGINS_DIR = "plugins";
|
|
72678
|
+
var ENV_FILE = ".env";
|
|
72282
72679
|
var STATUS_ORDER = ["backlog", "active", "paused", "completed", "cancelled"];
|
|
72283
72680
|
|
|
72284
72681
|
// ../../packages/core/src/json.ts
|
|
@@ -72326,6 +72723,24 @@ var updateConfigFile = async (filePath, updater) => {
|
|
|
72326
72723
|
await writeConfigFile(filePath, next);
|
|
72327
72724
|
return next;
|
|
72328
72725
|
};
|
|
72726
|
+
var resolveWorkspaceEnvPath = (workspaceRoot) => {
|
|
72727
|
+
return path2.join(workspaceRoot, ENV_FILE);
|
|
72728
|
+
};
|
|
72729
|
+
var resolveGlobalEnvPath = () => {
|
|
72730
|
+
const configHome = process.env.XDG_CONFIG_HOME ?? path2.join(homedir(), ".config");
|
|
72731
|
+
return path2.join(configHome, APP_NAME, ENV_FILE);
|
|
72732
|
+
};
|
|
72733
|
+
var readEnvFile = async (filePath) => {
|
|
72734
|
+
if (!await configFileExists(filePath)) {
|
|
72735
|
+
return {};
|
|
72736
|
+
}
|
|
72737
|
+
try {
|
|
72738
|
+
const content = await readFile2(filePath, "utf8");
|
|
72739
|
+
return import_dotenv.parse(content);
|
|
72740
|
+
} catch {
|
|
72741
|
+
return {};
|
|
72742
|
+
}
|
|
72743
|
+
};
|
|
72329
72744
|
var resolveGithubToken = async (workspaceRoot) => {
|
|
72330
72745
|
if (process.env.FLOWCAT_GITHUB_TOKEN) {
|
|
72331
72746
|
return process.env.FLOWCAT_GITHUB_TOKEN;
|
|
@@ -72333,6 +72748,14 @@ var resolveGithubToken = async (workspaceRoot) => {
|
|
|
72333
72748
|
if (process.env.IL_GITHUB_TOKEN) {
|
|
72334
72749
|
return process.env.IL_GITHUB_TOKEN;
|
|
72335
72750
|
}
|
|
72751
|
+
const workspaceEnv = await readEnvFile(resolveWorkspaceEnvPath(workspaceRoot));
|
|
72752
|
+
if (workspaceEnv.GITHUB_TOKEN) {
|
|
72753
|
+
return workspaceEnv.GITHUB_TOKEN;
|
|
72754
|
+
}
|
|
72755
|
+
const globalEnv = await readEnvFile(resolveGlobalEnvPath());
|
|
72756
|
+
if (globalEnv.GITHUB_TOKEN) {
|
|
72757
|
+
return globalEnv.GITHUB_TOKEN;
|
|
72758
|
+
}
|
|
72336
72759
|
const workspaceConfig = await readConfigFile(resolveWorkspaceConfigPath(workspaceRoot));
|
|
72337
72760
|
if (workspaceConfig.github?.token) {
|
|
72338
72761
|
return workspaceConfig.github.token;
|
|
@@ -72343,11 +72766,11 @@ var resolveGithubToken = async (workspaceRoot) => {
|
|
|
72343
72766
|
|
|
72344
72767
|
// ../../packages/core/src/lock.ts
|
|
72345
72768
|
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
72346
|
-
import { writeFile } from "fs/promises";
|
|
72769
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
72347
72770
|
import path5 from "path";
|
|
72348
72771
|
|
|
72349
72772
|
// ../../packages/core/src/workspace.ts
|
|
72350
|
-
import { access as access2, mkdir as mkdir2 } from "fs/promises";
|
|
72773
|
+
import { access as access2, mkdir as mkdir2, writeFile } from "fs/promises";
|
|
72351
72774
|
import { homedir as homedir2 } from "os";
|
|
72352
72775
|
import path3 from "path";
|
|
72353
72776
|
var exists = async (filePath) => {
|
|
@@ -72412,15 +72835,16 @@ var ensureWorkspaceLayout = async (workspaceRoot) => {
|
|
|
72412
72835
|
await mkdir2(path3.join(workspaceRoot, LOCK_DIR), { recursive: true });
|
|
72413
72836
|
await mkdir2(path3.join(workspaceRoot, PLUGINS_DIR), { recursive: true });
|
|
72414
72837
|
await Promise.all(STATUS_ORDER.map((status) => mkdir2(path3.join(workspaceRoot, TASKS_DIR, status), { recursive: true })));
|
|
72415
|
-
await
|
|
72838
|
+
await ensureWorkspacePackageJson(workspaceRoot);
|
|
72839
|
+
await ensureWorkspaceGitignore(workspaceRoot);
|
|
72416
72840
|
};
|
|
72417
|
-
var
|
|
72418
|
-
const packageJsonPath = path3.join(workspaceRoot,
|
|
72841
|
+
var ensureWorkspacePackageJson = async (workspaceRoot) => {
|
|
72842
|
+
const packageJsonPath = path3.join(workspaceRoot, "package.json");
|
|
72419
72843
|
if (await exists(packageJsonPath)) {
|
|
72420
72844
|
return;
|
|
72421
72845
|
}
|
|
72422
72846
|
const packageJson = {
|
|
72423
|
-
name: "flowcat-
|
|
72847
|
+
name: "flowcat-workspace",
|
|
72424
72848
|
type: "module",
|
|
72425
72849
|
private: true,
|
|
72426
72850
|
dependencies: {
|
|
@@ -72429,12 +72853,23 @@ var ensurePluginsPackageJson = async (workspaceRoot) => {
|
|
|
72429
72853
|
};
|
|
72430
72854
|
await writeJsonAtomic(packageJsonPath, packageJson);
|
|
72431
72855
|
};
|
|
72856
|
+
var ensureWorkspaceGitignore = async (workspaceRoot) => {
|
|
72857
|
+
const gitignorePath = path3.join(workspaceRoot, ".gitignore");
|
|
72858
|
+
if (await exists(gitignorePath)) {
|
|
72859
|
+
return;
|
|
72860
|
+
}
|
|
72861
|
+
const gitignoreContent = `# Flowcat workspace local files
|
|
72862
|
+
${ENV_FILE}
|
|
72863
|
+
${LOCK_DIR}/
|
|
72864
|
+
`;
|
|
72865
|
+
await writeFile(gitignorePath, gitignoreContent, "utf8");
|
|
72866
|
+
};
|
|
72432
72867
|
|
|
72433
72868
|
// ../../packages/core/src/lock.ts
|
|
72434
72869
|
var withWorkspaceLock = async (workspaceRoot, fn) => {
|
|
72435
72870
|
await ensureWorkspaceLayout(workspaceRoot);
|
|
72436
72871
|
const lockPath = path5.join(workspaceRoot, LOCK_DIR, LOCK_FILE);
|
|
72437
|
-
await
|
|
72872
|
+
await writeFile2(lockPath, "", { flag: "a" });
|
|
72438
72873
|
const release = await import_proper_lockfile.default.lock(lockPath, {
|
|
72439
72874
|
stale: 60000,
|
|
72440
72875
|
retries: {
|
|
@@ -81750,14 +82185,14 @@ var taskMatchesQuery = (task, query) => {
|
|
|
81750
82185
|
import path11 from "path";
|
|
81751
82186
|
|
|
81752
82187
|
// ../../packages/core/src/gitignore.ts
|
|
81753
|
-
import { readFile as
|
|
82188
|
+
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
81754
82189
|
import path10 from "path";
|
|
81755
|
-
var ignoredEntries = [`${APP_DIR}/.lock
|
|
82190
|
+
var ignoredEntries = [`${APP_DIR}/.lock/`];
|
|
81756
82191
|
var ensureWorkspaceIgnored = async (repoRoot) => {
|
|
81757
82192
|
const gitignorePath = path10.join(repoRoot, ".gitignore");
|
|
81758
82193
|
let current = "";
|
|
81759
82194
|
try {
|
|
81760
|
-
current = await
|
|
82195
|
+
current = await readFile3(gitignorePath, "utf8");
|
|
81761
82196
|
} catch {
|
|
81762
82197
|
current = "";
|
|
81763
82198
|
}
|
|
@@ -81773,7 +82208,7 @@ var ensureWorkspaceIgnored = async (repoRoot) => {
|
|
|
81773
82208
|
const next = `${current}${separator}${missingEntries.join(`
|
|
81774
82209
|
`)}
|
|
81775
82210
|
`;
|
|
81776
|
-
await
|
|
82211
|
+
await writeFile3(gitignorePath, next, "utf8");
|
|
81777
82212
|
return true;
|
|
81778
82213
|
};
|
|
81779
82214
|
|
package/dist/fweb
ADDED
|
Binary file
|
package/dist/index.mjs
CHANGED
|
@@ -1804,6 +1804,401 @@ var require_commander = __commonJS((exports, module) => {
|
|
|
1804
1804
|
exports.InvalidOptionArgumentError = InvalidArgumentError;
|
|
1805
1805
|
});
|
|
1806
1806
|
|
|
1807
|
+
// ../../node_modules/.bun/dotenv@17.2.3/node_modules/dotenv/package.json
|
|
1808
|
+
var require_package = __commonJS((exports, module) => {
|
|
1809
|
+
module.exports = {
|
|
1810
|
+
name: "dotenv",
|
|
1811
|
+
version: "17.2.3",
|
|
1812
|
+
description: "Loads environment variables from .env file",
|
|
1813
|
+
main: "lib/main.js",
|
|
1814
|
+
types: "lib/main.d.ts",
|
|
1815
|
+
exports: {
|
|
1816
|
+
".": {
|
|
1817
|
+
types: "./lib/main.d.ts",
|
|
1818
|
+
require: "./lib/main.js",
|
|
1819
|
+
default: "./lib/main.js"
|
|
1820
|
+
},
|
|
1821
|
+
"./config": "./config.js",
|
|
1822
|
+
"./config.js": "./config.js",
|
|
1823
|
+
"./lib/env-options": "./lib/env-options.js",
|
|
1824
|
+
"./lib/env-options.js": "./lib/env-options.js",
|
|
1825
|
+
"./lib/cli-options": "./lib/cli-options.js",
|
|
1826
|
+
"./lib/cli-options.js": "./lib/cli-options.js",
|
|
1827
|
+
"./package.json": "./package.json"
|
|
1828
|
+
},
|
|
1829
|
+
scripts: {
|
|
1830
|
+
"dts-check": "tsc --project tests/types/tsconfig.json",
|
|
1831
|
+
lint: "standard",
|
|
1832
|
+
pretest: "npm run lint && npm run dts-check",
|
|
1833
|
+
test: "tap run tests/**/*.js --allow-empty-coverage --disable-coverage --timeout=60000",
|
|
1834
|
+
"test:coverage": "tap run tests/**/*.js --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
|
|
1835
|
+
prerelease: "npm test",
|
|
1836
|
+
release: "standard-version"
|
|
1837
|
+
},
|
|
1838
|
+
repository: {
|
|
1839
|
+
type: "git",
|
|
1840
|
+
url: "git://github.com/motdotla/dotenv.git"
|
|
1841
|
+
},
|
|
1842
|
+
homepage: "https://github.com/motdotla/dotenv#readme",
|
|
1843
|
+
funding: "https://dotenvx.com",
|
|
1844
|
+
keywords: [
|
|
1845
|
+
"dotenv",
|
|
1846
|
+
"env",
|
|
1847
|
+
".env",
|
|
1848
|
+
"environment",
|
|
1849
|
+
"variables",
|
|
1850
|
+
"config",
|
|
1851
|
+
"settings"
|
|
1852
|
+
],
|
|
1853
|
+
readmeFilename: "README.md",
|
|
1854
|
+
license: "BSD-2-Clause",
|
|
1855
|
+
devDependencies: {
|
|
1856
|
+
"@types/node": "^18.11.3",
|
|
1857
|
+
decache: "^4.6.2",
|
|
1858
|
+
sinon: "^14.0.1",
|
|
1859
|
+
standard: "^17.0.0",
|
|
1860
|
+
"standard-version": "^9.5.0",
|
|
1861
|
+
tap: "^19.2.0",
|
|
1862
|
+
typescript: "^4.8.4"
|
|
1863
|
+
},
|
|
1864
|
+
engines: {
|
|
1865
|
+
node: ">=12"
|
|
1866
|
+
},
|
|
1867
|
+
browser: {
|
|
1868
|
+
fs: false
|
|
1869
|
+
}
|
|
1870
|
+
};
|
|
1871
|
+
});
|
|
1872
|
+
|
|
1873
|
+
// ../../node_modules/.bun/dotenv@17.2.3/node_modules/dotenv/lib/main.js
|
|
1874
|
+
var require_main = __commonJS((exports, module) => {
|
|
1875
|
+
var fs = __require("fs");
|
|
1876
|
+
var path = __require("path");
|
|
1877
|
+
var os = __require("os");
|
|
1878
|
+
var crypto = __require("crypto");
|
|
1879
|
+
var packageJson = require_package();
|
|
1880
|
+
var version = packageJson.version;
|
|
1881
|
+
var TIPS = [
|
|
1882
|
+
"\uD83D\uDD10 encrypt with Dotenvx: https://dotenvx.com",
|
|
1883
|
+
"\uD83D\uDD10 prevent committing .env to code: https://dotenvx.com/precommit",
|
|
1884
|
+
"\uD83D\uDD10 prevent building .env in docker: https://dotenvx.com/prebuild",
|
|
1885
|
+
"\uD83D\uDCE1 add observability to secrets: https://dotenvx.com/ops",
|
|
1886
|
+
"\uD83D\uDC65 sync secrets across teammates & machines: https://dotenvx.com/ops",
|
|
1887
|
+
"\uD83D\uDDC2️ backup and recover secrets: https://dotenvx.com/ops",
|
|
1888
|
+
"✅ audit secrets and track compliance: https://dotenvx.com/ops",
|
|
1889
|
+
"\uD83D\uDD04 add secrets lifecycle management: https://dotenvx.com/ops",
|
|
1890
|
+
"\uD83D\uDD11 add access controls to secrets: https://dotenvx.com/ops",
|
|
1891
|
+
"\uD83D\uDEE0️ run anywhere with `dotenvx run -- yourcommand`",
|
|
1892
|
+
"⚙️ specify custom .env file path with { path: '/custom/path/.env' }",
|
|
1893
|
+
"⚙️ enable debug logging with { debug: true }",
|
|
1894
|
+
"⚙️ override existing env vars with { override: true }",
|
|
1895
|
+
"⚙️ suppress all logs with { quiet: true }",
|
|
1896
|
+
"⚙️ write to custom object with { processEnv: myObject }",
|
|
1897
|
+
"⚙️ load multiple .env files with { path: ['.env.local', '.env'] }"
|
|
1898
|
+
];
|
|
1899
|
+
function _getRandomTip() {
|
|
1900
|
+
return TIPS[Math.floor(Math.random() * TIPS.length)];
|
|
1901
|
+
}
|
|
1902
|
+
function parseBoolean(value) {
|
|
1903
|
+
if (typeof value === "string") {
|
|
1904
|
+
return !["false", "0", "no", "off", ""].includes(value.toLowerCase());
|
|
1905
|
+
}
|
|
1906
|
+
return Boolean(value);
|
|
1907
|
+
}
|
|
1908
|
+
function supportsAnsi() {
|
|
1909
|
+
return process.stdout.isTTY;
|
|
1910
|
+
}
|
|
1911
|
+
function dim(text) {
|
|
1912
|
+
return supportsAnsi() ? `\x1B[2m${text}\x1B[0m` : text;
|
|
1913
|
+
}
|
|
1914
|
+
var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
|
|
1915
|
+
function parse(src) {
|
|
1916
|
+
const obj = {};
|
|
1917
|
+
let lines = src.toString();
|
|
1918
|
+
lines = lines.replace(/\r\n?/mg, `
|
|
1919
|
+
`);
|
|
1920
|
+
let match;
|
|
1921
|
+
while ((match = LINE.exec(lines)) != null) {
|
|
1922
|
+
const key = match[1];
|
|
1923
|
+
let value = match[2] || "";
|
|
1924
|
+
value = value.trim();
|
|
1925
|
+
const maybeQuote = value[0];
|
|
1926
|
+
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
|
|
1927
|
+
if (maybeQuote === '"') {
|
|
1928
|
+
value = value.replace(/\\n/g, `
|
|
1929
|
+
`);
|
|
1930
|
+
value = value.replace(/\\r/g, "\r");
|
|
1931
|
+
}
|
|
1932
|
+
obj[key] = value;
|
|
1933
|
+
}
|
|
1934
|
+
return obj;
|
|
1935
|
+
}
|
|
1936
|
+
function _parseVault(options) {
|
|
1937
|
+
options = options || {};
|
|
1938
|
+
const vaultPath = _vaultPath(options);
|
|
1939
|
+
options.path = vaultPath;
|
|
1940
|
+
const result = DotenvModule.configDotenv(options);
|
|
1941
|
+
if (!result.parsed) {
|
|
1942
|
+
const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
|
|
1943
|
+
err.code = "MISSING_DATA";
|
|
1944
|
+
throw err;
|
|
1945
|
+
}
|
|
1946
|
+
const keys = _dotenvKey(options).split(",");
|
|
1947
|
+
const length = keys.length;
|
|
1948
|
+
let decrypted;
|
|
1949
|
+
for (let i = 0;i < length; i++) {
|
|
1950
|
+
try {
|
|
1951
|
+
const key = keys[i].trim();
|
|
1952
|
+
const attrs = _instructions(result, key);
|
|
1953
|
+
decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
|
|
1954
|
+
break;
|
|
1955
|
+
} catch (error) {
|
|
1956
|
+
if (i + 1 >= length) {
|
|
1957
|
+
throw error;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
return DotenvModule.parse(decrypted);
|
|
1962
|
+
}
|
|
1963
|
+
function _warn(message) {
|
|
1964
|
+
console.error(`[dotenv@${version}][WARN] ${message}`);
|
|
1965
|
+
}
|
|
1966
|
+
function _debug(message) {
|
|
1967
|
+
console.log(`[dotenv@${version}][DEBUG] ${message}`);
|
|
1968
|
+
}
|
|
1969
|
+
function _log(message) {
|
|
1970
|
+
console.log(`[dotenv@${version}] ${message}`);
|
|
1971
|
+
}
|
|
1972
|
+
function _dotenvKey(options) {
|
|
1973
|
+
if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
|
|
1974
|
+
return options.DOTENV_KEY;
|
|
1975
|
+
}
|
|
1976
|
+
if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
|
|
1977
|
+
return process.env.DOTENV_KEY;
|
|
1978
|
+
}
|
|
1979
|
+
return "";
|
|
1980
|
+
}
|
|
1981
|
+
function _instructions(result, dotenvKey) {
|
|
1982
|
+
let uri;
|
|
1983
|
+
try {
|
|
1984
|
+
uri = new URL(dotenvKey);
|
|
1985
|
+
} catch (error) {
|
|
1986
|
+
if (error.code === "ERR_INVALID_URL") {
|
|
1987
|
+
const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
|
|
1988
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
1989
|
+
throw err;
|
|
1990
|
+
}
|
|
1991
|
+
throw error;
|
|
1992
|
+
}
|
|
1993
|
+
const key = uri.password;
|
|
1994
|
+
if (!key) {
|
|
1995
|
+
const err = new Error("INVALID_DOTENV_KEY: Missing key part");
|
|
1996
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
1997
|
+
throw err;
|
|
1998
|
+
}
|
|
1999
|
+
const environment = uri.searchParams.get("environment");
|
|
2000
|
+
if (!environment) {
|
|
2001
|
+
const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
|
|
2002
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
2003
|
+
throw err;
|
|
2004
|
+
}
|
|
2005
|
+
const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
|
|
2006
|
+
const ciphertext = result.parsed[environmentKey];
|
|
2007
|
+
if (!ciphertext) {
|
|
2008
|
+
const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
|
|
2009
|
+
err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
|
|
2010
|
+
throw err;
|
|
2011
|
+
}
|
|
2012
|
+
return { ciphertext, key };
|
|
2013
|
+
}
|
|
2014
|
+
function _vaultPath(options) {
|
|
2015
|
+
let possibleVaultPath = null;
|
|
2016
|
+
if (options && options.path && options.path.length > 0) {
|
|
2017
|
+
if (Array.isArray(options.path)) {
|
|
2018
|
+
for (const filepath of options.path) {
|
|
2019
|
+
if (fs.existsSync(filepath)) {
|
|
2020
|
+
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
} else {
|
|
2024
|
+
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
|
|
2025
|
+
}
|
|
2026
|
+
} else {
|
|
2027
|
+
possibleVaultPath = path.resolve(process.cwd(), ".env.vault");
|
|
2028
|
+
}
|
|
2029
|
+
if (fs.existsSync(possibleVaultPath)) {
|
|
2030
|
+
return possibleVaultPath;
|
|
2031
|
+
}
|
|
2032
|
+
return null;
|
|
2033
|
+
}
|
|
2034
|
+
function _resolveHome(envPath) {
|
|
2035
|
+
return envPath[0] === "~" ? path.join(os.homedir(), envPath.slice(1)) : envPath;
|
|
2036
|
+
}
|
|
2037
|
+
function _configVault(options) {
|
|
2038
|
+
const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
|
|
2039
|
+
const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options && options.quiet);
|
|
2040
|
+
if (debug || !quiet) {
|
|
2041
|
+
_log("Loading env from encrypted .env.vault");
|
|
2042
|
+
}
|
|
2043
|
+
const parsed = DotenvModule._parseVault(options);
|
|
2044
|
+
let processEnv = process.env;
|
|
2045
|
+
if (options && options.processEnv != null) {
|
|
2046
|
+
processEnv = options.processEnv;
|
|
2047
|
+
}
|
|
2048
|
+
DotenvModule.populate(processEnv, parsed, options);
|
|
2049
|
+
return { parsed };
|
|
2050
|
+
}
|
|
2051
|
+
function configDotenv(options) {
|
|
2052
|
+
const dotenvPath = path.resolve(process.cwd(), ".env");
|
|
2053
|
+
let encoding = "utf8";
|
|
2054
|
+
let processEnv = process.env;
|
|
2055
|
+
if (options && options.processEnv != null) {
|
|
2056
|
+
processEnv = options.processEnv;
|
|
2057
|
+
}
|
|
2058
|
+
let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || options && options.debug);
|
|
2059
|
+
let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options && options.quiet);
|
|
2060
|
+
if (options && options.encoding) {
|
|
2061
|
+
encoding = options.encoding;
|
|
2062
|
+
} else {
|
|
2063
|
+
if (debug) {
|
|
2064
|
+
_debug("No encoding is specified. UTF-8 is used by default");
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
let optionPaths = [dotenvPath];
|
|
2068
|
+
if (options && options.path) {
|
|
2069
|
+
if (!Array.isArray(options.path)) {
|
|
2070
|
+
optionPaths = [_resolveHome(options.path)];
|
|
2071
|
+
} else {
|
|
2072
|
+
optionPaths = [];
|
|
2073
|
+
for (const filepath of options.path) {
|
|
2074
|
+
optionPaths.push(_resolveHome(filepath));
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
let lastError;
|
|
2079
|
+
const parsedAll = {};
|
|
2080
|
+
for (const path2 of optionPaths) {
|
|
2081
|
+
try {
|
|
2082
|
+
const parsed = DotenvModule.parse(fs.readFileSync(path2, { encoding }));
|
|
2083
|
+
DotenvModule.populate(parsedAll, parsed, options);
|
|
2084
|
+
} catch (e) {
|
|
2085
|
+
if (debug) {
|
|
2086
|
+
_debug(`Failed to load ${path2} ${e.message}`);
|
|
2087
|
+
}
|
|
2088
|
+
lastError = e;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
const populated = DotenvModule.populate(processEnv, parsedAll, options);
|
|
2092
|
+
debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug);
|
|
2093
|
+
quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet);
|
|
2094
|
+
if (debug || !quiet) {
|
|
2095
|
+
const keysCount = Object.keys(populated).length;
|
|
2096
|
+
const shortPaths = [];
|
|
2097
|
+
for (const filePath of optionPaths) {
|
|
2098
|
+
try {
|
|
2099
|
+
const relative = path.relative(process.cwd(), filePath);
|
|
2100
|
+
shortPaths.push(relative);
|
|
2101
|
+
} catch (e) {
|
|
2102
|
+
if (debug) {
|
|
2103
|
+
_debug(`Failed to load ${filePath} ${e.message}`);
|
|
2104
|
+
}
|
|
2105
|
+
lastError = e;
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
_log(`injecting env (${keysCount}) from ${shortPaths.join(",")} ${dim(`-- tip: ${_getRandomTip()}`)}`);
|
|
2109
|
+
}
|
|
2110
|
+
if (lastError) {
|
|
2111
|
+
return { parsed: parsedAll, error: lastError };
|
|
2112
|
+
} else {
|
|
2113
|
+
return { parsed: parsedAll };
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
function config(options) {
|
|
2117
|
+
if (_dotenvKey(options).length === 0) {
|
|
2118
|
+
return DotenvModule.configDotenv(options);
|
|
2119
|
+
}
|
|
2120
|
+
const vaultPath = _vaultPath(options);
|
|
2121
|
+
if (!vaultPath) {
|
|
2122
|
+
_warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
|
|
2123
|
+
return DotenvModule.configDotenv(options);
|
|
2124
|
+
}
|
|
2125
|
+
return DotenvModule._configVault(options);
|
|
2126
|
+
}
|
|
2127
|
+
function decrypt(encrypted, keyStr) {
|
|
2128
|
+
const key = Buffer.from(keyStr.slice(-64), "hex");
|
|
2129
|
+
let ciphertext = Buffer.from(encrypted, "base64");
|
|
2130
|
+
const nonce = ciphertext.subarray(0, 12);
|
|
2131
|
+
const authTag = ciphertext.subarray(-16);
|
|
2132
|
+
ciphertext = ciphertext.subarray(12, -16);
|
|
2133
|
+
try {
|
|
2134
|
+
const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
|
|
2135
|
+
aesgcm.setAuthTag(authTag);
|
|
2136
|
+
return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
|
|
2137
|
+
} catch (error) {
|
|
2138
|
+
const isRange = error instanceof RangeError;
|
|
2139
|
+
const invalidKeyLength = error.message === "Invalid key length";
|
|
2140
|
+
const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
|
|
2141
|
+
if (isRange || invalidKeyLength) {
|
|
2142
|
+
const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
|
|
2143
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
2144
|
+
throw err;
|
|
2145
|
+
} else if (decryptionFailed) {
|
|
2146
|
+
const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
|
|
2147
|
+
err.code = "DECRYPTION_FAILED";
|
|
2148
|
+
throw err;
|
|
2149
|
+
} else {
|
|
2150
|
+
throw error;
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
function populate(processEnv, parsed, options = {}) {
|
|
2155
|
+
const debug = Boolean(options && options.debug);
|
|
2156
|
+
const override = Boolean(options && options.override);
|
|
2157
|
+
const populated = {};
|
|
2158
|
+
if (typeof parsed !== "object") {
|
|
2159
|
+
const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
|
|
2160
|
+
err.code = "OBJECT_REQUIRED";
|
|
2161
|
+
throw err;
|
|
2162
|
+
}
|
|
2163
|
+
for (const key of Object.keys(parsed)) {
|
|
2164
|
+
if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
|
|
2165
|
+
if (override === true) {
|
|
2166
|
+
processEnv[key] = parsed[key];
|
|
2167
|
+
populated[key] = parsed[key];
|
|
2168
|
+
}
|
|
2169
|
+
if (debug) {
|
|
2170
|
+
if (override === true) {
|
|
2171
|
+
_debug(`"${key}" is already defined and WAS overwritten`);
|
|
2172
|
+
} else {
|
|
2173
|
+
_debug(`"${key}" is already defined and was NOT overwritten`);
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
} else {
|
|
2177
|
+
processEnv[key] = parsed[key];
|
|
2178
|
+
populated[key] = parsed[key];
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
return populated;
|
|
2182
|
+
}
|
|
2183
|
+
var DotenvModule = {
|
|
2184
|
+
configDotenv,
|
|
2185
|
+
_configVault,
|
|
2186
|
+
_parseVault,
|
|
2187
|
+
config,
|
|
2188
|
+
decrypt,
|
|
2189
|
+
parse,
|
|
2190
|
+
populate
|
|
2191
|
+
};
|
|
2192
|
+
exports.configDotenv = DotenvModule.configDotenv;
|
|
2193
|
+
exports._configVault = DotenvModule._configVault;
|
|
2194
|
+
exports._parseVault = DotenvModule._parseVault;
|
|
2195
|
+
exports.config = DotenvModule.config;
|
|
2196
|
+
exports.decrypt = DotenvModule.decrypt;
|
|
2197
|
+
exports.parse = DotenvModule.parse;
|
|
2198
|
+
exports.populate = DotenvModule.populate;
|
|
2199
|
+
module.exports = DotenvModule;
|
|
2200
|
+
});
|
|
2201
|
+
|
|
1807
2202
|
// ../../node_modules/.bun/imurmurhash@0.1.4/node_modules/imurmurhash/imurmurhash.js
|
|
1808
2203
|
var require_imurmurhash = __commonJS((exports, module) => {
|
|
1809
2204
|
(function() {
|
|
@@ -2832,8 +3227,8 @@ GFS4: `);
|
|
|
2832
3227
|
fs2.createReadStream = createReadStream;
|
|
2833
3228
|
fs2.createWriteStream = createWriteStream;
|
|
2834
3229
|
var fs$readFile = fs2.readFile;
|
|
2835
|
-
fs2.readFile =
|
|
2836
|
-
function
|
|
3230
|
+
fs2.readFile = readFile3;
|
|
3231
|
+
function readFile3(path2, options, cb) {
|
|
2837
3232
|
if (typeof options === "function")
|
|
2838
3233
|
cb = options, options = null;
|
|
2839
3234
|
return go$readFile(path2, options, cb);
|
|
@@ -25136,7 +25531,8 @@ var coerce = {
|
|
|
25136
25531
|
};
|
|
25137
25532
|
var NEVER = INVALID;
|
|
25138
25533
|
// ../../packages/core/src/config.ts
|
|
25139
|
-
|
|
25534
|
+
var import_dotenv = __toESM(require_main(), 1);
|
|
25535
|
+
import { access, mkdir, readFile as readFile2 } from "node:fs/promises";
|
|
25140
25536
|
import { homedir } from "node:os";
|
|
25141
25537
|
import path from "node:path";
|
|
25142
25538
|
|
|
@@ -25147,6 +25543,7 @@ var LOCK_DIR = ".lock";
|
|
|
25147
25543
|
var LOCK_FILE = "store.lock";
|
|
25148
25544
|
var TASKS_DIR = "tasks";
|
|
25149
25545
|
var PLUGINS_DIR = "plugins";
|
|
25546
|
+
var ENV_FILE = ".env";
|
|
25150
25547
|
var STATUS_ORDER = ["backlog", "active", "paused", "completed", "cancelled"];
|
|
25151
25548
|
|
|
25152
25549
|
// ../../packages/core/src/json.ts
|
|
@@ -25202,6 +25599,24 @@ var resolveAutoCommitEnabled = async (workspaceRoot) => {
|
|
|
25202
25599
|
const globalConfig = await readConfigFile(resolveGlobalConfigPath());
|
|
25203
25600
|
return globalConfig.autoCommit ?? false;
|
|
25204
25601
|
};
|
|
25602
|
+
var resolveWorkspaceEnvPath = (workspaceRoot) => {
|
|
25603
|
+
return path.join(workspaceRoot, ENV_FILE);
|
|
25604
|
+
};
|
|
25605
|
+
var resolveGlobalEnvPath = () => {
|
|
25606
|
+
const configHome = process.env.XDG_CONFIG_HOME ?? path.join(homedir(), ".config");
|
|
25607
|
+
return path.join(configHome, APP_NAME, ENV_FILE);
|
|
25608
|
+
};
|
|
25609
|
+
var readEnvFile = async (filePath) => {
|
|
25610
|
+
if (!await configFileExists(filePath)) {
|
|
25611
|
+
return {};
|
|
25612
|
+
}
|
|
25613
|
+
try {
|
|
25614
|
+
const content = await readFile2(filePath, "utf8");
|
|
25615
|
+
return import_dotenv.parse(content);
|
|
25616
|
+
} catch {
|
|
25617
|
+
return {};
|
|
25618
|
+
}
|
|
25619
|
+
};
|
|
25205
25620
|
var resolveGithubToken = async (workspaceRoot) => {
|
|
25206
25621
|
if (process.env.FLOWCAT_GITHUB_TOKEN) {
|
|
25207
25622
|
return process.env.FLOWCAT_GITHUB_TOKEN;
|
|
@@ -25209,6 +25624,14 @@ var resolveGithubToken = async (workspaceRoot) => {
|
|
|
25209
25624
|
if (process.env.IL_GITHUB_TOKEN) {
|
|
25210
25625
|
return process.env.IL_GITHUB_TOKEN;
|
|
25211
25626
|
}
|
|
25627
|
+
const workspaceEnv = await readEnvFile(resolveWorkspaceEnvPath(workspaceRoot));
|
|
25628
|
+
if (workspaceEnv.GITHUB_TOKEN) {
|
|
25629
|
+
return workspaceEnv.GITHUB_TOKEN;
|
|
25630
|
+
}
|
|
25631
|
+
const globalEnv = await readEnvFile(resolveGlobalEnvPath());
|
|
25632
|
+
if (globalEnv.GITHUB_TOKEN) {
|
|
25633
|
+
return globalEnv.GITHUB_TOKEN;
|
|
25634
|
+
}
|
|
25212
25635
|
const workspaceConfig = await readConfigFile(resolveWorkspaceConfigPath(workspaceRoot));
|
|
25213
25636
|
if (workspaceConfig.github?.token) {
|
|
25214
25637
|
return workspaceConfig.github.token;
|
|
@@ -25219,11 +25642,11 @@ var resolveGithubToken = async (workspaceRoot) => {
|
|
|
25219
25642
|
|
|
25220
25643
|
// ../../packages/core/src/lock.ts
|
|
25221
25644
|
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
25222
|
-
import { writeFile } from "node:fs/promises";
|
|
25645
|
+
import { writeFile as writeFile2 } from "node:fs/promises";
|
|
25223
25646
|
import path3 from "node:path";
|
|
25224
25647
|
|
|
25225
25648
|
// ../../packages/core/src/workspace.ts
|
|
25226
|
-
import { access as access2, mkdir as mkdir2 } from "node:fs/promises";
|
|
25649
|
+
import { access as access2, mkdir as mkdir2, writeFile } from "node:fs/promises";
|
|
25227
25650
|
import { homedir as homedir2 } from "node:os";
|
|
25228
25651
|
import path2 from "node:path";
|
|
25229
25652
|
var exists = async (filePath) => {
|
|
@@ -25288,15 +25711,16 @@ var ensureWorkspaceLayout = async (workspaceRoot) => {
|
|
|
25288
25711
|
await mkdir2(path2.join(workspaceRoot, LOCK_DIR), { recursive: true });
|
|
25289
25712
|
await mkdir2(path2.join(workspaceRoot, PLUGINS_DIR), { recursive: true });
|
|
25290
25713
|
await Promise.all(STATUS_ORDER.map((status) => mkdir2(path2.join(workspaceRoot, TASKS_DIR, status), { recursive: true })));
|
|
25291
|
-
await
|
|
25714
|
+
await ensureWorkspacePackageJson(workspaceRoot);
|
|
25715
|
+
await ensureWorkspaceGitignore(workspaceRoot);
|
|
25292
25716
|
};
|
|
25293
|
-
var
|
|
25294
|
-
const packageJsonPath = path2.join(workspaceRoot,
|
|
25717
|
+
var ensureWorkspacePackageJson = async (workspaceRoot) => {
|
|
25718
|
+
const packageJsonPath = path2.join(workspaceRoot, "package.json");
|
|
25295
25719
|
if (await exists(packageJsonPath)) {
|
|
25296
25720
|
return;
|
|
25297
25721
|
}
|
|
25298
25722
|
const packageJson = {
|
|
25299
|
-
name: "flowcat-
|
|
25723
|
+
name: "flowcat-workspace",
|
|
25300
25724
|
type: "module",
|
|
25301
25725
|
private: true,
|
|
25302
25726
|
dependencies: {
|
|
@@ -25305,12 +25729,23 @@ var ensurePluginsPackageJson = async (workspaceRoot) => {
|
|
|
25305
25729
|
};
|
|
25306
25730
|
await writeJsonAtomic(packageJsonPath, packageJson);
|
|
25307
25731
|
};
|
|
25732
|
+
var ensureWorkspaceGitignore = async (workspaceRoot) => {
|
|
25733
|
+
const gitignorePath = path2.join(workspaceRoot, ".gitignore");
|
|
25734
|
+
if (await exists(gitignorePath)) {
|
|
25735
|
+
return;
|
|
25736
|
+
}
|
|
25737
|
+
const gitignoreContent = `# Flowcat workspace local files
|
|
25738
|
+
${ENV_FILE}
|
|
25739
|
+
${LOCK_DIR}/
|
|
25740
|
+
`;
|
|
25741
|
+
await writeFile(gitignorePath, gitignoreContent, "utf8");
|
|
25742
|
+
};
|
|
25308
25743
|
|
|
25309
25744
|
// ../../packages/core/src/lock.ts
|
|
25310
25745
|
var withWorkspaceLock = async (workspaceRoot, fn) => {
|
|
25311
25746
|
await ensureWorkspaceLayout(workspaceRoot);
|
|
25312
25747
|
const lockPath = path3.join(workspaceRoot, LOCK_DIR, LOCK_FILE);
|
|
25313
|
-
await
|
|
25748
|
+
await writeFile2(lockPath, "", { flag: "a" });
|
|
25314
25749
|
const release = await import_proper_lockfile.default.lock(lockPath, {
|
|
25315
25750
|
stale: 60000,
|
|
25316
25751
|
retries: {
|
|
@@ -30793,14 +31228,14 @@ var registerEditCommand = (program2, helpers) => {
|
|
|
30793
31228
|
import path8 from "node:path";
|
|
30794
31229
|
|
|
30795
31230
|
// ../../packages/core/src/gitignore.ts
|
|
30796
|
-
import { readFile as
|
|
31231
|
+
import { readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
30797
31232
|
import path7 from "node:path";
|
|
30798
|
-
var ignoredEntries = [`${APP_DIR}/.lock
|
|
31233
|
+
var ignoredEntries = [`${APP_DIR}/.lock/`];
|
|
30799
31234
|
var ensureWorkspaceIgnored = async (repoRoot) => {
|
|
30800
31235
|
const gitignorePath = path7.join(repoRoot, ".gitignore");
|
|
30801
31236
|
let current = "";
|
|
30802
31237
|
try {
|
|
30803
|
-
current = await
|
|
31238
|
+
current = await readFile3(gitignorePath, "utf8");
|
|
30804
31239
|
} catch {
|
|
30805
31240
|
current = "";
|
|
30806
31241
|
}
|
|
@@ -30816,7 +31251,7 @@ var ensureWorkspaceIgnored = async (repoRoot) => {
|
|
|
30816
31251
|
const next = `${current}${separator}${missingEntries.join(`
|
|
30817
31252
|
`)}
|
|
30818
31253
|
`;
|
|
30819
|
-
await
|
|
31254
|
+
await writeFile3(gitignorePath, next, "utf8");
|
|
30820
31255
|
return true;
|
|
30821
31256
|
};
|
|
30822
31257
|
|
|
@@ -31924,7 +32359,7 @@ var registerWhereCommand = (program2, helpers) => {
|
|
|
31924
32359
|
};
|
|
31925
32360
|
|
|
31926
32361
|
// helpers.ts
|
|
31927
|
-
import { readFile as
|
|
32362
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
31928
32363
|
import path10 from "node:path";
|
|
31929
32364
|
import { fileURLToPath } from "node:url";
|
|
31930
32365
|
|
|
@@ -32240,7 +32675,7 @@ var resolvePackageVersion = async () => {
|
|
|
32240
32675
|
while (true) {
|
|
32241
32676
|
const candidate = path10.join(current, "package.json");
|
|
32242
32677
|
try {
|
|
32243
|
-
const raw = await
|
|
32678
|
+
const raw = await readFile4(candidate, "utf8");
|
|
32244
32679
|
const parsed = JSON.parse(raw);
|
|
32245
32680
|
if (isPackageJson(parsed) && typeof parsed.version === "string") {
|
|
32246
32681
|
return parsed.version;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flowcat",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
},
|
|
10
10
|
"bin": {
|
|
11
11
|
"flowcat": "dist/index.mjs",
|
|
12
|
-
"fcat": "dist/fcat.mjs"
|
|
12
|
+
"fcat": "dist/fcat.mjs",
|
|
13
|
+
"fweb": "dist/fweb"
|
|
13
14
|
},
|
|
14
15
|
"files": [
|
|
15
16
|
"dist",
|