specweave 1.0.76 → 1.0.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +70 -1
- package/package.json +1 -1
- package/plugins/specweave/agents/pm/AGENT.md +9 -4
- package/plugins/specweave/commands/auto.md +22 -0
- package/plugins/specweave/commands/save.md +101 -4
- package/plugins/specweave/hooks/README.md +30 -0
- package/plugins/specweave/hooks/hooks.json +10 -0
- package/plugins/specweave/hooks/stop-auto.sh +548 -44
- package/plugins/specweave/skills/brownfield-onboarder/SKILL.md +6 -6
- package/plugins/specweave/skills/increment-planner/SKILL.md +18 -0
- package/plugins/specweave/skills/umbrella-repo-detector/SKILL.md +13 -0
package/CLAUDE.md
CHANGED
|
@@ -157,7 +157,7 @@ brew install omnisharp # or: dotnet tool install -g omnisharp
|
|
|
157
157
|
- Combine with Explore agent for comprehensive understanding
|
|
158
158
|
<!-- SW:END:lsp -->
|
|
159
159
|
|
|
160
|
-
<!-- SW:SECTION:structure version="1.0.
|
|
160
|
+
<!-- SW:SECTION:structure version="1.0.61" -->
|
|
161
161
|
## Structure
|
|
162
162
|
|
|
163
163
|
```
|
|
@@ -170,6 +170,47 @@ brew install omnisharp # or: dotnet tool install -g omnisharp
|
|
|
170
170
|
└── config.json
|
|
171
171
|
```
|
|
172
172
|
|
|
173
|
+
### ⚠️ CRITICAL: Increment Folder Organization (MANDATORY)
|
|
174
|
+
|
|
175
|
+
**ONLY these files allowed at increment ROOT:**
|
|
176
|
+
```
|
|
177
|
+
.specweave/increments/####-name/
|
|
178
|
+
├── metadata.json # Increment state
|
|
179
|
+
├── spec.md # Specification
|
|
180
|
+
├── plan.md # Implementation plan
|
|
181
|
+
└── tasks.md # Task list
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**ALL other files MUST go in subfolders:**
|
|
185
|
+
```
|
|
186
|
+
.specweave/increments/####-name/
|
|
187
|
+
├── reports/ # Validation reports, QA reports, completion summaries
|
|
188
|
+
│ └── *.md # PM-VALIDATION-REPORT.md, qa-post-closure.md, etc.
|
|
189
|
+
├── logs/ # Debug logs, execution traces, session logs
|
|
190
|
+
│ └── {YYYY-MM-DD}/ # Daily logs with assets/
|
|
191
|
+
├── scripts/ # Helper scripts, automation tools
|
|
192
|
+
├── docs/ # Additional documentation, domain knowledge
|
|
193
|
+
│ └── domain/ # Domain models for brownfield analysis
|
|
194
|
+
└── backups/ # Backup files
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**File Routing Rules:**
|
|
198
|
+
| File Type | Folder | Examples |
|
|
199
|
+
|-----------|--------|----------|
|
|
200
|
+
| Validation reports | `reports/` | `PM-VALIDATION-REPORT.md`, `validation-report.md` |
|
|
201
|
+
| QA assessments | `reports/` | `qa-post-closure.md`, `COMPLETION-SUMMARY.md` |
|
|
202
|
+
| Session logs | `logs/{date}/` | `session.md`, `assets/` |
|
|
203
|
+
| Domain analysis | `docs/domain/` | `appointments/domain-model.md` |
|
|
204
|
+
| Helper scripts | `scripts/` | `migrate.sh`, `validate.js` |
|
|
205
|
+
|
|
206
|
+
**FORBIDDEN - Files that pollute increment root:**
|
|
207
|
+
```
|
|
208
|
+
❌ .specweave/increments/0001/PM-VALIDATION-REPORT.md # → reports/
|
|
209
|
+
❌ .specweave/increments/0001/completion-report.md # → reports/
|
|
210
|
+
❌ .specweave/increments/0001/domain-model.md # → docs/domain/
|
|
211
|
+
❌ .specweave/increments/0001/helper.sh # → scripts/
|
|
212
|
+
```
|
|
213
|
+
|
|
173
214
|
### ⚠️ CRITICAL: Multi-Repo Project Paths (MANDATORY)
|
|
174
215
|
|
|
175
216
|
**ALL multi-project repositories MUST be created in `repositories/` folder - NEVER in project root!**
|
|
@@ -976,6 +1017,8 @@ For **contributors to SpecWeave itself** (not users).
|
|
|
976
1017
|
|
|
977
1018
|
## Marketplace Installation (CRITICAL)
|
|
978
1019
|
|
|
1020
|
+
### For SpecWeave Contributors (Development)
|
|
1021
|
+
|
|
979
1022
|
**ALWAYS use GitHub marketplace mode. NEVER use local symlinks or directory mode.**
|
|
980
1023
|
|
|
981
1024
|
```bash
|
|
@@ -996,6 +1039,32 @@ bash scripts/refresh-marketplace.sh --github
|
|
|
996
1039
|
bash scripts/refresh-marketplace.sh # Defaults to --github
|
|
997
1040
|
```
|
|
998
1041
|
|
|
1042
|
+
### For End Users (Production)
|
|
1043
|
+
|
|
1044
|
+
**Users install SpecWeave globally and use CLI commands:**
|
|
1045
|
+
|
|
1046
|
+
```bash
|
|
1047
|
+
# Install SpecWeave globally
|
|
1048
|
+
npm install -g specweave
|
|
1049
|
+
|
|
1050
|
+
# Initialize project (first time)
|
|
1051
|
+
specweave init .
|
|
1052
|
+
|
|
1053
|
+
# Update marketplace plugins (gets latest from GitHub)
|
|
1054
|
+
specweave refresh-marketplace
|
|
1055
|
+
|
|
1056
|
+
# Update instruction files (CLAUDE.md, AGENTS.md)
|
|
1057
|
+
specweave update-instructions
|
|
1058
|
+
```
|
|
1059
|
+
|
|
1060
|
+
**After marketplace updates**: Restart Claude Code for changes to take effect.
|
|
1061
|
+
|
|
1062
|
+
**Verify installation**:
|
|
1063
|
+
```bash
|
|
1064
|
+
specweave --version # Check SpecWeave version
|
|
1065
|
+
/plugin list --installed # In Claude Code - check plugins loaded
|
|
1066
|
+
```
|
|
1067
|
+
|
|
999
1068
|
---
|
|
1000
1069
|
|
|
1001
1070
|
## Critical Safety Rules
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specweave",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.78",
|
|
4
4
|
"description": "Spec-driven development framework for Claude Code. AI-native workflow with living documentation, intelligent agents, and multilingual support (9 languages). Enterprise-grade traceability with permanent specs and temporary increments.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -155,18 +155,22 @@ Before you finish ANY response, mentally verify:
|
|
|
155
155
|
**MANDATORY subfolder organization**:
|
|
156
156
|
```
|
|
157
157
|
.specweave/increments/####-name/
|
|
158
|
+
├── metadata.json # ✅ Core file (auto-managed)
|
|
158
159
|
├── spec.md # ✅ ONLY core file 1
|
|
159
160
|
├── plan.md # ✅ ONLY core file 2
|
|
160
161
|
├── tasks.md # ✅ ONLY core file 3
|
|
161
162
|
├── reports/ # ✅ ALL reports here
|
|
162
163
|
│ ├── PM-VALIDATION-REPORT.md
|
|
163
164
|
│ ├── COMPLETION-SUMMARY.md
|
|
164
|
-
│ ├──
|
|
165
|
-
│ └──
|
|
165
|
+
│ ├── qa-post-closure.md
|
|
166
|
+
│ └── validation-report.md
|
|
166
167
|
├── scripts/ # ✅ ALL scripts here
|
|
167
168
|
│ └── helper-*.sh
|
|
168
|
-
|
|
169
|
-
|
|
169
|
+
├── logs/ # ✅ ALL logs here
|
|
170
|
+
│ └── {YYYY-MM-DD}/session.md
|
|
171
|
+
├── docs/ # ✅ Additional documentation
|
|
172
|
+
│ └── domain/ # Domain models (brownfield)
|
|
173
|
+
└── backups/ # ✅ Backup files
|
|
170
174
|
```
|
|
171
175
|
|
|
172
176
|
**When writing ANY file**:
|
|
@@ -174,6 +178,7 @@ Before you finish ANY response, mentally verify:
|
|
|
174
178
|
- ✅ **ALWAYS** write reports to `reports/` subfolder
|
|
175
179
|
- ✅ **ALWAYS** write scripts to `scripts/` subfolder
|
|
176
180
|
- ✅ **ALWAYS** write logs to `logs/` subfolder
|
|
181
|
+
- ✅ **ALWAYS** write additional docs to `docs/` subfolder
|
|
177
182
|
|
|
178
183
|
**Example correct paths**:
|
|
179
184
|
- ✅ `.specweave/increments/0001-auth/reports/PM-VALIDATION-REPORT.md`
|
|
@@ -354,6 +354,28 @@ Pure Ralph Wiggum behavior:
|
|
|
354
354
|
- **Max Iterations**: Prevents runaway loops (2500 default)
|
|
355
355
|
- **Max Hours**: Time boxing (600 hours / 25 days default)
|
|
356
356
|
- **stop_hook_active**: Prevents infinite continuation loops
|
|
357
|
+
- **Sound Notifications** (v2.6): Audible alerts when Claude stops working
|
|
358
|
+
|
|
359
|
+
## 🔔 Sound Notifications (NEW in v2.6!)
|
|
360
|
+
|
|
361
|
+
**Auto mode plays a satisfying sound when work completes successfully!**
|
|
362
|
+
|
|
363
|
+
### When Sound Plays
|
|
364
|
+
|
|
365
|
+
| Event | Sound | Platforms | Meaning |
|
|
366
|
+
|-------|-------|-----------|---------|
|
|
367
|
+
| **Session Complete (Success)** ✅ | Glass.aiff (macOS)<br>complete.oga (Linux)<br>Windows Notify (Windows) | All | All tasks done, tests passing - work finished! |
|
|
368
|
+
|
|
369
|
+
**Sound plays ONLY on complete success** - when all tasks are done AND all tests pass. This way you know when to check back without being interrupted during ongoing work.
|
|
370
|
+
|
|
371
|
+
### Cross-Platform Support
|
|
372
|
+
|
|
373
|
+
The sound notification works automatically on:
|
|
374
|
+
- **macOS**: Glass.aiff (satisfying chime)
|
|
375
|
+
- **Linux**: PulseAudio/ALSA/speaker-test fallbacks
|
|
376
|
+
- **Windows**: PowerShell beeps
|
|
377
|
+
|
|
378
|
+
Sounds fail gracefully on systems without audio support.
|
|
357
379
|
|
|
358
380
|
## 🔧 v2.3 Per-Agent Stop Hook Behavior (NEW!)
|
|
359
381
|
|
|
@@ -44,19 +44,116 @@ The `/sw:save` command uses a **three-tier detection strategy**:
|
|
|
44
44
|
- Works for microservices architectures without explicit configuration
|
|
45
45
|
3. **Parent Project** - Always includes the root project if it has `.git`
|
|
46
46
|
|
|
47
|
+
#### Git-Scan Algorithm (CRITICAL for Microservices)
|
|
48
|
+
|
|
49
|
+
**MANDATORY: When no umbrella config exists, ALWAYS scan for nested repos:**
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Step 1: Find all nested .git directories (excluding .git itself and node_modules)
|
|
53
|
+
find . -maxdepth 4 -type d -name ".git" \
|
|
54
|
+
-not -path "./.git" \
|
|
55
|
+
-not -path "*/node_modules/*" \
|
|
56
|
+
-not -path "*/.specweave/*" \
|
|
57
|
+
2>/dev/null
|
|
58
|
+
|
|
59
|
+
# Step 2: For each .git found, the parent directory is a repo
|
|
60
|
+
# Example output:
|
|
61
|
+
# ./repositories/frontend/.git → repositories/frontend is a repo
|
|
62
|
+
# ./repositories/backend/.git → repositories/backend is a repo
|
|
63
|
+
# ./packages/shared/.git → packages/shared is a repo
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Priority scan paths** (check these first for performance):
|
|
67
|
+
1. `repositories/*/` - Standard SpecWeave multi-repo layout
|
|
68
|
+
2. `packages/*/` - Monorepo packages
|
|
69
|
+
3. `services/*/` - Microservices
|
|
70
|
+
4. `apps/*/` - App directories
|
|
71
|
+
5. `libs/*/` - Library directories
|
|
72
|
+
|
|
73
|
+
**Full discovery example:**
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Discovery script that /sw:save internally executes
|
|
77
|
+
REPOS=()
|
|
78
|
+
|
|
79
|
+
# 1. Check umbrella config first
|
|
80
|
+
if [ -f ".specweave/config.json" ]; then
|
|
81
|
+
UMBRELLA_REPOS=$(jq -r '.umbrella.childRepos[]?.path // empty' .specweave/config.json 2>/dev/null)
|
|
82
|
+
if [ -n "$UMBRELLA_REPOS" ]; then
|
|
83
|
+
while IFS= read -r repo; do
|
|
84
|
+
[ -d "$repo/.git" ] && REPOS+=("$repo")
|
|
85
|
+
done <<< "$UMBRELLA_REPOS"
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# 2. If no umbrella config OR it's empty, scan for nested repos
|
|
90
|
+
if [ ${#REPOS[@]} -eq 0 ]; then
|
|
91
|
+
# Scan priority paths first
|
|
92
|
+
for dir in repositories packages services apps libs; do
|
|
93
|
+
if [ -d "$dir" ]; then
|
|
94
|
+
for repo in "$dir"/*/; do
|
|
95
|
+
[ -d "${repo}.git" ] && REPOS+=("${repo%/}")
|
|
96
|
+
done
|
|
97
|
+
fi
|
|
98
|
+
done
|
|
99
|
+
|
|
100
|
+
# Full recursive scan if nothing found in priority paths
|
|
101
|
+
if [ ${#REPOS[@]} -eq 0 ]; then
|
|
102
|
+
while IFS= read -r git_dir; do
|
|
103
|
+
REPOS+=("$(dirname "$git_dir")")
|
|
104
|
+
done < <(find . -maxdepth 4 -type d -name ".git" -not -path "./.git" -not -path "*/node_modules/*" 2>/dev/null)
|
|
105
|
+
fi
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# 3. Always include parent project if it has .git
|
|
109
|
+
[ -d ".git" ] && REPOS+=(".")
|
|
110
|
+
|
|
111
|
+
# Result: REPOS array contains all repositories to process
|
|
112
|
+
echo "Discovered repos: ${REPOS[*]}"
|
|
113
|
+
```
|
|
114
|
+
|
|
47
115
|
**Example: Microservices without config**
|
|
48
116
|
|
|
49
117
|
```
|
|
50
|
-
my-project/ # ← Parent repo (included)
|
|
118
|
+
my-project/ # ← Parent repo (included via tier 3)
|
|
51
119
|
├── repositories/
|
|
52
|
-
│ ├── frontend/ # ← Auto-discovered
|
|
53
|
-
│
|
|
54
|
-
│
|
|
120
|
+
│ ├── frontend/ # ← Auto-discovered via tier 2
|
|
121
|
+
│ │ └── .git
|
|
122
|
+
│ ├── backend/ # ← Auto-discovered via tier 2
|
|
123
|
+
│ │ └── .git
|
|
124
|
+
│ └── shared-lib/ # ← Auto-discovered via tier 2
|
|
125
|
+
│ └── .git
|
|
55
126
|
└── .specweave/
|
|
56
127
|
```
|
|
57
128
|
|
|
58
129
|
Running `/sw:save` will detect and commit+push to **all 4 repositories** automatically!
|
|
59
130
|
|
|
131
|
+
**Microservices in `services/` folder:**
|
|
132
|
+
```
|
|
133
|
+
my-platform/
|
|
134
|
+
├── services/
|
|
135
|
+
│ ├── auth-service/ # ← Auto-discovered
|
|
136
|
+
│ │ └── .git
|
|
137
|
+
│ ├── payment-service/ # ← Auto-discovered
|
|
138
|
+
│ │ └── .git
|
|
139
|
+
│ └── notification-service/ # ← Auto-discovered
|
|
140
|
+
│ └── .git
|
|
141
|
+
└── .specweave/
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Monorepo with `packages/`:**
|
|
145
|
+
```
|
|
146
|
+
my-monorepo/
|
|
147
|
+
├── packages/
|
|
148
|
+
│ ├── frontend/ # ← Auto-discovered
|
|
149
|
+
│ │ └── .git
|
|
150
|
+
│ ├── backend/ # ← Auto-discovered
|
|
151
|
+
│ │ └── .git
|
|
152
|
+
│ └── shared/ # ← Auto-discovered
|
|
153
|
+
│ └── .git
|
|
154
|
+
└── .git # ← Parent repo also included
|
|
155
|
+
```
|
|
156
|
+
|
|
60
157
|
## Usage
|
|
61
158
|
|
|
62
159
|
```bash
|
|
@@ -117,6 +117,36 @@ Core hooks automate SpecWeave's fundamental workflows:
|
|
|
117
117
|
|
|
118
118
|
---
|
|
119
119
|
|
|
120
|
+
### 5. `stop-auto.sh` (Auto Mode)
|
|
121
|
+
**Triggers**: When Claude tries to exit during autonomous execution (`/sw:auto`)
|
|
122
|
+
|
|
123
|
+
**Actions**:
|
|
124
|
+
1. Checks if all tasks are complete
|
|
125
|
+
2. Validates test execution (unit + E2E)
|
|
126
|
+
3. Verifies completion criteria met
|
|
127
|
+
4. Blocks exit if work incomplete
|
|
128
|
+
5. Re-feeds prompt to continue iteration
|
|
129
|
+
|
|
130
|
+
**Configuration**: Registered in `hooks/hooks.json`:
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"hooks": {
|
|
134
|
+
"Stop": [{
|
|
135
|
+
"hooks": [{
|
|
136
|
+
"type": "command",
|
|
137
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/stop-auto.sh"
|
|
138
|
+
}]
|
|
139
|
+
}]
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Use case**: Enables autonomous execution loops. Claude works until ALL tasks complete and tests pass, then gracefully exits.
|
|
145
|
+
|
|
146
|
+
**See**: `/sw:auto` command documentation for full auto mode details.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
120
150
|
## How Hooks Work (Claude Code Native)
|
|
121
151
|
|
|
122
152
|
**CRITICAL**: Hooks are **NOT copied** to `.claude/hooks/`. They stay in `plugins/specweave/hooks/` and Claude Code discovers them automatically.
|
|
@@ -12,7 +12,14 @@
|
|
|
12
12
|
# - Extracts specific failure details for fix prompts
|
|
13
13
|
# - Blocks on ANY test failure (not just >3)
|
|
14
14
|
#
|
|
15
|
-
#
|
|
15
|
+
# AGENT HIERARCHY LABELS (v2.4):
|
|
16
|
+
# - Detects agent type: MAIN ORCHESTRATOR vs SUBAGENT
|
|
17
|
+
# - Clear session stop/continue labels with box art
|
|
18
|
+
# - Shows "WHEN WILL SESSION STOP?" criteria prominently
|
|
19
|
+
# - Subagents show "Returns to: Main Orchestrator" on completion
|
|
20
|
+
# - Tracks subagent spawns in session stats
|
|
21
|
+
#
|
|
22
|
+
# IMPORTANT (v2.3+): Stop hook runs PER AGENT
|
|
16
23
|
# - Each spawned subagent (Task tool) gets its own stop hook invocation
|
|
17
24
|
# - Iteration count is SHARED across all agents via session file
|
|
18
25
|
# - Parent agent's exit triggers hook, subagent exits do NOT by default
|
|
@@ -317,6 +324,196 @@ get_coverage_targets() {
|
|
|
317
324
|
fi
|
|
318
325
|
}
|
|
319
326
|
|
|
327
|
+
# ============================================================================
|
|
328
|
+
# AGENT TYPE DETECTION & HIERARCHY (NEW - v2.4)
|
|
329
|
+
# Distinguishes main orchestrator from subagents for clear labeling
|
|
330
|
+
# ============================================================================
|
|
331
|
+
|
|
332
|
+
# Agent type constants
|
|
333
|
+
AGENT_TYPE_ORCHESTRATOR="orchestrator"
|
|
334
|
+
AGENT_TYPE_SUBAGENT="subagent"
|
|
335
|
+
|
|
336
|
+
# Detect if this is main orchestrator or a subagent
|
|
337
|
+
# Returns: "orchestrator" or "subagent:<type>"
|
|
338
|
+
detect_agent_type() {
|
|
339
|
+
local transcript="$1"
|
|
340
|
+
|
|
341
|
+
# No transcript = assume orchestrator
|
|
342
|
+
if [ -z "$transcript" ] || [ ! -f "$transcript" ]; then
|
|
343
|
+
echo "$AGENT_TYPE_ORCHESTRATOR"
|
|
344
|
+
return
|
|
345
|
+
fi
|
|
346
|
+
|
|
347
|
+
# Check for /sw:auto command - indicates main orchestrator
|
|
348
|
+
if grep -qE '(/sw:auto|/specweave:auto|setup-auto\.sh)' "$transcript" 2>/dev/null; then
|
|
349
|
+
echo "$AGENT_TYPE_ORCHESTRATOR"
|
|
350
|
+
return
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
# Check for subagent invocation patterns in transcript
|
|
354
|
+
# Subagents are spawned via Task tool with subagent_type parameter
|
|
355
|
+
local subagent_pattern='subagent_type.*?["\x27]([^"\x27]+)["\x27]'
|
|
356
|
+
local subagent_match=$(grep -oE 'subagent_type["\x27]*:\s*["\x27]?[a-zA-Z0-9_:-]+' "$transcript" 2>/dev/null | tail -1)
|
|
357
|
+
|
|
358
|
+
if [ -n "$subagent_match" ]; then
|
|
359
|
+
# Extract the type name
|
|
360
|
+
local agent_name=$(echo "$subagent_match" | sed 's/.*["\x27]\([^"\x27]*\)["\x27].*/\1/' | sed 's/subagent_type["\x27]*:\s*["\x27]*//')
|
|
361
|
+
if [ -n "$agent_name" ] && [ "$agent_name" != "subagent_type" ]; then
|
|
362
|
+
echo "$AGENT_TYPE_SUBAGENT:$agent_name"
|
|
363
|
+
return
|
|
364
|
+
fi
|
|
365
|
+
fi
|
|
366
|
+
|
|
367
|
+
# Check for specialized agent prompts (subagent indicators)
|
|
368
|
+
if grep -qE '(You are a specialized agent|Task tool|subagent|Agent type:)' "$transcript" 2>/dev/null; then
|
|
369
|
+
# Try to extract agent type from common patterns
|
|
370
|
+
local agent_desc=$(grep -oE '(architect|qa-engineer|security|devops|frontend|backend|ml-engineer|data-scientist|sre|tech-lead|docs-writer)' "$transcript" 2>/dev/null | head -1)
|
|
371
|
+
if [ -n "$agent_desc" ]; then
|
|
372
|
+
echo "$AGENT_TYPE_SUBAGENT:$agent_desc"
|
|
373
|
+
return
|
|
374
|
+
fi
|
|
375
|
+
echo "$AGENT_TYPE_SUBAGENT:unknown"
|
|
376
|
+
return
|
|
377
|
+
fi
|
|
378
|
+
|
|
379
|
+
# Default to orchestrator if no subagent patterns found
|
|
380
|
+
echo "$AGENT_TYPE_ORCHESTRATOR"
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
# Get human-readable agent display name
|
|
384
|
+
# Input: agent type from detect_agent_type()
|
|
385
|
+
# Output: formatted display name
|
|
386
|
+
get_agent_display_name() {
|
|
387
|
+
local agent_type="$1"
|
|
388
|
+
|
|
389
|
+
case "$agent_type" in
|
|
390
|
+
orchestrator)
|
|
391
|
+
echo "🤖 MAIN ORCHESTRATOR"
|
|
392
|
+
;;
|
|
393
|
+
subagent:*)
|
|
394
|
+
local subtype="${agent_type#subagent:}"
|
|
395
|
+
# Format common agent types nicely
|
|
396
|
+
case "$subtype" in
|
|
397
|
+
sw:architect:architect|architect)
|
|
398
|
+
echo "🏗️ SUBAGENT: System Architect"
|
|
399
|
+
;;
|
|
400
|
+
sw:tech-lead:tech-lead|tech-lead)
|
|
401
|
+
echo "👨💻 SUBAGENT: Tech Lead"
|
|
402
|
+
;;
|
|
403
|
+
sw:qa-lead:qa-lead|qa-lead|qa-engineer)
|
|
404
|
+
echo "🧪 SUBAGENT: QA Engineer"
|
|
405
|
+
;;
|
|
406
|
+
sw:security:security|security)
|
|
407
|
+
echo "🔐 SUBAGENT: Security Engineer"
|
|
408
|
+
;;
|
|
409
|
+
sw-infra:devops:devops|devops)
|
|
410
|
+
echo "🚀 SUBAGENT: DevOps Engineer"
|
|
411
|
+
;;
|
|
412
|
+
sw-frontend:frontend-architect:*|frontend*)
|
|
413
|
+
echo "🎨 SUBAGENT: Frontend Architect"
|
|
414
|
+
;;
|
|
415
|
+
sw-backend:*|backend*)
|
|
416
|
+
echo "⚙️ SUBAGENT: Backend Engineer"
|
|
417
|
+
;;
|
|
418
|
+
sw-ml:ml-engineer:*|ml-engineer)
|
|
419
|
+
echo "🧠 SUBAGENT: ML Engineer"
|
|
420
|
+
;;
|
|
421
|
+
sw-ml:data-scientist:*|data-scientist)
|
|
422
|
+
echo "📊 SUBAGENT: Data Scientist"
|
|
423
|
+
;;
|
|
424
|
+
sw-infra:sre:sre|sre)
|
|
425
|
+
echo "🔧 SUBAGENT: SRE"
|
|
426
|
+
;;
|
|
427
|
+
sw:docs-writer:*|docs-writer)
|
|
428
|
+
echo "📝 SUBAGENT: Docs Writer"
|
|
429
|
+
;;
|
|
430
|
+
Explore|explore)
|
|
431
|
+
echo "🔍 SUBAGENT: Explorer"
|
|
432
|
+
;;
|
|
433
|
+
Plan|plan)
|
|
434
|
+
echo "📋 SUBAGENT: Planner"
|
|
435
|
+
;;
|
|
436
|
+
unknown)
|
|
437
|
+
echo "🔧 SUBAGENT: Specialized Agent"
|
|
438
|
+
;;
|
|
439
|
+
*)
|
|
440
|
+
echo "🔧 SUBAGENT: $subtype"
|
|
441
|
+
;;
|
|
442
|
+
esac
|
|
443
|
+
;;
|
|
444
|
+
*)
|
|
445
|
+
echo "🤖 AGENT: $agent_type"
|
|
446
|
+
;;
|
|
447
|
+
esac
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
# Get short agent type for JSON logging
|
|
451
|
+
get_agent_type_short() {
|
|
452
|
+
local agent_type="$1"
|
|
453
|
+
|
|
454
|
+
case "$agent_type" in
|
|
455
|
+
orchestrator)
|
|
456
|
+
echo "main"
|
|
457
|
+
;;
|
|
458
|
+
subagent:*)
|
|
459
|
+
echo "${agent_type#subagent:}"
|
|
460
|
+
;;
|
|
461
|
+
*)
|
|
462
|
+
echo "$agent_type"
|
|
463
|
+
;;
|
|
464
|
+
esac
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
# Detect recent subagent activity from transcript
|
|
468
|
+
# Returns JSON with subagent stats
|
|
469
|
+
detect_subagent_activity() {
|
|
470
|
+
local transcript="$1"
|
|
471
|
+
|
|
472
|
+
if [ -z "$transcript" ] || [ ! -f "$transcript" ]; then
|
|
473
|
+
echo '{"spawned":0,"types":[]}'
|
|
474
|
+
return
|
|
475
|
+
fi
|
|
476
|
+
|
|
477
|
+
# Count Task tool invocations
|
|
478
|
+
local task_count=$(grep -c 'Task tool\|subagent_type\|<invoke name="Task">' "$transcript" 2>/dev/null || echo "0")
|
|
479
|
+
|
|
480
|
+
# Extract unique agent types
|
|
481
|
+
local agent_types=$(grep -oE 'subagent_type["\x27]*:\s*["\x27]?[a-zA-Z0-9_:-]+' "$transcript" 2>/dev/null | \
|
|
482
|
+
sed 's/subagent_type["\x27]*:\s*["\x27]*//' | \
|
|
483
|
+
sort -u | \
|
|
484
|
+
head -10 | \
|
|
485
|
+
jq -R -s 'split("\n") | map(select(length > 0))' 2>/dev/null || echo '[]')
|
|
486
|
+
|
|
487
|
+
echo "{\"spawned\":$task_count,\"types\":$agent_types}"
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
# Track subagent in session (called when subagent activity detected)
|
|
491
|
+
track_subagent_spawn() {
|
|
492
|
+
local agent_type="$1"
|
|
493
|
+
local short_type=$(get_agent_type_short "$agent_type")
|
|
494
|
+
|
|
495
|
+
if [ -f "$SESSION_FILE" ]; then
|
|
496
|
+
local updated=$(cat "$SESSION_FILE" | jq \
|
|
497
|
+
--arg type "$short_type" \
|
|
498
|
+
--arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
499
|
+
'.subagentStats.totalSpawned = ((.subagentStats.totalSpawned // 0) + 1) |
|
|
500
|
+
.subagentStats.lastSpawned = $type |
|
|
501
|
+
.subagentStats.lastSpawnTime = $now |
|
|
502
|
+
.subagentStats.history = ((.subagentStats.history // []) + [{"type": $type, "time": $now}]) |
|
|
503
|
+
.subagentStats.history = (.subagentStats.history | if length > 20 then .[-20:] else . end)')
|
|
504
|
+
echo "$updated" > "$SESSION_FILE"
|
|
505
|
+
fi
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
# Get subagent stats from session
|
|
509
|
+
get_subagent_stats() {
|
|
510
|
+
if [ -f "$SESSION_FILE" ]; then
|
|
511
|
+
jq -r '.subagentStats // {"totalSpawned":0,"history":[]}' "$SESSION_FILE"
|
|
512
|
+
else
|
|
513
|
+
echo '{"totalSpawned":0,"history":[]}'
|
|
514
|
+
fi
|
|
515
|
+
}
|
|
516
|
+
|
|
320
517
|
# ============================================================================
|
|
321
518
|
# STOP REASON TRACKING (NEW - v2.2)
|
|
322
519
|
# Clear logging of WHY auto mode stops
|
|
@@ -373,74 +570,236 @@ detect_command_timeout() {
|
|
|
373
570
|
fi
|
|
374
571
|
}
|
|
375
572
|
|
|
573
|
+
# ================================================================
|
|
574
|
+
# SOUND NOTIFICATION HELPER (v2.6)
|
|
575
|
+
# Cross-platform sound notification for user awareness
|
|
576
|
+
# ================================================================
|
|
577
|
+
play_notification_sound() {
|
|
578
|
+
local sound_type="${1:-attention}" # "success" or "attention"
|
|
579
|
+
|
|
580
|
+
# Detect OS and play appropriate sound
|
|
581
|
+
case "$(uname -s)" in
|
|
582
|
+
Darwin)
|
|
583
|
+
# macOS - use afplay with system sounds
|
|
584
|
+
if [ "$sound_type" = "success" ]; then
|
|
585
|
+
afplay /System/Library/Sounds/Glass.aiff 2>/dev/null &
|
|
586
|
+
else
|
|
587
|
+
afplay /System/Library/Sounds/Ping.aiff 2>/dev/null &
|
|
588
|
+
fi
|
|
589
|
+
;;
|
|
590
|
+
Linux)
|
|
591
|
+
# Linux - try multiple sound systems (paplay, aplay, speaker-test)
|
|
592
|
+
if command -v paplay >/dev/null 2>&1; then
|
|
593
|
+
# PulseAudio (most common on modern Linux)
|
|
594
|
+
if [ "$sound_type" = "success" ]; then
|
|
595
|
+
paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null &
|
|
596
|
+
else
|
|
597
|
+
paplay /usr/share/sounds/freedesktop/stereo/bell.oga 2>/dev/null &
|
|
598
|
+
fi
|
|
599
|
+
elif command -v aplay >/dev/null 2>&1; then
|
|
600
|
+
# ALSA fallback
|
|
601
|
+
aplay /usr/share/sounds/alsa/Front_Center.wav 2>/dev/null &
|
|
602
|
+
elif command -v speaker-test >/dev/null 2>&1; then
|
|
603
|
+
# Last resort - system beep
|
|
604
|
+
speaker-test -t sine -f 1000 -l 1 >/dev/null 2>&1 &
|
|
605
|
+
fi
|
|
606
|
+
;;
|
|
607
|
+
MINGW*|MSYS*|CYGWIN*)
|
|
608
|
+
# Windows (Git Bash, WSL, Cygwin)
|
|
609
|
+
if command -v powershell.exe >/dev/null 2>&1; then
|
|
610
|
+
# Use PowerShell to play sound
|
|
611
|
+
if [ "$sound_type" = "success" ]; then
|
|
612
|
+
powershell.exe -c "(New-Object Media.SoundPlayer 'C:\Windows\Media\Windows Notify System Generic.wav').PlaySync();" 2>/dev/null &
|
|
613
|
+
else
|
|
614
|
+
powershell.exe -c "[console]::beep(800, 300)" 2>/dev/null &
|
|
615
|
+
fi
|
|
616
|
+
fi
|
|
617
|
+
;;
|
|
618
|
+
esac
|
|
619
|
+
}
|
|
620
|
+
|
|
376
621
|
# Helper: Output approve decision
|
|
377
622
|
# ALWAYS log why we're stopping for debugging
|
|
623
|
+
# Enhanced v2.4: Agent-aware labeling with clear hierarchy
|
|
378
624
|
approve() {
|
|
379
625
|
local reason="${1:-Session complete}"
|
|
380
626
|
local is_success="${2:-false}"
|
|
381
627
|
|
|
382
|
-
#
|
|
383
|
-
|
|
628
|
+
# Detect agent type for proper labeling
|
|
629
|
+
local agent_type=$(detect_agent_type "$TRANSCRIPT_PATH")
|
|
630
|
+
local agent_display=$(get_agent_display_name "$agent_type")
|
|
631
|
+
local agent_short=$(get_agent_type_short "$agent_type")
|
|
632
|
+
|
|
633
|
+
# Get subagent stats for summary
|
|
634
|
+
local subagent_stats=$(get_subagent_stats)
|
|
635
|
+
local subagents_spawned=$(echo "$subagent_stats" | jq -r '.totalSpawned // 0')
|
|
636
|
+
|
|
637
|
+
# Log the stop reason with agent info
|
|
638
|
+
log_stop_reason "$reason" "approve_called:$agent_short" "$is_success"
|
|
639
|
+
|
|
640
|
+
# Get test breakdown by type if available (NEW - v2.5)
|
|
641
|
+
local test_breakdown=$(get_test_type_breakdown "$TRANSCRIPT_PATH")
|
|
384
642
|
|
|
385
643
|
# Display the stop reason prominently to STDERR (not stdout, which is for JSON)
|
|
386
644
|
{
|
|
387
645
|
echo ""
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
646
|
+
if [ "$agent_type" = "orchestrator" ]; then
|
|
647
|
+
# Main orchestrator stopping - this is a SESSION END
|
|
648
|
+
if [ "$is_success" = "true" ]; then
|
|
649
|
+
echo "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓"
|
|
650
|
+
echo "┃ ✅ AUTO SESSION COMPLETE ┃"
|
|
651
|
+
echo "┃ $agent_display ┃"
|
|
652
|
+
echo "┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫"
|
|
653
|
+
echo "┃ Status: SUCCESS - All work completed ┃"
|
|
654
|
+
else
|
|
655
|
+
echo "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓"
|
|
656
|
+
echo "┃ 🛑 AUTO SESSION STOPPING ┃"
|
|
657
|
+
echo "┃ $agent_display ┃"
|
|
658
|
+
echo "┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫"
|
|
659
|
+
echo "┃ Status: STOPPED - Requires attention ┃"
|
|
660
|
+
fi
|
|
661
|
+
echo "┃ Reason: $(printf '%-48s' "$reason")┃"
|
|
662
|
+
echo "┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫"
|
|
663
|
+
echo "┃ 📊 SESSION SUMMARY ┃"
|
|
664
|
+
echo "┃ ├─ Iterations: ${ITERATION:-0}/${MAX_ITERATIONS:-100} ┃"
|
|
665
|
+
[ -n "$CURRENT_INCREMENT" ] && echo "┃ ├─ Increment: $(printf '%-42s' "$CURRENT_INCREMENT")┃"
|
|
666
|
+
[ "$subagents_spawned" -gt 0 ] && echo "┃ ├─ Subagents spawned: $(printf '%-35s' "$subagents_spawned")┃"
|
|
667
|
+
if [ "${TESTS_RUN:-false}" = "true" ]; then
|
|
668
|
+
if [ -n "$test_breakdown" ] && [ "$test_breakdown" != "{}" ]; then
|
|
669
|
+
# Show detailed breakdown by test type (NEW - v2.5)
|
|
670
|
+
echo "┃ └─ Tests (detailed breakdown): ┃"
|
|
671
|
+
local unit_passed=$(echo "$test_breakdown" | jq -r '.unit.passed // 0')
|
|
672
|
+
local unit_failed=$(echo "$test_breakdown" | jq -r '.unit.failed // 0')
|
|
673
|
+
local integration_passed=$(echo "$test_breakdown" | jq -r '.integration.passed // 0')
|
|
674
|
+
local integration_failed=$(echo "$test_breakdown" | jq -r '.integration.failed // 0')
|
|
675
|
+
local e2e_passed=$(echo "$test_breakdown" | jq -r '.e2e.passed // 0')
|
|
676
|
+
local e2e_failed=$(echo "$test_breakdown" | jq -r '.e2e.failed // 0')
|
|
677
|
+
|
|
678
|
+
if [ "$unit_passed" -gt 0 ] || [ "$unit_failed" -gt 0 ]; then
|
|
679
|
+
echo "┃ • Unit: ${unit_passed} passed, ${unit_failed} failed ┃"
|
|
680
|
+
fi
|
|
681
|
+
if [ "$integration_passed" -gt 0 ] || [ "$integration_failed" -gt 0 ]; then
|
|
682
|
+
echo "┃ • Integration: ${integration_passed} passed, ${integration_failed} failed ┃"
|
|
683
|
+
fi
|
|
684
|
+
if [ "$e2e_passed" -gt 0 ] || [ "$e2e_failed" -gt 0 ]; then
|
|
685
|
+
echo "┃ • E2E: ${e2e_passed} passed, ${e2e_failed} failed ┃"
|
|
686
|
+
fi
|
|
687
|
+
else
|
|
688
|
+
# Fallback to simple summary
|
|
689
|
+
echo "┃ └─ Tests: ${TESTS_PASSED:-0} passed, ${TESTS_FAILED:-0} failed ┃"
|
|
690
|
+
fi
|
|
691
|
+
fi
|
|
692
|
+
echo "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
|
|
693
|
+
|
|
694
|
+
# ================================================================
|
|
695
|
+
# SOUND NOTIFICATION ON SUCCESS (v2.6)
|
|
696
|
+
# Play sound ONLY when session completes successfully
|
|
697
|
+
# This lets users know they can check back - work is done!
|
|
698
|
+
# Cross-platform support via helper function
|
|
699
|
+
# ================================================================
|
|
700
|
+
if [ "$is_success" = "true" ]; then
|
|
701
|
+
play_notification_sound "success"
|
|
702
|
+
fi
|
|
703
|
+
else
|
|
704
|
+
# Subagent stopping - this is a RETURN TO PARENT
|
|
705
|
+
echo "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓"
|
|
706
|
+
echo "┃ ↩️ SUBAGENT COMPLETE - Returning to parent ┃"
|
|
707
|
+
echo "┃ $agent_display ┃"
|
|
708
|
+
echo "┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫"
|
|
709
|
+
echo "┃ Result: $(printf '%-49s' "$reason")┃"
|
|
710
|
+
echo "┃ ↩️ Control returning to: 🤖 Main Orchestrator ┃"
|
|
711
|
+
echo "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
|
|
712
|
+
fi
|
|
396
713
|
echo ""
|
|
397
714
|
} >&2
|
|
398
715
|
|
|
399
|
-
echo "{\"decision\": \"approve\", \"reason\": \"$reason\"}"
|
|
716
|
+
echo "{\"decision\": \"approve\", \"reason\": \"$reason\", \"agentType\": \"$agent_short\"}"
|
|
400
717
|
exit 0
|
|
401
718
|
}
|
|
402
719
|
|
|
403
720
|
# Helper: Output block decision with system message
|
|
404
721
|
# Properly escapes JSON strings with newlines
|
|
405
|
-
#
|
|
722
|
+
# Enhanced v2.4: Agent-aware labeling with clear hierarchy and stop conditions
|
|
406
723
|
block() {
|
|
407
724
|
local reason="$1"
|
|
408
725
|
local system_message="$2"
|
|
409
726
|
|
|
727
|
+
# Detect agent type for proper labeling
|
|
728
|
+
local agent_type=$(detect_agent_type "$TRANSCRIPT_PATH")
|
|
729
|
+
local agent_display=$(get_agent_display_name "$agent_type")
|
|
730
|
+
local agent_short=$(get_agent_type_short "$agent_type")
|
|
731
|
+
|
|
410
732
|
# Get current stop criteria for display
|
|
411
733
|
local tdd_mode=$(is_tdd_strict_mode)
|
|
412
734
|
local stop_criteria=""
|
|
735
|
+
local stop_criteria_detail=""
|
|
413
736
|
|
|
414
|
-
# Build stop criteria message - MORE PROMINENT (v2.
|
|
737
|
+
# Build stop criteria message - MORE PROMINENT (v2.4)
|
|
415
738
|
if [ "$tdd_mode" = "true" ]; then
|
|
416
|
-
stop_criteria="
|
|
739
|
+
stop_criteria="TDD STRICT MODE"
|
|
740
|
+
stop_criteria_detail="ALL tasks [x] + ALL tests GREEN (0 failures)"
|
|
417
741
|
else
|
|
418
|
-
stop_criteria="
|
|
742
|
+
stop_criteria="STANDARD MODE"
|
|
743
|
+
stop_criteria_detail="ALL tasks [x] completed + tests passing"
|
|
419
744
|
fi
|
|
420
745
|
|
|
421
|
-
#
|
|
746
|
+
# Get subagent activity for display
|
|
747
|
+
local subagent_stats=$(get_subagent_stats)
|
|
748
|
+
local subagents_spawned=$(echo "$subagent_stats" | jq -r '.totalSpawned // 0')
|
|
749
|
+
|
|
750
|
+
# Display stop criteria and continuation reason to STDERR (v2.4 enhanced)
|
|
422
751
|
{
|
|
423
752
|
echo ""
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
753
|
+
if [ "$agent_type" = "orchestrator" ]; then
|
|
754
|
+
# Main orchestrator continuing - SESSION CONTINUES
|
|
755
|
+
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
756
|
+
echo "║ 🔄 AUTO SESSION CONTINUING ║"
|
|
757
|
+
echo "║ $agent_display ║"
|
|
758
|
+
echo "╠══════════════════════════════════════════════════════════════╣"
|
|
759
|
+
echo "║ Why: $(printf '%-52s' "$reason")║"
|
|
760
|
+
echo "║ Iteration: $(printf '%-47s' "${ITERATION:-0}/${MAX_ITERATIONS:-2500}")║"
|
|
761
|
+
[ -n "$CURRENT_INCREMENT" ] && echo "║ Increment: $(printf '%-47s' "$CURRENT_INCREMENT")║"
|
|
762
|
+
[ "$subagents_spawned" -gt 0 ] && echo "║ Subagents used: $(printf '%-42s' "$subagents_spawned")║"
|
|
763
|
+
echo "╠══════════════════════════════════════════════════════════════╣"
|
|
764
|
+
echo "║ 🎯 WHEN WILL SESSION STOP? ║"
|
|
765
|
+
echo "║ ├─ Mode: $(printf '%-48s' "$stop_criteria")║"
|
|
766
|
+
echo "║ └─ Criteria: $(printf '%-44s' "$stop_criteria_detail")║"
|
|
767
|
+
if [ "${TESTS_RUN:-false}" = "true" ]; then
|
|
768
|
+
if [ "${TESTS_FAILED:-0}" -gt 0 ]; then
|
|
769
|
+
echo "║ ⚠️ Tests: ${TESTS_PASSED:-0} passed, ${TESTS_FAILED:-0} FAILED (blocking!) ║"
|
|
770
|
+
else
|
|
771
|
+
echo "║ ✅ Tests: ${TESTS_PASSED:-0} passed, 0 failed ║"
|
|
772
|
+
fi
|
|
773
|
+
else
|
|
774
|
+
echo "║ ⏳ Tests: NOT YET RUN ║"
|
|
775
|
+
fi
|
|
776
|
+
[ "$tdd_mode" = "true" ] && echo "║ 📋 TDD Source: $(printf '%-42s' "$(get_tdd_source)")║"
|
|
777
|
+
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
778
|
+
else
|
|
779
|
+
# Subagent continuing - SUBAGENT KEEPS WORKING
|
|
780
|
+
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
781
|
+
echo "║ 🔧 SUBAGENT CONTINUING WORK ║"
|
|
782
|
+
echo "║ $agent_display ║"
|
|
783
|
+
echo "╠══════════════════════════════════════════════════════════════╣"
|
|
784
|
+
echo "║ Task: $(printf '%-51s' "$reason")║"
|
|
785
|
+
echo "╠══════════════════════════════════════════════════════════════╣"
|
|
786
|
+
echo "║ 🎯 WHEN WILL SUBAGENT RETURN? ║"
|
|
787
|
+
echo "║ └─ When assigned task is complete ║"
|
|
788
|
+
echo "║ ↩️ Returns to: 🤖 Main Orchestrator ║"
|
|
789
|
+
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
790
|
+
fi
|
|
435
791
|
echo ""
|
|
436
792
|
} >&2
|
|
437
793
|
|
|
794
|
+
# NOTE: No sound notification on block - sounds only play on SUCCESS
|
|
795
|
+
# When Claude is continuing work, user doesn't need to be notified
|
|
796
|
+
|
|
438
797
|
if [ -n "$system_message" ]; then
|
|
439
798
|
# Escape special characters for JSON
|
|
440
799
|
local escaped_message=$(echo "$system_message" | jq -Rs .)
|
|
441
|
-
echo "{\"decision\": \"block\", \"reason\": \"$reason\", \"systemMessage\": $escaped_message}"
|
|
800
|
+
echo "{\"decision\": \"block\", \"reason\": \"$reason\", \"systemMessage\": $escaped_message, \"agentType\": \"$agent_short\"}"
|
|
442
801
|
else
|
|
443
|
-
echo "{\"decision\": \"block\", \"reason\": \"$reason\"}"
|
|
802
|
+
echo "{\"decision\": \"block\", \"reason\": \"$reason\", \"agentType\": \"$agent_short\"}"
|
|
444
803
|
fi
|
|
445
804
|
exit 0
|
|
446
805
|
}
|
|
@@ -859,6 +1218,80 @@ parse_test_results() {
|
|
|
859
1218
|
echo "{\"passed\":$passed,\"failed\":$failed,\"total\":$total,\"framework\":\"$framework\",\"testsRun\":$tests_run}"
|
|
860
1219
|
}
|
|
861
1220
|
|
|
1221
|
+
# ============================================================================
|
|
1222
|
+
# TEST TYPE BREAKDOWN (NEW - v2.5)
|
|
1223
|
+
# Categorizes test results by type (unit/integration/E2E) for detailed summary
|
|
1224
|
+
# ============================================================================
|
|
1225
|
+
|
|
1226
|
+
# Get test type breakdown from transcript
|
|
1227
|
+
# Returns: JSON with {unit: {passed, failed}, integration: {passed, failed}, e2e: {passed, failed}}
|
|
1228
|
+
get_test_type_breakdown() {
|
|
1229
|
+
local transcript="$1"
|
|
1230
|
+
|
|
1231
|
+
if [ ! -f "$transcript" ]; then
|
|
1232
|
+
echo "{}"
|
|
1233
|
+
return
|
|
1234
|
+
fi
|
|
1235
|
+
|
|
1236
|
+
local unit_passed=0
|
|
1237
|
+
local unit_failed=0
|
|
1238
|
+
local integration_passed=0
|
|
1239
|
+
local integration_failed=0
|
|
1240
|
+
local e2e_passed=0
|
|
1241
|
+
local e2e_failed=0
|
|
1242
|
+
|
|
1243
|
+
# Check for test command patterns to categorize
|
|
1244
|
+
# Unit tests: vitest, jest, pytest, go test
|
|
1245
|
+
if grep -qE '(npm.*test:unit|npx vitest|npx jest|pytest|go test|cargo test)' "$transcript" 2>/dev/null; then
|
|
1246
|
+
# Parse unit test results
|
|
1247
|
+
local unit_result=$(grep -oE 'Tests?\s+[0-9]+\s+passed' "$transcript" 2>/dev/null | tail -1)
|
|
1248
|
+
if [ -n "$unit_result" ]; then
|
|
1249
|
+
unit_passed=$(echo "$unit_result" | grep -oE '[0-9]+' | head -1)
|
|
1250
|
+
local unit_failed_match=$(grep -oE '[0-9]+\s+failed' "$transcript" 2>/dev/null | tail -1 | grep -oE '[0-9]+' || echo "0")
|
|
1251
|
+
unit_failed=${unit_failed_match:-0}
|
|
1252
|
+
fi
|
|
1253
|
+
fi
|
|
1254
|
+
|
|
1255
|
+
# Integration tests: usually named test:integration
|
|
1256
|
+
if grep -qE 'npm.*test:integration' "$transcript" 2>/dev/null; then
|
|
1257
|
+
# Parse integration test results (same format as unit)
|
|
1258
|
+
local int_result=$(grep -oE 'Tests?\s+[0-9]+\s+passed' "$transcript" 2>/dev/null | tail -1)
|
|
1259
|
+
if [ -n "$int_result" ]; then
|
|
1260
|
+
integration_passed=$(echo "$int_result" | grep -oE '[0-9]+' | head -1)
|
|
1261
|
+
local int_failed_match=$(grep -oE '[0-9]+\s+failed' "$transcript" 2>/dev/null | tail -1 | grep -oE '[0-9]+' || echo "0")
|
|
1262
|
+
integration_failed=${int_failed_match:-0}
|
|
1263
|
+
fi
|
|
1264
|
+
fi
|
|
1265
|
+
|
|
1266
|
+
# E2E tests: Playwright, Cypress, Detox, Maestro
|
|
1267
|
+
if grep -qE '(npx playwright|npx cypress|npx detox|maestro test|test:e2e)' "$transcript" 2>/dev/null; then
|
|
1268
|
+
# Parse E2E test results
|
|
1269
|
+
local e2e_passed_match=$(grep -oE '[0-9]+\s+passed' "$transcript" 2>/dev/null | tail -1 | grep -oE '[0-9]+')
|
|
1270
|
+
local e2e_failed_match=$(grep -oE '[0-9]+\s+failed' "$transcript" 2>/dev/null | tail -1 | grep -oE '[0-9]+')
|
|
1271
|
+
|
|
1272
|
+
e2e_passed=${e2e_passed_match:-0}
|
|
1273
|
+
e2e_failed=${e2e_failed_match:-0}
|
|
1274
|
+
fi
|
|
1275
|
+
|
|
1276
|
+
# Return JSON with breakdown
|
|
1277
|
+
cat <<EOF
|
|
1278
|
+
{
|
|
1279
|
+
"unit": {
|
|
1280
|
+
"passed": $unit_passed,
|
|
1281
|
+
"failed": $unit_failed
|
|
1282
|
+
},
|
|
1283
|
+
"integration": {
|
|
1284
|
+
"passed": $integration_passed,
|
|
1285
|
+
"failed": $integration_failed
|
|
1286
|
+
},
|
|
1287
|
+
"e2e": {
|
|
1288
|
+
"passed": $e2e_passed,
|
|
1289
|
+
"failed": $e2e_failed
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
EOF
|
|
1293
|
+
}
|
|
1294
|
+
|
|
862
1295
|
# Extract detailed failure information from transcript
|
|
863
1296
|
# Returns: JSON with failure details
|
|
864
1297
|
extract_failure_details() {
|
|
@@ -1787,7 +2220,30 @@ Continue with /sw:do and add missing E2E tests."
|
|
|
1787
2220
|
--argjson passed "${TESTS_PASSED:-0}" --argjson failed "${TESTS_FAILED:-0}" \
|
|
1788
2221
|
'.status = "completed" | .endTime = $now | .endReason = "all_tasks_complete" | .finalTestResults = {"passed": $passed, "failed": $failed}' \
|
|
1789
2222
|
> "$SESSION_FILE"
|
|
1790
|
-
|
|
2223
|
+
|
|
2224
|
+
# Build detailed completion reason with test breakdown (NEW - v2.5)
|
|
2225
|
+
local completion_reason="All tasks completed"
|
|
2226
|
+
local test_breakdown=$(get_test_type_breakdown "$TRANSCRIPT_PATH")
|
|
2227
|
+
if [ -n "$test_breakdown" ] && [ "$test_breakdown" != "{}" ]; then
|
|
2228
|
+
local unit_p=$(echo "$test_breakdown" | jq -r '.unit.passed // 0')
|
|
2229
|
+
local int_p=$(echo "$test_breakdown" | jq -r '.integration.passed // 0')
|
|
2230
|
+
local e2e_p=$(echo "$test_breakdown" | jq -r '.e2e.passed // 0')
|
|
2231
|
+
|
|
2232
|
+
local test_details=""
|
|
2233
|
+
[ "$unit_p" -gt 0 ] && test_details="${test_details}${unit_p} unit"
|
|
2234
|
+
[ "$int_p" -gt 0 ] && test_details="${test_details}${test_details:+, }${int_p} integration"
|
|
2235
|
+
[ "$e2e_p" -gt 0 ] && test_details="${test_details}${test_details:+, }${e2e_p} E2E"
|
|
2236
|
+
|
|
2237
|
+
if [ -n "$test_details" ]; then
|
|
2238
|
+
completion_reason="$completion_reason, tests passed: $test_details"
|
|
2239
|
+
else
|
|
2240
|
+
completion_reason="$completion_reason, all tests passed ($TESTS_PASSED passed, 0 failed)"
|
|
2241
|
+
fi
|
|
2242
|
+
else
|
|
2243
|
+
completion_reason="$completion_reason, all tests passed ($TESTS_PASSED passed, 0 failed)"
|
|
2244
|
+
fi
|
|
2245
|
+
|
|
2246
|
+
approve "$completion_reason" "true"
|
|
1791
2247
|
else
|
|
1792
2248
|
# More increments in queue - transition to next
|
|
1793
2249
|
NEXT_INCREMENT=$(echo "$SESSION" | jq -r '.incrementQueue[1] // null')
|
|
@@ -1909,7 +2365,15 @@ echo "$SESSION" | jq --argjson iter "$NEXT_ITERATION" --arg now "$(date -u +%Y-%
|
|
|
1909
2365
|
'.iteration = $iter | .lastActivity = $now' \
|
|
1910
2366
|
> "$SESSION_FILE"
|
|
1911
2367
|
|
|
1912
|
-
# Build context message with test instructions (v2.
|
|
2368
|
+
# Build context message with test instructions (v2.4 enhanced with agent hierarchy)
|
|
2369
|
+
# Detect agent type for context message
|
|
2370
|
+
AGENT_TYPE=$(detect_agent_type "$TRANSCRIPT_PATH")
|
|
2371
|
+
AGENT_DISPLAY=$(get_agent_display_name "$AGENT_TYPE")
|
|
2372
|
+
|
|
2373
|
+
# Get subagent activity for context
|
|
2374
|
+
SUBAGENT_ACTIVITY=$(detect_subagent_activity "$TRANSCRIPT_PATH")
|
|
2375
|
+
SUBAGENT_COUNT=$(echo "$SUBAGENT_ACTIVITY" | jq -r '.spawned // 0')
|
|
2376
|
+
|
|
1913
2377
|
if [ "$SIMPLE_MODE" = "true" ]; then
|
|
1914
2378
|
CONTEXT="Continue working. Iteration $NEXT_ITERATION/$MAX_ITERATIONS."
|
|
1915
2379
|
else
|
|
@@ -1936,36 +2400,75 @@ else
|
|
|
1936
2400
|
# Get test instructions for this project (NEW - v2.2)
|
|
1937
2401
|
TEST_INSTRUCTIONS=$(format_test_instructions)
|
|
1938
2402
|
|
|
1939
|
-
# Build
|
|
2403
|
+
# Build agent header based on type (NEW - v2.4)
|
|
2404
|
+
AGENT_HEADER=""
|
|
2405
|
+
if [ "$AGENT_TYPE" = "orchestrator" ]; then
|
|
2406
|
+
AGENT_HEADER="
|
|
2407
|
+
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2408
|
+
┃ $AGENT_DISPLAY ┃
|
|
2409
|
+
┃ AUTO SESSION - Iteration $NEXT_ITERATION/$MAX_ITERATIONS ┃
|
|
2410
|
+
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
|
|
2411
|
+
else
|
|
2412
|
+
AGENT_HEADER="
|
|
2413
|
+
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2414
|
+
┃ $AGENT_DISPLAY ┃
|
|
2415
|
+
┃ Working under: 🤖 Main Orchestrator ┃
|
|
2416
|
+
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
|
|
2417
|
+
fi
|
|
2418
|
+
|
|
2419
|
+
# Build stop criteria message - MUST be clear for each agent (v2.4)
|
|
1940
2420
|
STOP_CRITERIA=""
|
|
1941
|
-
if [ "$
|
|
1942
|
-
|
|
2421
|
+
if [ "$AGENT_TYPE" = "orchestrator" ]; then
|
|
2422
|
+
# Main orchestrator stop criteria
|
|
2423
|
+
if [ "$TDD_MODE" = "true" ]; then
|
|
2424
|
+
STOP_CRITERIA="
|
|
1943
2425
|
╔══════════════════════════════════════════════════════════════╗
|
|
1944
|
-
║ 🎯
|
|
2426
|
+
║ 🎯 SESSION STOP CONDITION (TDD STRICT MODE) ║
|
|
1945
2427
|
╠══════════════════════════════════════════════════════════════╣
|
|
1946
2428
|
║ ✅ ALL tasks in tasks.md marked [x] completed ║
|
|
1947
2429
|
║ ✅ ALL tests pass (0 failures required) ║
|
|
1948
2430
|
║ ✅ Test execution detected in output ║
|
|
1949
2431
|
╠══════════════════════════════════════════════════════════════╣
|
|
1950
|
-
║ Source: $(printf '%-
|
|
2432
|
+
║ TDD Source: $(printf '%-42s' "$(get_tdd_source)")║
|
|
1951
2433
|
╚══════════════════════════════════════════════════════════════╝"
|
|
1952
|
-
|
|
1953
|
-
|
|
2434
|
+
else
|
|
2435
|
+
STOP_CRITERIA="
|
|
1954
2436
|
╔══════════════════════════════════════════════════════════════╗
|
|
1955
|
-
║ 🎯
|
|
2437
|
+
║ 🎯 SESSION STOP CONDITION ║
|
|
1956
2438
|
╠══════════════════════════════════════════════════════════════╣
|
|
1957
2439
|
║ ✅ ALL tasks in tasks.md marked [x] completed ║
|
|
1958
2440
|
║ ✅ Tests executed and passing ║
|
|
1959
2441
|
╚══════════════════════════════════════════════════════════════╝"
|
|
2442
|
+
fi
|
|
2443
|
+
else
|
|
2444
|
+
# Subagent stop criteria - simpler, just complete the task
|
|
2445
|
+
STOP_CRITERIA="
|
|
2446
|
+
╔══════════════════════════════════════════════════════════════╗
|
|
2447
|
+
║ 🎯 SUBAGENT STOP CONDITION ║
|
|
2448
|
+
╠══════════════════════════════════════════════════════════════╣
|
|
2449
|
+
║ ✅ Complete the assigned task ║
|
|
2450
|
+
║ ↩️ Then return control to Main Orchestrator ║
|
|
2451
|
+
╚══════════════════════════════════════════════════════════════╝"
|
|
2452
|
+
fi
|
|
2453
|
+
|
|
2454
|
+
# Build subagent info if any were spawned (NEW - v2.4)
|
|
2455
|
+
SUBAGENT_INFO=""
|
|
2456
|
+
if [ "$SUBAGENT_COUNT" -gt 0 ] && [ "$AGENT_TYPE" = "orchestrator" ]; then
|
|
2457
|
+
SUBAGENT_TYPES=$(echo "$SUBAGENT_ACTIVITY" | jq -r '.types | join(", ")' 2>/dev/null || echo "various")
|
|
2458
|
+
SUBAGENT_INFO="
|
|
2459
|
+
📦 SUBAGENT ACTIVITY (this session):
|
|
2460
|
+
├─ Spawned: $SUBAGENT_COUNT subagent(s)
|
|
2461
|
+
└─ Types: $SUBAGENT_TYPES"
|
|
1960
2462
|
fi
|
|
1961
2463
|
|
|
1962
|
-
# Build full context message
|
|
1963
|
-
CONTEXT="
|
|
2464
|
+
# Build full context message (v2.4)
|
|
2465
|
+
CONTEXT="$AGENT_HEADER
|
|
1964
2466
|
$STOP_CRITERIA
|
|
1965
2467
|
|
|
1966
2468
|
📊 CURRENT PROGRESS:
|
|
1967
2469
|
$PROGRESS
|
|
1968
2470
|
$TEST_STATUS
|
|
2471
|
+
$SUBAGENT_INFO
|
|
1969
2472
|
|
|
1970
2473
|
$TEST_INSTRUCTIONS
|
|
1971
2474
|
|
|
@@ -1981,8 +2484,9 @@ $TEST_INSTRUCTIONS
|
|
|
1981
2484
|
⚠️ This agent will NOT stop until the STOP CONDITION above is met!"
|
|
1982
2485
|
fi
|
|
1983
2486
|
|
|
1984
|
-
# Log iteration
|
|
1985
|
-
|
|
2487
|
+
# Log iteration with agent info (v2.4)
|
|
2488
|
+
AGENT_SHORT=$(get_agent_type_short "$AGENT_TYPE")
|
|
2489
|
+
echo "{\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"event\":\"iteration\",\"iteration\":$NEXT_ITERATION,\"increment\":\"$CURRENT_INCREMENT\",\"agentType\":\"$AGENT_SHORT\",\"subagentsSpawned\":$SUBAGENT_COUNT,\"testsRun\":$TESTS_RUN,\"testsPassed\":${TESTS_PASSED:-0},\"testsFailed\":${TESTS_FAILED:-0}}" >> "$LOGS_DIR/auto-iterations.log"
|
|
1986
2490
|
|
|
1987
2491
|
# Block exit and re-feed prompt
|
|
1988
2492
|
block "Work incomplete, continuing..." "$CONTEXT"
|
|
@@ -98,7 +98,7 @@ Technology stack → .specweave/docs/internal/architecture/tech-stack.md
|
|
|
98
98
|
Business rules → .specweave/docs/internal/strategy/business-rules.md
|
|
99
99
|
Team workflows → .specweave/docs/internal/processes/team-workflows.md
|
|
100
100
|
Deployment process → .specweave/docs/internal/processes/deployment.md
|
|
101
|
-
Domain knowledge → .specweave/increments/{####-name}/domain/{domain}.md
|
|
101
|
+
Domain knowledge → .specweave/increments/{####-name}/docs/domain/{domain}.md
|
|
102
102
|
|
|
103
103
|
# Public Documentation (user-facing, can be published)
|
|
104
104
|
Project conventions → .specweave/docs/public/guides/project-conventions.md
|
|
@@ -438,7 +438,7 @@ function useCustomAuth() {
|
|
|
438
438
|
**Domain**: Healthcare, Patient Management, Provider Scheduling
|
|
439
439
|
|
|
440
440
|
### Quick Links
|
|
441
|
-
- [Domain Model](.specweave/increments/####-name/domain/appointments/domain-model.md)
|
|
441
|
+
- [Domain Model](.specweave/increments/####-name/docs/domain/appointments/domain-model.md)
|
|
442
442
|
- [Existing System Architecture](.specweave/docs/internal/architecture/existing-system.md)
|
|
443
443
|
- [Tech Stack](.specweave/docs/internal/architecture/tech-stack.md)
|
|
444
444
|
- [Business Rules](.specweave/docs/internal/strategy/appointments/business-rules.md)
|
|
@@ -508,7 +508,7 @@ if (exists("specifications/modules/appointments/domain-model.md")) {
|
|
|
508
508
|
I found the following project-specific content in your backup CLAUDE.md:
|
|
509
509
|
|
|
510
510
|
📦 Domain Model (Healthcare Appointments)
|
|
511
|
-
→ .specweave/increments/####-name/domain/appointments/domain-model.md
|
|
511
|
+
→ .specweave/increments/####-name/docs/domain/appointments/domain-model.md
|
|
512
512
|
|
|
513
513
|
🏗️ Microservices Architecture
|
|
514
514
|
→ .specweave/docs/internal/architecture/existing-system.md
|
|
@@ -665,7 +665,7 @@ The following content remains in the backup and will be extracted when you work
|
|
|
665
665
|
|
|
666
666
|
## Files Created
|
|
667
667
|
|
|
668
|
-
1. ✅ `.specweave/increments/####-name/domain/appointments/domain-model.md` (450 lines)
|
|
668
|
+
1. ✅ `.specweave/increments/####-name/docs/domain/appointments/domain-model.md` (450 lines)
|
|
669
669
|
2. ✅ `.specweave/docs/internal/architecture/existing-system.md` (320 lines)
|
|
670
670
|
3. ✅ `.specweave/docs/internal/architecture/tech-stack.md` (180 lines)
|
|
671
671
|
4. ✅ `.specweave/docs/internal/strategy/appointments/business-rules.md` (280 lines)
|
|
@@ -688,7 +688,7 @@ The following content remains in the backup and will be extracted when you work
|
|
|
688
688
|
|
|
689
689
|
| Content Type | Lines | Destination |
|
|
690
690
|
|--------------|-------|-------------|
|
|
691
|
-
| Domain Model | 450 | .specweave/increments/####-name/domain/ |
|
|
691
|
+
| Domain Model | 450 | .specweave/increments/####-name/docs/domain/ |
|
|
692
692
|
| Architecture | 320 | .specweave/docs/internal/architecture/ |
|
|
693
693
|
| Tech Stack | 180 | .specweave/docs/internal/architecture/ |
|
|
694
694
|
| Business Rules | 280 | .specweave/docs/internal/strategy/ |
|
|
@@ -782,7 +782,7 @@ Proceed with merge? (y/n)
|
|
|
782
782
|
✅ Merge complete!
|
|
783
783
|
|
|
784
784
|
Created:
|
|
785
|
-
1. .specweave/increments/####-name/domain/appointments/domain-model.md
|
|
785
|
+
1. .specweave/increments/####-name/docs/domain/appointments/domain-model.md
|
|
786
786
|
2. .specweave/docs/internal/architecture/existing-system.md
|
|
787
787
|
3. .specweave/docs/internal/architecture/tech-stack.md
|
|
788
788
|
4. .specweave/docs/internal/strategy/appointments/business-rules.md
|
|
@@ -762,6 +762,24 @@ node plugins/specweave/skills/increment-planner/scripts/feature-utils.js check-i
|
|
|
762
762
|
mkdir -p .specweave/increments/0021-feature-name
|
|
763
763
|
```
|
|
764
764
|
|
|
765
|
+
**⚠️ CRITICAL: Increment Folder Structure Rules**
|
|
766
|
+
|
|
767
|
+
**ONLY these files allowed at increment ROOT:**
|
|
768
|
+
- `metadata.json` - Increment state (auto-managed)
|
|
769
|
+
- `spec.md` - Specification
|
|
770
|
+
- `plan.md` - Implementation plan
|
|
771
|
+
- `tasks.md` - Task list
|
|
772
|
+
|
|
773
|
+
**ALL other files MUST go in subfolders:**
|
|
774
|
+
```
|
|
775
|
+
.specweave/increments/####-name/
|
|
776
|
+
├── reports/ # Validation reports, QA, completion summaries
|
|
777
|
+
├── logs/ # Debug logs, session traces
|
|
778
|
+
├── scripts/ # Helper scripts
|
|
779
|
+
├── docs/ # Additional documentation, domain knowledge
|
|
780
|
+
└── backups/ # Backup files
|
|
781
|
+
```
|
|
782
|
+
|
|
765
783
|
### STEP 4: Create metadata.json FIRST (MANDATORY - CRITICAL ORDER!)
|
|
766
784
|
|
|
767
785
|
**🚨 CRITICAL: metadata.json MUST be created BEFORE spec.md!**
|
|
@@ -271,12 +271,25 @@ Use `/sw:save` to commit and push changes across all repos at once:
|
|
|
271
271
|
```
|
|
272
272
|
|
|
273
273
|
**Features:**
|
|
274
|
+
- **Auto-discovers nested repos** - Scans `repositories/`, `packages/`, `services/`, `apps/`, `libs/` for `.git` directories (up to 4 levels deep)
|
|
274
275
|
- Auto-detects repos with changes
|
|
275
276
|
- Sets up remotes if missing (prompts for URL or uses umbrella config)
|
|
276
277
|
- Commits with same message to all repos
|
|
277
278
|
- Pushes to origin
|
|
278
279
|
- Skips repos with no changes
|
|
279
280
|
|
|
281
|
+
**Auto-Discovery (No Config Required):**
|
|
282
|
+
Even without umbrella config, `/sw:save` automatically finds all nested repos:
|
|
283
|
+
```
|
|
284
|
+
my-project/
|
|
285
|
+
├── repositories/
|
|
286
|
+
│ ├── frontend/.git # ← Auto-discovered
|
|
287
|
+
│ ├── backend/.git # ← Auto-discovered
|
|
288
|
+
│ └── shared/.git # ← Auto-discovered
|
|
289
|
+
└── .git # ← Parent repo included
|
|
290
|
+
```
|
|
291
|
+
All 4 repos will be committed and pushed with a single `/sw:save` command!
|
|
292
|
+
|
|
280
293
|
## Important Notes
|
|
281
294
|
|
|
282
295
|
1. **Each repo is independent** - Own `.specweave/`, own increments, own external tool sync
|