@fgv/repo-template 5.1.0-2
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/.rush/temp/45a8d0dcbb9c2e59fa02645657661dffbd25461f.tar.log +57 -0
- package/.rush/temp/92e27a75687fa5062b71fdb897f0928a8aa4e0c9.tar.log +57 -0
- package/.rush/temp/chunked-rush-logs/repo-template.build.chunks.jsonl +7 -0
- package/.rush/temp/operation/build/all.log +7 -0
- package/.rush/temp/operation/build/log-chunks.jsonl +7 -0
- package/.rush/temp/operation/build/state.json +3 -0
- package/.rush/temp/shrinkwrap-deps.json +576 -0
- package/README.md +216 -0
- package/bin/repo-template.js +18 -0
- package/config/rig.json +4 -0
- package/lib/cli.d.ts +14 -0
- package/lib/cli.d.ts.map +1 -0
- package/lib/cli.js +126 -0
- package/lib/cli.js.map +1 -0
- package/lib/commands/create.d.ts +17 -0
- package/lib/commands/create.d.ts.map +1 -0
- package/lib/commands/create.js +212 -0
- package/lib/commands/create.js.map +1 -0
- package/lib/commands/init-library.d.ts +25 -0
- package/lib/commands/init-library.d.ts.map +1 -0
- package/lib/commands/init-library.js +217 -0
- package/lib/commands/init-library.js.map +1 -0
- package/lib/commands/patch.d.ts +15 -0
- package/lib/commands/patch.d.ts.map +1 -0
- package/lib/commands/patch.js +104 -0
- package/lib/commands/patch.js.map +1 -0
- package/lib/commands/sync.d.ts +11 -0
- package/lib/commands/sync.d.ts.map +1 -0
- package/lib/commands/sync.js +156 -0
- package/lib/commands/sync.js.map +1 -0
- package/lib/index.d.ts +14 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +29 -0
- package/lib/index.js.map +1 -0
- package/lib/packlets/fs/index.d.ts +40 -0
- package/lib/packlets/fs/index.d.ts.map +1 -0
- package/lib/packlets/fs/index.js +142 -0
- package/lib/packlets/fs/index.js.map +1 -0
- package/lib/packlets/jsonc/index.d.ts +27 -0
- package/lib/packlets/jsonc/index.d.ts.map +1 -0
- package/lib/packlets/jsonc/index.js +124 -0
- package/lib/packlets/jsonc/index.js.map +1 -0
- package/lib/packlets/manifest/index.d.ts +15 -0
- package/lib/packlets/manifest/index.d.ts.map +1 -0
- package/lib/packlets/manifest/index.js +61 -0
- package/lib/packlets/manifest/index.js.map +1 -0
- package/lib/packlets/manifest/types.d.ts +33 -0
- package/lib/packlets/manifest/types.d.ts.map +1 -0
- package/lib/packlets/manifest/types.js +6 -0
- package/lib/packlets/manifest/types.js.map +1 -0
- package/lib/packlets/template/index.d.ts +22 -0
- package/lib/packlets/template/index.d.ts.map +1 -0
- package/lib/packlets/template/index.js +75 -0
- package/lib/packlets/template/index.js.map +1 -0
- package/package.json +32 -0
- package/rush-logs/repo-template.build.cache.log +4 -0
- package/rush-logs/repo-template.build.log +7 -0
- package/src/cli.ts +141 -0
- package/src/commands/create.ts +216 -0
- package/src/commands/init-library.ts +249 -0
- package/src/commands/patch.ts +84 -0
- package/src/commands/sync.ts +137 -0
- package/src/index.ts +14 -0
- package/src/packlets/fs/index.ts +114 -0
- package/src/packlets/jsonc/index.ts +134 -0
- package/src/packlets/manifest/index.ts +29 -0
- package/src/packlets/manifest/types.ts +36 -0
- package/src/packlets/template/index.ts +48 -0
- package/sync-manifest.json +222 -0
- package/temp/build/typescript/ts_l9Fw4VUO.json +1 -0
- package/templates/.gitignore.tmpl +85 -0
- package/templates/ACTIVE_DEVELOPMENT.md.tmpl +58 -0
- package/templates/CLAUDE.md.tmpl +124 -0
- package/templates/command-line.json.tmpl +50 -0
- package/templates/package.json.tmpl +5 -0
- package/templates/version-policies.json.tmpl +8 -0
- package/tsconfig.json +7 -0
package/README.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# fgv Monorepo Template System
|
|
2
|
+
|
|
3
|
+
This directory contains scripts and configuration for creating and maintaining fgv-derived Rush monorepos.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The fgv repository contains general-purpose TypeScript utilities (`@fgv/ts-utils`, `@fgv/ts-json`, etc.) alongside domain-specific code. This template system allows domain-specific code to live in its own monorepo while sharing infrastructure, coding standards, and agent configurations.
|
|
8
|
+
|
|
9
|
+
### Architecture
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
fgv (source of truth)
|
|
13
|
+
├── Utility libraries (published to npm)
|
|
14
|
+
├── Infrastructure & standards ──────► chocolate-lab (consumer)
|
|
15
|
+
│ ├── .ai/instructions/ ├── .ai/instructions/ (synced)
|
|
16
|
+
│ ├── .claude/agents/ ├── .claude/agents/ (synced)
|
|
17
|
+
│ ├── rigs/heft-dual-rig/ ├── rigs/heft-dual-rig/(synced)
|
|
18
|
+
│ └── ... ├── libraries/ts-chocolate/
|
|
19
|
+
│ ├── apps/chocolate-lab-web/
|
|
20
|
+
│ └── ... (domain code)
|
|
21
|
+
└── scripts/template/ (this dir)
|
|
22
|
+
├── create-repo.sh ──────► Stamps out new repos
|
|
23
|
+
├── sync-shared.sh ──────► Pushes updates to consumers
|
|
24
|
+
└── patch-rush-config.mjs ──────► JSONC config patching
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## How It Works
|
|
28
|
+
|
|
29
|
+
### Repo Creation: `rush init` + Customize
|
|
30
|
+
|
|
31
|
+
New repos are created using Rush's own `rush init` as the foundation, which ensures:
|
|
32
|
+
- All Rush config files have full inline documentation
|
|
33
|
+
- New Rush features appear automatically as Rush evolves
|
|
34
|
+
- The config structure stays in sync with the installed Rush version
|
|
35
|
+
|
|
36
|
+
After `rush init`, the script applies fgv-specific customizations:
|
|
37
|
+
|
|
38
|
+
1. **JSONC patches** (via `patch-rush-config.mjs`): Targeted edits to rush.json and other config files that preserve comments and formatting
|
|
39
|
+
2. **Templated files**: Generated from `.tmpl` templates with parameter substitution (consumer-owned after creation)
|
|
40
|
+
3. **Shared files**: Copied verbatim from fgv (overwritten on each sync)
|
|
41
|
+
|
|
42
|
+
### What Gets Patched vs. Synced vs. Templated
|
|
43
|
+
|
|
44
|
+
| Category | During Create | During Sync | Examples |
|
|
45
|
+
|----------|--------------|-------------|---------|
|
|
46
|
+
| Rush config (from `rush init`) | Patched with fgv opinions | Not touched (consumer-owned) | rush.json, build-cache.json, pnpm-config.json |
|
|
47
|
+
| Templated files | Generated from .tmpl | Not touched (consumer-owned) | CLAUDE.md, command-line.json, version-policies.json |
|
|
48
|
+
| Shared files | Copied from fgv | Overwritten from fgv | .ai/instructions/, .claude/agents/, rigs/, .prettierrc.js |
|
|
49
|
+
|
|
50
|
+
### Rush Config Patches Applied
|
|
51
|
+
|
|
52
|
+
These targeted customizations are applied to `rush init` output:
|
|
53
|
+
|
|
54
|
+
| File | Patch | Reason |
|
|
55
|
+
|------|-------|--------|
|
|
56
|
+
| rush.json | `ensureConsistentVersions: true` | Enforce version consistency |
|
|
57
|
+
| rush.json | `projectFolderMinDepth/MaxDepth: 2` | Enforce category folder structure |
|
|
58
|
+
| rush.json | `repository.url`, `defaultBranch`, `defaultRemote` | Enable `rush change` |
|
|
59
|
+
| rush.json | Add heft-dual-rig and typedoc-compact-theme projects | Shared build infrastructure |
|
|
60
|
+
| build-cache.json | `buildCacheEnabled: true` | Enable build caching |
|
|
61
|
+
| pnpm-config.json | `strictPeerDependencies: true` | Catch peer dependency issues |
|
|
62
|
+
|
|
63
|
+
## File Categories
|
|
64
|
+
|
|
65
|
+
### Shared Files (synced verbatim)
|
|
66
|
+
These files are identical across all fgv-derived repos and are overwritten on each sync:
|
|
67
|
+
|
|
68
|
+
| Category | Files |
|
|
69
|
+
|----------|-------|
|
|
70
|
+
| Coding standards | `.ai/instructions/CODING_STANDARDS.md`, `TESTING_GUIDELINES.md`, `CODE_REVIEW_CHECKLIST.md`, `MONOREPO_GUIDE.md` |
|
|
71
|
+
| Workflows | `.ai/workflows/*.yaml` |
|
|
72
|
+
| Claude agents | `.claude/agents/**/*.md` |
|
|
73
|
+
| Build rig | `rigs/heft-dual-rig/` |
|
|
74
|
+
| TypeDoc theme | `plugins/typedoc-compact-theme/` |
|
|
75
|
+
| Code formatting | `.prettierrc.js`, `.gitattributes` |
|
|
76
|
+
| CI | `.github/workflows/ci.yml` |
|
|
77
|
+
| AI adapters | `.windsurfrules`, `.cursorrules`, `.github/copilot-instructions.md` |
|
|
78
|
+
| Prettier | `common/autoinstallers/rush-prettier/package.json` |
|
|
79
|
+
|
|
80
|
+
### Templated Files (generated once, then consumer-owned)
|
|
81
|
+
These files are parameterized during repo creation and never overwritten by sync:
|
|
82
|
+
|
|
83
|
+
| File | Parameters |
|
|
84
|
+
|------|-----------|
|
|
85
|
+
| `CLAUDE.md` | `{{PROJECT_TABLE}}` — library/purpose table |
|
|
86
|
+
| `command-line.json` | Generic commands only; add domain commands manually |
|
|
87
|
+
| `version-policies.json` | `{{VERSION_POLICY_NAME}}`, `{{VERSION}}` |
|
|
88
|
+
| `ACTIVE_DEVELOPMENT.md` | `{{ACTIVE_LIBRARIES}}` — domain project table |
|
|
89
|
+
| `.gitignore` | No parameters (but consumer may customize) |
|
|
90
|
+
| `package.json` | No parameters |
|
|
91
|
+
|
|
92
|
+
### Rush Config Files (from `rush init`, consumer-owned)
|
|
93
|
+
These files come from `rush init` with targeted patches applied during creation. They are never synced — consumers own them fully:
|
|
94
|
+
|
|
95
|
+
- `rush.json`, `common-versions.json`, `experiments.json`, `pnpm-config.json`, `build-cache.json`, `rush-plugins.json`, `.pnpmfile.cjs`, `.npmrc`, `.npmrc-publish`, `artifactory.json`, `cobuild.json`, `custom-tips.json`, `subspaces.json`
|
|
96
|
+
|
|
97
|
+
## Usage
|
|
98
|
+
|
|
99
|
+
### Creating a New Repo
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
./create-repo.sh \
|
|
103
|
+
--target-dir /path/to/new-repo \
|
|
104
|
+
--repo-url https://github.com/ErikFortune/new-repo \
|
|
105
|
+
--version-policy my-domain \
|
|
106
|
+
--version 0.1.0
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
For existing git repos (e.g., already created on GitHub):
|
|
110
|
+
```bash
|
|
111
|
+
./create-repo.sh \
|
|
112
|
+
--target-dir /path/to/existing-repo \
|
|
113
|
+
--repo-url https://github.com/ErikFortune/existing-repo \
|
|
114
|
+
--version-policy my-domain \
|
|
115
|
+
--version 0.1.0 \
|
|
116
|
+
--allow-existing \
|
|
117
|
+
--no-git-init
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
After creation:
|
|
121
|
+
|
|
122
|
+
1. Copy your domain packages into `libraries/`, `apps/`, `tools/`, `services/`
|
|
123
|
+
2. Register them in `rush.json` (use `patch-rush-config.mjs` or edit directly)
|
|
124
|
+
3. Convert `workspace:*` dependencies on `@fgv/*` utilities to published versions (e.g., `^5.1.0-0`)
|
|
125
|
+
4. Fill in `CLAUDE.md` project table and `ACTIVE_DEVELOPMENT.md`
|
|
126
|
+
5. Add domain-specific Rush commands to `command-line.json`
|
|
127
|
+
6. Run `rush install && rush build && rush test`
|
|
128
|
+
|
|
129
|
+
### Syncing Updates
|
|
130
|
+
|
|
131
|
+
When shared files (coding standards, agents, etc.) are updated in fgv:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Preview what would change
|
|
135
|
+
./sync-shared.sh --target-dir /path/to/consumer-repo --dry-run
|
|
136
|
+
|
|
137
|
+
# Apply changes
|
|
138
|
+
./sync-shared.sh --target-dir /path/to/consumer-repo
|
|
139
|
+
|
|
140
|
+
# Review and commit in the consumer repo
|
|
141
|
+
cd /path/to/consumer-repo
|
|
142
|
+
git diff
|
|
143
|
+
git add -A
|
|
144
|
+
git commit -m "Sync shared files from fgv template"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### JSONC Config Patching
|
|
148
|
+
|
|
149
|
+
The `patch-rush-config.mjs` helper can modify any JSONC file while preserving comments:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# Set a value
|
|
153
|
+
node patch-rush-config.mjs rush.json --set 'ensureConsistentVersions=true'
|
|
154
|
+
|
|
155
|
+
# Uncomment a property then set its value
|
|
156
|
+
node patch-rush-config.mjs rush.json --uncomment 'projectFolderMinDepth' --set 'projectFolderMinDepth=2'
|
|
157
|
+
|
|
158
|
+
# Add to an array (JSON value)
|
|
159
|
+
node patch-rush-config.mjs rush.json --add-to-array 'projects={"packageName":"@my/lib","projectFolder":"libraries/my-lib"}'
|
|
160
|
+
|
|
161
|
+
# Set a value using raw JSON
|
|
162
|
+
node patch-rush-config.mjs rush.json --set-json 'repository={"url":"https://github.com/...","defaultBranch":"main"}'
|
|
163
|
+
|
|
164
|
+
# Remove a property
|
|
165
|
+
node patch-rush-config.mjs rush.json --remove 'telemetryEnabled'
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### How Sync Tracking Works
|
|
169
|
+
|
|
170
|
+
Each consumer repo has a `.template-sync` file that records:
|
|
171
|
+
- When the repo was created from the template
|
|
172
|
+
- Which source commit was last synced
|
|
173
|
+
- When the last sync occurred
|
|
174
|
+
|
|
175
|
+
This is informational — the sync script always copies the latest files regardless of tracking state.
|
|
176
|
+
|
|
177
|
+
## Consuming @fgv/* Utilities
|
|
178
|
+
|
|
179
|
+
Domain repos depend on fgv utility packages via npm (not workspace links):
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"dependencies": {
|
|
184
|
+
"@fgv/ts-utils": "^5.1.0-0",
|
|
185
|
+
"@fgv/ts-json": "^5.1.0-0"
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
To update utility versions, use `rush add -p @fgv/ts-utils@^5.2.0` etc. in the consumer repo.
|
|
191
|
+
|
|
192
|
+
## Manifest Reference
|
|
193
|
+
|
|
194
|
+
The `sync-manifest.json` file is the source of truth for which files are shared vs. templated. It has three sections:
|
|
195
|
+
|
|
196
|
+
- **`shared`** — Individual files copied verbatim
|
|
197
|
+
- **`sharedPackages`** — Entire directories synced (excluding build artifacts)
|
|
198
|
+
- **`templated`** — Files generated from `.tmpl` templates during creation only
|
|
199
|
+
|
|
200
|
+
## Extending
|
|
201
|
+
|
|
202
|
+
### Adding a new shared file
|
|
203
|
+
1. Add an entry to `sync-manifest.json` under `shared.files`
|
|
204
|
+
2. Run `sync-shared.sh` against consumer repos
|
|
205
|
+
|
|
206
|
+
### Adding a new template parameter
|
|
207
|
+
1. Add `{{PARAM_NAME}}` to the `.tmpl` file
|
|
208
|
+
2. Add the substitution to `create-repo.sh`'s `render_template` function
|
|
209
|
+
3. Document the parameter in this README
|
|
210
|
+
|
|
211
|
+
### Adding a Rush config patch
|
|
212
|
+
1. Add the patch command to `create-repo.sh` in the "Patch rush config" step
|
|
213
|
+
2. Document the patch in this README's "Rush Config Patches Applied" table
|
|
214
|
+
|
|
215
|
+
### Creating a new consumer repo
|
|
216
|
+
Follow the "Creating a New Repo" steps above. The template system is designed so that consumer repos are fully independent after creation — they can diverge as needed while still receiving shared file updates via sync.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { RepoTemplateCli } = require('../lib/cli');
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
try {
|
|
7
|
+
const cli = new RepoTemplateCli();
|
|
8
|
+
await cli.run(process.argv);
|
|
9
|
+
} catch (error) {
|
|
10
|
+
console.error('Fatal error:', error.message);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
main().catch((error) => {
|
|
16
|
+
console.error('Unhandled error:', error);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
});
|
package/config/rig.json
ADDED
package/lib/cli.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI entry point — sets up commander with create, sync, and patch subcommands.
|
|
3
|
+
*/
|
|
4
|
+
export declare class RepoTemplateCli {
|
|
5
|
+
private readonly _program;
|
|
6
|
+
constructor();
|
|
7
|
+
run(argv: string[]): Promise<void>;
|
|
8
|
+
private _setupCommands;
|
|
9
|
+
/**
|
|
10
|
+
* Auto-detect the fgv source directory by walking up from the current working directory.
|
|
11
|
+
*/
|
|
12
|
+
private _resolveSourceDir;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=cli.d.ts.map
|
package/lib/cli.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;;IAOtB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,OAAO,CAAC,cAAc;IAuGtB;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAW1B"}
|
package/lib/cli.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CLI entry point — sets up commander with create, sync, and patch subcommands.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RepoTemplateCli = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const fs_1 = require("./packlets/fs");
|
|
9
|
+
const create_1 = require("./commands/create");
|
|
10
|
+
const sync_1 = require("./commands/sync");
|
|
11
|
+
const patch_1 = require("./commands/patch");
|
|
12
|
+
const init_library_1 = require("./commands/init-library");
|
|
13
|
+
class RepoTemplateCli {
|
|
14
|
+
constructor() {
|
|
15
|
+
this._program = new commander_1.Command();
|
|
16
|
+
this._setupCommands();
|
|
17
|
+
}
|
|
18
|
+
async run(argv) {
|
|
19
|
+
await this._program.parseAsync(argv);
|
|
20
|
+
}
|
|
21
|
+
_setupCommands() {
|
|
22
|
+
this._program
|
|
23
|
+
.name('repo-template')
|
|
24
|
+
.description('Create and maintain fgv-derived Rush monorepos')
|
|
25
|
+
.version('5.1.0');
|
|
26
|
+
// ── create ──
|
|
27
|
+
this._program
|
|
28
|
+
.command('create')
|
|
29
|
+
.description('Stamp out a new fgv-derived Rush monorepo using rush init + JSONC patching')
|
|
30
|
+
.requiredOption('-t, --target-dir <path>', 'Directory to create the new repo in')
|
|
31
|
+
.requiredOption('-u, --repo-url <url>', 'GitHub repository URL')
|
|
32
|
+
.option('-p, --version-policy <name>', 'Version policy name', 'default')
|
|
33
|
+
.option('--initial-version <ver>', 'Initial version', '0.1.0')
|
|
34
|
+
.option('-s, --source-dir <path>', 'Source repo for shared files (auto-detected if in fgv repo)')
|
|
35
|
+
.option('--allow-existing', 'Allow target directory to already exist', false)
|
|
36
|
+
.option('--no-git-init', 'Skip git init and initial commit')
|
|
37
|
+
.action(async (opts) => {
|
|
38
|
+
var _a;
|
|
39
|
+
const sourceDir = (_a = opts.sourceDir) !== null && _a !== void 0 ? _a : this._resolveSourceDir();
|
|
40
|
+
await (0, create_1.runCreate)({
|
|
41
|
+
targetDir: opts.targetDir,
|
|
42
|
+
repoUrl: opts.repoUrl,
|
|
43
|
+
versionPolicy: opts.versionPolicy,
|
|
44
|
+
version: opts.initialVersion,
|
|
45
|
+
sourceDir,
|
|
46
|
+
allowExisting: opts.allowExisting,
|
|
47
|
+
gitInit: opts.gitInit
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
// ── sync ──
|
|
51
|
+
this._program
|
|
52
|
+
.command('sync')
|
|
53
|
+
.description('Sync shared files from the fgv source repo to a consumer repo')
|
|
54
|
+
.requiredOption('-t, --target-dir <path>', 'Consumer repo to update')
|
|
55
|
+
.option('-s, --source-dir <path>', 'Source repo (auto-detected if in fgv repo)')
|
|
56
|
+
.option('-n, --dry-run', 'Show what would change without modifying files', false)
|
|
57
|
+
.action(async (opts) => {
|
|
58
|
+
var _a;
|
|
59
|
+
const sourceDir = (_a = opts.sourceDir) !== null && _a !== void 0 ? _a : this._resolveSourceDir();
|
|
60
|
+
await (0, sync_1.runSync)({
|
|
61
|
+
targetDir: opts.targetDir,
|
|
62
|
+
sourceDir,
|
|
63
|
+
dryRun: opts.dryRun
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
// ── init-library ──
|
|
67
|
+
this._program
|
|
68
|
+
.command('init-library')
|
|
69
|
+
.description('Scaffold a new library package within an existing Rush monorepo')
|
|
70
|
+
.requiredOption('-n, --name <name>', 'Package name (e.g. "ts-my-lib" — auto-prefixed with @fgv/)')
|
|
71
|
+
.option('-d, --description <text>', 'Package description', '')
|
|
72
|
+
.option('-r, --rig <type>', 'Heft rig: dual (default), node, or browser', 'dual')
|
|
73
|
+
.option('-c, --category <type>', 'Category folder: libraries (default), tools, apps, services', 'libraries')
|
|
74
|
+
.option('--repo-dir <path>', 'Rush monorepo root (default: cwd)', process.cwd())
|
|
75
|
+
.option('-p, --version-policy <name>', 'Version policy name', 'default')
|
|
76
|
+
.option('--initial-version <ver>', 'Initial version', '0.1.0')
|
|
77
|
+
.option('--fgv-dep-version <ver>', 'Version spec for @fgv/* deps ("workspace:*" in fgv, version range in consumers)', 'workspace:*')
|
|
78
|
+
.action(async (opts) => {
|
|
79
|
+
await (0, init_library_1.runInitLibrary)({
|
|
80
|
+
name: opts.name,
|
|
81
|
+
description: opts.description,
|
|
82
|
+
rig: opts.rig,
|
|
83
|
+
category: opts.category,
|
|
84
|
+
repoDir: opts.repoDir,
|
|
85
|
+
versionPolicy: opts.versionPolicy,
|
|
86
|
+
version: opts.initialVersion,
|
|
87
|
+
fgvDepVersion: opts.fgvDepVersion
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
// ── patch ──
|
|
91
|
+
this._program
|
|
92
|
+
.command('patch <file>')
|
|
93
|
+
.description('Apply targeted edits to a JSONC config file while preserving comments')
|
|
94
|
+
.allowUnknownOption(true)
|
|
95
|
+
.helpOption(false)
|
|
96
|
+
.action(async (file, _opts, cmd) => {
|
|
97
|
+
// Parse the raw args after the file argument as patch operations
|
|
98
|
+
const rawArgs = cmd.args.slice(1); // skip the file arg
|
|
99
|
+
// Actually, commander passes remaining args differently. Let's get them from process.argv
|
|
100
|
+
const allArgs = process.argv;
|
|
101
|
+
const patchIdx = allArgs.indexOf('patch');
|
|
102
|
+
const fileIdx = patchIdx + 1;
|
|
103
|
+
const opArgs = allArgs.slice(fileIdx + 1);
|
|
104
|
+
const operations = (0, patch_1.parsePatchArgs)(opArgs);
|
|
105
|
+
if (operations.length === 0) {
|
|
106
|
+
console.error('No operations specified. Use --set, --uncomment, --add-to-array, etc.');
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
await (0, patch_1.runPatch)({ file, operations });
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Auto-detect the fgv source directory by walking up from the current working directory.
|
|
114
|
+
*/
|
|
115
|
+
_resolveSourceDir() {
|
|
116
|
+
const detected = (0, fs_1.detectSourceDir)(process.cwd());
|
|
117
|
+
if (!detected) {
|
|
118
|
+
console.error('ERROR: Could not auto-detect fgv source repo. ' +
|
|
119
|
+
'Please specify --source-dir or run from within the fgv repository.');
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
return detected;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.RepoTemplateCli = RepoTemplateCli;
|
|
126
|
+
//# sourceMappingURL=cli.js.map
|
package/lib/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * CLI entry point — sets up commander with create, sync, and patch subcommands.\n */\n\nimport { Command } from 'commander';\nimport { detectSourceDir } from './packlets/fs';\nimport { runCreate } from './commands/create';\nimport { runSync } from './commands/sync';\nimport { runPatch, parsePatchArgs } from './commands/patch';\nimport { runInitLibrary, RigType, CategoryType } from './commands/init-library';\n\nexport class RepoTemplateCli {\n private readonly _program: Command;\n\n public constructor() {\n this._program = new Command();\n this._setupCommands();\n }\n\n public async run(argv: string[]): Promise<void> {\n await this._program.parseAsync(argv);\n }\n\n private _setupCommands(): void {\n this._program\n .name('repo-template')\n .description('Create and maintain fgv-derived Rush monorepos')\n .version('5.1.0');\n\n // ── create ──\n this._program\n .command('create')\n .description('Stamp out a new fgv-derived Rush monorepo using rush init + JSONC patching')\n .requiredOption('-t, --target-dir <path>', 'Directory to create the new repo in')\n .requiredOption('-u, --repo-url <url>', 'GitHub repository URL')\n .option('-p, --version-policy <name>', 'Version policy name', 'default')\n .option('--initial-version <ver>', 'Initial version', '0.1.0')\n .option('-s, --source-dir <path>', 'Source repo for shared files (auto-detected if in fgv repo)')\n .option('--allow-existing', 'Allow target directory to already exist', false)\n .option('--no-git-init', 'Skip git init and initial commit')\n .action(async (opts) => {\n const sourceDir = opts.sourceDir ?? this._resolveSourceDir();\n await runCreate({\n targetDir: opts.targetDir,\n repoUrl: opts.repoUrl,\n versionPolicy: opts.versionPolicy,\n version: opts.initialVersion,\n sourceDir,\n allowExisting: opts.allowExisting,\n gitInit: opts.gitInit\n });\n });\n\n // ── sync ──\n this._program\n .command('sync')\n .description('Sync shared files from the fgv source repo to a consumer repo')\n .requiredOption('-t, --target-dir <path>', 'Consumer repo to update')\n .option('-s, --source-dir <path>', 'Source repo (auto-detected if in fgv repo)')\n .option('-n, --dry-run', 'Show what would change without modifying files', false)\n .action(async (opts) => {\n const sourceDir = opts.sourceDir ?? this._resolveSourceDir();\n await runSync({\n targetDir: opts.targetDir,\n sourceDir,\n dryRun: opts.dryRun\n });\n });\n\n // ── init-library ──\n this._program\n .command('init-library')\n .description('Scaffold a new library package within an existing Rush monorepo')\n .requiredOption('-n, --name <name>', 'Package name (e.g. \"ts-my-lib\" — auto-prefixed with @fgv/)')\n .option('-d, --description <text>', 'Package description', '')\n .option('-r, --rig <type>', 'Heft rig: dual (default), node, or browser', 'dual')\n .option(\n '-c, --category <type>',\n 'Category folder: libraries (default), tools, apps, services',\n 'libraries'\n )\n .option('--repo-dir <path>', 'Rush monorepo root (default: cwd)', process.cwd())\n .option('-p, --version-policy <name>', 'Version policy name', 'default')\n .option('--initial-version <ver>', 'Initial version', '0.1.0')\n .option(\n '--fgv-dep-version <ver>',\n 'Version spec for @fgv/* deps (\"workspace:*\" in fgv, version range in consumers)',\n 'workspace:*'\n )\n .action(async (opts) => {\n await runInitLibrary({\n name: opts.name,\n description: opts.description,\n rig: opts.rig as RigType,\n category: opts.category as CategoryType,\n repoDir: opts.repoDir,\n versionPolicy: opts.versionPolicy,\n version: opts.initialVersion,\n fgvDepVersion: opts.fgvDepVersion\n });\n });\n\n // ── patch ──\n this._program\n .command('patch <file>')\n .description('Apply targeted edits to a JSONC config file while preserving comments')\n .allowUnknownOption(true)\n .helpOption(false)\n .action(async (file, _opts, cmd) => {\n // Parse the raw args after the file argument as patch operations\n const rawArgs = cmd.args.slice(1); // skip the file arg\n // Actually, commander passes remaining args differently. Let's get them from process.argv\n const allArgs = process.argv;\n const patchIdx = allArgs.indexOf('patch');\n const fileIdx = patchIdx + 1;\n const opArgs = allArgs.slice(fileIdx + 1);\n\n const operations = parsePatchArgs(opArgs);\n if (operations.length === 0) {\n console.error('No operations specified. Use --set, --uncomment, --add-to-array, etc.');\n process.exit(1);\n }\n await runPatch({ file, operations });\n });\n }\n\n /**\n * Auto-detect the fgv source directory by walking up from the current working directory.\n */\n private _resolveSourceDir(): string {\n const detected = detectSourceDir(process.cwd());\n if (!detected) {\n console.error(\n 'ERROR: Could not auto-detect fgv source repo. ' +\n 'Please specify --source-dir or run from within the fgv repository.'\n );\n process.exit(1);\n }\n return detected;\n }\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create command — stamps out a new fgv-derived Rush monorepo.
|
|
3
|
+
*
|
|
4
|
+
* Uses `rush init` to generate base config with full documentation,
|
|
5
|
+
* then applies fgv-specific customizations via JSONC patching and shared file sync.
|
|
6
|
+
*/
|
|
7
|
+
export interface ICreateOptions {
|
|
8
|
+
targetDir: string;
|
|
9
|
+
repoUrl: string;
|
|
10
|
+
versionPolicy: string;
|
|
11
|
+
version: string;
|
|
12
|
+
sourceDir: string;
|
|
13
|
+
allowExisting: boolean;
|
|
14
|
+
gitInit: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function runCreate(options: ICreateOptions): Promise<void>;
|
|
17
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;CAClB;AAOD,wBAAsB,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA0LtE"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Create command — stamps out a new fgv-derived Rush monorepo.
|
|
4
|
+
*
|
|
5
|
+
* Uses `rush init` to generate base config with full documentation,
|
|
6
|
+
* then applies fgv-specific customizations via JSONC patching and shared file sync.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.runCreate = runCreate;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const manifest_1 = require("../packlets/manifest");
|
|
46
|
+
const jsonc_1 = require("../packlets/jsonc");
|
|
47
|
+
const template_1 = require("../packlets/template");
|
|
48
|
+
const fs_1 = require("../packlets/fs");
|
|
49
|
+
const RUSH_VERSION = '5.172.1';
|
|
50
|
+
const NODE_VERSION_RANGE = '>=14.15.0 <15.0.0 || >=16.13.0 <17.0.0 || >=18.15.0 <19.0.0 || >=20.18.0 <21.0.0 || >=22.22.0 <23.0.0';
|
|
51
|
+
async function runCreate(options) {
|
|
52
|
+
const { targetDir, repoUrl, versionPolicy, version, sourceDir, allowExisting, gitInit } = options;
|
|
53
|
+
// Validate
|
|
54
|
+
if (!allowExisting && fs.existsSync(targetDir)) {
|
|
55
|
+
throw new Error(`Target directory already exists: ${targetDir} (use --allow-existing to override)`);
|
|
56
|
+
}
|
|
57
|
+
if (!fs.existsSync(path.join(sourceDir, 'rush.json'))) {
|
|
58
|
+
throw new Error(`Source directory is not a Rush repo: ${sourceDir}`);
|
|
59
|
+
}
|
|
60
|
+
const manifestPath = (0, manifest_1.getDefaultManifestPath)();
|
|
61
|
+
const templatesDir = (0, template_1.getDefaultTemplatesDir)();
|
|
62
|
+
const manifest = (0, manifest_1.loadManifest)(manifestPath);
|
|
63
|
+
console.log(`Creating new monorepo at: ${targetDir}`);
|
|
64
|
+
console.log(` Source repo: ${sourceDir}`);
|
|
65
|
+
console.log(` Repo URL: ${repoUrl}`);
|
|
66
|
+
console.log(` Version: ${versionPolicy}@${version}`);
|
|
67
|
+
console.log('');
|
|
68
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
69
|
+
// ── Step 1: rush init ──
|
|
70
|
+
if (fs.existsSync(path.join(targetDir, 'rush.json'))) {
|
|
71
|
+
console.log('==> Target already has rush.json, skipping rush init');
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
console.log('==> Running rush init...');
|
|
75
|
+
try {
|
|
76
|
+
const output = (0, fs_1.exec)(`npx "@microsoft/rush@${RUSH_VERSION}" init`, { cwd: targetDir });
|
|
77
|
+
for (const line of output.split('\n')) {
|
|
78
|
+
console.log(` ${line}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
// rush init writes to stderr for some messages, check if rush.json was created
|
|
83
|
+
if (!fs.existsSync(path.join(targetDir, 'rush.json'))) {
|
|
84
|
+
throw new Error(`rush init failed: ${err.message}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// ── Step 2: Patch rush.json ──
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log('==> Patching rush.json with fgv customizations...');
|
|
91
|
+
const rushJsonOps = [
|
|
92
|
+
{ type: 'set', path: 'nodeSupportedVersionRange', value: NODE_VERSION_RANGE },
|
|
93
|
+
{ type: 'set', path: 'ensureConsistentVersions', value: true },
|
|
94
|
+
{ type: 'uncomment', path: 'projectFolderMinDepth' },
|
|
95
|
+
{ type: 'set', path: 'projectFolderMinDepth', value: 2 },
|
|
96
|
+
{ type: 'uncomment', path: 'projectFolderMaxDepth' },
|
|
97
|
+
{ type: 'set', path: 'projectFolderMaxDepth', value: 2 },
|
|
98
|
+
{ type: 'uncomment', path: 'url' },
|
|
99
|
+
{ type: 'set', path: 'repository.url', value: repoUrl },
|
|
100
|
+
{ type: 'uncomment', path: 'defaultBranch' },
|
|
101
|
+
{ type: 'uncomment', path: 'defaultRemote' }
|
|
102
|
+
];
|
|
103
|
+
(0, jsonc_1.patchFile)(path.join(targetDir, 'rush.json'), rushJsonOps);
|
|
104
|
+
for (const op of rushJsonOps) {
|
|
105
|
+
const desc = op.type === 'uncomment' || op.type === 'remove'
|
|
106
|
+
? ` ${op.type}: ${op.path}`
|
|
107
|
+
: ` ${op.type}: ${op.path}`;
|
|
108
|
+
console.log(desc);
|
|
109
|
+
}
|
|
110
|
+
// ── Step 3: Patch other rush config files ──
|
|
111
|
+
console.log('');
|
|
112
|
+
console.log('==> Patching rush config files...');
|
|
113
|
+
(0, jsonc_1.patchFile)(path.join(targetDir, 'common/config/rush/build-cache.json'), [
|
|
114
|
+
{ type: 'set', path: 'buildCacheEnabled', value: true }
|
|
115
|
+
]);
|
|
116
|
+
console.log(' build-cache.json: buildCacheEnabled = true');
|
|
117
|
+
(0, jsonc_1.patchFile)(path.join(targetDir, 'common/config/rush/pnpm-config.json'), [
|
|
118
|
+
{ type: 'uncomment', path: 'strictPeerDependencies' },
|
|
119
|
+
{ type: 'set', path: 'strictPeerDependencies', value: true }
|
|
120
|
+
]);
|
|
121
|
+
console.log(' pnpm-config.json: strictPeerDependencies = true');
|
|
122
|
+
// ── Step 4: Generate templated files ──
|
|
123
|
+
console.log('');
|
|
124
|
+
console.log('==> Generating templated config files...');
|
|
125
|
+
const templateVars = {
|
|
126
|
+
REPO_URL: repoUrl,
|
|
127
|
+
VERSION_POLICY_NAME: versionPolicy,
|
|
128
|
+
VERSION: version
|
|
129
|
+
};
|
|
130
|
+
for (const tmpl of manifest.templated.files) {
|
|
131
|
+
const templatePath = path.join(sourceDir, tmpl.template);
|
|
132
|
+
const destPath = path.join(targetDir, tmpl.destination);
|
|
133
|
+
(0, template_1.renderTemplateFile)(templatePath, destPath, templateVars);
|
|
134
|
+
}
|
|
135
|
+
// ── Step 5: Copy shared files ──
|
|
136
|
+
console.log('');
|
|
137
|
+
console.log('==> Copying shared files...');
|
|
138
|
+
for (const file of manifest.shared.files) {
|
|
139
|
+
const srcPath = path.join(sourceDir, file.source);
|
|
140
|
+
const destPath = path.join(targetDir, file.destination);
|
|
141
|
+
if (!fs.existsSync(srcPath)) {
|
|
142
|
+
console.warn(` WARNING: Source file not found, skipping: ${file.source}`);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
(0, fs_1.copyFile)(srcPath, destPath);
|
|
146
|
+
console.log(` Copied: ${file.destination}`);
|
|
147
|
+
}
|
|
148
|
+
for (const pkg of manifest.sharedPackages.packages) {
|
|
149
|
+
const srcPath = path.join(sourceDir, pkg.source);
|
|
150
|
+
const destPath = path.join(targetDir, pkg.destination);
|
|
151
|
+
if (!fs.existsSync(srcPath)) {
|
|
152
|
+
console.warn(` WARNING: Source directory not found, skipping: ${pkg.source}`);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
(0, fs_1.copyPackage)(srcPath, destPath);
|
|
156
|
+
console.log(` Copied package: ${pkg.destination}`);
|
|
157
|
+
}
|
|
158
|
+
// ── Step 6: Create standard directories ──
|
|
159
|
+
console.log('');
|
|
160
|
+
console.log('==> Creating directory structure...');
|
|
161
|
+
const dirs = ['libraries', 'tools', 'apps', 'services', '.claude/project', '.claude/skills'];
|
|
162
|
+
for (const dir of dirs) {
|
|
163
|
+
fs.mkdirSync(path.join(targetDir, dir), { recursive: true });
|
|
164
|
+
}
|
|
165
|
+
const gitkeeps = ['.claude/project/.gitkeep', '.claude/skills/.gitkeep'];
|
|
166
|
+
for (const gk of gitkeeps) {
|
|
167
|
+
fs.writeFileSync(path.join(targetDir, gk), '');
|
|
168
|
+
}
|
|
169
|
+
console.log(' Created standard directory structure');
|
|
170
|
+
// ── Step 7: Record template metadata ──
|
|
171
|
+
console.log('');
|
|
172
|
+
console.log('==> Recording template metadata...');
|
|
173
|
+
const sourceCommit = (0, fs_1.getGitCommit)(sourceDir);
|
|
174
|
+
const sourceRepo = (0, fs_1.getGitRemoteUrl)(sourceDir);
|
|
175
|
+
const syncMetadata = {
|
|
176
|
+
templateSource: repoUrl,
|
|
177
|
+
sourceRepo,
|
|
178
|
+
sourceCommit,
|
|
179
|
+
createdAt: new Date().toISOString(),
|
|
180
|
+
lastSyncedAt: new Date().toISOString(),
|
|
181
|
+
manifestVersion: '1.0.0'
|
|
182
|
+
};
|
|
183
|
+
fs.writeFileSync(path.join(targetDir, '.template-sync'), JSON.stringify(syncMetadata, null, 2) + '\n');
|
|
184
|
+
console.log(' Created .template-sync');
|
|
185
|
+
// ── Step 8: Git init ──
|
|
186
|
+
if (gitInit) {
|
|
187
|
+
console.log('');
|
|
188
|
+
console.log('==> Initializing git repository...');
|
|
189
|
+
try {
|
|
190
|
+
(0, fs_1.exec)('git init -b main', { cwd: targetDir });
|
|
191
|
+
(0, fs_1.exec)('git add -A', { cwd: targetDir });
|
|
192
|
+
(0, fs_1.exec)(`git commit -m "Initial commit from fgv monorepo template\n\nSource: ${sourceDir}\nTemplate commit: ${sourceCommit}"`, { cwd: targetDir });
|
|
193
|
+
console.log(' Git repository initialized with initial commit');
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
console.warn(` WARNING: Git init failed: ${err.message}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// ── Done ──
|
|
200
|
+
console.log('');
|
|
201
|
+
console.log(`=== Monorepo created successfully at: ${targetDir} ===`);
|
|
202
|
+
console.log('');
|
|
203
|
+
console.log('Next steps:');
|
|
204
|
+
console.log(' 1. Add your domain packages to libraries/, apps/, tools/, services/');
|
|
205
|
+
console.log(' 2. Register them in rush.json');
|
|
206
|
+
console.log(' 3. Fill in the project table in CLAUDE.md');
|
|
207
|
+
console.log(' 4. Fill in ACTIVE_DEVELOPMENT.md with your domain projects');
|
|
208
|
+
console.log(' 5. Add domain-specific Rush commands to common/config/rush/command-line.json');
|
|
209
|
+
console.log(` 6. Run: cd ${targetDir} && rush install && rush build`);
|
|
210
|
+
console.log('');
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=create.js.map
|