specweave 1.0.78 β†’ 1.0.80

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.
@@ -2,494 +2,9 @@
2
2
  name: sw:status
3
3
  description: Show increment status overview with rich details (active, backlog, paused, completed, abandoned)
4
4
  usage: /sw:status [--active|--backlog|--paused|--completed|--abandoned|--stale]
5
+ allowed-tools: Bash(bash:*)
5
6
  ---
6
7
 
7
- # Increment Status Command
8
+ # Increment Status
8
9
 
9
- **Usage**: `/sw:status [filter]`
10
-
11
- ---
12
-
13
- ## Purpose
14
-
15
- Display comprehensive increment status overview:
16
- - **Active** increments (currently working)
17
- - **Backlog** increments (planned but not started)
18
- - **Paused** increments (blocked/deprioritized)
19
- - **Completed** increments (done)
20
- - **Abandoned** increments (obsolete)
21
- - **Warnings** for stale increments (paused >7 days, active >30 days)
22
- - **Suggestions** for next actions
23
-
24
- ---
25
-
26
- ## Output Format
27
-
28
- ### Default (All Increments)
29
-
30
- ```bash
31
- /sw:status
32
-
33
- πŸ“Š Increment Status Overview
34
-
35
- πŸ”₯ Active (2):
36
- 🚨 0005-payment-hotfix [hotfix]
37
- Progress: 90% (18/20 tasks)
38
- Age: 6 hours
39
- Last: Fixed Stripe webhook signature
40
-
41
- πŸ”§ 0006-i18n [feature]
42
- Progress: 50% (10/20 tasks)
43
- Age: 2 days
44
- Last: Created translation pipeline
45
-
46
- πŸ—‚οΈ Backlog (2):
47
- πŸ“¦ 0032-feature-a [feature]
48
- In backlog: 5 days
49
- Reason: Low priority
50
-
51
- πŸ“¦ 0033-feature-b [feature]
52
- In backlog: 3 days
53
- Reason: Waiting for decisions
54
-
55
- ⏸️ Paused (1):
56
- πŸ”„ 0007-stripe-integration [feature]
57
- Progress: 30% (6/20 tasks)
58
- Paused: 3 days ago
59
- Reason: Waiting for Stripe API keys
60
- ⚠️ Review or abandon?
61
-
62
- βœ… Completed (4):
63
- 0001-core-framework
64
- 0002-core-enhancements
65
- 0003-intelligent-model-selection
66
- 0004-plugin-architecture
67
-
68
- πŸ“Š Summary:
69
- - Active: 2 increments (1 hotfix, 1 feature)
70
- - Backlog: 2 increments (planned for future)
71
- - Paused: 1 increment
72
- - Completed: 4 increments
73
- - Context switching: 20-40% cost (2 active)
74
-
75
- πŸ“‹ Type Limits (v0.7.0+):
76
- βœ… hotfix: 1/unlimited active
77
- βœ… feature: 1/2 active
78
- βœ… refactor: 0/1 active
79
- βœ… bug: 0/unlimited active
80
- βœ… change-request: 0/2 active
81
- βœ… experiment: 0/unlimited active
82
-
83
- πŸ’‘ Suggestions:
84
- - Complete 0005 first (90% done, almost there!)
85
- - Resume or abandon 0007 (stale)
86
-
87
- Commands:
88
- /sw:do # Continue current work
89
- /sw:resume 0007 # Resume paused increment
90
- /sw:abandon 0007 # Abandon if obsolete
91
- ```
92
-
93
- ### Filtered Views
94
-
95
- ```bash
96
- # Active only
97
- /sw:status --active
98
-
99
- πŸ”₯ Active Increments (2):
100
- 🚨 0005-payment-hotfix [hotfix] (90% done, 6 hours)
101
- πŸ”§ 0006-i18n [feature] (50% done, 2 days)
102
-
103
- # Paused only
104
- /sw:status --paused
105
-
106
- ⏸️ Paused Increments (1):
107
- πŸ”„ 0007-stripe [feature] (paused 3 days)
108
- Reason: Waiting for API keys
109
-
110
- # Stale only (paused >7 days OR active >30 days)
111
- /sw:status --stale
112
-
113
- ⚠️ Stale Increments (2):
114
- πŸ”„ 0008-experiment [experiment] (paused 10 days)
115
- 🚨 AUTO-ABANDON WARNING (14 days inactive)
116
-
117
- πŸ”§ 0009-big-refactor [refactor] (active 35 days)
118
- ⚠️ Long-running - consider breaking into smaller increments
119
- ```
120
-
121
- ---
122
-
123
- ## Implementation
124
-
125
- Uses MetadataManager and Limits to query and display:
126
-
127
- ```typescript
128
- import { MetadataManager, IncrementStatus } from '../src/core/increment/metadata-manager';
129
- import { checkAllLimits, getLimitsSummary } from '../src/core/increment/limits';
130
-
131
- // Get all increments
132
- const allIncrements = MetadataManager.getAll();
133
-
134
- // Group by status
135
- const active = allIncrements.filter(m => m.status === IncrementStatus.ACTIVE);
136
- const backlog = allIncrements.filter(m => m.status === IncrementStatus.BACKLOG);
137
- const paused = allIncrements.filter(m => m.status === IncrementStatus.PAUSED);
138
- const completed = allIncrements.filter(m => m.status === IncrementStatus.COMPLETED);
139
- const abandoned = allIncrements.filter(m => m.status === IncrementStatus.ABANDONED);
140
-
141
- // Get extended metadata (with progress%)
142
- const extended = active.map(m => MetadataManager.getExtended(m.id));
143
-
144
- // Display rich output
145
- console.log('πŸ“Š Increment Status Overview\n');
146
-
147
- // Active
148
- if (active.length > 0) {
149
- console.log(`πŸ”₯ Active (${active.length}):`);
150
- extended.forEach(inc => {
151
- const icon = inc.type === 'hotfix' ? '🚨' : 'πŸ”§';
152
- console.log(` ${icon} ${inc.id} [${inc.type}]`);
153
- console.log(` Progress: ${inc.progress}% (${inc.completedTasks}/${inc.totalTasks} tasks)`);
154
- console.log(` Age: ${formatAge(inc.ageInDays)}`);
155
- });
156
- }
157
-
158
- // ... similar for paused, completed, abandoned
159
-
160
- // Summary with type limits (v0.7.0+)
161
- console.log('\nπŸ“Š Summary:');
162
- console.log(` - Active: ${active.length} increments`);
163
- console.log(` - Backlog: ${backlog.length} increments`);
164
- console.log(` - Paused: ${paused.length} increments`);
165
- console.log(` - Completed: ${completed.length} increments`);
166
-
167
- // Type limits breakdown
168
- console.log('\nπŸ“‹ Type Limits (v0.7.0+):');
169
- const limitsCheck = checkAllLimits();
170
- for (const [type, check] of Object.entries(limitsCheck)) {
171
- const icon = check.exceeded ? '⚠️ ' : 'βœ…';
172
- const limitStr = check.limit === null ? 'unlimited' : check.limit.toString();
173
- console.log(` ${icon} ${type}: ${check.current}/${limitStr} active`);
174
- }
175
-
176
- // Context switching warning if multiple active
177
- if (active.length > 1) {
178
- const cost = active.length === 2 ? '20-30%' : '40%';
179
- console.log(`\n⚠️ Context switching: ${cost} productivity cost`);
180
- }
181
- ```
182
-
183
- ---
184
-
185
- ## Progress Calculation
186
-
187
- Progress percentage calculated from tasks.md:
188
-
189
- ```typescript
190
- // Count completed tasks: [x] or [X]
191
- const completedMatches = tasksContent.match(/\[x\]/gi);
192
- const completedTasks = completedMatches ? completedMatches.length : 0;
193
-
194
- // Count total tasks: [ ] or [x]
195
- const totalMatches = tasksContent.match(/\[ \]|\[x\]/gi);
196
- const totalTasks = totalMatches ? totalMatches.length : 0;
197
-
198
- // Calculate percentage
199
- const progress = Math.round((completedTasks / totalTasks) * 100);
200
- ```
201
-
202
- ---
203
-
204
- ## Warnings and Suggestions
205
-
206
- ### Stale Paused Increments
207
-
208
- Paused >7 days β†’ warning:
209
-
210
- ```
211
- ⏸️ Paused (1):
212
- πŸ”„ 0007-stripe [feature]
213
- Paused: 10 days ago
214
- ⚠️ STALE! Review or abandon?
215
-
216
- πŸ’‘ Actions:
217
- /sw:resume 0007 # If unblocked
218
- /sw:abandon 0007 # If no longer needed
219
- ```
220
-
221
- ### Long-Running Active Increments
222
-
223
- Active >30 days β†’ warning:
224
-
225
- ```
226
- πŸ”₯ Active (1):
227
- πŸ”§ 0009-big-refactor [refactor]
228
- Progress: 45% (23/50 tasks)
229
- Age: 35 days
230
- ⚠️ Long-running! Consider breaking into smaller increments
231
-
232
- πŸ’‘ Suggestion: Large increments increase risk and reduce velocity
233
- ```
234
-
235
- ### Context Switching Cost
236
-
237
- Multiple active features β†’ warning:
238
-
239
- ```
240
- πŸ“Š Summary:
241
- - Active: 3 features (0010, 0011, 0012)
242
- - Context switching: 40-60% productivity cost
243
-
244
- ⚠️ High context switching detected!
245
- Research shows: 3+ concurrent tasks = 40% productivity loss
246
- Suggestion: Complete or pause one before continuing
247
- ```
248
-
249
- ### Auto-Abandon Warning (Experiments)
250
-
251
- Experiments inactive >14 days β†’ warning:
252
-
253
- ```
254
- πŸ§ͺ Experiments (1):
255
- πŸ”¬ 0010-graphql-experiment [experiment]
256
- Last activity: 15 days ago
257
- 🚨 AUTO-ABANDON WARNING
258
-
259
- πŸ’‘ Experiments auto-abandon after 14 days of inactivity
260
- To prevent: Update via /sw:do or /touch 0010
261
- ```
262
-
263
- ---
264
-
265
- ## Cross-Project View (v0.33.0+)
266
-
267
- When an increment has user stories targeting multiple projects, show grouped view:
268
-
269
- ```bash
270
- /sw:status 0125
271
-
272
- πŸ“Š Increment Status: 0125-cross-project-targeting
273
-
274
- πŸ”€ Cross-Project Increment (spans 3 projects):
275
-
276
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
277
- β”‚ Project β”‚ Provider β”‚ USs β”‚ Status β”‚ External Issues β”‚
278
- β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
279
- β”‚ frontend-app β”‚ github β”‚ US-001, β”‚ βœ… Synced β”‚ #45, #46 β”‚
280
- β”‚ β”‚ β”‚ US-003 β”‚ β”‚ github.com/org/fe β”‚
281
- β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
282
- β”‚ backend-api β”‚ jira β”‚ US-002 β”‚ βœ… Synced β”‚ SEC-123 β”‚
283
- β”‚ β”‚ β”‚ β”‚ β”‚ jira.com/browse β”‚
284
- β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
285
- β”‚ shared-lib β”‚ ⚠️ None β”‚ US-004 β”‚ Not mapped β”‚ β€” β”‚
286
- β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
287
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
288
-
289
- πŸ“‹ Progress by Project:
290
- frontend-app: 75% (3/4 tasks)
291
- backend-api: 50% (2/4 tasks)
292
- shared-lib: 100% (2/2 tasks)
293
-
294
- πŸ’‘ Unmapped project 'shared-lib':
295
- Add to .specweave/config.json projectMappings or create issues manually
296
- ```
297
-
298
- ### Cross-Project Implementation
299
-
300
- ```typescript
301
- import { CrossProjectSync } from '../src/core/living-docs/cross-project-sync';
302
- import { ExternalSyncOrchestrator } from '../src/core/living-docs/external-sync-orchestrator';
303
-
304
- // Detect cross-project
305
- const crossProjectSync = new CrossProjectSync(projectRoot);
306
- const userStories = parseUserStories(specContent);
307
- const isCrossProject = crossProjectSync.isCrossProject(userStories, defaultProject);
308
-
309
- if (isCrossProject) {
310
- // Group by project
311
- const groups = crossProjectSync.groupByProject(userStories, defaultProject);
312
-
313
- // Load project mappings
314
- const orchestrator = new ExternalSyncOrchestrator(projectRoot);
315
- await orchestrator.loadProjectMappings();
316
-
317
- // Display per-project status
318
- for (const [projectId, stories] of groups) {
319
- const mapping = orchestrator.getProjectMapping(projectId);
320
- const provider = mapping?.github ? 'github' : mapping?.jira ? 'jira' : mapping?.ado ? 'ado' : null;
321
-
322
- console.log(`β”‚ ${projectId.padEnd(13)} β”‚ ${(provider || '⚠️ None').padEnd(10)} β”‚ ...`);
323
- }
324
- }
325
- ```
326
-
327
- ---
328
-
329
- ## Filters
330
-
331
- ### --active
332
-
333
- Show only active increments
334
-
335
- ```bash
336
- /sw:status --active
337
-
338
- πŸ”₯ Active (2):
339
- 🚨 0005-hotfix [hotfix] (90% done)
340
- πŸ”§ 0006-i18n [feature] (50% done)
341
- ```
342
-
343
- ### --backlog
344
-
345
- Show only backlog increments
346
-
347
- ```bash
348
- /sw:status --backlog
349
-
350
- πŸ—‚οΈ Backlog (3):
351
- πŸ“¦ 0032-feature-a [feature] (in backlog 5 days)
352
- Reason: Low priority
353
-
354
- πŸ“¦ 0033-feature-b [feature] (in backlog 3 days)
355
- Reason: Waiting for decisions
356
-
357
- πŸ“¦ 0034-feature-c [feature] (in backlog 1 day)
358
- Reason: Multiple planned ideas
359
-
360
- πŸ’‘ Start work: /sw:resume <id>
361
- ```
362
-
363
- ### --paused
364
-
365
- Show only paused increments
366
-
367
- ```bash
368
- /sw:status --paused
369
-
370
- ⏸️ Paused (2):
371
- πŸ”„ 0007-stripe [feature] (paused 3 days)
372
- Reason: Waiting for API keys
373
-
374
- πŸ”„ 0008-refactor [refactor] (paused 10 days)
375
- Reason: Deprioritized
376
- ⚠️ STALE
377
- ```
378
-
379
- ### --completed
380
-
381
- Show only completed increments
382
-
383
- ```bash
384
- /sw:status --completed
385
-
386
- βœ… Completed (5):
387
- 0001-core-framework (completed 30 days ago)
388
- 0002-core-enhancements (completed 25 days ago)
389
- 0003-model-selection (completed 20 days ago)
390
- 0004-plugin-architecture (completed 15 days ago)
391
- 0005-cross-platform (completed 10 days ago)
392
- ```
393
-
394
- ### --abandoned
395
-
396
- Show only abandoned increments
397
-
398
- ```bash
399
- /sw:status --abandoned
400
-
401
- ❌ Abandoned (3):
402
- 0008-old-approach (Requirements changed)
403
- 0009-failed-experiment (Experiment failed)
404
- 0010-superseded (Replaced by 0011)
405
-
406
- πŸ“Š Stats:
407
- - Abandonment rate: 30% (3/10 total)
408
- - Common reasons: Requirements changed (2), Experiment failed (1)
409
-
410
- πŸ’‘ Periodically review _abandoned/ for learnings
411
- ```
412
-
413
- ### --stale
414
-
415
- Show only stale increments (paused >7 days OR active >30 days)
416
-
417
- ```bash
418
- /sw:status --stale
419
-
420
- ⚠️ Stale Increments (3):
421
- πŸ”„ 0007-stripe [feature] (paused 10 days)
422
- πŸ”„ 0008-experiment [experiment] (paused 15 days)
423
- 🚨 AUTO-ABANDON WARNING
424
- πŸ”§ 0009-refactor [refactor] (active 35 days)
425
- ⚠️ Long-running
426
-
427
- πŸ’‘ Review stale increments weekly
428
- Paused >7 days: Resume or abandon
429
- Active >30 days: Consider breaking into smaller increments
430
- ```
431
-
432
- ---
433
-
434
- ## Related Commands
435
-
436
- - `/sw:do` - Continue work on active increment
437
- - `/sw:progress` - Detailed progress for current increment
438
- - `/sw:backlog <id>` - Move increment to backlog
439
- - `/sw:pause <id>` - Pause active increment
440
- - `/sw:resume <id>` - Resume paused or backlog increment
441
- - `/sw:abandon <id>` - Abandon increment (move to _abandoned/)
442
-
443
- ---
444
-
445
- ## Best Practices
446
-
447
- βœ… **Check status regularly** - Daily or before starting work
448
-
449
- βœ… **Address warnings promptly** - Don't let stale increments pile up
450
-
451
- βœ… **Complete before starting new** - Minimize context switching
452
-
453
- βœ… **Review abandoned for learnings** - Understand patterns
454
-
455
- ❌ **Don't ignore stale warnings** - They indicate blocked or forgotten work
456
-
457
- ❌ **Don't accumulate paused increments** - Resume or abandon
458
-
459
- ---
460
-
461
- ## Statistics and Analytics
462
-
463
- Future enhancement (v0.8.0+):
464
-
465
- ```bash
466
- /sw:status --analytics
467
-
468
- πŸ“Š Increment Analytics (Last 90 Days):
469
-
470
- Velocity:
471
- - Completed: 8 increments
472
- - Avg cycle time: 4.2 days
473
- - Completion rate: 80%
474
-
475
- Quality:
476
- - Avg coverage: 85%
477
- - Avg tasks/increment: 25
478
-
479
- Patterns:
480
- - Most common type: feature (70%)
481
- - Context switching: 1.5 active avg
482
- - Stale rate: 15% (paused >7 days)
483
-
484
- Recommendations:
485
- - βœ… Good velocity (8 increments/90 days)
486
- - ⚠️ High abandonment (20%) - review scoping
487
- - βœ… Low context switching (1.5 avg)
488
- ```
489
-
490
- ---
491
-
492
- **Command**: `/sw:status`
493
- **Plugin**: specweave (core)
494
- **Version**: v0.7.0+
495
- **Part of**: Increment 0007 - Smart Status Management
10
+ !`bash "${CLAUDE_PLUGIN_ROOT}/scripts/read-status.sh" $ARGUMENTS`
@@ -8,10 +8,11 @@
8
8
  ## Purpose
9
9
 
10
10
  Core hooks automate SpecWeave's fundamental workflows:
11
- - **Sound notifications** when tasks complete or input is needed
11
+ - **Sound notifications** when tasks complete (v1.0.77+: plays when task marked `[x]` in tasks.md)
12
12
  - **Living docs sync** after task completion
13
13
  - **Translation** of non-English documentation
14
14
  - **Self-reflection** for AI-driven quality improvements
15
+ - **Auto mode loops** for autonomous execution
15
16
 
16
17
  **Note**: External tool sync (GitHub, JIRA, Azure DevOps) has been moved to respective plugin hooks as of v0.13.0. See "Architecture Changes" section below.
17
18
 
@@ -147,6 +148,29 @@ Core hooks automate SpecWeave's fundamental workflows:
147
148
 
148
149
  ---
149
150
 
151
+ ### πŸ”Š Task Completion Sound (v1.0.77+)
152
+
153
+ **Triggers**: Automatically when any task is marked `[x]` in tasks.md
154
+
155
+ **How It Works**:
156
+ - Monitors task completion count in `.specweave/state/.last-task-completion`
157
+ - Plays pleasant sound (Glass.aiff) when count increases
158
+ - Runs in background (never blocks or delays hook execution)
159
+ - **Smart auto mode detection**: Skips during `/sw:auto` (Stop hook plays ONE sound at END)
160
+
161
+ **Behavior by Mode**:
162
+ - **Normal mode**: Sound plays after EACH task completion
163
+ - **Auto mode** (`/sw:auto`): NO sounds during execution, ONE completion sound when main orchestrator finishes
164
+
165
+ **Platforms**:
166
+ - macOS: `Glass.aiff` (built-in system sound)
167
+ - Linux (PulseAudio): `/usr/share/sounds/freedesktop/stereo/complete.oga`
168
+ - Linux (ALSA): `/usr/share/sounds/alsa/Front_Center.wav`
169
+
170
+ **Implementation**: Integrated into `PostToolUse` hook dispatcher (`v2/dispatchers/post-tool-use.sh`)
171
+
172
+ ---
173
+
150
174
  ## How Hooks Work (Claude Code Native)
151
175
 
152
176
  **CRITICAL**: Hooks are **NOT copied** to `.claude/hooks/`. They stay in `plugins/specweave/hooks/` and Claude Code discovers them automatically.
@@ -42,6 +42,8 @@ while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -d "$PROJECT_ROOT/.specweave" ]]; do
42
42
  done
43
43
  [[ ! -d "$PROJECT_ROOT/.specweave" ]] && exit 0
44
44
 
45
+ STATE_DIR="$PROJECT_ROOT/.specweave/state"
46
+
45
47
  # ============================================================================
46
48
  # LOGGING INFRASTRUCTURE
47
49
  # ============================================================================
@@ -154,6 +156,57 @@ safe_run_sync() {
154
156
  return 0 # Always succeed
155
157
  }
156
158
 
159
+ # ============================================================================
160
+ # TASK COMPLETION SOUND (plays when task marked [x])
161
+ # ============================================================================
162
+
163
+ play_task_completion_sound() {
164
+ local tasks_file="$1"
165
+ local state_file="$STATE_DIR/.last-task-completion"
166
+ local session_file="$STATE_DIR/auto-session.json"
167
+
168
+ # CRITICAL: Skip sound if auto mode is active
169
+ # Auto mode has its own completion sound via Stop hook (plays once at END)
170
+ if [[ -f "$session_file" ]]; then
171
+ local auto_status=$(jq -r '.status // "unknown"' "$session_file" 2>/dev/null || echo "unknown")
172
+ if [[ "$auto_status" == "active" ]] || [[ "$auto_status" == "running" ]]; then
173
+ log_debug "Auto mode active - skipping task completion sound (Stop hook will handle it)"
174
+ return 0
175
+ fi
176
+ fi
177
+
178
+ # Extract current completion count
179
+ local current_count=$(grep -c '\*\*Status\*\*:.*\[x\]' "$tasks_file" 2>/dev/null || echo "0")
180
+
181
+ # Read previous count
182
+ local previous_count="0"
183
+ if [[ -f "$state_file" ]]; then
184
+ previous_count=$(cat "$state_file" 2>/dev/null || echo "0")
185
+ fi
186
+
187
+ # If count increased, a task was just completed
188
+ if [[ "$current_count" -gt "$previous_count" ]]; then
189
+ # Save new count
190
+ echo "$current_count" > "$state_file" 2>/dev/null
191
+
192
+ # Play completion sound (background, never blocks)
193
+ (
194
+ if [[ "$OSTYPE" == "darwin"* ]]; then
195
+ # macOS - use Glass.aiff for pleasant completion sound
196
+ afplay /System/Library/Sounds/Glass.aiff 2>/dev/null &
197
+ elif command -v paplay >/dev/null 2>&1; then
198
+ # Linux with PulseAudio
199
+ paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null &
200
+ elif command -v aplay >/dev/null 2>&1; then
201
+ # Linux with ALSA
202
+ aplay /usr/share/sounds/alsa/Front_Center.wav 2>/dev/null &
203
+ fi
204
+ ) &
205
+
206
+ log_debug "Task completion sound played (count: $previous_count β†’ $current_count)"
207
+ fi
208
+ }
209
+
157
210
  # ============================================================================
158
211
  # INPUT PARSING (with safe fallbacks)
159
212
  # ============================================================================
@@ -217,6 +270,9 @@ case "$FILE_PATH" in
217
270
  log_debug "Running task-ac-sync guard"
218
271
  safe_run_sync "$SYNC_SCRIPT" "task-ac-sync" "$INPUT"
219
272
  fi
273
+
274
+ # Play completion sound if task was marked complete (v1.0.77+)
275
+ play_task_completion_sound "$FILE_PATH"
220
276
  fi
221
277
 
222
278
  # Tasks or spec changed -> check for US completion (background)