chore: release v0.1.2 - #9
Merged
Merged
Conversation
bump control version to 0.1.2. v0.1.2 adds the in-process settings panel, %%TIME CSA extension, and remaining time reporting fixes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Release housekeeping change to bump the package metadata version to v0.1.2 for KiouEngineBridge’s iOS tweak distribution.
Changes:
- Update Debian
controlmetadataVersionfrom0.1.1to0.1.2.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
7 tasks
tkgstrator
added a commit
that referenced
this pull request
Jun 22, 2026
- recipes/kiouenginebridge.py: the GetValidMatchFoundStatus row's comment said the hook returns NULL to reject the match, but the actual entry hook forwards orig's MatchFoundStatus unchanged and delivers the reject signal by firing ConnectionFailed at the stream. Rewrite the comment to match. - docs/research/cave_kinds.md / Hook_MatchingFilterObserve.m: tighten the AAPCS64 wording. W9 is not "arg #9" (the integer arg sequence ends at x7; x8 is the indirect-result register). It IS call-clobbered scratch (x9–x15), which is exactly why touching it from the entry cave is safe — but say so in the language the ABI actually uses. - docs/research/cave_kinds.md: drop BR / BLR from the "PC-relative, can't relocate" list. They're register-indirect, so the branch instruction itself IS PC-independent; what makes them unsafe to lift is the ADRP/MOVZ chain that loaded the target register a few insns earlier. Spell that out so the next contributor doesn't get the same wrong impression. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tkgstrator
added a commit
that referenced
this pull request
Jun 22, 2026
- recipes/kiouenginebridge.py: the GetValidMatchFoundStatus row's comment said the hook returns NULL to reject the match, but the actual entry hook forwards orig's MatchFoundStatus unchanged and delivers the reject signal by firing ConnectionFailed at the stream. Rewrite the comment to match. - docs/research/cave_kinds.md / Hook_MatchingFilterObserve.m: tighten the AAPCS64 wording. W9 is not "arg #9" (the integer arg sequence ends at x7; x8 is the indirect-result register). It IS call-clobbered scratch (x9–x15), which is exactly why touching it from the entry cave is safe — but say so in the language the ABI actually uses. - docs/research/cave_kinds.md: drop BR / BLR from the "PC-relative, can't relocate" list. They're register-indirect, so the branch instruction itself IS PC-independent; what makes them unsafe to lift is the ADRP/MOVZ chain that loaded the target register a few insns earlier. Spell that out so the next contributor doesn't get the same wrong impression. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tkgstrator
added a commit
that referenced
this pull request
Jun 22, 2026
… document cave kinds
* feat(chinlan): port LoginArgs / RegisterUserArgs argument swap to entry caves
So Account Switch and the Reset → Register distinctId pinning now work on
chinlan instead of being JB-only:
- recipes/kiouenginebridge.py: add LoginArgs.Create (RVA 0x5B9899C) and
RegisterUserArgs.Create (RVA 0x5B98A2C) as CAVE_ENTRY rows so the cave
hands the hook pristine x0..x7. CAVE_OBSERVER cannot do this because it
restores x0..x7 from the saved frame before B orig+4, undoing any swap.
ENTRY_SLOT_COUNT bumps from 1 to 3.
- Internal.h: enum entries + entry-slot enum entries for both sites.
- ChinlanDispatcher.m: publishes &HookLoginArgsCreateEntry and
&HookRegisterUserArgsCreateEntry into their entry slots at boot.
- Hook_AccountObserve.m: factors the JB substitution logic into
loginArgsSwapDeviceId() / registerUserArgsSwapDistinctId() so both the
JB hooks and the new chinlan entry hooks reuse it. The entry hooks
invoke orig themselves through the cave bypass entry (cave_va + 0x4C,
published via g_inject_entry[KIOU_BR_HOOK_*_CREATE]) and forward the
freshly built ILoginArgs* / IRegisterUserArgs*. The JB hooks are
wrapped in #if !KIOU_CHINLAN so chinlan's varargs-dropping
KIOU_CALL_ORIG_RET macro doesn't trip -Werror=unused-variable.
Builds: JB + chinlan both clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(matching): wire seat / rate-range filters on JB + chinlan
Two parts:
1. Tweak.m finally calls InstallMatchingFilterObserveHook from both the
JB and chinlan branches. The Settings UI rows were already shipping;
they just weren't connected to anything because nobody invoked the
installer.
2. recipes/kiouenginebridge.py adds three new chinlan cave sites so
the filter works without MSHookFunction:
* GetValidMatchFoundStatus (0x5D04E94) — CAVE_ENTRY. The hook fires
ConnectionFailed at the stream when the filter rejects the seat,
then forwards orig's MatchFoundStatus*.
* IShogiMatchStreamArgs.Create (0x5BCA664) — CAVE_ENTRY. Must be
entry, not observer: its 7th C argument lands in W6 which
CAVE_OBSERVER would clobber with the dispatcher hook_id. The entry
cave only touches W9, an unused slot here.
* MatchingHandler.ReceiveWithTimeoutAsync.MoveNext (0x5D06B10) —
CAVE_OBSERVER. Single-arg state-machine peek; we cache the stream
pointer and react to MatchingStatus replies for Fixed Rate Range.
ENTRY_SLOT_COUNT bumps from 3 to 5.
3. Hook_MatchingFilterObserve.m factors the JB hook bodies into shared
helpers (filterMatchFoundResult / cacheJoinQueueParams) so the new
chinlan entry hooks reuse the same decision logic and only differ in
how orig is invoked (MSHookFunction trampoline on JB; cave-bypass
entry on chinlan). InstallMatchingFilterObserveHook on chinlan now
points g_ArgsCreate at the cave-bypass entry so sendAction() doesn't
re-enter the entry hook on every requeue.
Builds: JB + chinlan both clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* docs: document chinlan cave kinds with capability matrix and walkthrough
New page covers CAVE_OBSERVER vs CAVE_ENTRY:
- At-a-glance capability matrix (override return, swap args, W6 clobber,
shared dispatcher vs per-site slot, etc.) so contributors can pick the
right cave kind without reading the recipe.
- Annotated 21-insn cave layouts side-by-side so the +0x4C bypass-entry
contract that both kinds preserve is obvious.
- 8-step walkthrough for adding a new site: pick the kind, validate the
prologue is PC-independent, edit recipe / Internal.h / hook file /
ChinlanDispatcher / Tweak.m, and verify with make ipa + chinlan boot
logs. Worked example targets a CAVE_ENTRY conversion since that's the
trickier case that needed cross-file coordination.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(chinlan): bump Sources/Chinlan submodule to 94d098d
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(chinlan): move ENTRY_SLOT_BASE_RVA into __common to fix the bss overflow
Previously the entry slot table started at 0x8F90CD0 — the last 8 bytes
of __DATA,__bss — so slot[0] fit but slot[1+] silently spilled into the
40-byte padding between __bss and __common. Both regions are zero-fill
so dyld didn't catch it, but Shared/tools/patch_macho.py's
assert_slot_in_bss only validates HOOK_SLOT_RVA and never noticed.
Relocate to 0x091E90B8 in __DATA,__common (2.4 MB section, 32-slot
reservation = 256 bytes at the section tail). Static asserts at recipe
import time now catch any future ENTRY_SLOT_CAPACITY / base bump that
would overflow the section bound captured in _COMMON_SECTION_END_RVA.
Extending the patcher's per-binary assert_slot_in_bss check to cover
every entry slot — not just HOOK_SLOT_RVA — is a separate Shared PR.
Builds: chinlan IPA repack confirmed; recipe import-time asserts hold
(reservation tail 0x091E91B8 == __common end).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(chinlan): persist LoginReply + SelfProfile on chinlan via entry caves
So accounts.json on chinlan finally carries the same accessToken-derived
userId, sessionId, deviceId, userName, and rank/rating array that the JB
build has been recording since PR #14.
- RunLoginSequenceAsync.MoveNext (RVA 0x5812534) and
GetSelfUserProfileAsync.MoveNext (RVA 0x5BB4774) join the entry-cave
table. The MoveNext fields they read (LoginReply pointer at
state-machine offset 0x50, SelfUserProfileStatus rank list at 0x28)
only land after orig advances state to -2, so the cave has to be
CAVE_ENTRY: the hook calls the per-site bypass entry to actually run
MoveNext, then reads the now-populated fields.
- Hook_AccountObserve.m factors the post-completion scan logic into
observeRunLoginSeqCompletion() / observeGetSelfProfileCompletion() so
the JB MSHook hooks and the new chinlan entry hooks reuse the same
body. JB hooks call KIOU_CALL_ORIG_VOID first; chinlan entry hooks
invoke orig through g_inject_entry[…] first. Either way the body sees
a state-machine struct that's already advanced past the await.
- ENTRY_SLOT_COUNT goes 5 → 7. ChinlanDispatcher's publish log adds the
two new pointers so a boot log makes the wiring obvious.
Builds: JB + chinlan + chinlan IPA repack all clean; all three new
patches (one observer for ReceiveTimeoutMoveNext, two entries for the
MoveNext observers) are applied to the IPA.
Untested on-device — but the read paths inside observe*() are unchanged
since PR #14 / #17, and the entry-cave dispatch shape is the same as
HookLoginArgsCreateEntry / HookAccountExistsEntry which have been
exercised in the prior chinlan boot logs.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(chinlan): bump Sources/Chinlan submodule
* docs: address Copilot review nits on PR #17
- recipes/kiouenginebridge.py: the GetValidMatchFoundStatus row's
comment said the hook returns NULL to reject the match, but the
actual entry hook forwards orig's MatchFoundStatus unchanged and
delivers the reject signal by firing ConnectionFailed at the stream.
Rewrite the comment to match.
- docs/research/cave_kinds.md / Hook_MatchingFilterObserve.m: tighten
the AAPCS64 wording. W9 is not "arg #9" (the integer arg sequence
ends at x7; x8 is the indirect-result register). It IS call-clobbered
scratch (x9–x15), which is exactly why touching it from the entry
cave is safe — but say so in the language the ABI actually uses.
- docs/research/cave_kinds.md: drop BR / BLR from the "PC-relative,
can't relocate" list. They're register-indirect, so the branch
instruction itself IS PC-independent; what makes them unsafe to lift
is the ADRP/MOVZ chain that loaded the target register a few insns
earlier. Spell that out so the next contributor doesn't get the same
wrong impression.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* docs(cave_kinds): unify ADRP/LDR placeholder names in cave diagrams
Copilot review on the sibling Chinlan PR (and applicable here too)
noted that the ADRP/LDR pair used different placeholders for the same
address — `page(HOOK_SLOT_RVA)` + `lo12(SLOT)`, and similarly
`page(entry_slot_va)` + `lo12(slot)`. Make both sides of each ADRP/LDR
pair name the same symbol so the relocation pattern is unambiguous.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(chinlan): bump submodule to 90512ec
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
tkgstrator
added a commit
that referenced
this pull request
Jun 23, 2026
… document cave kinds
* feat(chinlan): port LoginArgs / RegisterUserArgs argument swap to entry caves
So Account Switch and the Reset → Register distinctId pinning now work on
chinlan instead of being JB-only:
- recipes/kiouenginebridge.py: add LoginArgs.Create (RVA 0x5B9899C) and
RegisterUserArgs.Create (RVA 0x5B98A2C) as CAVE_ENTRY rows so the cave
hands the hook pristine x0..x7. CAVE_OBSERVER cannot do this because it
restores x0..x7 from the saved frame before B orig+4, undoing any swap.
ENTRY_SLOT_COUNT bumps from 1 to 3.
- Internal.h: enum entries + entry-slot enum entries for both sites.
- ChinlanDispatcher.m: publishes &HookLoginArgsCreateEntry and
&HookRegisterUserArgsCreateEntry into their entry slots at boot.
- Hook_AccountObserve.m: factors the JB substitution logic into
loginArgsSwapDeviceId() / registerUserArgsSwapDistinctId() so both the
JB hooks and the new chinlan entry hooks reuse it. The entry hooks
invoke orig themselves through the cave bypass entry (cave_va + 0x4C,
published via g_inject_entry[KIOU_BR_HOOK_*_CREATE]) and forward the
freshly built ILoginArgs* / IRegisterUserArgs*. The JB hooks are
wrapped in #if !KIOU_CHINLAN so chinlan's varargs-dropping
KIOU_CALL_ORIG_RET macro doesn't trip -Werror=unused-variable.
Builds: JB + chinlan both clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(matching): wire seat / rate-range filters on JB + chinlan
Two parts:
1. Tweak.m finally calls InstallMatchingFilterObserveHook from both the
JB and chinlan branches. The Settings UI rows were already shipping;
they just weren't connected to anything because nobody invoked the
installer.
2. recipes/kiouenginebridge.py adds three new chinlan cave sites so
the filter works without MSHookFunction:
* GetValidMatchFoundStatus (0x5D04E94) — CAVE_ENTRY. The hook fires
ConnectionFailed at the stream when the filter rejects the seat,
then forwards orig's MatchFoundStatus*.
* IShogiMatchStreamArgs.Create (0x5BCA664) — CAVE_ENTRY. Must be
entry, not observer: its 7th C argument lands in W6 which
CAVE_OBSERVER would clobber with the dispatcher hook_id. The entry
cave only touches W9, an unused slot here.
* MatchingHandler.ReceiveWithTimeoutAsync.MoveNext (0x5D06B10) —
CAVE_OBSERVER. Single-arg state-machine peek; we cache the stream
pointer and react to MatchingStatus replies for Fixed Rate Range.
ENTRY_SLOT_COUNT bumps from 3 to 5.
3. Hook_MatchingFilterObserve.m factors the JB hook bodies into shared
helpers (filterMatchFoundResult / cacheJoinQueueParams) so the new
chinlan entry hooks reuse the same decision logic and only differ in
how orig is invoked (MSHookFunction trampoline on JB; cave-bypass
entry on chinlan). InstallMatchingFilterObserveHook on chinlan now
points g_ArgsCreate at the cave-bypass entry so sendAction() doesn't
re-enter the entry hook on every requeue.
Builds: JB + chinlan both clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* docs: document chinlan cave kinds with capability matrix and walkthrough
New page covers CAVE_OBSERVER vs CAVE_ENTRY:
- At-a-glance capability matrix (override return, swap args, W6 clobber,
shared dispatcher vs per-site slot, etc.) so contributors can pick the
right cave kind without reading the recipe.
- Annotated 21-insn cave layouts side-by-side so the +0x4C bypass-entry
contract that both kinds preserve is obvious.
- 8-step walkthrough for adding a new site: pick the kind, validate the
prologue is PC-independent, edit recipe / Internal.h / hook file /
ChinlanDispatcher / Tweak.m, and verify with make ipa + chinlan boot
logs. Worked example targets a CAVE_ENTRY conversion since that's the
trickier case that needed cross-file coordination.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(chinlan): bump Sources/Chinlan submodule to 94d098d
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(chinlan): move ENTRY_SLOT_BASE_RVA into __common to fix the bss overflow
Previously the entry slot table started at 0x8F90CD0 — the last 8 bytes
of __DATA,__bss — so slot[0] fit but slot[1+] silently spilled into the
40-byte padding between __bss and __common. Both regions are zero-fill
so dyld didn't catch it, but Shared/tools/patch_macho.py's
assert_slot_in_bss only validates HOOK_SLOT_RVA and never noticed.
Relocate to 0x091E90B8 in __DATA,__common (2.4 MB section, 32-slot
reservation = 256 bytes at the section tail). Static asserts at recipe
import time now catch any future ENTRY_SLOT_CAPACITY / base bump that
would overflow the section bound captured in _COMMON_SECTION_END_RVA.
Extending the patcher's per-binary assert_slot_in_bss check to cover
every entry slot — not just HOOK_SLOT_RVA — is a separate Shared PR.
Builds: chinlan IPA repack confirmed; recipe import-time asserts hold
(reservation tail 0x091E91B8 == __common end).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(chinlan): persist LoginReply + SelfProfile on chinlan via entry caves
So accounts.json on chinlan finally carries the same accessToken-derived
userId, sessionId, deviceId, userName, and rank/rating array that the JB
build has been recording since PR #14.
- RunLoginSequenceAsync.MoveNext (RVA 0x5812534) and
GetSelfUserProfileAsync.MoveNext (RVA 0x5BB4774) join the entry-cave
table. The MoveNext fields they read (LoginReply pointer at
state-machine offset 0x50, SelfUserProfileStatus rank list at 0x28)
only land after orig advances state to -2, so the cave has to be
CAVE_ENTRY: the hook calls the per-site bypass entry to actually run
MoveNext, then reads the now-populated fields.
- Hook_AccountObserve.m factors the post-completion scan logic into
observeRunLoginSeqCompletion() / observeGetSelfProfileCompletion() so
the JB MSHook hooks and the new chinlan entry hooks reuse the same
body. JB hooks call KIOU_CALL_ORIG_VOID first; chinlan entry hooks
invoke orig through g_inject_entry[…] first. Either way the body sees
a state-machine struct that's already advanced past the await.
- ENTRY_SLOT_COUNT goes 5 → 7. ChinlanDispatcher's publish log adds the
two new pointers so a boot log makes the wiring obvious.
Builds: JB + chinlan + chinlan IPA repack all clean; all three new
patches (one observer for ReceiveTimeoutMoveNext, two entries for the
MoveNext observers) are applied to the IPA.
Untested on-device — but the read paths inside observe*() are unchanged
since PR #14 / #17, and the entry-cave dispatch shape is the same as
HookLoginArgsCreateEntry / HookAccountExistsEntry which have been
exercised in the prior chinlan boot logs.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(chinlan): bump Sources/Chinlan submodule
* docs: address Copilot review nits on PR #17
- recipes/kiouenginebridge.py: the GetValidMatchFoundStatus row's
comment said the hook returns NULL to reject the match, but the
actual entry hook forwards orig's MatchFoundStatus unchanged and
delivers the reject signal by firing ConnectionFailed at the stream.
Rewrite the comment to match.
- docs/research/cave_kinds.md / Hook_MatchingFilterObserve.m: tighten
the AAPCS64 wording. W9 is not "arg #9" (the integer arg sequence
ends at x7; x8 is the indirect-result register). It IS call-clobbered
scratch (x9–x15), which is exactly why touching it from the entry
cave is safe — but say so in the language the ABI actually uses.
- docs/research/cave_kinds.md: drop BR / BLR from the "PC-relative,
can't relocate" list. They're register-indirect, so the branch
instruction itself IS PC-independent; what makes them unsafe to lift
is the ADRP/MOVZ chain that loaded the target register a few insns
earlier. Spell that out so the next contributor doesn't get the same
wrong impression.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* docs(cave_kinds): unify ADRP/LDR placeholder names in cave diagrams
Copilot review on the sibling Chinlan PR (and applicable here too)
noted that the ADRP/LDR pair used different placeholders for the same
address — `page(HOOK_SLOT_RVA)` + `lo12(SLOT)`, and similarly
`page(entry_slot_va)` + `lo12(slot)`. Make both sides of each ADRP/LDR
pair name the same symbol so the relocation pattern is unambiguous.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(chinlan): bump submodule to 90512ec
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v0.1.2
bump control version to 0.1.2.
Added
%%TIMECSA extension command with millisecond-precision remaining time response.Fixed
Game_Summaryand%%TIMEresponses.MatchController.SurrenderAsync.🤖 Generated with Claude Code