frontmcp 0.7.2 → 0.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frontmcp",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "FrontMCP command line interface",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "homepage": "https://docs.agentfront.dev",
@@ -25,8 +25,11 @@
25
25
  "bin": {
26
26
  "frontmcp": "./src/cli.js"
27
27
  },
28
+ "engines": {
29
+ "node": ">=22.0.0"
30
+ },
28
31
  "dependencies": {
29
- "@frontmcp/utils": "0.7.2",
32
+ "@frontmcp/utils": "0.8.0",
30
33
  "tslib": "^2.3.0",
31
34
  "@rspack/core": "^1.3.12"
32
35
  },
@@ -6,6 +6,7 @@ const path = tslib_1.__importStar(require("path"));
6
6
  const child_process_1 = require("child_process");
7
7
  const colors_1 = require("../colors");
8
8
  const fs_1 = require("../utils/fs");
9
+ const env_1 = require("../utils/env");
9
10
  function killQuiet(proc) {
10
11
  try {
11
12
  if (proc) {
@@ -19,10 +20,17 @@ function killQuiet(proc) {
19
20
  async function runDev(opts) {
20
21
  const cwd = process.cwd();
21
22
  const entry = await (0, fs_1.resolveEntry)(cwd, opts.entry);
23
+ // Load .env and .env.local files before starting the server
24
+ (0, env_1.loadDevEnv)(cwd);
22
25
  console.log(`${(0, colors_1.c)('cyan', '[dev]')} using entry: ${path.relative(cwd, entry)}`);
23
26
  console.log(`${(0, colors_1.c)('gray', '[dev]')} starting ${(0, colors_1.c)('bold', 'tsx --watch')} and ${(0, colors_1.c)('bold', 'tsc --noEmit --watch')} (async type-checker)`);
24
27
  console.log(`${(0, colors_1.c)('gray', 'hint:')} press Ctrl+C to stop`);
25
- const app = (0, child_process_1.spawn)('npx', ['-y', 'tsx', '--watch', entry], { stdio: 'inherit', shell: true });
28
+ // Use --conditions node to ensure proper Node.js module resolution
29
+ // This helps with dynamic require() calls in packages like ioredis
30
+ const app = (0, child_process_1.spawn)('npx', ['-y', 'tsx', '--conditions', 'node', '--watch', entry], {
31
+ stdio: 'inherit',
32
+ shell: true,
33
+ });
26
34
  const checker = (0, child_process_1.spawn)('npx', ['-y', 'tsc', '--noEmit', '--pretty', '--watch'], {
27
35
  stdio: 'inherit',
28
36
  shell: true,
@@ -1 +1 @@
1
- {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../../src/commands/dev.ts"],"names":[],"mappings":";;AAgBA,wBAuCC;;AAvDD,mDAA6B;AAC7B,iDAAoD;AAEpD,sCAA8B;AAC9B,oCAA2C;AAE3C,SAAS,SAAS,CAAC,IAAmB;IACpC,IAAI,CAAC;QACH,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,MAAM,CAAC,IAAgB;IAC3C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,MAAM,IAAA,iBAAY,EAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAElD,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,CAAC,iBAAiB,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IAC/E,OAAO,CAAC,GAAG,CACT,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,CAAC,aAAa,IAAA,UAAC,EAAC,MAAM,EAAE,aAAa,CAAC,QAAQ,IAAA,UAAC,EACjE,MAAM,EACN,sBAAsB,CACvB,uBAAuB,CACzB,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAE1D,MAAM,GAAG,GAAG,IAAA,qBAAK,EAAC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7F,MAAM,OAAO,GAAG,IAAA,qBAAK,EAAC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE;QAC7E,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,SAAS,CAAC,OAAO,CAAC,CAAC;QACnB,SAAS,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,OAAO,EAAE,CAAC;QACV,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACnB,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACtB,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import * as path from 'path';\nimport { spawn, ChildProcess } from 'child_process';\nimport { ParsedArgs } from '../args';\nimport { c } from '../colors';\nimport { resolveEntry } from '../utils/fs';\n\nfunction killQuiet(proc?: ChildProcess) {\n try {\n if (proc) {\n proc.kill('SIGINT');\n }\n } catch {\n // ignore\n }\n}\n\nexport async function runDev(opts: ParsedArgs): Promise<void> {\n const cwd = process.cwd();\n const entry = await resolveEntry(cwd, opts.entry);\n\n console.log(`${c('cyan', '[dev]')} using entry: ${path.relative(cwd, entry)}`);\n console.log(\n `${c('gray', '[dev]')} starting ${c('bold', 'tsx --watch')} and ${c(\n 'bold',\n 'tsc --noEmit --watch',\n )} (async type-checker)`,\n );\n console.log(`${c('gray', 'hint:')} press Ctrl+C to stop`);\n\n const app = spawn('npx', ['-y', 'tsx', '--watch', entry], { stdio: 'inherit', shell: true });\n const checker = spawn('npx', ['-y', 'tsc', '--noEmit', '--pretty', '--watch'], {\n stdio: 'inherit',\n shell: true,\n });\n\n const cleanup = () => {\n killQuiet(checker);\n killQuiet(app);\n };\n\n process.on('SIGINT', () => {\n cleanup();\n process.exit(0);\n });\n\n await new Promise<void>((resolve, reject) => {\n app.on('close', () => {\n cleanup();\n resolve();\n });\n app.on('error', (err) => {\n cleanup();\n reject(err);\n });\n });\n}\n"]}
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../../src/commands/dev.ts"],"names":[],"mappings":";;AAiBA,wBA+CC;;AAhED,mDAA6B;AAC7B,iDAAoD;AAEpD,sCAA8B;AAC9B,oCAA2C;AAC3C,sCAA0C;AAE1C,SAAS,SAAS,CAAC,IAAmB;IACpC,IAAI,CAAC;QACH,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,MAAM,CAAC,IAAgB;IAC3C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,MAAM,IAAA,iBAAY,EAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAElD,4DAA4D;IAC5D,IAAA,gBAAU,EAAC,GAAG,CAAC,CAAC;IAEhB,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,CAAC,iBAAiB,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IAC/E,OAAO,CAAC,GAAG,CACT,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,CAAC,aAAa,IAAA,UAAC,EAAC,MAAM,EAAE,aAAa,CAAC,QAAQ,IAAA,UAAC,EACjE,MAAM,EACN,sBAAsB,CACvB,uBAAuB,CACzB,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAE1D,mEAAmE;IACnE,mEAAmE;IACnE,MAAM,GAAG,GAAG,IAAA,qBAAK,EAAC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;QAChF,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,IAAA,qBAAK,EAAC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE;QAC7E,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,SAAS,CAAC,OAAO,CAAC,CAAC;QACnB,SAAS,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,OAAO,EAAE,CAAC;QACV,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACnB,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACtB,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import * as path from 'path';\nimport { spawn, ChildProcess } from 'child_process';\nimport { ParsedArgs } from '../args';\nimport { c } from '../colors';\nimport { resolveEntry } from '../utils/fs';\nimport { loadDevEnv } from '../utils/env';\n\nfunction killQuiet(proc?: ChildProcess) {\n try {\n if (proc) {\n proc.kill('SIGINT');\n }\n } catch {\n // ignore\n }\n}\n\nexport async function runDev(opts: ParsedArgs): Promise<void> {\n const cwd = process.cwd();\n const entry = await resolveEntry(cwd, opts.entry);\n\n // Load .env and .env.local files before starting the server\n loadDevEnv(cwd);\n\n console.log(`${c('cyan', '[dev]')} using entry: ${path.relative(cwd, entry)}`);\n console.log(\n `${c('gray', '[dev]')} starting ${c('bold', 'tsx --watch')} and ${c(\n 'bold',\n 'tsc --noEmit --watch',\n )} (async type-checker)`,\n );\n console.log(`${c('gray', 'hint:')} press Ctrl+C to stop`);\n\n // Use --conditions node to ensure proper Node.js module resolution\n // This helps with dynamic require() calls in packages like ioredis\n const app = spawn('npx', ['-y', 'tsx', '--conditions', 'node', '--watch', entry], {\n stdio: 'inherit',\n shell: true,\n });\n const checker = spawn('npx', ['-y', 'tsc', '--noEmit', '--pretty', '--watch'], {\n stdio: 'inherit',\n shell: true,\n });\n\n const cleanup = () => {\n killQuiet(checker);\n killQuiet(app);\n };\n\n process.on('SIGINT', () => {\n cleanup();\n process.exit(0);\n });\n\n await new Promise<void>((resolve, reject) => {\n app.on('close', () => {\n cleanup();\n resolve();\n });\n app.on('error', (err) => {\n cleanup();\n reject(err);\n });\n });\n}\n"]}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Parse a .env file content into key-value pairs.
3
+ * Follows dotenv parsing rules:
4
+ * - Supports KEY=value format
5
+ * - Supports quoted values (single and double quotes)
6
+ * - Supports # comments
7
+ * - Trims whitespace
8
+ * - Expands escape sequences in double-quoted values (\n, \r, \t)
9
+ *
10
+ * @param content - Raw content of a .env file
11
+ * @returns Record of key-value pairs
12
+ */
13
+ export declare function parseEnvContent(content: string): Record<string, string>;
14
+ /**
15
+ * Load environment variables from .env files (synchronous).
16
+ * Follows NestJS-style priority: .env.local overrides .env
17
+ *
18
+ * @param basePath - Base directory to resolve files from
19
+ * @param envPath - Path to base .env file (relative to basePath)
20
+ * @param localEnvPath - Path to local override file (relative to basePath)
21
+ * @returns Record of merged environment variables
22
+ */
23
+ export declare function loadEnvFilesSync(basePath?: string, envPath?: string, localEnvPath?: string): Record<string, string>;
24
+ /**
25
+ * Populate process.env with loaded values.
26
+ * By default, does not override existing values.
27
+ *
28
+ * @param env - Environment variables to populate
29
+ * @param override - Whether to override existing values (default: false)
30
+ */
31
+ export declare function populateProcessEnv(env: Record<string, string>, override?: boolean): void;
32
+ /**
33
+ * Load environment variables for development.
34
+ * Logs the number of loaded variables.
35
+ *
36
+ * @param cwd - Current working directory
37
+ */
38
+ export declare function loadDevEnv(cwd: string): void;
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ // file: libs/cli/src/utils/env.ts
3
+ // CLI-specific environment loading utilities
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.parseEnvContent = parseEnvContent;
6
+ exports.loadEnvFilesSync = loadEnvFilesSync;
7
+ exports.populateProcessEnv = populateProcessEnv;
8
+ exports.loadDevEnv = loadDevEnv;
9
+ const tslib_1 = require("tslib");
10
+ const fs = tslib_1.__importStar(require("fs"));
11
+ const path = tslib_1.__importStar(require("path"));
12
+ const colors_1 = require("../colors");
13
+ /**
14
+ * Parse a .env file content into key-value pairs.
15
+ * Follows dotenv parsing rules:
16
+ * - Supports KEY=value format
17
+ * - Supports quoted values (single and double quotes)
18
+ * - Supports # comments
19
+ * - Trims whitespace
20
+ * - Expands escape sequences in double-quoted values (\n, \r, \t)
21
+ *
22
+ * @param content - Raw content of a .env file
23
+ * @returns Record of key-value pairs
24
+ */
25
+ function parseEnvContent(content) {
26
+ const result = {};
27
+ const lines = content.split('\n');
28
+ for (const line of lines) {
29
+ const trimmed = line.trim();
30
+ // Skip empty lines and comments
31
+ if (!trimmed || trimmed.startsWith('#')) {
32
+ continue;
33
+ }
34
+ // Match KEY=value pattern (KEY can contain letters, numbers, underscores)
35
+ const match = trimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)=(.*)$/);
36
+ if (match) {
37
+ const key = match[1];
38
+ let value = match[2].trim();
39
+ const originalValue = value;
40
+ // Handle quoted values
41
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
42
+ value = value.slice(1, -1);
43
+ }
44
+ // Expand escape sequences in double-quoted values
45
+ // Order matters: handle double-backslash first (as a placeholder),
46
+ // then other escapes, then convert placeholder back
47
+ if (originalValue.startsWith('"')) {
48
+ const PLACEHOLDER = '\x00BACKSLASH\x00';
49
+ value = value
50
+ .replace(/\\\\/g, PLACEHOLDER)
51
+ .replace(/\\n/g, '\n')
52
+ .replace(/\\r/g, '\r')
53
+ .replace(/\\t/g, '\t')
54
+ .replace(new RegExp(PLACEHOLDER, 'g'), '\\');
55
+ }
56
+ result[key] = value;
57
+ }
58
+ }
59
+ return result;
60
+ }
61
+ /**
62
+ * Load environment variables from .env files (synchronous).
63
+ * Follows NestJS-style priority: .env.local overrides .env
64
+ *
65
+ * @param basePath - Base directory to resolve files from
66
+ * @param envPath - Path to base .env file (relative to basePath)
67
+ * @param localEnvPath - Path to local override file (relative to basePath)
68
+ * @returns Record of merged environment variables
69
+ */
70
+ function loadEnvFilesSync(basePath = process.cwd(), envPath = '.env', localEnvPath = '.env.local') {
71
+ const result = {};
72
+ // Load base .env file
73
+ const envFile = path.resolve(basePath, envPath);
74
+ if (fs.existsSync(envFile)) {
75
+ const content = fs.readFileSync(envFile, 'utf8');
76
+ Object.assign(result, parseEnvContent(content));
77
+ }
78
+ // Load .env.local (overrides base)
79
+ const localFile = path.resolve(basePath, localEnvPath);
80
+ if (fs.existsSync(localFile)) {
81
+ const content = fs.readFileSync(localFile, 'utf8');
82
+ Object.assign(result, parseEnvContent(content));
83
+ }
84
+ return result;
85
+ }
86
+ /**
87
+ * Populate process.env with loaded values.
88
+ * By default, does not override existing values.
89
+ *
90
+ * @param env - Environment variables to populate
91
+ * @param override - Whether to override existing values (default: false)
92
+ */
93
+ function populateProcessEnv(env, override = false) {
94
+ for (const [key, value] of Object.entries(env)) {
95
+ if (override || process.env[key] === undefined) {
96
+ process.env[key] = value;
97
+ }
98
+ }
99
+ }
100
+ /**
101
+ * Load environment variables for development.
102
+ * Logs the number of loaded variables.
103
+ *
104
+ * @param cwd - Current working directory
105
+ */
106
+ function loadDevEnv(cwd) {
107
+ try {
108
+ const env = loadEnvFilesSync(cwd, '.env', '.env.local');
109
+ const count = Object.keys(env).length;
110
+ if (count > 0) {
111
+ populateProcessEnv(env, false);
112
+ console.log(`${(0, colors_1.c)('cyan', '[dev]')} loaded ${count} environment variable${count === 1 ? '' : 's'} from .env files`);
113
+ }
114
+ }
115
+ catch (err) {
116
+ const message = err instanceof Error ? err.message : String(err);
117
+ console.warn(`${(0, colors_1.c)('yellow', '[dev]')} warning: failed to load .env files: ${message}`);
118
+ }
119
+ }
120
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../../src/utils/env.ts"],"names":[],"mappings":";AAAA,kCAAkC;AAClC,6CAA6C;;AAkB7C,0CA0CC;AAWD,4CAsBC;AASD,gDAMC;AAQD,gCAeC;;AAjID,+CAAyB;AACzB,mDAA6B;AAC7B,sCAA8B;AAE9B;;;;;;;;;;;GAWG;AACH,SAAgB,eAAe,CAAC,OAAe;IAC7C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAE5B,gCAAgC;QAChC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACxC,SAAS;QACX,CAAC;QAED,0EAA0E;QAC1E,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QAC/D,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACrB,IAAI,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5B,MAAM,aAAa,GAAG,KAAK,CAAC;YAE5B,uBAAuB;YACvB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBACrG,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC7B,CAAC;YAED,kDAAkD;YAClD,mEAAmE;YACnE,oDAAoD;YACpD,IAAI,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClC,MAAM,WAAW,GAAG,mBAAmB,CAAC;gBACxC,KAAK,GAAG,KAAK;qBACV,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC;qBAC7B,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;qBACrB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;qBACrB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;qBACrB,OAAO,CAAC,IAAI,MAAM,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;YACjD,CAAC;YAED,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,gBAAgB,CAC9B,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,EACxB,OAAO,GAAG,MAAM,EAChB,YAAY,GAAG,YAAY;IAE3B,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,sBAAsB;IACtB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChD,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,mCAAmC;IACnC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACvD,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,kBAAkB,CAAC,GAA2B,EAAE,QAAQ,GAAG,KAAK;IAC9E,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,IAAI,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC3B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAgB,UAAU,CAAC,GAAW;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QAEtC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACd,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC/B,OAAO,CAAC,GAAG,CACT,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,KAAK,wBAAwB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,kBAAkB,CACtG,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAA,UAAC,EAAC,QAAQ,EAAE,OAAO,CAAC,wCAAwC,OAAO,EAAE,CAAC,CAAC;IACzF,CAAC;AACH,CAAC","sourcesContent":["// file: libs/cli/src/utils/env.ts\n// CLI-specific environment loading utilities\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { c } from '../colors';\n\n/**\n * Parse a .env file content into key-value pairs.\n * Follows dotenv parsing rules:\n * - Supports KEY=value format\n * - Supports quoted values (single and double quotes)\n * - Supports # comments\n * - Trims whitespace\n * - Expands escape sequences in double-quoted values (\\n, \\r, \\t)\n *\n * @param content - Raw content of a .env file\n * @returns Record of key-value pairs\n */\nexport function parseEnvContent(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n const lines = content.split('\\n');\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Skip empty lines and comments\n if (!trimmed || trimmed.startsWith('#')) {\n continue;\n }\n\n // Match KEY=value pattern (KEY can contain letters, numbers, underscores)\n const match = trimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)=(.*)$/);\n if (match) {\n const key = match[1];\n let value = match[2].trim();\n const originalValue = value;\n\n // Handle quoted values\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n\n // Expand escape sequences in double-quoted values\n // Order matters: handle double-backslash first (as a placeholder),\n // then other escapes, then convert placeholder back\n if (originalValue.startsWith('\"')) {\n const PLACEHOLDER = '\\x00BACKSLASH\\x00';\n value = value\n .replace(/\\\\\\\\/g, PLACEHOLDER)\n .replace(/\\\\n/g, '\\n')\n .replace(/\\\\r/g, '\\r')\n .replace(/\\\\t/g, '\\t')\n .replace(new RegExp(PLACEHOLDER, 'g'), '\\\\');\n }\n\n result[key] = value;\n }\n }\n\n return result;\n}\n\n/**\n * Load environment variables from .env files (synchronous).\n * Follows NestJS-style priority: .env.local overrides .env\n *\n * @param basePath - Base directory to resolve files from\n * @param envPath - Path to base .env file (relative to basePath)\n * @param localEnvPath - Path to local override file (relative to basePath)\n * @returns Record of merged environment variables\n */\nexport function loadEnvFilesSync(\n basePath = process.cwd(),\n envPath = '.env',\n localEnvPath = '.env.local',\n): Record<string, string> {\n const result: Record<string, string> = {};\n\n // Load base .env file\n const envFile = path.resolve(basePath, envPath);\n if (fs.existsSync(envFile)) {\n const content = fs.readFileSync(envFile, 'utf8');\n Object.assign(result, parseEnvContent(content));\n }\n\n // Load .env.local (overrides base)\n const localFile = path.resolve(basePath, localEnvPath);\n if (fs.existsSync(localFile)) {\n const content = fs.readFileSync(localFile, 'utf8');\n Object.assign(result, parseEnvContent(content));\n }\n\n return result;\n}\n\n/**\n * Populate process.env with loaded values.\n * By default, does not override existing values.\n *\n * @param env - Environment variables to populate\n * @param override - Whether to override existing values (default: false)\n */\nexport function populateProcessEnv(env: Record<string, string>, override = false): void {\n for (const [key, value] of Object.entries(env)) {\n if (override || process.env[key] === undefined) {\n process.env[key] = value;\n }\n }\n}\n\n/**\n * Load environment variables for development.\n * Logs the number of loaded variables.\n *\n * @param cwd - Current working directory\n */\nexport function loadDevEnv(cwd: string): void {\n try {\n const env = loadEnvFilesSync(cwd, '.env', '.env.local');\n const count = Object.keys(env).length;\n\n if (count > 0) {\n populateProcessEnv(env, false);\n console.log(\n `${c('cyan', '[dev]')} loaded ${count} environment variable${count === 1 ? '' : 's'} from .env files`,\n );\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.warn(`${c('yellow', '[dev]')} warning: failed to load .env files: ${message}`);\n }\n}\n"]}