fg-devkit 1.22.0 → 1.24.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 +30 -7
- package/configs/dependency-policy.vue-workspace.json +28 -28
- package/package.json +12 -85
- package/scaffold/vue/package.json +13 -13
- package/scripts/audit-override-commit.mjs +167 -24
- package/scripts/bump-node-toolchain.mjs +8 -31
- package/scripts/bump-pnpm-toolchain.mjs +8 -29
- package/scripts/check-dependency-policy.mjs +10 -35
- package/scripts/fg-devkit.mjs +290 -337
- package/scripts/fleet-bump-fg-devkit.mjs +4 -5
- package/scripts/fleet-git-commit-push-scoped.mjs +6 -26
- package/scripts/fleet-git-discard-scoped.mjs +5 -25
- package/scripts/fleet-git-pull-scoped.mjs +5 -25
- package/scripts/fleet-vulns.mjs +4 -9
- package/scripts/generate-release-notes.mjs +1 -1
- package/scripts/{audit-fix-plan.mjs → lib/audit-fix-plan.mjs} +77 -4
- package/scripts/{audit-fix-plan.test.mjs → lib/audit-fix-plan.test.mjs} +50 -2
- package/scripts/lib/common.mjs +95 -0
- package/scripts/{dependency-policy-toolchain.mjs → lib/dependency-policy-toolchain.mjs} +3 -35
- package/scripts/{git-commit-push-fleet-common.mjs → lib/git-commit-push-fleet-common.mjs} +1 -1
- package/scripts/{git-discard-fleet-common.mjs → lib/git-discard-fleet-common.mjs} +1 -1
- package/scripts/{git-pull-fleet-common.mjs → lib/git-pull-fleet-common.mjs} +1 -1
- package/scripts/{override-changes.mjs → lib/override-changes.mjs} +20 -0
- package/scripts/{piwik-dimensions.test.mjs → lib/piwik-dimensions.test.mjs} +0 -5
- package/scripts/{release-notes-common.mjs → lib/release-notes-common.mjs} +5 -7
- package/scripts/{resolve-dependency-policy-path.mjs → lib/resolve-dependency-policy-path.mjs} +4 -3
- package/scripts/piwik.mjs +6 -6
- package/scripts/poeditor-download.mjs +1 -1
- package/scripts/poeditor-upload.mjs +1 -1
- package/scripts/policy-outdated.mjs +3 -8
- package/scripts/policy-upgrade-commit.mjs +5 -26
- package/scripts/policy-upgrade.mjs +6 -30
- package/scripts/policy-vulns.mjs +3 -8
- package/scripts/prune-overrides.mjs +5 -16
- package/scripts/prune-release-age-exclude.mjs +1 -1
- package/scripts/refresh-dependency-policy-from-repos.mjs +5 -7
- package/scripts/release.sh +2 -1
- package/scripts/scaffold-vue.mjs +1 -3
- package/scripts/setup-ai-rules.mjs +135 -0
- package/scripts/sync-consumer-lefthook.mjs +7 -24
- package/scripts/sync-dependency-check-suppressions-commit.mjs +7 -46
- package/scripts/sync-dependency-policy-commit.mjs +6 -38
- package/scripts/sync-dependency-policy.mjs +9 -35
- package/scripts/sync-node-toolchain.mjs +5 -8
- package/scripts/sync-pnpm-toolchain.mjs +5 -8
- package/scripts/sync-scaffold-vue-deps.mjs +6 -7
- package/scripts/sync-tooling-configs.mjs +8 -23
- package/scripts/sync-vite-plugin-vue-inspector.mjs +7 -39
- package/scripts/verify-release-notes.mjs +1 -1
- package/.cursor/rules/core-coding-standards.mdc +0 -291
- package/scaffold/vue/.gitignore +0 -13
- package/scripts/cz/.cz-config.cjs +0 -29
- package/scripts/fleet-git-commit-push.mjs +0 -75
- package/scripts/fleet-git-discard.mjs +0 -66
- package/scripts/fleet-git-pull.mjs +0 -65
- package/scripts/sync-core-coding-standards.mjs +0 -77
- package/scripts/sync-peers-from-dev.mjs +0 -31
- package/scripts/vuln-commit.mjs +0 -142
- /package/configs/{fallowrc.sync-stub.json → fallowrc.json} +0 -0
- /package/scripts/{dependency-policy-pins.mjs → lib/dependency-policy-pins.mjs} +0 -0
- /package/scripts/{fleet-project-repos.mjs → lib/fleet-project-repos.mjs} +0 -0
- /package/scripts/{fleet-repo-picker.mjs → lib/fleet-repo-picker.mjs} +0 -0
- /package/scripts/{fleet-vue-repos.mjs → lib/fleet-vue-repos.mjs} +0 -0
- /package/scripts/{git-fleet-common.mjs → lib/git-fleet-common.mjs} +0 -0
- /package/scripts/{node-toolchain-sync.mjs → lib/node-toolchain-sync.mjs} +0 -0
- /package/scripts/{piwik-common.mjs → lib/piwik-common.mjs} +0 -0
- /package/scripts/{piwik-dimensions.mjs → lib/piwik-dimensions.mjs} +0 -0
- /package/scripts/{pnpm-toolchain-sync.mjs → lib/pnpm-toolchain-sync.mjs} +0 -0
- /package/scripts/{poeditor-common.mjs → lib/poeditor-common.mjs} +0 -0
package/scripts/{resolve-dependency-policy-path.mjs → lib/resolve-dependency-policy-path.mjs}
RENAMED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import fs from 'node:fs'
|
|
9
9
|
import path from 'node:path'
|
|
10
|
+
import { fgDevkitRoot } from './common.mjs'
|
|
10
11
|
|
|
11
12
|
const DEFAULT_POLICY = 'dependency-policy.vue-workspace.json'
|
|
12
13
|
|
|
@@ -16,12 +17,12 @@ const DEFAULT_POLICY = 'dependency-policy.vue-workspace.json'
|
|
|
16
17
|
* - Absolute path: used as-is
|
|
17
18
|
* - Relative path: if it exists under cwd, use it; else fg-devkit/configs/<arg>
|
|
18
19
|
*/
|
|
19
|
-
export function resolveDependencyPolicyPath(
|
|
20
|
+
export function resolveDependencyPolicyPath(cwd, argv) {
|
|
20
21
|
// Optional policy path is argv[2] only when it is not an option flag
|
|
21
22
|
// (e.g. `policy-upgrade --interactive` must use the default policy file).
|
|
22
23
|
const arg = argv[2]
|
|
23
24
|
if (!arg || arg.startsWith('-')) {
|
|
24
|
-
return path.
|
|
25
|
+
return path.join(fgDevkitRoot, 'configs', DEFAULT_POLICY)
|
|
25
26
|
}
|
|
26
27
|
if (path.isAbsolute(arg)) {
|
|
27
28
|
return arg
|
|
@@ -30,5 +31,5 @@ export function resolveDependencyPolicyPath(scriptDir, cwd, argv) {
|
|
|
30
31
|
if (fs.existsSync(fromCwd)) {
|
|
31
32
|
return fromCwd
|
|
32
33
|
}
|
|
33
|
-
return path.
|
|
34
|
+
return path.join(fgDevkitRoot, 'configs', arg)
|
|
34
35
|
}
|
package/scripts/piwik.mjs
CHANGED
|
@@ -37,14 +37,14 @@ import {
|
|
|
37
37
|
planLocalPull,
|
|
38
38
|
renderTable,
|
|
39
39
|
rewriteDimensionNumbers,
|
|
40
|
-
} from './piwik-dimensions.mjs'
|
|
40
|
+
} from './lib/piwik-dimensions.mjs'
|
|
41
41
|
import {
|
|
42
42
|
assertApiConfig,
|
|
43
43
|
createPiwikClient,
|
|
44
44
|
loadLocalDimensions,
|
|
45
45
|
resolveEnvironmentPair,
|
|
46
46
|
resolvePiwikConfig,
|
|
47
|
-
} from './piwik-common.mjs'
|
|
47
|
+
} from './lib/piwik-common.mjs'
|
|
48
48
|
|
|
49
49
|
const COMMANDS = new Set(['list', 'diff', 'add', 'update', 'sync', 'pull', 'compare', 'migrate'])
|
|
50
50
|
|
|
@@ -83,7 +83,7 @@ slot is not the local slot.`)
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
|
-
* @param {import('./piwik-dimensions.mjs').LocalDimension[]} locals
|
|
86
|
+
* @param {import('./lib/piwik-dimensions.mjs').LocalDimension[]} locals
|
|
87
87
|
*/
|
|
88
88
|
function printLocal(locals) {
|
|
89
89
|
for (const scope of SCOPES) {
|
|
@@ -100,7 +100,7 @@ function printLocal(locals) {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
/**
|
|
103
|
-
* @param {import('./piwik-dimensions.mjs').RemoteDimension[]} dimensions
|
|
103
|
+
* @param {import('./lib/piwik-dimensions.mjs').RemoteDimension[]} dimensions
|
|
104
104
|
* @param {Record<string, { used?: number, available?: number, left?: number }>} slots
|
|
105
105
|
*/
|
|
106
106
|
function printRemote(dimensions, slots) {
|
|
@@ -149,7 +149,7 @@ async function confirmApply(message, config) {
|
|
|
149
149
|
/**
|
|
150
150
|
* @param {ReturnType<typeof createPiwikClient>} client
|
|
151
151
|
* @param {ReturnType<typeof resolvePiwikConfig>} config
|
|
152
|
-
* @param {import('./piwik-dimensions.mjs').LocalDimension[]} creates
|
|
152
|
+
* @param {import('./lib/piwik-dimensions.mjs').LocalDimension[]} creates
|
|
153
153
|
*/
|
|
154
154
|
async function applyCreates(client, config, creates) {
|
|
155
155
|
for (const local of creates) {
|
|
@@ -179,7 +179,7 @@ async function applyCreates(client, config, creates) {
|
|
|
179
179
|
/**
|
|
180
180
|
* @param {ReturnType<typeof createPiwikClient>} client
|
|
181
181
|
* @param {string} websiteId
|
|
182
|
-
* @param {{ local: import('./piwik-dimensions.mjs').LocalDimension, remote: import('./piwik-dimensions.mjs').RemoteDimension }[]} updates
|
|
182
|
+
* @param {{ local: import('./lib/piwik-dimensions.mjs').LocalDimension, remote: import('./lib/piwik-dimensions.mjs').RemoteDimension }[]} updates
|
|
183
183
|
*/
|
|
184
184
|
async function applyUpdates(client, websiteId, updates) {
|
|
185
185
|
for (const { local, remote } of updates) {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import fs from 'node:fs'
|
|
14
14
|
import path from 'node:path'
|
|
15
15
|
|
|
16
|
-
import { getFlagValue, getPoeditorToken, loadPoeditorConfig, parseFlags, resolvePathFromCwd } from './poeditor-common.mjs'
|
|
16
|
+
import { getFlagValue, getPoeditorToken, loadPoeditorConfig, parseFlags, resolvePathFromCwd } from './lib/poeditor-common.mjs'
|
|
17
17
|
|
|
18
18
|
const MIN_UPLOAD_INTERVAL_MS = 20_000
|
|
19
19
|
const MAX_UPLOAD_RETRIES = 3
|
|
@@ -11,15 +11,10 @@ import fs from 'node:fs'
|
|
|
11
11
|
import os from 'node:os'
|
|
12
12
|
import path from 'node:path'
|
|
13
13
|
import { spawnSync } from 'node:child_process'
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
14
|
+
import { resolveDependencyPolicyPath } from './lib/resolve-dependency-policy-path.mjs'
|
|
15
|
+
import { readJson } from './lib/common.mjs'
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
const policyPath = resolveDependencyPolicyPath(scriptDir, process.cwd(), process.argv)
|
|
19
|
-
|
|
20
|
-
function readJson(p) {
|
|
21
|
-
return JSON.parse(fs.readFileSync(p, 'utf8'))
|
|
22
|
-
}
|
|
17
|
+
const policyPath = resolveDependencyPolicyPath(process.cwd(), process.argv)
|
|
23
18
|
|
|
24
19
|
const policy = readJson(policyPath)
|
|
25
20
|
const deps = {
|
|
@@ -17,10 +17,12 @@ import {
|
|
|
17
17
|
collectOverrideChanges,
|
|
18
18
|
collectOverrides,
|
|
19
19
|
formatOverrideValue,
|
|
20
|
-
} from './override-changes.mjs'
|
|
20
|
+
} from './lib/override-changes.mjs'
|
|
21
|
+
import { readJson, runGit, stageExistingFiles } from './lib/common.mjs'
|
|
21
22
|
|
|
22
23
|
const require = createRequire(import.meta.url)
|
|
23
24
|
const cwd = process.cwd()
|
|
25
|
+
const GIT = { cwd, tag: '[policy-upgrade-commit]' }
|
|
24
26
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
25
27
|
const packageJsonPath = path.join(cwd, 'package.json')
|
|
26
28
|
const PRUNE_FLAG = '--prune-overrides'
|
|
@@ -59,19 +61,6 @@ function runNcu(args = []) {
|
|
|
59
61
|
return result.status ?? 1
|
|
60
62
|
}
|
|
61
63
|
|
|
62
|
-
function runGit(args) {
|
|
63
|
-
const result = spawnSync('git', args, {
|
|
64
|
-
stdio: 'inherit',
|
|
65
|
-
cwd,
|
|
66
|
-
env: process.env,
|
|
67
|
-
})
|
|
68
|
-
if (result.error) {
|
|
69
|
-
console.error('[policy-upgrade-commit]', result.error.message)
|
|
70
|
-
return 1
|
|
71
|
-
}
|
|
72
|
-
return result.status ?? 1
|
|
73
|
-
}
|
|
74
|
-
|
|
75
64
|
function runPruneOverridesFix() {
|
|
76
65
|
console.log('[policy-upgrade-commit] Pruning overrides that no longer affect pnpm audit…')
|
|
77
66
|
const result = spawnSync(process.execPath, [path.join(scriptDir, 'prune-overrides.mjs'), '--fix'], {
|
|
@@ -86,16 +75,6 @@ function runPruneOverridesFix() {
|
|
|
86
75
|
return result.status ?? 1
|
|
87
76
|
}
|
|
88
77
|
|
|
89
|
-
function stageExistingFiles(files) {
|
|
90
|
-
const existingFiles = files.filter((filePath) => fs.existsSync(path.join(cwd, filePath)))
|
|
91
|
-
if (existingFiles.length === 0) return 0
|
|
92
|
-
return runGit(['add', '--', ...existingFiles])
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function readJson(jsonPath) {
|
|
96
|
-
return JSON.parse(fs.readFileSync(jsonPath, 'utf8'))
|
|
97
|
-
}
|
|
98
|
-
|
|
99
78
|
function collectPackageVersionChanges(beforePackage, afterPackage) {
|
|
100
79
|
const before = {
|
|
101
80
|
...(beforePackage.dependencies ?? {}),
|
|
@@ -144,7 +123,7 @@ function buildCommitMessage(changed) {
|
|
|
144
123
|
}
|
|
145
124
|
|
|
146
125
|
function commitChanges(prefix, subject, body) {
|
|
147
|
-
const stageExitCode = stageExistingFiles(['package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml'])
|
|
126
|
+
const stageExitCode = stageExistingFiles(['package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml'], GIT)
|
|
148
127
|
if (stageExitCode !== 0) {
|
|
149
128
|
return stageExitCode
|
|
150
129
|
}
|
|
@@ -153,7 +132,7 @@ function commitChanges(prefix, subject, body) {
|
|
|
153
132
|
console.log(body)
|
|
154
133
|
}
|
|
155
134
|
const commitArgs = body ? ['commit', '-m', subject, '-m', body] : ['commit', '-m', subject]
|
|
156
|
-
return runGit(commitArgs)
|
|
135
|
+
return runGit(commitArgs, GIT).status
|
|
157
136
|
}
|
|
158
137
|
|
|
159
138
|
function pruneAndCommitOverrides() {
|
|
@@ -15,14 +15,13 @@ import fs from 'node:fs'
|
|
|
15
15
|
import os from 'node:os'
|
|
16
16
|
import path from 'node:path'
|
|
17
17
|
import { spawnSync } from 'node:child_process'
|
|
18
|
-
import { fileURLToPath } from 'node:url'
|
|
19
18
|
import { createRequire } from 'node:module'
|
|
20
|
-
import { resolveDependencyPolicyPath } from './resolve-dependency-policy-path.mjs'
|
|
19
|
+
import { resolveDependencyPolicyPath } from './lib/resolve-dependency-policy-path.mjs'
|
|
21
20
|
import { syncScaffoldVueDepsFromPolicy } from './sync-scaffold-vue-deps.mjs'
|
|
21
|
+
import { fgDevkitRoot, readJson, runGit, stageExistingFiles } from './lib/common.mjs'
|
|
22
22
|
|
|
23
23
|
const require = createRequire(import.meta.url)
|
|
24
|
-
const
|
|
25
|
-
const fgDevkitRoot = path.resolve(scriptDir, '..')
|
|
24
|
+
const GIT = { cwd: fgDevkitRoot, tag: '[policy-upgrade]' }
|
|
26
25
|
|
|
27
26
|
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
28
27
|
console.log(`Usage:
|
|
@@ -36,13 +35,9 @@ Examples:
|
|
|
36
35
|
|
|
37
36
|
const argPolicy = process.argv[2]
|
|
38
37
|
const hasPolicyArg = Boolean(argPolicy) && !argPolicy.startsWith('-')
|
|
39
|
-
const policyPath = resolveDependencyPolicyPath(
|
|
38
|
+
const policyPath = resolveDependencyPolicyPath(process.cwd(), process.argv)
|
|
40
39
|
const ncuArgs = hasPolicyArg ? process.argv.slice(3) : process.argv.slice(2)
|
|
41
40
|
|
|
42
|
-
function readJson(p) {
|
|
43
|
-
return JSON.parse(fs.readFileSync(p, 'utf8'))
|
|
44
|
-
}
|
|
45
|
-
|
|
46
41
|
function collectPolicyVersions(policy) {
|
|
47
42
|
return {
|
|
48
43
|
...(policy.managedDependencies?.dependencies ?? {}),
|
|
@@ -72,25 +67,6 @@ function buildCommitMessage(changed) {
|
|
|
72
67
|
return { subject: `dep(): bump ${changed.length} packages`, body }
|
|
73
68
|
}
|
|
74
69
|
|
|
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
70
|
function toRepoRelative(absolutePath) {
|
|
95
71
|
return path.relative(fgDevkitRoot, absolutePath)
|
|
96
72
|
}
|
|
@@ -188,7 +164,7 @@ const stageExitCode = stageExistingFiles([
|
|
|
188
164
|
toRepoRelative(policyPath),
|
|
189
165
|
'scaffold/vue/package.json',
|
|
190
166
|
'scaffold/vue/Dockerfile.local',
|
|
191
|
-
])
|
|
167
|
+
], GIT)
|
|
192
168
|
if (stageExitCode !== 0) {
|
|
193
169
|
process.exit(stageExitCode)
|
|
194
170
|
}
|
|
@@ -199,4 +175,4 @@ if (body) {
|
|
|
199
175
|
console.log(body)
|
|
200
176
|
}
|
|
201
177
|
const commitArgs = body ? ['commit', '-m', subject, '-m', body] : ['commit', '-m', subject]
|
|
202
|
-
process.exit(runGit(commitArgs))
|
|
178
|
+
process.exit(runGit(commitArgs, GIT).status)
|
package/scripts/policy-vulns.mjs
CHANGED
|
@@ -11,15 +11,10 @@ import fs from 'node:fs'
|
|
|
11
11
|
import os from 'node:os'
|
|
12
12
|
import path from 'node:path'
|
|
13
13
|
import { spawnSync } from 'node:child_process'
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
14
|
+
import { resolveDependencyPolicyPath } from './lib/resolve-dependency-policy-path.mjs'
|
|
15
|
+
import { readJson } from './lib/common.mjs'
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
const policyPath = resolveDependencyPolicyPath(scriptDir, process.cwd(), process.argv)
|
|
19
|
-
|
|
20
|
-
function readJson(p) {
|
|
21
|
-
return JSON.parse(fs.readFileSync(p, 'utf8'))
|
|
22
|
-
}
|
|
17
|
+
const policyPath = resolveDependencyPolicyPath(process.cwd(), process.argv)
|
|
23
18
|
|
|
24
19
|
const policy = readJson(policyPath)
|
|
25
20
|
console.log(`[policy-vulns] policy=${policyPath}`)
|
|
@@ -23,9 +23,11 @@ import {
|
|
|
23
23
|
collectOverrideChanges,
|
|
24
24
|
collectOverrides,
|
|
25
25
|
formatOverrideValue,
|
|
26
|
-
} from './override-changes.mjs'
|
|
26
|
+
} from './lib/override-changes.mjs'
|
|
27
|
+
import { runGit } from './lib/common.mjs'
|
|
27
28
|
|
|
28
29
|
const ROOT = process.cwd()
|
|
30
|
+
const GIT = { cwd: ROOT, tag: '[prune-overrides]' }
|
|
29
31
|
const WORKSPACE_FILE = 'pnpm-workspace.yaml'
|
|
30
32
|
const COPIED_FILES = ['package.json', 'pnpm-lock.yaml', WORKSPACE_FILE, '.npmrc']
|
|
31
33
|
|
|
@@ -49,19 +51,6 @@ Pass --commit to apply the deletions and auto-commit.`)
|
|
|
49
51
|
|
|
50
52
|
const shouldFix = args.fix || args.commit
|
|
51
53
|
|
|
52
|
-
function runGit(gitArgs) {
|
|
53
|
-
const result = spawnSync('git', gitArgs, {
|
|
54
|
-
stdio: 'inherit',
|
|
55
|
-
cwd: ROOT,
|
|
56
|
-
env: process.env,
|
|
57
|
-
})
|
|
58
|
-
if (result.error) {
|
|
59
|
-
console.error('[prune-overrides]', result.error.message)
|
|
60
|
-
return 1
|
|
61
|
-
}
|
|
62
|
-
return result.status ?? 1
|
|
63
|
-
}
|
|
64
|
-
|
|
65
54
|
function commitOverrideChanges(beforeOverrides, afterOverrides) {
|
|
66
55
|
const changed = collectOverrideChanges(beforeOverrides, afterOverrides)
|
|
67
56
|
if (changed.length === 0) {
|
|
@@ -83,7 +72,7 @@ function commitOverrideChanges(beforeOverrides, afterOverrides) {
|
|
|
83
72
|
return 1
|
|
84
73
|
}
|
|
85
74
|
|
|
86
|
-
const stageExitCode = runGit(['add', '--', ...files])
|
|
75
|
+
const stageExitCode = runGit(['add', '--', ...files], GIT).status
|
|
87
76
|
if (stageExitCode !== 0) {
|
|
88
77
|
return stageExitCode
|
|
89
78
|
}
|
|
@@ -94,7 +83,7 @@ function commitOverrideChanges(beforeOverrides, afterOverrides) {
|
|
|
94
83
|
console.log(body)
|
|
95
84
|
}
|
|
96
85
|
const commitArgs = body ? ['commit', '-m', subject, '-m', body] : ['commit', '-m', subject]
|
|
97
|
-
return runGit(commitArgs)
|
|
86
|
+
return runGit(commitArgs, GIT).status
|
|
98
87
|
}
|
|
99
88
|
|
|
100
89
|
function runPnpm(cwd, pnpmArgs, { allowFailure = false } = {}) {
|
|
@@ -26,19 +26,17 @@
|
|
|
26
26
|
|
|
27
27
|
import fs from 'node:fs'
|
|
28
28
|
import path from 'node:path'
|
|
29
|
-
import { fileURLToPath } from 'node:url'
|
|
30
29
|
|
|
31
|
-
import { collectPinViolations } from './dependency-policy-pins.mjs'
|
|
32
|
-
import { collectToolchainPolicyViolations } from './dependency-policy-toolchain.mjs'
|
|
30
|
+
import { collectPinViolations } from './lib/dependency-policy-pins.mjs'
|
|
31
|
+
import { collectToolchainPolicyViolations } from './lib/dependency-policy-toolchain.mjs'
|
|
33
32
|
import { syncScaffoldVueDepsFromPolicy } from './sync-scaffold-vue-deps.mjs'
|
|
33
|
+
import { fgDevkitRoot } from './lib/common.mjs'
|
|
34
34
|
|
|
35
|
-
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
36
|
-
const fgDevkitRoot = path.resolve(scriptDir, '..')
|
|
37
35
|
const fgDevkitPackageJsonPath = path.join(fgDevkitRoot, 'package.json')
|
|
38
36
|
|
|
39
37
|
const projectsRoot = process.argv[2]
|
|
40
38
|
? path.resolve(process.cwd(), process.argv[2])
|
|
41
|
-
: path.resolve(
|
|
39
|
+
: path.resolve(fgDevkitRoot, '..')
|
|
42
40
|
|
|
43
41
|
const policyPath = process.argv[3]
|
|
44
42
|
? path.resolve(process.cwd(), process.argv[3])
|
|
@@ -56,7 +54,7 @@ try {
|
|
|
56
54
|
/** Relative paths under projectsRoot whose package.json files are ignored (maintainer choice). */
|
|
57
55
|
/** Relative path prefixes under projectsRoot to skip when scanning (add repo names as needed). */
|
|
58
56
|
const SKIP_DIR_PREFIXES = []
|
|
59
|
-
const EXTRA_TOOLING_EXCLUDES = new Set(['
|
|
57
|
+
const EXTRA_TOOLING_EXCLUDES = new Set(['@rushstack/eslint-patch', 'jsonc-eslint-parser', 'yaml-eslint-parser'])
|
|
60
58
|
const EXCLUDED_POLICY_PACKAGES = (() => {
|
|
61
59
|
try {
|
|
62
60
|
const pkg = JSON.parse(fs.readFileSync(fgDevkitPackageJsonPath, 'utf8'))
|
package/scripts/release.sh
CHANGED
|
@@ -79,7 +79,8 @@ is_fg_devkit_repo="$(
|
|
|
79
79
|
sync_fg_devkit_package_files() {
|
|
80
80
|
if [[ "$is_fg_devkit_repo" == "yes" && -f "./scripts/sync-scaffold-vue-deps.mjs" && -f "./scaffold/vue/package.json" ]]; then
|
|
81
81
|
node ./scripts/sync-scaffold-vue-deps.mjs
|
|
82
|
-
|
|
82
|
+
# Stage everything sync-scaffold-vue-deps can write, or the release leaves it uncommitted.
|
|
83
|
+
git add package.json scaffold/vue/package.json configs/dependency-policy.vue-workspace.json
|
|
83
84
|
else
|
|
84
85
|
git add package.json
|
|
85
86
|
fi
|
package/scripts/scaffold-vue.mjs
CHANGED
|
@@ -26,10 +26,8 @@
|
|
|
26
26
|
|
|
27
27
|
import fs from 'node:fs'
|
|
28
28
|
import path from 'node:path'
|
|
29
|
-
import {
|
|
29
|
+
import { fgDevkitRoot } from './lib/common.mjs'
|
|
30
30
|
|
|
31
|
-
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
32
|
-
const fgDevkitRoot = path.resolve(scriptDir, '..')
|
|
33
31
|
const scaffoldRoot = path.join(fgDevkitRoot, 'scaffold/vue')
|
|
34
32
|
|
|
35
33
|
/** True if the directory does not exist, is empty, or only contains a fresh clone (.git). */
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Set up the shared AI rules from feelgood/fg-ai-rules for Claude Code in the current repo:
|
|
4
|
+
*
|
|
5
|
+
* 1. Add the `fg` marketplace and enable fg-core and fg-frontend in .claude/settings.json,
|
|
6
|
+
* keeping every other setting.
|
|
7
|
+
* 2. Add the marketplace to Claude Code on this machine if it is missing.
|
|
8
|
+
* 3. Install the plugins for this repo (`claude plugin install … --scope project`). Claude Code
|
|
9
|
+
* does not install them from the settings file on its own, and without the install they don't
|
|
10
|
+
* load at session start.
|
|
11
|
+
*
|
|
12
|
+
* Safe to run again: it only changes what is missing. Commit .claude/settings.json afterwards so
|
|
13
|
+
* teammates get the same plugins; each of them still runs this once.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* pnpm exec fg-devkit setup-ai-rules
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { spawnSync } from 'node:child_process'
|
|
20
|
+
import fs from 'node:fs'
|
|
21
|
+
import path from 'node:path'
|
|
22
|
+
|
|
23
|
+
const TAG = '[setup-ai-rules]'
|
|
24
|
+
const MARKETPLACE = 'fg'
|
|
25
|
+
const MARKETPLACE_REPO = 'feelgood/fg-ai-rules'
|
|
26
|
+
const PLUGINS = ['fg-core', 'fg-frontend']
|
|
27
|
+
|
|
28
|
+
const projectRoot = fs.realpathSync(process.cwd())
|
|
29
|
+
const settingsPath = path.join(projectRoot, '.claude', 'settings.json')
|
|
30
|
+
|
|
31
|
+
function claude(args, { capture = false } = {}) {
|
|
32
|
+
const result = spawnSync('claude', args, {
|
|
33
|
+
cwd: projectRoot,
|
|
34
|
+
encoding: 'utf8',
|
|
35
|
+
stdio: capture ? ['ignore', 'pipe', 'pipe'] : 'inherit',
|
|
36
|
+
})
|
|
37
|
+
if (result.error) return { status: 1, stdout: '', missing: result.error.code === 'ENOENT' }
|
|
38
|
+
return { status: result.status ?? 1, stdout: result.stdout ?? '' }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function claudeJson(args) {
|
|
42
|
+
const result = claude([...args, '--json'], { capture: true })
|
|
43
|
+
if (result.status !== 0) return null
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(result.stdout)
|
|
46
|
+
} catch {
|
|
47
|
+
return null
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Add the marketplace and enabled plugins to .claude/settings.json. Returns true when it changed. */
|
|
52
|
+
function updateSettings() {
|
|
53
|
+
let settings = {}
|
|
54
|
+
if (fs.existsSync(settingsPath)) {
|
|
55
|
+
try {
|
|
56
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'))
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.error(`${TAG} Could not parse ${settingsPath}: ${err.message}`)
|
|
59
|
+
process.exit(1)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const before = JSON.stringify(settings)
|
|
63
|
+
settings.extraKnownMarketplaces = {
|
|
64
|
+
...settings.extraKnownMarketplaces,
|
|
65
|
+
[MARKETPLACE]: { source: { source: 'github', repo: MARKETPLACE_REPO }, autoUpdate: true },
|
|
66
|
+
}
|
|
67
|
+
settings.enabledPlugins = {
|
|
68
|
+
...settings.enabledPlugins,
|
|
69
|
+
...Object.fromEntries(PLUGINS.map((plugin) => [`${plugin}@${MARKETPLACE}`, true])),
|
|
70
|
+
}
|
|
71
|
+
if (JSON.stringify(settings) === before) return false
|
|
72
|
+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true })
|
|
73
|
+
fs.writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`)
|
|
74
|
+
return true
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function printManualSteps() {
|
|
78
|
+
console.log(`${TAG} Run these from the repo root, then restart Claude Code:`)
|
|
79
|
+
console.log(` claude plugin marketplace add ${MARKETPLACE_REPO}`)
|
|
80
|
+
for (const plugin of PLUGINS) console.log(` claude plugin install ${plugin}@${MARKETPLACE} --scope project`)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function main() {
|
|
84
|
+
if (!fs.existsSync(path.join(projectRoot, 'package.json'))) {
|
|
85
|
+
console.error(`${TAG} Run from the repo root (no package.json in ${projectRoot}).`)
|
|
86
|
+
return 1
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const settingsChanged = updateSettings()
|
|
90
|
+
console.log(`${TAG} ${settingsChanged ? 'Updated' : 'Already up to date:'} .claude/settings.json`)
|
|
91
|
+
|
|
92
|
+
const marketplaces = claudeJson(['plugin', 'marketplace', 'list'])
|
|
93
|
+
if (marketplaces === null) {
|
|
94
|
+
const missing = claude(['--version'], { capture: true }).missing
|
|
95
|
+
console.error(`${TAG} ${missing ? 'Claude Code (claude) is not installed.' : 'Could not read Claude Code plugins.'}`)
|
|
96
|
+
printManualSteps()
|
|
97
|
+
return 1
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!marketplaces.some((marketplace) => marketplace.name === MARKETPLACE)) {
|
|
101
|
+
console.log(`${TAG} Adding the ${MARKETPLACE} marketplace (${MARKETPLACE_REPO})…`)
|
|
102
|
+
if (claude(['plugin', 'marketplace', 'add', MARKETPLACE_REPO]).status !== 0) {
|
|
103
|
+
console.error(`${TAG} Could not add the marketplace. Check that you can clone ${MARKETPLACE_REPO} over SSH.`)
|
|
104
|
+
return 1
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const installed = claudeJson(['plugin', 'list']) ?? []
|
|
109
|
+
const isInstalledHere = (plugin) =>
|
|
110
|
+
installed.some(
|
|
111
|
+
(entry) =>
|
|
112
|
+
entry.id === `${plugin}@${MARKETPLACE}` &&
|
|
113
|
+
(entry.scope === 'user' || (entry.projectPath && fs.realpathSync(entry.projectPath) === projectRoot)),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
let failed = false
|
|
117
|
+
for (const plugin of PLUGINS) {
|
|
118
|
+
if (isInstalledHere(plugin)) {
|
|
119
|
+
console.log(`${TAG} ${plugin} is already installed for this repo.`)
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
122
|
+
console.log(`${TAG} Installing ${plugin}…`)
|
|
123
|
+
if (claude(['plugin', 'install', `${plugin}@${MARKETPLACE}`, '--scope', 'project']).status !== 0) failed = true
|
|
124
|
+
}
|
|
125
|
+
if (failed) {
|
|
126
|
+
printManualSteps()
|
|
127
|
+
return 1
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
console.log(`${TAG} Done. Restart Claude Code to load the rules.`)
|
|
131
|
+
if (settingsChanged) console.log(`${TAG} Commit .claude/settings.json so teammates get the same plugins.`)
|
|
132
|
+
return 0
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
process.exit(main())
|
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Syncs Lefthook setup into a consuming repo:
|
|
4
4
|
* - writes lefthook.yml from fg-devkit template
|
|
5
|
-
* - removes legacy
|
|
6
|
-
* - removes legacy lint-staged config block from package.json
|
|
7
|
-
* - removes legacy prepare hook scripts for husky/lefthook bootstrap
|
|
5
|
+
* - removes a legacy `prepare` script that bootstrapped lefthook (hooks are installed by setup-lefthook)
|
|
8
6
|
*
|
|
9
7
|
* Usage:
|
|
10
8
|
* node node_modules/fg-devkit/scripts/sync-consumer-lefthook.mjs
|
|
@@ -13,15 +11,12 @@
|
|
|
13
11
|
|
|
14
12
|
import fs from 'node:fs'
|
|
15
13
|
import path from 'node:path'
|
|
16
|
-
import {
|
|
14
|
+
import { fgDevkitRoot } from './lib/common.mjs'
|
|
17
15
|
|
|
18
16
|
const projectRoot = process.cwd()
|
|
19
|
-
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
20
|
-
const fgRoot = path.resolve(scriptDir, '..')
|
|
21
17
|
|
|
22
|
-
const lefthookTemplate = path.join(
|
|
18
|
+
const lefthookTemplate = path.join(fgDevkitRoot, 'configs', 'lefthook.yml')
|
|
23
19
|
const lefthookTarget = path.join(projectRoot, 'lefthook.yml')
|
|
24
|
-
const huskyDir = path.join(projectRoot, '.husky')
|
|
25
20
|
const packageJsonPath = path.join(projectRoot, 'package.json')
|
|
26
21
|
|
|
27
22
|
if (!fs.existsSync(lefthookTemplate)) {
|
|
@@ -42,25 +37,13 @@ try {
|
|
|
42
37
|
process.exit(1)
|
|
43
38
|
}
|
|
44
39
|
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
pkg.scripts.prepare &&
|
|
48
|
-
(pkg.scripts.prepare.includes('husky') || pkg.scripts.prepare.includes('setup-lefthook'))
|
|
49
|
-
) {
|
|
50
|
-
delete pkg.scripts.prepare
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (pkg['lint-staged'] !== undefined) {
|
|
54
|
-
delete pkg['lint-staged']
|
|
55
|
-
}
|
|
40
|
+
const removePrepare = pkg.scripts?.prepare?.includes('setup-lefthook')
|
|
41
|
+
if (removePrepare) delete pkg.scripts.prepare
|
|
56
42
|
|
|
57
43
|
try {
|
|
58
44
|
fs.copyFileSync(lefthookTemplate, lefthookTarget)
|
|
59
|
-
fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8')
|
|
60
|
-
|
|
61
|
-
fs.rmSync(huskyDir, { recursive: true, force: true })
|
|
62
|
-
}
|
|
63
|
-
console.log('[sync-consumer-lefthook] Synced lefthook.yml and removed .husky/lint-staged legacy setup.')
|
|
45
|
+
if (removePrepare) fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8')
|
|
46
|
+
console.log('[sync-consumer-lefthook] Synced lefthook.yml.')
|
|
64
47
|
} catch (err) {
|
|
65
48
|
console.error(`[sync-consumer-lefthook] ${err.message}`)
|
|
66
49
|
process.exit(1)
|