@rindrics/initrepo 0.2.0 → 0.2.1

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.
@@ -15,11 +15,16 @@ jobs:
15
15
  - uses: actions/checkout@v6
16
16
  with:
17
17
  token: ${{ secrets.PAT_FOR_TAGPR }}
18
-
18
+
19
+ - name: Configure SSH signing
20
+ run: |
21
+ mkdir -p ~/.ssh
22
+ echo "${{ secrets.SSH_SIGNING_KEY }}" > ~/.ssh/signing_key
23
+ chmod 600 ~/.ssh/signing_key
24
+ git config --global gpg.format ssh
25
+ git config --global user.signingkey ~/.ssh/signing_key
26
+ git config --global commit.gpgsign true
27
+
19
28
  - uses: Songmu/tagpr@v1
20
29
  env:
21
30
  GITHUB_TOKEN: ${{ secrets.PAT_FOR_TAGPR }}
22
- GIT_COMMITTER_NAME: github-actions[bot]
23
- GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
24
- GIT_AUTHOR_NAME: github-actions[bot]
25
- GIT_AUTHOR_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
@@ -0,0 +1,3 @@
1
+ # Format files changed in the last commit
2
+ # Changes remain unstaged for a separate "format" commit
3
+ bunx lint-staged --diff="HEAD~1 HEAD" --config=.lintstagedrc.format.json
@@ -0,0 +1 @@
1
+ bunx lint-staged
package/.husky/pre-push CHANGED
@@ -1,2 +1,3 @@
1
1
  bun run check
2
+ bun run test
2
3
  bun run build
@@ -0,0 +1,3 @@
1
+ {
2
+ "*.{ts,tsx,json,md}": ["biome format --write"]
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "*.{ts,tsx}": ["biome check --write"]
3
+ }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.2.1](https://github.com/Rindrics/initrepo/compare/v0.2.0...v0.2.1) - 2026-01-19
4
+ - docs: update README.md by @Rindrics in https://github.com/Rindrics/initrepo/pull/24
5
+ - feat: add command setup-husky by @Rindrics in https://github.com/Rindrics/initrepo/pull/32
6
+ - feat: generate .gitignore by @Rindrics in https://github.com/Rindrics/initrepo/pull/33
7
+ - feat: use ssh ket for commit signing by @Rindrics in https://github.com/Rindrics/initrepo/pull/34
8
+
3
9
  ## [v0.2.0](https://github.com/Rindrics/initrepo/compare/v0.1.5...v0.2.0) - 2025-12-28
4
10
  - ci: commit as GitHub Actions bot by @Rindrics in https://github.com/Rindrics/initrepo/pull/20
5
11
  - feat: generate publish.yml from prepare-release command by @Rindrics in https://github.com/Rindrics/initrepo/pull/21
package/README.md CHANGED
@@ -2,22 +2,19 @@
2
2
 
3
3
  CLI tool for rapid repository setup with CI/CD, code quality tools, and release automation via [tagpr](https://github.com/Songmu/tagpr).
4
4
 
5
- ## Installation
6
-
7
- ```bash
8
- npm install -g @rindrics/initrepo
9
- ```
10
-
11
5
  ## Usage
12
6
 
13
7
  ### Create a new project
14
8
 
15
9
  ```bash
16
- # Interactive mode (prompts for options)
17
- initrepo init my-super-project
10
+ # Using npx (recommended)
11
+ npx @rindrics/initrepo init my-super-project
12
+
13
+ # Using pnpm
14
+ pnpm dlx @rindrics/initrepo init my-super-project
18
15
 
19
16
  # Non-interactive mode
20
- initrepo init my-super-project --devcode --create-repo --private
17
+ npx @rindrics/initrepo init my-super-project --devcode --create-repo --private
21
18
  ```
22
19
 
23
20
  Options:
@@ -26,7 +23,12 @@ Options:
26
23
  - `-p, --private` - Make GitHub repository private
27
24
  - `-a, --author <name>` - Package author
28
25
 
29
- Requires `GITHUB_TOKEN` environment variable for repository creation.
26
+ To create a GitHub repository, set `GITHUB_TOKEN`:
27
+
28
+ ```bash
29
+ # Using GitHub CLI
30
+ GITHUB_TOKEN=$(gh auth token) npx @rindrics/initrepo init my-project --create-repo
31
+ ```
30
32
 
31
33
  ### Prepare for release
32
34
 
@@ -34,7 +36,7 @@ When ready to publish, convert your devcode project:
34
36
 
35
37
  ```bash
36
38
  cd my-super-project
37
- initrepo prepare-release @scope/my-package
39
+ npx @rindrics/initrepo prepare-release @scope/my-package
38
40
  ```
39
41
 
40
42
  This will:
package/bun.lock CHANGED
@@ -16,6 +16,7 @@
16
16
  "@types/ejs": "^3.1.5",
17
17
  "bun-types": "^1.0.0",
18
18
  "husky": "^9.0.0",
19
+ "lint-staged": "^16.2.7",
19
20
  "typescript": "^5.0.0",
20
21
  },
21
22
  },
@@ -139,9 +140,11 @@
139
140
 
140
141
  "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
141
142
 
143
+ "ansi-escapes": ["ansi-escapes@7.2.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw=="],
144
+
142
145
  "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
143
146
 
144
- "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
147
+ "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
145
148
 
146
149
  "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
147
150
 
@@ -157,18 +160,26 @@
157
160
 
158
161
  "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
159
162
 
163
+ "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
164
+
160
165
  "bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="],
161
166
 
162
167
  "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
163
168
 
164
169
  "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
165
170
 
171
+ "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
172
+
173
+ "cli-truncate": ["cli-truncate@5.1.1", "", { "dependencies": { "slice-ansi": "^7.1.0", "string-width": "^8.0.0" } }, "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A=="],
174
+
166
175
  "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
167
176
 
168
177
  "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
169
178
 
170
179
  "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
171
180
 
181
+ "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="],
182
+
172
183
  "commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="],
173
184
 
174
185
  "compare-func": ["compare-func@2.0.0", "", { "dependencies": { "array-ify": "^1.0.0", "dot-prop": "^5.1.0" } }, "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA=="],
@@ -193,10 +204,14 @@
193
204
 
194
205
  "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="],
195
206
 
207
+ "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="],
208
+
196
209
  "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="],
197
210
 
198
211
  "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
199
212
 
213
+ "eventemitter3": ["eventemitter3@5.0.2", "", {}, "sha512-RQ5d+HfzVjGO537vWau+KVFHUSj3sBOzd1nVQcnRMCak/OyXwwUTBh++rZrI3un9gtfSpg63jjOHUvhQnQBuAA=="],
214
+
200
215
  "fast-content-type-parse": ["fast-content-type-parse@3.0.0", "", {}, "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg=="],
201
216
 
202
217
  "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
@@ -205,10 +220,14 @@
205
220
 
206
221
  "filelist": ["filelist@1.0.4", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q=="],
207
222
 
223
+ "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
224
+
208
225
  "find-up": ["find-up@7.0.0", "", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="],
209
226
 
210
227
  "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
211
228
 
229
+ "get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],
230
+
212
231
  "git-raw-commits": ["git-raw-commits@4.0.0", "", { "dependencies": { "dargs": "^8.0.0", "meow": "^12.0.1", "split2": "^4.0.0" }, "bin": { "git-raw-commits": "cli.mjs" } }, "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ=="],
213
232
 
214
233
  "global-directory": ["global-directory@4.0.1", "", { "dependencies": { "ini": "4.1.1" } }, "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q=="],
@@ -225,6 +244,8 @@
225
244
 
226
245
  "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
227
246
 
247
+ "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
248
+
228
249
  "is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="],
229
250
 
230
251
  "is-text-path": ["is-text-path@2.0.0", "", { "dependencies": { "text-extensions": "^2.0.0" } }, "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw=="],
@@ -245,6 +266,10 @@
245
266
 
246
267
  "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
247
268
 
269
+ "lint-staged": ["lint-staged@16.2.7", "", { "dependencies": { "commander": "^14.0.2", "listr2": "^9.0.5", "micromatch": "^4.0.8", "nano-spawn": "^2.0.0", "pidtree": "^0.6.0", "string-argv": "^0.3.2", "yaml": "^2.8.1" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow=="],
270
+
271
+ "listr2": ["listr2@9.0.5", "", { "dependencies": { "cli-truncate": "^5.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" } }, "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g=="],
272
+
248
273
  "locate-path": ["locate-path@7.2.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA=="],
249
274
 
250
275
  "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="],
@@ -265,14 +290,24 @@
265
290
 
266
291
  "lodash.upperfirst": ["lodash.upperfirst@4.3.1", "", {}, "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg=="],
267
292
 
293
+ "log-update": ["log-update@6.1.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w=="],
294
+
268
295
  "meow": ["meow@12.1.1", "", {}, "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw=="],
269
296
 
297
+ "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
298
+
299
+ "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
300
+
270
301
  "minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
271
302
 
272
303
  "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
273
304
 
305
+ "nano-spawn": ["nano-spawn@2.0.0", "", {}, "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw=="],
306
+
274
307
  "octokit": ["octokit@5.0.5", "", { "dependencies": { "@octokit/app": "^16.1.2", "@octokit/core": "^7.0.6", "@octokit/oauth-app": "^8.0.3", "@octokit/plugin-paginate-graphql": "^6.0.0", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-rest-endpoint-methods": "^17.0.0", "@octokit/plugin-retry": "^8.0.3", "@octokit/plugin-throttling": "^11.0.3", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "@octokit/webhooks": "^14.0.0" } }, "sha512-4+/OFSqOjoyULo7eN7EA97DE0Xydj/PW5aIckxqQIoFjFwqXKuFCvXUJObyJfBF9Khu4RL/jlDRI9FPaMGfPnw=="],
275
308
 
309
+ "onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
310
+
276
311
  "p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="],
277
312
 
278
313
  "p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="],
@@ -285,16 +320,30 @@
285
320
 
286
321
  "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
287
322
 
323
+ "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
324
+
325
+ "pidtree": ["pidtree@0.6.0", "", { "bin": { "pidtree": "bin/pidtree.js" } }, "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g=="],
326
+
288
327
  "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
289
328
 
290
329
  "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
291
330
 
292
331
  "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
293
332
 
333
+ "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
334
+
335
+ "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="],
336
+
294
337
  "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
295
338
 
339
+ "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
340
+
341
+ "slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="],
342
+
296
343
  "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
297
344
 
345
+ "string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="],
346
+
298
347
  "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
299
348
 
300
349
  "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
@@ -305,6 +354,8 @@
305
354
 
306
355
  "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
307
356
 
357
+ "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
358
+
308
359
  "toad-cache": ["toad-cache@3.7.0", "", {}, "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw=="],
309
360
 
310
361
  "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
@@ -317,10 +368,12 @@
317
368
 
318
369
  "universal-user-agent": ["universal-user-agent@7.0.3", "", {}, "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A=="],
319
370
 
320
- "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
371
+ "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="],
321
372
 
322
373
  "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
323
374
 
375
+ "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],
376
+
324
377
  "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
325
378
 
326
379
  "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
@@ -329,6 +382,30 @@
329
382
 
330
383
  "@commitlint/config-conventional/@commitlint/types": ["@commitlint/types@20.2.0", "", { "dependencies": { "@types/conventional-commits-parser": "^5.0.0", "chalk": "^5.3.0" } }, "sha512-KTy0OqRDLR5y/zZMnizyx09z/rPlPC/zKhYgH8o/q6PuAjoQAKlRfY4zzv0M64yybQ//6//4H1n14pxaLZfUnA=="],
331
384
 
385
+ "cli-truncate/string-width": ["string-width@8.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg=="],
386
+
387
+ "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
388
+
332
389
  "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
390
+
391
+ "log-update/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
392
+
393
+ "slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.1" } }, "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ=="],
394
+
395
+ "wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
396
+
397
+ "wrap-ansi/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
398
+
399
+ "cli-truncate/string-width/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
400
+
401
+ "cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
402
+
403
+ "log-update/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
404
+
405
+ "wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
406
+
407
+ "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
408
+
409
+ "cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
333
410
  }
334
411
  }
package/dist/cli.js CHANGED
@@ -4207,7 +4207,7 @@ var {
4207
4207
  // package.json
4208
4208
  var package_default = {
4209
4209
  name: "@rindrics/initrepo",
4210
- version: "0.2.0",
4210
+ version: "0.2.1",
4211
4211
  description: "setup GitHub repo with dev tools",
4212
4212
  type: "module",
4213
4213
  bin: {
@@ -4223,7 +4223,12 @@ var package_default = {
4223
4223
  clean: "rm -rf test-* dist",
4224
4224
  prepare: "husky"
4225
4225
  },
4226
- keywords: ["cli", "scaffold", "setup", "repository"],
4226
+ keywords: [
4227
+ "cli",
4228
+ "scaffold",
4229
+ "setup",
4230
+ "repository"
4231
+ ],
4227
4232
  author: "Rindrics",
4228
4233
  license: "MIT",
4229
4234
  repository: {
@@ -4237,6 +4242,7 @@ var package_default = {
4237
4242
  "@types/ejs": "^3.1.5",
4238
4243
  "bun-types": "^1.0.0",
4239
4244
  husky: "^9.0.0",
4245
+ "lint-staged": "^16.2.7",
4240
4246
  typescript: "^5.0.0"
4241
4247
  },
4242
4248
  dependencies: {
@@ -4332,6 +4338,26 @@ updates:
4332
4338
  directory: "/"
4333
4339
  schedule:
4334
4340
  interval: "weekly"
4341
+ `,
4342
+ "common/husky/commit-msg.ejs": `bunx --no -- commitlint --edit $1
4343
+ `,
4344
+ "common/husky/post-commit.ejs": `# Format files changed in the last commit
4345
+ # Changes remain unstaged for a separate "format" commit
4346
+ bunx lint-staged --diff="HEAD~1 HEAD" --config=.lintstagedrc.format.json
4347
+ `,
4348
+ "common/husky/pre-commit.ejs": `bunx lint-staged
4349
+ `,
4350
+ "common/husky/pre-push.ejs": `bun run check
4351
+ bun run test
4352
+ bun run build
4353
+ `,
4354
+ "common/lintstagedrc.format.json.ejs": `{
4355
+ "*.{ts,tsx,json,md}": ["biome format --write"]
4356
+ }
4357
+ `,
4358
+ "common/lintstagedrc.json.ejs": `{
4359
+ "*.{ts,tsx}": ["biome check --write"]
4360
+ }
4335
4361
  `,
4336
4362
  "common/release.yml.ejs": `changelog:
4337
4363
  exclude:
@@ -4392,23 +4418,32 @@ jobs:
4392
4418
  steps:
4393
4419
  - uses: actions/checkout@<%= actionVersions['actions/checkout'] %>
4394
4420
  <% if (isDevcode) { -%>
4395
- # TODO: After replace-devcode, add token: \${{ secrets.PAT_FOR_TAGPR }}
4421
+ # TODO: After prepare-release, add token: \${{ secrets.PAT_FOR_TAGPR }}
4396
4422
  <% } else { -%>
4397
4423
  with:
4398
4424
  token: \${{ secrets.PAT_FOR_TAGPR }}
4399
4425
  <% } -%>
4400
4426
 
4427
+ <% if (isDevcode) { -%>
4428
+ # TODO: After prepare-release, add SSH signing configuration
4429
+ <% } else { -%>
4430
+ - name: Configure SSH signing
4431
+ run: |
4432
+ mkdir -p ~/.ssh
4433
+ echo "\${{ secrets.SSH_SIGNING_KEY }}" > ~/.ssh/signing_key
4434
+ chmod 600 ~/.ssh/signing_key
4435
+ git config --global gpg.format ssh
4436
+ git config --global user.signingkey ~/.ssh/signing_key
4437
+ git config --global commit.gpgsign true
4438
+
4439
+ <% } -%>
4401
4440
  - uses: Songmu/tagpr@<%= actionVersions['Songmu/tagpr'] %>
4402
4441
  env:
4403
4442
  <% if (isDevcode) { -%>
4404
4443
  GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
4405
- # TODO: After replace-devcode, use PAT_FOR_TAGPR instead
4444
+ # TODO: After prepare-release, use PAT_FOR_TAGPR instead
4406
4445
  <% } else { -%>
4407
4446
  GITHUB_TOKEN: \${{ secrets.PAT_FOR_TAGPR }}
4408
- GIT_COMMITTER_NAME: github-actions[bot]
4409
- GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
4410
- GIT_AUTHOR_NAME: github-actions[bot]
4411
- GIT_AUTHOR_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
4412
4447
  <% } -%>
4413
4448
  `,
4414
4449
  "typescript/.tagpr.ejs": `# tagpr configuration
@@ -4424,6 +4459,31 @@ paths:
4424
4459
 
4425
4460
  paths-ignore:
4426
4461
  - node_modules/
4462
+ `,
4463
+ "typescript/gitignore.ejs": `# Dependencies
4464
+ node_modules/
4465
+
4466
+ # Build output
4467
+ dist/
4468
+
4469
+ # Logs
4470
+ *.log
4471
+ npm-debug.log*
4472
+
4473
+ # OS files
4474
+ .DS_Store
4475
+
4476
+ # IDE
4477
+ .idea/
4478
+ .vscode/
4479
+ *.swp
4480
+ *.swo
4481
+
4482
+ # Test coverage
4483
+ coverage/
4484
+
4485
+ # Bun
4486
+ bun.lockb
4427
4487
  `,
4428
4488
  "typescript/package.json.ejs": `{
4429
4489
  "name": "<%= name %>",
@@ -4451,6 +4511,7 @@ paths-ignore:
4451
4511
  "@commitlint/config-conventional": "^<%= versions['@commitlint/config-conventional'] %>",
4452
4512
  "bun-types": "^<%= versions['bun-types'] %>",
4453
4513
  "husky": "^<%= versions['husky'] %>",
4514
+ "lint-staged": "^<%= versions['lint-staged'] %>",
4454
4515
  "typescript": "^<%= versions['typescript'] %>"
4455
4516
  }
4456
4517
  }
@@ -4583,6 +4644,35 @@ jobs:
4583
4644
  `
4584
4645
  };
4585
4646
 
4647
+ // src/generators/husky.ts
4648
+ var HUSKY_HOOKS = [
4649
+ "commit-msg",
4650
+ "pre-commit",
4651
+ "post-commit",
4652
+ "pre-push"
4653
+ ];
4654
+ function generateHuskyHooks() {
4655
+ return HUSKY_HOOKS.map((hook) => ({
4656
+ path: `.husky/${hook}`,
4657
+ content: loadTemplate(`common/husky/${hook}.ejs`, {})
4658
+ }));
4659
+ }
4660
+ function generateLintStagedConfigs() {
4661
+ return [
4662
+ {
4663
+ path: ".lintstagedrc.json",
4664
+ content: loadTemplate("common/lintstagedrc.json.ejs", {})
4665
+ },
4666
+ {
4667
+ path: ".lintstagedrc.format.json",
4668
+ content: loadTemplate("common/lintstagedrc.format.json.ejs", {})
4669
+ }
4670
+ ];
4671
+ }
4672
+ function generateHuskySetup() {
4673
+ return [...generateHuskyHooks(), ...generateLintStagedConfigs()];
4674
+ }
4675
+
4586
4676
  // src/generators/project.ts
4587
4677
  var DEV_DEPENDENCIES = [
4588
4678
  "@biomejs/biome",
@@ -4590,6 +4680,7 @@ var DEV_DEPENDENCIES = [
4590
4680
  "@commitlint/config-conventional",
4591
4681
  "bun-types",
4592
4682
  "husky",
4683
+ "lint-staged",
4593
4684
  "typescript"
4594
4685
  ];
4595
4686
 
@@ -4684,6 +4775,10 @@ async function generateReleaseConfig() {
4684
4775
  const content = loadTemplate("common/release.yml.ejs", {});
4685
4776
  return { path: ".github/release.yml", content };
4686
4777
  }
4778
+ async function generateGitignore(options) {
4779
+ const content = loadTemplate(`${options.lang}/gitignore.ejs`, {});
4780
+ return { path: ".gitignore", content };
4781
+ }
4687
4782
 
4688
4783
  class FileWriteError extends Error {
4689
4784
  targetPath;
@@ -4745,18 +4840,22 @@ async function generateProject(options) {
4745
4840
  validateProjectName(options.projectName);
4746
4841
  const outputDir = options.targetDir ?? options.projectName;
4747
4842
  const actionVersions = await getLatestActionVersions();
4748
- const files = await Promise.all([
4749
- generatePackageJson(options),
4750
- generateTsconfig(options),
4751
- generateEntryPoint(options),
4752
- generateTagprConfig(options),
4753
- generateTagprWorkflow(options, actionVersions),
4754
- generateCiWorkflow(options, actionVersions),
4755
- generateCodeqlWorkflow(options, actionVersions),
4756
- generateCodeqlConfig(options),
4757
- generateDependabot(options),
4758
- generateReleaseConfig()
4759
- ]);
4843
+ const files = [
4844
+ ...await Promise.all([
4845
+ generatePackageJson(options),
4846
+ generateTsconfig(options),
4847
+ generateEntryPoint(options),
4848
+ generateGitignore(options),
4849
+ generateTagprConfig(options),
4850
+ generateTagprWorkflow(options, actionVersions),
4851
+ generateCiWorkflow(options, actionVersions),
4852
+ generateCodeqlWorkflow(options, actionVersions),
4853
+ generateCodeqlConfig(options),
4854
+ generateDependabot(options),
4855
+ generateReleaseConfig()
4856
+ ]),
4857
+ ...generateHuskySetup()
4858
+ ];
4760
4859
  try {
4761
4860
  await writeGeneratedFiles(outputDir, files);
4762
4861
  } catch (error) {
@@ -11466,6 +11565,82 @@ function registerPrepareReleaseCommand(program2) {
11466
11565
  });
11467
11566
  }
11468
11567
 
11568
+ // src/commands/setup-husky.ts
11569
+ import * as fs3 from "node:fs/promises";
11570
+ import * as path3 from "node:path";
11571
+ async function fileExists(filePath) {
11572
+ try {
11573
+ await fs3.access(filePath);
11574
+ return true;
11575
+ } catch {
11576
+ return false;
11577
+ }
11578
+ }
11579
+ async function writeFiles(targetDir, files, force) {
11580
+ const written = [];
11581
+ const skipped = [];
11582
+ for (const file of files) {
11583
+ const filePath = path3.join(targetDir, file.path);
11584
+ const fileDir = path3.dirname(filePath);
11585
+ if (!force && await fileExists(filePath)) {
11586
+ skipped.push(file.path);
11587
+ continue;
11588
+ }
11589
+ await fs3.mkdir(fileDir, { recursive: true });
11590
+ await fs3.writeFile(filePath, file.content, "utf-8");
11591
+ if (file.path.startsWith(".husky/")) {
11592
+ await fs3.chmod(filePath, 493);
11593
+ }
11594
+ written.push(file.path);
11595
+ }
11596
+ return { written, skipped };
11597
+ }
11598
+ async function setupHusky(options) {
11599
+ const targetDir = options.targetDir ?? process.cwd();
11600
+ const force = options.force ?? false;
11601
+ const packageJsonPath = path3.join(targetDir, "package.json");
11602
+ if (!await fileExists(packageJsonPath)) {
11603
+ throw new Error("package.json not found. Are you in a project directory?");
11604
+ }
11605
+ console.log(`\uD83D\uDD27 Setting up husky hooks and lint-staged config...
11606
+ `);
11607
+ const files = generateHuskySetup();
11608
+ const { written, skipped } = await writeFiles(targetDir, files, force);
11609
+ if (written.length > 0) {
11610
+ console.log("✅ Created files:");
11611
+ for (const file of written) {
11612
+ console.log(` ${file}`);
11613
+ }
11614
+ }
11615
+ if (skipped.length > 0) {
11616
+ console.log(`
11617
+ ⏭️ Skipped (already exist, use --force to overwrite):`);
11618
+ for (const file of skipped) {
11619
+ console.log(` ${file}`);
11620
+ }
11621
+ }
11622
+ console.log(`
11623
+ \uD83C\uDF89 Husky setup complete!`);
11624
+ console.log(`
11625
+ \uD83D\uDCCB Next steps:`);
11626
+ console.log(" 1. Install dependencies: bun install");
11627
+ console.log(" 2. Initialize husky: bun run prepare");
11628
+ console.log(" 3. Ensure husky and lint-staged are in devDependencies");
11629
+ }
11630
+ function registerSetupHuskyCommand(program2) {
11631
+ program2.command("setup-husky").description("Set up husky hooks and lint-staged config in an existing project").option("-t, --target-dir <path>", "Target directory (defaults to current directory)").option("-f, --force", "Overwrite existing files").action(async (opts) => {
11632
+ try {
11633
+ await setupHusky({
11634
+ targetDir: opts.targetDir,
11635
+ force: opts.force
11636
+ });
11637
+ } catch (error) {
11638
+ console.error(`❌ Failed to setup husky: ${error instanceof Error ? error.message : String(error)}`);
11639
+ process.exit(1);
11640
+ }
11641
+ });
11642
+ }
11643
+
11469
11644
  // src/cli.ts
11470
11645
  var { version: VERSION17, name: NAME } = package_default;
11471
11646
  function createProgram() {
@@ -11473,6 +11648,7 @@ function createProgram() {
11473
11648
  program2.name(NAME).description("Rapid repository setup CLI tool").version(VERSION17);
11474
11649
  registerInitCommand(program2);
11475
11650
  registerPrepareReleaseCommand(program2);
11651
+ registerSetupHuskyCommand(program2);
11476
11652
  return program2;
11477
11653
  }
11478
11654
  if (__require.main == __require.module) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rindrics/initrepo",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "setup GitHub repo with dev tools",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,12 @@
16
16
  "clean": "rm -rf test-* dist",
17
17
  "prepare": "husky"
18
18
  },
19
- "keywords": ["cli", "scaffold", "setup", "repository"],
19
+ "keywords": [
20
+ "cli",
21
+ "scaffold",
22
+ "setup",
23
+ "repository"
24
+ ],
20
25
  "author": "Rindrics",
21
26
  "license": "MIT",
22
27
  "repository": {
@@ -30,6 +35,7 @@
30
35
  "@types/ejs": "^3.1.5",
31
36
  "bun-types": "^1.0.0",
32
37
  "husky": "^9.0.0",
38
+ "lint-staged": "^16.2.7",
33
39
  "typescript": "^5.0.0"
34
40
  },
35
41
  "dependencies": {
package/src/cli.ts CHANGED
@@ -3,6 +3,7 @@ import { Command } from 'commander';
3
3
  import packageJson from '../package.json';
4
4
  import { registerInitCommand } from './commands/init';
5
5
  import { registerPrepareReleaseCommand } from './commands/prepare-release';
6
+ import { registerSetupHuskyCommand } from './commands/setup-husky';
6
7
 
7
8
  const { version: VERSION, name: NAME } = packageJson;
8
9
 
@@ -16,6 +17,7 @@ export function createProgram(): Command {
16
17
 
17
18
  registerInitCommand(program);
18
19
  registerPrepareReleaseCommand(program);
20
+ registerSetupHuskyCommand(program);
19
21
 
20
22
  return program;
21
23
  }
@@ -0,0 +1,131 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import type { Command } from 'commander';
4
+ import { generateHuskySetup } from '../generators/husky';
5
+ import type { GeneratedFile } from '../generators/project';
6
+
7
+ export interface SetupHuskyOptions {
8
+ /** Target directory (defaults to current directory) */
9
+ targetDir?: string;
10
+ /** Force overwrite existing files */
11
+ force?: boolean;
12
+ }
13
+
14
+ /**
15
+ * Check if file exists
16
+ */
17
+ async function fileExists(filePath: string): Promise<boolean> {
18
+ try {
19
+ await fs.access(filePath);
20
+ return true;
21
+ } catch {
22
+ return false;
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Write generated files to target directory
28
+ */
29
+ async function writeFiles(
30
+ targetDir: string,
31
+ files: GeneratedFile[],
32
+ force: boolean,
33
+ ): Promise<{ written: string[]; skipped: string[] }> {
34
+ const written: string[] = [];
35
+ const skipped: string[] = [];
36
+
37
+ for (const file of files) {
38
+ const filePath = path.join(targetDir, file.path);
39
+ const fileDir = path.dirname(filePath);
40
+
41
+ // Check if file exists
42
+ if (!force && (await fileExists(filePath))) {
43
+ skipped.push(file.path);
44
+ continue;
45
+ }
46
+
47
+ // Create directory if needed
48
+ await fs.mkdir(fileDir, { recursive: true });
49
+
50
+ // Write file
51
+ await fs.writeFile(filePath, file.content, 'utf-8');
52
+
53
+ // Set executable permission for husky hooks
54
+ if (file.path.startsWith('.husky/')) {
55
+ await fs.chmod(filePath, 0o755);
56
+ }
57
+
58
+ written.push(file.path);
59
+ }
60
+
61
+ return { written, skipped };
62
+ }
63
+
64
+ /**
65
+ * Main setup-husky logic
66
+ */
67
+ export async function setupHusky(options: SetupHuskyOptions): Promise<void> {
68
+ const targetDir = options.targetDir ?? process.cwd();
69
+ const force = options.force ?? false;
70
+
71
+ // Check if package.json exists
72
+ const packageJsonPath = path.join(targetDir, 'package.json');
73
+ if (!(await fileExists(packageJsonPath))) {
74
+ throw new Error('package.json not found. Are you in a project directory?');
75
+ }
76
+
77
+ console.log('🔧 Setting up husky hooks and lint-staged config...\n');
78
+
79
+ // Generate husky files
80
+ const files = generateHuskySetup();
81
+
82
+ // Write files
83
+ const { written, skipped } = await writeFiles(targetDir, files, force);
84
+
85
+ // Report results
86
+ if (written.length > 0) {
87
+ console.log('✅ Created files:');
88
+ for (const file of written) {
89
+ console.log(` ${file}`);
90
+ }
91
+ }
92
+
93
+ if (skipped.length > 0) {
94
+ console.log('\n⏭️ Skipped (already exist, use --force to overwrite):');
95
+ for (const file of skipped) {
96
+ console.log(` ${file}`);
97
+ }
98
+ }
99
+
100
+ console.log('\n🎉 Husky setup complete!');
101
+ console.log('\n📋 Next steps:');
102
+ console.log(' 1. Install dependencies: bun install');
103
+ console.log(' 2. Initialize husky: bun run prepare');
104
+ console.log(' 3. Ensure husky and lint-staged are in devDependencies');
105
+ }
106
+
107
+ export function registerSetupHuskyCommand(program: Command): void {
108
+ program
109
+ .command('setup-husky')
110
+ .description(
111
+ 'Set up husky hooks and lint-staged config in an existing project',
112
+ )
113
+ .option(
114
+ '-t, --target-dir <path>',
115
+ 'Target directory (defaults to current directory)',
116
+ )
117
+ .option('-f, --force', 'Overwrite existing files')
118
+ .action(async (opts: { targetDir?: string; force?: boolean }) => {
119
+ try {
120
+ await setupHusky({
121
+ targetDir: opts.targetDir,
122
+ force: opts.force,
123
+ });
124
+ } catch (error) {
125
+ console.error(
126
+ `❌ Failed to setup husky: ${error instanceof Error ? error.message : String(error)}`,
127
+ );
128
+ process.exit(1);
129
+ }
130
+ });
131
+ }
@@ -0,0 +1,44 @@
1
+ import type { GeneratedFile } from './project';
2
+ import { loadTemplate } from './project';
3
+
4
+ const HUSKY_HOOKS = [
5
+ 'commit-msg',
6
+ 'pre-commit',
7
+ 'post-commit',
8
+ 'pre-push',
9
+ ] as const;
10
+
11
+ export type HuskyHook = (typeof HUSKY_HOOKS)[number];
12
+
13
+ /**
14
+ * Generate husky hook files
15
+ */
16
+ export function generateHuskyHooks(): GeneratedFile[] {
17
+ return HUSKY_HOOKS.map((hook) => ({
18
+ path: `.husky/${hook}`,
19
+ content: loadTemplate(`common/husky/${hook}.ejs`, {}),
20
+ }));
21
+ }
22
+
23
+ /**
24
+ * Generate lint-staged configuration files
25
+ */
26
+ export function generateLintStagedConfigs(): GeneratedFile[] {
27
+ return [
28
+ {
29
+ path: '.lintstagedrc.json',
30
+ content: loadTemplate('common/lintstagedrc.json.ejs', {}),
31
+ },
32
+ {
33
+ path: '.lintstagedrc.format.json',
34
+ content: loadTemplate('common/lintstagedrc.format.json.ejs', {}),
35
+ },
36
+ ];
37
+ }
38
+
39
+ /**
40
+ * Generate all husky-related files (hooks + lint-staged configs)
41
+ */
42
+ export function generateHuskySetup(): GeneratedFile[] {
43
+ return [...generateHuskyHooks(), ...generateLintStagedConfigs()];
44
+ }
@@ -248,7 +248,7 @@ describe('project generator', () => {
248
248
  expect(result.content).toContain(
249
249
  'GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}',
250
250
  );
251
- expect(result.content).toContain('# TODO: After replace-devcode');
251
+ expect(result.content).toContain('# TODO: After prepare-release');
252
252
 
253
253
  // Version should be at least the minimum expected
254
254
  expect(
@@ -5,6 +5,7 @@ import type { InitOptions } from '../types';
5
5
  import { getLatestActionVersions } from '../utils/github';
6
6
  import { getLatestVersions, getNpmUsername } from '../utils/npm';
7
7
  import { EMBEDDED_TEMPLATES } from './embedded-templates';
8
+ import { generateHuskySetup } from './husky';
8
9
 
9
10
  const DEV_DEPENDENCIES = [
10
11
  '@biomejs/biome',
@@ -12,6 +13,7 @@ const DEV_DEPENDENCIES = [
12
13
  '@commitlint/config-conventional',
13
14
  'bun-types',
14
15
  'husky',
16
+ 'lint-staged',
15
17
  'typescript',
16
18
  ];
17
19
 
@@ -159,6 +161,13 @@ export async function generateReleaseConfig(): Promise<GeneratedFile> {
159
161
  return { path: '.github/release.yml', content };
160
162
  }
161
163
 
164
+ export async function generateGitignore(
165
+ options: InitOptions,
166
+ ): Promise<GeneratedFile> {
167
+ const content = loadTemplate(`${options.lang}/gitignore.ejs`, {});
168
+ return { path: '.gitignore', content };
169
+ }
170
+
162
171
  export class FileWriteError extends Error {
163
172
  constructor(
164
173
  message: string,
@@ -251,18 +260,22 @@ export async function generateProject(options: InitOptions): Promise<void> {
251
260
  const outputDir = options.targetDir ?? options.projectName;
252
261
  const actionVersions = await getLatestActionVersions();
253
262
 
254
- const files: GeneratedFile[] = await Promise.all([
255
- generatePackageJson(options),
256
- generateTsconfig(options),
257
- generateEntryPoint(options),
258
- generateTagprConfig(options),
259
- generateTagprWorkflow(options, actionVersions),
260
- generateCiWorkflow(options, actionVersions),
261
- generateCodeqlWorkflow(options, actionVersions),
262
- generateCodeqlConfig(options),
263
- generateDependabot(options),
264
- generateReleaseConfig(),
265
- ]);
263
+ const files: GeneratedFile[] = [
264
+ ...(await Promise.all([
265
+ generatePackageJson(options),
266
+ generateTsconfig(options),
267
+ generateEntryPoint(options),
268
+ generateGitignore(options),
269
+ generateTagprConfig(options),
270
+ generateTagprWorkflow(options, actionVersions),
271
+ generateCiWorkflow(options, actionVersions),
272
+ generateCodeqlWorkflow(options, actionVersions),
273
+ generateCodeqlConfig(options),
274
+ generateDependabot(options),
275
+ generateReleaseConfig(),
276
+ ])),
277
+ ...generateHuskySetup(),
278
+ ];
266
279
 
267
280
  try {
268
281
  await writeGeneratedFiles(outputDir, files);
@@ -0,0 +1 @@
1
+ bunx --no -- commitlint --edit $1
@@ -0,0 +1,3 @@
1
+ # Format files changed in the last commit
2
+ # Changes remain unstaged for a separate "format" commit
3
+ bunx lint-staged --diff="HEAD~1 HEAD" --config=.lintstagedrc.format.json
@@ -0,0 +1 @@
1
+ bunx lint-staged
@@ -0,0 +1,3 @@
1
+ bun run check
2
+ bun run test
3
+ bun run build
@@ -0,0 +1,3 @@
1
+ {
2
+ "*.{ts,tsx,json,md}": ["biome format --write"]
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "*.{ts,tsx}": ["biome check --write"]
3
+ }
@@ -15,21 +15,30 @@ jobs:
15
15
  steps:
16
16
  - uses: actions/checkout@<%= actionVersions['actions/checkout'] %>
17
17
  <% if (isDevcode) { -%>
18
- # TODO: After replace-devcode, add token: ${{ secrets.PAT_FOR_TAGPR }}
18
+ # TODO: After prepare-release, add token: ${{ secrets.PAT_FOR_TAGPR }}
19
19
  <% } else { -%>
20
20
  with:
21
21
  token: ${{ secrets.PAT_FOR_TAGPR }}
22
22
  <% } -%>
23
23
 
24
+ <% if (isDevcode) { -%>
25
+ # TODO: After prepare-release, add SSH signing configuration
26
+ <% } else { -%>
27
+ - name: Configure SSH signing
28
+ run: |
29
+ mkdir -p ~/.ssh
30
+ echo "${{ secrets.SSH_SIGNING_KEY }}" > ~/.ssh/signing_key
31
+ chmod 600 ~/.ssh/signing_key
32
+ git config --global gpg.format ssh
33
+ git config --global user.signingkey ~/.ssh/signing_key
34
+ git config --global commit.gpgsign true
35
+
36
+ <% } -%>
24
37
  - uses: Songmu/tagpr@<%= actionVersions['Songmu/tagpr'] %>
25
38
  env:
26
39
  <% if (isDevcode) { -%>
27
40
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28
- # TODO: After replace-devcode, use PAT_FOR_TAGPR instead
41
+ # TODO: After prepare-release, use PAT_FOR_TAGPR instead
29
42
  <% } else { -%>
30
43
  GITHUB_TOKEN: ${{ secrets.PAT_FOR_TAGPR }}
31
- GIT_COMMITTER_NAME: github-actions[bot]
32
- GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
33
- GIT_AUTHOR_NAME: github-actions[bot]
34
- GIT_AUTHOR_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
35
44
  <% } -%>
@@ -0,0 +1,24 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Build output
5
+ dist/
6
+
7
+ # Logs
8
+ *.log
9
+ npm-debug.log*
10
+
11
+ # OS files
12
+ .DS_Store
13
+
14
+ # IDE
15
+ .idea/
16
+ .vscode/
17
+ *.swp
18
+ *.swo
19
+
20
+ # Test coverage
21
+ coverage/
22
+
23
+ # Bun
24
+ bun.lockb
@@ -24,6 +24,7 @@
24
24
  "@commitlint/config-conventional": "^<%= versions['@commitlint/config-conventional'] %>",
25
25
  "bun-types": "^<%= versions['bun-types'] %>",
26
26
  "husky": "^<%= versions['husky'] %>",
27
+ "lint-staged": "^<%= versions['lint-staged'] %>",
27
28
  "typescript": "^<%= versions['typescript'] %>"
28
29
  }
29
30
  }