{"_id":"@charles_lindecker/pvzf-console","_rev":"6-5ec96b64d58337616a7ac5dab5e57ff9","name":"@charles_lindecker/pvzf-console","dist-tags":{"latest":"1.6.0"},"versions":{"1.0.0":{"name":"@charles_lindecker/pvzf-console","version":"1.0.0","keywords":["pvz","plants-vs-zombies","fusion","translation","localization","cli","trello"],"author":{"name":"Charles Lindecker","email":"charles.lindecker@outlook.fr"},"license":"MIT","_id":"@charles_lindecker/pvzf-console@1.0.0","maintainers":[{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"}],"homepage":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager#readme","bugs":{"url":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager/issues"},"bin":{"pvzf-console":"bin/pvzf-console.js"},"dist":{"shasum":"d2148bb67d776773599b0734ca9194170314ac5e","tarball":"https://registry.npmjs.org/@charles_lindecker/pvzf-console/-/pvzf-console-1.0.0.tgz","fileCount":37,"integrity":"sha512-ioDwcRWTqA45QrOlsfC4OdYZhJaRi8qAh06ClmQ1Qihtqhxkpl8uTA4wj7rJGXoqs+AyBtdRTMUlr2QHsuuBWA==","signatures":[{"sig":"MEYCIQC760DwxtHLLr+3vIufkNuyeGbO/gli7/HBoANrCSxYhgIhAJ9F4IB2eRVtYsXqCLs31PxoG3gW4ck0l3p2dR32ndxL","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":179397},"engines":{"node":">=14"},"gitHead":"40de05e0362e78bb782f0855529b1fda82e2fcdb","scripts":{"build":"node bin/build.js","prepublishOnly":"node bin/build.js"},"_npmUser":{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"},"repository":{"url":"git+https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager.git","type":"git"},"_npmVersion":"11.7.0","description":"Translation toolkit for Plants vs Zombies: Fusion. Scans localization files, generates per-locale reports, and exports Trello CSVs.","directories":{},"_nodeVersion":"22.16.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/pvzf-console_1.0.0_1776621220500_0.17544011456243513","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@charles_lindecker/pvzf-console","version":"1.2.0","keywords":["pvz","plants-vs-zombies","fusion","translation","localization","cli","trello"],"author":{"name":"Charles Lindecker","email":"charles.lindecker@outlook.fr"},"license":"MIT","_id":"@charles_lindecker/pvzf-console@1.2.0","maintainers":[{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"}],"homepage":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager#readme","bugs":{"url":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager/issues"},"bin":{"pvzf-console":"bin/pvzf-console.js"},"dist":{"shasum":"b799b164238098f061303c08166c0e0eb7839760","tarball":"https://registry.npmjs.org/@charles_lindecker/pvzf-console/-/pvzf-console-1.2.0.tgz","fileCount":151,"integrity":"sha512-cc+LqZGXvlrybI8uSxQecs7sksOCcYZEzNfzo9e4ywi3SAq8UyVQFm+RfG6xh1O0Eiw5AKxg+9lYFd3fLbHTBA==","signatures":[{"sig":"MEQCIDmOuHIpqhbiPtM9/spADufhpDpjGBlhkNBflyWEGhR3AiBkcgOLZ7rUkAazXnmvk5Dx0QJQ9HDFw1VqYK57F2nHVw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13380001},"engines":{"node":">=14"},"gitHead":"33ff2813f945be66b1e521ee620f07ee3cdbbd81","scripts":{"build":"node bin/build.js","prepublishOnly":"node bin/build.js"},"_npmUser":{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"},"repository":{"url":"git+https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager.git","type":"git"},"_npmVersion":"11.7.0","description":"Translation toolkit for Plants vs Zombies: Fusion. Scans localization files, generates per-locale reports, and exports Trello CSVs.","directories":{},"_nodeVersion":"22.16.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/pvzf-console_1.2.0_1776716189270_0.0229607861832275","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@charles_lindecker/pvzf-console","version":"1.3.0","keywords":["pvz","plants-vs-zombies","fusion","translation","localization","cli","trello"],"author":{"name":"Charles Lindecker","email":"charles.lindecker@outlook.fr"},"license":"MIT","_id":"@charles_lindecker/pvzf-console@1.3.0","maintainers":[{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"}],"homepage":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager#readme","bugs":{"url":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager/issues"},"bin":{"pvzf-console":"bin/pvzf-console.js"},"dist":{"shasum":"b8e3e60804a271eec8eb827f5952423156e49013","tarball":"https://registry.npmjs.org/@charles_lindecker/pvzf-console/-/pvzf-console-1.3.0.tgz","fileCount":154,"integrity":"sha512-JXQxNFEoig3rZUV9KwxNGUE9U+x8NF/ER8unASJo0xFsxl0tBao+0odv7o73dl+wiQDoqkvFKQEqHN0XMO8RaA==","signatures":[{"sig":"MEUCIGKClqrfiBVP9sqOSNAvP85vUPfll5Rl2nOlfBnwNR8oAiEA3mVMGbWAQQdNQGo2Rfmvp1tM57VTfdCFsQgG9WantHU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13412507},"engines":{"node":">=20"},"gitHead":"e3dbbac31ac68d6fa9ab0a2d7fd15d719762103a","scripts":{"test":"node --test tests-js/build.test.js tests-js/pvzf-console.test.js","build":"node bin/build.js","test:cov":"c8 --reporter=text --reporter=lcov --include=bin/*.js --lines=75 --functions=75 --branches=75 --statements=75 node --test tests-js/build.test.js tests-js/pvzf-console.test.js","prepublishOnly":"node bin/build.js"},"_npmUser":{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"},"repository":{"url":"git+https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager.git","type":"git"},"_npmVersion":"11.13.0","description":"Translation toolkit for Plants vs Zombies: Fusion. Scans localization files, generates per-locale reports, and exports Trello CSVs.","directories":{},"_nodeVersion":"22.22.2","_hasShrinkwrap":false,"devDependencies":{"c8":"^10.1.2"},"_npmOperationalInternal":{"tmp":"tmp/pvzf-console_1.3.0_1777719872878_0.005873615487738126","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@charles_lindecker/pvzf-console","version":"1.4.0","keywords":["pvz","plants-vs-zombies","fusion","translation","localization","cli","trello"],"author":{"name":"Charles Lindecker","email":"charles.lindecker@outlook.fr"},"license":"MIT","_id":"@charles_lindecker/pvzf-console@1.4.0","maintainers":[{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"}],"homepage":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager#readme","bugs":{"url":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager/issues"},"bin":{"pvzf-console":"dist/cli.js"},"dist":{"shasum":"7d89a09d9b255163b5eb72e41509604f9977ee55","tarball":"https://registry.npmjs.org/@charles_lindecker/pvzf-console/-/pvzf-console-1.4.0.tgz","fileCount":8,"integrity":"sha512-TfTKDSjgcpRLLI/RtOZt7tBGhD64flV0AxATW6DwP1cW89v5PEUMiwZqRNK44fR+bCn9/Ed4Q+EB88VWzxAKPA==","signatures":[{"sig":"MEUCIEIMQrOUB3M67gbakeGc9X4MpLdBZxiznoCT0UmiKkO4AiEArCxjV8bz4Ko4QNdFCmjfpetm2cQcbX/4Ggr2UR4ezcg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":296082},"type":"module","engines":{"node":">=20"},"gitHead":"502d86eb764851d8dab2160aa1447ddaea7815ba","scripts":{"dev":"tsx src/cli.ts","lint":"eslint .","test":"vitest run","build":"tsup","test:cov":"vitest run --coverage","typecheck":"tsc --noEmit","lint:security":"eslint . --max-warnings=0","prepublishOnly":"tsup"},"_npmUser":{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"},"repository":{"url":"git+https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager.git","type":"git"},"_npmVersion":"11.17.0","description":"Translation toolkit for Plants vs Zombies: Fusion. Scans localization files, generates per-locale reports, and exports Trello CSVs.","directories":{},"_nodeVersion":"22.23.0","_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.3.5","eslint":"^10.5.0","vitest":"^2.1.8","globals":"^17.7.0","@eslint/js":"^10.0.1","typescript":"^5.7.2","@types/node":"^22.10.0","typescript-eslint":"^8.61.1","@vitest/coverage-v8":"^2.1.8","eslint-plugin-security":"^4.0.1"},"_npmOperationalInternal":{"tmp":"tmp/pvzf-console_1.4.0_1782151562717_0.06181312927442617","host":"s3://npm-registry-packages-npm-production"}},"1.4.1":{"name":"@charles_lindecker/pvzf-console","version":"1.4.1","keywords":["pvz","plants-vs-zombies","fusion","translation","localization","cli","trello"],"author":{"name":"Charles Lindecker","email":"charles.lindecker@outlook.fr"},"license":"MIT","_id":"@charles_lindecker/pvzf-console@1.4.1","maintainers":[{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"}],"homepage":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager#readme","bugs":{"url":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager/issues"},"bin":{"pvzf-console":"dist/cli.js"},"dist":{"shasum":"61dd18b69ba98782354ae361a03411f355b07b2d","tarball":"https://registry.npmjs.org/@charles_lindecker/pvzf-console/-/pvzf-console-1.4.1.tgz","fileCount":8,"integrity":"sha512-k5T8c0aZi+1W9hjhonH+QphjvGSkFoje+spNo9VCj4fvhtV0/moJhXWBNrDS0EzgwhaJnl2MmQMDwcyQpZc5QQ==","signatures":[{"sig":"MEYCIQDDD2ANOm31ntPOFEYNC498BfjokSpZf4+R+bNwF/dtCwIhAPL4zwaE93LgTTtTYprr4K/iPf5qWeP3KU8vGVU8o3jT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":307628},"type":"module","engines":{"node":">=20"},"gitHead":"f5e6d49862c9cccd296d0d1863479bab4f2ec66b","scripts":{"dev":"tsx src/cli.ts","lint":"eslint .","test":"vitest run","build":"tsup","test:cov":"vitest run --coverage","typecheck":"tsc --noEmit","lint:security":"eslint . --max-warnings=0","prepublishOnly":"tsup"},"_npmUser":{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"},"repository":{"url":"git+https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager.git","type":"git"},"_npmVersion":"12.0.1","description":"Translation toolkit for Plants vs Zombies: Fusion. Scans localization files, generates per-locale reports, and exports Trello CSVs.","directories":{},"_nodeVersion":"22.23.1","_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.3.5","eslint":"^10.5.0","vitest":"^4.1.9","globals":"^17.7.0","@eslint/js":"^10.0.1","typescript":"^6.0.3","@types/node":"^26.0.0","typescript-eslint":"^8.61.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-security":"^4.0.1"},"_npmOperationalInternal":{"tmp":"tmp/pvzf-console_1.4.1_1784057366771_0.43819812115734047","host":"s3://npm-registry-packages-npm-production"}},"1.6.0":{"name":"@charles_lindecker/pvzf-console","version":"1.6.0","description":"Translation toolkit for Plants vs Zombies: Fusion. Scans localization files, generates per-locale reports, exports Trello CSVs, and turns the weekly PR recap into contributor documentation.","keywords":["pvz","plants-vs-zombies","fusion","translation","localization","cli","tui","trello","changelog","documentation"],"author":{"name":"Charles Lindecker","email":"charles.lindecker@outlook.fr"},"license":"MIT","type":"module","bin":{"pvzf-console":"dist/cli.js"},"engines":{"node":">=20"},"scripts":{"build":"tsup","prepublishOnly":"tsup","dev":"tsx src/cli.ts","typecheck":"tsc --noEmit","lint":"eslint .","lint:security":"eslint . --max-warnings=0","test":"vitest run","test:cov":"vitest run --coverage"},"devDependencies":{"@eslint/js":"^10.0.1","@types/node":"^26.0.0","@vitest/coverage-v8":"^4.1.9","eslint":"^10.5.0","eslint-plugin-security":"^4.0.1","globals":"^17.7.0","tsup":"^8.3.5","tsx":"^4.19.2","typescript":"^6.0.3","typescript-eslint":"^8.61.1","vitest":"^4.1.9"},"repository":{"type":"git","url":"git+https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager.git"},"overrides":{"esbuild":"^0.28.1"},"dependencies":{"@clack/prompts":"^1.7.0","picocolors":"^1.1.1"},"gitHead":"c2ee3f18efd9477573fdba4e1d64bf2c99417b7b","_id":"@charles_lindecker/pvzf-console@1.6.0","bugs":{"url":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager/issues"},"homepage":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager#readme","_nodeVersion":"22.23.2","_npmVersion":"12.0.2","dist":{"integrity":"sha512-hL7Xtu54zAf2lHCHq9+3JAIUreHPf+t/zNScRK8fx+Ynn4fzM1884+IXOJxrsDmYuNY/FZNToVG1jPdMZSEG4g==","shasum":"6a17e7a8ca2ea3bfc18013b27c7655063baa27c2","tarball":"https://registry.npmjs.org/@charles_lindecker/pvzf-console/-/pvzf-console-1.6.0.tgz","fileCount":8,"unpackedSize":406794,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEDVlg0X8vooyA/ab8JoPlGszbWGshtEBdLZ0Ds2IidgAiEAmnaQvLtmfZ+/wS6Kb5E7pdNb5UcH/sfVdSAQHUL7CZU="}]},"_npmUser":{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"},"directories":{},"maintainers":[{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pvzf-console_1.6.0_1786200969435_0.051073105060924995"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-19T17:53:40.406Z","modified":"2026-08-08T14:56:09.744Z","1.0.0":"2026-04-19T17:53:40.645Z","1.2.0":"2026-04-20T20:16:29.649Z","1.3.0":"2026-05-02T11:04:33.204Z","1.4.0":"2026-06-22T18:06:02.858Z","1.4.1":"2026-07-14T19:29:26.956Z","1.6.0":"2026-08-08T14:56:09.581Z"},"bugs":{"url":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager/issues"},"author":{"name":"Charles Lindecker","email":"charles.lindecker@outlook.fr"},"license":"MIT","homepage":"https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager#readme","keywords":["pvz","plants-vs-zombies","fusion","translation","localization","cli","tui","trello","changelog","documentation"],"repository":{"type":"git","url":"git+https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager.git"},"description":"Translation toolkit for Plants vs Zombies: Fusion. Scans localization files, generates per-locale reports, exports Trello CSVs, and turns the weekly PR recap into contributor documentation.","maintainers":[{"name":"charles_lindecker","email":"charles.lindecker@outlook.fr"}],"readme":"# 🌱 PVZ Fuzion Console Manager\n\n> Translation toolkit for **Plants vs Zombies: Fusion**.\n> Scans every locale against the English source, generates per-locale Markdown\n> reports, migrates the new tips format, checks for duplicates, exports\n> Trello-ready CSV backlogs, and turns the weekly PR recap into contributor\n> documentation.\n\n[![node](https://img.shields.io/badge/node-%E2%89%A520-green)](https://nodejs.org/)\n[![typescript](https://img.shields.io/badge/typescript-strict-blue)](https://www.typescriptlang.org/)\n[![license](https://img.shields.io/badge/license-MIT-lightgrey)](#-license)\n\n---\n\n## 📑 Table of contents\n\n- [What it does](#-what-it-does)\n- [Prerequisites](#-prerequisites)\n- [Install & run](#-install--run)\n- [Features](#-features)\n- [Interactive menu reference](#-interactive-menu-reference)\n- [Headless CLI](#-headless-cli)\n- [Generated files](#-generated-files)\n- [Settings](#-settings)\n- [Project structure](#-project-structure)\n- [Build & distribute](#-build--distribute)\n- [Troubleshooting](#-troubleshooting)\n- [Contributing](#-contributing)\n- [Security](#-security)\n- [Credits](#-credits)\n- [License](#-license)\n\n---\n\n## 🎯 What it does\n\n1. **Detects untranslated content** across every file type the game uses:\n   plants, zombies, achievements, UI strings, regex translations, tips\n   (I, Zombie + Fusion Showcase), Abyss buffs, Travel buffs.\n2. **Writes per-locale Markdown reports** so translators see the exact source\n   JSON blocks they need to translate, and optionally emits machine-readable\n   **JSON diff files** that can be re-injected into the locale.\n3. **Migrates the new tips format** — rebuilds `tips_iz.json` / `tips_fs.json`\n   from the legacy `translation_strings.json`, all-or-nothing.\n4. **Checks for duplicates** — surfaces duplicate JSON keys and values shared\n   by multiple keys, per locale.\n5. **Exports Trello CSV backlogs** — one CSV per category, ready for the\n   *Import to Trello by Blue Cat* Power-Up.\n6. **Writes the contributor documentation** — splits the weekly translation-PR\n   recap into one Markdown block per contributor, counters and reviews\n   included, ready to archive.\n7. **Ships as a single npm package** (`@charles_lindecker/pvzf-console`) bundled\n   to one file with [tsup](https://tsup.egoist.dev/). No Python — just Node and\n   two small runtime dependencies (`@clack/prompts`, `picocolors`).\n\n---\n\n## 📋 Prerequisites\n\n| Tool        | Version    | Why                                                  |\n| ----------- | ---------- | ---------------------------------------------------- |\n| **Node.js** | **≥ 20**   | The whole engine is TypeScript bundled to ESM.       |\n| Git         | any        | To clone and contribute.                             |\n\nYou also need the `PvZ_Fusion_Translator/` folder. By default the tool probes\nfour locations (next to the install → one level up → cwd → cwd parent), and the\npath is configurable from the Settings menu.\n\n---\n\n## 🚀 Install & run\n\n### Option A — via npm (recommended)\n\n```bash\nnpm install -g @charles_lindecker/pvzf-console   # once published\n\npvzf-console                           # interactive TUI\npvzf-console diff --lang French        # non-interactive\n```\n\nOr run it without installing:\n\n```bash\nnpx @charles_lindecker/pvzf-console\nnpx @charles_lindecker/pvzf-console diff --lang French\n```\n\n### Option B — from source (recommended for devs)\n\n```bash\ngit clone https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager.git\ncd PVZ-Fuzion-ConsolManager\nnpm install\n\n# Launch the interactive TUI live (no build step, via tsx)\nnpm run dev\n\n# Or build the bundle and run it\nnpm run build\nnode dist/cli.js\n```\n\nThe published package bundles everything into `dist/cli.js` (the `data/` banner\nships alongside it), so the global `bin` works straight after install.\n\n---\n\n## ✨ Features\n\n### Diff engine\n\n- Detects missing entries by primary-key lookup (O(n + m) using set membership,\n  not a naive O(n·m) nested loop).\n- Detects **empty values**: keys present in the locale but with an empty\n  translation string — reported in a separate section of each report.\n- Handles both flat dicts (`translation_strings.json`, `abyss_buffs.json`, …)\n  and nested travel buffs (`category:id`, preserving their full `name`/`desc` object).\n- Source of truth is configurable: diff against another locale (default\n  `English`) **or** against the raw game `Dumps/` (`Dumps` source mode).\n- Gracefully logs malformed JSON and continues instead of crashing the run.\n\n### Report generators\n\n- Almanac reports (plants / zombies / achievements): condensed `name + id`\n  header plus a fenced ```` ```json ```` block with the raw source entry,\n  ready to copy/translate/paste.\n- Flat reports (strings / regex / tips / buffs): two sections — *Missing\n  Keys* (compact JSON object) and *Empty Values* (table).\n- Optional **JSON diff files** (`*_diff.json`) alongside the Markdown, holding\n  the missing entries in the file's native shape so they can be merged straight\n  back into the locale. Enabled with the `--with-diff` CLI flag or the prompt\n  in the TUI.\n\n### Tips migration (Translator tool)\n\n- Rebuilds `tips_iz.json` / `tips_fs.json` from matches in\n  `translation_strings.json`.\n- **All-or-nothing**: if even one source tip text is missing from the\n  translation strings, the migration aborts for that file and reports the gap\n  count. No partial writes.\n- Already-present files are preserved (no overwrite); files with no dump source\n  in `Dumps/` are skipped with a notice.\n\n### Duplicate checker (Translator tool)\n\n- Scans every flat / nested string file for **duplicate JSON keys** (keys that\n  appear more than once in the raw text — `JSON.parse` silently keeps the last,\n  so a strict recursive-descent scanner catches them) and **repeated values**\n  (one translation reused across multiple keys).\n- Writes a `duplicates.md` report under `reports/<Locale>/` for any locale with\n  matches; clean locales produce nothing.\n\n### Trello CSV export (Translator tool)\n\n- One CSV **per category** (Plants / Zombies / Achievements / Strings / Regex\n  / Tips IZ / Tips FS / Abyss Buffs / Travel Buffs) → keeps the Trello UI\n  responsive even on the largest locales.\n- Columns: `Name`, `Description`, `Labels`, `List`.\n- Descriptions are **JSON-fenced** (`` ```json … ``` ``). Almanac entries keep\n  the full source JSON (with braces), flat entries render as `\"key\": \"value\"`\n  — always with escape sequences (`\\n`, `\\\"`, …) preserved literally so\n  translators see the file exactly as it will appear on disk.\n- Companion `trello_README.md` is generated alongside each export:\n  - The exact Trello label to create.\n  - The exact Trello lists to create (derived from the CSVs actually\n    produced).\n  - Full *Import to Trello by Blue Cat* Power-Up walkthrough.\n\n### Contributor documentation (Documentation tab)\n\n- Turns the weekly translation-PR recap into **one Markdown block per\n  contributor**: week header, PR link, counters (*new* / *adjusted* /\n  *reviews*), then the detail of every item they touched.\n- The **lead maintainer's *Reviews* block is derived**, not written: every item\n  authored by someone else is mirrored under the lead, grouped by section then\n  by author. Sections whose name contains `check` are proof-reading passes and\n  are excluded.\n- Counters come from the section names (`new` / `nouveau` / `nouvelle` →\n  *Nouvelles traductions*; `modified` / `modifi` → *Traductions ajustées*).\n- The lead's identity is a **setting**, so any locale maintainer can use the\n  tool: a canonical display name plus the aliases the recap may spell them with\n  (`@LINDECKER-Charles`, `LINDECKER-Charles`, …) are folded into one block.\n- **Nothing is written before you have seen it**: the recap is rendered and its\n  stats shown first, and the file is written only on confirmation.\n- No GitHub API call — the PR URL you pass in is only reinjected into each\n  block's header.\n- Ported from the standalone\n  [`pvzf-make-pr`](https://github.com/LINDECKER-Charles/PVZF-PR-Resume) CLI;\n  output is byte-identical.\n\n### Terminal UI\n\n- Built on [`@clack/prompts`](https://github.com/bombshell-dev/clack): arrow-key\n  menus with hints, type-to-filter locale picker, inline validation, boxed\n  status and result panels.\n- The **locale picker switches to a filterable autocomplete** past ten locales —\n  the game ships more than twenty.\n- `Esc` / `Ctrl+C` leave the current screen instead of killing the process, and\n  never trigger the action they interrupted; the main menu's *Exit* is the way\n  out.\n- Theme still honours the settings (accent color, emoji, banner) and falls back\n  to `[OK] / [!] / [X]` when emoji are off.\n\n### Persistent settings\n\n- Stored per user, outside the package — see\n  [Where settings live](#where-settings-live).\n- Live-editable from `[4] Settings` in the TUI.\n- Theme applied immediately (color, accent, density, emoji/banner toggles).\n- On-disk format keeps snake_case keys for backward compatibility, unknown keys\n  are ignored on load, and a hand-edited alias list is filtered down to usable\n  strings.\n\n### CLI\n\n- Hand-rolled sub-command dispatch mirroring an `argparse`-style surface.\n- `pvzf-console diff --lang <locale> [--out <dir>] [--with-diff]` runs every\n  diff type for one locale in non-interactive mode.\n- `pvzf-console pr-resume [--input <file>] [--output <file>]` generates the\n  contributor summary headlessly.\n- Exit codes: `0` on success, `1` on a runtime failure (unreadable recap),\n  `2` on invalid arguments, locale or project root.\n\n### Auto-discovery\n\n- `PvZ_Fusion_Translator/` is probed in four places (install sibling → one\n  level up → cwd → cwd parent) — **not recursive**, single pass.\n\n### Cross-platform\n\n- Pure Node runtime, ESM, no shell scripts required.\n- Windows VT100 enablement so ANSI colors and emoji render on every modern\n  terminal; emoji and banner can be toggled off for legacy hosts.\n\n### Error hygiene\n\n- Invalid project root is detected at startup (warning) **and** before every\n  tool action (gated with a friendly `❌` message). No stack traces leak to\n  the user.\n\n---\n\n## 🧭 Interactive menu reference\n\nNavigate with `↑` `↓`, confirm with `Enter`, leave a screen with `Esc`.\n\n```\n┌  PVZF CONSOLE\n│\n◇  Status ──────────────────────────────────────────╮\n│                                                   │\n│  ✅  project   …/PvZ_Fusion_Translator            │\n│  ✅  source    English                            │\n│  ✅  reports   reports/                           │\n│                                                   │\n├───────────────────────────────────────────────────╯\n│\n◆  Main menu\n│  ● Show what's missing   diff locales · write reports\n│  ○ Translator tools      migrate · trello · duplicates\n│  ○ Documentation         PR recap → contributor docs\n│  ○ Settings\n│  ○ Exit\n└\n```\n\n### [1] Show what's missing\n\nPick a locale (or `*` for all), then a type:\n\n| Option         | Source file                                           | Output file (under `reports/<Locale>/`) |\n| -------------- | ----------------------------------------------------- | --------------------------------------- |\n| `[0] All types`    | every type below                                  | every file below                        |\n| `[1] Plants`       | `Almanac/LawnStringsTranslate.json`               | `missing_plants.md`                     |\n| `[2] Zombies`      | `Almanac/ZombieStringsTranslate.json`             | `missing_zombies.md`                    |\n| `[3] Achievements` | `Almanac/AchievementsTextTranslate.json`          | `missing_achievements.md`               |\n| `[4] Strings (UI)` | `Strings/translation_strings.json`                | `missing_strings.md`                    |\n| `[5] Regex`        | `Strings/translation_regexs.json`                 | `missing_regexs.md`                     |\n| `[6] Tips (IZ + FS)` | `Strings/tips_iz.json`, `Strings/tips_fs.json`  | `missing_tips_iz.md`, `missing_tips_fs.md` |\n| `[7] Abyss buffs`  | `Strings/abyss_buffs.json`                        | `missing_abyss_buffs.md`                |\n| `[8] Travel buffs` | `Strings/travel_buffs.json` (nested)              | `missing_travel_buffs.md`               |\n\nAfter picking a type, the TUI asks whether to **also export JSON diff files**.\nAnswer yes to write `*_diff.json` next to each Markdown report.\n\n### [2] Translator tools\n\n| Option | What it does |\n| ------ | ------------ |\n| `[1] Migrate tips & buffs` | Rebuilds `tips_iz.json` / `tips_fs.json` / `abyss_buffs.json` / `travel_buffs.json` from `translation_strings.json`. Single-locale only. All-or-nothing. |\n| `[2] Migrate custom levels` | Builds `customlevel_strings` / `customlevel_regexs` / `custom_level_data`; key set from the source locale, translations from the target. |\n| `[3] Export Trello CSV` | Produces one CSV per category under `exports/<Locale>/` plus a `trello_README.md` with the full import walkthrough. |\n| `[4] Check duplicates` | Scans every string file for duplicate keys and repeated values; writes `duplicates.md` per locale with matches. |\n| `[0] Back` | Returns to the main menu. |\n\n### [3] Documentation\n\n| Option | What it does |\n| ------ | ------------ |\n| `[1] PR recap → contributor summary` | Reads the weekly PR recap and writes one Markdown block per contributor. |\n| `[0] Back` | Returns to the main menu. |\n\nThe tool asks for the recap file (pre-filled with the first candidate `.md` in\nthe working directory) and the output file (defaults to the *Docs output*\nsetting), renders the result, shows the per-contributor stats, and writes only\nonce you confirm.\n\n**Expected input** — the first two non-empty lines are the header:\n\n```markdown\n2026-04-01..2026-04-07                      ← period (or already-formatted `01/04/26 → 07/04/26`)\nhttps://github.com/owner/repo/pull/123      ← PR URL; the number is read from /pull/(\\d+)\n\n## 🌱 Newly Added Plants                    ← section\n\n@lafourmiedugaming-collab :                 ← contributor: @handle, or [Name](link) :\n* **Briseur de Machoir** (`seedType: 1390`) ← item\n\n## 🔧 Modified Achievements\n\n@Kurodatenshi :\n* **D'où est-ce que je viens ?** (`achievement: 7`)\n```\n\n**Output** — one block per contributor, plus the lead's derived *Reviews*:\n\n```markdown\n## 👤 @Kurodatenshi\n\n### 📅 Semaine — `01/04/26 → 07/04/26`\n> [PR#123](https://github.com/owner/repo/pull/123)\n\n**Résumé de la semaine**\n\n* Nouvelles traductions : **0**\n* Traductions ajustées : **1**\n* Reviews effectuées : **0**\n\n---\n\n#### Détail\n\n## 🔧 Modified Achievements\n* **D'où est-ce que je viens ?** (`achievement: 7`)\n```\n\nThe rendered output stays in French by design — it lands verbatim in the French\ncontributor files.\n\n### [4] Settings\n\n| Key             | Default            | Notes                                          |\n| --------------- | ------------------ | ---------------------------------------------- |\n| Project root    | auto-discovered    | Absolute path to `PvZ_Fusion_Translator/`      |\n| Source locale   | `English`          | Reference used for diffs (`Dumps` for raw dumps) |\n| Text color      | `default`          | Primary text                                   |\n| Accent color    | `cyan`             | Headers, prompt, option keys                   |\n| Density         | `comfortable`      | `compact` · `comfortable` · `spacious`         |\n| Show emoji      | `true`             | Fallback: `[OK] / [!] / [X]`                   |\n| Show banner     | `true`             | ASCII banner at startup                        |\n| Trello label    | `To be translated` | Label written to every exported card           |\n| Docs lead       | `Charles LINDECKER` | Whose *Reviews* block the Documentation tab derives |\n| Docs aliases    | `@LINDECKER-Charles, LINDECKER-Charles` | Other spellings of the lead, folded into one block |\n| Docs output     | `contribution-summary.md` | Default target of the contributor summary |\n\nSupported ANSI colors: `default, red, green, yellow, blue, magenta, cyan,\nwhite` plus their `bright_*` variants.\n\n#### Where settings live\n\n`settings.json` is stored per user, outside the package, so a global install in\na root-owned prefix (`/usr/local/lib/node_modules`, `C:\\Program Files\\nodejs`)\nstays writable:\n\n| Platform    | Path                                                        |\n| ----------- | ----------------------------------------------------------- |\n| macOS       | `~/Library/Application Support/pvzf-console/settings.json`   |\n| Linux / BSD | `$XDG_CONFIG_HOME/pvzf-console/settings.json`, else `~/.config/pvzf-console/settings.json` |\n| Windows     | `%APPDATA%\\pvzf-console\\settings.json`                       |\n\n`$XDG_CONFIG_HOME` is honored on macOS too when set to an absolute path. Set\n`PVZF_CONSOLE_SETTINGS=/path/to/settings.json` to pin the file somewhere else\n(portable installs, CI). The active path is shown in `[4] Settings` under\n*Settings file*.\n\nUpgrading from ≤ 1.4.1, which kept `settings.json` inside the package: that file\nis still read on first launch and copied to the per-user location on the next\nsave. The old copy is left in place, so an older install alongside keeps working\n— but from then on the two no longer track each other.\n\n---\n\n## ⚡ Headless CLI\n\n```bash\npvzf-console diff --lang French\npvzf-console diff --lang German --out ./out --with-diff\npvzf-console pr-resume --input recap.md --output docs/contributions.md\n```\n\n| Command                                              | Effect                                                                      |\n| ---------------------------------------------------- | --------------------------------------------------------------------------- |\n| `pvzf-console`                                       | Launch the interactive TUI.                                                 |\n| `pvzf-console diff --lang French`                    | Run every diff type for French, write to `./reports/French/`.               |\n| `pvzf-console diff --lang French --out X`            | Same, writing to `X/French/` instead.                                       |\n| `pvzf-console diff --lang French --with-diff`        | Same, plus `*_diff.json` next to each Markdown report.                       |\n| `pvzf-console pr-resume`                             | Contributor summary from the first candidate `.md` in the cwd → `contribution-summary.md`. |\n| `pvzf-console pr-resume --input R.md --output O.md`  | Same, with both paths given. Aliases: none — long flags only.               |\n\nAuto-detection of the recap skips `README.md`, `README.dist.md`, `CHANGELOG.md`,\n`LICENSE.md`, `CONTRIBUTING.md`, `release.md` and the output file itself.\n\nExit codes:\n\n| Code | Meaning                                              |\n| ---- | ---------------------------------------------------- |\n| `0`  | Success.                                             |\n| `1`  | Runtime failure — recap missing, unreadable, or lacking its two header lines. |\n| `2`  | Invalid arguments, invalid locale, source locale rejected, or invalid project root (missing `Localization/` subfolder). |\n\nUse the `diff` command in CI to fail builds when a locale regresses, and\n`pr-resume` to regenerate the contributor documentation when the weekly PR\nmerges.\n\n---\n\n## 📁 Generated files\n\nEvery artifact is **grouped by locale**.\n\n```\nreports/\n├── Arabic/\n│   ├── missing_plants.md\n│   ├── missing_zombies.md\n│   ├── missing_strings.md\n│   ├── missing_regexs.md\n│   └── missing_travel_buffs.md\n└── French/\n    ├── missing_plants.md\n    ├── missing_zombies.md\n    ├── missing_strings.md\n    ├── missing_regexs.md\n    ├── duplicates.md                # only when duplicates were found\n    └── strings_diff.json            # only with --with-diff / TUI opt-in\n\nexports/\n└── French/\n    ├── trello_Plants.csv\n    ├── trello_Zombies.csv\n    ├── trello_Strings.csv\n    ├── trello_Regex.csv\n    ├── trello_Tips_IZ.csv\n    ├── trello_Tips_FS.csv\n    ├── trello_Abyss_Buffs.csv\n    ├── trello_Travel_Buffs.csv\n    └── trello_README.md\n\ncontribution-summary.md              # Documentation tab / pr-resume (path configurable)\n```\n\nEmpty categories (0 missing entries) do not produce a file — keeps the\noutput tidy.\n\n---\n\n## 🗂️ Project structure\n\n```\nPVZ-Fuzion-ConsolManager/\n├── package.json                   # npm package metadata + bin entry (dist/cli.js)\n├── tsconfig.json                  # strict TypeScript, ESM, Bundler resolution\n├── tsup.config.ts                 # bundle config: src/cli.ts → dist/cli.js (ESM)\n├── vitest.config.ts               # test + coverage config (75% gate)\n├── README.md                      # this file\n├── README.dist.md                 # end-user README shipped in the npm tarball\n├── data/                          # ASCII banner (title.md, logo.md)\n├── tests/                         # Vitest suites mirroring src/ layout\n└── src/\n    ├── cli.ts                     # executable entry point (shebang injected by tsup)\n    ├── config.ts                  # paths, source locale, auto-discovery\n    ├── settings.ts                # AppSettings + load/save (snake_case on disk)\n    ├── cli/\n    │   ├── app.ts                 # App orchestration + argv parsing (DI seam)\n    │   ├── banner.ts              # title renderer (reads data/title.md)\n    │   ├── menus.ts               # prompts, sections, locale picker, ConsoleIO\n    │   └── theme.ts               # ANSI colors + density + emoji toggle\n    ├── core/\n    │   ├── diff.ts                # missingById (O(n + m))\n    │   └── models.ts              # AlmanacEntry / StringEntry / TrelloCard …\n    ├── parsers/\n    │   ├── loaders.ts             # JSON reader + locale enumeration + Dumps source\n    │   ├── almanac.ts             # plant / zombie / achievement loaders\n    │   └── strings.ts             # flat + nested diff helpers\n    ├── reporting/\n    │   ├── markdown.ts            # per-locale Markdown writers + duplicates report\n    │   ├── diff-json.ts           # *_diff.json writers (native file shape)\n    │   └── trello-csv.ts          # per-category CSVs + README template\n    └── tools/\n        ├── migration.ts           # tips/buffs + custom-level builders (all-or-nothing)\n        ├── trello-export.ts       # collects cards + calls the writer\n        ├── duplicate-checker.ts   # duplicate keys + repeated values scanner\n        └── pr-resume/             # PR recap → contributor documentation\n            ├── index.ts           # orchestration + input/output resolution\n            ├── parser.ts          # header split, section/contributor/bullet detection\n            ├── service.ts         # per-contributor aggregation + derived reviews\n            ├── renderer.ts        # final Markdown rendering\n            └── period.ts          # ISO range → dd/mm/yy\n```\n\n---\n\n## 🏗️ Build & distribute\n\n### Bundle\n\n```bash\nnpm run build           # tsup: src/cli.ts → dist/cli.js (ESM, sourcemaps)\nnode dist/cli.js\n```\n\n`tsup` emits a single ESM bundle targeting Node 20, injecting the\n`#!/usr/bin/env node` shebang so `dist/cli.js` is directly executable. The\n`data/` banner is resolved at runtime relative to the package root, so it still\nrenders from a global install.\n\n### npm package\n\n```bash\nnpm install\nnpm run build           # or rely on prepublishOnly\nnpm publish             # prepublishOnly re-runs tsup automatically\n```\n\nThe published tarball ships `dist/`, `data/`, and both README files (see the\n`files` array in `package.json`). The `bin` entry maps `pvzf-console` →\n`dist/cli.js`, so the command works the moment install finishes — Node is the\nonly requirement.\n\n---\n\n## 🛟 Troubleshooting\n\n| Symptom                                           | Fix                                                                                              |\n| ------------------------------------------------- | ------------------------------------------------------------------------------------------------ |\n| `command not found: pvzf-console`                 | Install Node ≥ 20, then `npm install -g @charles_lindecker/pvzf-console` (or use `npx`).          |\n| `Directory does not exist: …PvZ_Fusion_Translator` | Settings → `[1] Change PvZ_Fusion_Translator folder`, paste the correct absolute path.           |\n| `Missing 'Localization' subfolder in …`           | Same as above — the configured path exists but isn't the translator bundle.                      |\n| `<locale>: tips_iz.json missing`                  | Run Translator Tools → `[1] Migrate tips` for that locale first, then rerun the diff.             |\n| `Settings could not be saved — …`                 | The per-user config directory isn't writable. Fix its permissions, or point `PVZF_CONSOLE_SETTINGS` at a writable file. Settings still apply for the session. |\n| `Skipped tips_iz.json — N source string(s) missing` | Your `translation_strings.json` is still missing some source tip keys. Finish those first, then rerun the migration. |\n| Emoji show up as `??` in your terminal            | `[4] Settings` → `[6] Toggle emoji` for the `[OK] / [!] / [X]` fallback.                         |\n| Banner ASCII art renders as mojibake              | `[4] Settings` → `[7] Toggle ASCII banner`. The tool enables VT100 on Windows but some legacy hosts still fail. |\n| Report file says 0 entries / no file at all       | 0 missing / empty-values is intentionally silent — the tool only writes a file when there's something to report. |\n| Travel-buffs keys look like `advancedBuffs:0`     | Expected: presence is checked by `category:id`; a missing ID keeps its complete `{name, desc}` object in the report. |\n\n---\n\n## 🤝 Contributing\n\nIssues and PRs welcome. To get hacking:\n\n```bash\ngit clone https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager.git\ncd PVZ-Fuzion-ConsolManager\nnpm install\n\nnpm run dev            # run the TUI live (tsx)\nnpm run typecheck      # tsc --noEmit (strict)\nnpm test               # vitest run\nnpm run test:cov       # vitest run --coverage (75% gate)\n```\n\n### Guidelines\n\n1. **Respect the layer boundaries** (one responsibility per directory, IO\n   pushed to the edges):\n   - `core/` — pure data models + comparison logic, **no IO**.\n   - `parsers/` — JSON loading + locale enumeration + diff helpers.\n   - `reporting/` — every output format lives here (Markdown, JSON diff, CSV).\n   - `tools/` — higher-level orchestrations that combine parsers + reporting.\n   - `cli/` — prompts, menus, argv parsing, theming; nothing domain-specific.\n   - `settings.ts` — persistence only.\n2. **Keep it dependency-free at runtime.** The engine is plain Node + the\n   standard library (`node:fs`, `node:path`, …). Dev tooling (tsup, tsx,\n   vitest, typescript) is the only allowed `devDependencies`.\n3. **ESM + strict TypeScript.** `\"type\": \"module\"`, `strict: true`,\n   `noImplicitOverride`, Bundler module resolution. Use `node:` import\n   specifiers; intra-package imports are extension-less (`./menus`,\n   `../core/diff`) and the bundler resolves them.\n4. **The app is built around a DI seam.** `cli/app.ts` exposes an `App` class\n   holding mutable state and an injectable `AppDeps` bundle of every UI/menu\n   function (ESM bindings can't be monkeypatched), so tests script answers and\n   capture writes. Keep new UI interactions behind `AppDeps`.\n5. **Adding a new translation type** is a 4-step drill:\n   - Drop a loader in `parsers/` (`almanac.ts` for typed entities, `strings.ts`\n     for flat/nested key-value files).\n   - Add the corresponding `diff<Kind>` helper in `parsers/strings.ts` (or reuse\n     `missingById` from `core/diff.ts` for almanac types).\n   - Add `build<Kind>Report` in `reporting/markdown.ts`, `build<Kind>Diff` in\n     `reporting/diff-json.ts`, and wire the category into\n     `tools/trello-export.ts`.\n   - Register it in `App.translationTypes` in `cli/app.ts` (the numbered\n     dispatch map drives both the menu and `runAll`).\n6. **Don't rebuild the wheel for a new Trello list**: reuse the flat-file and\n   almanac card collectors in `tools/trello-export.ts` and let the CSV writer\n   in `reporting/trello-csv.ts` do the per-list grouping.\n7. **Commit style**: `type(scope): summary`. Seen so far: `feat(reports)`,\n   `fix(cli)`, `chore(build)`, `docs(readme)`.\n8. **Keep settings JSON backward-compatible** — `loadSettings` already filters\n   unknown keys and the on-disk format stays snake_case; don't rename fields,\n   add new ones with a default in `AppSettings`.\n\n### npm scripts\n\n| Script              | What it does                                          |\n| ------------------- | ----------------------------------------------------- |\n| `npm run dev`       | Run the TUI live from source via `tsx`.               |\n| `npm run build`     | Bundle `src/cli.ts` → `dist/cli.js` with `tsup`.      |\n| `npm run typecheck` | `tsc --noEmit` against `src` + `tests` (strict).      |\n| `npm test`          | Run the Vitest suite once.                            |\n| `npm run test:cov`  | Run tests with V8 coverage (75% gate on lines/functions/branches/statements). |\n\n---\n\n## 🔐 Security\n\nFound a vulnerability? **Don't open a public issue** — report it privately via a\n[GitHub security advisory](https://github.com/LINDECKER-Charles/PVZ-Fuzion-ConsolManager/security/advisories/new)\nor by email. Supported versions, scope and response targets live in\n[SECURITY.md](SECURITY.md).\n\nEvery push and PR to `main` (plus a weekly schedule) runs the `Security`\nworkflow: `npm audit` (blocking on high/critical production advisories), the\nESLint security ruleset, Semgrep and Gitleaks.\n\n---\n\n## 👤 Credits\n\n**Charles Lindecker** — senior backend dev, translation-pipeline enthusiast,\nlong-time PvZ fan.\n\n- GitHub: [@LINDECKER-Charles](https://github.com/LINDECKER-Charles)\n- Email: [charles.lindecker@outlook.fr](mailto:charles.lindecker@outlook.fr)\n\nHuge thanks to the **PVZ Fusion translator community** — especially\n**@cassidy [BLMS]** for the original `migrate.py` / `migrate_odyssey.py`\nscripts that inspired the Translator Tools.\n\n---\n\n## 📜 License\n\n[MIT](LICENSE). Do what you want, keep the copyright notice, no warranty.\n","readmeFilename":"README.md"}