@oneflash/setup
v1.2.2
Published
Bootstrap a developer machine for OneFlash repos: PAT in ~/.npmrc, global knowledge clone.
Readme
@oneflash/setup
One-shot bootstrap CLI for OneFlash developer machines. Installs the GitLab Personal Access Token into ~/.npmrc and clones shared domain knowledge into a platform-native path.
Consumer repos depend on @oneflash/shared, whose postinstall keeps the clone fresh on every install. This CLI handles the one-time setup that the postinstall alone can't.
The @-import that wires the clone into Claude lives in each consumer repo's committed .claude/CLAUDE.md. This CLI does not touch the user-global ~/.claude/CLAUDE.md — Claude context is a per-project concern.
Usage
# One-shot bootstrap (first time on a machine)
npx @oneflash/setup
# Check state without writing anything
npx @oneflash/setup --verify
# Diagnose + suggest fixes
npx @oneflash/setup --doctor
# Apply the fixes
npx @oneflash/setup --fix
# Print the saved token, wipe state, re-run setup
npx @oneflash/setup --reset
# Remove everything this CLI installed
npx @oneflash/setup --uninstallNon-interactive use
Preferred: OF_SETUP_TOKEN env var. Safer than --token= because the PAT doesn't appear in ps output or shell history.
OF_SETUP_TOKEN=glpat-xxxxxxxxxxxx npx @oneflash/setup --non-interactivePairs cleanly with password-manager CLIs (the token never touches disk or history):
# 1Password CLI
op run --env-file=.env -- npx @oneflash/setup --non-interactive
# direnv / .envrc
npx @oneflash/setup --non-interactive # OF_SETUP_TOKEN loaded by direnvFallback: --token= flag. Still works but emits a warning — the PAT appears in ps aux and shell history.
npx @oneflash/setup --token=glpat-xxxxxxxxxxxx --non-interactivePrecedence when more than one source is set: --token= > OF_SETUP_TOKEN > existing token in ~/.npmrc. Use OF_SETUP_TOKEN=<new-pat> to rotate a PAT even when the old one is still in ~/.npmrc.
Fails cleanly with exit code 1 if no token source is found while --non-interactive is set. The CLI refuses to run at all when $CI is set.
What it writes
| Target | Content | Scope |
|---|---|---|
| ~/.npmrc | Marker block with two _authToken lines (instance + project endpoints) | User |
| ~/.config/oneflash-shared (Linux/macOS) or ~/AppData/Local/oneflash/shared (Windows Git Bash) | Sparse clone of oneflash/oneflash-shared (knowledge/ + CLAUDE.md) | User |
The CLI does not touch any other user- or repo-local file. The @-import that points Claude at the clone belongs in each consumer repo's committed .claude/CLAUDE.md, not in ~/.claude/CLAUDE.md (a machine-local file the developer owns).
Security notes
~/.npmrcis written atomically (tmp file + rename) andchmod 600. If chmod fails on POSIX, the CLI warns instead of silently leaving a world-readable PAT file.- PATs are never logged or echoed. Token input is masked in the TTY.
- Prefer
OF_SETUP_TOKENenv var over--token=— argv is visible inps auxand shell history. - The CLI validates the PAT against GitLab's
/userendpoint before writing it anywhere. - If GitLab returns PAT metadata, the CLI warns when expiry is within 14 days.
- Required PAT scope:
read_api. (On current GitLab this single scope covers both the API and the package registry — the formerread_package_registrywas folded intoread_api.) Theoneflash-sharedclone is public, so no repository scope is needed. Do NOT create PATs withwrite_*for this flow.
Commands
Default (oneflash-setup)
Interactive bootstrap. Prompts for a PAT, validates it, writes ~/.npmrc, clones into the platform path (or pulls if the clone exists). Idempotent: re-running with a good token is a safe no-op.
--verify
Read-only. Prints pass/fail for every expected piece of state. Exit 0 if all pass, exit 1 otherwise.
Checks:
giton PATH~/.npmrchas the managed block- no conflicting
_authTokenlines outside the block - GitLab token is valid
- token is not within 14 days of expiry
- clone dir exists
- clone's
originremote matches the allowlist - clone is on
main - clone
HEADis younger than 30 days - clone
CLAUDE.mdis present (catches partial sparse-checkout)
--doctor / --fix
--doctor lists fixes the CLI would apply (nothing is written). --fix applies them — equivalent to --doctor --fix.
Fixes:
- rewrites
~/.npmrcmanaged block (tightens perms, normalizes format) - rewrites the clone's
originURL if it drifted from the allowlist - resets
core.autocrlf=false+core.filemode=falseon the clone - runs
git pull --ff-onlyonce remote and config are normalized
Branch drift (e.g., clone checked out onto feat/xyz) is flagged but not auto-switched. The CLI assumes you have local work and refuses to clobber it.
--reset
Prints the token saved in ~/.npmrc, removes the managed block and the clone dir (with its local git config), then re-runs setup. By default the saved token is reused for the fresh setup, so you don't need to re-paste it. To start with a different token, pass --token=<pat> or set OF_SETUP_TOKEN — both take precedence over the saved one.
Prompts for confirmation unless --yes is passed. Useful when the clone gets into a broken state and you want a clean re-install without losing your token.
--uninstall
Removes the managed block from ~/.npmrc and the clone dir. Prompts for confirmation unless --yes is passed.
Exit codes
| Code | Meaning |
|---|---|
| 0 | success (or nothing to fix) |
| 1 | user-recoverable (bad token, missing clone, etc.) |
| 2 | system error (git not installed, can't write ~/.npmrc) |
Scope
The CLI deliberately does NOT:
- rotate tokens on your behalf (no
POST /personal_access_tokens) - write to any repo-local file
- touch
~/.claude/CLAUDE.md(per-project@-imports live in each consumer repo's committed.claude/CLAUDE.md) - run when
$CIis set (the whole premise is dev-machine bootstrap) - manage a shell env var or
.envrc
Anything outside that list belongs somewhere else.
Development
pnpm install
pnpm build # tsc → dist/
pnpm typecheck
pnpm test # tsx --test (covers markers, npmrc, gitlab, git, token source)Zero runtime dependencies. Only node:* stdlib + fetch (Node 20+).
Publishing
This package is published to the public npm registry so npx @oneflash/setup works on a machine with no prior OneFlash config.
