@nahisaho/shikigami 2.0.6 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +0 -42
- package/README.md +136 -132
- package/mcp-server/package.json +1 -1
- package/package.json +1 -1
- package/scripts/cli.js +1 -11
- package/scripts/init.js +0 -5
- package/scripts/build-cowork-plugin.js +0 -859
package/CHANGELOG.md
CHANGED
|
@@ -5,48 +5,6 @@ All notable changes to SHIKIGAMI will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [2.0.6] - 2026-05-18
|
|
9
|
-
|
|
10
|
-
### Changed
|
|
11
|
-
|
|
12
|
-
- **Coworkプラグインビルダーをゼロから再構築**
|
|
13
|
-
- 公式ドキュメント「プラグインをゼロからビルドする」に完全準拠
|
|
14
|
-
- ASKILL検証コード(ASKILL-M001〜P008)によるバリデーション
|
|
15
|
-
- コンパニオンファイルパス検証(隠しファイル、パストラバーサル、Windows予約名、安全文字チェック)
|
|
16
|
-
- Cowork用SKILL.md自動リライト(cowork.category, cowork.icon, metadata追加)
|
|
17
|
-
- パス参照の自動更新(統合後のreferences/パスに変換)
|
|
18
|
-
- Additional Resources セクション自動生成
|
|
19
|
-
- セキュリティ改善: execSync → execFileSync(シェルインジェクション防止)
|
|
20
|
-
- SKILL.md本文サイズ警告(3000語超で警告)
|
|
21
|
-
- 統合ファイルの5MB超過時チャンキング対応
|
|
22
|
-
- マニフェスト検証(GUID形式、重複folder、スキル数上限)
|
|
23
|
-
- クロスプラットフォーム互換性表示(GitHub Copilot CLI / VS Code / Claude Code / Gemini CLI)
|
|
24
|
-
- 参照: https://learn.microsoft.com/microsoft-365/copilot/cowork/cowork-plugin-development
|
|
25
|
-
|
|
26
|
-
## [2.0.5] - 2026-05-18
|
|
27
|
-
|
|
28
|
-
### Changed
|
|
29
|
-
|
|
30
|
-
- **Copilot Cowork連携を公式プラグイン方式に変更**
|
|
31
|
-
- 旧: サードパーティMCPサーバー(msartem/copilot_cowork_mcp)のセットアップ
|
|
32
|
-
- 新: M365 Unified App Manifest準拠のプラグインパッケージ(.zip)を生成
|
|
33
|
-
- `npx shikigami cowork` でCoworkプラグインをビルド
|
|
34
|
-
- manifest.json自動生成、アイコン生成、スキル検証機能
|
|
35
|
-
- Companionファイル20制限への自動統合(63ファイル→14ファイル等)
|
|
36
|
-
- 参照: https://learn.microsoft.com/microsoft-365/copilot/cowork/cowork-plugin-development
|
|
37
|
-
- **README.md全面刷新**
|
|
38
|
-
- インストールコマンド修正(`@nahisaho/shikigami`)
|
|
39
|
-
- 全19プロンプトをカテゴリ別に一覧化
|
|
40
|
-
- Agent Skills: npmパッケージ含有4スキルに正確化
|
|
41
|
-
- 50+コンサルティングフレームワーク一覧を追加
|
|
42
|
-
- アーキテクチャ図をv2.0.5に更新
|
|
43
|
-
- CLIコマンド一覧を追加
|
|
44
|
-
|
|
45
|
-
### Removed
|
|
46
|
-
|
|
47
|
-
- `setup-cowork.js` — サードパーティMCPサーバーセットアップスクリプト
|
|
48
|
-
- `init.js` の旧Cowork MCP状態チェック
|
|
49
|
-
|
|
50
8
|
## [2.0.4] - 2026-05-18
|
|
51
9
|
|
|
52
10
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,66 +1,90 @@
|
|
|
1
1
|
# SHIKIGAMI
|
|
2
2
|
|
|
3
|
-
**GitHub Copilot Agent Skills for Deep Research & Consulting**
|
|
3
|
+
**GitHub Copilot Agent Skills for Deep Research & McKinsey Consulting**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
マッキンゼーのコンサルティング手法(仮説駆動、MECE、ピラミッド原則、7Sフレームワーク等)を活用した深層リサーチ自動化Agent Skillsパッケージです。GitHub Copilot CLI と連携し、Copilot CLI の組み込み機能を活用しつつ、SHIKIGAMI独自のリサーチ・コンサルティング機能を提供します。
|
|
6
6
|
|
|
7
7
|
## 🎯 できること
|
|
8
8
|
|
|
9
|
-
- **対話的目的探索**:
|
|
10
|
-
- **Deep Research**:
|
|
11
|
-
-
|
|
12
|
-
- **高品質レポート生成**:
|
|
9
|
+
- **対話的目的探索**: ユーザーの表層的な依頼から「真の目的」を探索
|
|
10
|
+
- **Deep Research**: WebResearcherパラダイムに基づく反復的深層リサーチ
|
|
11
|
+
- **マッキンゼー・フレームワーク分析**: 仮説駆動、イシューツリー、7S、ピラミッド原則等を適用
|
|
12
|
+
- **高品質レポート生成**: ハルシネーション防止、ソース追跡、引用管理
|
|
13
13
|
- **マルチポップ探索**: リサーチ中の分岐点を自動検出し、複数パスを同時探索
|
|
14
14
|
- **ベクトル検索**: 過去のリサーチ資産をセマンティック検索で再利用
|
|
15
|
-
-
|
|
15
|
+
- **品質検証ループ**: Build→Type→Lint→Test→Security→Diff の6フェーズ検証
|
|
16
16
|
|
|
17
17
|
## 📦 インストール
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
npm install @nahisaho/shikigami
|
|
21
|
-
npx shikigami init
|
|
20
|
+
npm install @nahisaho/shikigami-mck
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
または、リポジトリをクローン:
|
|
25
24
|
|
|
26
25
|
```bash
|
|
27
|
-
|
|
26
|
+
git clone https://github.com/nahisaho/SHIKIGAMI.git
|
|
28
27
|
```
|
|
29
28
|
|
|
30
29
|
## 🏗️ アーキテクチャ
|
|
31
30
|
|
|
31
|
+
SHIKIGAMI v2.0.0 は GitHub Copilot CLI の組み込み機能を最大限活用する設計に移行しました。
|
|
32
|
+
|
|
32
33
|
```
|
|
33
34
|
┌─────────────────────────────────────────────────┐
|
|
34
35
|
│ GitHub Copilot CLI │
|
|
35
36
|
│ web_search / web_fetch / store_memory / grep │
|
|
36
37
|
│ explore / research / rubber-duck agents │
|
|
38
|
+
│ /session / /context / /compact │
|
|
37
39
|
├─────────────────────────────────────────────────┤
|
|
38
|
-
│ SHIKIGAMI v2.0.
|
|
40
|
+
│ SHIKIGAMI v2.0.0 │
|
|
39
41
|
│ ┌──────────────┐ ┌───────────────────────┐ │
|
|
40
42
|
│ │ Agent Skills │ │ MCP Server (10 tools) │ │
|
|
41
|
-
│ │ (
|
|
43
|
+
│ │ (15 skills) │ │ embed / similarity │ │
|
|
42
44
|
│ │ │ │ semantic_search │ │
|
|
43
|
-
│ │
|
|
44
|
-
│ │
|
|
45
|
-
│ │
|
|
46
|
-
│ │
|
|
47
|
-
│
|
|
48
|
-
│ │ 19 Prompts │ │
|
|
49
|
-
│ └──────────────┘ │
|
|
50
|
-
├─────────────────────────────────────────────────┤
|
|
51
|
-
│ Copilot Cowork Plugin (.zip) │
|
|
52
|
-
│ npx shikigami cowork で M365 プラグイン生成 │
|
|
45
|
+
│ │ Research │ │ branch_detect/eval/ │ │
|
|
46
|
+
│ │ Consulting │ │ select │ │
|
|
47
|
+
│ │ Quality │ │ set/get_project │ │
|
|
48
|
+
│ │ MUSUBIX SDD │ │ save_prompt/research │ │
|
|
49
|
+
│ └──────────────┘ └───────────────────────┘ │
|
|
53
50
|
└─────────────────────────────────────────────────┘
|
|
54
51
|
```
|
|
55
52
|
|
|
56
|
-
## 🔧 Agent Skills(
|
|
53
|
+
## 🔧 Agent Skills(15スキル)
|
|
54
|
+
|
|
55
|
+
### リサーチ・コンサルティング
|
|
57
56
|
|
|
58
57
|
| スキル | 説明 |
|
|
59
58
|
|--------|------|
|
|
60
59
|
| `shikigami-planner` | 対話的目的探索・5 Whys・JTBD・リサーチ計画立案 |
|
|
61
60
|
| `shikigami-deep-research` | Think→Report→Actionサイクルの反復的深層リサーチ |
|
|
62
|
-
| `shikigami-consulting-framework` |
|
|
63
|
-
| `shikigami-writing` |
|
|
61
|
+
| `shikigami-consulting-framework` | マッキンゼー・フレームワーク分析(仮説駆動・7S・ピラミッド原則等) |
|
|
62
|
+
| `shikigami-writing` | レポート生成・ハルシネーション検出・引用管理 |
|
|
63
|
+
|
|
64
|
+
### 品質・検証
|
|
65
|
+
|
|
66
|
+
| スキル | 説明 |
|
|
67
|
+
|--------|------|
|
|
68
|
+
| `build-fix` | ビルドエラーを分類・反復修正(TypeScript/ESLint/依存関係) |
|
|
69
|
+
| `checkpoint` | セーフポイントの作成・復元・比較(Git統合) |
|
|
70
|
+
| `e2e-runner` | Playwrightを使用したE2Eテスト生成・実行 |
|
|
71
|
+
| `eval-harness` | pass@kメトリクスでAIコード生成品質を評価 |
|
|
72
|
+
| `verification-loop` | Build→Type→Lint→Test→Security→Diff の6フェーズ検証 |
|
|
73
|
+
|
|
74
|
+
### MUSUBIX SDD
|
|
75
|
+
|
|
76
|
+
| スキル | 説明 |
|
|
77
|
+
|--------|------|
|
|
78
|
+
| `musubix-sdd-workflow` | 10憲法条項に従った仕様駆動開発ガイド |
|
|
79
|
+
| `musubix-domain-inference` | 自動ドメイン検出・コンポーネント推論 |
|
|
80
|
+
| `musubix-code-generation` | 設計仕様からのコード生成 |
|
|
81
|
+
| `musubix-test-generation` | TDD/BDDによるテスト生成 |
|
|
82
|
+
| `musubix-adr-generation` | Architecture Decision Records作成 |
|
|
83
|
+
| `musubix-best-practices` | 学習済み17ベストプラクティスガイド |
|
|
84
|
+
| `musubix-c4-design` | C4モデル設計ドキュメント作成 |
|
|
85
|
+
| `musubix-technical-writing` | 技術ドキュメント作成 |
|
|
86
|
+
| `musubix-ears-validation` | EARS形式要件の検証・作成 |
|
|
87
|
+
| `musubix-traceability` | 要件・設計・コード・テスト間のトレーサビリティ管理 |
|
|
64
88
|
|
|
65
89
|
## 🔌 MCP Server(10ツール)
|
|
66
90
|
|
|
@@ -76,131 +100,111 @@ cd mcp-server && npm install && npm run build
|
|
|
76
100
|
| `branch_evaluate` | 分岐パスのスコアリング・評価 |
|
|
77
101
|
| `branch_select` | 最適な探索パスの選択 |
|
|
78
102
|
|
|
79
|
-
## 📝 Prompts
|
|
80
|
-
|
|
81
|
-
### コア
|
|
103
|
+
## 📝 Prompts
|
|
82
104
|
|
|
83
105
|
| プロンプト | 説明 |
|
|
84
106
|
|-----------|------|
|
|
85
|
-
| `shikigami-full-research` | 統合リサーチ(Planner→Research→Framework→Writing) |
|
|
86
107
|
| `shikigami-purpose-discovery` | 目的探索を開始 |
|
|
87
108
|
| `shikigami-deep-research` | Deep Researchを実行 |
|
|
88
|
-
| `shikigami-framework-analysis` |
|
|
89
|
-
| `shikigami-report-writing` |
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
|
96
|
-
|
|
97
|
-
|
|
|
98
|
-
|
|
|
99
|
-
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
|
104
|
-
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
| `shikigami-qiita-article` | Qiita記事形式で出力 |
|
|
118
|
-
| `shikigami-manifest` | リサーチマニフェスト生成 |
|
|
119
|
-
|
|
120
|
-
## 📚 コンサルティング・フレームワーク一覧(50+)
|
|
121
|
-
|
|
122
|
-
### 戦略分析
|
|
123
|
-
SWOT、PEST、5Forces、3C、BCG Matrix、GE Matrix、Ansoff Matrix、Blue Ocean、VRIO、Value Chain
|
|
124
|
-
|
|
125
|
-
### マーケティング
|
|
126
|
-
4P、4C、STP、AIDMA/AISAS、Customer Journey、Persona、Positioning Map
|
|
127
|
-
|
|
128
|
-
### 問題解決
|
|
129
|
-
MECE、5 Whys、Issue Tree、Logic Tree、Fishbone、As-Is/To-Be
|
|
130
|
-
|
|
131
|
-
### 組織・プロセス
|
|
132
|
-
7S、RACI、PDCA、OODA、ECRS
|
|
133
|
-
|
|
134
|
-
### イノベーション
|
|
135
|
-
Business Model Canvas、Lean Canvas、Design Thinking、SCAMPER、TAM/SAM/SOM、AARRR、Value Proposition Canvas
|
|
136
|
-
|
|
137
|
-
### 意思決定
|
|
138
|
-
Decision Matrix、Cost-Benefit、Risk Matrix、Pros-Cons
|
|
139
|
-
|
|
140
|
-
### 思考フレームワーク
|
|
141
|
-
Pyramid Principle、So What/Why So、PREP
|
|
142
|
-
|
|
143
|
-
### PwC固有
|
|
144
|
-
BXT、Strategy&、Fit for Growth、Digital Maturity、ESG Integration、Three Lines of Defense、TIMM
|
|
145
|
-
|
|
146
|
-
## 🤝 Microsoft 365 Copilot Cowork 連携
|
|
147
|
-
|
|
148
|
-
SHIKIGAMIのAgent SkillsをCopilot Coworkプラグインとしてパッケージ化できます。
|
|
149
|
-
|
|
150
|
-
```bash
|
|
151
|
-
# Coworkプラグインパッケージをビルド
|
|
152
|
-
npx shikigami cowork
|
|
153
|
-
|
|
154
|
-
# 検証のみ(ドライラン)
|
|
155
|
-
npx shikigami cowork --check
|
|
156
|
-
|
|
157
|
-
# 出力先を指定
|
|
158
|
-
npx shikigami cowork --out ./dist
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
生成された `.zip` ファイルをM365 Admin Center > Manage Apps > Upload Custom Appからアップロードすると、Coworkで SHIKIGAMIのスキルが利用可能になります。
|
|
162
|
-
|
|
163
|
-
**参照**: [Cowork Plugin Development](https://learn.microsoft.com/microsoft-365/copilot/cowork/cowork-plugin-development)
|
|
164
|
-
|
|
165
|
-
## 🚀 CLI コマンド
|
|
166
|
-
|
|
167
|
-
```bash
|
|
168
|
-
npx shikigami init # SHIKIGAMIファイルを初期化
|
|
169
|
-
npx shikigami upgrade # 最新版にアップグレード
|
|
170
|
-
npx shikigami cowork # Coworkプラグインをビルド
|
|
171
|
-
npx shikigami new [name] # 新規リサーチプロジェクト作成
|
|
172
|
-
npx shikigami find-related [keyword] # 関連プロジェクト検索
|
|
173
|
-
npx shikigami inherit [options] # 過去レポートからナレッジ継承
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
## 🔄 リサーチワークフロー
|
|
109
|
+
| `shikigami-framework-analysis` | マッキンゼーフレームワーク分析を実行 |
|
|
110
|
+
| `shikigami-report-writing` | ピラミッド原則に基づくレポートを生成 |
|
|
111
|
+
| `shikigami-full-research` | 統合リサーチを実行 |
|
|
112
|
+
|
|
113
|
+
## 📚 マッキンゼー・フレームワーク一覧
|
|
114
|
+
|
|
115
|
+
### 問題解決・仮説思考
|
|
116
|
+
| フレームワーク | 説明 |
|
|
117
|
+
|--------------|------|
|
|
118
|
+
| **仮説駆動アプローチ** | 仮説を立て、検証し、結論を導く問題解決手法 |
|
|
119
|
+
| **イシューツリー** | 問題をMECEに分解し、解決の優先順位を明確化 |
|
|
120
|
+
| **ピラミッド原則** | 結論先行で論理的にコミュニケーション(Barbara Minto) |
|
|
121
|
+
| **MECE** | 漏れなくダブりなく整理 |
|
|
122
|
+
|
|
123
|
+
### 組織・戦略
|
|
124
|
+
| フレームワーク | 説明 |
|
|
125
|
+
|--------------|------|
|
|
126
|
+
| **マッキンゼーの7S** | 組織の7要素(Strategy, Structure, Systems, Shared Values, Style, Staff, Skills)の整合性分析 |
|
|
127
|
+
| **3つの地平線** | 短期(H1)・中期(H2)・長期(H3)の成長を同時管理 |
|
|
128
|
+
| **成長のグラニュラリティ** | 成長を詳細に分解して真の成長源を特定 |
|
|
129
|
+
|
|
130
|
+
### 業績改善
|
|
131
|
+
| フレームワーク | 説明 |
|
|
132
|
+
|--------------|------|
|
|
133
|
+
| **間接費価値分析(OVA)** | 間接部門のコストと価値を分析し最適化 |
|
|
134
|
+
| **プロフィットプール分析** | バリューチェーン全体の利益分布を可視化 |
|
|
135
|
+
| **SCP分析** | 産業構造→企業行動→業績の因果関係を分析 |
|
|
136
|
+
|
|
137
|
+
## 🔄 マッキンゼー式ワークフロー
|
|
177
138
|
|
|
178
139
|
```mermaid
|
|
179
140
|
flowchart TB
|
|
180
|
-
subgraph Phase1["Phase 1:
|
|
181
|
-
P1A[
|
|
182
|
-
P1B --> P1C[
|
|
141
|
+
subgraph Phase1["Phase 1: 問題定義"]
|
|
142
|
+
P1A[クライアントの真の課題特定] --> P1B[成功の定義]
|
|
143
|
+
P1B --> P1C[スコープと制約の確認]
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
subgraph Phase2["Phase 2: 仮説構築"]
|
|
147
|
+
P2A[初期仮説の設定] --> P2B[支持論拠の整理]
|
|
148
|
+
P2B --> P2C[反証可能な形式で表現]
|
|
183
149
|
end
|
|
184
150
|
|
|
185
|
-
subgraph
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
P2C --> P2A
|
|
151
|
+
subgraph Phase3["Phase 3: イシュー分解"]
|
|
152
|
+
P3A[イシューツリー作成] --> P3B[優先順位付け]
|
|
153
|
+
P3B --> P3C[分析計画策定]
|
|
189
154
|
end
|
|
190
155
|
|
|
191
|
-
subgraph
|
|
192
|
-
|
|
193
|
-
|
|
156
|
+
subgraph Phase4["Phase 4: データ収集・分析"]
|
|
157
|
+
P4A[定量・定性データ収集] --> P4B[80/20分析]
|
|
158
|
+
P4B --> P4C[So What?で洞察抽出]
|
|
194
159
|
end
|
|
195
160
|
|
|
196
|
-
subgraph
|
|
197
|
-
|
|
198
|
-
|
|
161
|
+
subgraph Phase5["Phase 5: 統合・提言"]
|
|
162
|
+
P5A[ピラミッド原則で構造化] --> P5B[アクションプラン策定]
|
|
163
|
+
P5B --> P5C[インパクト評価]
|
|
199
164
|
end
|
|
200
165
|
|
|
201
166
|
Phase1 --> Phase2
|
|
202
167
|
Phase2 --> Phase3
|
|
203
168
|
Phase3 --> Phase4
|
|
169
|
+
Phase4 --> Phase5
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## 🚀 使用例
|
|
173
|
+
|
|
174
|
+
### 例1: 成長戦略の検討
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
ユーザー: 「新規事業の方向性を検討したい」
|
|
178
|
+
|
|
179
|
+
SHIKIGAMI:
|
|
180
|
+
1. [Planner] 「成長の目標は何ですか?」→ 真の目的を探索
|
|
181
|
+
2. [Deep Research] 市場情報を仮説駆動で収集(web_search / web_fetch 活用)
|
|
182
|
+
3. [Framework] 3つの地平線、成長のグラニュラリティを適用
|
|
183
|
+
4. [Writing] ピラミッド原則で構造化した提言レポートを生成
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 例2: 組織変革の診断
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
ユーザー: 「組織の問題点を分析して」
|
|
190
|
+
|
|
191
|
+
SHIKIGAMI:
|
|
192
|
+
1. [Planner] 変革の目的・成功基準を確認
|
|
193
|
+
2. [Deep Research] 組織情報を収集
|
|
194
|
+
3. [Framework] マッキンゼーの7Sで整合性を分析
|
|
195
|
+
4. [Writing] イシューツリーで課題を構造化したレポートを生成
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 例3: コスト削減プロジェクト
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
ユーザー: 「間接費を削減したい」
|
|
202
|
+
|
|
203
|
+
SHIKIGAMI:
|
|
204
|
+
1. [Planner] 削減目標・制約を確認
|
|
205
|
+
2. [Deep Research] 間接部門の機能・コストを調査
|
|
206
|
+
3. [Framework] OVA(間接費価値分析)を適用
|
|
207
|
+
4. [Writing] 優先順位付きの削減提言レポートを生成
|
|
204
208
|
```
|
|
205
209
|
|
|
206
210
|
## 📄 ライセンス
|
package/mcp-server/package.json
CHANGED
package/package.json
CHANGED
package/scripts/cli.js
CHANGED
|
@@ -32,7 +32,6 @@ Usage: npx shikigami [command] [options]
|
|
|
32
32
|
Commands:
|
|
33
33
|
init Initialize SHIKIGAMI files in current directory
|
|
34
34
|
upgrade, update Upgrade SHIKIGAMI files (same as init --force) (v1.23.0)
|
|
35
|
-
cowork [options] Build Copilot Cowork plugin package (v2.0.4)
|
|
36
35
|
new [name] Create a new research project
|
|
37
36
|
find-related [keyword] Find related projects by keywords (v1.7.0)
|
|
38
37
|
inherit [options] Prepare knowledge inheritance from past reports (v1.8.0)
|
|
@@ -42,9 +41,6 @@ Commands:
|
|
|
42
41
|
Examples:
|
|
43
42
|
npx shikigami init # Initialize SHIKIGAMI
|
|
44
43
|
npx shikigami upgrade # Upgrade to latest version
|
|
45
|
-
npx shikigami cowork # Build Cowork plugin .zip
|
|
46
|
-
npx shikigami cowork --check # Validate skills (dry-run)
|
|
47
|
-
npx shikigami cowork --out ./dist # Specify output directory
|
|
48
44
|
npx shikigami new my-research # Create new project "my-research"
|
|
49
45
|
npx shikigami new # Create new project with auto-numbered name
|
|
50
46
|
npx shikigami find-related レアアース # Find projects related to "レアアース"
|
|
@@ -72,12 +68,6 @@ if (command === 'upgrade' || command === 'update') {
|
|
|
72
68
|
process.exit(0);
|
|
73
69
|
}
|
|
74
70
|
|
|
75
|
-
// Cowork command (v2.0.4)
|
|
76
|
-
if (command === 'cowork') {
|
|
77
|
-
require('./build-cowork-plugin.js');
|
|
78
|
-
process.exit(0);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
71
|
// New project command
|
|
82
72
|
if (command === 'new') {
|
|
83
73
|
const projectName = args[1];
|
|
@@ -99,7 +89,7 @@ if (command === 'inherit') {
|
|
|
99
89
|
}
|
|
100
90
|
|
|
101
91
|
// Unknown command
|
|
102
|
-
if (command !== 'find-related' && command !== 'inherit' && command !== 'upgrade' && command !== 'update'
|
|
92
|
+
if (command !== 'find-related' && command !== 'inherit' && command !== 'upgrade' && command !== 'update') {
|
|
103
93
|
console.error(`Unknown command: ${command}`);
|
|
104
94
|
console.log('Run "npx shikigami --help" for usage information.');
|
|
105
95
|
process.exit(1);
|
package/scripts/init.js
CHANGED
|
@@ -167,11 +167,6 @@ function init() {
|
|
|
167
167
|
console.log(`📊 Summary: ${copiedCount} copied, ${overwrittenCount} overwritten, ${skippedCount} skipped`);
|
|
168
168
|
console.log('');
|
|
169
169
|
|
|
170
|
-
// Cowork plugin hint
|
|
171
|
-
console.log('🤝 Copilot Cowork:');
|
|
172
|
-
console.log(' npx shikigami cowork でCoworkプラグインパッケージを生成');
|
|
173
|
-
console.log('');
|
|
174
|
-
|
|
175
170
|
console.log('📝 Next steps:');
|
|
176
171
|
console.log(' 1. cd mcp-server && npm install && npm run build');
|
|
177
172
|
console.log(' 2. Restart VS Code to activate Agent Skills');
|
|
@@ -1,859 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* SHIKIGAMI Cowork Plugin Builder
|
|
4
|
-
*
|
|
5
|
-
* Builds a Microsoft 365 Copilot Cowork plugin package (.zip)
|
|
6
|
-
* from SHIKIGAMI's Agent Skills following the official "Build from scratch" guide.
|
|
7
|
-
*
|
|
8
|
-
* Usage: npx shikigami cowork [options]
|
|
9
|
-
* --out <dir> Output directory (default: ./dist)
|
|
10
|
-
* --check Dry-run validation only
|
|
11
|
-
* --help Show help
|
|
12
|
-
*
|
|
13
|
-
* Reference: https://learn.microsoft.com/microsoft-365/copilot/cowork/cowork-plugin-development
|
|
14
|
-
*
|
|
15
|
-
* Cross-platform: The same SKILL.md files work in GitHub Copilot CLI,
|
|
16
|
-
* VS Code Copilot, Claude Code, Gemini CLI, and Copilot Cowork.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
const fs = require('fs');
|
|
20
|
-
const path = require('path');
|
|
21
|
-
const { execFileSync } = require('child_process');
|
|
22
|
-
|
|
23
|
-
// ── Constants ──────────────────────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
const MAX_COMPANIONS_PER_SKILL = 20;
|
|
26
|
-
const MAX_COMPANION_SIZE = 5 * 1024 * 1024; // 5 MB
|
|
27
|
-
const MAX_COMPANION_TOTAL = 10 * 1024 * 1024; // 10 MB per skill
|
|
28
|
-
const MAX_SKILLS = 20;
|
|
29
|
-
const MAX_FOLDER_PATH = 256;
|
|
30
|
-
const RECOMMENDED_BODY_WORDS = 3000;
|
|
31
|
-
|
|
32
|
-
const PACKAGE_NAME = 'com.nahisaho.shikigami';
|
|
33
|
-
const APP_ID = 'a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d';
|
|
34
|
-
const ACCENT_COLOR = '#6B46C1';
|
|
35
|
-
|
|
36
|
-
const WINDOWS_RESERVED = new Set([
|
|
37
|
-
'CON', 'PRN', 'AUX', 'NUL',
|
|
38
|
-
'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9',
|
|
39
|
-
'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9',
|
|
40
|
-
]);
|
|
41
|
-
|
|
42
|
-
const SAFE_FILENAME_RE = /^[a-zA-Z0-9\-_. !]+$/;
|
|
43
|
-
|
|
44
|
-
// Cowork-specific frontmatter defaults per skill
|
|
45
|
-
const COWORK_DEFAULTS = {
|
|
46
|
-
'shikigami-planner': { category: 'Research', icon: 'Lightbulb' },
|
|
47
|
-
'shikigami-deep-research': { category: 'Research', icon: 'Search' },
|
|
48
|
-
'shikigami-consulting-framework': { category: 'Analysis', icon: 'Briefcase' },
|
|
49
|
-
'shikigami-writing': { category: 'Writing', icon: 'DocumentBulletList' },
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// ── Minimal PNG generator (no dependencies) ───────────────────────────────
|
|
53
|
-
|
|
54
|
-
function createMinimalPNG(width, height, r, g, b) {
|
|
55
|
-
const signature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
56
|
-
|
|
57
|
-
function crc32(buf) {
|
|
58
|
-
let crc = 0xFFFFFFFF;
|
|
59
|
-
const table = new Int32Array(256);
|
|
60
|
-
for (let i = 0; i < 256; i++) {
|
|
61
|
-
let c = i;
|
|
62
|
-
for (let j = 0; j < 8; j++) c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
|
|
63
|
-
table[i] = c;
|
|
64
|
-
}
|
|
65
|
-
for (let i = 0; i < buf.length; i++) {
|
|
66
|
-
crc = table[(crc ^ buf[i]) & 0xFF] ^ (crc >>> 8);
|
|
67
|
-
}
|
|
68
|
-
return (crc ^ 0xFFFFFFFF) >>> 0;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function makeChunk(type, data) {
|
|
72
|
-
const len = Buffer.alloc(4);
|
|
73
|
-
len.writeUInt32BE(data.length);
|
|
74
|
-
const typeAndData = Buffer.concat([Buffer.from(type), data]);
|
|
75
|
-
const crcBuf = Buffer.alloc(4);
|
|
76
|
-
crcBuf.writeUInt32BE(crc32(typeAndData));
|
|
77
|
-
return Buffer.concat([len, typeAndData, crcBuf]);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const ihdr = Buffer.alloc(13);
|
|
81
|
-
ihdr.writeUInt32BE(width, 0);
|
|
82
|
-
ihdr.writeUInt32BE(height, 4);
|
|
83
|
-
ihdr[8] = 8; ihdr[9] = 2; ihdr[10] = 0; ihdr[11] = 0; ihdr[12] = 0;
|
|
84
|
-
|
|
85
|
-
const rowSize = 1 + width * 3;
|
|
86
|
-
const rawData = Buffer.alloc(rowSize * height);
|
|
87
|
-
for (let y = 0; y < height; y++) {
|
|
88
|
-
rawData[y * rowSize] = 0;
|
|
89
|
-
for (let x = 0; x < width; x++) {
|
|
90
|
-
const offset = y * rowSize + 1 + x * 3;
|
|
91
|
-
rawData[offset] = r;
|
|
92
|
-
rawData[offset + 1] = g;
|
|
93
|
-
rawData[offset + 2] = b;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const zlib = require('zlib');
|
|
98
|
-
const compressed = zlib.deflateSync(rawData);
|
|
99
|
-
|
|
100
|
-
return Buffer.concat([
|
|
101
|
-
signature,
|
|
102
|
-
makeChunk('IHDR', ihdr),
|
|
103
|
-
makeChunk('IDAT', compressed),
|
|
104
|
-
makeChunk('IEND', Buffer.alloc(0)),
|
|
105
|
-
]);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// ── YAML Frontmatter Parser ───────────────────────────────────────────────
|
|
109
|
-
|
|
110
|
-
function parseFrontmatter(content) {
|
|
111
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
112
|
-
if (!match) return null;
|
|
113
|
-
|
|
114
|
-
const yaml = match[1];
|
|
115
|
-
const result = {};
|
|
116
|
-
let currentKey = null;
|
|
117
|
-
let blockLines = [];
|
|
118
|
-
let inBlock = false;
|
|
119
|
-
let currentIndent = 0;
|
|
120
|
-
let mapKey = null;
|
|
121
|
-
let mapObj = null;
|
|
122
|
-
|
|
123
|
-
function flushBlock() {
|
|
124
|
-
if (inBlock && currentKey) {
|
|
125
|
-
result[currentKey] = blockLines.join('\n').trim();
|
|
126
|
-
inBlock = false;
|
|
127
|
-
blockLines = [];
|
|
128
|
-
}
|
|
129
|
-
if (mapKey && mapObj) {
|
|
130
|
-
result[mapKey] = mapObj;
|
|
131
|
-
mapKey = null;
|
|
132
|
-
mapObj = null;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
for (const line of yaml.split('\n')) {
|
|
137
|
-
// Handle block scalar continuation
|
|
138
|
-
if (inBlock) {
|
|
139
|
-
if (line.match(/^\s{2,}/) || line.trim() === '') {
|
|
140
|
-
blockLines.push(line.replace(/^\s{2}/, ''));
|
|
141
|
-
continue;
|
|
142
|
-
} else {
|
|
143
|
-
flushBlock();
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Handle map continuation (metadata:, cowork: style)
|
|
148
|
-
if (mapKey && line.match(/^\s{2,}\w/)) {
|
|
149
|
-
const kvMatch = line.trim().match(/^(\w[\w.-]*)\s*:\s*(.*)/);
|
|
150
|
-
if (kvMatch) {
|
|
151
|
-
mapObj[kvMatch[1]] = kvMatch[2].trim().replace(/^["']|["']$/g, '');
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
} else if (mapKey) {
|
|
155
|
-
flushBlock();
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Top-level key: value
|
|
159
|
-
const kvMatch = line.match(/^(\w[\w.-]*)\s*:\s*(.*)/);
|
|
160
|
-
if (kvMatch) {
|
|
161
|
-
currentKey = kvMatch[1];
|
|
162
|
-
const value = kvMatch[2].trim();
|
|
163
|
-
if (value === '|' || value === '>') {
|
|
164
|
-
inBlock = true;
|
|
165
|
-
blockLines = [];
|
|
166
|
-
} else if (value === '') {
|
|
167
|
-
// Could be a map start (metadata:, cowork:)
|
|
168
|
-
mapKey = currentKey;
|
|
169
|
-
mapObj = {};
|
|
170
|
-
} else {
|
|
171
|
-
result[currentKey] = value.replace(/^["']|["']$/g, '');
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
flushBlock();
|
|
177
|
-
return result;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function extractBody(content) {
|
|
181
|
-
const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)/);
|
|
182
|
-
return match ? match[1].trim() : content;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// ── Companion File Path Validation ────────────────────────────────────────
|
|
186
|
-
|
|
187
|
-
function validateCompanionPath(relPath) {
|
|
188
|
-
const errors = [];
|
|
189
|
-
const parts = relPath.split('/');
|
|
190
|
-
|
|
191
|
-
// No absolute paths
|
|
192
|
-
if (path.isAbsolute(relPath)) {
|
|
193
|
-
errors.push(`Absolute path not allowed: ${relPath}`);
|
|
194
|
-
}
|
|
195
|
-
// No path traversal
|
|
196
|
-
if (parts.includes('..')) {
|
|
197
|
-
errors.push(`Path traversal (..) not allowed: ${relPath}`);
|
|
198
|
-
}
|
|
199
|
-
// No backslashes or null bytes
|
|
200
|
-
if (relPath.includes('\\') || relPath.includes('\0')) {
|
|
201
|
-
errors.push(`Backslash or null byte in path: ${relPath}`);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
for (const part of parts) {
|
|
205
|
-
// No hidden files
|
|
206
|
-
if (part.startsWith('.')) {
|
|
207
|
-
errors.push(`Hidden file not allowed: ${relPath}`);
|
|
208
|
-
}
|
|
209
|
-
// No Windows reserved names
|
|
210
|
-
const baseName = part.replace(/\.[^.]*$/, '').toUpperCase();
|
|
211
|
-
if (WINDOWS_RESERVED.has(baseName)) {
|
|
212
|
-
errors.push(`Windows reserved name: ${part} in ${relPath}`);
|
|
213
|
-
}
|
|
214
|
-
// Safe characters only
|
|
215
|
-
if (!SAFE_FILENAME_RE.test(part)) {
|
|
216
|
-
errors.push(`Unsafe characters in filename: ${part} in ${relPath}`);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return errors;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// ── Companion File Consolidation ──────────────────────────────────────────
|
|
224
|
-
|
|
225
|
-
function discoverCompanions(skillDir) {
|
|
226
|
-
const allFiles = [];
|
|
227
|
-
|
|
228
|
-
function walkDir(dir, prefix) {
|
|
229
|
-
if (!fs.existsSync(dir)) return;
|
|
230
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
231
|
-
for (const entry of entries) {
|
|
232
|
-
if (entry.name.startsWith('.')) continue; // skip hidden
|
|
233
|
-
const fullPath = path.join(dir, entry.name);
|
|
234
|
-
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
235
|
-
if (entry.isDirectory()) {
|
|
236
|
-
walkDir(fullPath, relPath);
|
|
237
|
-
} else if (entry.name !== 'SKILL.md') {
|
|
238
|
-
allFiles.push({ fullPath, relPath, name: entry.name });
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
walkDir(skillDir, '');
|
|
244
|
-
return allFiles;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function consolidateCompanions(allFiles, skillName) {
|
|
248
|
-
if (allFiles.length <= MAX_COMPANIONS_PER_SKILL) {
|
|
249
|
-
return allFiles.map(f => ({
|
|
250
|
-
relativePath: f.relPath,
|
|
251
|
-
content: fs.readFileSync(f.fullPath),
|
|
252
|
-
}));
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const files = [];
|
|
256
|
-
|
|
257
|
-
// Group by top-level directory
|
|
258
|
-
const topGroups = {};
|
|
259
|
-
for (const f of allFiles) {
|
|
260
|
-
const topDir = f.relPath.split('/')[0] || '_root';
|
|
261
|
-
if (!topGroups[topDir]) topGroups[topDir] = [];
|
|
262
|
-
topGroups[topDir].push(f);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
for (const [dir, dirFiles] of Object.entries(topGroups)) {
|
|
266
|
-
if (dir === '_root') {
|
|
267
|
-
for (const f of dirFiles) {
|
|
268
|
-
files.push({
|
|
269
|
-
relativePath: f.relPath,
|
|
270
|
-
content: fs.readFileSync(f.fullPath),
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
continue;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Check if sub-directory grouping keeps within limits
|
|
277
|
-
const subGroups = {};
|
|
278
|
-
for (const f of dirFiles) {
|
|
279
|
-
const parts = f.relPath.split('/');
|
|
280
|
-
const subKey = parts.length > 1 ? parts[1] : '_direct';
|
|
281
|
-
if (!subGroups[subKey]) subGroups[subKey] = [];
|
|
282
|
-
subGroups[subKey].push(f);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// If sub-grouping fits, use it; otherwise consolidate entire directory
|
|
286
|
-
if (Object.keys(subGroups).length <= MAX_COMPANIONS_PER_SKILL - files.length) {
|
|
287
|
-
for (const [sub, subFiles] of Object.entries(subGroups)) {
|
|
288
|
-
let consolidated = `# ${dir}/${sub}\n\nConsolidated reference for ${skillName}.\n\n`;
|
|
289
|
-
for (const f of subFiles) {
|
|
290
|
-
const content = fs.readFileSync(f.fullPath, 'utf-8');
|
|
291
|
-
const basename = path.basename(f.name, path.extname(f.name));
|
|
292
|
-
consolidated += `---\n\n## ${basename}\n\n${content}\n\n`;
|
|
293
|
-
}
|
|
294
|
-
files.push({
|
|
295
|
-
relativePath: `references/${dir}-${sub}.md`,
|
|
296
|
-
content: Buffer.from(consolidated, 'utf-8'),
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
} else {
|
|
300
|
-
// Consolidate entire top-level directory into one file
|
|
301
|
-
let consolidated = `# ${dir}\n\nConsolidated reference for ${skillName}.\n\n`;
|
|
302
|
-
for (const f of dirFiles) {
|
|
303
|
-
const content = fs.readFileSync(f.fullPath, 'utf-8');
|
|
304
|
-
const basename = path.basename(f.name, path.extname(f.name));
|
|
305
|
-
consolidated += `---\n\n## ${basename}\n\n${content}\n\n`;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
const consolidatedBuf = Buffer.from(consolidated, 'utf-8');
|
|
309
|
-
|
|
310
|
-
// Chunk if exceeds 5MB
|
|
311
|
-
if (consolidatedBuf.length > MAX_COMPANION_SIZE) {
|
|
312
|
-
const lines = consolidated.split('\n');
|
|
313
|
-
let chunk = [];
|
|
314
|
-
let chunkSize = 0;
|
|
315
|
-
let chunkIdx = 1;
|
|
316
|
-
for (const line of lines) {
|
|
317
|
-
const lineSize = Buffer.byteLength(line + '\n', 'utf-8');
|
|
318
|
-
if (chunkSize + lineSize > MAX_COMPANION_SIZE * 0.9 && chunk.length > 0) {
|
|
319
|
-
files.push({
|
|
320
|
-
relativePath: `references/${dir}-${String(chunkIdx).padStart(2, '0')}.md`,
|
|
321
|
-
content: Buffer.from(chunk.join('\n'), 'utf-8'),
|
|
322
|
-
});
|
|
323
|
-
chunk = [];
|
|
324
|
-
chunkSize = 0;
|
|
325
|
-
chunkIdx++;
|
|
326
|
-
}
|
|
327
|
-
chunk.push(line);
|
|
328
|
-
chunkSize += lineSize;
|
|
329
|
-
}
|
|
330
|
-
if (chunk.length > 0) {
|
|
331
|
-
files.push({
|
|
332
|
-
relativePath: `references/${dir}-${String(chunkIdx).padStart(2, '0')}.md`,
|
|
333
|
-
content: Buffer.from(chunk.join('\n'), 'utf-8'),
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
} else {
|
|
337
|
-
files.push({
|
|
338
|
-
relativePath: `references/${dir}.md`,
|
|
339
|
-
content: consolidatedBuf,
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
return files;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// ── SKILL.md Rewriter for Cowork ──────────────────────────────────────────
|
|
349
|
-
|
|
350
|
-
function rewriteSkillMdForCowork(content, originalCompanions, packagedCompanions, skillName) {
|
|
351
|
-
/**
|
|
352
|
-
* Creates a Cowork-compatible version of SKILL.md:
|
|
353
|
-
* 1. Adds cowork.category and cowork.icon to frontmatter if missing
|
|
354
|
-
* 2. Adds metadata.author and metadata.version if missing
|
|
355
|
-
* 3. Updates file path references to match consolidated paths
|
|
356
|
-
* 4. Adds "Additional Resources" section listing companion files
|
|
357
|
-
*/
|
|
358
|
-
let result = content;
|
|
359
|
-
|
|
360
|
-
// Update frontmatter with Cowork fields
|
|
361
|
-
const fmMatch = result.match(/^(---\n)([\s\S]*?)(\n---)/);
|
|
362
|
-
if (fmMatch) {
|
|
363
|
-
let fm = fmMatch[2];
|
|
364
|
-
const defaults = COWORK_DEFAULTS[skillName] || {};
|
|
365
|
-
|
|
366
|
-
if (!fm.includes('cowork.category') && defaults.category) {
|
|
367
|
-
fm += `\ncowork.category: ${defaults.category}`;
|
|
368
|
-
}
|
|
369
|
-
if (!fm.includes('cowork.icon') && defaults.icon) {
|
|
370
|
-
fm += `\ncowork.icon: ${defaults.icon}`;
|
|
371
|
-
}
|
|
372
|
-
if (!fm.includes('metadata:')) {
|
|
373
|
-
fm += `\nmetadata:\n author: nahisaho\n version: "2.0"`;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
result = `${fmMatch[1]}${fm}${fmMatch[3]}${result.slice(fmMatch[0].length)}`;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// Build path mapping: original -> consolidated
|
|
380
|
-
if (originalCompanions.length > MAX_COMPANIONS_PER_SKILL) {
|
|
381
|
-
const pathMap = {};
|
|
382
|
-
for (const orig of originalCompanions) {
|
|
383
|
-
const topDir = orig.relPath.split('/')[0];
|
|
384
|
-
const consolidated = packagedCompanions.find(
|
|
385
|
-
p => p.relativePath.startsWith(`references/${topDir}`)
|
|
386
|
-
);
|
|
387
|
-
if (consolidated) {
|
|
388
|
-
pathMap[orig.relPath] = consolidated.relativePath;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// Replace file path references in body
|
|
393
|
-
for (const [origPath, newPath] of Object.entries(pathMap)) {
|
|
394
|
-
result = result.replace(new RegExp(escapeRegex(origPath), 'g'), newPath);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// Add Additional Resources section if companions exist and not already present
|
|
399
|
-
if (packagedCompanions.length > 0 && !result.includes('## Additional Resources')) {
|
|
400
|
-
let resources = '\n\n## Additional Resources\n\n';
|
|
401
|
-
for (const c of packagedCompanions) {
|
|
402
|
-
const name = path.basename(c.relativePath, path.extname(c.relativePath));
|
|
403
|
-
resources += `- **\`${c.relativePath}\`** — ${name}\n`;
|
|
404
|
-
}
|
|
405
|
-
result += resources;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
return result;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
function escapeRegex(str) {
|
|
412
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// ── ZIP Builder ───────────────────────────────────────────────────────────
|
|
416
|
-
|
|
417
|
-
function createZip(outputPath, files) {
|
|
418
|
-
const tmpDir = fs.mkdtempSync(path.join(require('os').tmpdir(), 'shikigami-cowork-'));
|
|
419
|
-
|
|
420
|
-
try {
|
|
421
|
-
for (const file of files) {
|
|
422
|
-
const filePath = path.join(tmpDir, file.path);
|
|
423
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
424
|
-
if (Buffer.isBuffer(file.content)) {
|
|
425
|
-
fs.writeFileSync(filePath, file.content);
|
|
426
|
-
} else {
|
|
427
|
-
fs.writeFileSync(filePath, file.content, 'utf-8');
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
const absOutput = path.resolve(outputPath);
|
|
432
|
-
try {
|
|
433
|
-
execFileSync('zip', ['-r', absOutput, '.'], { cwd: tmpDir, stdio: 'pipe' });
|
|
434
|
-
} catch {
|
|
435
|
-
// Fallback: PowerShell (Windows)
|
|
436
|
-
try {
|
|
437
|
-
execFileSync('powershell', [
|
|
438
|
-
'-Command',
|
|
439
|
-
`Compress-Archive -Path '${tmpDir}${path.sep}*' -DestinationPath '${absOutput}' -Force`
|
|
440
|
-
], { stdio: 'pipe' });
|
|
441
|
-
} catch {
|
|
442
|
-
console.error('❌ zip command not found. Install zip or use PowerShell on Windows.');
|
|
443
|
-
process.exit(1);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
} finally {
|
|
447
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// ── Manifest Generator ─────────────────────────────────────────────────────
|
|
452
|
-
|
|
453
|
-
function generateManifest(skills, version) {
|
|
454
|
-
return {
|
|
455
|
-
'$schema': 'https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.schema.json',
|
|
456
|
-
manifestVersion: 'devPreview',
|
|
457
|
-
version: version,
|
|
458
|
-
id: APP_ID,
|
|
459
|
-
packageName: PACKAGE_NAME,
|
|
460
|
-
developer: {
|
|
461
|
-
name: 'nahisaho',
|
|
462
|
-
websiteUrl: 'https://github.com/nahisaho/SHIKIGAMI',
|
|
463
|
-
privacyUrl: 'https://github.com/nahisaho/SHIKIGAMI/blob/main/LICENSE',
|
|
464
|
-
termsOfUseUrl: 'https://github.com/nahisaho/SHIKIGAMI/blob/main/LICENSE',
|
|
465
|
-
},
|
|
466
|
-
name: {
|
|
467
|
-
short: 'SHIKIGAMI',
|
|
468
|
-
full: 'SHIKIGAMI - Deep Research & Consulting Agent Skills',
|
|
469
|
-
},
|
|
470
|
-
description: {
|
|
471
|
-
short: 'AI-powered deep research and consulting framework analysis',
|
|
472
|
-
full: 'SHIKIGAMI provides 4 specialized Agent Skills: '
|
|
473
|
-
+ 'deep research with hallucination prevention, 50+ consulting frameworks '
|
|
474
|
-
+ '(SWOT, PEST, 5Forces, BCG Matrix, etc.), structured report writing, '
|
|
475
|
-
+ 'and project planning with 5 Whys/JTBD purpose discovery. '
|
|
476
|
-
+ 'Cross-platform compatible with GitHub Copilot CLI, VS Code, Claude Code, and Gemini CLI.',
|
|
477
|
-
},
|
|
478
|
-
icons: {
|
|
479
|
-
color: 'color.png',
|
|
480
|
-
outline: 'outline.png',
|
|
481
|
-
},
|
|
482
|
-
accentColor: ACCENT_COLOR,
|
|
483
|
-
agentSkills: skills.map(s => ({ folder: `./skills/${s.name}` })),
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// ── Validation (ASKILL codes from official docs) ──────────────────────────
|
|
488
|
-
|
|
489
|
-
function validateManifest(manifest) {
|
|
490
|
-
const errors = [];
|
|
491
|
-
|
|
492
|
-
// ASKILL-M001: folder required in each agentSkills entry
|
|
493
|
-
for (const skill of manifest.agentSkills || []) {
|
|
494
|
-
if (!skill.folder) {
|
|
495
|
-
errors.push('[ASKILL-M001] `folder` is required for each agentSkills entry');
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
// ASKILL-M002: max 20 skills
|
|
500
|
-
if ((manifest.agentSkills || []).length > MAX_SKILLS) {
|
|
501
|
-
errors.push(`[ASKILL-M002] Max ${MAX_SKILLS} agentSkills entries (found ${manifest.agentSkills.length})`);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
// ASKILL-M003: folder path max 256 chars
|
|
505
|
-
for (const skill of manifest.agentSkills || []) {
|
|
506
|
-
if (skill.folder && skill.folder.length > MAX_FOLDER_PATH) {
|
|
507
|
-
errors.push(`[ASKILL-M003] Folder path exceeds ${MAX_FOLDER_PATH} chars: ${skill.folder}`);
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
// ASKILL-P008: no duplicate folder values
|
|
512
|
-
const folders = (manifest.agentSkills || []).map(s => s.folder);
|
|
513
|
-
const dupes = folders.filter((f, i) => folders.indexOf(f) !== i);
|
|
514
|
-
if (dupes.length > 0) {
|
|
515
|
-
errors.push(`[ASKILL-P008] Duplicate folder values: ${[...new Set(dupes)].join(', ')}`);
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// GUID format
|
|
519
|
-
if (!manifest.id || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(manifest.id)) {
|
|
520
|
-
errors.push('[Manifest] Invalid GUID format for id');
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
return errors;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
function validateSkill(skillDir, skillName) {
|
|
527
|
-
const errors = [];
|
|
528
|
-
const warnings = [];
|
|
529
|
-
|
|
530
|
-
const skillMdPath = path.join(skillDir, 'SKILL.md');
|
|
531
|
-
if (!fs.existsSync(skillMdPath)) {
|
|
532
|
-
// ASKILL-P002
|
|
533
|
-
errors.push(`[ASKILL-P002] SKILL.md not found in ${skillName}`);
|
|
534
|
-
return { errors, warnings };
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
const content = fs.readFileSync(skillMdPath, 'utf-8');
|
|
538
|
-
const frontmatter = parseFrontmatter(content);
|
|
539
|
-
|
|
540
|
-
// ASKILL-P003: valid YAML frontmatter
|
|
541
|
-
if (!frontmatter) {
|
|
542
|
-
errors.push(`[ASKILL-P003] No valid YAML frontmatter in ${skillName}/SKILL.md`);
|
|
543
|
-
return { errors, warnings };
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
// ASKILL-P004: name field required
|
|
547
|
-
if (!frontmatter.name) {
|
|
548
|
-
errors.push(`[ASKILL-P004] Missing 'name' field in ${skillName}/SKILL.md frontmatter`);
|
|
549
|
-
} else {
|
|
550
|
-
// ASKILL-P006: name matches folder name
|
|
551
|
-
if (frontmatter.name !== skillName) {
|
|
552
|
-
errors.push(`[ASKILL-P006] Frontmatter name '${frontmatter.name}' doesn't match folder '${skillName}'`);
|
|
553
|
-
}
|
|
554
|
-
// ASKILL-P007: name is kebab-case, 1-64 chars
|
|
555
|
-
if (frontmatter.name.length > 64) {
|
|
556
|
-
errors.push(`[ASKILL-P007] Name exceeds 64 characters: ${frontmatter.name}`);
|
|
557
|
-
}
|
|
558
|
-
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(frontmatter.name)) {
|
|
559
|
-
errors.push(`[ASKILL-P007] Name must be kebab-case: ${frontmatter.name}`);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// ASKILL-P005: description field required, 1-1024 chars
|
|
564
|
-
if (!frontmatter.description) {
|
|
565
|
-
errors.push(`[ASKILL-P005] Missing 'description' field in ${skillName}/SKILL.md frontmatter`);
|
|
566
|
-
} else if (frontmatter.description.length > 1024) {
|
|
567
|
-
errors.push(`[ASKILL-P005] Description exceeds 1024 characters (${frontmatter.description.length}) in ${skillName}`);
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
// Body size warning
|
|
571
|
-
const body = extractBody(content);
|
|
572
|
-
const wordCount = body.split(/\s+/).filter(w => w.length > 0).length;
|
|
573
|
-
if (wordCount > RECOMMENDED_BODY_WORDS) {
|
|
574
|
-
warnings.push(`${skillName}: SKILL.md body is ~${wordCount} words (recommended <${RECOMMENDED_BODY_WORDS}). Consider moving details to references/`);
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
// Discover and validate companion files
|
|
578
|
-
const originalCompanions = discoverCompanions(skillDir);
|
|
579
|
-
|
|
580
|
-
// Validate companion file paths
|
|
581
|
-
for (const f of originalCompanions) {
|
|
582
|
-
const pathErrors = validateCompanionPath(f.relPath);
|
|
583
|
-
for (const e of pathErrors) {
|
|
584
|
-
errors.push(`[Companion] ${skillName}: ${e}`);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// Consolidate companions for packaging
|
|
589
|
-
const packagedCompanions = consolidateCompanions(originalCompanions, skillName);
|
|
590
|
-
|
|
591
|
-
// Validate consolidated results
|
|
592
|
-
if (packagedCompanions.length > MAX_COMPANIONS_PER_SKILL) {
|
|
593
|
-
errors.push(`[Companion] ${skillName}: ${packagedCompanions.length} files after consolidation (max ${MAX_COMPANIONS_PER_SKILL})`);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
const totalSize = packagedCompanions.reduce((sum, f) => sum + f.content.length, 0);
|
|
597
|
-
if (totalSize > MAX_COMPANION_TOTAL) {
|
|
598
|
-
errors.push(`[Companion] ${skillName}: Total size ${(totalSize / 1024 / 1024).toFixed(1)}MB exceeds 10MB limit`);
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
for (const f of packagedCompanions) {
|
|
602
|
-
if (f.content.length > MAX_COMPANION_SIZE) {
|
|
603
|
-
errors.push(`[Companion] ${skillName}: ${f.relativePath} exceeds 5MB limit`);
|
|
604
|
-
}
|
|
605
|
-
// Validate packaged paths too
|
|
606
|
-
const pathErrors = validateCompanionPath(f.relativePath);
|
|
607
|
-
for (const e of pathErrors) {
|
|
608
|
-
errors.push(`[Companion] ${skillName}: ${e}`);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
return { errors, warnings, originalCompanions, packagedCompanions, frontmatter, content };
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
// ── Main ───────────────────────────────────────────────────────────────────
|
|
616
|
-
|
|
617
|
-
function parseArgs() {
|
|
618
|
-
const args = process.argv.slice(2);
|
|
619
|
-
return {
|
|
620
|
-
out: args.includes('--out') ? args[args.indexOf('--out') + 1] : './dist',
|
|
621
|
-
check: args.includes('--check') || args.includes('--dry-run'),
|
|
622
|
-
help: args.includes('--help') || args.includes('-h'),
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
function showHelp() {
|
|
627
|
-
console.log(`
|
|
628
|
-
🎭 SHIKIGAMI Cowork Plugin Builder
|
|
629
|
-
|
|
630
|
-
Builds a Microsoft 365 Copilot Cowork plugin package (.zip)
|
|
631
|
-
following the official "Build a plugin from scratch" guide.
|
|
632
|
-
|
|
633
|
-
Usage: npx shikigami cowork [options]
|
|
634
|
-
|
|
635
|
-
Options:
|
|
636
|
-
--out <dir> Output directory (default: ./dist)
|
|
637
|
-
--check Validation only (dry-run)
|
|
638
|
-
-h, --help Show this help
|
|
639
|
-
|
|
640
|
-
Steps (per official docs):
|
|
641
|
-
1. Discover & validate SKILL.md files (frontmatter, naming, paths)
|
|
642
|
-
2. Consolidate companion files (max 20 per skill)
|
|
643
|
-
3. Rewrite SKILL.md for Cowork (add cowork.category, cowork.icon, metadata)
|
|
644
|
-
4. Generate manifest.json (M365 Unified App Manifest devPreview)
|
|
645
|
-
5. Generate icons (color.png 192×192, outline.png 32×32)
|
|
646
|
-
6. Create .zip package
|
|
647
|
-
|
|
648
|
-
Cross-platform:
|
|
649
|
-
Same SKILL.md files work in GitHub Copilot CLI, VS Code Copilot,
|
|
650
|
-
Claude Code, Gemini CLI, Cursor, JetBrains Junie, and Copilot Cowork.
|
|
651
|
-
|
|
652
|
-
Reference:
|
|
653
|
-
https://learn.microsoft.com/microsoft-365/copilot/cowork/cowork-plugin-development
|
|
654
|
-
`);
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
function build() {
|
|
658
|
-
const { out, check, help } = parseArgs();
|
|
659
|
-
|
|
660
|
-
if (help) {
|
|
661
|
-
showHelp();
|
|
662
|
-
process.exit(0);
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
console.log('');
|
|
666
|
-
console.log('🎭 SHIKIGAMI Cowork Plugin Builder');
|
|
667
|
-
console.log('====================================');
|
|
668
|
-
console.log('');
|
|
669
|
-
|
|
670
|
-
// ── Step 0: Locate skills directory ──
|
|
671
|
-
const packageDir = path.resolve(__dirname, '..');
|
|
672
|
-
let skillsRoot = path.join(packageDir, 'github-assets', 'skills');
|
|
673
|
-
|
|
674
|
-
if (!fs.existsSync(skillsRoot)) {
|
|
675
|
-
skillsRoot = path.join(packageDir, '.github', 'skills');
|
|
676
|
-
}
|
|
677
|
-
if (!fs.existsSync(skillsRoot)) {
|
|
678
|
-
skillsRoot = path.join(process.cwd(), '.github', 'skills');
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
if (!fs.existsSync(skillsRoot)) {
|
|
682
|
-
console.error('❌ Skills directory not found.');
|
|
683
|
-
console.error(' Run `npx shikigami init` first to copy skills to your project.');
|
|
684
|
-
process.exit(1);
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
let version = '1.0.0';
|
|
688
|
-
try {
|
|
689
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(packageDir, 'package.json'), 'utf-8'));
|
|
690
|
-
version = pkg.version || version;
|
|
691
|
-
} catch { /* ignore */ }
|
|
692
|
-
|
|
693
|
-
// ── Step 1: Discover & validate skills ──
|
|
694
|
-
console.log('Step 1: Discovering and validating skills...');
|
|
695
|
-
console.log(`📂 Skills root: ${skillsRoot}`);
|
|
696
|
-
console.log('');
|
|
697
|
-
|
|
698
|
-
const skillDirs = fs.readdirSync(skillsRoot, { withFileTypes: true })
|
|
699
|
-
.filter(d => d.isDirectory() && d.name.startsWith('shikigami-'))
|
|
700
|
-
.map(d => d.name);
|
|
701
|
-
|
|
702
|
-
if (skillDirs.length === 0) {
|
|
703
|
-
console.error('❌ No skills found (expected shikigami-* directories)');
|
|
704
|
-
process.exit(1);
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
let hasErrors = false;
|
|
708
|
-
const validatedSkills = [];
|
|
709
|
-
|
|
710
|
-
for (const skillName of skillDirs) {
|
|
711
|
-
const skillDir = path.join(skillsRoot, skillName);
|
|
712
|
-
const result = validateSkill(skillDir, skillName);
|
|
713
|
-
|
|
714
|
-
if (result.errors.length > 0) {
|
|
715
|
-
hasErrors = true;
|
|
716
|
-
for (const err of result.errors) console.log(` ❌ ${err}`);
|
|
717
|
-
}
|
|
718
|
-
for (const warn of result.warnings) console.log(` ⚠️ ${warn}`);
|
|
719
|
-
|
|
720
|
-
if (result.errors.length === 0) {
|
|
721
|
-
const origCount = result.originalCompanions ? result.originalCompanions.length : 0;
|
|
722
|
-
const pkgCount = result.packagedCompanions ? result.packagedCompanions.length : 0;
|
|
723
|
-
const consolidatedNote = origCount > MAX_COMPANIONS_PER_SKILL
|
|
724
|
-
? ` (consolidated ${origCount} → ${pkgCount})`
|
|
725
|
-
: '';
|
|
726
|
-
console.log(` ✅ ${skillName} (${pkgCount} companion files${consolidatedNote})`);
|
|
727
|
-
validatedSkills.push({
|
|
728
|
-
name: skillName,
|
|
729
|
-
dir: skillDir,
|
|
730
|
-
originalCompanions: result.originalCompanions,
|
|
731
|
-
packagedCompanions: result.packagedCompanions,
|
|
732
|
-
frontmatter: result.frontmatter,
|
|
733
|
-
content: result.content,
|
|
734
|
-
});
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
console.log('');
|
|
739
|
-
|
|
740
|
-
if (hasErrors) {
|
|
741
|
-
console.error('❌ Validation failed. Fix errors above before building.');
|
|
742
|
-
process.exit(1);
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
if (validatedSkills.length > MAX_SKILLS) {
|
|
746
|
-
console.error(`❌ [ASKILL-M002] Too many skills: ${validatedSkills.length} (max ${MAX_SKILLS})`);
|
|
747
|
-
process.exit(1);
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
// ── Manifest validation ──
|
|
751
|
-
const manifest = generateManifest(validatedSkills, version);
|
|
752
|
-
const manifestErrors = validateManifest(manifest);
|
|
753
|
-
if (manifestErrors.length > 0) {
|
|
754
|
-
hasErrors = true;
|
|
755
|
-
for (const err of manifestErrors) console.log(` ❌ ${err}`);
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
if (hasErrors) {
|
|
759
|
-
console.error('❌ Manifest validation failed.');
|
|
760
|
-
process.exit(1);
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
if (check) {
|
|
764
|
-
console.log('✅ Validation passed (dry-run mode)');
|
|
765
|
-
console.log(` ${validatedSkills.length} skills ready for packaging`);
|
|
766
|
-
console.log('');
|
|
767
|
-
console.log('Cross-platform compatibility:');
|
|
768
|
-
console.log(' ✅ GitHub Copilot CLI');
|
|
769
|
-
console.log(' ✅ VS Code Copilot');
|
|
770
|
-
console.log(' ✅ Microsoft 365 Copilot Cowork');
|
|
771
|
-
console.log(' ✅ Claude Code / Gemini CLI / Cursor');
|
|
772
|
-
process.exit(0);
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
// ── Step 2-5: Build package ──
|
|
776
|
-
console.log('Step 2: Building Cowork plugin package...');
|
|
777
|
-
|
|
778
|
-
const zipFiles = [];
|
|
779
|
-
|
|
780
|
-
// Step 4: manifest.json
|
|
781
|
-
zipFiles.push({
|
|
782
|
-
path: 'manifest.json',
|
|
783
|
-
content: JSON.stringify(manifest, null, 2),
|
|
784
|
-
});
|
|
785
|
-
console.log(' ✅ manifest.json');
|
|
786
|
-
|
|
787
|
-
// Step 5: Icons
|
|
788
|
-
const colorPng = createMinimalPNG(192, 192, 107, 70, 193);
|
|
789
|
-
const outlinePng = createMinimalPNG(32, 32, 107, 70, 193);
|
|
790
|
-
zipFiles.push({ path: 'color.png', content: colorPng });
|
|
791
|
-
zipFiles.push({ path: 'outline.png', content: outlinePng });
|
|
792
|
-
console.log(' ✅ color.png (192×192)');
|
|
793
|
-
console.log(' ✅ outline.png (32×32)');
|
|
794
|
-
|
|
795
|
-
// Steps 1-2: Skills with Cowork-specific SKILL.md
|
|
796
|
-
for (const skill of validatedSkills) {
|
|
797
|
-
// Rewrite SKILL.md for Cowork (add metadata, category, icon, update paths)
|
|
798
|
-
const rewrittenSkillMd = rewriteSkillMdForCowork(
|
|
799
|
-
skill.content,
|
|
800
|
-
skill.originalCompanions,
|
|
801
|
-
skill.packagedCompanions,
|
|
802
|
-
skill.name
|
|
803
|
-
);
|
|
804
|
-
|
|
805
|
-
zipFiles.push({
|
|
806
|
-
path: `skills/${skill.name}/SKILL.md`,
|
|
807
|
-
content: rewrittenSkillMd,
|
|
808
|
-
});
|
|
809
|
-
|
|
810
|
-
// Copy companion files (already consolidated)
|
|
811
|
-
for (const companion of skill.packagedCompanions) {
|
|
812
|
-
zipFiles.push({
|
|
813
|
-
path: `skills/${skill.name}/${companion.relativePath}`,
|
|
814
|
-
content: companion.content,
|
|
815
|
-
});
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
console.log(` ✅ skills/${skill.name}/ (${skill.packagedCompanions.length + 1} files)`);
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
// ── Step 6: Create ZIP ──
|
|
822
|
-
console.log('');
|
|
823
|
-
console.log('Step 3: Creating ZIP package...');
|
|
824
|
-
|
|
825
|
-
const outDir = path.resolve(out);
|
|
826
|
-
fs.mkdirSync(outDir, { recursive: true });
|
|
827
|
-
const zipPath = path.join(outDir, 'shikigami-cowork-plugin.zip');
|
|
828
|
-
|
|
829
|
-
if (fs.existsSync(zipPath)) {
|
|
830
|
-
fs.unlinkSync(zipPath);
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
createZip(zipPath, zipFiles);
|
|
834
|
-
|
|
835
|
-
const zipSize = fs.statSync(zipPath).size;
|
|
836
|
-
console.log('');
|
|
837
|
-
console.log('✅ Plugin package created!');
|
|
838
|
-
console.log('');
|
|
839
|
-
console.log(` 📦 ${zipPath}`);
|
|
840
|
-
console.log(` 📏 Size: ${(zipSize / 1024).toFixed(1)} KB`);
|
|
841
|
-
console.log(` 🔧 Skills: ${validatedSkills.length}`);
|
|
842
|
-
console.log(` 📋 Version: ${version}`);
|
|
843
|
-
console.log('');
|
|
844
|
-
console.log('Cross-platform compatibility:');
|
|
845
|
-
console.log(' ✅ GitHub Copilot CLI — use `npx shikigami init`');
|
|
846
|
-
console.log(' ✅ VS Code Copilot — same SKILL.md format');
|
|
847
|
-
console.log(' ✅ Copilot Cowork — upload .zip to M365 Admin Center');
|
|
848
|
-
console.log(' ✅ Claude Code — same SKILL.md format');
|
|
849
|
-
console.log('');
|
|
850
|
-
console.log('📝 Next steps (Copilot Cowork):');
|
|
851
|
-
console.log(' 1. Open M365 Admin Center > Manage Apps > Upload Custom App');
|
|
852
|
-
console.log(' 2. Upload shikigami-cowork-plugin.zip');
|
|
853
|
-
console.log(' 3. Open Cowork > Sources & Skills to verify');
|
|
854
|
-
console.log('');
|
|
855
|
-
console.log('📖 https://learn.microsoft.com/microsoft-365/copilot/cowork/cowork-plugin-development');
|
|
856
|
-
console.log('');
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
build();
|