fg-devkit

Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos
14,112
Install
npm install fg-devkit
Latest Version:1.27.0
License:Proprietary
Last Updated:Oct 22, 2026
Links: npm
Maintainer: igornorlin

fg-devkit

Shared settings and tools to improve the developer experience for Vue and TypeScript projects in the npm ecosystem.

Quick command alias (zsh)

To run fgd instead of pnpm exec fg-devkit, add this alias:

echo "alias fgd='pnpm exec fg-devkit'" >> ~/.zshrc && source ~/.zshrc

This works in repos where fg-devkit is installed.

Bundled ESLint stack

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.

Run lint via CLI:

pnpm exec fgd lint .
pnpm exec fgd lint-fix .

Bundled Prettier

fg-devkit also ships Prettier, so consuming repos can format using the bundled package.

Run formatting via CLI:

pnpm exec fgd format
pnpm exec fgd format-check

Bundled TypeScript

fg-devkit ships vue-tsc and typescript, so consuming repos can run Vue typecheck without installing local TS tooling.

Run typecheck via CLI:

pnpm exec fgd typecheck
pnpm exec fgd typecheck-watch

Bundled Fallow (dead code analysis)

fg-devkit also ships Fallow for dead code analysis in consuming repos.

Run dead code analysis via CLI:

pnpm exec fgd dead-code

Or run Fallow directly with custom args:

pnpm exec fgd fallow dead-code --json

Both use fg-devkit's shared configs/fallowrc.json, so config changes reach every repo on the next fg-devkit bump. A repo that has its own .fallowrc.json (or .fallowrc.jsonc, fallow.toml, .fallow.toml) uses that instead, and so does an explicit --config.

Write the OWASP Dependency-Check suppressions that apply to a consuming repo and commit them:

pnpm exec fgd sync-dependency-check-suppressions-commit        # only entries matching pnpm audit findings
pnpm exec fgd sync-dependency-check-suppressions-commit --all  # every entry in the shared file

The command runs pnpm audit and keeps only the active (not expired) <suppress> entries from fg-devkit's shared configs/dependency-check-suppressions.xml whose GHSA id is reported in the repo, so each repo accepts exactly the risks it has. OWASP Dependency-Check reads the file when it is configured as a suppression file. Add another <suppress> element in the shared fg-devkit file for each additional accepted finding. The command overwrites the consumer copy; if nothing applies and the repo has no copy, no file is created.

To sync standard consumer scripts to fgd commands:

pnpm exec fgd sync-consumer-scripts

To set up Lefthook git hooks:

pnpm exec fgd setup-lefthook

To use the shared AI rules from feelgood/fg-ai-rules in Claude Code:

pnpm exec fgd setup-ai-rules

It adds the fg marketplace to Claude Code if it is missing and asks which of its plugins the repo should use (the repo's current choice, or fg-core and fg-frontend, is preselected; pass --plugins=fg-core,fg-backend to skip the question). It enables those in .claude/settings.json and installs them once for the user, disabled at user scope. The repo's .claude/settings.json then switches them on, so every repo that commits that file gets the rules and other repos don't. When .claude/settings.json changed it commits that file on its own (chore(repo): enable fg-ai-rules Claude Code plugins). Each developer runs it once on their machine. Needs Claude Code and SSH access to feelgood/fg-ai-rules.

Run full consumer setup in one command:

pnpm exec fgd full-consumer-setup

It syncs the consumer scripts, Lefthook, configs and dependency policy, runs pnpm install, and finishes with setup-ai-rules, which commits .claude/settings.json. Without Claude Code that last step only prints a warning.

Dependency policy update workflow

Check outdated policy versions:

pnpm exec fgd policy-outdated

Check vulnerabilities for all policy packages together (including transitive dependencies):

pnpm exec fgd policy-vulns

Check vulnerabilities for all dependencies in the current repo (and nested packages with their own pnpm-lock.yaml):

pnpm exec fgd repo-vulns

Check vulnerabilities across all Vue repositories under the projects root:

pnpm exec fgd fleet-vulns

For summary-only mode (no full per-repo pnpm audit output):

pnpm exec fgd fleet-vulns --summary-only

If npm audit is rate-limited (429), slow the scan down:

pnpm exec fgd fleet-vulns --delay-ms=8000

Upgrade policy versions interactively and auto-commit (dep(package): bump to version, or dep(): bump N packages with a body listing each bump):

pnpm exec fgd policy-upgrade

Sync dependency policy, run pnpm install, and auto-commit (chore(repo): sync dependency policy):

pnpm exec fgd sync-deps-commit

Upgrade one or more package.json dependencies and auto-commit (dep(package): bump to version, or dep(): bump N packages with a body listing each bump):

pnpm exec fgd policy-upgrade-commit

Same upgrade, then prune unused workspace overrides in a second commit if any can be dropped (this is what the menu's Upgrade packages [interactive, auto-commit] runs):

pnpm exec fgd policy-upgrade-commit --prune-overrides

Fix pnpm audit findings with the smallest change, verify, and auto-commit:

pnpm exec fgd audit-override-commit              # refresh, override, prune, verify, commit
pnpm exec fgd audit-override-commit --no-verify  # skip lint/typecheck/test/build (git hooks still run)
pnpm exec fgd audit-override-commit --no-commit  # leave the changes in the working tree
pnpm exec fgd audit-override-commit --allow-major --allow-young --bump-direct  # force without asking
  1. Runs pnpm audit and refreshes the vulnerable packages in the lockfile (pnpm update <names>). Each moves to the newest version its parents' ranges already allow, so no override is needed.

  2. Audits again. When a patched version exists but a parent's range blocks it, adds a tight override to pnpm-workspace.yaml: 'name@>=installed <patched': 'patched' (the lowest patched version).

  3. Asks, one package at a time, before going further than that:

    • the only patch is in a new major: override across the major anyway (--allow-major)
    • the patch is younger than minimumReleaseAge: allow it by adding name@version to minimumReleaseAgeExclude (--allow-young). Step 5 removes the entry once it is old enough.
    • the package is a direct dependency: bump it in package.json, keeping the ^/~ prefix (--bump-direct)

    Without a terminal (CI) these are only reported unless the flag is passed. Findings with no patch are always reported (candidate for a suppression, see step 6). Forced changes go through the same checks in step 7.

  4. Prunes overrides that no longer change the audit.

  5. Removes minimumReleaseAgeExclude entries that are no longer needed (see prune-release-age-exclude below). This step also runs when pnpm audit is clean.

  6. If findings that are still reported have active (not expired) <suppress> entries in fg-devkit's shared configs/dependency-check-suppressions.xml, writes the repo's dependency-check-suppressions.xml with only those entries, so OWASP Dependency-Check accepts exactly the risks this repo has. Findings with no patch and no suppression are listed so you can add one.

  7. Installs and runs the repo's lint-check, lint:ts, test, test:unit and build scripts when present. Nothing is committed if a check fails.

  8. Commits the lockfile refresh (vuln(package): refresh lockfile / vuln(): refresh N packages in lockfile), the direct bumps (vuln(package): bump to version / vuln(): bump N dependencies), the override changes (vuln(package): override version, vuln(): override N packages), the release-age excludes (chore(repo): prune minimumReleaseAgeExclude) and the suppressions file (chore(repo): sync dependency-check suppressions) separately.

Report, remove, or remove and auto-commit workspace overrides that no longer change pnpm audit:

pnpm exec fgd prune-overrides
pnpm exec fgd prune-overrides --fix
pnpm exec fgd prune-overrides --commit

Report, remove, or remove and auto-commit minimumReleaseAgeExclude entries that are no longer needed:

pnpm exec fgd prune-release-age-exclude
pnpm exec fgd prune-release-age-exclude --fix
pnpm exec fgd prune-release-age-exclude --commit

A pinned version (name@1.2.3 or name@1.2.3 || 1.2.4) is only needed while it is in the lockfile and younger than minimumReleaseAge (1440 minutes unless configured). Versions that are old enough, or no longer installed, are removed, and an entry with no versions left is removed entirely. Name rules such as my-package or @scope/* allow every future release on purpose and are always kept. With --fix the lockfile is re-verified against the release-age policy, and pnpm-workspace.yaml is restored if pnpm rejects it.

tsconfig in consuming repos

Use fgd sync-project-configs (or fgd sync-tooling-configs) to write the local tsconfig.json template from fg-devkit.

Do not use an extends-only tsconfig.json to fg-devkit/tsconfig.app.sync.json in consuming repos. TypeScript resolves include/exclude relative to the extended config file location in node_modules, which can cause No inputs were found.

The supported approach is: keep a local tsconfig.json file in each consuming repo and let sync overwrite it with the shared app template.

Minimal local Prettier config for consuming repos

Use this as your local prettier.config.js to inherit defaults from fg-devkit:

import basePrettierConfig from 'fg-devkit/prettier.config.js'

export default {
  ...basePrettierConfig,
}

Piwik PRO custom dimensions

Compare the local slot map with a Piwik PRO site, then create missing dimensions or rename existing ones. Run it from a consuming repo.

The local map is src/analytics/dimensions.ts (customDimensions = event, sessionDimensions = session) or src/util/piwikDimensions.ts (CustomDimensions / SessionCustomDimensions). The site defaults to the first non-production entry in src/config/env.ts, such as preprod. Pass --env production to target production.

pnpm exec fgd piwik list
pnpm exec fgd piwik list --local
pnpm exec fgd piwik diff
pnpm exec fgd piwik add --dry-run
pnpm exec fgd piwik sync --yes
pnpm exec fgd piwik pull --env preprod --dry-run
pnpm exec fgd piwik compare --from preprod --to production
pnpm exec fgd piwik migrate --from preprod --to production --dry-run

sync copies the local map up to the selected Piwik site: it creates missing dimensions, then renames existing ones. It does not edit the repo. pull copies tracking ids from that site down into the local map for keys with the same name.

compare checks two sites from src/config/env.ts against each other. Event and session dimensions match on tracking_id, so a different slot on the other site is still in sync. migrate copies names, descriptions, and missing dimensions from --from onto --to, one create at a time. It stops if Piwik assigns a different tracking_id. Dimensions that exist only on the target stay there.

Set PIWIK_CLIENT_ID and PIWIK_CLIENT_SECRET in the environment, .env.local, or env.local. Optional piwik/.piwik.json can set account, websiteId, environment, dimensionsFile, and names (local key to Piwik label).

Session and event slots are assigned by Piwik as the next free number in that scope. The command creates one dimension at a time and stops if the returned slot is not the local slot. Deactivating a dimension does not free the slot. Product dimensions send the local slot (1–20).

Local fds-vue-core in a consuming repo

Replaces the yalc flow. Clone fds-vue-core next to the consuming repo, then in the consuming repo:

pnpm exec fgd link-fds-vue-core          # or: link-fds-vue-core ../path/to/fds-vue-core

It builds fds-vue-core, sets the dependency to file:../fds-vue-core and runs pnpm install. pnpm copies the build into node_modules and resolves vue from the consuming repo, so there is one vue at runtime and in the types. The command keeps watching fds-vue-core/src: each change rebuilds, reinstalls and restarts a running Vite dev server. Ctrl+C stops watching; --no-watch links without watching.

When fds-vue-core has a build:assets script, the watch uses vite build --watch plus build:assets instead of the full pnpm build (about 11 s instead of about 21 s per change). Types still come from vite-plugin-dts; only the extra vue-tsc type check is skipped, so a type error in fds-vue-core does not stop the update.

To link several repos at once, run link-fds-vue-core in each. The first one watches; the others only join its list of linked repos (kept in fds-vue-core/node_modules/.fg-devkit-linked-consumers.json). One build then updates every linked repo.

Before committing:

pnpm exec fgd unlink-fds-vue-core

This restores the version from the last commit. The shared Lefthook pre-commit hook runs fgd check-local-links and blocks commits where the staged package.json or pnpm-lock.yaml has a file: or link: dependency.

Local development with pnpm link

Use this flow to test local fg-devkit changes in a consuming repo.

In this repo (fg-devkit):

pnpm install
pnpm link --global

In the consuming repo:

pnpm link --global fg-devkit
pnpm install
pnpm exec fgd --help

To remove the global link in a consuming repo:

pnpm unlink fg-devkit
pnpm install

Install CLI in this repo

  1. Add this to your shell config (~/.zshrc) and update FGD_DEVKIT_PATH:
cat <<'EOF' >> ~/.zshrc
# Smart fgd: use local project binary when available, otherwise fg-devkit script
unalias fgd 2>/dev/null
export FGD_DEVKIT_PATH="/Users/username/projects/fg-devkit"
fgd() {
  if [ -x "./node_modules/.bin/fgd" ]; then
    pnpm exec fgd "$@"
  else
    node "$FGD_DEVKIT_PATH/scripts/fg-devkit.mjs" "$@"
  fi
}
EOF
  1. Reload shell config:
source ~/.zshrc

Related Packages

vue-eslint-standard

quickly start eslint in vue

3,269 1
@vue/eslint-config-prettier

eslint-config-prettier for create-vue

50,414,279 86
@takamachi/eslint-config

ESLint rules for macchiitaka

2,500 0
@uscreen.de/eslint-config-prettystandard-vue

ESLint sharable config: prettier & standard for vue

1,039 1
@forsakringskassan/eslint-config-vue

Försäkringskassans eslint shareable vue config

286,740 0

Version History

Version Released License
1.27.0 Proprietary
1.26.0 Proprietary
1.25.1 Proprietary
1.25.0 Proprietary
1.24.4 Proprietary