From 38ca8e44be214fe4d670bee1ba57a55cc4bd4603 Mon Sep 17 00:00:00 2001 From: DazedAnon Date: Sat, 25 Jul 2026 14:23:27 -0500 Subject: [PATCH] fix(workflow): scope game tools and externalize prompts - Install UberWolf CLI only for detected WOLF games - Move static clipboard prompts into editable shipped skills - Improve plugin and Ace translation audit workflows - Add regression coverage for engine filtering and prompt loading --- data/help/05-other-tabs.md | 5 + data/skills/ace_script_translation.md | 44 +++ data/skills/plugin_translation.md | 44 +++ data/skills/risky_codes.md | 145 +++++++++ data/skills/wolf_speakers.md | 26 ++ data/skills/wrap_config.md | 32 ++ gameupdate/gameupdate/patch.ps1 | 56 +++- gameupdate/gameupdate/patch.sh | 47 ++- gui/skills_tab.py | 35 +++ gui/wolf_workflow_tab.py | 46 +-- gui/workflow_tab.py | 402 +++---------------------- modules/rpgmakermvmz.py | 10 +- tests/test_bundled_updates.py | 5 + tests/test_gameupdate_engine_filter.py | 76 +++++ tests/test_workflow_prompts.py | 67 +++++ util/skills/__init__.py | 3 +- util/skills/setup.py | 13 + 17 files changed, 632 insertions(+), 424 deletions(-) create mode 100644 data/skills/ace_script_translation.md create mode 100644 data/skills/plugin_translation.md create mode 100644 data/skills/risky_codes.md create mode 100644 data/skills/wolf_speakers.md create mode 100644 data/skills/wrap_config.md create mode 100644 tests/test_gameupdate_engine_filter.py create mode 100644 tests/test_workflow_prompts.py diff --git a/data/help/05-other-tabs.md b/data/help/05-other-tabs.md index 0df3eb2..31803cc 100644 --- a/data/help/05-other-tabs.md +++ b/data/help/05-other-tabs.md @@ -29,6 +29,11 @@ Edit tool-level markdown: - `data/skills/system.md` - base translation system prompt - `data/skills/project_setup.md` - clipboard skill for IDE setup +- `data/skills/wrap_config.md` - RPG Maker wrap-width analysis prompt +- `data/skills/plugin_translation.md` - MV/MZ plugin translation prompt +- `data/skills/ace_script_translation.md` - VX Ace Ruby script translation prompt +- `data/skills/risky_codes.md` - RPG Maker optional event-code audit prompt +- `data/skills/wolf_speakers.md` - WOLF speaker-format audit prompt - `data/translation_contexts.json` - per-call history templates Per-game quirks / Translation Frame live under `/skills/` and are edited in Workflow Step 2, not here. diff --git a/data/skills/ace_script_translation.md b/data/skills/ace_script_translation.md new file mode 100644 index 0000000..5c7aa94 --- /dev/null +++ b/data/skills/ace_script_translation.md @@ -0,0 +1,44 @@ +You are an expert RPG Maker VX Ace Ruby/RGSS3 localisation engineer working inside an IDE with access to this game project. + + +Audit ace_json/scripts/*.rb for player-visible Japanese, tell me which scripts need localisation, and—only after I approve—translate the safe items directly in those files without breaking game logic. + + + +- Read vocab.txt and the extracted Ruby files under ace_json/scripts/. +- Use any script index/manifest to preserve script names and ordering. +- Treat vocab.txt as authoritative for names and terminology. +- If referenced script sources are missing or still packed, list what is needed and ask me to extract or provide them. + + + +Do not edit anything yet. Return a compact table with: +- Script/file +- Approximate count of player-visible Japanese strings +- 1-3 short examples with line references +- Classification: Easy/safe, Needs review, or No translation needed +- Why it appears visible or risky + +Then ask one focused question: which listed scripts should you translate? If all findings are easy and clearly display-only, explicitly offer to translate all safe items yourself now. Do not ask me to inspect every string manually. If nothing needs work, say so and stop. + + + +Translate only literals proven to reach the player through windows, draw_text/help methods, messages, menus, battle logs, or notifications. A string passed to print or p is not automatically player-visible; verify its runtime use. + +Never translate hash keys, symbols, identifiers, class/module/method/constant names, lookup values, case/when or equality operands, filenames, paths, URLs, fonts, colors, regexes, save-data keys, or text read back elsewhere. Preserve Ruby interpolation (#{...}), printf/sprintf placeholders, escape sequences, control codes, quote style, encoding, and syntax. Search usages before changing an ambiguous literal; skip it if safety cannot be established. + +Edit approved .rb files directly and make the smallest possible changes. Validate Ruby syntax when a suitable local check exists, and preserve the extracted script layout so RV2JSON can repack it. + + + +Never paste or repost an entire script. After edits, report only: +- Files/scripts changed and number of strings translated +- A few representative before -> after examples with line references +- Skipped ambiguous strings and the reason +- Validation performed + +If direct file editing is unavailable, provide only a minimal unified diff or targeted replacements—never complete file contents. + + +Start with the audit and approval question. Do not translate yet. + diff --git a/data/skills/plugin_translation.md b/data/skills/plugin_translation.md new file mode 100644 index 0000000..1f95980 --- /dev/null +++ b/data/skills/plugin_translation.md @@ -0,0 +1,44 @@ +You are an expert RPG Maker MV/MZ localisation engineer working inside an IDE with access to this game project. + + +Audit enabled plugins for player-visible Japanese, tell me which plugins need localisation, and—only after I approve—translate the safe items directly in the project files without breaking plugin behavior. + + + +- Read js/plugins.js and vocab.txt. +- For every enabled entry in js/plugins.js, inspect its parameter values. +- If available, also inspect the matching js/plugins/.js source file for visible Japanese literals. If a required source file is missing, list it and ask me to provide it. +- Treat vocab.txt as authoritative for names and terminology. + + + +Do not edit anything yet. Return a compact table with: +- Plugin and file +- Approximate count of player-visible Japanese strings +- 1-3 short examples with line/parameter references +- Classification: Easy/safe, Needs review, or No translation needed +- Why it appears visible or risky + +Then ask one focused question: which listed plugins should you translate? If all findings are easy and clearly display-only, explicitly offer to translate all safe items yourself now. Do not ask me to inspect every string manually. If nothing needs work, say so and stop. + + + +Translate only strings proven to be displayed to the player, including UI labels, window titles, help text, notifications, battle messages, and visible plugin parameters. + +Never translate plugin names, parameter/property keys, identifiers, lookup values, plugin commands, switch/variable names, filenames, paths, URLs, fonts, color codes, regexes, booleans, numeric strings, or text compared/read back elsewhere. Preserve placeholders, escapes, control codes, interpolation, whitespace, encoding, and JavaScript syntax. Search usages before changing an ambiguous literal; skip it if safety cannot be established. + +Edit approved files directly and make the smallest possible changes. Validate syntax when a suitable local check exists. + + + +Never paste or repost an entire file. After edits, report only: +- Files/plugins changed and number of strings translated +- A few representative before -> after examples with line/parameter references +- Skipped ambiguous strings and the reason +- Validation performed + +If direct file editing is unavailable, provide only a minimal unified diff or targeted replacements—never complete file contents. + + +Start with the audit and approval question. Do not translate yet. + diff --git a/data/skills/risky_codes.md b/data/skills/risky_codes.md new file mode 100644 index 0000000..12c2a30 --- /dev/null +++ b/data/skills/risky_codes.md @@ -0,0 +1,145 @@ +You are an expert RPGMaker MV/MZ event system analyst. + + +Audit several optional event code types and report: (a) which contain player-visible Japanese text that needs translation, and (b) for code 122, exactly which variable ID ranges carry display text versus internal keys. + + +--- attach Actors.json, CommonEvents.json, Troops.json, Map*.json, and js/plugins.js here --- + + +Read Actors.json in full before auditing event commands. Use it to resolve actor IDs, \N[n] references, and code 320/324/325 targets. If you see an event reference to a major actor whose full character vocab is missing or only appears as a placeholder mapping like \N[3] (Keimi), report that Actors.json should be included in the glossary build and that a full # Game Characters entry is needed. + + + +Code 122 — Control Variables — which variable IDs carry display text + +A code 122 entry looks like: + { "code": 122, "parameters": [startVarId, endVarId, 0, 4, "\"some string\""] } +parameters[0] is the variable ID being set; parameters[4] is the string value +(only present when parameters[3] == 4, direct string assignment). + +Collect every code 122 where parameters[3] == 4. For each variable ID found: + 1. Is the string also tested in a code 111 $gameVariables comparison? + → DO NOT TRANSLATE (would break game logic) + 2. Is the string used as an internal ID / plugin key / script argument? + → DO NOT TRANSLATE + 3. Is the string purely player-visible display text? + → SAFE TO TRANSLATE + +Summarise translatable variable IDs as compact numeric ranges, +e.g. 'Translate IDs: 5, 10-18, 42'. Separately list any DO NOT TRANSLATE IDs +with the reason. The ranges will be entered as min/max in the translation tool. + + + +Plugin codes with visible text — 357 / 356 / 355-655 / 657 / 320 / 324 / 325 / 108 +For each code type below, scan all events and report whether any instance contains Japanese text visible to the player at runtime. + +--- Code 357 (MZ Plugin Commands) --- +parameters[0] = plugin header; parameters[3] = data dict. +Look up each unique header in js/plugins.js. +Does any key in parameters[3] hold Japanese text shown on screen? +The module already handles: AdvExtentionllk, VisuMZ_4_ProximityMessages, LL_GalgeChoiceWindow +For other headers with visible text, check the commented-out headerMappings list: + "LL_InfoPopupWIndow": (["messageText"], None), + "QuestSystem": (["DetailNote"], None), + "BalloonInBattle": (["text"], None), + "MNKR_CommonPopupCoreMZ": (["text"], None), + "DestinationWindow": (["destination"], None), + "_TMLogWindowMZ": (["text"], None), + "TorigoyaMZ_NotifyMessage": (["message"], None), + "SoR_GabWindow": (["arg1"], None), + "DarkPlasma_CharacterText": (["text"], None), + "DTextPicture": (["text"], None), + "TextPicture": (["text"], None), + "TRP_SkitMZ": (["name"], None), + "LogWindow": (["text"], None), + "BattleLogOutput": (["message"], None), + "TorigoyaMZ_NotifyMessage_CommandMessage": (["message"], None), + "NUUN_SaveScreen": (["AnyName"], None), + "build/ARPG_Core": (["Text", "SkillByName"], None), +Output: EXACT uncomment line, or describe parameters[3] if header is new. + +--- Code 356 (MV Plugin Commands) --- +parameters[0] is a space-delimited string, e.g. 'D_TEXT テキスト 24'. +The module already handles: D_TEXT, ShowInfo, PushGab, addLog, DW_*, CommonPopup, AddCustomChoice. +Does any 356 line have Japanese that is shown on screen? +If yes: ENABLE CODE356 and list the command keywords found. +If no: SKIP CODE356. + +--- Code 355/655 (Inline Scripts) --- +Code 355 starts a script block; code 655 continues it. +parameters[0] is the raw JS/script text. +For each block with Japanese in a string passed to a message/popup/log function: + • The leading keyword/pattern that identifies the block + • A regex capturing only the display substring, e.g. テキスト-(.+) + • Whether it is single-line (355 only) or multi-line (355 + 655) + • The exact entry to add to the patterns dict: + "": (r"", ), + +--- Code 657 (Picture Text) --- +parameters[0] is a plain string drawn onto a picture. +Does any 657 entry contain Japanese text visible on screen (not a filename)? +If yes: ENABLE CODE657. If no: SKIP CODE657. + +--- Codes 320 / 324 / 325 (Actor Name / Nickname / Profile) --- +parameters[1] is the new name/nickname/profile string. +Do any of these codes set Japanese strings visible to the player +(not just internal IDs or filenames)? +If yes: ENABLE the respective code. If no: SKIP. + +--- Code 108 (Comment / Notetag) --- +parameters[0] is a comment string used as a plugin notetag. +The module only translates 108 lines that match specific patterns: + info:, ActiveMessage:, event_text, Menu Name, text_indicator, NW名前指定 +Do any 108 entries matching those patterns have Japanese visible to the player? +If yes: ENABLE CODE108 and list the patterns found. If no: SKIP CODE108. + + + +Reply with these exact sections: + +### Code 122 — Variable Translation Ranges + Translate IDs : + Do NOT translate: +If none: 'No display-text string assignments found.' + +### Code 357 — Plugin Handlers to Enable + • Already handled :
— no action needed + • Enable in module : uncomment → "
": ([""], None), + • New entry needed :
— parameters[3] structure: + • No visible text :
— internal only, skip +If none: 'No code 357 visible text found.' + +### Code 356 — Enable or Skip + ENABLE / SKIP — keywords found: + +### Code 355/655 — Script Patterns to Add + • Pattern key : + • Regex : + • Multiline : + • Module line : "": (r"", ), +If none: 'No translatable 355/655 scripts found.' + +### Code 657 — Enable or Skip + ENABLE / SKIP — + +### Codes 320 / 324 / 325 — Enable or Skip + 320: ENABLE / SKIP 324: ENABLE / SKIP 325: ENABLE / SKIP + +### Code 108 — Enable or Skip + ENABLE / SKIP — patterns found: + +### GUI Action Summary + +After all audit sections above, output this final block to configure the GUI: + +ENABLE CODES : +SKIP CODES : +357 PLUGINS : +355/655 PATTERNS : +122 VAR RANGE : min=, max= + +If a field has nothing to fill in, write NONE. + + diff --git a/data/skills/wolf_speakers.md b/data/skills/wolf_speakers.md new file mode 100644 index 0000000..e561b2e --- /dev/null +++ b/data/skills/wolf_speakers.md @@ -0,0 +1,26 @@ +You are an expert Japanese WOLF RPG Editor translator helping configure a translation tool. + + +WolfDawn extracts each line with a 'speaker' and a 'speaker_src' tag describing how it detected the speaker. Two tags carry the speaker name baked into the FIRST line of the 'source' text (the rest is the dialogue body): + - literal_line1 : HIGH confidence - a face/name window precedes the line, so the first line really is a nameplate. The tool always reshapes these; nothing to decide. + - literal_line1_lowconf : LOW confidence - a short first line with NO preceding face window. WolfDawn guesses it is a speaker name, but it might actually be the start of the dialogue or narration. +When a first-line format is trusted, the tool reshapes 'Name\nbody' into '[Name]: body' for translation, then restores 'Name\nbody' on inject (byte-safe either way). + + +--- attach the extracted JSON in files/ here (maps / CommonEvent) before continuing --- + + +Decide whether the LOW-confidence first-line guesses (speaker_src = literal_line1_lowconf) should be treated as speaker names for THIS game. Inspect a good sample of those entries in files/: look at the first line of each such 'source' and judge whether it is genuinely a character/speaker label as opposed to real dialogue or narration. + - ENABLE if the low-confidence first lines are overwhelmingly real speaker names. + - DISABLE if many are actually dialogue/narration (reshaping them would mislabel lines). +(The high-confidence nameplates are always handled; you are only ruling on the guesses.) + + + +Return ONLY a fenced code block containing the recommendation and a one-line reason, e.g. +``` +LOWCONF_FIRSTLINE: ENABLE - low-confidence first lines are short character names (市民, 兵士...). +``` +Use exactly ENABLE or DISABLE after the colon. + + diff --git a/data/skills/wrap_config.md b/data/skills/wrap_config.md new file mode 100644 index 0000000..c8af06f --- /dev/null +++ b/data/skills/wrap_config.md @@ -0,0 +1,32 @@ +You are an expert RPGMaker MV/MZ configuration analyst. + + +Calculate the correct text-wrap width settings for a Japanese-to-English RPGMaker MV/MZ translation tool. The tool wraps translated English using character-count limits (not pixels). I need three values: width, listWidth, and noteWidth. + + +--- attach System.json and js/plugins.js here before continuing --- + + +1. Read screenWidth and fontSize from System.json. + Check js/plugins.js for any MessageCore or Window plugin that overrides these values. +2. For each window type, estimate its pixel width, subtract ~48px padding, then calculate: + chars = floor(content_px / (font_size × 0.58)) + - width: main dialogue/message box (Show Text) — typically full screen width + - listWidth: item/skill/help description windows — typically full or half screen width + - noteWidth: database note fields — typically the narrowest pane (~40–50% screen width) +3. If font size is above 26px and reducing it would meaningfully increase characters per line, note where to change it (System.json or the relevant plugin parameter). + + + +Output only the final values — do not show calculations: + +``` +width= +listWidth= +noteWidth= +fontSize= # or: no change needed +``` + +Followed by one sentence of assumptions if anything was estimated. + + diff --git a/gameupdate/gameupdate/patch.ps1 b/gameupdate/gameupdate/patch.ps1 index 278af0c..f792ea7 100644 --- a/gameupdate/gameupdate/patch.ps1 +++ b/gameupdate/gameupdate/patch.ps1 @@ -376,6 +376,21 @@ function Test-WolfLooseDataReady { return $false } +function Test-WolfGameRoot { + param([Parameter(Mandatory = $true)][string]$Root) + foreach ($name in @('Data.wolf', 'data.wolf')) { + if (Test-Path -LiteralPath (Join-Path $Root $name) -PathType Leaf) { + return $true + } + } + foreach ($name in @('Data', 'data')) { + if (Test-WolfLooseDataReady -DataDir (Join-Path $Root $name)) { + return $true + } + } + return $false +} + function Find-UberWolfCli { param([Parameter(Mandatory = $true)][string]$Root) $candidates = @( @@ -849,20 +864,41 @@ function Invoke-PatchDownloadExtract { throw ('PATCH_ERR:ZIP:Expected one root folder in archive, found {0}.' -f $dirs.Count) } $stagedRoot = $dirs[0].FullName + $isWolfGame = Test-WolfGameRoot -Root $Root + $wolfOnlyNames = @('UberWolfCli.exe', 'UberWolfCli.LICENSE.txt') - # Stage UberWolfCli into the game root before unpack so first-time - # players can convert Data.wolf -> Data/ before English files land. - foreach ($cliName in @('UberWolfCli.exe', 'UberWolfCli.LICENSE.txt')) { - $stagedCli = Join-Path $stagedRoot $cliName - $destCli = Join-Path $Root $cliName - if ((Test-Path -LiteralPath $stagedCli -PathType Leaf) -and - -not (Test-Path -LiteralPath $destCli -PathType Leaf)) { - Copy-Item -LiteralPath $stagedCli -Destination $destCli -Force + if ($isWolfGame) { + # Stage UberWolfCli before unpack so packed WOLF games can + # convert Data.wolf -> Data/ before English files land. + foreach ($cliName in $wolfOnlyNames) { + $stagedCli = Join-Path $stagedRoot $cliName + $destCli = Join-Path $Root $cliName + if ((Test-Path -LiteralPath $stagedCli -PathType Leaf) -and + -not (Test-Path -LiteralPath $destCli -PathType Leaf)) { + Copy-Item -LiteralPath $stagedCli -Destination $destCli -Force + } } + Invoke-WolfPreSetup -Root $Root } - Invoke-WolfPreSetup -Root $Root - Copy-Item -Path (Join-Path $stagedRoot '*') -Destination $PWD.Path -Recurse -Force + # Copy file-by-file so WOLF-only tools never leak into RPG Maker, + # SRPG, or other game roots through a downloaded patch archive. + $sourcePrefix = $stagedRoot.TrimEnd( + [IO.Path]::DirectorySeparatorChar, + [IO.Path]::AltDirectorySeparatorChar + ) + [IO.Path]::DirectorySeparatorChar + foreach ($file in Get-ChildItem -LiteralPath $stagedRoot -Recurse -File -Force) { + if ((-not $isWolfGame) -and ($file.Name -in $wolfOnlyNames)) { + continue + } + $relative = $file.FullName.Substring($sourcePrefix.Length) + $destination = Join-Path $Root $relative + $destinationDir = Split-Path -Parent $destination + if (-not (Test-Path -LiteralPath $destinationDir -PathType Container)) { + New-Item -ItemType Directory -Path $destinationDir -Force | Out-Null + } + Copy-Item -LiteralPath $file.FullName -Destination $destination -Force + } } finally { if (Test-Path -LiteralPath $zipPath) { diff --git a/gameupdate/gameupdate/patch.sh b/gameupdate/gameupdate/patch.sh index e3c2a47..3913267 100755 --- a/gameupdate/gameupdate/patch.sh +++ b/gameupdate/gameupdate/patch.sh @@ -225,6 +225,17 @@ wolf_loose_data_ready() { return 1 } +is_wolf_game() { + local name data_dir + for name in Data.wolf data.wolf; do + [ -f "$ROOT_DIR/$name" ] && return 0 + done + for data_dir in "$ROOT_DIR/Data" "$ROOT_DIR/data"; do + wolf_loose_data_ready "$data_dir" && return 0 + done + return 1 +} + find_uberwolf_cli() { if [ -f "$ROOT_DIR/UberWolfCli.exe" ]; then echo "$ROOT_DIR/UberWolfCli.exe" @@ -389,17 +400,35 @@ download_extract() { return 1 fi - # Stage UberWolfCli before unpack so Data.wolf -> Data/ happens before - # English patch files are copied on top. - for cli_name in UberWolfCli.exe UberWolfCli.LICENSE.txt; do - if [ -f "$inner/$cli_name" ] && [ ! -f "$ROOT_DIR/$cli_name" ]; then - cp -f "$inner/$cli_name" "$ROOT_DIR/$cli_name" - fi - done - invoke_wolf_pre_setup + wolf_patch=0 + if is_wolf_game; then + wolf_patch=1 + # Stage UberWolfCli before unpack so Data.wolf -> Data/ happens before + # English patch files are copied on top. + for cli_name in UberWolfCli.exe UberWolfCli.LICENSE.txt; do + if [ -f "$inner/$cli_name" ] && [ ! -f "$ROOT_DIR/$cli_name" ]; then + cp -f "$inner/$cli_name" "$ROOT_DIR/$cli_name" + fi + done + invoke_wolf_pre_setup + fi echo "Applying patch..." - if ! cp -rf "$inner"/* "$ROOT_DIR/"; then + copy_failed=0 + while IFS= read -r -d '' patch_file; do + relative_path="${patch_file#"$inner"/}" + file_name="${patch_file##*/}" + if [ "$wolf_patch" -ne 1 ] && \ + { [ "$file_name" = "UberWolfCli.exe" ] || [ "$file_name" = "UberWolfCli.LICENSE.txt" ]; }; then + continue + fi + target_path="$ROOT_DIR/$relative_path" + if ! mkdir -p "$(dirname "$target_path")" || ! cp -f "$patch_file" "$target_path"; then + copy_failed=1 + break + fi + done < <(find "$inner" -type f -print0) + if [ "$copy_failed" -ne 0 ]; then echo "Patch application failed!" rm -rf "$TMP_EX" rm -f "$ROOT_DIR/repo.zip" diff --git a/gui/skills_tab.py b/gui/skills_tab.py index 5c96b59..16feb4e 100644 --- a/gui/skills_tab.py +++ b/gui/skills_tab.py @@ -97,6 +97,41 @@ class SkillsTab(QWidget): ), is_json=False, ) + self._add_file_page( + key="wrap_config", + tab_title="Wrap Config", + path=SKILLS_DIR / "wrap_config.md", + hint="Clipboard prompt that asks the IDE to calculate RPG Maker wrap widths.", + is_json=False, + ) + self._add_file_page( + key="plugin_translation", + tab_title="Plugin TL", + path=SKILLS_DIR / "plugin_translation.md", + hint="MV/MZ plugin localisation audit and approved in-place translation prompt.", + is_json=False, + ) + self._add_file_page( + key="ace_script_translation", + tab_title="Ace Script TL", + path=SKILLS_DIR / "ace_script_translation.md", + hint="VX Ace Ruby script localisation audit and approved in-place translation prompt.", + is_json=False, + ) + self._add_file_page( + key="risky_codes", + tab_title="Risky Codes", + path=SKILLS_DIR / "risky_codes.md", + hint="Clipboard prompt for auditing optional RPG Maker event-code translation settings.", + is_json=False, + ) + self._add_file_page( + key="wolf_speakers", + tab_title="WOLF Speakers", + path=SKILLS_DIR / "wolf_speakers.md", + hint="Clipboard prompt for reviewing WOLF low-confidence first-line speakers.", + is_json=False, + ) self._add_file_page( key="contexts", tab_title="Contexts", diff --git a/gui/wolf_workflow_tab.py b/gui/wolf_workflow_tab.py index 63b5d38..23c0e2c 100644 --- a/gui/wolf_workflow_tab.py +++ b/gui/wolf_workflow_tab.py @@ -113,7 +113,7 @@ from util.project_scanner import ( wolf_repair_nested_data_dir, wolf_unpack_out_dir, ) -from util.skills import load_project_setup +from util.skills import load_clipboard_skill, load_project_setup # Workflow-level label for the non-batch (live) translation path. The Translation # tab's own mode is called "Translate"; _workflow_mode_text() maps to that. @@ -129,47 +129,7 @@ WORK_DIR_NAME = "wolf_json" PHASE_NAMES_KINDS = {"names"} PHASE_DB_KINDS = {"db"} PHASE_MAPS_EVENTS_KINDS = {"map", "common", "gamedat", "txt", "txt-dir"} - -# Speaker-format prompt for a repo-aware AI. WolfDawn already detects and tags who -# speaks on each line, so the only decision left is whether its LOW-confidence -# first-line guesses are really speaker names for this game. The AI inspects the -# extracted text and returns a single ENABLE/DISABLE recommendation. -_WOLF_SPEAKER_PROMPT = ( - "You are an expert Japanese WOLF RPG Editor translator helping configure a translation tool.\n" - "\n" - "\n" - "WolfDawn extracts each line with a 'speaker' and a 'speaker_src' tag describing how it " - "detected the speaker. Two tags carry the speaker name baked into the FIRST line of the " - "'source' text (the rest is the dialogue body):\n" - " - literal_line1 : HIGH confidence - a face/name window precedes the line, so the " - "first line really is a nameplate. The tool always reshapes these; nothing to decide.\n" - " - literal_line1_lowconf : LOW confidence - a short first line with NO preceding face " - "window. WolfDawn guesses it is a speaker name, but it might actually be the start of the " - "dialogue or narration.\n" - "When a first-line format is trusted, the tool reshapes 'Name\\nbody' into '[Name]: body' for " - "translation, then restores 'Name\\nbody' on inject (byte-safe either way).\n" - "\n" - "\n" - "--- attach the extracted JSON in files/ here (maps / CommonEvent) before continuing ---\n" - "\n" - "\n" - "Decide whether the LOW-confidence first-line guesses (speaker_src = literal_line1_lowconf) " - "should be treated as speaker names for THIS game. Inspect a good sample of those entries in " - "files/: look at the first line of each such 'source' and judge whether it is genuinely a " - "character/speaker label as opposed to real dialogue or narration.\n" - " - ENABLE if the low-confidence first lines are overwhelmingly real speaker names.\n" - " - DISABLE if many are actually dialogue/narration (reshaping them would mislabel lines).\n" - "(The high-confidence nameplates are always handled; you are only ruling on the guesses.)\n" - "\n" - "\n" - "\n" - "Return ONLY a fenced code block containing the recommendation and a one-line reason, e.g.\n" - "```\n" - "LOWCONF_FIRSTLINE: ENABLE - low-confidence first lines are short character names (市民, 兵士...).\n" - "```\n" - "Use exactly ENABLE or DISABLE after the colon.\n" - "\n" -) +# The speaker-format prompt is loaded from editable data/skills/wolf_speakers.md. class _WolfTaskWorker(QThread): @@ -2160,7 +2120,7 @@ class WolfWorkflowTab(QWidget): def _copy_wolf_speaker_prompt(self): try: - QApplication.clipboard().setText(_WOLF_SPEAKER_PROMPT) + QApplication.clipboard().setText(load_clipboard_skill("wolf_speakers.md")) self._log( "📋 Speaker-format prompt copied. Paste it into Cursor/Copilot with files/ open; " "set the low-confidence box to match its recommendation." diff --git a/gui/workflow_tab.py b/gui/workflow_tab.py index 31d96cb..749427e 100644 --- a/gui/workflow_tab.py +++ b/gui/workflow_tab.py @@ -21,7 +21,7 @@ import threading from pathlib import Path from util.paths import VOCAB_PATH, APP_NAME, ORG_NAME -from util.skills import load_project_setup +from util.skills import load_clipboard_skill, load_project_setup from util.vocab import BASE_SEPARATOR as _SHARED_BASE_SEPARATOR import jsbeautifier @@ -318,6 +318,17 @@ _GAMEUPDATE_COPY_SKIP_NAMES = frozenset({ "previous_patch_sha.txt", }) +# UberWolf is only useful for WOLF RPG Editor archives. The generic workflow +# handles RPG Maker MV/MZ/Ace and must never install these files; the dedicated +# WOLF workflow intentionally continues using the smaller shared skip set. +_WOLF_ONLY_GAMEUPDATE_NAMES = frozenset({ + "UberWolfCli.exe", + "UberWolfCli.LICENSE.txt", +}) +_RPG_GAMEUPDATE_COPY_SKIP_NAMES = ( + _GAMEUPDATE_COPY_SKIP_NAMES | _WOLF_ONLY_GAMEUPDATE_NAMES +) + class _FileCopyWorker(QThread): """Recursively copy a source folder into a destination folder.""" @@ -1155,345 +1166,7 @@ class WorkflowTab(QWidget): # ── Step 3: Vocab / Glossary ──────────────────────────────────────────── - # ── Copilot prompt templates ──────────────────────────────────────────── - - _WRAP_PROMPT = ( - "You are an expert RPGMaker MV/MZ configuration analyst.\n" - "\n" - "\n" - "Calculate the correct text-wrap width settings for a Japanese-to-English RPGMaker MV/MZ " - "translation tool. The tool wraps translated English using character-count limits (not pixels). " - "I need three values: width, listWidth, and noteWidth.\n" - "\n" - "\n" - "--- attach System.json and js/plugins.js here before continuing ---\n" - "\n" - "\n" - "1. Read screenWidth and fontSize from System.json.\n" - " Check js/plugins.js for any MessageCore or Window plugin that overrides these values.\n" - "2. For each window type, estimate its pixel width, subtract ~48px padding, then calculate:\n" - " chars = floor(content_px / (font_size × 0.58))\n" - " - width: main dialogue/message box (Show Text) — typically full screen width\n" - " - listWidth: item/skill/help description windows — typically full or half screen width\n" - " - noteWidth: database note fields — typically the narrowest pane (~40–50% screen width)\n" - "3. If font size is above 26px and reducing it would meaningfully increase characters per line, " - "note where to change it (System.json or the relevant plugin parameter).\n" - "\n" - "\n" - "\n" - "Output only the final values — do not show calculations:\n" - "\n" - "```\n" - "width=\n" - "listWidth=\n" - "noteWidth=\n" - "fontSize= # or: no change needed\n" - "```\n" - "\n" - "Followed by one sentence of assumptions if anything was estimated.\n" - "\n" - ) - - _PLUGINS_JS_TRANSLATE_PROMPT = ( - "You are an expert RPGMaker MV/MZ localisation engineer.\n" - "\n" - "\n" - "Translate visible Japanese strings inside js/plugins.js without breaking any game logic " - "or plugin functionality. A vocab.txt glossary is attached — use it as your primary reference. " - "Any name or term that appears in the glossary must be translated exactly as shown there.\n" - "\n" - "\n" - "--- attach js/plugins.js and vocab.txt here before continuing ---\n" - "\n" - "\n" - "\n" - "Only translate string values directly shown to the player at runtime:\n" - "- Menu/button labels in-game UI (e.g. 決定, キャンセル)\n" - "- Scene/window title text (e.g. アイテム, スキル, 装備)\n" - "- In-game popup, tooltip, or notification messages\n" - "- Default NPC names or pronouns used in UI display\n" - "- Help or description text shown in help windows\n" - "- Battle log messages or status effect messages\n" - "\n" - "\n" - "\n" - "Translating the following WILL BREAK THE GAME:\n" - "\n" - "1. Plugin parameter keys (object property names).\n" - " { \"CommandName\": \"セーブ\" } → translate セーブ but NOT CommandName\n" - "\n" - "2. Strings used as internal identifiers or lookup keys:\n" - " - Switch/variable names matching System.json entries\n" - " - Actor, skill, item, weapon, armour names used as keys inside other plugin parameters\n" - " - Strings passed as plugin command arguments that the engine looks up\n" - "\n" - "3. File paths, filenames, URLs, colour codes, font names, icon indices.\n" - " (e.g. img/faces/Actor1 or #ffffff)\n" - "\n" - "4. Plugin names and script identifiers:\n" - " - The \"name\" property at the top of each plugin block (e.g. { \"name\": \"YEP_CoreEngine\" })\n" - " - Function identifiers, class names, JS event names\n" - "\n" - "5. Any string in the game data files (Actors.json, Skills.json, Items.json, etc.) that is " - "also used as a lookup key in the plugin — changing it here would desync it from the data file.\n" - "\n" - "6. Boolean strings, numeric strings, regex patterns.\n" - "\n" - "\n" - "\n" - "Before translating any string, confirm all three are true:\n" - "- It is displayed directly to the player as visible text\n" - "- It is purely a UI label, not used as a key anywhere else\n" - "- Nothing in the codebase compares this exact string to another value\n" - "When in doubt, skip it — untranslated Japanese is better than a broken game.\n" - "\n" - "\n" - "\n" - "Provide the translated file as a complete replacement of js/plugins.js, inside a single " - "fenced code block (```js ... ```) so it can be copied in one click. Only change the " - "string values identified above. Preserve all original formatting, indentation, comments, and structure.\n" - "\n" - "After the code block, output a summary:\n" - "\n" - "### Translations Made\n" - " Plugin: \n" - " Parameter: \n" - " Before: \n" - " After: \n" - "\n" - "### Skipped (Ambiguous or Internal)\n" - "List any Japanese strings you detected but did not translate, with a one-line reason.\n" - "\n" - ) - - _ACE_SCRIPTS_TRANSLATE_PROMPT = ( - "You are an expert RPGMaker VX Ace (Ruby) localisation engineer.\n" - "\n" - "\n" - "Translate visible Japanese strings inside the game's Ruby scripts (ace_json/scripts/*.rb) " - "without breaking any game logic or script functionality. A vocab.txt glossary is attached - " - "use it as your primary reference. Any name or term in the glossary must be translated exactly as shown.\n" - "\n" - "\n" - "--- attach the .rb script files and vocab.txt here before continuing ---\n" - "\n" - "\n" - "========================================\n" - "## WHAT TO TRANSLATE\n" - "========================================\n" - "\n" - "Only translate string literals that are directly shown to the player at runtime.\n" - "These typically appear as:\n" - " - Strings passed to msgbox, msgbox_p, print, p\n" - " - Labels and text in Window or Scene classes rendered to screen\n" - " - draw_text / draw_item calls with a Japanese string literal\n" - " - Default UI label text (menu names, button labels, status window text)\n" - " - Battle log messages, notifications, popup strings\n" - " - Help or description text shown in help windows\n" - "\n" - "========================================\n" - "## WHAT MUST NOT BE TRANSLATED\n" - "========================================\n" - "\n" - "CRITICAL - translating the following will break the game:\n" - "\n" - " 1. Strings used as hash keys, method names, or symbol equivalents.\n" - " Example: vocab[\"HP\"] = \"体力\" -> translate \"体力\" but NOT the key \"HP\"\n" - "\n" - " 2. Strings used as internal identifiers compared with == or used in case/when:\n" - " - Actor/class/skill/item names used as lookup strings\n" - " - Script-internal state names or flag strings\n" - " Example: if type == \"スキル\" -> do NOT translate \"スキル\"\n" - "\n" - " 3. File paths, filenames, font names, colour strings, URLs.\n" - "\n" - " 4. Regular expressions, format strings used with sprintf or % operator\n" - " where the placeholders must stay in the same position.\n" - " (You may translate the human-readable parts but keep %s / %d / %1 etc intact.)\n" - "\n" - " 5. Script class names, module names, method names, constants.\n" - "\n" - " 6. Any string that is read back elsewhere in the scripts with an exact match.\n" - "\n" - "\n" - "Before translating any string, confirm all three are true:\n" - "- It is displayed directly to the player as visible text\n" - "- It is purely a display string, not compared or looked up anywhere\n" - "- Changing it would break no conditional logic or data lookup\n" - "When in doubt, skip it - untranslated Japanese is better than a broken game.\n" - "\n" - "\n" - "\n" - "For each .rb file that needed changes, provide the full translated file content inside its " - "own fenced code block (```ruby ... ```), preceded by the filename, so each file can be " - "copied in one click. Only change string values identified as safe. " - "Preserve all Ruby syntax, indentation, comments, and structure exactly.\n" - "\n" - "After all files, output a summary:\n" - "\n" - "### Translations Made\n" - " File: