From bb23a65c7fbb8f595c9e6481a738763b442221d1 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sat, 8 Aug 2026 02:53:18 +0000 Subject: [PATCH 01/11] =?UTF-8?q?chore:=20feature/inventory-kiro-delivery?= =?UTF-8?q?=20=E3=81=AE=20Draft=20PR=20=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From b2108002dbbce4e23fcf74bcfdc417c328d43b2f Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sat, 8 Aug 2026 04:20:01 +0000 Subject: [PATCH 02/11] =?UTF-8?q?Fix:=20Kiro=20=E3=81=AE=E5=B0=8E=E5=85=A5?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=E3=82=92=E4=BF=AE=E6=AD=A3=E3=81=97=E3=82=A8?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=82=A7=E3=83=B3=E3=83=88=E3=82=92=E6=9C=89?= =?UTF-8?q?=E5=8A=B9=E5=8C=96=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit install.sh が生成していた .kiro/agents/default.json は Kiro の既定エージェント にならず、組み込みの kiro_default が使われ続けていた。結果として起動時フック、 終了通知フック、外部 AI 連携設定、resources の明示読み込みがすべて無効だった。 - エージェント名を ndf にし、完了メッセージを kiro-cli chat --agent ndf に修正 - --set-default オプトインを追加。現在の既定を表示し確認を取ってから切り替える - resources から skill://.kiro/skills/**/SKILL.md を削除(組み込みと二重登録) - 常時指示を .kiro/steering/ndf-policies.md へ移し、resources から file://.kiro/skills/ndf-policies/SKILL.md を削除 - --scope workspace|global(既定 workspace)を追加 - 既存の .kiro/agents/default.json を検出したらバックアップし移行手順を案内 - README に allowed-tools が事前承認にならないこと(kirodotdev/Kiro#6055)と kiro-cli 2.16.1 での実機検証結果・占有率の実測値を記録 - runtime smoke に assert-kiro-agent.sh を追加。agent list への ndf の出現、 --set-default による既定の切り替え、文脈ファイルの合計量を検査する Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01AGejnYyYFuSkQjBhW2KQNy --- AGENTS.md | 2 +- KIRO.md | 6 +- README.md | 6 +- docs/ndf-plugin-reference.md | 2 +- docs/specifications/ndf-knowledge-and-kiro.md | 11 +- .../runtime-plugin-container-smoke.md | 1 + .../runtime-plugin-distribution.md | 4 +- plugins/ndf-kiro/README.md | 108 ++++++++++- ...efault.json.template => ndf.json.template} | 6 +- plugins/ndf-kiro/install.sh | 171 +++++++++++++++--- tests/runtime-smoke/adapters/kiro.sh | 4 + .../assertions/assert-hook-fixtures.sh | 6 +- .../assertions/assert-kiro-agent.sh | 106 +++++++++++ .../assertions/assert-plugin-files.sh | 5 +- 14 files changed, 394 insertions(+), 44 deletions(-) rename plugins/ndf-kiro/agents/{default.json.template => ndf.json.template} (76%) create mode 100755 tests/runtime-smoke/assertions/assert-kiro-agent.sh diff --git a/AGENTS.md b/AGENTS.md index a4f1b0cd..7543f2af 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -77,7 +77,7 @@ ai-plugins/ - 共通編集元は `plugins/ndf-shared/` - Claude Code版は 8個の専門サブエージェント、公開Skills、SessionStart/Stopフックを提供 - Codex版は Codex向け公開Skillsと任意Slack通知hookを提供 -- Kiro版は installer で `.kiro/skills/` と `.kiro/agents/default.json` を生成 +- Kiro版は installer で `.kiro/skills/`、`.kiro/steering/ndf-policies.md`、`.kiro/agents/ndf.json` を生成 - 外部AI委譲は `/ndf:codex` skill と `corder` エージェント経由で Codex CLI を呼び出し(v4.0.0 で Codex MCP サーバは廃止) 詳細は各 runtime README と `docs/ndf-plugin-reference.md` を参照。 diff --git a/KIRO.md b/KIRO.md index 4b6caba8..1a5459f8 100644 --- a/KIRO.md +++ b/KIRO.md @@ -27,7 +27,7 @@ bash plugins/ndf-kiro/install.sh --with-slack bash plugins/ndf-kiro/install.sh --with-slack --with-codex ``` -インストーラーは `plugins/ndf-kiro/skills/` から `.kiro/skills/` への symlink と `.kiro/agents/default.json` を生成します。`plugins/ndf-kiro/skills/` は `plugins/ndf-shared/manifests/kiro-skills.txt` から build された生成物です。 +インストーラーは `plugins/ndf-kiro/skills/` から `.kiro/skills/` への symlink、`.kiro/steering/ndf-policies.md`、`.kiro/agents/ndf.json` を生成します。`plugins/ndf-kiro/skills/` は `plugins/ndf-shared/manifests/kiro-skills.txt` から build された生成物です。 ### Slack通知の設定(オプション) @@ -66,7 +66,7 @@ ls -la plugins/ndf-kiro/ code search_symbols "ndf" # 特定のファイル内のシンボル一覧 -code get_document_symbols plugins/ndf-kiro/agents/default.json.template +code get_document_symbols plugins/ndf-kiro/agents/ndf.json.template ``` **パターン検索**: @@ -82,7 +82,7 @@ grep "MCP" --include="*.md" ``` # ファイル全体を読む -fs_read plugins/ndf-kiro/agents/default.json.template +fs_read plugins/ndf-kiro/agents/ndf.json.template # 特定の行範囲を読む fs_read plugins/ndf-kiro/README.md --start_line=1 --end_line=50 diff --git a/README.md b/README.md index ad8381b4..02b96a08 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ bash plugins/ndf-kiro/install.sh --with-slack bash plugins/ndf-kiro/install.sh --with-slack --with-codex ``` -インストーラーは `plugins/ndf-kiro/skills/` から `.kiro/skills/` への symlink と `.kiro/agents/default.json` を生成します。 +インストーラーは `plugins/ndf-kiro/skills/` から `.kiro/skills/` への symlink、`.kiro/steering/ndf-policies.md`、`.kiro/agents/ndf.json` を生成します。 #### 3. Slack通知の設定(オプション) @@ -91,9 +91,11 @@ SLACK_USER_MENTION=<@U0123456789> #### 4. 起動 ```bash -kiro-cli chat +kiro-cli chat --agent ndf ``` +既定エージェントとして使いたい場合は `bash plugins/ndf-kiro/install.sh --set-default` を実行します。 + 詳細は [KIRO.md](./KIRO.md) を参照。 ### 利用可能なプラグイン diff --git a/docs/ndf-plugin-reference.md b/docs/ndf-plugin-reference.md index 37d1ccac..1e80885f 100644 --- a/docs/ndf-plugin-reference.md +++ b/docs/ndf-plugin-reference.md @@ -34,7 +34,7 @@ plugins/ │ └── scripts/ └── ndf-kiro/ ├── install.sh - ├── agents/default.json.template + ├── agents/ndf.json.template ├── prompts/ ├── skills/ └── scripts/ diff --git a/docs/specifications/ndf-knowledge-and-kiro.md b/docs/specifications/ndf-knowledge-and-kiro.md index 4971ff84..2fa1bc87 100644 --- a/docs/specifications/ndf-knowledge-and-kiro.md +++ b/docs/specifications/ndf-knowledge-and-kiro.md @@ -27,9 +27,9 @@ AI エージェント向けの知識は以下の層で管理する。 ## Kiro CLI 対応 -Kiro CLI 用設定は `.kiro/agents/default.json` で管理する。agent 設定は `AGENTS.md` と `README.md` を `file://` resource として読み込み、`.kiro/skills/**/SKILL.md` を `skill://` resource として参照する。 +Kiro CLI 用設定は `.kiro/agents/ndf.json` で管理する。agent 設定は `AGENTS.md` と `README.md` を `file://` resource として読み込む。`.kiro/skills/**/SKILL.md` の `skill://` 指定は組み込み agent の読み込み対象と重複するため持たない。常時適用したい指示は agent 選択に依存しない `.kiro/steering/ndf-policies.md` へ置く。 -Kiro CLI では `plugins/ndf-kiro/install.sh` が `plugins/ndf-kiro/skills/` から `.kiro/skills/` への symlink と `.kiro/agents/default.json` を生成する。`agentSpawn` hook は初期化時の案内に使い、`--with-slack` 指定時のみ `stop` hook 相当の Slack 通知を有効化する。Kiro の stop hook payload に `assistant_response` が含まれる場合、`plugins/ndf-kiro/scripts/slack-notify.js` は transcript よりも `assistant_response` を優先して要約に使う。 +Kiro CLI では `plugins/ndf-kiro/install.sh` が `plugins/ndf-kiro/skills/` から `.kiro/skills/` への symlink、`.kiro/steering/ndf-policies.md`、`.kiro/agents/ndf.json` を生成する。`--scope global` を指定した場合の生成先は `~/.kiro/` 配下になる。生成した agent は既定にならないため、`--set-default` を指定したときだけ `kiro-cli agent set-default ndf` を実行する。`agentSpawn` hook は初期化時の案内に使い、`--with-slack` 指定時のみ `stop` hook 相当の Slack 通知を有効化する。Kiro の stop hook payload に `assistant_response` が含まれる場合、`plugins/ndf-kiro/scripts/slack-notify.js` は transcript よりも `assistant_response` を優先して要約に使う。 Codex 連携は MCP サーバではなく `/ndf:codex` skill と `corder` エージェント経由の Codex CLI 直接実行を標準とする。Kiro 用 `--with-codex` は Kiro セッションから Codex CLI を扱う場合の補助設定である。 @@ -38,14 +38,15 @@ Codex 連携は MCP サーバではなく `/ndf:codex` skill と `corder` エー | 設定 | 用途 | |---|---| | `cleanupPeriodDays` | Claude Code transcript 保持期間。NDF hook が 90 日以上に保つ | -| `.kiro/agents/default.json` | Kiro CLI 用 agent 設定 | +| `.kiro/agents/ndf.json` | Kiro CLI 用 agent 設定 | +| `.kiro/steering/ndf-policies.md` | agent 選択に依存しない常時指示 | | `.kiro/skills/` | Kiro CLI 用 Skill symlink 配置 | ## 外部連携 | 連携 | 仕様 | |---|---| -| Kiro CLI | `.kiro/agents/default.json` と `.kiro/skills/` で Skill / hook / MCP 設定を提供 | +| Kiro CLI | `.kiro/agents/ndf.json`、`.kiro/steering/`、`.kiro/skills/` で Skill / hook / MCP 設定を提供 | | Serena MCP | `mcp-serena` プラグインとして分離提供 | | Codex CLI | `/ndf:codex` skill と `corder` エージェントから直接実行 | | Slack | Claude Code / Kiro / Codex の終了通知に使用 | @@ -54,7 +55,7 @@ Codex 連携は MCP サーバではなく `/ndf:codex` skill と `corder` エー | 領域 | 確認内容 | |---|---| -| Kiro CLI | `.kiro/agents/default.json` が resources / hooks / mcpServers を持つこと | +| Kiro CLI | `.kiro/agents/ndf.json` が resources / hooks / mcpServers を持ち、`kiro-cli agent list` に `ndf` が現れること | | ドキュメント | `AGENTS.md` / `CLAUDE.md` / `KIRO.md` / `docs/` の役割が重複しすぎていないこと | ## 関連リンク diff --git a/docs/specifications/runtime-plugin-container-smoke.md b/docs/specifications/runtime-plugin-container-smoke.md index 982a5564..bf5e6242 100644 --- a/docs/specifications/runtime-plugin-container-smoke.md +++ b/docs/specifications/runtime-plugin-container-smoke.md @@ -98,6 +98,7 @@ Kiro adapter は以下を実行する。 | `assert-plugin-files.sh` | runtime 側の install 先に plugin manifest、Skill、hook、agent / prompt / MCP runtime link が存在することを確認する | | `assert-mcp-config.sh` | `mcp-bigquery` config に `BIGQUERY_PROJECT`、`BIGQUERY_LOCATION`、`BIGQUERY_DATASET`、`BIGQUERY_KEY_FILE` の placeholder があり、secret 実値や `/tmp/runtime-secrets` が混入していないことを確認する | | `assert-hook-fixtures.sh` | fixture payload で Claude / Codex / Kiro の hook script を非認証実行できることを確認する | +| `assert-kiro-agent.sh` | Kiro の `ndf` エージェント定義と steering を検査する。`kiro-cli` が使える場合は `agent list` に `ndf` が現れること、`--set-default` で既定が切り替わることも確認し、確認後に既定を元へ戻す。文脈ファイルの合計文字数が予算内であることも検査する | | `assert-authenticated-smoke.sh` | `--with-secrets` が有効な場合に、利用可能な runtime / BigQuery secret で認証付き smoke を実行する | | `assert-no-host-contamination.sh` | `HOME` と project が `/tmp/runtime-*` 配下であり、repo root や host-like credential path が汚染されていないことを確認する | diff --git a/docs/specifications/runtime-plugin-distribution.md b/docs/specifications/runtime-plugin-distribution.md index 5401a8d1..df1aa7e0 100644 --- a/docs/specifications/runtime-plugin-distribution.md +++ b/docs/specifications/runtime-plugin-distribution.md @@ -31,7 +31,7 @@ NDF plugin の plugin name は全 runtime で `ndf` を維持する。旧 `plugi |---|---|---| | Claude Code | `plugins/ndf-claude/.claude-plugin/plugin.json` | Claude Code agents、hooks、skills、scripts | | Codex | `plugins/ndf-codex/.codex-plugin/plugin.json` | Codex 用 skills、hooks、scripts | -| Kiro CLI | `plugins/ndf-kiro/install.sh` | `.kiro/agents/default.json`、`.kiro/skills/` symlink、prompts、任意 hook | +| Kiro CLI | `plugins/ndf-kiro/install.sh` | `.kiro/agents/ndf.json`、`.kiro/steering/ndf-policies.md`、`.kiro/skills/` symlink、prompts、任意 hook | `plugins/ndf-shared/manifests/{claude,codex,kiro}-skills.txt` は runtime ごとの配布 Skill 一覧を定義する。`scripts/build-runtime-plugins.sh` はこの manifest を読み、`plugins/ndf-shared/skills` から各 runtime の `skills/` へ同期する。 @@ -60,6 +60,8 @@ Claude 用配布物は `.claude-plugin/plugin.json` と `.mcp.json` を持つ。 Kiro MCP installer は対象 project の `.mcp.json` へ MCP server 設定を merge する。hooks や skills を持つ MCP plugin では、必要に応じて `.kiro/agents/default.json` や `.kiro/skills/` も更新する。 +NDF installer が生成する agent は `.kiro/agents/ndf.json` であり、MCP installer が更新する `.kiro/agents/default.json` とは別である。NDF と Kiro MCP plugin を併用する場合、MCP server 設定は `ndf.json` へ写す必要がある(`plugins/ndf-kiro/README.md`「旧バージョンからの移行」)。MCP installer 側の出力先統一は未対応。 + ## Marketplace Claude Code marketplace は `.claude-plugin/marketplace.json` で管理する。各 entry の `source` は Claude 用配布ディレクトリを指す。 diff --git a/plugins/ndf-kiro/README.md b/plugins/ndf-kiro/README.md index 89ba28b3..321fbc05 100644 --- a/plugins/ndf-kiro/README.md +++ b/plugins/ndf-kiro/README.md @@ -7,7 +7,7 @@ Kiro CLI 向けの NDF 配布物です。`plugins/ndf-shared` から生成され リポジトリ root で実行します。 ```bash -# 基本(Skills + agentSpawn hook) +# 基本(Skills + steering + agentSpawn hook) bash plugins/ndf-kiro/install.sh # Slack通知も有効化 @@ -17,6 +17,12 @@ bash plugins/ndf-kiro/install.sh --with-slack bash plugins/ndf-kiro/install.sh --with-slack --with-codex ``` +installer は `.kiro/agents/ndf.json` を生成します。導入後の起動方法は次のとおりです。 + +```bash +kiro-cli chat --agent ndf +``` + 動作確認だけを行う場合: ```bash @@ -25,6 +31,106 @@ bash plugins/ndf-kiro/install.sh --dry-run installer は `.claude-plugin/plugin.json` を読みません。公開 Skill は build 済みの `plugins/ndf-kiro/skills/` を source として `.kiro/skills/` へ symlink します。 +### 主なオプション + +| オプション | 内容 | +| --- | --- | +| `--project PATH` | 現在のディレクトリではなく PATH へ導入する(`--scope workspace` のみ有効) | +| `--scope workspace\|global` | `workspace`(既定)はプロジェクトの `.kiro/`、`global` は `~/.kiro/` へ導入する | +| `--set-default` | `kiro-cli` の既定エージェントを `ndf` に切り替える(オプトイン) | +| `-y`, `--yes` | `--set-default` の確認プロンプトを省略する | +| `--with-slack` | stop フックに Slack 通知を追加する | +| `--with-codex` | Codex CLI 直接実行用プロンプトを追加する | +| `--dry-run` | 書き込みを行わず実行内容を表示する | + +### 既定エージェントの切り替え + +Kiro の既定エージェントは組み込みの `kiro_default` です。`kiro-cli chat` を素で起動する限り、NDF のフック・外部 AI 連携・`resources` は読み込まれません。既定として使いたい場合は `--set-default` を付けます。 + +```bash +bash plugins/ndf-kiro/install.sh --set-default +``` + +利用者の既存設定を無断で奪わないよう、`--set-default` は明示指定したときだけ動作します。実行前に現在の既定エージェントを表示し、対話端末では確認を取ります。元に戻す場合は次のとおりです。 + +```bash +kiro-cli agent set-default kiro_default +``` + +`--scope workspace`(既定)で導入したエージェントはそのプロジェクトでしか見つかりません。既定を `ndf` にしたまま別のディレクトリで `kiro-cli chat` を起動すると `user defined default ndf not found. Falling back to in-memory default` になります。どこでも既定として使いたい場合は `--scope global` と併用してください。 + +### 導入スコープ + +| スコープ | Skills | 常時指示 | エージェント定義 | +| --- | --- | --- | --- | +| `workspace`(既定) | `.kiro/skills/` | `.kiro/steering/ndf-policies.md` | `.kiro/agents/ndf.json` | +| `global` | `~/.kiro/skills/` | `~/.kiro/steering/ndf-policies.md` | `~/.kiro/agents/ndf.json` | + +常時適用したい指示は steering へ置きます。steering はエージェント選択に依存せず読み込まれるため、既定エージェントを書き換えない運用でも効きます。`.kiro/steering/ndf-policies.md` は `plugins/ndf-shared/skills/ndf-policies/SKILL.md` から生成されるため、直接編集しないでください。 + +### 旧バージョンからの移行 + +v4 系の installer は `.kiro/agents/default.json` を生成していました。この設定は Kiro の既定エージェントにならず、フックも `resources` も無効のままでした。エージェント名を `ndf` に変えたため、再インストールが必要です。 + +```bash +# 1. 再インストール(旧 default.json は自動でバックアップされます) +bash plugins/ndf-kiro/install.sh --with-slack + +# 2. 旧設定に独自の追記があれば .kiro/agents/ndf.json へ写す +# 差分の確認例 +diff .kiro/agents/default.json.bak .kiro/agents/ndf.json + +# 3. 旧設定を削除する +rm .kiro/agents/default.json .kiro/agents/default.json.bak + +# 4. 必要なら既定エージェントを切り替える +bash plugins/ndf-kiro/install.sh --set-default +``` + +Kiro 用 MCP プラグインの installer(`plugins/mcp/kiro/*/install.sh`)は `.kiro/agents/default.json` を更新します。MCP を併用する場合は、`mcpServers` を `.kiro/agents/ndf.json` へ写してください。 + +## Kiro CLI の制限 + +### `allowed-tools` は事前承認にならない + +Skill frontmatter の `allowed-tools` は、プロジェクト配置(`.kiro/skills/`)では事前承認として機能しません([kirodotdev/Kiro#6055](https://github.com/kirodotdev/Kiro/issues/6055))。`allowed-tools: execute_bash` を持つ Skill でも `Command execute_bash is rejected because it matches one or more rules on the denied list` になります。 + +Kiro では、Skill の実行時にツール利用の確認が入る前提で操作してください。NDF の Skill 本文は「無確認で実行される」前提を持ちません。 + +### プラグイン機構がない + +Kiro CLI には Skill・フック・外部連携・常時指示をまとめて配布する仕組みがありません([kirodotdev/Kiro#8578](https://github.com/kirodotdev/Kiro/issues/8578))。Kiro IDE の Powers は CLI では使えないため、`install.sh` による導入を継続します。 + +## 実機検証の記録 + +kiro-cli **2.16.1** / 検証日 **2026-08-07**(ランタイム規約の調査)、**2026-08-08**(本変更の導入方式の検証)。 + +`docs/specifications/ndf-skill-inventory.md`(Skill 棚卸台帳)は本ブランチ時点で未作成のため、検証結果はここに記録します。台帳への転記は台帳作成後に行います。 + +| 検証項目 | 結果 | 根拠 | +| --- | --- | --- | +| シンボリックリンク経由の Skill を認識するか | 認識する([#6401](https://github.com/kirodotdev/Kiro/issues/6401) は 2.16.1 で再現せず) | 実体ディレクトリとリンクを並べ、両方が一覧・読み取りとも成功 | +| 起動時に Skill 本文を読み込むか | 読み込まない([#6680](https://github.com/kirodotdev/Kiro/issues/6680) は 2.16.1 で再現せず) | 「ファイルを読まずに本文中のマーカーを出力せよ」に対し「本文なし」と応答 | +| `description` 一致で自動発動するか | 発動する([#5867](https://github.com/kirodotdev/Kiro/issues/5867) は 2.16.1 で再現せず) | `skill://` 指定を削除した状態で、該当依頼に対し `docker-container-access/SKILL.md` を自ら読みに行った | +| プロジェクト配置で `allowed-tools` が事前承認になるか | **ならない**([#6055](https://github.com/kirodotdev/Kiro/issues/6055)) | `allowed-tools: execute_bash` を持つ検査用 Skill が denied list で拒否された | +| `install.sh` 後に `kiro-cli agent list` へ現れるか | 現れる | `ndf Workspace NDF統合開発エージェント(Kiro CLI用)` | +| `--agent ndf` で agentSpawn フックが動くか | 動く | `[NDF] CLAUDE.ndf.md が検出されました…` が文脈へ注入された。`kiro_default` では注入されない | +| `--set-default` で既定が切り替わるか | 切り替わる | `agent list` の `*` が `ndf` へ移り、素の `kiro-cli chat` でも agentSpawn フックが動いた | +| `--scope global` で `~/.kiro/` へ配置されるか | 配置される | `~/.kiro/{skills,steering,prompts,agents}` が生成され、プロジェクト外でも `Global` として一覧に出た | +| steering がエージェント選択に依存せず読まれるか | 読まれる | `kiro_default` の `/context show` にも `.kiro/steering/**/*.md` の一致として現れた | + +コンテキスト占有率(Skill 23 個の配布物、`/context show` の `Context files total`): + +| 構成 | 一致ファイル数 | 占有率 | 文脈ファイルの合計文字数 | +| --- | --- | --- | --- | +| 変更前 `default` エージェント | 26(`ndf-policies/SKILL.md` が二重) | 0.2% | 112,598 | +| 変更後 `ndf` エージェント | 26(重複なし、steering が 1 件増) | 0.2% | 112,621 | +| 参考: 組み込み `kiro_default` | 25 | 0.2% | - | + +`resources` の二重登録は解消しましたが、代わりに steering ファイルが 1 件増えるため、総量はほぼ変わりません(+23 文字は生成ヘッダ 2 行分)。`/context show` の表示は 0.1% 刻みのため、この差は表示上変化しません。 + +`--scope global` でプロジェクト側に Skill がない状態では 24 ファイル / 0.1% でした。 + ## 開発 Skill を変更する場合は `plugins/ndf-shared/skills/` を編集し、runtime plugin を再生成します。 diff --git a/plugins/ndf-kiro/agents/default.json.template b/plugins/ndf-kiro/agents/ndf.json.template similarity index 76% rename from plugins/ndf-kiro/agents/default.json.template rename to plugins/ndf-kiro/agents/ndf.json.template index 59bcc0ca..2707ccf4 100644 --- a/plugins/ndf-kiro/agents/default.json.template +++ b/plugins/ndf-kiro/agents/ndf.json.template @@ -1,14 +1,12 @@ { - "name": "default", + "name": "ndf", "description": "NDF統合開発エージェント(Kiro CLI用)", "tools": [ "*" ], "resources": [ "file://AGENTS.md", - "file://README.md", - "file://.kiro/skills/ndf-policies/SKILL.md", - "skill://.kiro/skills/**/SKILL.md" + "file://README.md" ], "hooks": { "agentSpawn": [ diff --git a/plugins/ndf-kiro/install.sh b/plugins/ndf-kiro/install.sh index 8c8a3823..6b99ee1f 100755 --- a/plugins/ndf-kiro/install.sh +++ b/plugins/ndf-kiro/install.sh @@ -1,20 +1,24 @@ #!/usr/bin/env bash # NDF Plugin Installer for Kiro CLI -# Usage: bash plugins/ndf-kiro/install.sh [--project PATH] [--with-slack] [--with-codex] [--dry-run] +# Usage: bash plugins/ndf-kiro/install.sh [--project PATH] [--scope workspace|global] +# [--set-default] [--yes] +# [--with-slack] [--with-codex] [--dry-run] set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -PROJECT_ROOT="$(pwd)" PLUGIN_DIR="$SCRIPT_DIR" -KIRO_DIR="$PROJECT_ROOT/.kiro" -SKILLS_DIR="$KIRO_DIR/skills" -PROMPTS_DIR="$KIRO_DIR/prompts" -AGENT_FILE="$KIRO_DIR/agents/default.json" -TEMPLATE_FILE="$PLUGIN_DIR/agents/default.json.template" +AGENT_NAME="ndf" +TEMPLATE_FILE="$PLUGIN_DIR/agents/$AGENT_NAME.json.template" PLUGIN_SKILLS_DIR="$PLUGIN_DIR/skills" PLUGIN_PROMPTS_DIR="$PLUGIN_DIR/prompts" +POLICY_SKILL_FILE="$PLUGIN_SKILLS_DIR/ndf-policies/SKILL.md" # Parse options +PROJECT_ROOT="$(pwd)" +PROJECT_GIVEN=false +SCOPE="workspace" +SET_DEFAULT=false +ASSUME_YES=false WITH_SLACK=false WITH_CODEX=false DRY_RUN=false @@ -23,12 +27,16 @@ while [ "$#" -gt 0 ]; do --project) [ "$#" -ge 2 ] || { echo "ERROR: --project requires a path" >&2; exit 2; } PROJECT_ROOT="$(cd "$2" && pwd)" - KIRO_DIR="$PROJECT_ROOT/.kiro" - SKILLS_DIR="$KIRO_DIR/skills" - PROMPTS_DIR="$KIRO_DIR/prompts" - AGENT_FILE="$KIRO_DIR/agents/default.json" + PROJECT_GIVEN=true shift ;; + --scope) + [ "$#" -ge 2 ] || { echo "ERROR: --scope requires workspace or global" >&2; exit 2; } + SCOPE="$2" + shift + ;; + --set-default) SET_DEFAULT=true ;; + --yes|-y) ASSUME_YES=true ;; --with-slack) WITH_SLACK=true ;; --with-codex) WITH_CODEX=true ;; --dry-run) DRY_RUN=true ;; @@ -36,11 +44,14 @@ while [ "$#" -gt 0 ]; do echo "Usage: bash plugins/ndf-kiro/install.sh [OPTIONS]" echo "" echo "Options:" - echo " --project PATH install into PATH instead of current directory" - echo " --with-slack stopフックにSlack通知を追加" - echo " --with-codex Codex CLI直接実行用プロンプトを追加" - echo " --dry-run 書き込みを行わず実行内容を表示" - echo " -h, --help このヘルプを表示" + echo " --project PATH install into PATH instead of current directory (--scope workspace のみ)" + echo " --scope SCOPE workspace(既定, プロジェクトの .kiro/)または global(~/.kiro/)" + echo " --set-default kiro-cli の既定エージェントを ndf に切り替える(オプトイン)" + echo " -y, --yes --set-default の確認プロンプトを省略する" + echo " --with-slack stopフックにSlack通知を追加" + echo " --with-codex Codex CLI直接実行用プロンプトを追加" + echo " --dry-run 書き込みを行わず実行内容を表示" + echo " -h, --help このヘルプを表示" exit 0 ;; *) @@ -51,7 +62,31 @@ while [ "$#" -gt 0 ]; do shift done +case "$SCOPE" in + workspace) + KIRO_DIR="$PROJECT_ROOT/.kiro" + ;; + global) + [ -n "${HOME:-}" ] || { echo "ERROR: --scope global には HOME が必要です" >&2; exit 2; } + KIRO_DIR="$HOME/.kiro" + if [ "$PROJECT_GIVEN" = true ]; then + echo "WARN: --scope global では --project は使用されません" >&2 + fi + ;; + *) + echo "ERROR: invalid --scope: $SCOPE (workspace|global)" >&2 + exit 2 + ;; +esac + +SKILLS_DIR="$KIRO_DIR/skills" +PROMPTS_DIR="$KIRO_DIR/prompts" +STEERING_FILE="$KIRO_DIR/steering/ndf-policies.md" +AGENT_FILE="$KIRO_DIR/agents/$AGENT_NAME.json" +LEGACY_AGENT_FILE="$KIRO_DIR/agents/default.json" + echo "=== NDF Plugin Installer for Kiro CLI ===" +echo " スコープ: $SCOPE ($KIRO_DIR)" if [ ! -d "$PLUGIN_SKILLS_DIR" ]; then echo "ERROR: $PLUGIN_SKILLS_DIR が見つかりません。先に scripts/build-runtime-plugins.sh を実行してください。" >&2 @@ -61,8 +96,12 @@ if [ ! -f "$TEMPLATE_FILE" ]; then echo "ERROR: $TEMPLATE_FILE が見つかりません" >&2 exit 1 fi +if [ ! -f "$POLICY_SKILL_FILE" ]; then + echo "ERROR: $POLICY_SKILL_FILE が見つかりません" >&2 + exit 1 +fi -# --- Step 1: Create symlinks in .kiro/skills/ --- +# --- Step 1: Create symlinks in /skills/ --- echo "Skills シンボリックリンクを作成中..." SKILL_COUNT=0 if [ "$DRY_RUN" = false ]; then @@ -95,7 +134,7 @@ while IFS= read -r src_dir; do SKILL_COUNT=$((SKILL_COUNT + 1)) done < <(find "$PLUGIN_SKILLS_DIR" -mindepth 1 -maxdepth 1 -type d | sort) -# --- Step 2: Create prompts in .kiro/prompts/ for workflow skills --- +# --- Step 2: Create prompts in /prompts/ for workflow skills --- echo "ワークフロープロンプトを作成中..." if [ "$DRY_RUN" = false ]; then mkdir -p "$PROMPTS_DIR" @@ -125,11 +164,61 @@ if [ "$DRY_RUN" = true ]; then echo "" echo "DRY RUN: 書き込みは行いませんでした" echo " エージェント設定: $AGENT_FILE" + echo " 常時指示: $STEERING_FILE" echo " Skills数: $SKILL_COUNT" exit 0 fi -# --- Step 3: Generate agent config --- +# --- Step 3: Generate steering (always-on instructions) --- +# steering はエージェント選択に依存せず読み込まれるため、常時指示はここへ置く。 +mkdir -p "$(dirname "$STEERING_FILE")" +python3 - "$POLICY_SKILL_FILE" "$STEERING_FILE" <<'PY' +import sys +from pathlib import Path + +source, dest = (Path(p) for p in sys.argv[1:3]) +text = source.read_text(encoding="utf-8") +if text.startswith("---\n"): + end = text.find("\n---\n", 3) + if end != -1: + text = text[end + len("\n---\n"):] +body = text.strip("\n") +header = ( + "\n" + "\n" +) +dest.write_text(f"{header}\n{body}\n", encoding="utf-8") +PY +echo "常時指示を生成: $STEERING_FILE" + +# --- Step 4: Migrate legacy default agent --- +if [ -f "$LEGACY_AGENT_FILE" ]; then + cp "$LEGACY_AGENT_FILE" "${LEGACY_AGENT_FILE}.bak" + echo "" + echo "WARN: 旧エージェント設定 $LEGACY_AGENT_FILE を検出しました。" + echo " バックアップ: ${LEGACY_AGENT_FILE}.bak" + if python3 -c ' +import json, sys +try: + config = json.load(open(sys.argv[1], encoding="utf-8")) +except Exception: + sys.exit(1) +sys.exit(0 if config.get("name") == "default" and "NDF" in (config.get("description") or "") else 1) +' "$LEGACY_AGENT_FILE"; then + echo " これは旧版 NDF installer の生成物です。移行手順:" + echo " 1. 独自に追記した設定があればバックアップから $AGENT_FILE へ写す" + echo " 2. rm $LEGACY_AGENT_FILE ${LEGACY_AGENT_FILE}.bak" + else + echo " NDF 以外が管理している設定です。移行手順:" + echo " 1. 必要な mcpServers / hooks を $AGENT_FILE へ写す" + echo " 2. 不要になったら rm $LEGACY_AGENT_FILE ${LEGACY_AGENT_FILE}.bak" + echo " Kiro 用 MCP プラグインの installer は default.json を更新するため、" + echo " MCP を併用する場合は上記の写し替えが必要です。" + fi + echo "" +fi + +# --- Step 5: Generate agent config --- mkdir -p "$KIRO_DIR/agents" if [ -f "$AGENT_FILE" ]; then @@ -175,10 +264,50 @@ with open(agent_file, "w", encoding="utf-8") as f: f.write("\n") PY +# --- Step 6: Optionally switch the default agent --- +if [ "$SET_DEFAULT" = true ]; then + echo "" + if ! command -v kiro-cli >/dev/null 2>&1; then + echo "ERROR: kiro-cli が見つからないため既定エージェントを変更できません" >&2 + exit 1 + fi + esc="$(printf '\033')" + # kiro-cli 2.16.1 の agent list は一覧を標準エラー出力へ書く + current_default="$(kiro-cli agent list 2>&1 \ + | sed -e "s/${esc}\\[[0-9;]*m//g" \ + | awk '/^\*/ { print $2; exit }')" + echo "現在の既定エージェント: ${current_default:-不明}" + echo "変更後の既定エージェント: $AGENT_NAME" + proceed=true + if [ "$ASSUME_YES" = false ]; then + if [ -t 0 ]; then + printf '既定エージェントを %s に変更しますか? [y/N]: ' "$AGENT_NAME" + read -r answer + case "$answer" in + [yY]|[yY][eE][sS]) ;; + *) proceed=false ;; + esac + else + echo "確認入力を取得できないため、--set-default の指定を承認とみなして続行します" + fi + fi + if [ "$proceed" = true ]; then + kiro-cli agent set-default "$AGENT_NAME" + echo "既定エージェントを $AGENT_NAME に変更しました(元に戻す: kiro-cli agent set-default ${current_default:-kiro_default})" + else + echo "既定エージェントは変更しませんでした" + fi +fi + echo "" echo "=== インストール完了 ===" echo " エージェント設定: $AGENT_FILE" -echo " Skills数: $SKILL_COUNT (シンボリックリンク: .kiro/skills/)" +echo " 常時指示: $STEERING_FILE" +echo " Skills数: $SKILL_COUNT (シンボリックリンク: $SKILLS_DIR)" echo "" echo "Kiro CLIを起動して動作確認してください:" -echo " kiro-cli chat" +echo " kiro-cli chat --agent $AGENT_NAME" +if [ "$SET_DEFAULT" = false ]; then + echo "" + echo "既定エージェントとして起動したい場合は --set-default を付けて再実行してください。" +fi diff --git a/tests/runtime-smoke/adapters/kiro.sh b/tests/runtime-smoke/adapters/kiro.sh index 47b5f2b3..2e7f52d7 100755 --- a/tests/runtime-smoke/adapters/kiro.sh +++ b/tests/runtime-smoke/adapters/kiro.sh @@ -18,6 +18,10 @@ run_step "kiro install mcp-bigquery idempotent" bash "$REPO_ROOT/plugins/mcp/kir "$REPO_ROOT/tests/runtime-smoke/assertions/assert-plugin-files.sh" kiro "$REPO_ROOT/tests/runtime-smoke/assertions/assert-mcp-config.sh" kiro "$PROJECT_DIR/.mcp.json" "$REPO_ROOT/tests/runtime-smoke/assertions/assert-hook-fixtures.sh" kiro +"$REPO_ROOT/tests/runtime-smoke/assertions/assert-kiro-agent.sh" workspace + +run_step "kiro install ndf global" bash "$REPO_ROOT/plugins/ndf-kiro/install.sh" --scope global --with-slack +"$REPO_ROOT/tests/runtime-smoke/assertions/assert-kiro-agent.sh" global "$REPO_ROOT/tests/runtime-smoke/assertions/assert-authenticated-smoke.sh" kiro "$REPO_ROOT/tests/runtime-smoke/assertions/assert-no-host-contamination.sh" kiro write_junit kiro diff --git a/tests/runtime-smoke/assertions/assert-hook-fixtures.sh b/tests/runtime-smoke/assertions/assert-hook-fixtures.sh index 6e18ad74..0e3c075d 100755 --- a/tests/runtime-smoke/assertions/assert-hook-fixtures.sh +++ b/tests/runtime-smoke/assertions/assert-hook-fixtures.sh @@ -18,9 +18,9 @@ case "$runtime" in node "$REPO_ROOT/plugins/ndf-codex/scripts/codex-slack-notify.js" < "$REPO_ROOT/tests/runtime-smoke/fixtures/hook-stop.json" >/dev/null ;; kiro) - test -f "$PROJECT_DIR/.kiro/agents/default.json" - jq -e '.hooks.agentSpawn[0].command' "$PROJECT_DIR/.kiro/agents/default.json" >/dev/null - stop_command="$(jq -r '.hooks.stop[0].command // empty' "$PROJECT_DIR/.kiro/agents/default.json")" + test -f "$PROJECT_DIR/.kiro/agents/ndf.json" + jq -e '.hooks.agentSpawn[0].command' "$PROJECT_DIR/.kiro/agents/ndf.json" >/dev/null + stop_command="$(jq -r '.hooks.stop[0].command // empty' "$PROJECT_DIR/.kiro/agents/ndf.json")" test -n "$stop_command" stop_script="$(python3 - "$stop_command" <<'PY' import shlex diff --git a/tests/runtime-smoke/assertions/assert-kiro-agent.sh b/tests/runtime-smoke/assertions/assert-kiro-agent.sh new file mode 100755 index 00000000..f8da58b8 --- /dev/null +++ b/tests/runtime-smoke/assertions/assert-kiro-agent.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +# Kiro の ndf エージェントが「選択できる状態」で導入されたことを検査する。 +# 旧実装は .kiro/agents/default.json を生成していたが、Kiro の既定は組み込みの +# kiro_default であり、生成したエージェントは選択されないままだった。 +# +# Usage: assert-kiro-agent.sh [workspace|global] +set -euo pipefail + +scope="${1:-workspace}" +: "${REPO_ROOT:=/workspace/ai-plugins}" +: "${PROJECT_DIR:=/tmp/runtime-project}" +: "${ARTIFACT_DIR:=/tmp/runtime-artifacts}" +: "${HOME:=/tmp/runtime-home}" + +AGENT_NAME="ndf" +case "$scope" in + workspace) KIRO_DIR="$PROJECT_DIR/.kiro" ;; + global) KIRO_DIR="$HOME/.kiro" ;; + *) echo "unknown scope: $scope" >&2; exit 2 ;; +esac + +AGENT_FILE="$KIRO_DIR/agents/$AGENT_NAME.json" +STEERING_FILE="$KIRO_DIR/steering/ndf-policies.md" +LOG="$ARTIFACT_DIR/kiro-agent-$scope.log" + +mkdir -p "$ARTIFACT_DIR" +: > "$LOG" + +test -f "$AGENT_FILE" +test -s "$STEERING_FILE" +find -L "$KIRO_DIR/skills" -path '*/SKILL.md' -print | grep -q . + +# エージェント定義と、起動時に読み込まれる文脈量を検査する。 +# 上限は 2026-08-07 / kiro-cli 2.16.1 の実測 112,621 文字に対する余裕分。 +python3 - "$AGENT_FILE" "$KIRO_DIR" "$PROJECT_DIR" "$STEERING_FILE" 200000 >> "$LOG" <<'PY' +import json +import sys +from pathlib import Path + +agent_file, kiro_dir, project_dir, steering_file, budget = sys.argv[1:6] +budget = int(budget) +config = json.loads(Path(agent_file).read_text(encoding="utf-8")) + +if config.get("name") != "ndf": + raise SystemExit(f"agent name must be 'ndf': {config.get('name')!r}") +if not config.get("tools"): + raise SystemExit(f"agent config declares no tools: {agent_file}") + +resources = config.get("resources", []) +for entry in resources: + if entry.startswith("skill://"): + raise SystemExit(f"skill:// resource duplicates the built-in rule: {entry}") + if "ndf-policies" in entry: + raise SystemExit(f"ndf-policies must be delivered via steering, not resources: {entry}") +if len(resources) != len(set(resources)): + raise SystemExit(f"duplicated resources in {agent_file}") + +context_files = sorted(Path(kiro_dir).glob("skills/*/SKILL.md")) +project = Path(project_dir) +context_files += [p for p in (project / "AGENTS.md", project / "README.md") if p.is_file()] +context_files.append(Path(steering_file)) +total = sum(len(p.read_text(encoding="utf-8")) for p in context_files) +print(f"context files: {len(context_files)} / chars: {total} / budget: {budget}") +if total > budget: + raise SystemExit(f"context files exceed the budget: {total} > {budget}") +PY + +[ "$scope" = workspace ] || exit 0 + +if ! command -v kiro-cli >/dev/null 2>&1; then + echo "kiro-cli agent checks skipped: kiro-cli is not available" >> "$LOG" + exit 0 +fi + +esc="$(printf '\033')" +agent_list() { + # kiro-cli 2.16.1 の agent list は一覧を標準エラー出力へ書く + (cd "$PROJECT_DIR" && kiro-cli agent list 2>&1) | sed -e "s/${esc}\\[[0-9;]*m//g" +} +current_default() { + agent_list | awk '/^\*/ { print $2; exit }' +} + +if ! agent_list > "$ARTIFACT_DIR/kiro-agent-list.txt"; then + echo "kiro-cli agent checks skipped: agent list failed" >> "$LOG" + exit 0 +fi +if ! awk '{ print $1, $2 }' "$ARTIFACT_DIR/kiro-agent-list.txt" | grep -qw "$AGENT_NAME"; then + echo "agent list does not contain $AGENT_NAME" >&2 + cat "$ARTIFACT_DIR/kiro-agent-list.txt" >&2 + exit 1 +fi + +before_default="$(current_default)" +echo "default agent before: ${before_default:-unknown}" >> "$LOG" +bash "$REPO_ROOT/plugins/ndf-kiro/install.sh" --project "$PROJECT_DIR" --with-slack --set-default --yes >> "$LOG" 2>&1 +after_default="$(current_default)" +echo "default agent after: ${after_default:-unknown}" >> "$LOG" +if [ "$after_default" != "$AGENT_NAME" ]; then + echo "--set-default did not switch the default agent: ${after_default:-unknown}" >&2 + exit 1 +fi +if [ -n "$before_default" ] && [ "$before_default" != "$AGENT_NAME" ]; then + kiro-cli agent set-default "$before_default" >> "$LOG" 2>&1 + echo "default agent restored: $before_default" >> "$LOG" +fi diff --git a/tests/runtime-smoke/assertions/assert-plugin-files.sh b/tests/runtime-smoke/assertions/assert-plugin-files.sh index b205ad7a..96b6b367 100755 --- a/tests/runtime-smoke/assertions/assert-plugin-files.sh +++ b/tests/runtime-smoke/assertions/assert-plugin-files.sh @@ -19,7 +19,7 @@ case "$runtime" in find "$HOME" -path '*/hooks/hooks.json' -print | grep -q . ;; kiro) - test -f "$PROJECT_DIR/.kiro/agents/default.json" + test -f "$PROJECT_DIR/.kiro/agents/ndf.json" # tools が未宣言だと Kiro CLI はツールなしのエージェントとして読み込み、 # skill が SKILL.md を読むことも git / gh を実行することもできなくなる。 python3 -c ' @@ -28,9 +28,10 @@ config = json.load(open(sys.argv[1])) tools = config.get("tools") if not tools: sys.exit("agent config declares no tools: " + sys.argv[1]) -' "$PROJECT_DIR/.kiro/agents/default.json" +' "$PROJECT_DIR/.kiro/agents/ndf.json" find -L "$PROJECT_DIR/.kiro/skills" -path '*/SKILL.md' -print | grep -q . test -f "$PROJECT_DIR/.kiro/prompts/pr.md" + test -s "$PROJECT_DIR/.kiro/steering/ndf-policies.md" test -L "$PROJECT_DIR/.kiro/mcp_runtime/mcp-bigquery" ;; *) echo "unknown runtime: $runtime" >&2; exit 2 ;; From 65f9cac79ecfd97259b68ce6d06b2b2670d986ef Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sat, 8 Aug 2026 04:38:59 +0000 Subject: [PATCH 03/11] =?UTF-8?q?Fix:=20Kiro=20installer=20=E3=81=AE=20set?= =?UTF-8?q?-default=20=E5=AE=9F=E8=A1=8C=E4=BD=8D=E7=BD=AE=E3=81=A8=20ndf-?= =?UTF-8?q?policies=20=E3=81=AE=E4=BA=8C=E9=87=8D=E6=B3=A8=E5=85=A5?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cross-review round 1 の指摘 2 件に対応する。 - `--set-default` の `kiro-cli` 呼び出しを導入先で実行する。`kiro-cli` は workspace agent を cwd 配下の `.kiro/agents/` からのみ検出するため、 `--project` で別ディレクトリへ導入すると `agent list` / `set-default` が 対象を見つけられなかった。`workspace` は `--project` のパス、`global` は `$HOME` を実行ディレクトリにする。 - `set-default` は agent 未検出でも終了コード 0 を返すため、実行後に `agent list` で反映を検証し、切り替わっていなければ失敗させる。 - `ndf-policies` を `.kiro/skills/` へ symlink しない。Kiro は `.kiro/skills/*/SKILL.md` と `.kiro/steering/**/*.md` の両方を読み込むため 二重注入になっていた。manifest には steering の生成元として残す。 - `assert-kiro-agent.sh` に回帰検査を追加。`.kiro/skills/ndf-policies` の 不在を検査し、`--set-default` の検査は `PROJECT_DIR` 以外の cwd から実行する。 - 占有率を同一プロジェクトで 4 構成測り直し、README を更新する。 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01AGejnYyYFuSkQjBhW2KQNy --- KIRO.md | 2 +- docs/specifications/ndf-knowledge-and-kiro.md | 2 +- plugins/ndf-kiro/README.md | 25 ++++++++---- plugins/ndf-kiro/install.sh | 38 +++++++++++++++++-- .../assertions/assert-kiro-agent.sh | 13 ++++++- 5 files changed, 64 insertions(+), 16 deletions(-) diff --git a/KIRO.md b/KIRO.md index 1a5459f8..35d6bd4f 100644 --- a/KIRO.md +++ b/KIRO.md @@ -27,7 +27,7 @@ bash plugins/ndf-kiro/install.sh --with-slack bash plugins/ndf-kiro/install.sh --with-slack --with-codex ``` -インストーラーは `plugins/ndf-kiro/skills/` から `.kiro/skills/` への symlink、`.kiro/steering/ndf-policies.md`、`.kiro/agents/ndf.json` を生成します。`plugins/ndf-kiro/skills/` は `plugins/ndf-shared/manifests/kiro-skills.txt` から build された生成物です。 +インストーラーは `plugins/ndf-kiro/skills/` から `.kiro/skills/` への symlink、`.kiro/steering/ndf-policies.md`、`.kiro/agents/ndf.json` を生成します。`plugins/ndf-kiro/skills/` は `plugins/ndf-shared/manifests/kiro-skills.txt` から build された生成物です。`ndf-policies` だけは steering の生成元として使い、`.kiro/skills/` へは symlink しません(Skill と steering の二重注入を避けるため)。 ### Slack通知の設定(オプション) diff --git a/docs/specifications/ndf-knowledge-and-kiro.md b/docs/specifications/ndf-knowledge-and-kiro.md index 2fa1bc87..b10b2199 100644 --- a/docs/specifications/ndf-knowledge-and-kiro.md +++ b/docs/specifications/ndf-knowledge-and-kiro.md @@ -29,7 +29,7 @@ AI エージェント向けの知識は以下の層で管理する。 Kiro CLI 用設定は `.kiro/agents/ndf.json` で管理する。agent 設定は `AGENTS.md` と `README.md` を `file://` resource として読み込む。`.kiro/skills/**/SKILL.md` の `skill://` 指定は組み込み agent の読み込み対象と重複するため持たない。常時適用したい指示は agent 選択に依存しない `.kiro/steering/ndf-policies.md` へ置く。 -Kiro CLI では `plugins/ndf-kiro/install.sh` が `plugins/ndf-kiro/skills/` から `.kiro/skills/` への symlink、`.kiro/steering/ndf-policies.md`、`.kiro/agents/ndf.json` を生成する。`--scope global` を指定した場合の生成先は `~/.kiro/` 配下になる。生成した agent は既定にならないため、`--set-default` を指定したときだけ `kiro-cli agent set-default ndf` を実行する。`agentSpawn` hook は初期化時の案内に使い、`--with-slack` 指定時のみ `stop` hook 相当の Slack 通知を有効化する。Kiro の stop hook payload に `assistant_response` が含まれる場合、`plugins/ndf-kiro/scripts/slack-notify.js` は transcript よりも `assistant_response` を優先して要約に使う。 +Kiro CLI では `plugins/ndf-kiro/install.sh` が `plugins/ndf-kiro/skills/` から `.kiro/skills/` への symlink、`.kiro/steering/ndf-policies.md`、`.kiro/agents/ndf.json` を生成する。`ndf-policies` は steering の生成元としてのみ使い、`.kiro/skills/` へは symlink しない。Kiro は `.kiro/skills/*/SKILL.md` と `.kiro/steering/**/*.md` の両方を文脈へ読み込むため、両方に置くと同じ内容が 2 回注入されるからである。manifest(`plugins/ndf-shared/manifests/kiro-skills.txt`)には steering の生成元として残す。`--scope global` を指定した場合の生成先は `~/.kiro/` 配下になる。生成した agent は既定にならないため、`--set-default` を指定したときだけ `kiro-cli agent set-default ndf` を実行する。`kiro-cli` は workspace agent を cwd 配下の `.kiro/agents/` からのみ検出するため、この呼び出しは導入先(`workspace` なら `--project` のパス、`global` なら `$HOME`)で行い、`agent list` で反映を検証する(`set-default` は agent 未検出でも終了コード 0 を返すため)。`agentSpawn` hook は初期化時の案内に使い、`--with-slack` 指定時のみ `stop` hook 相当の Slack 通知を有効化する。Kiro の stop hook payload に `assistant_response` が含まれる場合、`plugins/ndf-kiro/scripts/slack-notify.js` は transcript よりも `assistant_response` を優先して要約に使う。 Codex 連携は MCP サーバではなく `/ndf:codex` skill と `corder` エージェント経由の Codex CLI 直接実行を標準とする。Kiro 用 `--with-codex` は Kiro セッションから Codex CLI を扱う場合の補助設定である。 diff --git a/plugins/ndf-kiro/README.md b/plugins/ndf-kiro/README.md index 321fbc05..e7592f0f 100644 --- a/plugins/ndf-kiro/README.md +++ b/plugins/ndf-kiro/README.md @@ -68,6 +68,10 @@ kiro-cli agent set-default kiro_default 常時適用したい指示は steering へ置きます。steering はエージェント選択に依存せず読み込まれるため、既定エージェントを書き換えない運用でも効きます。`.kiro/steering/ndf-policies.md` は `plugins/ndf-shared/skills/ndf-policies/SKILL.md` から生成されるため、直接編集しないでください。 +`ndf-policies` は steering の生成元としてのみ使うため、`.kiro/skills/` へは symlink しません。Kiro は `.kiro/skills/*/SKILL.md` と `.kiro/steering/**/*.md` の両方を文脈へ読み込むため、両方に置くと同じ内容が 2 回注入されます。`plugins/ndf-shared/manifests/kiro-skills.txt` には引き続き載せます(`plugins/ndf-kiro/skills/ndf-policies/SKILL.md` が steering の生成元だからです)。 + +`--project` で別ディレクトリへ導入する場合も `--set-default` は正しく動きます。`kiro-cli` は workspace エージェントを cwd 配下の `.kiro/agents/` からのみ検出するため、installer は `kiro-cli` を導入先(`--scope workspace` なら `--project` のパス、`--scope global` なら `$HOME`)で実行します。`kiro-cli agent set-default` はエージェントが見つからなくても終了コード 0 を返すので、installer は実行後に `agent list` で反映を検証し、切り替わっていなければ失敗させます。 + ### 旧バージョンからの移行 v4 系の installer は `.kiro/agents/default.json` を生成していました。この設定は Kiro の既定エージェントにならず、フックも `resources` も無効のままでした。エージェント名を `ndf` に変えたため、再インストールが必要です。 @@ -116,20 +120,25 @@ kiro-cli **2.16.1** / 検証日 **2026-08-07**(ランタイム規約の調査 | `install.sh` 後に `kiro-cli agent list` へ現れるか | 現れる | `ndf Workspace NDF統合開発エージェント(Kiro CLI用)` | | `--agent ndf` で agentSpawn フックが動くか | 動く | `[NDF] CLAUDE.ndf.md が検出されました…` が文脈へ注入された。`kiro_default` では注入されない | | `--set-default` で既定が切り替わるか | 切り替わる | `agent list` の `*` が `ndf` へ移り、素の `kiro-cli chat` でも agentSpawn フックが動いた | +| `--project` で別ディレクトリへ導入したとき `--set-default` が効くか | 効く(修正後) | 修正前は導入先以外の cwd から実行すると `Failed to set default agent: No agent with name ndf found` になり、しかも終了コード 0 で「変更しました」と表示していた。修正後は導入先で `kiro-cli` を実行し、`agent list` で反映を検証する | +| `--scope global --set-default` が効くか | 効く | `$HOME` で `kiro-cli` を実行し `agent list` の `*` が `ndf` へ移った。検証後に `kiro-cli agent set-default kiro_default` で復旧し、`~/.kiro` の `find` 比較で検証前と一致することを確認 | | `--scope global` で `~/.kiro/` へ配置されるか | 配置される | `~/.kiro/{skills,steering,prompts,agents}` が生成され、プロジェクト外でも `Global` として一覧に出た | | steering がエージェント選択に依存せず読まれるか | 読まれる | `kiro_default` の `/context show` にも `.kiro/steering/**/*.md` の一致として現れた | -コンテキスト占有率(Skill 23 個の配布物、`/context show` の `Context files total`): +コンテキスト占有率を `kiro-cli chat --agent <名前> --no-interactive '/context show'` で実測しました。測定用プロジェクトには本リポジトリの `AGENTS.md` と `README.md` を置き、`install.sh --project <測定用ディレクトリ>` で配布物(Skill 23 個)を導入しています。`一致ファイル数` と `合計文字数` は `/context show` が列挙したファイルを数え上げた値、`占有率` は `Context files total` の表示値です。 -| 構成 | 一致ファイル数 | 占有率 | 文脈ファイルの合計文字数 | -| --- | --- | --- | --- | -| 変更前 `default` エージェント | 26(`ndf-policies/SKILL.md` が二重) | 0.2% | 112,598 | -| 変更後 `ndf` エージェント | 26(重複なし、steering が 1 件増) | 0.2% | 112,621 | -| 参考: 組み込み `kiro_default` | 25 | 0.2% | - | +| 構成 | 一致ファイル数 | `ndf-policies` の注入回数 | 占有率 | 文脈ファイルの合計文字数 | +| --- | --- | --- | --- | --- | +| 変更前 `default` エージェント | 26 | 2(`resources` + Skill) | 0.6% | 125,723 | +| 本 PR 初版 `ndf` エージェント | 26 | 2(Skill + steering) | 0.6% | 125,746 | +| 修正後 `ndf` エージェント | 25 | 1(steering のみ) | 0.6% | 125,562 | +| 参考: 組み込み `kiro_default` | 25 | 1(steering のみ) | 0.6% | 125,562 | + +`resources` の二重登録を解消しただけでは、代わりに steering が 1 件増えるためファイル数は 26 のまま減りませんでした。`ndf-policies` を `.kiro/skills/` へ symlink しない変更を加えて、はじめて 26 → 25 に減っています。ただし `ndf-policies/SKILL.md` は 184 文字しかないため、合計文字数の削減は 125,746 → 125,562(-184 文字)にとどまり、`/context show` の表示(0.1% 刻み)は 0.6% のまま変わりません。重複解消の目的は表示上の占有率低減ではなく、同じ指示が 2 回注入される状態を解消することです。 -`resources` の二重登録は解消しましたが、代わりに steering ファイルが 1 件増えるため、総量はほぼ変わりません(+23 文字は生成ヘッダ 2 行分)。`/context show` の表示は 0.1% 刻みのため、この差は表示上変化しません。 +`ndf-policies` を Skill として置かなくても機能は落ちません。`user-invocable: false` で本文の参照を前提としない Skill であり、内容は steering として常時読み込まれるためです。 -`--scope global` でプロジェクト側に Skill がない状態では 24 ファイル / 0.1% でした。 +なお 2026-08-07 に別プロジェクトで測った 0.2% / 112,598 文字という値は、測定用プロジェクトの `AGENTS.md` / `README.md` が異なるため本表とは比較できません。上表は 4 構成すべてを同一プロジェクトで測り直した値です。 ## 開発 diff --git a/plugins/ndf-kiro/install.sh b/plugins/ndf-kiro/install.sh index 6b99ee1f..7c0dc4bd 100755 --- a/plugins/ndf-kiro/install.sh +++ b/plugins/ndf-kiro/install.sh @@ -127,6 +127,14 @@ while IFS= read -r src_dir; do continue fi + # ndf-policies は Step 3 で steering として展開する。Skill としてもリンクすると + # Kiro 組み込みルールの Skill 読み込みと steering 読み込みで文脈へ二重注入されるため、 + # ここではリンクしない。manifest には残す(steering の生成元として必要なため)。 + if [ "$skill_name" = "ndf-policies" ]; then + echo " SKIP: $skill_name (steering として配置)" + continue + fi + if [ "$DRY_RUN" = false ]; then ln -sfn "$PLUGIN_SKILLS_DIR/$skill_name" "$SKILLS_DIR/$skill_name" fi @@ -271,11 +279,27 @@ if [ "$SET_DEFAULT" = true ]; then echo "ERROR: kiro-cli が見つからないため既定エージェントを変更できません" >&2 exit 1 fi + # kiro-cli は workspace エージェントを cwd 配下の .kiro/agents からのみ検出する。 + # 呼び出し元 cwd のままだと、--project で別ディレクトリへ導入したエージェントを + # 見つけられない(または同名の別エージェントを既定にしてしまう)。生成した + # $AGENT_FILE を確実に指すディレクトリで kiro-cli を実行する。 + # workspace: 導入先プロジェクトルート ($PROJECT_ROOT/.kiro/agents) + # global: $HOME ($HOME/.kiro/agents = 生成先。global エージェントはどこからでも + # 解決できるが、cwd 側の同名 workspace エージェントに隠されないようにする) + case "$SCOPE" in + workspace) KIRO_CWD="$PROJECT_ROOT" ;; + *) KIRO_CWD="$HOME" ;; + esac esc="$(printf '\033')" # kiro-cli 2.16.1 の agent list は一覧を標準エラー出力へ書く - current_default="$(kiro-cli agent list 2>&1 \ - | sed -e "s/${esc}\\[[0-9;]*m//g" \ - | awk '/^\*/ { print $2; exit }')" + kiro_default_agent() { + (cd "$KIRO_CWD" && kiro-cli agent list 2>&1) \ + | sed -e "s/${esc}\\[[0-9;]*m//g" \ + | awk '/^\*/ { print $2; exit }' + } + # 表示用の取得は失敗しても続行する(未ログイン等でも set-default の結果は後段で検証する) + current_default="$(kiro_default_agent || true)" + echo "既定エージェントの操作ディレクトリ: $KIRO_CWD" echo "現在の既定エージェント: ${current_default:-不明}" echo "変更後の既定エージェント: $AGENT_NAME" proceed=true @@ -292,7 +316,13 @@ if [ "$SET_DEFAULT" = true ]; then fi fi if [ "$proceed" = true ]; then - kiro-cli agent set-default "$AGENT_NAME" + (cd "$KIRO_CWD" && kiro-cli agent set-default "$AGENT_NAME") + # kiro-cli 2.16.1 の set-default はエージェント未検出でも終了コード 0 を返すため、 + # 反映結果を agent list で検証する。 + if [ "$(kiro_default_agent || true)" != "$AGENT_NAME" ]; then + echo "ERROR: 既定エージェントを $AGENT_NAME に変更できませんでした($KIRO_CWD で検出できず)" >&2 + exit 1 + fi echo "既定エージェントを $AGENT_NAME に変更しました(元に戻す: kiro-cli agent set-default ${current_default:-kiro_default})" else echo "既定エージェントは変更しませんでした" diff --git a/tests/runtime-smoke/assertions/assert-kiro-agent.sh b/tests/runtime-smoke/assertions/assert-kiro-agent.sh index f8da58b8..1e35e73b 100755 --- a/tests/runtime-smoke/assertions/assert-kiro-agent.sh +++ b/tests/runtime-smoke/assertions/assert-kiro-agent.sh @@ -30,8 +30,15 @@ test -f "$AGENT_FILE" test -s "$STEERING_FILE" find -L "$KIRO_DIR/skills" -path '*/SKILL.md' -print | grep -q . +# ndf-policies は steering として配置する。Skill としても置くと Kiro 組み込みルールの +# Skill 読み込みと steering 読み込みで文脈へ二重注入される。 +if [ -e "$KIRO_DIR/skills/ndf-policies" ]; then + echo "ndf-policies must be delivered via steering only: $KIRO_DIR/skills/ndf-policies" >&2 + exit 1 +fi + # エージェント定義と、起動時に読み込まれる文脈量を検査する。 -# 上限は 2026-08-07 / kiro-cli 2.16.1 の実測 112,621 文字に対する余裕分。 +# 上限は 2026-08-08 / kiro-cli 2.16.1 でのこのフィクスチャの実測 112,404 文字に対する余裕分。 python3 - "$AGENT_FILE" "$KIRO_DIR" "$PROJECT_DIR" "$STEERING_FILE" 200000 >> "$LOG" <<'PY' import json import sys @@ -93,7 +100,9 @@ fi before_default="$(current_default)" echo "default agent before: ${before_default:-unknown}" >> "$LOG" -bash "$REPO_ROOT/plugins/ndf-kiro/install.sh" --project "$PROJECT_DIR" --with-slack --set-default --yes >> "$LOG" 2>&1 +# kiro-cli は workspace エージェントを cwd 配下からのみ検出する。--project で別ディレクトリへ +# 導入したときに --set-default が効くことを検査するため、PROJECT_DIR 以外の cwd から実行する。 +(cd "$ARTIFACT_DIR" && bash "$REPO_ROOT/plugins/ndf-kiro/install.sh" --project "$PROJECT_DIR" --with-slack --set-default --yes) >> "$LOG" 2>&1 after_default="$(current_default)" echo "default agent after: ${after_default:-unknown}" >> "$LOG" if [ "$after_default" != "$AGENT_NAME" ]; then From 6e357a2cea941b96ebb17b167f5bbb7ff49cf3fa Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sat, 8 Aug 2026 04:58:22 +0000 Subject: [PATCH 04/11] =?UTF-8?q?Fix:=20Kiro=20installer=20=E3=81=8C?= =?UTF-8?q?=E5=88=A9=E7=94=A8=E8=80=85=E7=AE=A1=E7=90=86=E3=81=AE=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A=E3=82=92=E4=BF=9D=E6=8C=81=E3=81=97=E3=80=81=E3=83=86?= =?UTF-8?q?=E3=82=B9=E3=83=88=E3=81=8C=E6=97=A2=E5=AE=9A=E3=82=A8=E3=83=BC?= =?UTF-8?q?=E3=82=B8=E3=82=A7=E3=83=B3=E3=83=88=E3=82=92=E7=A2=BA=E5=AE=9F?= =?UTF-8?q?=E3=81=AB=E5=BE=A9=E6=97=A7=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cross-review round 2 の指摘 2 件に対応する。 - install.sh は .kiro/agents/ndf.json をテンプレートから再生成する際に、 既存ファイルの利用者管理の設定(mcpServers エントリ、独自フック、独自 トップレベルキー)をマージして引き継ぐ。上書きするのはテンプレート由来の キーと、フラグで切り替える hooks.stop / mcpServers.codex だけにする。 - assert-kiro-agent.sh の既定エージェント復旧を PROJECT_DIR から実行し、 復旧できたことを agent list で検証する。途中の検査が落ちても復旧するよう trap EXIT で実行する。 - 再インストールで利用者管理の設定が失われないことの回帰検査を追加する。 kiro-cli に依存しないため CI のコンテナでも実行される。 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01AGejnYyYFuSkQjBhW2KQNy --- plugins/ndf-kiro/README.md | 22 +++++- plugins/ndf-kiro/install.sh | 56 ++++++++++++-- .../assertions/assert-kiro-agent.sh | 77 ++++++++++++++++++- 3 files changed, 144 insertions(+), 11 deletions(-) diff --git a/plugins/ndf-kiro/README.md b/plugins/ndf-kiro/README.md index e7592f0f..52174dfb 100644 --- a/plugins/ndf-kiro/README.md +++ b/plugins/ndf-kiro/README.md @@ -91,7 +91,22 @@ rm .kiro/agents/default.json .kiro/agents/default.json.bak bash plugins/ndf-kiro/install.sh --set-default ``` -Kiro 用 MCP プラグインの installer(`plugins/mcp/kiro/*/install.sh`)は `.kiro/agents/default.json` を更新します。MCP を併用する場合は、`mcpServers` を `.kiro/agents/ndf.json` へ写してください。 +Kiro 用 MCP プラグインの installer(`plugins/mcp/kiro/*/install.sh`)は `.kiro/agents/default.json` を更新します。MCP を併用する場合は、`mcpServers` を `.kiro/agents/ndf.json` へ写してください。写し替えは一度だけで済みます。`install.sh` を再実行しても、写した `mcpServers` は保持されます。 + +### 再インストール時に保持される設定 + +`install.sh` は `.kiro/agents/ndf.json` を毎回テンプレートから再生成しますが、上書きするのは installer が管理するキーだけです。既存ファイルにある利用者管理の設定は読み取ってマージし直します。 + +| 区分 | キー | 再実行時の扱い | +| --- | --- | --- | +| installer 管理 | `name` / `description` / `tools` / `resources` / `hooks.agentSpawn` | テンプレートから再生成する(上書き) | +| installer 管理 | `hooks.stop` | `--with-slack` の有無で生成・削除する | +| installer 管理 | `mcpServers.codex` | `--with-codex` の有無で生成・削除する | +| 利用者管理 | 上記以外の `mcpServers` エントリ、`hooks` の項目、トップレベルキー | そのまま引き継ぐ | + +引き継いだ項目は実行ログに `利用者管理の設定を引き継ぎました: mcpServers.bigquery` のように表示します。再生成の前に `.kiro/agents/ndf.json.bak` へバックアップも取るため、意図しない結果になった場合は差し戻せます。 + +`mcpServers.codex` だけは installer 管理です。`--with-codex` を付けずに再実行すると削除されるため、Codex MCP を使う場合は `--with-codex` を付けたまま運用してください。 ## Kiro CLI の制限 @@ -124,6 +139,11 @@ kiro-cli **2.16.1** / 検証日 **2026-08-07**(ランタイム規約の調査 | `--scope global --set-default` が効くか | 効く | `$HOME` で `kiro-cli` を実行し `agent list` の `*` が `ndf` へ移った。検証後に `kiro-cli agent set-default kiro_default` で復旧し、`~/.kiro` の `find` 比較で検証前と一致することを確認 | | `--scope global` で `~/.kiro/` へ配置されるか | 配置される | `~/.kiro/{skills,steering,prompts,agents}` が生成され、プロジェクト外でも `Global` として一覧に出た | | steering がエージェント選択に依存せず読まれるか | 読まれる | `kiro_default` の `/context show` にも `.kiro/steering/**/*.md` の一致として現れた | +| 再インストールで利用者管理の設定が残るか | 残る | `mcpServers.bigquery` / `hooks.userPromptSubmit` / `toolsSettings` を書き足してから再実行し、すべて残ることを確認。ログに `利用者管理の設定を引き継ぎました: hooks.userPromptSubmit, mcpServers.bigquery, toolsSettings` | +| `--with-codex` を外した再実行の挙動 | `mcpServers.codex` だけ消える | 同じ再実行で `mcpServers.bigquery` は残った。`codex` は installer 管理のため | +| 既存 `ndf.json` が壊れた JSON のとき | テンプレートから再生成する | `WARN: 既存の … を読めないため引き継ぎません` を出して続行し、`.bak` は残る | +| `kiro-cli agent set-default` の保存先 | `~/.local/share/kiro-cli/data.sqlite3`(マシン全体の設定) | 実行した cwd に `.kiro/settings.json` は生成されず、`find ~/.kiro ~/.aws` にも差分が出なかった | +| 既定エージェントが cwd 依存で復旧できるか | 導入先から実行すれば復旧できる | 対象プロジェクト限定の workspace エージェントを既定にした状態では、別 cwd からの `set-default` が `No agent with name … found` になりつつ終了コード 0 を返し、既定が戻らなかった | コンテキスト占有率を `kiro-cli chat --agent <名前> --no-interactive '/context show'` で実測しました。測定用プロジェクトには本リポジトリの `AGENTS.md` と `README.md` を置き、`install.sh --project <測定用ディレクトリ>` で配布物(Skill 23 個)を導入しています。`一致ファイル数` と `合計文字数` は `/context show` が列挙したファイルを数え上げた値、`占有率` は `Context files total` の表示値です。 diff --git a/plugins/ndf-kiro/install.sh b/plugins/ndf-kiro/install.sh index 7c0dc4bd..2c3896b5 100755 --- a/plugins/ndf-kiro/install.sh +++ b/plugins/ndf-kiro/install.sh @@ -222,6 +222,7 @@ sys.exit(0 if config.get("name") == "default" and "NDF" in (config.get("descript echo " 2. 不要になったら rm $LEGACY_AGENT_FILE ${LEGACY_AGENT_FILE}.bak" echo " Kiro 用 MCP プラグインの installer は default.json を更新するため、" echo " MCP を併用する場合は上記の写し替えが必要です。" + echo " 写した設定は本 installer を再実行しても保持されます。" fi echo "" fi @@ -234,6 +235,10 @@ if [ -f "$AGENT_FILE" ]; then echo "既存設定をバックアップ: ${AGENT_FILE}.bak" fi +# installer が管理するのはテンプレート由来のキー(name / description / tools / +# resources / hooks.agentSpawn)と、フラグで切り替える hooks.stop / mcpServers.codex +# だけ。それ以外(利用者が足した mcpServers エントリ、独自フック、独自キー)は +# 既存の $AGENT_FILE から引き継ぐ。再インストールで写し替えた設定が消えないようにする。 python3 - "$TEMPLATE_FILE" "$WITH_SLACK" "$WITH_CODEX" "$AGENT_FILE" "$SCRIPT_DIR" <<'PY' import json import shlex @@ -244,6 +249,11 @@ template_file, with_slack, with_codex, agent_file, script_dir = sys.argv[1:6] with open(template_file, encoding="utf-8") as f: config = json.load(f) +# installer が上書きする範囲 +managed_keys = set(config) | {"mcpServers"} +managed_hooks = set(config.get("hooks") or {}) | {"stop"} +managed_servers = {"codex"} + hooks = config.setdefault("hooks", {}) if with_slack == "true": slack_script = Path(script_dir) / "scripts" / "slack-notify.js" @@ -256,20 +266,54 @@ if with_slack == "true": else: hooks.pop("stop", None) +servers = {} if with_codex == "true": - config["mcpServers"] = { - "codex": { - "command": "codex", - "args": ["mcp-server"], - "env": {}, - } + servers["codex"] = { + "command": "codex", + "args": ["mcp-server"], + "env": {}, } + +existing = {} +agent_path = Path(agent_file) +if agent_path.is_file(): + try: + loaded = json.loads(agent_path.read_text(encoding="utf-8")) + except (json.JSONDecodeError, UnicodeDecodeError) as exc: + print(f" WARN: 既存の {agent_file} を読めないため引き継ぎません: {exc}") + else: + if isinstance(loaded, dict): + existing = loaded + else: + print(f" WARN: 既存の {agent_file} が JSON オブジェクトではないため引き継ぎません") + +kept = [] +for key, value in existing.items(): + if key not in managed_keys: + config[key] = value + kept.append(key) +for key, value in (existing.get("hooks") or {}).items(): + if key not in managed_hooks: + hooks[key] = value + kept.append(f"hooks.{key}") +for key, value in (existing.get("mcpServers") or {}).items(): + if key not in managed_servers: + servers[key] = value + kept.append(f"mcpServers.{key}") + +if not hooks: + config.pop("hooks", None) +if servers: + config["mcpServers"] = servers else: config.pop("mcpServers", None) with open(agent_file, "w", encoding="utf-8") as f: json.dump(config, f, indent=2, ensure_ascii=False) f.write("\n") + +if kept: + print(" 利用者管理の設定を引き継ぎました: " + ", ".join(sorted(kept))) PY # --- Step 6: Optionally switch the default agent --- diff --git a/tests/runtime-smoke/assertions/assert-kiro-agent.sh b/tests/runtime-smoke/assertions/assert-kiro-agent.sh index 1e35e73b..b9cfb8d2 100755 --- a/tests/runtime-smoke/assertions/assert-kiro-agent.sh +++ b/tests/runtime-smoke/assertions/assert-kiro-agent.sh @@ -74,6 +74,60 @@ PY [ "$scope" = workspace ] || exit 0 +# 利用者が $AGENT_FILE へ写した設定(MCP プラグインの mcpServers など)が、 +# installer の再実行で失われないことを検査する。kiro-cli には依存しない。 +python3 - "$AGENT_FILE" <<'PY' +import json +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +config = json.loads(path.read_text(encoding="utf-8")) +config.setdefault("mcpServers", {})["smoke-user-mcp"] = { + "command": "echo", + "args": ["user-managed"], +} +config.setdefault("hooks", {})["userPromptSubmit"] = [{"command": "true"}] +config["smokeUserKey"] = "keep-me" +path.write_text(json.dumps(config, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") +PY +bash "$REPO_ROOT/plugins/ndf-kiro/install.sh" --project "$PROJECT_DIR" --with-slack >> "$LOG" 2>&1 +python3 - "$AGENT_FILE" <<'PY' +import json +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +config = json.loads(path.read_text(encoding="utf-8")) +if "smoke-user-mcp" not in config.get("mcpServers", {}): + raise SystemExit(f"reinstall dropped a user-managed mcpServers entry: {path}") +if "userPromptSubmit" not in config.get("hooks", {}): + raise SystemExit(f"reinstall dropped a user-managed hook: {path}") +if config.get("smokeUserKey") != "keep-me": + raise SystemExit(f"reinstall dropped a user-managed key: {path}") +# installer 管理のキーはテンプレートから再生成されている +if config.get("name") != "ndf" or not config.get("hooks", {}).get("agentSpawn"): + raise SystemExit(f"reinstall did not regenerate installer-managed keys: {path}") +if not config.get("hooks", {}).get("stop"): + raise SystemExit(f"--with-slack did not regenerate the stop hook: {path}") +PY +# 検査用に注入した設定を取り除き、以降の検査へ持ち越さない +python3 - "$AGENT_FILE" <<'PY' +import json +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +config = json.loads(path.read_text(encoding="utf-8")) +config.get("mcpServers", {}).pop("smoke-user-mcp", None) +if not config.get("mcpServers"): + config.pop("mcpServers", None) +config.get("hooks", {}).pop("userPromptSubmit", None) +config.pop("smokeUserKey", None) +path.write_text(json.dumps(config, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") +PY +echo "reinstall preserved user-managed agent settings" >> "$LOG" + if ! command -v kiro-cli >/dev/null 2>&1; then echo "kiro-cli agent checks skipped: kiro-cli is not available" >> "$LOG" exit 0 @@ -100,6 +154,25 @@ fi before_default="$(current_default)" echo "default agent before: ${before_default:-unknown}" >> "$LOG" + +# kiro-cli の既定エージェントは ~/.local/share/kiro-cli/data.sqlite3 に保存されるマシン全体の +# 設定であり、この検査は必ず元へ戻す必要がある。set-default は agent list と同じく workspace +# エージェントを cwd 配下からしか検出せず、しかも未検出でも終了コード 0 を返すため、 +# agent_list と同じ PROJECT_DIR から実行し、戻ったことを agent list で検証する。 +# 途中の検査が落ちても復旧するよう trap で実行する。 +restore_default() { + [ -n "$before_default" ] || return 0 + [ "$before_default" != "$AGENT_NAME" ] || return 0 + (cd "$PROJECT_DIR" && kiro-cli agent set-default "$before_default") >> "$LOG" 2>&1 || true + restored_default="$(current_default || true)" + echo "default agent restored: ${restored_default:-unknown}" >> "$LOG" + if [ "$restored_default" != "$before_default" ]; then + echo "failed to restore the default agent: ${restored_default:-unknown} (expected $before_default)" >&2 + return 1 + fi +} +trap 'rc=$?; restore_default || rc=1; exit $rc' EXIT + # kiro-cli は workspace エージェントを cwd 配下からのみ検出する。--project で別ディレクトリへ # 導入したときに --set-default が効くことを検査するため、PROJECT_DIR 以外の cwd から実行する。 (cd "$ARTIFACT_DIR" && bash "$REPO_ROOT/plugins/ndf-kiro/install.sh" --project "$PROJECT_DIR" --with-slack --set-default --yes) >> "$LOG" 2>&1 @@ -109,7 +182,3 @@ if [ "$after_default" != "$AGENT_NAME" ]; then echo "--set-default did not switch the default agent: ${after_default:-unknown}" >&2 exit 1 fi -if [ -n "$before_default" ] && [ "$before_default" != "$AGENT_NAME" ]; then - kiro-cli agent set-default "$before_default" >> "$LOG" 2>&1 - echo "default agent restored: $before_default" >> "$LOG" -fi From 3303e2b388fe47175ac7ef20a6dd51658695fa88 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sat, 8 Aug 2026 05:06:14 +0000 Subject: [PATCH 05/11] =?UTF-8?q?Docs:=20Kiro=20=E3=81=AE=E7=A2=BA?= =?UTF-8?q?=E8=AA=8D=E8=A6=B3=E7=82=B9=E3=81=8B=E3=82=89=20mcpServers=20?= =?UTF-8?q?=E3=82=92=E5=BF=85=E9=A0=88=E6=89=B1=E3=81=84=E3=81=8B=E3=82=89?= =?UTF-8?q?=E5=A4=96=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mcpServers はテンプレートに無く、--with-codex 指定時または既存の利用者管理設定を 引き継いだ場合にだけ .kiro/agents/ndf.json に現れる。必須のテスト観点にすると 通常インストールと矛盾するため、条件付きの記述へ改めた。 --- docs/specifications/ndf-knowledge-and-kiro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/specifications/ndf-knowledge-and-kiro.md b/docs/specifications/ndf-knowledge-and-kiro.md index b10b2199..0129f404 100644 --- a/docs/specifications/ndf-knowledge-and-kiro.md +++ b/docs/specifications/ndf-knowledge-and-kiro.md @@ -55,7 +55,7 @@ Codex 連携は MCP サーバではなく `/ndf:codex` skill と `corder` エー | 領域 | 確認内容 | |---|---| -| Kiro CLI | `.kiro/agents/ndf.json` が resources / hooks / mcpServers を持ち、`kiro-cli agent list` に `ndf` が現れること | +| Kiro CLI | `.kiro/agents/ndf.json` が resources と hooks を持ち、`kiro-cli agent list` に `ndf` が現れること。`mcpServers` は `--with-codex` 指定時、または既存の利用者管理設定を引き継いだ場合にのみ現れる | | ドキュメント | `AGENTS.md` / `CLAUDE.md` / `KIRO.md` / `docs/` の役割が重複しすぎていないこと | ## 関連リンク From 01b7865bdf57e9f34ba6cd2ee1592a6a2c994b19 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sat, 8 Aug 2026 05:21:54 +0000 Subject: [PATCH 06/11] =?UTF-8?q?Fix:=20Kiro=20installer=20=E3=81=AE?= =?UTF-8?q?=E6=97=A7=20ndf-policies=20=E3=83=AA=E3=83=B3=E3=82=AF=E6=8E=83?= =?UTF-8?q?=E9=99=A4=E3=81=A8=E5=85=A5=E5=8A=9B/JSON=20=E3=81=AE=E7=95=B0?= =?UTF-8?q?=E5=B8=B8=E7=B3=BB=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - install.sh: 旧 installer が別 checkout から張った .kiro/skills/ndf-policies の symlink / 実体を、リンク先に関係なく削除してから skip する。旧導入済みプロジェクト でも steering との二重注入が再インストール 1 回で解消される - install.sh: 旧 default.json が JSON 配列でも AttributeError にせず、壊れた JSON と 同じ「NDF 生成物ではない」扱いへ倒す - install.sh: set -e 下で read が EOF を受けてもクラッシュせず [y/N] の N へ倒す - assert-kiro-agent.sh: global scope でも agent list と --scope global --set-default --yes 後の既定切替を検査する(復旧は既存の trap に載せる) - assert-kiro-agent.sh: 旧 ndf-policies symlink が再インストールで消えることを workspace / global 両方で検査する(kiro-cli 非依存なので CI でも動く) - README: 旧 symlink の掃除挙動を移行手順に追記 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01AGejnYyYFuSkQjBhW2KQNy --- plugins/ndf-kiro/README.md | 2 + plugins/ndf-kiro/install.sh | 20 +++++- .../assertions/assert-kiro-agent.sh | 69 +++++++++++++++---- 3 files changed, 75 insertions(+), 16 deletions(-) diff --git a/plugins/ndf-kiro/README.md b/plugins/ndf-kiro/README.md index 52174dfb..f58e22c7 100644 --- a/plugins/ndf-kiro/README.md +++ b/plugins/ndf-kiro/README.md @@ -76,6 +76,8 @@ kiro-cli agent set-default kiro_default v4 系の installer は `.kiro/agents/default.json` を生成していました。この設定は Kiro の既定エージェントにならず、フックも `resources` も無効のままでした。エージェント名を `ndf` に変えたため、再インストールが必要です。 +旧 installer が張った `.kiro/skills/ndf-policies` の symlink は、リンク先が現在のプラグイン配下でなくても再インストール時に削除します(削除するのはリンク自体だけで、リンク先の実体には触れません)。別の checkout パスから導入した環境でも、steering との二重注入が再インストール 1 回で解消されます。 + ```bash # 1. 再インストール(旧 default.json は自動でバックアップされます) bash plugins/ndf-kiro/install.sh --with-slack diff --git a/plugins/ndf-kiro/install.sh b/plugins/ndf-kiro/install.sh index 2c3896b5..e1fdb10e 100755 --- a/plugins/ndf-kiro/install.sh +++ b/plugins/ndf-kiro/install.sh @@ -130,7 +130,15 @@ while IFS= read -r src_dir; do # ndf-policies は Step 3 で steering として展開する。Skill としてもリンクすると # Kiro 組み込みルールの Skill 読み込みと steering 読み込みで文脈へ二重注入されるため、 # ここではリンクしない。manifest には残す(steering の生成元として必要なため)。 + # 旧 installer が別 checkout から張ったリンクは Step 1 の掃除(現在の + # $PLUGIN_SKILLS_DIR 配下を指すものだけ削除)に掛からないため、ここで + # リンク先に関係なく既存のエントリを取り除いてから skip する。 if [ "$skill_name" = "ndf-policies" ]; then + if [ "$DRY_RUN" = false ] && + { [ -e "$SKILLS_DIR/$skill_name" ] || [ -L "$SKILLS_DIR/$skill_name" ]; }; then + rm -rf "$SKILLS_DIR/$skill_name" + echo " REMOVED: $skill_name (steering へ移行済みのため .kiro/skills から削除)" + fi echo " SKIP: $skill_name (steering として配置)" continue fi @@ -209,9 +217,16 @@ if [ -f "$LEGACY_AGENT_FILE" ]; then import json, sys try: config = json.load(open(sys.argv[1], encoding="utf-8")) + # JSON がオブジェクト以外(配列など)でも AttributeError にせず、壊れた JSON と + # 同じ「NDF 生成物ではない」扱いへ倒す。 + matched = ( + isinstance(config, dict) + and config.get("name") == "default" + and "NDF" in (config.get("description") or "") + ) except Exception: sys.exit(1) -sys.exit(0 if config.get("name") == "default" and "NDF" in (config.get("description") or "") else 1) +sys.exit(0 if matched else 1) ' "$LEGACY_AGENT_FILE"; then echo " これは旧版 NDF installer の生成物です。移行手順:" echo " 1. 独自に追記した設定があればバックアップから $AGENT_FILE へ写す" @@ -350,7 +365,8 @@ if [ "$SET_DEFAULT" = true ]; then if [ "$ASSUME_YES" = false ]; then if [ -t 0 ]; then printf '既定エージェントを %s に変更しますか? [y/N]: ' "$AGENT_NAME" - read -r answer + # EOF (Ctrl+D) で read が非ゼロ終了しても set -e で落とさず、既定の N へ倒す + read -r answer || answer="" case "$answer" in [yY]|[yY][eE][sS]) ;; *) proceed=false ;; diff --git a/tests/runtime-smoke/assertions/assert-kiro-agent.sh b/tests/runtime-smoke/assertions/assert-kiro-agent.sh index b9cfb8d2..dfe56310 100755 --- a/tests/runtime-smoke/assertions/assert-kiro-agent.sh +++ b/tests/runtime-smoke/assertions/assert-kiro-agent.sh @@ -13,9 +13,16 @@ scope="${1:-workspace}" : "${HOME:=/tmp/runtime-home}" AGENT_NAME="ndf" +# INSTALL_ARGS: この scope の導入先を再現する installer 引数 case "$scope" in - workspace) KIRO_DIR="$PROJECT_DIR/.kiro" ;; - global) KIRO_DIR="$HOME/.kiro" ;; + workspace) + KIRO_DIR="$PROJECT_DIR/.kiro" + INSTALL_ARGS=(--project "$PROJECT_DIR") + ;; + global) + KIRO_DIR="$HOME/.kiro" + INSTALL_ARGS=(--scope global) + ;; *) echo "unknown scope: $scope" >&2; exit 2 ;; esac @@ -72,8 +79,23 @@ if total > budget: raise SystemExit(f"context files exceed the budget: {total} > {budget}") PY -[ "$scope" = workspace ] || exit 0 +# 旧 installer が別 checkout から張った .kiro/skills/ndf-policies symlink は、現在の +# プラグイン配下を指さないため「自分が張ったリンクだけ消す」掃除に掛からない。旧導入済み +# プロジェクトでも steering との二重注入が解消されることを検査する。 +STALE_ROOT="$ARTIFACT_DIR/stale-checkout-$scope/skills/ndf-policies" +mkdir -p "$STALE_ROOT" +echo "stale" > "$STALE_ROOT/SKILL.md" +ln -sfn "$STALE_ROOT" "$KIRO_DIR/skills/ndf-policies" +bash "$REPO_ROOT/plugins/ndf-kiro/install.sh" "${INSTALL_ARGS[@]}" --with-slack >> "$LOG" 2>&1 +if [ -e "$KIRO_DIR/skills/ndf-policies" ] || [ -L "$KIRO_DIR/skills/ndf-policies" ]; then + echo "installer left a stale ndf-policies skill link: $KIRO_DIR/skills/ndf-policies" >&2 + exit 1 +fi +test -f "$STALE_ROOT/SKILL.md" # リンク先の実体まで消していないこと +echo "installer removed a stale ndf-policies skill link" >> "$LOG" +# --- workspace 限定の検査(ここから fi まで。heredoc の終端子の都合でインデントしない) --- +if [ "$scope" = workspace ]; then # 利用者が $AGENT_FILE へ写した設定(MCP プラグインの mcpServers など)が、 # installer の再実行で失われないことを検査する。kiro-cli には依存しない。 python3 - "$AGENT_FILE" <<'PY' @@ -127,28 +149,46 @@ config.pop("smokeUserKey", None) path.write_text(json.dumps(config, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") PY echo "reinstall preserved user-managed agent settings" >> "$LOG" +fi +# --- workspace 限定の検査ここまで --- if ! command -v kiro-cli >/dev/null 2>&1; then echo "kiro-cli agent checks skipped: kiro-cli is not available" >> "$LOG" exit 0 fi +# kiro-cli は workspace エージェントを cwd 配下の .kiro/agents からしか検出しない。 +# scope ごとに、生成した $AGENT_FILE を検出できる cwd と installer の再実行引数を選ぶ。 +case "$scope" in + workspace) KIRO_CWD="$PROJECT_DIR" ;; + # global エージェントはどこからでも解決できるはずなので、.kiro を持たない中立の + # ディレクトリを cwd にする。$HOME を使うと $HOME/.kiro が workspace 扱いにもなり、 + # 「Global として見えている」ことの検査にならない。 + global) KIRO_CWD="$ARTIFACT_DIR" ;; +esac +if [ "$scope" = global ] && [ -e "$KIRO_CWD/.kiro" ]; then + echo "global agent checks need a cwd without .kiro: $KIRO_CWD" >&2 + exit 1 +fi + esc="$(printf '\033')" agent_list() { # kiro-cli 2.16.1 の agent list は一覧を標準エラー出力へ書く - (cd "$PROJECT_DIR" && kiro-cli agent list 2>&1) | sed -e "s/${esc}\\[[0-9;]*m//g" + (cd "$KIRO_CWD" && kiro-cli agent list 2>&1) | sed -e "s/${esc}\\[[0-9;]*m//g" } current_default() { agent_list | awk '/^\*/ { print $2; exit }' } -if ! agent_list > "$ARTIFACT_DIR/kiro-agent-list.txt"; then +if ! agent_list > "$ARTIFACT_DIR/kiro-agent-list-$scope.txt"; then echo "kiro-cli agent checks skipped: agent list failed" >> "$LOG" exit 0 fi -if ! awk '{ print $1, $2 }' "$ARTIFACT_DIR/kiro-agent-list.txt" | grep -qw "$AGENT_NAME"; then - echo "agent list does not contain $AGENT_NAME" >&2 - cat "$ARTIFACT_DIR/kiro-agent-list.txt" >&2 +# global scope の $KIRO_CWD には .kiro がないため、ここに $AGENT_NAME が出ること自体が +# 「Global: ~/.kiro/agents 経由でどこからでも解決できる」ことの検査になる。 +if ! awk '{ print $1, $2 }' "$ARTIFACT_DIR/kiro-agent-list-$scope.txt" | grep -qw "$AGENT_NAME"; then + echo "agent list ($scope) does not contain $AGENT_NAME" >&2 + cat "$ARTIFACT_DIR/kiro-agent-list-$scope.txt" >&2 exit 1 fi @@ -158,12 +198,12 @@ echo "default agent before: ${before_default:-unknown}" >> "$LOG" # kiro-cli の既定エージェントは ~/.local/share/kiro-cli/data.sqlite3 に保存されるマシン全体の # 設定であり、この検査は必ず元へ戻す必要がある。set-default は agent list と同じく workspace # エージェントを cwd 配下からしか検出せず、しかも未検出でも終了コード 0 を返すため、 -# agent_list と同じ PROJECT_DIR から実行し、戻ったことを agent list で検証する。 +# agent_list と同じ $KIRO_CWD から実行し、戻ったことを agent list で検証する。 # 途中の検査が落ちても復旧するよう trap で実行する。 restore_default() { [ -n "$before_default" ] || return 0 [ "$before_default" != "$AGENT_NAME" ] || return 0 - (cd "$PROJECT_DIR" && kiro-cli agent set-default "$before_default") >> "$LOG" 2>&1 || true + (cd "$KIRO_CWD" && kiro-cli agent set-default "$before_default") >> "$LOG" 2>&1 || true restored_default="$(current_default || true)" echo "default agent restored: ${restored_default:-unknown}" >> "$LOG" if [ "$restored_default" != "$before_default" ]; then @@ -173,12 +213,13 @@ restore_default() { } trap 'rc=$?; restore_default || rc=1; exit $rc' EXIT -# kiro-cli は workspace エージェントを cwd 配下からのみ検出する。--project で別ディレクトリへ -# 導入したときに --set-default が効くことを検査するため、PROJECT_DIR 以外の cwd から実行する。 -(cd "$ARTIFACT_DIR" && bash "$REPO_ROOT/plugins/ndf-kiro/install.sh" --project "$PROJECT_DIR" --with-slack --set-default --yes) >> "$LOG" 2>&1 +# kiro-cli はエージェントを cwd / $HOME 配下からのみ検出する。workspace では --project で +# 別ディレクトリへ導入したときに --set-default が効くことを検査するため、PROJECT_DIR 以外の +# cwd から実行する。global でも同様に $HOME 以外の cwd から実行して既定切替を検査する。 +(cd "$ARTIFACT_DIR" && bash "$REPO_ROOT/plugins/ndf-kiro/install.sh" "${INSTALL_ARGS[@]}" --with-slack --set-default --yes) >> "$LOG" 2>&1 after_default="$(current_default)" echo "default agent after: ${after_default:-unknown}" >> "$LOG" if [ "$after_default" != "$AGENT_NAME" ]; then - echo "--set-default did not switch the default agent: ${after_default:-unknown}" >&2 + echo "--set-default did not switch the default agent ($scope): ${after_default:-unknown}" >&2 exit 1 fi From 83588e69df68fe71e99ff8161ee09f97c57da41a Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sat, 8 Aug 2026 05:29:16 +0000 Subject: [PATCH 07/11] =?UTF-8?q?Fix:=20ndf-policies=20=E3=81=AE=E6=8E=83?= =?UTF-8?q?=E9=99=A4=E3=82=92=20symlink=20=E3=81=AB=E9=99=90=E5=AE=9A?= =?UTF-8?q?=E3=81=97=E5=AE=9F=E4=BD=93=E3=81=AF=E6=B6=88=E3=81=95=E3=81=AA?= =?UTF-8?q?=E3=81=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rm -rf は .kiro/skills/ndf-policies が実体のディレクトリやファイルだった場合に 中身ごと消してしまい、README の「削除するのはリンク自体だけ」とも矛盾していた。 - 削除対象を [ -L ] のシンボリックリンクだけに限り rm -f で外す - 実体だった場合は削除せず、二重注入の理由と手動対応を促す警告を出す - README に実体だった場合の扱いを追記 --- plugins/ndf-kiro/README.md | 2 +- plugins/ndf-kiro/install.sh | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/plugins/ndf-kiro/README.md b/plugins/ndf-kiro/README.md index f58e22c7..5975041a 100644 --- a/plugins/ndf-kiro/README.md +++ b/plugins/ndf-kiro/README.md @@ -76,7 +76,7 @@ kiro-cli agent set-default kiro_default v4 系の installer は `.kiro/agents/default.json` を生成していました。この設定は Kiro の既定エージェントにならず、フックも `resources` も無効のままでした。エージェント名を `ndf` に変えたため、再インストールが必要です。 -旧 installer が張った `.kiro/skills/ndf-policies` の symlink は、リンク先が現在のプラグイン配下でなくても再インストール時に削除します(削除するのはリンク自体だけで、リンク先の実体には触れません)。別の checkout パスから導入した環境でも、steering との二重注入が再インストール 1 回で解消されます。 +旧 installer が張った `.kiro/skills/ndf-policies` の symlink は、リンク先が現在のプラグイン配下でなくても再インストール時に削除します(削除するのはリンク自体だけで、リンク先の実体には触れません)。`.kiro/skills/ndf-policies` が symlink ではなく実体のディレクトリやファイルだった場合は、利用者が置いたものの可能性があるため installer は削除せず警告を出します。二重注入を避けるため、内容を確認のうえ手動で退避または削除してください。別の checkout パスから導入した環境でも、steering との二重注入が再インストール 1 回で解消されます。 ```bash # 1. 再インストール(旧 default.json は自動でバックアップされます) diff --git a/plugins/ndf-kiro/install.sh b/plugins/ndf-kiro/install.sh index e1fdb10e..a040e957 100755 --- a/plugins/ndf-kiro/install.sh +++ b/plugins/ndf-kiro/install.sh @@ -134,10 +134,18 @@ while IFS= read -r src_dir; do # $PLUGIN_SKILLS_DIR 配下を指すものだけ削除)に掛からないため、ここで # リンク先に関係なく既存のエントリを取り除いてから skip する。 if [ "$skill_name" = "ndf-policies" ]; then - if [ "$DRY_RUN" = false ] && - { [ -e "$SKILLS_DIR/$skill_name" ] || [ -L "$SKILLS_DIR/$skill_name" ]; }; then - rm -rf "$SKILLS_DIR/$skill_name" - echo " REMOVED: $skill_name (steering へ移行済みのため .kiro/skills から削除)" + # 削除するのは旧 installer が張ったシンボリックリンクだけに限る。実体 + # ディレクトリや通常ファイルは利用者が置いたものの可能性があるため、 + # 消さずに案内して手動対応に委ねる。 + if [ -L "$SKILLS_DIR/$skill_name" ]; then + if [ "$DRY_RUN" = false ]; then + rm -f "$SKILLS_DIR/$skill_name" + fi + echo " REMOVED: $skill_name (steering へ移行済みのため .kiro/skills のリンクを削除)" + elif [ -e "$SKILLS_DIR/$skill_name" ]; then + echo " WARN: $SKILLS_DIR/$skill_name はシンボリックリンクではありません。" >&2 + echo " steering (.kiro/steering/ndf-policies.md) と二重に読み込まれるため、" >&2 + echo " 内容を確認のうえ手動で退避または削除してください。" >&2 fi echo " SKIP: $skill_name (steering として配置)" continue From cbced44f5f2bb87388b0a16f1a54003a7dc972d7 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sat, 8 Aug 2026 05:39:32 +0000 Subject: [PATCH 08/11] =?UTF-8?q?Fix:=20=E6=97=A7=20default.json=20?= =?UTF-8?q?=E3=82=92=E5=AE=89=E5=85=A8=E3=81=AA=E5=A0=B4=E5=90=88=E3=81=AB?= =?UTF-8?q?=E9=99=90=E3=82=8A=20ndf.json=20=E3=81=B8=E8=87=AA=E5=8B=95?= =?UTF-8?q?=E7=A7=BB=E8=A1=8C=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 旧版 installer が生成した .kiro/agents/default.json の移行を利用者の手作業に 委ねていたため、移行漏れが起きうる状態だった。NDF 生成物と判定でき、かつ 移行先が未作成のときに限り ndf.json へ移動し、Step 5 の既存マージ処理へ渡す。 - NDF 生成物 + ndf.json なし: default.json を ndf.json へ mv(.bak は残す)。 利用者が追記した mcpServers / hooks / 独自キーは Step 5 のマージで保持される - NDF 生成物 + ndf.json あり: 上書きになるため移行しない - NDF 生成物と判定できない default.json: 利用者の設定を壊すため移行しない - --dry-run: 従来どおり書き込みなし。旧設定を検出したことだけ表示する 移行直後は default.json.bak が同内容のバックアップになるため、ndf.json.bak は 作らない。 回帰テストは kiro-cli 非依存の形で assert-kiro-agent.sh に追加した。 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01AGejnYyYFuSkQjBhW2KQNy --- plugins/ndf-kiro/README.md | 26 +++-- plugins/ndf-kiro/install.sh | 26 ++++- .../assertions/assert-kiro-agent.sh | 97 +++++++++++++++++++ 3 files changed, 135 insertions(+), 14 deletions(-) diff --git a/plugins/ndf-kiro/README.md b/plugins/ndf-kiro/README.md index 5975041a..73f6cfb5 100644 --- a/plugins/ndf-kiro/README.md +++ b/plugins/ndf-kiro/README.md @@ -79,21 +79,27 @@ v4 系の installer は `.kiro/agents/default.json` を生成していました 旧 installer が張った `.kiro/skills/ndf-policies` の symlink は、リンク先が現在のプラグイン配下でなくても再インストール時に削除します(削除するのはリンク自体だけで、リンク先の実体には触れません)。`.kiro/skills/ndf-policies` が symlink ではなく実体のディレクトリやファイルだった場合は、利用者が置いたものの可能性があるため installer は削除せず警告を出します。二重注入を避けるため、内容を確認のうえ手動で退避または削除してください。別の checkout パスから導入した環境でも、steering との二重注入が再インストール 1 回で解消されます。 ```bash -# 1. 再インストール(旧 default.json は自動でバックアップされます) +# 1. 再インストール(旧 default.json は自動でバックアップ・移行されます) bash plugins/ndf-kiro/install.sh --with-slack -# 2. 旧設定に独自の追記があれば .kiro/agents/ndf.json へ写す -# 差分の確認例 -diff .kiro/agents/default.json.bak .kiro/agents/ndf.json - -# 3. 旧設定を削除する -rm .kiro/agents/default.json .kiro/agents/default.json.bak - -# 4. 必要なら既定エージェントを切り替える +# 2. 必要なら既定エージェントを切り替える bash plugins/ndf-kiro/install.sh --set-default + +# 3. 移行を確認したらバックアップを削除する +rm .kiro/agents/default.json.bak ``` -Kiro 用 MCP プラグインの installer(`plugins/mcp/kiro/*/install.sh`)は `.kiro/agents/default.json` を更新します。MCP を併用する場合は、`mcpServers` を `.kiro/agents/ndf.json` へ写してください。写し替えは一度だけで済みます。`install.sh` を再実行しても、写した `mcpServers` は保持されます。 +`.kiro/agents/default.json` は再インストール時に必ず `.kiro/agents/default.json.bak` へバックアップされます。そのうえで installer は次のように振る舞います。 + +| 旧 `default.json` | `ndf.json` | 振る舞い | +| --- | --- | --- | +| 旧版 NDF installer の生成物(`name` が `default` かつ `description` に `NDF` を含む) | なし | `ndf.json` へ自動移行する(`default.json` は残らない)。独自に追記した `mcpServers` / フック / 独自キーは下表のマージで保持される | +| 同上 | あり | 自動移行しない(`ndf.json` の設定を失わないため)。`default.json` は残るので、必要な設定を写したうえで削除する | +| NDF 以外が管理している(利用者が作成したものなど) | 問わない | 自動移行しない。勝手に移行すると利用者の設定を壊すため、バックアップと移行手順の案内のみを行う | + +`--dry-run` では上記の移行を含め一切の書き込みを行いません(旧設定を検出したことだけ表示します)。 + +Kiro 用 MCP プラグインの installer(`plugins/mcp/kiro/*/install.sh`)は `.kiro/agents/default.json` を更新します。自動移行後に MCP installer を実行すると `default.json` が再び作られるため、`mcpServers` を `.kiro/agents/ndf.json` へ写してください。写し替えは一度だけで済みます。`install.sh` を再実行しても、写した `mcpServers` は保持されます。 ### 再インストール時に保持される設定 diff --git a/plugins/ndf-kiro/install.sh b/plugins/ndf-kiro/install.sh index a040e957..63d43429 100755 --- a/plugins/ndf-kiro/install.sh +++ b/plugins/ndf-kiro/install.sh @@ -187,6 +187,9 @@ if [ "$WITH_CODEX" = true ]; then echo "Codex CLI連携: 有効"; else echo "Cod if [ "$DRY_RUN" = true ]; then echo "" echo "DRY RUN: 書き込みは行いませんでした" + if [ -f "$LEGACY_AGENT_FILE" ]; then + echo " 旧設定 $LEGACY_AGENT_FILE を検出(実行時に移行可否を判定します)" + fi echo " エージェント設定: $AGENT_FILE" echo " 常時指示: $STEERING_FILE" echo " Skills数: $SKILL_COUNT" @@ -216,6 +219,7 @@ PY echo "常時指示を生成: $STEERING_FILE" # --- Step 4: Migrate legacy default agent --- +MIGRATED_FROM_LEGACY=false if [ -f "$LEGACY_AGENT_FILE" ]; then cp "$LEGACY_AGENT_FILE" "${LEGACY_AGENT_FILE}.bak" echo "" @@ -236,9 +240,22 @@ except Exception: sys.exit(1) sys.exit(0 if matched else 1) ' "$LEGACY_AGENT_FILE"; then - echo " これは旧版 NDF installer の生成物です。移行手順:" - echo " 1. 独自に追記した設定があればバックアップから $AGENT_FILE へ写す" - echo " 2. rm $LEGACY_AGENT_FILE ${LEGACY_AGENT_FILE}.bak" + echo " これは旧版 NDF installer の生成物です。" + if [ -f "$AGENT_FILE" ]; then + # 移行先が既にある場合に上書きすると、そちらの利用者設定を失う。手動判断へ回す。 + echo " ただし $AGENT_FILE が既に存在するため自動移行しません。" + echo " 移行手順:" + echo " 1. 必要な設定が ${LEGACY_AGENT_FILE}.bak にだけ残っていないか確認する" + echo " 2. rm $LEGACY_AGENT_FILE" + else + # 旧設定を移行先へ置いてから Step 5 に進める。Step 5 は既存ファイルから + # installer 管理外のキーを引き継ぐため、これだけで利用者設定の移行と + # テンプレート由来キー(エージェント名など)の最新化が両方完了する。 + mv "$LEGACY_AGENT_FILE" "$AGENT_FILE" + MIGRATED_FROM_LEGACY=true + echo " $AGENT_FILE へ自動移行しました(利用者が追記した設定は下で引き継ぎます)。" + echo " 不要になったら: rm ${LEGACY_AGENT_FILE}.bak" + fi else echo " NDF 以外が管理している設定です。移行手順:" echo " 1. 必要な mcpServers / hooks を $AGENT_FILE へ写す" @@ -253,7 +270,8 @@ fi # --- Step 5: Generate agent config --- mkdir -p "$KIRO_DIR/agents" -if [ -f "$AGENT_FILE" ]; then +# Step 4 で移行した直後は ${LEGACY_AGENT_FILE}.bak が同じ内容のバックアップなので取らない。 +if [ -f "$AGENT_FILE" ] && [ "$MIGRATED_FROM_LEGACY" = false ]; then cp "$AGENT_FILE" "${AGENT_FILE}.bak" echo "既存設定をバックアップ: ${AGENT_FILE}.bak" fi diff --git a/tests/runtime-smoke/assertions/assert-kiro-agent.sh b/tests/runtime-smoke/assertions/assert-kiro-agent.sh index dfe56310..750e77b1 100755 --- a/tests/runtime-smoke/assertions/assert-kiro-agent.sh +++ b/tests/runtime-smoke/assertions/assert-kiro-agent.sh @@ -149,6 +149,103 @@ config.pop("smokeUserKey", None) path.write_text(json.dumps(config, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") PY echo "reinstall preserved user-managed agent settings" >> "$LOG" + +# 旧 .kiro/agents/default.json からの自動移行を検査する。kiro-cli には依存しない。 +MIGRATION_ROOT="$ARTIFACT_DIR/kiro-legacy-migration" +rm -rf "$MIGRATION_ROOT" + +# $1: プロジェクト, $2: description(installer の NDF 生成物判定に使う) +write_legacy_agent() { + mkdir -p "$1/.kiro/agents" + cat > "$1/.kiro/agents/default.json" <> "$LOG" 2>&1 +} + +# 1. NDF 生成物 + ndf.json なし → 自動移行し、利用者の mcpServers を引き継ぐ +case_ndf="$MIGRATION_ROOT/ndf-generated" +write_legacy_agent "$case_ndf" "NDF workflow agent" +install_into "$case_ndf" +test ! -e "$case_ndf/.kiro/agents/default.json" +test -f "$case_ndf/.kiro/agents/default.json.bak" +python3 - "$case_ndf/.kiro/agents/ndf.json" <<'PY' +import json +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +config = json.loads(path.read_text(encoding="utf-8")) +if config.get("name") != "ndf": + raise SystemExit(f"legacy migration did not refresh installer-managed keys: {path}") +if "legacy-user-mcp" not in config.get("mcpServers", {}): + raise SystemExit(f"legacy migration dropped a user-managed mcpServers entry: {path}") +PY + +# 2. NDF 生成物と判定できない default.json → 移行せず元のまま残す +case_user="$MIGRATION_ROOT/user-owned" +write_legacy_agent "$case_user" "my own agent" +install_into "$case_user" +test -f "$case_user/.kiro/agents/default.json" +test -f "$case_user/.kiro/agents/default.json.bak" +python3 - "$case_user/.kiro/agents/ndf.json" <<'PY' +import json +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +config = json.loads(path.read_text(encoding="utf-8")) +if "legacy-user-mcp" in config.get("mcpServers", {}): + raise SystemExit(f"a non-NDF default.json must not be migrated automatically: {path}") +PY + +# 3. default.json と ndf.json の両方がある → 移行せず既存の ndf.json を尊重する +case_both="$MIGRATION_ROOT/both" +mkdir -p "$case_both" +install_into "$case_both" +python3 - "$case_both/.kiro/agents/ndf.json" <<'PY' +import json +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +config = json.loads(path.read_text(encoding="utf-8")) +config["smokeExistingKey"] = "keep-me" +path.write_text(json.dumps(config, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") +PY +write_legacy_agent "$case_both" "NDF workflow agent" +install_into "$case_both" +test -f "$case_both/.kiro/agents/default.json" +python3 - "$case_both/.kiro/agents/ndf.json" <<'PY' +import json +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +config = json.loads(path.read_text(encoding="utf-8")) +if config.get("smokeExistingKey") != "keep-me": + raise SystemExit(f"legacy migration overwrote an existing ndf.json: {path}") +if "legacy-user-mcp" in config.get("mcpServers", {}): + raise SystemExit(f"legacy migration overwrote an existing ndf.json: {path}") +PY + +# 4. --dry-run → 移行を含め一切書き込まない +case_dry="$MIGRATION_ROOT/dry-run" +write_legacy_agent "$case_dry" "NDF workflow agent" +dry_state() { (cd "$case_dry" && find . | sort && find . -type f -exec sha256sum {} + | sort); } +before_dry="$(dry_state)" +install_into "$case_dry" --dry-run +if [ "$(dry_state)" != "$before_dry" ]; then + echo "--dry-run modified the project: $case_dry" >&2 + exit 1 +fi +echo "installer migrated a legacy default.json only when it is safe" >> "$LOG" fi # --- workspace 限定の検査ここまで --- From 07ca52202ab222547895ad505e9f903e88d6f1d2 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sat, 8 Aug 2026 05:46:48 +0000 Subject: [PATCH 09/11] =?UTF-8?q?Fix:=20=E6=97=A7=20default.json=20?= =?UTF-8?q?=E3=81=AE=E6=A1=88=E5=86=85=E3=81=A7=20.bak=20=E3=82=82?= =?UTF-8?q?=E5=89=8A=E9=99=A4=E5=AF=BE=E8=B1=A1=E3=81=AB=E5=90=AB=E3=82=81?= =?UTF-8?q?=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移行しない分岐の案内が default.json だけを消す形になっており、NDF 生成物と 判定できない場合の案内 (.bak も含めて削除) と揃っていなかった。利用者の環境に 不要なバックアップが残り続けるのを防ぐため、両方を挙げる形へ統一した。 --- plugins/ndf-kiro/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ndf-kiro/install.sh b/plugins/ndf-kiro/install.sh index 63d43429..7331c2a0 100755 --- a/plugins/ndf-kiro/install.sh +++ b/plugins/ndf-kiro/install.sh @@ -246,7 +246,7 @@ sys.exit(0 if matched else 1) echo " ただし $AGENT_FILE が既に存在するため自動移行しません。" echo " 移行手順:" echo " 1. 必要な設定が ${LEGACY_AGENT_FILE}.bak にだけ残っていないか確認する" - echo " 2. rm $LEGACY_AGENT_FILE" + echo " 2. 不要になったら rm $LEGACY_AGENT_FILE ${LEGACY_AGENT_FILE}.bak" else # 旧設定を移行先へ置いてから Step 5 に進める。Step 5 は既存ファイルから # installer 管理外のキーを引き継ぐため、これだけで利用者設定の移行と From 2c6081d7553b1cc5cc30302ac54e37b8827d556d Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sat, 8 Aug 2026 05:51:33 +0000 Subject: [PATCH 10/11] =?UTF-8?q?Fix:=20=E6=97=A7=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E3=81=AE=E8=87=AA=E5=8B=95=E7=A7=BB=E8=A1=8C=E3=82=92=E5=8E=B3?= =?UTF-8?q?=E5=AF=86=E5=8C=96=E3=81=97=E3=80=81=E5=BC=95=E3=81=8D=E7=B6=99?= =?UTF-8?q?=E3=81=8E=E6=99=82=E3=81=AE=E5=9E=8B=E6=A4=9C=E8=A8=BC=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 旧 NDF 生成物の判定を description の部分一致から、旧テンプレート固有の description 完全一致 + (resources の skill:// 指定 または agentSpawn フックの CLAUDE.ndf.md 検査) の組み合わせへ変えた。NDF 用に自作した default エージェントをテンプレートで上書きしてしまう問題を防ぐ - 既存 ndf.json の hooks / mcpServers が dict 以外だと .items() で installer が 例外終了していた。壊れた JSON と同じく警告して引き継ぎ対象から外す --- plugins/ndf-kiro/install.sh | 51 ++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/plugins/ndf-kiro/install.sh b/plugins/ndf-kiro/install.sh index b601879d..d3124f8f 100755 --- a/plugins/ndf-kiro/install.sh +++ b/plugins/ndf-kiro/install.sh @@ -239,10 +239,35 @@ try: config = json.load(open(sys.argv[1], encoding="utf-8")) # JSON がオブジェクト以外(配列など)でも AttributeError にせず、壊れた JSON と # 同じ「NDF 生成物ではない」扱いへ倒す。 + # 旧 installer が生成したものだけを識別する。description に NDF が含まれる + # だけでは、利用者が NDF 用に自作した default エージェントまで移行対象に + # なり、テンプレートで上書きしてしまう。旧テンプレート固有の値との一致を + # 求める。 + LEGACY_DESCRIPTION = "NDF統合開発エージェント(Kiro CLI用)" + LEGACY_RESOURCE = "skill://.kiro/skills/**/SKILL.md" + LEGACY_HOOK_MARK = "CLAUDE.ndf.md" + + def has_legacy_hook(cfg): + hooks = cfg.get("hooks") + if not isinstance(hooks, dict): + return False + spawn = hooks.get("agentSpawn") + if not isinstance(spawn, list): + return False + return any( + isinstance(h, dict) and LEGACY_HOOK_MARK in str(h.get("command") or "") + for h in spawn + ) + + resources = config.get("resources") if isinstance(config, dict) else None matched = ( isinstance(config, dict) and config.get("name") == "default" - and "NDF" in (config.get("description") or "") + and config.get("description") == LEGACY_DESCRIPTION + and ( + (isinstance(resources, list) and LEGACY_RESOURCE in resources) + or has_legacy_hook(config) + ) ) except Exception: sys.exit(1) @@ -341,14 +366,22 @@ for key, value in existing.items(): if key not in managed_keys: config[key] = value kept.append(key) -for key, value in (existing.get("hooks") or {}).items(): - if key not in managed_hooks: - hooks[key] = value - kept.append(f"hooks.{key}") -for key, value in (existing.get("mcpServers") or {}).items(): - if key not in managed_servers: - servers[key] = value - kept.append(f"mcpServers.{key}") +# hooks / mcpServers が dict 以外(配列や文字列)だと .items() で落ちるため、 +# 壊れた JSON と同じく警告して引き継ぎ対象から外す。 +for section, target, managed in ( + ("hooks", hooks, managed_hooks), + ("mcpServers", servers, managed_servers), +): + value = existing.get(section) + if value is None: + continue + if not isinstance(value, dict): + print(f" WARN: 既存の {agent_file} の {section} が JSON オブジェクトではないため引き継ぎません") + continue + for key, item in value.items(): + if key not in managed: + target[key] = item + kept.append(f"{section}.{key}") if not hooks: config.pop("hooks", None) From 784532107e2caf5e20698bc7fc2e811ea0082214 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sat, 8 Aug 2026 05:55:46 +0000 Subject: [PATCH 11/11] =?UTF-8?q?Test:=20=E8=87=AA=E5=8B=95=E7=A7=BB?= =?UTF-8?q?=E8=A1=8C=E3=81=AE=20fixture=20=E3=81=A8=20README=20=E3=82=92?= =?UTF-8?q?=E5=AE=9F=E8=A3=85=E3=81=AE=E5=88=A4=E5=AE=9A=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E3=81=AB=E5=90=88=E3=82=8F=E3=81=9B=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 旧 NDF 生成物の判定を厳密化した際に、動作確認テストの fixture と README の 説明が追随していなかった。 - fixture を旧 default.json.template と同じ description / resources / agentSpawn フックを持つ形にし、NDF 生成物ケースと利用者自作ケースを 引数で切り替える。both / dry-run のケースも NDF 生成物側へ揃えた - README の自動移行の条件を実装(description 完全一致 + 旧 resources または 旧 agentSpawn フック)と一致させた fixture を利用者自作側へ差し替えると runtime-smoke-test.sh --runtime kiro が exit 1 になることを確認済み(検査が実際に効いている)。 --- plugins/ndf-kiro/README.md | 2 +- .../assertions/assert-kiro-agent.sh | 42 +++++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/plugins/ndf-kiro/README.md b/plugins/ndf-kiro/README.md index 73f6cfb5..7d8feead 100644 --- a/plugins/ndf-kiro/README.md +++ b/plugins/ndf-kiro/README.md @@ -93,7 +93,7 @@ rm .kiro/agents/default.json.bak | 旧 `default.json` | `ndf.json` | 振る舞い | | --- | --- | --- | -| 旧版 NDF installer の生成物(`name` が `default` かつ `description` に `NDF` を含む) | なし | `ndf.json` へ自動移行する(`default.json` は残らない)。独自に追記した `mcpServers` / フック / 独自キーは下表のマージで保持される | +| 旧版 NDF installer の生成物(`name` が `default`、`description` が旧テンプレートと完全一致、かつ旧 `resources` の `skill://.kiro/skills/**/SKILL.md` または `agentSpawn` フックの `CLAUDE.ndf.md` 検査を持つ) | なし | `ndf.json` へ自動移行する(`default.json` は残らない)。独自に追記した `mcpServers` / フック / 独自キーは下表のマージで保持される | | 同上 | あり | 自動移行しない(`ndf.json` の設定を失わないため)。`default.json` は残るので、必要な設定を写したうえで削除する | | NDF 以外が管理している(利用者が作成したものなど) | 問わない | 自動移行しない。勝手に移行すると利用者の設定を壊すため、バックアップと移行手順の案内のみを行う | diff --git a/tests/runtime-smoke/assertions/assert-kiro-agent.sh b/tests/runtime-smoke/assertions/assert-kiro-agent.sh index 750e77b1..3bf96f9f 100755 --- a/tests/runtime-smoke/assertions/assert-kiro-agent.sh +++ b/tests/runtime-smoke/assertions/assert-kiro-agent.sh @@ -154,16 +154,44 @@ echo "reinstall preserved user-managed agent settings" >> "$LOG" MIGRATION_ROOT="$ARTIFACT_DIR/kiro-legacy-migration" rm -rf "$MIGRATION_ROOT" -# $1: プロジェクト, $2: description(installer の NDF 生成物判定に使う) +# $1: プロジェクト, $2: ndf ならば旧 installer の生成物そのままの fixture、 +# それ以外なら NDF 生成物と判定されない fixture を書く。 +# +# installer の判定は「旧テンプレート固有の description の完全一致」+「旧 resources +# の skill:// 指定 または agentSpawn フックの CLAUDE.ndf.md 検査」なので、 +# 自動移行ケースの fixture は旧 default.json.template と同じ値を持たせる。 write_legacy_agent() { mkdir -p "$1/.kiro/agents" - cat > "$1/.kiro/agents/default.json" < "$1/.kiro/agents/default.json" <<'JSON' { "name": "default", - "description": "$2", + "description": "NDF統合開発エージェント(Kiro CLI用)", + "tools": ["*"], + "resources": [ + "file://AGENTS.md", + "file://README.md", + "file://.kiro/skills/ndf-policies/SKILL.md", + "skill://.kiro/skills/**/SKILL.md" + ], + "hooks": { + "agentSpawn": [ + { "command": "if [ -f \"${PWD}/CLAUDE.ndf.md\" ]; then echo \"[NDF] CLAUDE.ndf.md\"; fi" } + ] + }, "mcpServers": { "legacy-user-mcp": { "command": "echo", "args": ["legacy"] } } } JSON + else + cat > "$1/.kiro/agents/default.json" <<'JSON' +{ + "name": "default", + "description": "my own agent", + "resources": ["file://AGENTS.md"], + "mcpServers": { "legacy-user-mcp": { "command": "echo", "args": ["legacy"] } } +} +JSON + fi } install_into() { bash "$REPO_ROOT/plugins/ndf-kiro/install.sh" --project "$1" "${@:2}" >> "$LOG" 2>&1 @@ -171,7 +199,7 @@ install_into() { # 1. NDF 生成物 + ndf.json なし → 自動移行し、利用者の mcpServers を引き継ぐ case_ndf="$MIGRATION_ROOT/ndf-generated" -write_legacy_agent "$case_ndf" "NDF workflow agent" +write_legacy_agent "$case_ndf" ndf install_into "$case_ndf" test ! -e "$case_ndf/.kiro/agents/default.json" test -f "$case_ndf/.kiro/agents/default.json.bak" @@ -190,7 +218,7 @@ PY # 2. NDF 生成物と判定できない default.json → 移行せず元のまま残す case_user="$MIGRATION_ROOT/user-owned" -write_legacy_agent "$case_user" "my own agent" +write_legacy_agent "$case_user" user install_into "$case_user" test -f "$case_user/.kiro/agents/default.json" test -f "$case_user/.kiro/agents/default.json.bak" @@ -219,7 +247,7 @@ config = json.loads(path.read_text(encoding="utf-8")) config["smokeExistingKey"] = "keep-me" path.write_text(json.dumps(config, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") PY -write_legacy_agent "$case_both" "NDF workflow agent" +write_legacy_agent "$case_both" ndf install_into "$case_both" test -f "$case_both/.kiro/agents/default.json" python3 - "$case_both/.kiro/agents/ndf.json" <<'PY' @@ -237,7 +265,7 @@ PY # 4. --dry-run → 移行を含め一切書き込まない case_dry="$MIGRATION_ROOT/dry-run" -write_legacy_agent "$case_dry" "NDF workflow agent" +write_legacy_agent "$case_dry" ndf dry_state() { (cd "$case_dry" && find . | sort && find . -type f -exec sha256sum {} + | sort); } before_dry="$(dry_state)" install_into "$case_dry" --dry-run