superpowers-mcp 6.3.0 → 6.3.2
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.ja.md +27 -2
- package/README.ko.md +27 -2
- package/README.md +27 -2
- package/README.zh-TW.md +27 -2
- package/out/server.js +1 -1
- package/package.json +1 -1
- package/skills/brainstorming/SKILL.md +1 -0
- package/skills/requesting-code-review/SKILL.md +1 -1
- package/skills/subagent-driven-development/SKILL.md +56 -2
- package/skills/subagent-driven-development/implementer-prompt.md +5 -2
- package/skills/subagent-driven-development/scripts/review-package +11 -1
- package/skills/subagent-driven-development/scripts/review-package.ps1 +13 -1
- package/skills/subagent-driven-development/scripts/sdd-workspace +43 -4
- package/skills/subagent-driven-development/scripts/sdd-workspace.ps1 +65 -3
- package/skills/subagent-driven-development/scripts/task-brief +1 -1
- package/skills/subagent-driven-development/scripts/task-brief.ps1 +1 -1
- package/skills/test-driven-development/SKILL.md +10 -0
- package/skills/writing-plans/SKILL.md +24 -0
- package/skills/writing-plans/skeleton-first-plans.md +131 -0
- package/skills/writing-skills/render-graphs.js +7 -6
package/README.ja.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | [繁體中文](README.zh-TW.md) | [日本語](README.ja.md) | [한국어](README.ko.md)
|
|
4
4
|
|
|
5
|
-
[](https://github.com/Poseidoncode/superpowers-mcp)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
8
|
このドキュメントは、オリジナルの Superpowers スキルライブラリを独立した MCP Toolpack にパッケージ化するための情報と使用手順をまとめたものです。
|
|
@@ -128,7 +128,32 @@
|
|
|
128
128
|
|
|
129
129
|
## 🆕 最近の更新
|
|
130
130
|
|
|
131
|
-
### v6.3.
|
|
131
|
+
### v6.3.2(最新)
|
|
132
|
+
|
|
133
|
+
- **writing-plans — 2 つのプラン形状(Two Plan Shapes)と骨格優先(Skeleton-First)**:
|
|
134
|
+
- `skills/writing-plans/SKILL.md` に **Two Plan Shapes** ルーターを追加(`task-by-task` デフォルト vs `skeleton-first` 代替案)。
|
|
135
|
+
- 新規 [`skills/writing-plans/skeleton-first-plans.md`](skills/writing-plans/skeleton-first-plans.md) で Walking Skeleton(Task 1 で全サブシステムを貫通する最小稼働スライスを作成)、契約型タスク(Task Contracts、コードを直接書かずに厳密な Consumes/Produces インターフェースと観察可能な検証基準を定義)、`Tier: mechanical | judgment` タグを定義。
|
|
136
|
+
- **subagent-driven-development (SDD) — ウェーブディスパッチ(Wave Dispatch)と並列 Worktree プロトコル**:
|
|
137
|
+
- skeleton-first プランに対して **DISPATCH PLAN** を生成し、ファイルの競合がないタスクをウェーブとして並列ディスパッチ。
|
|
138
|
+
- **並列 Worktree プロトコル(Parallel Worktree Protocol)**:独立した `.worktrees/task-<N>` で並行タスクを実行し、プラン順序で順次統合。競合時は自動 rebase と implementer 再開で修正。
|
|
139
|
+
- Step 5 に完了後の `Plan holds` / `Amendment:` チェック行を追加し、進行中タスクの整合性を保ちながら後続タスクに更新された契約を伝播。
|
|
140
|
+
- **SDD — Tier 駆動モデルディスパッチ**:
|
|
141
|
+
- SDD ディスパッチャーと `implementer-prompt.md` が `Tier:` 指定(`mechanical` → 経済的な軽量モデル、`judgment` → 標準モデル)を直接適用し、トークンを節約。
|
|
142
|
+
- **writing-skills — バイナリ実行セキュリティ強化(`render-graphs.js`)**:
|
|
143
|
+
- `execSync` から `execFileSync('dot', ['-Tsvg'], ...)` に移行してシェルインジェクションを根絶。10MB バッファ上限、Windows CRLF 対応(`\r?\n`)、`winget` インストール案内を追加。
|
|
144
|
+
- **テストと検証**:MCP プロトコル、セキュリティ、SDD Bash(11 アサーション)、PowerShell(70 アサーション)、Graphviz レンダリングテストのすべてが 100% 合格。
|
|
145
|
+
|
|
146
|
+
### v6.3.1
|
|
147
|
+
|
|
148
|
+
- **SDD ワークスペース所有権マーカーと物理パス正規化**:`sdd-workspace`(Bash)と `sdd-workspace.ps1`(PowerShell)は `plan-path` マーカーと物理パス正規化(`pwd -P` および動的 `pwd` 検出)を使用。同名のプラン(`docs/alpha/plan.md` と `docs/beta/plan.md` など)が衝突せず個別の `.superpowers/sdd/` ワークスペースに分離されます。
|
|
149
|
+
- **SDD レビューパッケージ範囲ガード**:`review-package` および `review-package.ps1` は `git merge-base --is-ancestor BASE HEAD` とコミット数を検証し、空や逆転した範囲による誤判定(false-pass)を防止。
|
|
150
|
+
- **実行権限喪失への耐性**:`task-brief` と `review-package` は `"${BASH:-bash}"` で明示的に呼び出し、アーカイブ解凍等で `+x` 権限が失われても安定して動作。
|
|
151
|
+
- **TDD プロジェクトスイート検証フロア**:`skills/test-driven-development/SKILL.md` はタスク完了前にプロジェクト全体のテストコマンド(`npm test`、`pytest` 等)の実行を義務化。
|
|
152
|
+
- **Code Review ゴースト変更防止**:`skills/requesting-code-review/SKILL.md` で複数コミットのレビュー起点を `git merge-base origin/main HEAD` に固定。
|
|
153
|
+
- **Brainstorming ツールチェーン決定ゲート**:`skills/brainstorming/SKILL.md` の設計提示フェーズでツールチェーン設定を事前に確認し、`Global Constraints` に記録。
|
|
154
|
+
- **テスト拡充**:`tests/sdd/test-sdd-workspace.sh`(11 アサーション)を追加、PowerShell スイート(70 アサーション)を拡張。
|
|
155
|
+
|
|
156
|
+
### v6.3.0
|
|
132
157
|
|
|
133
158
|
- **上流 obra/superpowers v6.3.0 との同期** — 適用可能な改善をすべて採用し、フォーク固有のセキュリティ強化と PowerShell サポートは維持。
|
|
134
159
|
- **brainstorming — 3 パスルーター**: すべてのリクエストを事前に `spike` / `bounded` / `architectural` に分類し、プロセス量をタスクに合わせて調整。ただし承認ゲートは常に全パスに適用されます。実行中に隠れた複雑さが判明した場合はパスをアップグレード — ダウングレードはありません。
|
package/README.ko.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | [繁體中文](README.zh-TW.md) | [日本語](README.ja.md) | [한국어](README.ko.md)
|
|
4
4
|
|
|
5
|
-
[](https://github.com/Poseidoncode/superpowers-mcp)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
8
|
이 문서는 원본 Superpowers 스킬 라이브러리를 독립적인 MCP Toolpack으로 패키징하기 위한 정보와 사용 지침을 요약한 것입니다.
|
|
@@ -128,7 +128,32 @@
|
|
|
128
128
|
|
|
129
129
|
## 🆕 최근 업데이트
|
|
130
130
|
|
|
131
|
-
### v6.3.
|
|
131
|
+
### v6.3.2 (최신)
|
|
132
|
+
|
|
133
|
+
- **writing-plans — 2가지 계획 형태(Two Plan Shapes)와 스켈레톤 우선(Skeleton-First)**:
|
|
134
|
+
- `skills/writing-plans/SKILL.md`에 **Two Plan Shapes** 라우터를 추가(`task-by-task` 기본값 vs `skeleton-first` 대안).
|
|
135
|
+
- 새 [`skills/writing-plans/skeleton-first-plans.md`](skills/writing-plans/skeleton-first-plans.md)에서 Walking Skeleton(Task 1에서 전체 하위 시스템을 얇게 관통하는 실행 슬라이스 구축), 계약 기반 작업(Task Contracts, 코드 스크립트 대신 엄격한 Consumes/Produces 인터페이스 및 관찰 가능한 성공 기준 명시), `Tier: mechanical | judgment` 태그 정의.
|
|
136
|
+
- **subagent-driven-development (SDD) — 웨이브 디스패치(Wave Dispatch) 및 병렬 Worktree 프로토콜**:
|
|
137
|
+
- skeleton-first 계획에 대해 **DISPATCH PLAN**을 생성하여 파일 충돌이 없는 작업을 웨이브 단위로 병렬 디스패치.
|
|
138
|
+
- **병렬 Worktree 프로토콜(Parallel Worktree Protocol)**: 독립된 `.worktrees/task-<N>`에서 동시 작업을 실행하고 계획 순서대로 순차 병합. 충돌 시 자동 rebase 후 implementer를 재개하여 자체 해결.
|
|
139
|
+
- Step 5에 완료 후 `Plan holds` / `Amendment:` 점검 라인을 추가하여 진행 중인 작업의 무결성을 유지하면서 후속 작업에 변경된 계약 전파.
|
|
140
|
+
- **SDD — Tier 기반 모델 디스패치**:
|
|
141
|
+
- SDD 디스패처 및 `implementer-prompt.md`가 `Tier:` 지정(`mechanical` → 경제적인 경량 모델, `judgment` → 표준 모델)을 즉시 적용하여 토큰 낭비 방지.
|
|
142
|
+
- **writing-skills — 바이너리 실행 보안 강화(`render-graphs.js`)**:
|
|
143
|
+
- `execSync` 대신 `execFileSync('dot', ['-Tsvg'], ...)`로 전환하여 쉘 인젝션 위험 근절. 10MB 버퍼 제한, Windows CRLF(`\r?\n`) 호환 및 `winget` 설치 안내 추가.
|
|
144
|
+
- **테스트 및 검증**: MCP 프로토콜, 보안, SDD Bash(11개 어서션), PowerShell(70개 어서션), Graphviz 렌더링 테스트 100% 통과.
|
|
145
|
+
|
|
146
|
+
### v6.3.1
|
|
147
|
+
|
|
148
|
+
- **SDD 워크스페이스 소유권 마커 및 물리 경로 정규화**: `sdd-workspace`(Bash) 및 `sdd-workspace.ps1`(PowerShell)은 `plan-path` 마커와 물리 경로 정규화(`pwd -P` 및 동적 `pwd` 감지)를 사용. 동일한 이름의 계획 파일(`docs/alpha/plan.md` 및 `docs/beta/plan.md` 등)이 충돌 없이 별도의 `.superpowers/sdd/` 워크스페이스로 격리됩니다.
|
|
149
|
+
- **SDD 리뷰 패키지 범위 가드**: `review-package` 및 `review-package.ps1`은 `git merge-base --is-ancestor BASE HEAD`와 커밋 수를 검증하여 비어 있거나 역전된 범위로 인한 오탐(false-pass)을 방지합니다.
|
|
150
|
+
- **실행 권한 상실에 대한 복원력**: `task-brief`와 `review-package`는 `"${BASH:-bash}"`로 명시적 호출하여 아카이브 압축 해제 등으로 `+x` 권限이 손실되어도 정상 동작합니다.
|
|
151
|
+
- **TDD 프로젝트 스위트 검증 하한선**: `skills/test-driven-development/SKILL.md`는 작업 완료 선언 전 프로젝트 전체 테스트 명령(`npm test`, `pytest` 등) 실행을 의무화합니다.
|
|
152
|
+
- **Code Review 유령 변경 방지**: `skills/requesting-code-review/SKILL.md`에서 다중 커밋의 리뷰 기준점을 `git merge-base origin/main HEAD`로 고정합니다.
|
|
153
|
+
- **Brainstorming 툴체인 결정 게이트**: `skills/brainstorming/SKILL.md`의 설계 제시 단계에서 툴체인 설정을 사전에 확인하고 `Global Constraints`에 기록합니다.
|
|
154
|
+
- **테스트 확장**: `tests/sdd/test-sdd-workspace.sh`(11개 어서션) 추가 및 PowerShell 스위트(70개 어서션) 확장.
|
|
155
|
+
|
|
156
|
+
### v6.3.0
|
|
132
157
|
|
|
133
158
|
- **상류 obra/superpowers v6.3.0 동기화** — 적용 가능한 개선 사항을 모두 채택하고, 포크 고유의 보안 강화와 PowerShell 지원은 유지.
|
|
134
159
|
- **brainstorming — 3경로 라우터**: 모든 요청을 사전에 `spike` / `bounded` / `architectural`로 분류하며, 절차의 양은 작업 규모에 맞춰 조정됩니다. 단 승인 게이트는 모든 경로에 동일하게 적용됩니다. 실행 중 숨은 복잡성이 발견되면 경로를 업그레이드 — 다운그레이드는 없습니다.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | [繁體中文](README.zh-TW.md) | [日本語](README.ja.md) | [한국어](README.ko.md)
|
|
4
4
|
|
|
5
|
-
[](https://github.com/Poseidoncode/superpowers-mcp)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
8
|
This document summarizes the information and usage instructions for packaging the original Superpowers skills library into an independent MCP Toolpack.
|
|
@@ -128,7 +128,32 @@ These skills are designed for orchestrating complex meta-execution patterns with
|
|
|
128
128
|
|
|
129
129
|
## 🆕 Recent Updates
|
|
130
130
|
|
|
131
|
-
### v6.3.
|
|
131
|
+
### v6.3.2 (Latest)
|
|
132
|
+
|
|
133
|
+
- **writing-plans — Two Plan Shapes Router & Skeleton-First Plans**:
|
|
134
|
+
- `skills/writing-plans/SKILL.md` introduces the **Two Plan Shapes** router (`task-by-task` default vs `skeleton-first` alternative) to determine architecture upfront.
|
|
135
|
+
- New [`skills/writing-plans/skeleton-first-plans.md`](skills/writing-plans/skeleton-first-plans.md) defines the Walking Skeleton pattern (Task 1 builds the thinnest running end-to-end slice across all subsystems), Task Contracts (strict interfaces and observable behaviors without code scripts), and deliberate `Tier: mechanical | judgment` tagging.
|
|
136
|
+
- **subagent-driven-development (SDD) — Wave Dispatch & Parallel Worktree Protocol**:
|
|
137
|
+
- SDD controller performs **Dispatch Plan** scanning on skeleton-first plans, grouping mutually file-disjoint tasks into waves for concurrent dispatch.
|
|
138
|
+
- **Parallel Worktree Protocol**: Runs concurrent tasks in dedicated `.worktrees/task-<N>` worktrees, with sequential plan-order merges and automatic rebase-to-fix loops on merge conflict or test regression.
|
|
139
|
+
- Step 5 adds the post-completion `Plan holds` / `Amendment:` check line, ensuring in-flight tasks complete cleanly while downstream tasks inherit updated plan contracts.
|
|
140
|
+
- **SDD — Tier-Driven Model Selection**:
|
|
141
|
+
- SDD dispatcher and `implementer-prompt.md` respect task `Tier:` markings (`mechanical` → fastest/cheapest tier; `judgment` → standard tier), saving tokens without redundant re-adjudication.
|
|
142
|
+
- **writing-skills — Binary Execution Hardening (`render-graphs.js`)**:
|
|
143
|
+
- Replaced `execSync` shell execution with direct `execFileSync('dot', ['-Tsvg'], ...)` to eliminate shell injection risks. Added 10MB buffer limits, Windows CRLF support (`\r?\n`), and Windows `winget` installation guidance.
|
|
144
|
+
- **Tests & Verification**: Full regression suites pass 100% across MCP protocol, Security Edge Cases, SDD Bash (11 assertions), PowerShell (70 assertions), and Graphviz rendering.
|
|
145
|
+
|
|
146
|
+
### v6.3.1
|
|
147
|
+
|
|
148
|
+
- **SDD Ownership Markers & Path Normalization**: `sdd-workspace` (Bash) and `sdd-workspace.ps1` (PowerShell) now manage plan-scoped workspaces using `plan-path` markers with canonical physical path normalization (`pwd -P` and dynamic `pwd` detection). Same-basename plans (e.g. `docs/alpha/plan.md` vs `docs/beta/plan.md`) safely disambiguate into distinct `.superpowers/sdd/` workspaces, preventing artifact and ledger overwrites.
|
|
149
|
+
- **SDD Review Package Range Mechanical Guards**: `review-package` and `review-package.ps1` now enforce `git merge-base --is-ancestor BASE HEAD` and `git rev-list --count BASE..HEAD > 0` (exiting with code 3 on error) to reject invalid or empty commit ranges and prevent false-pass review approvals.
|
|
150
|
+
- **SDD Helper Resilience on Stripped Permissions**: `task-brief` and `review-package` invoke `sdd-workspace` via explicit `"${BASH:-bash}"`, surviving environments where execution bits (`+x`) are stripped during archive extraction.
|
|
151
|
+
- **TDD Verification Floor**: `skills/test-driven-development/SKILL.md` explicitly defines "green" as passing the entire repository test suite (e.g., bare `npm test`, `pytest`, `cargo test`) before declaring a task complete.
|
|
152
|
+
- **Code Review Merge-Base Anchoring**: `skills/requesting-code-review/SKILL.md` now anchors multi-commit review `BASE_SHA` to `git merge-base origin/main HEAD` to prevent phantom deletions when `origin/main` advances.
|
|
153
|
+
- **Brainstorming Tooling Decision Gate**: `skills/brainstorming/SKILL.md` adds a proactive tooling inquiry (linter, formatting, unit/e2e tests, fuzzing) during the Design Presentation phase for new projects, recording choices into the spec's `Global Constraints`.
|
|
154
|
+
- **Tests & Coverage**: Added `tests/sdd/test-sdd-workspace.sh` (11 assertions) and expanded PowerShell suites (70 assertions across 5 files). Full test suites passing 100%.
|
|
155
|
+
|
|
156
|
+
### v6.3.0
|
|
132
157
|
|
|
133
158
|
- **Upstream sync with obra/superpowers v6.3.0** — all applicable improvements adopted, fork-specific security hardening and PowerShell support preserved.
|
|
134
159
|
- **brainstorming — three-path router**: every request is classified `spike` / `bounded` / `architectural` up front; the ceremony scales with the task but the approval gate never does. Hidden complexity upgrades the path mid-task — never downgrades.
|
package/README.zh-TW.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | [繁體中文](README.zh-TW.md) | [日本語](README.ja.md) | [한국어](README.ko.md)
|
|
4
4
|
|
|
5
|
-
[](https://github.com/Poseidoncode/superpowers-mcp)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
8
|
本文檔總結了將原始 Superpowers 技能庫打包成獨立 MCP Toolpack 的相關資訊與使用說明。
|
|
@@ -128,7 +128,32 @@
|
|
|
128
128
|
|
|
129
129
|
## 🆕 最近更新
|
|
130
130
|
|
|
131
|
-
### v6.3.
|
|
131
|
+
### v6.3.2 (最新版)
|
|
132
|
+
|
|
133
|
+
- **writing-plans — 雙計畫形態(Two Plan Shapes)與骨架優先(Skeleton-First)**:
|
|
134
|
+
- `skills/writing-plans/SKILL.md` 加入 **Two Plan Shapes** 路由機制(`task-by-task` 預設模式 vs `skeleton-first` 骨架優先),在撰寫計畫前提早決定架構模型。
|
|
135
|
+
- 新增 [`skills/writing-plans/skeleton-first-plans.md`](skills/writing-plans/skeleton-first-plans.md) 定義 Walking Skeleton(Task 1 先完成貫穿所有子系統的真實薄切片)、契約式任務(Task Contracts,嚴格定義 Consumes/Produces 接口與可觀測驗收標準,不預寫代碼腳本)與 `Tier: mechanical | judgment` 標記。
|
|
136
|
+
- **subagent-driven-development (SDD) — 波次派發(Wave Dispatch)與並行工作樹協議**:
|
|
137
|
+
- 控制器在衝突掃描階段針對 skeleton-first 計畫生成 **DISPATCH PLAN**,將檔案互斥且無未完成介面依賴的任務組成波次並行派發。
|
|
138
|
+
- **並行工作樹協議(Parallel Worktree Protocol)**:並行任務各於專屬 `.worktrees/task-<N>` 執行,按計畫順序依次合併;若遇衝突或驗證失敗,自動 rebase 並喚醒 implementer 自行修復。
|
|
139
|
+
- Step 5 增加完工後的 `Plan holds` / `Amendment:` 檢查行,確保並行在途任務順利收斂,並將介面變動直接傳遞給後續任務。
|
|
140
|
+
- **SDD — Tier 驅動模型分派**:
|
|
141
|
+
- SDD 控制器與 `implementer-prompt.md` 嚴格遵循計畫中的 `Tier:` 標記(`mechanical` → 快速經濟型模型;`judgment` → 標準中階模型),大幅節省 token 且不再重複審議。
|
|
142
|
+
- **writing-skills — 二進位安全加固(`render-graphs.js`)**:
|
|
143
|
+
- 改用 `execFileSync('dot', ['-Tsvg'], ...)` 徹底杜絕 shell 注入,設置 10MB 緩衝上限,支援 Windows CRLF(`\r?\n`)換行匹配與 `winget` 安裝提示。
|
|
144
|
+
- **測試與驗證**:MCP 協定、邊界安全、SDD Bash(11 項斷言)、PowerShell(70 項斷言)及 Graphviz 渲染測試全數 100% 通過。
|
|
145
|
+
|
|
146
|
+
### v6.3.1
|
|
147
|
+
|
|
148
|
+
- **SDD 工作區歸屬標記與實體路徑正規化**:`sdd-workspace`(Bash)與 `sdd-workspace.ps1`(PowerShell)改用 `plan-path` 歸屬標記與標準化實體路徑(`pwd -P` 與動態 `pwd` 偵測)。同名 plan(如 `docs/alpha/plan.md` 與 `docs/beta/plan.md`)會自動解析為獨立的 `.superpowers/sdd/` 工作區,杜絕產物與進度覆蓋。
|
|
149
|
+
- **SDD 審查包範圍機械守衛**:`review-package` 與 `review-package.ps1` 強制校驗 `git merge-base --is-ancestor BASE HEAD` 與 commit 數量大於 0(錯誤時 exit 3),防止空範圍或倒置範圍造成審查假綠燈。
|
|
150
|
+
- **執行權限剝離韌性**:`task-brief` 與 `review-package` 改以 `"${BASH:-bash}"` 調用,在解壓縮或跨系統搬移丟失 `+x` 權限時依然能穩定執行。
|
|
151
|
+
- **TDD 全套件驗證下限**:`skills/test-driven-development/SKILL.md` 明確規定任務完成前必須跑過全專案測試指令(如 `npm test`、`pytest`、`cargo test`)。
|
|
152
|
+
- **Code Review 防幽靈變更**:`skills/requesting-code-review/SKILL.md` 將多 commit 審查起點錨定為 `git merge-base origin/main HEAD`,消除 main 推進引發的幽靈刪除。
|
|
153
|
+
- **Brainstorming 工具鏈決策門禁**:`skills/brainstorming/SKILL.md` 在設計展示階段主動詢問工具鏈配置並記錄於 `Global Constraints`。
|
|
154
|
+
- **測試擴充**:新增 `tests/sdd/test-sdd-workspace.sh`(11 項斷言)並擴充 PowerShell 套件(70 項斷言)。
|
|
155
|
+
|
|
156
|
+
### v6.3.0
|
|
132
157
|
|
|
133
158
|
- **對齊上游 obra/superpowers v6.3.0** — 採用所有適用改進,保留本 fork 的安全強化與 PowerShell 支援。
|
|
134
159
|
- **brainstorming — 三路分類流程(three-path router)**:每個請求先分類為 `spike` / `bounded` / `architectural`;流程深度隨任務規模調整,但審批門檻永遠不變。隱藏複雜度會在執行途中升級路徑——絕不降級。
|
package/out/server.js
CHANGED
|
@@ -49,7 +49,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
49
49
|
`}var vs=class{constructor(t=hf.default.stdin,r=hf.default.stdout){this._stdin=t,this._stdout=r,this._readBuffer=new gs,this._started=!1,this._ondata=n=>{this._readBuffer.append(n),this.processReadBuffer()},this._onerror=n=>{this.onerror?.(n)}}async start(){if(this._started)throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");this._started=!0,this._stdin.on("data",this._ondata),this._stdin.on("error",this._onerror)}processReadBuffer(){for(;;)try{let t=this._readBuffer.readMessage();if(t===null)break;this.onmessage?.(t)}catch(t){this.onerror?.(t)}}async close(){this._stdin.off("data",this._ondata),this._stdin.off("error",this._onerror),this._stdin.listenerCount("data")===0&&this._stdin.pause(),this._readBuffer.clear(),this.onclose?.()}send(t){return new Promise(r=>{let n=j_(t);this._stdout.write(n)?r():this._stdout.once("drain",r)})}};var ze=sr(require("fs/promises")),ye=sr(require("path")),$n=10*1024*1024,ys=class{skillsPath;cachedSkills=null;loadingPromise=null;skillMap=new Map;contentCache=new Map;constructor(t){this.skillsPath=t}stripQuotes(t){return t.replace(/^"(.*)"$|^'(.*)'$/,"$1$2").trim()}parseFrontmatter(t){let r=t;if(r.charCodeAt(0)===65279&&(r=r.slice(1)),!r.startsWith("---"))return{name:"",description:""};let n=r.split(/\r?\n/),o=[],i=!1;for(let u=1;u<n.length;u++){if(n[u].trim()==="---"){i=!0;break}o.push(n[u])}if(!i)return{name:"",description:""};let a="",s="",c=!1;for(let u of o){let l=u.match(/^name:\s*(.*?)\s*$/);if(l){a=this.stripQuotes(l[1]),c=!1;continue}let d=u.match(/^description:\s*(.*?)\s*$/);if(d){s=this.stripQuotes(d[1]),c=!0;continue}c&&/^\s+/.test(u)?s+=" "+u.trim():c=!1}return{name:a,description:s}}async exists(t){try{return await ze.access(t),!0}catch{return!1}}async listSkills(t=!1){if(this.cachedSkills&&!t)return this.cachedSkills;if(this.loadingPromise&&!t)return this.loadingPromise;t&&this.contentCache.clear();let r=this.internalListSkills();this.loadingPromise=r;try{return await r}finally{this.loadingPromise===r&&(this.loadingPromise=null)}}async internalListSkills(){if(!await this.exists(this.skillsPath))return this.cachedSkills??[];let t=[],r=new Map,n=!1;try{let o=await ze.readdir(this.skillsPath,{withFileTypes:!0});for(let i of o){if(!i.isDirectory()&&!i.isSymbolicLink())continue;let a=ye.join(this.skillsPath,i.name),s=ye.join(a,"SKILL.md");if(await this.exists(s))try{let c=await this.readFileNoFollow(s,this.skillsPath),{name:u,description:l}=this.parseFrontmatter(c),m={name:u||i.name,description:l,skillPath:s};t.push(m),r.set(m.name.toLowerCase(),m);let p=ye.basename(ye.dirname(m.skillPath)).toLowerCase();r.set(p,m)}catch{process.stderr.write(`Warning: Failed to read skill file in directory "${i.name}"
|
|
50
50
|
`)}}n=!0}catch(o){process.stderr.write(`Error reading skills directory: ${String(o)}
|
|
51
51
|
`)}return n&&(this.skillMap=r,this.cachedSkills=t.sort((o,i)=>o.name.localeCompare(i.name))),this.cachedSkills??[]}async findSkill(t){let r=typeof t=="string"?t.trim():"";if(!(!r||r==="."||r===".."||r.includes("/")||r.includes("\\")||r.includes("\0")))return this.cachedSkills||await this.listSkills(),this.skillMap.get(r.toLowerCase())}async readFileNoFollow(t,r){let n=ye.resolve(t),o=ye.resolve(r),i=async()=>{let l=await ze.realpath(n),d=await ze.realpath(o);if(!(await ze.stat(d)).isDirectory())throw new Error("Skills directory must be a directory");let p=ye.relative(d,l);if(p===".."||p.startsWith(`..${ye.sep}`)||ye.isAbsolute(p))throw new Error("File is outside skills directory");let h=await ze.stat(l);if(!h.isFile()||h.nlink!==1)throw new Error("Skill path is not a regular file");if(h.size>$n)throw new Error("Skill file exceeds size limit");return{realFilePath:l,stat:h}},a=await i(),s=await i();if(a.realFilePath!==s.realFilePath||a.stat.dev!==s.stat.dev||a.stat.ino!==s.stat.ino)throw new Error("File changed while validating its path");let c=process.platform==="win32"?0:ze.constants.O_NOFOLLOW,u=await ze.open(s.realFilePath,ze.constants.O_RDONLY|c);try{let l=await u.stat();if(!l.isFile()||l.nlink!==1||l.dev!==s.stat.dev||l.ino!==s.stat.ino||l.size>$n)throw new Error("File changed while opening");let d=[],m=64*1024,p=0;for(;p<=$n;){let v=Buffer.allocUnsafe(Math.min(m,$n+1-p)),{bytesRead:$}=await u.read(v,0,v.length,null);if($===0)break;if(p+=$,d.push(v.subarray(0,$)),p>$n)throw new Error("Skill file exceeds size limit")}let h=await u.stat();if(h.size>$n||h.dev!==s.stat.dev||h.ino!==s.stat.ino)throw new Error("File changed while reading");return Buffer.concat(d,p).toString("utf-8")}finally{await u.close()}}async readSkillContent(t,r=!1){let n=ye.resolve(t),o=ye.resolve(this.skillsPath),i=n,a=o;try{i=await ze.realpath(n),a=await ze.realpath(o)}catch{}let s=ye.relative(a,i);if(s.startsWith("..")||ye.isAbsolute(s))throw new Error(`Access denied: path "${t}" is outside skills directory`);if(this.contentCache.has(i)&&!r)return this.contentCache.get(i);try{let c=await this.readFileNoFollow(t,this.skillsPath);c.charCodeAt(0)===65279&&(c=c.slice(1));let u=c.replace(/^---\s*\r?\n[\s\S]*?\r?\n---\s*\r?\n?/,"").trim();return this.contentCache.set(i,u),u}catch(c){throw new Error(`Failed to read skill content: ${c instanceof Error?c.message:String(c)}`)}}clearCache(){this.cachedSkills=null,this.loadingPromise=null,this.skillMap.clear(),this.contentCache.clear()}};function jT(){let e=process.env.SKILLS_PATH;if(e){let r=ct.resolve(e),n=ct.normalize(r).toLowerCase(),o=ct.parse(r).root.toLowerCase();if(n===o||["/etc","/var","/bin","/sbin","/usr","/root","/sys","/proc","/dev","c:\\windows","c:\\program files","c:\\program files (x86)"].some(s=>n===s||n.startsWith(s+ct.sep)))process.stderr.write(`Warning: Potentially unsafe SKILLS_PATH: "${e}". Fallback to default.
|
|
52
|
-
`);else return r}let t=ct.join(__dirname,"..","skills");return E_.existsSync(t)?t:ct.join(__dirname,"skills")}var O_=jT(),It=new ys(O_),Pr=new hs({name:"superpowers-mcp",version:"6.3.
|
|
52
|
+
`);else return r}let t=ct.join(__dirname,"..","skills");return E_.existsSync(t)?t:ct.join(__dirname,"skills")}var O_=jT(),It=new ys(O_),Pr=new hs({name:"superpowers-mcp",version:"6.3.2"},{capabilities:{resources:{subscribe:!1},prompts:{},tools:{}}});Pr.setRequestHandler(od,async()=>({resources:(await It.listSkills()).map(t=>({uri:`skill://superpowers/${encodeURIComponent(t.name)}`,name:t.name,description:t.description,mimeType:"text/markdown"}))}));Pr.setRequestHandler(ad,async e=>{let t=e.params.uri,r=t.match(/^skill:\/\/superpowers\/(.+)$/);if(!r)throw new D(M.InvalidRequest,`Invalid skill URI: ${t}`);let n;try{n=decodeURIComponent(r[1])}catch{throw new D(M.InvalidRequest,`Invalid skill URI: ${t}`)}let o=await It.findSkill(n);if(!o)throw new D(M.InvalidRequest,`Skill not found: ${n}`);try{let i=await It.readSkillContent(o.skillPath);return{contents:[{uri:t,mimeType:"text/markdown",text:i}]}}catch{throw new D(M.InternalError,"Failed to read skill content safely.")}});Pr.setRequestHandler(sd,async()=>({prompts:[{name:"session-start",description:"Inject the Superpowers context into an AI agent session. Tells the agent it has superpowers and how to use the skill system."}]}));Pr.setRequestHandler(cd,async e=>{if(e.params.name!=="session-start")throw new D(M.InvalidRequest,`Unknown prompt: ${e.params.name}`);let t=await It.findSkill("using-superpowers"),r="";if(t)try{r=await It.readSkillContent(t.skillPath)}catch{r=`# Superpowers
|
|
53
53
|
|
|
54
54
|
You have superpowers. Use the read_skill and list_skills tools to discover and load skills.`}else{let o=ct.join(O_,"using-superpowers","SKILL.md");try{r=await It.readSkillContent(o)}catch{r=`# Superpowers
|
|
55
55
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "superpowers-mcp",
|
|
3
3
|
"displayName": "Superpowers MCP",
|
|
4
4
|
"description": "Superpowers skills library (TDD, debugging, collaboration workflows) as an MCP server for VSCode and Antigravity",
|
|
5
|
-
"version": "6.3.
|
|
5
|
+
"version": "6.3.2",
|
|
6
6
|
"publisher": "superpowers",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -184,6 +184,7 @@ is the whole process.
|
|
|
184
184
|
- Scale each section to its complexity: a few sentences if straightforward, up to 200-300 words if nuanced
|
|
185
185
|
- Ask after each section whether it looks right so far
|
|
186
186
|
- Cover: architecture, components, data flow, error handling, testing
|
|
187
|
+
- For a new project (or one with no configured tooling), the design presentation includes a short tooling question alongside the architecture: which of these to set up from the start — cheapest before any code exists: aggressive linting + auto-formatting (the stack's standard, e.g. ruff+format / eslint+prettier / clippy+rustfmt); unit-test infrastructure (runner, layout, a first passing fixture); end-to-end test infrastructure; fuzz or mutation testing where the stack supports it. The user's selections land in the spec's Global Constraints so every later plan and task inherits them.
|
|
187
188
|
- Be ready to go back and clarify if something doesn't make sense
|
|
188
189
|
|
|
189
190
|
**Design for isolation and clarity:**
|
|
@@ -25,7 +25,7 @@ Dispatch a code reviewer subagent to catch issues before they cascade. The revie
|
|
|
25
25
|
|
|
26
26
|
**1. Get git SHAs:**
|
|
27
27
|
```bash
|
|
28
|
-
BASE_SHA=$(git rev-parse HEAD~1) # or origin/main
|
|
28
|
+
BASE_SHA=$(git rev-parse HEAD~1) # or: git merge-base origin/main HEAD
|
|
29
29
|
HEAD_SHA=$(git rev-parse HEAD)
|
|
30
30
|
```
|
|
31
31
|
|
|
@@ -173,6 +173,14 @@ its own text agrees with itself — the tests it specifies against the code it
|
|
|
173
173
|
specifies, the files it creates against the files it later touches. "The scan
|
|
174
174
|
is clean" without those rows is not a scan you ran.
|
|
175
175
|
|
|
176
|
+
**When the plan's header declares `Plan shape: skeleton-first`,** the
|
|
177
|
+
table gets a final section: the DISPATCH PLAN — group the pending tasks
|
|
178
|
+
into waves. Tasks in the same wave are mutually file-disjoint and consume
|
|
179
|
+
no interface still under construction — dispatch each wave's implementers
|
|
180
|
+
concurrently, one worktree per task, and integrate before the next wave;
|
|
181
|
+
tasks that fail those conditions serialize. On a skeleton-first plan, a
|
|
182
|
+
scan without a dispatch plan is not a scan you ran.
|
|
183
|
+
|
|
176
184
|
Write the table to the ledger. Rule on everything you find before execution
|
|
177
185
|
begins — each finding against the plan text that mandates it — and record
|
|
178
186
|
each ruling in the ledger. If the scan is clean, proceed without comment.
|
|
@@ -187,6 +195,10 @@ Use the least powerful model that can handle each role to conserve cost and incr
|
|
|
187
195
|
|
|
188
196
|
**Mechanical implementation tasks** (isolated functions, clear specs, 1-2 files): use a fast, cheap model. Most implementation tasks are mechanical when the plan is well-specified.
|
|
189
197
|
|
|
198
|
+
When a task carries a **Tier:** field, follow it — the planner already
|
|
199
|
+
ruled: mechanical → the cheapest available model; judgment → a standard
|
|
200
|
+
model. Do not re-litigate the tier at dispatch.
|
|
201
|
+
|
|
190
202
|
**Integration and judgment tasks** (multi-file coordination, pattern matching, debugging): use a standard model.
|
|
191
203
|
|
|
192
204
|
**Architecture and design tasks**: use the most capable available model.
|
|
@@ -208,7 +220,10 @@ most expensive — which silently defeats this section.
|
|
|
208
220
|
**Turn count beats token price.** Wall-clock and context cost scale with how
|
|
209
221
|
many turns a subagent takes, and the cheapest models routinely take 2-3× the
|
|
210
222
|
turns on multi-step work — costing more overall. Use a mid-tier model as the
|
|
211
|
-
floor for reviewers and for implementers working from
|
|
223
|
+
floor for reviewers and for implementers working from task contracts or
|
|
224
|
+
prose descriptions — unless the task's Tier line says mechanical: the
|
|
225
|
+
planner has already ruled the deliverable fully specified, so treat a
|
|
226
|
+
mechanical-tier contract like spelled-out content.
|
|
212
227
|
When the task's plan text contains the complete code to write, the
|
|
213
228
|
implementation is transcription plus testing: use the cheapest tier for
|
|
214
229
|
that implementer. Single-file mechanical fixes also take the cheapest tier.
|
|
@@ -260,7 +275,13 @@ and fix-round diffs need it.
|
|
|
260
275
|
know; (4) your resolution of any ambiguity you noticed in the brief;
|
|
261
276
|
(5) the report-file path and report contract. Exact values (numbers,
|
|
262
277
|
magic strings, signatures, test cases) appear only in the brief. Never
|
|
263
|
-
make a subagent read the whole plan file.
|
|
278
|
+
make a subagent read the whole plan file. When the brief is a contract
|
|
279
|
+
(goal, success criteria, interfaces) rather than written-out code, item
|
|
280
|
+
(3) also carries the elaboration the contract leaves to dispatch time:
|
|
281
|
+
the interfaces as actually built by completed tasks, environment facts
|
|
282
|
+
and discoveries from earlier reports, and any amendment rulings. There
|
|
283
|
+
the success criteria name the cases the tests must cover, and the
|
|
284
|
+
implementer designs its own code and tests within the contract.
|
|
264
285
|
- **Report file:** name the implementer's report file after the brief
|
|
265
286
|
(brief `…/task-N-brief.md` → report `…/task-N-report.md`) and put it in
|
|
266
287
|
the dispatch prompt. The implementer writes the full report there and
|
|
@@ -281,6 +302,26 @@ and fix-round diffs need it.
|
|
|
281
302
|
- Record the implementer's agent identity from the dispatch result —
|
|
282
303
|
fix-loop rounds 1-3 resume this agent.
|
|
283
304
|
- Never dispatch multiple implementation subagents in parallel (conflicts).
|
|
305
|
+
The one exception is a skeleton-first plan whose dispatch plan shows two
|
|
306
|
+
or more pending tasks mutually file-disjoint with none consuming an
|
|
307
|
+
interface still under construction. Dispatch those implementers
|
|
308
|
+
concurrently, each in its own worktree:
|
|
309
|
+
- Record the integration base commit in the ledger before the first
|
|
310
|
+
concurrent dispatch.
|
|
311
|
+
- Create one worktree per concurrent task off that base
|
|
312
|
+
(`git worktree add <repo-root>/.worktrees/task-<N> -b task-<N>
|
|
313
|
+
<base>`); each dispatch's `Work from:` is its own worktree, and its
|
|
314
|
+
BASE is that worktree's HEAD.
|
|
315
|
+
- Review each task's diff as usual when it reports. Integrate reviewed
|
|
316
|
+
branches in plan order: merge each into the integration branch
|
|
317
|
+
(`git merge --no-ff task-<N>`), and run that task's verification
|
|
318
|
+
commands after each merge.
|
|
319
|
+
- A merge conflict or post-merge verification failure is that task's
|
|
320
|
+
fix-loop round 1: rebase the task branch onto the current
|
|
321
|
+
integration head in its worktree, then resume its implementer
|
|
322
|
+
there. Never resolve conflicts yourself.
|
|
323
|
+
- Remove each worktree (`git worktree remove`) once its branch is
|
|
324
|
+
integrated, and record the integrated range in the ledger as usual.
|
|
284
325
|
|
|
285
326
|
Template: [implementer-prompt.md](implementer-prompt.md)
|
|
286
327
|
|
|
@@ -442,6 +483,19 @@ message as your other bookkeeping:
|
|
|
442
483
|
- `Task <N>: complete (commits <base7>..<head7>, <K> parked)` after a
|
|
443
484
|
tripped breaker
|
|
444
485
|
|
|
486
|
+
**On a skeleton-first plan,** write one plan-check line with the
|
|
487
|
+
completion line. Re-read the remaining tasks against what this task
|
|
488
|
+
actually established — interfaces as built, environment facts,
|
|
489
|
+
discoveries in the report — and append either `Plan holds` or
|
|
490
|
+
`Amendment: Task <M>: <what changes and why>` to the ledger. An
|
|
491
|
+
amendment is plan authority applied at the plan layer: from then on the
|
|
492
|
+
amended text IS the plan's text, and it rides into every affected task's
|
|
493
|
+
dispatch under item (3). In-flight tasks in the same concurrent wave are
|
|
494
|
+
not aborted mid-flight; any interface divergences are surfaced and
|
|
495
|
+
resolved through the standard integration merge, rebase, and fix-loop
|
|
496
|
+
protocol. Never dispatch a task whose brief a completed task's report has
|
|
497
|
+
already invalidated.
|
|
498
|
+
|
|
445
499
|
Then mark the todo complete and move on. Never move to the next task while
|
|
446
500
|
the review has open Critical/Important issues that are neither fixed nor
|
|
447
501
|
parked-with-ruling at the cap.
|
|
@@ -5,8 +5,11 @@ Use this template when dispatching an implementer subagent.
|
|
|
5
5
|
```
|
|
6
6
|
Subagent (general-purpose):
|
|
7
7
|
description: "Implement Task N: [task name]"
|
|
8
|
-
model: [MODEL — REQUIRED:
|
|
9
|
-
|
|
8
|
+
model: [MODEL — REQUIRED: when the brief carries a Tier line, set from it:
|
|
9
|
+
mechanical → the cheapest model the subagent tool offers; judgment →
|
|
10
|
+
a standard mid-tier model. Otherwise choose per SKILL.md Model
|
|
11
|
+
Selection. An omitted model silently inherits the session's most
|
|
12
|
+
expensive one]
|
|
10
13
|
prompt: |
|
|
11
14
|
You are implementing Task N: [task name]
|
|
12
15
|
|
|
@@ -22,10 +22,20 @@ head=$3
|
|
|
22
22
|
git rev-parse --verify --quiet "$base" >/dev/null || { echo "bad BASE: $base" >&2; exit 2; }
|
|
23
23
|
git rev-parse --verify --quiet "$head" >/dev/null || { echo "bad HEAD: $head" >&2; exit 2; }
|
|
24
24
|
|
|
25
|
+
git merge-base --is-ancestor "$base" "$head" || {
|
|
26
|
+
echo "HEAD ($head) is not a descendant of BASE ($base)" >&2
|
|
27
|
+
exit 3
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if [ "$(git rev-list --count "${base}..${head}")" -eq 0 ]; then
|
|
31
|
+
echo "empty commit range: ${base}..${head}" >&2
|
|
32
|
+
exit 3
|
|
33
|
+
fi
|
|
34
|
+
|
|
25
35
|
if [ $# -eq 4 ]; then
|
|
26
36
|
out=$4
|
|
27
37
|
else
|
|
28
|
-
dir=$("$(cd "$(dirname "$0")" && pwd)/sdd-workspace" "$plan")
|
|
38
|
+
dir=$("${BASH:-bash}" "$(cd "$(dirname "$0")" && pwd)/sdd-workspace" "$plan")
|
|
29
39
|
out="$dir/review-$(git rev-parse --short "$base")..$(git rev-parse --short "$head").diff"
|
|
30
40
|
fi
|
|
31
41
|
|
|
@@ -31,6 +31,18 @@ if ($LASTEXITCODE -ne 0) {
|
|
|
31
31
|
exit 2
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
& git merge-base --is-ancestor $base $head *> $null
|
|
35
|
+
if ($LASTEXITCODE -ne 0) {
|
|
36
|
+
[Console]::Error.WriteLine("HEAD ($head) is not a descendant of BASE ($base)")
|
|
37
|
+
exit 3
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
$commitCount = (& git rev-list --count "${base}..${head}").Trim()
|
|
41
|
+
if ([int]$commitCount -eq 0) {
|
|
42
|
+
[Console]::Error.WriteLine("empty commit range: ${base}..${head}")
|
|
43
|
+
exit 3
|
|
44
|
+
}
|
|
45
|
+
|
|
34
46
|
if ($args.Count -eq 4) {
|
|
35
47
|
$out = $args[3]
|
|
36
48
|
} else {
|
|
@@ -53,7 +65,7 @@ $content.Add("")
|
|
|
53
65
|
$content.Add("## Diff")
|
|
54
66
|
(& git diff -U10 "${base}..${head}") | ForEach-Object { $content.Add($_) }
|
|
55
67
|
|
|
56
|
-
Set-Content -
|
|
68
|
+
Set-Content -LiteralPath $out -Value $content -Encoding utf8
|
|
57
69
|
$commits = (& git rev-list --count "${base}..${head}").Trim()
|
|
58
70
|
$bytes = (Get-Item -LiteralPath $out).Length
|
|
59
71
|
Write-Output "wrote ${out}: $commits commit(s), $bytes bytes"
|
|
@@ -3,11 +3,17 @@
|
|
|
3
3
|
# short-lived artifacts: task briefs, implementer reports, review packages,
|
|
4
4
|
# and the progress ledger. Print the plan directory's absolute path.
|
|
5
5
|
#
|
|
6
|
-
# One directory per plan (.superpowers/sdd/<plan-
|
|
6
|
+
# One directory per plan (.superpowers/sdd/<plan-slug>/) so a follow-up
|
|
7
7
|
# plan in the same working tree can never read or overwrite another plan's
|
|
8
8
|
# artifacts. A stale ledger misread as current progress makes controllers
|
|
9
9
|
# skip whole task sequences — plan-scoping removes that failure structurally.
|
|
10
10
|
#
|
|
11
|
+
# Ownership markers (plan-path file in the workspace directory) disambiguate
|
|
12
|
+
# same-basename plans (e.g. docs/alpha/plan.md vs docs/beta/plan.md) by appending
|
|
13
|
+
# the parent-directory name, then a counter. A workspace with no marker
|
|
14
|
+
# predates the marker scheme and is adopted for the current plan so in-flight
|
|
15
|
+
# workspaces keep resolving.
|
|
16
|
+
#
|
|
11
17
|
# The workspace lives in the working tree (not under .git/) because Claude Code
|
|
12
18
|
# treats .git/ as a protected path and denies agent writes there — which blocks
|
|
13
19
|
# an implementer subagent from writing its report file. A self-ignoring
|
|
@@ -28,13 +34,46 @@ fi
|
|
|
28
34
|
plan=$1
|
|
29
35
|
[ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; }
|
|
30
36
|
|
|
31
|
-
slug=$(basename "$plan" .md)
|
|
37
|
+
slug=$(basename -- "$plan" .md)
|
|
32
38
|
[ -n "$slug" ] && [ "$slug" != "." ] && [ "$slug" != ".." ] \
|
|
33
39
|
|| { echo "cannot derive a workspace name from: $plan" >&2; exit 2; }
|
|
34
40
|
|
|
35
41
|
root=$(git rev-parse --show-toplevel)
|
|
42
|
+
root=$(CDPATH= cd -- "$root" && pwd -P)
|
|
36
43
|
base="$root/.superpowers/sdd"
|
|
44
|
+
|
|
45
|
+
# Normalize the plan path (physical directory, so relative/absolute/../
|
|
46
|
+
# spellings of one plan compare equal) and express it as the marker value:
|
|
47
|
+
# repo-relative when the plan lives under the repo root, absolute otherwise.
|
|
48
|
+
plan_dir=$(CDPATH= cd -- "$(dirname -- "$plan")" && pwd -P)
|
|
49
|
+
plan_abs="$plan_dir/$(basename -- "$plan")"
|
|
50
|
+
case "$plan_abs" in
|
|
51
|
+
"$root"/*) plan_id=${plan_abs#"$root"/} ;;
|
|
52
|
+
*) plan_id=$plan_abs ;;
|
|
53
|
+
esac
|
|
54
|
+
|
|
55
|
+
# True when the workspace at $1 is (or becomes) this plan's: an existing
|
|
56
|
+
# marker must name this plan; a missing marker means a new workspace or a
|
|
57
|
+
# pre-marker legacy one, and either way the plan claims it by writing one.
|
|
58
|
+
owns() {
|
|
59
|
+
if [ -e "$1/plan-path" ]; then
|
|
60
|
+
[ "$(cat "$1/plan-path")" = "$plan_id" ]
|
|
61
|
+
else
|
|
62
|
+
mkdir -p "$1"
|
|
63
|
+
printf '%s\n' "$plan_id" > "$1/plan-path"
|
|
64
|
+
fi
|
|
65
|
+
}
|
|
66
|
+
|
|
37
67
|
dir="$base/$slug"
|
|
38
|
-
|
|
68
|
+
if ! owns "$dir"; then
|
|
69
|
+
parent=$(basename -- "$plan_dir")
|
|
70
|
+
dir="$base/$slug-$parent"
|
|
71
|
+
if ! owns "$dir"; then
|
|
72
|
+
n=2
|
|
73
|
+
while ! owns "$base/$slug-$parent-$n"; do n=$((n + 1)); done
|
|
74
|
+
dir="$base/$slug-$parent-$n"
|
|
75
|
+
fi
|
|
76
|
+
fi
|
|
77
|
+
|
|
39
78
|
printf '*\n' > "$base/.gitignore"
|
|
40
|
-
cd "$dir" && pwd
|
|
79
|
+
CDPATH= cd -- "$dir" && pwd
|
|
@@ -30,7 +30,69 @@ if ([string]::IsNullOrEmpty($slug) -or $slug -eq "." -or $slug -eq "..") {
|
|
|
30
30
|
|
|
31
31
|
$root = (& git rev-parse --show-toplevel).Trim()
|
|
32
32
|
$base = Join-Path $root ".superpowers/sdd"
|
|
33
|
+
|
|
34
|
+
function Get-PhysicalDirectoryPath($path) {
|
|
35
|
+
if (-not (Test-Path -LiteralPath $path)) { return $path }
|
|
36
|
+
if ($IsWindows) {
|
|
37
|
+
return (Resolve-Path -LiteralPath $path).Path
|
|
38
|
+
}
|
|
39
|
+
$orig = Get-Location
|
|
40
|
+
try {
|
|
41
|
+
Set-Location -LiteralPath $path
|
|
42
|
+
$pwdCmd = (Get-Command -Type Application pwd -ErrorAction SilentlyContinue).Source
|
|
43
|
+
if ($pwdCmd) {
|
|
44
|
+
return (& $pwdCmd -P).Trim()
|
|
45
|
+
} else {
|
|
46
|
+
return (Resolve-Path -LiteralPath $path).Path
|
|
47
|
+
}
|
|
48
|
+
} finally {
|
|
49
|
+
Set-Location $orig
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Normalize the plan path (physical directory, so relative/absolute/../
|
|
54
|
+
# spellings of one plan compare equal) and express it as the marker value:
|
|
55
|
+
# repo-relative when the plan lives under the repo root, absolute otherwise.
|
|
56
|
+
$planLeaf = Split-Path -Leaf $plan
|
|
57
|
+
$planParent = Split-Path -Parent $plan
|
|
58
|
+
if ([string]::IsNullOrEmpty($planParent)) { $planParent = "." }
|
|
59
|
+
|
|
60
|
+
$planDir = Get-PhysicalDirectoryPath $planParent
|
|
61
|
+
$rootPhys = Get-PhysicalDirectoryPath $root
|
|
62
|
+
|
|
63
|
+
$planAbs = (Join-Path $planDir $planLeaf) -replace '\\', '/'
|
|
64
|
+
$rootNorm = $rootPhys -replace '\\', '/'
|
|
65
|
+
|
|
66
|
+
if ($planAbs.StartsWith($rootNorm + "/", [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
67
|
+
$planId = $planAbs.Substring($rootNorm.Length + 1)
|
|
68
|
+
} else {
|
|
69
|
+
$planId = $planAbs
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function Test-And-Claim-Workspace($targetDir, $id) {
|
|
73
|
+
$markerPath = Join-Path $targetDir "plan-path"
|
|
74
|
+
if (Test-Path -LiteralPath $markerPath -PathType Leaf) {
|
|
75
|
+
$existingId = (Get-Content -LiteralPath $markerPath -Raw).Trim()
|
|
76
|
+
return ($existingId -eq $id)
|
|
77
|
+
} else {
|
|
78
|
+
New-Item -ItemType Directory -Force -Path $targetDir | Out-Null
|
|
79
|
+
Set-Content -LiteralPath $markerPath -Value $id -Encoding ascii
|
|
80
|
+
return $true
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
33
84
|
$dir = Join-Path $base $slug
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
85
|
+
if (-not (Test-And-Claim-Workspace $dir $planId)) {
|
|
86
|
+
$parent = Split-Path -Leaf $planDir
|
|
87
|
+
$dir = Join-Path $base "$slug-$parent"
|
|
88
|
+
if (-not (Test-And-Claim-Workspace $dir $planId)) {
|
|
89
|
+
$n = 2
|
|
90
|
+
while (-not (Test-And-Claim-Workspace (Join-Path $base "$slug-$parent-$n") $planId)) {
|
|
91
|
+
$n++
|
|
92
|
+
}
|
|
93
|
+
$dir = Join-Path $base "$slug-$parent-$n"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
Set-Content -LiteralPath (Join-Path $base ".gitignore") -Value "*" -NoNewline -Encoding ascii
|
|
98
|
+
(Resolve-Path -LiteralPath $dir).Path
|
|
@@ -42,7 +42,7 @@ foreach ($line in [System.IO.File]::ReadLines((Resolve-Path -LiteralPath $plan).
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
Set-Content -
|
|
45
|
+
Set-Content -LiteralPath $out -Value $selected -Encoding utf8
|
|
46
46
|
if ((-not (Test-Path -LiteralPath $out)) -or ((Get-Item -LiteralPath $out).Length -eq 0)) {
|
|
47
47
|
[Console]::Error.WriteLine("task $taskNumber not found in $plan (no heading matching 'Task $taskNumber')")
|
|
48
48
|
exit 3
|
|
@@ -182,6 +182,16 @@ Confirm:
|
|
|
182
182
|
|
|
183
183
|
**Other tests fail?** Fix now.
|
|
184
184
|
|
|
185
|
+
**"Other tests" means the project's suite, not just your file.** A
|
|
186
|
+
green run of the test you wrote is not a green suite. Before you call
|
|
187
|
+
the change done, run the project's test command (bare `pytest`,
|
|
188
|
+
`npm test`, `cargo test` — whatever the repo uses) even when your task
|
|
189
|
+
named only one test file. A scope statement in your task bounds the
|
|
190
|
+
deliverable, not your verification. Any failure that run shows —
|
|
191
|
+
including one you didn't cause — goes in your report by name; a red
|
|
192
|
+
test you watched scroll past and didn't mention is a report falsified
|
|
193
|
+
by omission.
|
|
194
|
+
|
|
185
195
|
### REFACTOR - Clean Up
|
|
186
196
|
|
|
187
197
|
After green only:
|
|
@@ -22,6 +22,30 @@ Assume they are a skilled developer, but know almost nothing about our toolset o
|
|
|
22
22
|
|
|
23
23
|
If the spec covers multiple independent subsystems, it should have been broken into sub-project specs during brainstorming. If it wasn't, suggest breaking this into separate plans — one per subsystem. Each plan should produce working, testable software on its own.
|
|
24
24
|
|
|
25
|
+
## Two Plan Shapes
|
|
26
|
+
|
|
27
|
+
Before mapping files, classify the plan's shape and say the
|
|
28
|
+
classification out loud — "this composes three subsystems, so I'll plan
|
|
29
|
+
it skeleton-first" — so your human partner can override it:
|
|
30
|
+
|
|
31
|
+
- **Task-by-task (default)** — tasks build the feature a component at a
|
|
32
|
+
time, each step carrying the actual content the engineer needs. Use it
|
|
33
|
+
for changes to code that already exists, for a spec that touches one
|
|
34
|
+
subsystem, and whenever the alternative's conditions do not clearly
|
|
35
|
+
hold. The rest of this skill describes this shape.
|
|
36
|
+
- **Skeleton-first (alternative)** — Task 1 is the thinnest end-to-end
|
|
37
|
+
slice through every subsystem the spec composes; later tasks widen it
|
|
38
|
+
one component at a time, each from a contract rather than written-out
|
|
39
|
+
code. Use it when the spec composes more than one subsystem AND a
|
|
40
|
+
running end-to-end slice early is worth a longer total build. Read
|
|
41
|
+
[skeleton-first-plans.md](skeleton-first-plans.md) before writing one
|
|
42
|
+
— it adds one line to the plan header and replaces this skill's task
|
|
43
|
+
granularity, task template, and plan-failure list.
|
|
44
|
+
|
|
45
|
+
When in doubt, plan task-by-task. Skeleton-first buys an earlier running
|
|
46
|
+
system and pays for it in total wall clock; it is a trade, not an
|
|
47
|
+
upgrade.
|
|
48
|
+
|
|
25
49
|
## File Structure
|
|
26
50
|
|
|
27
51
|
Before defining tasks, map out which files will be created or modified and what each one is responsible for. This is where decomposition decisions get locked in.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Skeleton-First Plans
|
|
2
|
+
|
|
3
|
+
The alternative plan shape from writing-plans' Two Plan Shapes router.
|
|
4
|
+
Each section below replaces the same-named section of
|
|
5
|
+
[SKILL.md](SKILL.md); everything SKILL.md says that is not named here
|
|
6
|
+
still binds — Scope Check, File Structure, Task Right-Sizing, the plan
|
|
7
|
+
header, Self-Review, and the Execution Handoff.
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Write a plan that carries the decisions, not the keystrokes:
|
|
12
|
+
decomposition, file structure, interfaces, constraints, and a precise
|
|
13
|
+
contract per task. Assume the engineer is skilled and designs their own
|
|
14
|
+
code and tests from a precise contract, but knows nothing about our
|
|
15
|
+
codebase, toolset, or problem domain — every name, path, constraint, and
|
|
16
|
+
behavior they must match is stated explicitly. DRY. YAGNI. TDD.
|
|
17
|
+
Frequent commits.
|
|
18
|
+
|
|
19
|
+
## When This Shape Fits
|
|
20
|
+
|
|
21
|
+
Use it when the spec composes more than one subsystem and a running
|
|
22
|
+
end-to-end slice early is worth a longer total build: the value arrives
|
|
23
|
+
as soon as real input reaches real output, and every later task widens
|
|
24
|
+
something that already runs.
|
|
25
|
+
|
|
26
|
+
Do not use it for a change to one subsystem, or when the whole point is
|
|
27
|
+
to land the finished thing as fast as possible. This shape spends its
|
|
28
|
+
first task on a slice that does almost nothing, and it spends planning
|
|
29
|
+
effort on contracts and interfaces the task-by-task shape gets for free
|
|
30
|
+
by writing the code out.
|
|
31
|
+
|
|
32
|
+
## Plan Document Header
|
|
33
|
+
|
|
34
|
+
The header is SKILL.md's, plus one line directly under the **Goal:**
|
|
35
|
+
line, which is how executors know which shape they are running:
|
|
36
|
+
|
|
37
|
+
```markdown
|
|
38
|
+
**Plan shape:** skeleton-first
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Walking Skeleton First
|
|
42
|
+
|
|
43
|
+
Task 1 builds the thinnest end-to-end slice through every subsystem the
|
|
44
|
+
spec composes — real input to real output — before any task deepens a
|
|
45
|
+
single layer; later tasks widen the skeleton.
|
|
46
|
+
|
|
47
|
+
The test of a skeleton is that it runs. A first task that builds the
|
|
48
|
+
data loader, the schema, or the config layer is a foundation, not a
|
|
49
|
+
skeleton: nothing runs until something above it exists. A skeleton
|
|
50
|
+
reaches the output — thinly, with one real case — through every
|
|
51
|
+
subsystem the spec names.
|
|
52
|
+
|
|
53
|
+
## Task Contracts, Not Task Scripts
|
|
54
|
+
|
|
55
|
+
A task states WHAT must exist when it is done, precisely enough that a
|
|
56
|
+
skilled engineer can build it without asking you anything, without
|
|
57
|
+
prescribing HOW:
|
|
58
|
+
|
|
59
|
+
- **Goal:** one short paragraph naming the deliverable and its role in
|
|
60
|
+
the feature.
|
|
61
|
+
- **Success criteria:** concrete, checkable behaviors — exact commands
|
|
62
|
+
to run and what they must show, the cases tests must cover (including
|
|
63
|
+
failure cases), constraints that bind the implementation.
|
|
64
|
+
- **Notes:** what the engineer needs and cannot discover alone — spec
|
|
65
|
+
sections to read, files worth reading first, known pitfalls.
|
|
66
|
+
|
|
67
|
+
The Interfaces block carries the exact names, signatures, and types;
|
|
68
|
+
the success criteria carry the behaviors; the engineer supplies the
|
|
69
|
+
code and the test design. TDD and frequent commits remain required.
|
|
70
|
+
|
|
71
|
+
## Task Structure
|
|
72
|
+
|
|
73
|
+
````markdown
|
|
74
|
+
### Task N: [Component Name]
|
|
75
|
+
|
|
76
|
+
**Files:**
|
|
77
|
+
- Create: `exact/path/to/file.py`
|
|
78
|
+
- Modify: `exact/path/to/existing.py:123-145`
|
|
79
|
+
- Test: `tests/exact/path/to/test.py`
|
|
80
|
+
|
|
81
|
+
**Interfaces:**
|
|
82
|
+
- Consumes: [what this task uses from earlier tasks — exact signatures]
|
|
83
|
+
- Produces: [what later tasks rely on — exact function names, parameter
|
|
84
|
+
and return types. A task's implementer sees only their own task; this
|
|
85
|
+
block is how they learn the names and types neighboring tasks use.]
|
|
86
|
+
|
|
87
|
+
**Goal:** [one paragraph — the deliverable and its role in the feature]
|
|
88
|
+
|
|
89
|
+
**Success criteria:**
|
|
90
|
+
- Run: `pytest tests/exact/path/to/test.py -v` — all tests pass; tests
|
|
91
|
+
cover [the specific behaviors and failure cases, named concretely]
|
|
92
|
+
- [observable behavior the deliverable must exhibit, with the exact
|
|
93
|
+
command or input/output that demonstrates it]
|
|
94
|
+
- [constraint that binds the implementation, copied from the spec]
|
|
95
|
+
|
|
96
|
+
**Notes:** [spec sections to read; files to read first; known pitfalls]
|
|
97
|
+
|
|
98
|
+
**Tier:** mechanical | judgment. Mechanical = the deliverable is fully
|
|
99
|
+
specified by Files + Interfaces + success criteria above (most tasks in
|
|
100
|
+
a well-specified plan are mechanical); judgment = multi-file
|
|
101
|
+
coordination, debugging, or real design latitude remains. The
|
|
102
|
+
implementer's model follows this field — mark it deliberately.
|
|
103
|
+
|
|
104
|
+
**Commit:** one commit ending the task; message named here.
|
|
105
|
+
````
|
|
106
|
+
|
|
107
|
+
## No Vague Contracts
|
|
108
|
+
|
|
109
|
+
Every contract must be checkable by someone who did not write it. These
|
|
110
|
+
are **plan failures** — never write them:
|
|
111
|
+
- "TBD", "TODO", "implement later", "fill in details"
|
|
112
|
+
- Goals naming activity instead of a deliverable ("improve error handling")
|
|
113
|
+
- Success criteria with no observable check ("works correctly", "handles edge cases")
|
|
114
|
+
- Interfaces blocks omitting a name, signature, or type another task consumes
|
|
115
|
+
- "Similar to Task N" (state this task's own contract in full — the engineer may be reading tasks out of order)
|
|
116
|
+
- References to types, functions, or methods not defined in any task's Interfaces block
|
|
117
|
+
|
|
118
|
+
## Self-Review
|
|
119
|
+
|
|
120
|
+
Run SKILL.md's Self-Review checklist, reading step 2 against "No Vague
|
|
121
|
+
Contracts" above rather than "No Placeholders".
|
|
122
|
+
|
|
123
|
+
## Red Flags
|
|
124
|
+
|
|
125
|
+
| Thought | Reality |
|
|
126
|
+
|---------|---------|
|
|
127
|
+
| "Task 1 is the data loader — that's the foundation" | A foundation is a layer. The skeleton runs real input to real output through every subsystem the spec names, thinly. |
|
|
128
|
+
| "The skeleton can return a hardcoded value for now" | It may be thin, but the path must be real: real input, real wiring, real output. A hardcoded response tests nothing end to end. |
|
|
129
|
+
| "A contract without the code is vague" | Vague is an uncheckable success criterion. Exact names, exact commands, exact expected output — no code. |
|
|
130
|
+
| "I'll write the test code into the task to be safe" | The success criteria name the cases; the implementer designs the tests. Written-out tests are the task-by-task shape. |
|
|
131
|
+
| "Skeleton-first is the better shape, so I'll use it here" | It costs total wall clock. Without more than one subsystem and a reason to want an early running slice, plan task-by-task. |
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
|
|
16
16
|
const fs = require('fs');
|
|
17
17
|
const path = require('path');
|
|
18
|
-
const {
|
|
18
|
+
const { execFileSync } = require('child_process');
|
|
19
19
|
|
|
20
20
|
function extractDotBlocks(markdown) {
|
|
21
21
|
const blocks = [];
|
|
22
|
-
const regex = /```dot\n([\s\S]*?)```/g;
|
|
22
|
+
const regex = /```dot\r?\n([\s\S]*?)```/g;
|
|
23
23
|
let match;
|
|
24
24
|
|
|
25
25
|
while ((match = regex.exec(markdown)) !== null) {
|
|
@@ -69,7 +69,7 @@ ${bodies.join('\n\n')}
|
|
|
69
69
|
|
|
70
70
|
function renderToSvg(dotContent) {
|
|
71
71
|
try {
|
|
72
|
-
return
|
|
72
|
+
return execFileSync('dot', ['-Tsvg'], {
|
|
73
73
|
input: dotContent,
|
|
74
74
|
encoding: 'utf-8',
|
|
75
75
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -110,11 +110,12 @@ function main() {
|
|
|
110
110
|
// Check if dot is available. Run the binary directly rather than probing
|
|
111
111
|
// with `which`, which is not a command on Windows.
|
|
112
112
|
try {
|
|
113
|
-
|
|
113
|
+
execFileSync('dot', ['-V'], { stdio: 'ignore' });
|
|
114
114
|
} catch {
|
|
115
115
|
console.error('Error: graphviz (dot) not found. Install with:');
|
|
116
|
-
console.error(' brew install graphviz
|
|
117
|
-
console.error(' apt install graphviz
|
|
116
|
+
console.error(' brew install graphviz # macOS');
|
|
117
|
+
console.error(' apt install graphviz # Linux');
|
|
118
|
+
console.error(' winget install Graphviz.Graphviz # Windows');
|
|
118
119
|
process.exit(1);
|
|
119
120
|
}
|
|
120
121
|
|