@regardio/dev 1.24.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +2 -2
  2. package/dist/bin/ship/hotfix.bin.mjs +140 -0
  3. package/dist/bin/ship/production.bin.mjs +120 -0
  4. package/dist/bin/ship/staging.bin.mjs +70 -0
  5. package/dist/bin/ship/utils-BQ-JZ2D5.mjs +45 -0
  6. package/dist/playwright/index.d.mts +24 -0
  7. package/dist/playwright/index.mjs +61 -0
  8. package/dist/vitest/node.d.mts +22 -0
  9. package/dist/vitest/node.mjs +28 -0
  10. package/dist/vitest/react.d.mts +22 -0
  11. package/dist/vitest/react.mjs +28 -0
  12. package/docs/en/README.md +95 -0
  13. package/docs/en/agents.md +57 -0
  14. package/docs/en/standards/api.md +324 -0
  15. package/docs/en/standards/coding.md +144 -0
  16. package/docs/en/standards/commits.md +111 -0
  17. package/docs/en/standards/documentation.md +173 -0
  18. package/docs/en/standards/naming.md +180 -0
  19. package/docs/en/standards/principles.md +84 -0
  20. package/docs/en/standards/react.md +246 -0
  21. package/docs/en/standards/sql.md +258 -0
  22. package/docs/en/standards/testing.md +139 -0
  23. package/docs/en/standards/writing.md +119 -0
  24. package/docs/en/tools/biome.md +89 -0
  25. package/docs/en/tools/commitlint.md +92 -0
  26. package/docs/en/tools/dependencies.md +116 -0
  27. package/docs/en/tools/husky.md +90 -0
  28. package/docs/en/tools/markdownlint.md +84 -0
  29. package/docs/en/tools/playwright.md +117 -0
  30. package/docs/en/tools/releases.md +242 -0
  31. package/docs/en/tools/typescript.md +89 -0
  32. package/docs/en/tools/vitest.md +146 -0
  33. package/package.json +57 -70
  34. package/src/biome/preset.json +3 -0
  35. package/templates/changeset/README.md +14 -0
  36. package/templates/changeset/config.json +11 -0
  37. package/templates/github/release.yml +77 -0
  38. package/dist/bin/exec/clean.d.ts +0 -3
  39. package/dist/bin/exec/clean.d.ts.map +0 -1
  40. package/dist/bin/exec/clean.js +0 -25
  41. package/dist/bin/exec/clean.test.d.ts +0 -2
  42. package/dist/bin/exec/clean.test.d.ts.map +0 -1
  43. package/dist/bin/exec/clean.test.js +0 -45
  44. package/dist/bin/exec/husky.d.ts +0 -3
  45. package/dist/bin/exec/husky.d.ts.map +0 -1
  46. package/dist/bin/exec/husky.js +0 -9
  47. package/dist/bin/exec/p.d.ts +0 -3
  48. package/dist/bin/exec/p.d.ts.map +0 -1
  49. package/dist/bin/exec/p.js +0 -8
  50. package/dist/bin/exec/s.d.ts +0 -3
  51. package/dist/bin/exec/s.d.ts.map +0 -1
  52. package/dist/bin/exec/s.js +0 -8
  53. package/dist/bin/exec/tsc.d.ts +0 -3
  54. package/dist/bin/exec/tsc.d.ts.map +0 -1
  55. package/dist/bin/exec/tsc.js +0 -8
  56. package/dist/bin/lint/biome.d.ts +0 -3
  57. package/dist/bin/lint/biome.d.ts.map +0 -1
  58. package/dist/bin/lint/biome.js +0 -8
  59. package/dist/bin/lint/commit.d.ts +0 -3
  60. package/dist/bin/lint/commit.d.ts.map +0 -1
  61. package/dist/bin/lint/commit.js +0 -8
  62. package/dist/bin/lint/md.d.ts +0 -3
  63. package/dist/bin/lint/md.d.ts.map +0 -1
  64. package/dist/bin/lint/md.js +0 -16
  65. package/dist/bin/lint/package.d.ts +0 -4
  66. package/dist/bin/lint/package.d.ts.map +0 -1
  67. package/dist/bin/lint/package.js +0 -81
  68. package/dist/bin/lint/package.test.d.ts +0 -2
  69. package/dist/bin/lint/package.test.d.ts.map +0 -1
  70. package/dist/bin/lint/package.test.js +0 -65
  71. package/dist/bin/ship/hotfix.d.ts +0 -3
  72. package/dist/bin/ship/hotfix.d.ts.map +0 -1
  73. package/dist/bin/ship/hotfix.js +0 -141
  74. package/dist/bin/ship/production.d.ts +0 -3
  75. package/dist/bin/ship/production.d.ts.map +0 -1
  76. package/dist/bin/ship/production.js +0 -124
  77. package/dist/bin/ship/staging.d.ts +0 -3
  78. package/dist/bin/ship/staging.d.ts.map +0 -1
  79. package/dist/bin/ship/staging.js +0 -51
  80. package/dist/bin/ship/utils.d.ts +0 -9
  81. package/dist/bin/ship/utils.d.ts.map +0 -1
  82. package/dist/bin/ship/utils.js +0 -63
  83. package/dist/bin/ship/utils.test.d.ts +0 -2
  84. package/dist/bin/ship/utils.test.d.ts.map +0 -1
  85. package/dist/bin/ship/utils.test.js +0 -127
  86. package/dist/config.test.d.ts +0 -2
  87. package/dist/config.test.d.ts.map +0 -1
  88. package/dist/config.test.js +0 -101
  89. package/dist/playwright/index.d.ts +0 -10
  90. package/dist/playwright/index.d.ts.map +0 -1
  91. package/dist/playwright/index.js +0 -42
  92. package/dist/playwright/index.test.d.ts +0 -2
  93. package/dist/playwright/index.test.d.ts.map +0 -1
  94. package/dist/playwright/index.test.js +0 -55
  95. package/dist/testing/setup-react.d.ts +0 -2
  96. package/dist/testing/setup-react.d.ts.map +0 -1
  97. package/dist/testing/setup-react.js +0 -1
  98. package/dist/vitest/node.d.ts +0 -22
  99. package/dist/vitest/node.d.ts.map +0 -1
  100. package/dist/vitest/node.js +0 -16
  101. package/dist/vitest/react.d.ts +0 -17
  102. package/dist/vitest/react.d.ts.map +0 -1
  103. package/dist/vitest/react.js +0 -12
  104. package/src/bin/exec/clean.test.ts +0 -63
  105. package/src/bin/exec/clean.ts +0 -36
  106. package/src/bin/exec/husky.ts +0 -14
  107. package/src/bin/exec/p.ts +0 -13
  108. package/src/bin/exec/s.ts +0 -13
  109. package/src/bin/exec/tsc.ts +0 -13
  110. package/src/bin/lint/biome.ts +0 -13
  111. package/src/bin/lint/commit.ts +0 -13
  112. package/src/bin/lint/md.ts +0 -28
  113. package/src/bin/lint/package.test.ts +0 -83
  114. package/src/bin/lint/package.ts +0 -108
  115. package/src/bin/ship/hotfix.ts +0 -241
  116. package/src/bin/ship/production.ts +0 -240
  117. package/src/bin/ship/staging.ts +0 -108
  118. package/src/bin/ship/utils.test.ts +0 -178
  119. package/src/bin/ship/utils.ts +0 -109
  120. package/src/config.test.ts +0 -129
  121. package/src/markdownlint/markdownlint-cli2.jsonc +0 -9
  122. package/src/playwright/index.test.ts +0 -73
  123. package/src/playwright/index.ts +0 -63
  124. package/src/templates/release.yml +0 -128
  125. package/src/testing/setup-react.ts +0 -8
  126. package/src/vitest/node.ts +0 -25
  127. package/src/vitest/react.ts +0 -19
  128. /package/{src → templates}/sqlfluff/setup.cfg +0 -0
package/src/bin/exec/s.ts DELETED
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * exec-s: Run npm scripts sequentially via npm-run-all's run-s.
4
- * Usage: exec-s <script-patterns>
5
- */
6
- import { spawn } from 'node:child_process';
7
- import { createRequire } from 'node:module';
8
-
9
- const require = createRequire(import.meta.url);
10
- const bin = require.resolve('npm-run-all/bin/run-s/index.js');
11
- const args = process.argv.slice(2);
12
- const child = spawn(process.execPath, [bin, ...args], { stdio: 'inherit' });
13
- child.on('exit', (code) => process.exit(code ?? 0));
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * exec-tsc: Run the TypeScript compiler (tsc) via local dependency.
4
- * Usage: exec-tsc [tsc args...]
5
- */
6
- import { spawn } from 'node:child_process';
7
- import { createRequire } from 'node:module';
8
-
9
- const require = createRequire(import.meta.url);
10
- const bin = require.resolve('typescript/bin/tsc');
11
- const args = process.argv.slice(2);
12
- const child = spawn(process.execPath, [bin, ...args], { stdio: 'inherit' });
13
- child.on('exit', (code) => process.exit(code ?? 0));
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * lint-biome: Run Biome (formatter/linter) against the codebase.
4
- * Usage: lint-biome [biome args...]
5
- */
6
- import { spawn } from 'node:child_process';
7
- import { createRequire } from 'node:module';
8
-
9
- const require = createRequire(import.meta.url);
10
- const bin = require.resolve('@biomejs/biome/bin/biome');
11
- const args = process.argv.slice(2);
12
- const child = spawn(process.execPath, [bin, ...args], { stdio: 'inherit' });
13
- child.on('exit', (code) => process.exit(code ?? 0));
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * lint-commit: Run commitlint against commit messages.
4
- * Usage: lint-commit [commitlint args...]
5
- */
6
- import { spawn } from 'node:child_process';
7
- import { createRequire } from 'node:module';
8
-
9
- const require = createRequire(import.meta.url);
10
- const bin = require.resolve('@commitlint/cli/cli.js');
11
- const args = process.argv.slice(2);
12
- const child = spawn(process.execPath, [bin, ...args], { stdio: 'inherit' });
13
- child.on('exit', (code) => process.exit(code ?? 0));
@@ -1,28 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * lint-md: Run markdownlint-cli2 to lint and fix Markdown files.
4
- * Usage: lint-md [--fix] [globs...]
5
- *
6
- * Default globs (if none provided): "**\/*.md" "**\/*.mdx"
7
- * Default exclusions (always added): "!**\/dist/**" "!**\/node_modules/**"
8
- */
9
- import { spawn } from 'node:child_process';
10
- import { createRequire } from 'node:module';
11
- import { dirname, join } from 'node:path';
12
-
13
- const require = createRequire(import.meta.url);
14
- const packageDir = dirname(require.resolve('markdownlint-cli2'));
15
- const bin = join(packageDir, 'markdownlint-cli2-bin.mjs');
16
-
17
- const DEFAULT_GLOBS = ['**/*.md', '**/*.mdx'];
18
- const DEFAULT_EXCLUSIONS = ['!**/dist/**', '!**/node_modules/**'];
19
-
20
- const rawArgs = process.argv.slice(2);
21
- const fixFlag = rawArgs.includes('--fix');
22
- const userGlobs = rawArgs.filter((arg) => arg !== '--fix');
23
-
24
- const globs = userGlobs.length > 0 ? userGlobs : DEFAULT_GLOBS;
25
- const args = [...(fixFlag ? ['--fix'] : []), ...globs, ...DEFAULT_EXCLUSIONS];
26
-
27
- const child = spawn(process.execPath, [bin, ...args], { stdio: 'inherit' });
28
- child.on('exit', (code) => process.exit(code ?? 0));
@@ -1,83 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
3
- import { reorderConditions } from './package.js';
4
-
5
- describe('lint-package', () => {
6
- describe('reorderConditions', () => {
7
- it('reorders types before default when default comes first', () => {
8
- const input = {
9
- './foo': {
10
- default: './dist/foo.js',
11
- types: './dist/foo.d.ts',
12
- },
13
- };
14
-
15
- const result = reorderConditions(input);
16
-
17
- expect(Object.keys(result['./foo'] as Record<string, unknown>)).toEqual(['types', 'default']);
18
- });
19
-
20
- it('does not modify when types already comes before default', () => {
21
- const input = {
22
- './foo': {
23
- default: './dist/foo.js',
24
- types: './dist/foo.d.ts',
25
- },
26
- };
27
-
28
- const result = reorderConditions(input);
29
-
30
- expect(Object.keys(result['./foo'] as Record<string, unknown>)).toEqual(['types', 'default']);
31
- });
32
-
33
- it('handles multiple exports with mixed order', () => {
34
- const input = {
35
- './a': { default: './dist/a.js', types: './dist/a.d.ts' },
36
- './b': { default: './dist/b.js', types: './dist/b.d.ts' },
37
- };
38
-
39
- const result = reorderConditions(input);
40
-
41
- expect(Object.keys(result['./a'] as Record<string, unknown>)[0]).toBe('types');
42
- expect(Object.keys(result['./b'] as Record<string, unknown>)[0]).toBe('types');
43
- });
44
-
45
- it('preserves other keys after types', () => {
46
- const input = {
47
- './foo': {
48
- default: './dist/foo.js',
49
- import: './dist/foo.mjs',
50
- require: './dist/foo.cjs',
51
- types: './dist/foo.d.ts',
52
- },
53
- };
54
-
55
- const result = reorderConditions(input);
56
- const keys = Object.keys(result['./foo'] as Record<string, unknown>);
57
-
58
- expect(keys[0]).toBe('types');
59
- expect(keys.slice(1)).toEqual(['default', 'import', 'require']);
60
- });
61
-
62
- it('handles exports without types or default', () => {
63
- const input = { './styles.css': './dist/styles.css' };
64
-
65
- expect(reorderConditions(input)).toEqual(input);
66
- });
67
-
68
- it('handles deeply nested condition objects', () => {
69
- const input = {
70
- './foo': {
71
- browser: { default: './dist/foo.browser.js', types: './dist/foo.browser.d.ts' },
72
- node: { default: './dist/foo.node.js', types: './dist/foo.node.d.ts' },
73
- },
74
- };
75
-
76
- const result = reorderConditions(input);
77
- const foo = result['./foo'] as Record<string, Record<string, unknown>>;
78
-
79
- expect(Object.keys(foo.node as object)[0]).toBe('types');
80
- expect(Object.keys(foo.browser as object)[0]).toBe('types');
81
- });
82
- });
83
- });
@@ -1,108 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Sorts package.json files using sort-package-json and fixes
4
- * exports condition order (types must come before default for TypeScript).
5
- */
6
- import { execSync } from 'node:child_process';
7
- import { existsSync, readFileSync, writeFileSync } from 'node:fs';
8
- import { dirname, join, resolve } from 'node:path';
9
- import { fileURLToPath } from 'node:url';
10
-
11
- /**
12
- * Recursively reorder exports condition objects so that `types` always
13
- * appears before `default`. Returns a new object; does not mutate input.
14
- */
15
- export function reorderConditions(obj: Record<string, unknown>): Record<string, unknown> {
16
- if (typeof obj !== 'object' || obj === null) return obj;
17
-
18
- const processed: Record<string, unknown> = {};
19
- for (const [key, value] of Object.entries(obj)) {
20
- processed[key] =
21
- typeof value === 'object' && value !== null && !Array.isArray(value)
22
- ? reorderConditions(value as Record<string, unknown>)
23
- : value;
24
- }
25
-
26
- if ('types' in processed && 'default' in processed) {
27
- const keys = Object.keys(processed);
28
- if (keys.indexOf('default') < keys.indexOf('types')) {
29
- const reordered: Record<string, unknown> = { types: processed.types };
30
- for (const key of keys) {
31
- if (key !== 'types') reordered[key] = processed[key];
32
- }
33
- return reordered;
34
- }
35
- }
36
-
37
- return processed;
38
- }
39
-
40
- /**
41
- * Fix exports condition order in a package.json file.
42
- * Returns true if the file needs changes (or was changed when fix=true).
43
- */
44
- export function fixExportsOrder(filePath: string, fix: boolean): boolean {
45
- const fullPath = resolve(process.cwd(), filePath);
46
- if (!existsSync(fullPath)) return false;
47
-
48
- const content = readFileSync(fullPath, 'utf-8');
49
- const pkg = JSON.parse(content) as Record<string, unknown>;
50
-
51
- if (!pkg.exports || typeof pkg.exports !== 'object') return false;
52
-
53
- const fixed = reorderConditions(pkg.exports as Record<string, unknown>);
54
- const changed = JSON.stringify(fixed) !== JSON.stringify(pkg.exports);
55
-
56
- if (changed && fix) {
57
- writeFileSync(fullPath, `${JSON.stringify({ ...pkg, exports: fixed }, null, 2)}\n`);
58
- }
59
-
60
- return changed;
61
- }
62
-
63
- // ---------------------------------------------------------------------------
64
- // CLI entry point — only runs when executed directly
65
- // ---------------------------------------------------------------------------
66
- if (fileURLToPath(import.meta.url) === resolve(process.argv[1] ?? '')) {
67
- const __dirname = dirname(fileURLToPath(import.meta.url));
68
- const devRoot = resolve(__dirname, '../../..');
69
-
70
- const sortPkgBin = join(devRoot, 'node_modules/.bin/sort-package-json');
71
- const sortPkgBinAlt = join(devRoot, 'node_modules/sort-package-json/cli.js');
72
-
73
- let bin = '';
74
- if (existsSync(sortPkgBin)) {
75
- bin = sortPkgBin;
76
- } else if (existsSync(sortPkgBinAlt)) {
77
- bin = `node ${sortPkgBinAlt}`;
78
- } else {
79
- bin = 'npx sort-package-json';
80
- }
81
-
82
- const args = process.argv.slice(2);
83
- const fixMode = args.includes('--fix');
84
- const files = args.filter((arg) => arg !== '--fix');
85
- const targets = files.length > 0 ? files : ['package.json'];
86
-
87
- try {
88
- const checkFlag = fixMode ? '' : '--check';
89
- execSync(`${bin} ${checkFlag} ${targets.join(' ')}`.trim(), { stdio: 'inherit' });
90
- } catch {
91
- process.exit(1);
92
- }
93
-
94
- let hasExportsIssues = false;
95
- for (const file of targets) {
96
- const needsFix = fixExportsOrder(file, fixMode);
97
- if (needsFix && !fixMode) {
98
- console.error(
99
- `${file}: exports condition order is incorrect (types must come before default)`,
100
- );
101
- hasExportsIssues = true;
102
- }
103
- }
104
-
105
- if (hasExportsIssues) {
106
- process.exit(1);
107
- }
108
- }
@@ -1,241 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * ship-hotfix: Manage hotfix branches based on production code.
4
- *
5
- * Usage:
6
- * ship-hotfix start <name> - Create hotfix/<name> from production
7
- * ship-hotfix finish <patch|minor> "description" - Finish and propagate the hotfix
8
- *
9
- * GitLab workflow:
10
- * production → hotfix/<name> → production → staging → main
11
- *
12
- * start:
13
- * 1. Fetches origin, checks out production, creates hotfix/<name>
14
- *
15
- * finish:
16
- * 1. Ensures you are on a hotfix/* branch with a clean working tree
17
- * 2. Runs quality checks
18
- * 3. Bumps version (patch or minor) and updates CHANGELOG.md
19
- * 4. Commits, then merges into production
20
- * 5. Merges production into staging
21
- * 6. Merges staging into main
22
- * 7. Pushes all three branches, deletes the hotfix branch
23
- * 8. Checks out main
24
- */
25
- import { execSync } from 'node:child_process';
26
- import { existsSync, readFileSync, writeFileSync } from 'node:fs';
27
- import { join } from 'node:path';
28
-
29
- import {
30
- branchExists,
31
- bumpVersion,
32
- git,
33
- gitRead,
34
- insertChangelog,
35
- runQualityChecks,
36
- runScript,
37
- } from './utils.js';
38
-
39
- const subcommand = process.argv[2];
40
- const subArgs = process.argv.slice(3);
41
-
42
- // ---------------------------------------------------------------------------
43
- // flow-hotfix start <name>
44
- // ---------------------------------------------------------------------------
45
- if (subcommand === 'start') {
46
- const name = subArgs[0];
47
- if (!name) {
48
- console.error('Usage: ship-hotfix start <name>');
49
- process.exit(1);
50
- }
51
-
52
- const hotfixBranch = `hotfix/${name}`;
53
-
54
- const status = gitRead('status', '--porcelain');
55
- if (status) {
56
- console.error('Working directory has uncommitted changes. Commit or stash them first.');
57
- process.exit(1);
58
- }
59
-
60
- console.log('\nFetching latest state from origin...');
61
- git('fetch', 'origin');
62
-
63
- if (!branchExists('production')) {
64
- console.error(
65
- 'Branch "production" does not exist. Create it first:\n'
66
- + ' git checkout -b production && git push -u origin production',
67
- );
68
- process.exit(1);
69
- }
70
-
71
- git('checkout', 'production');
72
- git('pull', '--ff-only', 'origin', 'production');
73
- git('checkout', '-b', hotfixBranch);
74
-
75
- console.log(`\n✅ Hotfix branch "${hotfixBranch}" created from production.`);
76
- console.log('Apply your fix, then run: ship-hotfix finish <patch|minor> "description"');
77
- process.exit(0);
78
- }
79
-
80
- // ---------------------------------------------------------------------------
81
- // flow-hotfix finish <patch|minor> "description"
82
- // ---------------------------------------------------------------------------
83
- if (subcommand === 'finish') {
84
- const bumpType = subArgs[0];
85
- const message = subArgs.slice(1).join(' ');
86
-
87
- if (!bumpType || !['patch', 'minor'].includes(bumpType)) {
88
- console.error('Usage: ship-hotfix finish <patch|minor> "description"');
89
- console.error('Hotfixes use patch or minor bumps only.');
90
- process.exit(1);
91
- }
92
-
93
- if (!message) {
94
- console.error('A description is required.');
95
- console.error('Example: ship-hotfix finish patch "Fix critical auth bug"');
96
- process.exit(1);
97
- }
98
-
99
- // Guard: must be on a hotfix/* branch
100
- const currentBranch = gitRead('branch', '--show-current');
101
- if (!currentBranch.startsWith('hotfix/')) {
102
- console.error(`Must be on a hotfix/* branch. Currently on: ${currentBranch}`);
103
- process.exit(1);
104
- }
105
-
106
- // Guard: working tree must be clean
107
- const status = gitRead('status', '--porcelain');
108
- if (status) {
109
- console.error('Working directory has uncommitted changes. Commit or stash them first.');
110
- process.exit(1);
111
- }
112
-
113
- // Quality checks
114
- console.log('\nRunning quality checks...');
115
- try {
116
- runQualityChecks();
117
- } catch {
118
- console.error('\nQuality checks failed. Fix all issues before finishing the hotfix.');
119
- process.exit(1);
120
- }
121
- console.log('✅ Quality checks passed');
122
-
123
- // Read package.json
124
- const packageJsonPath = join(process.cwd(), 'package.json');
125
- if (!existsSync(packageJsonPath)) {
126
- console.error('No package.json found in current directory.');
127
- process.exit(1);
128
- }
129
-
130
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as {
131
- name: string;
132
- version: string;
133
- };
134
- const packageName = packageJson.name;
135
- const oldVersion = packageJson.version;
136
- const newVersion = bumpVersion(oldVersion, bumpType);
137
-
138
- console.log(`\nBumping ${packageName}: ${oldVersion} → ${newVersion}`);
139
-
140
- writeFileSync(
141
- packageJsonPath,
142
- `${JSON.stringify({ ...packageJson, version: newVersion }, null, 2)}\n`,
143
- );
144
-
145
- // Update CHANGELOG.md
146
- const changelogPath = join(process.cwd(), 'CHANGELOG.md');
147
- const today = new Date().toISOString().slice(0, 10);
148
- insertChangelog(changelogPath, `## [${newVersion}] - ${today} (hotfix)\n\n${message}\n`);
149
-
150
- // Fix formatting of modified files (package.json, CHANGELOG.md)
151
- try {
152
- runScript('fix:pkg');
153
- } catch {
154
- // fix:pkg may not exist
155
- }
156
-
157
- // Format modified files
158
- try {
159
- git('add', '-A');
160
- const changedFiles = gitRead('diff', '--cached', '--name-only').split('\n').filter(Boolean);
161
-
162
- // Format JSON files with biome
163
- for (const file of changedFiles) {
164
- if (file.endsWith('.json')) {
165
- try {
166
- execSync(`npx biome check --write ${file}`, { cwd: process.cwd(), stdio: 'inherit' });
167
- } catch {
168
- // File might not need formatting or biome not available
169
- }
170
- }
171
- }
172
-
173
- // Format markdown files with markdownlint
174
- for (const file of changedFiles) {
175
- if (file.endsWith('.md')) {
176
- try {
177
- execSync(`npx markdownlint-cli2 --fix ${file}`, { cwd: process.cwd(), stdio: 'inherit' });
178
- } catch {
179
- // File might not need formatting or markdownlint not available
180
- }
181
- }
182
- }
183
- } catch {
184
- // Formatters not available
185
- }
186
-
187
- // Commit
188
- git('add', '-A');
189
- git('commit', '-m', `chore(hotfix): ${packageName}@${newVersion}`, '-m', message);
190
-
191
- // Fetch before merging
192
- console.log('\nFetching latest state from origin...');
193
- git('fetch', 'origin');
194
-
195
- // Merge hotfix → production
196
- console.log('\nMerging hotfix into production...');
197
- git('checkout', 'production');
198
- git('pull', '--ff-only', 'origin', 'production');
199
- git(
200
- 'merge',
201
- '--no-ff',
202
- currentBranch,
203
- '-m',
204
- `chore(hotfix): merge ${currentBranch} into production`,
205
- );
206
- git('push', 'origin', 'production');
207
-
208
- // Merge production → staging
209
- console.log('\nPropagating hotfix to staging...');
210
- git('checkout', 'staging');
211
- git('pull', '--ff-only', 'origin', 'staging');
212
- git('merge', '--no-ff', 'production', '-m', 'chore(hotfix): merge production into staging');
213
- git('push', 'origin', 'staging');
214
-
215
- // Merge staging → main
216
- console.log('\nPropagating hotfix to main...');
217
- git('checkout', 'main');
218
- git('pull', '--ff-only', 'origin', 'main');
219
- git('merge', '--no-ff', 'staging', '-m', 'chore(hotfix): merge staging into main');
220
- git('push', 'origin', 'main');
221
-
222
- // Delete hotfix branch
223
- git('branch', '-d', currentBranch);
224
- try {
225
- git('push', 'origin', '--delete', currentBranch);
226
- } catch {
227
- // Remote branch may not exist if it was never pushed
228
- }
229
-
230
- console.log(`\n✅ Hotfix ${packageName}@${newVersion} shipped to production → staging → main`);
231
- console.log('You are on main and ready to keep working.');
232
- process.exit(0);
233
- }
234
-
235
- // ---------------------------------------------------------------------------
236
- // Unknown subcommand
237
- // ---------------------------------------------------------------------------
238
- console.error('Usage:');
239
- console.error(' ship-hotfix start <name>');
240
- console.error(' ship-hotfix finish <patch|minor> "description"');
241
- process.exit(1);