@icebreakers/monorepo-templates 1.2.1 → 1.3.0

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 (63) hide show
  1. package/assets/.github/workflows/ci.yml +4 -4
  2. package/assets/.github/workflows/release.yml +8 -7
  3. package/assets/package.json +2 -1
  4. package/assets/renovate.json +0 -1
  5. package/assets-data.mjs +0 -1
  6. package/dist/cli.mjs +1 -1
  7. package/dist/index.mjs +1 -1
  8. package/dist/{prepare--cxFop8c.mjs → prepare-D7eJqEqy.mjs} +1 -2
  9. package/package.json +2 -2
  10. package/templates/cli/package.json +1 -1
  11. package/templates/client/package.json +1 -1
  12. package/templates/server/package.json +1 -1
  13. package/templates/tsdown/package.json +1 -1
  14. package/templates/vitepress/.vitepress/config.ts +9 -119
  15. package/templates/vitepress/.vitepress/env.d.ts +1 -0
  16. package/templates/vitepress/.vitepress/home/content.ts +186 -0
  17. package/templates/vitepress/.vitepress/home/types.ts +65 -0
  18. package/templates/vitepress/.vitepress/navigation/routes.ts +138 -0
  19. package/templates/vitepress/.vitepress/seo.ts +40 -0
  20. package/templates/vitepress/.vitepress/theme/components/HomePage.vue +134 -0
  21. package/templates/vitepress/.vitepress/theme/home/foundation.css +180 -0
  22. package/templates/vitepress/.vitepress/theme/home/index.css +3 -0
  23. package/templates/vitepress/.vitepress/theme/home/responsive.css +49 -0
  24. package/templates/vitepress/.vitepress/theme/home/sections.css +153 -0
  25. package/templates/vitepress/.vitepress/theme/index.ts +9 -1
  26. package/templates/vitepress/ai/llms-txt.md +2 -2
  27. package/templates/vitepress/index.md +6 -60
  28. package/templates/vitepress/package.json +11 -4
  29. package/templates/vitepress/public/repoctl-doctor.png +0 -0
  30. package/templates/vitepress/repoctl/workflows.md +35 -0
  31. package/templates/vitepress/scripts/check-locales.ts +162 -0
  32. package/templates/vitepress/thinking.md +15 -0
  33. package/templates/vitepress/tools/changeset.md +17 -12
  34. package/templates/vitepress/tools/husky.md +41 -3
  35. package/templates/vitepress/tools/lint-staged.md +32 -5
  36. package/templates/vitepress/tools/pnpm.md +39 -7
  37. package/templates/vitepress/tools/renovate.md +27 -3
  38. package/templates/vitepress/tools/turborepo.md +33 -7
  39. package/templates/vitepress/tsconfig.json +7 -0
  40. package/templates/vitepress/why/examples/2.npm-basic-package/README.md +1 -1
  41. package/templates/vitepress/why/examples/3.npm-basic-package/README.md +1 -1
  42. package/templates/vitepress/why/how-to-reuse-js-code.md +36 -6
  43. package/templates/vitepress/why/js-cjs-mjs.md +31 -9
  44. package/templates/vitepress/why/js-keywords.md +33 -4
  45. package/templates/vitepress/why/modern/bundlers.md +37 -2
  46. package/templates/vitepress/why/modern/dts.md +44 -3
  47. package/templates/vitepress/why/modern/esm-vs-cjs.md +38 -3
  48. package/templates/vitepress/why/modern/index.md +33 -9
  49. package/templates/vitepress/why/modern/package-entry-points.md +33 -4
  50. package/templates/vitepress/why/modern/typescript.md +40 -4
  51. package/templates/vitepress/why/publish-basic-npm-package.md +37 -13
  52. package/templates/vitepress/why/what-is-npm-package.md +32 -3
  53. package/templates/vitepress/wrangler.jsonc +20 -3
  54. package/templates/vitepress/zh/ai/index.md +1 -1
  55. package/templates/vitepress/zh/ai/llms-txt.md +1 -1
  56. package/templates/vitepress/zh/index.md +6 -63
  57. package/templates/vitepress/zh/repoctl/workflows.md +35 -0
  58. package/templates/vitepress/zh/thinking.md +9 -6
  59. package/templates/vitepress/zh/why/examples/2.npm-basic-package/README.md +1 -1
  60. package/templates/vitepress/zh/why/examples/3.npm-basic-package/README.md +1 -1
  61. package/templates/vitepress/zh/why/index.md +38 -1
  62. package/templates/vue-lib/package.json +1 -1
  63. package/assets/netlify.toml +0 -14
@@ -1,4 +1,12 @@
1
+ import type { EnhanceAppContext, Theme } from 'vitepress'
1
2
  import DefaultTheme from 'vitepress/theme'
3
+ import HomePage from './components/HomePage.vue'
2
4
  import './tailwind.css'
5
+ import './home/index.css'
3
6
 
4
- export default DefaultTheme
7
+ export default {
8
+ ...DefaultTheme,
9
+ enhanceApp({ app }: EnhanceAppContext) {
10
+ app.component('HomePage', HomePage)
11
+ },
12
+ } satisfies Theme
@@ -9,8 +9,8 @@ The documentation build generates `/llms.txt` and `/llms-full.txt`. English is t
9
9
  ## Usage
10
10
 
11
11
  ```text
12
- https://repo.icebreaker.top/llms.txt
13
- https://repo.icebreaker.top/llms-full.txt
12
+ https://repoctl.icebreaker.top/llms.txt
13
+ https://repoctl.icebreaker.top/llms-full.txt
14
14
  ```
15
15
 
16
16
  Use the compact index for discovery and the full file only when the consumer has enough context budget.
@@ -1,63 +1,9 @@
1
1
  ---
2
- layout: home
3
-
4
- hero:
5
- name: repoctl
6
- text: Short, stable workflows for pnpm monorepos
7
- tagline: Initialize, diagnose, scaffold, verify, and upgrade practical Turborepo workspaces from one CLI.
8
- image:
9
- src: /logo.jpg
10
- alt: repoctl logo
11
- actions:
12
- - theme: brand
13
- text: Get Started
14
- link: /repoctl/getting-started
15
- - theme: alt
16
- text: Commands
17
- link: /repoctl/commands
18
- - theme: alt
19
- text: AI Docs
20
- link: /ai/
21
-
22
- features:
23
- - title: Adopt existing workspaces
24
- details: Run setup and doctor to align workspace patterns, root scripts, config files, and commit hooks.
25
- - title: Create packages and apps
26
- details: Scaffold libraries, apps, services, docs, and CLIs with interactive prompts or explicit template keys.
27
- - title: Make checks repeatable
28
- details: Preview and run local verification plans that match your lint, typecheck, build, test, and tsd workflow.
29
- - title: AI-readable documentation
30
- details: Generate llms.txt, llms-full.txt, and Markdown page output so AI coding tools can read the repoctl docs directly.
2
+ layout: page
3
+ aside: false
4
+ pageClass: repoctl-home-page
5
+ title: repoctl
6
+ description: Task-first CLI for initializing, maintaining, validating, and releasing pnpm and Turborepo monorepos.
31
7
  ---
32
8
 
33
- ## Fast Path
34
-
35
- ```bash
36
- pnpm add -D repoctl
37
- pnpm exec repo init
38
- pnpm exec repo doctor
39
- pnpm exec repo new
40
- pnpm exec repo check
41
- ```
42
-
43
- Generated repositories expose the same workflow as shorter root scripts:
44
-
45
- ```bash
46
- pnpm run repo:init
47
- pnpm run repo:doctor
48
- pnpm run repo:new
49
- pnpm run repo:check
50
- ```
51
-
52
- ## Keep Reading
53
-
54
- - [repoctl Overview](./repoctl/index.md)
55
- - [Getting Started](./repoctl/getting-started.md)
56
- - [Adopt Existing Repositories](./repoctl/adopt-existing.md)
57
- - [Choose By Scenario](./repoctl/scenarios.md)
58
- - [Command Reference](./repoctl/commands.md)
59
- - [Configuration](./repoctl/config.md)
60
- - [Templates](./repoctl/templates.md)
61
- - [Workflows and CI](./repoctl/workflows.md)
62
- - [AI Docs: llms.txt](./ai/llms-txt.md)
63
- - [Knowledge Base](./knowledge/index.md)
9
+ <HomePage locale="en" />
@@ -5,7 +5,7 @@
5
5
  "private": true,
6
6
  "description": "Documentation website for repoctl",
7
7
  "author": "ice breaker <hi@sonofmagic.top>",
8
- "homepage": "https://repo.icebreaker.top",
8
+ "homepage": "https://repoctl.icebreaker.top",
9
9
  "repository": {
10
10
  "type": "git",
11
11
  "url": "git+https://github.com/sonofmagic/repoctl.git",
@@ -22,11 +22,15 @@
22
22
  ],
23
23
  "scripts": {
24
24
  "dev": "vitepress dev",
25
- "build": "vitepress build",
25
+ "check:locales": "tsx scripts/check-locales.ts",
26
+ "build": "pnpm run check:locales && vitepress build",
26
27
  "preview": "vitepress preview",
28
+ "deploy": "wrangler deploy",
29
+ "deploy:preview": "wrangler versions upload",
30
+ "deploy:dry-run": "wrangler deploy --dry-run",
27
31
  "lint": "eslint .",
28
32
  "lint:fix": "eslint . --fix",
29
- "typecheck": "tsc -p tsconfig.json"
33
+ "typecheck": "vue-tsc -p tsconfig.json --noEmit"
30
34
  },
31
35
  "dependencies": {
32
36
  "vue": "^3.5.41"
@@ -40,8 +44,11 @@
40
44
  "debug": "^4.4.3",
41
45
  "mermaid": "^11.16.1",
42
46
  "tailwindcss": "^4.3.3",
47
+ "tsx": "^4.23.12",
43
48
  "vitepress": "^1.6.4",
44
49
  "vitepress-plugin-llms": "^1.13.5",
45
- "vitepress-plugin-mermaid": "^2.0.17"
50
+ "vitepress-plugin-mermaid": "^2.0.17",
51
+ "vue-tsc": "^3.3.10",
52
+ "wrangler": "^4.123.0"
46
53
  }
47
54
  }
@@ -82,6 +82,41 @@ repo verify pre-push
82
82
  | Output for scripts | `--json --out <file>` |
83
83
  | Share a redacted report | `--markdown --redact --out <file>` |
84
84
 
85
+ ## Documentation Worker
86
+
87
+ The repoctl documentation is deployed as the `repoctl-docs` Cloudflare Worker. VitePress produces static assets, and Workers Static Assets serves them without an application handler or an `ASSETS` binding.
88
+
89
+ ### Workers Builds settings
90
+
91
+ | Setting | Value |
92
+ | --------------------- | ------------------------------------------------------- |
93
+ | Repository root | Repository root |
94
+ | Production branch | `main` |
95
+ | Build command | `pnpm --filter @icebreakers/website build` |
96
+ | Production deploy | `pnpm --filter @icebreakers/website run deploy` |
97
+ | Non-production deploy | `pnpm --filter @icebreakers/website run deploy:preview` |
98
+
99
+ The build command checks locale parity before VitePress generates `.vitepress/dist`. The Worker config serves the generated `404.html` for missing routes and keeps `public/_redirects` active for legacy `/en/*` links.
100
+
101
+ ### Preview, release, and rollback
102
+
103
+ Run a local validation before changing production:
104
+
105
+ ```bash
106
+ pnpm --filter @icebreakers/website build
107
+ pnpm --filter @icebreakers/website run deploy:dry-run
108
+ pnpm --filter @icebreakers/website exec wrangler dev
109
+ ```
110
+
111
+ Non-production Workers Builds upload a preview version. Promote a validated build through the production deploy command. To roll back, inspect the version history and select the last known-good version:
112
+
113
+ ```bash
114
+ pnpm --filter @icebreakers/website exec wrangler versions list
115
+ pnpm --filter @icebreakers/website exec wrangler rollback <VERSION_ID>
116
+ ```
117
+
118
+ `repoctl.icebreaker.top` is the canonical custom domain. Cloudflare Redirect Rules send `repo.icebreaker.top/*` and `monorepo.icebreaker.top/*` to the canonical host with a permanent redirect while preserving the path and query string.
119
+
85
120
  ## Keep Reading
86
121
 
87
122
  - [Command Reference](./commands.md)
@@ -0,0 +1,162 @@
1
+ import { readdir, readFile, stat } from 'node:fs/promises'
2
+ import path from 'node:path'
3
+ import process from 'node:process'
4
+ import { homeContent } from '../.vitepress/home/content'
5
+
6
+ const root = process.cwd()
7
+ const ignoredDirectories = new Set(['.vitepress', 'node_modules'])
8
+ const ignoredFiles = new Set(['CHANGELOG.md'])
9
+
10
+ function toPosixPath(value: string) {
11
+ return value.replaceAll('\\', '/')
12
+ }
13
+
14
+ function relativePath(file: string) {
15
+ return toPosixPath(path.relative(root, file))
16
+ }
17
+
18
+ async function markdownFiles(directory: string): Promise<string[]> {
19
+ const entries = await readdir(directory)
20
+ const files = await Promise.all(entries.map(async (entry) => {
21
+ if (ignoredDirectories.has(entry)) {
22
+ return []
23
+ }
24
+ const absolute = path.join(directory, entry)
25
+ const metadata = await stat(absolute)
26
+ if (metadata.isDirectory()) {
27
+ return markdownFiles(absolute)
28
+ }
29
+ return entry.endsWith('.md') && !ignoredFiles.has(entry) ? [absolute] : []
30
+ }))
31
+ return files.flat()
32
+ }
33
+
34
+ function normalizeRoute(route: string) {
35
+ const withoutHash = toPosixPath(route).split('#', 1)[0]!.split('?', 1)[0]!
36
+ const withoutLocale = withoutHash.replace(/^\/zh(?=\/|$)/, '')
37
+ return withoutLocale.replace(/\/index(?:\.md)?$/, '/').replace(/\.md$/, '').replace(/\/$/, '') || '/'
38
+ }
39
+
40
+ function localLinks(markdown: string) {
41
+ const links = [...markdown.matchAll(/\[[^\]]+\]\(([^)\s]+)(?:\s[^)]*)?\)/g)]
42
+ .map(match => match[1]!)
43
+ .filter(link => !/^(?:https?:|mailto:|#)/.test(link))
44
+ return links
45
+ }
46
+
47
+ function headingLevels(markdown: string) {
48
+ const withoutCode = markdown.replace(/```[\s\S]*?```/g, '')
49
+ return [...withoutCode.matchAll(/^(#{1,6})\s+(?:\S.*|[\t\v\f \xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF])$/gm)].map(match => match[1]!.length)
50
+ }
51
+
52
+ function fencedLanguages(markdown: string) {
53
+ return [...markdown.matchAll(/^```([^\s`]*)/gm)]
54
+ .map(match => match[1]!)
55
+ .filter((_, index) => index % 2 === 0)
56
+ }
57
+
58
+ function contentKeys(value: unknown, prefix = ''): string[] {
59
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
60
+ return [prefix]
61
+ }
62
+ return Object.entries(value).flatMap(([key, nested]) => contentKeys(nested, prefix ? `${prefix}.${key}` : key))
63
+ }
64
+
65
+ async function existsAtLocale(sourceFile: string, href: string) {
66
+ const route = href.split('#', 1)[0]!.split('?', 1)[0]!
67
+ const resolved = route.startsWith('/')
68
+ ? path.join(root, route.replace(/^\//, ''))
69
+ : path.resolve(path.dirname(sourceFile), route)
70
+ const candidates = route.endsWith('/')
71
+ ? [path.join(resolved, 'index.md')]
72
+ : [resolved, `${resolved}.md`, path.join(resolved, 'index.md')]
73
+ return (await Promise.all(candidates.map(async (candidate) => {
74
+ try {
75
+ return (await stat(candidate)).isFile()
76
+ }
77
+ catch {
78
+ return false
79
+ }
80
+ }))).some(Boolean)
81
+ }
82
+
83
+ function validateDocument(relativePath: string, markdown: string) {
84
+ const errors: string[] = []
85
+ const isHome = relativePath === 'index.md' || relativePath === 'zh/index.md'
86
+ const isExampleReadme = /(?:^|\/)why\/examples\/.*\/README\.md$/.test(relativePath)
87
+ if (isHome || isExampleReadme) {
88
+ return errors
89
+ }
90
+ const headings = headingLevels(markdown)
91
+ if (headings.filter(level => level === 1).length !== 1) {
92
+ errors.push(`${relativePath}: expected one H1`)
93
+ }
94
+ for (let index = 1; index < headings.length; index += 1) {
95
+ if (headings[index]! > headings[index - 1]! + 1) {
96
+ errors.push(`${relativePath}: heading level jumps from H${headings[index - 1]} to H${headings[index]}`)
97
+ }
98
+ }
99
+ const fenceLines = [...markdown.matchAll(/^```([^\s`]*)/gm)]
100
+ if (fenceLines.length % 2 !== 0) {
101
+ errors.push(`${relativePath}: unbalanced code fence`)
102
+ }
103
+ for (const language of fencedLanguages(markdown)) {
104
+ if (!language) {
105
+ errors.push(`${relativePath}: code fences require a language marker`)
106
+ }
107
+ }
108
+ return errors
109
+ }
110
+
111
+ const files = await markdownFiles(root)
112
+ const englishFiles = files.filter(file => !relativePath(file).startsWith('zh/'))
113
+ const chineseFiles = files.filter(file => relativePath(file).startsWith('zh/'))
114
+ const englishPaths = new Set(englishFiles.map(relativePath))
115
+ const chinesePaths = new Set(chineseFiles.map(file => relativePath(file).replace(/^zh\//, '')))
116
+ const errors: string[] = []
117
+
118
+ for (const relativePath of englishPaths) {
119
+ if (!chinesePaths.has(relativePath)) {
120
+ errors.push(`missing Chinese counterpart: zh/${relativePath}`)
121
+ }
122
+ }
123
+ for (const relativePath of chinesePaths) {
124
+ if (!englishPaths.has(relativePath)) {
125
+ errors.push(`missing English counterpart: ${relativePath}`)
126
+ }
127
+ }
128
+
129
+ for (const file of files) {
130
+ const relative = relativePath(file)
131
+ const markdown = await readFile(file, 'utf8')
132
+ errors.push(...validateDocument(relative, markdown))
133
+ const links = localLinks(markdown)
134
+ for (const href of links) {
135
+ if (!await existsAtLocale(file, href)) {
136
+ errors.push(`${relative}: unresolved internal link ${href}`)
137
+ }
138
+ }
139
+
140
+ const counterpart = relative.startsWith('zh/')
141
+ ? path.join(root, relative.slice(3))
142
+ : path.join(root, 'zh', relative)
143
+ const counterpartRoute = `/${normalizeRoute(relativePath(counterpart))}`
144
+ if (await existsAtLocale(file, counterpartRoute === '/' ? '/' : counterpartRoute)) {
145
+ continue
146
+ }
147
+ errors.push(`${relative}: counterpart route cannot be resolved`)
148
+ }
149
+
150
+ const englishKeys = contentKeys(homeContent.en).sort()
151
+ const chineseKeys = contentKeys(homeContent.zh).sort()
152
+ if (englishKeys.join('\n') !== chineseKeys.join('\n')) {
153
+ errors.push('homepage locale content keys differ')
154
+ }
155
+
156
+ if (errors.length > 0) {
157
+ console.error(`Locale parity failed with ${errors.length} issue(s):\n${errors.map(error => `- ${error}`).join('\n')}`)
158
+ process.exitCode = 1
159
+ }
160
+ else {
161
+ console.log(`Locale parity passed for ${englishPaths.size} English and ${chinesePaths.size} Chinese Markdown pages.`)
162
+ }
@@ -5,3 +5,18 @@ This repository began as a reusable monorepo template. It has since evolved into
5
5
  Templates remain an important capability, but they are now private source workspaces packaged through `@icebreakers/monorepo-templates`, not the product identity or independent release units.
6
6
 
7
7
  See the [repoctl overview](./repoctl/index.md) for the current architecture and public entrypoints.
8
+
9
+ ## Documentation Deployment
10
+
11
+ The documentation is a VitePress static site deployed as a Cloudflare Worker named `repoctl-docs`. Workers Static Assets serves the generated `.vitepress/dist` directory directly, including the custom 404 page and `_redirects` compatibility rules. There is no application Worker handler because the site has no dynamic request path.
12
+
13
+ Cloudflare Workers Builds uses the repository root and runs these commands:
14
+
15
+ ```bash
16
+ pnpm --filter @icebreakers/website build
17
+ pnpm --filter @icebreakers/website run deploy
18
+ ```
19
+
20
+ Non-production branches upload preview versions with `pnpm --filter @icebreakers/website run deploy:preview`. Before a production change, `pnpm --filter @icebreakers/website run deploy:dry-run` validates the asset manifest and Wrangler configuration. A production rollback uses `wrangler rollback <VERSION_ID>` after reviewing `wrangler versions list`.
21
+
22
+ The canonical host is `https://repoctl.icebreaker.top`. The legacy `repo.icebreaker.top` and `monorepo.icebreaker.top` hosts are redirect-only entrypoints and preserve the original path and query string.
@@ -1,25 +1,30 @@
1
1
  # pnpm Versioning
2
2
 
3
- This repository uses pnpm change intents and workspace versioning for releases.
3
+ repoctl uses pnpm's native versioning workflow. A change intent records why a publishable package needs a release, and the repository ledger keeps that intent with the source change.
4
4
 
5
- ## Daily Development
5
+ ## Record release intent
6
6
 
7
7
  ```bash
8
8
  pnpm change
9
- pnpm change status
9
+ pnpm version -r
10
+ pnpm publish -r
10
11
  ```
11
12
 
12
- Choose every publishable package whose public behavior changed and record the correct patch, minor, or major level. Private template workspaces are not release units.
13
+ Choose the smallest version bump that matches the public contract. Removing a managed asset from a published template package is a minor change because consumers no longer receive that asset. Metadata-only URL changes are patch changes.
13
14
 
14
- ## Release
15
+ ## Fixed packages
15
16
 
16
- ```bash
17
- repo release stable prepare
18
- repo release stable publish
19
- ```
17
+ Some packages version together because they share a public contract. The versioning configuration defines those groups; do not manually align versions in package manifests.
18
+
19
+ ## Before publishing
20
20
 
21
- repoctl coordinates the release workflow, validates configuration, and publishes metadata. pnpm owns the versioning state and repository changelog storage.
21
+ 1. Build the affected packages.
22
+ 2. Run lint and typecheck.
23
+ 3. Run unit, integration, and end-to-end tests where available.
24
+ 4. Confirm the generated changelog and package contents match the intent.
22
25
 
23
- ## Prerelease Lanes
26
+ ## Keep Reading
24
27
 
25
- Use `repo release pre enter <tag>`, `repo release pre publish`, and `repo release pre exit` for alpha, beta, rc, or next lanes.
28
+ - [Publishing and Changelogs](../monorepo/publish.md)
29
+ - [Workflows and CI](../repoctl/workflows.md)
30
+ - [Template Assets](../repoctl/template-assets.md)
@@ -1,12 +1,50 @@
1
1
  # Husky
2
2
 
3
- Husky connects repository scripts to Git hooks. repoctl-managed workspaces use it as a thin entrypoint, keeping verification logic in versioned commands.
3
+ Husky connects Git hooks to versioned repository scripts. In a repoctl workspace it is only a trigger: the actual verification lives in `repo verify` so people, CI, and hooks use the same contract.
4
+
5
+ ## Recommended hooks
4
6
 
5
7
  ```sh
6
8
  # .husky/pre-commit
7
9
  pnpm exec repo verify pre-commit
10
+
11
+ # .husky/commit-msg
12
+ pnpm exec repo verify commit-msg "$1"
13
+
14
+ # .husky/pre-push
15
+ pnpm exec repo verify pre-push
8
16
  ```
9
17
 
10
- Use `commit-msg` for commitlint and `pre-push` for broader build and test verification. Hooks should remain fast enough for local work and should not contain duplicated task logic.
18
+ Keep hooks small. A hook should select a repository task, not duplicate lint, typecheck, or build commands that will drift from CI.
19
+
20
+ ## What each hook protects
21
+
22
+ | Hook | Purpose | Usual scope |
23
+ | ------------ | ------------------------------------ | --------------------------------------------------- |
24
+ | `pre-commit` | Fast feedback before a commit exists | Staged formatting, lint, and typecheck |
25
+ | `commit-msg` | Enforce the commit message contract | The pending commit message file |
26
+ | `pre-push` | Catch broader integration failures | Root checks and affected build, test, and tsd tasks |
27
+
28
+ `repo doctor` reports incomplete Husky and lint-staged configuration. Use `repo upgrade --no-overwrite` to preview managed hook changes before accepting them.
29
+
30
+ ## Install and initialize
31
+
32
+ ```bash
33
+ pnpm add -D husky
34
+ pnpm exec husky init
35
+ ```
36
+
37
+ The initializer creates `.husky/pre-commit`. Replace its generated command with the repository task instead of adding a second tool-specific pipeline.
38
+
39
+ ## Troubleshooting
40
+
41
+ - Confirm the hook file is executable after a fresh clone.
42
+ - Run the command from the hook directly before debugging Git.
43
+ - Do not use interactive prompts in a hook.
44
+ - Keep network calls and release work out of `pre-commit`.
45
+
46
+ ## Keep Reading
11
47
 
12
- `repo doctor` reports when Husky and lint-staged are only partially configured. `repo upgrade` can synchronize the managed defaults.
48
+ - [lint-staged](./lint-staged.md)
49
+ - [Workflows and CI](../repoctl/workflows.md)
50
+ - [Verification](../repoctl/checks.md)
@@ -1,12 +1,39 @@
1
1
  # lint-staged
2
2
 
3
- lint-staged runs checks only for files included in the next commit.
3
+ lint-staged runs focused checks against files staged for a commit. It keeps the pre-commit hook quick while preserving the same ESLint, Stylelint, and typecheck rules used elsewhere in the workspace.
4
4
 
5
- The repository policy routes JavaScript, TypeScript, and Vue files through ESLint, style files through Stylelint, and TypeScript or Vue files to the owning workspace's typecheck script.
5
+ ## Recommended responsibility
6
6
 
7
- ```bash
7
+ Use lint-staged for checks that can safely operate on selected files. Keep full builds, integration tests, and release checks in `repo check --full` or CI.
8
+
9
+ ```js
10
+ // lint-staged.config.js
11
+ export default {
12
+ '*.{js,mjs,cjs,ts,tsx,vue}': ['eslint --fix'],
13
+ '*.{css,scss,less,vue}': ['stylelint --fix'],
14
+ }
15
+ ```
16
+
17
+ repoctl-managed workspaces also route staged TypeScript and Vue files into the appropriate workspace typecheck command. This matters because Vue packages need `vue-tsc`, while TypeScript-only packages use `tsc`.
18
+
19
+ ## Pair it with Husky
20
+
21
+ ```sh
22
+ # .husky/pre-commit
8
23
  pnpm exec repo verify pre-commit
9
- pnpm exec repo verify staged-typecheck <files...>
10
24
  ```
11
25
 
12
- Vue workspaces should use `vue-tsc`; plain TypeScript workspaces should use `tsc`. Keep the routing in `lint-staged.config.js` so local hooks and CI can share the same contract.
26
+ The hook selects repoctl's pre-commit workflow. That workflow can call lint-staged without embedding a second copy of the configuration in the hook file.
27
+
28
+ ## Safe fixes
29
+
30
+ - Use `--fix` only for deterministic formatting and lint repairs.
31
+ - Do not stage unrelated generated output from a task.
32
+ - Run `pnpm lint` before opening a pull request because it covers more than staged files.
33
+ - Test hook behavior from a clean index, not only with already-staged fixes.
34
+
35
+ ## Keep Reading
36
+
37
+ - [Husky](./husky.md)
38
+ - [Verification](../repoctl/checks.md)
39
+ - [Workflows and CI](../repoctl/workflows.md)
@@ -1,15 +1,47 @@
1
1
  # pnpm
2
2
 
3
- pnpm owns workspace discovery, dependency installation, script execution, and versioning configuration.
3
+ pnpm is the package manager used by repoctl workspaces. Its workspace protocol, content-addressable store, and filter syntax make it a practical fit for repositories with several packages and applications.
4
+
5
+ ## Install dependencies
4
6
 
5
7
  ```bash
6
8
  pnpm install
7
- pnpm --filter <package> build
8
- pnpm -r test
9
- pnpm change
10
- pnpm change status
9
+ pnpm install --frozen-lockfile
11
10
  ```
12
11
 
13
- `pnpm-workspace.yaml` is the source of truth for package patterns and release groups. repoctl can diagnose missing patterns and synchronize recommended defaults, but pnpm remains the package manager.
12
+ Use the frozen form in CI. It proves that `package.json` files and the lockfile describe the same dependency graph.
13
+
14
+ ## Work with one workspace
15
+
16
+ ```bash
17
+ pnpm --filter repoctl build
18
+ pnpm --filter @icebreakers/monorepo test
19
+ pnpm --filter './packages/*' lint
20
+ ```
21
+
22
+ Filters are a routing tool, not a replacement for repository scripts. Prefer an existing package script over an ad hoc command when a task should be repeatable.
23
+
24
+ ## Link local packages
25
+
26
+ ```json
27
+ {
28
+ "dependencies": {
29
+ "@icebreakers/monorepo": "workspace:*"
30
+ }
31
+ }
32
+ ```
33
+
34
+ The `workspace:` protocol prevents accidentally resolving a local package from the public registry during development.
35
+
36
+ ## Operational guidance
37
+
38
+ - Pin the package manager in the root `package.json`.
39
+ - Commit `pnpm-lock.yaml` for applications and monorepos.
40
+ - Use `pnpm exec` for binaries supplied by the current workspace.
41
+ - Use `pnpm --filter` for a scoped package command and Turbo for graph-wide task orchestration.
42
+
43
+ ## Keep Reading
14
44
 
15
- Prefer exact workspace filters in automation and keep `packageManager` plus `engines.node` declared at the repository root.
45
+ - [Turborepo](./turborepo.md)
46
+ - [Managing A Monorepo](../monorepo/manage.md)
47
+ - [repoctl Commands](../repoctl/commands.md)
@@ -1,7 +1,31 @@
1
1
  # Renovate
2
2
 
3
- Renovate opens dependency update pull requests according to repository policy.
3
+ Renovate keeps dependencies current through reviewable pull requests. It is most useful when the configuration groups compatible updates, lets CI prove the upgrade, and avoids mixing unrelated ecosystem changes.
4
4
 
5
- Group related tooling updates, respect pnpm workspace constraints, and let the normal build, lint, typecheck, tsd, and test matrix validate each update. Avoid combining unrelated runtime and tooling upgrades when separate review makes regressions easier to isolate.
5
+ ## Repository policy
6
6
 
7
- repoctl does not replace Renovate. It provides the diagnostic and verification commands that Renovate pull requests can run consistently.
7
+ ```json
8
+ {
9
+ "extends": ["config:recommended", "group:allNonMajor"],
10
+ "rangeStrategy": "bump",
11
+ "automerge": true,
12
+ "automergeType": "pr"
13
+ }
14
+ ```
15
+
16
+ The repository groups compatible minor and patch updates. Cloudflare Workers tooling is grouped separately because Wrangler and its Vite plugin have a deliberate compatibility relationship.
17
+
18
+ ## Review an update
19
+
20
+ 1. Read the package release notes when the update changes build, test, or deployment tooling.
21
+ 2. Run the normal build and validation sequence against the updated lockfile.
22
+ 3. Check generated assets and package metadata for unexpected churn.
23
+ 4. Merge only after the configured checks prove the update is compatible.
24
+
25
+ Do not rely on commit-message directives for a retired deployment provider. Deployment behavior belongs in the active platform configuration and CI settings.
26
+
27
+ ## Keep Reading
28
+
29
+ - [pnpm](./pnpm.md)
30
+ - [Workflows and CI](../repoctl/workflows.md)
31
+ - [Troubleshooting](../repoctl/troubleshooting.md)
@@ -1,14 +1,40 @@
1
1
  # Turborepo
2
2
 
3
- Turborepo runs the monorepo task graph and caches repeatable work.
3
+ Turborepo turns package scripts into a dependency-aware task graph. repoctl workspaces use it for the repository-wide work that should be cached and run in dependency order.
4
+
5
+ ## Define task boundaries
6
+
7
+ ```json
8
+ {
9
+ "tasks": {
10
+ "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] },
11
+ "test": { "dependsOn": ["build"], "outputs": ["coverage/**"] },
12
+ "typecheck": { "dependsOn": ["^typecheck"], "outputs": [] }
13
+ }
14
+ }
15
+ ```
16
+
17
+ `^build` means that a package must build its workspace dependencies before its own build starts. Declare outputs accurately so the cache can restore useful artifacts and ignore transient files.
18
+
19
+ ## Run graph-aware tasks
4
20
 
5
21
  ```bash
6
- pnpm build
7
- pnpm lint
8
- pnpm typecheck
9
- pnpm test
22
+ pnpm turbo run build
23
+ pnpm turbo run test --filter=repoctl
24
+ pnpm turbo run lint typecheck
10
25
  ```
11
26
 
12
- Root scripts delegate to `turbo run`. Package scripts define the actual build, lint, typecheck, and test commands; `turbo.json` defines dependencies, inputs, outputs, and cache behavior.
27
+ Use root scripts for the common entrypoints. The root script is the stable command people and CI should remember; Turbo remains the graph executor beneath it.
28
+
29
+ ## Cache with care
30
+
31
+ - Include configuration files that materially affect output in task inputs.
32
+ - Keep secrets out of cached output.
33
+ - Set `outputs: []` for validation-only tasks.
34
+ - Use `--force` only when diagnosing cache behavior.
35
+
36
+ ## Keep Reading
13
37
 
14
- Mark generated artifacts as task outputs and declare upstream dependencies such as `build` before tests that consume built packages.
38
+ - [pnpm](./pnpm.md)
39
+ - [Verification](../repoctl/checks.md)
40
+ - [Managing A Monorepo](../monorepo/manage.md)
@@ -9,6 +9,13 @@
9
9
  "skipLibCheck": true
10
10
  },
11
11
  "include": [
12
+ ".vitepress/home/**/*.ts",
13
+ ".vitepress/navigation/**/*.ts",
14
+ ".vitepress/seo.ts",
15
+ ".vitepress/theme/**/*.ts",
16
+ ".vitepress/theme/**/*.vue",
17
+ ".vitepress/env.d.ts",
18
+ "scripts/**/*.ts",
12
19
  "why/examples/2.npm-basic-package/src/**/*.ts",
13
20
  "why/examples/3.npm-basic-package/src/**/*.ts"
14
21
  ]