Compare commits
22 Commits
prettier-e
...
v5.1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4cf4732a0 | ||
|
|
cf22fd98f3 | ||
|
|
fe318ecc07 | ||
|
|
f959a07bda | ||
|
|
c0899432c1 | ||
|
|
8573852a6e | ||
|
|
39437e9268 | ||
|
|
1772a30368 | ||
|
|
ba4fb4d084 | ||
|
|
3eb706c49a | ||
|
|
3f5abf347d | ||
|
|
ed539432fb | ||
|
|
51284d6ecf | ||
|
|
6cba05114e | ||
|
|
ac360cd0bf | ||
|
|
fab9d5e1f5 | ||
|
|
93426c2d2f | ||
|
|
f56d37a60a | ||
|
|
224cfc05dc | ||
|
|
6cb2fa68b3 | ||
|
|
d21ac491a0 | ||
|
|
848e33fdd9 |
173
.github/workflows/manual-release.yaml
vendored
Normal file
173
.github/workflows/manual-release.yaml
vendored
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
name: Manual Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version_bump:
|
||||||
|
description: Version bump type
|
||||||
|
required: true
|
||||||
|
default: patch
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- patch
|
||||||
|
- minor
|
||||||
|
- major
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: "20"
|
||||||
|
cache: npm
|
||||||
|
registry-url: https://registry.npmjs.org
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Run tests and validation
|
||||||
|
run: |
|
||||||
|
npm run validate
|
||||||
|
npm run format:check
|
||||||
|
npm run lint
|
||||||
|
|
||||||
|
- name: Configure Git
|
||||||
|
run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
|
- name: Bump version
|
||||||
|
run: npm run version:${{ github.event.inputs.version_bump }}
|
||||||
|
|
||||||
|
- name: Get new version and previous tag
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
echo "new_version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
|
||||||
|
echo "previous_tag=$(git describe --tags --abbrev=0)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Update installer package.json
|
||||||
|
run: |
|
||||||
|
sed -i 's/"version": ".*"/"version": "${{ steps.version.outputs.new_version }}"/' tools/installer/package.json
|
||||||
|
|
||||||
|
- name: Build project
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Commit version bump
|
||||||
|
run: |
|
||||||
|
git add .
|
||||||
|
git commit -m "release: bump to v${{ steps.version.outputs.new_version }}"
|
||||||
|
|
||||||
|
- name: Generate release notes
|
||||||
|
id: release_notes
|
||||||
|
run: |
|
||||||
|
# Get commits since last tag
|
||||||
|
COMMITS=$(git log ${{ steps.version.outputs.previous_tag }}..HEAD --pretty=format:"- %s" --reverse)
|
||||||
|
|
||||||
|
# Categorize commits
|
||||||
|
FEATURES=$(echo "$COMMITS" | grep -E "^- (feat|Feature)" || true)
|
||||||
|
FIXES=$(echo "$COMMITS" | grep -E "^- (fix|Fix)" || true)
|
||||||
|
CHORES=$(echo "$COMMITS" | grep -E "^- (chore|Chore)" || true)
|
||||||
|
OTHERS=$(echo "$COMMITS" | grep -v -E "^- (feat|Feature|fix|Fix|chore|Chore|release:|Release:)" || true)
|
||||||
|
|
||||||
|
# Build release notes
|
||||||
|
cat > release_notes.md << 'EOF'
|
||||||
|
## 🚀 What's New in v${{ steps.version.outputs.new_version }}
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if [ ! -z "$FEATURES" ]; then
|
||||||
|
echo "### ✨ New Features" >> release_notes.md
|
||||||
|
echo "$FEATURES" >> release_notes.md
|
||||||
|
echo "" >> release_notes.md
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "$FIXES" ]; then
|
||||||
|
echo "### 🐛 Bug Fixes" >> release_notes.md
|
||||||
|
echo "$FIXES" >> release_notes.md
|
||||||
|
echo "" >> release_notes.md
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "$OTHERS" ]; then
|
||||||
|
echo "### 📦 Other Changes" >> release_notes.md
|
||||||
|
echo "$OTHERS" >> release_notes.md
|
||||||
|
echo "" >> release_notes.md
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "$CHORES" ]; then
|
||||||
|
echo "### 🔧 Maintenance" >> release_notes.md
|
||||||
|
echo "$CHORES" >> release_notes.md
|
||||||
|
echo "" >> release_notes.md
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat >> release_notes.md << 'EOF'
|
||||||
|
|
||||||
|
## 📦 Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx bmad-method install
|
||||||
|
```
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/bmadcode/BMAD-METHOD/compare/${{ steps.version.outputs.previous_tag }}...v${{ steps.version.outputs.new_version }}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Output for GitHub Actions
|
||||||
|
echo "RELEASE_NOTES<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
cat release_notes.md >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Create and push tag
|
||||||
|
run: |
|
||||||
|
# Check if tag already exists
|
||||||
|
if git rev-parse "v${{ steps.version.outputs.new_version }}" >/dev/null 2>&1; then
|
||||||
|
echo "Tag v${{ steps.version.outputs.new_version }} already exists, skipping tag creation"
|
||||||
|
else
|
||||||
|
git tag -a "v${{ steps.version.outputs.new_version }}" -m "Release v${{ steps.version.outputs.new_version }}"
|
||||||
|
git push origin "v${{ steps.version.outputs.new_version }}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Push changes to main
|
||||||
|
run: |
|
||||||
|
if git push origin HEAD:main 2>/dev/null; then
|
||||||
|
echo "✅ Successfully pushed to main branch"
|
||||||
|
else
|
||||||
|
echo "⚠️ Could not push to main (protected branch). This is expected."
|
||||||
|
echo "📝 Version bump and tag were created successfully."
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Publish to NPM
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
run: npm publish
|
||||||
|
|
||||||
|
- name: Create GitHub Release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: v${{ steps.version.outputs.new_version }}
|
||||||
|
release_name: "BMad Method v${{ steps.version.outputs.new_version }}"
|
||||||
|
body: ${{ steps.release_notes.outputs.RELEASE_NOTES }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
run: |
|
||||||
|
echo "🎉 Successfully released v${{ steps.version.outputs.new_version }}!"
|
||||||
|
echo "📦 Published to NPM with @latest tag"
|
||||||
|
echo "🏷️ Git tag: v${{ steps.version.outputs.new_version }}"
|
||||||
|
echo "✅ Users running 'npx bmad-method install' will now get version ${{ steps.version.outputs.new_version }}"
|
||||||
|
echo ""
|
||||||
|
echo "📝 Release notes preview:"
|
||||||
|
cat release_notes.md
|
||||||
122
.github/workflows/promote-to-stable.yaml
vendored
122
.github/workflows/promote-to-stable.yaml
vendored
@@ -1,122 +0,0 @@
|
|||||||
name: Promote to Stable
|
|
||||||
|
|
||||||
"on":
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
version_bump:
|
|
||||||
description: "Version bump type"
|
|
||||||
required: true
|
|
||||||
default: "minor"
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- patch
|
|
||||||
- minor
|
|
||||||
- major
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
promote:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "20"
|
|
||||||
registry-url: "https://registry.npmjs.org"
|
|
||||||
|
|
||||||
- name: Configure Git
|
|
||||||
run: |
|
|
||||||
git config --global user.name "github-actions[bot]"
|
|
||||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
git config --global url."https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/".insteadOf "https://github.com/"
|
|
||||||
|
|
||||||
- name: Switch to stable branch
|
|
||||||
run: |
|
|
||||||
git checkout stable
|
|
||||||
git pull origin stable
|
|
||||||
|
|
||||||
- name: Merge main into stable
|
|
||||||
run: |
|
|
||||||
git merge origin/main --no-edit
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Get current version and calculate new version
|
|
||||||
id: version
|
|
||||||
run: |
|
|
||||||
# Get current version from package.json
|
|
||||||
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
||||||
echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# Remove beta suffix if present
|
|
||||||
BASE_VERSION=$(echo $CURRENT_VERSION | sed 's/-beta\.[0-9]\+//')
|
|
||||||
echo "base_version=$BASE_VERSION" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# Calculate new version based on bump type
|
|
||||||
IFS='.' read -ra VERSION_PARTS <<< "$BASE_VERSION"
|
|
||||||
MAJOR=${VERSION_PARTS[0]}
|
|
||||||
MINOR=${VERSION_PARTS[1]}
|
|
||||||
PATCH=${VERSION_PARTS[2]}
|
|
||||||
|
|
||||||
case "${{ github.event.inputs.version_bump }}" in
|
|
||||||
"major")
|
|
||||||
NEW_VERSION="$((MAJOR + 1)).0.0"
|
|
||||||
;;
|
|
||||||
"minor")
|
|
||||||
NEW_VERSION="$MAJOR.$((MINOR + 1)).0"
|
|
||||||
;;
|
|
||||||
"patch")
|
|
||||||
NEW_VERSION="$MAJOR.$MINOR.$((PATCH + 1))"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
NEW_VERSION="$BASE_VERSION"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
|
||||||
echo "Promoting from $CURRENT_VERSION to $NEW_VERSION"
|
|
||||||
|
|
||||||
- name: Update package.json versions
|
|
||||||
run: |
|
|
||||||
# Update main package.json
|
|
||||||
npm version ${{ steps.version.outputs.new_version }} --no-git-tag-version
|
|
||||||
|
|
||||||
# Update installer package.json
|
|
||||||
sed -i 's/"version": ".*"/"version": "${{ steps.version.outputs.new_version }}"/' tools/installer/package.json
|
|
||||||
|
|
||||||
- name: Update package-lock.json
|
|
||||||
run: npm install --package-lock-only
|
|
||||||
|
|
||||||
- name: Commit stable release
|
|
||||||
run: |
|
|
||||||
git add .
|
|
||||||
git commit -m "release: promote to stable ${{ steps.version.outputs.new_version }}
|
|
||||||
|
|
||||||
- Promote beta features to stable release
|
|
||||||
- Update version from ${{ steps.version.outputs.current_version }} to ${{ steps.version.outputs.new_version }}
|
|
||||||
- Automated promotion via GitHub Actions"
|
|
||||||
|
|
||||||
- name: Push stable release
|
|
||||||
run: |
|
|
||||||
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
|
|
||||||
git push origin stable
|
|
||||||
|
|
||||||
- name: Switch back to main
|
|
||||||
run: git checkout main
|
|
||||||
|
|
||||||
- name: Summary
|
|
||||||
run: |
|
|
||||||
echo "🎉 Successfully promoted to stable!"
|
|
||||||
echo "📦 Version: ${{ steps.version.outputs.new_version }}"
|
|
||||||
echo "🚀 The stable release will be automatically published to NPM via semantic-release"
|
|
||||||
echo "✅ Users running 'npx bmad-method install' will now get version ${{ steps.version.outputs.new_version }}"
|
|
||||||
74
.github/workflows/release.yaml
vendored
74
.github/workflows/release.yaml
vendored
@@ -1,74 +0,0 @@
|
|||||||
name: Release
|
|
||||||
"on":
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- stable
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
version_type:
|
|
||||||
description: Version bump type
|
|
||||||
required: true
|
|
||||||
default: patch
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- patch
|
|
||||||
- minor
|
|
||||||
- major
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
packages: write
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.event_name != 'push' || !contains(github.event.head_commit.message, '[skip ci]') }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "20"
|
|
||||||
cache: "npm"
|
|
||||||
registry-url: "https://registry.npmjs.org"
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
- name: Run tests and validation
|
|
||||||
run: |
|
|
||||||
npm run validate
|
|
||||||
npm run format
|
|
||||||
- name: Debug permissions
|
|
||||||
run: |
|
|
||||||
echo "Testing git permissions..."
|
|
||||||
git config user.name "github-actions[bot]"
|
|
||||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
echo "Git config set successfully"
|
|
||||||
- name: Manual version bump
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
run: npm run version:${{ github.event.inputs.version_type }}
|
|
||||||
- name: Semantic Release
|
|
||||||
if: github.event_name == 'push'
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
||||||
run: npm run release
|
|
||||||
- name: Clean changelog formatting
|
|
||||||
if: github.event_name == 'push'
|
|
||||||
run: |
|
|
||||||
git config user.name "github-actions[bot]"
|
|
||||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
# Remove any Claude Code attribution from changelog
|
|
||||||
sed -i '/🤖 Generated with \[Claude Code\]/,+2d' CHANGELOG.md || true
|
|
||||||
# Format and commit if changes exist
|
|
||||||
npm run format
|
|
||||||
if ! git diff --quiet CHANGELOG.md; then
|
|
||||||
git add CHANGELOG.md
|
|
||||||
git commit -m "chore: clean changelog formatting [skip ci]"
|
|
||||||
git push
|
|
||||||
fi
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -43,4 +43,4 @@ CLAUDE.md
|
|||||||
test-project-install/*
|
test-project-install/*
|
||||||
sample-project/*
|
sample-project/*
|
||||||
flattened-codebase.xml
|
flattened-codebase.xml
|
||||||
|
*.stats.md
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"branches": [
|
|
||||||
{
|
|
||||||
"name": "main",
|
|
||||||
"prerelease": "beta",
|
|
||||||
"channel": "beta"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "stable",
|
|
||||||
"channel": "latest"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
"@semantic-release/commit-analyzer",
|
|
||||||
"@semantic-release/release-notes-generator",
|
|
||||||
[
|
|
||||||
"@semantic-release/changelog",
|
|
||||||
{
|
|
||||||
"changelogFile": "CHANGELOG.md",
|
|
||||||
"changelogTitle": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@semantic-release/npm",
|
|
||||||
"./tools/semantic-release-sync-installer.js",
|
|
||||||
"@semantic-release/github"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -75,6 +75,8 @@ This makes it easy to benefit from the latest improvements, bug fixes, and new a
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx bmad-method install
|
npx bmad-method install
|
||||||
|
# OR explicitly use stable tag:
|
||||||
|
npx bmad-method@stable install
|
||||||
# OR if you already have BMad installed:
|
# OR if you already have BMad installed:
|
||||||
git pull
|
git pull
|
||||||
npm run install:bmad
|
npm run install:bmad
|
||||||
|
|||||||
234
dist/agents/analyst.txt
vendored
234
dist/agents/analyst.txt
vendored
@@ -1101,24 +1101,24 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/brief.md
|
filename: docs/brief.md
|
||||||
title: 'Project Brief: {{project_name}}'
|
title: "Project Brief: {{project_name}}"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
elicitation: advanced-elicitation
|
elicitation: advanced-elicitation
|
||||||
custom_elicitation:
|
custom_elicitation:
|
||||||
title: 'Project Brief Elicitation Actions'
|
title: "Project Brief Elicitation Actions"
|
||||||
options:
|
options:
|
||||||
- 'Expand section with more specific details'
|
- "Expand section with more specific details"
|
||||||
- 'Validate against similar successful products'
|
- "Validate against similar successful products"
|
||||||
- 'Stress test assumptions with edge cases'
|
- "Stress test assumptions with edge cases"
|
||||||
- 'Explore alternative solution approaches'
|
- "Explore alternative solution approaches"
|
||||||
- 'Analyze resource/constraint trade-offs'
|
- "Analyze resource/constraint trade-offs"
|
||||||
- 'Generate risk mitigation strategies'
|
- "Generate risk mitigation strategies"
|
||||||
- 'Challenge scope from MVP minimalist view'
|
- "Challenge scope from MVP minimalist view"
|
||||||
- 'Brainstorm creative feature possibilities'
|
- "Brainstorm creative feature possibilities"
|
||||||
- 'If only we had [resource/capability/time]...'
|
- "If only we had [resource/capability/time]..."
|
||||||
- 'Proceed to next section'
|
- "Proceed to next section"
|
||||||
|
|
||||||
sections:
|
sections:
|
||||||
- id: introduction
|
- id: introduction
|
||||||
@@ -1140,7 +1140,7 @@ sections:
|
|||||||
- Primary problem being solved
|
- Primary problem being solved
|
||||||
- Target market identification
|
- Target market identification
|
||||||
- Key value proposition
|
- Key value proposition
|
||||||
template: '{{executive_summary_content}}'
|
template: "{{executive_summary_content}}"
|
||||||
|
|
||||||
- id: problem-statement
|
- id: problem-statement
|
||||||
title: Problem Statement
|
title: Problem Statement
|
||||||
@@ -1150,7 +1150,7 @@ sections:
|
|||||||
- Impact of the problem (quantify if possible)
|
- Impact of the problem (quantify if possible)
|
||||||
- Why existing solutions fall short
|
- Why existing solutions fall short
|
||||||
- Urgency and importance of solving this now
|
- Urgency and importance of solving this now
|
||||||
template: '{{detailed_problem_description}}'
|
template: "{{detailed_problem_description}}"
|
||||||
|
|
||||||
- id: proposed-solution
|
- id: proposed-solution
|
||||||
title: Proposed Solution
|
title: Proposed Solution
|
||||||
@@ -1160,7 +1160,7 @@ sections:
|
|||||||
- Key differentiators from existing solutions
|
- Key differentiators from existing solutions
|
||||||
- Why this solution will succeed where others haven't
|
- Why this solution will succeed where others haven't
|
||||||
- High-level vision for the product
|
- High-level vision for the product
|
||||||
template: '{{solution_description}}'
|
template: "{{solution_description}}"
|
||||||
|
|
||||||
- id: target-users
|
- id: target-users
|
||||||
title: Target Users
|
title: Target Users
|
||||||
@@ -1172,12 +1172,12 @@ sections:
|
|||||||
- Goals they're trying to achieve
|
- Goals they're trying to achieve
|
||||||
sections:
|
sections:
|
||||||
- id: primary-segment
|
- id: primary-segment
|
||||||
title: 'Primary User Segment: {{segment_name}}'
|
title: "Primary User Segment: {{segment_name}}"
|
||||||
template: '{{primary_user_description}}'
|
template: "{{primary_user_description}}"
|
||||||
- id: secondary-segment
|
- id: secondary-segment
|
||||||
title: 'Secondary User Segment: {{segment_name}}'
|
title: "Secondary User Segment: {{segment_name}}"
|
||||||
condition: Has secondary user segment
|
condition: Has secondary user segment
|
||||||
template: '{{secondary_user_description}}'
|
template: "{{secondary_user_description}}"
|
||||||
|
|
||||||
- id: goals-metrics
|
- id: goals-metrics
|
||||||
title: Goals & Success Metrics
|
title: Goals & Success Metrics
|
||||||
@@ -1186,15 +1186,15 @@ sections:
|
|||||||
- id: business-objectives
|
- id: business-objectives
|
||||||
title: Business Objectives
|
title: Business Objectives
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{objective_with_metric}}'
|
template: "- {{objective_with_metric}}"
|
||||||
- id: user-success-metrics
|
- id: user-success-metrics
|
||||||
title: User Success Metrics
|
title: User Success Metrics
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{user_metric}}'
|
template: "- {{user_metric}}"
|
||||||
- id: kpis
|
- id: kpis
|
||||||
title: Key Performance Indicators (KPIs)
|
title: Key Performance Indicators (KPIs)
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{kpi}}: {{definition_and_target}}'
|
template: "- {{kpi}}: {{definition_and_target}}"
|
||||||
|
|
||||||
- id: mvp-scope
|
- id: mvp-scope
|
||||||
title: MVP Scope
|
title: MVP Scope
|
||||||
@@ -1203,14 +1203,14 @@ sections:
|
|||||||
- id: core-features
|
- id: core-features
|
||||||
title: Core Features (Must Have)
|
title: Core Features (Must Have)
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- **{{feature}}:** {{description_and_rationale}}'
|
template: "- **{{feature}}:** {{description_and_rationale}}"
|
||||||
- id: out-of-scope
|
- id: out-of-scope
|
||||||
title: Out of Scope for MVP
|
title: Out of Scope for MVP
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{feature_or_capability}}'
|
template: "- {{feature_or_capability}}"
|
||||||
- id: mvp-success-criteria
|
- id: mvp-success-criteria
|
||||||
title: MVP Success Criteria
|
title: MVP Success Criteria
|
||||||
template: '{{mvp_success_definition}}'
|
template: "{{mvp_success_definition}}"
|
||||||
|
|
||||||
- id: post-mvp-vision
|
- id: post-mvp-vision
|
||||||
title: Post-MVP Vision
|
title: Post-MVP Vision
|
||||||
@@ -1218,13 +1218,13 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: phase-2-features
|
- id: phase-2-features
|
||||||
title: Phase 2 Features
|
title: Phase 2 Features
|
||||||
template: '{{next_priority_features}}'
|
template: "{{next_priority_features}}"
|
||||||
- id: long-term-vision
|
- id: long-term-vision
|
||||||
title: Long-term Vision
|
title: Long-term Vision
|
||||||
template: '{{one_two_year_vision}}'
|
template: "{{one_two_year_vision}}"
|
||||||
- id: expansion-opportunities
|
- id: expansion-opportunities
|
||||||
title: Expansion Opportunities
|
title: Expansion Opportunities
|
||||||
template: '{{potential_expansions}}'
|
template: "{{potential_expansions}}"
|
||||||
|
|
||||||
- id: technical-considerations
|
- id: technical-considerations
|
||||||
title: Technical Considerations
|
title: Technical Considerations
|
||||||
@@ -1265,7 +1265,7 @@ sections:
|
|||||||
- id: key-assumptions
|
- id: key-assumptions
|
||||||
title: Key Assumptions
|
title: Key Assumptions
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{assumption}}'
|
template: "- {{assumption}}"
|
||||||
|
|
||||||
- id: risks-questions
|
- id: risks-questions
|
||||||
title: Risks & Open Questions
|
title: Risks & Open Questions
|
||||||
@@ -1274,15 +1274,15 @@ sections:
|
|||||||
- id: key-risks
|
- id: key-risks
|
||||||
title: Key Risks
|
title: Key Risks
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- **{{risk}}:** {{description_and_impact}}'
|
template: "- **{{risk}}:** {{description_and_impact}}"
|
||||||
- id: open-questions
|
- id: open-questions
|
||||||
title: Open Questions
|
title: Open Questions
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{question}}'
|
template: "- {{question}}"
|
||||||
- id: research-areas
|
- id: research-areas
|
||||||
title: Areas Needing Further Research
|
title: Areas Needing Further Research
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{research_topic}}'
|
template: "- {{research_topic}}"
|
||||||
|
|
||||||
- id: appendices
|
- id: appendices
|
||||||
title: Appendices
|
title: Appendices
|
||||||
@@ -1299,10 +1299,10 @@ sections:
|
|||||||
- id: stakeholder-input
|
- id: stakeholder-input
|
||||||
title: B. Stakeholder Input
|
title: B. Stakeholder Input
|
||||||
condition: Has stakeholder feedback
|
condition: Has stakeholder feedback
|
||||||
template: '{{stakeholder_feedback}}'
|
template: "{{stakeholder_feedback}}"
|
||||||
- id: references
|
- id: references
|
||||||
title: C. References
|
title: C. References
|
||||||
template: '{{relevant_links_and_docs}}'
|
template: "{{relevant_links_and_docs}}"
|
||||||
|
|
||||||
- id: next-steps
|
- id: next-steps
|
||||||
title: Next Steps
|
title: Next Steps
|
||||||
@@ -1310,7 +1310,7 @@ sections:
|
|||||||
- id: immediate-actions
|
- id: immediate-actions
|
||||||
title: Immediate Actions
|
title: Immediate Actions
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
template: '{{action_item}}'
|
template: "{{action_item}}"
|
||||||
- id: pm-handoff
|
- id: pm-handoff
|
||||||
title: PM Handoff
|
title: PM Handoff
|
||||||
content: |
|
content: |
|
||||||
@@ -1325,24 +1325,24 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/market-research.md
|
filename: docs/market-research.md
|
||||||
title: 'Market Research Report: {{project_product_name}}'
|
title: "Market Research Report: {{project_product_name}}"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
elicitation: advanced-elicitation
|
elicitation: advanced-elicitation
|
||||||
custom_elicitation:
|
custom_elicitation:
|
||||||
title: 'Market Research Elicitation Actions'
|
title: "Market Research Elicitation Actions"
|
||||||
options:
|
options:
|
||||||
- 'Expand market sizing calculations with sensitivity analysis'
|
- "Expand market sizing calculations with sensitivity analysis"
|
||||||
- 'Deep dive into a specific customer segment'
|
- "Deep dive into a specific customer segment"
|
||||||
- 'Analyze an emerging market trend in detail'
|
- "Analyze an emerging market trend in detail"
|
||||||
- 'Compare this market to an analogous market'
|
- "Compare this market to an analogous market"
|
||||||
- 'Stress test market assumptions'
|
- "Stress test market assumptions"
|
||||||
- 'Explore adjacent market opportunities'
|
- "Explore adjacent market opportunities"
|
||||||
- 'Challenge market definition and boundaries'
|
- "Challenge market definition and boundaries"
|
||||||
- 'Generate strategic scenarios (best/base/worst case)'
|
- "Generate strategic scenarios (best/base/worst case)"
|
||||||
- 'If only we had considered [X market factor]...'
|
- "If only we had considered [X market factor]..."
|
||||||
- 'Proceed to next section'
|
- "Proceed to next section"
|
||||||
|
|
||||||
sections:
|
sections:
|
||||||
- id: executive-summary
|
- id: executive-summary
|
||||||
@@ -1424,7 +1424,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: segment
|
- id: segment
|
||||||
title: 'Segment {{segment_number}}: {{segment_name}}'
|
title: "Segment {{segment_number}}: {{segment_name}}"
|
||||||
template: |
|
template: |
|
||||||
- **Description:** {{brief_overview}}
|
- **Description:** {{brief_overview}}
|
||||||
- **Size:** {{number_of_customers_market_value}}
|
- **Size:** {{number_of_customers_market_value}}
|
||||||
@@ -1493,20 +1493,20 @@ sections:
|
|||||||
instruction: Analyze each force with specific evidence and implications
|
instruction: Analyze each force with specific evidence and implications
|
||||||
sections:
|
sections:
|
||||||
- id: supplier-power
|
- id: supplier-power
|
||||||
title: 'Supplier Power: {{power_level}}'
|
title: "Supplier Power: {{power_level}}"
|
||||||
template: '{{analysis_and_implications}}'
|
template: "{{analysis_and_implications}}"
|
||||||
- id: buyer-power
|
- id: buyer-power
|
||||||
title: 'Buyer Power: {{power_level}}'
|
title: "Buyer Power: {{power_level}}"
|
||||||
template: '{{analysis_and_implications}}'
|
template: "{{analysis_and_implications}}"
|
||||||
- id: competitive-rivalry
|
- id: competitive-rivalry
|
||||||
title: 'Competitive Rivalry: {{intensity_level}}'
|
title: "Competitive Rivalry: {{intensity_level}}"
|
||||||
template: '{{analysis_and_implications}}'
|
template: "{{analysis_and_implications}}"
|
||||||
- id: threat-new-entry
|
- id: threat-new-entry
|
||||||
title: 'Threat of New Entry: {{threat_level}}'
|
title: "Threat of New Entry: {{threat_level}}"
|
||||||
template: '{{analysis_and_implications}}'
|
template: "{{analysis_and_implications}}"
|
||||||
- id: threat-substitutes
|
- id: threat-substitutes
|
||||||
title: 'Threat of Substitutes: {{threat_level}}'
|
title: "Threat of Substitutes: {{threat_level}}"
|
||||||
template: '{{analysis_and_implications}}'
|
template: "{{analysis_and_implications}}"
|
||||||
- id: adoption-lifecycle
|
- id: adoption-lifecycle
|
||||||
title: Technology Adoption Lifecycle Stage
|
title: Technology Adoption Lifecycle Stage
|
||||||
instruction: |
|
instruction: |
|
||||||
@@ -1524,7 +1524,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: opportunity
|
- id: opportunity
|
||||||
title: 'Opportunity {{opportunity_number}}: {{name}}'
|
title: "Opportunity {{opportunity_number}}: {{name}}"
|
||||||
template: |
|
template: |
|
||||||
- **Description:** {{what_is_the_opportunity}}
|
- **Description:** {{what_is_the_opportunity}}
|
||||||
- **Size/Potential:** {{quantified_potential}}
|
- **Size/Potential:** {{quantified_potential}}
|
||||||
@@ -1580,24 +1580,24 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/competitor-analysis.md
|
filename: docs/competitor-analysis.md
|
||||||
title: 'Competitive Analysis Report: {{project_product_name}}'
|
title: "Competitive Analysis Report: {{project_product_name}}"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
elicitation: advanced-elicitation
|
elicitation: advanced-elicitation
|
||||||
custom_elicitation:
|
custom_elicitation:
|
||||||
title: 'Competitive Analysis Elicitation Actions'
|
title: "Competitive Analysis Elicitation Actions"
|
||||||
options:
|
options:
|
||||||
- "Deep dive on a specific competitor's strategy"
|
- "Deep dive on a specific competitor's strategy"
|
||||||
- 'Analyze competitive dynamics in a specific segment'
|
- "Analyze competitive dynamics in a specific segment"
|
||||||
- 'War game competitive responses to your moves'
|
- "War game competitive responses to your moves"
|
||||||
- 'Explore partnership vs. competition scenarios'
|
- "Explore partnership vs. competition scenarios"
|
||||||
- 'Stress test differentiation claims'
|
- "Stress test differentiation claims"
|
||||||
- 'Analyze disruption potential (yours or theirs)'
|
- "Analyze disruption potential (yours or theirs)"
|
||||||
- 'Compare to competition in adjacent markets'
|
- "Compare to competition in adjacent markets"
|
||||||
- 'Generate win/loss analysis insights'
|
- "Generate win/loss analysis insights"
|
||||||
- "If only we had known about [competitor X's plan]..."
|
- "If only we had known about [competitor X's plan]..."
|
||||||
- 'Proceed to next section'
|
- "Proceed to next section"
|
||||||
|
|
||||||
sections:
|
sections:
|
||||||
- id: executive-summary
|
- id: executive-summary
|
||||||
@@ -1664,7 +1664,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: competitor
|
- id: competitor
|
||||||
title: '{{competitor_name}} - Priority {{priority_level}}'
|
title: "{{competitor_name}} - Priority {{priority_level}}"
|
||||||
sections:
|
sections:
|
||||||
- id: company-overview
|
- id: company-overview
|
||||||
title: Company Overview
|
title: Company Overview
|
||||||
@@ -1696,11 +1696,11 @@ sections:
|
|||||||
- id: strengths
|
- id: strengths
|
||||||
title: Strengths
|
title: Strengths
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{strength}}'
|
template: "- {{strength}}"
|
||||||
- id: weaknesses
|
- id: weaknesses
|
||||||
title: Weaknesses
|
title: Weaknesses
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{weakness}}'
|
template: "- {{weakness}}"
|
||||||
- id: market-position
|
- id: market-position
|
||||||
title: Market Position & Performance
|
title: Market Position & Performance
|
||||||
template: |
|
template: |
|
||||||
@@ -1718,35 +1718,35 @@ sections:
|
|||||||
type: table
|
type: table
|
||||||
columns:
|
columns:
|
||||||
[
|
[
|
||||||
'Feature Category',
|
"Feature Category",
|
||||||
'{{your_company}}',
|
"{{your_company}}",
|
||||||
'{{competitor_1}}',
|
"{{competitor_1}}",
|
||||||
'{{competitor_2}}',
|
"{{competitor_2}}",
|
||||||
'{{competitor_3}}',
|
"{{competitor_3}}",
|
||||||
]
|
]
|
||||||
rows:
|
rows:
|
||||||
- category: 'Core Functionality'
|
- category: "Core Functionality"
|
||||||
items:
|
items:
|
||||||
- ['Feature A', '{{status}}', '{{status}}', '{{status}}', '{{status}}']
|
- ["Feature A", "{{status}}", "{{status}}", "{{status}}", "{{status}}"]
|
||||||
- ['Feature B', '{{status}}', '{{status}}', '{{status}}', '{{status}}']
|
- ["Feature B", "{{status}}", "{{status}}", "{{status}}", "{{status}}"]
|
||||||
- category: 'User Experience'
|
- category: "User Experience"
|
||||||
items:
|
items:
|
||||||
- ['Mobile App', '{{rating}}', '{{rating}}', '{{rating}}', '{{rating}}']
|
- ["Mobile App", "{{rating}}", "{{rating}}", "{{rating}}", "{{rating}}"]
|
||||||
- ['Onboarding Time', '{{time}}', '{{time}}', '{{time}}', '{{time}}']
|
- ["Onboarding Time", "{{time}}", "{{time}}", "{{time}}", "{{time}}"]
|
||||||
- category: 'Integration & Ecosystem'
|
- category: "Integration & Ecosystem"
|
||||||
items:
|
items:
|
||||||
- [
|
- [
|
||||||
'API Availability',
|
"API Availability",
|
||||||
'{{availability}}',
|
"{{availability}}",
|
||||||
'{{availability}}',
|
"{{availability}}",
|
||||||
'{{availability}}',
|
"{{availability}}",
|
||||||
'{{availability}}',
|
"{{availability}}",
|
||||||
]
|
]
|
||||||
- ['Third-party Integrations', '{{number}}', '{{number}}', '{{number}}', '{{number}}']
|
- ["Third-party Integrations", "{{number}}", "{{number}}", "{{number}}", "{{number}}"]
|
||||||
- category: 'Pricing & Plans'
|
- category: "Pricing & Plans"
|
||||||
items:
|
items:
|
||||||
- ['Starting Price', '{{price}}', '{{price}}', '{{price}}', '{{price}}']
|
- ["Starting Price", "{{price}}", "{{price}}", "{{price}}", "{{price}}"]
|
||||||
- ['Free Tier', '{{yes_no}}', '{{yes_no}}', '{{yes_no}}', '{{yes_no}}']
|
- ["Free Tier", "{{yes_no}}", "{{yes_no}}", "{{yes_no}}", "{{yes_no}}"]
|
||||||
- id: swot-comparison
|
- id: swot-comparison
|
||||||
title: SWOT Comparison
|
title: SWOT Comparison
|
||||||
instruction: Create SWOT analysis for your solution vs. top competitors
|
instruction: Create SWOT analysis for your solution vs. top competitors
|
||||||
@@ -1759,7 +1759,7 @@ sections:
|
|||||||
- **Opportunities:** {{opportunities}}
|
- **Opportunities:** {{opportunities}}
|
||||||
- **Threats:** {{threats}}
|
- **Threats:** {{threats}}
|
||||||
- id: vs-competitor
|
- id: vs-competitor
|
||||||
title: 'vs. {{main_competitor}}'
|
title: "vs. {{main_competitor}}"
|
||||||
template: |
|
template: |
|
||||||
- **Competitive Advantages:** {{your_advantages}}
|
- **Competitive Advantages:** {{your_advantages}}
|
||||||
- **Competitive Disadvantages:** {{their_advantages}}
|
- **Competitive Disadvantages:** {{their_advantages}}
|
||||||
@@ -1889,7 +1889,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/brainstorming-session-results.md
|
filename: docs/brainstorming-session-results.md
|
||||||
title: 'Brainstorming Session Results'
|
title: "Brainstorming Session Results"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: non-interactive
|
mode: non-interactive
|
||||||
@@ -1914,38 +1914,38 @@ sections:
|
|||||||
|
|
||||||
**Total Ideas Generated:** {{total_ideas}}
|
**Total Ideas Generated:** {{total_ideas}}
|
||||||
- id: key-themes
|
- id: key-themes
|
||||||
title: 'Key Themes Identified:'
|
title: "Key Themes Identified:"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{theme}}'
|
template: "- {{theme}}"
|
||||||
|
|
||||||
- id: technique-sessions
|
- id: technique-sessions
|
||||||
title: Technique Sessions
|
title: Technique Sessions
|
||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: technique
|
- id: technique
|
||||||
title: '{{technique_name}} - {{duration}}'
|
title: "{{technique_name}} - {{duration}}"
|
||||||
sections:
|
sections:
|
||||||
- id: description
|
- id: description
|
||||||
template: '**Description:** {{technique_description}}'
|
template: "**Description:** {{technique_description}}"
|
||||||
- id: ideas-generated
|
- id: ideas-generated
|
||||||
title: 'Ideas Generated:'
|
title: "Ideas Generated:"
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
template: '{{idea}}'
|
template: "{{idea}}"
|
||||||
- id: insights
|
- id: insights
|
||||||
title: 'Insights Discovered:'
|
title: "Insights Discovered:"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{insight}}'
|
template: "- {{insight}}"
|
||||||
- id: connections
|
- id: connections
|
||||||
title: 'Notable Connections:'
|
title: "Notable Connections:"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{connection}}'
|
template: "- {{connection}}"
|
||||||
|
|
||||||
- id: idea-categorization
|
- id: idea-categorization
|
||||||
title: Idea Categorization
|
title: Idea Categorization
|
||||||
sections:
|
sections:
|
||||||
- id: immediate-opportunities
|
- id: immediate-opportunities
|
||||||
title: Immediate Opportunities
|
title: Immediate Opportunities
|
||||||
content: '*Ideas ready to implement now*'
|
content: "*Ideas ready to implement now*"
|
||||||
repeatable: true
|
repeatable: true
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
template: |
|
template: |
|
||||||
@@ -1955,7 +1955,7 @@ sections:
|
|||||||
- Resources needed: {{requirements}}
|
- Resources needed: {{requirements}}
|
||||||
- id: future-innovations
|
- id: future-innovations
|
||||||
title: Future Innovations
|
title: Future Innovations
|
||||||
content: '*Ideas requiring development/research*'
|
content: "*Ideas requiring development/research*"
|
||||||
repeatable: true
|
repeatable: true
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
template: |
|
template: |
|
||||||
@@ -1965,7 +1965,7 @@ sections:
|
|||||||
- Timeline estimate: {{timeline}}
|
- Timeline estimate: {{timeline}}
|
||||||
- id: moonshots
|
- id: moonshots
|
||||||
title: Moonshots
|
title: Moonshots
|
||||||
content: '*Ambitious, transformative concepts*'
|
content: "*Ambitious, transformative concepts*"
|
||||||
repeatable: true
|
repeatable: true
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
template: |
|
template: |
|
||||||
@@ -1975,9 +1975,9 @@ sections:
|
|||||||
- Challenges to overcome: {{challenges}}
|
- Challenges to overcome: {{challenges}}
|
||||||
- id: insights-learnings
|
- id: insights-learnings
|
||||||
title: Insights & Learnings
|
title: Insights & Learnings
|
||||||
content: '*Key realizations from the session*'
|
content: "*Key realizations from the session*"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{insight}}: {{description_and_implications}}'
|
template: "- {{insight}}: {{description_and_implications}}"
|
||||||
|
|
||||||
- id: action-planning
|
- id: action-planning
|
||||||
title: Action Planning
|
title: Action Planning
|
||||||
@@ -1986,21 +1986,21 @@ sections:
|
|||||||
title: Top 3 Priority Ideas
|
title: Top 3 Priority Ideas
|
||||||
sections:
|
sections:
|
||||||
- id: priority-1
|
- id: priority-1
|
||||||
title: '#1 Priority: {{idea_name}}'
|
title: "#1 Priority: {{idea_name}}"
|
||||||
template: |
|
template: |
|
||||||
- Rationale: {{rationale}}
|
- Rationale: {{rationale}}
|
||||||
- Next steps: {{next_steps}}
|
- Next steps: {{next_steps}}
|
||||||
- Resources needed: {{resources}}
|
- Resources needed: {{resources}}
|
||||||
- Timeline: {{timeline}}
|
- Timeline: {{timeline}}
|
||||||
- id: priority-2
|
- id: priority-2
|
||||||
title: '#2 Priority: {{idea_name}}'
|
title: "#2 Priority: {{idea_name}}"
|
||||||
template: |
|
template: |
|
||||||
- Rationale: {{rationale}}
|
- Rationale: {{rationale}}
|
||||||
- Next steps: {{next_steps}}
|
- Next steps: {{next_steps}}
|
||||||
- Resources needed: {{resources}}
|
- Resources needed: {{resources}}
|
||||||
- Timeline: {{timeline}}
|
- Timeline: {{timeline}}
|
||||||
- id: priority-3
|
- id: priority-3
|
||||||
title: '#3 Priority: {{idea_name}}'
|
title: "#3 Priority: {{idea_name}}"
|
||||||
template: |
|
template: |
|
||||||
- Rationale: {{rationale}}
|
- Rationale: {{rationale}}
|
||||||
- Next steps: {{next_steps}}
|
- Next steps: {{next_steps}}
|
||||||
@@ -2013,19 +2013,19 @@ sections:
|
|||||||
- id: what-worked
|
- id: what-worked
|
||||||
title: What Worked Well
|
title: What Worked Well
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{aspect}}'
|
template: "- {{aspect}}"
|
||||||
- id: areas-exploration
|
- id: areas-exploration
|
||||||
title: Areas for Further Exploration
|
title: Areas for Further Exploration
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{area}}: {{reason}}'
|
template: "- {{area}}: {{reason}}"
|
||||||
- id: recommended-techniques
|
- id: recommended-techniques
|
||||||
title: Recommended Follow-up Techniques
|
title: Recommended Follow-up Techniques
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{technique}}: {{reason}}'
|
template: "- {{technique}}: {{reason}}"
|
||||||
- id: questions-emerged
|
- id: questions-emerged
|
||||||
title: Questions That Emerged
|
title: Questions That Emerged
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{question}}'
|
template: "- {{question}}"
|
||||||
- id: next-session
|
- id: next-session
|
||||||
title: Next Session Planning
|
title: Next Session Planning
|
||||||
template: |
|
template: |
|
||||||
|
|||||||
286
dist/agents/architect.txt
vendored
286
dist/agents/architect.txt
vendored
@@ -933,7 +933,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/architecture.md
|
filename: docs/architecture.md
|
||||||
title: '{{project_name}} Architecture Document'
|
title: "{{project_name}} Architecture Document"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -1044,11 +1044,11 @@ sections:
|
|||||||
- Code organization patterns (Dependency Injection, Repository, Module, Factory)
|
- Code organization patterns (Dependency Injection, Repository, Module, Factory)
|
||||||
- Data patterns (Event Sourcing, Saga, Database per Service)
|
- Data patterns (Event Sourcing, Saga, Database per Service)
|
||||||
- Communication patterns (REST, GraphQL, Message Queue, Pub/Sub)
|
- Communication patterns (REST, GraphQL, Message Queue, Pub/Sub)
|
||||||
template: '- **{{pattern_name}}:** {{pattern_description}} - _Rationale:_ {{rationale}}'
|
template: "- **{{pattern_name}}:** {{pattern_description}} - _Rationale:_ {{rationale}}"
|
||||||
examples:
|
examples:
|
||||||
- '**Serverless Architecture:** Using AWS Lambda for compute - _Rationale:_ Aligns with PRD requirement for cost optimization and automatic scaling'
|
- "**Serverless Architecture:** Using AWS Lambda for compute - _Rationale:_ Aligns with PRD requirement for cost optimization and automatic scaling"
|
||||||
- '**Repository Pattern:** Abstract data access logic - _Rationale:_ Enables testing and future database migration flexibility'
|
- "**Repository Pattern:** Abstract data access logic - _Rationale:_ Enables testing and future database migration flexibility"
|
||||||
- '**Event-Driven Communication:** Using SNS/SQS for service decoupling - _Rationale:_ Supports async processing and system resilience'
|
- "**Event-Driven Communication:** Using SNS/SQS for service decoupling - _Rationale:_ Supports async processing and system resilience"
|
||||||
|
|
||||||
- id: tech-stack
|
- id: tech-stack
|
||||||
title: Tech Stack
|
title: Tech Stack
|
||||||
@@ -1086,9 +1086,9 @@ sections:
|
|||||||
columns: [Category, Technology, Version, Purpose, Rationale]
|
columns: [Category, Technology, Version, Purpose, Rationale]
|
||||||
instruction: Populate the technology stack table with all relevant technologies
|
instruction: Populate the technology stack table with all relevant technologies
|
||||||
examples:
|
examples:
|
||||||
- '| **Language** | TypeScript | 5.3.3 | Primary development language | Strong typing, excellent tooling, team expertise |'
|
- "| **Language** | TypeScript | 5.3.3 | Primary development language | Strong typing, excellent tooling, team expertise |"
|
||||||
- '| **Runtime** | Node.js | 20.11.0 | JavaScript runtime | LTS version, stable performance, wide ecosystem |'
|
- "| **Runtime** | Node.js | 20.11.0 | JavaScript runtime | LTS version, stable performance, wide ecosystem |"
|
||||||
- '| **Framework** | NestJS | 10.3.2 | Backend framework | Enterprise-ready, good DI, matches team patterns |'
|
- "| **Framework** | NestJS | 10.3.2 | Backend framework | Enterprise-ready, good DI, matches team patterns |"
|
||||||
|
|
||||||
- id: data-models
|
- id: data-models
|
||||||
title: Data Models
|
title: Data Models
|
||||||
@@ -1106,7 +1106,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: model
|
- id: model
|
||||||
title: '{{model_name}}'
|
title: "{{model_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Purpose:** {{model_purpose}}
|
**Purpose:** {{model_purpose}}
|
||||||
|
|
||||||
@@ -1137,7 +1137,7 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: component-list
|
- id: component-list
|
||||||
repeatable: true
|
repeatable: true
|
||||||
title: '{{component_name}}'
|
title: "{{component_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Responsibility:** {{component_description}}
|
**Responsibility:** {{component_description}}
|
||||||
|
|
||||||
@@ -1175,7 +1175,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: api
|
- id: api
|
||||||
title: '{{api_name}} API'
|
title: "{{api_name}} API"
|
||||||
template: |
|
template: |
|
||||||
- **Purpose:** {{api_purpose}}
|
- **Purpose:** {{api_purpose}}
|
||||||
- **Documentation:** {{api_docs_url}}
|
- **Documentation:** {{api_docs_url}}
|
||||||
@@ -1300,12 +1300,12 @@ sections:
|
|||||||
- id: environments
|
- id: environments
|
||||||
title: Environments
|
title: Environments
|
||||||
repeatable: true
|
repeatable: true
|
||||||
template: '- **{{env_name}}:** {{env_purpose}} - {{env_details}}'
|
template: "- **{{env_name}}:** {{env_purpose}} - {{env_details}}"
|
||||||
- id: promotion-flow
|
- id: promotion-flow
|
||||||
title: Environment Promotion Flow
|
title: Environment Promotion Flow
|
||||||
type: code
|
type: code
|
||||||
language: text
|
language: text
|
||||||
template: '{{promotion_flow_diagram}}'
|
template: "{{promotion_flow_diagram}}"
|
||||||
- id: rollback-strategy
|
- id: rollback-strategy
|
||||||
title: Rollback Strategy
|
title: Rollback Strategy
|
||||||
template: |
|
template: |
|
||||||
@@ -1401,16 +1401,16 @@ sections:
|
|||||||
|
|
||||||
Avoid obvious rules like "use SOLID principles" or "write clean code"
|
Avoid obvious rules like "use SOLID principles" or "write clean code"
|
||||||
repeatable: true
|
repeatable: true
|
||||||
template: '- **{{rule_name}}:** {{rule_description}}'
|
template: "- **{{rule_name}}:** {{rule_description}}"
|
||||||
- id: language-specifics
|
- id: language-specifics
|
||||||
title: Language-Specific Guidelines
|
title: Language-Specific Guidelines
|
||||||
condition: Critical language-specific rules needed
|
condition: Critical language-specific rules needed
|
||||||
instruction: Add ONLY if critical for preventing AI mistakes. Most teams don't need this section.
|
instruction: Add ONLY if critical for preventing AI mistakes. Most teams don't need this section.
|
||||||
sections:
|
sections:
|
||||||
- id: language-rules
|
- id: language-rules
|
||||||
title: '{{language_name}} Specifics'
|
title: "{{language_name}} Specifics"
|
||||||
repeatable: true
|
repeatable: true
|
||||||
template: '- **{{rule_topic}}:** {{rule_detail}}'
|
template: "- **{{rule_topic}}:** {{rule_detail}}"
|
||||||
|
|
||||||
- id: test-strategy
|
- id: test-strategy
|
||||||
title: Test Strategy and Standards
|
title: Test Strategy and Standards
|
||||||
@@ -1458,9 +1458,9 @@ sections:
|
|||||||
- **Test Infrastructure:**
|
- **Test Infrastructure:**
|
||||||
- **{{dependency_name}}:** {{test_approach}} ({{test_tool}})
|
- **{{dependency_name}}:** {{test_approach}} ({{test_tool}})
|
||||||
examples:
|
examples:
|
||||||
- '**Database:** In-memory H2 for unit tests, Testcontainers PostgreSQL for integration'
|
- "**Database:** In-memory H2 for unit tests, Testcontainers PostgreSQL for integration"
|
||||||
- '**Message Queue:** Embedded Kafka for tests'
|
- "**Message Queue:** Embedded Kafka for tests"
|
||||||
- '**External APIs:** WireMock for stubbing'
|
- "**External APIs:** WireMock for stubbing"
|
||||||
- id: e2e-tests
|
- id: e2e-tests
|
||||||
title: End-to-End Tests
|
title: End-to-End Tests
|
||||||
template: |
|
template: |
|
||||||
@@ -1586,7 +1586,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/ui-architecture.md
|
filename: docs/ui-architecture.md
|
||||||
title: '{{project_name}} Frontend Architecture Document'
|
title: "{{project_name}} Frontend Architecture Document"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -1654,29 +1654,29 @@ sections:
|
|||||||
columns: [Category, Technology, Version, Purpose, Rationale]
|
columns: [Category, Technology, Version, Purpose, Rationale]
|
||||||
instruction: Fill in appropriate technology choices based on the selected framework and project requirements.
|
instruction: Fill in appropriate technology choices based on the selected framework and project requirements.
|
||||||
rows:
|
rows:
|
||||||
- ['Framework', '{{framework}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Framework", "{{framework}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['UI Library', '{{ui_library}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["UI Library", "{{ui_library}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- [
|
- [
|
||||||
'State Management',
|
"State Management",
|
||||||
'{{state_management}}',
|
"{{state_management}}",
|
||||||
'{{version}}',
|
"{{version}}",
|
||||||
'{{purpose}}',
|
"{{purpose}}",
|
||||||
'{{why_chosen}}',
|
"{{why_chosen}}",
|
||||||
]
|
]
|
||||||
- ['Routing', '{{routing_library}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Routing", "{{routing_library}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Build Tool', '{{build_tool}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Build Tool", "{{build_tool}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Styling', '{{styling_solution}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Styling", "{{styling_solution}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Testing', '{{test_framework}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Testing", "{{test_framework}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- [
|
- [
|
||||||
'Component Library',
|
"Component Library",
|
||||||
'{{component_lib}}',
|
"{{component_lib}}",
|
||||||
'{{version}}',
|
"{{version}}",
|
||||||
'{{purpose}}',
|
"{{purpose}}",
|
||||||
'{{why_chosen}}',
|
"{{why_chosen}}",
|
||||||
]
|
]
|
||||||
- ['Form Handling', '{{form_library}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Form Handling", "{{form_library}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Animation', '{{animation_lib}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Animation", "{{animation_lib}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Dev Tools', '{{dev_tools}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Dev Tools", "{{dev_tools}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
|
|
||||||
- id: project-structure
|
- id: project-structure
|
||||||
title: Project Structure
|
title: Project Structure
|
||||||
@@ -1770,12 +1770,12 @@ sections:
|
|||||||
title: Testing Best Practices
|
title: Testing Best Practices
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
items:
|
items:
|
||||||
- '**Unit Tests**: Test individual components in isolation'
|
- "**Unit Tests**: Test individual components in isolation"
|
||||||
- '**Integration Tests**: Test component interactions'
|
- "**Integration Tests**: Test component interactions"
|
||||||
- '**E2E Tests**: Test critical user flows (using Cypress/Playwright)'
|
- "**E2E Tests**: Test critical user flows (using Cypress/Playwright)"
|
||||||
- '**Coverage Goals**: Aim for 80% code coverage'
|
- "**Coverage Goals**: Aim for 80% code coverage"
|
||||||
- '**Test Structure**: Arrange-Act-Assert pattern'
|
- "**Test Structure**: Arrange-Act-Assert pattern"
|
||||||
- '**Mock External Dependencies**: API calls, routing, state management'
|
- "**Mock External Dependencies**: API calls, routing, state management"
|
||||||
|
|
||||||
- id: environment-configuration
|
- id: environment-configuration
|
||||||
title: Environment Configuration
|
title: Environment Configuration
|
||||||
@@ -1807,7 +1807,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/architecture.md
|
filename: docs/architecture.md
|
||||||
title: '{{project_name}} Fullstack Architecture Document'
|
title: "{{project_name}} Fullstack Architecture Document"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -1928,12 +1928,12 @@ sections:
|
|||||||
|
|
||||||
For each pattern, provide recommendation and rationale.
|
For each pattern, provide recommendation and rationale.
|
||||||
repeatable: true
|
repeatable: true
|
||||||
template: '- **{{pattern_name}}:** {{pattern_description}} - _Rationale:_ {{rationale}}'
|
template: "- **{{pattern_name}}:** {{pattern_description}} - _Rationale:_ {{rationale}}"
|
||||||
examples:
|
examples:
|
||||||
- '**Jamstack Architecture:** Static site generation with serverless APIs - _Rationale:_ Optimal performance and scalability for content-heavy applications'
|
- "**Jamstack Architecture:** Static site generation with serverless APIs - _Rationale:_ Optimal performance and scalability for content-heavy applications"
|
||||||
- '**Component-Based UI:** Reusable React components with TypeScript - _Rationale:_ Maintainability and type safety across large codebases'
|
- "**Component-Based UI:** Reusable React components with TypeScript - _Rationale:_ Maintainability and type safety across large codebases"
|
||||||
- '**Repository Pattern:** Abstract data access logic - _Rationale:_ Enables testing and future database migration flexibility'
|
- "**Repository Pattern:** Abstract data access logic - _Rationale:_ Enables testing and future database migration flexibility"
|
||||||
- '**API Gateway Pattern:** Single entry point for all API calls - _Rationale:_ Centralized auth, rate limiting, and monitoring'
|
- "**API Gateway Pattern:** Single entry point for all API calls - _Rationale:_ Centralized auth, rate limiting, and monitoring"
|
||||||
|
|
||||||
- id: tech-stack
|
- id: tech-stack
|
||||||
title: Tech Stack
|
title: Tech Stack
|
||||||
@@ -1957,45 +1957,45 @@ sections:
|
|||||||
type: table
|
type: table
|
||||||
columns: [Category, Technology, Version, Purpose, Rationale]
|
columns: [Category, Technology, Version, Purpose, Rationale]
|
||||||
rows:
|
rows:
|
||||||
- ['Frontend Language', '{{fe_language}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Frontend Language", "{{fe_language}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- [
|
- [
|
||||||
'Frontend Framework',
|
"Frontend Framework",
|
||||||
'{{fe_framework}}',
|
"{{fe_framework}}",
|
||||||
'{{version}}',
|
"{{version}}",
|
||||||
'{{purpose}}',
|
"{{purpose}}",
|
||||||
'{{why_chosen}}',
|
"{{why_chosen}}",
|
||||||
]
|
]
|
||||||
- [
|
- [
|
||||||
'UI Component Library',
|
"UI Component Library",
|
||||||
'{{ui_library}}',
|
"{{ui_library}}",
|
||||||
'{{version}}',
|
"{{version}}",
|
||||||
'{{purpose}}',
|
"{{purpose}}",
|
||||||
'{{why_chosen}}',
|
"{{why_chosen}}",
|
||||||
]
|
]
|
||||||
- ['State Management', '{{state_mgmt}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["State Management", "{{state_mgmt}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Backend Language', '{{be_language}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Backend Language", "{{be_language}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- [
|
- [
|
||||||
'Backend Framework',
|
"Backend Framework",
|
||||||
'{{be_framework}}',
|
"{{be_framework}}",
|
||||||
'{{version}}',
|
"{{version}}",
|
||||||
'{{purpose}}',
|
"{{purpose}}",
|
||||||
'{{why_chosen}}',
|
"{{why_chosen}}",
|
||||||
]
|
]
|
||||||
- ['API Style', '{{api_style}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["API Style", "{{api_style}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Database', '{{database}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Database", "{{database}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Cache', '{{cache}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Cache", "{{cache}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['File Storage', '{{storage}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["File Storage", "{{storage}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Authentication', '{{auth}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Authentication", "{{auth}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Frontend Testing', '{{fe_test}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Frontend Testing", "{{fe_test}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Backend Testing', '{{be_test}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Backend Testing", "{{be_test}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['E2E Testing', '{{e2e_test}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["E2E Testing", "{{e2e_test}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Build Tool', '{{build_tool}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Build Tool", "{{build_tool}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Bundler', '{{bundler}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Bundler", "{{bundler}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['IaC Tool', '{{iac_tool}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["IaC Tool", "{{iac_tool}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['CI/CD', '{{cicd}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["CI/CD", "{{cicd}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Monitoring', '{{monitoring}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Monitoring", "{{monitoring}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['Logging', '{{logging}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["Logging", "{{logging}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ['CSS Framework', '{{css_framework}}', '{{version}}', '{{purpose}}', '{{why_chosen}}']
|
- ["CSS Framework", "{{css_framework}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
|
|
||||||
- id: data-models
|
- id: data-models
|
||||||
title: Data Models
|
title: Data Models
|
||||||
@@ -2014,7 +2014,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: model
|
- id: model
|
||||||
title: '{{model_name}}'
|
title: "{{model_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Purpose:** {{model_purpose}}
|
**Purpose:** {{model_purpose}}
|
||||||
|
|
||||||
@@ -2026,11 +2026,11 @@ sections:
|
|||||||
title: TypeScript Interface
|
title: TypeScript Interface
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{model_interface}}'
|
template: "{{model_interface}}"
|
||||||
- id: relationships
|
- id: relationships
|
||||||
title: Relationships
|
title: Relationships
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{relationship}}'
|
template: "- {{relationship}}"
|
||||||
|
|
||||||
- id: api-spec
|
- id: api-spec
|
||||||
title: API Specification
|
title: API Specification
|
||||||
@@ -2067,13 +2067,13 @@ sections:
|
|||||||
condition: API style is GraphQL
|
condition: API style is GraphQL
|
||||||
type: code
|
type: code
|
||||||
language: graphql
|
language: graphql
|
||||||
template: '{{graphql_schema}}'
|
template: "{{graphql_schema}}"
|
||||||
- id: trpc-api
|
- id: trpc-api
|
||||||
title: tRPC Router Definitions
|
title: tRPC Router Definitions
|
||||||
condition: API style is tRPC
|
condition: API style is tRPC
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{trpc_routers}}'
|
template: "{{trpc_routers}}"
|
||||||
|
|
||||||
- id: components
|
- id: components
|
||||||
title: Components
|
title: Components
|
||||||
@@ -2094,7 +2094,7 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: component-list
|
- id: component-list
|
||||||
repeatable: true
|
repeatable: true
|
||||||
title: '{{component_name}}'
|
title: "{{component_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Responsibility:** {{component_description}}
|
**Responsibility:** {{component_description}}
|
||||||
|
|
||||||
@@ -2132,7 +2132,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: api
|
- id: api
|
||||||
title: '{{api_name}} API'
|
title: "{{api_name}} API"
|
||||||
template: |
|
template: |
|
||||||
- **Purpose:** {{api_purpose}}
|
- **Purpose:** {{api_purpose}}
|
||||||
- **Documentation:** {{api_docs_url}}
|
- **Documentation:** {{api_docs_url}}
|
||||||
@@ -2189,12 +2189,12 @@ sections:
|
|||||||
title: Component Organization
|
title: Component Organization
|
||||||
type: code
|
type: code
|
||||||
language: text
|
language: text
|
||||||
template: '{{component_structure}}'
|
template: "{{component_structure}}"
|
||||||
- id: component-template
|
- id: component-template
|
||||||
title: Component Template
|
title: Component Template
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{component_template}}'
|
template: "{{component_template}}"
|
||||||
- id: state-management
|
- id: state-management
|
||||||
title: State Management Architecture
|
title: State Management Architecture
|
||||||
instruction: Detail state management approach based on chosen solution.
|
instruction: Detail state management approach based on chosen solution.
|
||||||
@@ -2203,11 +2203,11 @@ sections:
|
|||||||
title: State Structure
|
title: State Structure
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{state_structure}}'
|
template: "{{state_structure}}"
|
||||||
- id: state-patterns
|
- id: state-patterns
|
||||||
title: State Management Patterns
|
title: State Management Patterns
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{pattern}}'
|
template: "- {{pattern}}"
|
||||||
- id: routing-architecture
|
- id: routing-architecture
|
||||||
title: Routing Architecture
|
title: Routing Architecture
|
||||||
instruction: Define routing structure based on framework choice.
|
instruction: Define routing structure based on framework choice.
|
||||||
@@ -2216,12 +2216,12 @@ sections:
|
|||||||
title: Route Organization
|
title: Route Organization
|
||||||
type: code
|
type: code
|
||||||
language: text
|
language: text
|
||||||
template: '{{route_structure}}'
|
template: "{{route_structure}}"
|
||||||
- id: protected-routes
|
- id: protected-routes
|
||||||
title: Protected Route Pattern
|
title: Protected Route Pattern
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{protected_route_example}}'
|
template: "{{protected_route_example}}"
|
||||||
- id: frontend-services
|
- id: frontend-services
|
||||||
title: Frontend Services Layer
|
title: Frontend Services Layer
|
||||||
instruction: Define how frontend communicates with backend.
|
instruction: Define how frontend communicates with backend.
|
||||||
@@ -2230,12 +2230,12 @@ sections:
|
|||||||
title: API Client Setup
|
title: API Client Setup
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{api_client_setup}}'
|
template: "{{api_client_setup}}"
|
||||||
- id: service-example
|
- id: service-example
|
||||||
title: Service Example
|
title: Service Example
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{service_example}}'
|
template: "{{service_example}}"
|
||||||
|
|
||||||
- id: backend-architecture
|
- id: backend-architecture
|
||||||
title: Backend Architecture
|
title: Backend Architecture
|
||||||
@@ -2253,12 +2253,12 @@ sections:
|
|||||||
title: Function Organization
|
title: Function Organization
|
||||||
type: code
|
type: code
|
||||||
language: text
|
language: text
|
||||||
template: '{{function_structure}}'
|
template: "{{function_structure}}"
|
||||||
- id: function-template
|
- id: function-template
|
||||||
title: Function Template
|
title: Function Template
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{function_template}}'
|
template: "{{function_template}}"
|
||||||
- id: traditional-server
|
- id: traditional-server
|
||||||
condition: Traditional server architecture chosen
|
condition: Traditional server architecture chosen
|
||||||
sections:
|
sections:
|
||||||
@@ -2266,12 +2266,12 @@ sections:
|
|||||||
title: Controller/Route Organization
|
title: Controller/Route Organization
|
||||||
type: code
|
type: code
|
||||||
language: text
|
language: text
|
||||||
template: '{{controller_structure}}'
|
template: "{{controller_structure}}"
|
||||||
- id: controller-template
|
- id: controller-template
|
||||||
title: Controller Template
|
title: Controller Template
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{controller_template}}'
|
template: "{{controller_template}}"
|
||||||
- id: database-architecture
|
- id: database-architecture
|
||||||
title: Database Architecture
|
title: Database Architecture
|
||||||
instruction: Define database schema and access patterns.
|
instruction: Define database schema and access patterns.
|
||||||
@@ -2280,12 +2280,12 @@ sections:
|
|||||||
title: Schema Design
|
title: Schema Design
|
||||||
type: code
|
type: code
|
||||||
language: sql
|
language: sql
|
||||||
template: '{{database_schema}}'
|
template: "{{database_schema}}"
|
||||||
- id: data-access-layer
|
- id: data-access-layer
|
||||||
title: Data Access Layer
|
title: Data Access Layer
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{repository_pattern}}'
|
template: "{{repository_pattern}}"
|
||||||
- id: auth-architecture
|
- id: auth-architecture
|
||||||
title: Authentication and Authorization
|
title: Authentication and Authorization
|
||||||
instruction: Define auth implementation details.
|
instruction: Define auth implementation details.
|
||||||
@@ -2294,12 +2294,12 @@ sections:
|
|||||||
title: Auth Flow
|
title: Auth Flow
|
||||||
type: mermaid
|
type: mermaid
|
||||||
mermaid_type: sequence
|
mermaid_type: sequence
|
||||||
template: '{{auth_flow_diagram}}'
|
template: "{{auth_flow_diagram}}"
|
||||||
- id: auth-middleware
|
- id: auth-middleware
|
||||||
title: Middleware/Guards
|
title: Middleware/Guards
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{auth_middleware}}'
|
template: "{{auth_middleware}}"
|
||||||
|
|
||||||
- id: unified-project-structure
|
- id: unified-project-structure
|
||||||
title: Unified Project Structure
|
title: Unified Project Structure
|
||||||
@@ -2375,12 +2375,12 @@ sections:
|
|||||||
title: Prerequisites
|
title: Prerequisites
|
||||||
type: code
|
type: code
|
||||||
language: bash
|
language: bash
|
||||||
template: '{{prerequisites_commands}}'
|
template: "{{prerequisites_commands}}"
|
||||||
- id: initial-setup
|
- id: initial-setup
|
||||||
title: Initial Setup
|
title: Initial Setup
|
||||||
type: code
|
type: code
|
||||||
language: bash
|
language: bash
|
||||||
template: '{{setup_commands}}'
|
template: "{{setup_commands}}"
|
||||||
- id: dev-commands
|
- id: dev-commands
|
||||||
title: Development Commands
|
title: Development Commands
|
||||||
type: code
|
type: code
|
||||||
@@ -2436,15 +2436,15 @@ sections:
|
|||||||
title: CI/CD Pipeline
|
title: CI/CD Pipeline
|
||||||
type: code
|
type: code
|
||||||
language: yaml
|
language: yaml
|
||||||
template: '{{cicd_pipeline_config}}'
|
template: "{{cicd_pipeline_config}}"
|
||||||
- id: environments
|
- id: environments
|
||||||
title: Environments
|
title: Environments
|
||||||
type: table
|
type: table
|
||||||
columns: [Environment, Frontend URL, Backend URL, Purpose]
|
columns: [Environment, Frontend URL, Backend URL, Purpose]
|
||||||
rows:
|
rows:
|
||||||
- ['Development', '{{dev_fe_url}}', '{{dev_be_url}}', 'Local development']
|
- ["Development", "{{dev_fe_url}}", "{{dev_be_url}}", "Local development"]
|
||||||
- ['Staging', '{{staging_fe_url}}', '{{staging_be_url}}', 'Pre-production testing']
|
- ["Staging", "{{staging_fe_url}}", "{{staging_be_url}}", "Pre-production testing"]
|
||||||
- ['Production', '{{prod_fe_url}}', '{{prod_be_url}}', 'Live environment']
|
- ["Production", "{{prod_fe_url}}", "{{prod_be_url}}", "Live environment"]
|
||||||
|
|
||||||
- id: security-performance
|
- id: security-performance
|
||||||
title: Security and Performance
|
title: Security and Performance
|
||||||
@@ -2503,17 +2503,17 @@ sections:
|
|||||||
title: Frontend Tests
|
title: Frontend Tests
|
||||||
type: code
|
type: code
|
||||||
language: text
|
language: text
|
||||||
template: '{{frontend_test_structure}}'
|
template: "{{frontend_test_structure}}"
|
||||||
- id: backend-tests
|
- id: backend-tests
|
||||||
title: Backend Tests
|
title: Backend Tests
|
||||||
type: code
|
type: code
|
||||||
language: text
|
language: text
|
||||||
template: '{{backend_test_structure}}'
|
template: "{{backend_test_structure}}"
|
||||||
- id: e2e-tests
|
- id: e2e-tests
|
||||||
title: E2E Tests
|
title: E2E Tests
|
||||||
type: code
|
type: code
|
||||||
language: text
|
language: text
|
||||||
template: '{{e2e_test_structure}}'
|
template: "{{e2e_test_structure}}"
|
||||||
- id: test-examples
|
- id: test-examples
|
||||||
title: Test Examples
|
title: Test Examples
|
||||||
sections:
|
sections:
|
||||||
@@ -2521,17 +2521,17 @@ sections:
|
|||||||
title: Frontend Component Test
|
title: Frontend Component Test
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{frontend_test_example}}'
|
template: "{{frontend_test_example}}"
|
||||||
- id: backend-test
|
- id: backend-test
|
||||||
title: Backend API Test
|
title: Backend API Test
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{backend_test_example}}'
|
template: "{{backend_test_example}}"
|
||||||
- id: e2e-test
|
- id: e2e-test
|
||||||
title: E2E Test
|
title: E2E Test
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{e2e_test_example}}'
|
template: "{{e2e_test_example}}"
|
||||||
|
|
||||||
- id: coding-standards
|
- id: coding-standards
|
||||||
title: Coding Standards
|
title: Coding Standards
|
||||||
@@ -2541,22 +2541,22 @@ sections:
|
|||||||
- id: critical-rules
|
- id: critical-rules
|
||||||
title: Critical Fullstack Rules
|
title: Critical Fullstack Rules
|
||||||
repeatable: true
|
repeatable: true
|
||||||
template: '- **{{rule_name}}:** {{rule_description}}'
|
template: "- **{{rule_name}}:** {{rule_description}}"
|
||||||
examples:
|
examples:
|
||||||
- '**Type Sharing:** Always define types in packages/shared and import from there'
|
- "**Type Sharing:** Always define types in packages/shared and import from there"
|
||||||
- '**API Calls:** Never make direct HTTP calls - use the service layer'
|
- "**API Calls:** Never make direct HTTP calls - use the service layer"
|
||||||
- '**Environment Variables:** Access only through config objects, never process.env directly'
|
- "**Environment Variables:** Access only through config objects, never process.env directly"
|
||||||
- '**Error Handling:** All API routes must use the standard error handler'
|
- "**Error Handling:** All API routes must use the standard error handler"
|
||||||
- '**State Updates:** Never mutate state directly - use proper state management patterns'
|
- "**State Updates:** Never mutate state directly - use proper state management patterns"
|
||||||
- id: naming-conventions
|
- id: naming-conventions
|
||||||
title: Naming Conventions
|
title: Naming Conventions
|
||||||
type: table
|
type: table
|
||||||
columns: [Element, Frontend, Backend, Example]
|
columns: [Element, Frontend, Backend, Example]
|
||||||
rows:
|
rows:
|
||||||
- ['Components', 'PascalCase', '-', '`UserProfile.tsx`']
|
- ["Components", "PascalCase", "-", "`UserProfile.tsx`"]
|
||||||
- ['Hooks', "camelCase with 'use'", '-', '`useAuth.ts`']
|
- ["Hooks", "camelCase with 'use'", "-", "`useAuth.ts`"]
|
||||||
- ['API Routes', '-', 'kebab-case', '`/api/user-profile`']
|
- ["API Routes", "-", "kebab-case", "`/api/user-profile`"]
|
||||||
- ['Database Tables', '-', 'snake_case', '`user_profiles`']
|
- ["Database Tables", "-", "snake_case", "`user_profiles`"]
|
||||||
|
|
||||||
- id: error-handling
|
- id: error-handling
|
||||||
title: Error Handling Strategy
|
title: Error Handling Strategy
|
||||||
@@ -2567,7 +2567,7 @@ sections:
|
|||||||
title: Error Flow
|
title: Error Flow
|
||||||
type: mermaid
|
type: mermaid
|
||||||
mermaid_type: sequence
|
mermaid_type: sequence
|
||||||
template: '{{error_flow_diagram}}'
|
template: "{{error_flow_diagram}}"
|
||||||
- id: error-format
|
- id: error-format
|
||||||
title: Error Response Format
|
title: Error Response Format
|
||||||
type: code
|
type: code
|
||||||
@@ -2586,12 +2586,12 @@ sections:
|
|||||||
title: Frontend Error Handling
|
title: Frontend Error Handling
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{frontend_error_handler}}'
|
template: "{{frontend_error_handler}}"
|
||||||
- id: backend-error-handling
|
- id: backend-error-handling
|
||||||
title: Backend Error Handling
|
title: Backend Error Handling
|
||||||
type: code
|
type: code
|
||||||
language: typescript
|
language: typescript
|
||||||
template: '{{backend_error_handler}}'
|
template: "{{backend_error_handler}}"
|
||||||
|
|
||||||
- id: monitoring
|
- id: monitoring
|
||||||
title: Monitoring and Observability
|
title: Monitoring and Observability
|
||||||
@@ -2633,7 +2633,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/architecture.md
|
filename: docs/architecture.md
|
||||||
title: '{{project_name}} Brownfield Enhancement Architecture'
|
title: "{{project_name}} Brownfield Enhancement Architecture"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -2691,11 +2691,11 @@ sections:
|
|||||||
- id: available-docs
|
- id: available-docs
|
||||||
title: Available Documentation
|
title: Available Documentation
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{existing_docs_summary}}'
|
template: "- {{existing_docs_summary}}"
|
||||||
- id: constraints
|
- id: constraints
|
||||||
title: Identified Constraints
|
title: Identified Constraints
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{constraint}}'
|
template: "- {{constraint}}"
|
||||||
- id: changelog
|
- id: changelog
|
||||||
title: Change Log
|
title: Change Log
|
||||||
type: table
|
type: table
|
||||||
@@ -2775,7 +2775,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: model
|
- id: model
|
||||||
title: '{{model_name}}'
|
title: "{{model_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Purpose:** {{model_purpose}}
|
**Purpose:** {{model_purpose}}
|
||||||
**Integration:** {{integration_with_existing}}
|
**Integration:** {{integration_with_existing}}
|
||||||
@@ -2818,7 +2818,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: component
|
- id: component
|
||||||
title: '{{component_name}}'
|
title: "{{component_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Responsibility:** {{component_description}}
|
**Responsibility:** {{component_description}}
|
||||||
**Integration Points:** {{integration_points}}
|
**Integration Points:** {{integration_points}}
|
||||||
@@ -2861,7 +2861,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: endpoint
|
- id: endpoint
|
||||||
title: '{{endpoint_name}}'
|
title: "{{endpoint_name}}"
|
||||||
template: |
|
template: |
|
||||||
- **Method:** {{http_method}}
|
- **Method:** {{http_method}}
|
||||||
- **Endpoint:** {{endpoint_path}}
|
- **Endpoint:** {{endpoint_path}}
|
||||||
@@ -2872,12 +2872,12 @@ sections:
|
|||||||
title: Request
|
title: Request
|
||||||
type: code
|
type: code
|
||||||
language: json
|
language: json
|
||||||
template: '{{request_schema}}'
|
template: "{{request_schema}}"
|
||||||
- id: response
|
- id: response
|
||||||
title: Response
|
title: Response
|
||||||
type: code
|
type: code
|
||||||
language: json
|
language: json
|
||||||
template: '{{response_schema}}'
|
template: "{{response_schema}}"
|
||||||
|
|
||||||
- id: external-api-integration
|
- id: external-api-integration
|
||||||
title: External API Integration
|
title: External API Integration
|
||||||
@@ -2886,7 +2886,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: external-api
|
- id: external-api
|
||||||
title: '{{api_name}} API'
|
title: "{{api_name}} API"
|
||||||
template: |
|
template: |
|
||||||
- **Purpose:** {{api_purpose}}
|
- **Purpose:** {{api_purpose}}
|
||||||
- **Documentation:** {{api_docs_url}}
|
- **Documentation:** {{api_docs_url}}
|
||||||
@@ -2915,7 +2915,7 @@ sections:
|
|||||||
type: code
|
type: code
|
||||||
language: plaintext
|
language: plaintext
|
||||||
instruction: Document relevant parts of current structure
|
instruction: Document relevant parts of current structure
|
||||||
template: '{{existing_structure_relevant_parts}}'
|
template: "{{existing_structure_relevant_parts}}"
|
||||||
- id: new-file-organization
|
- id: new-file-organization
|
||||||
title: New File Organization
|
title: New File Organization
|
||||||
type: code
|
type: code
|
||||||
@@ -2990,7 +2990,7 @@ sections:
|
|||||||
title: Enhancement-Specific Standards
|
title: Enhancement-Specific Standards
|
||||||
condition: New patterns needed for enhancement
|
condition: New patterns needed for enhancement
|
||||||
repeatable: true
|
repeatable: true
|
||||||
template: '- **{{standard_name}}:** {{standard_description}}'
|
template: "- **{{standard_name}}:** {{standard_description}}"
|
||||||
- id: integration-rules
|
- id: integration-rules
|
||||||
title: Critical Integration Rules
|
title: Critical Integration Rules
|
||||||
template: |
|
template: |
|
||||||
|
|||||||
672
dist/agents/bmad-master.txt
vendored
672
dist/agents/bmad-master.txt
vendored
File diff suppressed because it is too large
Load Diff
80
dist/agents/pm.txt
vendored
80
dist/agents/pm.txt
vendored
@@ -1159,7 +1159,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/prd.md
|
filename: docs/prd.md
|
||||||
title: '{{project_name}} Product Requirements Document (PRD)'
|
title: "{{project_name}} Product Requirements Document (PRD)"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -1196,14 +1196,14 @@ sections:
|
|||||||
prefix: FR
|
prefix: FR
|
||||||
instruction: Each Requirement will be a bullet markdown and an identifier sequence starting with FR
|
instruction: Each Requirement will be a bullet markdown and an identifier sequence starting with FR
|
||||||
examples:
|
examples:
|
||||||
- 'FR6: The Todo List uses AI to detect and warn against potentially duplicate todo items that are worded differently.'
|
- "FR6: The Todo List uses AI to detect and warn against potentially duplicate todo items that are worded differently."
|
||||||
- id: non-functional
|
- id: non-functional
|
||||||
title: Non Functional
|
title: Non Functional
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
prefix: NFR
|
prefix: NFR
|
||||||
instruction: Each Requirement will be a bullet markdown and an identifier sequence starting with NFR
|
instruction: Each Requirement will be a bullet markdown and an identifier sequence starting with NFR
|
||||||
examples:
|
examples:
|
||||||
- 'NFR1: AWS service usage must aim to stay within free-tier limits where feasible.'
|
- "NFR1: AWS service usage must aim to stay within free-tier limits where feasible."
|
||||||
|
|
||||||
- id: ui-goals
|
- id: ui-goals
|
||||||
title: User Interface Design Goals
|
title: User Interface Design Goals
|
||||||
@@ -1229,24 +1229,24 @@ sections:
|
|||||||
title: Core Screens and Views
|
title: Core Screens and Views
|
||||||
instruction: From a product perspective, what are the most critical screens or views necessary to deliver the the PRD values and goals? This is meant to be Conceptual High Level to Drive Rough Epic or User Stories
|
instruction: From a product perspective, what are the most critical screens or views necessary to deliver the the PRD values and goals? This is meant to be Conceptual High Level to Drive Rough Epic or User Stories
|
||||||
examples:
|
examples:
|
||||||
- 'Login Screen'
|
- "Login Screen"
|
||||||
- 'Main Dashboard'
|
- "Main Dashboard"
|
||||||
- 'Item Detail Page'
|
- "Item Detail Page"
|
||||||
- 'Settings Page'
|
- "Settings Page"
|
||||||
- id: accessibility
|
- id: accessibility
|
||||||
title: 'Accessibility: {None|WCAG AA|WCAG AAA|Custom Requirements}'
|
title: "Accessibility: {None|WCAG AA|WCAG AAA|Custom Requirements}"
|
||||||
- id: branding
|
- id: branding
|
||||||
title: Branding
|
title: Branding
|
||||||
instruction: Any known branding elements or style guides that must be incorporated?
|
instruction: Any known branding elements or style guides that must be incorporated?
|
||||||
examples:
|
examples:
|
||||||
- 'Replicate the look and feel of early 1900s black and white cinema, including animated effects replicating film damage or projector glitches during page or state transitions.'
|
- "Replicate the look and feel of early 1900s black and white cinema, including animated effects replicating film damage or projector glitches during page or state transitions."
|
||||||
- 'Attached is the full color pallet and tokens for our corporate branding.'
|
- "Attached is the full color pallet and tokens for our corporate branding."
|
||||||
- id: target-platforms
|
- id: target-platforms
|
||||||
title: 'Target Device and Platforms: {Web Responsive|Mobile Only|Desktop Only|Cross-Platform}'
|
title: "Target Device and Platforms: {Web Responsive|Mobile Only|Desktop Only|Cross-Platform}"
|
||||||
examples:
|
examples:
|
||||||
- 'Web Responsive, and all mobile platforms'
|
- "Web Responsive, and all mobile platforms"
|
||||||
- 'iPhone Only'
|
- "iPhone Only"
|
||||||
- 'ASCII Windows Desktop'
|
- "ASCII Windows Desktop"
|
||||||
|
|
||||||
- id: technical-assumptions
|
- id: technical-assumptions
|
||||||
title: Technical Assumptions
|
title: Technical Assumptions
|
||||||
@@ -1265,13 +1265,13 @@ sections:
|
|||||||
testing: [Unit Only, Unit + Integration, Full Testing Pyramid]
|
testing: [Unit Only, Unit + Integration, Full Testing Pyramid]
|
||||||
sections:
|
sections:
|
||||||
- id: repository-structure
|
- id: repository-structure
|
||||||
title: 'Repository Structure: {Monorepo|Polyrepo|Multi-repo}'
|
title: "Repository Structure: {Monorepo|Polyrepo|Multi-repo}"
|
||||||
- id: service-architecture
|
- id: service-architecture
|
||||||
title: Service Architecture
|
title: Service Architecture
|
||||||
instruction: 'CRITICAL DECISION - Document the high-level service architecture (e.g., Monolith, Microservices, Serverless functions within a Monorepo).'
|
instruction: "CRITICAL DECISION - Document the high-level service architecture (e.g., Monolith, Microservices, Serverless functions within a Monorepo)."
|
||||||
- id: testing-requirements
|
- id: testing-requirements
|
||||||
title: Testing Requirements
|
title: Testing Requirements
|
||||||
instruction: 'CRITICAL DECISION - Document the testing requirements, unit only, integration, e2e, manual, need for manual testing convenience methods).'
|
instruction: "CRITICAL DECISION - Document the testing requirements, unit only, integration, e2e, manual, need for manual testing convenience methods)."
|
||||||
- id: additional-assumptions
|
- id: additional-assumptions
|
||||||
title: Additional Technical Assumptions and Requests
|
title: Additional Technical Assumptions and Requests
|
||||||
instruction: Throughout the entire process of drafting this document, if any other technical assumptions are raised or discovered appropriate for the architect, add them here as additional bulleted items
|
instruction: Throughout the entire process of drafting this document, if any other technical assumptions are raised or discovered appropriate for the architect, add them here as additional bulleted items
|
||||||
@@ -1291,10 +1291,10 @@ sections:
|
|||||||
- Cross Cutting Concerns should flow through epics and stories and not be final stories. For example, adding a logging framework as a last story of an epic, or at the end of a project as a final epic or story would be terrible as we would not have logging from the beginning.
|
- Cross Cutting Concerns should flow through epics and stories and not be final stories. For example, adding a logging framework as a last story of an epic, or at the end of a project as a final epic or story would be terrible as we would not have logging from the beginning.
|
||||||
elicit: true
|
elicit: true
|
||||||
examples:
|
examples:
|
||||||
- 'Epic 1: Foundation & Core Infrastructure: Establish project setup, authentication, and basic user management'
|
- "Epic 1: Foundation & Core Infrastructure: Establish project setup, authentication, and basic user management"
|
||||||
- 'Epic 2: Core Business Entities: Create and manage primary domain objects with CRUD operations'
|
- "Epic 2: Core Business Entities: Create and manage primary domain objects with CRUD operations"
|
||||||
- 'Epic 3: User Workflows & Interactions: Enable key user journeys and business processes'
|
- "Epic 3: User Workflows & Interactions: Enable key user journeys and business processes"
|
||||||
- 'Epic 4: Reporting & Analytics: Provide insights and data visualization for users'
|
- "Epic 4: Reporting & Analytics: Provide insights and data visualization for users"
|
||||||
|
|
||||||
- id: epic-details
|
- id: epic-details
|
||||||
title: Epic {{epic_number}} {{epic_title}}
|
title: Epic {{epic_number}} {{epic_title}}
|
||||||
@@ -1316,7 +1316,7 @@ sections:
|
|||||||
- Think "junior developer working for 2-4 hours" - stories must be small, focused, and self-contained
|
- Think "junior developer working for 2-4 hours" - stories must be small, focused, and self-contained
|
||||||
- If a story seems complex, break it down further as long as it can deliver a vertical slice
|
- If a story seems complex, break it down further as long as it can deliver a vertical slice
|
||||||
elicit: true
|
elicit: true
|
||||||
template: '{{epic_goal}}'
|
template: "{{epic_goal}}"
|
||||||
sections:
|
sections:
|
||||||
- id: story
|
- id: story
|
||||||
title: Story {{epic_number}}.{{story_number}} {{story_title}}
|
title: Story {{epic_number}}.{{story_number}} {{story_title}}
|
||||||
@@ -1329,7 +1329,7 @@ sections:
|
|||||||
- id: acceptance-criteria
|
- id: acceptance-criteria
|
||||||
title: Acceptance Criteria
|
title: Acceptance Criteria
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
item_template: '{{criterion_number}}: {{criteria}}'
|
item_template: "{{criterion_number}}: {{criteria}}"
|
||||||
repeatable: true
|
repeatable: true
|
||||||
instruction: |
|
instruction: |
|
||||||
Define clear, comprehensive, and testable acceptance criteria that:
|
Define clear, comprehensive, and testable acceptance criteria that:
|
||||||
@@ -1364,7 +1364,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/prd.md
|
filename: docs/prd.md
|
||||||
title: '{{project_name}} Brownfield Enhancement PRD'
|
title: "{{project_name}} Brownfield Enhancement PRD"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -1427,7 +1427,7 @@ sections:
|
|||||||
- External API Documentation [[LLM: If from document-project, check ✓]]
|
- External API Documentation [[LLM: If from document-project, check ✓]]
|
||||||
- UX/UI Guidelines [[LLM: May not be in document-project]]
|
- UX/UI Guidelines [[LLM: May not be in document-project]]
|
||||||
- Technical Debt Documentation [[LLM: If from document-project, check ✓]]
|
- Technical Debt Documentation [[LLM: If from document-project, check ✓]]
|
||||||
- 'Other: {{other_docs}}'
|
- "Other: {{other_docs}}"
|
||||||
instruction: |
|
instruction: |
|
||||||
- If document-project was already run: "Using existing project analysis from document-project output."
|
- If document-project was already run: "Using existing project analysis from document-project output."
|
||||||
- If critical documentation is missing and no document-project: "I recommend running the document-project task first..."
|
- If critical documentation is missing and no document-project: "I recommend running the document-project task first..."
|
||||||
@@ -1447,7 +1447,7 @@ sections:
|
|||||||
- UI/UX Overhaul
|
- UI/UX Overhaul
|
||||||
- Technology Stack Upgrade
|
- Technology Stack Upgrade
|
||||||
- Bug Fix and Stability Improvements
|
- Bug Fix and Stability Improvements
|
||||||
- 'Other: {{other_type}}'
|
- "Other: {{other_type}}"
|
||||||
- id: enhancement-description
|
- id: enhancement-description
|
||||||
title: Enhancement Description
|
title: Enhancement Description
|
||||||
instruction: 2-3 sentences describing what the user wants to add or change
|
instruction: 2-3 sentences describing what the user wants to add or change
|
||||||
@@ -1488,29 +1488,29 @@ sections:
|
|||||||
prefix: FR
|
prefix: FR
|
||||||
instruction: Each Requirement will be a bullet markdown with identifier starting with FR
|
instruction: Each Requirement will be a bullet markdown with identifier starting with FR
|
||||||
examples:
|
examples:
|
||||||
- 'FR1: The existing Todo List will integrate with the new AI duplicate detection service without breaking current functionality.'
|
- "FR1: The existing Todo List will integrate with the new AI duplicate detection service without breaking current functionality."
|
||||||
- id: non-functional
|
- id: non-functional
|
||||||
title: Non Functional
|
title: Non Functional
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
prefix: NFR
|
prefix: NFR
|
||||||
instruction: Each Requirement will be a bullet markdown with identifier starting with NFR. Include constraints from existing system
|
instruction: Each Requirement will be a bullet markdown with identifier starting with NFR. Include constraints from existing system
|
||||||
examples:
|
examples:
|
||||||
- 'NFR1: Enhancement must maintain existing performance characteristics and not exceed current memory usage by more than 20%.'
|
- "NFR1: Enhancement must maintain existing performance characteristics and not exceed current memory usage by more than 20%."
|
||||||
- id: compatibility
|
- id: compatibility
|
||||||
title: Compatibility Requirements
|
title: Compatibility Requirements
|
||||||
instruction: Critical for brownfield - what must remain compatible
|
instruction: Critical for brownfield - what must remain compatible
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
prefix: CR
|
prefix: CR
|
||||||
template: '{{requirement}}: {{description}}'
|
template: "{{requirement}}: {{description}}"
|
||||||
items:
|
items:
|
||||||
- id: cr1
|
- id: cr1
|
||||||
template: 'CR1: {{existing_api_compatibility}}'
|
template: "CR1: {{existing_api_compatibility}}"
|
||||||
- id: cr2
|
- id: cr2
|
||||||
template: 'CR2: {{database_schema_compatibility}}'
|
template: "CR2: {{database_schema_compatibility}}"
|
||||||
- id: cr3
|
- id: cr3
|
||||||
template: 'CR3: {{ui_ux_consistency}}'
|
template: "CR3: {{ui_ux_consistency}}"
|
||||||
- id: cr4
|
- id: cr4
|
||||||
template: 'CR4: {{integration_compatibility}}'
|
template: "CR4: {{integration_compatibility}}"
|
||||||
|
|
||||||
- id: ui-enhancement-goals
|
- id: ui-enhancement-goals
|
||||||
title: User Interface Enhancement Goals
|
title: User Interface Enhancement Goals
|
||||||
@@ -1593,10 +1593,10 @@ sections:
|
|||||||
- id: epic-approach
|
- id: epic-approach
|
||||||
title: Epic Approach
|
title: Epic Approach
|
||||||
instruction: Explain the rationale for epic structure - typically single epic for brownfield unless multiple unrelated features
|
instruction: Explain the rationale for epic structure - typically single epic for brownfield unless multiple unrelated features
|
||||||
template: '**Epic Structure Decision**: {{epic_decision}} with rationale'
|
template: "**Epic Structure Decision**: {{epic_decision}} with rationale"
|
||||||
|
|
||||||
- id: epic-details
|
- id: epic-details
|
||||||
title: 'Epic 1: {{enhancement_title}}'
|
title: "Epic 1: {{enhancement_title}}"
|
||||||
instruction: |
|
instruction: |
|
||||||
Comprehensive epic that delivers the brownfield enhancement while maintaining existing functionality
|
Comprehensive epic that delivers the brownfield enhancement while maintaining existing functionality
|
||||||
|
|
||||||
@@ -1616,7 +1616,7 @@ sections:
|
|||||||
**Integration Requirements**: {{integration_requirements}}
|
**Integration Requirements**: {{integration_requirements}}
|
||||||
sections:
|
sections:
|
||||||
- id: story
|
- id: story
|
||||||
title: 'Story 1.{{story_number}} {{story_title}}'
|
title: "Story 1.{{story_number}} {{story_title}}"
|
||||||
repeatable: true
|
repeatable: true
|
||||||
template: |
|
template: |
|
||||||
As a {{user_type}},
|
As a {{user_type}},
|
||||||
@@ -1627,16 +1627,16 @@ sections:
|
|||||||
title: Acceptance Criteria
|
title: Acceptance Criteria
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
instruction: Define criteria that include both new functionality and existing system integrity
|
instruction: Define criteria that include both new functionality and existing system integrity
|
||||||
item_template: '{{criterion_number}}: {{criteria}}'
|
item_template: "{{criterion_number}}: {{criteria}}"
|
||||||
- id: integration-verification
|
- id: integration-verification
|
||||||
title: Integration Verification
|
title: Integration Verification
|
||||||
instruction: Specific verification steps to ensure existing functionality remains intact
|
instruction: Specific verification steps to ensure existing functionality remains intact
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
prefix: IV
|
prefix: IV
|
||||||
items:
|
items:
|
||||||
- template: 'IV1: {{existing_functionality_verification}}'
|
- template: "IV1: {{existing_functionality_verification}}"
|
||||||
- template: 'IV2: {{integration_point_verification}}'
|
- template: "IV2: {{integration_point_verification}}"
|
||||||
- template: 'IV3: {{performance_impact_verification}}'
|
- template: "IV3: {{performance_impact_verification}}"
|
||||||
==================== END: .bmad-core/templates/brownfield-prd-tmpl.yaml ====================
|
==================== END: .bmad-core/templates/brownfield-prd-tmpl.yaml ====================
|
||||||
|
|
||||||
==================== START: .bmad-core/checklists/pm-checklist.md ====================
|
==================== START: .bmad-core/checklists/pm-checklist.md ====================
|
||||||
|
|||||||
4
dist/agents/po.txt
vendored
4
dist/agents/po.txt
vendored
@@ -593,7 +593,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/stories/{{epic_num}}.{{story_num}}.{{story_title_short}}.md
|
filename: docs/stories/{{epic_num}}.{{story_num}}.{{story_title_short}}.md
|
||||||
title: 'Story {{epic_num}}.{{story_num}}: {{story_title_short}}'
|
title: "Story {{epic_num}}.{{story_num}}: {{story_title_short}}"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -695,7 +695,7 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: agent-model
|
- id: agent-model
|
||||||
title: Agent Model Used
|
title: Agent Model Used
|
||||||
template: '{{agent_model_name_version}}'
|
template: "{{agent_model_name_version}}"
|
||||||
instruction: Record the specific AI agent model and version used for development
|
instruction: Record the specific AI agent model and version used for development
|
||||||
owner: dev-agent
|
owner: dev-agent
|
||||||
editors: [dev-agent]
|
editors: [dev-agent]
|
||||||
|
|||||||
18
dist/agents/qa.txt
vendored
18
dist/agents/qa.txt
vendored
@@ -1743,7 +1743,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/stories/{{epic_num}}.{{story_num}}.{{story_title_short}}.md
|
filename: docs/stories/{{epic_num}}.{{story_num}}.{{story_title_short}}.md
|
||||||
title: 'Story {{epic_num}}.{{story_num}}: {{story_title_short}}'
|
title: "Story {{epic_num}}.{{story_num}}: {{story_title_short}}"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -1845,7 +1845,7 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: agent-model
|
- id: agent-model
|
||||||
title: Agent Model Used
|
title: Agent Model Used
|
||||||
template: '{{agent_model_name_version}}'
|
template: "{{agent_model_name_version}}"
|
||||||
instruction: Record the specific AI agent model and version used for development
|
instruction: Record the specific AI agent model and version used for development
|
||||||
owner: dev-agent
|
owner: dev-agent
|
||||||
editors: [dev-agent]
|
editors: [dev-agent]
|
||||||
@@ -1883,16 +1883,16 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: yaml
|
format: yaml
|
||||||
filename: docs/qa/gates/{{epic_num}}.{{story_num}}-{{story_slug}}.yml
|
filename: docs/qa/gates/{{epic_num}}.{{story_num}}-{{story_slug}}.yml
|
||||||
title: 'Quality Gate: {{epic_num}}.{{story_num}}'
|
title: "Quality Gate: {{epic_num}}.{{story_num}}"
|
||||||
|
|
||||||
# Required fields (keep these first)
|
# Required fields (keep these first)
|
||||||
schema: 1
|
schema: 1
|
||||||
story: '{{epic_num}}.{{story_num}}'
|
story: "{{epic_num}}.{{story_num}}"
|
||||||
story_title: '{{story_title}}'
|
story_title: "{{story_title}}"
|
||||||
gate: '{{gate_status}}' # PASS|CONCERNS|FAIL|WAIVED
|
gate: "{{gate_status}}" # PASS|CONCERNS|FAIL|WAIVED
|
||||||
status_reason: '{{status_reason}}' # 1-2 sentence summary of why this gate decision
|
status_reason: "{{status_reason}}" # 1-2 sentence summary of why this gate decision
|
||||||
reviewer: 'Quinn (Test Architect)'
|
reviewer: "Quinn (Test Architect)"
|
||||||
updated: '{{iso_timestamp}}'
|
updated: "{{iso_timestamp}}"
|
||||||
|
|
||||||
# Always present but only active when WAIVED
|
# Always present but only active when WAIVED
|
||||||
waiver: { active: false }
|
waiver: { active: false }
|
||||||
|
|||||||
4
dist/agents/sm.txt
vendored
4
dist/agents/sm.txt
vendored
@@ -369,7 +369,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/stories/{{epic_num}}.{{story_num}}.{{story_title_short}}.md
|
filename: docs/stories/{{epic_num}}.{{story_num}}.{{story_title_short}}.md
|
||||||
title: 'Story {{epic_num}}.{{story_num}}: {{story_title_short}}'
|
title: "Story {{epic_num}}.{{story_num}}: {{story_title_short}}"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -471,7 +471,7 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: agent-model
|
- id: agent-model
|
||||||
title: Agent Model Used
|
title: Agent Model Used
|
||||||
template: '{{agent_model_name_version}}'
|
template: "{{agent_model_name_version}}"
|
||||||
instruction: Record the specific AI agent model and version used for development
|
instruction: Record the specific AI agent model and version used for development
|
||||||
owner: dev-agent
|
owner: dev-agent
|
||||||
editors: [dev-agent]
|
editors: [dev-agent]
|
||||||
|
|||||||
114
dist/agents/ux-expert.txt
vendored
114
dist/agents/ux-expert.txt
vendored
@@ -343,7 +343,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/front-end-spec.md
|
filename: docs/front-end-spec.md
|
||||||
title: '{{project_name}} UI/UX Specification'
|
title: "{{project_name}} UI/UX Specification"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -371,29 +371,29 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: user-personas
|
- id: user-personas
|
||||||
title: Target User Personas
|
title: Target User Personas
|
||||||
template: '{{persona_descriptions}}'
|
template: "{{persona_descriptions}}"
|
||||||
examples:
|
examples:
|
||||||
- '**Power User:** Technical professionals who need advanced features and efficiency'
|
- "**Power User:** Technical professionals who need advanced features and efficiency"
|
||||||
- '**Casual User:** Occasional users who prioritize ease of use and clear guidance'
|
- "**Casual User:** Occasional users who prioritize ease of use and clear guidance"
|
||||||
- '**Administrator:** System managers who need control and oversight capabilities'
|
- "**Administrator:** System managers who need control and oversight capabilities"
|
||||||
- id: usability-goals
|
- id: usability-goals
|
||||||
title: Usability Goals
|
title: Usability Goals
|
||||||
template: '{{usability_goals}}'
|
template: "{{usability_goals}}"
|
||||||
examples:
|
examples:
|
||||||
- 'Ease of learning: New users can complete core tasks within 5 minutes'
|
- "Ease of learning: New users can complete core tasks within 5 minutes"
|
||||||
- 'Efficiency of use: Power users can complete frequent tasks with minimal clicks'
|
- "Efficiency of use: Power users can complete frequent tasks with minimal clicks"
|
||||||
- 'Error prevention: Clear validation and confirmation for destructive actions'
|
- "Error prevention: Clear validation and confirmation for destructive actions"
|
||||||
- 'Memorability: Infrequent users can return without relearning'
|
- "Memorability: Infrequent users can return without relearning"
|
||||||
- id: design-principles
|
- id: design-principles
|
||||||
title: Design Principles
|
title: Design Principles
|
||||||
template: '{{design_principles}}'
|
template: "{{design_principles}}"
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
examples:
|
examples:
|
||||||
- '**Clarity over cleverness** - Prioritize clear communication over aesthetic innovation'
|
- "**Clarity over cleverness** - Prioritize clear communication over aesthetic innovation"
|
||||||
- "**Progressive disclosure** - Show only what's needed, when it's needed"
|
- "**Progressive disclosure** - Show only what's needed, when it's needed"
|
||||||
- '**Consistent patterns** - Use familiar UI patterns throughout the application'
|
- "**Consistent patterns** - Use familiar UI patterns throughout the application"
|
||||||
- '**Immediate feedback** - Every action should have a clear, immediate response'
|
- "**Immediate feedback** - Every action should have a clear, immediate response"
|
||||||
- '**Accessible by default** - Design for all users from the start'
|
- "**Accessible by default** - Design for all users from the start"
|
||||||
- id: changelog
|
- id: changelog
|
||||||
title: Change Log
|
title: Change Log
|
||||||
type: table
|
type: table
|
||||||
@@ -415,7 +415,7 @@ sections:
|
|||||||
title: Site Map / Screen Inventory
|
title: Site Map / Screen Inventory
|
||||||
type: mermaid
|
type: mermaid
|
||||||
mermaid_type: graph
|
mermaid_type: graph
|
||||||
template: '{{sitemap_diagram}}'
|
template: "{{sitemap_diagram}}"
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
graph TD
|
graph TD
|
||||||
@@ -455,7 +455,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: flow
|
- id: flow
|
||||||
title: '{{flow_name}}'
|
title: "{{flow_name}}"
|
||||||
template: |
|
template: |
|
||||||
**User Goal:** {{flow_goal}}
|
**User Goal:** {{flow_goal}}
|
||||||
|
|
||||||
@@ -467,13 +467,13 @@ sections:
|
|||||||
title: Flow Diagram
|
title: Flow Diagram
|
||||||
type: mermaid
|
type: mermaid
|
||||||
mermaid_type: graph
|
mermaid_type: graph
|
||||||
template: '{{flow_diagram}}'
|
template: "{{flow_diagram}}"
|
||||||
- id: edge-cases
|
- id: edge-cases
|
||||||
title: 'Edge Cases & Error Handling:'
|
title: "Edge Cases & Error Handling:"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '- {{edge_case}}'
|
template: "- {{edge_case}}"
|
||||||
- id: notes
|
- id: notes
|
||||||
template: '**Notes:** {{flow_notes}}'
|
template: "**Notes:** {{flow_notes}}"
|
||||||
|
|
||||||
- id: wireframes-mockups
|
- id: wireframes-mockups
|
||||||
title: Wireframes & Mockups
|
title: Wireframes & Mockups
|
||||||
@@ -482,13 +482,13 @@ sections:
|
|||||||
elicit: true
|
elicit: true
|
||||||
sections:
|
sections:
|
||||||
- id: design-files
|
- id: design-files
|
||||||
template: '**Primary Design Files:** {{design_tool_link}}'
|
template: "**Primary Design Files:** {{design_tool_link}}"
|
||||||
- id: key-screen-layouts
|
- id: key-screen-layouts
|
||||||
title: Key Screen Layouts
|
title: Key Screen Layouts
|
||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: screen
|
- id: screen
|
||||||
title: '{{screen_name}}'
|
title: "{{screen_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Purpose:** {{screen_purpose}}
|
**Purpose:** {{screen_purpose}}
|
||||||
|
|
||||||
@@ -508,13 +508,13 @@ sections:
|
|||||||
elicit: true
|
elicit: true
|
||||||
sections:
|
sections:
|
||||||
- id: design-system-approach
|
- id: design-system-approach
|
||||||
template: '**Design System Approach:** {{design_system_approach}}'
|
template: "**Design System Approach:** {{design_system_approach}}"
|
||||||
- id: core-components
|
- id: core-components
|
||||||
title: Core Components
|
title: Core Components
|
||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: component
|
- id: component
|
||||||
title: '{{component_name}}'
|
title: "{{component_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Purpose:** {{component_purpose}}
|
**Purpose:** {{component_purpose}}
|
||||||
|
|
||||||
@@ -531,19 +531,19 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: visual-identity
|
- id: visual-identity
|
||||||
title: Visual Identity
|
title: Visual Identity
|
||||||
template: '**Brand Guidelines:** {{brand_guidelines_link}}'
|
template: "**Brand Guidelines:** {{brand_guidelines_link}}"
|
||||||
- id: color-palette
|
- id: color-palette
|
||||||
title: Color Palette
|
title: Color Palette
|
||||||
type: table
|
type: table
|
||||||
columns: ['Color Type', 'Hex Code', 'Usage']
|
columns: ["Color Type", "Hex Code", "Usage"]
|
||||||
rows:
|
rows:
|
||||||
- ['Primary', '{{primary_color}}', '{{primary_usage}}']
|
- ["Primary", "{{primary_color}}", "{{primary_usage}}"]
|
||||||
- ['Secondary', '{{secondary_color}}', '{{secondary_usage}}']
|
- ["Secondary", "{{secondary_color}}", "{{secondary_usage}}"]
|
||||||
- ['Accent', '{{accent_color}}', '{{accent_usage}}']
|
- ["Accent", "{{accent_color}}", "{{accent_usage}}"]
|
||||||
- ['Success', '{{success_color}}', 'Positive feedback, confirmations']
|
- ["Success", "{{success_color}}", "Positive feedback, confirmations"]
|
||||||
- ['Warning', '{{warning_color}}', 'Cautions, important notices']
|
- ["Warning", "{{warning_color}}", "Cautions, important notices"]
|
||||||
- ['Error', '{{error_color}}', 'Errors, destructive actions']
|
- ["Error", "{{error_color}}", "Errors, destructive actions"]
|
||||||
- ['Neutral', '{{neutral_colors}}', 'Text, borders, backgrounds']
|
- ["Neutral", "{{neutral_colors}}", "Text, borders, backgrounds"]
|
||||||
- id: typography
|
- id: typography
|
||||||
title: Typography
|
title: Typography
|
||||||
sections:
|
sections:
|
||||||
@@ -556,13 +556,13 @@ sections:
|
|||||||
- id: type-scale
|
- id: type-scale
|
||||||
title: Type Scale
|
title: Type Scale
|
||||||
type: table
|
type: table
|
||||||
columns: ['Element', 'Size', 'Weight', 'Line Height']
|
columns: ["Element", "Size", "Weight", "Line Height"]
|
||||||
rows:
|
rows:
|
||||||
- ['H1', '{{h1_size}}', '{{h1_weight}}', '{{h1_line}}']
|
- ["H1", "{{h1_size}}", "{{h1_weight}}", "{{h1_line}}"]
|
||||||
- ['H2', '{{h2_size}}', '{{h2_weight}}', '{{h2_line}}']
|
- ["H2", "{{h2_size}}", "{{h2_weight}}", "{{h2_line}}"]
|
||||||
- ['H3', '{{h3_size}}', '{{h3_weight}}', '{{h3_line}}']
|
- ["H3", "{{h3_size}}", "{{h3_weight}}", "{{h3_line}}"]
|
||||||
- ['Body', '{{body_size}}', '{{body_weight}}', '{{body_line}}']
|
- ["Body", "{{body_size}}", "{{body_weight}}", "{{body_line}}"]
|
||||||
- ['Small', '{{small_size}}', '{{small_weight}}', '{{small_line}}']
|
- ["Small", "{{small_size}}", "{{small_weight}}", "{{small_line}}"]
|
||||||
- id: iconography
|
- id: iconography
|
||||||
title: Iconography
|
title: Iconography
|
||||||
template: |
|
template: |
|
||||||
@@ -583,7 +583,7 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: compliance-target
|
- id: compliance-target
|
||||||
title: Compliance Target
|
title: Compliance Target
|
||||||
template: '**Standard:** {{compliance_standard}}'
|
template: "**Standard:** {{compliance_standard}}"
|
||||||
- id: key-requirements
|
- id: key-requirements
|
||||||
title: Key Requirements
|
title: Key Requirements
|
||||||
template: |
|
template: |
|
||||||
@@ -603,7 +603,7 @@ sections:
|
|||||||
- Form labels: {{form_requirements}}
|
- Form labels: {{form_requirements}}
|
||||||
- id: testing-strategy
|
- id: testing-strategy
|
||||||
title: Testing Strategy
|
title: Testing Strategy
|
||||||
template: '{{accessibility_testing}}'
|
template: "{{accessibility_testing}}"
|
||||||
|
|
||||||
- id: responsiveness
|
- id: responsiveness
|
||||||
title: Responsiveness Strategy
|
title: Responsiveness Strategy
|
||||||
@@ -613,12 +613,12 @@ sections:
|
|||||||
- id: breakpoints
|
- id: breakpoints
|
||||||
title: Breakpoints
|
title: Breakpoints
|
||||||
type: table
|
type: table
|
||||||
columns: ['Breakpoint', 'Min Width', 'Max Width', 'Target Devices']
|
columns: ["Breakpoint", "Min Width", "Max Width", "Target Devices"]
|
||||||
rows:
|
rows:
|
||||||
- ['Mobile', '{{mobile_min}}', '{{mobile_max}}', '{{mobile_devices}}']
|
- ["Mobile", "{{mobile_min}}", "{{mobile_max}}", "{{mobile_devices}}"]
|
||||||
- ['Tablet', '{{tablet_min}}', '{{tablet_max}}', '{{tablet_devices}}']
|
- ["Tablet", "{{tablet_min}}", "{{tablet_max}}", "{{tablet_devices}}"]
|
||||||
- ['Desktop', '{{desktop_min}}', '{{desktop_max}}', '{{desktop_devices}}']
|
- ["Desktop", "{{desktop_min}}", "{{desktop_max}}", "{{desktop_devices}}"]
|
||||||
- ['Wide', '{{wide_min}}', '-', '{{wide_devices}}']
|
- ["Wide", "{{wide_min}}", "-", "{{wide_devices}}"]
|
||||||
- id: adaptation-patterns
|
- id: adaptation-patterns
|
||||||
title: Adaptation Patterns
|
title: Adaptation Patterns
|
||||||
template: |
|
template: |
|
||||||
@@ -637,11 +637,11 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: motion-principles
|
- id: motion-principles
|
||||||
title: Motion Principles
|
title: Motion Principles
|
||||||
template: '{{motion_principles}}'
|
template: "{{motion_principles}}"
|
||||||
- id: key-animations
|
- id: key-animations
|
||||||
title: Key Animations
|
title: Key Animations
|
||||||
repeatable: true
|
repeatable: true
|
||||||
template: '- **{{animation_name}}:** {{animation_description}} (Duration: {{duration}}, Easing: {{easing}})'
|
template: "- **{{animation_name}}:** {{animation_description}} (Duration: {{duration}}, Easing: {{easing}})"
|
||||||
|
|
||||||
- id: performance
|
- id: performance
|
||||||
title: Performance Considerations
|
title: Performance Considerations
|
||||||
@@ -655,7 +655,7 @@ sections:
|
|||||||
- **Animation FPS:** {{animation_goal}}
|
- **Animation FPS:** {{animation_goal}}
|
||||||
- id: design-strategies
|
- id: design-strategies
|
||||||
title: Design Strategies
|
title: Design Strategies
|
||||||
template: '{{performance_strategies}}'
|
template: "{{performance_strategies}}"
|
||||||
|
|
||||||
- id: next-steps
|
- id: next-steps
|
||||||
title: Next Steps
|
title: Next Steps
|
||||||
@@ -670,17 +670,17 @@ sections:
|
|||||||
- id: immediate-actions
|
- id: immediate-actions
|
||||||
title: Immediate Actions
|
title: Immediate Actions
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
template: '{{action}}'
|
template: "{{action}}"
|
||||||
- id: design-handoff-checklist
|
- id: design-handoff-checklist
|
||||||
title: Design Handoff Checklist
|
title: Design Handoff Checklist
|
||||||
type: checklist
|
type: checklist
|
||||||
items:
|
items:
|
||||||
- 'All user flows documented'
|
- "All user flows documented"
|
||||||
- 'Component inventory complete'
|
- "Component inventory complete"
|
||||||
- 'Accessibility requirements defined'
|
- "Accessibility requirements defined"
|
||||||
- 'Responsive strategy clear'
|
- "Responsive strategy clear"
|
||||||
- 'Brand guidelines incorporated'
|
- "Brand guidelines incorporated"
|
||||||
- 'Performance goals established'
|
- "Performance goals established"
|
||||||
|
|
||||||
- id: checklist-results
|
- id: checklist-results
|
||||||
title: Checklist Results
|
title: Checklist Results
|
||||||
|
|||||||
@@ -981,8 +981,8 @@ template:
|
|||||||
version: 2.0
|
version: 2.0
|
||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: 'docs/{{game_name}}-game-design-document.md'
|
filename: "docs/{{game_name}}-game-design-document.md"
|
||||||
title: '{{game_title}} Game Design Document (GDD)'
|
title: "{{game_title}} Game Design Document (GDD)"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -1019,7 +1019,7 @@ sections:
|
|||||||
title: Unique Selling Points
|
title: Unique Selling Points
|
||||||
instruction: List 3-5 key features that differentiate this game from competitors
|
instruction: List 3-5 key features that differentiate this game from competitors
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
template: '{{usp}}'
|
template: "{{usp}}"
|
||||||
|
|
||||||
- id: core-gameplay
|
- id: core-gameplay
|
||||||
title: Core Gameplay
|
title: Core Gameplay
|
||||||
@@ -1064,7 +1064,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: mechanic
|
- id: mechanic
|
||||||
title: '{{mechanic_name}}'
|
title: "{{mechanic_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Description:** {{detailed_description}}
|
**Description:** {{detailed_description}}
|
||||||
|
|
||||||
@@ -1129,7 +1129,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: level-type
|
- id: level-type
|
||||||
title: '{{level_type_name}}'
|
title: "{{level_type_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Purpose:** {{gameplay_purpose}}
|
**Purpose:** {{gameplay_purpose}}
|
||||||
**Duration:** {{target_time}}
|
**Duration:** {{target_time}}
|
||||||
@@ -1230,10 +1230,10 @@ sections:
|
|||||||
instruction: Break down the development into phases that can be converted to epics
|
instruction: Break down the development into phases that can be converted to epics
|
||||||
sections:
|
sections:
|
||||||
- id: phase-1-core-systems
|
- id: phase-1-core-systems
|
||||||
title: 'Phase 1: Core Systems ({{duration}})'
|
title: "Phase 1: Core Systems ({{duration}})"
|
||||||
sections:
|
sections:
|
||||||
- id: foundation-epic
|
- id: foundation-epic
|
||||||
title: 'Epic: Foundation'
|
title: "Epic: Foundation"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Engine setup and configuration
|
- Engine setup and configuration
|
||||||
@@ -1241,41 +1241,41 @@ sections:
|
|||||||
- Core input handling
|
- Core input handling
|
||||||
- Asset loading pipeline
|
- Asset loading pipeline
|
||||||
- id: core-mechanics-epic
|
- id: core-mechanics-epic
|
||||||
title: 'Epic: Core Mechanics'
|
title: "Epic: Core Mechanics"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- {{primary_mechanic}} implementation
|
- {{primary_mechanic}} implementation
|
||||||
- Basic physics and collision
|
- Basic physics and collision
|
||||||
- Player controller
|
- Player controller
|
||||||
- id: phase-2-gameplay-features
|
- id: phase-2-gameplay-features
|
||||||
title: 'Phase 2: Gameplay Features ({{duration}})'
|
title: "Phase 2: Gameplay Features ({{duration}})"
|
||||||
sections:
|
sections:
|
||||||
- id: game-systems-epic
|
- id: game-systems-epic
|
||||||
title: 'Epic: Game Systems'
|
title: "Epic: Game Systems"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- {{mechanic_2}} implementation
|
- {{mechanic_2}} implementation
|
||||||
- {{mechanic_3}} implementation
|
- {{mechanic_3}} implementation
|
||||||
- Game state management
|
- Game state management
|
||||||
- id: content-creation-epic
|
- id: content-creation-epic
|
||||||
title: 'Epic: Content Creation'
|
title: "Epic: Content Creation"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Level loading system
|
- Level loading system
|
||||||
- First playable levels
|
- First playable levels
|
||||||
- Basic UI implementation
|
- Basic UI implementation
|
||||||
- id: phase-3-polish-optimization
|
- id: phase-3-polish-optimization
|
||||||
title: 'Phase 3: Polish & Optimization ({{duration}})'
|
title: "Phase 3: Polish & Optimization ({{duration}})"
|
||||||
sections:
|
sections:
|
||||||
- id: performance-epic
|
- id: performance-epic
|
||||||
title: 'Epic: Performance'
|
title: "Epic: Performance"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Optimization and profiling
|
- Optimization and profiling
|
||||||
- Mobile platform testing
|
- Mobile platform testing
|
||||||
- Memory management
|
- Memory management
|
||||||
- id: user-experience-epic
|
- id: user-experience-epic
|
||||||
title: 'Epic: User Experience'
|
title: "Epic: User Experience"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Audio implementation
|
- Audio implementation
|
||||||
@@ -1317,7 +1317,7 @@ sections:
|
|||||||
title: References
|
title: References
|
||||||
instruction: List any competitive analysis, inspiration, or research sources
|
instruction: List any competitive analysis, inspiration, or research sources
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: '{{reference}}'
|
template: "{{reference}}"
|
||||||
==================== END: .bmad-2d-phaser-game-dev/templates/game-design-doc-tmpl.yaml ====================
|
==================== END: .bmad-2d-phaser-game-dev/templates/game-design-doc-tmpl.yaml ====================
|
||||||
|
|
||||||
==================== START: .bmad-2d-phaser-game-dev/templates/level-design-doc-tmpl.yaml ====================
|
==================== START: .bmad-2d-phaser-game-dev/templates/level-design-doc-tmpl.yaml ====================
|
||||||
@@ -1327,8 +1327,8 @@ template:
|
|||||||
version: 2.0
|
version: 2.0
|
||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: 'docs/{{game_name}}-level-design-document.md'
|
filename: "docs/{{game_name}}-level-design-document.md"
|
||||||
title: '{{game_title}} Level Design Document'
|
title: "{{game_title}} Level Design Document"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -1389,7 +1389,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: level-category
|
- id: level-category
|
||||||
title: '{{category_name}} Levels'
|
title: "{{category_name}} Levels"
|
||||||
template: |
|
template: |
|
||||||
**Purpose:** {{gameplay_purpose}}
|
**Purpose:** {{gameplay_purpose}}
|
||||||
|
|
||||||
@@ -1694,19 +1694,19 @@ sections:
|
|||||||
title: Playtesting Checklist
|
title: Playtesting Checklist
|
||||||
type: checklist
|
type: checklist
|
||||||
items:
|
items:
|
||||||
- 'Level completes within target time range'
|
- "Level completes within target time range"
|
||||||
- 'All mechanics function correctly'
|
- "All mechanics function correctly"
|
||||||
- 'Difficulty feels appropriate for level category'
|
- "Difficulty feels appropriate for level category"
|
||||||
- 'Player guidance is clear and effective'
|
- "Player guidance is clear and effective"
|
||||||
- 'No exploits or sequence breaks (unless intended)'
|
- "No exploits or sequence breaks (unless intended)"
|
||||||
- id: player-experience-testing
|
- id: player-experience-testing
|
||||||
title: Player Experience Testing
|
title: Player Experience Testing
|
||||||
type: checklist
|
type: checklist
|
||||||
items:
|
items:
|
||||||
- 'Tutorial levels teach effectively'
|
- "Tutorial levels teach effectively"
|
||||||
- 'Challenge feels fair and rewarding'
|
- "Challenge feels fair and rewarding"
|
||||||
- 'Flow and pacing maintain engagement'
|
- "Flow and pacing maintain engagement"
|
||||||
- 'Audio and visual feedback support gameplay'
|
- "Audio and visual feedback support gameplay"
|
||||||
- id: balance-validation
|
- id: balance-validation
|
||||||
title: Balance Validation
|
title: Balance Validation
|
||||||
template: |
|
template: |
|
||||||
@@ -1814,8 +1814,8 @@ template:
|
|||||||
version: 2.0
|
version: 2.0
|
||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: 'docs/{{game_name}}-game-brief.md'
|
filename: "docs/{{game_name}}-game-brief.md"
|
||||||
title: '{{game_title}} Game Brief'
|
title: "{{game_title}} Game Brief"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -2101,21 +2101,21 @@ sections:
|
|||||||
title: Development Roadmap
|
title: Development Roadmap
|
||||||
sections:
|
sections:
|
||||||
- id: phase-1-preproduction
|
- id: phase-1-preproduction
|
||||||
title: 'Phase 1: Pre-Production ({{duration}})'
|
title: "Phase 1: Pre-Production ({{duration}})"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Detailed Game Design Document creation
|
- Detailed Game Design Document creation
|
||||||
- Technical architecture planning
|
- Technical architecture planning
|
||||||
- Art style exploration and pipeline setup
|
- Art style exploration and pipeline setup
|
||||||
- id: phase-2-prototype
|
- id: phase-2-prototype
|
||||||
title: 'Phase 2: Prototype ({{duration}})'
|
title: "Phase 2: Prototype ({{duration}})"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Core mechanic implementation
|
- Core mechanic implementation
|
||||||
- Technical proof of concept
|
- Technical proof of concept
|
||||||
- Initial playtesting and iteration
|
- Initial playtesting and iteration
|
||||||
- id: phase-3-production
|
- id: phase-3-production
|
||||||
title: 'Phase 3: Production ({{duration}})'
|
title: "Phase 3: Production ({{duration}})"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Full feature development
|
- Full feature development
|
||||||
|
|||||||
@@ -197,8 +197,8 @@ template:
|
|||||||
version: 2.0
|
version: 2.0
|
||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: 'docs/{{game_name}}-game-architecture.md'
|
filename: "docs/{{game_name}}-game-architecture.md"
|
||||||
title: '{{game_title}} Game Architecture Document'
|
title: "{{game_title}} Game Architecture Document"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -422,7 +422,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: mechanic-system
|
- id: mechanic-system
|
||||||
title: '{{mechanic_name}} System'
|
title: "{{mechanic_name}} System"
|
||||||
template: |
|
template: |
|
||||||
**Purpose:** {{system_purpose}}
|
**Purpose:** {{system_purpose}}
|
||||||
|
|
||||||
@@ -719,7 +719,7 @@ sections:
|
|||||||
instruction: Break down the architecture implementation into phases that align with the GDD development phases
|
instruction: Break down the architecture implementation into phases that align with the GDD development phases
|
||||||
sections:
|
sections:
|
||||||
- id: phase-1-foundation
|
- id: phase-1-foundation
|
||||||
title: 'Phase 1: Foundation ({{duration}})'
|
title: "Phase 1: Foundation ({{duration}})"
|
||||||
sections:
|
sections:
|
||||||
- id: phase-1-core
|
- id: phase-1-core
|
||||||
title: Core Systems
|
title: Core Systems
|
||||||
@@ -737,7 +737,7 @@ sections:
|
|||||||
- "Basic Scene Management System"
|
- "Basic Scene Management System"
|
||||||
- "Asset Loading Foundation"
|
- "Asset Loading Foundation"
|
||||||
- id: phase-2-game-systems
|
- id: phase-2-game-systems
|
||||||
title: 'Phase 2: Game Systems ({{duration}})'
|
title: "Phase 2: Game Systems ({{duration}})"
|
||||||
sections:
|
sections:
|
||||||
- id: phase-2-gameplay
|
- id: phase-2-gameplay
|
||||||
title: Gameplay Systems
|
title: Gameplay Systems
|
||||||
@@ -755,7 +755,7 @@ sections:
|
|||||||
- "Physics and Collision Framework"
|
- "Physics and Collision Framework"
|
||||||
- "Game State Management System"
|
- "Game State Management System"
|
||||||
- id: phase-3-content-polish
|
- id: phase-3-content-polish
|
||||||
title: 'Phase 3: Content & Polish ({{duration}})'
|
title: "Phase 3: Content & Polish ({{duration}})"
|
||||||
sections:
|
sections:
|
||||||
- id: phase-3-content
|
- id: phase-3-content
|
||||||
title: Content Systems
|
title: Content Systems
|
||||||
|
|||||||
@@ -402,8 +402,8 @@ template:
|
|||||||
version: 2.0
|
version: 2.0
|
||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: 'stories/{{epic_name}}/{{story_id}}-{{story_name}}.md'
|
filename: "stories/{{epic_name}}/{{story_id}}-{{story_name}}.md"
|
||||||
title: 'Story: {{story_title}}'
|
title: "Story: {{story_title}}"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -432,7 +432,7 @@ sections:
|
|||||||
- id: description
|
- id: description
|
||||||
title: Description
|
title: Description
|
||||||
instruction: Provide a clear, concise description of what this story implements. Focus on the specific game feature or system being built. Reference the GDD section that defines this feature.
|
instruction: Provide a clear, concise description of what this story implements. Focus on the specific game feature or system being built. Reference the GDD section that defines this feature.
|
||||||
template: '{{clear_description_of_what_needs_to_be_implemented}}'
|
template: "{{clear_description_of_what_needs_to_be_implemented}}"
|
||||||
|
|
||||||
- id: acceptance-criteria
|
- id: acceptance-criteria
|
||||||
title: Acceptance Criteria
|
title: Acceptance Criteria
|
||||||
@@ -442,22 +442,22 @@ sections:
|
|||||||
title: Functional Requirements
|
title: Functional Requirements
|
||||||
type: checklist
|
type: checklist
|
||||||
items:
|
items:
|
||||||
- '{{specific_functional_requirement}}'
|
- "{{specific_functional_requirement}}"
|
||||||
- id: technical-requirements
|
- id: technical-requirements
|
||||||
title: Technical Requirements
|
title: Technical Requirements
|
||||||
type: checklist
|
type: checklist
|
||||||
items:
|
items:
|
||||||
- 'Code follows TypeScript strict mode standards'
|
- "Code follows TypeScript strict mode standards"
|
||||||
- 'Maintains 60 FPS on target devices'
|
- "Maintains 60 FPS on target devices"
|
||||||
- 'No memory leaks or performance degradation'
|
- "No memory leaks or performance degradation"
|
||||||
- '{{specific_technical_requirement}}'
|
- "{{specific_technical_requirement}}"
|
||||||
- id: game-design-requirements
|
- id: game-design-requirements
|
||||||
title: Game Design Requirements
|
title: Game Design Requirements
|
||||||
type: checklist
|
type: checklist
|
||||||
items:
|
items:
|
||||||
- '{{gameplay_requirement_from_gdd}}'
|
- "{{gameplay_requirement_from_gdd}}"
|
||||||
- '{{balance_requirement_if_applicable}}'
|
- "{{balance_requirement_if_applicable}}"
|
||||||
- '{{player_experience_requirement}}'
|
- "{{player_experience_requirement}}"
|
||||||
|
|
||||||
- id: technical-specifications
|
- id: technical-specifications
|
||||||
title: Technical Specifications
|
title: Technical Specifications
|
||||||
@@ -622,14 +622,14 @@ sections:
|
|||||||
instruction: Checklist that must be completed before the story is considered finished
|
instruction: Checklist that must be completed before the story is considered finished
|
||||||
type: checklist
|
type: checklist
|
||||||
items:
|
items:
|
||||||
- 'All acceptance criteria met'
|
- "All acceptance criteria met"
|
||||||
- 'Code reviewed and approved'
|
- "Code reviewed and approved"
|
||||||
- 'Unit tests written and passing'
|
- "Unit tests written and passing"
|
||||||
- 'Integration tests passing'
|
- "Integration tests passing"
|
||||||
- 'Performance targets met'
|
- "Performance targets met"
|
||||||
- 'No linting errors'
|
- "No linting errors"
|
||||||
- 'Documentation updated'
|
- "Documentation updated"
|
||||||
- '{{game_specific_dod_item}}'
|
- "{{game_specific_dod_item}}"
|
||||||
|
|
||||||
- id: notes
|
- id: notes
|
||||||
title: Notes
|
title: Notes
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1231,7 +1231,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/game-architecture.md
|
filename: docs/game-architecture.md
|
||||||
title: '{{project_name}} Game Architecture Document'
|
title: "{{project_name}} Game Architecture Document"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -1341,11 +1341,11 @@ sections:
|
|||||||
- Game management patterns (Singleton managers, Event systems, State machines)
|
- Game management patterns (Singleton managers, Event systems, State machines)
|
||||||
- Data patterns (ScriptableObject configuration, Save/Load systems)
|
- Data patterns (ScriptableObject configuration, Save/Load systems)
|
||||||
- Unity-specific patterns (Object pooling, Coroutines, Unity Events)
|
- Unity-specific patterns (Object pooling, Coroutines, Unity Events)
|
||||||
template: '- **{{pattern_name}}:** {{pattern_description}} - _Rationale:_ {{rationale}}'
|
template: "- **{{pattern_name}}:** {{pattern_description}} - _Rationale:_ {{rationale}}"
|
||||||
examples:
|
examples:
|
||||||
- "**Component-Based Architecture:** Using MonoBehaviour components for game logic - _Rationale:_ Aligns with Unity's design philosophy and enables reusable, testable game systems"
|
- "**Component-Based Architecture:** Using MonoBehaviour components for game logic - _Rationale:_ Aligns with Unity's design philosophy and enables reusable, testable game systems"
|
||||||
- '**ScriptableObject Data:** Using ScriptableObjects for game configuration - _Rationale:_ Enables data-driven design and easy balancing without code changes'
|
- "**ScriptableObject Data:** Using ScriptableObjects for game configuration - _Rationale:_ Enables data-driven design and easy balancing without code changes"
|
||||||
- '**Event-Driven Communication:** Using Unity Events and C# events for system decoupling - _Rationale:_ Supports modular architecture and easier testing'
|
- "**Event-Driven Communication:** Using Unity Events and C# events for system decoupling - _Rationale:_ Supports modular architecture and easier testing"
|
||||||
|
|
||||||
- id: tech-stack
|
- id: tech-stack
|
||||||
title: Tech Stack
|
title: Tech Stack
|
||||||
@@ -1384,13 +1384,13 @@ sections:
|
|||||||
columns: [Category, Technology, Version, Purpose, Rationale]
|
columns: [Category, Technology, Version, Purpose, Rationale]
|
||||||
instruction: Populate the technology stack table with all relevant Unity technologies
|
instruction: Populate the technology stack table with all relevant Unity technologies
|
||||||
examples:
|
examples:
|
||||||
- '| **Game Engine** | Unity | 2022.3.21f1 | Core game development platform | Latest LTS version, stable 2D tooling, comprehensive package ecosystem |'
|
- "| **Game Engine** | Unity | 2022.3.21f1 | Core game development platform | Latest LTS version, stable 2D tooling, comprehensive package ecosystem |"
|
||||||
- "| **Language** | C# | 10.0 | Primary scripting language | Unity's native language, strong typing, excellent tooling |"
|
- "| **Language** | C# | 10.0 | Primary scripting language | Unity's native language, strong typing, excellent tooling |"
|
||||||
- '| **Render Pipeline** | Universal Render Pipeline (URP) | 14.0.10 | 2D/3D rendering | Optimized for mobile, excellent 2D features, future-proof |'
|
- "| **Render Pipeline** | Universal Render Pipeline (URP) | 14.0.10 | 2D/3D rendering | Optimized for mobile, excellent 2D features, future-proof |"
|
||||||
- '| **Input System** | Unity Input System | 1.7.0 | Cross-platform input handling | Modern input system, supports multiple devices, rebindable controls |'
|
- "| **Input System** | Unity Input System | 1.7.0 | Cross-platform input handling | Modern input system, supports multiple devices, rebindable controls |"
|
||||||
- '| **Physics** | Unity 2D Physics | Built-in | 2D collision and physics | Integrated Box2D, optimized for 2D games |'
|
- "| **Physics** | Unity 2D Physics | Built-in | 2D collision and physics | Integrated Box2D, optimized for 2D games |"
|
||||||
- '| **Audio** | Unity Audio | Built-in | Audio playback and mixing | Built-in audio system with mixer support |'
|
- "| **Audio** | Unity Audio | Built-in | Audio playback and mixing | Built-in audio system with mixer support |"
|
||||||
- '| **Testing** | Unity Test Framework | 1.1.33 | Unit and integration testing | Built-in testing framework based on NUnit |'
|
- "| **Testing** | Unity Test Framework | 1.1.33 | Unit and integration testing | Built-in testing framework based on NUnit |"
|
||||||
|
|
||||||
- id: data-models
|
- id: data-models
|
||||||
title: Game Data Models
|
title: Game Data Models
|
||||||
@@ -1408,7 +1408,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: model
|
- id: model
|
||||||
title: '{{model_name}}'
|
title: "{{model_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Purpose:** {{model_purpose}}
|
**Purpose:** {{model_purpose}}
|
||||||
|
|
||||||
@@ -1443,7 +1443,7 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: system-list
|
- id: system-list
|
||||||
repeatable: true
|
repeatable: true
|
||||||
title: '{{system_name}} System'
|
title: "{{system_name}} System"
|
||||||
template: |
|
template: |
|
||||||
**Responsibility:** {{system_description}}
|
**Responsibility:** {{system_description}}
|
||||||
|
|
||||||
@@ -1967,7 +1967,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: integration
|
- id: integration
|
||||||
title: '{{service_name}} Integration'
|
title: "{{service_name}} Integration"
|
||||||
template: |
|
template: |
|
||||||
- **Purpose:** {{service_purpose}}
|
- **Purpose:** {{service_purpose}}
|
||||||
- **Documentation:** {{service_docs_url}}
|
- **Documentation:** {{service_docs_url}}
|
||||||
@@ -2079,12 +2079,12 @@ sections:
|
|||||||
- id: environments
|
- id: environments
|
||||||
title: Build Environments
|
title: Build Environments
|
||||||
repeatable: true
|
repeatable: true
|
||||||
template: '- **{{env_name}}:** {{env_purpose}} - {{platform_settings}}'
|
template: "- **{{env_name}}:** {{env_purpose}} - {{platform_settings}}"
|
||||||
- id: platform-specific-builds
|
- id: platform-specific-builds
|
||||||
title: Platform-Specific Build Settings
|
title: Platform-Specific Build Settings
|
||||||
type: code
|
type: code
|
||||||
language: text
|
language: text
|
||||||
template: '{{platform_build_configurations}}'
|
template: "{{platform_build_configurations}}"
|
||||||
|
|
||||||
- id: coding-standards
|
- id: coding-standards
|
||||||
title: Coding Standards
|
title: Coding Standards
|
||||||
@@ -2113,9 +2113,9 @@ sections:
|
|||||||
columns: [Element, Convention, Example]
|
columns: [Element, Convention, Example]
|
||||||
instruction: Only include if deviating from Unity defaults
|
instruction: Only include if deviating from Unity defaults
|
||||||
examples:
|
examples:
|
||||||
- '| MonoBehaviour | PascalCase + Component suffix | PlayerController, HealthSystem |'
|
- "| MonoBehaviour | PascalCase + Component suffix | PlayerController, HealthSystem |"
|
||||||
- '| ScriptableObject | PascalCase + Data/Config suffix | PlayerData, GameConfig |'
|
- "| ScriptableObject | PascalCase + Data/Config suffix | PlayerData, GameConfig |"
|
||||||
- '| Prefab | PascalCase descriptive | PlayerCharacter, EnvironmentTile |'
|
- "| Prefab | PascalCase descriptive | PlayerCharacter, EnvironmentTile |"
|
||||||
- id: critical-rules
|
- id: critical-rules
|
||||||
title: Critical Unity Rules
|
title: Critical Unity Rules
|
||||||
instruction: |
|
instruction: |
|
||||||
@@ -2127,7 +2127,7 @@ sections:
|
|||||||
|
|
||||||
Avoid obvious rules like "follow SOLID principles" or "optimize performance"
|
Avoid obvious rules like "follow SOLID principles" or "optimize performance"
|
||||||
repeatable: true
|
repeatable: true
|
||||||
template: '- **{{rule_name}}:** {{rule_description}}'
|
template: "- **{{rule_name}}:** {{rule_description}}"
|
||||||
- id: unity-specifics
|
- id: unity-specifics
|
||||||
title: Unity-Specific Guidelines
|
title: Unity-Specific Guidelines
|
||||||
condition: Critical Unity-specific rules needed
|
condition: Critical Unity-specific rules needed
|
||||||
@@ -2136,7 +2136,7 @@ sections:
|
|||||||
- id: unity-lifecycle
|
- id: unity-lifecycle
|
||||||
title: Unity Lifecycle Rules
|
title: Unity Lifecycle Rules
|
||||||
repeatable: true
|
repeatable: true
|
||||||
template: '- **{{lifecycle_method}}:** {{usage_rule}}'
|
template: "- **{{lifecycle_method}}:** {{usage_rule}}"
|
||||||
|
|
||||||
- id: test-strategy
|
- id: test-strategy
|
||||||
title: Test Strategy and Standards
|
title: Test Strategy and Standards
|
||||||
|
|||||||
@@ -1175,7 +1175,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/game-design-document.md
|
filename: docs/game-design-document.md
|
||||||
title: '{{game_title}} Game Design Document (GDD)'
|
title: "{{game_title}} Game Design Document (GDD)"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -1223,8 +1223,8 @@ sections:
|
|||||||
**Primary:** {{age_range}}, {{player_type}}, {{platform_preference}}
|
**Primary:** {{age_range}}, {{player_type}}, {{platform_preference}}
|
||||||
**Secondary:** {{secondary_audience}}
|
**Secondary:** {{secondary_audience}}
|
||||||
examples:
|
examples:
|
||||||
- 'Primary: Ages 8-16, casual mobile gamers, prefer short play sessions'
|
- "Primary: Ages 8-16, casual mobile gamers, prefer short play sessions"
|
||||||
- 'Secondary: Adult puzzle enthusiasts, educators looking for teaching tools'
|
- "Secondary: Adult puzzle enthusiasts, educators looking for teaching tools"
|
||||||
- id: platform-technical
|
- id: platform-technical
|
||||||
title: Platform & Technical Requirements
|
title: Platform & Technical Requirements
|
||||||
instruction: Based on the technical preferences or user input, define the target platforms and Unity-specific requirements
|
instruction: Based on the technical preferences or user input, define the target platforms and Unity-specific requirements
|
||||||
@@ -1235,7 +1235,7 @@ sections:
|
|||||||
**Screen Support:** {{resolution_range}}
|
**Screen Support:** {{resolution_range}}
|
||||||
**Build Targets:** {{build_targets}}
|
**Build Targets:** {{build_targets}}
|
||||||
examples:
|
examples:
|
||||||
- 'Primary Platform: Mobile (iOS/Android), Engine: Unity 2022.3 LTS & C#, Performance: 60 FPS on iPhone 8/Galaxy S8'
|
- "Primary Platform: Mobile (iOS/Android), Engine: Unity 2022.3 LTS & C#, Performance: 60 FPS on iPhone 8/Galaxy S8"
|
||||||
- id: unique-selling-points
|
- id: unique-selling-points
|
||||||
title: Unique Selling Points
|
title: Unique Selling Points
|
||||||
instruction: List 3-5 key features that differentiate this game from competitors
|
instruction: List 3-5 key features that differentiate this game from competitors
|
||||||
@@ -1286,8 +1286,8 @@ sections:
|
|||||||
- {{loss_condition_1}} - Trigger: {{unity_trigger}}
|
- {{loss_condition_1}} - Trigger: {{unity_trigger}}
|
||||||
- {{loss_condition_2}} - Trigger: {{unity_trigger}}
|
- {{loss_condition_2}} - Trigger: {{unity_trigger}}
|
||||||
examples:
|
examples:
|
||||||
- 'Victory: Player reaches exit portal - Unity Event: OnTriggerEnter2D with Portal tag'
|
- "Victory: Player reaches exit portal - Unity Event: OnTriggerEnter2D with Portal tag"
|
||||||
- 'Failure: Health reaches zero - Trigger: Health component value <= 0'
|
- "Failure: Health reaches zero - Trigger: Health component value <= 0"
|
||||||
|
|
||||||
- id: game-mechanics
|
- id: game-mechanics
|
||||||
title: Game Mechanics
|
title: Game Mechanics
|
||||||
@@ -1299,7 +1299,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: mechanic
|
- id: mechanic
|
||||||
title: '{{mechanic_name}}'
|
title: "{{mechanic_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Description:** {{detailed_description}}
|
**Description:** {{detailed_description}}
|
||||||
|
|
||||||
@@ -1321,8 +1321,8 @@ sections:
|
|||||||
- {{script_name}}.cs - {{responsibility}}
|
- {{script_name}}.cs - {{responsibility}}
|
||||||
- {{manager_script}}.cs - {{management_role}}
|
- {{manager_script}}.cs - {{management_role}}
|
||||||
examples:
|
examples:
|
||||||
- 'Components Needed: Rigidbody2D, BoxCollider2D, PlayerMovement script'
|
- "Components Needed: Rigidbody2D, BoxCollider2D, PlayerMovement script"
|
||||||
- 'Physics Requirements: 2D Physics material for ground friction, Gravity scale 3'
|
- "Physics Requirements: 2D Physics material for ground friction, Gravity scale 3"
|
||||||
- id: controls
|
- id: controls
|
||||||
title: Controls
|
title: Controls
|
||||||
instruction: Define all input methods for different platforms using Unity's Input System
|
instruction: Define all input methods for different platforms using Unity's Input System
|
||||||
@@ -1377,7 +1377,7 @@ sections:
|
|||||||
**Late Game:** {{duration}} - {{difficulty_description}}
|
**Late Game:** {{duration}} - {{difficulty_description}}
|
||||||
- Unity Config: {{scriptable_object_values}}
|
- Unity Config: {{scriptable_object_values}}
|
||||||
examples:
|
examples:
|
||||||
- 'enemy speed: 2.0f, jump height: 4.5f, obstacle density: 0.3f'
|
- "enemy speed: 2.0f, jump height: 4.5f, obstacle density: 0.3f"
|
||||||
- id: economy-resources
|
- id: economy-resources
|
||||||
title: Economy & Resources
|
title: Economy & Resources
|
||||||
condition: has_economy
|
condition: has_economy
|
||||||
@@ -1400,7 +1400,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: level-type
|
- id: level-type
|
||||||
title: '{{level_type_name}}'
|
title: "{{level_type_name}}"
|
||||||
template: |
|
template: |
|
||||||
**Purpose:** {{gameplay_purpose}}
|
**Purpose:** {{gameplay_purpose}}
|
||||||
**Target Duration:** {{target_time}}
|
**Target Duration:** {{target_time}}
|
||||||
@@ -1424,7 +1424,7 @@ sections:
|
|||||||
|
|
||||||
- {{prefab_name}} - {{prefab_purpose}}
|
- {{prefab_name}} - {{prefab_purpose}}
|
||||||
examples:
|
examples:
|
||||||
- 'Environment: TilemapRenderer with Platform tileset, Lighting: 2D Global Light + Point Lights'
|
- "Environment: TilemapRenderer with Platform tileset, Lighting: 2D Global Light + Point Lights"
|
||||||
- id: level-progression
|
- id: level-progression
|
||||||
title: Level Progression
|
title: Level Progression
|
||||||
template: |
|
template: |
|
||||||
@@ -1439,7 +1439,7 @@ sections:
|
|||||||
- Addressable Assets: {{addressable_groups}}
|
- Addressable Assets: {{addressable_groups}}
|
||||||
- Loading Screens: {{loading_implementation}}
|
- Loading Screens: {{loading_implementation}}
|
||||||
examples:
|
examples:
|
||||||
- 'Scene Naming: World{X}_Level{Y}_Name, Addressable Groups: Levels_World1, World_Environments'
|
- "Scene Naming: World{X}_Level{Y}_Name, Addressable Groups: Levels_World1, World_Environments"
|
||||||
|
|
||||||
- id: technical-specifications
|
- id: technical-specifications
|
||||||
title: Technical Specifications
|
title: Technical Specifications
|
||||||
@@ -1471,7 +1471,7 @@ sections:
|
|||||||
- Physics Settings: {{physics_config}}
|
- Physics Settings: {{physics_config}}
|
||||||
examples:
|
examples:
|
||||||
- com.unity.addressables 1.20.5 - Asset loading and memory management
|
- com.unity.addressables 1.20.5 - Asset loading and memory management
|
||||||
- 'Color Space: Linear, Quality: Mobile/Desktop presets, Gravity: -20'
|
- "Color Space: Linear, Quality: Mobile/Desktop presets, Gravity: -20"
|
||||||
- id: performance-requirements
|
- id: performance-requirements
|
||||||
title: Performance Requirements
|
title: Performance Requirements
|
||||||
template: |
|
template: |
|
||||||
@@ -1487,7 +1487,7 @@ sections:
|
|||||||
- GC Allocs: <{{gc_limit}}KB per frame
|
- GC Allocs: <{{gc_limit}}KB per frame
|
||||||
- Draw Calls: <{{draw_calls}} per frame
|
- Draw Calls: <{{draw_calls}} per frame
|
||||||
examples:
|
examples:
|
||||||
- '60 FPS (minimum 30), CPU: <16.67ms, GPU: <16.67ms, GC: <4KB, Draws: <50'
|
- "60 FPS (minimum 30), CPU: <16.67ms, GPU: <16.67ms, GC: <4KB, Draws: <50"
|
||||||
- id: platform-specific
|
- id: platform-specific
|
||||||
title: Platform Specific Requirements
|
title: Platform Specific Requirements
|
||||||
template: |
|
template: |
|
||||||
@@ -1510,7 +1510,7 @@ sections:
|
|||||||
- Browser Support: {{browser_list}}
|
- Browser Support: {{browser_list}}
|
||||||
- Compression: {{compression_format}}
|
- Compression: {{compression_format}}
|
||||||
examples:
|
examples:
|
||||||
- 'Resolution: 1280x720 - 4K, Gamepad: Xbox/PlayStation controllers via Input System'
|
- "Resolution: 1280x720 - 4K, Gamepad: Xbox/PlayStation controllers via Input System"
|
||||||
- id: asset-requirements
|
- id: asset-requirements
|
||||||
title: Asset Requirements
|
title: Asset Requirements
|
||||||
instruction: Define asset specifications for Unity pipeline optimization
|
instruction: Define asset specifications for Unity pipeline optimization
|
||||||
@@ -1536,7 +1536,7 @@ sections:
|
|||||||
- Font: {{font_requirements}}
|
- Font: {{font_requirements}}
|
||||||
- Icon Sizes: {{icon_specifications}}
|
- Icon Sizes: {{icon_specifications}}
|
||||||
examples:
|
examples:
|
||||||
- 'Sprites: 32x32 to 256x256 at 16 PPU, Format: RGBA32 for quality/RGBA16 for performance'
|
- "Sprites: 32x32 to 256x256 at 16 PPU, Format: RGBA32 for quality/RGBA16 for performance"
|
||||||
|
|
||||||
- id: technical-architecture-requirements
|
- id: technical-architecture-requirements
|
||||||
title: Technical Architecture Requirements
|
title: Technical Architecture Requirements
|
||||||
@@ -1578,8 +1578,8 @@ sections:
|
|||||||
- Prefabs: {{prefab_naming}}
|
- Prefabs: {{prefab_naming}}
|
||||||
- Scenes: {{scene_naming}}
|
- Scenes: {{scene_naming}}
|
||||||
examples:
|
examples:
|
||||||
- 'Architecture: Component-Based with ScriptableObject data containers'
|
- "Architecture: Component-Based with ScriptableObject data containers"
|
||||||
- 'Scripts: PascalCase (PlayerController), Prefabs: Player_Prefab, Scenes: Level_01_Forest'
|
- "Scripts: PascalCase (PlayerController), Prefabs: Player_Prefab, Scenes: Level_01_Forest"
|
||||||
- id: unity-systems-integration
|
- id: unity-systems-integration
|
||||||
title: Unity Systems Integration
|
title: Unity Systems Integration
|
||||||
template: |
|
template: |
|
||||||
@@ -1601,8 +1601,8 @@ sections:
|
|||||||
- **Memory Management:** {{memory_strategy}}
|
- **Memory Management:** {{memory_strategy}}
|
||||||
- **Build Pipeline:** {{build_automation}}
|
- **Build Pipeline:** {{build_automation}}
|
||||||
examples:
|
examples:
|
||||||
- 'Input System: Action Maps for Menu/Gameplay contexts with device switching'
|
- "Input System: Action Maps for Menu/Gameplay contexts with device switching"
|
||||||
- 'DOTween: Smooth UI transitions and gameplay animations'
|
- "DOTween: Smooth UI transitions and gameplay animations"
|
||||||
- id: data-management
|
- id: data-management
|
||||||
title: Data Management
|
title: Data Management
|
||||||
template: |
|
template: |
|
||||||
@@ -1625,8 +1625,8 @@ sections:
|
|||||||
- **Memory Pools:** {{pooling_objects}}
|
- **Memory Pools:** {{pooling_objects}}
|
||||||
- **Asset References:** {{asset_reference_system}}
|
- **Asset References:** {{asset_reference_system}}
|
||||||
examples:
|
examples:
|
||||||
- 'Save Data: JSON format with AES encryption, stored in persistent data path'
|
- "Save Data: JSON format with AES encryption, stored in persistent data path"
|
||||||
- 'ScriptableObjects: Game settings, level configurations, character data'
|
- "ScriptableObjects: Game settings, level configurations, character data"
|
||||||
|
|
||||||
- id: development-phases
|
- id: development-phases
|
||||||
title: Development Phases & Epic Planning
|
title: Development Phases & Epic Planning
|
||||||
@@ -1638,15 +1638,15 @@ sections:
|
|||||||
instruction: Present a high-level list of all phases for user approval. Each phase's design should deliver significant Unity functionality.
|
instruction: Present a high-level list of all phases for user approval. Each phase's design should deliver significant Unity functionality.
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
examples:
|
examples:
|
||||||
- 'Phase 1: Unity Foundation & Core Systems: Project setup, input handling, basic scene management'
|
- "Phase 1: Unity Foundation & Core Systems: Project setup, input handling, basic scene management"
|
||||||
- 'Phase 2: Core Game Mechanics: Player controller, physics systems, basic gameplay loop'
|
- "Phase 2: Core Game Mechanics: Player controller, physics systems, basic gameplay loop"
|
||||||
- 'Phase 3: Level Systems & Content Pipeline: Scene loading, prefab systems, level progression'
|
- "Phase 3: Level Systems & Content Pipeline: Scene loading, prefab systems, level progression"
|
||||||
- 'Phase 4: Polish & Platform Optimization: Performance tuning, platform-specific features, deployment'
|
- "Phase 4: Polish & Platform Optimization: Performance tuning, platform-specific features, deployment"
|
||||||
- id: phase-1-foundation
|
- id: phase-1-foundation
|
||||||
title: 'Phase 1: Unity Foundation & Core Systems ({{duration}})'
|
title: "Phase 1: Unity Foundation & Core Systems ({{duration}})"
|
||||||
sections:
|
sections:
|
||||||
- id: foundation-design
|
- id: foundation-design
|
||||||
title: 'Design: Unity Project Foundation'
|
title: "Design: Unity Project Foundation"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Unity project setup with proper folder structure and naming conventions
|
- Unity project setup with proper folder structure and naming conventions
|
||||||
@@ -1656,9 +1656,9 @@ sections:
|
|||||||
- Development tools setup (debugging, profiling integration)
|
- Development tools setup (debugging, profiling integration)
|
||||||
- Initial build pipeline and platform configuration
|
- Initial build pipeline and platform configuration
|
||||||
examples:
|
examples:
|
||||||
- 'Input System: Configure PlayerInput component with Action Maps for movement and UI'
|
- "Input System: Configure PlayerInput component with Action Maps for movement and UI"
|
||||||
- id: core-systems-design
|
- id: core-systems-design
|
||||||
title: 'Design: Essential Game Systems'
|
title: "Design: Essential Game Systems"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Save/Load system implementation with {{save_format}} format
|
- Save/Load system implementation with {{save_format}} format
|
||||||
@@ -1668,10 +1668,10 @@ sections:
|
|||||||
- Basic UI framework and canvas configuration
|
- Basic UI framework and canvas configuration
|
||||||
- Settings and configuration management with ScriptableObjects
|
- Settings and configuration management with ScriptableObjects
|
||||||
- id: phase-2-gameplay
|
- id: phase-2-gameplay
|
||||||
title: 'Phase 2: Core Gameplay Implementation ({{duration}})'
|
title: "Phase 2: Core Gameplay Implementation ({{duration}})"
|
||||||
sections:
|
sections:
|
||||||
- id: gameplay-mechanics-design
|
- id: gameplay-mechanics-design
|
||||||
title: 'Design: Primary Game Mechanics'
|
title: "Design: Primary Game Mechanics"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Player controller with {{movement_type}} movement system
|
- Player controller with {{movement_type}} movement system
|
||||||
@@ -1681,7 +1681,7 @@ sections:
|
|||||||
- Basic collision detection and response systems
|
- Basic collision detection and response systems
|
||||||
- Animation system integration with Animator controllers
|
- Animation system integration with Animator controllers
|
||||||
- id: level-systems-design
|
- id: level-systems-design
|
||||||
title: 'Design: Level & Content Systems'
|
title: "Design: Level & Content Systems"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Scene loading and transition system
|
- Scene loading and transition system
|
||||||
@@ -1691,10 +1691,10 @@ sections:
|
|||||||
- Collectibles and pickup systems
|
- Collectibles and pickup systems
|
||||||
- Victory/defeat condition implementation
|
- Victory/defeat condition implementation
|
||||||
- id: phase-3-polish
|
- id: phase-3-polish
|
||||||
title: 'Phase 3: Polish & Optimization ({{duration}})'
|
title: "Phase 3: Polish & Optimization ({{duration}})"
|
||||||
sections:
|
sections:
|
||||||
- id: performance-design
|
- id: performance-design
|
||||||
title: 'Design: Performance & Platform Optimization'
|
title: "Design: Performance & Platform Optimization"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Unity Profiler analysis and optimization passes
|
- Unity Profiler analysis and optimization passes
|
||||||
@@ -1704,7 +1704,7 @@ sections:
|
|||||||
- Build size optimization and asset bundling
|
- Build size optimization and asset bundling
|
||||||
- Quality settings configuration for different device tiers
|
- Quality settings configuration for different device tiers
|
||||||
- id: user-experience-design
|
- id: user-experience-design
|
||||||
title: 'Design: User Experience & Polish'
|
title: "Design: User Experience & Polish"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Complete UI/UX implementation with responsive design
|
- Complete UI/UX implementation with responsive design
|
||||||
@@ -1729,10 +1729,10 @@ sections:
|
|||||||
- Cross Cutting Concerns should flow through epics and stories and not be final stories. For example, adding a logging framework as a last story of an epic, or at the end of a project as a final epic or story would be terrible as we would not have logging from the beginning.
|
- Cross Cutting Concerns should flow through epics and stories and not be final stories. For example, adding a logging framework as a last story of an epic, or at the end of a project as a final epic or story would be terrible as we would not have logging from the beginning.
|
||||||
elicit: true
|
elicit: true
|
||||||
examples:
|
examples:
|
||||||
- 'Epic 1: Unity Foundation & Core Systems: Project setup, input handling, basic scene management'
|
- "Epic 1: Unity Foundation & Core Systems: Project setup, input handling, basic scene management"
|
||||||
- 'Epic 2: Core Game Mechanics: Player controller, physics systems, basic gameplay loop'
|
- "Epic 2: Core Game Mechanics: Player controller, physics systems, basic gameplay loop"
|
||||||
- 'Epic 3: Level Systems & Content Pipeline: Scene loading, prefab systems, level progression'
|
- "Epic 3: Level Systems & Content Pipeline: Scene loading, prefab systems, level progression"
|
||||||
- 'Epic 4: Polish & Platform Optimization: Performance tuning, platform-specific features, deployment'
|
- "Epic 4: Polish & Platform Optimization: Performance tuning, platform-specific features, deployment"
|
||||||
|
|
||||||
- id: epic-details
|
- id: epic-details
|
||||||
title: Epic {{epic_number}} {{epic_title}}
|
title: Epic {{epic_number}} {{epic_title}}
|
||||||
@@ -1754,13 +1754,13 @@ sections:
|
|||||||
- Think "junior developer working for 2-4 hours" - stories must be small, focused, and self-contained
|
- Think "junior developer working for 2-4 hours" - stories must be small, focused, and self-contained
|
||||||
- If a story seems complex, break it down further as long as it can deliver a vertical slice
|
- If a story seems complex, break it down further as long as it can deliver a vertical slice
|
||||||
elicit: true
|
elicit: true
|
||||||
template: '{{epic_goal}}'
|
template: "{{epic_goal}}"
|
||||||
sections:
|
sections:
|
||||||
- id: story
|
- id: story
|
||||||
title: Story {{epic_number}}.{{story_number}} {{story_title}}
|
title: Story {{epic_number}}.{{story_number}} {{story_title}}
|
||||||
repeatable: true
|
repeatable: true
|
||||||
instruction: Provide a clear, concise description of what this story implements. Focus on the specific game feature or system being built. Reference the GDD section that defines this feature and reference the gamearchitecture section for additional implementation and integration specifics.
|
instruction: Provide a clear, concise description of what this story implements. Focus on the specific game feature or system being built. Reference the GDD section that defines this feature and reference the gamearchitecture section for additional implementation and integration specifics.
|
||||||
template: '{{clear_description_of_what_needs_to_be_implemented}}'
|
template: "{{clear_description_of_what_needs_to_be_implemented}}"
|
||||||
sections:
|
sections:
|
||||||
- id: acceptance-criteria
|
- id: acceptance-criteria
|
||||||
title: Acceptance Criteria
|
title: Acceptance Criteria
|
||||||
@@ -1770,7 +1770,7 @@ sections:
|
|||||||
title: Functional Requirements
|
title: Functional Requirements
|
||||||
type: checklist
|
type: checklist
|
||||||
items:
|
items:
|
||||||
- '{{specific_functional_requirement}}'
|
- "{{specific_functional_requirement}}"
|
||||||
- id: technical-requirements
|
- id: technical-requirements
|
||||||
title: Technical Requirements
|
title: Technical Requirements
|
||||||
type: checklist
|
type: checklist
|
||||||
@@ -1778,14 +1778,14 @@ sections:
|
|||||||
- Code follows C# best practices
|
- Code follows C# best practices
|
||||||
- Maintains stable frame rate on target devices
|
- Maintains stable frame rate on target devices
|
||||||
- No memory leaks or performance degradation
|
- No memory leaks or performance degradation
|
||||||
- '{{specific_technical_requirement}}'
|
- "{{specific_technical_requirement}}"
|
||||||
- id: game-design-requirements
|
- id: game-design-requirements
|
||||||
title: Game Design Requirements
|
title: Game Design Requirements
|
||||||
type: checklist
|
type: checklist
|
||||||
items:
|
items:
|
||||||
- '{{gameplay_requirement_from_gdd}}'
|
- "{{gameplay_requirement_from_gdd}}"
|
||||||
- '{{balance_requirement_if_applicable}}'
|
- "{{balance_requirement_if_applicable}}"
|
||||||
- '{{player_experience_requirement}}'
|
- "{{player_experience_requirement}}"
|
||||||
|
|
||||||
- id: success-metrics
|
- id: success-metrics
|
||||||
title: Success Metrics & Quality Assurance
|
title: Success Metrics & Quality Assurance
|
||||||
@@ -1803,8 +1803,8 @@ sections:
|
|||||||
- **Build Size:** Final build <{{size_limit}}MB for mobile, <{{desktop_limit}}MB for desktop
|
- **Build Size:** Final build <{{size_limit}}MB for mobile, <{{desktop_limit}}MB for desktop
|
||||||
- **Battery Life:** Mobile gameplay sessions >{{battery_target}} hours on average device
|
- **Battery Life:** Mobile gameplay sessions >{{battery_target}} hours on average device
|
||||||
examples:
|
examples:
|
||||||
- 'Frame Rate: Consistent 60 FPS with <5% drops below 45 FPS on target hardware'
|
- "Frame Rate: Consistent 60 FPS with <5% drops below 45 FPS on target hardware"
|
||||||
- 'Crash Rate: <0.5% across iOS/Android, <0.1% on desktop platforms'
|
- "Crash Rate: <0.5% across iOS/Android, <0.1% on desktop platforms"
|
||||||
- id: gameplay-metrics
|
- id: gameplay-metrics
|
||||||
title: Gameplay & User Engagement Metrics
|
title: Gameplay & User Engagement Metrics
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
@@ -1816,8 +1816,8 @@ sections:
|
|||||||
- **Gameplay Completion:** {{completion_rate}}% complete main game content
|
- **Gameplay Completion:** {{completion_rate}}% complete main game content
|
||||||
- **Control Responsiveness:** Input lag <{{input_lag}}ms on all platforms
|
- **Control Responsiveness:** Input lag <{{input_lag}}ms on all platforms
|
||||||
examples:
|
examples:
|
||||||
- 'Tutorial Completion: 85% of players complete movement and basic mechanics tutorial'
|
- "Tutorial Completion: 85% of players complete movement and basic mechanics tutorial"
|
||||||
- 'Session Duration: Average 15-20 minutes per session for mobile, 30-45 minutes for desktop'
|
- "Session Duration: Average 15-20 minutes per session for mobile, 30-45 minutes for desktop"
|
||||||
- id: platform-specific-metrics
|
- id: platform-specific-metrics
|
||||||
title: Platform-Specific Quality Metrics
|
title: Platform-Specific Quality Metrics
|
||||||
type: table
|
type: table
|
||||||
@@ -1862,17 +1862,17 @@ sections:
|
|||||||
- Consider cross-platform testing requirements
|
- Consider cross-platform testing requirements
|
||||||
- Account for Unity build and deployment steps
|
- Account for Unity build and deployment steps
|
||||||
examples:
|
examples:
|
||||||
- 'Foundation stories: Individual Unity systems (Input, Audio, Scene Management) - 1-2 days each'
|
- "Foundation stories: Individual Unity systems (Input, Audio, Scene Management) - 1-2 days each"
|
||||||
- 'Feature stories: Complete gameplay mechanics with UI and feedback - 2-4 days each'
|
- "Feature stories: Complete gameplay mechanics with UI and feedback - 2-4 days each"
|
||||||
- id: recommended-agents
|
- id: recommended-agents
|
||||||
title: Recommended BMad Agent Sequence
|
title: Recommended BMad Agent Sequence
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
template: |
|
template: |
|
||||||
1. **{{agent_name}}**: {{agent_responsibility}}
|
1. **{{agent_name}}**: {{agent_responsibility}}
|
||||||
examples:
|
examples:
|
||||||
- 'Unity Architect: Create detailed technical architecture document with specific Unity implementation patterns'
|
- "Unity Architect: Create detailed technical architecture document with specific Unity implementation patterns"
|
||||||
- 'Unity Developer: Implement core systems and gameplay mechanics according to architecture'
|
- "Unity Developer: Implement core systems and gameplay mechanics according to architecture"
|
||||||
- 'QA Tester: Validate performance metrics and cross-platform functionality'
|
- "QA Tester: Validate performance metrics and cross-platform functionality"
|
||||||
==================== END: .bmad-2d-unity-game-dev/templates/game-design-doc-tmpl.yaml ====================
|
==================== END: .bmad-2d-unity-game-dev/templates/game-design-doc-tmpl.yaml ====================
|
||||||
|
|
||||||
==================== START: .bmad-2d-unity-game-dev/templates/level-design-doc-tmpl.yaml ====================
|
==================== START: .bmad-2d-unity-game-dev/templates/level-design-doc-tmpl.yaml ====================
|
||||||
@@ -1883,7 +1883,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/level-design-document.md
|
filename: docs/level-design-document.md
|
||||||
title: '{{game_title}} Level Design Document'
|
title: "{{game_title}} Level Design Document"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -1944,7 +1944,7 @@ sections:
|
|||||||
repeatable: true
|
repeatable: true
|
||||||
sections:
|
sections:
|
||||||
- id: level-category
|
- id: level-category
|
||||||
title: '{{category_name}} Levels'
|
title: "{{category_name}} Levels"
|
||||||
template: |
|
template: |
|
||||||
**Purpose:** {{gameplay_purpose}}
|
**Purpose:** {{gameplay_purpose}}
|
||||||
|
|
||||||
@@ -2370,7 +2370,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/game-brief.md
|
filename: docs/game-brief.md
|
||||||
title: '{{game_title}} Game Brief'
|
title: "{{game_title}} Game Brief"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -2656,21 +2656,21 @@ sections:
|
|||||||
title: Development Roadmap
|
title: Development Roadmap
|
||||||
sections:
|
sections:
|
||||||
- id: phase-1-preproduction
|
- id: phase-1-preproduction
|
||||||
title: 'Phase 1: Pre-Production ({{duration}})'
|
title: "Phase 1: Pre-Production ({{duration}})"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Detailed Game Design Document creation
|
- Detailed Game Design Document creation
|
||||||
- Technical architecture planning
|
- Technical architecture planning
|
||||||
- Art style exploration and pipeline setup
|
- Art style exploration and pipeline setup
|
||||||
- id: phase-2-prototype
|
- id: phase-2-prototype
|
||||||
title: 'Phase 2: Prototype ({{duration}})'
|
title: "Phase 2: Prototype ({{duration}})"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Core mechanic implementation
|
- Core mechanic implementation
|
||||||
- Technical proof of concept
|
- Technical proof of concept
|
||||||
- Initial playtesting and iteration
|
- Initial playtesting and iteration
|
||||||
- id: phase-3-production
|
- id: phase-3-production
|
||||||
title: 'Phase 3: Production ({{duration}})'
|
title: "Phase 3: Production ({{duration}})"
|
||||||
type: bullet-list
|
type: bullet-list
|
||||||
template: |
|
template: |
|
||||||
- Full feature development
|
- Full feature development
|
||||||
|
|||||||
@@ -514,8 +514,8 @@ template:
|
|||||||
version: 3.0
|
version: 3.0
|
||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: 'stories/{{epic_name}}/{{story_id}}-{{story_name}}.md'
|
filename: "stories/{{epic_name}}/{{story_id}}-{{story_name}}.md"
|
||||||
title: 'Story: {{story_title}}'
|
title: "Story: {{story_title}}"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -544,7 +544,7 @@ sections:
|
|||||||
- id: description
|
- id: description
|
||||||
title: Description
|
title: Description
|
||||||
instruction: Provide a clear, concise description of what this story implements. Focus on the specific game feature or system being built. Reference the GDD section that defines this feature.
|
instruction: Provide a clear, concise description of what this story implements. Focus on the specific game feature or system being built. Reference the GDD section that defines this feature.
|
||||||
template: '{{clear_description_of_what_needs_to_be_implemented}}'
|
template: "{{clear_description_of_what_needs_to_be_implemented}}"
|
||||||
|
|
||||||
- id: acceptance-criteria
|
- id: acceptance-criteria
|
||||||
title: Acceptance Criteria
|
title: Acceptance Criteria
|
||||||
@@ -554,7 +554,7 @@ sections:
|
|||||||
title: Functional Requirements
|
title: Functional Requirements
|
||||||
type: checklist
|
type: checklist
|
||||||
items:
|
items:
|
||||||
- '{{specific_functional_requirement}}'
|
- "{{specific_functional_requirement}}"
|
||||||
- id: technical-requirements
|
- id: technical-requirements
|
||||||
title: Technical Requirements
|
title: Technical Requirements
|
||||||
type: checklist
|
type: checklist
|
||||||
@@ -562,14 +562,14 @@ sections:
|
|||||||
- Code follows C# best practices
|
- Code follows C# best practices
|
||||||
- Maintains stable frame rate on target devices
|
- Maintains stable frame rate on target devices
|
||||||
- No memory leaks or performance degradation
|
- No memory leaks or performance degradation
|
||||||
- '{{specific_technical_requirement}}'
|
- "{{specific_technical_requirement}}"
|
||||||
- id: game-design-requirements
|
- id: game-design-requirements
|
||||||
title: Game Design Requirements
|
title: Game Design Requirements
|
||||||
type: checklist
|
type: checklist
|
||||||
items:
|
items:
|
||||||
- '{{gameplay_requirement_from_gdd}}'
|
- "{{gameplay_requirement_from_gdd}}"
|
||||||
- '{{balance_requirement_if_applicable}}'
|
- "{{balance_requirement_if_applicable}}"
|
||||||
- '{{player_experience_requirement}}'
|
- "{{player_experience_requirement}}"
|
||||||
|
|
||||||
- id: technical-specifications
|
- id: technical-specifications
|
||||||
title: Technical Specifications
|
title: Technical Specifications
|
||||||
@@ -744,7 +744,7 @@ sections:
|
|||||||
- Performance targets met
|
- Performance targets met
|
||||||
- No C# compiler errors or warnings
|
- No C# compiler errors or warnings
|
||||||
- Documentation updated
|
- Documentation updated
|
||||||
- '{{game_specific_dod_item}}'
|
- "{{game_specific_dod_item}}"
|
||||||
|
|
||||||
- id: notes
|
- id: notes
|
||||||
title: Notes
|
title: Notes
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -530,23 +530,23 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/infrastructure-architecture.md
|
filename: docs/infrastructure-architecture.md
|
||||||
title: '{{project_name}} Infrastructure Architecture'
|
title: "{{project_name}} Infrastructure Architecture"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
elicitation: advanced-elicitation
|
elicitation: advanced-elicitation
|
||||||
custom_elicitation:
|
custom_elicitation:
|
||||||
title: 'Infrastructure Architecture Elicitation Actions'
|
title: "Infrastructure Architecture Elicitation Actions"
|
||||||
sections:
|
sections:
|
||||||
- id: infrastructure-overview
|
- id: infrastructure-overview
|
||||||
options:
|
options:
|
||||||
- 'Multi-Cloud Strategy Analysis - Evaluate cloud provider options and vendor lock-in considerations'
|
- "Multi-Cloud Strategy Analysis - Evaluate cloud provider options and vendor lock-in considerations"
|
||||||
- 'Regional Distribution Planning - Analyze latency requirements and data residency needs'
|
- "Regional Distribution Planning - Analyze latency requirements and data residency needs"
|
||||||
- 'Environment Isolation Strategy - Design security boundaries and resource segregation'
|
- "Environment Isolation Strategy - Design security boundaries and resource segregation"
|
||||||
- 'Scalability Patterns Review - Assess auto-scaling needs and traffic patterns'
|
- "Scalability Patterns Review - Assess auto-scaling needs and traffic patterns"
|
||||||
- 'Compliance Requirements Analysis - Review regulatory and security compliance needs'
|
- "Compliance Requirements Analysis - Review regulatory and security compliance needs"
|
||||||
- 'Cost-Benefit Analysis - Compare infrastructure options and TCO'
|
- "Cost-Benefit Analysis - Compare infrastructure options and TCO"
|
||||||
- 'Proceed to next section'
|
- "Proceed to next section"
|
||||||
|
|
||||||
sections:
|
sections:
|
||||||
- id: initial-setup
|
- id: initial-setup
|
||||||
@@ -606,7 +606,7 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: environments
|
- id: environments
|
||||||
repeatable: true
|
repeatable: true
|
||||||
title: '{{environment_name}} Environment'
|
title: "{{environment_name}} Environment"
|
||||||
template: |
|
template: |
|
||||||
- **Purpose:** {{environment_purpose}}
|
- **Purpose:** {{environment_purpose}}
|
||||||
- **Resources:** {{environment_resources}}
|
- **Resources:** {{environment_resources}}
|
||||||
@@ -957,24 +957,24 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/platform-infrastructure/platform-implementation.md
|
filename: docs/platform-infrastructure/platform-implementation.md
|
||||||
title: '{{project_name}} Platform Infrastructure Implementation'
|
title: "{{project_name}} Platform Infrastructure Implementation"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
elicitation: advanced-elicitation
|
elicitation: advanced-elicitation
|
||||||
custom_elicitation:
|
custom_elicitation:
|
||||||
title: 'Platform Implementation Elicitation Actions'
|
title: "Platform Implementation Elicitation Actions"
|
||||||
sections:
|
sections:
|
||||||
- id: foundation-infrastructure
|
- id: foundation-infrastructure
|
||||||
options:
|
options:
|
||||||
- 'Platform Layer Security Hardening - Additional security controls and compliance validation'
|
- "Platform Layer Security Hardening - Additional security controls and compliance validation"
|
||||||
- 'Performance Optimization - Network and resource optimization'
|
- "Performance Optimization - Network and resource optimization"
|
||||||
- 'Operational Excellence Enhancement - Automation and monitoring improvements'
|
- "Operational Excellence Enhancement - Automation and monitoring improvements"
|
||||||
- 'Platform Integration Validation - Verify foundation supports upper layers'
|
- "Platform Integration Validation - Verify foundation supports upper layers"
|
||||||
- 'Developer Experience Analysis - Foundation impact on developer workflows'
|
- "Developer Experience Analysis - Foundation impact on developer workflows"
|
||||||
- 'Disaster Recovery Testing - Foundation resilience validation'
|
- "Disaster Recovery Testing - Foundation resilience validation"
|
||||||
- 'BMAD Workflow Integration - Cross-agent support verification'
|
- "BMAD Workflow Integration - Cross-agent support verification"
|
||||||
- 'Finalize and Proceed to Container Platform'
|
- "Finalize and Proceed to Container Platform"
|
||||||
|
|
||||||
sections:
|
sections:
|
||||||
- id: initial-setup
|
- id: initial-setup
|
||||||
|
|||||||
858
dist/teams/team-all.txt
vendored
858
dist/teams/team-all.txt
vendored
File diff suppressed because it is too large
Load Diff
842
dist/teams/team-fullstack.txt
vendored
842
dist/teams/team-fullstack.txt
vendored
File diff suppressed because it is too large
Load Diff
18
dist/teams/team-ide-minimal.txt
vendored
18
dist/teams/team-ide-minimal.txt
vendored
@@ -2246,7 +2246,7 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: docs/stories/{{epic_num}}.{{story_num}}.{{story_title_short}}.md
|
filename: docs/stories/{{epic_num}}.{{story_num}}.{{story_title_short}}.md
|
||||||
title: 'Story {{epic_num}}.{{story_num}}: {{story_title_short}}'
|
title: "Story {{epic_num}}.{{story_num}}: {{story_title_short}}"
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
@@ -2348,7 +2348,7 @@ sections:
|
|||||||
sections:
|
sections:
|
||||||
- id: agent-model
|
- id: agent-model
|
||||||
title: Agent Model Used
|
title: Agent Model Used
|
||||||
template: '{{agent_model_name_version}}'
|
template: "{{agent_model_name_version}}"
|
||||||
instruction: Record the specific AI agent model and version used for development
|
instruction: Record the specific AI agent model and version used for development
|
||||||
owner: dev-agent
|
owner: dev-agent
|
||||||
editors: [dev-agent]
|
editors: [dev-agent]
|
||||||
@@ -4999,16 +4999,16 @@ template:
|
|||||||
output:
|
output:
|
||||||
format: yaml
|
format: yaml
|
||||||
filename: docs/qa/gates/{{epic_num}}.{{story_num}}-{{story_slug}}.yml
|
filename: docs/qa/gates/{{epic_num}}.{{story_num}}-{{story_slug}}.yml
|
||||||
title: 'Quality Gate: {{epic_num}}.{{story_num}}'
|
title: "Quality Gate: {{epic_num}}.{{story_num}}"
|
||||||
|
|
||||||
# Required fields (keep these first)
|
# Required fields (keep these first)
|
||||||
schema: 1
|
schema: 1
|
||||||
story: '{{epic_num}}.{{story_num}}'
|
story: "{{epic_num}}.{{story_num}}"
|
||||||
story_title: '{{story_title}}'
|
story_title: "{{story_title}}"
|
||||||
gate: '{{gate_status}}' # PASS|CONCERNS|FAIL|WAIVED
|
gate: "{{gate_status}}" # PASS|CONCERNS|FAIL|WAIVED
|
||||||
status_reason: '{{status_reason}}' # 1-2 sentence summary of why this gate decision
|
status_reason: "{{status_reason}}" # 1-2 sentence summary of why this gate decision
|
||||||
reviewer: 'Quinn (Test Architect)'
|
reviewer: "Quinn (Test Architect)"
|
||||||
updated: '{{iso_timestamp}}'
|
updated: "{{iso_timestamp}}"
|
||||||
|
|
||||||
# Always present but only active when WAIVED
|
# Always present but only active when WAIVED
|
||||||
waiver: { active: false }
|
waiver: { active: false }
|
||||||
|
|||||||
640
dist/teams/team-no-ui.txt
vendored
640
dist/teams/team-no-ui.txt
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,77 +1,147 @@
|
|||||||
# How to Release a New Version
|
# Versioning and Releases
|
||||||
|
|
||||||
## Automated Releases (Recommended)
|
BMad Method uses a simplified release system with manual control and automatic release notes generation.
|
||||||
|
|
||||||
The easiest way to release new versions is through **automatic semantic releases**. Just commit with the right message format and push and everything else happens automatically.
|
## 🚀 Release Workflow
|
||||||
|
|
||||||
### Commit Message Format
|
### Command Line Release (Recommended)
|
||||||
|
|
||||||
Use these prefixes to control what type of release happens:
|
The fastest way to create a release with beautiful release notes:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
fix: resolve CLI argument parsing bug # → patch release (4.1.0 → 4.1.1)
|
# Preview what will be in the release
|
||||||
feat: add new agent orchestration mode # → minor release (4.1.0 → 4.2.0)
|
npm run preview:release
|
||||||
feat!: redesign CLI interface # → major release (4.1.0 → 5.0.0)
|
|
||||||
|
# Create a release
|
||||||
|
npm run release:patch # 5.1.0 → 5.1.1 (bug fixes)
|
||||||
|
npm run release:minor # 5.1.0 → 5.2.0 (new features)
|
||||||
|
npm run release:major # 5.1.0 → 6.0.0 (breaking changes)
|
||||||
|
|
||||||
|
# Watch the release process
|
||||||
|
npm run release:watch
|
||||||
```
|
```
|
||||||
|
|
||||||
### What Happens Automatically
|
### One-Liner Release
|
||||||
|
|
||||||
When you push commits with `fix:` or `feat:`, GitHub Actions will:
|
|
||||||
|
|
||||||
1. ✅ Analyze your commit messages
|
|
||||||
2. ✅ Bump version in `package.json`
|
|
||||||
3. ✅ Generate changelog
|
|
||||||
4. ✅ Create git tag
|
|
||||||
5. ✅ **Publish to NPM automatically**
|
|
||||||
6. ✅ Create GitHub release with notes
|
|
||||||
|
|
||||||
### Your Simple Workflow
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Make your changes
|
npm run preview:release && npm run release:minor && npm run release:watch
|
||||||
git add .
|
|
||||||
git commit -m "feat: add team collaboration mode"
|
|
||||||
git push
|
|
||||||
|
|
||||||
# That's it! Release happens automatically 🎉
|
|
||||||
# Users can now run: npx bmad-method (and get the new version)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Commits That DON'T Trigger Releases
|
## 📝 What Happens Automatically
|
||||||
|
|
||||||
These commit types won't create releases (use them for maintenance):
|
When you trigger a release, the GitHub Actions workflow automatically:
|
||||||
|
|
||||||
|
1. ✅ **Validates** - Runs tests, linting, and formatting checks
|
||||||
|
2. ✅ **Bumps Version** - Updates `package.json` and installer version
|
||||||
|
3. ✅ **Generates Release Notes** - Categorizes commits since last release:
|
||||||
|
- ✨ **New Features** (`feat:`, `Feature:`)
|
||||||
|
- 🐛 **Bug Fixes** (`fix:`, `Fix:`)
|
||||||
|
- 🔧 **Maintenance** (`chore:`, `Chore:`)
|
||||||
|
- 📦 **Other Changes** (everything else)
|
||||||
|
4. ✅ **Creates Git Tag** - Tags the release version
|
||||||
|
5. ✅ **Publishes to NPM** - With `@latest` tag for user installations
|
||||||
|
6. ✅ **Creates GitHub Release** - With formatted release notes
|
||||||
|
|
||||||
|
## 📋 Sample Release Notes
|
||||||
|
|
||||||
|
The workflow automatically generates professional release notes like this:
|
||||||
|
|
||||||
|
````markdown
|
||||||
|
## 🚀 What's New in v5.2.0
|
||||||
|
|
||||||
|
### ✨ New Features
|
||||||
|
|
||||||
|
- feat: add team collaboration mode
|
||||||
|
- feat: enhance CLI with interactive prompts
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- fix: resolve installation path issues
|
||||||
|
- fix: handle edge cases in agent loading
|
||||||
|
|
||||||
|
### 🔧 Maintenance
|
||||||
|
|
||||||
|
- chore: update dependencies
|
||||||
|
- chore: improve error messages
|
||||||
|
|
||||||
|
## 📦 Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
chore: update dependencies # No release
|
npx bmad-method install
|
||||||
docs: fix typo in readme # No release
|
|
||||||
style: format code # No release
|
|
||||||
test: add unit tests # No release
|
|
||||||
```
|
```
|
||||||
|
````
|
||||||
|
|
||||||
### Test Your Setup
|
**Full Changelog**: https://github.com/bmadcode/BMAD-METHOD/compare/v5.1.0...v5.2.0
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
## 🎯 User Installation
|
||||||
|
|
||||||
|
After any release, users can immediately get the new version with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run release:test # Safe to run locally - tests the config
|
npx bmad-method install # Always gets latest release
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
## 📊 Preview Before Release
|
||||||
|
|
||||||
## Manual Release Methods (Exceptions Only)
|
Always preview what will be included in your release:
|
||||||
|
|
||||||
⚠️ Only use these methods if you need to bypass the automatic system
|
|
||||||
|
|
||||||
### Quick Manual Version Bump
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run version:patch # 4.1.0 → 4.1.1 (bug fixes)
|
npm run preview:release
|
||||||
npm run version:minor # 4.1.0 → 4.2.0 (new features)
|
|
||||||
npm run version:major # 4.1.0 → 5.0.0 (breaking changes)
|
|
||||||
|
|
||||||
# Then manually publish:
|
|
||||||
npm publish
|
|
||||||
git push && git push --tags
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Manual GitHub Actions Trigger
|
This shows:
|
||||||
|
|
||||||
You can also trigger releases manually through GitHub Actions workflow dispatch if needed.
|
- Commits since last release
|
||||||
|
- Categorized changes
|
||||||
|
- Estimated next version
|
||||||
|
- Release notes preview
|
||||||
|
|
||||||
|
## 🔧 Manual Release (GitHub UI)
|
||||||
|
|
||||||
|
You can also trigger releases through GitHub Actions:
|
||||||
|
|
||||||
|
1. Go to **GitHub Actions** → **Manual Release**
|
||||||
|
2. Click **"Run workflow"**
|
||||||
|
3. Choose version bump type (patch/minor/major)
|
||||||
|
4. Everything else happens automatically
|
||||||
|
|
||||||
|
## 📈 Version Strategy
|
||||||
|
|
||||||
|
- **Patch** (5.1.0 → 5.1.1): Bug fixes, minor improvements
|
||||||
|
- **Minor** (5.1.0 → 5.2.0): New features, enhancements
|
||||||
|
- **Major** (5.1.0 → 6.0.0): Breaking changes, major redesigns
|
||||||
|
|
||||||
|
## 🛠️ Development Workflow
|
||||||
|
|
||||||
|
1. **Develop Freely** - Merge PRs to main without triggering releases
|
||||||
|
2. **Test Unreleased Changes** - Clone repo to test latest main branch
|
||||||
|
3. **Release When Ready** - Use command line or GitHub Actions to cut releases
|
||||||
|
4. **Users Get Updates** - Via simple `npx bmad-method install` command
|
||||||
|
|
||||||
|
This gives you complete control over when releases happen while automating all the tedious parts like version bumping, release notes, and publishing.
|
||||||
|
|
||||||
|
## 🔍 Troubleshooting
|
||||||
|
|
||||||
|
### Check Release Status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gh run list --workflow="Manual Release"
|
||||||
|
npm view bmad-method dist-tags
|
||||||
|
git tag -l | sort -V | tail -5
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Latest Release
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gh release view --web
|
||||||
|
npm view bmad-method versions --json
|
||||||
|
```
|
||||||
|
|
||||||
|
### If Release Fails
|
||||||
|
|
||||||
|
- Check GitHub Actions logs: `gh run view <run-id> --log-failed`
|
||||||
|
- Verify NPM tokens are configured
|
||||||
|
- Ensure branch protection allows workflow pushes
|
||||||
|
````
|
||||||
|
|||||||
15
package.json
15
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "bmad-method",
|
"name": "bmad-method",
|
||||||
"version": "5.0.0",
|
"version": "5.1.2",
|
||||||
"description": "Breakthrough Method of Agile AI-driven Development",
|
"description": "Breakthrough Method of Agile AI-driven Development",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"agile",
|
"agile",
|
||||||
@@ -35,8 +35,11 @@
|
|||||||
"lint:fix": "eslint . --ext .js,.cjs,.mjs,.yaml --fix",
|
"lint:fix": "eslint . --ext .js,.cjs,.mjs,.yaml --fix",
|
||||||
"list:agents": "node tools/cli.js list:agents",
|
"list:agents": "node tools/cli.js list:agents",
|
||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"release": "semantic-release",
|
"preview:release": "node tools/preview-release-notes.js",
|
||||||
"release:test": "semantic-release --dry-run --no-ci || echo 'Config test complete - authentication errors are expected locally'",
|
"release:major": "gh workflow run \"Manual Release\" -f version_bump=major",
|
||||||
|
"release:minor": "gh workflow run \"Manual Release\" -f version_bump=minor",
|
||||||
|
"release:patch": "gh workflow run \"Manual Release\" -f version_bump=patch",
|
||||||
|
"release:watch": "gh run watch",
|
||||||
"validate": "node tools/cli.js validate",
|
"validate": "node tools/cli.js validate",
|
||||||
"version:all": "node tools/bump-all-versions.js",
|
"version:all": "node tools/bump-all-versions.js",
|
||||||
"version:all:major": "node tools/bump-all-versions.js major",
|
"version:all:major": "node tools/bump-all-versions.js major",
|
||||||
@@ -80,8 +83,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.33.0",
|
"@eslint/js": "^9.33.0",
|
||||||
"@semantic-release/changelog": "^6.0.3",
|
|
||||||
"@semantic-release/git": "^10.0.1",
|
|
||||||
"eslint": "^9.33.0",
|
"eslint": "^9.33.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-n": "^17.21.3",
|
"eslint-plugin-n": "^17.21.3",
|
||||||
@@ -92,11 +93,13 @@
|
|||||||
"lint-staged": "^16.1.1",
|
"lint-staged": "^16.1.1",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"prettier-plugin-packagejson": "^2.5.19",
|
"prettier-plugin-packagejson": "^2.5.19",
|
||||||
"semantic-release": "^22.0.0",
|
|
||||||
"yaml-eslint-parser": "^1.2.3",
|
"yaml-eslint-parser": "^1.2.3",
|
||||||
"yaml-lint": "^1.7.0"
|
"yaml-lint": "^1.7.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.10.0"
|
"node": ">=20.10.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,9 +125,6 @@ program
|
|||||||
// Ensure output directory exists
|
// Ensure output directory exists
|
||||||
await fs.ensureDir(path.dirname(outputPath));
|
await fs.ensureDir(path.dirname(outputPath));
|
||||||
|
|
||||||
console.log(`Flattening codebase from: ${inputDir}`);
|
|
||||||
console.log(`Output file: ${outputPath}`);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Verify input directory exists
|
// Verify input directory exists
|
||||||
if (!(await fs.pathExists(inputDir))) {
|
if (!(await fs.pathExists(inputDir))) {
|
||||||
@@ -158,10 +155,6 @@ program
|
|||||||
if (aggregatedContent.errors.length > 0) {
|
if (aggregatedContent.errors.length > 0) {
|
||||||
console.log(`Errors: ${aggregatedContent.errors.length}`);
|
console.log(`Errors: ${aggregatedContent.errors.length}`);
|
||||||
}
|
}
|
||||||
console.log(`Text files: ${aggregatedContent.textFiles.length}`);
|
|
||||||
if (aggregatedContent.binaryFiles.length > 0) {
|
|
||||||
console.log(`Binary files: ${aggregatedContent.binaryFiles.length}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate XML output using streaming
|
// Generate XML output using streaming
|
||||||
const xmlSpinner = ora('🔧 Generating XML output...').start();
|
const xmlSpinner = ora('🔧 Generating XML output...').start();
|
||||||
@@ -170,7 +163,7 @@ program
|
|||||||
|
|
||||||
// Calculate and display statistics
|
// Calculate and display statistics
|
||||||
const outputStats = await fs.stat(outputPath);
|
const outputStats = await fs.stat(outputPath);
|
||||||
const stats = calculateStatistics(aggregatedContent, outputStats.size);
|
const stats = await calculateStatistics(aggregatedContent, outputStats.size, inputDir);
|
||||||
|
|
||||||
// Display completion summary
|
// Display completion summary
|
||||||
console.log('\n📊 Completion Summary:');
|
console.log('\n📊 Completion Summary:');
|
||||||
@@ -183,8 +176,389 @@ program
|
|||||||
console.log(`📝 Total lines of code: ${stats.totalLines.toLocaleString()}`);
|
console.log(`📝 Total lines of code: ${stats.totalLines.toLocaleString()}`);
|
||||||
console.log(`🔢 Estimated tokens: ${stats.estimatedTokens}`);
|
console.log(`🔢 Estimated tokens: ${stats.estimatedTokens}`);
|
||||||
console.log(
|
console.log(
|
||||||
`📊 File breakdown: ${stats.textFiles} text, ${stats.binaryFiles} binary, ${stats.errorFiles} errors`,
|
`📊 File breakdown: ${stats.textFiles} text, ${stats.binaryFiles} binary, ${stats.errorFiles} errors\n`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Ask user if they want detailed stats + markdown report
|
||||||
|
const generateDetailed = await promptYesNo(
|
||||||
|
'Generate detailed stats (console + markdown) now?',
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (generateDetailed) {
|
||||||
|
// Additional detailed stats
|
||||||
|
console.log('\n📈 Size Percentiles:');
|
||||||
|
console.log(
|
||||||
|
` Avg: ${Math.round(stats.avgFileSize).toLocaleString()} B, Median: ${Math.round(
|
||||||
|
stats.medianFileSize,
|
||||||
|
).toLocaleString()} B, p90: ${stats.p90.toLocaleString()} B, p95: ${stats.p95.toLocaleString()} B, p99: ${stats.p99.toLocaleString()} B`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (Array.isArray(stats.histogram) && stats.histogram.length > 0) {
|
||||||
|
console.log('\n🧮 Size Histogram:');
|
||||||
|
for (const b of stats.histogram.slice(0, 2)) {
|
||||||
|
console.log(` ${b.label}: ${b.count} files, ${b.bytes.toLocaleString()} bytes`);
|
||||||
|
}
|
||||||
|
if (stats.histogram.length > 2) {
|
||||||
|
console.log(` … and ${stats.histogram.length - 2} more buckets`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(stats.byExtension) && stats.byExtension.length > 0) {
|
||||||
|
const topExt = stats.byExtension.slice(0, 2);
|
||||||
|
console.log('\n📦 Top Extensions:');
|
||||||
|
for (const e of topExt) {
|
||||||
|
const pct = stats.totalBytes ? (e.bytes / stats.totalBytes) * 100 : 0;
|
||||||
|
console.log(
|
||||||
|
` ${e.ext}: ${e.count} files, ${e.bytes.toLocaleString()} bytes (${pct.toFixed(
|
||||||
|
2,
|
||||||
|
)}%)`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (stats.byExtension.length > 2) {
|
||||||
|
console.log(` … and ${stats.byExtension.length - 2} more extensions`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(stats.byDirectory) && stats.byDirectory.length > 0) {
|
||||||
|
const topDir = stats.byDirectory.slice(0, 2);
|
||||||
|
console.log('\n📂 Top Directories:');
|
||||||
|
for (const d of topDir) {
|
||||||
|
const pct = stats.totalBytes ? (d.bytes / stats.totalBytes) * 100 : 0;
|
||||||
|
console.log(
|
||||||
|
` ${d.dir}: ${d.count} files, ${d.bytes.toLocaleString()} bytes (${pct.toFixed(
|
||||||
|
2,
|
||||||
|
)}%)`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (stats.byDirectory.length > 2) {
|
||||||
|
console.log(` … and ${stats.byDirectory.length - 2} more directories`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(stats.depthDistribution) && stats.depthDistribution.length > 0) {
|
||||||
|
console.log('\n🌳 Depth Distribution:');
|
||||||
|
const dd = stats.depthDistribution.slice(0, 2);
|
||||||
|
let line = ' ' + dd.map((d) => `${d.depth}:${d.count}`).join(' ');
|
||||||
|
if (stats.depthDistribution.length > 2) {
|
||||||
|
line += ` … +${stats.depthDistribution.length - 2} more`;
|
||||||
|
}
|
||||||
|
console.log(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(stats.longestPaths) && stats.longestPaths.length > 0) {
|
||||||
|
console.log('\n🧵 Longest Paths:');
|
||||||
|
for (const p of stats.longestPaths.slice(0, 2)) {
|
||||||
|
console.log(` ${p.path} (${p.length} chars, ${p.size.toLocaleString()} bytes)`);
|
||||||
|
}
|
||||||
|
if (stats.longestPaths.length > 2) {
|
||||||
|
console.log(` … and ${stats.longestPaths.length - 2} more paths`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.temporal) {
|
||||||
|
console.log('\n⏱️ Temporal:');
|
||||||
|
if (stats.temporal.oldest) {
|
||||||
|
console.log(
|
||||||
|
` Oldest: ${stats.temporal.oldest.path} (${stats.temporal.oldest.mtime})`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (stats.temporal.newest) {
|
||||||
|
console.log(
|
||||||
|
` Newest: ${stats.temporal.newest.path} (${stats.temporal.newest.mtime})`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (Array.isArray(stats.temporal.ageBuckets)) {
|
||||||
|
console.log(' Age buckets:');
|
||||||
|
for (const b of stats.temporal.ageBuckets.slice(0, 2)) {
|
||||||
|
console.log(` ${b.label}: ${b.count} files, ${b.bytes.toLocaleString()} bytes`);
|
||||||
|
}
|
||||||
|
if (stats.temporal.ageBuckets.length > 2) {
|
||||||
|
console.log(` … and ${stats.temporal.ageBuckets.length - 2} more buckets`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.quality) {
|
||||||
|
console.log('\n✅ Quality Signals:');
|
||||||
|
console.log(` Zero-byte files: ${stats.quality.zeroByteFiles}`);
|
||||||
|
console.log(` Empty text files: ${stats.quality.emptyTextFiles}`);
|
||||||
|
console.log(` Hidden files: ${stats.quality.hiddenFiles}`);
|
||||||
|
console.log(` Symlinks: ${stats.quality.symlinks}`);
|
||||||
|
console.log(
|
||||||
|
` Large files (>= ${(stats.quality.largeThreshold / (1024 * 1024)).toFixed(
|
||||||
|
0,
|
||||||
|
)} MB): ${stats.quality.largeFilesCount}`,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
` Suspiciously large files (>= 100 MB): ${stats.quality.suspiciousLargeFilesCount}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(stats.duplicateCandidates) && stats.duplicateCandidates.length > 0) {
|
||||||
|
console.log('\n🧬 Duplicate Candidates:');
|
||||||
|
for (const d of stats.duplicateCandidates.slice(0, 2)) {
|
||||||
|
console.log(` ${d.reason}: ${d.count} files @ ${d.size.toLocaleString()} bytes`);
|
||||||
|
}
|
||||||
|
if (stats.duplicateCandidates.length > 2) {
|
||||||
|
console.log(` … and ${stats.duplicateCandidates.length - 2} more groups`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof stats.compressibilityRatio === 'number') {
|
||||||
|
console.log(
|
||||||
|
`\n🗜️ Compressibility ratio (sampled): ${(stats.compressibilityRatio * 100).toFixed(
|
||||||
|
2,
|
||||||
|
)}%`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.git && stats.git.isRepo) {
|
||||||
|
console.log('\n🔧 Git:');
|
||||||
|
console.log(
|
||||||
|
` Tracked: ${stats.git.trackedCount} files, ${stats.git.trackedBytes.toLocaleString()} bytes`,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
` Untracked: ${stats.git.untrackedCount} files, ${stats.git.untrackedBytes.toLocaleString()} bytes`,
|
||||||
|
);
|
||||||
|
if (Array.isArray(stats.git.lfsCandidates) && stats.git.lfsCandidates.length > 0) {
|
||||||
|
console.log(' LFS candidates (top 2):');
|
||||||
|
for (const f of stats.git.lfsCandidates.slice(0, 2)) {
|
||||||
|
console.log(` ${f.path} (${f.size.toLocaleString()} bytes)`);
|
||||||
|
}
|
||||||
|
if (stats.git.lfsCandidates.length > 2) {
|
||||||
|
console.log(` … and ${stats.git.lfsCandidates.length - 2} more`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(stats.largestFiles) && stats.largestFiles.length > 0) {
|
||||||
|
console.log('\n📚 Largest Files (top 2):');
|
||||||
|
for (const f of stats.largestFiles.slice(0, 2)) {
|
||||||
|
// Show LOC for text files when available; omit ext and mtime
|
||||||
|
let locStr = '';
|
||||||
|
if (!f.isBinary && Array.isArray(aggregatedContent?.textFiles)) {
|
||||||
|
const tf = aggregatedContent.textFiles.find((t) => t.path === f.path);
|
||||||
|
if (tf && typeof tf.lines === 'number') {
|
||||||
|
locStr = `, LOC: ${tf.lines.toLocaleString()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(
|
||||||
|
` ${f.path} – ${f.sizeFormatted} (${f.percentOfTotal.toFixed(2)}%)${locStr}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (stats.largestFiles.length > 2) {
|
||||||
|
console.log(` … and ${stats.largestFiles.length - 2} more files`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write a comprehensive markdown report next to the XML
|
||||||
|
{
|
||||||
|
const mdPath = outputPath.endsWith('.xml')
|
||||||
|
? outputPath.replace(/\.xml$/i, '.stats.md')
|
||||||
|
: outputPath + '.stats.md';
|
||||||
|
try {
|
||||||
|
const pct = (num, den) => (den ? (num / den) * 100 : 0);
|
||||||
|
const md = [];
|
||||||
|
md.push(
|
||||||
|
`# 🧾 Flatten Stats for ${path.basename(outputPath)}`,
|
||||||
|
'',
|
||||||
|
'## 📊 Summary',
|
||||||
|
`- Total source size: ${stats.totalSize}`,
|
||||||
|
`- Generated XML size: ${stats.xmlSize}`,
|
||||||
|
`- Total lines of code: ${stats.totalLines.toLocaleString()}`,
|
||||||
|
`- Estimated tokens: ${stats.estimatedTokens}`,
|
||||||
|
`- File breakdown: ${stats.textFiles} text, ${stats.binaryFiles} binary, ${stats.errorFiles} errors`,
|
||||||
|
'',
|
||||||
|
'## 📈 Size Percentiles',
|
||||||
|
`Avg: ${Math.round(stats.avgFileSize).toLocaleString()} B, Median: ${Math.round(
|
||||||
|
stats.medianFileSize,
|
||||||
|
).toLocaleString()} B, p90: ${stats.p90.toLocaleString()} B, p95: ${stats.p95.toLocaleString()} B, p99: ${stats.p99.toLocaleString()} B`,
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Histogram
|
||||||
|
if (Array.isArray(stats.histogram) && stats.histogram.length > 0) {
|
||||||
|
md.push(
|
||||||
|
'## 🧮 Size Histogram',
|
||||||
|
'| Bucket | Files | Bytes |',
|
||||||
|
'| --- | ---: | ---: |',
|
||||||
|
);
|
||||||
|
for (const b of stats.histogram) {
|
||||||
|
md.push(`| ${b.label} | ${b.count} | ${b.bytes.toLocaleString()} |`);
|
||||||
|
}
|
||||||
|
md.push('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top Extensions
|
||||||
|
if (Array.isArray(stats.byExtension) && stats.byExtension.length > 0) {
|
||||||
|
md.push(
|
||||||
|
'## 📦 Top Extensions by Bytes (Top 20)',
|
||||||
|
'| Ext | Files | Bytes | % of total |',
|
||||||
|
'| --- | ---: | ---: | ---: |',
|
||||||
|
);
|
||||||
|
for (const e of stats.byExtension.slice(0, 20)) {
|
||||||
|
const p = pct(e.bytes, stats.totalBytes);
|
||||||
|
md.push(
|
||||||
|
`| ${e.ext} | ${e.count} | ${e.bytes.toLocaleString()} | ${p.toFixed(2)}% |`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
md.push('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top Directories
|
||||||
|
if (Array.isArray(stats.byDirectory) && stats.byDirectory.length > 0) {
|
||||||
|
md.push(
|
||||||
|
'## 📂 Top Directories by Bytes (Top 20)',
|
||||||
|
'| Directory | Files | Bytes | % of total |',
|
||||||
|
'| --- | ---: | ---: | ---: |',
|
||||||
|
);
|
||||||
|
for (const d of stats.byDirectory.slice(0, 20)) {
|
||||||
|
const p = pct(d.bytes, stats.totalBytes);
|
||||||
|
md.push(
|
||||||
|
`| ${d.dir} | ${d.count} | ${d.bytes.toLocaleString()} | ${p.toFixed(2)}% |`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
md.push('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depth distribution
|
||||||
|
if (Array.isArray(stats.depthDistribution) && stats.depthDistribution.length > 0) {
|
||||||
|
md.push('## 🌳 Depth Distribution', '| Depth | Count |', '| ---: | ---: |');
|
||||||
|
for (const d of stats.depthDistribution) {
|
||||||
|
md.push(`| ${d.depth} | ${d.count} |`);
|
||||||
|
}
|
||||||
|
md.push('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Longest paths
|
||||||
|
if (Array.isArray(stats.longestPaths) && stats.longestPaths.length > 0) {
|
||||||
|
md.push(
|
||||||
|
'## 🧵 Longest Paths (Top 25)',
|
||||||
|
'| Path | Length | Bytes |',
|
||||||
|
'| --- | ---: | ---: |',
|
||||||
|
);
|
||||||
|
for (const pth of stats.longestPaths) {
|
||||||
|
md.push(`| ${pth.path} | ${pth.length} | ${pth.size.toLocaleString()} |`);
|
||||||
|
}
|
||||||
|
md.push('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporal
|
||||||
|
if (stats.temporal) {
|
||||||
|
md.push('## ⏱️ Temporal');
|
||||||
|
if (stats.temporal.oldest) {
|
||||||
|
md.push(`- Oldest: ${stats.temporal.oldest.path} (${stats.temporal.oldest.mtime})`);
|
||||||
|
}
|
||||||
|
if (stats.temporal.newest) {
|
||||||
|
md.push(`- Newest: ${stats.temporal.newest.path} (${stats.temporal.newest.mtime})`);
|
||||||
|
}
|
||||||
|
if (Array.isArray(stats.temporal.ageBuckets)) {
|
||||||
|
md.push('', '| Age | Files | Bytes |', '| --- | ---: | ---: |');
|
||||||
|
for (const b of stats.temporal.ageBuckets) {
|
||||||
|
md.push(`| ${b.label} | ${b.count} | ${b.bytes.toLocaleString()} |`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
md.push('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quality signals
|
||||||
|
if (stats.quality) {
|
||||||
|
md.push(
|
||||||
|
'## ✅ Quality Signals',
|
||||||
|
`- Zero-byte files: ${stats.quality.zeroByteFiles}`,
|
||||||
|
`- Empty text files: ${stats.quality.emptyTextFiles}`,
|
||||||
|
`- Hidden files: ${stats.quality.hiddenFiles}`,
|
||||||
|
`- Symlinks: ${stats.quality.symlinks}`,
|
||||||
|
`- Large files (>= ${(stats.quality.largeThreshold / (1024 * 1024)).toFixed(0)} MB): ${stats.quality.largeFilesCount}`,
|
||||||
|
`- Suspiciously large files (>= 100 MB): ${stats.quality.suspiciousLargeFilesCount}`,
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplicates
|
||||||
|
if (Array.isArray(stats.duplicateCandidates) && stats.duplicateCandidates.length > 0) {
|
||||||
|
md.push(
|
||||||
|
'## 🧬 Duplicate Candidates',
|
||||||
|
'| Reason | Files | Size (bytes) |',
|
||||||
|
'| --- | ---: | ---: |',
|
||||||
|
);
|
||||||
|
for (const d of stats.duplicateCandidates) {
|
||||||
|
md.push(`| ${d.reason} | ${d.count} | ${d.size.toLocaleString()} |`);
|
||||||
|
}
|
||||||
|
md.push('', '### 🧬 Duplicate Groups Details');
|
||||||
|
let dupIndex = 1;
|
||||||
|
for (const d of stats.duplicateCandidates) {
|
||||||
|
md.push(
|
||||||
|
`#### Group ${dupIndex}: ${d.count} files @ ${d.size.toLocaleString()} bytes (${d.reason})`,
|
||||||
|
);
|
||||||
|
if (Array.isArray(d.files) && d.files.length > 0) {
|
||||||
|
for (const fp of d.files) {
|
||||||
|
md.push(`- ${fp}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
md.push('- (file list unavailable)');
|
||||||
|
}
|
||||||
|
md.push('');
|
||||||
|
dupIndex++;
|
||||||
|
}
|
||||||
|
md.push('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compressibility
|
||||||
|
if (typeof stats.compressibilityRatio === 'number') {
|
||||||
|
md.push(
|
||||||
|
'## 🗜️ Compressibility',
|
||||||
|
`Sampled compressibility ratio: ${(stats.compressibilityRatio * 100).toFixed(2)}%`,
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Git
|
||||||
|
if (stats.git && stats.git.isRepo) {
|
||||||
|
md.push(
|
||||||
|
'## 🔧 Git',
|
||||||
|
`- Tracked: ${stats.git.trackedCount} files, ${stats.git.trackedBytes.toLocaleString()} bytes`,
|
||||||
|
`- Untracked: ${stats.git.untrackedCount} files, ${stats.git.untrackedBytes.toLocaleString()} bytes`,
|
||||||
|
);
|
||||||
|
if (Array.isArray(stats.git.lfsCandidates) && stats.git.lfsCandidates.length > 0) {
|
||||||
|
md.push('', '### 📦 LFS Candidates (Top 20)', '| Path | Bytes |', '| --- | ---: |');
|
||||||
|
for (const f of stats.git.lfsCandidates.slice(0, 20)) {
|
||||||
|
md.push(`| ${f.path} | ${f.size.toLocaleString()} |`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
md.push('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Largest Files
|
||||||
|
if (Array.isArray(stats.largestFiles) && stats.largestFiles.length > 0) {
|
||||||
|
md.push(
|
||||||
|
'## 📚 Largest Files (Top 50)',
|
||||||
|
'| Path | Size | % of total | LOC |',
|
||||||
|
'| --- | ---: | ---: | ---: |',
|
||||||
|
);
|
||||||
|
for (const f of stats.largestFiles) {
|
||||||
|
let loc = '';
|
||||||
|
if (!f.isBinary && Array.isArray(aggregatedContent?.textFiles)) {
|
||||||
|
const tf = aggregatedContent.textFiles.find((t) => t.path === f.path);
|
||||||
|
if (tf && typeof tf.lines === 'number') {
|
||||||
|
loc = tf.lines.toLocaleString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
md.push(
|
||||||
|
`| ${f.path} | ${f.sizeFormatted} | ${f.percentOfTotal.toFixed(2)}% | ${loc} |`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
md.push('');
|
||||||
|
}
|
||||||
|
|
||||||
|
await fs.writeFile(mdPath, md.join('\n'));
|
||||||
|
console.log(`\n🧾 Detailed stats report written to: ${mdPath}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`⚠️ Failed to write stats markdown: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Critical error:', error.message);
|
console.error('❌ Critical error:', error.message);
|
||||||
console.error('An unexpected error occurred.');
|
console.error('An unexpected error occurred.');
|
||||||
|
|||||||
@@ -1,40 +1,203 @@
|
|||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
|
|
||||||
|
// Deno/Node compatibility: explicitly import process
|
||||||
|
const process = require('node:process');
|
||||||
|
const { execFile } = require('node:child_process');
|
||||||
|
const { promisify } = require('node:util');
|
||||||
|
const execFileAsync = promisify(execFile);
|
||||||
|
|
||||||
|
// Simple memoization across calls (keyed by realpath of startDir)
|
||||||
|
const _cache = new Map();
|
||||||
|
|
||||||
|
async function _tryRun(cmd, args, cwd, timeoutMs = 500) {
|
||||||
|
try {
|
||||||
|
const { stdout } = await execFileAsync(cmd, args, {
|
||||||
|
cwd,
|
||||||
|
timeout: timeoutMs,
|
||||||
|
windowsHide: true,
|
||||||
|
maxBuffer: 1024 * 1024,
|
||||||
|
});
|
||||||
|
const out = String(stdout || '').trim();
|
||||||
|
return out || null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _detectVcsTopLevel(startDir) {
|
||||||
|
// Run common VCS root queries in parallel; ignore failures
|
||||||
|
const gitP = _tryRun('git', ['rev-parse', '--show-toplevel'], startDir);
|
||||||
|
const hgP = _tryRun('hg', ['root'], startDir);
|
||||||
|
const svnP = (async () => {
|
||||||
|
const show = await _tryRun('svn', ['info', '--show-item', 'wc-root'], startDir);
|
||||||
|
if (show) return show;
|
||||||
|
const info = await _tryRun('svn', ['info'], startDir);
|
||||||
|
if (info) {
|
||||||
|
const line = info
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.find((l) => l.toLowerCase().startsWith('working copy root path:'));
|
||||||
|
if (line) return line.split(':').slice(1).join(':').trim();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})();
|
||||||
|
const [git, hg, svn] = await Promise.all([gitP, hgP, svnP]);
|
||||||
|
return git || hg || svn || null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to find the project root by walking up from startDir
|
* Attempt to find the project root by walking up from startDir.
|
||||||
* Looks for common project markers like .git, package.json, pyproject.toml, etc.
|
* Uses a robust, prioritized set of ecosystem markers (VCS > workspaces/monorepo > lock/build > language config).
|
||||||
|
* Also recognizes package.json with "workspaces" as a workspace root.
|
||||||
|
* You can augment markers via env PROJECT_ROOT_MARKERS as a comma-separated list of file/dir names.
|
||||||
* @param {string} startDir
|
* @param {string} startDir
|
||||||
* @returns {Promise<string|null>} project root directory or null if not found
|
* @returns {Promise<string|null>} project root directory or null if not found
|
||||||
*/
|
*/
|
||||||
async function findProjectRoot(startDir) {
|
async function findProjectRoot(startDir) {
|
||||||
try {
|
try {
|
||||||
|
// Resolve symlinks for robustness (e.g., when invoked from a symlinked path)
|
||||||
let dir = path.resolve(startDir);
|
let dir = path.resolve(startDir);
|
||||||
const root = path.parse(dir).root;
|
try {
|
||||||
const markers = [
|
dir = await fs.realpath(dir);
|
||||||
'.git',
|
} catch {
|
||||||
'package.json',
|
// ignore if realpath fails; continue with resolved path
|
||||||
'pnpm-workspace.yaml',
|
}
|
||||||
'yarn.lock',
|
const startKey = dir; // preserve starting point for caching
|
||||||
'pnpm-lock.yaml',
|
if (_cache.has(startKey)) return _cache.get(startKey);
|
||||||
'pyproject.toml',
|
const fsRoot = path.parse(dir).root;
|
||||||
'requirements.txt',
|
|
||||||
'go.mod',
|
// Helper to safely check for existence
|
||||||
'Cargo.toml',
|
const exists = (p) => fs.pathExists(p);
|
||||||
'composer.json',
|
|
||||||
'.hg',
|
// Build checks: an array of { makePath: (dir) => string, weight }
|
||||||
'.svn',
|
const checks = [];
|
||||||
];
|
|
||||||
|
const add = (rel, weight) => {
|
||||||
|
const makePath = (d) => (Array.isArray(rel) ? path.join(d, ...rel) : path.join(d, rel));
|
||||||
|
checks.push({ makePath, weight });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Highest priority: explicit sentinel markers
|
||||||
|
add('.project-root', 110);
|
||||||
|
add('.workspace-root', 110);
|
||||||
|
add('.repo-root', 110);
|
||||||
|
|
||||||
|
// Highest priority: VCS roots
|
||||||
|
add('.git', 100);
|
||||||
|
add('.hg', 95);
|
||||||
|
add('.svn', 95);
|
||||||
|
|
||||||
|
// Monorepo/workspace indicators
|
||||||
|
add('pnpm-workspace.yaml', 90);
|
||||||
|
add('lerna.json', 90);
|
||||||
|
add('turbo.json', 90);
|
||||||
|
add('nx.json', 90);
|
||||||
|
add('rush.json', 90);
|
||||||
|
add('go.work', 90);
|
||||||
|
add('WORKSPACE', 90);
|
||||||
|
add('WORKSPACE.bazel', 90);
|
||||||
|
add('MODULE.bazel', 90);
|
||||||
|
add('pants.toml', 90);
|
||||||
|
|
||||||
|
// Lockfiles and package-manager/top-level locks
|
||||||
|
add('yarn.lock', 85);
|
||||||
|
add('pnpm-lock.yaml', 85);
|
||||||
|
add('package-lock.json', 85);
|
||||||
|
add('bun.lockb', 85);
|
||||||
|
add('Cargo.lock', 85);
|
||||||
|
add('composer.lock', 85);
|
||||||
|
add('poetry.lock', 85);
|
||||||
|
add('Pipfile.lock', 85);
|
||||||
|
add('Gemfile.lock', 85);
|
||||||
|
|
||||||
|
// Build-system root indicators
|
||||||
|
add('settings.gradle', 80);
|
||||||
|
add('settings.gradle.kts', 80);
|
||||||
|
add('gradlew', 80);
|
||||||
|
add('pom.xml', 80);
|
||||||
|
add('build.sbt', 80);
|
||||||
|
add(['project', 'build.properties'], 80);
|
||||||
|
|
||||||
|
// Language/project config markers
|
||||||
|
add('deno.json', 75);
|
||||||
|
add('deno.jsonc', 75);
|
||||||
|
add('pyproject.toml', 75);
|
||||||
|
add('Pipfile', 75);
|
||||||
|
add('requirements.txt', 75);
|
||||||
|
add('go.mod', 75);
|
||||||
|
add('Cargo.toml', 75);
|
||||||
|
add('composer.json', 75);
|
||||||
|
add('mix.exs', 75);
|
||||||
|
add('Gemfile', 75);
|
||||||
|
add('CMakeLists.txt', 75);
|
||||||
|
add('stack.yaml', 75);
|
||||||
|
add('cabal.project', 75);
|
||||||
|
add('rebar.config', 75);
|
||||||
|
add('pubspec.yaml', 75);
|
||||||
|
add('flake.nix', 75);
|
||||||
|
add('shell.nix', 75);
|
||||||
|
add('default.nix', 75);
|
||||||
|
add('.tool-versions', 75);
|
||||||
|
add('package.json', 74); // generic Node project (lower than lockfiles/workspaces)
|
||||||
|
|
||||||
|
// Changesets
|
||||||
|
add(['.changeset', 'config.json'], 70);
|
||||||
|
add('.changeset', 70);
|
||||||
|
|
||||||
|
// Custom markers via env (comma-separated names)
|
||||||
|
if (process.env.PROJECT_ROOT_MARKERS) {
|
||||||
|
for (const name of process.env.PROJECT_ROOT_MARKERS.split(',')
|
||||||
|
.map((s) => s.trim())
|
||||||
|
.filter(Boolean)) {
|
||||||
|
add(name, 72);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Check for package.json with "workspaces" */
|
||||||
|
const hasWorkspacePackageJson = async (d) => {
|
||||||
|
const pkgPath = path.join(d, 'package.json');
|
||||||
|
if (!(await exists(pkgPath))) return false;
|
||||||
|
try {
|
||||||
|
const raw = await fs.readFile(pkgPath, 'utf8');
|
||||||
|
const pkg = JSON.parse(raw);
|
||||||
|
return Boolean(pkg && pkg.workspaces);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let best = null; // { dir, weight }
|
||||||
|
|
||||||
|
// Try to detect VCS toplevel once up-front; treat as authoritative slightly above .git marker
|
||||||
|
const vcsTop = await _detectVcsTopLevel(dir);
|
||||||
|
if (vcsTop) {
|
||||||
|
best = { dir: vcsTop, weight: 101 };
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const exists = await Promise.all(markers.map((m) => fs.pathExists(path.join(dir, m))));
|
// Special check: package.json with "workspaces"
|
||||||
if (exists.some(Boolean)) {
|
if ((await hasWorkspacePackageJson(dir)) && (!best || 90 >= best.weight))
|
||||||
return dir;
|
best = { dir, weight: 90 };
|
||||||
|
|
||||||
|
// Evaluate all other checks in parallel
|
||||||
|
const results = await Promise.all(
|
||||||
|
checks.map(async (c) => ({ c, ok: await exists(c.makePath(dir)) })),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const { c, ok } of results) {
|
||||||
|
if (!ok) continue;
|
||||||
|
if (!best || c.weight >= best.weight) {
|
||||||
|
best = { dir, weight: c.weight };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (dir === root) break;
|
|
||||||
|
if (dir === fsRoot) break;
|
||||||
dir = path.dirname(dir);
|
dir = path.dirname(dir);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
const out = best ? best.dir : null;
|
||||||
|
_cache.set(startKey, out);
|
||||||
|
return out;
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
395
tools/flattener/stats.helpers.js
Normal file
395
tools/flattener/stats.helpers.js
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('node:fs/promises');
|
||||||
|
const path = require('node:path');
|
||||||
|
const zlib = require('node:zlib');
|
||||||
|
const { Buffer } = require('node:buffer');
|
||||||
|
const crypto = require('node:crypto');
|
||||||
|
const cp = require('node:child_process');
|
||||||
|
|
||||||
|
const KB = 1024;
|
||||||
|
const MB = 1024 * KB;
|
||||||
|
|
||||||
|
const formatSize = (bytes) => {
|
||||||
|
if (bytes < 1024) return `${bytes} B`;
|
||||||
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
||||||
|
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
||||||
|
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const percentile = (sorted, p) => {
|
||||||
|
if (sorted.length === 0) return 0;
|
||||||
|
const idx = Math.min(sorted.length - 1, Math.max(0, Math.ceil((p / 100) * sorted.length) - 1));
|
||||||
|
return sorted[idx];
|
||||||
|
};
|
||||||
|
|
||||||
|
async function processWithLimit(items, fn, concurrency = 64) {
|
||||||
|
for (let i = 0; i < items.length; i += concurrency) {
|
||||||
|
await Promise.all(items.slice(i, i + concurrency).map(fn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function enrichAllFiles(textFiles, binaryFiles) {
|
||||||
|
/** @type {Array<{ path: string; absolutePath: string; size: number; lines?: number; isBinary: boolean; ext: string; dir: string; depth: number; hidden: boolean; mtimeMs: number; isSymlink: boolean; }>} */
|
||||||
|
const allFiles = [];
|
||||||
|
|
||||||
|
async function enrich(file, isBinary) {
|
||||||
|
const ext = (path.extname(file.path) || '').toLowerCase();
|
||||||
|
const dir = path.dirname(file.path) || '.';
|
||||||
|
const depth = file.path.split(path.sep).filter(Boolean).length;
|
||||||
|
const hidden = file.path.split(path.sep).some((seg) => seg.startsWith('.'));
|
||||||
|
let mtimeMs = 0;
|
||||||
|
let isSymlink = false;
|
||||||
|
try {
|
||||||
|
const lst = await fs.lstat(file.absolutePath);
|
||||||
|
mtimeMs = lst.mtimeMs;
|
||||||
|
isSymlink = lst.isSymbolicLink();
|
||||||
|
} catch {
|
||||||
|
/* ignore lstat errors during enrichment */
|
||||||
|
}
|
||||||
|
allFiles.push({
|
||||||
|
path: file.path,
|
||||||
|
absolutePath: file.absolutePath,
|
||||||
|
size: file.size || 0,
|
||||||
|
lines: file.lines,
|
||||||
|
isBinary,
|
||||||
|
ext,
|
||||||
|
dir,
|
||||||
|
depth,
|
||||||
|
hidden,
|
||||||
|
mtimeMs,
|
||||||
|
isSymlink,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await processWithLimit(textFiles, (f) => enrich(f, false));
|
||||||
|
await processWithLimit(binaryFiles, (f) => enrich(f, true));
|
||||||
|
return allFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildHistogram(allFiles) {
|
||||||
|
const buckets = [
|
||||||
|
[1 * KB, '0–1KB'],
|
||||||
|
[10 * KB, '1–10KB'],
|
||||||
|
[100 * KB, '10–100KB'],
|
||||||
|
[1 * MB, '100KB–1MB'],
|
||||||
|
[10 * MB, '1–10MB'],
|
||||||
|
[100 * MB, '10–100MB'],
|
||||||
|
[Infinity, '>=100MB'],
|
||||||
|
];
|
||||||
|
const histogram = buckets.map(([_, label]) => ({ label, count: 0, bytes: 0 }));
|
||||||
|
for (const f of allFiles) {
|
||||||
|
for (const [i, bucket] of buckets.entries()) {
|
||||||
|
if (f.size < bucket[0]) {
|
||||||
|
histogram[i].count++;
|
||||||
|
histogram[i].bytes += f.size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return histogram;
|
||||||
|
}
|
||||||
|
|
||||||
|
function aggregateByExtension(allFiles) {
|
||||||
|
const byExtension = new Map();
|
||||||
|
for (const f of allFiles) {
|
||||||
|
const key = f.ext || '<none>';
|
||||||
|
const v = byExtension.get(key) || { ext: key, count: 0, bytes: 0 };
|
||||||
|
v.count++;
|
||||||
|
v.bytes += f.size;
|
||||||
|
byExtension.set(key, v);
|
||||||
|
}
|
||||||
|
return [...byExtension.values()].sort((a, b) => b.bytes - a.bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
function aggregateByDirectory(allFiles) {
|
||||||
|
const byDirectory = new Map();
|
||||||
|
function addDirBytes(dir, bytes) {
|
||||||
|
const v = byDirectory.get(dir) || { dir, count: 0, bytes: 0 };
|
||||||
|
v.count++;
|
||||||
|
v.bytes += bytes;
|
||||||
|
byDirectory.set(dir, v);
|
||||||
|
}
|
||||||
|
for (const f of allFiles) {
|
||||||
|
const parts = f.dir === '.' ? [] : f.dir.split(path.sep);
|
||||||
|
let acc = '';
|
||||||
|
for (let i = 0; i < parts.length; i++) {
|
||||||
|
acc = i === 0 ? parts[0] : acc + path.sep + parts[i];
|
||||||
|
addDirBytes(acc, f.size);
|
||||||
|
}
|
||||||
|
if (parts.length === 0) addDirBytes('.', f.size);
|
||||||
|
}
|
||||||
|
return [...byDirectory.values()].sort((a, b) => b.bytes - a.bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeDepthAndLongest(allFiles) {
|
||||||
|
const depthDistribution = new Map();
|
||||||
|
for (const f of allFiles) {
|
||||||
|
depthDistribution.set(f.depth, (depthDistribution.get(f.depth) || 0) + 1);
|
||||||
|
}
|
||||||
|
const longestPaths = [...allFiles]
|
||||||
|
.sort((a, b) => b.path.length - a.path.length)
|
||||||
|
.slice(0, 25)
|
||||||
|
.map((f) => ({ path: f.path, length: f.path.length, size: f.size }));
|
||||||
|
const depthDist = [...depthDistribution.entries()]
|
||||||
|
.sort((a, b) => a[0] - b[0])
|
||||||
|
.map(([depth, count]) => ({ depth, count }));
|
||||||
|
return { depthDist, longestPaths };
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeTemporal(allFiles, nowMs) {
|
||||||
|
let oldest = null,
|
||||||
|
newest = null;
|
||||||
|
const ageBuckets = [
|
||||||
|
{ label: '> 1 year', minDays: 365, maxDays: Infinity, count: 0, bytes: 0 },
|
||||||
|
{ label: '6–12 months', minDays: 180, maxDays: 365, count: 0, bytes: 0 },
|
||||||
|
{ label: '1–6 months', minDays: 30, maxDays: 180, count: 0, bytes: 0 },
|
||||||
|
{ label: '7–30 days', minDays: 7, maxDays: 30, count: 0, bytes: 0 },
|
||||||
|
{ label: '1–7 days', minDays: 1, maxDays: 7, count: 0, bytes: 0 },
|
||||||
|
{ label: '< 1 day', minDays: 0, maxDays: 1, count: 0, bytes: 0 },
|
||||||
|
];
|
||||||
|
for (const f of allFiles) {
|
||||||
|
const ageDays = Math.max(0, (nowMs - (f.mtimeMs || nowMs)) / (24 * 60 * 60 * 1000));
|
||||||
|
for (const b of ageBuckets) {
|
||||||
|
if (ageDays >= b.minDays && ageDays < b.maxDays) {
|
||||||
|
b.count++;
|
||||||
|
b.bytes += f.size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!oldest || f.mtimeMs < oldest.mtimeMs) oldest = f;
|
||||||
|
if (!newest || f.mtimeMs > newest.mtimeMs) newest = f;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
oldest: oldest
|
||||||
|
? { path: oldest.path, mtime: oldest.mtimeMs ? new Date(oldest.mtimeMs).toISOString() : null }
|
||||||
|
: null,
|
||||||
|
newest: newest
|
||||||
|
? { path: newest.path, mtime: newest.mtimeMs ? new Date(newest.mtimeMs).toISOString() : null }
|
||||||
|
: null,
|
||||||
|
ageBuckets,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeQuality(allFiles, textFiles) {
|
||||||
|
const zeroByteFiles = allFiles.filter((f) => f.size === 0).length;
|
||||||
|
const emptyTextFiles = textFiles.filter(
|
||||||
|
(f) => (f.size || 0) === 0 || (f.lines || 0) === 0,
|
||||||
|
).length;
|
||||||
|
const hiddenFiles = allFiles.filter((f) => f.hidden).length;
|
||||||
|
const symlinks = allFiles.filter((f) => f.isSymlink).length;
|
||||||
|
const largeThreshold = 50 * MB;
|
||||||
|
const suspiciousThreshold = 100 * MB;
|
||||||
|
const largeFilesCount = allFiles.filter((f) => f.size >= largeThreshold).length;
|
||||||
|
const suspiciousLargeFilesCount = allFiles.filter((f) => f.size >= suspiciousThreshold).length;
|
||||||
|
return {
|
||||||
|
zeroByteFiles,
|
||||||
|
emptyTextFiles,
|
||||||
|
hiddenFiles,
|
||||||
|
symlinks,
|
||||||
|
largeFilesCount,
|
||||||
|
suspiciousLargeFilesCount,
|
||||||
|
largeThreshold,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeDuplicates(allFiles, textFiles) {
|
||||||
|
const duplicatesBySize = new Map();
|
||||||
|
for (const f of allFiles) {
|
||||||
|
const key = String(f.size);
|
||||||
|
const arr = duplicatesBySize.get(key) || [];
|
||||||
|
arr.push(f);
|
||||||
|
duplicatesBySize.set(key, arr);
|
||||||
|
}
|
||||||
|
const duplicateCandidates = [];
|
||||||
|
for (const [sizeKey, arr] of duplicatesBySize.entries()) {
|
||||||
|
if (arr.length < 2) continue;
|
||||||
|
const textGroup = arr.filter((f) => !f.isBinary);
|
||||||
|
const otherGroup = arr.filter((f) => f.isBinary);
|
||||||
|
const contentHashGroups = new Map();
|
||||||
|
for (const tf of textGroup) {
|
||||||
|
try {
|
||||||
|
const src = textFiles.find((x) => x.absolutePath === tf.absolutePath);
|
||||||
|
const content = src ? src.content : '';
|
||||||
|
const h = crypto.createHash('sha1').update(content).digest('hex');
|
||||||
|
const g = contentHashGroups.get(h) || [];
|
||||||
|
g.push(tf);
|
||||||
|
contentHashGroups.set(h, g);
|
||||||
|
} catch {
|
||||||
|
/* ignore hashing errors for duplicate detection */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const [_h, g] of contentHashGroups.entries()) {
|
||||||
|
if (g.length > 1)
|
||||||
|
duplicateCandidates.push({
|
||||||
|
reason: 'same-size+text-hash',
|
||||||
|
size: Number(sizeKey),
|
||||||
|
count: g.length,
|
||||||
|
files: g.map((f) => f.path),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (otherGroup.length > 1) {
|
||||||
|
duplicateCandidates.push({
|
||||||
|
reason: 'same-size',
|
||||||
|
size: Number(sizeKey),
|
||||||
|
count: otherGroup.length,
|
||||||
|
files: otherGroup.map((f) => f.path),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return duplicateCandidates;
|
||||||
|
}
|
||||||
|
|
||||||
|
function estimateCompressibility(textFiles) {
|
||||||
|
let compSampleBytes = 0;
|
||||||
|
let compCompressedBytes = 0;
|
||||||
|
for (const tf of textFiles) {
|
||||||
|
try {
|
||||||
|
const sampleLen = Math.min(256 * 1024, tf.size || 0);
|
||||||
|
if (sampleLen <= 0) continue;
|
||||||
|
const sample = tf.content.slice(0, sampleLen);
|
||||||
|
const gz = zlib.gzipSync(Buffer.from(sample, 'utf8'));
|
||||||
|
compSampleBytes += sampleLen;
|
||||||
|
compCompressedBytes += gz.length;
|
||||||
|
} catch {
|
||||||
|
/* ignore compression errors during sampling */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return compSampleBytes > 0 ? compCompressedBytes / compSampleBytes : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeGitInfo(allFiles, rootDir, largeThreshold) {
|
||||||
|
const info = {
|
||||||
|
isRepo: false,
|
||||||
|
trackedCount: 0,
|
||||||
|
trackedBytes: 0,
|
||||||
|
untrackedCount: 0,
|
||||||
|
untrackedBytes: 0,
|
||||||
|
lfsCandidates: [],
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
if (!rootDir) return info;
|
||||||
|
const top = cp
|
||||||
|
.execFileSync('git', ['rev-parse', '--show-toplevel'], {
|
||||||
|
cwd: rootDir,
|
||||||
|
stdio: ['ignore', 'pipe', 'ignore'],
|
||||||
|
})
|
||||||
|
.toString()
|
||||||
|
.trim();
|
||||||
|
if (!top) return info;
|
||||||
|
info.isRepo = true;
|
||||||
|
const out = cp.execFileSync('git', ['ls-files', '-z'], {
|
||||||
|
cwd: rootDir,
|
||||||
|
stdio: ['ignore', 'pipe', 'ignore'],
|
||||||
|
});
|
||||||
|
const tracked = new Set(out.toString().split('\0').filter(Boolean));
|
||||||
|
let trackedBytes = 0,
|
||||||
|
trackedCount = 0,
|
||||||
|
untrackedBytes = 0,
|
||||||
|
untrackedCount = 0;
|
||||||
|
const lfsCandidates = [];
|
||||||
|
for (const f of allFiles) {
|
||||||
|
const isTracked = tracked.has(f.path);
|
||||||
|
if (isTracked) {
|
||||||
|
trackedCount++;
|
||||||
|
trackedBytes += f.size;
|
||||||
|
if (f.size >= largeThreshold) lfsCandidates.push({ path: f.path, size: f.size });
|
||||||
|
} else {
|
||||||
|
untrackedCount++;
|
||||||
|
untrackedBytes += f.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.trackedCount = trackedCount;
|
||||||
|
info.trackedBytes = trackedBytes;
|
||||||
|
info.untrackedCount = untrackedCount;
|
||||||
|
info.untrackedBytes = untrackedBytes;
|
||||||
|
info.lfsCandidates = lfsCandidates.sort((a, b) => b.size - a.size).slice(0, 50);
|
||||||
|
} catch {
|
||||||
|
/* git not available or not a repo, ignore */
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeLargestFiles(allFiles, totalBytes) {
|
||||||
|
const toPct = (num, den) => (den === 0 ? 0 : (num / den) * 100);
|
||||||
|
return [...allFiles]
|
||||||
|
.sort((a, b) => b.size - a.size)
|
||||||
|
.slice(0, 50)
|
||||||
|
.map((f) => ({
|
||||||
|
path: f.path,
|
||||||
|
size: f.size,
|
||||||
|
sizeFormatted: formatSize(f.size),
|
||||||
|
percentOfTotal: toPct(f.size, totalBytes),
|
||||||
|
ext: f.ext || '',
|
||||||
|
isBinary: f.isBinary,
|
||||||
|
mtime: f.mtimeMs ? new Date(f.mtimeMs).toISOString() : null,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function mdTable(rows, headers) {
|
||||||
|
const header = `| ${headers.join(' | ')} |`;
|
||||||
|
const sep = `| ${headers.map(() => '---').join(' | ')} |`;
|
||||||
|
const body = rows.map((r) => `| ${r.join(' | ')} |`).join('\n');
|
||||||
|
return `${header}\n${sep}\n${body}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildMarkdownReport(largestFiles, byExtensionArr, byDirectoryArr, totalBytes) {
|
||||||
|
const toPct = (num, den) => (den === 0 ? 0 : (num / den) * 100);
|
||||||
|
const md = [];
|
||||||
|
md.push(
|
||||||
|
'\n### Top Largest Files (Top 50)\n',
|
||||||
|
mdTable(
|
||||||
|
largestFiles.map((f) => [
|
||||||
|
f.path,
|
||||||
|
f.sizeFormatted,
|
||||||
|
`${f.percentOfTotal.toFixed(2)}%`,
|
||||||
|
f.ext || '',
|
||||||
|
f.isBinary ? 'binary' : 'text',
|
||||||
|
]),
|
||||||
|
['Path', 'Size', '% of total', 'Ext', 'Type'],
|
||||||
|
),
|
||||||
|
'\n\n### Top Extensions by Bytes (Top 20)\n',
|
||||||
|
);
|
||||||
|
const topExtRows = byExtensionArr
|
||||||
|
.slice(0, 20)
|
||||||
|
.map((e) => [
|
||||||
|
e.ext,
|
||||||
|
String(e.count),
|
||||||
|
formatSize(e.bytes),
|
||||||
|
`${toPct(e.bytes, totalBytes).toFixed(2)}%`,
|
||||||
|
]);
|
||||||
|
md.push(
|
||||||
|
mdTable(topExtRows, ['Ext', 'Count', 'Bytes', '% of total']),
|
||||||
|
'\n\n### Top Directories by Bytes (Top 20)\n',
|
||||||
|
);
|
||||||
|
const topDirRows = byDirectoryArr
|
||||||
|
.slice(0, 20)
|
||||||
|
.map((d) => [
|
||||||
|
d.dir,
|
||||||
|
String(d.count),
|
||||||
|
formatSize(d.bytes),
|
||||||
|
`${toPct(d.bytes, totalBytes).toFixed(2)}%`,
|
||||||
|
]);
|
||||||
|
md.push(mdTable(topDirRows, ['Directory', 'Files', 'Bytes', '% of total']));
|
||||||
|
return md.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
KB,
|
||||||
|
MB,
|
||||||
|
formatSize,
|
||||||
|
percentile,
|
||||||
|
processWithLimit,
|
||||||
|
enrichAllFiles,
|
||||||
|
buildHistogram,
|
||||||
|
aggregateByExtension,
|
||||||
|
aggregateByDirectory,
|
||||||
|
computeDepthAndLongest,
|
||||||
|
computeTemporal,
|
||||||
|
computeQuality,
|
||||||
|
computeDuplicates,
|
||||||
|
estimateCompressibility,
|
||||||
|
computeGitInfo,
|
||||||
|
computeLargestFiles,
|
||||||
|
buildMarkdownReport,
|
||||||
|
};
|
||||||
@@ -1,29 +1,79 @@
|
|||||||
function calculateStatistics(aggregatedContent, xmlFileSize) {
|
const H = require('./stats.helpers.js');
|
||||||
|
|
||||||
|
async function calculateStatistics(aggregatedContent, xmlFileSize, rootDir) {
|
||||||
const { textFiles, binaryFiles, errors } = aggregatedContent;
|
const { textFiles, binaryFiles, errors } = aggregatedContent;
|
||||||
|
|
||||||
const totalTextSize = textFiles.reduce((sum, file) => sum + file.size, 0);
|
const totalLines = textFiles.reduce((sum, f) => sum + (f.lines || 0), 0);
|
||||||
const totalBinarySize = binaryFiles.reduce((sum, file) => sum + file.size, 0);
|
|
||||||
const totalSize = totalTextSize + totalBinarySize;
|
|
||||||
|
|
||||||
const totalLines = textFiles.reduce((sum, file) => sum + file.lines, 0);
|
|
||||||
|
|
||||||
const estimatedTokens = Math.ceil(xmlFileSize / 4);
|
const estimatedTokens = Math.ceil(xmlFileSize / 4);
|
||||||
|
|
||||||
const formatSize = (bytes) => {
|
// Build enriched file list
|
||||||
if (bytes < 1024) return `${bytes} B`;
|
const allFiles = await H.enrichAllFiles(textFiles, binaryFiles);
|
||||||
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
const totalBytes = allFiles.reduce((s, f) => s + f.size, 0);
|
||||||
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
const sizes = allFiles.map((f) => f.size).sort((a, b) => a - b);
|
||||||
};
|
const avgSize = sizes.length > 0 ? totalBytes / sizes.length : 0;
|
||||||
|
const medianSize = sizes.length > 0 ? H.percentile(sizes, 50) : 0;
|
||||||
|
const p90 = H.percentile(sizes, 90);
|
||||||
|
const p95 = H.percentile(sizes, 95);
|
||||||
|
const p99 = H.percentile(sizes, 99);
|
||||||
|
|
||||||
|
const histogram = H.buildHistogram(allFiles);
|
||||||
|
const byExtensionArr = H.aggregateByExtension(allFiles);
|
||||||
|
const byDirectoryArr = H.aggregateByDirectory(allFiles);
|
||||||
|
const { depthDist, longestPaths } = H.computeDepthAndLongest(allFiles);
|
||||||
|
const temporal = H.computeTemporal(allFiles, Date.now());
|
||||||
|
const quality = H.computeQuality(allFiles, textFiles);
|
||||||
|
const duplicateCandidates = H.computeDuplicates(allFiles, textFiles);
|
||||||
|
const compressibilityRatio = H.estimateCompressibility(textFiles);
|
||||||
|
const git = H.computeGitInfo(allFiles, rootDir, quality.largeThreshold);
|
||||||
|
const largestFiles = H.computeLargestFiles(allFiles, totalBytes);
|
||||||
|
const markdownReport = H.buildMarkdownReport(
|
||||||
|
largestFiles,
|
||||||
|
byExtensionArr,
|
||||||
|
byDirectoryArr,
|
||||||
|
totalBytes,
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
// Back-compat summary
|
||||||
totalFiles: textFiles.length + binaryFiles.length,
|
totalFiles: textFiles.length + binaryFiles.length,
|
||||||
textFiles: textFiles.length,
|
textFiles: textFiles.length,
|
||||||
binaryFiles: binaryFiles.length,
|
binaryFiles: binaryFiles.length,
|
||||||
errorFiles: errors.length,
|
errorFiles: errors.length,
|
||||||
totalSize: formatSize(totalSize),
|
totalSize: H.formatSize(totalBytes),
|
||||||
xmlSize: formatSize(xmlFileSize),
|
totalBytes,
|
||||||
|
xmlSize: H.formatSize(xmlFileSize),
|
||||||
totalLines,
|
totalLines,
|
||||||
estimatedTokens: estimatedTokens.toLocaleString(),
|
estimatedTokens: estimatedTokens.toLocaleString(),
|
||||||
|
|
||||||
|
// Distributions and percentiles
|
||||||
|
avgFileSize: avgSize,
|
||||||
|
medianFileSize: medianSize,
|
||||||
|
p90,
|
||||||
|
p95,
|
||||||
|
p99,
|
||||||
|
histogram,
|
||||||
|
|
||||||
|
// Extensions and directories
|
||||||
|
byExtension: byExtensionArr,
|
||||||
|
byDirectory: byDirectoryArr,
|
||||||
|
depthDistribution: depthDist,
|
||||||
|
longestPaths,
|
||||||
|
|
||||||
|
// Temporal
|
||||||
|
temporal,
|
||||||
|
|
||||||
|
// Quality signals
|
||||||
|
quality,
|
||||||
|
|
||||||
|
// Duplicates and compressibility
|
||||||
|
duplicateCandidates,
|
||||||
|
compressibilityRatio,
|
||||||
|
|
||||||
|
// Git-aware
|
||||||
|
git,
|
||||||
|
|
||||||
|
largestFiles,
|
||||||
|
markdownReport,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
413
tools/flattener/test-matrix.js
Normal file
413
tools/flattener/test-matrix.js
Normal file
@@ -0,0 +1,413 @@
|
|||||||
|
/* deno-lint-ignore-file */
|
||||||
|
/*
|
||||||
|
Automatic test matrix for project root detection.
|
||||||
|
Creates temporary fixtures for various ecosystems and validates findProjectRoot().
|
||||||
|
No external options or flags required. Safe to run multiple times.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const os = require('node:os');
|
||||||
|
const path = require('node:path');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const { promisify } = require('node:util');
|
||||||
|
const { execFile } = require('node:child_process');
|
||||||
|
const process = require('node:process');
|
||||||
|
const execFileAsync = promisify(execFile);
|
||||||
|
|
||||||
|
const { findProjectRoot } = require('./projectRoot.js');
|
||||||
|
|
||||||
|
async function cmdAvailable(cmd) {
|
||||||
|
try {
|
||||||
|
await execFileAsync(cmd, ['--version'], { timeout: 500, windowsHide: true });
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testSvnMarker() {
|
||||||
|
const root = await mkTmpDir('svn');
|
||||||
|
const nested = path.join(root, 'proj', 'code');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.ensureDir(path.join(root, '.svn'));
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
assertEqual(found, root, '.svn marker should be detected');
|
||||||
|
return { name: 'svn-marker', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testSymlinkStart() {
|
||||||
|
const root = await mkTmpDir('symlink-start');
|
||||||
|
const nested = path.join(root, 'a', 'b');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, '.project-root'), '\n');
|
||||||
|
const tmp = await mkTmpDir('symlink-tmp');
|
||||||
|
const link = path.join(tmp, 'link-to-b');
|
||||||
|
try {
|
||||||
|
await fs.symlink(nested, link);
|
||||||
|
} catch {
|
||||||
|
// symlink may not be permitted on some systems; skip
|
||||||
|
return { name: 'symlink-start', ok: true, skipped: true };
|
||||||
|
}
|
||||||
|
const found = await findProjectRoot(link);
|
||||||
|
assertEqual(found, root, 'should resolve symlinked start to real root');
|
||||||
|
return { name: 'symlink-start', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testSubmoduleLikeInnerGitFile() {
|
||||||
|
const root = await mkTmpDir('submodule-like');
|
||||||
|
const mid = path.join(root, 'mid');
|
||||||
|
const leaf = path.join(mid, 'leaf');
|
||||||
|
await fs.ensureDir(leaf);
|
||||||
|
// outer repo
|
||||||
|
await fs.ensureDir(path.join(root, '.git'));
|
||||||
|
// inner submodule-like .git file
|
||||||
|
await fs.writeFile(path.join(mid, '.git'), 'gitdir: ../.git/modules/mid\n');
|
||||||
|
const found = await findProjectRoot(leaf);
|
||||||
|
assertEqual(found, root, 'outermost .git should win on tie weight');
|
||||||
|
return { name: 'submodule-like-gitfile', ok: true };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mkTmpDir(name) {
|
||||||
|
const base = await fs.realpath(os.tmpdir());
|
||||||
|
const dir = await fs.mkdtemp(path.join(base, `flattener-${name}-`));
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertEqual(actual, expected, msg) {
|
||||||
|
if (actual !== expected) {
|
||||||
|
throw new Error(`${msg}: expected="${expected}" actual="${actual}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testSentinel() {
|
||||||
|
const root = await mkTmpDir('sentinel');
|
||||||
|
const nested = path.join(root, 'a', 'b', 'c');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, '.project-root'), '\n');
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'sentinel .project-root should win');
|
||||||
|
return { name: 'sentinel', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testOtherSentinels() {
|
||||||
|
const root = await mkTmpDir('other-sentinels');
|
||||||
|
const nested = path.join(root, 'x', 'y');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, '.workspace-root'), '\n');
|
||||||
|
const found1 = await findProjectRoot(nested);
|
||||||
|
assertEqual(found1, root, 'sentinel .workspace-root should win');
|
||||||
|
|
||||||
|
await fs.remove(path.join(root, '.workspace-root'));
|
||||||
|
await fs.writeFile(path.join(root, '.repo-root'), '\n');
|
||||||
|
const found2 = await findProjectRoot(nested);
|
||||||
|
assertEqual(found2, root, 'sentinel .repo-root should win');
|
||||||
|
return { name: 'other-sentinels', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testGitCliAndMarker() {
|
||||||
|
const hasGit = await cmdAvailable('git');
|
||||||
|
if (!hasGit) return { name: 'git-cli', ok: true, skipped: true };
|
||||||
|
|
||||||
|
const root = await mkTmpDir('git');
|
||||||
|
const nested = path.join(root, 'pkg', 'src');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await execFileAsync('git', ['init'], { cwd: root, timeout: 2000 });
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'git toplevel should be detected');
|
||||||
|
return { name: 'git-cli', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testHgMarkerOrCli() {
|
||||||
|
// Prefer simple marker test to avoid requiring Mercurial install
|
||||||
|
const root = await mkTmpDir('hg');
|
||||||
|
const nested = path.join(root, 'lib');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.ensureDir(path.join(root, '.hg'));
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, '.hg marker should be detected');
|
||||||
|
return { name: 'hg-marker', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testWorkspacePnpm() {
|
||||||
|
const root = await mkTmpDir('pnpm-workspace');
|
||||||
|
const pkgA = path.join(root, 'packages', 'a');
|
||||||
|
await fs.ensureDir(pkgA);
|
||||||
|
await fs.writeFile(path.join(root, 'pnpm-workspace.yaml'), 'packages:\n - packages/*\n');
|
||||||
|
const found = await findProjectRoot(pkgA);
|
||||||
|
await assertEqual(found, root, 'pnpm-workspace.yaml should be detected');
|
||||||
|
return { name: 'pnpm-workspace', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testPackageJsonWorkspaces() {
|
||||||
|
const root = await mkTmpDir('package-workspaces');
|
||||||
|
const pkgA = path.join(root, 'packages', 'a');
|
||||||
|
await fs.ensureDir(pkgA);
|
||||||
|
await fs.writeJson(
|
||||||
|
path.join(root, 'package.json'),
|
||||||
|
{ private: true, workspaces: ['packages/*'] },
|
||||||
|
{ spaces: 2 },
|
||||||
|
);
|
||||||
|
const found = await findProjectRoot(pkgA);
|
||||||
|
await assertEqual(found, root, 'package.json workspaces should be detected');
|
||||||
|
return { name: 'package.json-workspaces', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testLockfiles() {
|
||||||
|
const root = await mkTmpDir('lockfiles');
|
||||||
|
const nested = path.join(root, 'src');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, 'yarn.lock'), '\n');
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'yarn.lock should be detected');
|
||||||
|
return { name: 'lockfiles', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testLanguageConfigs() {
|
||||||
|
const root = await mkTmpDir('lang-configs');
|
||||||
|
const nested = path.join(root, 'x', 'y');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, 'pyproject.toml'), "[tool.poetry]\nname='tmp'\n");
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'pyproject.toml should be detected');
|
||||||
|
return { name: 'language-configs', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testPreferOuterOnTie() {
|
||||||
|
const root = await mkTmpDir('tie');
|
||||||
|
const mid = path.join(root, 'mid');
|
||||||
|
const leaf = path.join(mid, 'leaf');
|
||||||
|
await fs.ensureDir(leaf);
|
||||||
|
// same weight marker at two levels
|
||||||
|
await fs.writeFile(path.join(root, 'requirements.txt'), '\n');
|
||||||
|
await fs.writeFile(path.join(mid, 'requirements.txt'), '\n');
|
||||||
|
const found = await findProjectRoot(leaf);
|
||||||
|
await assertEqual(found, root, 'outermost directory should win on equal weight');
|
||||||
|
return { name: 'prefer-outermost-tie', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional coverage: Bazel, Nx/Turbo/Rush, Go workspaces, Deno, Java/Scala, PHP, Rust, Nix, Changesets, env markers,
|
||||||
|
// and priority interaction between package.json and lockfiles.
|
||||||
|
|
||||||
|
async function testBazelWorkspace() {
|
||||||
|
const root = await mkTmpDir('bazel');
|
||||||
|
const nested = path.join(root, 'apps', 'svc');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, 'WORKSPACE'), 'workspace(name="tmp")\n');
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'Bazel WORKSPACE should be detected');
|
||||||
|
return { name: 'bazel-workspace', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testNx() {
|
||||||
|
const root = await mkTmpDir('nx');
|
||||||
|
const nested = path.join(root, 'apps', 'web');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeJson(path.join(root, 'nx.json'), { npmScope: 'tmp' }, { spaces: 2 });
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'nx.json should be detected');
|
||||||
|
return { name: 'nx', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testTurbo() {
|
||||||
|
const root = await mkTmpDir('turbo');
|
||||||
|
const nested = path.join(root, 'packages', 'x');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeJson(path.join(root, 'turbo.json'), { pipeline: {} }, { spaces: 2 });
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'turbo.json should be detected');
|
||||||
|
return { name: 'turbo', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testRush() {
|
||||||
|
const root = await mkTmpDir('rush');
|
||||||
|
const nested = path.join(root, 'apps', 'a');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeJson(path.join(root, 'rush.json'), { projectFolderMinDepth: 1 }, { spaces: 2 });
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'rush.json should be detected');
|
||||||
|
return { name: 'rush', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testGoWorkAndMod() {
|
||||||
|
const root = await mkTmpDir('gowork');
|
||||||
|
const mod = path.join(root, 'modA');
|
||||||
|
const nested = path.join(mod, 'pkg');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, 'go.work'), 'go 1.22\nuse ./modA\n');
|
||||||
|
await fs.writeFile(path.join(mod, 'go.mod'), 'module example.com/a\ngo 1.22\n');
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'go.work should define the workspace root');
|
||||||
|
return { name: 'go-work', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testDenoJson() {
|
||||||
|
const root = await mkTmpDir('deno');
|
||||||
|
const nested = path.join(root, 'src');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeJson(path.join(root, 'deno.json'), { tasks: {} }, { spaces: 2 });
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'deno.json should be detected');
|
||||||
|
return { name: 'deno-json', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testGradleSettings() {
|
||||||
|
const root = await mkTmpDir('gradle');
|
||||||
|
const nested = path.join(root, 'app');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, 'settings.gradle'), "rootProject.name='tmp'\n");
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'settings.gradle should be detected');
|
||||||
|
return { name: 'gradle-settings', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testMavenPom() {
|
||||||
|
const root = await mkTmpDir('maven');
|
||||||
|
const nested = path.join(root, 'module');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, 'pom.xml'), '<project></project>\n');
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'pom.xml should be detected');
|
||||||
|
return { name: 'maven-pom', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testSbtBuild() {
|
||||||
|
const root = await mkTmpDir('sbt');
|
||||||
|
const nested = path.join(root, 'sub');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, 'build.sbt'), 'name := "tmp"\n');
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'build.sbt should be detected');
|
||||||
|
return { name: 'sbt-build', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testComposer() {
|
||||||
|
const root = await mkTmpDir('composer');
|
||||||
|
const nested = path.join(root, 'src');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeJson(path.join(root, 'composer.json'), { name: 'tmp/pkg' }, { spaces: 2 });
|
||||||
|
await fs.writeFile(path.join(root, 'composer.lock'), '{}\n');
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'composer.{json,lock} should be detected');
|
||||||
|
return { name: 'composer', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testCargo() {
|
||||||
|
const root = await mkTmpDir('cargo');
|
||||||
|
const nested = path.join(root, 'src');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, 'Cargo.toml'), "[package]\nname='tmp'\nversion='0.0.0'\n");
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'Cargo.toml should be detected');
|
||||||
|
return { name: 'cargo', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testNixFlake() {
|
||||||
|
const root = await mkTmpDir('nix');
|
||||||
|
const nested = path.join(root, 'work');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, 'flake.nix'), '{ }\n');
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'flake.nix should be detected');
|
||||||
|
return { name: 'nix-flake', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testChangesetConfig() {
|
||||||
|
const root = await mkTmpDir('changeset');
|
||||||
|
const nested = path.join(root, 'pkg');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.ensureDir(path.join(root, '.changeset'));
|
||||||
|
await fs.writeJson(
|
||||||
|
path.join(root, '.changeset', 'config.json'),
|
||||||
|
{ $schema: 'https://unpkg.com/@changesets/config@2.3.1/schema.json' },
|
||||||
|
{ spaces: 2 },
|
||||||
|
);
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, '.changeset/config.json should be detected');
|
||||||
|
return { name: 'changesets', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testEnvCustomMarker() {
|
||||||
|
const root = await mkTmpDir('env-marker');
|
||||||
|
const nested = path.join(root, 'dir');
|
||||||
|
await fs.ensureDir(nested);
|
||||||
|
await fs.writeFile(path.join(root, 'MY_ROOT'), '\n');
|
||||||
|
const prev = process.env.PROJECT_ROOT_MARKERS;
|
||||||
|
process.env.PROJECT_ROOT_MARKERS = 'MY_ROOT';
|
||||||
|
try {
|
||||||
|
const found = await findProjectRoot(nested);
|
||||||
|
await assertEqual(found, root, 'custom env marker should be honored');
|
||||||
|
} finally {
|
||||||
|
if (prev === undefined) delete process.env.PROJECT_ROOT_MARKERS;
|
||||||
|
else process.env.PROJECT_ROOT_MARKERS = prev;
|
||||||
|
}
|
||||||
|
return { name: 'env-custom-marker', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testPackageLowPriorityVsLock() {
|
||||||
|
const root = await mkTmpDir('pkg-vs-lock');
|
||||||
|
const nested = path.join(root, 'nested');
|
||||||
|
await fs.ensureDir(path.join(nested, 'deep'));
|
||||||
|
await fs.writeJson(path.join(nested, 'package.json'), { name: 'nested' }, { spaces: 2 });
|
||||||
|
await fs.writeFile(path.join(root, 'yarn.lock'), '\n');
|
||||||
|
const found = await findProjectRoot(path.join(nested, 'deep'));
|
||||||
|
await assertEqual(found, root, 'lockfile at root should outrank nested package.json');
|
||||||
|
return { name: 'package-vs-lock-priority', ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
const tests = [
|
||||||
|
testSentinel,
|
||||||
|
testOtherSentinels,
|
||||||
|
testGitCliAndMarker,
|
||||||
|
testHgMarkerOrCli,
|
||||||
|
testWorkspacePnpm,
|
||||||
|
testPackageJsonWorkspaces,
|
||||||
|
testLockfiles,
|
||||||
|
testLanguageConfigs,
|
||||||
|
testPreferOuterOnTie,
|
||||||
|
testBazelWorkspace,
|
||||||
|
testNx,
|
||||||
|
testTurbo,
|
||||||
|
testRush,
|
||||||
|
testGoWorkAndMod,
|
||||||
|
testDenoJson,
|
||||||
|
testGradleSettings,
|
||||||
|
testMavenPom,
|
||||||
|
testSbtBuild,
|
||||||
|
testComposer,
|
||||||
|
testCargo,
|
||||||
|
testNixFlake,
|
||||||
|
testChangesetConfig,
|
||||||
|
testEnvCustomMarker,
|
||||||
|
testPackageLowPriorityVsLock,
|
||||||
|
testSvnMarker,
|
||||||
|
testSymlinkStart,
|
||||||
|
testSubmoduleLikeInnerGitFile,
|
||||||
|
];
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
for (const t of tests) {
|
||||||
|
try {
|
||||||
|
const r = await t();
|
||||||
|
results.push({ ...r, ok: true });
|
||||||
|
console.log(`✔ ${r.name}${r.skipped ? ' (skipped)' : ''}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`✖ ${t.name}:`, error && error.message ? error.message : error);
|
||||||
|
results.push({ name: t.name, ok: false, error: String(error) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const failed = results.filter((r) => !r.ok);
|
||||||
|
console.log('\nSummary:');
|
||||||
|
for (const r of results) {
|
||||||
|
console.log(`- ${r.name}: ${r.ok ? 'ok' : 'FAIL'}${r.skipped ? ' (skipped)' : ''}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failed.length > 0) {
|
||||||
|
process.exitCode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run().catch((error) => {
|
||||||
|
console.error('Fatal error:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -403,6 +403,7 @@ async function promptInstallation() {
|
|||||||
{ name: 'Cline', value: 'cline' },
|
{ name: 'Cline', value: 'cline' },
|
||||||
{ name: 'Gemini CLI', value: 'gemini' },
|
{ name: 'Gemini CLI', value: 'gemini' },
|
||||||
{ name: 'Qwen Code', value: 'qwen-code' },
|
{ name: 'Qwen Code', value: 'qwen-code' },
|
||||||
|
{ name: 'Crush', value: 'crush' },
|
||||||
{ name: 'Github Copilot', value: 'github-copilot' },
|
{ name: 'Github Copilot', value: 'github-copilot' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -28,6 +28,16 @@ ide-configurations:
|
|||||||
# To use BMad agents in Claude Code:
|
# To use BMad agents in Claude Code:
|
||||||
# 1. Type /agent-name (e.g., "/dev", "/pm", "/architect")
|
# 1. Type /agent-name (e.g., "/dev", "/pm", "/architect")
|
||||||
# 2. Claude will switch to that agent's persona
|
# 2. Claude will switch to that agent's persona
|
||||||
|
crush:
|
||||||
|
name: Crush
|
||||||
|
rule-dir: .crush/commands/BMad/
|
||||||
|
format: multi-file
|
||||||
|
command-suffix: .md
|
||||||
|
instructions: |
|
||||||
|
# To use BMad agents in Crush:
|
||||||
|
# 1. Press CTRL + P and press TAB
|
||||||
|
# 2. Select agent or task
|
||||||
|
# 3. Crush will switch to that agent's persona / task
|
||||||
windsurf:
|
windsurf:
|
||||||
name: Windsurf
|
name: Windsurf
|
||||||
rule-dir: .windsurf/workflows/
|
rule-dir: .windsurf/workflows/
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ class IdeSetup extends BaseIdeSetup {
|
|||||||
case 'claude-code': {
|
case 'claude-code': {
|
||||||
return this.setupClaudeCode(installDir, selectedAgent);
|
return this.setupClaudeCode(installDir, selectedAgent);
|
||||||
}
|
}
|
||||||
|
case 'crush': {
|
||||||
|
return this.setupCrush(installDir, selectedAgent);
|
||||||
|
}
|
||||||
case 'windsurf': {
|
case 'windsurf': {
|
||||||
return this.setupWindsurf(installDir, selectedAgent);
|
return this.setupWindsurf(installDir, selectedAgent);
|
||||||
}
|
}
|
||||||
@@ -99,6 +102,44 @@ class IdeSetup extends BaseIdeSetup {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setupCrush(installDir, selectedAgent) {
|
||||||
|
// Setup bmad-core commands
|
||||||
|
const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
|
||||||
|
const coreAgents = selectedAgent ? [selectedAgent] : await this.getCoreAgentIds(installDir);
|
||||||
|
const coreTasks = await this.getCoreTaskIds(installDir);
|
||||||
|
await this.setupCrushForPackage(
|
||||||
|
installDir,
|
||||||
|
'core',
|
||||||
|
coreSlashPrefix,
|
||||||
|
coreAgents,
|
||||||
|
coreTasks,
|
||||||
|
'.bmad-core',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Setup expansion pack commands
|
||||||
|
const expansionPacks = await this.getInstalledExpansionPacks(installDir);
|
||||||
|
for (const packInfo of expansionPacks) {
|
||||||
|
const packSlashPrefix = await this.getExpansionPackSlashPrefix(packInfo.path);
|
||||||
|
const packAgents = await this.getExpansionPackAgents(packInfo.path);
|
||||||
|
const packTasks = await this.getExpansionPackTasks(packInfo.path);
|
||||||
|
|
||||||
|
if (packAgents.length > 0 || packTasks.length > 0) {
|
||||||
|
// Use the actual directory name where the expansion pack is installed
|
||||||
|
const rootPath = path.relative(installDir, packInfo.path);
|
||||||
|
await this.setupCrushForPackage(
|
||||||
|
installDir,
|
||||||
|
packInfo.name,
|
||||||
|
packSlashPrefix,
|
||||||
|
packAgents,
|
||||||
|
packTasks,
|
||||||
|
rootPath,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
async setupClaudeCode(installDir, selectedAgent) {
|
async setupClaudeCode(installDir, selectedAgent) {
|
||||||
// Setup bmad-core commands
|
// Setup bmad-core commands
|
||||||
const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
|
const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
|
||||||
@@ -234,6 +275,94 @@ class IdeSetup extends BaseIdeSetup {
|
|||||||
console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
|
console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setupCrushForPackage(installDir, packageName, slashPrefix, agentIds, taskIds, rootPath) {
|
||||||
|
const commandsBaseDir = path.join(installDir, '.crush', 'commands', slashPrefix);
|
||||||
|
const agentsDir = path.join(commandsBaseDir, 'agents');
|
||||||
|
const tasksDir = path.join(commandsBaseDir, 'tasks');
|
||||||
|
|
||||||
|
// Ensure directories exist
|
||||||
|
await fileManager.ensureDirectory(agentsDir);
|
||||||
|
await fileManager.ensureDirectory(tasksDir);
|
||||||
|
|
||||||
|
// Setup agents
|
||||||
|
for (const agentId of agentIds) {
|
||||||
|
// Find the agent file - for expansion packs, prefer the expansion pack version
|
||||||
|
let agentPath;
|
||||||
|
if (packageName === 'core') {
|
||||||
|
// For core, use the normal search
|
||||||
|
agentPath = await this.findAgentPath(agentId, installDir);
|
||||||
|
} else {
|
||||||
|
// For expansion packs, first try to find the agent in the expansion pack directory
|
||||||
|
const expansionPackPath = path.join(installDir, rootPath, 'agents', `${agentId}.md`);
|
||||||
|
if (await fileManager.pathExists(expansionPackPath)) {
|
||||||
|
agentPath = expansionPackPath;
|
||||||
|
} else {
|
||||||
|
// Fall back to core if not found in expansion pack
|
||||||
|
agentPath = await this.findAgentPath(agentId, installDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandPath = path.join(agentsDir, `${agentId}.md`);
|
||||||
|
|
||||||
|
if (agentPath) {
|
||||||
|
// Create command file with agent content
|
||||||
|
let agentContent = await fileManager.readFile(agentPath);
|
||||||
|
|
||||||
|
// Replace {root} placeholder with the appropriate root path for this context
|
||||||
|
agentContent = agentContent.replaceAll('{root}', rootPath);
|
||||||
|
|
||||||
|
// Add command header
|
||||||
|
let commandContent = `# /${agentId} Command\n\n`;
|
||||||
|
commandContent += `When this command is used, adopt the following agent persona:\n\n`;
|
||||||
|
commandContent += agentContent;
|
||||||
|
|
||||||
|
await fileManager.writeFile(commandPath, commandContent);
|
||||||
|
console.log(chalk.green(`✓ Created agent command: /${agentId}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup tasks
|
||||||
|
for (const taskId of taskIds) {
|
||||||
|
// Find the task file - for expansion packs, prefer the expansion pack version
|
||||||
|
let taskPath;
|
||||||
|
if (packageName === 'core') {
|
||||||
|
// For core, use the normal search
|
||||||
|
taskPath = await this.findTaskPath(taskId, installDir);
|
||||||
|
} else {
|
||||||
|
// For expansion packs, first try to find the task in the expansion pack directory
|
||||||
|
const expansionPackPath = path.join(installDir, rootPath, 'tasks', `${taskId}.md`);
|
||||||
|
if (await fileManager.pathExists(expansionPackPath)) {
|
||||||
|
taskPath = expansionPackPath;
|
||||||
|
} else {
|
||||||
|
// Fall back to core if not found in expansion pack
|
||||||
|
taskPath = await this.findTaskPath(taskId, installDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandPath = path.join(tasksDir, `${taskId}.md`);
|
||||||
|
|
||||||
|
if (taskPath) {
|
||||||
|
// Create command file with task content
|
||||||
|
let taskContent = await fileManager.readFile(taskPath);
|
||||||
|
|
||||||
|
// Replace {root} placeholder with the appropriate root path for this context
|
||||||
|
taskContent = taskContent.replaceAll('{root}', rootPath);
|
||||||
|
|
||||||
|
// Add command header
|
||||||
|
let commandContent = `# /${taskId} Task\n\n`;
|
||||||
|
commandContent += `When this command is used, execute the following task:\n\n`;
|
||||||
|
commandContent += taskContent;
|
||||||
|
|
||||||
|
await fileManager.writeFile(commandPath, commandContent);
|
||||||
|
console.log(chalk.green(`✓ Created task command: /${taskId}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.green(`\n✓ Created Crush commands for ${packageName} in ${commandsBaseDir}`));
|
||||||
|
console.log(chalk.dim(` - Agents in: ${agentsDir}`));
|
||||||
|
console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
|
||||||
|
}
|
||||||
|
|
||||||
async setupWindsurf(installDir, selectedAgent) {
|
async setupWindsurf(installDir, selectedAgent) {
|
||||||
const windsurfWorkflowDir = path.join(installDir, '.windsurf', 'workflows');
|
const windsurfWorkflowDir = path.join(installDir, '.windsurf', 'workflows');
|
||||||
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bmad-method",
|
"name": "bmad-method",
|
||||||
"version": "5.0.0",
|
"version": "5.1.2",
|
||||||
"description": "BMad Method installer - AI-powered Agile development framework",
|
"description": "BMad Method installer - AI-powered Agile development framework",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bmad",
|
"bmad",
|
||||||
|
|||||||
66
tools/preview-release-notes.js
Executable file
66
tools/preview-release-notes.js
Executable file
@@ -0,0 +1,66 @@
|
|||||||
|
const { execSync } = require('node:child_process');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
|
||||||
|
// Get the latest stable tag (exclude beta tags)
|
||||||
|
const allTags = execSync('git tag -l | sort -V', { encoding: 'utf8' }).split('\n').filter(Boolean);
|
||||||
|
const stableTags = allTags.filter((tag) => !tag.includes('beta'));
|
||||||
|
const latestTag = stableTags.at(-1) || 'v5.0.0';
|
||||||
|
|
||||||
|
// Get commits since last tag
|
||||||
|
const commits = execSync(`git log ${latestTag}..HEAD --pretty=format:"- %s" --reverse`, {
|
||||||
|
encoding: 'utf8',
|
||||||
|
})
|
||||||
|
.split('\n')
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
// Categorize commits
|
||||||
|
const features = commits.filter((commit) => /^- (feat|Feature)/.test(commit));
|
||||||
|
const fixes = commits.filter((commit) => /^- (fix|Fix)/.test(commit));
|
||||||
|
const chores = commits.filter((commit) => /^- (chore|Chore)/.test(commit));
|
||||||
|
const others = commits.filter(
|
||||||
|
(commit) => !/^- (feat|Feature|fix|Fix|chore|Chore|release:|Release:)/.test(commit),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get next version (you can modify this logic)
|
||||||
|
const currentVersion = require('../package.json').version;
|
||||||
|
const versionParts = currentVersion.split('.').map(Number);
|
||||||
|
const nextVersion = `${versionParts[0]}.${versionParts[1] + 1}.0`; // Default to minor bump
|
||||||
|
|
||||||
|
console.log(`## 🚀 What's New in v${nextVersion}\n`);
|
||||||
|
|
||||||
|
if (features.length > 0) {
|
||||||
|
console.log('### ✨ New Features');
|
||||||
|
for (const feature of features) console.log(feature);
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fixes.length > 0) {
|
||||||
|
console.log('### 🐛 Bug Fixes');
|
||||||
|
for (const fix of fixes) console.log(fix);
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (others.length > 0) {
|
||||||
|
console.log('### 📦 Other Changes');
|
||||||
|
for (const other of others) console.log(other);
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chores.length > 0) {
|
||||||
|
console.log('### 🔧 Maintenance');
|
||||||
|
for (const chore of chores) console.log(chore);
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n## 📦 Installation\n');
|
||||||
|
console.log('```bash');
|
||||||
|
console.log('npx bmad-method install');
|
||||||
|
console.log('```');
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`\n**Full Changelog**: https://github.com/bmadcode/BMAD-METHOD/compare/${latestTag}...v${nextVersion}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`\n---\n📊 **Summary**: ${commits.length} commits since ${latestTag}`);
|
||||||
|
console.log(`🏷️ **Previous tag**: ${latestTag}`);
|
||||||
|
console.log(`🚀 **Next version**: v${nextVersion} (estimated)`);
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/**
|
|
||||||
* Semantic-release plugin to sync installer package.json version
|
|
||||||
*/
|
|
||||||
|
|
||||||
const fs = require('node:fs');
|
|
||||||
const path = require('node:path');
|
|
||||||
|
|
||||||
// This function runs during the "prepare" step of semantic-release
|
|
||||||
function prepare(_, { nextRelease, logger }) {
|
|
||||||
// Define the path to the installer package.json file
|
|
||||||
const file = path.join(process.cwd(), 'tools/installer/package.json');
|
|
||||||
|
|
||||||
// If the file does not exist, skip syncing and log a message
|
|
||||||
if (!fs.existsSync(file)) return logger.log('Installer package.json not found, skipping');
|
|
||||||
|
|
||||||
// Read and parse the package.json file
|
|
||||||
const package_ = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
||||||
|
|
||||||
// Update the version field with the next release version
|
|
||||||
package_.version = nextRelease.version;
|
|
||||||
|
|
||||||
// Write the updated JSON back to the file
|
|
||||||
fs.writeFileSync(file, JSON.stringify(package_, null, 2) + '\n');
|
|
||||||
|
|
||||||
// Log success message
|
|
||||||
logger.log(`Synced installer package.json to version ${nextRelease.version}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Export the prepare function so semantic-release can use it
|
|
||||||
module.exports = { prepare };
|
|
||||||
@@ -31,18 +31,35 @@ async function bumpVersion(type = 'patch') {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(chalk.yellow('⚠️ Manual version bumping is disabled.'));
|
const currentVersion = getCurrentVersion();
|
||||||
console.log(chalk.blue('🤖 This project uses semantic-release for automated versioning.'));
|
const versionParts = currentVersion.split('.').map(Number);
|
||||||
console.log('');
|
let newVersion;
|
||||||
console.log(chalk.bold('To create a new release, use conventional commits:'));
|
|
||||||
console.log(chalk.cyan(' feat: new feature (minor version bump)'));
|
|
||||||
console.log(chalk.cyan(' fix: bug fix (patch version bump)'));
|
|
||||||
console.log(chalk.cyan(' feat!: breaking change (major version bump)'));
|
|
||||||
console.log('');
|
|
||||||
console.log(chalk.dim('Example: git commit -m "feat: add new installer features"'));
|
|
||||||
console.log(chalk.dim('Then push to main branch to trigger automatic release.'));
|
|
||||||
|
|
||||||
return null;
|
switch (type) {
|
||||||
|
case 'major': {
|
||||||
|
newVersion = `${versionParts[0] + 1}.0.0`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'minor': {
|
||||||
|
newVersion = `${versionParts[0]}.${versionParts[1] + 1}.0`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'patch': {
|
||||||
|
newVersion = `${versionParts[0]}.${versionParts[1]}.${versionParts[2] + 1}`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.blue(`Bumping version: ${currentVersion} → ${newVersion}`));
|
||||||
|
|
||||||
|
// Update package.json
|
||||||
|
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
||||||
|
packageJson.version = newVersion;
|
||||||
|
fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2) + '\n');
|
||||||
|
|
||||||
|
console.log(chalk.green(`✓ Updated package.json to ${newVersion}`));
|
||||||
|
|
||||||
|
return newVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
|
|||||||
Reference in New Issue
Block a user