@fgv/repo-template 5.1.0-10

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 (81) hide show
  1. package/.rush/temp/9cc3c12fcd90dc622d9e260e68873bfe822f80a1.tar.log +61 -0
  2. package/.rush/temp/chunked-rush-logs/repo-template.build.chunks.jsonl +6 -0
  3. package/.rush/temp/operation/build/all.log +6 -0
  4. package/.rush/temp/operation/build/log-chunks.jsonl +6 -0
  5. package/.rush/temp/operation/build/state.json +3 -0
  6. package/.rush/temp/shrinkwrap-deps.json +576 -0
  7. package/README.md +216 -0
  8. package/bin/repo-template.js +18 -0
  9. package/config/rig.json +4 -0
  10. package/lib/cli.d.ts +14 -0
  11. package/lib/cli.d.ts.map +1 -0
  12. package/lib/cli.js +167 -0
  13. package/lib/cli.js.map +1 -0
  14. package/lib/commands/create.d.ts +17 -0
  15. package/lib/commands/create.d.ts.map +1 -0
  16. package/lib/commands/create.js +212 -0
  17. package/lib/commands/create.js.map +1 -0
  18. package/lib/commands/init-library.d.ts +38 -0
  19. package/lib/commands/init-library.d.ts.map +1 -0
  20. package/lib/commands/init-library.js +269 -0
  21. package/lib/commands/init-library.js.map +1 -0
  22. package/lib/commands/link.d.ts +20 -0
  23. package/lib/commands/link.d.ts.map +1 -0
  24. package/lib/commands/link.js +273 -0
  25. package/lib/commands/link.js.map +1 -0
  26. package/lib/commands/patch.d.ts +15 -0
  27. package/lib/commands/patch.d.ts.map +1 -0
  28. package/lib/commands/patch.js +104 -0
  29. package/lib/commands/patch.js.map +1 -0
  30. package/lib/commands/sync.d.ts +11 -0
  31. package/lib/commands/sync.d.ts.map +1 -0
  32. package/lib/commands/sync.js +156 -0
  33. package/lib/commands/sync.js.map +1 -0
  34. package/lib/index.d.ts +15 -0
  35. package/lib/index.d.ts.map +1 -0
  36. package/lib/index.js +33 -0
  37. package/lib/index.js.map +1 -0
  38. package/lib/packlets/fs/index.d.ts +40 -0
  39. package/lib/packlets/fs/index.d.ts.map +1 -0
  40. package/lib/packlets/fs/index.js +142 -0
  41. package/lib/packlets/fs/index.js.map +1 -0
  42. package/lib/packlets/jsonc/index.d.ts +27 -0
  43. package/lib/packlets/jsonc/index.d.ts.map +1 -0
  44. package/lib/packlets/jsonc/index.js +124 -0
  45. package/lib/packlets/jsonc/index.js.map +1 -0
  46. package/lib/packlets/manifest/index.d.ts +15 -0
  47. package/lib/packlets/manifest/index.d.ts.map +1 -0
  48. package/lib/packlets/manifest/index.js +61 -0
  49. package/lib/packlets/manifest/index.js.map +1 -0
  50. package/lib/packlets/manifest/types.d.ts +33 -0
  51. package/lib/packlets/manifest/types.d.ts.map +1 -0
  52. package/lib/packlets/manifest/types.js +6 -0
  53. package/lib/packlets/manifest/types.js.map +1 -0
  54. package/lib/packlets/template/index.d.ts +22 -0
  55. package/lib/packlets/template/index.d.ts.map +1 -0
  56. package/lib/packlets/template/index.js +75 -0
  57. package/lib/packlets/template/index.js.map +1 -0
  58. package/package.json +32 -0
  59. package/rush-logs/repo-template.build.cache.log +5 -0
  60. package/rush-logs/repo-template.build.log +6 -0
  61. package/src/cli.ts +197 -0
  62. package/src/commands/create.ts +216 -0
  63. package/src/commands/init-library.ts +313 -0
  64. package/src/commands/link.ts +299 -0
  65. package/src/commands/patch.ts +84 -0
  66. package/src/commands/sync.ts +137 -0
  67. package/src/index.ts +22 -0
  68. package/src/packlets/fs/index.ts +114 -0
  69. package/src/packlets/jsonc/index.ts +134 -0
  70. package/src/packlets/manifest/index.ts +29 -0
  71. package/src/packlets/manifest/types.ts +36 -0
  72. package/src/packlets/template/index.ts +48 -0
  73. package/sync-manifest.json +222 -0
  74. package/temp/build/typescript/ts_l9Fw4VUO.json +1 -0
  75. package/templates/.gitignore.tmpl +85 -0
  76. package/templates/ACTIVE_DEVELOPMENT.md.tmpl +58 -0
  77. package/templates/CLAUDE.md.tmpl +124 -0
  78. package/templates/command-line.json.tmpl +50 -0
  79. package/templates/package.json.tmpl +5 -0
  80. package/templates/version-policies.json.tmpl +8 -0
  81. 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;AAgBH,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;IAwJtB;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAW1B"}
package/lib/cli.js ADDED
@@ -0,0 +1,167 @@
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
+ const link_1 = require("./commands/link");
14
+ class RepoTemplateCli {
15
+ constructor() {
16
+ this._program = new commander_1.Command();
17
+ this._setupCommands();
18
+ }
19
+ async run(argv) {
20
+ await this._program.parseAsync(argv);
21
+ }
22
+ _setupCommands() {
23
+ this._program
24
+ .name('repo-template')
25
+ .description('Create and maintain fgv-derived Rush monorepos')
26
+ .version('5.1.0');
27
+ // ── create ──
28
+ this._program
29
+ .command('create')
30
+ .description('Stamp out a new fgv-derived Rush monorepo using rush init + JSONC patching')
31
+ .requiredOption('-t, --target-dir <path>', 'Directory to create the new repo in')
32
+ .requiredOption('-u, --repo-url <url>', 'GitHub repository URL')
33
+ .option('-p, --version-policy <name>', 'Version policy name', 'default')
34
+ .option('--initial-version <ver>', 'Initial version', '0.1.0')
35
+ .option('-s, --source-dir <path>', 'Source repo for shared files (auto-detected if in fgv repo)')
36
+ .option('--allow-existing', 'Allow target directory to already exist', false)
37
+ .option('--no-git-init', 'Skip git init and initial commit')
38
+ .action(async (opts) => {
39
+ var _a;
40
+ const sourceDir = (_a = opts.sourceDir) !== null && _a !== void 0 ? _a : this._resolveSourceDir();
41
+ await (0, create_1.runCreate)({
42
+ targetDir: opts.targetDir,
43
+ repoUrl: opts.repoUrl,
44
+ versionPolicy: opts.versionPolicy,
45
+ version: opts.initialVersion,
46
+ sourceDir,
47
+ allowExisting: opts.allowExisting,
48
+ gitInit: opts.gitInit
49
+ });
50
+ });
51
+ // ── sync ──
52
+ this._program
53
+ .command('sync')
54
+ .description('Sync shared files from the fgv source repo to a consumer repo')
55
+ .requiredOption('-t, --target-dir <path>', 'Consumer repo to update')
56
+ .option('-s, --source-dir <path>', 'Source repo (auto-detected if in fgv repo)')
57
+ .option('-n, --dry-run', 'Show what would change without modifying files', false)
58
+ .action(async (opts) => {
59
+ var _a;
60
+ const sourceDir = (_a = opts.sourceDir) !== null && _a !== void 0 ? _a : this._resolveSourceDir();
61
+ await (0, sync_1.runSync)({
62
+ targetDir: opts.targetDir,
63
+ sourceDir,
64
+ dryRun: opts.dryRun
65
+ });
66
+ });
67
+ // ── init-library ──
68
+ this._program
69
+ .command('init-library')
70
+ .description('Scaffold a new library package within an existing Rush monorepo')
71
+ .requiredOption('-n, --name <name>', 'Package name (e.g. "ts-my-lib" — auto-prefixed with @fgv/)')
72
+ .option('-d, --description <text>', 'Package description', '')
73
+ .option('-r, --rig <type>', 'Heft rig: dual (default), node, or browser', 'dual')
74
+ .option('-c, --category <type>', 'Category folder: libraries (default), tools, apps, services', 'libraries')
75
+ .option('--repo-dir <path>', 'Rush monorepo root (default: cwd)', process.cwd())
76
+ .option('-p, --version-policy <name>', 'Version policy name', 'default')
77
+ .option('--initial-version <ver>', 'Initial version', '0.1.0')
78
+ .option('--fgv-dep-version <ver>', 'Explicit version spec for @fgv/* deps (auto-detected if omitted: "workspace:*" in fgv, derived from repo-template version in consumers)')
79
+ .option('--fgv-dep-channel <channel>', 'Channel for auto-detected @fgv/* dep version: alpha, release, or auto (default: auto — infers from repo-template build)', 'auto')
80
+ .action(async (opts) => {
81
+ var _a;
82
+ const repoDir = opts.repoDir;
83
+ const fgvDepVersion = (_a = opts.fgvDepVersion) !== null && _a !== void 0 ? _a : (0, init_library_1.resolveFgvDepVersion)(repoDir, opts.fgvDepChannel);
84
+ await (0, init_library_1.runInitLibrary)({
85
+ name: opts.name,
86
+ description: opts.description,
87
+ rig: opts.rig,
88
+ category: opts.category,
89
+ repoDir,
90
+ versionPolicy: opts.versionPolicy,
91
+ version: opts.initialVersion,
92
+ fgvDepVersion
93
+ });
94
+ });
95
+ // ── link ──
96
+ this._program
97
+ .command('link')
98
+ .description('Link to a local fgv worktree for cross-repo development')
99
+ .requiredOption('--fgv-dir <path>', 'Path to the local fgv worktree')
100
+ .option('--repo-dir <path>', 'Consumer Rush repo root (default: cwd)', process.cwd())
101
+ .action(async (opts) => {
102
+ await (0, link_1.runLink)({
103
+ fgvDir: opts.fgvDir,
104
+ repoDir: opts.repoDir
105
+ });
106
+ });
107
+ // ── unlink ──
108
+ this._program
109
+ .command('unlink')
110
+ .description('Switch back from local fgv worktree to published npm packages')
111
+ .option('--repo-dir <path>', 'Consumer Rush repo root (default: cwd)', process.cwd())
112
+ .option('--fgv-version <spec>', 'Also bump @fgv/* deps to this version spec')
113
+ .action(async (opts) => {
114
+ await (0, link_1.runUnlink)({
115
+ repoDir: opts.repoDir,
116
+ version: opts.fgvVersion
117
+ });
118
+ });
119
+ // ── update-fgv-versions ──
120
+ this._program
121
+ .command('update-fgv-versions')
122
+ .description('Bump @fgv/* dependency version specs across all projects')
123
+ .option('--repo-dir <path>', 'Consumer Rush repo root (default: cwd)', process.cwd())
124
+ .option('--fgv-version <spec>', 'Version spec to set (e.g. "~5.2.0"). If omitted, queries npm for latest.')
125
+ .action(async (opts) => {
126
+ await (0, link_1.runUpdateFgvVersions)({
127
+ repoDir: opts.repoDir,
128
+ version: opts.fgvVersion
129
+ });
130
+ });
131
+ // ── patch ──
132
+ this._program
133
+ .command('patch <file>')
134
+ .description('Apply targeted edits to a JSONC config file while preserving comments')
135
+ .allowUnknownOption(true)
136
+ .helpOption(false)
137
+ .action(async (file, _opts, cmd) => {
138
+ // Parse the raw args after the file argument as patch operations
139
+ const rawArgs = cmd.args.slice(1); // skip the file arg
140
+ // Actually, commander passes remaining args differently. Let's get them from process.argv
141
+ const allArgs = process.argv;
142
+ const patchIdx = allArgs.indexOf('patch');
143
+ const fileIdx = patchIdx + 1;
144
+ const opArgs = allArgs.slice(fileIdx + 1);
145
+ const operations = (0, patch_1.parsePatchArgs)(opArgs);
146
+ if (operations.length === 0) {
147
+ console.error('No operations specified. Use --set, --uncomment, --add-to-array, etc.');
148
+ process.exit(1);
149
+ }
150
+ await (0, patch_1.runPatch)({ file, operations });
151
+ });
152
+ }
153
+ /**
154
+ * Auto-detect the fgv source directory by walking up from the current working directory.
155
+ */
156
+ _resolveSourceDir() {
157
+ const detected = (0, fs_1.detectSourceDir)(process.cwd());
158
+ if (!detected) {
159
+ console.error('ERROR: Could not auto-detect fgv source repo. ' +
160
+ 'Please specify --source-dir or run from within the fgv repository.');
161
+ process.exit(1);
162
+ }
163
+ return detected;
164
+ }
165
+ }
166
+ exports.RepoTemplateCli = RepoTemplateCli;
167
+ //# 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 {\n runInitLibrary,\n resolveFgvDepVersion,\n RigType,\n CategoryType,\n DepChannelType\n} from './commands/init-library';\nimport { runLink, runUnlink, runUpdateFgvVersions } from './commands/link';\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 'Explicit version spec for @fgv/* deps (auto-detected if omitted: \"workspace:*\" in fgv, derived from repo-template version in consumers)'\n )\n .option(\n '--fgv-dep-channel <channel>',\n 'Channel for auto-detected @fgv/* dep version: alpha, release, or auto (default: auto — infers from repo-template build)',\n 'auto'\n )\n .action(async (opts) => {\n const repoDir = opts.repoDir as string;\n const fgvDepVersion =\n opts.fgvDepVersion ?? resolveFgvDepVersion(repoDir, opts.fgvDepChannel as DepChannelType);\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,\n versionPolicy: opts.versionPolicy,\n version: opts.initialVersion,\n fgvDepVersion\n });\n });\n\n // ── link ──\n this._program\n .command('link')\n .description('Link to a local fgv worktree for cross-repo development')\n .requiredOption('--fgv-dir <path>', 'Path to the local fgv worktree')\n .option('--repo-dir <path>', 'Consumer Rush repo root (default: cwd)', process.cwd())\n .action(async (opts) => {\n await runLink({\n fgvDir: opts.fgvDir,\n repoDir: opts.repoDir\n });\n });\n\n // ── unlink ──\n this._program\n .command('unlink')\n .description('Switch back from local fgv worktree to published npm packages')\n .option('--repo-dir <path>', 'Consumer Rush repo root (default: cwd)', process.cwd())\n .option('--fgv-version <spec>', 'Also bump @fgv/* deps to this version spec')\n .action(async (opts) => {\n await runUnlink({\n repoDir: opts.repoDir,\n version: opts.fgvVersion\n });\n });\n\n // ── update-fgv-versions ──\n this._program\n .command('update-fgv-versions')\n .description('Bump @fgv/* dependency version specs across all projects')\n .option('--repo-dir <path>', 'Consumer Rush repo root (default: cwd)', process.cwd())\n .option(\n '--fgv-version <spec>',\n 'Version spec to set (e.g. \"~5.2.0\"). If omitted, queries npm for latest.'\n )\n .action(async (opts) => {\n await runUpdateFgvVersions({\n repoDir: opts.repoDir,\n version: opts.fgvVersion\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"}