背景
open な bug issue を分類する過程(#2379 )で、#2123 と #2085 が同じ根を持つと分かった。どちらも「上流がアーカイブの構造を変えたが apm-data の定義が古いまま」だが、症状が正反対 で、そこに apm 側の課題が 2 つ見える。
前提として、downloadURLs は多くのパッケージで releases/latest を指している。つまりユーザーは常に上流の最新アーカイブを取得する 一方、files / archivePath は apm-data を更新するまで古い構造を記述したままになる。この乖離は構造的に避けられない。
課題 1: archivePath がリテラルで、バージョン入りの階層に追従できない
src/shared/install.ts のコピー元はこう決まる。
file . archivePath
? resolveInside ( unzippedPath , file . archivePath , path . basename ( file . filename ) )
: path . join ( unzippedPath , path . basename ( file . filename ) )
archivePath はリテラルで、グロブは効かない。
#2123 (x264guiEx)では、上流のアーカイブが x264guiEx_3.31v3/plugins/... のようにバージョン名のルート階層 を持つ形になっていた。apm-data は archivePath: "plugins" なので届かない。
問題は、フォルダ名にバージョンが入るため固定値では原理的に追従できない こと。apm-data の値を直しても次のリリースでまた壊れる。
考えられる方向:
archivePath にグロブを許す(matcher は既に依存にある)
展開結果が単一のルートディレクトリだけの場合、それを自動的に剥がす
何もしない — apm-data 側で毎リリース追従する(現実的でない)
なお #2123 は失敗が表に出る 。plugins/x264guiEx.auo 等は通常ファイルなので verifyFilesByCount に引っかかり、報告者も「エラーが発生しました」と見えている。挙動としては正しい。
課題 2: isUninstallOnly のファイルが検証から除外されている
export function verifyFilesByCount ( installationPath : string , files : Files ) {
for ( const file of files ) {
if ( ! file . isUninstallOnly && ! file . isObsolete ) { // ← 除外
#2085 (アルティメットプラグイン)の plugins/ultimate は isDirectory かつ isUninstallOnly で定義されている。このためコピーに失敗しても検証対象に入らず、インストールは成功扱いになる 。報告者の環境で module/ が丸ごと無いのにエラーが出なかったのはこのため。
isUninstallOnly の実装は「アンインストール時にだけ消す」ではなく、コピー時も
if ( existsSync ( filePath [ 0 ] ) && ! existsSync ( filePath [ 1 ] ) ) filesToCopy . push ( filePath ) ;
つまり「コピー元にあり、コピー先に無ければ入れる」。既に存在する場合は更新されない ので、上流が新しいモジュールを追加しても届かない。ディレクトリ丸ごとを isUninstallOnly にすると、この性質が subtree 全体に効く。
検証から外れているぶん、失敗が誰にも見えない点が課題。
先に apm-data の更新が要る(2026-08-23 追記)
この issue の設計判断に入る前に、apm-data の更新が必要 であることが分かった。GitHub 由来のパッケージ 79 件について、apm-data の latestVersion と上流の最新リリースを突き合わせた結果:
一致: 55 件
不一致: 21 件
リリース情報を取得できず: 3 件
不一致のうち、この issue に直接関わるもの:
パッケージ
apm-data
上流
rigaya/x264guiEx (#2123 )
3.31
4.12
hebiiro/UltimatePlugin (#2085 )
r38
r117
rigaya/NVEnc
7.73
9.32
rigaya/QSVEnc
7.72
8.27
rigaya/svtAV1guiEx
1.26
2.13
rigaya/x265guiEx
4.21
5.10
rigaya/VCEEnc
8.23
9.13
#2123 の x264guiEx はデータが 3.31、上流は 4.12。 報告当時のアーカイブ構造(x264guiEx_3.31v3/)を前提に設計を決めても、現在の 4.12 では構造が変わっている可能性がある。同様に #2085 も r38 と r117 で開きが大きい。
したがって次の順序になる。
apm-data を更新する
更新後も x264guiExのインストールに失敗する #2123 / アルティメットプラグインをうまく導入できない #2085 が再現するか確かめる
再現するなら、そのときの実際のアーカイブ構造をもとに課題 1 の方向を決める
課題 2(検証の穴)はデータの新旧に依存しないため、独立して進められる。ただし単純に isUninstallOnly を検証対象へ含めると「アーカイブに無いのが正常」なケースまで失敗扱いになるため、切り分けが要る。
調査の副産物
同じ突き合わせで、データ側の別の異常も見つかった。
latestVersion が 最新 という文字列 — HolyWu/LSMASHWorks / MrOjii/LSMASHWorks / VFRmaniac/LSMASHWorks の 3 件。バージョン比較が機能しないはず
oov/PSDToolKit — data が 0.2beta56 で上流が 0.1.3。データのほうが新しく見えるので、上流のリリースタグとは別の場所で配布している可能性
いずれも apm-data 側の話なので、この issue では扱わない。
確認した事実
matcher は既に dependencies にある(グロブ対応の追加コストは低い)
apm-data 現況: rigaya/x264guiEx は archivePath: "plugins"、hebiiro/UltimatePlugin の plugins/ultimate は isDirectory + isUninstallOnly
スコープ
apm-data 側のデータ更新(#1930 / #2042 / #2085 / #2123 )とは別の、apm 本体の課題としてここに切り出す。データを直しても課題 1 は再発しうるし、課題 2 は表面化しないままになるため。
調査と文面の作成に Claude Code を使用しています。
背景
open な bug issue を分類する過程(#2379)で、#2123 と #2085 が同じ根を持つと分かった。どちらも「上流がアーカイブの構造を変えたが apm-data の定義が古いまま」だが、症状が正反対で、そこに apm 側の課題が 2 つ見える。
前提として、
downloadURLsは多くのパッケージでreleases/latestを指している。つまりユーザーは常に上流の最新アーカイブを取得する一方、files/archivePathは apm-data を更新するまで古い構造を記述したままになる。この乖離は構造的に避けられない。課題 1:
archivePathがリテラルで、バージョン入りの階層に追従できないsrc/shared/install.tsのコピー元はこう決まる。archivePathはリテラルで、グロブは効かない。#2123(x264guiEx)では、上流のアーカイブが
x264guiEx_3.31v3/plugins/...のようにバージョン名のルート階層を持つ形になっていた。apm-data はarchivePath: "plugins"なので届かない。問題は、フォルダ名にバージョンが入るため固定値では原理的に追従できないこと。apm-data の値を直しても次のリリースでまた壊れる。
考えられる方向:
archivePathにグロブを許す(matcherは既に依存にある)なお #2123 は失敗が表に出る。
plugins/x264guiEx.auo等は通常ファイルなのでverifyFilesByCountに引っかかり、報告者も「エラーが発生しました」と見えている。挙動としては正しい。課題 2:
isUninstallOnlyのファイルが検証から除外されている#2085(アルティメットプラグイン)の
plugins/ultimateはisDirectoryかつisUninstallOnlyで定義されている。このためコピーに失敗しても検証対象に入らず、インストールは成功扱いになる。報告者の環境でmodule/が丸ごと無いのにエラーが出なかったのはこのため。isUninstallOnlyの実装は「アンインストール時にだけ消す」ではなく、コピー時もつまり「コピー元にあり、コピー先に無ければ入れる」。既に存在する場合は更新されないので、上流が新しいモジュールを追加しても届かない。ディレクトリ丸ごとを
isUninstallOnlyにすると、この性質が subtree 全体に効く。検証から外れているぶん、失敗が誰にも見えない点が課題。
先に apm-data の更新が要る(2026-08-23 追記)
この issue の設計判断に入る前に、apm-data の更新が必要であることが分かった。GitHub 由来のパッケージ 79 件について、apm-data の
latestVersionと上流の最新リリースを突き合わせた結果:不一致のうち、この issue に直接関わるもの:
#2123 の x264guiEx はデータが 3.31、上流は 4.12。 報告当時のアーカイブ構造(
x264guiEx_3.31v3/)を前提に設計を決めても、現在の 4.12 では構造が変わっている可能性がある。同様に #2085 も r38 と r117 で開きが大きい。したがって次の順序になる。
課題 2(検証の穴)はデータの新旧に依存しないため、独立して進められる。ただし単純に
isUninstallOnlyを検証対象へ含めると「アーカイブに無いのが正常」なケースまで失敗扱いになるため、切り分けが要る。調査の副産物
同じ突き合わせで、データ側の別の異常も見つかった。
latestVersionが最新という文字列 —HolyWu/LSMASHWorks/MrOjii/LSMASHWorks/VFRmaniac/LSMASHWorksの 3 件。バージョン比較が機能しないはずoov/PSDToolKit— data が0.2beta56で上流が0.1.3。データのほうが新しく見えるので、上流のリリースタグとは別の場所で配布している可能性いずれも apm-data 側の話なので、この issue では扱わない。
確認した事実
matcherは既に dependencies にある(グロブ対応の追加コストは低い)rigaya/x264guiExはarchivePath: "plugins"、hebiiro/UltimatePluginのplugins/ultimateはisDirectory+isUninstallOnlyスコープ
apm-data 側のデータ更新(#1930 / #2042 / #2085 / #2123)とは別の、apm 本体の課題としてここに切り出す。データを直しても課題 1 は再発しうるし、課題 2 は表面化しないままになるため。
調査と文面の作成に Claude Code を使用しています。