@einja/dev-cli 0.1.38 → 0.1.39
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/README.md +1 -0
- package/dist/lib/file-system.d.ts +1 -5
- package/dist/lib/file-system.d.ts.map +1 -1
- package/dist/lib/file-system.js +2 -8
- package/dist/lib/file-system.js.map +1 -1
- package/dist/lib/mcp-config.js +3 -3
- package/dist/lib/mcp-config.js.map +1 -1
- package/dist/lib/mcp-config.test.js +2 -2
- package/dist/lib/mcp-config.test.js.map +1 -1
- package/dist/lib/merger.d.ts.map +1 -1
- package/dist/lib/merger.js +5 -5
- package/dist/lib/merger.js.map +1 -1
- package/dist/lib/preset-update/file-copier.d.ts.map +1 -1
- package/dist/lib/preset-update/file-copier.js +5 -0
- package/dist/lib/preset-update/file-copier.js.map +1 -1
- package/dist/lib/preset-update/file-copier.test.js +26 -0
- package/dist/lib/preset-update/file-copier.test.js.map +1 -1
- package/dist/lib/sync/category-validator.d.ts +5 -1
- package/dist/lib/sync/category-validator.d.ts.map +1 -1
- package/dist/lib/sync/category-validator.js +16 -2
- package/dist/lib/sync/category-validator.js.map +1 -1
- package/dist/lib/sync/category-validator.test.js +14 -4
- package/dist/lib/sync/category-validator.test.js.map +1 -1
- package/dist/lib/sync/file-filter.d.ts.map +1 -1
- package/dist/lib/sync/file-filter.js +24 -0
- package/dist/lib/sync/file-filter.js.map +1 -1
- package/dist/lib/sync/file-filter.test.js +37 -0
- package/dist/lib/sync/file-filter.test.js.map +1 -1
- package/package.json +1 -1
- package/presets/default/.claude/agents/einja/specs/spec-qa-generator.md +40 -43
- package/presets/default/.claude/agents/einja/specs/spec-tasks-generator.md +16 -6
- package/presets/default/.claude/agents/einja/task/task-executer.md +13 -11
- package/presets/default/.claude/commands/einja/einja-sync.md +238 -0
- package/presets/default/.claude/commands/einja/spec-create.md +7 -3
- package/presets/default/.claude/commands/einja/task-exec.md +6 -6
- package/presets/default/.claude/settings.json +1 -0
- package/presets/default/.claude/skills/einja-coding-standards/SKILL.md +4 -3
- package/presets/default/.claude/skills/einja-coding-standards/references/import-conventions.md +69 -0
- package/presets/default/.claude/skills/einja-component-design/SKILL.md +3 -3
- package/presets/default/.claude/skills/einja-project-overview/SKILL.md +35 -0
- package/presets/default/.claude/skills/einja-skill-creator/SKILL.md +421 -0
- package/presets/default/.claude/skills/einja-skill-creator/scripts/init_skill.py +333 -0
- package/presets/default/.claude/skills/einja-skill-creator/scripts/package_skill.py +110 -0
- package/presets/default/.claude/skills/einja-skill-creator/scripts/quick_validate.py +117 -0
- package/presets/default/.claude/skills/einja-spec-context-loader/SKILL.md +6 -6
- package/presets/default/.claude/skills/einja-task-qa/SKILL.md +24 -22
- package/presets/default/.claude/skills/einja-task-qa/{reference → references}/troubleshooting.md +1 -1
- package/presets/default/.claude/skills/einja-task-qa/{reference → references}/usage-patterns.md +2 -2
- package/presets/default/.claude/skills/einja-task-qa/templates/qa-test-template.md +13 -13
- package/{scaffolds → presets/default}/.mcp.json +27 -6
- package/presets/default/.vscode/settings.json +18 -0
- package/presets/default/CLAUDE.md.template +192 -0
- package/{scaffolds → presets/default/docs/einja}/example/README.md +1 -1
- package/{scaffolds → presets/default/docs/einja}/example/specs/issues/issue999-example-task/qa-tests/README.md +20 -23
- package/presets/default/docs/einja/example/specs/issues/issue999-example-task/qa-tests/evidence/story3/.gitkeep +0 -0
- package/{scaffolds → presets/default/docs/einja}/example/specs/issues/issue999-example-task/qa-tests/scenarios.md +12 -16
- package/presets/default/docs/einja/example/specs/issues/issue999-example-task/qa-tests/story1.md +101 -0
- package/presets/default/docs/einja/example/specs/issues/issue999-example-task/qa-tests/story2.md +70 -0
- package/presets/default/docs/einja/example/specs/issues/issue999-example-task/qa-tests/story3.md +69 -0
- package/{scaffolds → presets/default/docs/einja}/instructions/deployment-setup.md +93 -9
- package/{scaffolds → presets/default/docs/einja}/instructions/environment-setup.md +152 -4
- package/{scaffolds → presets/default/docs/einja}/instructions/local-server-environment-and-worktree.md +99 -0
- package/presets/default/docs/einja/instructions/neon-cli-reference.md +605 -0
- package/{scaffolds → presets/default/docs/einja}/instructions/vercel-cli-reference.md +80 -0
- package/{scaffolds → presets/default/docs/einja}/steering/acceptance-criteria-and-qa-guide.md +3 -4
- package/{scaffolds → presets/default/docs/einja}/steering/infrastructure/environment-variables.md +4 -4
- package/{scaffolds → presets/default/docs/einja}/templates/README.md +1 -1
- package/{scaffolds → presets/default/docs/einja}/templates/qa-test.md.template +29 -26
- package/presets/default/symlinks.json +0 -45
- package/scaffolds/cli/preset.yaml +0 -137
- package/scaffolds/example/specs/issues/issue999-example-task/qa-tests/phase1/1-1.md +0 -268
- package/scaffolds/example/specs/issues/issue999-example-task/qa-tests/phase1/1-2.md +0 -179
- package/scaffolds/example/specs/issues/issue999-example-task/qa-tests/phase1/1-3.md +0 -392
- package/scaffolds/example/specs/issues/issue999-example-task/qa-tests/phase2/2-1.md +0 -459
- /package/presets/default/.claude/skills/einja-coding-standards/{reference → references}/naming-conventions.md +0 -0
- /package/presets/default/.claude/skills/einja-coding-standards/{reference → references}/prohibited-patterns.md +0 -0
- /package/presets/default/.claude/skills/einja-coding-standards/{reference → references}/typescript-rules.md +0 -0
- /package/presets/default/.claude/skills/einja-component-design/{reference → references}/directory-structure.md +0 -0
- /package/presets/default/.claude/skills/einja-component-design/{reference → references}/props-patterns.md +0 -0
- /package/presets/default/.claude/skills/einja-component-design/{reference → references}/styling-guide.md +0 -0
- /package/presets/default/.claude/skills/einja-task-qa/{reference → references}/failure-patterns.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/example/specs/issues/issue999-example-task/design.md +0 -0
- /package/{scaffolds/example/specs/issues/issue999-example-task/qa-tests/phase1/evidence → presets/default/docs/einja/example/specs/issues/issue999-example-task/qa-tests/evidence/story1}/.gitkeep +0 -0
- /package/{scaffolds/example/specs/issues/issue999-example-task/qa-tests/phase2/evidence → presets/default/docs/einja/example/specs/issues/issue999-example-task/qa-tests/evidence/story2}/.gitkeep +0 -0
- /package/{scaffolds → presets/default/docs/einja}/example/specs/issues/issue999-example-task/requirements.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/example/specs/issues/issue999-example-task/tasks.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/instructions/task-execute.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/instructions/task-vibe-kanban-loop.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/README.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/architecture.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/branch-strategy.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/commit-rules.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/db-schema-design.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/development/api-development.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/development/backend-architecture.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/development/database-guidelines.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/development/frontend-development.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/development/review-guidelines.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/development/testing-strategy.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/development-workflow.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/infrastructure/deployment.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/product.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/steering/task-management.md +0 -0
- /package/{scaffolds → presets/default/docs/einja}/templates/design-simple.md.template +0 -0
- /package/{scaffolds → presets/default/docs/einja}/templates/design.md.template +0 -0
- /package/{scaffolds → presets/default/docs/einja}/templates/requirements.md.template +0 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Skill初期化スクリプト - テンプレートから新しいSkillを作成
|
|
4
|
+
|
|
5
|
+
使用法:
|
|
6
|
+
init_skill.py <skill-name> --path <output-directory>
|
|
7
|
+
|
|
8
|
+
例:
|
|
9
|
+
init_skill.py einja-my-new-skill --path .claude/skills
|
|
10
|
+
init_skill.py einja-api-helper --path .claude/skills
|
|
11
|
+
init_skill.py custom-skill --path /custom/location
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
SKILL_TEMPLATE = """---
|
|
19
|
+
name: {skill_name}
|
|
20
|
+
description: [TODO: このSkillが何をするか、いつ使用すべきかについての完全かつ有益な説明。特定のシナリオ、ファイルタイプ、またはトリガーとなるタスクを含めてください。]
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# {skill_title}
|
|
24
|
+
|
|
25
|
+
## 概要
|
|
26
|
+
|
|
27
|
+
[TODO: このSkillが可能にすることについての1-2文の説明]
|
|
28
|
+
|
|
29
|
+
## Skillの構造化
|
|
30
|
+
|
|
31
|
+
[TODO: このSkillの目的に最適な構造を選択してください。一般的なパターン:
|
|
32
|
+
|
|
33
|
+
**1. ワークフローベース**(順次プロセスに最適)
|
|
34
|
+
- 明確なステップバイステップの手順がある場合に適している
|
|
35
|
+
- 例: DOCXスキルの「ワークフロー決定ツリー」→「読み込み」→「作成」→「編集」
|
|
36
|
+
- 構造: ## 概要 → ## ワークフロー決定ツリー → ## ステップ1 → ## ステップ2...
|
|
37
|
+
|
|
38
|
+
**2. タスクベース**(ツールコレクションに最適)
|
|
39
|
+
- Skillが異なる操作/機能を提供する場合に適している
|
|
40
|
+
- 例: PDFスキルの「クイックスタート」→「PDFを結合」→「PDFを分割」→「テキストを抽出」
|
|
41
|
+
- 構造: ## 概要 → ## クイックスタート → ## タスクカテゴリ1 → ## タスクカテゴリ2...
|
|
42
|
+
|
|
43
|
+
**3. リファレンス/ガイドライン**(標準や仕様に最適)
|
|
44
|
+
- ブランドガイドライン、コーディング規約、要件に適している
|
|
45
|
+
- 例: ブランドスタイリングの「ブランドガイドライン」→「カラー」→「タイポグラフィ」→「機能」
|
|
46
|
+
- 構造: ## 概要 → ## ガイドライン → ## 仕様 → ## 使用方法...
|
|
47
|
+
|
|
48
|
+
**4. 機能ベース**(統合システムに最適)
|
|
49
|
+
- Skillが複数の関連機能を提供する場合に適している
|
|
50
|
+
- 例: プロダクト管理の「コア機能」→ 番号付き機能リスト
|
|
51
|
+
- 構造: ## 概要 → ## コア機能 → ### 1. 機能 → ### 2. 機能...
|
|
52
|
+
|
|
53
|
+
パターンは必要に応じて混在させて使用できます。ほとんどのSkillはパターンを組み合わせます(例: タスクベースで始め、複雑な操作にはワークフローを追加)。
|
|
54
|
+
|
|
55
|
+
完了したら、この「Skillの構造化」セクション全体を削除してください - これは単なるガイダンスです。]
|
|
56
|
+
|
|
57
|
+
## [TODO: 選択した構造に基づいて最初のメインセクションに置き換えてください]
|
|
58
|
+
|
|
59
|
+
[TODO: ここにコンテンツを追加してください。既存のSkillの例を参照:
|
|
60
|
+
- 技術的なSkillのためのコードサンプル
|
|
61
|
+
- 複雑なワークフローのための決定ツリー
|
|
62
|
+
- 現実的なユーザーリクエストを含む具体例
|
|
63
|
+
- 必要に応じてscripts/templates/referencesへの参照]
|
|
64
|
+
|
|
65
|
+
## リソース
|
|
66
|
+
|
|
67
|
+
このSkillには、異なるタイプのバンドルリソースをどのように整理するかを示す例のリソースディレクトリが含まれています:
|
|
68
|
+
|
|
69
|
+
### scripts/
|
|
70
|
+
特定の操作を実行するために直接実行できる実行可能コード(Python/Bash等)。
|
|
71
|
+
|
|
72
|
+
**他のSkillからの例:**
|
|
73
|
+
- PDFスキル: `fill_fillable_fields.py`, `extract_form_field_info.py` - PDF操作のためのユーティリティ
|
|
74
|
+
- DOCXスキル: `document.py`, `utilities.py` - ドキュメント処理のためのPythonモジュール
|
|
75
|
+
|
|
76
|
+
**適切な用途:** Pythonスクリプト、シェルスクリプト、または自動化、データ処理、特定の操作を実行する実行可能コード。
|
|
77
|
+
|
|
78
|
+
**注意:** スクリプトはコンテキストに読み込まずに実行できますが、パッチや環境調整のためにClaudeによって読まれる場合があります。
|
|
79
|
+
|
|
80
|
+
例のリソースディレクトリを作成:`scripts/`、`references/`、`assets/`
|
|
81
|
+
|
|
82
|
+
### references/
|
|
83
|
+
Claudeの処理と思考を導くためにコンテキストに読み込まれることを意図したドキュメントと参照資料。
|
|
84
|
+
|
|
85
|
+
**他のSkillからの例:**
|
|
86
|
+
- プロダクト管理: `communication.md`, `context_building.md` - 詳細なワークフローガイド
|
|
87
|
+
- BigQuery: APIリファレンスドキュメントとクエリ例
|
|
88
|
+
- 財務: スキーマドキュメント、会社ポリシー
|
|
89
|
+
|
|
90
|
+
**適切な用途:** 詳細なドキュメント、APIリファレンス、データベーススキーマ、包括的なガイド、またはClaudeが作業中に参照すべき詳細情報。
|
|
91
|
+
|
|
92
|
+
### assets/
|
|
93
|
+
コンテキストに読み込まれることを意図せず、Claudeが生成する出力で使用されるファイル。
|
|
94
|
+
|
|
95
|
+
**他のSkillからの例:**
|
|
96
|
+
- ブランドスタイリング: PowerPointテンプレートファイル (.pptx), ロゴファイル
|
|
97
|
+
- フロントエンドビルダー: HTML/Reactボイラープレートプロジェクトディレクトリ
|
|
98
|
+
- タイポグラフィ: フォントファイル (.ttf, .woff2)
|
|
99
|
+
|
|
100
|
+
**適切な用途:** テンプレート、ボイラープレートコード、ドキュメントテンプレート、画像、アイコン、フォント、または最終出力でコピーまたは使用されるファイル。
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
**不要なディレクトリは削除できます。** すべてのSkillが3種類のリソースすべてを必要とするわけではありません。
|
|
105
|
+
|
|
106
|
+
## einja固有の注意事項
|
|
107
|
+
|
|
108
|
+
### マネージドセクション
|
|
109
|
+
|
|
110
|
+
一部のドキュメントでマネージドセクションを使用する場合:
|
|
111
|
+
|
|
112
|
+
```markdown
|
|
113
|
+
<!-- @einja:managed:start -->
|
|
114
|
+
この内容は`einja sync`で上書きされる
|
|
115
|
+
<!-- @einja:managed:end -->
|
|
116
|
+
|
|
117
|
+
<!-- @einja:seed:start id="unique-id" -->
|
|
118
|
+
プロジェクト固有の内容をここに追記
|
|
119
|
+
<!-- @einja:seed:end -->
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### ビルドシステム連携
|
|
123
|
+
|
|
124
|
+
einja management templateでは、`.claude/skills/einja-*/` 内のファイルはビルド時に自動的に `presets/default/` にコピーされます。
|
|
125
|
+
|
|
126
|
+
### 関連Skill
|
|
127
|
+
|
|
128
|
+
- [einja-output-format](../einja-output-format/SKILL.md) - サブエージェント出力形式
|
|
129
|
+
- [einja-coding-standards](../einja-coding-standards/SKILL.md) - コーディング規約
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
EXAMPLE_SCRIPT = '''#!/usr/bin/env python3
|
|
133
|
+
"""
|
|
134
|
+
{skill_name}のための例のヘルパースクリプト
|
|
135
|
+
|
|
136
|
+
これは直接実行できるプレースホルダースクリプトです。
|
|
137
|
+
実際の実装に置き換えるか、不要な場合は削除してください。
|
|
138
|
+
|
|
139
|
+
他のSkillからの実際のスクリプト例:
|
|
140
|
+
- pdf/scripts/fill_fillable_fields.py - PDFフォームフィールドに入力
|
|
141
|
+
- pdf/scripts/convert_pdf_to_images.py - PDFページを画像に変換
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
def main():
|
|
145
|
+
print("これは{skill_name}の例のスクリプトです")
|
|
146
|
+
# TODO: ここに実際のスクリプトロジックを追加
|
|
147
|
+
# これはデータ処理、ファイル変換、API呼び出し等です。
|
|
148
|
+
|
|
149
|
+
if __name__ == "__main__":
|
|
150
|
+
main()
|
|
151
|
+
'''
|
|
152
|
+
|
|
153
|
+
EXAMPLE_REFERENCE = """# {skill_title}のリファレンスドキュメント
|
|
154
|
+
|
|
155
|
+
これは詳細なリファレンスドキュメントのプレースホルダーです。
|
|
156
|
+
実際のリファレンスコンテンツに置き換えるか、不要な場合は削除してください。
|
|
157
|
+
|
|
158
|
+
他のSkillからの実際のリファレンスドキュメント例:
|
|
159
|
+
- product-management/reference/communication.md - ステータス更新のための包括的なガイド
|
|
160
|
+
- product-management/reference/context_building.md - コンテキスト収集の深掘り
|
|
161
|
+
- bigquery/reference/ - APIリファレンスとクエリ例
|
|
162
|
+
|
|
163
|
+
## リファレンスドキュメントが有用な場合
|
|
164
|
+
|
|
165
|
+
リファレンスドキュメントは以下に最適:
|
|
166
|
+
- 包括的なAPIドキュメント
|
|
167
|
+
- 詳細なワークフローガイド
|
|
168
|
+
- 複雑な複数ステップのプロセス
|
|
169
|
+
- メインのSKILL.mdには長すぎる情報
|
|
170
|
+
- 特定のユースケースにのみ必要なコンテンツ
|
|
171
|
+
|
|
172
|
+
## 構造の提案
|
|
173
|
+
|
|
174
|
+
### APIリファレンスの例
|
|
175
|
+
- 概要
|
|
176
|
+
- 認証
|
|
177
|
+
- 例付きエンドポイント
|
|
178
|
+
- エラーコード
|
|
179
|
+
- レート制限
|
|
180
|
+
|
|
181
|
+
### ワークフローガイドの例
|
|
182
|
+
- 前提条件
|
|
183
|
+
- ステップバイステップの指示
|
|
184
|
+
- 一般的なパターン
|
|
185
|
+
- トラブルシューティング
|
|
186
|
+
- ベストプラクティス
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
EXAMPLE_ASSET = """# 例のアセットファイル
|
|
190
|
+
|
|
191
|
+
このプレースホルダーは、アセットファイルが保存される場所を表しています。
|
|
192
|
+
実際のアセットファイル(テンプレート、画像、フォント等)に置き換えるか、不要な場合は削除してください。
|
|
193
|
+
|
|
194
|
+
アセットファイルはコンテキストに読み込まれることを意図せず、Claudeが生成する
|
|
195
|
+
出力で使用されます。
|
|
196
|
+
|
|
197
|
+
他のSkillからの例のアセットファイル:
|
|
198
|
+
- ブランドガイドライン: logo.png, slides_template.pptx
|
|
199
|
+
- フロントエンドビルダー: HTML/Reactボイラープレートを含むhello-world/ディレクトリ
|
|
200
|
+
- タイポグラフィ: custom-font.ttf, font-family.woff2
|
|
201
|
+
- データ: sample_data.csv, test_dataset.json
|
|
202
|
+
|
|
203
|
+
## 一般的なアセットタイプ
|
|
204
|
+
|
|
205
|
+
- テンプレート: .pptx, .docx, ボイラープレートディレクトリ
|
|
206
|
+
- 画像: .png, .jpg, .svg, .gif
|
|
207
|
+
- フォント: .ttf, .otf, .woff, .woff2
|
|
208
|
+
- ボイラープレートコード: プロジェクトディレクトリ、スターターファイル
|
|
209
|
+
- アイコン: .ico, .svg
|
|
210
|
+
- データファイル: .csv, .json, .xml, .yaml
|
|
211
|
+
|
|
212
|
+
注意: これはテキストプレースホルダーです。実際のアセットは任意のファイルタイプにできます。
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def title_case_skill_name(skill_name):
|
|
217
|
+
"""ハイフン区切りのスキル名を表示用のタイトルケースに変換"""
|
|
218
|
+
return ' '.join(word.capitalize() for word in skill_name.split('-'))
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def init_skill(skill_name, path):
|
|
222
|
+
"""
|
|
223
|
+
テンプレートSKILL.mdを含む新しいSkillディレクトリを初期化
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
skill_name: Skillの名前
|
|
227
|
+
path: Skillディレクトリを作成するパス
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
作成されたSkillディレクトリへのパス、エラーの場合はNone
|
|
231
|
+
"""
|
|
232
|
+
# Skillディレクトリパスを決定
|
|
233
|
+
skill_dir = Path(path).resolve() / skill_name
|
|
234
|
+
|
|
235
|
+
# ディレクトリがすでに存在するか確認
|
|
236
|
+
if skill_dir.exists():
|
|
237
|
+
print(f"❌ エラー: Skillディレクトリはすでに存在します: {skill_dir}")
|
|
238
|
+
return None
|
|
239
|
+
|
|
240
|
+
# Skillディレクトリを作成
|
|
241
|
+
try:
|
|
242
|
+
skill_dir.mkdir(parents=True, exist_ok=False)
|
|
243
|
+
print(f"✅ Skillディレクトリを作成しました: {skill_dir}")
|
|
244
|
+
except Exception as e:
|
|
245
|
+
print(f"❌ ディレクトリ作成エラー: {e}")
|
|
246
|
+
return None
|
|
247
|
+
|
|
248
|
+
# テンプレートからSKILL.mdを作成
|
|
249
|
+
skill_title = title_case_skill_name(skill_name)
|
|
250
|
+
skill_content = SKILL_TEMPLATE.format(
|
|
251
|
+
skill_name=skill_name,
|
|
252
|
+
skill_title=skill_title
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
skill_md_path = skill_dir / 'SKILL.md'
|
|
256
|
+
try:
|
|
257
|
+
skill_md_path.write_text(skill_content)
|
|
258
|
+
print("✅ SKILL.mdを作成しました")
|
|
259
|
+
except Exception as e:
|
|
260
|
+
print(f"❌ SKILL.md作成エラー: {e}")
|
|
261
|
+
return None
|
|
262
|
+
|
|
263
|
+
# 例のファイルを含むリソースディレクトリを作成
|
|
264
|
+
try:
|
|
265
|
+
# 例のスクリプトを含むscripts/ディレクトリを作成
|
|
266
|
+
scripts_dir = skill_dir / 'scripts'
|
|
267
|
+
scripts_dir.mkdir(exist_ok=True)
|
|
268
|
+
example_script = scripts_dir / 'example.py'
|
|
269
|
+
example_script.write_text(EXAMPLE_SCRIPT.format(skill_name=skill_name))
|
|
270
|
+
example_script.chmod(0o755)
|
|
271
|
+
print("✅ scripts/example.pyを作成しました")
|
|
272
|
+
|
|
273
|
+
# 例のリファレンスドキュメントを含むreferences/ディレクトリを作成
|
|
274
|
+
reference_dir = skill_dir / 'references'
|
|
275
|
+
reference_dir.mkdir(exist_ok=True)
|
|
276
|
+
example_reference = reference_dir / 'api_reference.md'
|
|
277
|
+
example_reference.write_text(EXAMPLE_REFERENCE.format(skill_title=skill_title))
|
|
278
|
+
print("✅ references/api_reference.mdを作成しました")
|
|
279
|
+
|
|
280
|
+
# 例のアセットプレースホルダーを含むassets/ディレクトリを作成
|
|
281
|
+
assets_dir = skill_dir / 'assets'
|
|
282
|
+
assets_dir.mkdir(exist_ok=True)
|
|
283
|
+
example_asset = assets_dir / 'example_asset.txt'
|
|
284
|
+
example_asset.write_text(EXAMPLE_ASSET)
|
|
285
|
+
print("✅ assets/example_asset.txtを作成しました")
|
|
286
|
+
except Exception as e:
|
|
287
|
+
print(f"❌ リソースディレクトリ作成エラー: {e}")
|
|
288
|
+
return None
|
|
289
|
+
|
|
290
|
+
# 次のステップを表示
|
|
291
|
+
print(f"\n✅ Skill '{skill_name}' を {skill_dir} に初期化しました")
|
|
292
|
+
print("\n次のステップ:")
|
|
293
|
+
print("1. SKILL.mdを編集してTODO項目を完了し、descriptionを更新")
|
|
294
|
+
print("2. scripts/、references/、assets/の例のファイルをカスタマイズまたは削除")
|
|
295
|
+
print("3. 準備ができたら、バリデータを実行してSkill構造を確認")
|
|
296
|
+
|
|
297
|
+
return skill_dir
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def main():
|
|
301
|
+
if len(sys.argv) < 4 or sys.argv[2] != '--path':
|
|
302
|
+
print("使用法: init_skill.py <skill-name> --path <path>")
|
|
303
|
+
print("\nSkill名の要件:")
|
|
304
|
+
print(" - ケバブケース識別子(例: 'my-data-analyzer')")
|
|
305
|
+
print(" - 小文字、数字、ハイフンのみ")
|
|
306
|
+
print(" - 最大64文字")
|
|
307
|
+
print(" - ディレクトリ名と正確に一致する必要があります")
|
|
308
|
+
print("\neinja固有:")
|
|
309
|
+
print(" - einjaプロジェクトでは 'einja-' プレフィックスを推奨")
|
|
310
|
+
print(" - references/ディレクトリは複数形(公式仕様準拠)")
|
|
311
|
+
print("\n例:")
|
|
312
|
+
print(" init_skill.py einja-my-new-skill --path .claude/skills")
|
|
313
|
+
print(" init_skill.py einja-api-helper --path .claude/skills")
|
|
314
|
+
print(" init_skill.py custom-skill --path /custom/location")
|
|
315
|
+
sys.exit(1)
|
|
316
|
+
|
|
317
|
+
skill_name = sys.argv[1]
|
|
318
|
+
path = sys.argv[3]
|
|
319
|
+
|
|
320
|
+
print(f"🚀 Skillを初期化中: {skill_name}")
|
|
321
|
+
print(f" 場所: {path}")
|
|
322
|
+
print()
|
|
323
|
+
|
|
324
|
+
result = init_skill(skill_name, path)
|
|
325
|
+
|
|
326
|
+
if result:
|
|
327
|
+
sys.exit(0)
|
|
328
|
+
else:
|
|
329
|
+
sys.exit(1)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
if __name__ == "__main__":
|
|
333
|
+
main()
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Skillパッケージャー - Skillフォルダの配布可能な.skillファイルを作成
|
|
4
|
+
|
|
5
|
+
使用法:
|
|
6
|
+
python package_skill.py <path/to/skill-folder> [output-directory]
|
|
7
|
+
|
|
8
|
+
例:
|
|
9
|
+
python package_skill.py .claude/skills/einja-my-skill
|
|
10
|
+
python package_skill.py .claude/skills/einja-my-skill ./dist
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
import zipfile
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from quick_validate import validate_skill
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def package_skill(skill_path, output_dir=None):
|
|
20
|
+
"""
|
|
21
|
+
Skillフォルダを.skillファイルにパッケージ化
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
skill_path: Skillフォルダへのパス
|
|
25
|
+
output_dir: .skillファイルのオプションの出力ディレクトリ(デフォルトは現在のディレクトリ)
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
作成された.skillファイルへのパス、エラーの場合はNone
|
|
29
|
+
"""
|
|
30
|
+
skill_path = Path(skill_path).resolve()
|
|
31
|
+
|
|
32
|
+
# Skillフォルダが存在することを検証
|
|
33
|
+
if not skill_path.exists():
|
|
34
|
+
print(f"❌ エラー: Skillフォルダが見つかりません: {skill_path}")
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
if not skill_path.is_dir():
|
|
38
|
+
print(f"❌ エラー: パスはディレクトリではありません: {skill_path}")
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
# SKILL.mdが存在することを検証
|
|
42
|
+
skill_md = skill_path / "SKILL.md"
|
|
43
|
+
if not skill_md.exists():
|
|
44
|
+
print(f"❌ エラー: {skill_path} にSKILL.mdが見つかりません")
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
# パッケージ化前にバリデーションを実行
|
|
48
|
+
print("🔍 Skillをバリデーション中...")
|
|
49
|
+
valid, message = validate_skill(skill_path)
|
|
50
|
+
if not valid:
|
|
51
|
+
print(f"❌ バリデーション失敗: {message}")
|
|
52
|
+
print(" パッケージ化前にバリデーションエラーを修正してください。")
|
|
53
|
+
return None
|
|
54
|
+
print(f"✅ {message}\n")
|
|
55
|
+
|
|
56
|
+
# 出力場所を決定
|
|
57
|
+
skill_name = skill_path.name
|
|
58
|
+
if output_dir:
|
|
59
|
+
output_path = Path(output_dir).resolve()
|
|
60
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
|
61
|
+
else:
|
|
62
|
+
output_path = Path.cwd()
|
|
63
|
+
|
|
64
|
+
skill_filename = output_path / f"{skill_name}.skill"
|
|
65
|
+
|
|
66
|
+
# .skillファイル(zip形式)を作成
|
|
67
|
+
try:
|
|
68
|
+
with zipfile.ZipFile(skill_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
|
69
|
+
# Skillディレクトリを走査
|
|
70
|
+
for file_path in skill_path.rglob('*'):
|
|
71
|
+
if file_path.is_file():
|
|
72
|
+
# zip内の相対パスを計算
|
|
73
|
+
arcname = file_path.relative_to(skill_path.parent)
|
|
74
|
+
zipf.write(file_path, arcname)
|
|
75
|
+
print(f" 追加: {arcname}")
|
|
76
|
+
|
|
77
|
+
print(f"\n✅ Skillを正常にパッケージ化しました: {skill_filename}")
|
|
78
|
+
return skill_filename
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
print(f"❌ .skillファイル作成エラー: {e}")
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def main():
|
|
86
|
+
if len(sys.argv) < 2:
|
|
87
|
+
print("使用法: python package_skill.py <path/to/skill-folder> [output-directory]")
|
|
88
|
+
print("\n例:")
|
|
89
|
+
print(" python package_skill.py .claude/skills/einja-my-skill")
|
|
90
|
+
print(" python package_skill.py .claude/skills/einja-my-skill ./dist")
|
|
91
|
+
sys.exit(1)
|
|
92
|
+
|
|
93
|
+
skill_path = sys.argv[1]
|
|
94
|
+
output_dir = sys.argv[2] if len(sys.argv) > 2 else None
|
|
95
|
+
|
|
96
|
+
print(f"📦 Skillをパッケージ化中: {skill_path}")
|
|
97
|
+
if output_dir:
|
|
98
|
+
print(f" 出力ディレクトリ: {output_dir}")
|
|
99
|
+
print()
|
|
100
|
+
|
|
101
|
+
result = package_skill(skill_path, output_dir)
|
|
102
|
+
|
|
103
|
+
if result:
|
|
104
|
+
sys.exit(0)
|
|
105
|
+
else:
|
|
106
|
+
sys.exit(1)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
if __name__ == "__main__":
|
|
110
|
+
main()
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Skillの簡易バリデーションスクリプト - 最小バージョン
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
import yaml
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
def validate_skill(skill_path):
|
|
13
|
+
"""Skillの基本バリデーション"""
|
|
14
|
+
skill_path = Path(skill_path)
|
|
15
|
+
|
|
16
|
+
# SKILL.mdの存在を確認
|
|
17
|
+
skill_md = skill_path / 'SKILL.md'
|
|
18
|
+
if not skill_md.exists():
|
|
19
|
+
return False, "SKILL.mdが見つかりません"
|
|
20
|
+
|
|
21
|
+
# フロントマターの読み込みと検証
|
|
22
|
+
content = skill_md.read_text()
|
|
23
|
+
if not content.startswith('---'):
|
|
24
|
+
return False, "YAMLフロントマターが見つかりません"
|
|
25
|
+
|
|
26
|
+
# フロントマターの抽出
|
|
27
|
+
match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
|
|
28
|
+
if not match:
|
|
29
|
+
return False, "無効なフロントマター形式"
|
|
30
|
+
|
|
31
|
+
frontmatter_text = match.group(1)
|
|
32
|
+
|
|
33
|
+
# YAMLフロントマターのパース
|
|
34
|
+
try:
|
|
35
|
+
frontmatter = yaml.safe_load(frontmatter_text)
|
|
36
|
+
if not isinstance(frontmatter, dict):
|
|
37
|
+
return False, "フロントマターはYAML辞書である必要があります"
|
|
38
|
+
except yaml.YAMLError as e:
|
|
39
|
+
return False, f"フロントマターの無効なYAML: {e}"
|
|
40
|
+
|
|
41
|
+
# 許可されたプロパティを定義
|
|
42
|
+
ALLOWED_PROPERTIES = {'name', 'description', 'license', 'allowed-tools', 'metadata', 'compatibility'}
|
|
43
|
+
|
|
44
|
+
# 予期しないプロパティを確認(metadata配下のネストされたキーを除く)
|
|
45
|
+
unexpected_keys = set(frontmatter.keys()) - ALLOWED_PROPERTIES
|
|
46
|
+
if unexpected_keys:
|
|
47
|
+
return False, (
|
|
48
|
+
f"SKILL.mdフロントマターに予期しないキー: {', '.join(sorted(unexpected_keys))}。"
|
|
49
|
+
f"許可されたプロパティ: {', '.join(sorted(ALLOWED_PROPERTIES))}"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# 必須フィールドの確認
|
|
53
|
+
if 'name' not in frontmatter:
|
|
54
|
+
return False, "フロントマターに'name'がありません"
|
|
55
|
+
if 'description' not in frontmatter:
|
|
56
|
+
return False, "フロントマターに'description'がありません"
|
|
57
|
+
|
|
58
|
+
# バリデーション用にnameを抽出
|
|
59
|
+
name = frontmatter.get('name', '')
|
|
60
|
+
if not isinstance(name, str):
|
|
61
|
+
return False, f"Nameは文字列である必要があります。{type(name).__name__}が指定されました"
|
|
62
|
+
name = name.strip()
|
|
63
|
+
if name:
|
|
64
|
+
# 命名規則をチェック(ケバブケース: 小文字、ハイフンのみ)
|
|
65
|
+
if not re.match(r'^[a-z0-9-]+$', name):
|
|
66
|
+
return False, f"Name '{name}' はケバブケース(小文字、数字、ハイフンのみ)である必要があります"
|
|
67
|
+
if name.startswith('-') or name.endswith('-') or '--' in name:
|
|
68
|
+
return False, f"Name '{name}' はハイフンで始まる/終わる、または連続したハイフンを含めません"
|
|
69
|
+
# 名前の長さをチェック(仕様に従い最大64文字)
|
|
70
|
+
if len(name) > 64:
|
|
71
|
+
return False, f"Nameが長すぎます({len(name)}文字)。最大64文字です。"
|
|
72
|
+
|
|
73
|
+
# einja固有: einja-プレフィックスの推奨(警告レベル)
|
|
74
|
+
if not name.startswith('einja-'):
|
|
75
|
+
print(f"⚠️ 警告: einjaプロジェクトでは 'einja-' プレフィックスを推奨します(現在: '{name}')")
|
|
76
|
+
|
|
77
|
+
# descriptionを抽出・検証
|
|
78
|
+
description = frontmatter.get('description', '')
|
|
79
|
+
if not isinstance(description, str):
|
|
80
|
+
return False, f"Descriptionは文字列である必要があります。{type(description).__name__}が指定されました"
|
|
81
|
+
description = description.strip()
|
|
82
|
+
if description:
|
|
83
|
+
# 山括弧を確認
|
|
84
|
+
if '<' in description or '>' in description:
|
|
85
|
+
return False, "Descriptionには山括弧(<または>)を含められません"
|
|
86
|
+
# descriptionの長さをチェック(仕様に従い最大1024文字)
|
|
87
|
+
if len(description) > 1024:
|
|
88
|
+
return False, f"Descriptionが長すぎます({len(description)}文字)。最大1024文字です。"
|
|
89
|
+
|
|
90
|
+
# compatibilityフィールドが存在する場合に検証(オプション)
|
|
91
|
+
compatibility = frontmatter.get('compatibility', '')
|
|
92
|
+
if compatibility:
|
|
93
|
+
if not isinstance(compatibility, str):
|
|
94
|
+
return False, f"Compatibilityは文字列である必要があります。{type(compatibility).__name__}が指定されました"
|
|
95
|
+
if len(compatibility) > 500:
|
|
96
|
+
return False, f"Compatibilityが長すぎます({len(compatibility)}文字)。最大500文字です。"
|
|
97
|
+
|
|
98
|
+
# einja固有: SKILL.mdの行数チェック(500行以内推奨)
|
|
99
|
+
line_count = len(content.split('\n'))
|
|
100
|
+
if line_count > 500:
|
|
101
|
+
print(f"⚠️ 警告: SKILL.mdが500行を超えています({line_count}行)。コンテンツをreferenceファイルに分割することを検討してください。")
|
|
102
|
+
|
|
103
|
+
# einja固有: references/ディレクトリ名チェック(reference/は警告)
|
|
104
|
+
reference_dir = skill_path / 'reference'
|
|
105
|
+
if reference_dir.exists():
|
|
106
|
+
print(f"⚠️ 警告: 'reference/'ディレクトリが見つかりました。公式仕様に準拠し 'references/'(複数形)を使用してください。")
|
|
107
|
+
|
|
108
|
+
return True, "Skillは有効です!"
|
|
109
|
+
|
|
110
|
+
if __name__ == "__main__":
|
|
111
|
+
if len(sys.argv) != 2:
|
|
112
|
+
print("使用法: python quick_validate.py <skill_directory>")
|
|
113
|
+
sys.exit(1)
|
|
114
|
+
|
|
115
|
+
valid, message = validate_skill(sys.argv[1])
|
|
116
|
+
print(message)
|
|
117
|
+
sys.exit(0 if valid else 1)
|
|
@@ -21,9 +21,9 @@ spec-create で作成された仕様書(requirements.md、design.md、qa-tests
|
|
|
21
21
|
|
|
22
22
|
**必須パラメータ**:
|
|
23
23
|
- `spec_dir`: spec ディレクトリのパス(例: `/docs/specs/issues/auth/issue21-login-feature/`)
|
|
24
|
-
- `
|
|
24
|
+
- `ac_ids`: 対象AC番号(例: `AC1.1, AC1.2`)
|
|
25
25
|
|
|
26
|
-
**入力形式**:
|
|
26
|
+
**入力形式**: 自然言語でAC情報を指定
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
@@ -67,8 +67,8 @@ spec-create で作成された仕様書(requirements.md、design.md、qa-tests
|
|
|
67
67
|
|
|
68
68
|
### ステップ4: qa-tests/ からのテスト仕様抽出
|
|
69
69
|
|
|
70
|
-
1.
|
|
71
|
-
- 例:
|
|
70
|
+
1. AC番号からストーリー番号を特定し、テストファイルを参照
|
|
71
|
+
- 例: AC1.1 → Story 1 → `qa-tests/story1.md`、AC2.3 → Story 2 → `qa-tests/story2.md`
|
|
72
72
|
2. scenarios.md から該当タスクのシナリオテストを確認
|
|
73
73
|
3. 以下の情報を抽出:
|
|
74
74
|
- **テストシナリオ**: 実行すべきテストケース
|
|
@@ -86,7 +86,7 @@ spec-create で作成された仕様書(requirements.md、design.md、qa-tests
|
|
|
86
86
|
|
|
87
87
|
### spec 情報
|
|
88
88
|
- **ディレクトリ**: {spec_dir}
|
|
89
|
-
-
|
|
89
|
+
- **対象AC**: {ac_ids}
|
|
90
90
|
|
|
91
91
|
### 要件
|
|
92
92
|
#### 機能要件
|
|
@@ -126,7 +126,7 @@ interface Example {
|
|
|
126
126
|
|
|
127
127
|
### テスト仕様
|
|
128
128
|
#### 対象テストファイル
|
|
129
|
-
- `qa-tests/
|
|
129
|
+
- `qa-tests/story{N}.md`(該当ACセクション)
|
|
130
130
|
|
|
131
131
|
#### シナリオテスト
|
|
132
132
|
- **シナリオ1**: [概要] - 実施タイミング: [Step X-Y]
|