Skip to content

fix(shared): 依存が循環していてもパッケージ一覧が落ちないようにする - #2445

Merged
hal-shu-sato merged 1 commit into
mainfrom
fix/deps-cycle-crash
Aug 23, 2026
Merged

hal-shu-sato merged 1 commit into
mainfrom
fix/deps-cycle-crash

Conversation

@hal-shu-sato

Copy link
Copy Markdown
Member

症状

パッケージデータの依存に循環(A → B → A、あるいは自己依存 A → A)が 1 つでもあると、Plugins タブが丸ごと表示できなくなる。

原因

computePackagesStatus の isInstallable は依存を再帰で辿るだけで、評価中の id を持っていない。

const isInstallable = (id: string): boolean => {
  const thisPackage = packages.filter((p) => p.id === id).find(() => true);
  if (thisPackage) {
    const isDepsInstallable = (): boolean =>
      (thisPackage.info.dependencies ?? [])
        .map((orOfID) => orOfID.split('|').map((id2) => isInstallable(id2)).some((x) => x))
        …

dependencies はリモート由来 — dataURL の packages.json と {installationPath}/packages.json(localRepoPath)— なので循環が書かれうる。書かれると RangeError: Maximum call stack size exceeded になる。

呼び出し元の getPackagesWithStatus(src/main/services/packageList.ts)に try/catch が無いため、この例外は tRPC のクエリごと失敗する。パッケージ 1 件の記述ミスで一覧全体が死ぬうえ、ユーザーには原因が分からない。

修正

評価中の id を Set で持ち、循環を検出したら false(導入できない)を返す。

false に倒す理由: 一覧そのものが出なくなるより、その 1 件が「導入不可」と表示されるほうがユーザーは先へ進める。

到達経路について

公式データ(apm-data v3、285 パッケージ)を実際に集計したところ 最大依存深さ 2・循環なしだった。したがって現時点で踏むのは主に次の 2 つ:

  • {installationPath}/packages.json(ローカルリポジトリ。自作パッケージの検証で手書きされる)
  • サードパーティの dataURL

「自作パッケージ・サードパーティデータの検証」は AGENTS.md が明示的に守ると決めているユースケースなので、そこで一覧が落ちるのは避けたい。

テスト

computePackagesStatus に 3 件追加した。修正前は 3 件とも Maximum call stack size exceeded で落ち、修正後は通る。

3 件目の「循環に巻き込まれていないパッケージの判定は変わらない」は、循環の巻き添えで無関係なパッケージまで導入不可にしていないことの確認。


調査と文面の作成に Claude Code を使用しています。

computePackagesStatus の isInstallable は依存を再帰で辿るだけで、
評価中の id を持っていない。dependencies はリモート由来
(dataURL の packages.json と {installationPath}/packages.json)なので、
A→B→A や A→A が書かれると無限再帰で RangeError になる。

getPackagesWithStatus に try/catch が無いため、この例外は tRPC の
クエリごと失敗させる。パッケージ 1 件の問題でタブが丸ごと表示できなくなり、
ユーザーには原因も分からない。

循環を検出したら false(導入できない)を返す。一覧そのものが出なくなるより、
その 1 件が導入不可と表示されるほうが先へ進めるため。

なお公式データ(apm-data v3、285 パッケージ)は最大依存深さ 2 で循環は無い。
到達経路は主に localRepoPath とサードパーティの dataURL。
@hal-shu-sato
hal-shu-sato merged commit 3188030 into main Aug 23, 2026
9 checks passed
@hal-shu-sato
hal-shu-sato deleted the fix/deps-cycle-crash branch August 23, 2026 07:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant