@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.
Files changed (77) hide show
  1. package/.rush/temp/45a8d0dcbb9c2e59fa02645657661dffbd25461f.tar.log +57 -0
  2. package/.rush/temp/92e27a75687fa5062b71fdb897f0928a8aa4e0c9.tar.log +57 -0
  3. package/.rush/temp/chunked-rush-logs/repo-template.build.chunks.jsonl +7 -0
  4. package/.rush/temp/operation/build/all.log +7 -0
  5. package/.rush/temp/operation/build/log-chunks.jsonl +7 -0
  6. package/.rush/temp/operation/build/state.json +3 -0
  7. package/.rush/temp/shrinkwrap-deps.json +576 -0
  8. package/README.md +216 -0
  9. package/bin/repo-template.js +18 -0
  10. package/config/rig.json +4 -0
  11. package/lib/cli.d.ts +14 -0
  12. package/lib/cli.d.ts.map +1 -0
  13. package/lib/cli.js +126 -0
  14. package/lib/cli.js.map +1 -0
  15. package/lib/commands/create.d.ts +17 -0
  16. package/lib/commands/create.d.ts.map +1 -0
  17. package/lib/commands/create.js +212 -0
  18. package/lib/commands/create.js.map +1 -0
  19. package/lib/commands/init-library.d.ts +25 -0
  20. package/lib/commands/init-library.d.ts.map +1 -0
  21. package/lib/commands/init-library.js +217 -0
  22. package/lib/commands/init-library.js.map +1 -0
  23. package/lib/commands/patch.d.ts +15 -0
  24. package/lib/commands/patch.d.ts.map +1 -0
  25. package/lib/commands/patch.js +104 -0
  26. package/lib/commands/patch.js.map +1 -0
  27. package/lib/commands/sync.d.ts +11 -0
  28. package/lib/commands/sync.d.ts.map +1 -0
  29. package/lib/commands/sync.js +156 -0
  30. package/lib/commands/sync.js.map +1 -0
  31. package/lib/index.d.ts +14 -0
  32. package/lib/index.d.ts.map +1 -0
  33. package/lib/index.js +29 -0
  34. package/lib/index.js.map +1 -0
  35. package/lib/packlets/fs/index.d.ts +40 -0
  36. package/lib/packlets/fs/index.d.ts.map +1 -0
  37. package/lib/packlets/fs/index.js +142 -0
  38. package/lib/packlets/fs/index.js.map +1 -0
  39. package/lib/packlets/jsonc/index.d.ts +27 -0
  40. package/lib/packlets/jsonc/index.d.ts.map +1 -0
  41. package/lib/packlets/jsonc/index.js +124 -0
  42. package/lib/packlets/jsonc/index.js.map +1 -0
  43. package/lib/packlets/manifest/index.d.ts +15 -0
  44. package/lib/packlets/manifest/index.d.ts.map +1 -0
  45. package/lib/packlets/manifest/index.js +61 -0
  46. package/lib/packlets/manifest/index.js.map +1 -0
  47. package/lib/packlets/manifest/types.d.ts +33 -0
  48. package/lib/packlets/manifest/types.d.ts.map +1 -0
  49. package/lib/packlets/manifest/types.js +6 -0
  50. package/lib/packlets/manifest/types.js.map +1 -0
  51. package/lib/packlets/template/index.d.ts +22 -0
  52. package/lib/packlets/template/index.d.ts.map +1 -0
  53. package/lib/packlets/template/index.js +75 -0
  54. package/lib/packlets/template/index.js.map +1 -0
  55. package/package.json +32 -0
  56. package/rush-logs/repo-template.build.cache.log +4 -0
  57. package/rush-logs/repo-template.build.log +7 -0
  58. package/src/cli.ts +141 -0
  59. package/src/commands/create.ts +216 -0
  60. package/src/commands/init-library.ts +249 -0
  61. package/src/commands/patch.ts +84 -0
  62. package/src/commands/sync.ts +137 -0
  63. package/src/index.ts +14 -0
  64. package/src/packlets/fs/index.ts +114 -0
  65. package/src/packlets/jsonc/index.ts +134 -0
  66. package/src/packlets/manifest/index.ts +29 -0
  67. package/src/packlets/manifest/types.ts +36 -0
  68. package/src/packlets/template/index.ts +48 -0
  69. package/sync-manifest.json +222 -0
  70. package/temp/build/typescript/ts_l9Fw4VUO.json +1 -0
  71. package/templates/.gitignore.tmpl +85 -0
  72. package/templates/ACTIVE_DEVELOPMENT.md.tmpl +58 -0
  73. package/templates/CLAUDE.md.tmpl +124 -0
  74. package/templates/command-line.json.tmpl +50 -0
  75. package/templates/package.json.tmpl +5 -0
  76. package/templates/version-policies.json.tmpl +8 -0
  77. 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
+ });
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
3
+ "rigPackageName": "@rushstack/heft-node-rig"
4
+ }
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
@@ -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