Align repo config with global development standards
Some checks failed
CI / backend-lint (push) Failing after 1m4s
CI / actions-lint (push) Failing after 6s
CI / frontend-lint (push) Successful in 59s

- Add missing tsconfig strictness flags (noUncheckedIndexedAccess,
  exactOptionalPropertyTypes, noImplicitOverride,
  noPropertyAccessFromIndexSignature) and fix all resulting type errors
- Replace ESLint/Prettier with oxlint 1.48.0 and oxfmt 0.33.0
- Pin all frontend and backend dependencies to exact versions
- Pin GitHub Actions to SHA hashes with persist-credentials: false
- Fix CI Python version mismatch (3.12 -> 3.14) and ruff target-version
- Add vitest 4.0.18 with jsdom environment for frontend testing
- Add ty 0.0.17 for Python type checking (non-blocking in CI)
- Add actionlint and zizmor CI job for workflow linting and security audit
- Add Dependabot config for npm, pip, and github-actions
- Update CLAUDE.md and pre-commit hooks to reflect new tooling
- Ignore Claude Code sandbox artifacts in gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 20:39:41 +01:00
parent e4814250db
commit 3a64661760
91 changed files with 2073 additions and 3215 deletions

View File

@@ -18,10 +18,7 @@ interface LegEntry {
type PresetType = 'true' | 'normal' | 'custom' | null
function buildLegsFromPreset(
regions: Region[],
preset: 'true' | 'normal'
): LegEntry[] {
function buildLegsFromPreset(regions: Region[], preset: 'true' | 'normal'): LegEntry[] {
const legs: LegEntry[] = []
for (const region of regions) {
const targetSlug =
@@ -45,8 +42,7 @@ export function NewGenlocke() {
const [name, setName] = useState('')
const [legs, setLegs] = useState<LegEntry[]>([])
const [preset, setPreset] = useState<PresetType>(null)
const [nuzlockeRules, setNuzlockeRules] =
useState<NuzlockeRules>(DEFAULT_RULES)
const [nuzlockeRules, setNuzlockeRules] = useState<NuzlockeRules>(DEFAULT_RULES)
const [genlockeRules, setGenlockeRules] = useState<GenlockeRules>({
retireHoF: false,
})
@@ -64,9 +60,7 @@ export function NewGenlocke() {
}
const handleGameChange = (index: number, game: Game) => {
setLegs((prev) =>
prev.map((leg, i) => (i === index ? { ...leg, game } : leg))
)
setLegs((prev) => prev.map((leg, i) => (i === index ? { ...leg, game } : leg)))
}
const handleRemoveLeg = (index: number) => {
@@ -75,8 +69,7 @@ export function NewGenlocke() {
const handleAddLeg = (region: Region) => {
const defaultSlug = region.genlockeDefaults.normalGenlocke
const game =
region.games.find((g) => g.slug === defaultSlug) ?? region.games[0]
const game = region.games.find((g) => g.slug === defaultSlug) ?? region.games[0]
if (game) {
setLegs((prev) => [...prev, { region: region.name, game }])
}
@@ -87,7 +80,7 @@ export function NewGenlocke() {
if (target < 0 || target >= legs.length) return
setLegs((prev) => {
const next = [...prev]
;[next[index], next[target]] = [next[target], next[index]]
;[next[index], next[target]] = [next[target]!, next[index]!]
return next
})
}
@@ -115,23 +108,16 @@ export function NewGenlocke() {
)
}
const enabledRuleCount = RULE_DEFINITIONS.filter(
(r) => nuzlockeRules[r.key]
).length
const enabledRuleCount = RULE_DEFINITIONS.filter((r) => nuzlockeRules[r.key]).length
const totalRuleCount = RULE_DEFINITIONS.length
// Regions not yet used in legs (for "add leg" picker)
const availableRegions =
regions?.filter((r) => !legs.some((l) => l.region === r.name)) ?? []
const availableRegions = regions?.filter((r) => !legs.some((l) => l.region === r.name)) ?? []
return (
<div className="max-w-4xl mx-auto p-8">
<h1 className="text-3xl font-bold text-gray-900 dark:text-gray-100 mb-2">
New Genlocke
</h1>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Set up your generational challenge.
</p>
<h1 className="text-3xl font-bold text-gray-900 dark:text-gray-100 mb-2">New Genlocke</h1>
<p className="text-gray-600 dark:text-gray-400 mb-6">Set up your generational challenge.</p>
<StepIndicator currentStep={step} onStepClick={setStep} steps={STEPS} />
@@ -250,17 +236,11 @@ export function NewGenlocke() {
)}
{/* Also allow adding extra regions for presets */}
{preset &&
preset !== 'custom' &&
availableRegions.length > 0 &&
legs.length > 0 && (
<div className="mt-4">
<AddLegDropdown
regions={availableRegions}
onAdd={handleAddLeg}
/>
</div>
)}
{preset && preset !== 'custom' && availableRegions.length > 0 && legs.length > 0 && (
<div className="mt-4">
<AddLegDropdown regions={availableRegions} onAdd={handleAddLeg} />
</div>
)}
<div className="mt-6 flex justify-between">
<button
@@ -285,10 +265,7 @@ export function NewGenlocke() {
{/* Step 3: Rules */}
{step === 3 && (
<div>
<RulesConfiguration
rules={nuzlockeRules}
onChange={setNuzlockeRules}
/>
<RulesConfiguration rules={nuzlockeRules} onChange={setNuzlockeRules} />
{/* Genlocke-specific rules */}
<div className="mt-6 bg-white dark:bg-gray-800 rounded-lg shadow">
@@ -319,8 +296,7 @@ export function NewGenlocke() {
Keep Hall of Fame
</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
Pokemon that beat the Elite Four can continue to the
next leg
Pokemon that beat the Elite Four can continue to the next leg
</div>
</div>
</label>
@@ -337,8 +313,8 @@ export function NewGenlocke() {
Retire Hall of Fame
</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
Pokemon that beat the Elite Four are retired and cannot
be used in the next leg
Pokemon that beat the Elite Four are retired and cannot be used in the next
leg
</div>
</div>
</label>
@@ -354,8 +330,8 @@ export function NewGenlocke() {
Naming Scheme
</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">
Get nickname suggestions from a themed word list when catching
Pokemon. Applied to all legs.
Get nickname suggestions from a themed word list when catching Pokemon. Applied to
all legs.
</p>
</div>
<div className="px-4 py-4">
@@ -402,12 +378,8 @@ export function NewGenlocke() {
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 space-y-4">
<div>
<h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">
Name
</h3>
<p className="text-gray-900 dark:text-gray-100 font-medium">
{name}
</p>
<h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">Name</h3>
<p className="text-gray-900 dark:text-gray-100 font-medium">{name}</p>
</div>
<div className="border-t border-gray-200 dark:border-gray-700 pt-4">
@@ -426,8 +398,7 @@ export function NewGenlocke() {
{leg.game.name}
</span>
<span className="text-sm text-gray-500 dark:text-gray-400 ml-2">
{leg.region.charAt(0).toUpperCase() +
leg.region.slice(1)}
{leg.region.charAt(0).toUpperCase() + leg.region.slice(1)}
</span>
</div>
</li>
@@ -436,34 +407,25 @@ export function NewGenlocke() {
</div>
<div className="border-t border-gray-200 dark:border-gray-700 pt-4">
<h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">
Rules
</h3>
<h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">Rules</h3>
<dl className="space-y-1 text-sm">
<div className="flex justify-between">
<dt className="text-gray-600 dark:text-gray-400">
Nuzlocke Rules
</dt>
<dt className="text-gray-600 dark:text-gray-400">Nuzlocke Rules</dt>
<dd className="text-gray-900 dark:text-gray-100 font-medium">
{enabledRuleCount} of {totalRuleCount} enabled
</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-600 dark:text-gray-400">
Hall of Fame
</dt>
<dt className="text-gray-600 dark:text-gray-400">Hall of Fame</dt>
<dd className="text-gray-900 dark:text-gray-100 font-medium">
{genlockeRules.retireHoF ? 'Retire' : 'Keep'}
</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-600 dark:text-gray-400">
Naming Scheme
</dt>
<dt className="text-gray-600 dark:text-gray-400">Naming Scheme</dt>
<dd className="text-gray-900 dark:text-gray-100 font-medium">
{namingScheme
? namingScheme.charAt(0).toUpperCase() +
namingScheme.slice(1)
? namingScheme.charAt(0).toUpperCase() + namingScheme.slice(1)
: 'None'}
</dd>
</div>
@@ -548,9 +510,7 @@ function LegRow({
))}
</select>
) : (
<div className="text-gray-900 dark:text-gray-100 font-medium">
{leg.game.name}
</div>
<div className="text-gray-900 dark:text-gray-100 font-medium">{leg.game.name}</div>
)}
</div>
<div className="flex items-center gap-1 shrink-0">
@@ -568,11 +528,7 @@ function LegRow({
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M5 15l7-7 7 7"
/>
<path strokeLinecap="round" strokeLinejoin="round" d="M5 15l7-7 7 7" />
</svg>
</button>
<button
@@ -589,11 +545,7 @@ function LegRow({
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M19 9l-7 7-7-7"
/>
<path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
</svg>
</button>
<button
@@ -609,11 +561,7 @@ function LegRow({
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M6 18L18 6M6 6l12 12"
/>
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
@@ -644,11 +592,7 @@ function AddLegDropdown({
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M12 4v16m8-8H4"
/>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4v16m8-8H4" />
</svg>
Add Region
</button>