Conversation
* Stub out most papyrus dependencies for release and Ci Builds * Add Github Actions CI * Add dev-scripts to simplify building locally * Maintain reference to real sources for local dev builds
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughAdds a SkyUI MCM framework (menus, widgets, settings, favorites), Papyrus API stubs for CI compilation, PowerShell build tooling and GitHub Actions CI, updated Papyrus project files, README/gitignore updates, and renames one MCM event handler in the main script. (50 words) Changes
Sequence Diagram(s)sequenceDiagram
participant Player
participant UI as "SkyUI Menu"
participant ConfigMgr as "SKI_ConfigManager"
participant Config as "SKI_ConfigBase / SKI_ConfigMenu"
participant Settings as "SKI_SettingsManager"
participant WidgetMgr as "SKI_WidgetManager"
Player->>UI: Open Journal / Config menu
UI->>ConfigMgr: SKICP_modOpen / selection events
ConfigMgr->>Config: Route register/select/highlight events
Config->>Settings: Request/Apply overrides
Config->>UI: Push option buffers / UI invocations
Player->>UI: Interact (toggle/slider/menu/color/key)
UI->>ConfigMgr: OnOptionSelect / OnOptionHighlight events
ConfigMgr->>Config: Dispatch to page/state handlers
Config->>Config: Update internal state & settings
Config->>UI: Update displayed values
WidgetMgr->>WidgetMgr: Init widget loader -> UI inject
WidgetMgr->>Config/Widgets: Notify OnWidgetLoad / ready
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai please review |
|
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 27
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.agents/workflows/build.md:
- Line 17: Remove the stray token "// turbo" from the Markdown (it appears
accidentally in the build instructions); open the .agents/workflows/build.md
content and delete the exact string "// turbo" so the README no longer contains
the stray comment line and the build instructions render correctly.
In @.github/workflows/build.yml:
- Around line 24-35: The workflow currently calls Resolve-Path "Scripts"
(assigned to $output) before ensuring the Scripts directory exists and is clean,
which can fail or include stale .pex files; update the job to create the Scripts
directory if missing and remove existing contents (or explicitly delete *.pex)
prior to calling Resolve-Path "Scripts" and before packing the archive (also
apply same fix at the other occurrence around the later Resolve-Path call),
ensuring $output points to a fresh directory.
- Around line 1-12: The workflow "name: Build FSMP MCM" (jobs: build) lacks an
explicit permissions block, so add a top-level permissions mapping to minimize
GITHUB_TOKEN scope; insert a permissions block at the root of the workflow
(above jobs) that grants only what this job needs, e.g. permissions: contents:
read and actions: write (so the job can read repo files and upload artifacts)
and remove any broader defaults.
In `@dev-scripts/compile.ps1`:
- Around line 95-100: The output directory creation step (using $OutputDir)
doesn't remove stale .pex binaries, so before collecting $SourceFiles or
creating $OutputDir you should delete existing .pex files in the target Scripts
directory (e.g., remove "*.pex" under $OutputDir/Scripts or the concrete Scripts
folder) to ensure renamed/deleted source scripts don't leave stale binaries;
implement a cleanup that tests for and removes matching .pex files (and create
the Scripts dir afterwards if missing) so the subsequent $SourceFiles =
Get-ChildItem ... only reflects freshly built sources.
- Around line 16-38: The script currently auto-downloads Caprica from
$CapricaUrl using Invoke-WebRequest and extracts it to $DestDir without
provenance checks; either remove this auto-download block or replace it with a
verified flow: update $CapricaUrl to an authoritative release (e.g., the
Orvid/Caprica v0.3.0 release), add SHA-256 (or signature) verification of the
downloaded $zipFile before Expand-Archive, and document manual-install steps and
verification in comments (or fail with a clear message instructing the user to
install Caprica.exe into $DestDir). Ensure references to $Name, $zipFile,
$outDir, Invoke-WebRequest, and Expand-Archive are updated to reflect the new
verified download or removed if you choose manual-only installation.
In `@dev-scripts/setup_ci.ps1`:
- Around line 33-34: The script trusts the downloaded Caprica artifact and
assumes Get-ChildItem returns Caprica.exe; add integrity verification and an
explicit missing-file failure: after Download-And-Extract (captured in
$capricaPath) compute the file hash for the downloaded Caprica.zip or the
extracted Caprica.exe using Get-FileHash and compare it to a known expected
checksum variable (e.g., $expectedCapricaChecksum); if the checksum mismatches,
remove the bad artifact, write an error to the console, and exit non-zero. Also
change the Get-ChildItem pipeline that finds "Caprica.exe" to capture the result
in a variable (e.g., $capricaExe = Get-ChildItem ... | Select-Object -First 1)
and if $capricaExe is $null, write an explicit error and exit non-zero instead
of calling Copy-Item; only call Copy-Item when the checksum passes and
$capricaExe is present.
In `@README.md`:
- Around line 44-64: Add blank lines before and after the fenced PowerShell code
blocks in README.md to satisfy markdownlint MD031: ensure there is an empty line
immediately above the opening ```powershell and an empty line immediately below
the closing ``` for both the compile.ps1 example block and the Caprica.exe
example block so the fenced blocks are separated from surrounding paragraphs.
- Line 3: Update the build badge URL in README.md so it points to the canonical
repository; replace the repository segment "KaninHop/FSMP-MCM" with
"DaymareOn/FSMP-MCM" in the badge image/link URL (the string containing
"https://github.com/KaninHop/FSMP-MCM/actions/...") so the badge reflects the
correct CI pipeline for this repo.
In `@skyrimse.dev.ppj`:
- Line 4: Replace the hardcoded Flags path value with a placeholder and guiding
comment so other developers know to set their local compiler flags path; update
the Flags attribute (the Flags="..." entry) to something like
Flags="PATH_TO_LOCAL_FLAGS\TESV_Papyrus_Flags.flg" and add a short comment
"ADJUST THIS PATH" or similar next to it so it's clear it must be customized on
each machine.
In `@Source/Scripts/SkyUI_SDK/SKI_ConfigBase.psc`:
- Around line 411-433: The comment and code in SetOptionFlags indicate the
option flags buffer (_optionFlagsBuf) should be updated but the computed
oldFlags is never written back; fix by assigning the newly composed value into
_optionFlagsBuf[index] after calculating oldFlags (preserving the lower
byte/type via oldFlags %= 0x100 and adding a_flags * 0x100), so the buffer
matches the UI update performed by UI.InvokeIntA and remains consistent with
future reads.
In `@Source/Scripts/SkyUI_SDK/SKI_ConfigManager.psc`:
- Around line 143-226: Add a guard at the start of every routed UI event handler
from OnPageSelect through OnColorAccept to bail out if _activeConfig is none;
for handlers that normally call UI.InvokeBool(JOURNAL_MENU, MENU_ROOT +
".unlock", true) ensure you still call that unlock before returning so the UI
interaction stack isn’t left locked (reference the event handlers OnPageSelect,
OnOptionHighlight, OnOptionSelect, OnOptionDefault, OnKeymapChange,
OnSliderSelect, OnSliderAccept, OnMenuSelect, OnMenuAccept, OnColorSelect,
OnColorAccept and the _activeConfig.RemapKey/_activeConfig.* calls to locate the
spots).
- Around line 237-248: The capacity check (_configCount >= 128) runs before the
duplicate scan so an already-registered menu (a_menu) returns -1 at capacity;
change the flow in the registration routine to first iterate _modConfigs to
check for an existing entry (comparing _modConfigs[i] to a_menu and returning i
via GotoState("") if found) and only after that duplicate check enforce the
capacity limit using _configCount >= 128 to return -1, preserving the
redundant-registration path; reference the existing loop over _modConfigs, the
_configCount comparison, and the use of GotoState("") when reordering the
checks.
- Around line 128-139: OnModSelect currently only checks configIndex > -1 and
then uses _modConfigs[configIndex] without validating bounds or presence; update
the handler to ensure configIndex is within range (configIndex <
_modConfigs.length) and that _modConfigs[configIndex] is not none before calling
CloseConfig/OpenConfig on _activeConfig/_modConfigs[configIndex]; if the guard
fails, do not change _activeConfig (optionally log or ignore the event) so
OpenConfig() is never invoked on a none entry.
In `@Source/Scripts/SkyUI_SDK/SKI_ConfigMenu.psc`:
- Around line 1010-1014: The OnDefaultST handler resets the label/index but
fails to restore the widget's anchor state; update OnDefaultST to mirror its
select handler by setting the widget anchor property (e.g., assign
_effectWidgetVAnchorIdx and also write SKI_ActiveEffectsWidgetInstance.VAnchor
or the equivalent widget anchor field) and recompute the widget position after
changing anchors (use _alignmentBaseOffsets/_effectWidgetHAnchorIdx and
_effectWidgetXOffset for X and the vertical equivalents for Y), and make the
same change in the corresponding default handler at the 1036-1039 region so both
label text and actual widget anchors are restored when Default is pressed.
- Around line 796-800: The OnDefaultST event is clearing the armor flag instead
of hands; change the flag constant used when calling
SKI_FavoritesManagerInstance.SetGroupFlag in OnDefaultST from
GROUP_FLAG_UNEQUIP_ARMOR to GROUP_FLAG_UNEQUIP_HANDS so the handler toggles the
correct bit (reference the event OnDefaultST and
SKI_FavoritesManagerInstance.SetGroupFlag and the GROUP_FLAG_UNEQUIP_HANDS
symbol exposed in SKI_FavoritesManager).
- Around line 746-751: OnDefaultST resets _favCurGroupIdx and current group but
sets the displayed text with SetTextOptionValueST(_favCurGroupIdx+1), causing
the UI label to differ from the accept path which uses
SetMenuOptionValueST(_favGroupNames[_favCurGroupIdx]); change the default path
to call SetMenuOptionValueST(_favGroupNames[_favCurGroupIdx]) (use the same
_favGroupNames and _favCurGroupIdx as in the accept flow) so the visible menu
label matches the selected favorite group.
In `@Source/Scripts/SkyUI_SDK/SKI_FavoritesManager.psc`:
- Around line 373-412: In SetGroupHotkey move or add the declaration/assignment
of oldKeycode before the unmap special-case so UnregisterForKey(oldKeycode) uses
a defined value: retrieve oldKeycode = _groupHotkeys[a_groupIndex] (and ensure
oldIndex = _groupHotkeys.Find(a_keycode) is also available if needed) before the
if (a_keycode == -1) block, then use that oldKeycode in UnregisterForKey and
proceed with setting _groupHotkeys[a_groupIndex] = -1; this ensures
UnregisterForKey is called with the current key instead of an undeclared
variable.
- Around line 230-246: OnMenuOpen currently iterates _itemInvalidFlags1 and
_itemInvalidFlags2 which may be nil if OnVersionUpdate hasn't run; add a
nil-check (and lazy initialization) for both arrays at the start of OnMenuOpen
so they are created (with length 128 and default false values) if unset before
the loops that reset them, then continue calling InitControls() and
InitMenuGroupData(); reference _itemInvalidFlags1, _itemInvalidFlags2,
OnMenuOpen and OnVersionUpdate to ensure the initialization logic matches the
version-upgrade creation behavior.
- Around line 721-732: The loop stops early because it compares signed ints
against 0x80000000; change the loop termination to iterate until the bit mask
becomes zero rather than comparing to 0x80000000: start with h = 0x00000001 and
use a loop condition like "while (h != 0)" (or equivalent) so LeftShift(h,1)
will produce 0 after the highest bit and the loop covers all mask bits; update
the block around GetGroupFlag(GROUP_FLAG_UNEQUIP_ARMOR), PlayerREF.GetWornForm,
LogicalAND(h, _usedOutfitMask) and PlayerREF.UnEquipItemEX to use this new
condition so all slot masks including 0x80000000 are processed correctly.
In `@Source/Scripts/SkyUI_SDK/SKI_PlayerLoadGameAlias.psc`:
- Around line 5-7: The current OnPlayerLoadGame event directly casts
GetOwningQuest() to SKI_QuestBase and calls OnGameReload(), which can fail
silently; instead, store GetOwningQuest() in a local variable, check that it is
not None and that it is of type SKI_QuestBase (or use a safe cast check) before
calling OnGameReload() on that instance (refer to OnPlayerLoadGame,
GetOwningQuest, SKI_QuestBase, and OnGameReload to locate the code).
In `@Source/Scripts/SkyUI_SDK/SKI_QF_ConfigManagerInstance.psc`:
- Around line 13-18: The code currently casts self to Quest (__temp) and then to
SKI_ConfigManager (kmyQuest) and calls kmyQuest.ForceReset() unconditionally;
you must guard against a failed cast by checking that kmyQuest is not None
before calling ForceReset. Modify the block around the casts (__temp and
kmyQuest) to perform a null-check on kmyQuest (or __temp) and only call
SKI_ConfigManager.ForceReset() when the cast succeeded, otherwise skip the call
(and optionally log or return) to avoid runtime errors.
In `@Source/Scripts/SkyUI_SDK/SKI_WidgetBase.psc`:
- Around line 42-46: The Ready property currently returns _initialized but
should expose the widget's true readiness flag _ready; change the getter in the
Ready property to return _ready (so UI.Invoke* calls and property setters don't
run before OnWidgetLoad() sets _ready and _widgetRoot exists), leaving the
property read-only and preserving existing behavior in OnGameReload() and
OnWidgetLoad().
In `@Source/Scripts/SkyUI_SDK/SKI_WidgetManager.psc`:
- Around line 65-100: InitWidgetLoader currently bails if both UI.InvokeString
loadMovie attempts fail; change it to perform a bounded retry instead: in
InitWidgetLoader (reference symbols: InitWidgetLoader, UI.InvokeString,
UI.GetInt, HUD_MENU) implement a short retry loop (e.g. 3 attempts) with a small
delay (Utility.Wait or RegisterForSingleUpdate) that re-runs the loadMovie calls
and re-reads _global.WidgetLoader.SKYUI_RELEASE_IDX before returning; only
return after exhausting retries, and if it eventually succeeds send the existing
SKIWF_widgetManagerReady notification (or proceed with the normal success path);
additionally ensure the code re-registers for the HUD/menu open event if you
rely on menu callbacks so the loader will try again later if HUD was still
coming up.
- Around line 115-129: Both event handlers (OnWidgetLoad and OnWidgetError)
index _widgets using IDs from the SWF without validating them; add a
bounds-and-null check before any _widgets[widgetID] access. In OnWidgetLoad
(where widgetID is obtained via "int widgetID = a_strArg as int") and
OnWidgetError (where widgetID comes from a_numArg), validate that widgetID is >=
0 and < _widgets.Length and that _widgets[widgetID] != none; only then call
client.OnWidgetLoad() or use the widget for logging. If the ID is invalid or the
cast fails, avoid indexing and emit a safe fallback Debug.Trace that includes
the raw widgetID (or arg) and errorType so you can recover without causing an
out‑of‑bounds access.
In `@Source/Scripts/Stubs/JContainers/JMap.psc`:
- Line 5: The getStr stub currently declares a String default parameter which
breaks callers that pass ints/floats; update the stub for function getStr(Int
object, String key, String default="") to accept a flexible default type (e.g.
change the default parameter to a Variant/Any type or provide overloads allowing
Int and Float defaults) so the signature matches actual JContainers usage;
ensure the native/global modifiers remain and update any dependent declarations
to use the new parameter type to preserve compatibility.
In `@Source/Scripts/Stubs/SKSE/UI.psc`:
- Around line 16-18: The current stub for Function Invoke(string menuName,
string target) incorrectly calls InvokeBool(menuName, target, false) which adds
an extra boolean argument; change the stub to match the real SKSE signature by
declaring Function Invoke(...) as native (i.e., make Invoke a native function
instead of a wrapper) so it invokes Scaleform with no added arguments; update
the declaration for Invoke in this file (and any related declarations) to be
native and remove the wrapper call to InvokeBool to ensure behavior matches
UI.Invoke.
In `@Source/Scripts/Stubs/SKSE/Utility.psc`:
- Around line 6-7: Update the declaration for the SKSE Papyrus Utility.Wait
function by removing the incorrect float return type so it is declared as a void
(i.e. match the pattern used by WaitMenuMode); locate the `Function Wait(float
afSeconds) native global` declaration (symbol: Wait) in
Source/Scripts/Stubs/SKSE/Utility.psc and change it to the no-return form
consistent with the SKSE API.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 45e9d744-1009-4740-8524-395a2a6ee8f6
📒 Files selected for processing (44)
.agents/workflows/build.md.github/workflows/build.yml.gitignoreREADME.mdScripts/FSMPM.pexScripts/FSMPMPlayerScript.pexSource/Scripts/FSMPM.pscSource/Scripts/SkyUI_SDK/SKI_ActiveEffectsWidget.pscSource/Scripts/SkyUI_SDK/SKI_ConfigBase.pscSource/Scripts/SkyUI_SDK/SKI_ConfigManager.pscSource/Scripts/SkyUI_SDK/SKI_ConfigMenu.pscSource/Scripts/SkyUI_SDK/SKI_FavoritesManager.pscSource/Scripts/SkyUI_SDK/SKI_Main.pscSource/Scripts/SkyUI_SDK/SKI_PlayerLoadGameAlias.pscSource/Scripts/SkyUI_SDK/SKI_QF_ConfigManagerInstance.pscSource/Scripts/SkyUI_SDK/SKI_QuestBase.pscSource/Scripts/SkyUI_SDK/SKI_SettingsManager.pscSource/Scripts/SkyUI_SDK/SKI_WidgetBase.pscSource/Scripts/SkyUI_SDK/SKI_WidgetManager.pscSource/Scripts/Stubs/BaseGame/Actor.pscSource/Scripts/Stubs/BaseGame/Alias.pscSource/Scripts/Stubs/BaseGame/Debug.pscSource/Scripts/Stubs/BaseGame/Faction.pscSource/Scripts/Stubs/BaseGame/Form.pscSource/Scripts/Stubs/BaseGame/GlobalVariable.pscSource/Scripts/Stubs/BaseGame/Keyword.pscSource/Scripts/Stubs/BaseGame/ObjectReference.pscSource/Scripts/Stubs/BaseGame/Quest.pscSource/Scripts/Stubs/BaseGame/ReferenceAlias.pscSource/Scripts/Stubs/BaseGame/TESV_Papyrus_Flags.flgSource/Scripts/Stubs/ConsoleUtil/ConsoleUtil.pscSource/Scripts/Stubs/JContainers/JMap.pscSource/Scripts/Stubs/JContainers/JValue.pscSource/Scripts/Stubs/PapyrusUtil/JsonUtil.pscSource/Scripts/Stubs/PapyrusUtil/MiscUtil.pscSource/Scripts/Stubs/PapyrusUtil/PapyrusUtil.pscSource/Scripts/Stubs/SKSE/StringUtil.pscSource/Scripts/Stubs/SKSE/UI.pscSource/Scripts/Stubs/SKSE/Utility.pscdev-scripts/compile.ps1dev-scripts/setup_ci.ps1skyrimse.dev.ppjskyrimse.ppjskyrimse_ci.ppj
| name: Build FSMP MCM | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ main ] | ||
| pull_request: | ||
| branches: [ main ] | ||
| workflow_dispatch: | ||
|
|
||
| jobs: | ||
| build: | ||
| runs-on: windows-latest |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/build.ymlRepository: DaymareOn/FSMP-MCM
Length of output: 3598
🌐 Web query:
actions/upload-artifact GitHub Actions permissions required
💡 Result:
The actions/upload-artifact action in GitHub Actions does not require explicit permissions configuration in the workflow's permissions block for the GITHUB_TOKEN. It uses a special internal token (ACTIONS_RUNTIME_TOKEN or similar, not GITHUB_TOKEN) provided automatically to official GitHub actions for artifact operations, which bypasses standard GITHUB_TOKEN permission restrictions. This allows upload-artifact to work even with restrictive workflow permissions like permissions: {} or contents: read. Official documentation for upload-artifact and artifact storage does not specify any required permissions, confirming it operates independently of declared GITHUB_TOKEN scopes. Note: This is distinct from GitHub Packages (e.g., publishing Docker images), which requires packages: write. For workflow artifacts, no such permission is needed. File system permissions on the runner must allow reading the paths to upload (e.g., avoid root-owned files without chmod). File permissions are not preserved in uploads (all files set to 644, dirs to 755).
Citations:
- 1: Add details on authentication / permissions used during upload actions/upload-artifact#197
- 2: https://docs.github.com/actions/using-workflows/storing-workflow-data-as-artifacts
- 3: https://github.com/actions/upload-artifact
- 4: https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
- 5: https://www.npmjs.com/package/@actions/artifact
🌐 Web query:
GitHub Actions GITHUB_TOKEN default permissions push pull_request scope
💡 Result:
The default permissions for the GITHUB_TOKEN in GitHub Actions workflows depend on repository/organization settings and the triggering event. By default (historical/current for many repos), GITHUB_TOKEN has read/write permissions for all scopes. However, for new repositories and organizations, the default is limited to read-only permissions on repository contents (contents: read) and packages. This can be configured in repository Settings > Actions > General > Workflow permissions, with options "Read and write permissions" or "Read repository contents and packages permissions". If no permissions key is specified in the workflow YAML, the GITHUB_TOKEN uses these default settings. For workflows triggered by pull_request events from forked repositories (especially public forks), the GITHUB_TOKEN is always restricted to read-only permissions across all scopes, regardless of settings, as a security measure to prevent malicious code execution. For push events or internal PRs (not from forks), it follows the configured defaults (read/write all or contents:read). To grant specific permissions, use the permissions key at workflow or job level, e.g.: permissions: contents: read pull-requests: write Unspecified permissions default to none if any are explicitly set. Primary scopes relevant to push/PR: contents (for git read/write), pull-requests (for PR operations), statuses (commit statuses). Sources confirm: for fork PRs, always read-only GITHUB_TOKEN ({1,11,12,13,16}); defaults changed to read-only for new repos/orgs ({12}); admin settings for defaults ({1,11}); workflow syntax ({13}).
Citations:
- 1: https://github.blog/changelog/2021-04-20-github-actions-control-permissions-for-github_token/
- 2: https://docs.github.com/en/actions/security-guides/automatic-token-authentication
- 3: https://docs.github.com/en/actions/concepts/security/github_token
- 4: https://docs.github.com/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token
- 5: https://stackoverflow.com/questions/78444367/github-token-permission-in-workflow-changes-to-read-after-setting-it-to-write
- 6: https://www.stepsecurity.io/blog/github-token-how-it-works-and-how-to-secure-automatic-github-action-tokens
- 7: https://github.blog/changelog/2021-04-20-github-actions-control-permissions-for-github_token
- 8: https://github.blog/security/new-tool-to-secure-your-github-actions/
- 9: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
- 10: https://stackoverflow.com/questions/75744849/permission-to-repo-denied-to-github-actions-for-pr-coming-from-a-fork-only
Scope the workflow token down explicitly.
This job only needs repository reads plus artifact upload. Without an explicit permissions block it can inherit broader GITHUB_TOKEN access than necessary depending on repository settings, which increases the blast radius if a downloaded tool or build step is compromised.
Suggested fix
name: Build FSMP MCM
+permissions:
+ contents: read
+
on:📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| name: Build FSMP MCM | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| workflow_dispatch: | |
| jobs: | |
| build: | |
| runs-on: windows-latest | |
| name: Build FSMP MCM | |
| permissions: | |
| contents: read | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| workflow_dispatch: | |
| jobs: | |
| build: | |
| runs-on: windows-latest |
🧰 Tools
🪛 YAMLlint (1.38.0)
[warning] 3-3: truthy value should be one of [false, true]
(truthy)
[error] 5-5: too many spaces inside brackets
(brackets)
[error] 5-5: too many spaces inside brackets
(brackets)
[error] 7-7: too many spaces inside brackets
(brackets)
[error] 7-7: too many spaces inside brackets
(brackets)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/build.yml around lines 1 - 12, The workflow "name: Build
FSMP MCM" (jobs: build) lacks an explicit permissions block, so add a top-level
permissions mapping to minimize GITHUB_TOKEN scope; insert a permissions block
at the root of the workflow (above jobs) that grants only what this job needs,
e.g. permissions: contents: read and actions: write (so the job can read repo
files and upload artifacts) and remove any broader defaults.
| $CapricaUrl = "https://github.com/KrisV-777/Caprica/releases/download/0.3.0a/Caprica.zip" | ||
| $Name = "Caprica-AutoInstall" | ||
|
|
||
| Write-Host "Caprica not found. Attempting to auto-download..." | ||
|
|
||
| try { | ||
| if (-not (Test-Path $DestDir)) { New-Item -ItemType Directory -Path $DestDir -Force } | ||
|
|
||
| $zipFile = Join-Path $env:TEMP "$Name.zip" | ||
| $outDir = Join-Path $env:TEMP "$Name-extracted" | ||
|
|
||
| Write-Host " Downloading from $CapricaUrl..." | ||
| Invoke-WebRequest -Uri $CapricaUrl -OutFile $zipFile -UseBasicParsing | ||
|
|
||
| if (Test-Path $outDir) { Remove-Item -Recurse -Force $outDir } | ||
| Write-Host " Extracting..." | ||
| Expand-Archive -Path $zipFile -DestinationPath $outDir -Force | ||
|
|
||
| $exePath = Get-ChildItem -Path $outDir -Filter "Caprica.exe" -Recurse | Select-Object -First 1 | ||
| if ($exePath) { | ||
| Copy-Item -Path $exePath.FullName -Destination (Join-Path $DestDir "Caprica.exe") -Force | ||
| Write-Host " Successfully installed Caprica to $DestDir" | ||
| return $true |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
git ls-files | grep -E "(compile|setup_ci)\.ps1"Repository: DaymareOn/FSMP-MCM
Length of output: 110
🏁 Script executed:
cat -n dev-scripts/compile.ps1 | head -60Repository: DaymareOn/FSMP-MCM
Length of output: 2820
🏁 Script executed:
cat -n dev-scripts/setup_ci.ps1Repository: DaymareOn/FSMP-MCM
Length of output: 2074
🌐 Web query:
Caprica 0.3.0a GitHub release SHA256 checksum
💡 Result:
No GitHub release for Caprica version 0.3.0a was found. The official Orvid/Caprica repository has a v0.3.0 release from October 2, 2023, with 3 assets, but no SHA256 checksums are provided in the release notes, and no 0.3.0a version exists in the releases list. GitHub does not automatically publish SHA256 checksums for release assets; users must compute them manually if needed. References to Caprica builds like commit 6378296518 or master build >= v0.3.0 appear in modding communities, but no specific SHA256 for a 0.3.0a binary was located in authoritative sources.
Citations:
- 1: https://github.com/Orvid/Caprica/releases
- 2: https://github.com/Orvid/Caprica
- 3: https://www.nexusmods.com/starfield/mods/3921
- 4: https://gist.github.com/fromanan/7a05da7b153d0b99dd8307f623cd0375
🌐 Web query:
KrisV-777 Caprica fork GitHub releases
💡 Result:
No GitHub repository or fork named "Caprica" by user KrisV-777 (https://github.com/KrisV-777) was found. The user has 32 public repositories, but none match "Caprica" or forks of known Caprica projects like Orvid/Caprica (Papyrus compiler with releases at https://github.com/Orvid/Caprica/releases). Other Caprica repos exist (e.g., kitschpatrol/Caprica, caprica/caprica), but no connection to KrisV-777. No releases for any KrisV-777 Caprica fork.
Citations:
- 1: https://github.com/KrisV-777
- 2: https://github.com/Orvid/Caprica/releases
- 3: https://github.com/ShikyoKira/Caprica
- 4: https://github.com/Orvid/Caprica
🏁 Script executed:
cat -n dev-scripts/compile.ps1 | sed -n '55,75p'Repository: DaymareOn/FSMP-MCM
Length of output: 970
🌐 Web query:
KrisV-777 Caprica release 0.3.0a zip download
💡 Result:
No official or verifiable download link for a "KrisV-777 Caprica release 0.3.0a zip" was found across multiple web searches, GitHub repositories, and LinkedIn profiles. The closest match is the Orvid/Caprica project (a Papyrus compiler for Bethesda games like Fallout 4/Skyrim/Starfield), which has a v0.3.0 release from October 2023 available at https://github.com/Orvid/Caprica/releases/tag/v0.3.0, including 3 assets (likely binaries/ZIPs). No mention of "KrisV-777", "0.3.0a", or an exact match. "KrisV-777" does not appear as a GitHub user, contributor, or related profile. It may refer to an unofficial fork, private build, or non-public project not indexed on the web. Recommend checking Nexus Mods (mentioned in related forums) or modding communities for Papyrus tools, but no direct evidence found.
Citations:
- 1: https://github.com/Orvid/Caprica/releases
- 2: https://github.com/Orvid/Caprica
- 3: https://www.gamesas.com/caprica-papyrus-compiler-t395747.html
- 4: https://github.com/IamKrisshK/IamKrisshK
- 5: https://github.com/ccris02
- 6: https://github.com/kris
- 7: https://github-redirect.dependabot.com/kris3713
- 8: https://github.com/krisb1220
- 9: https://github.com/Kr1s77
Clarify the Caprica release source and remove the auto-download if unverifiable.
The download URL references https://github.com/KrisV-777/Caprica/releases/download/0.3.0a/Caprica.zip, but this repository does not exist on GitHub. The official Caprica compiler is maintained at https://github.com/Orvid/Caprica (v0.3.0, not 0.3.0a) and does not publish SHA-256 checksums for its releases.
If this URL is intended to work, its source and security properties must be documented. If it is an outdated reference, either update it to point to a verifiable release with published checksums, or remove auto-download entirely and require manual installation with documented verification steps (e.g., check file signature, verify against known hash from trusted source, or link to authoritative binary locations used by the modding community).
🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)
[warning] 19-19: File 'compile.ps1' uses Write-Host. Avoid using Write-Host because it might not work in all hosts, does not work when there is no host, and (prior to PS 5.0) cannot be suppressed, captured, or redirected. Instead, use Write-Output, Write-Verbose, or Write-Information.
(PSAvoidUsingWriteHost)
[warning] 27-27: File 'compile.ps1' uses Write-Host. Avoid using Write-Host because it might not work in all hosts, does not work when there is no host, and (prior to PS 5.0) cannot be suppressed, captured, or redirected. Instead, use Write-Output, Write-Verbose, or Write-Information.
(PSAvoidUsingWriteHost)
[warning] 31-31: File 'compile.ps1' uses Write-Host. Avoid using Write-Host because it might not work in all hosts, does not work when there is no host, and (prior to PS 5.0) cannot be suppressed, captured, or redirected. Instead, use Write-Output, Write-Verbose, or Write-Information.
(PSAvoidUsingWriteHost)
[warning] 37-37: File 'compile.ps1' uses Write-Host. Avoid using Write-Host because it might not work in all hosts, does not work when there is no host, and (prior to PS 5.0) cannot be suppressed, captured, or redirected. Instead, use Write-Output, Write-Verbose, or Write-Information.
(PSAvoidUsingWriteHost)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@dev-scripts/compile.ps1` around lines 16 - 38, The script currently
auto-downloads Caprica from $CapricaUrl using Invoke-WebRequest and extracts it
to $DestDir without provenance checks; either remove this auto-download block or
replace it with a verified flow: update $CapricaUrl to an authoritative release
(e.g., the Orvid/Caprica v0.3.0 release), add SHA-256 (or signature)
verification of the downloaded $zipFile before Expand-Archive, and document
manual-install steps and verification in comments (or fail with a clear message
instructing the user to install Caprica.exe into $DestDir). Ensure references to
$Name, $zipFile, $outDir, Invoke-WebRequest, and Expand-Archive are updated to
reflect the new verified download or removed if you choose manual-only
installation.
| # Ensure output directory exists | ||
| if (-not (Test-Path $OutputDir)) { | ||
| New-Item -ItemType Directory -Path $OutputDir -Force | ||
| } | ||
|
|
||
| $SourceFiles = Get-ChildItem "Source/Scripts/*.psc" -Exclude "FSMPM_AutoBindings.psc" |
There was a problem hiding this comment.
Remove old .pex files before each build.
The script only creates Scripts/; it never cleans it. If a source script is renamed or deleted, the stale binary survives and the Dev deploy step still copies it, so local testing can run code that is no longer built from source.
Suggested fix
# Ensure output directory exists
if (-not (Test-Path $OutputDir)) {
- New-Item -ItemType Directory -Path $OutputDir -Force
+ New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
+} else {
+ Get-ChildItem -Path $OutputDir -Filter "*.pex" -File -ErrorAction SilentlyContinue | Remove-Item -Force
}Also applies to: 126-128
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@dev-scripts/compile.ps1` around lines 95 - 100, The output directory creation
step (using $OutputDir) doesn't remove stale .pex binaries, so before collecting
$SourceFiles or creating $OutputDir you should delete existing .pex files in the
target Scripts directory (e.g., remove "*.pex" under $OutputDir/Scripts or the
concrete Scripts folder) to ensure renamed/deleted source scripts don't leave
stale binaries; implement a cleanup that tests for and removes matching .pex
files (and create the Scripts dir afterwards if missing) so the subsequent
$SourceFiles = Get-ChildItem ... only reflects freshly built sources.
| float Function Wait(float afSeconds) native global | ||
| Function WaitMenuMode(float afSeconds) native global |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
SKSE Papyrus Utility Wait function return type
💡 Result:
The SKSE Papyrus Utility.Wait function has no return type (void). It is a procedure that pauses the current script for the specified real-time seconds without returning a value.
Citations:
- 1: https://papyrus.bellcube.dev/skyrimse/script/utility/function/wait/
- 2: https://ck.uesp.net/wiki/Wait_-_Utility
- 3: https://papyrus.bellcube.dev/skyrimse/script/papyrusutil/
Change Wait return type from float to void.
The SKSE Papyrus Utility.Wait function returns void, not float. Line 6 should be:
Function Wait(float afSeconds) native global
This matches the actual SKSE API and is consistent with WaitMenuMode on line 7.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Source/Scripts/Stubs/SKSE/Utility.psc` around lines 6 - 7, Update the
declaration for the SKSE Papyrus Utility.Wait function by removing the incorrect
float return type so it is declared as a void (i.e. match the pattern used by
WaitMenuMode); locate the `Function Wait(float afSeconds) native global`
declaration (symbol: Wait) in Source/Scripts/Stubs/SKSE/Utility.psc and change
it to the no-return form consistent with the SKSE API.
|
@coderabbitai -> update your review with the latest changes; Resolve all comments in Source/Scripts/SkyUI_SDK as that's a third party MIT licenses sdk that is only included to make CI reliable |
🧩 Analysis chain
🏁 Script executed: Length of output: 4725 🏁 Script executed: Length of output: 1600 🏁 Script executed: Length of output: 306
The threads to resolve are all on these files:
I already have this recorded in long-term memory so I won't raise issues for those files in future reviews. I'll now trigger a fresh review of the latest changes (excluding Please exclude all files under 🧠 Learnings used✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 6
♻️ Duplicate comments (6)
skyrimse.dev.ppj (1)
3-4: 🧹 Nitpick | 🔵 TrivialAdd guidance comment for the Flags path.
The
Flagsattribute at line 4 uses a hardcoded path without the "ADJUST THIS PATH" comment that other paths (lines 25-31) have. This inconsistency could cause confusion for developers setting up their local environment.📝 Suggested improvement
<PapyrusProject xmlns="PapyrusProject.xsd" - Flags="C:\Games\Skyrim Special Edition\Data\Source\Scripts\TESV_Papyrus_Flags.flg" + Flags="C:\Games\Skyrim Special Edition\Data\Source\Scripts\TESV_Papyrus_Flags.flg" <!-- ADJUST THIS PATH --> Game="sse"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skyrimse.dev.ppj` around lines 3 - 4, The Flags attribute on the PapyrusProject element is using a hardcoded absolute path without the same "ADJUST THIS PATH" guidance present for other path attributes; update the Flags attribute (the Flags="...TESV_Papyrus_Flags.flg" entry) to include the same developer guidance comment (e.g., add an "ADJUST THIS PATH" inline comment or surrounding XML comment) so it's consistent with the other paths and makes local setup expectations clear.README.md (1)
3-3:⚠️ Potential issue | 🟡 MinorUse the canonical repository in the badge URL.
The badge still tracks the fork, so the main README can show the wrong pipeline state after merge.
🪪 Proposed fix
- +🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` at line 3, The build badge in README.md currently points to the forked repo URL (the image line containing "https://github.com/KaninHop/FSMP-MCM/actions/workflows/build.yml/badge.svg"); update that URL to the canonical repository's owner/repo in the badge markdown so the README shows the upstream pipeline status (replace "KaninHop/FSMP-MCM" with the canonical owner/repository name in the badge image and link).dev-scripts/setup_ci.ps1 (1)
33-34:⚠️ Potential issue | 🟠 MajorValidate the downloaded Caprica artifact before copying it.
This still trusts the ZIP contents and pipes a possibly empty
Get-ChildItemresult straight intoCopy-Item. Please pin the expected checksum and fail explicitly whenCaprica.exeis missing instead of surfacing a generic pipeline error.🔒 Proposed hardening
$capricaPath = Download-And-Extract "https://github.com/KrisV-777/Caprica/releases/download/0.3.0a/Caprica.zip" "Caprica" -Get-ChildItem -Path $capricaPath -Filter "Caprica.exe" -Recurse | Select-Object -First 1 | Copy-Item -Destination (Join-Path $toolDir "Caprica.exe") +$expectedCapricaSha256 = "<pin Caprica.zip sha256>" +$actualCapricaSha256 = (Get-FileHash -Path (Join-Path $env:TEMP "Caprica.zip") -Algorithm SHA256).Hash +if ($actualCapricaSha256 -ne $expectedCapricaSha256) { + throw "Caprica.zip checksum mismatch." +} + +$capricaExe = Get-ChildItem -Path $capricaPath -Filter "Caprica.exe" -Recurse | Select-Object -First 1 +if (-not $capricaExe) { + throw "Caprica.exe not found after extraction." +} + +Copy-Item -LiteralPath $capricaExe.FullName -Destination (Join-Path $toolDir "Caprica.exe") -Force🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dev-scripts/setup_ci.ps1` around lines 33 - 34, The script currently pipes the possibly-empty Get-ChildItem result into Copy-Item after Download-And-Extract; instead, verify the downloaded artifact and the extracted Caprica.exe explicitly: after calling Download-And-Extract (keep the call to Download-And-Extract), compute and compare the expected checksum (pin the expected SHA256) of the downloaded ZIP or the extracted Caprica.exe, then use Get-ChildItem to find Caprica.exe (from the same logic) and check that the file exists before calling Copy-Item; if the checksum mismatches or Caprica.exe is not found, throw/Write-Error with a clear message and exit non-zero rather than allowing a generic pipeline error. Ensure references to Download-And-Extract, Get-ChildItem, Copy-Item, Caprica.exe and $toolDir are used so you update the correct variables and checks.dev-scripts/compile.ps1 (2)
129-134:⚠️ Potential issue | 🟠 MajorClean stale
.pexoutputs before compiling.Line 129–134 still only ensures the output directory exists. If scripts are removed/renamed, stale binaries can leak into dev deploys.
Suggested fix
# Ensure output directory exists if (-not (Test-Path $OutputDir)) { - New-Item -ItemType Directory -Path $OutputDir -Force + New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null +} else { + Get-ChildItem -Path $OutputDir -Filter "*.pex" -File -ErrorAction SilentlyContinue | Remove-Item -Force }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dev-scripts/compile.ps1` around lines 129 - 134, The script currently only ensures $OutputDir exists but doesn't remove stale .pex files; modify the compile flow to delete any existing .pex files in $OutputDir before compiling (e.g., remove files matching *.pex), then proceed to create the directory and collect source files via Get-ChildItem "Source/Scripts/*.psc" (excluding FSMPM_AutoBindings.psc); ensure the removal step runs safely (only target $OutputDir and optionally check it exists) so renamed/removed scripts cannot leave stale binaries.
16-31:⚠️ Potential issue | 🟠 MajorCaprica auto-download source remains questionable and brittle.
Line 16 still depends on the previously flagged
KrisV-777/Capricarelease URL. If unavailable or unofficial, bootstrap fails or weakens supply-chain trust.Use this read-only check to validate endpoint/repo availability and compare with upstream release metadata:
#!/bin/bash set -euo pipefail echo "== Check configured download URL ==" curl -sSI "https://github.com/KrisV-777/Caprica/releases/download/0.3.0a/Caprica.zip" | head -n 5 echo echo "== Check configured repository metadata ==" curl -sS "https://api.github.com/repos/KrisV-777/Caprica" | jq -r '.full_name // .message' echo echo "== Check upstream Caprica latest release ==" curl -sS "https://api.github.com/repos/Orvid/Caprica/releases/latest" | jq -r '.tag_name // .message'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dev-scripts/compile.ps1` around lines 16 - 31, The script currently hardcodes $CapricaUrl and $ExpectedHash which is brittle and points to an unofficial repo; change the logic in the bootstrap block (the variables $CapricaUrl, $ExpectedHash and the download via Invoke-WebRequest/$zipFile) to dynamically validate and/or fetch the upstream release from the official Orvid/Caprica GitHub release API: use Invoke-RestMethod to query "repos/Orvid/Caprica/releases/latest", derive the asset download URL and tag, compare the tag against your configured version, fetch the release asset to $zipFile, then compute and verify its checksum instead of trusting the hardcoded $ExpectedHash; also add a clear fallback or error path if the upstream API or asset URL is missing so the install fails safe rather than silently using an unofficial source.Source/Scripts/Stubs/JContainers/JMap.psc (1)
5-5:⚠️ Potential issue | 🟠 Major
getStrdefault parameter type still looks too restrictive.Line 5 keeps
String default=""; if current callsites still pass numeric defaults, this stub signature can break CI compilation. This appears to be the same unresolved concern raised earlier.Run this to confirm callsite argument types against the current stub definition:
#!/bin/bash set -euo pipefail echo "== JMap.getStr stub definition ==" cat -n Source/Scripts/Stubs/JContainers/JMap.psc | sed -n '1,20p' echo echo "== JMap.getStr callsites with context ==" rg -n --type-add 'psc:*.psc' --type psc -C2 '\bJMap\.getStr\s*\('If non-string third arguments are present, update the stub to accept a flexible type (for example
Var) to match real usage.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Source/Scripts/Stubs/JContainers/JMap.psc` at line 5, The stub for JMap.getStr currently declares the third parameter as String default="" which is too restrictive for callsites that pass numbers; update the signature in JMap.psc for the function getStr(Int object, String key, String default="") to accept a flexible type (e.g., replace the third parameter type with Var and adjust the default accordingly) so the stub matches real usage and CI compilation; locate the declaration of getStr in Source/Scripts/Stubs/JContainers/JMap.psc and change the parameter type to Var (and ensure any related native declaration remains consistent).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.agents/workflows/build.md:
- Around line 11-12: Update the Caprica download reference in the "Caprica
Compiler: `Caprica/Caprica.exe`" line to point to the KrisV-777 fork used by CI
(KrisV-777/Caprica, v0.3.0a) instead of Orvid/Caprica so builders fetch the same
compiler version as README.md and dev-scripts/setup_ci.ps1; replace the current
Orvid/Caprica/releases URL with the KrisV-777/Caprica release URL and mention
version 0.3.0a for clarity.
In `@dev-scripts/setup_ci.ps1`:
- Around line 8-10: The script currently sets $rootDir using Get-Location which
depends on the caller's CWD; change root resolution to derive the repository
root from the script location instead (e.g. use $PSScriptRoot or Split-Path on
$MyInvocation.MyCommand.Definition) and then recompute $toolDir from that root
($toolDir = Join-Path $rootDir "ci_tools") so Caprica.exe lookups no longer
depend on where the script was invoked; update the assignment to $rootDir and
ensure $toolDir uses that new value.
In `@Source/Scripts/Stubs/BaseGame/Alias.psc`:
- Around line 24-49: Alias.psc is missing the Event OnPlayerLoadGame stub
declared elsewhere (e.g. SKI_PlayerLoadGameAlias.psc), so add a matching empty
event declaration Event OnPlayerLoadGame() EndEvent to the base alias stub
chain; locate the Event blocks in Alias.psc (and mirror the same addition in
ReferenceAlias.psc if present) so the base alias classes expose the
OnPlayerLoadGame event for CI and consistent handling.
- Around line 4-23: The Alias stub is missing SKSE mod-event methods which
prevents scripts from compiling; add the SKSE Alias members RegisterForModEvent
and SendModEvent to match the Form.psc SKSE surface. Specifically, declare a
RegisterForModEvent method (e.g., RegisterForModEvent(string asEventName, string
asSender) native) and the SendModEvent method(s) used by SKSE (e.g.,
SendModEvent(string asEventName, string asArg, string asSender) native, and an
overload with fewer args if Form.psc provides one) so alias-based scripts can
register and dispatch mod events.
In `@Source/Scripts/Stubs/BaseGame/Form.psc`:
- Around line 5-31: The Form.psc stub is missing SKSE menu APIs required by
SkyUI scripts; add native declarations for RegisterForMenu(string menuName,
string callbackName) and UnregisterForMenu(string menuName) as well as the menu
callbacks OnMenuOpen(string menuName) native and OnMenuClose(string menuName)
native to the Form class so calls from SKI_Main.psc, SKI_ConfigManager.psc,
SKI_WidgetManager.psc, SKI_SettingsManager.psc and SKI_FavoritesManager.psc
resolve; ensure the signatures exactly match those names so subclasses like
Quest.psc inherit them.
In `@Source/Scripts/Stubs/BaseGame/GlobalVariable.psc`:
- Around line 4-6: The stub for GlobalVariable.Mod is missing its float return
type; update the declaration for Mod (the GlobalVariable.Mod function) to return
float (i.e., change the signature from a void/unnamed return to a float return)
so it matches the Papyrus API and CI contract—ensure the signature reads as a
float-returning function and keep the parameter name afHowMuch intact and the
native specifier.
---
Duplicate comments:
In `@dev-scripts/compile.ps1`:
- Around line 129-134: The script currently only ensures $OutputDir exists but
doesn't remove stale .pex files; modify the compile flow to delete any existing
.pex files in $OutputDir before compiling (e.g., remove files matching *.pex),
then proceed to create the directory and collect source files via Get-ChildItem
"Source/Scripts/*.psc" (excluding FSMPM_AutoBindings.psc); ensure the removal
step runs safely (only target $OutputDir and optionally check it exists) so
renamed/removed scripts cannot leave stale binaries.
- Around line 16-31: The script currently hardcodes $CapricaUrl and
$ExpectedHash which is brittle and points to an unofficial repo; change the
logic in the bootstrap block (the variables $CapricaUrl, $ExpectedHash and the
download via Invoke-WebRequest/$zipFile) to dynamically validate and/or fetch
the upstream release from the official Orvid/Caprica GitHub release API: use
Invoke-RestMethod to query "repos/Orvid/Caprica/releases/latest", derive the
asset download URL and tag, compare the tag against your configured version,
fetch the release asset to $zipFile, then compute and verify its checksum
instead of trusting the hardcoded $ExpectedHash; also add a clear fallback or
error path if the upstream API or asset URL is missing so the install fails safe
rather than silently using an unofficial source.
In `@dev-scripts/setup_ci.ps1`:
- Around line 33-34: The script currently pipes the possibly-empty Get-ChildItem
result into Copy-Item after Download-And-Extract; instead, verify the downloaded
artifact and the extracted Caprica.exe explicitly: after calling
Download-And-Extract (keep the call to Download-And-Extract), compute and
compare the expected checksum (pin the expected SHA256) of the downloaded ZIP or
the extracted Caprica.exe, then use Get-ChildItem to find Caprica.exe (from the
same logic) and check that the file exists before calling Copy-Item; if the
checksum mismatches or Caprica.exe is not found, throw/Write-Error with a clear
message and exit non-zero rather than allowing a generic pipeline error. Ensure
references to Download-And-Extract, Get-ChildItem, Copy-Item, Caprica.exe and
$toolDir are used so you update the correct variables and checks.
In `@README.md`:
- Line 3: The build badge in README.md currently points to the forked repo URL
(the image line containing
"https://github.com/KaninHop/FSMP-MCM/actions/workflows/build.yml/badge.svg");
update that URL to the canonical repository's owner/repo in the badge markdown
so the README shows the upstream pipeline status (replace "KaninHop/FSMP-MCM"
with the canonical owner/repository name in the badge image and link).
In `@skyrimse.dev.ppj`:
- Around line 3-4: The Flags attribute on the PapyrusProject element is using a
hardcoded absolute path without the same "ADJUST THIS PATH" guidance present for
other path attributes; update the Flags attribute (the
Flags="...TESV_Papyrus_Flags.flg" entry) to include the same developer guidance
comment (e.g., add an "ADJUST THIS PATH" inline comment or surrounding XML
comment) so it's consistent with the other paths and makes local setup
expectations clear.
In `@Source/Scripts/Stubs/JContainers/JMap.psc`:
- Line 5: The stub for JMap.getStr currently declares the third parameter as
String default="" which is too restrictive for callsites that pass numbers;
update the signature in JMap.psc for the function getStr(Int object, String key,
String default="") to accept a flexible type (e.g., replace the third parameter
type with Var and adjust the default accordingly) so the stub matches real usage
and CI compilation; locate the declaration of getStr in
Source/Scripts/Stubs/JContainers/JMap.psc and change the parameter type to Var
(and ensure any related native declaration remains consistent).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 7bd3016b-a26d-454f-a312-fbd012aaf550
📒 Files selected for processing (45)
.agents/workflows/build.md.github/workflows/build.yml.gitignore.vscode/tasks.jsonREADME.mdScripts/FSMPM.pexScripts/FSMPMPlayerScript.pexSource/Scripts/FSMPM.pscSource/Scripts/SkyUI_SDK/SKI_ActiveEffectsWidget.pscSource/Scripts/SkyUI_SDK/SKI_ConfigBase.pscSource/Scripts/SkyUI_SDK/SKI_ConfigManager.pscSource/Scripts/SkyUI_SDK/SKI_ConfigMenu.pscSource/Scripts/SkyUI_SDK/SKI_FavoritesManager.pscSource/Scripts/SkyUI_SDK/SKI_Main.pscSource/Scripts/SkyUI_SDK/SKI_PlayerLoadGameAlias.pscSource/Scripts/SkyUI_SDK/SKI_QF_ConfigManagerInstance.pscSource/Scripts/SkyUI_SDK/SKI_QuestBase.pscSource/Scripts/SkyUI_SDK/SKI_SettingsManager.pscSource/Scripts/SkyUI_SDK/SKI_WidgetBase.pscSource/Scripts/SkyUI_SDK/SKI_WidgetManager.pscSource/Scripts/Stubs/BaseGame/Actor.pscSource/Scripts/Stubs/BaseGame/Alias.pscSource/Scripts/Stubs/BaseGame/Debug.pscSource/Scripts/Stubs/BaseGame/Faction.pscSource/Scripts/Stubs/BaseGame/Form.pscSource/Scripts/Stubs/BaseGame/GlobalVariable.pscSource/Scripts/Stubs/BaseGame/Keyword.pscSource/Scripts/Stubs/BaseGame/ObjectReference.pscSource/Scripts/Stubs/BaseGame/Quest.pscSource/Scripts/Stubs/BaseGame/ReferenceAlias.pscSource/Scripts/Stubs/BaseGame/TESV_Papyrus_Flags.flgSource/Scripts/Stubs/ConsoleUtil/ConsoleUtil.pscSource/Scripts/Stubs/JContainers/JMap.pscSource/Scripts/Stubs/JContainers/JValue.pscSource/Scripts/Stubs/PapyrusUtil/JsonUtil.pscSource/Scripts/Stubs/PapyrusUtil/MiscUtil.pscSource/Scripts/Stubs/PapyrusUtil/PapyrusUtil.pscSource/Scripts/Stubs/SKSE/StringUtil.pscSource/Scripts/Stubs/SKSE/UI.pscSource/Scripts/Stubs/SKSE/Utility.pscdev-scripts/compile.ps1dev-scripts/setup_ci.ps1skyrimse.dev.ppjskyrimse.ppjskyrimse_ci.ppj
| - **Caprica Compiler**: `Caprica/Caprica.exe` must be present. | ||
| - If missing, download it from [Orvid/Caprica Releases](https://github.com/Orvid/Caprica/releases). |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if files exist and get their line counts
for file in ".agents/workflows/build.md" "README.md" "dev-scripts/setup_ci.ps1"; do
if [ -f "$file" ]; then
echo "=== $file exists ==="
wc -l "$file"
else
echo "=== $file NOT FOUND ==="
fi
doneRepository: DaymareOn/FSMP-MCM
Length of output: 239
🏁 Script executed:
#!/bin/bash
# Read the specific lines from each file
echo "=== .agents/workflows/build.md lines 10-15 ==="
sed -n '10,15p' ".agents/workflows/build.md" 2>/dev/null || echo "File not found or error"
echo ""
echo "=== README.md lines 28-32 ==="
sed -n '28,32p' "README.md" 2>/dev/null || echo "File not found or error"
echo ""
echo "=== dev-scripts/setup_ci.ps1 lines 31-35 ==="
sed -n '31,35p' "dev-scripts/setup_ci.ps1" 2>/dev/null || echo "File not found or error"Repository: DaymareOn/FSMP-MCM
Length of output: 1395
Standardize the documented Caprica source.
This file references Orvid/Caprica/releases, but README.md (lines 28-32) and dev-scripts/setup_ci.ps1 (line 33) both reference the KrisV-777/Caprica fork (specifically version 0.3.0a). Update .agents/workflows/build.md to point to the same KrisV-777 source so builders download the compiler version that CI actually uses.
🧰 Tools
🪛 markdownlint-cli2 (0.22.0)
[warning] 11-11: Trailing spaces
Expected: 0 or 2; Actual: 1
(MD009, no-trailing-spaces)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/workflows/build.md around lines 11 - 12, Update the Caprica download
reference in the "Caprica Compiler: `Caprica/Caprica.exe`" line to point to the
KrisV-777 fork used by CI (KrisV-777/Caprica, v0.3.0a) instead of Orvid/Caprica
so builders fetch the same compiler version as README.md and
dev-scripts/setup_ci.ps1; replace the current Orvid/Caprica/releases URL with
the KrisV-777/Caprica release URL and mention version 0.3.0a for clarity.
| $rootDir = Get-Location | ||
| $toolDir = Join-Path $rootDir "ci_tools" | ||
|
|
There was a problem hiding this comment.
Resolve the repo root from the script path.
Get-Location makes ci_tools/ depend on the caller's current directory. If this script is launched from anywhere except the repository root, later steps will look for Caprica.exe in the wrong place.
🧭 Proposed fix
-$rootDir = Get-Location
+$rootDir = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
$toolDir = Join-Path $rootDir "ci_tools"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| $rootDir = Get-Location | |
| $toolDir = Join-Path $rootDir "ci_tools" | |
| $rootDir = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path | |
| $toolDir = Join-Path $rootDir "ci_tools" |
🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)
[warning] Missing BOM encoding for non-ASCII encoded file 'setup_ci.ps1'
(PSUseBOMForUnicodeEncodedFile)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@dev-scripts/setup_ci.ps1` around lines 8 - 10, The script currently sets
$rootDir using Get-Location which depends on the caller's CWD; change root
resolution to derive the repository root from the script location instead (e.g.
use $PSScriptRoot or Split-Path on $MyInvocation.MyCommand.Definition) and then
recompute $toolDir from that root ($toolDir = Join-Path $rootDir "ci_tools") so
Caprica.exe lookups no longer depend on where the script was invoked; update the
assignment to $rootDir and ensure $toolDir uses that new value.
| Quest Function GetOwningQuest() native | ||
| bool Function RegisterForAnimationEvent(ObjectReference akSender, string asEventName) native | ||
| Function RegisterForLOS(Actor akViewer, ObjectReference akTarget) native | ||
| Function RegisterForSingleLOSGain(Actor akViewer, ObjectReference akTarget) native | ||
| Function RegisterForSingleLOSLost(Actor akViewer, ObjectReference akTarget) native | ||
| Function RegisterForSingleUpdate(float afInterval) native | ||
| Function RegisterForUpdate(float afInterval) native | ||
| Function RegisterForUpdateGameTime(float afInterval) native | ||
| Function RegisterForSingleUpdateGameTime(float afInterval) native | ||
| Function RegisterForSleep() native | ||
| Function RegisterForTrackedStatsEvent() native | ||
| Function StartObjectProfiling() native | ||
| Function StopObjectProfiling() native | ||
| Function UnregisterForLOS(Actor akViewer, ObjectReference akTarget) native | ||
| Function UnregisterForAnimationEvent(ObjectReference akSender, string asEventName) native | ||
| Function UnregisterForSleep() native | ||
| Function UnregisterForTrackedStatsEvent() native | ||
| Function UnregisterForUpdate() native | ||
| Function UnregisterForUpdateGameTime() native | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate and read the Alias.psc file
find . -name "Alias.psc" -type fRepository: DaymareOn/FSMP-MCM
Length of output: 103
🏁 Script executed:
# Search for RegisterForModEvent and SendModEvent in the repository
rg "RegisterForModEvent|SendModEvent" --type pscRepository: DaymareOn/FSMP-MCM
Length of output: 89
🏁 Script executed:
# Check if ReferenceAlias.psc exists and compare
find . -name "ReferenceAlias.psc" -type fRepository: DaymareOn/FSMP-MCM
Length of output: 112
🏁 Script executed:
# Look at the full Alias.psc file to understand current state
cat -n Source/Scripts/Stubs/BaseGame/Alias.pscRepository: DaymareOn/FSMP-MCM
Length of output: 2129
🏁 Script executed:
# Check ReferenceAlias.psc to see if it has RegisterForModEvent/SendModEvent
cat -n Source/Scripts/Stubs/BaseGame/ReferenceAlias.psc | head -50Repository: DaymareOn/FSMP-MCM
Length of output: 1162
🏁 Script executed:
# Search for any usage of RegisterForModEvent or SendModEvent in the actual scripts
rg "RegisterForModEvent\|SendModEvent" --type txt -iRepository: DaymareOn/FSMP-MCM
Length of output: 44
🏁 Script executed:
# Check what SKSE form methods might be in other stubs for comparison
ls -la Source/Scripts/Stubs/BaseGame/Repository: DaymareOn/FSMP-MCM
Length of output: 866
🏁 Script executed:
# Check if there are any actual scripts that use RegisterForModEvent with Alias types
rg "as Alias\|extends Alias" Source/Scripts --type txt -A 5 | head -100Repository: DaymareOn/FSMP-MCM
Length of output: 44
🏁 Script executed:
# Look for any imports or uses of RegisterForModEvent to understand context
find Source/Scripts -name "*.psc" -type f | head -20Repository: DaymareOn/FSMP-MCM
Length of output: 943
🌐 Web query:
RegisterForModEvent SKSE Alias Papyrus API documentation
💡 Result:
RegisterForModEvent is an SKSE function available on Alias scripts (and Form, ActiveMagicEffect) in Papyrus for Skyrim Special Edition. It registers a custom event callback for a given mod event name. Syntax: Function RegisterForModEvent(string eventName, string callbackName) native Parameters: - eventName: The name of the event sent by SendModEvent. - callbackName: The name of the callback event handler (e.g., "OnMyModEvent"). Callback signature: Event callbackName(string eventName, string strArg, float numArg, Form sender) EndEvent Example in an Alias script: RegisterForModEvent("HectorHitMe", "OnHectorHitMe") Event OnHectorHitMe(string eventName, string strArg, float numArg, Form sender) ; Handle the event EndEvent Notes: - Registrations must be refreshed after each game load as they are stored in the SKSE co-save (MCBR record). - Aliases automatically unregister when the quest stops. - Prefix event names for uniqueness (e.g., "MyMod_MyEvent").
Citations:
- 1: https://papyrus.bellcube.dev/skyrimse/script/form/function/registerformodevent/
- 2: https://papyrus.bellcube.dev/skyrimse/script/alias/function/registerformodevent/
- 3: https://ck.uesp.net/wiki/RegisterForModEvent_-_Form
🏁 Script executed:
# Check if SKI_PlayerLoadGameAlias.psc uses RegisterForModEvent
cat -n Source/Scripts/SkyUI_SDK/SKI_PlayerLoadGameAlias.pscRepository: DaymareOn/FSMP-MCM
Length of output: 356
🏁 Script executed:
# Search for RegisterForModEvent usage in actual scripts
grep -r "RegisterForModEvent" Source/Scripts --include="*.psc" 2>/dev/nullRepository: DaymareOn/FSMP-MCM
Length of output: 3051
🏁 Script executed:
# Check Form.psc stub to see if RegisterForModEvent is there (comparison)
cat -n Source/Scripts/Stubs/BaseGame/Form.psc | grep -A 2 -B 2 "RegisterForModEvent"Repository: DaymareOn/FSMP-MCM
Length of output: 332
Add missing SKSE mod-event members to the Alias stub.
RegisterForModEvent(...) and SendModEvent(...) are part of the SKSE Alias surface (confirmed in Form.psc stub and SKSE documentation), so alias-based scripts cannot compile against this stub if they rely on mod events.
🔧 Minimal parity fix
Scriptname Alias Hidden
Quest Function GetOwningQuest() native
+Function RegisterForModEvent(string eventName, string callbackName) native
+Function UnregisterForModEvent(string eventName) native
+Function SendModEvent(string eventName, string strArg = "", float numArg = 0.0) native
bool Function RegisterForAnimationEvent(ObjectReference akSender, string asEventName) native
Function RegisterForLOS(Actor akViewer, ObjectReference akTarget) native🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Source/Scripts/Stubs/BaseGame/Alias.psc` around lines 4 - 23, The Alias stub
is missing SKSE mod-event methods which prevents scripts from compiling; add the
SKSE Alias members RegisterForModEvent and SendModEvent to match the Form.psc
SKSE surface. Specifically, declare a RegisterForModEvent method (e.g.,
RegisterForModEvent(string asEventName, string asSender) native) and the
SendModEvent method(s) used by SKSE (e.g., SendModEvent(string asEventName,
string asArg, string asSender) native, and an overload with fewer args if
Form.psc provides one) so alias-based scripts can register and dispatch mod
events.
| Event OnAnimationEvent(ObjectReference akSource, string asEventName) | ||
| EndEvent | ||
|
|
||
| Event OnAnimationEventUnregistered(ObjectReference akSource, string asEventName) | ||
| EndEvent | ||
|
|
||
| Event OnGainLOS(Actor akViewer, ObjectReference akTarget) | ||
| EndEvent | ||
|
|
||
| Event OnLostLOS(Actor akViewer, ObjectReference akTarget) | ||
| EndEvent | ||
|
|
||
| Event OnSleepStart(float afSleepStartTime, float afDesiredSleepEndTime) | ||
| EndEvent | ||
|
|
||
| Event OnSleepStop(bool abInterrupted) | ||
| EndEvent | ||
|
|
||
| Event OnTrackedStatsEvent(string arStatName, int aiStatValue) | ||
| EndEvent | ||
|
|
||
| Event OnUpdate() | ||
| EndEvent | ||
|
|
||
| Event OnUpdateGameTime() | ||
| EndEvent |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Alias/ReferenceAlias stubs:"
fd -a 'Alias\.psc|ReferenceAlias\.psc' Source/Scripts
echo
echo "Any stub declaration of OnPlayerLoadGame:"
rg -nP --iglob '*.psc' '^\s*Event\s+OnPlayerLoadGame\s*\(' Source/Scripts/Stubs -C1
echo
echo "Repo scripts that implement OnPlayerLoadGame:"
rg -nP --iglob '*.psc' '^\s*Event\s+OnPlayerLoadGame\s*\(' Source/Scripts -C2Repository: DaymareOn/FSMP-MCM
Length of output: 331
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== SKI_PlayerLoadGameAlias.psc content ==="
head -50 'Source/Scripts/SkyUI_SDK/SKI_PlayerLoadGameAlias.psc'
echo
echo "=== Alias.psc first 50 lines ==="
head -50 'Source/Scripts/Stubs/BaseGame/Alias.psc'
echo
echo "=== ReferenceAlias.psc first 50 lines ==="
head -50 'Source/Scripts/Stubs/BaseGame/ReferenceAlias.psc'
echo
echo "=== Check all Event declarations in Alias.psc ==="
rg -n 'Event\s+' 'Source/Scripts/Stubs/BaseGame/Alias.psc'Repository: DaymareOn/FSMP-MCM
Length of output: 3518
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== All Event declarations in ReferenceAlias.psc ==="
rg -n 'Event\s+' 'Source/Scripts/Stubs/BaseGame/ReferenceAlias.psc'
echo
echo "=== Full ReferenceAlias.psc ==="
wc -l 'Source/Scripts/Stubs/BaseGame/ReferenceAlias.psc'
echo
echo "=== Check if OnPlayerLoadGame exists anywhere in Stubs ==="
rg -n 'OnPlayerLoadGame' 'Source/Scripts/Stubs/'Repository: DaymareOn/FSMP-MCM
Length of output: 431
Add OnPlayerLoadGame event stub to the alias stub chain.
SKI_PlayerLoadGameAlias.psc declares OnPlayerLoadGame, but neither Alias.psc nor ReferenceAlias.psc includes it. CreationKit explicitly documents this event for player-alias handling. For a complete CI surface, OnPlayerLoadGame should be declared in the base stub.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Source/Scripts/Stubs/BaseGame/Alias.psc` around lines 24 - 49, Alias.psc is
missing the Event OnPlayerLoadGame stub declared elsewhere (e.g.
SKI_PlayerLoadGameAlias.psc), so add a matching empty event declaration Event
OnPlayerLoadGame() EndEvent to the base alias stub chain; locate the Event
blocks in Alias.psc (and mirror the same addition in ReferenceAlias.psc if
present) so the base alias classes expose the OnPlayerLoadGame event for CI and
consistent handling.
| Int Function GetFormID() native | ||
| int Function GetGoldValue() native | ||
| bool Function HasKeyword(Keyword akKeyword) native | ||
| bool Function PlayerKnows() native | ||
| bool Function RegisterForAnimationEvent(ObjectReference akSender, string asEventName) native | ||
| Function RegisterForLOS(Actor akViewer, ObjectReference akTarget) native | ||
| Function RegisterForSingleLOSGain(Actor akViewer, ObjectReference akTarget) native | ||
| Function RegisterForSingleLOSLost(Actor akViewer, ObjectReference akTarget) native | ||
| Function RegisterForSingleUpdate(float afInterval) native | ||
| Function RegisterForSleep() native | ||
| Function RegisterForTrackedStatsEvent() native | ||
| Function RegisterForUpdate(float afInterval) native | ||
| Function RegisterForUpdateGameTime(float afInterval) native | ||
| Function RegisterForSingleUpdateGameTime(float afInterval) native | ||
| Function StartObjectProfiling() native | ||
| Function StopObjectProfiling() native | ||
| Function UnregisterForAnimationEvent(ObjectReference akSender, string asEventName) native | ||
| Function UnregisterForLOS(Actor akViewer, ObjectReference akTarget) native | ||
| Function UnregisterForSleep() native | ||
| Function UnregisterForTrackedStatsEvent() native | ||
| Function UnregisterForUpdate() native | ||
| Function UnregisterForUpdateGameTime() native | ||
|
|
||
| ; SKSE additions | ||
| Function RegisterForModEvent(string eventName, string callbackName) native | ||
| Function UnregisterForModEvent(string eventName) native | ||
| Function SendModEvent(string eventName, string strArg = "", float numArg = 0.0) native |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Quest stub(s):"
fd -a 'Quest\.psc' Source/Scripts
echo
echo "Menu APIs declared anywhere under Source/Scripts/Stubs:"
rg -nP --iglob '*.psc' '^\s*(Function|Event)\s+(RegisterForMenu|UnregisterForMenu|OnMenuOpen|OnMenuClose)\b' Source/Scripts/Stubs -C1
echo
echo "Project call sites that require those APIs:"
rg -nP --iglob '*.psc' '\b(RegisterForMenu|UnregisterForMenu)\s*\(|\bOnMenu(Open|Close)\s*\(' Source/Scripts -C1Repository: DaymareOn/FSMP-MCM
Length of output: 192
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Quest.psc contents ==="
cat Source/Scripts/Stubs/BaseGame/Quest.psc
echo ""
echo "=== Checking for menu API declarations in Quest.psc ==="
grep -n -i 'RegisterForMenu\|UnregisterForMenu\|OnMenuOpen\|OnMenuClose' Source/Scripts/Stubs/BaseGame/Quest.psc || echo "[No matches found]"
echo ""
echo "=== Checking all Stubs files for menu APIs ==="
rg 'RegisterForMenu|UnregisterForMenu|OnMenuOpen|OnMenuClose' Source/Scripts/Stubs/ --iglob '*.psc' || echo "[No matches found]"
echo ""
echo "=== Checking SkyUI scripts for menu API usage ==="
rg 'RegisterForMenu|UnregisterForMenu|OnMenuOpen|OnMenuClose' Source/Scripts/SkyUI_SDK/ --iglob '*.psc' -l || echo "[No matches found]"Repository: DaymareOn/FSMP-MCM
Length of output: 2030
Add missing SKSE menu APIs to Form stub.
RegisterForMenu / UnregisterForMenu and OnMenuOpen / OnMenuClose are part of the Papyrus Form API (SKSE). The embedded SkyUI SDK scripts (SKI_Main.psc, SKI_ConfigManager.psc, SKI_ConfigBase.psc, SKI_WidgetManager.psc, SKI_SettingsManager.psc, SKI_FavoritesManager.psc) invoke these functions, but neither Form.psc nor its subclass Quest.psc declare them. CI builds will fail when these scripts attempt to call undefined functions. Add these declarations to Form.psc to complete the SKSE API surface.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Source/Scripts/Stubs/BaseGame/Form.psc` around lines 5 - 31, The Form.psc
stub is missing SKSE menu APIs required by SkyUI scripts; add native
declarations for RegisterForMenu(string menuName, string callbackName) and
UnregisterForMenu(string menuName) as well as the menu callbacks
OnMenuOpen(string menuName) native and OnMenuClose(string menuName) native to
the Form class so calls from SKI_Main.psc, SKI_ConfigManager.psc,
SKI_WidgetManager.psc, SKI_SettingsManager.psc and SKI_FavoritesManager.psc
resolve; ensure the signatures exactly match those names so subclasses like
Quest.psc inherit them.
| Function SetValue(float afNewValue) native | ||
| float Function GetValue() native | ||
| Function Mod(float afHowMuch) native |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check if the file exists and view its contents
find . -name "GlobalVariable.psc" -type fRepository: DaymareOn/FSMP-MCM
Length of output: 112
🏁 Script executed:
# If found, read the file to confirm current state
if [ -f "Source/Scripts/Stubs/BaseGame/GlobalVariable.psc" ]; then
cat -n "Source/Scripts/Stubs/BaseGame/GlobalVariable.psc"
fiRepository: DaymareOn/FSMP-MCM
Length of output: 312
🏁 Script executed:
# Search for references to GlobalVariable.Mod in the codebase
rg "GlobalVariable.*Mod" --type papyrus -A 2 -B 2Repository: DaymareOn/FSMP-MCM
Length of output: 93
🌐 Web query:
Papyrus GlobalVariable Mod function return type UESP
💡 Result:
The Papyrus GlobalVariable.Mod function has a return type of float. It modifies the value of the global variable in a thread-safe manner and returns the new value as a float.
Citations:
- 1: https://papyrus.bellcube.dev/skyrimse/script/globalvariable/function/mod/
- 2: https://papyrus.bellcube.dev/skyrimse/script/globalvariable/
Return float from GlobalVariable.Mod.
The Papyrus GlobalVariable.Mod API returns the updated value as a float. Declaring it without a return type changes the CI stub contract and will break any code that reads the result.
🔧 Proposed fix
Function SetValue(float afNewValue) native
float Function GetValue() native
-Function Mod(float afHowMuch) native
+float Function Mod(float afHowMuch) native📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Function SetValue(float afNewValue) native | |
| float Function GetValue() native | |
| Function Mod(float afHowMuch) native | |
| Function SetValue(float afNewValue) native | |
| float Function GetValue() native | |
| float Function Mod(float afHowMuch) native |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Source/Scripts/Stubs/BaseGame/GlobalVariable.psc` around lines 4 - 6, The
stub for GlobalVariable.Mod is missing its float return type; update the
declaration for Mod (the GlobalVariable.Mod function) to return float (i.e.,
change the signature from a void/unnamed return to a float return) so it matches
the Papyrus API and CI contract—ensure the signature reads as a float-returning
function and keep the parameter name afHowMuch intact and the native specifier.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation