@mono-labs/cli 0.0.238 → 0.0.242

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.
Files changed (179) hide show
  1. package/bin/mono.js +1 -1
  2. package/dist/index.js +32 -51
  3. package/dist/lib/app.js +52 -0
  4. package/dist/lib/commands/build-process/boot.js +12 -0
  5. package/dist/lib/commands/build-process/cliFactory.js +145 -0
  6. package/dist/lib/commands/build-process/dataLayer.js +56 -0
  7. package/dist/lib/commands/build-process/index.js +11 -0
  8. package/dist/lib/commands/build-process/readEnv.js +34 -0
  9. package/dist/lib/commands/build-process/runMonoCommand.js +82 -0
  10. package/dist/lib/commands/build-process/runners/processManager.js +45 -0
  11. package/dist/lib/commands/build-process/runners/runBackground.js +46 -0
  12. package/dist/lib/commands/build-process/runners/runForeground.js +52 -0
  13. package/dist/lib/commands/build-process/test.js +32 -0
  14. package/dist/lib/commands/build-process/testflag.js +4 -0
  15. package/dist/lib/commands/build-process/validators.js +17 -0
  16. package/dist/lib/commands/loadFromRoot.js +53 -0
  17. package/dist/lib/commands/prune/index.js +10 -0
  18. package/dist/lib/commands/prune/prune.js +49 -0
  19. package/dist/lib/config.js +6 -0
  20. package/dist/lib/filterUnwantedEnvVars.js +88 -0
  21. package/dist/lib/generateNewEnvList.js +17 -0
  22. package/dist/lib/index.js +49 -0
  23. package/dist/src/cdk/cdk.js +6 -0
  24. package/dist/src/cdk/index.js +17 -0
  25. package/dist/{expo.js → src/expo.js} +18 -34
  26. package/dist/src/index.js +56 -0
  27. package/dist/src/merge-env.js +25 -0
  28. package/dist/{project → src/project}/build-mono-readme.js +11 -20
  29. package/dist/{project → src/project}/generate-readme.js +6 -13
  30. package/dist/{project → src/project}/index.js +4 -12
  31. package/dist/{stack.js → src/stack.js} +2 -2
  32. package/dist/src/tools.js +39 -0
  33. package/dist/types/index.d.ts +50 -9
  34. package/dist/types/lib/app.d.ts +3 -0
  35. package/dist/types/lib/commands/build-process/boot.d.ts +8 -0
  36. package/dist/types/lib/commands/build-process/cliFactory.d.ts +32 -0
  37. package/dist/types/lib/commands/build-process/dataLayer.d.ts +7 -0
  38. package/dist/types/lib/commands/build-process/readEnv.d.ts +1 -0
  39. package/dist/types/lib/commands/build-process/runMonoCommand.d.ts +10 -0
  40. package/dist/types/lib/commands/build-process/runners/processManager.d.ts +5 -0
  41. package/dist/types/lib/commands/build-process/runners/runBackground.d.ts +2 -0
  42. package/dist/types/lib/commands/build-process/runners/runForeground.d.ts +6 -0
  43. package/dist/types/lib/commands/build-process/test.d.ts +1 -0
  44. package/dist/types/lib/commands/build-process/testflag.d.ts +1 -0
  45. package/dist/types/lib/commands/build-process/validators.d.ts +1 -0
  46. package/dist/types/lib/commands/loadFromRoot.d.ts +7 -0
  47. package/dist/types/lib/commands/prune/prune.d.ts +1 -0
  48. package/dist/types/lib/config.d.ts +2 -0
  49. package/dist/types/lib/filterUnwantedEnvVars.d.ts +2 -0
  50. package/dist/types/lib/generateNewEnvList.d.ts +1 -0
  51. package/dist/types/lib/index.d.ts +2 -0
  52. package/dist/types/src/cdk/cdk.d.ts +1 -0
  53. package/dist/types/src/cdk/index.d.ts +1 -0
  54. package/dist/types/src/expo.d.ts +4 -0
  55. package/dist/types/src/index.d.ts +15 -0
  56. package/dist/types/src/project/build-mono-readme.d.ts +1 -0
  57. package/dist/types/src/project/generate-readme.d.ts +1 -0
  58. package/dist/types/{project → src/project}/index.d.ts +1 -1
  59. package/dist/types/src/project/merge-env.d.ts +1 -0
  60. package/dist/types/src/tools.d.ts +3 -0
  61. package/lib/app.d.ts +3 -0
  62. package/lib/app.ts +58 -0
  63. package/lib/commands/build-process/boot.d.ts +8 -0
  64. package/lib/commands/build-process/boot.ts +21 -0
  65. package/lib/commands/build-process/cliFactory.d.ts +32 -0
  66. package/lib/commands/build-process/cliFactory.ts +219 -0
  67. package/lib/commands/build-process/dataLayer.d.ts +7 -0
  68. package/lib/commands/build-process/dataLayer.ts +61 -0
  69. package/lib/commands/build-process/index.d.ts +1 -0
  70. package/lib/commands/build-process/index.ts +14 -0
  71. package/lib/commands/build-process/readEnv.d.ts +1 -0
  72. package/lib/commands/build-process/readEnv.ts +37 -0
  73. package/lib/commands/build-process/runMonoCommand.d.ts +10 -0
  74. package/lib/commands/build-process/runMonoCommand.ts +96 -0
  75. package/lib/commands/build-process/runners/processManager.d.ts +5 -0
  76. package/lib/commands/build-process/runners/processManager.ts +42 -0
  77. package/lib/commands/build-process/runners/runBackground.d.ts +2 -0
  78. package/lib/commands/build-process/runners/runBackground.ts +56 -0
  79. package/lib/commands/build-process/runners/runForeground.d.ts +6 -0
  80. package/lib/commands/build-process/runners/runForeground.ts +59 -0
  81. package/lib/commands/build-process/test.d.ts +1 -0
  82. package/lib/commands/build-process/test.ts +42 -0
  83. package/lib/commands/build-process/testflag.d.ts +1 -0
  84. package/lib/commands/build-process/testflag.ts +1 -0
  85. package/lib/commands/build-process/validators.d.ts +1 -0
  86. package/lib/commands/build-process/validators.ts +16 -0
  87. package/lib/commands/loadFromRoot.d.ts +7 -0
  88. package/lib/commands/loadFromRoot.ts +51 -0
  89. package/lib/commands/prune/index.d.ts +1 -0
  90. package/lib/commands/prune/index.ts +9 -0
  91. package/lib/commands/prune/prune.d.ts +1 -0
  92. package/lib/commands/prune/prune.ts +50 -0
  93. package/lib/config.d.ts +2 -0
  94. package/lib/filterUnwantedEnvVars.d.ts +2 -0
  95. package/lib/filterUnwantedEnvVars.ts +95 -0
  96. package/lib/generateNewEnvList.d.ts +1 -0
  97. package/lib/generateNewEnvList.ts +17 -0
  98. package/lib/index.d.ts +2 -0
  99. package/lib/index.ts +59 -0
  100. package/package.json +99 -84
  101. package/src/cdk/cdk.d.ts +1 -7
  102. package/src/cdk/cdk.ts +1 -0
  103. package/src/cdk/index.d.ts +1 -0
  104. package/src/cdk/index.ts +1 -0
  105. package/src/expo-files/filterUnwantedEnvVars.d.ts +3 -0
  106. package/src/expo-files/filterUnwantedEnvVars.ts +141 -144
  107. package/src/expo.d.ts +2 -9
  108. package/src/expo.ts +116 -0
  109. package/src/index.d.ts +22 -0
  110. package/src/index.ts +39 -42
  111. package/src/loadFromRoot.d.ts +32 -0
  112. package/src/merge-env.d.ts +1 -0
  113. package/src/merge-env.ts +24 -0
  114. package/src/project/build-mono-readme.d.ts +1 -0
  115. package/src/project/build-mono-readme.ts +460 -514
  116. package/src/project/build-readme.d.ts +2 -0
  117. package/src/project/generate-docs.d.ts +11 -0
  118. package/src/project/generate-readme.d.ts +1 -0
  119. package/src/project/generate-readme.ts +259 -284
  120. package/src/project/index.d.ts +45 -0
  121. package/src/project/index.ts +134 -144
  122. package/src/project/merge-env.d.ts +1 -0
  123. package/src/stack.d.ts +21 -0
  124. package/src/stack.ts +54 -55
  125. package/src/tools.d.ts +3 -4
  126. package/src/tools.ts +48 -0
  127. package/src/types/expo-config.d.ts +49 -0
  128. package/dist/cdk/index.js +0 -55
  129. package/dist/project/merge-env.js +0 -31
  130. package/dist/tools.js +0 -35
  131. package/dist/types/cdk/index.d.ts +0 -2
  132. package/dist/types/expo.d.ts +0 -3
  133. package/dist/types/merge-env.d.ts +0 -1
  134. package/dist/types/tools.d.ts +0 -1
  135. package/lib/app.js +0 -49
  136. package/lib/commands/build-process/boot.js +0 -15
  137. package/lib/commands/build-process/cliFactory.js +0 -163
  138. package/lib/commands/build-process/dataLayer.js +0 -59
  139. package/lib/commands/build-process/index.js +0 -13
  140. package/lib/commands/build-process/readEnv.js +0 -37
  141. package/lib/commands/build-process/runMonoCommand.js +0 -102
  142. package/lib/commands/build-process/runners/processManager.js +0 -38
  143. package/lib/commands/build-process/runners/runBackground.js +0 -60
  144. package/lib/commands/build-process/runners/runForeground.js +0 -60
  145. package/lib/commands/build-process/test.js +0 -50
  146. package/lib/commands/build-process/testflag.js +0 -1
  147. package/lib/commands/build-process/validators.js +0 -17
  148. package/lib/commands/generate/generateSeed.js +0 -223
  149. package/lib/commands/generate/index.js +0 -30
  150. package/lib/commands/loadFromRoot.js +0 -55
  151. package/lib/commands/prune/index.js +0 -12
  152. package/lib/commands/prune/prune.js +0 -50
  153. package/lib/commands/seed/import.js +0 -30
  154. package/lib/commands/seed/index.js +0 -12
  155. package/lib/commands/submit/index.js +0 -38
  156. package/lib/commands/update/eas.js +0 -39
  157. package/lib/commands/update/index.js +0 -87
  158. package/lib/filterUnwantedEnvVars.js +0 -123
  159. package/lib/generateNewEnvList.js +0 -14
  160. package/lib/index.js +0 -58
  161. package/src/cdk/index.js +0 -59
  162. package/src/expo.js +0 -133
  163. package/src/merge-env.js +0 -32
  164. package/src/tools.js +0 -36
  165. package/types.d.ts +0 -83
  166. /package/dist/{expo-files → src/expo-files}/filterUnwantedEnvVars.js +0 -0
  167. /package/dist/{loadFromRoot.js → src/loadFromRoot.js} +0 -0
  168. /package/dist/{project → src/project}/build-readme.js +0 -0
  169. /package/dist/{project → src/project}/generate-docs.js +0 -0
  170. /package/dist/{merge-env.js → src/project/merge-env.js} +0 -0
  171. /package/dist/types/{project/build-mono-readme.d.ts → lib/commands/build-process/index.d.ts} +0 -0
  172. /package/dist/types/{project/generate-readme.d.ts → lib/commands/prune/index.d.ts} +0 -0
  173. /package/dist/types/{expo-files → src/expo-files}/filterUnwantedEnvVars.d.ts +0 -0
  174. /package/dist/types/{loadFromRoot.d.ts → src/loadFromRoot.d.ts} +0 -0
  175. /package/dist/types/{project → src}/merge-env.d.ts +0 -0
  176. /package/dist/types/{project → src/project}/build-readme.d.ts +0 -0
  177. /package/dist/types/{project → src/project}/generate-docs.d.ts +0 -0
  178. /package/dist/types/{stack.d.ts → src/stack.d.ts} +0 -0
  179. /package/lib/{config.js → config.ts} +0 -0
@@ -1,599 +1,545 @@
1
1
  // scripts/generate-readme.mjs
2
2
  // Node >= 18 recommended
3
- import { promises as fs } from 'node:fs';
4
- import { Dirent } from 'node:fs';
5
- import path from 'node:path';
6
- import { generateDocsIndex } from './generate-docs.js';
3
+ import { promises as fs } from 'node:fs'
4
+ import { Dirent } from 'node:fs'
5
+ import path from 'node:path'
6
+ import { generateDocsIndex } from './generate-docs'
7
7
 
8
- const REPO_ROOT = path.resolve(process.cwd());
9
- const MONO_DIR = path.join(REPO_ROOT, '.mono');
10
- const ROOT_PKG_JSON = path.join(REPO_ROOT, 'package.json');
11
- const OUTPUT_PATH = path.join(REPO_ROOT, 'docs');
12
- const OUTPUT_README = path.join(OUTPUT_PATH, 'command-line.md');
8
+ const REPO_ROOT = path.resolve(process.cwd())
9
+ const MONO_DIR = path.join(REPO_ROOT, '.mono')
10
+ const ROOT_PKG_JSON = path.join(REPO_ROOT, 'package.json')
11
+ const OUTPUT_PATH = path.join(REPO_ROOT, 'docs')
12
+ const OUTPUT_README = path.join(OUTPUT_PATH, 'command-line.md')
13
13
 
14
14
  async function ensureParentDir(filePath: string): Promise<void> {
15
- const dir = path.dirname(filePath);
16
- await fs.mkdir(dir, { recursive: true });
15
+ const dir = path.dirname(filePath)
16
+ await fs.mkdir(dir, { recursive: true })
17
17
  }
18
18
 
19
19
  // ---------- utils ----------
20
20
  async function exists(p: string): Promise<boolean> {
21
- try {
22
- await fs.access(p);
23
- // Log existence check
24
-
25
- return true;
26
- } catch {
27
- return false;
28
- }
21
+ try {
22
+ await fs.access(p)
23
+ // Log existence check
24
+
25
+ return true
26
+ } catch {
27
+ return false
28
+ }
29
29
  }
30
30
  function isObject(v: unknown): v is Record<string, unknown> {
31
- return v !== null && typeof v === 'object' && !Array.isArray(v);
31
+ return v !== null && typeof v === 'object' && !Array.isArray(v)
32
32
  }
33
33
  function toPosix(p: string): string {
34
- return p.split(path.sep).join('/');
34
+ return p.split(path.sep).join('/')
35
35
  }
36
36
  async function readJson<T = any>(filePath: string): Promise<T> {
37
- const raw = await fs.readFile(filePath, 'utf8');
38
- try {
39
- const parsed = JSON.parse(raw);
40
-
41
- return parsed;
42
- } catch (err) {
43
- throw err;
44
- }
37
+ const raw = await fs.readFile(filePath, 'utf8')
38
+ try {
39
+ const parsed = JSON.parse(raw)
40
+
41
+ return parsed
42
+ } catch (err) {
43
+ throw err
44
+ }
45
45
  }
46
46
  async function listDir(dir: string): Promise<Dirent[]> {
47
- const entries = await fs.readdir(dir, { withFileTypes: true });
47
+ const entries = await fs.readdir(dir, { withFileTypes: true })
48
48
 
49
- return entries;
49
+ return entries
50
50
  }
51
51
  function normalizeWorkspacePatterns(workspacesField: unknown): string[] {
52
- if (Array.isArray(workspacesField)) return workspacesField as string[];
53
- if (
54
- isObject(workspacesField) &&
55
- Array.isArray((workspacesField as any).packages)
56
- )
57
- return (workspacesField as any).packages;
58
- return [];
52
+ if (Array.isArray(workspacesField)) return workspacesField as string[]
53
+ if (isObject(workspacesField) && Array.isArray((workspacesField as any).packages))
54
+ return (workspacesField as any).packages
55
+ return []
59
56
  }
60
57
  function mdEscapeInline(s: string): string {
61
- return String(s ?? '').replaceAll('`', '\`');
58
+ return String(s ?? '').replaceAll('`', '\`')
62
59
  }
63
60
  function indentLines(s: string, spaces = 2): string {
64
- const pad = ' '.repeat(spaces);
65
- return String(s ?? '')
66
- .split('\n')
67
- .map((l) => pad + l)
68
- .join('\n');
61
+ const pad = ' '.repeat(spaces)
62
+ return String(s ?? '')
63
+ .split('\n')
64
+ .map((l) => pad + l)
65
+ .join('\n')
69
66
  }
70
67
 
71
68
  // ---------- workspace glob matching (supports *, **, and plain segments) ----------
72
69
  function matchSegment(patternSeg: string, name: string): boolean {
73
- if (patternSeg === '*') return true;
74
- if (!patternSeg.includes('*')) return patternSeg === name;
75
- const escaped = patternSeg.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
76
- const regex = new RegExp('^' + escaped.replaceAll('*', '.*') + '$');
77
- return regex.test(name);
70
+ if (patternSeg === '*') return true
71
+ if (!patternSeg.includes('*')) return patternSeg === name
72
+ const escaped = patternSeg.replace(/[.+?^${}()|[\]\\]/g, '\\$&')
73
+ const regex = new RegExp('^' + escaped.replaceAll('*', '.*') + '$')
74
+ return regex.test(name)
78
75
  }
79
76
 
80
- async function expandWorkspacePattern(
81
- root: string,
82
- pattern: string
83
- ): Promise<string[]> {
84
- const segs = toPosix(pattern).split('/').filter(Boolean);
85
-
86
- async function expandFrom(dir: string, segIndex: number): Promise<string[]> {
87
- if (segIndex >= segs.length) return [dir];
88
- const seg = segs[segIndex];
89
-
90
- if (seg === '**') {
91
- const results: string[] = [];
92
- results.push(...(await expandFrom(dir, segIndex + 1)));
93
- const entries = await fs
94
- .readdir(dir, { withFileTypes: true })
95
- .catch(() => []);
96
-
97
- for (const e of entries) {
98
- if (!e.isDirectory()) continue;
99
-
100
- results.push(...(await expandFrom(path.join(dir, e.name), segIndex)));
101
- }
102
- return results;
103
- }
104
-
105
- const entries = await fs
106
- .readdir(dir, { withFileTypes: true })
107
- .catch(() => []);
108
-
109
- const results: string[] = [];
110
- for (const e of entries) {
111
- if (!e.isDirectory()) continue;
112
- if (!matchSegment(seg, e.name)) continue;
113
-
114
- results.push(...(await expandFrom(path.join(dir, e.name), segIndex + 1)));
115
- }
116
- return results;
117
- }
118
-
119
- const dirs = await expandFrom(root, 0);
120
-
121
- const pkgDirs: string[] = [];
122
- for (const d of dirs) {
123
- const pkgPath = path.join(d, 'package.json');
124
- if (await exists(pkgPath)) {
125
- pkgDirs.push(d);
126
- }
127
- }
128
-
129
- return [...new Set(pkgDirs)];
77
+ async function expandWorkspacePattern(root: string, pattern: string): Promise<string[]> {
78
+ const segs = toPosix(pattern).split('/').filter(Boolean)
79
+
80
+ async function expandFrom(dir: string, segIndex: number): Promise<string[]> {
81
+ if (segIndex >= segs.length) return [dir]
82
+ const seg = segs[segIndex]
83
+
84
+ if (seg === '**') {
85
+ const results: string[] = []
86
+ results.push(...(await expandFrom(dir, segIndex + 1)))
87
+ const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => [])
88
+
89
+ for (const e of entries) {
90
+ if (!e.isDirectory()) continue
91
+
92
+ results.push(...(await expandFrom(path.join(dir, e.name), segIndex)))
93
+ }
94
+ return results
95
+ }
96
+
97
+ const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => [])
98
+
99
+ const results: string[] = []
100
+ for (const e of entries) {
101
+ if (!e.isDirectory()) continue
102
+ if (!matchSegment(seg, e.name)) continue
103
+
104
+ results.push(...(await expandFrom(path.join(dir, e.name), segIndex + 1)))
105
+ }
106
+ return results
107
+ }
108
+
109
+ const dirs = await expandFrom(root, 0)
110
+
111
+ const pkgDirs: string[] = []
112
+ for (const d of dirs) {
113
+ const pkgPath = path.join(d, 'package.json')
114
+ if (await exists(pkgPath)) {
115
+ pkgDirs.push(d)
116
+ }
117
+ }
118
+
119
+ return [...new Set(pkgDirs)]
130
120
  }
131
121
 
132
122
  async function findWorkspacePackageDirs(
133
- repoRoot: string,
134
- workspacePatterns: string[]
123
+ repoRoot: string,
124
+ workspacePatterns: string[]
135
125
  ): Promise<string[]> {
136
- const dirs: string[] = [];
137
- for (const pat of workspacePatterns) {
138
- const expanded = await expandWorkspacePattern(repoRoot, pat);
139
- dirs.push(...expanded);
140
- dirs.push(...expanded);
141
- }
142
- const uniqueDirs = [...new Set(dirs)];
143
- return uniqueDirs;
126
+ const dirs: string[] = []
127
+ for (const pat of workspacePatterns) {
128
+ const expanded = await expandWorkspacePattern(repoRoot, pat)
129
+ dirs.push(...expanded)
130
+ dirs.push(...expanded)
131
+ }
132
+ const uniqueDirs = [...new Set(dirs)]
133
+ return uniqueDirs
144
134
  }
145
135
 
146
136
  // ---------- .mono parsing ----------
147
137
  async function readMonoConfig(): Promise<MonoConfig | null> {
148
- const configPath = path.join(MONO_DIR, 'config.json');
149
- console.log(`[readMonoConfig] Looking for mono config at:`, configPath);
150
- if (!(await exists(configPath))) {
151
- console.log(`[readMonoConfig] No mono config found.`);
152
- return null;
153
- }
154
- try {
155
- const config = await readJson<any>(configPath);
156
- return { path: configPath, config };
157
- } catch (err) {
158
- return null;
159
- }
138
+ const configPath = path.join(MONO_DIR, 'config.json')
139
+ console.log(`[readMonoConfig] Looking for mono config at:`, configPath)
140
+ if (!(await exists(configPath))) {
141
+ console.log(`[readMonoConfig] No mono config found.`)
142
+ return null
143
+ }
144
+ try {
145
+ const config = await readJson<any>(configPath)
146
+ return { path: configPath, config }
147
+ } catch (err) {
148
+ return null
149
+ }
160
150
  }
161
151
 
162
152
  function commandNameFromFile(filePath: string): string {
163
- return path.basename(filePath).replace(/\.json$/i, '');
153
+ return path.basename(filePath).replace(/\.json$/i, '')
164
154
  }
165
155
 
166
156
  async function readMonoCommands(): Promise<MonoCommand[]> {
167
- if (!(await exists(MONO_DIR))) {
168
- return [];
169
- }
170
- const entries = await listDir(MONO_DIR);
171
-
172
- const jsonFiles = entries
173
- .filter((e) => e.isFile() && e.name.toLowerCase().endsWith('.json'))
174
- .map((e) => path.join(MONO_DIR, e.name))
175
- .filter((p) => path.basename(p).toLowerCase() !== 'config.json');
176
-
177
- const commands: MonoCommand[] = [];
178
- for (const file of jsonFiles) {
179
- try {
180
- const j = await readJson<any>(file);
181
- commands.push({
182
- name: commandNameFromFile(file),
183
- file,
184
- json: j,
185
- });
186
- } catch (err) {
187
- console.error(
188
- `[readMonoCommands] Failed to load command file:`,
189
- file,
190
- err
191
- );
192
- // skip invalid json
193
- }
194
- }
195
-
196
- commands.sort((a, b) => a.name.localeCompare(b.name));
197
-
198
- return commands;
157
+ if (!(await exists(MONO_DIR))) {
158
+ return []
159
+ }
160
+ const entries = await listDir(MONO_DIR)
161
+
162
+ const jsonFiles = entries
163
+ .filter((e) => e.isFile() && e.name.toLowerCase().endsWith('.json'))
164
+ .map((e) => path.join(MONO_DIR, e.name))
165
+ .filter((p) => path.basename(p).toLowerCase() !== 'config.json')
166
+
167
+ const commands: MonoCommand[] = []
168
+ for (const file of jsonFiles) {
169
+ try {
170
+ const j = await readJson<any>(file)
171
+ commands.push({
172
+ name: commandNameFromFile(file),
173
+ file,
174
+ json: j,
175
+ })
176
+ } catch (err) {
177
+ console.error(`[readMonoCommands] Failed to load command file:`, file, err)
178
+ // skip invalid json
179
+ }
180
+ }
181
+
182
+ commands.sort((a, b) => a.name.localeCompare(b.name))
183
+
184
+ return commands
199
185
  }
200
186
 
201
187
  // ---------- mono docs formatting ----------
202
188
  type OptionSchema = {
203
- key: string;
204
- kind: 'boolean' | 'value';
205
- type: string;
206
- description: string;
207
- shortcut: string;
208
- default: any;
209
- allowed: string[] | null;
210
- allowAll: boolean;
211
- };
189
+ key: string
190
+ kind: 'boolean' | 'value'
191
+ type: string
192
+ description: string
193
+ shortcut: string
194
+ default: any
195
+ allowed: string[] | null
196
+ allowAll: boolean
197
+ }
212
198
 
213
199
  type MonoConfig = {
214
- path: string;
215
- config: any;
216
- };
200
+ path: string
201
+ config: any
202
+ }
217
203
 
218
204
  function parseOptionsSchema(optionsObj: unknown): OptionSchema[] {
219
- // New structure supports:
220
- // - optionKey: { type: "string", default, options: [], allowAll, shortcut, description }
221
- // - boolean toggle: { shortcut, description } (no type)
222
- if (!isObject(optionsObj)) return [];
223
-
224
- const entries: OptionSchema[] = Object.entries(optionsObj).map(
225
- ([key, raw]) => {
226
- const o = isObject(raw) ? raw : {};
227
- const hasType = typeof o.type === 'string' && o.type.trim().length > 0;
228
- const isBoolToggle = !hasType; // in your examples, booleans omit `type`
229
- return {
230
- key,
231
- kind: isBoolToggle ? 'boolean' : 'value',
232
- type: hasType ? String(o.type) : 'boolean',
233
- description: typeof o.description === 'string' ? o.description : '',
234
- shortcut: typeof o.shortcut === 'string' ? o.shortcut : '',
235
- default: o.default,
236
- allowed: Array.isArray(o.options) ? o.options : null,
237
- allowAll: o.allowAll === true,
238
- };
239
- }
240
- );
241
-
242
- entries.sort((a, b) => a.key.localeCompare(b.key));
243
- return entries;
205
+ // New structure supports:
206
+ // - optionKey: { type: "string", default, options: [], allowAll, shortcut, description }
207
+ // - boolean toggle: { shortcut, description } (no type)
208
+ if (!isObject(optionsObj)) return []
209
+
210
+ const entries: OptionSchema[] = Object.entries(optionsObj).map(([key, raw]) => {
211
+ const o = isObject(raw) ? raw : {}
212
+ const hasType = typeof o.type === 'string' && o.type.trim().length > 0
213
+ const isBoolToggle = !hasType // in your examples, booleans omit `type`
214
+ return {
215
+ key,
216
+ kind: isBoolToggle ? 'boolean' : 'value',
217
+ type: hasType ? String(o.type) : 'boolean',
218
+ description: typeof o.description === 'string' ? o.description : '',
219
+ shortcut: typeof o.shortcut === 'string' ? o.shortcut : '',
220
+ default: o.default,
221
+ allowed: Array.isArray(o.options) ? o.options : null,
222
+ allowAll: o.allowAll === true,
223
+ }
224
+ })
225
+
226
+ entries.sort((a, b) => a.key.localeCompare(b.key))
227
+ return entries
244
228
  }
245
229
 
246
- function buildUsageExample(
247
- commandName: string,
248
- cmdJson: any,
249
- options: OptionSchema[]
250
- ): string {
251
- const arg = cmdJson?.argument;
252
- const hasArg = isObject(arg);
253
- const argToken = hasArg ? `<${commandName}-arg>` : '';
254
-
255
- // choose a representative value option to show
256
- const valueOpts = options.filter((o) => o.kind === 'value');
257
- const boolOpts = options.filter((o) => o.kind === 'boolean');
258
-
259
- const exampleParts = [`yarn mono ${commandName}`];
260
- if (argToken) exampleParts.push(argToken);
261
-
262
- // include at most 2 value options and 1 boolean in the example for readability
263
- for (const o of valueOpts.slice(0, 2)) {
264
- const flag = `--${o.key}`;
265
- const val =
266
- o.default !== undefined ? o.default : (o.allowed?.[0] ?? '<value>');
267
- exampleParts.push(`${flag} ${val}`);
268
- }
269
- if (boolOpts.length) {
270
- exampleParts.push(`--${boolOpts[0].key}`);
271
- }
272
-
273
- return exampleParts.join(' ');
230
+ function buildUsageExample(commandName: string, cmdJson: any, options: OptionSchema[]): string {
231
+ const arg = cmdJson?.argument
232
+ const hasArg = isObject(arg)
233
+ const argToken = hasArg ? `<${commandName}-arg>` : ''
234
+
235
+ // choose a representative value option to show
236
+ const valueOpts = options.filter((o) => o.kind === 'value')
237
+ const boolOpts = options.filter((o) => o.kind === 'boolean')
238
+
239
+ const exampleParts = [`yarn mono ${commandName}`]
240
+ if (argToken) exampleParts.push(argToken)
241
+
242
+ // include at most 2 value options and 1 boolean in the example for readability
243
+ for (const o of valueOpts.slice(0, 2)) {
244
+ const flag = `--${o.key}`
245
+ const val = o.default !== undefined ? o.default : (o.allowed?.[0] ?? '<value>')
246
+ exampleParts.push(`${flag} ${val}`)
247
+ }
248
+ if (boolOpts.length) {
249
+ exampleParts.push(`--${boolOpts[0].key}`)
250
+ }
251
+
252
+ return exampleParts.join(' ')
274
253
  }
275
254
 
276
255
  function formatMonoConfigSection(monoConfig: MonoConfig | null): string {
277
- const lines: string[] = [];
278
- lines.push('## Mono configuration');
279
- lines.push('');
280
-
281
- if (!monoConfig) {
282
- lines.push('_No `.mono/config.json` found._');
283
- return lines.join('\n');
284
- }
285
-
286
- const c = monoConfig.config;
287
- lines.push(
288
- `Source: \`${toPosix(path.relative(REPO_ROOT, monoConfig.path))}\``
289
- );
290
- lines.push('');
291
-
292
- if (Array.isArray(c.envMap) && c.envMap.length) {
293
- lines.push('### envMap');
294
- lines.push('');
295
- lines.push(
296
- '- ' + c.envMap.map((x: string) => `\`${mdEscapeInline(x)}\``).join(', ')
297
- );
298
- lines.push('');
299
- }
300
-
301
- const pkgMaps = c?.workspace?.packageMaps;
302
- if (pkgMaps && isObject(pkgMaps) && Object.keys(pkgMaps).length) {
303
- lines.push('### Workspace aliases (packageMaps)');
304
- lines.push('');
305
- const entries = Object.entries(pkgMaps).sort(([a], [b]) =>
306
- a.localeCompare(b)
307
- );
308
- for (const [alias, target] of entries) {
309
- lines.push(
310
- `- \`${mdEscapeInline(alias)}\` \`${mdEscapeInline(String(target))}\``
311
- );
312
- }
313
- lines.push('');
314
- }
315
-
316
- const pre = c?.workspace?.preactions;
317
- if (Array.isArray(pre) && pre.length) {
318
- lines.push('### Global preactions');
319
- lines.push('');
320
- lines.push('```bash');
321
- for (const p of pre) lines.push(String(p));
322
- lines.push('```');
323
- lines.push('');
324
- }
325
-
326
- if (typeof c.prodFlag === 'string' && c.prodFlag.trim()) {
327
- lines.push('### prodFlag');
328
- lines.push('');
329
- lines.push(
330
- `Production flag keyword: \`${mdEscapeInline(c.prodFlag.trim())}\``
331
- );
332
- lines.push('');
333
- }
334
-
335
- return lines.join('\n');
256
+ const lines: string[] = []
257
+ lines.push('## Mono configuration')
258
+ lines.push('')
259
+
260
+ if (!monoConfig) {
261
+ lines.push('_No `.mono/config.json` found._')
262
+ return lines.join('\n')
263
+ }
264
+
265
+ const c = monoConfig.config
266
+ lines.push(`Source: \`${toPosix(path.relative(REPO_ROOT, monoConfig.path))}\``)
267
+ lines.push('')
268
+
269
+ if (Array.isArray(c.envMap) && c.envMap.length) {
270
+ lines.push('### envMap')
271
+ lines.push('')
272
+ lines.push('- ' + c.envMap.map((x: string) => `\`${mdEscapeInline(x)}\``).join(', '))
273
+ lines.push('')
274
+ }
275
+
276
+ const pkgMaps = c?.workspace?.packageMaps
277
+ if (pkgMaps && isObject(pkgMaps) && Object.keys(pkgMaps).length) {
278
+ lines.push('### Workspace aliases (packageMaps)')
279
+ lines.push('')
280
+ const entries = Object.entries(pkgMaps).sort(([a], [b]) => a.localeCompare(b))
281
+ for (const [alias, target] of entries) {
282
+ lines.push(`- \`${mdEscapeInline(alias)}\` \`${mdEscapeInline(String(target))}\``)
283
+ }
284
+ lines.push('')
285
+ }
286
+
287
+ const pre = c?.workspace?.preactions
288
+ if (Array.isArray(pre) && pre.length) {
289
+ lines.push('### Global preactions')
290
+ lines.push('')
291
+ lines.push('```bash')
292
+ for (const p of pre) lines.push(String(p))
293
+ lines.push('```')
294
+ lines.push('')
295
+ }
296
+
297
+ if (typeof c.prodFlag === 'string' && c.prodFlag.trim()) {
298
+ lines.push('### prodFlag')
299
+ lines.push('')
300
+ lines.push(`Production flag keyword: \`${mdEscapeInline(c.prodFlag.trim())}\``)
301
+ lines.push('')
302
+ }
303
+
304
+ return lines.join('\n')
336
305
  }
337
306
 
338
307
  type MonoCommand = {
339
- name: string;
340
- file: string;
341
- json: any;
342
- };
308
+ name: string
309
+ file: string
310
+ json: any
311
+ }
343
312
 
344
313
  function formatMonoCommandsSection(commands: MonoCommand[]): string {
345
- const lines: string[] = [];
346
- lines.push('## Mono commands');
347
- lines.push('');
348
- lines.push(
349
- 'Generated from `.mono/*.json` (excluding `config.json`). Each filename becomes a command:'
350
- );
351
- lines.push('');
352
- lines.push('```bash');
353
- lines.push('yarn mono <command> [argument] [--options]');
354
- lines.push('```');
355
- lines.push('');
356
-
357
- if (!commands.length) {
358
- lines.push('_No mono command JSON files found._');
359
- return lines.join('\n');
360
- }
361
-
362
- // Index
363
- lines.push('### Command index');
364
- lines.push('');
365
- for (const c of commands) {
366
- const desc =
367
- typeof c.json?.description === 'string' ? c.json.description.trim() : '';
368
- const suffix = desc ? ` — ${desc}` : '';
369
- lines.push(
370
- `- [\`${mdEscapeInline(c.name)}\`](#mono-command-${mdEscapeInline(c.name).toLowerCase()})${suffix}`
371
- );
372
- }
373
- lines.push('');
374
-
375
- for (const c of commands) {
376
- const j = c.json || {};
377
- const rel = toPosix(path.relative(REPO_ROOT, c.file));
378
- const anchor = `mono-command-${c.name.toLowerCase()}`;
379
-
380
- const desc = typeof j.description === 'string' ? j.description.trim() : '';
381
- const arg = j.argument;
382
- const options = parseOptionsSchema(j.options);
383
-
384
- lines.push('---');
385
- lines.push(`### Mono command: ${c.name}`);
386
- lines.push(`<a id="${anchor}"></a>`);
387
- lines.push('');
388
- lines.push(`Source: \`${rel}\``);
389
- lines.push('');
390
-
391
- if (desc) {
392
- lines.push(`**Description:** ${mdEscapeInline(desc)}`);
393
- lines.push('');
394
- }
395
-
396
- // Usage
397
- lines.push('**Usage**');
398
- lines.push('');
399
- lines.push('```bash');
400
- lines.push(
401
- `yarn mono ${c.name}${isObject(arg) ? ` <${c.name}-arg>` : ''} [--options]`
402
- );
403
- lines.push('```');
404
- lines.push('');
405
- lines.push('Example:');
406
- lines.push('');
407
- lines.push('```bash');
408
- lines.push(buildUsageExample(c.name, j, options));
409
- lines.push('```');
410
- lines.push('');
411
-
412
- // Argument
413
- if (isObject(arg)) {
414
- lines.push('**Argument**');
415
- lines.push('');
416
- const bits: string[] = [];
417
- if (typeof arg.type === 'string')
418
- bits.push(`type: \`${mdEscapeInline(arg.type)}\``);
419
- if (arg.default !== undefined)
420
- bits.push(`default: \`${mdEscapeInline(String(arg.default))}\``);
421
- if (typeof arg.description === 'string')
422
- bits.push(mdEscapeInline(arg.description));
423
- lines.push(`- ${bits.join(' • ') || '_(no details)_'} `);
424
- lines.push('');
425
- }
426
-
427
- // Options
428
- if (options.length) {
429
- lines.push('**Options**');
430
- lines.push('');
431
- lines.push('| Option | Type | Shortcut | Default | Allowed | Notes |');
432
- lines.push('|---|---:|:---:|---:|---|---|');
433
- for (const o of options) {
434
- const optCol =
435
- o.kind === 'boolean' ?
436
- `\`--${mdEscapeInline(o.key)}\``
437
- : `\`--${mdEscapeInline(o.key)} <${mdEscapeInline(o.key)}>\``;
438
- const typeCol = `\`${mdEscapeInline(o.type)}\``;
439
- const shortCol = o.shortcut ? `\`-${mdEscapeInline(o.shortcut)}\`` : '';
440
- const defCol =
441
- o.default !== undefined ? `\`${mdEscapeInline(o.default)}\`` : '';
442
- const allowedCol =
443
- o.allowed ?
444
- o.allowed.map((x) => `\`${mdEscapeInline(x)}\``).join(', ')
445
- : '';
446
- const notes = [
447
- o.allowAll ? 'allowAll' : '',
448
- o.description ? mdEscapeInline(o.description) : '',
449
- ]
450
- .filter(Boolean)
451
- .join(' • ');
452
- lines.push(
453
- `| ${optCol} | ${typeCol} | ${shortCol} | ${defCol} | ${allowedCol} | ${notes} |`
454
- );
455
- }
456
- lines.push('');
457
- }
458
-
459
- // Environments
460
- if (
461
- j.environments &&
462
- isObject(j.environments) &&
463
- Object.keys(j.environments).length
464
- ) {
465
- lines.push('**Environment Variables**');
466
- lines.push('');
467
- const envs = Object.entries(j.environments).sort(([a], [b]) =>
468
- a.localeCompare(b)
469
- );
470
- for (const [envName, envObj] of envs) {
471
- lines.push(`- \`${mdEscapeInline(envName)}\``);
472
- if (isObject(envObj) && Object.keys(envObj).length) {
473
- const kv = Object.entries(envObj).sort(([a], [b]) =>
474
- a.localeCompare(b)
475
- );
476
- lines.push(
477
- indentLines(
478
- kv
479
- .map(
480
- ([k, v]) =>
481
- `- \`${mdEscapeInline(k)}\` = \`${mdEscapeInline(String(v))}\``
482
- )
483
- .join('\n'),
484
- 2
485
- )
486
- );
487
- }
488
- }
489
- lines.push('');
490
- }
491
-
492
- // preactions/actions
493
- if (Array.isArray(j.preactions) && j.preactions.length) {
494
- lines.push('**Preactions**');
495
- lines.push('');
496
- lines.push('```bash');
497
- for (const p of j.preactions) lines.push(String(p));
498
- lines.push('```');
499
- lines.push('');
500
- }
501
-
502
- if (Array.isArray(j.actions) && j.actions.length) {
503
- lines.push('**Actions**');
504
- lines.push('');
505
- lines.push('```bash');
506
- for (const a of j.actions) lines.push(String(a));
507
- lines.push('```');
508
- lines.push('');
509
- }
510
- }
511
-
512
- return lines.join('\n');
314
+ const lines: string[] = []
315
+ lines.push('## Mono commands')
316
+ lines.push('')
317
+ lines.push(
318
+ 'Generated from `.mono/*.json` (excluding `config.json`). Each filename becomes a command:'
319
+ )
320
+ lines.push('')
321
+ lines.push('```bash')
322
+ lines.push('yarn mono <command> [argument] [--options]')
323
+ lines.push('```')
324
+ lines.push('')
325
+
326
+ if (!commands.length) {
327
+ lines.push('_No mono command JSON files found._')
328
+ return lines.join('\n')
329
+ }
330
+
331
+ // Index
332
+ lines.push('### Command index')
333
+ lines.push('')
334
+ for (const c of commands) {
335
+ const desc = typeof c.json?.description === 'string' ? c.json.description.trim() : ''
336
+ const suffix = desc ? ` — ${desc}` : ''
337
+ lines.push(
338
+ `- [\`${mdEscapeInline(c.name)}\`](#mono-command-${mdEscapeInline(c.name).toLowerCase()})${suffix}`
339
+ )
340
+ }
341
+ lines.push('')
342
+
343
+ for (const c of commands) {
344
+ const j = c.json || {}
345
+ const rel = toPosix(path.relative(REPO_ROOT, c.file))
346
+ const anchor = `mono-command-${c.name.toLowerCase()}`
347
+
348
+ const desc = typeof j.description === 'string' ? j.description.trim() : ''
349
+ const arg = j.argument
350
+ const options = parseOptionsSchema(j.options)
351
+
352
+ lines.push('---')
353
+ lines.push(`### Mono command: ${c.name}`)
354
+ lines.push(`<a id="${anchor}"></a>`)
355
+ lines.push('')
356
+ lines.push(`Source: \`${rel}\``)
357
+ lines.push('')
358
+
359
+ if (desc) {
360
+ lines.push(`**Description:** ${mdEscapeInline(desc)}`)
361
+ lines.push('')
362
+ }
363
+
364
+ // Usage
365
+ lines.push('**Usage**')
366
+ lines.push('')
367
+ lines.push('```bash')
368
+ lines.push(`yarn mono ${c.name}${isObject(arg) ? ` <${c.name}-arg>` : ''} [--options]`)
369
+ lines.push('```')
370
+ lines.push('')
371
+ lines.push('Example:')
372
+ lines.push('')
373
+ lines.push('```bash')
374
+ lines.push(buildUsageExample(c.name, j, options))
375
+ lines.push('```')
376
+ lines.push('')
377
+
378
+ // Argument
379
+ if (isObject(arg)) {
380
+ lines.push('**Argument**')
381
+ lines.push('')
382
+ const bits: string[] = []
383
+ if (typeof arg.type === 'string') bits.push(`type: \`${mdEscapeInline(arg.type)}\``)
384
+ if (arg.default !== undefined)
385
+ bits.push(`default: \`${mdEscapeInline(String(arg.default))}\``)
386
+ if (typeof arg.description === 'string') bits.push(mdEscapeInline(arg.description))
387
+ lines.push(`- ${bits.join(' • ') || '_(no details)_'} `)
388
+ lines.push('')
389
+ }
390
+
391
+ // Options
392
+ if (options.length) {
393
+ lines.push('**Options**')
394
+ lines.push('')
395
+ lines.push('| Option | Type | Shortcut | Default | Allowed | Notes |')
396
+ lines.push('|---|---:|:---:|---:|---|---|')
397
+ for (const o of options) {
398
+ const optCol =
399
+ o.kind === 'boolean'
400
+ ? `\`--${mdEscapeInline(o.key)}\``
401
+ : `\`--${mdEscapeInline(o.key)} <${mdEscapeInline(o.key)}>\``
402
+ const typeCol = `\`${mdEscapeInline(o.type)}\``
403
+ const shortCol = o.shortcut ? `\`-${mdEscapeInline(o.shortcut)}\`` : ''
404
+ const defCol = o.default !== undefined ? `\`${mdEscapeInline(o.default)}\`` : ''
405
+ const allowedCol = o.allowed
406
+ ? o.allowed.map((x) => `\`${mdEscapeInline(x)}\``).join(', ')
407
+ : ''
408
+ const notes = [
409
+ o.allowAll ? 'allowAll' : '',
410
+ o.description ? mdEscapeInline(o.description) : '',
411
+ ]
412
+ .filter(Boolean)
413
+ .join(' ')
414
+ lines.push(
415
+ `| ${optCol} | ${typeCol} | ${shortCol} | ${defCol} | ${allowedCol} | ${notes} |`
416
+ )
417
+ }
418
+ lines.push('')
419
+ }
420
+
421
+ // Environments
422
+ if (j.environments && isObject(j.environments) && Object.keys(j.environments).length) {
423
+ lines.push('**Environment Variables**')
424
+ lines.push('')
425
+ const envs = Object.entries(j.environments).sort(([a], [b]) => a.localeCompare(b))
426
+ for (const [envName, envObj] of envs) {
427
+ lines.push(`- \`${mdEscapeInline(envName)}\``)
428
+ if (isObject(envObj) && Object.keys(envObj).length) {
429
+ const kv = Object.entries(envObj).sort(([a], [b]) => a.localeCompare(b))
430
+ lines.push(
431
+ indentLines(
432
+ kv
433
+ .map(([k, v]) => `- \`${mdEscapeInline(k)}\` = \`${mdEscapeInline(String(v))}\``)
434
+ .join('\n'),
435
+ 2
436
+ )
437
+ )
438
+ }
439
+ }
440
+ lines.push('')
441
+ }
442
+
443
+ // preactions/actions
444
+ if (Array.isArray(j.preactions) && j.preactions.length) {
445
+ lines.push('**Preactions**')
446
+ lines.push('')
447
+ lines.push('```bash')
448
+ for (const p of j.preactions) lines.push(String(p))
449
+ lines.push('```')
450
+ lines.push('')
451
+ }
452
+
453
+ if (Array.isArray(j.actions) && j.actions.length) {
454
+ lines.push('**Actions**')
455
+ lines.push('')
456
+ lines.push('```bash')
457
+ for (const a of j.actions) lines.push(String(a))
458
+ lines.push('```')
459
+ lines.push('')
460
+ }
461
+ }
462
+
463
+ return lines.join('\n')
513
464
  }
514
465
 
515
466
  // ---------- workspace scripts summary ----------
516
467
 
517
468
  // Define PackageInfo type
518
469
  type PackageInfo = {
519
- name: string;
520
- dir: string;
521
- scripts: Record<string, string>;
522
- };
470
+ name: string
471
+ dir: string
472
+ scripts: Record<string, string>
473
+ }
523
474
 
524
475
  function collectScripts(packages: PackageInfo[]): Map<string, string[]> {
525
- const scriptToPackages = new Map<string, string[]>();
526
- for (const p of packages) {
527
- for (const scriptName of Object.keys(p.scripts || {})) {
528
- if (!scriptToPackages.has(scriptName))
529
- scriptToPackages.set(scriptName, []);
530
- scriptToPackages.get(scriptName)!.push(p.name);
531
- }
532
- }
533
- return scriptToPackages;
476
+ const scriptToPackages = new Map<string, string[]>()
477
+ for (const p of packages) {
478
+ for (const scriptName of Object.keys(p.scripts || {})) {
479
+ if (!scriptToPackages.has(scriptName)) scriptToPackages.set(scriptName, [])
480
+ scriptToPackages.get(scriptName)!.push(p.name)
481
+ }
482
+ }
483
+ return scriptToPackages
534
484
  }
535
485
 
536
486
  // ---------- main ----------
537
487
  async function main(): Promise<void> {
538
- if (!(await exists(ROOT_PKG_JSON)))
539
- throw new Error(`Missing: ${ROOT_PKG_JSON}`);
540
- await ensureParentDir(OUTPUT_PATH);
541
-
542
- const rootPkg = await readJson<any>(ROOT_PKG_JSON);
543
- const workspacePatterns = normalizeWorkspacePatterns(rootPkg.workspaces);
544
-
545
- const monoConfig = await readMonoConfig();
546
- const monoCommands = await readMonoCommands();
547
-
548
- const pkgDirs = await findWorkspacePackageDirs(REPO_ROOT, workspacePatterns);
549
- const packages: PackageInfo[] = [];
550
- for (const dir of pkgDirs) {
551
- try {
552
- const pkgPath = path.join(dir, 'package.json');
553
- const pj = await readJson<any>(pkgPath);
554
- packages.push({
555
- name:
556
- pj.name ||
557
- toPosix(path.relative(REPO_ROOT, dir)) ||
558
- path.basename(dir),
559
- dir,
560
- scripts: pj.scripts || {},
561
- });
562
- } catch (err) {
563
- console.error(`[main] Failed to load package.json for:`, dir, err);
564
- // skip
565
- }
566
- }
567
-
568
- const parts: string[] = [];
569
- parts.push(`# ⚙️ Command Line Reference
488
+ if (!(await exists(ROOT_PKG_JSON))) throw new Error(`Missing: ${ROOT_PKG_JSON}`)
489
+ await ensureParentDir(OUTPUT_PATH)
490
+
491
+ const rootPkg = await readJson<any>(ROOT_PKG_JSON)
492
+ const workspacePatterns = normalizeWorkspacePatterns(rootPkg.workspaces)
493
+
494
+ const monoConfig = await readMonoConfig()
495
+ const monoCommands = await readMonoCommands()
496
+
497
+ const pkgDirs = await findWorkspacePackageDirs(REPO_ROOT, workspacePatterns)
498
+ const packages: PackageInfo[] = []
499
+ for (const dir of pkgDirs) {
500
+ try {
501
+ const pkgPath = path.join(dir, 'package.json')
502
+ const pj = await readJson<any>(pkgPath)
503
+ packages.push({
504
+ name: pj.name || toPosix(path.relative(REPO_ROOT, dir)) || path.basename(dir),
505
+ dir,
506
+ scripts: pj.scripts || {},
507
+ })
508
+ } catch (err) {
509
+ console.error(`[main] Failed to load package.json for:`, dir, err)
510
+ // skip
511
+ }
512
+ }
513
+
514
+ const parts: string[] = []
515
+ parts.push(`# ⚙️ Command Line Reference
570
516
 
571
517
  > Generated by \`scripts/generate-readme.mjs\`.
572
518
  > Update \`.mono/config.json\`, \`.mono/*.json\`, and workspace package scripts to change this output.
573
519
 
574
- `);
575
- parts.push(formatMonoConfigSection(monoConfig));
576
- parts.push('');
577
- parts.push(formatMonoCommandsSection(monoCommands));
578
- parts.push('');
520
+ `)
521
+ parts.push(formatMonoConfigSection(monoConfig))
522
+ parts.push('')
523
+ parts.push(formatMonoCommandsSection(monoCommands))
524
+ parts.push('')
579
525
 
580
- const val = await generateDocsIndex({
581
- docsDir: path.join(REPO_ROOT, 'docs'),
582
- excludeFile: 'command-line.md',
583
- });
526
+ const val = await generateDocsIndex({
527
+ docsDir: path.join(REPO_ROOT, 'docs'),
528
+ excludeFile: 'command-line.md',
529
+ })
584
530
 
585
- val.split('\n').forEach((line) => parts.push(line));
531
+ val.split('\n').forEach((line) => parts.push(line))
586
532
 
587
- await ensureParentDir(OUTPUT_README);
588
- await fs.writeFile(OUTPUT_README, parts.join('\n'), 'utf8');
533
+ await ensureParentDir(OUTPUT_README)
534
+ await fs.writeFile(OUTPUT_README, parts.join('\n'), 'utf8')
589
535
 
590
- console.log(`[main] Generated: ${OUTPUT_README}`);
591
- console.log(`[main] mono config: ${monoConfig ? 'yes' : 'no'}`);
592
- console.log(`[main] mono commands: ${monoCommands.length}`);
593
- console.log(`[main] workspace packages: ${packages.length}`);
536
+ console.log(`[main] Generated: ${OUTPUT_README}`)
537
+ console.log(`[main] mono config: ${monoConfig ? 'yes' : 'no'}`)
538
+ console.log(`[main] mono commands: ${monoCommands.length}`)
539
+ console.log(`[main] workspace packages: ${packages.length}`)
594
540
  }
595
541
 
596
542
  main().catch((err) => {
597
- console.error(err?.stack || String(err));
598
- process.exitCode = 1;
599
- });
543
+ console.error(err?.stack || String(err))
544
+ process.exitCode = 1
545
+ })