@mono-labs/cli 0.0.214 → 0.0.216
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/dist/project/build-mono-readme.js +2 -37
- package/dist/project/index.js +67 -31
- package/dist/types/project/index.d.ts +0 -6
- package/package.json +1 -1
- package/src/project/build-mono-readme.ts +12 -70
- package/src/project/index.ts +110 -59
|
@@ -15,7 +15,6 @@ const OUTPUT_PATH = node_path_1.default.join(REPO_ROOT, 'docs');
|
|
|
15
15
|
const OUTPUT_README = node_path_1.default.join(OUTPUT_PATH, 'command-line.md');
|
|
16
16
|
async function ensureParentDir(filePath) {
|
|
17
17
|
const dir = node_path_1.default.dirname(filePath);
|
|
18
|
-
console.log(`[ensureParentDir] Ensuring directory:`, dir);
|
|
19
18
|
await node_fs_1.promises.mkdir(dir, { recursive: true });
|
|
20
19
|
}
|
|
21
20
|
// ---------- utils ----------
|
|
@@ -23,11 +22,9 @@ async function exists(p) {
|
|
|
23
22
|
try {
|
|
24
23
|
await node_fs_1.promises.access(p);
|
|
25
24
|
// Log existence check
|
|
26
|
-
console.log(`[exists] Path exists:`, p);
|
|
27
25
|
return true;
|
|
28
26
|
}
|
|
29
27
|
catch {
|
|
30
|
-
console.log(`[exists] Path does NOT exist:`, p);
|
|
31
28
|
return false;
|
|
32
29
|
}
|
|
33
30
|
}
|
|
@@ -38,22 +35,17 @@ function toPosix(p) {
|
|
|
38
35
|
return p.split(node_path_1.default.sep).join('/');
|
|
39
36
|
}
|
|
40
37
|
async function readJson(filePath) {
|
|
41
|
-
console.log(`[readJson] Reading JSON file:`, filePath);
|
|
42
38
|
const raw = await node_fs_1.promises.readFile(filePath, 'utf8');
|
|
43
39
|
try {
|
|
44
40
|
const parsed = JSON.parse(raw);
|
|
45
|
-
console.log(`[readJson] Successfully parsed:`, filePath);
|
|
46
41
|
return parsed;
|
|
47
42
|
}
|
|
48
43
|
catch (err) {
|
|
49
|
-
console.error(`[readJson] Failed to parse JSON:`, filePath, err);
|
|
50
44
|
throw err;
|
|
51
45
|
}
|
|
52
46
|
}
|
|
53
47
|
async function listDir(dir) {
|
|
54
|
-
console.log(`[listDir] Listing directory:`, dir);
|
|
55
48
|
const entries = await node_fs_1.promises.readdir(dir, { withFileTypes: true });
|
|
56
|
-
console.log(`[listDir] Found ${entries.length} entries in:`, dir);
|
|
57
49
|
return entries;
|
|
58
50
|
}
|
|
59
51
|
function normalizeWorkspacePatterns(workspacesField) {
|
|
@@ -85,25 +77,20 @@ function matchSegment(patternSeg, name) {
|
|
|
85
77
|
return regex.test(name);
|
|
86
78
|
}
|
|
87
79
|
async function expandWorkspacePattern(root, pattern) {
|
|
88
|
-
console.log(`[expandWorkspacePattern] Expanding pattern:`, pattern, `from root:`, root);
|
|
89
80
|
const segs = toPosix(pattern).split('/').filter(Boolean);
|
|
90
81
|
async function expandFrom(dir, segIndex) {
|
|
91
|
-
console.log(`[expandFrom] Directory:`, dir, `Segment index:`, segIndex);
|
|
92
82
|
if (segIndex >= segs.length)
|
|
93
83
|
return [dir];
|
|
94
84
|
const seg = segs[segIndex];
|
|
95
|
-
console.log(`[expandFrom] Segment:`, seg);
|
|
96
85
|
if (seg === '**') {
|
|
97
86
|
const results = [];
|
|
98
87
|
results.push(...(await expandFrom(dir, segIndex + 1)));
|
|
99
88
|
const entries = await node_fs_1.promises
|
|
100
89
|
.readdir(dir, { withFileTypes: true })
|
|
101
90
|
.catch(() => []);
|
|
102
|
-
console.log(`[expandFrom] '**' entries in ${dir}:`, entries.map((e) => e.name));
|
|
103
91
|
for (const e of entries) {
|
|
104
92
|
if (!e.isDirectory())
|
|
105
93
|
continue;
|
|
106
|
-
console.log(`[expandFrom] Recursing into subdir:`, node_path_1.default.join(dir, e.name));
|
|
107
94
|
results.push(...(await expandFrom(node_path_1.default.join(dir, e.name), segIndex)));
|
|
108
95
|
}
|
|
109
96
|
return results;
|
|
@@ -111,45 +98,34 @@ async function expandWorkspacePattern(root, pattern) {
|
|
|
111
98
|
const entries = await node_fs_1.promises
|
|
112
99
|
.readdir(dir, { withFileTypes: true })
|
|
113
100
|
.catch(() => []);
|
|
114
|
-
console.log(`[expandFrom] Entries in ${dir}:`, entries.map((e) => e.name));
|
|
115
101
|
const results = [];
|
|
116
102
|
for (const e of entries) {
|
|
117
103
|
if (!e.isDirectory())
|
|
118
104
|
continue;
|
|
119
105
|
if (!matchSegment(seg, e.name))
|
|
120
106
|
continue;
|
|
121
|
-
console.log(`[expandFrom] Matched segment '${seg}' with directory:`, e.name);
|
|
122
107
|
results.push(...(await expandFrom(node_path_1.default.join(dir, e.name), segIndex + 1)));
|
|
123
108
|
}
|
|
124
109
|
return results;
|
|
125
110
|
}
|
|
126
111
|
const dirs = await expandFrom(root, 0);
|
|
127
|
-
console.log(`[expandWorkspacePattern] Expanded directories:`, dirs);
|
|
128
112
|
const pkgDirs = [];
|
|
129
113
|
for (const d of dirs) {
|
|
130
114
|
const pkgPath = node_path_1.default.join(d, 'package.json');
|
|
131
115
|
if (await exists(pkgPath)) {
|
|
132
|
-
console.log(`[expandWorkspacePattern] Found package.json:`, pkgPath);
|
|
133
116
|
pkgDirs.push(d);
|
|
134
117
|
}
|
|
135
|
-
else {
|
|
136
|
-
console.log(`[expandWorkspacePattern] No package.json in:`, d);
|
|
137
|
-
}
|
|
138
118
|
}
|
|
139
|
-
console.log(`[expandWorkspacePattern] Final package directories:`, pkgDirs);
|
|
140
119
|
return [...new Set(pkgDirs)];
|
|
141
120
|
}
|
|
142
121
|
async function findWorkspacePackageDirs(repoRoot, workspacePatterns) {
|
|
143
|
-
console.log(`[findWorkspacePackageDirs] repoRoot:`, repoRoot, `workspacePatterns:`, workspacePatterns);
|
|
144
122
|
const dirs = [];
|
|
145
123
|
for (const pat of workspacePatterns) {
|
|
146
|
-
console.log(`[findWorkspacePackageDirs] Expanding pattern:`, pat);
|
|
147
124
|
const expanded = await expandWorkspacePattern(repoRoot, pat);
|
|
148
|
-
|
|
125
|
+
dirs.push(...expanded);
|
|
149
126
|
dirs.push(...expanded);
|
|
150
127
|
}
|
|
151
128
|
const uniqueDirs = [...new Set(dirs)];
|
|
152
|
-
console.log(`[findWorkspacePackageDirs] Final unique package dirs:`, uniqueDirs);
|
|
153
129
|
return uniqueDirs;
|
|
154
130
|
}
|
|
155
131
|
// ---------- .mono parsing ----------
|
|
@@ -162,11 +138,9 @@ async function readMonoConfig() {
|
|
|
162
138
|
}
|
|
163
139
|
try {
|
|
164
140
|
const config = await readJson(configPath);
|
|
165
|
-
console.log(`[readMonoConfig] Loaded mono config.`);
|
|
166
141
|
return { path: configPath, config };
|
|
167
142
|
}
|
|
168
143
|
catch (err) {
|
|
169
|
-
console.error(`[readMonoConfig] Failed to load mono config:`, err);
|
|
170
144
|
return null;
|
|
171
145
|
}
|
|
172
146
|
}
|
|
@@ -174,9 +148,7 @@ function commandNameFromFile(filePath) {
|
|
|
174
148
|
return node_path_1.default.basename(filePath).replace(/\.json$/i, '');
|
|
175
149
|
}
|
|
176
150
|
async function readMonoCommands() {
|
|
177
|
-
console.log(`[readMonoCommands] Reading mono commands from:`, MONO_DIR);
|
|
178
151
|
if (!(await exists(MONO_DIR))) {
|
|
179
|
-
console.log(`[readMonoCommands] Mono directory does not exist.`);
|
|
180
152
|
return [];
|
|
181
153
|
}
|
|
182
154
|
const entries = await listDir(MONO_DIR);
|
|
@@ -184,18 +156,15 @@ async function readMonoCommands() {
|
|
|
184
156
|
.filter((e) => e.isFile() && e.name.toLowerCase().endsWith('.json'))
|
|
185
157
|
.map((e) => node_path_1.default.join(MONO_DIR, e.name))
|
|
186
158
|
.filter((p) => node_path_1.default.basename(p).toLowerCase() !== 'config.json');
|
|
187
|
-
console.log(`[readMonoCommands] Found JSON files:`, jsonFiles);
|
|
188
159
|
const commands = [];
|
|
189
160
|
for (const file of jsonFiles) {
|
|
190
161
|
try {
|
|
191
|
-
console.log(`[readMonoCommands] Reading command file:`, file);
|
|
192
162
|
const j = await readJson(file);
|
|
193
163
|
commands.push({
|
|
194
164
|
name: commandNameFromFile(file),
|
|
195
165
|
file,
|
|
196
166
|
json: j,
|
|
197
167
|
});
|
|
198
|
-
console.log(`[readMonoCommands] Successfully loaded command:`, commandNameFromFile(file));
|
|
199
168
|
}
|
|
200
169
|
catch (err) {
|
|
201
170
|
console.error(`[readMonoCommands] Failed to load command file:`, file, err);
|
|
@@ -203,7 +172,6 @@ async function readMonoCommands() {
|
|
|
203
172
|
}
|
|
204
173
|
}
|
|
205
174
|
commands.sort((a, b) => a.name.localeCompare(b.name));
|
|
206
|
-
console.log(`[readMonoCommands] Final sorted commands:`, commands.map((c) => c.name));
|
|
207
175
|
return commands;
|
|
208
176
|
}
|
|
209
177
|
function parseOptionsSchema(optionsObj) {
|
|
@@ -450,12 +418,10 @@ async function main() {
|
|
|
450
418
|
const monoConfig = await readMonoConfig();
|
|
451
419
|
const monoCommands = await readMonoCommands();
|
|
452
420
|
const pkgDirs = await findWorkspacePackageDirs(REPO_ROOT, workspacePatterns);
|
|
453
|
-
console.log(`[main] Package directories found:`, pkgDirs);
|
|
454
421
|
const packages = [];
|
|
455
422
|
for (const dir of pkgDirs) {
|
|
456
423
|
try {
|
|
457
424
|
const pkgPath = node_path_1.default.join(dir, 'package.json');
|
|
458
|
-
console.log(`[main] Reading package.json:`, pkgPath);
|
|
459
425
|
const pj = await readJson(pkgPath);
|
|
460
426
|
packages.push({
|
|
461
427
|
name: pj.name ||
|
|
@@ -464,7 +430,6 @@ async function main() {
|
|
|
464
430
|
dir,
|
|
465
431
|
scripts: pj.scripts || {},
|
|
466
432
|
});
|
|
467
|
-
console.log(`[main] Loaded package:`, pj.name || dir);
|
|
468
433
|
}
|
|
469
434
|
catch (err) {
|
|
470
435
|
console.error(`[main] Failed to load package.json for:`, dir, err);
|
|
@@ -473,7 +438,7 @@ async function main() {
|
|
|
473
438
|
}
|
|
474
439
|
const parts = [];
|
|
475
440
|
parts.push(`# ⚙️ Command Line Reference
|
|
476
|
-
|
|
441
|
+
|
|
477
442
|
> Generated by \`scripts/generate-readme.mjs\`.
|
|
478
443
|
> Update \`.mono/config.json\`, \`.mono/*.json\`, and workspace package scripts to change this output.
|
|
479
444
|
|
package/dist/project/index.js
CHANGED
|
@@ -4,19 +4,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.loadMergedEnv = exports.loadProjectConfig = void 0;
|
|
7
|
-
exports.detectWorkspaceAndConfigPath = detectWorkspaceAndConfigPath;
|
|
8
7
|
exports.loadAppConfig = loadAppConfig;
|
|
9
8
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
const requiredSystemDefaults = {
|
|
11
|
+
ec2User: 'ec2-user',
|
|
12
|
+
regions: ['us-east-1'],
|
|
13
|
+
};
|
|
14
|
+
/* ──────────────────────────────────────────────────────────
|
|
15
|
+
* Environment helpers
|
|
16
|
+
* ────────────────────────────────────────────────────────── */
|
|
17
|
+
function isLambdaRuntime() {
|
|
18
|
+
return !!process.env.AWS_LAMBDA_FUNCTION_NAME;
|
|
19
|
+
}
|
|
20
|
+
/* ──────────────────────────────────────────────────────────
|
|
21
|
+
* Workspace detection (CLI / local dev only)
|
|
22
|
+
* ────────────────────────────────────────────────────────── */
|
|
23
|
+
function detectWorkspaceAndConfigPath(startDir, configFileName) {
|
|
17
24
|
const cwd = node_path_1.default.resolve(startDir);
|
|
18
25
|
const isWorkspaceRootDir = (dir) => {
|
|
19
|
-
// 1) package.json workspaces
|
|
20
26
|
const pkgPath = node_path_1.default.join(dir, 'package.json');
|
|
21
27
|
if (node_fs_1.default.existsSync(pkgPath)) {
|
|
22
28
|
try {
|
|
@@ -28,41 +34,71 @@ function detectWorkspaceAndConfigPath(startDir = process.cwd(), configFileName =
|
|
|
28
34
|
// ignore
|
|
29
35
|
}
|
|
30
36
|
}
|
|
31
|
-
// 2) other common monorepo root markers (fallback)
|
|
32
37
|
const markers = [
|
|
33
38
|
'pnpm-workspace.yaml',
|
|
34
39
|
'lerna.json',
|
|
35
40
|
'turbo.json',
|
|
36
41
|
'nx.json',
|
|
37
|
-
'.git',
|
|
42
|
+
'.git',
|
|
38
43
|
];
|
|
39
44
|
return markers.some((m) => node_fs_1.default.existsSync(node_path_1.default.join(dir, m)));
|
|
40
45
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
let dir = cwd;
|
|
47
|
+
while (true) {
|
|
48
|
+
if (isWorkspaceRootDir(dir)) {
|
|
49
|
+
return {
|
|
50
|
+
cwd,
|
|
51
|
+
workspaceRoot: dir,
|
|
52
|
+
isWorkspaceRoot: dir === cwd,
|
|
53
|
+
configDir: dir,
|
|
54
|
+
configPath: node_path_1.default.join(dir, configFileName),
|
|
55
|
+
};
|
|
50
56
|
}
|
|
57
|
+
const parent = node_path_1.default.dirname(dir);
|
|
58
|
+
if (parent === dir)
|
|
59
|
+
break;
|
|
60
|
+
dir = parent;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
cwd,
|
|
64
|
+
workspaceRoot: null,
|
|
65
|
+
isWorkspaceRoot: false,
|
|
66
|
+
configDir: cwd,
|
|
67
|
+
configPath: node_path_1.default.join(cwd, configFileName),
|
|
51
68
|
};
|
|
52
|
-
const workspaceRoot = findUp(cwd, isWorkspaceRootDir);
|
|
53
|
-
const isWorkspaceRoot = workspaceRoot !== null && workspaceRoot === cwd;
|
|
54
|
-
// If we are inside a workspace package, config lives at root.
|
|
55
|
-
// If we're already at root, config lives in cwd (same thing).
|
|
56
|
-
const configDir = workspaceRoot ?? cwd;
|
|
57
|
-
const configPath = node_path_1.default.join(configDir, configFileName);
|
|
58
|
-
return { cwd, workspaceRoot, isWorkspaceRoot, configDir, configPath };
|
|
59
69
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
/* ──────────────────────────────────────────────────────────
|
|
71
|
+
* Bundled config loader (Lambda runtime)
|
|
72
|
+
* ────────────────────────────────────────────────────────── */
|
|
73
|
+
function loadConfigFromBundle(fileName) {
|
|
74
|
+
const bundledPath = node_path_1.default.join(__dirname, fileName);
|
|
75
|
+
if (node_fs_1.default.existsSync(bundledPath)) {
|
|
76
|
+
return JSON.parse(node_fs_1.default.readFileSync(bundledPath, 'utf8'));
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
/* ──────────────────────────────────────────────────────────
|
|
81
|
+
* Public API
|
|
82
|
+
* ────────────────────────────────────────────────────────── */
|
|
64
83
|
function loadAppConfig(configType = 'app', startDir = process.cwd()) {
|
|
65
84
|
const fileName = `mono.${configType}.json`;
|
|
85
|
+
// ✅ 1. Lambda runtime: load bundled config if present
|
|
86
|
+
if (isLambdaRuntime()) {
|
|
87
|
+
const bundled = loadConfigFromBundle(fileName);
|
|
88
|
+
if (bundled) {
|
|
89
|
+
return {
|
|
90
|
+
config: bundled,
|
|
91
|
+
meta: {
|
|
92
|
+
cwd: __dirname,
|
|
93
|
+
workspaceRoot: null,
|
|
94
|
+
isWorkspaceRoot: false,
|
|
95
|
+
configDir: __dirname,
|
|
96
|
+
configPath: node_path_1.default.join(__dirname, fileName),
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// ✅ 2. CLI / local dev: workspace discovery
|
|
66
102
|
const meta = detectWorkspaceAndConfigPath(startDir, fileName);
|
|
67
103
|
if (!node_fs_1.default.existsSync(meta.configPath)) {
|
|
68
104
|
const where = meta.workspaceRoot ?
|
|
@@ -72,7 +108,7 @@ function loadAppConfig(configType = 'app', startDir = process.cwd()) {
|
|
|
72
108
|
}
|
|
73
109
|
const raw = node_fs_1.default.readFileSync(meta.configPath, 'utf8');
|
|
74
110
|
const config = JSON.parse(raw);
|
|
75
|
-
// Apply
|
|
111
|
+
// ✅ Apply required system defaults
|
|
76
112
|
if (typeof config === 'object' && config !== null) {
|
|
77
113
|
for (const key of Object.keys(requiredSystemDefaults)) {
|
|
78
114
|
// @ts-ignore: index signature
|
|
@@ -5,12 +5,6 @@ type WorkspaceDetectResult = {
|
|
|
5
5
|
configDir: string;
|
|
6
6
|
configPath: string;
|
|
7
7
|
};
|
|
8
|
-
/**
|
|
9
|
-
* Finds the workspace root by walking up from `startDir`.
|
|
10
|
-
* Works for Yarn/npm workspaces via package.json "workspaces".
|
|
11
|
-
* Also recognizes common mono-repo markers as fallback.
|
|
12
|
-
*/
|
|
13
|
-
export declare function detectWorkspaceAndConfigPath(startDir?: string, configFileName?: string): WorkspaceDetectResult;
|
|
14
8
|
type DefaultAppConfig = {
|
|
15
9
|
appleAppId?: string;
|
|
16
10
|
androidAppId?: string;
|
package/package.json
CHANGED
|
@@ -13,7 +13,6 @@ const OUTPUT_README = path.join(OUTPUT_PATH, 'command-line.md');
|
|
|
13
13
|
|
|
14
14
|
async function ensureParentDir(filePath: string): Promise<void> {
|
|
15
15
|
const dir = path.dirname(filePath);
|
|
16
|
-
console.log(`[ensureParentDir] Ensuring directory:`, dir);
|
|
17
16
|
await fs.mkdir(dir, { recursive: true });
|
|
18
17
|
}
|
|
19
18
|
|
|
@@ -22,10 +21,9 @@ async function exists(p: string): Promise<boolean> {
|
|
|
22
21
|
try {
|
|
23
22
|
await fs.access(p);
|
|
24
23
|
// Log existence check
|
|
25
|
-
|
|
24
|
+
|
|
26
25
|
return true;
|
|
27
26
|
} catch {
|
|
28
|
-
console.log(`[exists] Path does NOT exist:`, p);
|
|
29
27
|
return false;
|
|
30
28
|
}
|
|
31
29
|
}
|
|
@@ -36,21 +34,18 @@ function toPosix(p: string): string {
|
|
|
36
34
|
return p.split(path.sep).join('/');
|
|
37
35
|
}
|
|
38
36
|
async function readJson<T = any>(filePath: string): Promise<T> {
|
|
39
|
-
console.log(`[readJson] Reading JSON file:`, filePath);
|
|
40
37
|
const raw = await fs.readFile(filePath, 'utf8');
|
|
41
38
|
try {
|
|
42
39
|
const parsed = JSON.parse(raw);
|
|
43
|
-
|
|
40
|
+
|
|
44
41
|
return parsed;
|
|
45
42
|
} catch (err) {
|
|
46
|
-
console.error(`[readJson] Failed to parse JSON:`, filePath, err);
|
|
47
43
|
throw err;
|
|
48
44
|
}
|
|
49
45
|
}
|
|
50
46
|
async function listDir(dir: string): Promise<Dirent[]> {
|
|
51
|
-
console.log(`[listDir] Listing directory:`, dir);
|
|
52
47
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
53
|
-
|
|
48
|
+
|
|
54
49
|
return entries;
|
|
55
50
|
}
|
|
56
51
|
function normalizeWorkspacePatterns(workspacesField: unknown): string[] {
|
|
@@ -86,19 +81,11 @@ async function expandWorkspacePattern(
|
|
|
86
81
|
root: string,
|
|
87
82
|
pattern: string
|
|
88
83
|
): Promise<string[]> {
|
|
89
|
-
console.log(
|
|
90
|
-
`[expandWorkspacePattern] Expanding pattern:`,
|
|
91
|
-
pattern,
|
|
92
|
-
`from root:`,
|
|
93
|
-
root
|
|
94
|
-
);
|
|
95
84
|
const segs = toPosix(pattern).split('/').filter(Boolean);
|
|
96
85
|
|
|
97
86
|
async function expandFrom(dir: string, segIndex: number): Promise<string[]> {
|
|
98
|
-
console.log(`[expandFrom] Directory:`, dir, `Segment index:`, segIndex);
|
|
99
87
|
if (segIndex >= segs.length) return [dir];
|
|
100
88
|
const seg = segs[segIndex];
|
|
101
|
-
console.log(`[expandFrom] Segment:`, seg);
|
|
102
89
|
|
|
103
90
|
if (seg === '**') {
|
|
104
91
|
const results: string[] = [];
|
|
@@ -106,16 +93,10 @@ async function expandWorkspacePattern(
|
|
|
106
93
|
const entries = await fs
|
|
107
94
|
.readdir(dir, { withFileTypes: true })
|
|
108
95
|
.catch(() => []);
|
|
109
|
-
|
|
110
|
-
`[expandFrom] '**' entries in ${dir}:`,
|
|
111
|
-
entries.map((e) => e.name)
|
|
112
|
-
);
|
|
96
|
+
|
|
113
97
|
for (const e of entries) {
|
|
114
98
|
if (!e.isDirectory()) continue;
|
|
115
|
-
|
|
116
|
-
`[expandFrom] Recursing into subdir:`,
|
|
117
|
-
path.join(dir, e.name)
|
|
118
|
-
);
|
|
99
|
+
|
|
119
100
|
results.push(...(await expandFrom(path.join(dir, e.name), segIndex)));
|
|
120
101
|
}
|
|
121
102
|
return results;
|
|
@@ -124,36 +105,27 @@ async function expandWorkspacePattern(
|
|
|
124
105
|
const entries = await fs
|
|
125
106
|
.readdir(dir, { withFileTypes: true })
|
|
126
107
|
.catch(() => []);
|
|
127
|
-
|
|
128
|
-
`[expandFrom] Entries in ${dir}:`,
|
|
129
|
-
entries.map((e) => e.name)
|
|
130
|
-
);
|
|
108
|
+
|
|
131
109
|
const results: string[] = [];
|
|
132
110
|
for (const e of entries) {
|
|
133
111
|
if (!e.isDirectory()) continue;
|
|
134
112
|
if (!matchSegment(seg, e.name)) continue;
|
|
135
|
-
|
|
136
|
-
`[expandFrom] Matched segment '${seg}' with directory:`,
|
|
137
|
-
e.name
|
|
138
|
-
);
|
|
113
|
+
|
|
139
114
|
results.push(...(await expandFrom(path.join(dir, e.name), segIndex + 1)));
|
|
140
115
|
}
|
|
141
116
|
return results;
|
|
142
117
|
}
|
|
143
118
|
|
|
144
119
|
const dirs = await expandFrom(root, 0);
|
|
145
|
-
|
|
120
|
+
|
|
146
121
|
const pkgDirs: string[] = [];
|
|
147
122
|
for (const d of dirs) {
|
|
148
123
|
const pkgPath = path.join(d, 'package.json');
|
|
149
124
|
if (await exists(pkgPath)) {
|
|
150
|
-
console.log(`[expandWorkspacePattern] Found package.json:`, pkgPath);
|
|
151
125
|
pkgDirs.push(d);
|
|
152
|
-
} else {
|
|
153
|
-
console.log(`[expandWorkspacePattern] No package.json in:`, d);
|
|
154
126
|
}
|
|
155
127
|
}
|
|
156
|
-
|
|
128
|
+
|
|
157
129
|
return [...new Set(pkgDirs)];
|
|
158
130
|
}
|
|
159
131
|
|
|
@@ -161,27 +133,13 @@ async function findWorkspacePackageDirs(
|
|
|
161
133
|
repoRoot: string,
|
|
162
134
|
workspacePatterns: string[]
|
|
163
135
|
): Promise<string[]> {
|
|
164
|
-
console.log(
|
|
165
|
-
`[findWorkspacePackageDirs] repoRoot:`,
|
|
166
|
-
repoRoot,
|
|
167
|
-
`workspacePatterns:`,
|
|
168
|
-
workspacePatterns
|
|
169
|
-
);
|
|
170
136
|
const dirs: string[] = [];
|
|
171
137
|
for (const pat of workspacePatterns) {
|
|
172
|
-
console.log(`[findWorkspacePackageDirs] Expanding pattern:`, pat);
|
|
173
138
|
const expanded = await expandWorkspacePattern(repoRoot, pat);
|
|
174
|
-
|
|
175
|
-
`[findWorkspacePackageDirs] Expanded dirs for pattern '${pat}':`,
|
|
176
|
-
expanded
|
|
177
|
-
);
|
|
139
|
+
dirs.push(...expanded);
|
|
178
140
|
dirs.push(...expanded);
|
|
179
141
|
}
|
|
180
142
|
const uniqueDirs = [...new Set(dirs)];
|
|
181
|
-
console.log(
|
|
182
|
-
`[findWorkspacePackageDirs] Final unique package dirs:`,
|
|
183
|
-
uniqueDirs
|
|
184
|
-
);
|
|
185
143
|
return uniqueDirs;
|
|
186
144
|
}
|
|
187
145
|
|
|
@@ -195,10 +153,8 @@ async function readMonoConfig(): Promise<MonoConfig | null> {
|
|
|
195
153
|
}
|
|
196
154
|
try {
|
|
197
155
|
const config = await readJson<any>(configPath);
|
|
198
|
-
console.log(`[readMonoConfig] Loaded mono config.`);
|
|
199
156
|
return { path: configPath, config };
|
|
200
157
|
} catch (err) {
|
|
201
|
-
console.error(`[readMonoConfig] Failed to load mono config:`, err);
|
|
202
158
|
return null;
|
|
203
159
|
}
|
|
204
160
|
}
|
|
@@ -208,9 +164,7 @@ function commandNameFromFile(filePath: string): string {
|
|
|
208
164
|
}
|
|
209
165
|
|
|
210
166
|
async function readMonoCommands(): Promise<MonoCommand[]> {
|
|
211
|
-
console.log(`[readMonoCommands] Reading mono commands from:`, MONO_DIR);
|
|
212
167
|
if (!(await exists(MONO_DIR))) {
|
|
213
|
-
console.log(`[readMonoCommands] Mono directory does not exist.`);
|
|
214
168
|
return [];
|
|
215
169
|
}
|
|
216
170
|
const entries = await listDir(MONO_DIR);
|
|
@@ -220,21 +174,15 @@ async function readMonoCommands(): Promise<MonoCommand[]> {
|
|
|
220
174
|
.map((e) => path.join(MONO_DIR, e.name))
|
|
221
175
|
.filter((p) => path.basename(p).toLowerCase() !== 'config.json');
|
|
222
176
|
|
|
223
|
-
console.log(`[readMonoCommands] Found JSON files:`, jsonFiles);
|
|
224
177
|
const commands: MonoCommand[] = [];
|
|
225
178
|
for (const file of jsonFiles) {
|
|
226
179
|
try {
|
|
227
|
-
console.log(`[readMonoCommands] Reading command file:`, file);
|
|
228
180
|
const j = await readJson<any>(file);
|
|
229
181
|
commands.push({
|
|
230
182
|
name: commandNameFromFile(file),
|
|
231
183
|
file,
|
|
232
184
|
json: j,
|
|
233
185
|
});
|
|
234
|
-
console.log(
|
|
235
|
-
`[readMonoCommands] Successfully loaded command:`,
|
|
236
|
-
commandNameFromFile(file)
|
|
237
|
-
);
|
|
238
186
|
} catch (err) {
|
|
239
187
|
console.error(
|
|
240
188
|
`[readMonoCommands] Failed to load command file:`,
|
|
@@ -246,10 +194,7 @@ async function readMonoCommands(): Promise<MonoCommand[]> {
|
|
|
246
194
|
}
|
|
247
195
|
|
|
248
196
|
commands.sort((a, b) => a.name.localeCompare(b.name));
|
|
249
|
-
|
|
250
|
-
`[readMonoCommands] Final sorted commands:`,
|
|
251
|
-
commands.map((c) => c.name)
|
|
252
|
-
);
|
|
197
|
+
|
|
253
198
|
return commands;
|
|
254
199
|
}
|
|
255
200
|
|
|
@@ -601,12 +546,10 @@ async function main(): Promise<void> {
|
|
|
601
546
|
const monoCommands = await readMonoCommands();
|
|
602
547
|
|
|
603
548
|
const pkgDirs = await findWorkspacePackageDirs(REPO_ROOT, workspacePatterns);
|
|
604
|
-
console.log(`[main] Package directories found:`, pkgDirs);
|
|
605
549
|
const packages: PackageInfo[] = [];
|
|
606
550
|
for (const dir of pkgDirs) {
|
|
607
551
|
try {
|
|
608
552
|
const pkgPath = path.join(dir, 'package.json');
|
|
609
|
-
console.log(`[main] Reading package.json:`, pkgPath);
|
|
610
553
|
const pj = await readJson<any>(pkgPath);
|
|
611
554
|
packages.push({
|
|
612
555
|
name:
|
|
@@ -616,7 +559,6 @@ async function main(): Promise<void> {
|
|
|
616
559
|
dir,
|
|
617
560
|
scripts: pj.scripts || {},
|
|
618
561
|
});
|
|
619
|
-
console.log(`[main] Loaded package:`, pj.name || dir);
|
|
620
562
|
} catch (err) {
|
|
621
563
|
console.error(`[main] Failed to load package.json for:`, dir, err);
|
|
622
564
|
// skip
|
|
@@ -625,7 +567,7 @@ async function main(): Promise<void> {
|
|
|
625
567
|
|
|
626
568
|
const parts: string[] = [];
|
|
627
569
|
parts.push(`# ⚙️ Command Line Reference
|
|
628
|
-
|
|
570
|
+
|
|
629
571
|
> Generated by \`scripts/generate-readme.mjs\`.
|
|
630
572
|
> Update \`.mono/config.json\`, \`.mono/*.json\`, and workspace package scripts to change this output.
|
|
631
573
|
|
package/src/project/index.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
+
/* ──────────────────────────────────────────────────────────
|
|
5
|
+
* Types
|
|
6
|
+
* ────────────────────────────────────────────────────────── */
|
|
7
|
+
|
|
4
8
|
type WorkspaceDetectResult = {
|
|
5
9
|
cwd: string;
|
|
6
10
|
workspaceRoot: string | null;
|
|
@@ -9,64 +13,6 @@ type WorkspaceDetectResult = {
|
|
|
9
13
|
configPath: string;
|
|
10
14
|
};
|
|
11
15
|
|
|
12
|
-
/**
|
|
13
|
-
* Finds the workspace root by walking up from `startDir`.
|
|
14
|
-
* Works for Yarn/npm workspaces via package.json "workspaces".
|
|
15
|
-
* Also recognizes common mono-repo markers as fallback.
|
|
16
|
-
*/
|
|
17
|
-
export function detectWorkspaceAndConfigPath(
|
|
18
|
-
startDir: string = process.cwd(),
|
|
19
|
-
configFileName: string = 'mono.app.json'
|
|
20
|
-
): WorkspaceDetectResult {
|
|
21
|
-
const cwd = path.resolve(startDir);
|
|
22
|
-
|
|
23
|
-
const isWorkspaceRootDir = (dir: string): boolean => {
|
|
24
|
-
// 1) package.json workspaces
|
|
25
|
-
const pkgPath = path.join(dir, 'package.json');
|
|
26
|
-
if (fs.existsSync(pkgPath)) {
|
|
27
|
-
try {
|
|
28
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) as any;
|
|
29
|
-
if (pkg?.workspaces) return true;
|
|
30
|
-
} catch {
|
|
31
|
-
// ignore
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// 2) other common monorepo root markers (fallback)
|
|
36
|
-
const markers = [
|
|
37
|
-
'pnpm-workspace.yaml',
|
|
38
|
-
'lerna.json',
|
|
39
|
-
'turbo.json',
|
|
40
|
-
'nx.json',
|
|
41
|
-
'.git', // good enough for many repos
|
|
42
|
-
];
|
|
43
|
-
return markers.some((m) => fs.existsSync(path.join(dir, m)));
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const findUp = (
|
|
47
|
-
from: string,
|
|
48
|
-
predicate: (dir: string) => boolean
|
|
49
|
-
): string | null => {
|
|
50
|
-
let dir = path.resolve(from);
|
|
51
|
-
while (true) {
|
|
52
|
-
if (predicate(dir)) return dir;
|
|
53
|
-
const parent = path.dirname(dir);
|
|
54
|
-
if (parent === dir) return null; // reached filesystem root
|
|
55
|
-
dir = parent;
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const workspaceRoot = findUp(cwd, isWorkspaceRootDir);
|
|
60
|
-
const isWorkspaceRoot = workspaceRoot !== null && workspaceRoot === cwd;
|
|
61
|
-
|
|
62
|
-
// If we are inside a workspace package, config lives at root.
|
|
63
|
-
// If we're already at root, config lives in cwd (same thing).
|
|
64
|
-
const configDir = workspaceRoot ?? cwd;
|
|
65
|
-
const configPath = path.join(configDir, configFileName);
|
|
66
|
-
|
|
67
|
-
return { cwd, workspaceRoot, isWorkspaceRoot, configDir, configPath };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
16
|
type DefaultAppConfig = {
|
|
71
17
|
appleAppId?: string;
|
|
72
18
|
androidAppId?: string;
|
|
@@ -103,11 +49,115 @@ type ConfigTypeMap = {
|
|
|
103
49
|
type ResolveConfig<TType extends string, TCustom = unknown> =
|
|
104
50
|
TType extends keyof ConfigTypeMap ? ConfigTypeMap[TType] : TCustom;
|
|
105
51
|
|
|
52
|
+
/* ──────────────────────────────────────────────────────────
|
|
53
|
+
* Environment helpers
|
|
54
|
+
* ────────────────────────────────────────────────────────── */
|
|
55
|
+
|
|
56
|
+
function isLambdaRuntime(): boolean {
|
|
57
|
+
return !!process.env.AWS_LAMBDA_FUNCTION_NAME;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* ──────────────────────────────────────────────────────────
|
|
61
|
+
* Workspace detection (CLI / local dev only)
|
|
62
|
+
* ────────────────────────────────────────────────────────── */
|
|
63
|
+
|
|
64
|
+
function detectWorkspaceAndConfigPath(
|
|
65
|
+
startDir: string,
|
|
66
|
+
configFileName: string
|
|
67
|
+
): WorkspaceDetectResult {
|
|
68
|
+
const cwd = path.resolve(startDir);
|
|
69
|
+
|
|
70
|
+
const isWorkspaceRootDir = (dir: string): boolean => {
|
|
71
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
72
|
+
if (fs.existsSync(pkgPath)) {
|
|
73
|
+
try {
|
|
74
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
75
|
+
if (pkg?.workspaces) return true;
|
|
76
|
+
} catch {
|
|
77
|
+
// ignore
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const markers = [
|
|
82
|
+
'pnpm-workspace.yaml',
|
|
83
|
+
'lerna.json',
|
|
84
|
+
'turbo.json',
|
|
85
|
+
'nx.json',
|
|
86
|
+
'.git',
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
return markers.some((m) => fs.existsSync(path.join(dir, m)));
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
let dir = cwd;
|
|
93
|
+
while (true) {
|
|
94
|
+
if (isWorkspaceRootDir(dir)) {
|
|
95
|
+
return {
|
|
96
|
+
cwd,
|
|
97
|
+
workspaceRoot: dir,
|
|
98
|
+
isWorkspaceRoot: dir === cwd,
|
|
99
|
+
configDir: dir,
|
|
100
|
+
configPath: path.join(dir, configFileName),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const parent = path.dirname(dir);
|
|
105
|
+
if (parent === dir) break;
|
|
106
|
+
dir = parent;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
cwd,
|
|
111
|
+
workspaceRoot: null,
|
|
112
|
+
isWorkspaceRoot: false,
|
|
113
|
+
configDir: cwd,
|
|
114
|
+
configPath: path.join(cwd, configFileName),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* ──────────────────────────────────────────────────────────
|
|
119
|
+
* Bundled config loader (Lambda runtime)
|
|
120
|
+
* ────────────────────────────────────────────────────────── */
|
|
121
|
+
|
|
122
|
+
function loadConfigFromBundle(fileName: string): unknown | null {
|
|
123
|
+
const bundledPath = path.join(__dirname, fileName);
|
|
124
|
+
|
|
125
|
+
if (fs.existsSync(bundledPath)) {
|
|
126
|
+
return JSON.parse(fs.readFileSync(bundledPath, 'utf8'));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* ──────────────────────────────────────────────────────────
|
|
133
|
+
* Public API
|
|
134
|
+
* ────────────────────────────────────────────────────────── */
|
|
135
|
+
|
|
106
136
|
export function loadAppConfig<TCustom = unknown, TType extends string = 'app'>(
|
|
107
137
|
configType: TType = 'app' as TType,
|
|
108
138
|
startDir: string = process.cwd()
|
|
109
139
|
): { config: ResolveConfig<TType, TCustom>; meta: WorkspaceDetectResult } {
|
|
110
140
|
const fileName = `mono.${configType}.json`;
|
|
141
|
+
|
|
142
|
+
// ✅ 1. Lambda runtime: load bundled config if present
|
|
143
|
+
if (isLambdaRuntime()) {
|
|
144
|
+
const bundled = loadConfigFromBundle(fileName);
|
|
145
|
+
|
|
146
|
+
if (bundled) {
|
|
147
|
+
return {
|
|
148
|
+
config: bundled as ResolveConfig<TType, TCustom>,
|
|
149
|
+
meta: {
|
|
150
|
+
cwd: __dirname,
|
|
151
|
+
workspaceRoot: null,
|
|
152
|
+
isWorkspaceRoot: false,
|
|
153
|
+
configDir: __dirname,
|
|
154
|
+
configPath: path.join(__dirname, fileName),
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ✅ 2. CLI / local dev: workspace discovery
|
|
111
161
|
const meta = detectWorkspaceAndConfigPath(startDir, fileName);
|
|
112
162
|
|
|
113
163
|
if (!fs.existsSync(meta.configPath)) {
|
|
@@ -115,6 +165,7 @@ export function loadAppConfig<TCustom = unknown, TType extends string = 'app'>(
|
|
|
115
165
|
meta.workspaceRoot ?
|
|
116
166
|
`workspace root: ${meta.workspaceRoot}`
|
|
117
167
|
: `cwd: ${meta.cwd}`;
|
|
168
|
+
|
|
118
169
|
throw new Error(
|
|
119
170
|
`Could not find ${fileName} at ${meta.configPath} (detected from ${where}).`
|
|
120
171
|
);
|
|
@@ -123,7 +174,7 @@ export function loadAppConfig<TCustom = unknown, TType extends string = 'app'>(
|
|
|
123
174
|
const raw = fs.readFileSync(meta.configPath, 'utf8');
|
|
124
175
|
const config = JSON.parse(raw) as ResolveConfig<TType, TCustom>;
|
|
125
176
|
|
|
126
|
-
// Apply
|
|
177
|
+
// ✅ Apply required system defaults
|
|
127
178
|
if (typeof config === 'object' && config !== null) {
|
|
128
179
|
for (const key of Object.keys(requiredSystemDefaults)) {
|
|
129
180
|
// @ts-ignore: index signature
|