specweave 0.23.0 → 0.23.1
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/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +5 -17
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/core/repo-structure/repo-id-generator.d.ts +20 -0
- package/dist/src/core/repo-structure/repo-id-generator.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-id-generator.js +44 -0
- package/dist/src/core/repo-structure/repo-id-generator.js.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.js +5 -2
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/commands/specweave-archive.md +51 -15
- package/plugins/specweave/hooks/post-edit-spec.sh +62 -9
- package/plugins/specweave/hooks/post-write-spec.sh +62 -8
- package/plugins/specweave/lib/hooks/auto-transition.js.bak +50 -0
- package/plugins/specweave/lib/hooks/auto-transition.ts.bak +84 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.d.ts.bak +89 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.js.bak +142 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.ts.bak +269 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.d.ts.bak +60 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.js.bak +155 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.ts.bak +264 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.d.ts.bak +42 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.js.bak +110 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.ts.bak +178 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.d.ts.bak +45 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.js.bak +92 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.ts.bak +156 -0
- package/plugins/specweave/lib/hooks/reflection-parser.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-parser.d.ts.bak +33 -0
- package/plugins/specweave/lib/hooks/reflection-parser.js.bak +301 -0
- package/plugins/specweave/lib/hooks/reflection-parser.ts.bak +484 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.ts.bak +56 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.js.bak +182 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.ts.bak +306 -0
- package/plugins/specweave/lib/hooks/reflection-storage.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-storage.d.ts.bak +64 -0
- package/plugins/specweave/lib/hooks/reflection-storage.js.bak +231 -0
- package/plugins/specweave/lib/hooks/reflection-storage.ts.bak +369 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.d.ts.bak +43 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.js.bak +132 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.ts.bak +258 -0
- package/plugins/specweave/lib/hooks/sync-cache.js.bak +294 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.d.js.bak +1 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.d.ts.bak +27 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.js.bak +339 -0
- package/plugins/specweave/lib/hooks/sync-us-tasks.js.bak +476 -0
- package/plugins/specweave/lib/hooks/translate-file.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/translate-file.d.ts.bak +59 -0
- package/plugins/specweave/lib/hooks/translate-file.js.bak +289 -0
- package/plugins/specweave/lib/hooks/translate-file.ts.bak +428 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.d.ts.bak +13 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.js.bak +119 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.ts.bak +224 -0
- package/plugins/specweave/lib/hooks/update-ac-status.js.bak +51 -0
- package/plugins/specweave/lib/hooks/update-ac-status.ts.bak +103 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.d.js.bak +1 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.d.ts.bak +29 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.js.bak +296 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.ts.bak +489 -0
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +1 -0
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +6225 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
async function syncLivingDocs(incrementId) {
|
|
6
|
+
try {
|
|
7
|
+
console.log(`
|
|
8
|
+
\u{1F4DA} Checking living docs sync for increment: ${incrementId}`);
|
|
9
|
+
const configPath = path.join(process.cwd(), ".specweave", "config.json");
|
|
10
|
+
let config = {};
|
|
11
|
+
if (fs.existsSync(configPath)) {
|
|
12
|
+
config = JSON.parse(await fs.readFile(configPath, "utf-8"));
|
|
13
|
+
}
|
|
14
|
+
const syncEnabled = config.hooks?.post_task_completion?.sync_living_docs ?? false;
|
|
15
|
+
if (!syncEnabled) {
|
|
16
|
+
console.log("\u2139\uFE0F Living docs sync disabled in config");
|
|
17
|
+
console.log(" To enable: Set hooks.post_task_completion.sync_living_docs = true");
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
console.log("\u2705 Living docs sync enabled");
|
|
21
|
+
const intelligentEnabled = config.livingDocs?.intelligent?.enabled ?? false;
|
|
22
|
+
let specCopied = false;
|
|
23
|
+
let changedDocs = [];
|
|
24
|
+
if (intelligentEnabled) {
|
|
25
|
+
console.log("\u{1F9E0} Using intelligent sync mode (v0.18.0+)");
|
|
26
|
+
const result = await intelligentSyncLivingDocs(incrementId, config);
|
|
27
|
+
specCopied = result.success;
|
|
28
|
+
changedDocs = result.changedFiles;
|
|
29
|
+
} else {
|
|
30
|
+
console.log("\u{1F4CA} Using hierarchical distribution mode (v2.1 - Epic + User Stories)");
|
|
31
|
+
const result = await hierarchicalDistribution(incrementId);
|
|
32
|
+
specCopied = result.success;
|
|
33
|
+
changedDocs = result.changedFiles;
|
|
34
|
+
}
|
|
35
|
+
if (changedDocs.length === 0 && !specCopied) {
|
|
36
|
+
console.log("\u2139\uFE0F No living docs changed");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
console.log(`\u{1F4C4} Changed/created ${changedDocs.length} file(s)`);
|
|
40
|
+
|
|
41
|
+
// ========================================================================
|
|
42
|
+
// CHECK PERMISSION: canUpdateExternalItems (v0.24.0 - Three-Permission Architecture)
|
|
43
|
+
// ========================================================================
|
|
44
|
+
// This permission controls whether SpecWeave can UPDATE externally-created items
|
|
45
|
+
// (full content: title, description, ACs, tasks, comments).
|
|
46
|
+
// If false, living docs sync happens locally but doesn't push to external tools.
|
|
47
|
+
const canUpdateExternal = config.sync?.settings?.canUpdateExternalItems ?? false;
|
|
48
|
+
|
|
49
|
+
if (!canUpdateExternal) {
|
|
50
|
+
console.log("\u2139\uFE0F GitHub sync skipped (canUpdateExternalItems = false)");
|
|
51
|
+
console.log(" Living docs updated locally only");
|
|
52
|
+
console.log(" To enable: Set sync.settings.canUpdateExternalItems = true in config.json");
|
|
53
|
+
console.log("\u2705 Living docs sync complete (local only)\n");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await syncToGitHub(incrementId, changedDocs);
|
|
58
|
+
console.log("\u2705 Living docs sync complete\n");
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("\u274C Error syncing living docs:", error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function intelligentSyncLivingDocs(incrementId, config) {
|
|
64
|
+
console.log(" \u26A0\uFE0F Intelligent sync not yet fully implemented");
|
|
65
|
+
console.log(" Falling back to hierarchical distribution mode...");
|
|
66
|
+
return await hierarchicalDistribution(incrementId);
|
|
67
|
+
}
|
|
68
|
+
async function hierarchicalDistribution(incrementId) {
|
|
69
|
+
try {
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// LONG-TERM FIX (2025-11-19): Use LivingDocsSync instead of old SpecDistributor
|
|
72
|
+
// ============================================================================
|
|
73
|
+
//
|
|
74
|
+
// Why this change:
|
|
75
|
+
// - Old SpecDistributor.distribute() method no longer exists (removed in v3.0.0)
|
|
76
|
+
// - LivingDocsSync is the official, stable API for syncing increments
|
|
77
|
+
// - Used by /specweave:sync-docs command - battle-tested and maintained
|
|
78
|
+
// - Future-proof: Won't break when internal APIs change
|
|
79
|
+
//
|
|
80
|
+
// Architecture:
|
|
81
|
+
// - LivingDocsSync delegates to FeatureIDManager, TaskProjectSpecificGenerator, etc.
|
|
82
|
+
// - Handles greenfield/brownfield detection automatically
|
|
83
|
+
// - Returns consistent SyncResult interface
|
|
84
|
+
//
|
|
85
|
+
// Previous broken code:
|
|
86
|
+
// const { SpecDistributor } = await import("../../../../dist/src/core/living-docs/index.js");
|
|
87
|
+
// const distributor = new SpecDistributor(projectRoot, { overwriteExisting: false, createBackups: true });
|
|
88
|
+
// const result = await distributor.distribute(incrementId); // ❌ Method doesn't exist
|
|
89
|
+
//
|
|
90
|
+
// ============================================================================
|
|
91
|
+
|
|
92
|
+
const { LivingDocsSync } = await import("../../../../dist/src/core/living-docs/living-docs-sync.js");
|
|
93
|
+
|
|
94
|
+
console.log(" \u{1F4CA} Syncing increment to living docs structure...");
|
|
95
|
+
const projectRoot = process.cwd();
|
|
96
|
+
|
|
97
|
+
// ========================================================================
|
|
98
|
+
// USE FEATURE ID FROM ENVIRONMENT (NEW in v0.23.0 - Increment 0047)
|
|
99
|
+
// ========================================================================
|
|
100
|
+
// If FEATURE_ID is provided via environment variable (extracted from spec.md),
|
|
101
|
+
// use it directly instead of auto-generating. This ensures correct traceability.
|
|
102
|
+
const explicitFeatureId = process.env.FEATURE_ID;
|
|
103
|
+
if (explicitFeatureId) {
|
|
104
|
+
console.log(` \u{1F4CE} Using explicit feature ID from spec.md: ${explicitFeatureId}`);
|
|
105
|
+
} else {
|
|
106
|
+
console.log(" \u{1F504} Feature ID will be auto-generated from increment number");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Create logger adapter for LivingDocsSync
|
|
110
|
+
const logger = {
|
|
111
|
+
log: (msg) => console.log(` ${msg}`),
|
|
112
|
+
error: (msg, err) => console.error(` ${msg}`, err || ''),
|
|
113
|
+
warn: (msg) => console.warn(` ${msg}`)
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const sync = new LivingDocsSync(projectRoot, { logger });
|
|
117
|
+
const result = await sync.syncIncrement(incrementId, {
|
|
118
|
+
dryRun: false,
|
|
119
|
+
force: false,
|
|
120
|
+
// Pass explicit feature ID if available (v0.23.0+)
|
|
121
|
+
explicitFeatureId: explicitFeatureId || undefined
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
if (!result.success) {
|
|
125
|
+
console.error(` \u274C Sync failed with errors:`);
|
|
126
|
+
for (const error of result.errors) {
|
|
127
|
+
console.error(` - ${error}`);
|
|
128
|
+
}
|
|
129
|
+
return { success: false, changedFiles: [] };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.log(` \u2705 Living docs sync complete:`);
|
|
133
|
+
console.log(` Feature ID: ${result.featureId}`);
|
|
134
|
+
console.log(` Files created/updated: ${result.filesCreated.length + result.filesUpdated.length}`);
|
|
135
|
+
|
|
136
|
+
const changedFiles = [...result.filesCreated, ...result.filesUpdated];
|
|
137
|
+
|
|
138
|
+
// NEW (v0.23.0): Sync tasks from tasks.md to living docs US files
|
|
139
|
+
// Part of increment 0047-us-task-linkage implementation
|
|
140
|
+
try {
|
|
141
|
+
const { syncUSTasksToLivingDocs } = await import("./sync-us-tasks.js");
|
|
142
|
+
const taskSyncResult = await syncUSTasksToLivingDocs(
|
|
143
|
+
incrementId,
|
|
144
|
+
projectRoot,
|
|
145
|
+
result.featureId,
|
|
146
|
+
{}
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
if (taskSyncResult.success && taskSyncResult.updatedFiles.length > 0) {
|
|
150
|
+
changedFiles.push(...taskSyncResult.updatedFiles);
|
|
151
|
+
}
|
|
152
|
+
} catch (error) {
|
|
153
|
+
// Don't fail entire sync if US-Task sync fails (graceful degradation)
|
|
154
|
+
console.log(` \u26A0\uFE0F US-Task sync failed (non-fatal):`, error.message);
|
|
155
|
+
console.log(` \u{1F4A1} Tip: This is a new feature (v0.23.0) - may need task parser build`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
success: true,
|
|
160
|
+
changedFiles
|
|
161
|
+
};
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.error(` \u274C Living docs sync failed: ${error}`);
|
|
164
|
+
console.error(error.stack);
|
|
165
|
+
console.error(" \u26A0\uFE0F Living docs sync skipped due to error");
|
|
166
|
+
console.error(" \u{1F4A1} Tip: Run /specweave:sync-docs manually to retry");
|
|
167
|
+
return {
|
|
168
|
+
success: false,
|
|
169
|
+
changedFiles: []
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async function extractAndMergeLivingDocs(incrementId) {
|
|
174
|
+
try {
|
|
175
|
+
const {
|
|
176
|
+
parseIncrementSpec,
|
|
177
|
+
parseLivingDocsSpec,
|
|
178
|
+
extractSpecId,
|
|
179
|
+
mergeUserStories,
|
|
180
|
+
generateRelatedDocsLinks,
|
|
181
|
+
writeLivingDocsSpec
|
|
182
|
+
} = await import("../../../../dist/src/utils/spec-parser.js");
|
|
183
|
+
const projectRoot = process.cwd();
|
|
184
|
+
const incrementSpecPath = path.join(projectRoot, ".specweave", "increments", incrementId, "spec.md");
|
|
185
|
+
if (!fs.existsSync(incrementSpecPath)) {
|
|
186
|
+
console.log(`\u26A0\uFE0F Increment spec not found: ${incrementSpecPath}`);
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
console.log(` \u{1F4D6} Parsing increment spec: ${incrementId}`);
|
|
190
|
+
const incrementSpec = await parseIncrementSpec(incrementSpecPath);
|
|
191
|
+
if (incrementSpec.userStories.length === 0) {
|
|
192
|
+
console.log(`\u2139\uFE0F No user stories found in increment spec, skipping sync`);
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
console.log(` \u2705 Found ${incrementSpec.userStories.length} user stories in increment`);
|
|
196
|
+
const specId = incrementSpec.implementsSpec || extractSpecId(incrementId);
|
|
197
|
+
const livingDocsDir = path.join(projectRoot, ".specweave", "docs", "internal", "specs", "default");
|
|
198
|
+
const livingDocsPath = path.join(livingDocsDir, `${specId}-${incrementId.replace(/^\d+-/, "")}.md`);
|
|
199
|
+
const livingDocsExists = fs.existsSync(livingDocsPath);
|
|
200
|
+
if (livingDocsExists) {
|
|
201
|
+
console.log(` \u{1F4DA} Living docs spec exists, merging user stories...`);
|
|
202
|
+
const livingSpec = await parseLivingDocsSpec(livingDocsPath);
|
|
203
|
+
const mergedStories = mergeUserStories(
|
|
204
|
+
livingSpec.userStories,
|
|
205
|
+
incrementSpec.userStories,
|
|
206
|
+
incrementId
|
|
207
|
+
);
|
|
208
|
+
const newStoriesCount = mergedStories.length - livingSpec.userStories.length;
|
|
209
|
+
const existingEntry = livingSpec.implementationHistory.find((e) => e.increment === incrementId);
|
|
210
|
+
if (!existingEntry) {
|
|
211
|
+
livingSpec.implementationHistory.push({
|
|
212
|
+
increment: incrementId,
|
|
213
|
+
stories: incrementSpec.userStories.map((s) => s.id),
|
|
214
|
+
status: "complete",
|
|
215
|
+
date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0]
|
|
216
|
+
});
|
|
217
|
+
} else {
|
|
218
|
+
existingEntry.status = "complete";
|
|
219
|
+
existingEntry.date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
220
|
+
}
|
|
221
|
+
livingSpec.userStories = mergedStories;
|
|
222
|
+
livingSpec.lastUpdated = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
223
|
+
await writeLivingDocsSpec(livingDocsPath, livingSpec);
|
|
224
|
+
console.log(` \u2705 Merged ${newStoriesCount} new user stories into living docs`);
|
|
225
|
+
console.log(` \u2705 Updated implementation history for ${incrementId}`);
|
|
226
|
+
} else {
|
|
227
|
+
console.log(` \u{1F4DD} Creating new living docs spec: ${specId}`);
|
|
228
|
+
const relatedDocs = generateRelatedDocsLinks(incrementSpec, projectRoot);
|
|
229
|
+
const livingSpec = {
|
|
230
|
+
id: specId,
|
|
231
|
+
title: incrementSpec.title,
|
|
232
|
+
featureArea: extractFeatureArea(incrementSpec.title),
|
|
233
|
+
overview: incrementSpec.overview,
|
|
234
|
+
userStories: incrementSpec.userStories.map((story) => ({
|
|
235
|
+
...story,
|
|
236
|
+
implementedIn: incrementId,
|
|
237
|
+
status: "complete"
|
|
238
|
+
})),
|
|
239
|
+
implementationHistory: [
|
|
240
|
+
{
|
|
241
|
+
increment: incrementId,
|
|
242
|
+
stories: incrementSpec.userStories.map((s) => s.id),
|
|
243
|
+
status: "complete",
|
|
244
|
+
date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0]
|
|
245
|
+
}
|
|
246
|
+
],
|
|
247
|
+
relatedDocs,
|
|
248
|
+
externalLinks: {},
|
|
249
|
+
priority: incrementSpec.priority,
|
|
250
|
+
status: "active",
|
|
251
|
+
created: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
252
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString().split("T")[0]
|
|
253
|
+
};
|
|
254
|
+
await fs.ensureDir(livingDocsDir);
|
|
255
|
+
await writeLivingDocsSpec(livingDocsPath, livingSpec);
|
|
256
|
+
console.log(` \u2705 Created new living docs spec: ${specId}`);
|
|
257
|
+
console.log(` \u2705 Added ${incrementSpec.userStories.length} user stories`);
|
|
258
|
+
console.log(` \u2705 Generated links to ${relatedDocs.architecture.length} architecture docs`);
|
|
259
|
+
console.log(` \u2705 Generated links to ${relatedDocs.adrs.length} ADRs`);
|
|
260
|
+
}
|
|
261
|
+
return true;
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.error(`\u274C Error extracting/merging living docs: ${error}`);
|
|
264
|
+
console.error(error.stack);
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function extractFeatureArea(title) {
|
|
269
|
+
return title.replace(/^(Increment \d+:\s*)?/, "").trim();
|
|
270
|
+
}
|
|
271
|
+
function detectChangedDocs() {
|
|
272
|
+
try {
|
|
273
|
+
const output = execSync("git diff --name-only .specweave/docs/ 2>/dev/null || true", {
|
|
274
|
+
encoding: "utf-8",
|
|
275
|
+
cwd: process.cwd()
|
|
276
|
+
}).trim();
|
|
277
|
+
if (!output) {
|
|
278
|
+
return [];
|
|
279
|
+
}
|
|
280
|
+
const files = output.split("\n").filter((f) => f.endsWith(".md")).filter((f) => f.length > 0);
|
|
281
|
+
return files;
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.warn("\u26A0\uFE0F Could not detect git changes:", error);
|
|
284
|
+
return [];
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
async function syncToGitHub(incrementId, changedDocs) {
|
|
288
|
+
try {
|
|
289
|
+
console.log("\n\u{1F504} Syncing to GitHub...");
|
|
290
|
+
const {
|
|
291
|
+
loadIncrementMetadata,
|
|
292
|
+
detectRepo,
|
|
293
|
+
collectLivingDocs,
|
|
294
|
+
updateIssueLivingDocs,
|
|
295
|
+
postArchitectureComment
|
|
296
|
+
} = await import("../../../../dist/plugins/specweave-github/lib/github-issue-updater.js");
|
|
297
|
+
const metadata = await loadIncrementMetadata(incrementId);
|
|
298
|
+
if (!metadata?.github?.issue) {
|
|
299
|
+
console.log("\u2139\uFE0F No GitHub issue linked, skipping GitHub sync");
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const repoInfo = await detectRepo();
|
|
303
|
+
if (!repoInfo) {
|
|
304
|
+
console.log("\u26A0\uFE0F Could not detect GitHub repository, skipping GitHub sync");
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const { owner, repo } = repoInfo;
|
|
308
|
+
const issueNumber = metadata.github.issue;
|
|
309
|
+
console.log(` Syncing to ${owner}/${repo}#${issueNumber}`);
|
|
310
|
+
const livingDocs = await collectLivingDocs(incrementId);
|
|
311
|
+
if (livingDocs.specs.length > 0 || livingDocs.architecture.length > 0 || livingDocs.diagrams.length > 0) {
|
|
312
|
+
await updateIssueLivingDocs(issueNumber, livingDocs, owner, repo);
|
|
313
|
+
}
|
|
314
|
+
for (const docPath of changedDocs) {
|
|
315
|
+
if (docPath.includes("/architecture/")) {
|
|
316
|
+
await postArchitectureComment(issueNumber, docPath, owner, repo);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
console.log("\u2705 GitHub sync complete");
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.error("\u274C Error syncing to GitHub:", error);
|
|
322
|
+
console.error(" (Non-blocking - continuing...)");
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
326
|
+
if (isMainModule) {
|
|
327
|
+
const incrementId = process.argv[2];
|
|
328
|
+
if (!incrementId) {
|
|
329
|
+
console.error("\u274C Usage: sync-living-docs <incrementId>");
|
|
330
|
+
console.error(" Example: sync-living-docs 0006-llm-native-i18n");
|
|
331
|
+
process.exit(1);
|
|
332
|
+
}
|
|
333
|
+
syncLivingDocs(incrementId).catch((error) => {
|
|
334
|
+
console.error("\u274C Fatal error:", error);
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
export {
|
|
338
|
+
syncLivingDocs
|
|
339
|
+
};
|