fg-devkit 1.12.13 → 1.14.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.
package/README.md CHANGED
@@ -102,7 +102,7 @@ Check vulnerabilities for all policy packages together (including transitive dep
102
102
  pnpm exec fgd policy-vulns
103
103
  ```
104
104
 
105
- Check vulnerabilities for all dependencies in the current repo:
105
+ Check vulnerabilities for all dependencies in the current repo (and nested packages with their own `pnpm-lock.yaml`):
106
106
 
107
107
  ```bash
108
108
  pnpm exec fgd repo-vulns
@@ -126,19 +126,28 @@ If npm audit is rate-limited (429), slow the scan down:
126
126
  pnpm exec fgd fleet-vulns --delay-ms=8000
127
127
  ```
128
128
 
129
- Upgrade policy versions interactively:
129
+ Upgrade policy versions interactively and auto-commit
130
+ (`dep(package): bump to version`, or `dep(): bump N packages` with a body listing each bump):
130
131
 
131
132
  ```bash
132
133
  pnpm exec fgd policy-upgrade
133
134
  ```
134
135
 
135
- Upgrade one package.json dependency and auto-commit (`dep(package): bump to version`):
136
+ Sync dependency policy, run pnpm install, and auto-commit (`chore(repo): sync dependency policy`):
137
+
138
+ ```bash
139
+ pnpm exec fgd sync-deps-commit
140
+ ```
141
+
142
+ Upgrade one or more package.json dependencies and auto-commit
143
+ (`dep(package): bump to version`, or `dep(): bump N packages` with a body listing each bump):
136
144
 
137
145
  ```bash
138
146
  pnpm exec fgd policy-upgrade-commit
139
147
  ```
140
148
 
141
- Fix one vulnerability override interactively and auto-commit (`vuln(package): override version`):
149
+ Fix one or more vulnerability overrides interactively and auto-commit
150
+ (`vuln(package): override version`, or `vuln(): override N packages` with a body listing each change):
142
151
 
143
152
  ```bash
144
153
  pnpm exec fgd audit-override-commit
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "toolchain": {
3
- "packageManager": "pnpm@11.20.0",
3
+ "packageManager": "pnpm@11.21.0",
4
4
  "node": {
5
5
  "nvmrc": "22",
6
6
  "engines": ">=22.13.0",
@@ -10,16 +10,17 @@
10
10
  },
11
11
  "managedDependencies": {
12
12
  "dependencies": {
13
+ "@e965/xlsx": "0.20.3",
13
14
  "@element-plus/icons-vue": "2.3.2",
14
15
  "@lexical/html": "0.49.0",
15
16
  "@lexical/list": "0.49.0",
16
17
  "@lexical/rich-text": "0.49.0",
18
+ "@lexical/link": "0.49.0",
17
19
  "@piwikpro/vue-piwik-pro": "1.7.1",
18
- "@sentry/browser": "10.69.0",
20
+ "@sentry/browser": "10.70.0",
19
21
  "@sentry/tracing": "7.120.4",
20
- "@sentry/vue": "10.69.0",
21
- "@sentry/wasm": "10.69.0",
22
- "@tailwindcss/postcss": "4.3.3",
22
+ "@sentry/vue": "10.70.0",
23
+ "@sentry/wasm": "10.70.0",
23
24
  "@tanstack/vue-query": "5.101.4",
24
25
  "@types/leaflet": "1.9.22",
25
26
  "@unhead/vue": "2.0.5",
@@ -31,7 +32,7 @@
31
32
  "chart.js": "4.5.1",
32
33
  "content-disposition-header": "0.6.0",
33
34
  "date-fns": "4.4.0",
34
- "element-plus": "2.14.3",
35
+ "element-plus": "2.14.4",
35
36
  "fds-vue-core": "8.4.3",
36
37
  "imask": "7.6.1",
37
38
  "leaflet": "1.9.4",
@@ -60,11 +61,11 @@
60
61
  "@eslint/js": "9.39.1",
61
62
  "@intlify/unplugin-vue-i18n": "11.2.4",
62
63
  "@playwright/test": "1.62.1",
63
- "@storybook/addon-a11y": "10.5.6",
64
- "@storybook/addon-docs": "10.5.6",
65
- "@storybook/addon-vitest": "10.5.6",
66
- "@storybook/vue3": "10.5.6",
67
- "@storybook/vue3-vite": "10.5.6",
64
+ "@storybook/addon-a11y": "10.5.7",
65
+ "@storybook/addon-docs": "10.5.7",
66
+ "@storybook/addon-vitest": "10.5.7",
67
+ "@storybook/vue3": "10.5.7",
68
+ "@storybook/vue3-vite": "10.5.7",
68
69
  "@tanstack/vue-query-devtools": "6.1.38",
69
70
  "@tsconfig/node22": "22.0.5",
70
71
  "@types/lodash-es": "4.17.12",
@@ -76,13 +77,12 @@
76
77
  "@vue/test-utils": "2.4.11",
77
78
  "arg": "5.0.2",
78
79
  "babel-eslint": "10.1.0",
79
- "eslint-plugin-storybook": "10.5.6",
80
+ "eslint-plugin-storybook": "10.5.7",
80
81
  "globals": "15.11.0",
81
82
  "jsdom": "26.1.0",
82
- "postcss": "8.5.26",
83
83
  "sass": "1.102.0",
84
- "storybook": "10.5.6",
85
- "tsx": "4.23.9",
84
+ "storybook": "10.5.7",
85
+ "tsx": "4.23.12",
86
86
  "vega": "6.3.1",
87
87
  "vite-plugin-dts": "4.5.4",
88
88
  "vite-plugin-vue-devtools": "8.2.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fg-devkit",
3
- "version": "1.12.13",
3
+ "version": "1.14.2",
4
4
  "description": "Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -56,6 +56,7 @@
56
56
  "./scripts/audit-override-commit.mjs": "./scripts/audit-override-commit.mjs",
57
57
  "./scripts/check-dependency-policy.mjs": "./scripts/check-dependency-policy.mjs",
58
58
  "./scripts/sync-dependency-policy.mjs": "./scripts/sync-dependency-policy.mjs",
59
+ "./scripts/sync-dependency-policy-commit.mjs": "./scripts/sync-dependency-policy-commit.mjs",
59
60
  "./scripts/resolve-dependency-policy-path.mjs": "./scripts/resolve-dependency-policy-path.mjs",
60
61
  "./scripts/refresh-dependency-policy-from-repos.mjs": "./scripts/refresh-dependency-policy-from-repos.mjs",
61
62
  "./scripts/sync-scaffold-vue-deps.mjs": "./scripts/sync-scaffold-vue-deps.mjs",
@@ -106,13 +107,13 @@
106
107
  "@inquirer/input": "5.1.2",
107
108
  "@inquirer/select": "5.2.1",
108
109
  "@intlify/eslint-plugin-vue-i18n": "4.5.1",
109
- "@typescript-eslint/eslint-plugin": "8.66.0",
110
- "@typescript-eslint/parser": "8.66.0",
111
- "@vitest/eslint-plugin": "1.6.26",
110
+ "@typescript-eslint/eslint-plugin": "8.67.0",
111
+ "@typescript-eslint/parser": "8.67.0",
112
+ "@vitest/eslint-plugin": "1.6.27",
112
113
  "@vue/eslint-config-prettier": "10.2.0",
113
114
  "@vue/eslint-config-typescript": "14.9.0",
114
115
  "@vue/tsconfig": "0.9.1",
115
- "eslint": "10.8.0",
116
+ "eslint": "10.8.1",
116
117
  "eslint-plugin-prettier": "5.5.6",
117
118
  "eslint-plugin-vue": "10.10.0",
118
119
  "fallow": "2.101.0",
@@ -120,13 +121,19 @@
120
121
  "lefthook": "2.1.10",
121
122
  "npm-check-updates": "22.2.7",
122
123
  "prettier": "3.9.6",
123
- "tsx": "4.23.9",
124
+ "tsx": "4.23.12",
124
125
  "typescript": "5.9.3",
125
126
  "vue-eslint-parser": "10.4.1",
126
127
  "vue-tsc": "3.3.9"
127
128
  },
128
129
  "devDependencies": {
129
- "cz-git": "1.13.1",
130
- "czg": "1.13.1"
130
+ "cz-git": "1.13.2",
131
+ "czg": "1.13.2"
132
+ },
133
+ "scripts": {
134
+ "maintainer-ui": "pnpm --dir electron/maintainer-ui start",
135
+ "maintainer-ui:install": "pnpm --dir electron/maintainer-ui install",
136
+ "fgd-ui": "pnpm --dir electron/maintainer-ui start",
137
+ "fgd-ui:install": "pnpm --dir electron/maintainer-ui install"
131
138
  }
132
139
  }
@@ -15,7 +15,6 @@
15
15
  "poeditor:upload": "pnpm exec fg-devkit poeditor-upload"
16
16
  },
17
17
  "dependencies": {
18
- "@tailwindcss/postcss": "4.3.3",
19
18
  "@tailwindcss/vite": "4.3.3",
20
19
  "@tanstack/vue-query": "5.101.4",
21
20
  "axios": "1.19.0",
@@ -34,12 +33,12 @@
34
33
  "@tanstack/vue-query-devtools": "6.1.38",
35
34
  "@types/node": "22.16.5",
36
35
  "@vitejs/plugin-vue": "6.0.8",
37
- "fg-devkit": "1.12.13",
36
+ "fg-devkit": "1.14.2",
38
37
  "tailwindcss": "4.3.3",
39
- "tsx": "4.23.9",
38
+ "tsx": "4.23.12",
40
39
  "vite": "7.3.5"
41
40
  },
42
- "packageManager": "pnpm@11.20.0",
41
+ "packageManager": "pnpm@11.21.0",
43
42
  "engines": {
44
43
  "node": ">=22.13.0"
45
44
  }
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Fix one vulnerability via `pnpm audit --fix override -i`, install, then auto-commit.
3
+ * Fix one or more vulnerabilities via `pnpm audit --fix override -i`, install, then auto-commit.
4
4
  *
5
5
  * Usage:
6
6
  * pnpm exec fg-devkit audit-override-commit [pnpm-audit-args...]
@@ -150,14 +150,11 @@ function main() {
150
150
  console.log('[audit-override-commit] No override changes detected.')
151
151
  process.exit(0)
152
152
  }
153
- if (changed.length > 1) {
154
- console.log('[audit-override-commit] Multiple override changes detected:')
155
- for (const item of changed) {
156
- const fromLabel = item.from ?? '(missing)'
157
- console.log(` - ${item.name}: ${fromLabel} -> ${item.to}`)
158
- }
159
- console.log('[audit-override-commit] Auto-commit supports exactly one override change. Commit manually.')
160
- process.exit(1)
153
+
154
+ console.log('[audit-override-commit] Override changes detected:')
155
+ for (const item of changed) {
156
+ const fromLabel = item.from ?? '(missing)'
157
+ console.log(` - ${item.name}: ${fromLabel} -> ${item.to}`)
161
158
  }
162
159
 
163
160
  const installExitCode = runPnpm(['install'])
@@ -165,16 +162,30 @@ function main() {
165
162
  process.exit(installExitCode)
166
163
  }
167
164
 
168
- const [only] = changed
169
165
  const stageExitCode = stageExistingFiles(['package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml'])
170
166
  if (stageExitCode !== 0) {
171
167
  process.exit(stageExitCode)
172
168
  }
173
169
 
174
- const commitMessage = `vuln(${only.name}): override ${only.to}`
175
- console.log(`[audit-override-commit] Staged override for ${only.name} -> ${only.to}`)
176
- console.log(`[audit-override-commit] Auto-committing: ${commitMessage}`)
177
- process.exit(runGit(['commit', '-m', commitMessage]))
170
+ const { subject, body } = buildCommitMessage(changed)
171
+ console.log(`[audit-override-commit] Auto-committing: ${subject}`)
172
+ if (body) {
173
+ console.log(body)
174
+ }
175
+ const commitArgs = body ? ['commit', '-m', subject, '-m', body] : ['commit', '-m', subject]
176
+ process.exit(runGit(commitArgs))
177
+ }
178
+
179
+ function buildCommitMessage(changed) {
180
+ if (changed.length === 1) {
181
+ const only = changed[0]
182
+ return { subject: `vuln(${only.name}): override ${only.to}`, body: '' }
183
+ }
184
+
185
+ const body = changed
186
+ .map((item) => `- ${item.name}: ${item.from ?? '(missing)'} -> ${item.to}`)
187
+ .join('\n')
188
+ return { subject: `vuln(): override ${changed.length} packages`, body }
178
189
  }
179
190
 
180
191
  main()
@@ -5,6 +5,7 @@
5
5
  * Non-interactive (for scripts and automation):
6
6
  * pnpm exec fg-devkit check-deps [policy-file]
7
7
  * pnpm exec fg-devkit sync-deps [policy-file]
8
+ * pnpm exec fg-devkit sync-deps-commit [policy-file]
8
9
  * pnpm exec fg-devkit policy-outdated [policy-file]
9
10
  * pnpm exec fg-devkit policy-vulns [policy-file]
10
11
  * pnpm exec fg-devkit repo-vulns
@@ -458,6 +459,7 @@ function runSyncConfigTarget(target) {
458
459
  const DIRECT_COMMANDS = {
459
460
  'check-deps': 'check-dependency-policy.mjs',
460
461
  'sync-deps': 'sync-dependency-policy.mjs',
462
+ 'sync-deps-commit': 'sync-dependency-policy-commit.mjs',
461
463
  'policy-outdated': 'policy-outdated.mjs',
462
464
  'policy-vulns': 'policy-vulns.mjs',
463
465
  'repo-vulns': 'repo-vulns.mjs',
@@ -498,9 +500,10 @@ function printHelp() {
498
500
  Commands:
499
501
  check-deps [policy-file] Validate package.json + pins + toolchain against policy
500
502
  sync-deps [policy-file] Align declared versions, packageManager, and Node toolchain to policy
503
+ sync-deps-commit [policy-file] Sync dependency policy, pnpm install, then auto-commit
501
504
  policy-outdated [policy-file] Show outdated policy packages via pnpm outdated
502
505
  policy-vulns [policy-file] Check all policy packages together (including transitives) via pnpm audit
503
- repo-vulns Check all repo dependencies for vulnerabilities via pnpm audit
506
+ repo-vulns Check repo + nested lockfile packages via pnpm audit
504
507
  fleet-vulns [projects-root] [--summary-only] [--delay-ms=<ms>]
505
508
  Run pnpm audit across Vue repos (full output + combined summary)
506
509
  fleet-bump-fg-devkit [projects-root] [--dry-run]
@@ -532,11 +535,11 @@ Commands:
532
535
  Maintainer: discard tracked git changes in chosen repositories
533
536
  Options: --dry-run, --fg-devkit-only, --pick, --all, --only=a,b
534
537
  policy-upgrade [policy-file] [ncu-args...]
535
- Upgrade policy packages via npm-check-updates (default interactive)
538
+ Upgrade policy packages via ncu (interactive) and auto-commit
536
539
  policy-upgrade-commit [ncu-args...]
537
- Upgrade one consumer package.json package and auto-commit
540
+ Upgrade one or more consumer package.json packages and auto-commit
538
541
  audit-override-commit [pnpm-audit-args...]
539
- Fix one vulnerability override via pnpm audit and auto-commit
542
+ Fix one or more vulnerability overrides via pnpm audit and auto-commit
540
543
  sync-project-configs VS Code + tooling sync (overwrites config files)
541
544
  sync-tooling-configs Tooling sync only (overwrites config files)
542
545
  sync-vscode-settings Copy shared VS Code settings into .vscode/settings.json
@@ -781,9 +784,9 @@ async function runInteractiveMenu() {
781
784
  message: 'Dependecy policy',
782
785
  choices: [
783
786
  { name: 'Check', value: 'check' },
784
- { name: 'Sync', value: 'sync' },
785
- { name: 'Upgrade one package.json package and auto-commit', value: 'upgrade-commit' },
786
- { name: 'Fix one vulnerability override and auto-commit', value: 'audit-override-commit' },
787
+ { name: 'Sync and auto-commit', value: 'sync-commit' },
788
+ { name: 'Upgrade package.json packages and auto-commit', value: 'upgrade-commit' },
789
+ { name: 'Fix vulnerability overrides and auto-commit', value: 'audit-override-commit' },
787
790
  { name: 'Cancel', value: 'cancel' },
788
791
  ],
789
792
  default: 'check',
@@ -791,7 +794,9 @@ async function runInteractiveMenu() {
791
794
  })
792
795
  if (choice === 'cancel') continue
793
796
  if (choice === 'check') return runSelectedAction(() => runNode('check-dependency-policy.mjs'))
794
- if (choice === 'sync') return runSelectedAction(() => runNode('sync-dependency-policy.mjs'))
797
+ if (choice === 'sync-commit') {
798
+ return runSelectedAction(() => runNode('sync-dependency-policy-commit.mjs'))
799
+ }
795
800
  if (choice === 'audit-override-commit') {
796
801
  return runSelectedAction(() => runNode('audit-override-commit.mjs'))
797
802
  }
@@ -852,7 +857,7 @@ async function runInteractiveMenu() {
852
857
  message: 'Maintainer',
853
858
  choices: [
854
859
  { name: 'Show outdated dependency policy packages', value: 'm1' },
855
- { name: 'Upgrade dependency policy (interactive)', value: 'm2' },
860
+ { name: 'Upgrade dependency policy (interactive) and auto-commit', value: 'm2' },
856
861
  { name: 'Refresh dependency policy from repos (and scaffold/vue package.json)', value: 'm3' },
857
862
  { name: 'Check policy vulnerabilities (audit)', value: 'm4' },
858
863
  { name: 'Check fg-devkit repo vulnerabilities', value: 'm5' },
@@ -3,47 +3,86 @@
3
3
  * Bumps fg-devkit to latest in Vue repositories, syncs dependency policy, and runs pnpm install.
4
4
  *
5
5
  * Usage:
6
- * pnpm exec fg-devkit fleet-bump-fg-devkit [projects-root] [--dry-run]
6
+ * pnpm exec fg-devkit fleet-bump-fg-devkit [projects-root] [options]
7
+ *
8
+ * Options:
9
+ * --dry-run Print planned bumps without changing files or installing
10
+ * --all Run on all matching Vue repos (default when not picking)
11
+ * --fg-devkit-only No-op for this command (fg-devkit is not a consumer of itself)
12
+ * --pick Interactive checkbox (TTY); prefer --only= from automation/UI
13
+ * --only=a,b Run only on matching repos (basename or path under projects root)
7
14
  */
8
15
 
16
+ import fs from 'node:fs'
9
17
  import path from 'node:path'
10
18
  import { spawnSync } from 'node:child_process'
11
19
  import { fileURLToPath } from 'node:url'
12
20
 
13
21
  import { collectFleetVueRepos } from './fleet-vue-repos.mjs'
22
+ import { parseFleetSelectionFlags, resolveFleetRepos } from './fleet-repo-picker.mjs'
14
23
 
15
24
  const scriptDir = path.dirname(fileURLToPath(import.meta.url))
16
25
  const cliArgs = process.argv.slice(2)
17
26
  const dryRun = cliArgs.includes('--dry-run')
18
- const projectsRootArg = cliArgs.find((a) => !a.startsWith('-'))
19
- const projectsRoot = projectsRootArg ? path.resolve(process.cwd(), projectsRootArg) : path.resolve(scriptDir, '../..')
27
+ const fgDevkitOnly = cliArgs.includes('--fg-devkit-only')
28
+ const { pick, all, only, filteredArgs: positionalArgs } = parseFleetSelectionFlags(cliArgs)
29
+ const projectsRootArg = positionalArgs.find((a) => !a.startsWith('-'))
30
+ const projectsRoot = projectsRootArg
31
+ ? path.resolve(process.cwd(), projectsRootArg)
32
+ : path.resolve(scriptDir, '../..')
33
+
34
+ const LOG_PREFIX = '[fleet-bump-fg-devkit]'
35
+
36
+ if (fgDevkitOnly) {
37
+ console.log(
38
+ `${LOG_PREFIX} Nothing to do for fg-devkit only — bump targets Vue consumer repos that depend on fg-devkit.`,
39
+ )
40
+ process.exit(0)
41
+ }
42
+
43
+ if (!fs.existsSync(projectsRoot)) {
44
+ console.error(`${LOG_PREFIX} projects root not found: ${projectsRoot}`)
45
+ process.exit(1)
46
+ }
47
+
48
+ const allRepos = collectFleetVueRepos(projectsRoot)
49
+ if (allRepos.length === 0) {
50
+ console.log(`${LOG_PREFIX} No Vue repositories with fg-devkit found under ${projectsRoot}`)
51
+ process.exit(0)
52
+ }
53
+
54
+ const uniqueRepos = await resolveFleetRepos(allRepos, projectsRoot, {
55
+ pick,
56
+ only,
57
+ all: all || (!pick && !only),
58
+ message: 'Select Vue repositories to bump fg-devkit',
59
+ })
20
60
 
21
- const uniqueRepos = collectFleetVueRepos(projectsRoot)
22
61
  if (uniqueRepos.length === 0) {
23
- console.log(`[fleet-bump-fg-devkit] No Vue repositories with fg-devkit found under ${projectsRoot}`)
62
+ console.log(`${LOG_PREFIX} No repositories selected.`)
24
63
  process.exit(0)
25
64
  }
26
65
 
27
- console.log(`[fleet-bump-fg-devkit] projectsRoot=${projectsRoot}`)
28
- console.log(`[fleet-bump-fg-devkit] repositories=${uniqueRepos.length}`)
66
+ console.log(`${LOG_PREFIX} projectsRoot=${projectsRoot}`)
67
+ console.log(`${LOG_PREFIX} repositories=${uniqueRepos.length}`)
29
68
 
30
69
  let failures = 0
31
70
  let updated = 0
32
71
 
33
72
  for (const repoDir of uniqueRepos) {
34
- const repoName = path.basename(repoDir)
73
+ const repoName = path.relative(projectsRoot, repoDir).split(path.sep).join('/') || path.basename(repoDir)
35
74
  const bumpArgs = ['up', 'fg-devkit@latest']
36
75
  const syncDepsArgs = ['exec', 'fg-devkit', 'sync-deps']
37
76
  const installArgs = ['install']
38
77
 
39
78
  if (dryRun) {
40
- console.log(`[fleet-bump-fg-devkit] DRY RUN ${repoName}: pnpm ${bumpArgs.join(' ')}`)
41
- console.log(`[fleet-bump-fg-devkit] DRY RUN ${repoName}: pnpm ${syncDepsArgs.join(' ')}`)
42
- console.log(`[fleet-bump-fg-devkit] DRY RUN ${repoName}: pnpm ${installArgs.join(' ')}`)
79
+ console.log(`${LOG_PREFIX} DRY RUN ${repoName}: pnpm ${bumpArgs.join(' ')}`)
80
+ console.log(`${LOG_PREFIX} DRY RUN ${repoName}: pnpm ${syncDepsArgs.join(' ')}`)
81
+ console.log(`${LOG_PREFIX} DRY RUN ${repoName}: pnpm ${installArgs.join(' ')}`)
43
82
  continue
44
83
  }
45
84
 
46
- console.log(`\n[fleet-bump-fg-devkit] Updating ${repoName}`)
85
+ console.log(`\n${LOG_PREFIX} Updating ${repoName}`)
47
86
  const bump = spawnSync('pnpm', bumpArgs, {
48
87
  cwd: repoDir,
49
88
  stdio: 'inherit',
@@ -56,14 +95,14 @@ for (const repoDir of uniqueRepos) {
56
95
 
57
96
  if (bump.error) {
58
97
  failures += 1
59
- console.error(`[fleet-bump-fg-devkit] FAIL ${repoName}: ${bump.error.message}`)
98
+ console.error(`${LOG_PREFIX} FAIL ${repoName}: ${bump.error.message}`)
60
99
  continue
61
100
  }
62
101
 
63
102
  const bumpStatus = bump.status ?? 1
64
103
  if (bumpStatus !== 0) {
65
104
  failures += 1
66
- console.error(`[fleet-bump-fg-devkit] FAIL ${repoName}: pnpm up exited with code ${bumpStatus}`)
105
+ console.error(`${LOG_PREFIX} FAIL ${repoName}: pnpm up exited with code ${bumpStatus}`)
67
106
  continue
68
107
  }
69
108
 
@@ -79,14 +118,14 @@ for (const repoDir of uniqueRepos) {
79
118
 
80
119
  if (syncDeps.error) {
81
120
  failures += 1
82
- console.error(`[fleet-bump-fg-devkit] FAIL ${repoName}: ${syncDeps.error.message}`)
121
+ console.error(`${LOG_PREFIX} FAIL ${repoName}: ${syncDeps.error.message}`)
83
122
  continue
84
123
  }
85
124
 
86
125
  const syncDepsStatus = syncDeps.status ?? 1
87
126
  if (syncDepsStatus !== 0) {
88
127
  failures += 1
89
- console.error(`[fleet-bump-fg-devkit] FAIL ${repoName}: sync-deps exited with code ${syncDepsStatus}`)
128
+ console.error(`${LOG_PREFIX} FAIL ${repoName}: sync-deps exited with code ${syncDepsStatus}`)
90
129
  continue
91
130
  }
92
131
 
@@ -102,20 +141,20 @@ for (const repoDir of uniqueRepos) {
102
141
 
103
142
  if (install.error) {
104
143
  failures += 1
105
- console.error(`[fleet-bump-fg-devkit] FAIL ${repoName}: ${install.error.message}`)
144
+ console.error(`${LOG_PREFIX} FAIL ${repoName}: ${install.error.message}`)
106
145
  continue
107
146
  }
108
147
 
109
148
  const status = install.status ?? 1
110
149
  if (status !== 0) {
111
150
  failures += 1
112
- console.error(`[fleet-bump-fg-devkit] FAIL ${repoName}: pnpm install exited with code ${status}`)
151
+ console.error(`${LOG_PREFIX} FAIL ${repoName}: pnpm install exited with code ${status}`)
113
152
  continue
114
153
  }
115
154
 
116
155
  updated += 1
117
- console.log(`[fleet-bump-fg-devkit] OK ${repoName}`)
156
+ console.log(`${LOG_PREFIX} OK ${repoName}`)
118
157
  }
119
158
 
120
- console.log(`\n[fleet-bump-fg-devkit] Done: updated=${updated}, failed=${failures}`)
159
+ console.log(`\n${LOG_PREFIX} Done: updated=${updated}, failed=${failures}`)
121
160
  process.exit(failures > 0 ? 1 : 0)
@@ -4,7 +4,7 @@
4
4
  * pnpm audit output and a combined summary.
5
5
  *
6
6
  * Usage:
7
- * pnpm exec fg-devkit fleet-vulns [projects-root] [--summary-only] [--delay-ms=<ms>]
7
+ * pnpm exec fg-devkit fleet-vulns [projects-root] [--summary-only] [--delay-ms=<ms>] [--dry-run] [--only=a,b]
8
8
  */
9
9
 
10
10
  import fs from 'node:fs'
@@ -12,10 +12,13 @@ import path from 'node:path'
12
12
  import { spawnSync } from 'node:child_process'
13
13
  import { fileURLToPath } from 'node:url'
14
14
  import { isFgDevkitRepoDir } from './fleet-project-repos.mjs'
15
+ import { filterReposByOnly, parseFleetOnlyArg } from './fleet-repo-picker.mjs'
15
16
 
16
17
  const scriptDir = path.dirname(fileURLToPath(import.meta.url))
17
18
  const cliArgs = process.argv.slice(2)
18
19
  const summaryOnly = cliArgs.includes('--summary-only')
20
+ const dryRun = cliArgs.includes('--dry-run')
21
+ const only = parseFleetOnlyArg(cliArgs)
19
22
  const projectsRootArg = cliArgs.find((a) => !a.startsWith('-'))
20
23
  const projectsRoot = projectsRootArg ? path.resolve(process.cwd(), projectsRootArg) : path.resolve(scriptDir, '../..')
21
24
  const delayArg = cliArgs.find((a) => a.startsWith('--delay-ms='))
@@ -63,7 +66,16 @@ for (const packageJsonPath of packageJsonFiles) {
63
66
  }
64
67
  }
65
68
 
66
- const uniqueRepos = [...new Set(repos)].sort((a, b) => a.localeCompare(b))
69
+ const uniqueReposAll = [...new Set(repos)].sort((a, b) => a.localeCompare(b))
70
+ let uniqueRepos = uniqueReposAll
71
+ if (only?.length) {
72
+ uniqueRepos = filterReposByOnly(uniqueReposAll, projectsRoot, only)
73
+ if (uniqueRepos.length === 0) {
74
+ console.error(`[fleet-vulns] No repositories matched --only=${only.join(',')}`)
75
+ process.exit(1)
76
+ }
77
+ }
78
+
67
79
  if (uniqueRepos.length === 0) {
68
80
  console.log(`[fleet-vulns] No pnpm repositories found under ${projectsRoot}`)
69
81
  process.exit(0)
@@ -72,6 +84,16 @@ if (uniqueRepos.length === 0) {
72
84
  console.log(`[fleet-vulns] projectsRoot=${projectsRoot}`)
73
85
  console.log(`[fleet-vulns] repositories=${uniqueRepos.length}`)
74
86
 
87
+ if (dryRun) {
88
+ console.log('[fleet-vulns] DRY RUN — would audit:')
89
+ for (const repoDir of uniqueRepos) {
90
+ const rel = path.relative(projectsRoot, repoDir).split(path.sep).join('/') || path.basename(repoDir)
91
+ const hasLock = fs.existsSync(path.join(repoDir, 'pnpm-lock.yaml'))
92
+ console.log(` - ${rel}${hasLock ? '' : ' (missing pnpm-lock.yaml → skip)'}`)
93
+ }
94
+ process.exit(0)
95
+ }
96
+
75
97
  const results = []
76
98
  let hasFailures = false
77
99
  let hasVulnerabilities = false
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Upgrade one package in the consumer package.json, then auto-commit.
3
+ * Upgrade one or more packages in the consumer package.json, then auto-commit.
4
4
  *
5
5
  * Usage:
6
6
  * pnpm exec fg-devkit policy-upgrade-commit [ncu-args...]
@@ -87,6 +87,21 @@ function collectPackageVersionChanges(beforePackage, afterPackage) {
87
87
  return changed
88
88
  }
89
89
 
90
+ /** ncu can upgrade package.json `packageManager` (e.g. pnpm@x.y.z); treat as one bump. */
91
+ function collectPackageManagerChange(beforePackage, afterPackage) {
92
+ const before = beforePackage.packageManager
93
+ const after = afterPackage.packageManager
94
+ if (after === undefined || after === before) {
95
+ return null
96
+ }
97
+ const match = typeof after === 'string' ? after.match(/^pnpm@(.+)$/i) : null
98
+ return {
99
+ name: 'pnpm',
100
+ from: before ?? '(missing)',
101
+ to: match ? match[1] : after,
102
+ }
103
+ }
104
+
90
105
  function main() {
91
106
  if (!fs.existsSync(packageJsonPath)) {
92
107
  console.error(`[policy-upgrade-commit] package.json not found at ${packageJsonPath}`)
@@ -115,29 +130,43 @@ function main() {
115
130
  }
116
131
 
117
132
  const changed = collectPackageVersionChanges(beforePackage, afterPackage)
133
+ const packageManagerChange = collectPackageManagerChange(beforePackage, afterPackage)
134
+ if (packageManagerChange) {
135
+ changed.push(packageManagerChange)
136
+ }
137
+
118
138
  if (changed.length === 0) {
119
139
  console.log('[policy-upgrade-commit] No package version changes detected in package.json.')
120
140
  process.exit(0)
121
141
  }
122
- if (changed.length > 1) {
123
- console.log('[policy-upgrade-commit] Multiple package changes detected in package.json:')
124
- for (const item of changed) {
125
- console.log(` - ${item.name}: ${item.from} -> ${item.to}`)
126
- }
127
- console.log('[policy-upgrade-commit] Auto-commit supports exactly one changed package. Commit manually.')
128
- process.exit(1)
142
+
143
+ console.log('[policy-upgrade-commit] Package version changes detected in package.json:')
144
+ for (const item of changed) {
145
+ console.log(` - ${item.name}: ${item.from} -> ${item.to}`)
129
146
  }
130
147
 
131
- const [only] = changed
132
148
  const stageExitCode = stageExistingFiles(['package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml'])
133
149
  if (stageExitCode !== 0) {
134
150
  process.exit(stageExitCode)
135
151
  }
136
152
 
137
- const commitMessage = `dep(${only.name}): bump to ${only.to}`
138
- console.log(`[policy-upgrade-commit] Staged changes for ${only.name} -> ${only.to}`)
139
- console.log(`[policy-upgrade-commit] Auto-committing: ${commitMessage}`)
140
- process.exit(runGit(['commit', '-m', commitMessage]))
153
+ const { subject, body } = buildCommitMessage(changed)
154
+ console.log(`[policy-upgrade-commit] Auto-committing: ${subject}`)
155
+ if (body) {
156
+ console.log(body)
157
+ }
158
+ const commitArgs = body ? ['commit', '-m', subject, '-m', body] : ['commit', '-m', subject]
159
+ process.exit(runGit(commitArgs))
160
+ }
161
+
162
+ function buildCommitMessage(changed) {
163
+ if (changed.length === 1) {
164
+ const only = changed[0]
165
+ return { subject: `dep(${only.name}): bump to ${only.to}`, body: '' }
166
+ }
167
+
168
+ const body = changed.map((item) => `- ${item.name}: ${item.from} -> ${item.to}`).join('\n')
169
+ return { subject: `dep(): bump ${changed.length} packages`, body }
141
170
  }
142
171
 
143
172
  main()
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Upgrades dependency policy package versions through npm-check-updates.
4
- * It projects the policy into a temporary package.json, runs ncu, then writes
5
- * selected versions back to the policy file.
3
+ * Upgrades dependency policy package versions through npm-check-updates, then auto-commits.
4
+ * It projects the policy into a temporary package.json, runs ncu, writes selected versions
5
+ * back to the policy file, syncs scaffold, and commits.
6
6
  *
7
7
  * Usage:
8
8
  * pnpm exec fg-devkit policy-upgrade [policy-file] [ncu-args...]
@@ -22,6 +22,7 @@ import { syncScaffoldVueDepsFromPolicy } from './sync-scaffold-vue-deps.mjs'
22
22
 
23
23
  const require = createRequire(import.meta.url)
24
24
  const scriptDir = path.dirname(fileURLToPath(import.meta.url))
25
+ const fgDevkitRoot = path.resolve(scriptDir, '..')
25
26
 
26
27
  if (process.argv.includes('--help') || process.argv.includes('-h')) {
27
28
  console.log(`Usage:
@@ -42,7 +43,60 @@ function readJson(p) {
42
43
  return JSON.parse(fs.readFileSync(p, 'utf8'))
43
44
  }
44
45
 
46
+ function collectPolicyVersions(policy) {
47
+ return {
48
+ ...(policy.managedDependencies?.dependencies ?? {}),
49
+ ...(policy.managedDependencies?.devDependencies ?? {}),
50
+ ...(policy.managedAnywhere ?? {}),
51
+ }
52
+ }
53
+
54
+ function collectVersionChanges(before, after) {
55
+ const changed = []
56
+ for (const [name, newVersion] of Object.entries(after)) {
57
+ const previousVersion = before[name]
58
+ if (previousVersion !== undefined && previousVersion !== newVersion) {
59
+ changed.push({ name, from: previousVersion, to: newVersion })
60
+ }
61
+ }
62
+ return changed
63
+ }
64
+
65
+ function buildCommitMessage(changed) {
66
+ if (changed.length === 1) {
67
+ const only = changed[0]
68
+ return { subject: `dep(${only.name}): bump to ${only.to}`, body: '' }
69
+ }
70
+
71
+ const body = changed.map((item) => `- ${item.name}: ${item.from} -> ${item.to}`).join('\n')
72
+ return { subject: `dep(): bump ${changed.length} packages`, body }
73
+ }
74
+
75
+ function runGit(args) {
76
+ const result = spawnSync('git', args, {
77
+ stdio: 'inherit',
78
+ cwd: fgDevkitRoot,
79
+ env: process.env,
80
+ })
81
+ if (result.error) {
82
+ console.error('[policy-upgrade]', result.error.message)
83
+ return 1
84
+ }
85
+ return result.status ?? 1
86
+ }
87
+
88
+ function stageExistingFiles(files) {
89
+ const existingFiles = files.filter((filePath) => fs.existsSync(path.join(fgDevkitRoot, filePath)))
90
+ if (existingFiles.length === 0) return 0
91
+ return runGit(['add', '--', ...existingFiles])
92
+ }
93
+
94
+ function toRepoRelative(absolutePath) {
95
+ return path.relative(fgDevkitRoot, absolutePath)
96
+ }
97
+
45
98
  const policy = readJson(policyPath)
99
+ const beforeVersions = collectPolicyVersions(policy)
46
100
 
47
101
  const depNames = new Set(Object.keys(policy.managedDependencies?.dependencies ?? {}))
48
102
  const devNames = new Set(Object.keys(policy.managedDependencies?.devDependencies ?? {}))
@@ -115,6 +169,34 @@ for (const [name, version] of Object.entries(updatedDevDeps)) {
115
169
  }
116
170
 
117
171
  fs.writeFileSync(policyPath, `${JSON.stringify(policy, null, 2)}\n`, 'utf8')
118
- const fgDevkitRoot = path.resolve(scriptDir, '..')
119
172
  syncScaffoldVueDepsFromPolicy({ fgDevkitRoot, policyPath })
120
- console.log('[policy-upgrade] Updated dependency policy from selected ncu changes.')
173
+
174
+ const afterPolicy = readJson(policyPath)
175
+ const changed = collectVersionChanges(beforeVersions, collectPolicyVersions(afterPolicy))
176
+
177
+ if (changed.length === 0) {
178
+ console.log('[policy-upgrade] No package version changes detected in dependency policy.')
179
+ process.exit(0)
180
+ }
181
+
182
+ console.log('[policy-upgrade] Package version changes detected in dependency policy:')
183
+ for (const item of changed) {
184
+ console.log(` - ${item.name}: ${item.from} -> ${item.to}`)
185
+ }
186
+
187
+ const stageExitCode = stageExistingFiles([
188
+ toRepoRelative(policyPath),
189
+ 'scaffold/vue/package.json',
190
+ 'scaffold/vue/Dockerfile.local',
191
+ ])
192
+ if (stageExitCode !== 0) {
193
+ process.exit(stageExitCode)
194
+ }
195
+
196
+ const { subject, body } = buildCommitMessage(changed)
197
+ console.log(`[policy-upgrade] Auto-committing: ${subject}`)
198
+ if (body) {
199
+ console.log(body)
200
+ }
201
+ const commitArgs = body ? ['commit', '-m', subject, '-m', body] : ['commit', '-m', subject]
202
+ process.exit(runGit(commitArgs))
@@ -1,26 +1,83 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * Checks vulnerabilities for the full dependency graph in the current repository
4
- * by running `pnpm audit` in the working directory.
4
+ * by running `pnpm audit` in the working directory and any nested packages that
5
+ * have their own pnpm-lock.yaml (e.g. electron/maintainer-ui in fg-devkit).
5
6
  *
6
7
  * Usage:
7
8
  * pnpm exec fg-devkit repo-vulns
8
9
  */
9
10
 
11
+ import fs from 'node:fs'
12
+ import path from 'node:path'
10
13
  import { spawnSync } from 'node:child_process'
11
14
 
12
- console.log(`[repo-vulns] cwd=${process.cwd()}`)
13
- const audit = spawnSync('pnpm', ['audit'], {
14
- cwd: process.cwd(),
15
- stdio: 'inherit',
16
- env: process.env,
17
- })
18
- if (audit.error) {
19
- console.error('[repo-vulns]', audit.error.message)
20
- process.exit(1)
15
+ const root = process.cwd()
16
+
17
+ const SKIP_DIR_NAMES = new Set([
18
+ 'node_modules',
19
+ '.git',
20
+ '.next',
21
+ 'dist',
22
+ 'build',
23
+ 'coverage',
24
+ 'storybook-static',
25
+ ])
26
+
27
+ /**
28
+ * @param {string} dir
29
+ * @param {string[]} [acc]
30
+ * @returns {string[]}
31
+ */
32
+ function findNestedLockfileDirs(dir, acc = []) {
33
+ for (const item of fs.readdirSync(dir, { withFileTypes: true })) {
34
+ if (!item.isDirectory()) continue
35
+ if (SKIP_DIR_NAMES.has(item.name) || item.name.startsWith('.')) continue
36
+ const child = path.join(dir, item.name)
37
+ if (
38
+ fs.existsSync(path.join(child, 'pnpm-lock.yaml')) &&
39
+ fs.existsSync(path.join(child, 'package.json'))
40
+ ) {
41
+ acc.push(child)
42
+ }
43
+ findNestedLockfileDirs(child, acc)
44
+ }
45
+ return acc
21
46
  }
22
- // pnpm audit returns exit code 1 when vulnerabilities are found.
23
- if ((audit.status ?? 1) === 1) {
24
- process.exit(0)
47
+
48
+ /**
49
+ * @param {string} dir
50
+ * @param {string} label
51
+ * @returns {number}
52
+ */
53
+ function auditDir(dir, label) {
54
+ console.log(`\n[repo-vulns] Auditing ${label}`)
55
+ console.log(`[repo-vulns] cwd=${dir}`)
56
+ const audit = spawnSync('pnpm', ['audit'], {
57
+ cwd: dir,
58
+ stdio: 'inherit',
59
+ env: process.env,
60
+ })
61
+ if (audit.error) {
62
+ console.error('[repo-vulns]', audit.error.message)
63
+ return 1
64
+ }
65
+ return audit.status ?? 1
25
66
  }
26
- process.exit(audit.status ?? 1)
67
+
68
+ const nested = findNestedLockfileDirs(root).sort((a, b) => a.localeCompare(b))
69
+ const targets = [root, ...nested]
70
+
71
+ console.log(`[repo-vulns] packages=${targets.length}`)
72
+
73
+ let worstFailure = 0
74
+
75
+ for (const dir of targets) {
76
+ const label = dir === root ? '.' : path.relative(root, dir).split(path.sep).join('/')
77
+ const code = auditDir(dir, label)
78
+ // pnpm audit returns exit code 1 when vulnerabilities are found — treat as ok.
79
+ if (code === 0 || code === 1) continue
80
+ worstFailure = code || 1
81
+ }
82
+
83
+ process.exit(worstFailure)
@@ -2,7 +2,7 @@
2
2
  * Resolves which dependency policy JSON file check/sync scripts should load.
3
3
  *
4
4
  * Used by check-dependency-policy.mjs and sync-dependency-policy.mjs so both tools share one rule:
5
- * optional argv[2] override, otherwise the packaged default next to this package.
5
+ * optional argv[2] override (ignored when it looks like a CLI flag), otherwise the packaged default.
6
6
  */
7
7
 
8
8
  import fs from 'node:fs'
@@ -17,8 +17,10 @@ const DEFAULT_POLICY = 'dependency-policy.vue-workspace.json'
17
17
  * - Relative path: if it exists under cwd, use it; else fg-devkit/configs/<arg>
18
18
  */
19
19
  export function resolveDependencyPolicyPath(scriptDir, cwd, argv) {
20
+ // Optional policy path is argv[2] only when it is not an option flag
21
+ // (e.g. `policy-upgrade --interactive` must use the default policy file).
20
22
  const arg = argv[2]
21
- if (!arg) {
23
+ if (!arg || arg.startsWith('-')) {
22
24
  return path.resolve(scriptDir, '../configs', DEFAULT_POLICY)
23
25
  }
24
26
  if (path.isAbsolute(arg)) {
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Sync dependency policy into the consumer repo, run pnpm install, then auto-commit.
4
+ *
5
+ * Usage:
6
+ * pnpm exec fg-devkit sync-deps-commit [policy-file]
7
+ */
8
+
9
+ import fs from 'node:fs'
10
+ import path from 'node:path'
11
+ import { fileURLToPath } from 'node:url'
12
+ import { spawnSync } from 'node:child_process'
13
+
14
+ const cwd = process.cwd()
15
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url))
16
+ const syncScriptPath = path.join(scriptDir, 'sync-dependency-policy.mjs')
17
+ const commitMessage = 'chore(repo): sync dependency policy'
18
+
19
+ function runSync(args) {
20
+ const result = spawnSync(process.execPath, [syncScriptPath, ...args], {
21
+ encoding: 'utf8',
22
+ cwd,
23
+ env: process.env,
24
+ })
25
+ if (result.stdout) process.stdout.write(result.stdout)
26
+ if (result.stderr) process.stderr.write(result.stderr)
27
+ if (result.error) {
28
+ console.error('[sync-deps-commit]', result.error.message)
29
+ return { status: 1, stdout: '' }
30
+ }
31
+ return { status: result.status ?? 1, stdout: result.stdout ?? '' }
32
+ }
33
+
34
+ function runPnpm(args) {
35
+ const result = spawnSync('pnpm', args, {
36
+ stdio: 'inherit',
37
+ cwd,
38
+ env: process.env,
39
+ })
40
+ if (result.error) {
41
+ console.error('[sync-deps-commit]', result.error.message)
42
+ return 1
43
+ }
44
+ return result.status ?? 1
45
+ }
46
+
47
+ function runGit(args, options = {}) {
48
+ const result = spawnSync('git', args, {
49
+ stdio: options.capture ? 'pipe' : 'inherit',
50
+ encoding: options.capture ? 'utf8' : undefined,
51
+ cwd,
52
+ env: process.env,
53
+ })
54
+ if (result.error) {
55
+ console.error('[sync-deps-commit]', result.error.message)
56
+ return { status: 1, stdout: '' }
57
+ }
58
+ return { status: result.status ?? 1, stdout: result.stdout ?? '' }
59
+ }
60
+
61
+ function listTrackedFiles() {
62
+ const result = runGit(['ls-files', '-z'], { capture: true })
63
+ if (result.status !== 0) return []
64
+ return result.stdout.split('\0').filter(Boolean)
65
+ }
66
+
67
+ function isSyncRelatedPath(filePath) {
68
+ const base = path.basename(filePath)
69
+ if (
70
+ base === 'package.json' ||
71
+ base === 'pnpm-lock.yaml' ||
72
+ base === 'pnpm-workspace.yaml' ||
73
+ base === '.nvmrc' ||
74
+ base === '.node-version' ||
75
+ base === 'Dockerfile' ||
76
+ base === 'Dockerfile.local' ||
77
+ base === 'Jenkinsfile'
78
+ ) {
79
+ return true
80
+ }
81
+ if (filePath.includes(`${path.sep}.github${path.sep}workflows${path.sep}`) || filePath.startsWith('.github/workflows/')) {
82
+ return /\.(ya?ml)$/i.test(base)
83
+ }
84
+ return base.endsWith('.sh')
85
+ }
86
+
87
+ function fileDiffersFromHead(filePath) {
88
+ const absolutePath = path.join(cwd, filePath)
89
+ if (!fs.existsSync(absolutePath)) return false
90
+
91
+ const tracked = runGit(['ls-files', '--error-unmatch', '--', filePath], { capture: true })
92
+ if (tracked.status !== 0) {
93
+ return true
94
+ }
95
+
96
+ const diff = runGit(['diff', '--quiet', 'HEAD', '--', filePath], { capture: true })
97
+ return diff.status !== 0
98
+ }
99
+
100
+ function stageExistingFiles(files) {
101
+ const existingFiles = files.filter((filePath) => fs.existsSync(path.join(cwd, filePath)))
102
+ if (existingFiles.length === 0) return 0
103
+ return runGit(['add', '--', ...existingFiles]).status
104
+ }
105
+
106
+ function main() {
107
+ const syncResult = runSync(process.argv.slice(2))
108
+ if (syncResult.status !== 0) {
109
+ process.exit(syncResult.status)
110
+ }
111
+
112
+ if (syncResult.stdout.includes('already match dependency policy')) {
113
+ console.log('[sync-deps-commit] Nothing to install or commit.')
114
+ process.exit(0)
115
+ }
116
+
117
+ const installExitCode = runPnpm(['install'])
118
+ if (installExitCode !== 0) {
119
+ process.exit(installExitCode)
120
+ }
121
+
122
+ const candidateFiles = new Set([
123
+ 'package.json',
124
+ 'pnpm-lock.yaml',
125
+ 'pnpm-workspace.yaml',
126
+ '.nvmrc',
127
+ '.node-version',
128
+ 'Dockerfile',
129
+ 'Dockerfile.local',
130
+ 'Jenkinsfile',
131
+ ])
132
+ for (const filePath of listTrackedFiles()) {
133
+ if (isSyncRelatedPath(filePath)) {
134
+ candidateFiles.add(filePath)
135
+ }
136
+ }
137
+
138
+ const filesToStage = [...candidateFiles].filter((filePath) => fileDiffersFromHead(filePath))
139
+ if (filesToStage.length === 0) {
140
+ console.log('[sync-deps-commit] No sync-related changes to commit.')
141
+ process.exit(0)
142
+ }
143
+
144
+ const stageExitCode = stageExistingFiles(filesToStage)
145
+ if (stageExitCode !== 0) {
146
+ process.exit(stageExitCode)
147
+ }
148
+
149
+ console.log(`[sync-deps-commit] Staged ${filesToStage.length} file(s)`)
150
+ console.log(`[sync-deps-commit] Auto-committing: ${commitMessage}`)
151
+ process.exit(runGit(['commit', '-m', commitMessage]).status)
152
+ }
153
+
154
+ main()