specweave 0.22.14 → 0.23.0
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 +178 -1
- package/dist/src/cli/commands/import-external.d.ts +22 -0
- package/dist/src/cli/commands/import-external.d.ts.map +1 -0
- package/dist/src/cli/commands/import-external.js +282 -0
- package/dist/src/cli/commands/import-external.js.map +1 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +46 -0
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/github-repo-selector.d.ts +59 -0
- package/dist/src/cli/helpers/github-repo-selector.d.ts.map +1 -0
- package/dist/src/cli/helpers/github-repo-selector.js +265 -0
- package/dist/src/cli/helpers/github-repo-selector.js.map +1 -0
- package/dist/src/config/types.d.ts +16 -16
- package/dist/src/core/increment/ac-status-manager.d.ts.map +1 -1
- package/dist/src/core/increment/ac-status-manager.js +4 -2
- package/dist/src/core/increment/ac-status-manager.js.map +1 -1
- package/dist/src/core/increment/completion-validator.d.ts +30 -1
- package/dist/src/core/increment/completion-validator.d.ts.map +1 -1
- package/dist/src/core/increment/completion-validator.js +151 -3
- package/dist/src/core/increment/completion-validator.js.map +1 -1
- package/dist/src/core/increment/increment-archiver.d.ts +25 -0
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +130 -3
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.d.ts +37 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.js +262 -18
- package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.d.ts +17 -0
- package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.js +25 -0
- package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +14 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +46 -0
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/sync/sync-event-logger.d.ts +15 -1
- package/dist/src/core/sync/sync-event-logger.d.ts.map +1 -1
- package/dist/src/core/sync/sync-event-logger.js +39 -1
- package/dist/src/core/sync/sync-event-logger.js.map +1 -1
- package/dist/src/core/types/sync-config-validator.d.ts +57 -0
- package/dist/src/core/types/sync-config-validator.d.ts.map +1 -0
- package/dist/src/core/types/sync-config-validator.js +116 -0
- package/dist/src/core/types/sync-config-validator.js.map +1 -0
- package/dist/src/importers/duplicate-detector.d.ts +107 -0
- package/dist/src/importers/duplicate-detector.d.ts.map +1 -0
- package/dist/src/importers/duplicate-detector.js +189 -0
- package/dist/src/importers/duplicate-detector.js.map +1 -0
- package/dist/src/importers/import-coordinator.d.ts +15 -0
- package/dist/src/importers/import-coordinator.d.ts.map +1 -1
- package/dist/src/importers/import-coordinator.js +43 -1
- package/dist/src/importers/import-coordinator.js.map +1 -1
- package/dist/src/importers/item-converter.d.ts +5 -0
- package/dist/src/importers/item-converter.d.ts.map +1 -1
- package/dist/src/importers/item-converter.js +27 -2
- package/dist/src/importers/item-converter.js.map +1 -1
- package/dist/src/importers/rate-limiter.d.ts +128 -0
- package/dist/src/importers/rate-limiter.d.ts.map +1 -0
- package/dist/src/importers/rate-limiter.js +200 -0
- package/dist/src/importers/rate-limiter.js.map +1 -0
- package/dist/src/init/compliance/types.d.ts +2 -2
- package/dist/src/integrations/ado/ado-client.d.ts +6 -0
- package/dist/src/integrations/ado/ado-client.d.ts.map +1 -1
- package/dist/src/integrations/ado/ado-client.js +23 -0
- package/dist/src/integrations/ado/ado-client.js.map +1 -1
- package/dist/src/integrations/jira/jira-client.d.ts +6 -0
- package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-client.js +38 -0
- package/dist/src/integrations/jira/jira-client.js.map +1 -1
- package/dist/src/sync/external-item-sync-service.d.ts +150 -0
- package/dist/src/sync/external-item-sync-service.d.ts.map +1 -0
- package/dist/src/sync/external-item-sync-service.js +241 -0
- package/dist/src/sync/external-item-sync-service.js.map +1 -0
- package/dist/src/sync/format-preservation-sync.d.ts +90 -0
- package/dist/src/sync/format-preservation-sync.d.ts.map +1 -0
- package/dist/src/sync/format-preservation-sync.js +173 -0
- package/dist/src/sync/format-preservation-sync.js.map +1 -0
- package/dist/src/sync/index.d.ts +8 -0
- package/dist/src/sync/index.d.ts.map +1 -0
- package/dist/src/sync/index.js +6 -0
- package/dist/src/sync/index.js.map +1 -0
- package/dist/src/sync/sync-coordinator.d.ts +49 -0
- package/dist/src/sync/sync-coordinator.d.ts.map +1 -0
- package/dist/src/sync/sync-coordinator.js +248 -0
- package/dist/src/sync/sync-coordinator.js.map +1 -0
- package/dist/src/sync/sync-metadata.d.ts +75 -0
- package/dist/src/sync/sync-metadata.d.ts.map +1 -0
- package/dist/src/sync/sync-metadata.js +100 -0
- package/dist/src/sync/sync-metadata.js.map +1 -0
- package/dist/src/types/living-docs-us-file.d.ts +63 -0
- package/dist/src/types/living-docs-us-file.d.ts.map +1 -0
- package/dist/src/types/living-docs-us-file.js +27 -0
- package/dist/src/types/living-docs-us-file.js.map +1 -0
- package/dist/src/validators/format-preservation-validator.d.ts +127 -0
- package/dist/src/validators/format-preservation-validator.d.ts.map +1 -0
- package/dist/src/validators/format-preservation-validator.js +187 -0
- package/dist/src/validators/format-preservation-validator.js.map +1 -0
- package/package.json +3 -2
- package/plugins/specweave/.claude-plugin/plugin.json +20 -0
- package/plugins/specweave/commands/specweave-archive-features.md +11 -1
- package/plugins/specweave/commands/specweave-import-docs.md +88 -278
- package/plugins/specweave/commands/specweave-import-external.md +407 -0
- package/plugins/specweave/hooks/post-edit-spec.sh +41 -0
- package/plugins/specweave/hooks/post-increment-completion.sh +0 -0
- package/plugins/specweave/hooks/post-spec-update.sh +0 -0
- package/plugins/specweave/hooks/post-task-completion.sh +13 -3
- package/plugins/specweave/hooks/post-write-spec.sh +37 -0
- package/plugins/specweave/lib/hooks/auto-transition.js +1 -1
- package/plugins/specweave/lib/hooks/auto-transition.ts +1 -1
- package/plugins/specweave/lib/hooks/invoke-translator-skill.js +1 -1
- package/plugins/specweave/lib/hooks/invoke-translator-skill.ts +1 -1
- package/plugins/specweave/lib/hooks/sync-living-docs.js +35 -1
- package/plugins/specweave/lib/hooks/sync-us-tasks.js +179 -3
- package/plugins/specweave/lib/hooks/translate-file.js +1 -1
- package/plugins/specweave/lib/hooks/translate-file.ts +1 -1
- package/plugins/specweave/lib/hooks/update-ac-status.js +1 -1
- package/plugins/specweave/lib/hooks/update-ac-status.ts +1 -1
- package/plugins/specweave/lib/vendor/core/increment/ac-status-manager.d.ts +115 -0
- package/plugins/specweave/lib/vendor/core/increment/ac-status-manager.js +345 -0
- package/plugins/specweave/lib/vendor/core/increment/ac-status-manager.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/increment/active-increment-manager.d.ts +106 -0
- package/plugins/specweave/lib/vendor/core/increment/active-increment-manager.js +220 -0
- package/plugins/specweave/lib/vendor/core/increment/active-increment-manager.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.d.ts +60 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js +192 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.d.ts +52 -0
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js +276 -0
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.d.ts +163 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +541 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +157 -0
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.js +191 -0
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.js.map +1 -0
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.d.ts +95 -0
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.js +301 -0
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.js.map +1 -0
- package/plugins/specweave/lib/vendor/utils/logger.d.ts +48 -0
- package/plugins/specweave/lib/vendor/utils/logger.js +53 -0
- package/plugins/specweave/lib/vendor/utils/logger.js.map +1 -0
- package/plugins/specweave/lib/vendor/utils/translation.d.ts +187 -0
- package/plugins/specweave/lib/vendor/utils/translation.js +414 -0
- package/plugins/specweave/lib/vendor/utils/translation.js.map +1 -0
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +0 -1
- package/plugins/specweave-github/commands/specweave-github-update-user-story.md +1 -1
- package/plugins/specweave-github/skills/github-issue-standard/SKILL.md +1 -1
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -170
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +0 -5694
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync Coordinator (T-034E)
|
|
3
|
+
*
|
|
4
|
+
* High-level coordinator that integrates FormatPreservationSyncService
|
|
5
|
+
* with living docs sync workflow. Called by post-task-completion hook.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import yaml from 'yaml';
|
|
10
|
+
import { getOrigin } from '../types/living-docs-us-file.js';
|
|
11
|
+
import { FormatPreservationSyncService } from './format-preservation-sync.js';
|
|
12
|
+
import { GitHubClientV2 } from '../../plugins/specweave-github/lib/github-client-v2.js';
|
|
13
|
+
import { consoleLogger } from '../utils/logger.js';
|
|
14
|
+
export class SyncCoordinator {
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.projectRoot = options.projectRoot;
|
|
17
|
+
this.incrementId = options.incrementId;
|
|
18
|
+
this.logger = options.logger ?? consoleLogger;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Sync increment completion to external tools using format preservation
|
|
22
|
+
*/
|
|
23
|
+
async syncIncrementCompletion() {
|
|
24
|
+
const result = {
|
|
25
|
+
success: false,
|
|
26
|
+
userStoriesSynced: 0,
|
|
27
|
+
syncMode: 'read-only',
|
|
28
|
+
errors: []
|
|
29
|
+
};
|
|
30
|
+
try {
|
|
31
|
+
this.logger.log(`\n🔄 Syncing increment ${this.incrementId} with format preservation...`);
|
|
32
|
+
// 1. Load config
|
|
33
|
+
const config = await this.loadConfig();
|
|
34
|
+
// 2. Check if sync is enabled
|
|
35
|
+
if (!config.sync?.settings?.canUpdateExternalItems) {
|
|
36
|
+
this.logger.log('ℹ️ External sync disabled (canUpdateExternalItems=false)');
|
|
37
|
+
result.syncMode = 'read-only';
|
|
38
|
+
result.success = true;
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
// 3. Load living docs User Stories for this increment
|
|
42
|
+
const userStories = await this.loadUserStoriesForIncrement();
|
|
43
|
+
if (userStories.length === 0) {
|
|
44
|
+
this.logger.log('ℹ️ No user stories found for this increment');
|
|
45
|
+
result.success = true;
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
this.logger.log(`📚 Found ${userStories.length} user story/stories`);
|
|
49
|
+
// 4. Initialize sync service
|
|
50
|
+
const syncService = new FormatPreservationSyncService({
|
|
51
|
+
canUpdateExternalItems: config.sync?.settings?.canUpdateExternalItems ?? false,
|
|
52
|
+
canUpdateStatus: config.sync?.settings?.canUpdateStatus ?? false
|
|
53
|
+
}, { logger: this.logger });
|
|
54
|
+
// 5. Sync each user story
|
|
55
|
+
for (const usFile of userStories) {
|
|
56
|
+
try {
|
|
57
|
+
await this.syncUserStory(usFile, syncService, config);
|
|
58
|
+
result.userStoriesSynced++;
|
|
59
|
+
const origin = getOrigin(usFile);
|
|
60
|
+
if (origin === 'external') {
|
|
61
|
+
result.syncMode = 'comment-only';
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
result.syncMode = 'full-sync';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
const errorMsg = `Failed to sync ${usFile.id}: ${error}`;
|
|
69
|
+
this.logger.error(errorMsg);
|
|
70
|
+
result.errors.push(errorMsg);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
result.success = result.errors.length === 0;
|
|
74
|
+
this.logger.log(`\n✅ Sync complete: ${result.userStoriesSynced}/${userStories.length} synced`);
|
|
75
|
+
if (result.errors.length > 0) {
|
|
76
|
+
this.logger.log(`⚠️ ${result.errors.length} error(s) occurred`);
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
result.errors.push(`Sync coordinator error: ${error}`);
|
|
82
|
+
this.logger.error('❌ Sync failed:', error);
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Sync individual user story
|
|
88
|
+
*/
|
|
89
|
+
async syncUserStory(usFile, syncService, config) {
|
|
90
|
+
const origin = getOrigin(usFile);
|
|
91
|
+
this.logger.log(`\n 📝 ${usFile.id} (${origin})`);
|
|
92
|
+
// Load completion data
|
|
93
|
+
const completionData = await this.loadCompletionData(usFile);
|
|
94
|
+
// Determine external tool and create client
|
|
95
|
+
const externalSource = usFile.external_source || 'github'; // Default to GitHub
|
|
96
|
+
if (externalSource === 'github') {
|
|
97
|
+
// Extract owner/repo from config or detect from git
|
|
98
|
+
const githubConfig = config.sync?.github || {};
|
|
99
|
+
const repoInfo = await this.detectGitHubRepo(githubConfig);
|
|
100
|
+
if (!repoInfo) {
|
|
101
|
+
throw new Error('GitHub repository not configured');
|
|
102
|
+
}
|
|
103
|
+
const client = GitHubClientV2.fromRepo(repoInfo.owner, repoInfo.repo);
|
|
104
|
+
await syncService.syncUserStory(usFile, completionData, client);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
this.logger.log(` ⚠️ ${externalSource} sync not yet implemented`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Load completion data for user story
|
|
112
|
+
*/
|
|
113
|
+
async loadCompletionData(usFile) {
|
|
114
|
+
// Parse tasks from increment tasks.md
|
|
115
|
+
const tasksFile = path.join(this.projectRoot, '.specweave/increments', this.incrementId, 'tasks.md');
|
|
116
|
+
const tasks = [];
|
|
117
|
+
const acs = [];
|
|
118
|
+
if (await fs.pathExists(tasksFile)) {
|
|
119
|
+
const content = await fs.readFile(tasksFile, 'utf-8');
|
|
120
|
+
// Parse tasks (simplified - just count completed for now)
|
|
121
|
+
const taskMatches = content.match(/### T-\d+:/g) || [];
|
|
122
|
+
const completedMatches = content.match(/\*\*Status\*\*: \[x\] completed/g) || [];
|
|
123
|
+
// Add mock data for demo (real implementation would parse tasks.md properly)
|
|
124
|
+
for (let i = 0; i < taskMatches.length; i++) {
|
|
125
|
+
tasks.push({
|
|
126
|
+
taskId: `T-${String(i + 1).padStart(3, '0')}`,
|
|
127
|
+
title: 'Task title',
|
|
128
|
+
completed: i < completedMatches.length
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Parse ACs from spec.md
|
|
133
|
+
const specFile = path.join(this.projectRoot, '.specweave/increments', this.incrementId, 'spec.md');
|
|
134
|
+
if (await fs.pathExists(specFile)) {
|
|
135
|
+
const content = await fs.readFile(specFile, 'utf-8');
|
|
136
|
+
// Parse ACs
|
|
137
|
+
const acMatches = content.match(/- \[x\] \*\*AC-[^:]+\*\*:/g) || [];
|
|
138
|
+
for (const match of acMatches) {
|
|
139
|
+
const acId = match.match(/AC-[^*]+/)?.[0] || '';
|
|
140
|
+
acs.push({
|
|
141
|
+
acId: acId.trim(),
|
|
142
|
+
description: 'AC description',
|
|
143
|
+
satisfied: true
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const totalTasks = tasks.length;
|
|
148
|
+
const completedTasks = tasks.filter(t => t.completed).length;
|
|
149
|
+
const progressPercentage = totalTasks > 0
|
|
150
|
+
? Math.round((completedTasks / totalTasks) * 100)
|
|
151
|
+
: 0;
|
|
152
|
+
return {
|
|
153
|
+
tasks,
|
|
154
|
+
acceptanceCriteria: acs,
|
|
155
|
+
progressPercentage,
|
|
156
|
+
livingDocsUrl: `${this.projectRoot}/.specweave/docs/internal/specs/specweave/${usFile.id}/`
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Load user stories affected by this increment
|
|
161
|
+
*/
|
|
162
|
+
async loadUserStoriesForIncrement() {
|
|
163
|
+
const specFile = path.join(this.projectRoot, '.specweave/increments', this.incrementId, 'spec.md');
|
|
164
|
+
if (!await fs.pathExists(specFile)) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
const content = await fs.readFile(specFile, 'utf-8');
|
|
168
|
+
// Parse frontmatter to get feature ID
|
|
169
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
170
|
+
if (!frontmatterMatch) {
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
const frontmatter = yaml.parse(frontmatterMatch[1]);
|
|
174
|
+
const featureId = frontmatter.epic || frontmatter.feature;
|
|
175
|
+
if (!featureId) {
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
// Find living docs for this feature
|
|
179
|
+
const featurePath = path.join(this.projectRoot, '.specweave/docs/internal/specs/specweave', featureId);
|
|
180
|
+
if (!await fs.pathExists(featurePath)) {
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
// Load all US files
|
|
184
|
+
const files = await fs.readdir(featurePath);
|
|
185
|
+
const usFiles = [];
|
|
186
|
+
for (const file of files) {
|
|
187
|
+
if (file.startsWith('us-') && file.endsWith('.md')) {
|
|
188
|
+
const filePath = path.join(featurePath, file);
|
|
189
|
+
const fileContent = await fs.readFile(filePath, 'utf-8');
|
|
190
|
+
// Parse frontmatter
|
|
191
|
+
const match = fileContent.match(/^---\n([\s\S]*?)\n---/);
|
|
192
|
+
if (match) {
|
|
193
|
+
const fm = yaml.parse(match[1]);
|
|
194
|
+
usFiles.push({
|
|
195
|
+
id: fm.id,
|
|
196
|
+
title: fm.title,
|
|
197
|
+
format_preservation: fm.format_preservation,
|
|
198
|
+
external_title: fm.external_title,
|
|
199
|
+
external_source: fm.external_source,
|
|
200
|
+
external_id: fm.external_id,
|
|
201
|
+
external_url: fm.external_url,
|
|
202
|
+
imported_at: fm.imported_at,
|
|
203
|
+
origin: fm.origin
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return usFiles;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Load config
|
|
212
|
+
*/
|
|
213
|
+
async loadConfig() {
|
|
214
|
+
const configPath = path.join(this.projectRoot, '.specweave/config.json');
|
|
215
|
+
if (!await fs.pathExists(configPath)) {
|
|
216
|
+
return {};
|
|
217
|
+
}
|
|
218
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
219
|
+
return JSON.parse(content);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Detect GitHub repository from config or git
|
|
223
|
+
*/
|
|
224
|
+
async detectGitHubRepo(githubConfig) {
|
|
225
|
+
// Check config first
|
|
226
|
+
if (githubConfig.owner && githubConfig.repo) {
|
|
227
|
+
return { owner: githubConfig.owner, repo: githubConfig.repo };
|
|
228
|
+
}
|
|
229
|
+
// Try to detect from git remote
|
|
230
|
+
try {
|
|
231
|
+
const { execSync } = await import('child_process');
|
|
232
|
+
const remote = execSync('git remote get-url origin', {
|
|
233
|
+
cwd: this.projectRoot,
|
|
234
|
+
encoding: 'utf-8'
|
|
235
|
+
}).trim();
|
|
236
|
+
// Parse GitHub URL: git@github.com:owner/repo.git or https://github.com/owner/repo.git
|
|
237
|
+
const match = remote.match(/github\.com[:/]([^/]+)\/([^.]+)/);
|
|
238
|
+
if (match) {
|
|
239
|
+
return { owner: match[1], repo: match[2].replace('.git', '') };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
// Ignore git errors
|
|
244
|
+
}
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=sync-coordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-coordinator.js","sourceRoot":"","sources":["../../../src/sync/sync-coordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync Metadata Management
|
|
3
|
+
*
|
|
4
|
+
* Tracks last import timestamps per platform to support incremental imports
|
|
5
|
+
* and prevent duplicate imports.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Platform-specific sync metadata
|
|
9
|
+
*/
|
|
10
|
+
export interface PlatformSyncMetadata {
|
|
11
|
+
/** Timestamp of last successful import */
|
|
12
|
+
lastImport: string;
|
|
13
|
+
/** Total items imported in last sync */
|
|
14
|
+
lastImportCount?: number;
|
|
15
|
+
/** Total items skipped as duplicates in last sync */
|
|
16
|
+
lastSkippedCount?: number;
|
|
17
|
+
/** Last sync result (success, partial, failed) */
|
|
18
|
+
lastSyncResult?: 'success' | 'partial' | 'failed';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Sync metadata for all platforms
|
|
22
|
+
*/
|
|
23
|
+
export interface SyncMetadata {
|
|
24
|
+
/** GitHub sync metadata */
|
|
25
|
+
github?: PlatformSyncMetadata;
|
|
26
|
+
/** JIRA sync metadata */
|
|
27
|
+
jira?: PlatformSyncMetadata;
|
|
28
|
+
/** Azure DevOps sync metadata */
|
|
29
|
+
ado?: PlatformSyncMetadata;
|
|
30
|
+
/** Last updated timestamp */
|
|
31
|
+
lastUpdated?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Default sync metadata file path relative to project root
|
|
35
|
+
*/
|
|
36
|
+
export declare const SYNC_METADATA_FILE = ".specweave/sync-metadata.json";
|
|
37
|
+
/**
|
|
38
|
+
* Load sync metadata from file
|
|
39
|
+
*
|
|
40
|
+
* @param projectRoot - Project root directory
|
|
41
|
+
* @returns Sync metadata or empty object if file doesn't exist
|
|
42
|
+
*/
|
|
43
|
+
export declare function loadSyncMetadata(projectRoot: string): SyncMetadata;
|
|
44
|
+
/**
|
|
45
|
+
* Update sync metadata for a platform
|
|
46
|
+
*
|
|
47
|
+
* @param projectRoot - Project root directory
|
|
48
|
+
* @param platform - Platform to update (github, jira, ado)
|
|
49
|
+
* @param metadata - Platform-specific metadata to update
|
|
50
|
+
*/
|
|
51
|
+
export declare function updateSyncMetadata(projectRoot: string, platform: 'github' | 'jira' | 'ado', metadata: PlatformSyncMetadata): void;
|
|
52
|
+
/**
|
|
53
|
+
* Get last import timestamp for a platform
|
|
54
|
+
*
|
|
55
|
+
* @param projectRoot - Project root directory
|
|
56
|
+
* @param platform - Platform to query
|
|
57
|
+
* @returns ISO timestamp of last import, or undefined if never imported
|
|
58
|
+
*/
|
|
59
|
+
export declare function getLastImportTimestamp(projectRoot: string, platform: 'github' | 'jira' | 'ado'): string | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* Check if platform has been imported before
|
|
62
|
+
*
|
|
63
|
+
* @param projectRoot - Project root directory
|
|
64
|
+
* @param platform - Platform to check
|
|
65
|
+
* @returns True if platform has been imported at least once
|
|
66
|
+
*/
|
|
67
|
+
export declare function hasPlatformBeenImported(projectRoot: string, platform: 'github' | 'jira' | 'ado'): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Clear sync metadata for a platform (useful for testing or reset)
|
|
70
|
+
*
|
|
71
|
+
* @param projectRoot - Project root directory
|
|
72
|
+
* @param platform - Platform to clear
|
|
73
|
+
*/
|
|
74
|
+
export declare function clearPlatformMetadata(projectRoot: string, platform: 'github' | 'jira' | 'ado'): void;
|
|
75
|
+
//# sourceMappingURL=sync-metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-metadata.d.ts","sourceRoot":"","sources":["../../../src/sync/sync-metadata.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;IAEnB,wCAAwC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,kDAAkD;IAClD,cAAc,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,2BAA2B;IAC3B,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAE9B,yBAAyB;IACzB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAE5B,iCAAiC;IACjC,GAAG,CAAC,EAAE,oBAAoB,CAAC;IAE3B,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,kCAAkC,CAAC;AAElE;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,CAalE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,EACnC,QAAQ,EAAE,oBAAoB,GAC7B,IAAI,CAuBN;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,GAClC,MAAM,GAAG,SAAS,CAGpB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,GAClC,OAAO,CAGT;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,GAClC,IAAI,CAcN"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync Metadata Management
|
|
3
|
+
*
|
|
4
|
+
* Tracks last import timestamps per platform to support incremental imports
|
|
5
|
+
* and prevent duplicate imports.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
/**
|
|
10
|
+
* Default sync metadata file path relative to project root
|
|
11
|
+
*/
|
|
12
|
+
export const SYNC_METADATA_FILE = '.specweave/sync-metadata.json';
|
|
13
|
+
/**
|
|
14
|
+
* Load sync metadata from file
|
|
15
|
+
*
|
|
16
|
+
* @param projectRoot - Project root directory
|
|
17
|
+
* @returns Sync metadata or empty object if file doesn't exist
|
|
18
|
+
*/
|
|
19
|
+
export function loadSyncMetadata(projectRoot) {
|
|
20
|
+
const metadataPath = path.join(projectRoot, SYNC_METADATA_FILE);
|
|
21
|
+
if (!fs.existsSync(metadataPath)) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const content = fs.readFileSync(metadataPath, 'utf-8');
|
|
26
|
+
return JSON.parse(content);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
throw new Error(`Failed to load sync metadata from ${metadataPath}: ${error.message}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Update sync metadata for a platform
|
|
34
|
+
*
|
|
35
|
+
* @param projectRoot - Project root directory
|
|
36
|
+
* @param platform - Platform to update (github, jira, ado)
|
|
37
|
+
* @param metadata - Platform-specific metadata to update
|
|
38
|
+
*/
|
|
39
|
+
export function updateSyncMetadata(projectRoot, platform, metadata) {
|
|
40
|
+
const metadataPath = path.join(projectRoot, SYNC_METADATA_FILE);
|
|
41
|
+
// Load existing metadata
|
|
42
|
+
const existingMetadata = loadSyncMetadata(projectRoot);
|
|
43
|
+
// Update platform-specific metadata
|
|
44
|
+
const updatedMetadata = {
|
|
45
|
+
...existingMetadata,
|
|
46
|
+
[platform]: metadata,
|
|
47
|
+
lastUpdated: new Date().toISOString(),
|
|
48
|
+
};
|
|
49
|
+
// Ensure directory exists
|
|
50
|
+
const metadataDir = path.dirname(metadataPath);
|
|
51
|
+
fs.mkdirSync(metadataDir, { recursive: true });
|
|
52
|
+
// Write updated metadata
|
|
53
|
+
try {
|
|
54
|
+
fs.writeFileSync(metadataPath, JSON.stringify(updatedMetadata, null, 2), 'utf-8');
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
throw new Error(`Failed to write sync metadata to ${metadataPath}: ${error.message}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get last import timestamp for a platform
|
|
62
|
+
*
|
|
63
|
+
* @param projectRoot - Project root directory
|
|
64
|
+
* @param platform - Platform to query
|
|
65
|
+
* @returns ISO timestamp of last import, or undefined if never imported
|
|
66
|
+
*/
|
|
67
|
+
export function getLastImportTimestamp(projectRoot, platform) {
|
|
68
|
+
const metadata = loadSyncMetadata(projectRoot);
|
|
69
|
+
return metadata[platform]?.lastImport;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Check if platform has been imported before
|
|
73
|
+
*
|
|
74
|
+
* @param projectRoot - Project root directory
|
|
75
|
+
* @param platform - Platform to check
|
|
76
|
+
* @returns True if platform has been imported at least once
|
|
77
|
+
*/
|
|
78
|
+
export function hasPlatformBeenImported(projectRoot, platform) {
|
|
79
|
+
const timestamp = getLastImportTimestamp(projectRoot, platform);
|
|
80
|
+
return timestamp !== undefined;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Clear sync metadata for a platform (useful for testing or reset)
|
|
84
|
+
*
|
|
85
|
+
* @param projectRoot - Project root directory
|
|
86
|
+
* @param platform - Platform to clear
|
|
87
|
+
*/
|
|
88
|
+
export function clearPlatformMetadata(projectRoot, platform) {
|
|
89
|
+
const metadataPath = path.join(projectRoot, SYNC_METADATA_FILE);
|
|
90
|
+
const existingMetadata = loadSyncMetadata(projectRoot);
|
|
91
|
+
// Remove platform metadata
|
|
92
|
+
const { [platform]: _, ...remainingMetadata } = existingMetadata;
|
|
93
|
+
// Write updated metadata
|
|
94
|
+
const updatedMetadata = {
|
|
95
|
+
...remainingMetadata,
|
|
96
|
+
lastUpdated: new Date().toISOString(),
|
|
97
|
+
};
|
|
98
|
+
fs.writeFileSync(metadataPath, JSON.stringify(updatedMetadata, null, 2), 'utf-8');
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=sync-metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-metadata.js","sourceRoot":"","sources":["../../../src/sync/sync-metadata.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Living Docs User Story File Type Definitions
|
|
3
|
+
* Includes format preservation metadata (T-034A)
|
|
4
|
+
*/
|
|
5
|
+
export interface LivingDocsUSFile {
|
|
6
|
+
/** User Story ID (e.g., "US-001", "US-002E") */
|
|
7
|
+
id: string;
|
|
8
|
+
/** User Story title */
|
|
9
|
+
title: string;
|
|
10
|
+
/** User Story description/overview */
|
|
11
|
+
description?: string;
|
|
12
|
+
/** Acceptance Criteria IDs */
|
|
13
|
+
acceptanceCriteria?: string[];
|
|
14
|
+
/** Implementation status */
|
|
15
|
+
status?: 'draft' | 'in-progress' | 'completed' | 'archived';
|
|
16
|
+
/** Priority level */
|
|
17
|
+
priority?: 'P0' | 'P1' | 'P2' | 'P3';
|
|
18
|
+
/**
|
|
19
|
+
* Format preservation flag
|
|
20
|
+
* - true: External item, preserve original format (comment-only sync)
|
|
21
|
+
* - false: Internal item, allow full sync (title, description, ACs)
|
|
22
|
+
*/
|
|
23
|
+
format_preservation?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Original external title (for validation)
|
|
26
|
+
* Stored to detect if external tool accidentally modified title
|
|
27
|
+
*/
|
|
28
|
+
external_title?: string;
|
|
29
|
+
/**
|
|
30
|
+
* External source platform
|
|
31
|
+
*/
|
|
32
|
+
external_source?: 'github' | 'jira' | 'ado';
|
|
33
|
+
/**
|
|
34
|
+
* External item ID (e.g., "GH-#638", "JIRA-SPEC-789")
|
|
35
|
+
*/
|
|
36
|
+
external_id?: string;
|
|
37
|
+
/**
|
|
38
|
+
* External item URL
|
|
39
|
+
*/
|
|
40
|
+
external_url?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Import timestamp
|
|
43
|
+
*/
|
|
44
|
+
imported_at?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Origin (internal | external)
|
|
47
|
+
* Derived from ID suffix (E = external)
|
|
48
|
+
*/
|
|
49
|
+
origin?: 'internal' | 'external';
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check if US file has format preservation enabled
|
|
53
|
+
*/
|
|
54
|
+
export declare function hasFormatPreservation(usFile: LivingDocsUSFile): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Check if US is external (based on ID suffix)
|
|
57
|
+
*/
|
|
58
|
+
export declare function isExternalUS(usId: string): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Extract origin from US metadata
|
|
61
|
+
*/
|
|
62
|
+
export declare function getOrigin(usFile: LivingDocsUSFile): 'internal' | 'external';
|
|
63
|
+
//# sourceMappingURL=living-docs-us-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"living-docs-us-file.d.ts","sourceRoot":"","sources":["../../../src/types/living-docs-us-file.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,EAAE,EAAE,MAAM,CAAC;IAEX,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IAEd,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,8BAA8B;IAC9B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE9B,4BAA4B;IAC5B,MAAM,CAAC,EAAE,OAAO,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;IAE5D,qBAAqB;IACrB,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAMrC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,eAAe,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;IAE5C;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;CAClC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAEvE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,GAAG,UAAU,CAO3E"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Living Docs User Story File Type Definitions
|
|
3
|
+
* Includes format preservation metadata (T-034A)
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Check if US file has format preservation enabled
|
|
7
|
+
*/
|
|
8
|
+
export function hasFormatPreservation(usFile) {
|
|
9
|
+
return usFile.format_preservation === true;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Check if US is external (based on ID suffix)
|
|
13
|
+
*/
|
|
14
|
+
export function isExternalUS(usId) {
|
|
15
|
+
return usId.toUpperCase().endsWith('E');
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Extract origin from US metadata
|
|
19
|
+
*/
|
|
20
|
+
export function getOrigin(usFile) {
|
|
21
|
+
if (usFile.origin) {
|
|
22
|
+
return usFile.origin;
|
|
23
|
+
}
|
|
24
|
+
// Infer from ID
|
|
25
|
+
return isExternalUS(usFile.id) ? 'external' : 'internal';
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=living-docs-us-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"living-docs-us-file.js","sourceRoot":"","sources":["../../../src/types/living-docs-us-file.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiEH;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAwB;IAC5D,OAAO,MAAM,CAAC,mBAAmB,KAAK,IAAI,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,MAAwB;IAChD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,gBAAgB;IAChB,OAAO,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;AAC3D,CAAC"}
|