fg-devkit 1.0.0 → 1.1.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.
package/README.md CHANGED
@@ -4,10 +4,66 @@ Shared settings and tools to improve the developer experience for Vue and TypeSc
4
4
 
5
5
  ## Quick command alias (zsh)
6
6
 
7
- To run `fg` instead of `pnpm exec fg`, add this alias:
7
+ To run `fgd` instead of `pnpm exec fg-devkit`, add this alias:
8
8
 
9
9
  ```bash
10
- echo "alias fg='pnpm exec fg'" >> ~/.zshrc && source ~/.zshrc
10
+ echo "alias fgd='pnpm exec fg-devkit'" >> ~/.zshrc && source ~/.zshrc
11
11
  ```
12
12
 
13
13
  This works in repos where `fg-devkit` is installed.
14
+
15
+ ## Bundled ESLint stack
16
+
17
+ `fg-devkit` ships its own ESLint stack (core + parser + plugins), so consuming repos do not need to install ESLint packages just to lint with the shared config.
18
+
19
+ Run lint via CLI:
20
+
21
+ ```bash
22
+ pnpm exec fgd lint .
23
+ pnpm exec fgd lint-fix .
24
+ ```
25
+
26
+ ## Bundled Prettier
27
+
28
+ `fg-devkit` also ships Prettier, so consuming repos can format using the bundled package.
29
+
30
+ Run formatting via CLI:
31
+
32
+ ```bash
33
+ pnpm exec fgd format
34
+ pnpm exec fgd format-check
35
+ ```
36
+
37
+ ## Bundled TypeScript
38
+
39
+ `fg-devkit` ships `vue-tsc` and `typescript`, so consuming repos can run Vue typecheck without installing local TS tooling.
40
+
41
+ Run typecheck via CLI:
42
+
43
+ ```bash
44
+ pnpm exec fgd typecheck
45
+ pnpm exec fgd typecheck-watch
46
+ ```
47
+
48
+ ## tsconfig in consuming repos
49
+
50
+ Use `fgd sync-project-configs` (or `fgd sync-tooling-configs`) to write the local `tsconfig.json` template from `fg-devkit`.
51
+
52
+ Do not use an extends-only `tsconfig.json` to `fg-devkit/tsconfig.app.sync.json` in consuming repos.
53
+ TypeScript resolves `include`/`exclude` relative to the extended config file location in `node_modules`,
54
+ which can cause `No inputs were found`.
55
+
56
+ The supported approach is: keep a local `tsconfig.json` file in each consuming repo and let sync overwrite
57
+ it with the shared app template.
58
+
59
+ ## Minimal local Prettier config for consuming repos
60
+
61
+ Use this as your local `prettier.config.js` to inherit defaults from `fg-devkit`:
62
+
63
+ ```js
64
+ import basePrettierConfig from 'fg-devkit/prettier.config.js'
65
+
66
+ export default {
67
+ ...basePrettierConfig,
68
+ }
69
+ ```
@@ -3,8 +3,10 @@
3
3
 
4
4
  import tseslint from '@typescript-eslint/eslint-plugin'
5
5
  import tsparser from '@typescript-eslint/parser'
6
+ import pluginI18n from '@intlify/eslint-plugin-vue-i18n'
6
7
  import pluginVitest from '@vitest/eslint-plugin'
7
8
  import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
9
+ import pluginPrettier from 'eslint-plugin-prettier'
8
10
  import pluginVue from 'eslint-plugin-vue'
9
11
  import { globalIgnores } from 'eslint/config'
10
12
  import vueParser from 'vue-eslint-parser'
@@ -23,9 +25,6 @@ export default function createBaseConfig(options = {}) {
23
25
  additionalSettings = {},
24
26
  } = options
25
27
 
26
- // Note: Optional plugins should be imported by the consuming project
27
- // This config accepts them via additionalPlugins option
28
-
29
28
  const defaultAdditionalIgnores = [
30
29
  'test-results/**',
31
30
  'playwright-report/**',
@@ -130,6 +129,8 @@ export default function createBaseConfig(options = {}) {
130
129
  files: ['**/*.vue', '**/*.js', '**/*.jsx', '**/*.cjs', '**/*.mjs', '**/*.ts', '**/*.tsx', '**/*.cts', '**/*.mts'],
131
130
  plugins: {
132
131
  '@typescript-eslint': tseslint,
132
+ ...(enablePrettier ? { prettier: pluginPrettier } : {}),
133
+ ...(enableI18n ? { '@intlify/vue-i18n': pluginI18n } : {}),
133
134
  ...additionalPlugins,
134
135
  },
135
136
  settings: {
@@ -172,12 +173,13 @@ export default function createBaseConfig(options = {}) {
172
173
  'no-useless-return': 'error',
173
174
  'no-useless-concat': 'error',
174
175
  '@typescript-eslint/no-unused-vars': [
175
- 'error',
176
+ 'warn',
176
177
  {
177
178
  argsIgnorePattern: '^_',
178
179
  varsIgnorePattern: '^_',
179
180
  },
180
181
  ],
182
+ 'padding-line-between-statements': ['error', { blankLine: 'always', prev: 'export', next: 'export' }],
181
183
  '@typescript-eslint/ban-ts-comment': 'off',
182
184
  '@typescript-eslint/explicit-function-return-type': 'off',
183
185
  '@typescript-eslint/no-var-requires': 'off',
@@ -197,9 +199,9 @@ export default function createBaseConfig(options = {}) {
197
199
  'eol-last': 'error',
198
200
  'no-lonely-if': 'error',
199
201
  // Prettier integration (if enabled and plugin provided)
200
- ...(enablePrettier && additionalPlugins.prettier ? { 'prettier/prettier': 'warn' } : {}),
202
+ ...(enablePrettier ? { 'prettier/prettier': 'warn' } : {}),
201
203
  // i18n rules (if enabled and plugin provided)
202
- ...(enableI18n && additionalPlugins['@intlify/vue-i18n']
204
+ ...(enableI18n
203
205
  ? {
204
206
  '@intlify/vue-i18n/no-missing-keys': 'error',
205
207
  '@intlify/vue-i18n/no-raw-text': [
@@ -1,7 +1,6 @@
1
1
  /**
2
- * Minimal ESLint flat config for apps using fg-devkit.
3
- * Copied to eslint.config.js by sync-tooling-configs / sync-project-configs.
4
- * Customize locally (plugins, rules) or pass options via createBaseConfig after syncing.
2
+ * ESLint sync template for Vue apps using fg-devkit.
3
+ * Mirrors the previously used project defaults so sync preserves current behavior.
5
4
  */
6
5
  import createBaseConfig from 'fg-devkit/eslint.config.base.js'
7
6
  import { fileURLToPath } from 'node:url'
@@ -9,11 +8,12 @@ import { fileURLToPath } from 'node:url'
9
8
  const tsconfigRootDir = fileURLToPath(new URL('.', import.meta.url))
10
9
 
11
10
  export default [
12
- {
13
- ignores: ['.yalc/**', '**/node_modules/**'],
14
- },
15
11
  ...createBaseConfig({
16
12
  tsconfigRootDir,
17
13
  tsconfigFiles: ['./tsconfig.json'],
14
+ extraNonTypeAwareFiles: ['playwright.config.ts', 'poeditor/**/*.ts'],
15
+ enablePrettier: true,
16
+ enableI18n: true,
17
+ i18nLocaleDir: './src/lang/*.json',
18
18
  }),
19
19
  ]
@@ -0,0 +1,6 @@
1
+ // Extend shared Prettier config from fg-devkit
2
+ import basePrettierConfig from 'fg-devkit/prettier.config.js'
3
+
4
+ export default {
5
+ ...basePrettierConfig,
6
+ }
@@ -1,38 +1,14 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/tsconfig",
3
3
  "extends": "fg-devkit/tsconfig.base.json",
4
- "include": [
5
- "env.d.ts",
6
- "src/**/*",
7
- "src/**/*.vue",
8
- "src/**/*.ts",
9
- "src/**/*.d.ts",
10
- "src/vuex.d.ts"
11
- ],
4
+ "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "src/**/*.ts", "src/**/*.d.ts", "src/vuex.d.ts"],
12
5
  "exclude": ["src/**/__tests__/*"],
13
6
  "compilerOptions": {
14
- "strict": true,
15
- "composite": true,
16
- "noEmit": true,
17
7
  "types": ["@intlify/unplugin-vue-i18n/messages", "vue-i18n", "vite/client"],
18
- "moduleResolution": "bundler",
19
- "resolvePackageJsonExports": true,
20
8
  "paths": {
21
9
  "@/*": ["./src/*"],
22
10
  "@intlify/*": ["./node_modules/@intlify/*"]
23
11
  },
24
- "baseUrl": ".",
25
- "allowJs": true,
26
- "esModuleInterop": true,
27
- "allowSyntheticDefaultImports": true,
28
- "noUnusedLocals": true,
29
- "noUnusedParameters": true,
30
- "skipLibCheck": true,
31
- "preserveSymlinks": false
32
- },
33
- "vueCompilerOptions": {
34
- "strictTemplates": true,
35
- "experimentalCompatMode": 2,
36
- "types": ["fds-vue-core"]
12
+ "baseUrl": "."
37
13
  }
38
14
  }
@@ -2,17 +2,28 @@
2
2
  "$schema": "https://json.schemastore.org/tsconfig",
3
3
  "extends": "@vue/tsconfig/tsconfig.dom.json",
4
4
  "compilerOptions": {
5
+ "target": "ES2022",
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "strict": true,
8
+ "moduleResolution": "bundler",
9
+ "resolvePackageJsonExports": true,
10
+ "noEmit": true,
11
+ "composite": true,
5
12
  "skipLibCheck": true,
6
13
  "resolveJsonModule": true,
7
14
  "allowJs": true,
15
+ "esModuleInterop": true,
16
+ "allowSyntheticDefaultImports": true,
8
17
  "noUnusedLocals": true,
9
18
  "noUnusedParameters": true,
19
+ "preserveSymlinks": false,
10
20
  "paths": {
11
21
  "@/*": ["./src/*"]
12
22
  }
13
23
  },
14
24
  "vueCompilerOptions": {
15
25
  "strictTemplates": true,
26
+ "experimentalCompatMode": 2,
16
27
  "types": ["fds-vue-core"]
17
28
  }
18
29
  }
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "fg-devkit",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
7
7
  "bin": {
8
- "fg": "./scripts/fg-devkit.mjs",
8
+ "fgd": "./scripts/fg-devkit.mjs",
9
9
  "fg-devkit": "./scripts/fg-devkit.mjs",
10
10
  "fg-vuln-commit": "./scripts/vuln-commit.mjs",
11
11
  "fds-vuln-commit": "./scripts/vuln-commit.mjs"
@@ -48,20 +48,19 @@
48
48
  "typescript",
49
49
  "vue"
50
50
  ],
51
- "peerDependencies": {
52
- "@typescript-eslint/eslint-plugin": "^8.57.0",
53
- "@typescript-eslint/parser": "^8.57.0",
54
- "@vitest/eslint-plugin": "^1.5.0",
55
- "@vue/eslint-config-prettier": "^10.0.0",
56
- "@vue/tsconfig": "^0.8.0",
57
- "eslint": "^9.0.0 || ^10.0.0",
58
- "eslint-plugin-vue": "^10.0.0",
59
- "typescript": ">=5.0.0",
60
- "vue-eslint-parser": "^10.0.0"
61
- },
62
- "peerDependenciesMeta": {
63
- "@vitest/eslint-plugin": {
64
- "optional": true
65
- }
51
+ "dependencies": {
52
+ "@intlify/eslint-plugin-vue-i18n": "4.3.0",
53
+ "@typescript-eslint/eslint-plugin": "8.58.2",
54
+ "@typescript-eslint/parser": "8.58.2",
55
+ "@vitest/eslint-plugin": "1.6.16",
56
+ "@vue/eslint-config-prettier": "10.2.0",
57
+ "commitizen": "4.3.1",
58
+ "eslint": "10.2.1",
59
+ "eslint-plugin-prettier": "5.5.5",
60
+ "eslint-plugin-vue": "10.8.0",
61
+ "prettier": "3.8.3",
62
+ "typescript": "5.9.3",
63
+ "vue-eslint-parser": "10.4.0",
64
+ "vue-tsc": "3.2.7"
66
65
  }
67
66
  }
@@ -5,12 +5,18 @@
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-project-configs (VS Code + Prettier + ESLint stub + tsconfig app template)
9
- * pnpm exec fg-devkit sync-tooling-configs (Prettier + ESLint stub + tsconfig app template only)
8
+ * pnpm exec fg-devkit sync-project-configs (VS Code + tooling sync; overwrites config files)
9
+ * pnpm exec fg-devkit sync-tooling-configs (tooling sync only; overwrites config files)
10
10
  * pnpm exec fg-devkit sync-vscode-settings
11
11
  * pnpm exec fg-devkit create-release [patch|minor|major]
12
12
  * pnpm exec fg-devkit commit [cz-args...] (Commitizen; uses package.json config.commitizen.path)
13
13
  * pnpm exec fg-devkit commit-vuln (staged package.json version bumps → vuln() commit)
14
+ * pnpm exec fg-devkit lint [eslint-args...] (run ESLint with fg-devkit bundled packages)
15
+ * pnpm exec fg-devkit lint-fix [eslint-args...] (same as lint plus --fix)
16
+ * pnpm exec fg-devkit format [prettier-args...] (run Prettier with fg-devkit bundled package)
17
+ * pnpm exec fg-devkit format-check [prettier-args...] (same as format plus --check)
18
+ * pnpm exec fg-devkit typecheck [vue-tsc-args...] (run vue-tsc with fg-devkit bundled package)
19
+ * pnpm exec fg-devkit typecheck-watch [vue-tsc-args...] (same as typecheck plus --watch)
14
20
  * Interactive menu (no subcommand):
15
21
  * pnpm exec fg-devkit
16
22
  *
@@ -24,8 +30,10 @@ import readline from 'node:readline/promises'
24
30
  import path from 'node:path'
25
31
  import { fileURLToPath } from 'node:url'
26
32
  import { stdin as input, stdout as output } from 'node:process'
33
+ import { createRequire } from 'node:module'
27
34
 
28
35
  const scriptDir = path.dirname(fileURLToPath(import.meta.url))
36
+ const require = createRequire(import.meta.url)
29
37
 
30
38
  /** Run another script in this package via Node; inherits stdio and returns the child exit code. */
31
39
  function runNode(scriptRelative, args = [], options = {}) {
@@ -68,37 +76,121 @@ function runReleaseScript(args = []) {
68
76
  return r.status ?? 1
69
77
  }
70
78
 
79
+ /** Prompt release type in CLI before invoking release.sh to avoid a "stuck" terminal feeling. */
80
+ async function promptReleaseType(rl) {
81
+ console.log('\nSelect release type:')
82
+ console.log(' 1) patch')
83
+ console.log(' 2) minor')
84
+ console.log(' 3) major')
85
+ console.log(' 0) Cancel\n')
86
+ const choice = (await rl.question('Release type [1-3] (default: 1): ')).trim() || '1'
87
+ if (choice === '0') {
88
+ return null
89
+ }
90
+ if (choice === '1') {
91
+ return 'patch'
92
+ }
93
+ if (choice === '2') {
94
+ return 'minor'
95
+ }
96
+ if (choice === '3') {
97
+ return 'major'
98
+ }
99
+ console.error('[fg-devkit] Invalid release type selection.')
100
+ return null
101
+ }
102
+
71
103
  /**
72
- * Run Commitizen in the consumer repo (reads config.commitizen.path from package.json).
73
- * Tries pnpm exec cz, then pnpm exec git-cz, then npx commitizen git-cz.
104
+ * Run Commitizen from fg-devkit's bundled dependency set.
105
+ * Uses the consuming repo's config.commitizen.path when present.
74
106
  */
75
107
  function runCommitizen(args = []) {
76
- const cwd = process.cwd()
77
- const attempts = [
78
- () => spawnSync('pnpm', ['exec', 'cz', ...args], { stdio: 'inherit', cwd, env: process.env }),
79
- () => spawnSync('pnpm', ['exec', 'git-cz', ...args], { stdio: 'inherit', cwd, env: process.env }),
80
- () =>
81
- spawnSync('npx', ['--yes', 'commitizen', 'git-cz', ...args], {
82
- stdio: 'inherit',
83
- cwd,
84
- env: process.env,
85
- }),
86
- ]
87
- for (const run of attempts) {
88
- const r = run()
89
- if (r.error) {
90
- if (r.error.code === 'ENOENT') {
91
- continue
92
- }
93
- console.error('[fg-devkit]', r.error.message)
94
- return 1
95
- }
96
- return r.status ?? 1
108
+ let gitCzBin
109
+ try {
110
+ gitCzBin = require.resolve('commitizen/bin/git-cz')
111
+ } catch {
112
+ console.error('[fg-devkit] Could not resolve bundled commitizen. Reinstall fg-devkit and retry.')
113
+ return 1
114
+ }
115
+
116
+ const r = spawnSync(process.execPath, [gitCzBin, ...args], {
117
+ stdio: 'inherit',
118
+ cwd: process.cwd(),
119
+ env: process.env,
120
+ })
121
+ if (r.error) {
122
+ console.error('[fg-devkit]', r.error.message)
123
+ return 1
124
+ }
125
+ return r.status ?? 1
126
+ }
127
+
128
+
129
+ /** Run ESLint from fg-devkit's bundled dependency set. */
130
+ function runBundledEslint(args = []) {
131
+ let eslintBin
132
+ try {
133
+ const eslintPkgPath = require.resolve('eslint/package.json')
134
+ eslintBin = path.join(path.dirname(eslintPkgPath), 'bin', 'eslint.js')
135
+ } catch {
136
+ console.error('[fg-devkit] Could not resolve bundled eslint. Reinstall fg-devkit and retry.')
137
+ return 1
138
+ }
139
+
140
+ const r = spawnSync(process.execPath, [eslintBin, ...args], {
141
+ stdio: 'inherit',
142
+ cwd: process.cwd(),
143
+ env: process.env,
144
+ })
145
+ if (r.error) {
146
+ console.error('[fg-devkit]', r.error.message)
147
+ return 1
148
+ }
149
+ return r.status ?? 1
150
+ }
151
+
152
+ /** Run Prettier from fg-devkit's bundled dependency set. */
153
+ function runBundledPrettier(args = []) {
154
+ let prettierBin
155
+ try {
156
+ prettierBin = require.resolve('prettier/bin/prettier.cjs')
157
+ } catch {
158
+ console.error('[fg-devkit] Could not resolve bundled prettier. Reinstall fg-devkit and retry.')
159
+ return 1
160
+ }
161
+
162
+ const r = spawnSync(process.execPath, [prettierBin, ...args], {
163
+ stdio: 'inherit',
164
+ cwd: process.cwd(),
165
+ env: process.env,
166
+ })
167
+ if (r.error) {
168
+ console.error('[fg-devkit]', r.error.message)
169
+ return 1
170
+ }
171
+ return r.status ?? 1
172
+ }
173
+
174
+ /** Run vue-tsc from fg-devkit's bundled dependency set. */
175
+ function runBundledTypeScript(args = []) {
176
+ let vueTscBin
177
+ try {
178
+ vueTscBin = require.resolve('vue-tsc/bin/vue-tsc.js')
179
+ } catch {
180
+ console.error('[fg-devkit] Could not resolve bundled vue-tsc. Reinstall fg-devkit and retry.')
181
+ return 1
182
+ }
183
+
184
+ const r = spawnSync(process.execPath, [vueTscBin, ...args], {
185
+ stdio: 'inherit',
186
+ cwd: process.cwd(),
187
+ env: process.env,
188
+ })
189
+ if (r.error) {
190
+ console.error('[fg-devkit]', r.error.message)
191
+ return 1
97
192
  }
98
- console.error(
99
- '[fg-devkit] Commitizen not found. Add devDependency "commitizen", set config.commitizen.path, then retry.',
100
- )
101
- return 1
193
+ return r.status ?? 1
102
194
  }
103
195
 
104
196
  /** Map subcommand name → script file (extra argv after subcommand is forwarded). */
@@ -117,13 +209,19 @@ function printHelp() {
117
209
  Commands:
118
210
  check-deps [policy-file] Validate package.json + pins against policy
119
211
  sync-deps [policy-file] Align declared versions to policy (existing keys only)
120
- sync-project-configs VS Code settings + Prettier + ESLint + tsconfig (app template)
121
- sync-tooling-configs Prettier + ESLint + tsconfig (app template; no VS Code)
212
+ sync-project-configs VS Code + tooling sync (overwrites config files)
213
+ sync-tooling-configs Tooling sync only (overwrites config files)
122
214
  sync-vscode-settings Copy shared VS Code settings into .vscode/settings.json
123
215
  create-release [bump] Version bump, git push, GitHub release (patch|minor|major; omit = prompt)
124
216
  (alias: createRelease)
125
217
  commit [args...] Commitizen (git-cz); uses config.commitizen.path in package.json
126
218
  commit-vuln Commit staged dependency bumps as vuln() (alias: vuln-commit)
219
+ lint [eslint-args...] Run ESLint using fg-devkit bundled ESLint stack
220
+ lint-fix [eslint-args...] Run ESLint with --fix using fg-devkit bundled ESLint stack
221
+ format [prettier-args...] Run Prettier using fg-devkit bundled package
222
+ format-check [prettier-args...] Run Prettier with --check using fg-devkit bundled package
223
+ typecheck [vue-tsc-args...] Run vue-tsc using fg-devkit bundled package
224
+ typecheck-watch [vue-tsc-args...] Run vue-tsc with --watch using fg-devkit bundled package
127
225
 
128
226
  With no command, opens an interactive menu.
129
227
 
@@ -135,32 +233,32 @@ Options:
135
233
  const MENU = [
136
234
  {
137
235
  key: '1',
138
- label: 'Check dependency policy against package.json (check-deps)',
236
+ label: 'Check dependency policy',
139
237
  run: () => runNode('check-dependency-policy.mjs'),
140
238
  },
141
239
  {
142
240
  key: '2',
143
- label: 'Sync dependency versions from policy (sync-deps)',
241
+ label: 'Sync dependency policy',
144
242
  run: () => runNode('sync-dependency-policy.mjs'),
145
243
  },
146
244
  {
147
245
  key: '3',
148
- label: 'Sync project configs (VS Code + Prettier + ESLint + tsconfig app template)',
246
+ label: 'Sync configs (vscode, eslint, prettier, tsconfig)',
149
247
  run: () => runNode('sync-project-configs.mjs'),
150
248
  },
151
249
  {
152
250
  key: '4',
153
- label: 'Create release (version bump, push, gh release — run from package repo root)',
251
+ label: 'Create release',
154
252
  run: () => runReleaseScript(),
155
253
  },
156
254
  {
157
255
  key: '5',
158
- label: 'Commit (Commitizen — interactive conventional commit)',
256
+ label: 'Commit (Commitizen)',
159
257
  run: () => runCommitizen(),
160
258
  },
161
259
  {
162
260
  key: '6',
163
- label: 'Commit vulnerability bumps (staged package.json → vuln() message)',
261
+ label: 'Commit vulnerability (Commitizen)',
164
262
  run: () => runNode('vuln-commit.mjs'),
165
263
  },
166
264
  ]
@@ -191,7 +289,16 @@ async function runInteractiveMenu() {
191
289
 
192
290
  let exitCode = 0
193
291
  try {
194
- const out = item.run()
292
+ let out
293
+ if (item.key === '4') {
294
+ const bumpType = await promptReleaseType(rl)
295
+ if (!bumpType) {
296
+ return 0
297
+ }
298
+ out = runReleaseScript([bumpType])
299
+ } else {
300
+ out = item.run()
301
+ }
195
302
  if (typeof out === 'object' && out !== null && typeof out.then === 'function') {
196
303
  exitCode = await out
197
304
  } else if (typeof out === 'number') {
@@ -224,6 +331,30 @@ async function main() {
224
331
  process.exitCode = runNode('vuln-commit.mjs', rest)
225
332
  return
226
333
  }
334
+ if (sub === 'lint') {
335
+ process.exitCode = runBundledEslint(rest.length > 0 ? rest : ['.'])
336
+ return
337
+ }
338
+ if (sub === 'lint-fix') {
339
+ process.exitCode = runBundledEslint(rest.length > 0 ? ['--fix', ...rest] : ['--fix', '.'])
340
+ return
341
+ }
342
+ if (sub === 'format') {
343
+ process.exitCode = runBundledPrettier(rest.length > 0 ? rest : ['--write', '.'])
344
+ return
345
+ }
346
+ if (sub === 'format-check') {
347
+ process.exitCode = runBundledPrettier(rest.length > 0 ? ['--check', ...rest] : ['--check', '.'])
348
+ return
349
+ }
350
+ if (sub === 'typecheck') {
351
+ process.exitCode = runBundledTypeScript(rest.length > 0 ? rest : ['--noEmit', '-p', 'tsconfig.json'])
352
+ return
353
+ }
354
+ if (sub === 'typecheck-watch') {
355
+ process.exitCode = runBundledTypeScript(rest.length > 0 ? ['--watch', ...rest] : ['--noEmit', '--watch', '-p', 'tsconfig.json'])
356
+ return
357
+ }
227
358
  const script = DIRECT_COMMANDS[sub]
228
359
  if (!script) {
229
360
  console.error(`[fg-devkit] Unknown command: ${sub}`)
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * Syncs shared tooling files from fg-devkit into the repo root:
4
- * - prettier.config.js — full copy from fg-devkit
5
- * - eslint.config.js — copy of the minimal eslint.sync-stub.js (flat config + createBaseConfig)
6
- * - tsconfig.json — full copy of tsconfig.app.sync.json (Vue app defaults: include/exclude,
7
- * compilerOptions, vueCompilerOptions, extends fg-devkit/tsconfig.base.json)
4
+ * - prettier.config.js — overwritten from fg-devkit prettier sync template
5
+ * - eslint.config.js — overwritten from fg-devkit eslint sync template
6
+ * - tsconfig.json — overwritten from fg-devkit tsconfig app sync template
7
+ *
8
+ * This command is intentionally deterministic: each run rewrites files to the shared templates.
8
9
  *
9
10
  * Requires fg-devkit on disk (direct dependency or via fds-vue-core).
10
11
  *
@@ -15,11 +16,14 @@
15
16
 
16
17
  import fs from 'node:fs'
17
18
  import path from 'node:path'
19
+ import { fileURLToPath } from 'node:url'
18
20
 
19
21
  const projectRoot = process.cwd()
22
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url))
20
23
 
21
24
  function findFgDevkitPackageRoot() {
22
25
  const candidates = [
26
+ path.resolve(scriptDir, '..'),
23
27
  path.join(projectRoot, 'node_modules', 'fg-devkit'),
24
28
  path.join(projectRoot, 'node_modules', 'fds-vue-core', 'node_modules', 'fg-devkit'),
25
29
  ]
@@ -39,13 +43,13 @@ if (!fgRoot) {
39
43
  process.exit(1)
40
44
  }
41
45
 
42
- const prettierSrc = path.join(fgRoot, 'configs', 'prettier.config.js')
46
+ const prettierSrc = path.join(fgRoot, 'configs', 'prettier.sync-stub.js')
43
47
  const eslintStubSrc = path.join(fgRoot, 'configs', 'eslint.sync-stub.js')
44
48
  const tsconfigSrc = path.join(fgRoot, 'configs', 'tsconfig.app.sync.json')
45
49
 
46
50
  if (!fs.existsSync(prettierSrc) || !fs.existsSync(eslintStubSrc) || !fs.existsSync(tsconfigSrc)) {
47
51
  console.error(
48
- '[sync-tooling] Missing prettier.config.js, eslint.sync-stub.js, or tsconfig.app.sync.json inside fg-devkit package.',
52
+ '[sync-tooling] Missing prettier.sync-stub.js, eslint.sync-stub.js, or tsconfig.app.sync.json inside fg-devkit package.',
49
53
  )
50
54
  process.exit(1)
51
55
  }
@@ -54,9 +58,8 @@ try {
54
58
  fs.copyFileSync(prettierSrc, path.join(projectRoot, 'prettier.config.js'))
55
59
  fs.copyFileSync(eslintStubSrc, path.join(projectRoot, 'eslint.config.js'))
56
60
  fs.copyFileSync(tsconfigSrc, path.join(projectRoot, 'tsconfig.json'))
61
+ console.log('[sync-tooling] Updated prettier.config.js, eslint.config.js, and tsconfig.json.')
57
62
  } catch (err) {
58
63
  console.error(`[sync-tooling] ${err.message}`)
59
64
  process.exit(1)
60
65
  }
61
-
62
- console.log('[sync-tooling] Updated prettier.config.js, eslint.config.js, and tsconfig.json.')