1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【改善】Amazon Q plugin を Kiro CLI と同じにする方法

1
Last updated at Posted at 2026-04-11

Amazon Q for IntelliJ IDEA を拡張した記録 (通称:尊師モード)

この記事の位置づけ

本記事は Amazon Q Plugin の承認フローの仕組みを理解し、ローカル環境で挙動を変更した検証記録である。
本検証はAmazon Qが提供する安全機構(Human-in-the-Loop)を意図的に無効化するものであり、実運用環境では推奨されない。
本手法は公式バイナリ/ コードを書き換えるものであり、アップデートにより正常動作しない可能性がある。また組織ポリシーに違反する場合があるため注意が必要である。

業務環境での利用については、組織のセキュリティポリシーおよび承認プロセスに従う必要がある。
実施は自己責任でお願いいたします。


きっかけ

Amazon Q for JetBrains(IntelliJ IDEA)のagentic-codingモードでは、コマンド実行のたびに「Run」ボタンの押下が必要となる。
複数ステップの調査ではこの操作がボトルネックとなるため、LSPサーバーのminified JSにパッチを適用し、セッション単位で承認をスキップする仕組みを実装した。


背景と動機

Amazon Q Plugin は以下の承認フローを持つ。

  • ファイルアクセス時:Allow
  • コマンド実行時:Run

これは安全性および監査性の観点では妥当な設計である。一方で調査作業においては以下の問題が顕在化する。
>数十回のコマンド実行のたびに「Run」を押下する必要がある

他ツールでは以下のような自律実行モードが提供されている。

  • Kiro CLI:セッション単位で自動承認
  • Codex CLI:--full-auto
  • Claude Code:--dangerously-skip-permissions

👉 一定条件下で処理を委譲できる設計となっている。うらやましい。裏山。


問題の本質 (設計思想の違い)

本件は単なる機能差ではなく、設計思想の差異である。

観点 Amazon Q Plugin CLI系(Kiro等)
操作主体 人間 AI
実行制御 都度承認 セッション単位
安全性 高い 可変
作業速度 低め 高い

👉 IDEは「統制」、CLIは「自律」を前提とした設計である

本当は私も Kiroが使いたいのですが、まだWindowsでは動かないの。
WSL必須だし。そしたら、ほら改造しかないでしょ。


アーキテクチャ調査

承認制御はすべて LSPサーバー側のJavaScript に実装されている。

対象ファイルは以下である。

%LOCALAPPDATA%\aws\toolkits\language-servers\AmazonQ-JetBrains-temp\{ver}\aws-lsp-codewhisperer.js

👉 plugin配下ではなく、実行時に展開された領域が対象となる点に注意が必要

プラグインの構造

Amazon Q plugin は以下の2層構造になっている:

┌─────────────────────────────────┐
│  JetBrains側(Kotlin/JVM)       │  ← UIの表示、ボタンのレンダリング
│  plugin-amazonq/lib/*.jar       │
├─────────────────────────────────┤
│  LSPサーバー側(Node.js)         │  ← ツール承認ロジック、チャット処理
│  aws-lsp-codewhisperer.js      │
└─────────────────────────────────┘

承認フロー(Run/Allow/Rejectボタン)の制御はLSPサーバー側のJavaScriptで行われている。JetBrains側はLSPサーバーから受け取ったUIブロックをレンダリングするだけ。


承認フローのコード解析

約6MBのminified JSから、承認制御の核心部分を特定した。

// processToolUses メソッド内(簡略化)
switch(u.name) {
  case EXECUTE_BASH: {
    // requiresAcceptance: ファイルアクセス等で承認が必要か
    {requiresAcceptance:l, warning:d, commandCategory:p} = await s.requiresAcceptance(u.input, c);
    
    if (l || u.name === a.EXECUTE_BASH) {
      const i = this.#we(u, l, d, p);        // 承認UIブロック生成
      e = await t.writeResultBlock(i);         // UIに表示
      l && await this.waitForToolApproval(...); // 承認待ち
    }
    break;
  }
  default: {
    // MCPツール(search, fetch_content等)はここ
    if (a) { // requiresAcceptance
      await this.waitForToolApproval(...);     // 承認待ち
    }
  }
}

ポイント:

  • executeBashrequiresAcceptance の結果に関わらず常にUIブロックを表示
  • waitForToolApproval は Promise ベースで、ボタンクリック時に resolve/reject される
  • MCPツールは default ケースで別の承認フローを持つ

実装の核心

minified JSを扱う上で最も重要な原則は以下である。
既存変数を書き換えず、条件式のみを拡張する

NG例 (実際に発生した障害)

u = !0

👉 const 再代入により全ツールが使用不能となる

OK例

(l && !r.__sonshiMode) && await this.waitForToolApproval(...)

実装方針

2段階確認UI

セキュリティリスクを考慮し、発動時に2段階の確認を設けた。

1段階目: 通常のRun/Rejectボタンに「⚡ Sonshi Mode」ボタンを追加

buttons: [
  {id: "run-shell-command", text: "Run", icon: "play"},
  {id: "reject-shell-command", text: "Reject", icon: "cancel"},
  {id: "sonshi-mode-confirm1", text: "⚡ Sonshi Mode", icon: "zap"}
]

2段階目: セキュリティ警告を表示

⚠️ SONSHI MODE WARNING
This will skip ALL confirmation dialogs (Run/Allow) for the rest of this chat session.
Commands will execute immediately without review.
Security Risk: Prompt injection or unintended commands could run without your approval.
Are you REALLY sure?

尊師モード発動

セッションオブジェクトに以下のフラグを付与。

__sonshiMode = true

この状態では以下の挙動となる。

  • 承認UIの表示をスキップ
  • waitForToolApproval を無効化
通常フロー:
  executeBash → UIブロック表示 → [Run] → コマンド実行

尊師モード発動フロー:
  executeBash → UIブロック表示 → [⚡ Sonshi Mode] → セキュリティ警告 → [Yes] → コマンド実行
  以降: executeBash → コマンド実行(UIスキップ)

尊師モードは
コマンドが連続実行される
MCPツールも承認不要
処理が停止しない。もはや魔法の道具に早変わり。


調査プロセス (MCPツール対応)

上記改修後にMCPツール(search / fetch_content)のみ承認ダイアログが残る事象を確認した。調査手順は以下である。

  1. ビルトインツールとの差異を確認
  2. processToolUses を再解析
  3. MCPツールが default ケースで処理されていることを特定
  4. 当該分岐に __sonshiMode チェックが存在しないことを確認
  5. 条件式に1行追加し検証
if (a && !r.__sonshiMode) {

👉 +17バイトの変更で全体挙動が改善された


クイックスタート(最短手順)

  1. 対象JSファイルを特定
  2. パッチを適用
  3. IDEを再起動
  4. Sonshi Modeを有効化

👉 上記で動作する


詳細手順

クリックで展開

Step1: 実行ファイル特定

wmic process where "name='node.exe'" get CommandLine

Step2: パッチ適用

まず、実際にLSPサーバーが使っているJSファイルのパスを特定する。

wmic process where "name='node.exe'" get CommandLine /format:list 2>nul | findstr /i "aws-lsp-codewhisperer"

出力例:

CommandLine=...\AmazonQ-JetBrains-temp\1.64.0\aws-lsp-codewhisperer.js...

このパスに含まれるバージョン番号(例: 1.64.0)を確認する。パッチ対象は以下のファイル:

%LOCALAPPDATA%\aws\toolkits\language-servers\AmazonQ-JetBrains-temp\{バージョン}\aws-lsp-codewhisperer.js

⚠️ plugins\plugin-amazonq\flare\ 配下にも同名ファイルがあるが、そちらは参照されない。必ず上記パスのファイルを修正すること。

Step 2: パッチスクリプトを配置

パッチポイント(全7箇所)

# 箇所 変更内容 目的
1 waitForToolApproval 呼び出し条件 l&&await(l&&!r.__sonshiMode)&&await 承認待ちスキップ
2 #we 関数(ボタン生成) Rejectボタンの後に Sonshi Mode ボタン追加 UIに⚡ボタン表示
3 onButtonClick ルーティング sonshi-mode-confirm1/2 を追加 ボタンクリックのハンドリング
4 ボタンクリック resolve/reject confirm1→__sonshiPending=true, confirm2→__sonshiMode=true 2段階確認でフラグ設定
5 #we 呼び出し前 __sonshiPending 時にセキュリティ警告UI表示 2段階目の確認ダイアログ
6 承認ブロック全体の条件 if(!r.__sonshiMode&&(...)) でガード 承認ブロック全体スキップ
7 MCPツール分岐(defaultケース) if(a)if(a&&!r.__sonshiMode) MCPツール承認もスキップ

以下の2ファイルを任意のディレクトリに保存する。

sonshi_patch_v2.py(クリックで展開 — Sonshi 1-6: ビルトインツール対応)
"""
Sonshi Mode Patch v2 - Safe implementation avoiding const reassignment
Target: aws-lsp-codewhisperer.js

Patches 1-6: Built-in tool approval skip + UI + 2-step confirmation
Key rule: NEVER reassign const variables. Modify conditions inline only.
"""
import sys, io, os, shutil, subprocess

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')

LSP_BASE = os.path.expandvars(
    r"%LOCALAPPDATA%\aws\toolkits\language-servers\AmazonQ-JetBrains-temp"
)

def get_running_version():
    try:
        out = subprocess.check_output(
            'wmic process where "name=\'node.exe\'" get CommandLine /format:list',
            shell=True, text=True, stderr=subprocess.DEVNULL
        )
        for line in out.splitlines():
            if "aws-lsp-codewhisperer" in line:
                parts = line.replace("\\", "/").split("AmazonQ-JetBrains-temp/")
                if len(parts) > 1:
                    return parts[1].split("/")[0]
    except Exception:
        pass
    return None

def resolve_js_dir():
    ver = get_running_version()
    if ver:
        print(f"Detected running version: {ver}")
        return os.path.join(LSP_BASE, ver), ver
    if os.path.isdir(LSP_BASE):
        versions = sorted(os.listdir(LSP_BASE), reverse=True)
        if versions:
            print(f"IDE not running. Using newest installed version: {versions[0]}")
            return os.path.join(LSP_BASE, versions[0]), versions[0]
    return None, None

def main():
    js_dir, ver = resolve_js_dir()
    if not js_dir:
        print("ERROR: No version detected"); return False
    js_file = os.path.join(js_dir, 'aws-lsp-codewhisperer.js')
    backup = os.path.join(js_dir, 'aws-lsp-codewhisperer.js.pre-sonshi-v2.bak')
    if not os.path.exists(js_file):
        print(f"ERROR: Target not found: {js_file}"); return False

    shutil.copy2(js_file, backup)
    print(f"Backup: {backup}")
    text = open(js_file, 'r', encoding='utf-8').read()
    original_len = len(text)
    applied = 0

    # PATCH 1: Skip waitForToolApproval when sonshi mode active
    old1 = 'l&&await this.waitForToolApproval(u,t,e,r,u.name)'
    new1 = '(l&&!r.__sonshiMode)&&await this.waitForToolApproval(u,t,e,r,u.name)'
    if old1 in text: text = text.replace(old1, new1, 1); applied += 1; print("PATCH 1 OK")
    else: print("PATCH 1 SKIP")

    # PATCH 2: Add Sonshi Mode button
    old2 = '{id:a.BUTTON_REJECT_SHELL_COMMAND,status:"dimmed-clear",text:"Reject",icon:"cancel",...o?{description:`Reject:  ${o}`}:{}}]:[]'
    new2 = '{id:a.BUTTON_REJECT_SHELL_COMMAND,status:"dimmed-clear",text:"Reject",icon:"cancel",...o?{description:`Reject:  ${o}`}:{}},{id:"sonshi-mode-confirm1",status:"dimmed-clear",text:"\\u26A1 Sonshi Mode",icon:"lightning"}]:[]'
    if old2 in text: text = text.replace(old2, new2, 1); applied += 1; print("PATCH 2 OK")
    else: print("PATCH 2 SKIP")

    # PATCH 3: Add sonshi button IDs to handler routing
    old3 = 'e.buttonId===a.BUTTON_RUN_SHELL_COMMAND||e.buttonId===a.BUTTON_REJECT_SHELL_COMMAND||e.buttonId===a.BUTTON_REJECT_MCP_TOOL||e.buttonId===a.BUTTON_ALLOW_TOOLS'
    new3 = old3 + '||e.buttonId==="sonshi-mode-confirm1"||e.buttonId==="sonshi-mode-confirm2"'
    if old3 in text: text = text.replace(old3, new3, 1); applied += 1; print("PATCH 3 OK")
    else: print("PATCH 3 SKIP")

    # PATCH 4: Add sonshi mode activation logic
    old4 = 'e.buttonId===a.BUTTON_REJECT_SHELL_COMMAND||e.buttonId===a.BUTTON_REJECT_MCP_TOOL?(()=>{n.reject(new F.ToolApprovalException("Command was rejected.",!0)),this.#A.add(r)})():n.res'
    new4 = old4.replace(')():n.res', ')():e.buttonId==="sonshi-mode-confirm1"?(()=>{t.data.__sonshiPending=!0,n.resolve()})():e.buttonId==="sonshi-mode-confirm2"?(()=>{t.data.__sonshiMode=!0,t.data.__sonshiPending=!1,n.resolve()})():n.res')
    if old4 in text: text = text.replace(old4, new4, 1); applied += 1; print("PATCH 4 OK")
    else: print("PATCH 4 SKIP")

    # PATCH 5: Show 2nd confirmation when sonshiPending
    old5 = 'const i=this.#we(u,l,d,p);e=await t.writeResultBlock(i);const o=u.name===a.EXECUTE_BASH'
    warn = '## \\u26A0\\uFE0F SONSHI MODE WARNING\\n\\nThis will skip ALL confirmation dialogs for the rest of this chat session.\\nCommands will execute immediately without review.\\n\\n**Security Risk**: Prompt injection or unintended commands could run without your approval.\\n\\nAre you REALLY sure?'
    new5 = f'const i=r.__sonshiPending?{{type:"directive",messageId:u.toolUseId,body:"{warn}",buttons:[{{id:"sonshi-mode-confirm2",text:"Yes, activate Sonshi Mode",icon:"lightning",status:"clear"}},{{id:a.BUTTON_REJECT_SHELL_COMMAND,text:"Cancel",icon:"cancel",status:"dimmed-clear"}}]}}:this.#we(u,l,d,p);e=await t.writeResultBlock(i);const o=u.name===a.EXECUTE_BASH'
    if old5 in text: text = text.replace(old5, new5, 1); applied += 1; print("PATCH 5 OK")
    else: print("PATCH 5 SKIP")

    # PATCH 6: Skip entire approval block when sonshi mode active
    old6 = 'if(l||u.name===a.EXECUTE_BASH){const i='
    new6 = 'if(!r.__sonshiMode&&(l||u.name===a.EXECUTE_BASH)){const i='
    if old6 in text: text = text.replace(old6, new6, 1); applied += 1; print("PATCH 6 OK")
    else: print("PATCH 6 SKIP")

    if applied == 0:
        print("\nERROR: No patches applied."); return False
    open(js_file, 'w', encoding='utf-8').write(text)
    print(f"\nPatched: {applied}/6 | Size: {original_len:,} -> {len(text):,} (+{len(text)-original_len})")
    print(f"Rollback: copy /Y \"{backup}\" \"{js_file}\"")
    return applied == 6

if __name__ == '__main__':
    sys.exit(0 if main() else 1)
sonshi_patch_v3.py(クリックで展開 — Sonshi 7: MCPツール対応)
"""
Sonshi Mode Patch v3 - MCP Tool approval skip
Prerequisite: v2 patches must already be applied.
"""
import sys, io, os, shutil, subprocess

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')

LSP_BASE = os.path.expandvars(
    r"%LOCALAPPDATA%\aws\toolkits\language-servers\AmazonQ-JetBrains-temp"
)

def get_running_version():
    try:
        out = subprocess.check_output(
            'wmic process where "name=\'node.exe\'" get CommandLine /format:list',
            shell=True, text=True, stderr=subprocess.DEVNULL
        )
        for line in out.splitlines():
            if "aws-lsp-codewhisperer" in line:
                parts = line.replace("\\", "/").split("AmazonQ-JetBrains-temp/")
                if len(parts) > 1:
                    return parts[1].split("/")[0]
    except Exception:
        pass
    return None

def resolve_js_dir():
    ver = get_running_version()
    if ver:
        print(f"Detected running version: {ver}")
        return os.path.join(LSP_BASE, ver), ver
    if os.path.isdir(LSP_BASE):
        versions = sorted(os.listdir(LSP_BASE), reverse=True)
        if versions:
            print(f"IDE not running. Using newest installed version: {versions[0]}")
            return os.path.join(LSP_BASE, versions[0]), versions[0]
    return None, None

def main():
    js_dir, ver = resolve_js_dir()
    if not js_dir:
        print("ERROR: No version detected"); return False
    js_file = os.path.join(js_dir, 'aws-lsp-codewhisperer.js')
    backup = os.path.join(js_dir, 'aws-lsp-codewhisperer.js.pre-sonshi-v3.bak')
    if not os.path.exists(js_file):
        print(f"ERROR: Target not found: {js_file}"); return False

    text = open(js_file, 'r', encoding='utf-8').read()

    # Verify v2
    if '__sonshiMode' not in text:
        print("ERROR: v2 patches not found. Run sonshi_patch_v2.py first."); return False
    print("v2 patches verified OK")

    if not os.path.exists(backup):
        shutil.copy2(js_file, backup)
        print(f"Backup: {backup}")

    original_len = len(text)

    # PATCH 7: Skip MCP tool approval when sonshi mode active
    old7 = 'if(a){const n=this.#we(u,a,c,void 0,o);e=await t.writeResultBlock(n),await this.waitForToolApproval(u,t,e,r,o)}'
    new7 = 'if(a&&!r.__sonshiMode){const n=this.#we(u,a,c,void 0,o);e=await t.writeResultBlock(n),await this.waitForToolApproval(u,t,e,r,o)}'

    if old7 in text:
        if text.count(old7) != 1:
            print(f"WARNING: Pattern found {text.count(old7)} times. Aborting."); return False
        text = text.replace(old7, new7, 1)
        print("PATCH 7 OK: MCP tool approval skip")
    elif new7 in text:
        print("PATCH 7: Already applied")
    else:
        print("PATCH 7 FAIL: Pattern not found"); return False

    open(js_file, 'w', encoding='utf-8').write(text)
    print(f"\nSize: {original_len:,} -> {len(text):,} (+{len(text)-original_len})")
    print(f"Rollback: copy /Y \"{backup}\" \"{js_file}\"")
    print("\n** IDE restart required **")
    return True

if __name__ == '__main__':
    sys.exit(0 if main() else 1)

Step3: IDE再起動

Step4: 動作確認

  • ⚡ Sonshi Mode ボタン表示
  • 有効化後、自動実行を確認

運用の工夫

  • バージョン自動検出
  • パッチ自動適用
  • 差分退避
  • 状態チェック

👉 プラグイン更新にも一定程度追従可能な構成とした


セキュリティに関する考慮

尊師モードは「AIが任意のコマンドを確認なしで実行できる」状態を作る。
以下のリスクを認識した上で使用すること。

  • プロンプトインジェクション: 悪意あるコンテンツを含むファイルを読み込んだ際に、意図しないコマンドが実行される可能性
  • スコープ: セッション(チャット)単位。新しいチャットを開けばリセットされる
  • 緩和策: 2段階確認UIでユーザーに明示的に警告

いずれにしても検証用途に限定すべき。

以下のケースでは本手法を適用すべきではない

  • 外部リポジトリや未知のコードを扱う場合
  • 本番環境または業務データを扱う環境
  • セキュリティ要件が厳格な環境

結論

Amazon Q Plugin は安全性を重視した設計である。
本検証はその設計を理解した上で、自律性を拡張したものである。

本手法は開発効率向上の一手段ではあるが
Amazon Q Pluginが提供する安全機構を変更するものである。


環境情報

  • IntelliJ IDEA 2026.1
  • Amazon Q for JetBrains プラグイン v4.0.261
  • LSPサーバー: aws-lsp-codewhisperer.js
  • OS: Windows 11
  • Node.js: プラグイン同梱版

通称:尊師モード


まとめ

Amazon Q は優秀な同僚です。
でも席を外すと処理が停止するし、OK出さないと何もしない。

本検証で目指したのは、
席を外しても処理が継続する状態。

でも本当に何も確認しないで突き進むから要注意。
尊師ってば自信持ちすぎ・・。

これで Amazon Q plugin があれば Kiro CLI 使わなくても大丈夫。
私には尊師がついてるから。いつも心に太陽を。

セキュリティおよび運用上の注意 (重要)

本記事の手法は以下の前提を理解した上でのみ適用すること。

  • Amazon Qが提供するHuman-in-the-Loopを無効化している
  • AIによる自動コマンド実行のリスクが増加する
  • プロンプトインジェクション攻撃への耐性が低下する
  • ローカル環境のコード改変を伴うためサプライチェーンリスクがある

本手法は検証用途に限定し、業務環境・本番環境での利用は推奨しない。
適用にあたってはリスクを十分に理解し
利用環境および組織ポリシーに従い慎重に判断されたい。

最後に。本検証はAmazon Qの設計思想を否定するものではなく
用途に応じて自律性と統制のバランスを調整する一例である。

編集後記(2026-05-06追記): v1.66.0 対応 — PATCH 4 パターン不一致の修正

概要

Amazon Q Plugin が v1.66.0 に更新された際、尊師モードパッチの PATCH 4(ボタンクリック時のフラグ設定) がパターン不一致で適用できなくなった。
原因を特定し、パッチスクリプトを正規表現対応に改修して解決した記録。

発生した事象

PATCH 1 OK: waitForToolApproval condition (skip when sonshi active)
PATCH 2 OK: Added Sonshi Mode button to EXECUTE_BASH UI
PATCH 3 OK: Added sonshi button IDs to handler routing
PATCH 4 SKIP: pattern not found        ← ★ここだけ失敗
PATCH 5 OK: Added 2nd confirmation dialog for sonshi mode
PATCH 6 OK: Skip entire approval block when sonshi mode active

PATCH 4 が適用されないと、⚡ボタンを押しても __sonshiMode=true が設定されず、尊師モードが発動しない。

原因

minified JS のビルド時に、モジュールスコープの変数名が変更されていた。

バージョン 変数名 コード
v1.63.0〜v1.65.0 F new F.ToolApprovalException("Command was rejected.",!0)
v1.66.0 j new j.ToolApprovalException("Command was rejected.",!0)

パッチスクリプトの old4 パターンが F.ToolApprovalExceptionリテラル文字列で検索していたため、j.ToolApprovalException にマッチしなかった。

なぜ他のパッチは影響を受けなかったか

PATCH 1〜3, 5〜7 のパターンは定数名(a.BUTTON_REJECT_SHELL_COMMAND 等)やメソッド名(this.waitForToolApproval, this.#we)を使っており、これらはminify時に変更されない。PATCH 4 だけがモジュールスコープの短縮変数名に依存していた。

修正内容

PATCH 4 のパターンマッチを固定文字列 → 正規表現に変更し、変数名部分を [A-Za-z_$]+ でキャプチャするようにした。

Before(v1.63.0〜v1.65.0 専用)

old4 = 'e.buttonId===a.BUTTON_REJECT_SHELL_COMMAND||e.buttonId===a.BUTTON_REJECT_MCP_TOOL?(()=>{n.reject(new F.ToolApprovalException("Command was rejected.",!0)),this.#A.add(r)})():n.res'
if old4 in text:
    text = text.replace(old4, new4, 1)

After(任意の変数名に対応)

import re

pat4 = re.compile(
    r'e\.buttonId===a\.BUTTON_REJECT_SHELL_COMMAND\|\|e\.buttonId===a\.BUTTON_REJECT_MCP_TOOL\?\(\(\)=>\{n\.reject\(new ([A-Za-z_$]+)\.ToolApprovalException\("Command was rejected\.",!0\)\),this\.#A\.add\(r\)\}\)\(\):n\.res'
)
m4 = pat4.search(text)
if m4:
    var_name = m4.group(1)  # 'F' or 'j' or any future name
    old4_actual = m4.group(0)
    new4_actual = f'...{var_name}.ToolApprovalException...(sonshi handlers)...:n.res'
    text = text.replace(old4_actual, new4_actual, 1)
    print(f"PATCH 4 OK: Added sonshi mode activation logic (var={var_name})")

ポイント:

  • ([A-Za-z_$]+) でminify変数名をキャプチャ
  • キャプチャした変数名を new4 の生成時にそのまま使用
  • 将来のバージョンで変数名が Fjk → ... と変わっても自動追従

適用結果

PATCH 4 OK: Added sonshi mode activation logic (var=j)

Patched: 6/6 patches applied
Size: 5,962,292 -> 5,963,226 bytes (diff: +934)

教訓

# 教訓 詳細
1 minified JSの短縮変数名はバージョンごとに変わる モジュールスコープの変数(F, j, k...)はビルドのたびに再割り当てされる
2 定数名・メソッド名は安定 a.BUTTON_*, this.#we, this.waitForToolApproval 等はminify対象外
3 パターンマッチは正規表現で柔軟に 固定文字列マッチは1バージョンで壊れる。変動部分は正規表現でキャプチャすべき
4 PATCH SKIPは即座に調査 5/6適用でも「動くかも」と放置すると、肝心のフラグ設定が欠落して全体が機能しない

バージョン対応状況(更新)

バージョン PATCH 1-7 備考
v1.63.0 ✅ 全OK 初版対応
v1.64.0 ✅ 全OK
v1.65.0 ✅ 全OK
v1.66.0 ✅ 全OK PATCH 4 を正規表現対応に修正して解決

環境情報(更新)

  • IntelliJ IDEA 2026.1
  • Amazon Q for JetBrains プラグイン v1.66.0
  • LSPサーバー: aws-lsp-codewhisperer.js (5,962,292 bytes)
  • OS: Windows 11
  • パッチスクリプト: sonshi_patch_v2.py(正規表現対応版)

まとめ

プラグイン更新のたびにパッチが壊れるリスクは本手法の宿命。
今回の修正で「変数名の変更」という最も頻繁に起こるminify差異に対して耐性を獲得した。

ただし、コード構造自体が変わった場合(三項演算子→if文への書き換え等)は依然として手動調査が必要。
check-export-patch.py による定期チェックで早期検出する運用は引き続き有効。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?