Skip to content

add Claude Code setup - #59

Merged
irahopkinson merged 1 commit into
mainfrom
add-claude-code-setup
Aug 6, 2026
Merged

add Claude Code setup#59
irahopkinson merged 1 commit into
mainfrom
add-claude-code-setup

Conversation

@irahopkinson

Copy link
Copy Markdown
Collaborator

Adds Claude Code configuration to this repo, adapted from the sibling
scripture-editors repo and adjusted for this one being npm + a single-package
library rather than pnpm + an Nx monorepo.

No runtime impact: no dependencies change, no build tooling or existing script
changed, and the one new devDependency is never published (files ships dist
and src only).

What's here

CLAUDE.md — commands, CI-matching verification steps, the public API map,
and the port-fidelity rule from the README's Contributing section. It also
records three things that are easy to get wrong:

  • There is no typecheck script, and lint is not a substitute. ESLint's
    type-checked rules consume type information but never report compile errors.
    Test files are type-checked by nothing CI runs — npx tsc -p tsconfig.test.json --noEmit is the command for that.
  • Dependency updates — this repo takes security Dependabot PRs only, and
    since there are no runtime dependencies, advisories never reach consumers.
    Dependabot's lockfiles are not idempotent, so re-resolve and diff before
    accepting one. One residual brace-expansion advisory is known and accepted;
    pinning minimatch@^10 via overrides silently breaks lint.
  • Known porting gaps — members that exist but don't behave like the C#, so a
    ported test can fail for reasons not visible in the source (internalValid()'s
    commented-out range check, isExcluded hardcoded false, set verseNum
    missing the negative guard, BBBCCCVVVS unimplemented, the numeric constructor
    bypassing setters, the BookSet stub).

.claude/settings.json — shared permissions. Every Bash(...) deny/ask rule
has a PowerShell(...) twin, since Bash patterns don't match PowerShell calls and
PowerShell is the primary shell on Windows.

.claude/skills/typescript-lsp-volta/ — a committed skills-directory plugin
providing go-to-definition, find-references and diagnostics, plus
typescript-language-server as a devDependency. It replaces the official
typescript-lsp plugin, which needs a global install and, on Windows, spawns the
binary shell-free so it cannot launch Volta's .cmd shim (ENOENT: uv_spawn).
This one runs the server through node, which works under Volta on every OS.

.mcp.json + scripts/mcp-launcher.mjs — Context7 as a single team-wide
server. settings.json disables the equivalent personal plugin for this project
only, so contributors who have it keep it in their other repos and there's no
post-merge cleanup to remember.

.gitignore, tsconfig.lint.json — track settings.json and skills/ while
keeping local-only files out; let eslint . type-check the launcher.

A caveat worth reading

The permission deny list is defence in depth, not a boundary. Matching is
prefix-based over tokens, so a rule only fires on the exact spelling it names.
Verified during review: git push --force origin main is denied, while
git push origin main --force — the same operation with the flag moved — is not.
A PreToolUse hook is the only form immune to reordering, and is the natural
follow-up if we want a real boundary.

Verification

lint, prettier:ci, build, test:ci (43/43) and
npx tsc -p tsconfig.test.json --noEmit all exit 0. Context7 completes an MCP
handshake through the launcher, and the language server completes an LSP
initialize handshake advertising definitionProvider and referencesProvider.

🤖 Generated with Claude Code

Adapted from the sibling scripture-editors repo, adjusted for this repo being
npm + a single-package library rather than pnpm + an Nx monorepo.

Config
------

- .claude/settings.json: shared permissions. Every Bash(...) deny/ask rule has a
  PowerShell(...) twin, since Bash patterns don't match PowerShell calls and
  PowerShell is the primary shell on Windows. Covers the Remove-Item aliases
  (del/rd/ri/erase), sudo, and Invoke-Expression/iex.

  These raise the bar rather than making the guardrails sound. Matching is
  prefix-based over tokens, so a rule only fires on the spelling it names:
  verified that `git push --force origin main` is denied while
  `git push origin main --force` -- same operation, flag moved -- is not. Treat
  the deny list as defence in depth, not a boundary. A PreToolUse hook is the
  only form immune to reordering.

  Editing this file is in `ask` rather than `deny`: denying it locks out routine
  maintenance, while `ask` still prevents Claude silently widening its own
  permissions.

- .claude/skills/typescript-lsp-volta/: committed skills-directory plugin giving
  go-to-definition, find-references and diagnostics. It replaces the official
  typescript-lsp plugin (explicitly set to false), which requires a global
  install and, on Windows, spawns the binary shell-free so it cannot launch
  Volta's .cmd shim and dies with ENOENT: uv_spawn. This one runs the server via
  `node node_modules/typescript-language-server/lib/cli.mjs --stdio`, which works
  under Volta on every OS.

- package.json: adds typescript-language-server as a devDependency, required by
  the above. Dev-only -- `files` publishes dist and src, so it is never shipped.
  No build tooling or existing scripts changed.

- .mcp.json + scripts/mcp-launcher.mjs: Context7, as the single team-wide server.
  settings.json sets context7@claude-plugins-official to false so a personal
  copy of that plugin is disabled for this project only, leaving other repos
  alone -- no post-merge cleanup to remember, and it reverts with the branch.
  The launcher is ESM rather than the sibling's CJS so it passes this repo's
  type-checked ESLint, and spawns cmd.exe explicitly instead of using
  `shell: true`, which Node 24 (pinned here) deprecates via DEP0190. That is not
  argument-hardening: both forms are equally injectable, which is acceptable only
  because .mcp.json already names the command to execute.

- tsconfig.lint.json: include scripts/**/*.mjs, matching how the other root tool
  configs are already listed, so `eslint .` can type-check the launcher.

- .gitignore: switch the Claude block to `.claude/*` plus negations so
  settings.json and skills/ stay tracked while local-only files don't.

Documentation
-------------

CLAUDE.md records commands, CI-matching verification, the public API map, and
the port-fidelity rule from README's Contributing section, plus three things
learned the hard way:

- There is no typecheck script, and lint is not a substitute. ESLint's
  type-checked rules consume type information but never report compile errors,
  so only tsc catches those. Test files are type-checked by nothing CI runs;
  `npx tsc -p tsconfig.test.json --noEmit` is the command for that.

- Dependency updates: this repo takes security Dependabot PRs only, and there
  are no runtime dependencies, so advisories never reach consumers. Dependabot's
  lockfiles are not idempotent -- the baseline is that
  `npm install --package-lock-only` on main is a no-op, so re-resolve and diff
  before accepting one. One residual brace-expansion advisory is known and
  accepted; pinning minimatch@^10 through overrides silently breaks lint, and
  the reason is narrower than it looks -- it is v10's ESM build that lacks a
  default export, while its CommonJS build has one.

- Known porting gaps: members that exist but don't behave like the C#, so a
  ported test can fail for reasons that aren't visible in the source --
  internalValid()'s commented-out range check, isExcluded hardcoded false,
  set verseNum missing the negative guard and `verse = null`, BBBCCCVVVS
  declared not implemented, the numeric constructor bypassing the setters, and
  the BookSet stub.

Verified: lint, prettier:ci, build, test:ci (43/43) and
`npx tsc -p tsconfig.test.json --noEmit` all exit 0. Context7 completes an MCP
handshake through the launcher, and the language server completes an LSP
initialize handshake advertising definitionProvider and referencesProvider.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.93%. Comparing base (766361c) to head (eb15e6f).

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #59   +/-   ##
=======================================
  Coverage   83.93%   83.93%           
=======================================
  Files           4        4           
  Lines         330      330           
  Branches       77       77           
=======================================
  Hits          277      277           
  Misses         33       33           
  Partials       20       20           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@irahopkinson
irahopkinson merged commit 32d457b into main Aug 6, 2026
3 checks passed
@irahopkinson
irahopkinson deleted the add-claude-code-setup branch August 6, 2026 02:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant