@mono-labs/cli 0.0.203 → 0.0.205

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.
@@ -0,0 +1,311 @@
1
+ // scripts/generate-repo-help.mjs
2
+ // Generates a developer-friendly workspace command reference.
3
+ //
4
+ // Output: docs/workspaces.md
5
+ //
6
+ // Run (from repo root):
7
+ // node ./scripts/generate-repo-help.mjs
8
+ //
9
+ // Philosophy:
10
+ // - Optimize for onboarding and day-to-day use
11
+ // - Keep raw yarn workspace commands for reference
12
+ // - Emphasize `yarn mono` as the primary interface
13
+ import { promises as fs } from 'node:fs';
14
+ import path from 'node:path';
15
+ import { generateDocsIndex } from './generate-docs.js';
16
+ // ----------------- config -----------------
17
+ // Always use the working directory as the root for all file actions
18
+ const REPO_ROOT = path.resolve(process.cwd());
19
+ const ROOT_PKG_JSON = path.join(REPO_ROOT, 'package.json');
20
+ const OUTPUT_PATH = path.join(REPO_ROOT, 'docs', 'workspaces.md');
21
+ // ----------------- helpers -----------------
22
+ async function exists(p) {
23
+ // Always resolve path relative to working directory
24
+ const absPath = path.resolve(process.cwd(), p);
25
+ try {
26
+ await fs.access(absPath);
27
+ return true;
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ function isObject(v) {
34
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
35
+ }
36
+ function toPosix(p) {
37
+ return p.split(path.sep).join('/');
38
+ }
39
+ function mdEscapeInline(s) {
40
+ return String(s ?? '').replaceAll('`', '\`');
41
+ }
42
+ function slugifyForGithubAnchor(title) {
43
+ return String(title ?? '')
44
+ .trim()
45
+ .toLowerCase()
46
+ .replace(/[^\w\s-]/g, '')
47
+ .replace(/\s+/g, '-')
48
+ .replace(/-+/g, '-');
49
+ }
50
+ async function readJson(filePath) {
51
+ // Always resolve filePath relative to working directory
52
+ const absPath = path.resolve(process.cwd(), filePath);
53
+ const raw = await fs.readFile(absPath, 'utf8');
54
+ return JSON.parse(raw);
55
+ }
56
+ function normalizeWorkspacePatterns(workspacesField) {
57
+ if (Array.isArray(workspacesField))
58
+ return workspacesField;
59
+ if (isObject(workspacesField) &&
60
+ Array.isArray(workspacesField.packages))
61
+ return workspacesField.packages;
62
+ return [];
63
+ }
64
+ // ----------------- glob expansion -----------------
65
+ function matchSegment(patternSeg, name) {
66
+ if (patternSeg === '*')
67
+ return true;
68
+ if (!patternSeg.includes('*'))
69
+ return patternSeg === name;
70
+ const escaped = patternSeg.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
71
+ const regex = new RegExp('^' + escaped.replaceAll('*', '.*') + '$');
72
+ return regex.test(name);
73
+ }
74
+ async function expandWorkspacePattern(root, pattern) {
75
+ const segs = toPosix(pattern).split('/').filter(Boolean);
76
+ async function expandFrom(dir, segIndex) {
77
+ // Always resolve dir relative to working directory
78
+ const absDir = path.resolve(process.cwd(), dir);
79
+ if (segIndex >= segs.length)
80
+ return [absDir];
81
+ const seg = segs[segIndex];
82
+ if (seg === '**') {
83
+ const results = [];
84
+ results.push(...(await expandFrom(absDir, segIndex + 1)));
85
+ const entries = await fs
86
+ .readdir(absDir, { withFileTypes: true })
87
+ .catch(() => []);
88
+ for (const e of entries) {
89
+ if (e.isDirectory()) {
90
+ results.push(...(await expandFrom(path.join(absDir, e.name), segIndex)));
91
+ }
92
+ }
93
+ return results;
94
+ }
95
+ const entries = await fs
96
+ .readdir(absDir, { withFileTypes: true })
97
+ .catch(() => []);
98
+ const results = [];
99
+ for (const e of entries) {
100
+ if (e.isDirectory() && matchSegment(seg, e.name)) {
101
+ results.push(...(await expandFrom(path.join(absDir, e.name), segIndex + 1)));
102
+ }
103
+ }
104
+ return results;
105
+ }
106
+ return [...new Set(await expandFrom(root, 0))];
107
+ }
108
+ async function findWorkspaceRoots(repoRoot, workspacePatterns) {
109
+ const roots = [];
110
+ for (const pat of workspacePatterns) {
111
+ const expandedDirs = await expandWorkspacePattern(repoRoot, pat);
112
+ roots.push(...expandedDirs);
113
+ }
114
+ return [...new Set(roots)];
115
+ }
116
+ // ----------------- package discovery -----------------
117
+ const SKIP_DIRS = new Set([
118
+ 'node_modules',
119
+ '.git',
120
+ '.next',
121
+ 'dist',
122
+ 'build',
123
+ 'out',
124
+ 'coverage',
125
+ '.turbo',
126
+ ]);
127
+ async function findPackageJsonFilesRecursive(startDir) {
128
+ const found = [];
129
+ async function walk(dir) {
130
+ // Always resolve dir relative to working directory
131
+ const absDir = path.resolve(process.cwd(), dir);
132
+ const entries = await fs
133
+ .readdir(absDir, { withFileTypes: true })
134
+ .catch(() => []);
135
+ for (const e of entries) {
136
+ const full = path.join(absDir, e.name);
137
+ if (e.isDirectory()) {
138
+ if (!SKIP_DIRS.has(e.name))
139
+ await walk(full);
140
+ }
141
+ else if (e.isFile() && e.name === 'package.json') {
142
+ found.push(full);
143
+ }
144
+ }
145
+ }
146
+ await walk(startDir);
147
+ return found;
148
+ }
149
+ async function collectPackagesFromWorkspaceRoots(workspaceRoots) {
150
+ const pkgJsonFiles = [];
151
+ for (const root of workspaceRoots) {
152
+ if (await exists(root)) {
153
+ pkgJsonFiles.push(...(await findPackageJsonFilesRecursive(root)));
154
+ }
155
+ }
156
+ const packages = [];
157
+ for (const file of [...new Set(pkgJsonFiles)]) {
158
+ if (path.resolve(file) === path.resolve(ROOT_PKG_JSON))
159
+ continue;
160
+ try {
161
+ const pj = await readJson(file);
162
+ const dir = path.dirname(file);
163
+ packages.push({
164
+ name: pj.name || toPosix(path.relative(REPO_ROOT, dir)),
165
+ dir,
166
+ scripts: isObject(pj.scripts) ? pj.scripts : {},
167
+ });
168
+ }
169
+ catch { }
170
+ }
171
+ const seen = new Set();
172
+ return packages
173
+ .sort((a, b) => a.name.localeCompare(b.name))
174
+ .filter((p) => (seen.has(p.name) ? false : seen.add(p.name)));
175
+ }
176
+ // ----------------- classification -----------------
177
+ function classifyPackage(pkg) {
178
+ const p = toPosix(pkg.dir);
179
+ if (p.startsWith('apps/'))
180
+ return 'Apps';
181
+ if (p.startsWith('packages/'))
182
+ return 'Libraries';
183
+ return 'Other';
184
+ }
185
+ // ----------------- markdown generation -----------------
186
+ function formatQuickStart(pkgMgr) {
187
+ return [
188
+ '# 🗂️ Workspace Overview',
189
+ '',
190
+ 'This document explains how to run and discover commands in this monorepo.',
191
+ '',
192
+ '---',
193
+ '',
194
+ '## 🚀 Quick Start',
195
+ '',
196
+ 'Most developers only need the following:',
197
+ '',
198
+ '```bash',
199
+ `${pkgMgr} dev`,
200
+ `${pkgMgr} serve`,
201
+ `${pkgMgr} mobile`,
202
+ `${pkgMgr} help`,
203
+ '```',
204
+ '',
205
+ 'Use `yarn mono` whenever possible. It handles environment setup,',
206
+ 'workspace routing, and service coordination automatically.',
207
+ '',
208
+ '---',
209
+ '',
210
+ ];
211
+ }
212
+ function formatReferenceIntro() {
213
+ return [
214
+ '## 📖 Reference',
215
+ '',
216
+ 'This section lists all workspace packages and their available scripts.',
217
+ '',
218
+ 'Use this when:',
219
+ '- Debugging',
220
+ '- Working on internal libraries',
221
+ '- Running CI or low-level tooling',
222
+ '',
223
+ ];
224
+ }
225
+ function formatIndex(packages) {
226
+ const groups = {};
227
+ for (const p of packages) {
228
+ const g = classifyPackage(p);
229
+ groups[g] ||= [];
230
+ groups[g].push(p);
231
+ }
232
+ const lines = ['## Workspace Index', ''];
233
+ for (const group of Object.keys(groups)) {
234
+ lines.push(`### ${group}`);
235
+ lines.push('');
236
+ for (const p of groups[group]) {
237
+ lines.push(`- [\`${mdEscapeInline(p.name)}\`](#${slugifyForGithubAnchor(p.name)})`);
238
+ }
239
+ lines.push('');
240
+ }
241
+ return lines;
242
+ }
243
+ function formatPackages(packages) {
244
+ const lines = [];
245
+ for (const p of packages) {
246
+ lines.push(`### ${p.name}`);
247
+ lines.push('');
248
+ lines.push(`_Location: \`${toPosix(path.relative(REPO_ROOT, p.dir))}\`_`);
249
+ lines.push('');
250
+ const scripts = Object.keys(p.scripts).sort();
251
+ if (!scripts.length) {
252
+ lines.push('_No scripts defined._');
253
+ lines.push('');
254
+ continue;
255
+ }
256
+ lines.push('| Script | Recommended |');
257
+ lines.push('|------|-------------|');
258
+ for (const s of scripts) {
259
+ lines.push(`| \`${s}\` | \`yarn mono ${p.name} ${s}\` |`);
260
+ }
261
+ lines.push('');
262
+ lines.push('<details>');
263
+ lines.push('<summary>Raw yarn workspace commands</summary>');
264
+ lines.push('');
265
+ for (const s of scripts) {
266
+ lines.push(`- \`yarn workspace ${p.name} ${s}\``);
267
+ }
268
+ lines.push('</details>');
269
+ lines.push('');
270
+ }
271
+ return lines;
272
+ }
273
+ async function ensureParentDir(filePath) {
274
+ // Always resolve parent dir relative to working directory
275
+ const dir = path.resolve(process.cwd(), path.dirname(filePath));
276
+ await fs.mkdir(dir, { recursive: true });
277
+ }
278
+ // ----------------- main -----------------
279
+ async function main() {
280
+ // Always resolve all paths relative to working directory
281
+ if (!(await exists(ROOT_PKG_JSON))) {
282
+ throw new Error('Root package.json not found');
283
+ }
284
+ const rootPkg = await readJson(ROOT_PKG_JSON);
285
+ const workspacePatterns = normalizeWorkspacePatterns(rootPkg.workspaces);
286
+ const pkgMgr = `${(rootPkg.packageManager || 'yarn').split('@')[0]} mono`;
287
+ const workspaceRoots = await findWorkspaceRoots(REPO_ROOT, workspacePatterns);
288
+ const fallbackRoots = ['packages', 'apps'].map((p) => path.join(REPO_ROOT, p));
289
+ const roots = workspaceRoots.length ? workspaceRoots : fallbackRoots;
290
+ const packages = await collectPackagesFromWorkspaceRoots(roots);
291
+ const lines = [];
292
+ lines.push(...formatQuickStart(pkgMgr));
293
+ lines.push(...formatReferenceIntro());
294
+ lines.push(...formatIndex(packages));
295
+ lines.push('## Packages');
296
+ lines.push('');
297
+ lines.push(...formatPackages(packages));
298
+ const val = await generateDocsIndex({
299
+ docsDir: path.join(REPO_ROOT, 'docs'),
300
+ excludeFile: 'workspaces.md',
301
+ });
302
+ val.split('\n').forEach((line) => lines.push(line));
303
+ await ensureParentDir(OUTPUT_PATH);
304
+ await fs.writeFile(OUTPUT_PATH, lines.join('\n'), 'utf8');
305
+ console.log(`✅ Generated ${OUTPUT_PATH}`);
306
+ console.log(`📦 Packages found: ${packages.length}`);
307
+ }
308
+ main().catch((err) => {
309
+ console.error(err);
310
+ process.exitCode = 1;
311
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import './build-mono-readme';
2
+ import './generate-readme';
@@ -0,0 +1,11 @@
1
+ export interface GenerateDocsIndexOptions {
2
+ docsDir: string;
3
+ excludeFile?: string;
4
+ }
5
+ /**
6
+ * Generate a docs index from markdown files.
7
+ *
8
+ * @param options - Options for docs index generation
9
+ * @returns Markdown-formatted index
10
+ */
11
+ export declare function generateDocsIndex({ docsDir, excludeFile, }: GenerateDocsIndexOptions): Promise<string>;
@@ -0,0 +1 @@
1
+ export {};
@@ -25,6 +25,8 @@ type DefaultDeployConfig = {
25
25
  defaultKeyPair?: string;
26
26
  regions: string[];
27
27
  ec2User: string;
28
+ defaultVpcId?: string;
29
+ defaultVpcSecurityGroupId?: string;
28
30
  };
29
31
  type ConfigTypeMap = {
30
32
  app: DefaultAppConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mono-labs/cli",
3
- "version": "0.0.203",
3
+ "version": "0.0.205",
4
4
  "description": "A CLI tool for building and deploying projects",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",