specweave 0.26.2 → 0.26.4
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 +172 -1413
- package/dist/src/cli/commands/plan/plan-orchestrator.js +2 -2
- package/dist/src/cli/commands/plan/plan-orchestrator.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +147 -55
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
- package/dist/src/core/increment/completion-validator.d.ts +4 -0
- package/dist/src/core/increment/completion-validator.d.ts.map +1 -1
- package/dist/src/core/increment/completion-validator.js +36 -0
- package/dist/src/core/increment/completion-validator.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +47 -13
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/us-sync-throttle.d.ts +113 -0
- package/dist/src/core/us-sync-throttle.d.ts.map +1 -0
- package/dist/src/core/us-sync-throttle.js +195 -0
- package/dist/src/core/us-sync-throttle.js.map +1 -0
- package/dist/src/utils/external-tool-drift-detector.d.ts +76 -0
- package/dist/src/utils/external-tool-drift-detector.d.ts.map +1 -0
- package/dist/src/utils/external-tool-drift-detector.js +235 -0
- package/dist/src/utils/external-tool-drift-detector.js.map +1 -0
- package/package.json +4 -4
- package/plugins/specweave/hooks/post-task-completion.sh +6 -6
- package/plugins/specweave/hooks/pre-increment-start.sh +6 -1
- package/plugins/specweave/lib/hooks/us-completion-orchestrator.js +62 -89
- package/plugins/specweave/lib/hooks/us-completion-orchestrator.ts +215 -0
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +0 -1
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-release/hooks/post-task-completion.sh +5 -1
- package/plugins/specweave/agents/pm/AGENT.md.bak +0 -1893
- package/plugins/specweave/hooks/docs-changed.sh.backup +0 -79
- package/plugins/specweave/hooks/human-input-required.sh.backup +0 -75
- package/plugins/specweave/hooks/lib/migrate-increment-work.sh.bak +0 -245
- package/plugins/specweave/hooks/lib/sync-spec-content.sh.bak +0 -149
- package/plugins/specweave/hooks/lib/validate-spec-status.sh.bak +0 -163
- package/plugins/specweave/hooks/post-first-increment.sh.backup +0 -61
- package/plugins/specweave/hooks/post-first-increment.sh.bak +0 -61
- package/plugins/specweave/hooks/post-increment-change.sh.backup +0 -98
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +0 -231
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +0 -1048
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +0 -147
- package/plugins/specweave/hooks/post-spec-update.sh.backup +0 -158
- package/plugins/specweave/hooks/post-spec-update.sh.bak +0 -158
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +0 -179
- package/plugins/specweave/hooks/post-user-story-complete.sh.bak +0 -179
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +0 -83
- package/plugins/specweave/hooks/pre-command-deduplication.sh.bak +0 -83
- package/plugins/specweave/hooks/pre-implementation.sh.backup +0 -67
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +0 -194
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +0 -133
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +0 -386
- package/plugins/specweave/hooks/user-prompt-submit.sh.bak +0 -386
- package/plugins/specweave/lib/hooks/auto-transition.js.bak +0 -50
- package/plugins/specweave/lib/hooks/auto-transition.ts.bak +0 -84
- package/plugins/specweave/lib/hooks/git-diff-analyzer.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.d.ts.bak +0 -89
- package/plugins/specweave/lib/hooks/git-diff-analyzer.js.bak +0 -142
- package/plugins/specweave/lib/hooks/git-diff-analyzer.ts.bak +0 -269
- package/plugins/specweave/lib/hooks/invoke-translator-skill.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.d.ts.bak +0 -60
- package/plugins/specweave/lib/hooks/invoke-translator-skill.js.bak +0 -155
- package/plugins/specweave/lib/hooks/invoke-translator-skill.ts.bak +0 -264
- package/plugins/specweave/lib/hooks/prepare-reflection-context.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.d.ts.bak +0 -42
- package/plugins/specweave/lib/hooks/prepare-reflection-context.js.bak +0 -110
- package/plugins/specweave/lib/hooks/prepare-reflection-context.ts.bak +0 -178
- package/plugins/specweave/lib/hooks/reflection-config-loader.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.d.ts.bak +0 -45
- package/plugins/specweave/lib/hooks/reflection-config-loader.js.bak +0 -92
- package/plugins/specweave/lib/hooks/reflection-config-loader.ts.bak +0 -156
- package/plugins/specweave/lib/hooks/reflection-parser.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-parser.d.ts.bak +0 -33
- package/plugins/specweave/lib/hooks/reflection-parser.js.bak +0 -301
- package/plugins/specweave/lib/hooks/reflection-parser.ts.bak +0 -484
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.ts.bak +0 -56
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.js.bak +0 -182
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.ts.bak +0 -306
- package/plugins/specweave/lib/hooks/reflection-storage.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-storage.d.ts.bak +0 -64
- package/plugins/specweave/lib/hooks/reflection-storage.js.bak +0 -231
- package/plugins/specweave/lib/hooks/reflection-storage.ts.bak +0 -369
- package/plugins/specweave/lib/hooks/run-self-reflection.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.d.ts.bak +0 -43
- package/plugins/specweave/lib/hooks/run-self-reflection.js.bak +0 -132
- package/plugins/specweave/lib/hooks/run-self-reflection.ts.bak +0 -258
- package/plugins/specweave/lib/hooks/sync-cache.js.bak +0 -294
- package/plugins/specweave/lib/hooks/sync-living-docs.d.js.bak +0 -1
- package/plugins/specweave/lib/hooks/sync-living-docs.d.ts.bak +0 -27
- package/plugins/specweave/lib/hooks/sync-living-docs.js.bak +0 -339
- package/plugins/specweave/lib/hooks/sync-us-tasks.js.bak +0 -476
- package/plugins/specweave/lib/hooks/translate-file.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/translate-file.d.ts.bak +0 -59
- package/plugins/specweave/lib/hooks/translate-file.js.bak +0 -289
- package/plugins/specweave/lib/hooks/translate-file.ts.bak +0 -428
- package/plugins/specweave/lib/hooks/translate-living-docs.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.d.ts.bak +0 -13
- package/plugins/specweave/lib/hooks/translate-living-docs.js.bak +0 -119
- package/plugins/specweave/lib/hooks/translate-living-docs.ts.bak +0 -224
- package/plugins/specweave/lib/hooks/update-ac-status.js.bak +0 -51
- package/plugins/specweave/lib/hooks/update-ac-status.ts.bak +0 -103
- package/plugins/specweave/lib/hooks/update-tasks-md.d.js.bak +0 -1
- package/plugins/specweave/lib/hooks/update-tasks-md.d.ts.bak +0 -29
- package/plugins/specweave/lib/hooks/update-tasks-md.js.bak +0 -296
- package/plugins/specweave/lib/hooks/update-tasks-md.ts.bak +0 -489
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +0 -353
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +0 -172
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -170
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +0 -904
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +0 -258
- package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +0 -172
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +0 -738
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +0 -110
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External Tool Drift Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects when external tools (GitHub/JIRA/ADO) haven't been synced recently,
|
|
5
|
+
* indicating potential drift between living docs and external systems.
|
|
6
|
+
*
|
|
7
|
+
* Used by:
|
|
8
|
+
* - /specweave:done (validation warning if drift > 24h)
|
|
9
|
+
* - Status line (show "sync pending" indicator)
|
|
10
|
+
* - /specweave:progress (show last sync time)
|
|
11
|
+
*
|
|
12
|
+
* See: ADR-0131 (External Tool Sync Context Detection)
|
|
13
|
+
*/
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import { promises as fs } from 'fs';
|
|
16
|
+
import { consoleLogger } from './logger.js';
|
|
17
|
+
// Drift thresholds (extracted constants for P0-5 fix)
|
|
18
|
+
const DRIFT_THRESHOLD_HOURS = 24; // Warning threshold
|
|
19
|
+
const WARNING_THRESHOLD_HOURS = 48; // Elevated warning
|
|
20
|
+
const CRITICAL_THRESHOLD_HOURS = 168; // 7 days - critical staleness
|
|
21
|
+
export class ExternalToolDriftDetector {
|
|
22
|
+
constructor(projectRoot, options = {}) {
|
|
23
|
+
this.projectRoot = projectRoot;
|
|
24
|
+
this.logger = options.logger ?? consoleLogger;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Validate increment ID format to prevent path traversal attacks
|
|
28
|
+
* P0-1: Path traversal vulnerability fix
|
|
29
|
+
*
|
|
30
|
+
* @param incrementId - Increment ID to validate
|
|
31
|
+
* @throws Error if increment ID format is invalid
|
|
32
|
+
*/
|
|
33
|
+
validateIncrementId(incrementId) {
|
|
34
|
+
// Expected format: 4 digits + hyphen + kebab-case (e.g., "0053-safe-feature-deletion")
|
|
35
|
+
if (!/^\d{4}-[a-z0-9-]+$/.test(incrementId)) {
|
|
36
|
+
throw new Error(`Invalid increment ID format: ${incrementId}. Expected format: XXXX-kebab-case`);
|
|
37
|
+
}
|
|
38
|
+
// Additional safety: reject path traversal attempts
|
|
39
|
+
if (incrementId.includes('..') || incrementId.includes('/') || incrementId.includes('\\')) {
|
|
40
|
+
throw new Error(`Path traversal attempt detected in increment ID: ${incrementId}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Safely parse and validate metadata.json
|
|
45
|
+
* P0-2: JSON injection protection
|
|
46
|
+
*
|
|
47
|
+
* @param metadataPath - Path to metadata.json
|
|
48
|
+
* @returns Parsed metadata object
|
|
49
|
+
* @throws Error if JSON is invalid or malformed
|
|
50
|
+
*/
|
|
51
|
+
async readAndValidateMetadata(metadataPath) {
|
|
52
|
+
const content = await fs.readFile(metadataPath, 'utf-8');
|
|
53
|
+
let metadata;
|
|
54
|
+
try {
|
|
55
|
+
metadata = JSON.parse(content);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
throw new Error(`Invalid JSON in metadata file: ${error instanceof Error ? error.message : 'Parse error'}`);
|
|
59
|
+
}
|
|
60
|
+
// Validate JSON structure
|
|
61
|
+
if (typeof metadata !== 'object' || metadata === null) {
|
|
62
|
+
throw new Error('Metadata must be a valid JSON object');
|
|
63
|
+
}
|
|
64
|
+
return metadata;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get most recent sync time across ALL external tools
|
|
68
|
+
* P1-1: Check all tools instead of just first configured tool
|
|
69
|
+
*
|
|
70
|
+
* @param metadata - Parsed metadata.json
|
|
71
|
+
* @returns Most recent sync date or null if no syncs found
|
|
72
|
+
*/
|
|
73
|
+
getMostRecentSync(metadata) {
|
|
74
|
+
const syncTimes = [];
|
|
75
|
+
// Collect all sync times from configured external tools
|
|
76
|
+
if (metadata.github?.lastSync) {
|
|
77
|
+
const date = this.parseSafeDate(metadata.github.lastSync);
|
|
78
|
+
if (date)
|
|
79
|
+
syncTimes.push(date);
|
|
80
|
+
}
|
|
81
|
+
if (metadata.jira?.lastSync) {
|
|
82
|
+
const date = this.parseSafeDate(metadata.jira.lastSync);
|
|
83
|
+
if (date)
|
|
84
|
+
syncTimes.push(date);
|
|
85
|
+
}
|
|
86
|
+
if (metadata.ado?.lastSync) {
|
|
87
|
+
const date = this.parseSafeDate(metadata.ado.lastSync);
|
|
88
|
+
if (date)
|
|
89
|
+
syncTimes.push(date);
|
|
90
|
+
}
|
|
91
|
+
if (syncTimes.length === 0) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
// Return most recent sync time (sort descending, take first)
|
|
95
|
+
return syncTimes.sort((a, b) => b.getTime() - a.getTime())[0];
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Safely parse date string with validation
|
|
99
|
+
*
|
|
100
|
+
* @param dateString - ISO date string
|
|
101
|
+
* @returns Date object or null if invalid
|
|
102
|
+
*/
|
|
103
|
+
parseSafeDate(dateString) {
|
|
104
|
+
if (typeof dateString !== 'string')
|
|
105
|
+
return null;
|
|
106
|
+
const date = new Date(dateString);
|
|
107
|
+
// Check if date is valid
|
|
108
|
+
if (isNaN(date.getTime())) {
|
|
109
|
+
this.logger.warn(`Invalid date format: ${dateString}`);
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
return date;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Detect drift for a specific increment
|
|
116
|
+
*
|
|
117
|
+
* @param incrementId - Increment ID (e.g., "0053-safe-feature-deletion")
|
|
118
|
+
* @returns Drift status with recommendations
|
|
119
|
+
*/
|
|
120
|
+
async detectDrift(incrementId) {
|
|
121
|
+
try {
|
|
122
|
+
// P0-1: Validate increment ID to prevent path traversal
|
|
123
|
+
this.validateIncrementId(incrementId);
|
|
124
|
+
// P0-4: Use async fs operations (replaced existsSync/readFileSync)
|
|
125
|
+
const metadataPath = path.join(this.projectRoot, '.specweave/increments', incrementId, 'metadata.json');
|
|
126
|
+
// Check if metadata exists (async)
|
|
127
|
+
try {
|
|
128
|
+
await fs.access(metadataPath);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return {
|
|
132
|
+
hasDrift: false,
|
|
133
|
+
lastSyncTime: null,
|
|
134
|
+
hoursSinceSync: null,
|
|
135
|
+
externalToolsConfigured: false,
|
|
136
|
+
recommendation: 'No metadata found'
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// P0-2: Safe JSON parsing with validation
|
|
140
|
+
const metadata = await this.readAndValidateMetadata(metadataPath);
|
|
141
|
+
// Check if external tools are configured
|
|
142
|
+
const hasGitHub = metadata.github && metadata.github.issues && metadata.github.issues.length > 0;
|
|
143
|
+
const hasJira = metadata.jira && metadata.jira.issues && metadata.jira.issues.length > 0;
|
|
144
|
+
const hasADO = metadata.ado && metadata.ado.workItems && metadata.ado.workItems.length > 0;
|
|
145
|
+
const externalToolsConfigured = hasGitHub || hasJira || hasADO;
|
|
146
|
+
if (!externalToolsConfigured) {
|
|
147
|
+
return {
|
|
148
|
+
hasDrift: false,
|
|
149
|
+
lastSyncTime: null,
|
|
150
|
+
hoursSinceSync: null,
|
|
151
|
+
externalToolsConfigured: false,
|
|
152
|
+
recommendation: 'No external tools configured'
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
// P1-1: Get most recent sync time across ALL external tools (not just first one)
|
|
156
|
+
const lastSyncTime = this.getMostRecentSync(metadata);
|
|
157
|
+
if (!lastSyncTime) {
|
|
158
|
+
return {
|
|
159
|
+
hasDrift: true,
|
|
160
|
+
lastSyncTime: null,
|
|
161
|
+
hoursSinceSync: null,
|
|
162
|
+
externalToolsConfigured: true,
|
|
163
|
+
recommendation: 'External tools never synced - run /specweave:sync-progress'
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// Calculate hours since last sync
|
|
167
|
+
const now = new Date();
|
|
168
|
+
const hoursSinceSync = (now.getTime() - lastSyncTime.getTime()) / (1000 * 60 * 60);
|
|
169
|
+
// Use extracted constants (P0-5 fix)
|
|
170
|
+
const hasDrift = hoursSinceSync > DRIFT_THRESHOLD_HOURS;
|
|
171
|
+
let recommendation = '';
|
|
172
|
+
if (hasDrift) {
|
|
173
|
+
if (hoursSinceSync < WARNING_THRESHOLD_HOURS) {
|
|
174
|
+
recommendation = 'External tools synced 1-2 days ago - consider running /specweave:sync-progress';
|
|
175
|
+
}
|
|
176
|
+
else if (hoursSinceSync < CRITICAL_THRESHOLD_HOURS) {
|
|
177
|
+
recommendation = `External tools synced ${Math.floor(hoursSinceSync / 24)} days ago - run /specweave:sync-progress soon`;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
recommendation = `External tools synced ${Math.floor(hoursSinceSync / 168)} weeks ago - URGENT: run /specweave:sync-progress`;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
recommendation = `External tools synced ${Math.floor(hoursSinceSync)} hours ago - up to date`;
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
hasDrift,
|
|
188
|
+
lastSyncTime,
|
|
189
|
+
hoursSinceSync,
|
|
190
|
+
externalToolsConfigured,
|
|
191
|
+
recommendation
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
// P0-5: Don't mask errors - expose them in return value
|
|
196
|
+
this.logger.error(`Error detecting drift for ${incrementId}:`, error);
|
|
197
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
198
|
+
return {
|
|
199
|
+
hasDrift: false,
|
|
200
|
+
lastSyncTime: null,
|
|
201
|
+
hoursSinceSync: null,
|
|
202
|
+
externalToolsConfigured: false,
|
|
203
|
+
recommendation: `Error detecting drift: ${errorMessage}`,
|
|
204
|
+
error: errorMessage // Expose error for caller to handle
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Get human-readable drift message for display
|
|
210
|
+
*
|
|
211
|
+
* @param drift - Drift status from detectDrift()
|
|
212
|
+
* @returns Formatted message with emoji indicator
|
|
213
|
+
*/
|
|
214
|
+
getDriftMessage(drift) {
|
|
215
|
+
if (!drift.externalToolsConfigured) {
|
|
216
|
+
return '';
|
|
217
|
+
}
|
|
218
|
+
if (!drift.lastSyncTime) {
|
|
219
|
+
return '⚠️ External tools never synced';
|
|
220
|
+
}
|
|
221
|
+
if (drift.hasDrift) {
|
|
222
|
+
if (drift.hoursSinceSync && drift.hoursSinceSync < 48) {
|
|
223
|
+
return `⚠️ External sync: ${Math.floor(drift.hoursSinceSync)}h ago`;
|
|
224
|
+
}
|
|
225
|
+
else if (drift.hoursSinceSync && drift.hoursSinceSync < 168) {
|
|
226
|
+
return `🔴 External sync: ${Math.floor(drift.hoursSinceSync / 24)}d ago`;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
return `🔴 External sync: ${Math.floor((drift.hoursSinceSync || 0) / 168)}w ago (STALE)`;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return `✅ External sync: ${Math.floor(drift.hoursSinceSync || 0)}h ago`;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=external-tool-drift-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-tool-drift-detector.js","sourceRoot":"","sources":["../../../src/utils/external-tool-drift-detector.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specweave",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.4",
|
|
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",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"LICENSE"
|
|
78
78
|
],
|
|
79
79
|
"dependencies": {
|
|
80
|
-
"@anthropic-ai/sdk": "^0.
|
|
80
|
+
"@anthropic-ai/sdk": "^0.70.1",
|
|
81
81
|
"@octokit/rest": "^22.0.1",
|
|
82
82
|
"@types/handlebars": "^4.0.40",
|
|
83
83
|
"axios": "^1.13.2",
|
|
@@ -86,9 +86,9 @@
|
|
|
86
86
|
"glob": "^11.0.3",
|
|
87
87
|
"gray-matter": "^4.0.3",
|
|
88
88
|
"handlebars": "^4.7.8",
|
|
89
|
-
"inquirer": "^
|
|
89
|
+
"inquirer": "^13.0.1",
|
|
90
90
|
"js-yaml": "^4.1.0",
|
|
91
|
-
"open": "^
|
|
91
|
+
"open": "^11.0.0",
|
|
92
92
|
"ora": "^9.0.0",
|
|
93
93
|
"yaml": "^2.3.4"
|
|
94
94
|
},
|
|
@@ -455,12 +455,12 @@ fi
|
|
|
455
455
|
# This prevents 27 duplicate comments (see root cause analysis)
|
|
456
456
|
export SKIP_GITHUB_SYNC=true
|
|
457
457
|
|
|
458
|
-
#
|
|
459
|
-
#
|
|
460
|
-
#
|
|
461
|
-
#
|
|
462
|
-
#
|
|
463
|
-
|
|
458
|
+
# v0.26.1: SKIP_US_SYNC removed - no longer needed!
|
|
459
|
+
# Automatic US sync restored with multi-layer protection:
|
|
460
|
+
# 1. SKIP_EXTERNAL_SYNC guard at LivingDocsSync layer (prevents recursion)
|
|
461
|
+
# 2. Smart throttle (60s window prevents spam)
|
|
462
|
+
# 3. fs.writeFile() confirmed to NOT trigger hooks (test validated)
|
|
463
|
+
# See: FS-WRITEFILE-HOOK-TEST-RESULTS-2025-11-24.md, ADR-0129
|
|
464
464
|
|
|
465
465
|
# Run consolidated sync (single Node.js process handles ALL operations)
|
|
466
466
|
if (cd "$PROJECT_ROOT" && node "$CONSOLIDATED_SCRIPT" "$CURRENT_INCREMENT") >> "$DEBUG_LOG" 2>&1; then
|
|
@@ -19,7 +19,12 @@
|
|
|
19
19
|
# **See**: ADR-0062 (AC Embedding Architecture)
|
|
20
20
|
#
|
|
21
21
|
|
|
22
|
-
set -
|
|
22
|
+
# CRITICAL (v0.25.2): NEVER use 'set -e' in hooks - causes Claude Code crashes
|
|
23
|
+
# See: CLAUDE.md Section 9a (Hook Safety Checklist), ADR-0060 (Hook Performance)
|
|
24
|
+
# NOTE: This validation hook explicitly exits with code 1 on failures (controlled behavior)
|
|
25
|
+
set +e # Allow commands to fail without terminating script
|
|
26
|
+
set -u # Fail on undefined variables
|
|
27
|
+
set -o pipefail # Fail if any command in pipeline fails
|
|
23
28
|
|
|
24
29
|
# Get increment path from environment or argument
|
|
25
30
|
INCREMENT_PATH="${1:-}"
|
|
@@ -1,96 +1,67 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* 2. Update living docs for completed USs
|
|
8
|
-
* 3. Trigger external tool sync (GitHub/JIRA/ADO)
|
|
9
|
-
*
|
|
10
|
-
* CRITICAL: This is the bridge between AC-level completion and US-level sync.
|
|
11
|
-
* Called by consolidated-sync.js after AC sync completes.
|
|
12
|
-
*
|
|
13
|
-
* Architecture:
|
|
14
|
-
* - Uses USCompletionDetector to find newly completed USs
|
|
15
|
-
* - Uses LivingDocsSync to update living docs (which triggers external tools)
|
|
16
|
-
* - Non-blocking: Errors logged but don't break workflow
|
|
17
|
-
*
|
|
18
|
-
* Integration:
|
|
19
|
-
* - Called from consolidated-sync.js (OPERATION 6)
|
|
20
|
-
* - Runs after AC sync (ensures ACs are up-to-date)
|
|
21
|
-
* - Skipped if SKIP_US_SYNC=true (performance optimization)
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
// Import REAL implementations
|
|
25
|
-
import { USCompletionDetector } from '../../../../dist/src/core/us-completion-detector.js';
|
|
26
|
-
import { LivingDocsSync } from '../../../../dist/src/core/living-docs/living-docs-sync.js';
|
|
27
|
-
import { consoleLogger } from '../vendor/utils/logger.js';
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Detect and sync newly completed user stories
|
|
31
|
-
*
|
|
32
|
-
* @param incrementId - Increment ID (e.g., "0053-safe-feature-deletion")
|
|
33
|
-
* @returns Result object with success status and sync details
|
|
34
|
-
*/
|
|
35
|
-
export async function syncCompletedUserStories(incrementId) {
|
|
2
|
+
import { USCompletionDetector } from "../../../../dist/src/core/us-completion-detector.js";
|
|
3
|
+
import { LivingDocsSync } from "../../../../dist/src/core/living-docs/living-docs-sync.js";
|
|
4
|
+
import { USSyncThrottle } from "../../../../dist/src/core/us-sync-throttle.js";
|
|
5
|
+
import { consoleLogger } from "../vendor/utils/logger.js";
|
|
6
|
+
async function syncCompletedUserStories(incrementId) {
|
|
36
7
|
try {
|
|
37
|
-
console.log(
|
|
38
|
-
|
|
8
|
+
console.log(`
|
|
9
|
+
\u{1F3AF} [6/6] Detecting completed user stories for ${incrementId}...`);
|
|
39
10
|
const projectRoot = process.cwd();
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
11
|
+
const throttle = USSyncThrottle.getInstance({ projectRoot });
|
|
12
|
+
if (throttle.shouldSkipSync(incrementId)) {
|
|
13
|
+
const timeSinceLastSync = throttle.getTimeSinceLastSync(incrementId);
|
|
14
|
+
const secondsRemaining = Math.ceil((6e4 - timeSinceLastSync) / 1e3);
|
|
15
|
+
console.log(`\u23ED\uFE0F US sync throttled (last sync ${Math.floor(timeSinceLastSync / 1e3)}s ago)`);
|
|
16
|
+
console.log(` \u2139\uFE0F Sync will be available in ${secondsRemaining}s`);
|
|
17
|
+
console.log(` \u{1F4A1} Manual sync: /specweave:sync-progress ${incrementId}`);
|
|
18
|
+
return {
|
|
19
|
+
success: true,
|
|
20
|
+
message: "Sync throttled",
|
|
21
|
+
throttled: true,
|
|
22
|
+
skipped: true
|
|
23
|
+
};
|
|
45
24
|
}
|
|
46
|
-
|
|
47
|
-
// 1. Initialize US completion detector
|
|
48
25
|
const detector = new USCompletionDetector(projectRoot, {
|
|
49
26
|
logger: consoleLogger
|
|
50
27
|
});
|
|
51
|
-
|
|
52
|
-
// 2. Detect newly completed user stories
|
|
53
28
|
const newlyCompleted = await detector.getNewlyCompletedUSs(incrementId);
|
|
54
|
-
|
|
55
29
|
if (newlyCompleted.length === 0) {
|
|
56
|
-
console.log(
|
|
57
|
-
return {
|
|
30
|
+
console.log("\u2705 No newly completed user stories detected (no sync needed)");
|
|
31
|
+
return {
|
|
32
|
+
success: true,
|
|
33
|
+
newlyCompleted: [],
|
|
34
|
+
message: "No new completions"
|
|
35
|
+
};
|
|
58
36
|
}
|
|
59
|
-
|
|
60
|
-
|
|
37
|
+
console.log(`
|
|
38
|
+
\u{1F389} DETECTED ${newlyCompleted.length} NEWLY COMPLETED USER STORIES:`);
|
|
61
39
|
for (const us of newlyCompleted) {
|
|
62
40
|
console.log(` ${us.usId}: ${us.title} (${us.completedACs}/${us.totalACs} ACs complete)`);
|
|
63
41
|
}
|
|
64
|
-
|
|
65
|
-
// 3. Save completion state (mark USs as complete to prevent re-sync)
|
|
66
42
|
const allCompletions = await detector.detectCompletions(incrementId);
|
|
67
43
|
await detector.saveCompletionState(incrementId, allCompletions);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
console.log(`\n📚 Syncing living docs for ${incrementId}...`);
|
|
71
|
-
|
|
44
|
+
console.log(`
|
|
45
|
+
\u{1F4DA} Syncing living docs for ${incrementId}...`);
|
|
72
46
|
const livingDocsSync = new LivingDocsSync(projectRoot, {
|
|
73
47
|
logger: consoleLogger
|
|
74
48
|
});
|
|
75
|
-
|
|
76
49
|
const syncResult = await livingDocsSync.syncIncrement(incrementId);
|
|
77
|
-
|
|
78
50
|
if (syncResult.success) {
|
|
79
|
-
console.log(
|
|
51
|
+
console.log(`\u2705 Living docs synced successfully`);
|
|
80
52
|
console.log(` Feature: ${syncResult.featureId}`);
|
|
81
53
|
console.log(` Files updated: ${syncResult.filesCreated.length + syncResult.filesUpdated.length}`);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
console.log(
|
|
54
|
+
console.log(`
|
|
55
|
+
\u{1F4E1} External tool sync completed (GitHub/JIRA/ADO updated if configured)`);
|
|
56
|
+
throttle.recordSync(incrementId);
|
|
57
|
+
console.log(` \u23F1\uFE0F Throttle recorded (next sync allowed in 60s)`);
|
|
86
58
|
} else {
|
|
87
|
-
console.warn(
|
|
88
|
-
console.warn(` Errors: ${syncResult.errors.join(
|
|
59
|
+
console.warn(`\u26A0\uFE0F Living docs sync had errors (see logs)`);
|
|
60
|
+
console.warn(` Errors: ${syncResult.errors.join(", ")}`);
|
|
89
61
|
}
|
|
90
|
-
|
|
91
62
|
return {
|
|
92
63
|
success: true,
|
|
93
|
-
newlyCompleted: newlyCompleted.map(us => ({
|
|
64
|
+
newlyCompleted: newlyCompleted.map((us) => ({
|
|
94
65
|
usId: us.usId,
|
|
95
66
|
title: us.title,
|
|
96
67
|
totalACs: us.totalACs,
|
|
@@ -99,37 +70,39 @@ export async function syncCompletedUserStories(incrementId) {
|
|
|
99
70
|
syncResult,
|
|
100
71
|
message: `${newlyCompleted.length} user stories synced`
|
|
101
72
|
};
|
|
102
|
-
|
|
103
73
|
} catch (error) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
74
|
+
console.error("\u274C Error in US completion orchestrator:", error.message);
|
|
75
|
+
return {
|
|
76
|
+
success: false,
|
|
77
|
+
error: error.message,
|
|
78
|
+
message: "Orchestrator error"
|
|
79
|
+
};
|
|
107
80
|
}
|
|
108
81
|
}
|
|
109
|
-
|
|
110
|
-
// CLI Interface (for manual testing)
|
|
111
82
|
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
112
83
|
if (isMainModule) {
|
|
113
84
|
const incrementId = process.argv[2];
|
|
114
|
-
|
|
115
85
|
if (!incrementId) {
|
|
116
|
-
console.error(
|
|
117
|
-
console.error(
|
|
86
|
+
console.error("Usage: node us-completion-orchestrator.js <increment-id>");
|
|
87
|
+
console.error("Example: node us-completion-orchestrator.js 0053-safe-feature-deletion");
|
|
118
88
|
process.exit(1);
|
|
119
89
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (result.
|
|
124
|
-
console.log(
|
|
125
|
-
process.exit(0);
|
|
126
|
-
} else {
|
|
127
|
-
console.error('\n❌ US completion orchestration failed');
|
|
128
|
-
process.exit(1);
|
|
90
|
+
syncCompletedUserStories(incrementId).then((result) => {
|
|
91
|
+
if (result.success) {
|
|
92
|
+
console.log("\n\u2705 US completion orchestration completed successfully");
|
|
93
|
+
if (result.throttled) {
|
|
94
|
+
console.log(" (Throttled - no sync performed)");
|
|
129
95
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
console.error(
|
|
96
|
+
process.exit(0);
|
|
97
|
+
} else {
|
|
98
|
+
console.error("\n\u274C US completion orchestration failed");
|
|
133
99
|
process.exit(1);
|
|
134
|
-
}
|
|
100
|
+
}
|
|
101
|
+
}).catch((error) => {
|
|
102
|
+
console.error("\n\u274C Fatal error:", error);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
});
|
|
135
105
|
}
|
|
106
|
+
export {
|
|
107
|
+
syncCompletedUserStories
|
|
108
|
+
};
|