specweave 0.17.16 → 0.17.19
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 +405 -2495
- package/README.md +92 -2
- package/dist/locales/de/.gitkeep +0 -0
- package/dist/locales/de/cli.json +108 -0
- package/dist/locales/en/cli.json +287 -0
- package/dist/locales/en/errors.json +7 -0
- package/dist/locales/en/templates.json +6 -0
- package/dist/locales/es/.gitkeep +0 -0
- package/dist/locales/es/cli.json +41 -0
- package/dist/locales/fr/.gitkeep +0 -0
- package/dist/locales/fr/cli.json +108 -0
- package/dist/locales/ja/.gitkeep +0 -0
- package/dist/locales/ja/cli.json +108 -0
- package/dist/locales/ko/.gitkeep +0 -0
- package/dist/locales/ko/cli.json +108 -0
- package/dist/locales/pt/.gitkeep +0 -0
- package/dist/locales/pt/cli.json +108 -0
- package/dist/locales/ru/.gitkeep +0 -0
- package/dist/locales/ru/cli.json +269 -0
- package/dist/locales/zh/.gitkeep +0 -0
- package/dist/locales/zh/cli.json +108 -0
- package/dist/plugins/specweave/lib/hooks/sync-living-docs.d.ts.map +1 -1
- package/dist/plugins/specweave/lib/hooks/sync-living-docs.js +188 -36
- package/dist/plugins/specweave/lib/hooks/sync-living-docs.js.map +1 -1
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js +65 -6
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js.map +1 -1
- package/dist/plugins/specweave-ado/lib/ado-status-sync.d.ts +54 -0
- package/dist/plugins/specweave-ado/lib/ado-status-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-ado/lib/ado-status-sync.js +86 -0
- package/dist/plugins/specweave-ado/lib/ado-status-sync.js.map +1 -0
- package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.d.ts +25 -0
- package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.js +191 -0
- package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/duplicate-detector.d.ts +139 -0
- package/dist/plugins/specweave-github/lib/duplicate-detector.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/duplicate-detector.js +389 -0
- package/dist/plugins/specweave-github/lib/duplicate-detector.js.map +1 -0
- package/dist/plugins/specweave-github/lib/enhanced-github-sync.d.ts +26 -0
- package/dist/plugins/specweave-github/lib/enhanced-github-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/enhanced-github-sync.js +249 -0
- package/dist/plugins/specweave-github/lib/enhanced-github-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts +63 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.js +216 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-client.d.ts +1 -1
- package/dist/plugins/specweave-github/lib/github-client.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-client.js +25 -13
- package/dist/plugins/specweave-github/lib/github-client.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts +83 -0
- package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-epic-sync.js +466 -0
- package/dist/plugins/specweave-github/lib/github-epic-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-status-sync.d.ts +43 -0
- package/dist/plugins/specweave-github/lib/github-status-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-status-sync.js +82 -0
- package/dist/plugins/specweave-github/lib/github-status-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/task-sync.d.ts +5 -0
- package/dist/plugins/specweave-github/lib/task-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/task-sync.js +38 -2
- package/dist/plugins/specweave-github/lib/task-sync.js.map +1 -1
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts +28 -0
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js +156 -0
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-epic-sync.d.ts +66 -0
- package/dist/plugins/specweave-jira/lib/jira-epic-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-epic-sync.js +274 -0
- package/dist/plugins/specweave-jira/lib/jira-epic-sync.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-status-sync.d.ts +56 -0
- package/dist/plugins/specweave-jira/lib/jira-status-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-status-sync.js +93 -0
- package/dist/plugins/specweave-jira/lib/jira-status-sync.js.map +1 -0
- package/dist/spec-parser.js +629 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +107 -3
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +48 -3
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/core/deduplication/command-deduplicator.d.ts +166 -0
- package/dist/src/core/deduplication/command-deduplicator.d.ts.map +1 -0
- package/dist/src/core/deduplication/command-deduplicator.js +254 -0
- package/dist/src/core/deduplication/command-deduplicator.js.map +1 -0
- package/dist/src/core/living-docs/hierarchy-mapper.d.ts +142 -0
- package/dist/src/core/living-docs/hierarchy-mapper.d.ts.map +1 -0
- package/dist/src/core/living-docs/hierarchy-mapper.js +453 -0
- package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -0
- package/dist/src/core/living-docs/index.d.ts +10 -84
- package/dist/src/core/living-docs/index.d.ts.map +1 -1
- package/dist/src/core/living-docs/index.js +10 -164
- package/dist/src/core/living-docs/index.js.map +1 -1
- package/dist/src/core/living-docs/spec-distributor.d.ts +106 -0
- package/dist/src/core/living-docs/spec-distributor.d.ts.map +1 -0
- package/dist/src/core/living-docs/spec-distributor.js +823 -0
- package/dist/src/core/living-docs/spec-distributor.js.map +1 -0
- package/dist/src/core/living-docs/types.d.ts +201 -0
- package/dist/src/core/living-docs/types.d.ts.map +1 -0
- package/dist/src/core/living-docs/types.js +15 -0
- package/dist/src/core/living-docs/types.js.map +1 -0
- package/dist/src/core/logging/prompt-logger.d.ts +70 -0
- package/dist/src/core/logging/prompt-logger.d.ts.map +1 -0
- package/dist/src/core/logging/prompt-logger.js +247 -0
- package/dist/src/core/logging/prompt-logger.js.map +1 -0
- package/dist/src/core/status-line/status-line-manager.d.ts +15 -24
- package/dist/src/core/status-line/status-line-manager.d.ts.map +1 -1
- package/dist/src/core/status-line/status-line-manager.js +33 -70
- package/dist/src/core/status-line/status-line-manager.js.map +1 -1
- package/dist/src/core/status-line/types.d.ts +19 -31
- package/dist/src/core/status-line/types.d.ts.map +1 -1
- package/dist/src/core/status-line/types.js +5 -9
- package/dist/src/core/status-line/types.js.map +1 -1
- package/dist/src/core/sync/conflict-resolver.d.ts +66 -0
- package/dist/src/core/sync/conflict-resolver.d.ts.map +1 -0
- package/dist/src/core/sync/conflict-resolver.js +108 -0
- package/dist/src/core/sync/conflict-resolver.js.map +1 -0
- package/dist/src/core/sync/enhanced-content-builder.d.ts +55 -0
- package/dist/src/core/sync/enhanced-content-builder.d.ts.map +1 -0
- package/dist/src/core/sync/enhanced-content-builder.js +202 -0
- package/dist/src/core/sync/enhanced-content-builder.js.map +1 -0
- package/dist/src/core/sync/label-detector.d.ts +66 -0
- package/dist/src/core/sync/label-detector.d.ts.map +1 -0
- package/dist/src/core/sync/label-detector.js +211 -0
- package/dist/src/core/sync/label-detector.js.map +1 -0
- package/dist/src/core/sync/retry-logic.d.ts +64 -0
- package/dist/src/core/sync/retry-logic.d.ts.map +1 -0
- package/dist/src/core/sync/retry-logic.js +165 -0
- package/dist/src/core/sync/retry-logic.js.map +1 -0
- package/dist/src/core/sync/spec-content-sync.d.ts +88 -0
- package/dist/src/core/sync/spec-content-sync.d.ts.map +1 -0
- package/dist/src/core/sync/spec-content-sync.js +5 -0
- package/dist/src/core/sync/spec-content-sync.js.map +1 -0
- package/dist/src/core/sync/spec-increment-mapper.d.ts +100 -0
- package/dist/src/core/sync/spec-increment-mapper.d.ts.map +1 -0
- package/dist/src/core/sync/spec-increment-mapper.js +424 -0
- package/dist/src/core/sync/spec-increment-mapper.js.map +1 -0
- package/dist/src/core/sync/status-cache.d.ts +91 -0
- package/dist/src/core/sync/status-cache.d.ts.map +1 -0
- package/dist/src/core/sync/status-cache.js +140 -0
- package/dist/src/core/sync/status-cache.js.map +1 -0
- package/dist/src/core/sync/status-mapper.d.ts +69 -0
- package/dist/src/core/sync/status-mapper.d.ts.map +1 -0
- package/dist/src/core/sync/status-mapper.js +90 -0
- package/dist/src/core/sync/status-mapper.js.map +1 -0
- package/dist/src/core/sync/status-sync-engine.d.ts +162 -0
- package/dist/src/core/sync/status-sync-engine.d.ts.map +1 -0
- package/dist/src/core/sync/status-sync-engine.js +347 -0
- package/dist/src/core/sync/status-sync-engine.js.map +1 -0
- package/dist/src/core/sync/sync-event-logger.d.ts +99 -0
- package/dist/src/core/sync/sync-event-logger.d.ts.map +1 -0
- package/dist/src/core/sync/sync-event-logger.js +103 -0
- package/dist/src/core/sync/sync-event-logger.js.map +1 -0
- package/dist/src/core/sync/types.d.ts +52 -0
- package/dist/src/core/sync/types.d.ts.map +1 -0
- package/dist/src/core/sync/types.js +5 -0
- package/dist/src/core/sync/types.js.map +1 -0
- package/dist/src/core/sync/workflow-detector.d.ts +95 -0
- package/dist/src/core/sync/workflow-detector.d.ts.map +1 -0
- package/dist/src/core/sync/workflow-detector.js +175 -0
- package/dist/src/core/sync/workflow-detector.js.map +1 -0
- package/dist/src/core/types/config.d.ts +51 -0
- package/dist/src/core/types/config.d.ts.map +1 -1
- package/dist/src/core/types/config.js +47 -0
- package/dist/src/core/types/config.js.map +1 -1
- package/dist/src/core/types/increment-metadata.d.ts +4 -0
- package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
- package/dist/src/core/types/increment-metadata.js.map +1 -1
- package/dist/src/utils/github-url.d.ts +53 -0
- package/dist/src/utils/github-url.d.ts.map +1 -0
- package/dist/src/utils/github-url.js +90 -0
- package/dist/src/utils/github-url.js.map +1 -0
- package/dist/src/utils/spec-parser.d.ts +145 -0
- package/dist/src/utils/spec-parser.d.ts.map +1 -0
- package/dist/src/utils/spec-parser.js +640 -0
- package/dist/src/utils/spec-parser.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +1 -1
- package/plugins/specweave/agents/pm/AGENT.md +160 -13
- package/plugins/specweave/agents/pm/templates/increment-spec.md +158 -0
- package/plugins/specweave/agents/pm/templates/living-docs-spec.md +113 -0
- package/plugins/specweave/commands/specweave-done.md +163 -0
- package/plugins/specweave/commands/specweave.md +70 -405
- package/plugins/specweave/hooks/hooks.json +4 -0
- package/plugins/specweave/hooks/lib/sync-spec-content.sh +2 -2
- package/plugins/specweave/hooks/lib/update-status-line.sh +79 -111
- package/plugins/specweave/hooks/post-increment-planning.sh +133 -37
- package/plugins/specweave/hooks/pre-command-deduplication.sh +86 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.js +139 -34
- package/plugins/specweave/lib/hooks/sync-living-docs.ts +234 -38
- package/plugins/specweave/skills/SKILLS-INDEX.md +4 -24
- package/plugins/specweave/skills/increment-planner/SKILL.md +94 -0
- package/plugins/specweave/skills/increment-work-router/SKILL.md +466 -0
- package/plugins/specweave-ado/commands/specweave-ado-sync-spec.md +1 -1
- package/plugins/specweave-ado/lib/ado-spec-content-sync.js +49 -5
- package/plugins/specweave-ado/lib/ado-spec-content-sync.ts +72 -6
- package/plugins/specweave-ado/lib/ado-status-sync.js +80 -0
- package/plugins/specweave-ado/lib/ado-status-sync.ts +121 -0
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-github/commands/specweave-github-cleanup-duplicates.md +205 -0
- package/plugins/specweave-github/commands/specweave-github-sync-epic.md +248 -0
- package/plugins/specweave-github/commands/specweave-github-sync-spec.md +1 -1
- package/plugins/specweave-github/hooks/post-task-completion.sh +32 -0
- package/plugins/specweave-github/lib/duplicate-detector.js +370 -0
- package/plugins/specweave-github/lib/duplicate-detector.ts +525 -0
- package/plugins/specweave-github/lib/enhanced-github-sync.js +220 -0
- package/plugins/specweave-github/lib/enhanced-github-sync.ts +322 -0
- package/plugins/specweave-github/lib/epic-content-builder.js +227 -0
- package/plugins/specweave-github/lib/epic-content-builder.ts +317 -0
- package/plugins/specweave-github/lib/github-client.js +21 -10
- package/plugins/specweave-github/lib/github-client.ts +27 -16
- package/plugins/specweave-github/lib/github-epic-sync.js +488 -0
- package/plugins/specweave-github/lib/github-epic-sync.ts +715 -0
- package/plugins/specweave-github/lib/github-status-sync.js +71 -0
- package/plugins/specweave-github/lib/github-status-sync.ts +107 -0
- package/plugins/specweave-github/lib/task-sync.js +33 -2
- package/plugins/specweave-github/lib/task-sync.ts +44 -2
- package/plugins/specweave-jira/commands/specweave-jira-sync-epic.md +267 -0
- package/plugins/specweave-jira/commands/specweave-jira-sync-spec.md +1 -1
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.ts +196 -0
- package/plugins/specweave-jira/lib/jira-epic-sync.js +304 -0
- package/plugins/specweave-jira/lib/jira-epic-sync.ts +459 -0
- package/plugins/specweave-jira/lib/jira-status-sync.js +79 -0
- package/plugins/specweave-jira/lib/jira-status-sync.ts +139 -0
- package/plugins/specweave-release/commands/specweave-release-platform.md +1 -1
- package/plugins/specweave-release/hooks/post-task-completion.sh +2 -2
- package/src/templates/AGENTS.md.template +88 -1
- package/src/templates/CLAUDE.md.template +49 -0
- package/plugins/specweave/skills/increment-quality-judge/SKILL.md +0 -524
- package/plugins/specweave/skills/plugin-installer/SKILL.md +0 -353
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced GitHub Spec Content Sync
|
|
3
|
+
*
|
|
4
|
+
* Uses EnhancedContentBuilder and SpecIncrementMapper for rich external descriptions.
|
|
5
|
+
* NEW (v0.21.0): Supports task checkboxes and automatic labeling.
|
|
6
|
+
*/
|
|
7
|
+
import { GitHubClientV2 } from './github-client-v2.js';
|
|
8
|
+
import { EnhancedContentBuilder } from '../../../src/core/sync/enhanced-content-builder.js';
|
|
9
|
+
import { SpecIncrementMapper } from '../../../src/core/sync/spec-increment-mapper.js';
|
|
10
|
+
import { parseSpecContent } from '../../../src/core/spec-content-sync.js';
|
|
11
|
+
import { LabelDetector } from '../../../src/core/sync/label-detector.js';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import fs from 'fs/promises';
|
|
14
|
+
/**
|
|
15
|
+
* Enhanced sync with rich content including task mappings
|
|
16
|
+
*/
|
|
17
|
+
export async function syncSpecWithEnhancedContent(options) {
|
|
18
|
+
const { specPath, owner, repo, dryRun = false, verbose = false } = options;
|
|
19
|
+
try {
|
|
20
|
+
// 1. Parse spec content
|
|
21
|
+
const baseSpec = await parseSpecContent(specPath);
|
|
22
|
+
if (!baseSpec) {
|
|
23
|
+
return {
|
|
24
|
+
success: false,
|
|
25
|
+
action: 'error',
|
|
26
|
+
error: 'Failed to parse spec content',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (verbose) {
|
|
30
|
+
console.log(`📄 Parsed spec: ${baseSpec.identifier.compact}`);
|
|
31
|
+
}
|
|
32
|
+
// 2. Build enhanced spec with task mappings
|
|
33
|
+
const specId = baseSpec.identifier.full || baseSpec.identifier.compact;
|
|
34
|
+
const rootDir = await findSpecWeaveRoot(specPath);
|
|
35
|
+
const mapper = new SpecIncrementMapper(rootDir);
|
|
36
|
+
const mapping = await mapper.mapSpecToIncrements(specId);
|
|
37
|
+
if (verbose) {
|
|
38
|
+
console.log(`🔗 Found ${mapping.increments.length} related increments`);
|
|
39
|
+
console.log(`📋 Mapped ${Object.keys(mapping.userStoryMappings).length} user stories to tasks`);
|
|
40
|
+
}
|
|
41
|
+
// 3. Build task mapping for EnhancedSpecContent
|
|
42
|
+
const taskMapping = buildTaskMapping(mapping.increments, owner, repo);
|
|
43
|
+
// 4. Build architecture docs references
|
|
44
|
+
const architectureDocs = await findArchitectureDocs(rootDir, specId);
|
|
45
|
+
// 5. Build source links
|
|
46
|
+
const sourceLinks = buildSourceLinks(mapping.increments[0]?.id, owner, repo);
|
|
47
|
+
// 6. Create enhanced spec content
|
|
48
|
+
const enhancedSpec = {
|
|
49
|
+
...baseSpec,
|
|
50
|
+
summary: baseSpec.description,
|
|
51
|
+
taskMapping,
|
|
52
|
+
architectureDocs,
|
|
53
|
+
sourceLinks
|
|
54
|
+
};
|
|
55
|
+
// 7. Build external description with task checkboxes
|
|
56
|
+
const builder = new EnhancedContentBuilder();
|
|
57
|
+
// NEW: Override buildTasksSection call to include checkboxes
|
|
58
|
+
const originalBuildExternal = builder.buildExternalDescription.bind(builder);
|
|
59
|
+
const description = (() => {
|
|
60
|
+
const sections = [];
|
|
61
|
+
// Summary
|
|
62
|
+
sections.push(builder.buildSummarySection(enhancedSpec));
|
|
63
|
+
// User stories
|
|
64
|
+
if (enhancedSpec.userStories && enhancedSpec.userStories.length > 0) {
|
|
65
|
+
sections.push(builder.buildUserStoriesSection(enhancedSpec.userStories));
|
|
66
|
+
}
|
|
67
|
+
// Tasks with checkboxes (NEW!)
|
|
68
|
+
if (enhancedSpec.taskMapping) {
|
|
69
|
+
sections.push(builder.buildTasksSection(enhancedSpec.taskMapping, {
|
|
70
|
+
showCheckboxes: true,
|
|
71
|
+
showProgressBar: true,
|
|
72
|
+
showCompletionStatus: true,
|
|
73
|
+
provider: 'github'
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
// Architecture
|
|
77
|
+
if (enhancedSpec.architectureDocs && enhancedSpec.architectureDocs.length > 0) {
|
|
78
|
+
sections.push(builder.buildArchitectureSection(enhancedSpec.architectureDocs));
|
|
79
|
+
}
|
|
80
|
+
// Source links
|
|
81
|
+
if (enhancedSpec.sourceLinks) {
|
|
82
|
+
sections.push(builder.buildSourceLinksSection(enhancedSpec.sourceLinks));
|
|
83
|
+
}
|
|
84
|
+
return sections.filter(s => s.length > 0).join('\n\n---\n\n');
|
|
85
|
+
})();
|
|
86
|
+
if (verbose) {
|
|
87
|
+
console.log(`📝 Generated description: ${description.length} characters`);
|
|
88
|
+
}
|
|
89
|
+
if (dryRun) {
|
|
90
|
+
console.log('🔍 DRY RUN - Would create/update issue with:');
|
|
91
|
+
console.log(` Title: ${baseSpec.title}`);
|
|
92
|
+
console.log(` Description length: ${description.length}`);
|
|
93
|
+
console.log(` Tasks linked: ${taskMapping?.tasks.length || 0}`);
|
|
94
|
+
return {
|
|
95
|
+
success: true,
|
|
96
|
+
action: 'no-change',
|
|
97
|
+
tasksLinked: taskMapping?.tasks.length || 0
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// 8. Create or update GitHub issue
|
|
101
|
+
if (!owner || !repo) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
action: 'error',
|
|
105
|
+
error: 'GitHub owner/repo not specified',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const client = GitHubClientV2.fromRepo(owner, repo);
|
|
109
|
+
// NEW: Detect increment type and apply labels
|
|
110
|
+
const labelDetector = new LabelDetector(undefined, false); // Use GitHub format
|
|
111
|
+
const detection = labelDetector.detectType(await fs.readFile(specPath, 'utf-8'), mapping.increments[0]?.id);
|
|
112
|
+
const githubLabels = labelDetector.getGitHubLabels(detection.type);
|
|
113
|
+
const allLabels = ['spec', ...githubLabels]; // Include both 'spec' and type labels
|
|
114
|
+
if (verbose) {
|
|
115
|
+
console.log(`🏷️ Detected type: ${detection.type} (${detection.confidence}% confidence)`);
|
|
116
|
+
console.log(` Labels: ${allLabels.join(', ')}`);
|
|
117
|
+
}
|
|
118
|
+
// Check if issue already exists
|
|
119
|
+
const existingIssue = await findExistingIssue(client, baseSpec.identifier.compact);
|
|
120
|
+
let result;
|
|
121
|
+
if (existingIssue) {
|
|
122
|
+
// Update existing issue (body + labels)
|
|
123
|
+
await client.updateIssueBody(existingIssue.number, description);
|
|
124
|
+
// Update labels if autoApplyLabels is enabled
|
|
125
|
+
// TODO: Read from config, for now always apply
|
|
126
|
+
await client.addLabels(existingIssue.number, allLabels);
|
|
127
|
+
result = {
|
|
128
|
+
success: true,
|
|
129
|
+
action: 'updated',
|
|
130
|
+
issueNumber: existingIssue.number,
|
|
131
|
+
issueUrl: existingIssue.html_url,
|
|
132
|
+
tasksLinked: taskMapping?.tasks.length || 0
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// Create new issue with labels
|
|
137
|
+
const issue = await client.createEpicIssue(`[${baseSpec.identifier.compact}] ${baseSpec.title}`, description, undefined, allLabels // Apply labels at creation
|
|
138
|
+
);
|
|
139
|
+
result = {
|
|
140
|
+
success: true,
|
|
141
|
+
action: 'created',
|
|
142
|
+
issueNumber: issue.number,
|
|
143
|
+
issueUrl: issue.html_url,
|
|
144
|
+
tasksLinked: taskMapping?.tasks.length || 0
|
|
145
|
+
};
|
|
146
|
+
// Update spec with GitHub link
|
|
147
|
+
await mapper.updateSpecWithIncrementLinks(specId, mapping.increments[0]?.id);
|
|
148
|
+
}
|
|
149
|
+
if (verbose) {
|
|
150
|
+
console.log(`✅ ${result.action === 'created' ? 'Created' : 'Updated'} issue #${result.issueNumber}`);
|
|
151
|
+
console.log(` URL: ${result.issueUrl}`);
|
|
152
|
+
console.log(` Tasks linked: ${result.tasksLinked}`);
|
|
153
|
+
}
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return {
|
|
158
|
+
success: false,
|
|
159
|
+
action: 'error',
|
|
160
|
+
error: error.message
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Helper functions
|
|
165
|
+
async function findSpecWeaveRoot(specPath) {
|
|
166
|
+
let currentDir = path.dirname(specPath);
|
|
167
|
+
while (true) {
|
|
168
|
+
const specweaveDir = path.join(currentDir, '.specweave');
|
|
169
|
+
try {
|
|
170
|
+
await fs.access(specweaveDir);
|
|
171
|
+
return currentDir;
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
const parentDir = path.dirname(currentDir);
|
|
175
|
+
if (parentDir === currentDir) {
|
|
176
|
+
throw new Error('.specweave directory not found');
|
|
177
|
+
}
|
|
178
|
+
currentDir = parentDir;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function buildTaskMapping(increments, owner, repo) {
|
|
183
|
+
if (increments.length === 0)
|
|
184
|
+
return undefined;
|
|
185
|
+
const firstIncrement = increments[0];
|
|
186
|
+
const tasks = firstIncrement.tasks.map((task) => ({
|
|
187
|
+
id: task.id,
|
|
188
|
+
title: task.title,
|
|
189
|
+
userStories: task.userStories,
|
|
190
|
+
githubIssue: task.githubIssue
|
|
191
|
+
}));
|
|
192
|
+
return {
|
|
193
|
+
incrementId: firstIncrement.id,
|
|
194
|
+
tasks,
|
|
195
|
+
tasksUrl: `https://github.com/${owner}/${repo}/blob/develop/.specweave/increments/${firstIncrement.id}/tasks.md`
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
async function findArchitectureDocs(rootDir, specId) {
|
|
199
|
+
const docs = [];
|
|
200
|
+
const archDir = path.join(rootDir, '.specweave/docs/internal/architecture');
|
|
201
|
+
try {
|
|
202
|
+
// Check for ADRs
|
|
203
|
+
const adrDir = path.join(archDir, 'adr');
|
|
204
|
+
try {
|
|
205
|
+
const adrs = await fs.readdir(adrDir);
|
|
206
|
+
const relatedAdrs = adrs.filter(file => file.includes(specId.replace('spec-', '')));
|
|
207
|
+
for (const adr of relatedAdrs) {
|
|
208
|
+
docs.push({
|
|
209
|
+
type: 'adr',
|
|
210
|
+
path: path.join(adrDir, adr),
|
|
211
|
+
title: adr.replace('.md', '').replace(/-/g, ' ')
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch { }
|
|
216
|
+
// Check for HLD
|
|
217
|
+
const hlds = await fs.readdir(archDir);
|
|
218
|
+
const relatedHlds = hlds.filter(file => file.includes('hld') && file.includes(specId.replace('spec-', '')));
|
|
219
|
+
for (const hld of relatedHlds) {
|
|
220
|
+
docs.push({
|
|
221
|
+
type: 'hld',
|
|
222
|
+
path: path.join(archDir, hld),
|
|
223
|
+
title: hld.replace('.md', '').replace(/-/g, ' ')
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
catch { }
|
|
228
|
+
return docs;
|
|
229
|
+
}
|
|
230
|
+
function buildSourceLinks(incrementId, owner, repo) {
|
|
231
|
+
if (!incrementId)
|
|
232
|
+
return undefined;
|
|
233
|
+
const baseUrl = `https://github.com/${owner}/${repo}/blob/develop/.specweave`;
|
|
234
|
+
return {
|
|
235
|
+
spec: `${baseUrl}/docs/internal/specs/default/spec-${incrementId.replace(/^\d+-/, '')}.md`,
|
|
236
|
+
plan: `${baseUrl}/increments/${incrementId}/plan.md`,
|
|
237
|
+
tasks: `${baseUrl}/increments/${incrementId}/tasks.md`
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
async function findExistingIssue(client, specId) {
|
|
241
|
+
try {
|
|
242
|
+
const issues = await client.listIssuesInTimeRange('ALL');
|
|
243
|
+
return issues.find((issue) => issue.title.includes(`[${specId}]`) && issue.labels?.some((l) => l.name === 'spec')) || null;
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=enhanced-github-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enhanced-github-sync.js","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/enhanced-github-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Epic Content Builder - Hierarchical GitHub issue content for Feature Specs
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* - Reads FS-* folder (FEATURE.md + us-*.md files)
|
|
6
|
+
* - Reads increment tasks.md files to map tasks to user stories
|
|
7
|
+
* - Generates hierarchical issue body:
|
|
8
|
+
* 1. User Stories section (with status + increment)
|
|
9
|
+
* 2. Tasks section (grouped by User Story)
|
|
10
|
+
*
|
|
11
|
+
* Key Features:
|
|
12
|
+
* - NO single "Increment" field (epics span multiple increments)
|
|
13
|
+
* - User Stories are checkable with status and increment link
|
|
14
|
+
* - Tasks grouped under their User Story
|
|
15
|
+
* - Shows which increment each US/task belongs to
|
|
16
|
+
*/
|
|
17
|
+
export declare class EpicContentBuilder {
|
|
18
|
+
private epicFolder;
|
|
19
|
+
private projectRoot;
|
|
20
|
+
constructor(epicFolder: string, projectRoot: string);
|
|
21
|
+
/**
|
|
22
|
+
* Build hierarchical GitHub issue body
|
|
23
|
+
*
|
|
24
|
+
* Format:
|
|
25
|
+
* - Epic overview
|
|
26
|
+
* - User Stories section (checkable, with status + increment)
|
|
27
|
+
* - Tasks section (grouped by User Story)
|
|
28
|
+
*/
|
|
29
|
+
buildIssueBody(): Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* Read Epic FEATURE.md frontmatter
|
|
32
|
+
*/
|
|
33
|
+
private readEpicMetadata;
|
|
34
|
+
/**
|
|
35
|
+
* Read all user stories from us-*.md files
|
|
36
|
+
*/
|
|
37
|
+
private readUserStories;
|
|
38
|
+
/**
|
|
39
|
+
* Extract tasks for a user story from its Implementation section
|
|
40
|
+
*/
|
|
41
|
+
private extractTasksForUserStory;
|
|
42
|
+
/**
|
|
43
|
+
* Build overview section
|
|
44
|
+
*/
|
|
45
|
+
private buildOverviewSection;
|
|
46
|
+
/**
|
|
47
|
+
* Build User Stories section
|
|
48
|
+
*/
|
|
49
|
+
private buildUserStoriesSection;
|
|
50
|
+
/**
|
|
51
|
+
* Build Tasks section (grouped by User Story)
|
|
52
|
+
*/
|
|
53
|
+
private buildTasksSection;
|
|
54
|
+
/**
|
|
55
|
+
* Normalize status values
|
|
56
|
+
*/
|
|
57
|
+
private normalizeStatus;
|
|
58
|
+
/**
|
|
59
|
+
* Get status emoji
|
|
60
|
+
*/
|
|
61
|
+
private getStatusEmoji;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=epic-content-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"epic-content-builder.d.ts","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/epic-content-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAuCH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;gBAEhB,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAKnD;;;;;;;OAOG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAgBvC;;OAEG;YACW,gBAAgB;IAY9B;;OAEG;YACW,eAAe;IA0C7B;;OAEG;YACW,wBAAwB;IAoEtC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAoB/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiCzB;;OAEG;IACH,OAAO,CAAC,eAAe;IAUvB;;OAEG;IACH,OAAO,CAAC,cAAc;CAgBvB"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Epic Content Builder - Hierarchical GitHub issue content for Feature Specs
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* - Reads FS-* folder (FEATURE.md + us-*.md files)
|
|
6
|
+
* - Reads increment tasks.md files to map tasks to user stories
|
|
7
|
+
* - Generates hierarchical issue body:
|
|
8
|
+
* 1. User Stories section (with status + increment)
|
|
9
|
+
* 2. Tasks section (grouped by User Story)
|
|
10
|
+
*
|
|
11
|
+
* Key Features:
|
|
12
|
+
* - NO single "Increment" field (epics span multiple increments)
|
|
13
|
+
* - User Stories are checkable with status and increment link
|
|
14
|
+
* - Tasks grouped under their User Story
|
|
15
|
+
* - Shows which increment each US/task belongs to
|
|
16
|
+
*/
|
|
17
|
+
import { readdir, readFile } from 'fs/promises';
|
|
18
|
+
import { existsSync } from 'fs';
|
|
19
|
+
import * as path from 'path';
|
|
20
|
+
import * as yaml from 'yaml';
|
|
21
|
+
export class EpicContentBuilder {
|
|
22
|
+
constructor(epicFolder, projectRoot) {
|
|
23
|
+
this.epicFolder = epicFolder;
|
|
24
|
+
this.projectRoot = projectRoot;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build hierarchical GitHub issue body
|
|
28
|
+
*
|
|
29
|
+
* Format:
|
|
30
|
+
* - Epic overview
|
|
31
|
+
* - User Stories section (checkable, with status + increment)
|
|
32
|
+
* - Tasks section (grouped by User Story)
|
|
33
|
+
*/
|
|
34
|
+
async buildIssueBody() {
|
|
35
|
+
// 1. Read Epic metadata
|
|
36
|
+
const epicData = await this.readEpicMetadata();
|
|
37
|
+
// 2. Read User Stories
|
|
38
|
+
const userStories = await this.readUserStories();
|
|
39
|
+
// 3. Build sections
|
|
40
|
+
const overview = this.buildOverviewSection(epicData);
|
|
41
|
+
const userStoriesSection = this.buildUserStoriesSection(userStories);
|
|
42
|
+
const tasksSection = this.buildTasksSection(userStories);
|
|
43
|
+
// 4. Combine
|
|
44
|
+
return `${overview}\n\n---\n\n${userStoriesSection}\n\n---\n\n${tasksSection}\n\n---\n\n🤖 Auto-created by SpecWeave Epic Sync`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Read Epic FEATURE.md frontmatter
|
|
48
|
+
*/
|
|
49
|
+
async readEpicMetadata() {
|
|
50
|
+
const featurePath = path.join(this.epicFolder, 'FEATURE.md');
|
|
51
|
+
const content = await readFile(featurePath, 'utf-8');
|
|
52
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
53
|
+
if (!match) {
|
|
54
|
+
throw new Error('FEATURE.md missing YAML frontmatter');
|
|
55
|
+
}
|
|
56
|
+
return yaml.parse(match[1]);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Read all user stories from us-*.md files
|
|
60
|
+
*/
|
|
61
|
+
async readUserStories() {
|
|
62
|
+
const files = await readdir(this.epicFolder);
|
|
63
|
+
const usFiles = files.filter((f) => f.startsWith('us-') && f.endsWith('.md'));
|
|
64
|
+
const userStories = [];
|
|
65
|
+
for (const file of usFiles.sort()) {
|
|
66
|
+
const filePath = path.join(this.epicFolder, file);
|
|
67
|
+
const content = await readFile(filePath, 'utf-8');
|
|
68
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
69
|
+
if (!match) {
|
|
70
|
+
console.warn(` ⚠️ ${file} missing frontmatter, skipping`);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const frontmatter = yaml.parse(match[1]);
|
|
74
|
+
const bodyContent = content.slice(match[0].length).trim();
|
|
75
|
+
// Extract increment from Implementation section
|
|
76
|
+
const incrementMatch = bodyContent.match(/\*\*Increment\*\*:\s*\[([^\]]+)\]/);
|
|
77
|
+
const increment = incrementMatch ? incrementMatch[1] : null;
|
|
78
|
+
// Extract tasks from Implementation section
|
|
79
|
+
const tasks = await this.extractTasksForUserStory(frontmatter.id, increment, bodyContent);
|
|
80
|
+
userStories.push({
|
|
81
|
+
id: frontmatter.id,
|
|
82
|
+
title: frontmatter.title,
|
|
83
|
+
status: this.normalizeStatus(frontmatter.status),
|
|
84
|
+
increment,
|
|
85
|
+
tasks,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return userStories;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Extract tasks for a user story from its Implementation section
|
|
92
|
+
*/
|
|
93
|
+
async extractTasksForUserStory(userStoryId, incrementId, content) {
|
|
94
|
+
if (!incrementId) {
|
|
95
|
+
return []; // No increment yet, no tasks
|
|
96
|
+
}
|
|
97
|
+
// Find increment folder
|
|
98
|
+
const incrementFolder = path.join(this.projectRoot, '.specweave', 'increments', incrementId);
|
|
99
|
+
if (!existsSync(incrementFolder)) {
|
|
100
|
+
console.warn(` ⚠️ Increment folder not found: ${incrementId}`);
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
const tasksPath = path.join(incrementFolder, 'tasks.md');
|
|
104
|
+
if (!existsSync(tasksPath)) {
|
|
105
|
+
console.warn(` ⚠️ tasks.md not found in ${incrementId}`);
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
// Read tasks.md
|
|
109
|
+
const tasksContent = await readFile(tasksPath, 'utf-8');
|
|
110
|
+
// Extract task links from user story's Implementation section
|
|
111
|
+
// Format: - [T-001: Title](link#t-001-title)
|
|
112
|
+
const taskLinkPattern = /- \[([T-\d]+):\s*([^\]]+)\]/g;
|
|
113
|
+
const taskLinks = [];
|
|
114
|
+
let match;
|
|
115
|
+
while ((match = taskLinkPattern.exec(content)) !== null) {
|
|
116
|
+
taskLinks.push({
|
|
117
|
+
id: match[1], // e.g., "T-001"
|
|
118
|
+
title: match[2].trim(),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
// Parse tasks from tasks.md to get completion status
|
|
122
|
+
const tasks = [];
|
|
123
|
+
for (const taskLink of taskLinks) {
|
|
124
|
+
// Find task in tasks.md by heading pattern: ### T-001: Title
|
|
125
|
+
const taskPattern = new RegExp(`###\\s+${taskLink.id}:\\s*([^\\n]+)[\\s\\S]*?\\*\\*Status\\*\\*:\\s*\\[([x\\s])\\]`, 'i');
|
|
126
|
+
const taskMatch = tasksContent.match(taskPattern);
|
|
127
|
+
const isCompleted = taskMatch ? taskMatch[2] === 'x' : false;
|
|
128
|
+
tasks.push({
|
|
129
|
+
id: taskLink.id,
|
|
130
|
+
title: taskLink.title,
|
|
131
|
+
status: isCompleted,
|
|
132
|
+
userStoryId,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return tasks;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Build overview section
|
|
139
|
+
*/
|
|
140
|
+
buildOverviewSection(epic) {
|
|
141
|
+
return `# [${epic.id}] ${epic.title}\n\n**Status**: ${epic.status}\n**Created**: ${epic.created}\n**Last Updated**: ${epic.last_updated}`;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Build User Stories section
|
|
145
|
+
*/
|
|
146
|
+
buildUserStoriesSection(userStories) {
|
|
147
|
+
const total = userStories.length;
|
|
148
|
+
const completed = userStories.filter((us) => us.status === 'complete').length;
|
|
149
|
+
const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;
|
|
150
|
+
let section = `## User Stories\n\nProgress: ${completed}/${total} user stories complete (${percentage}%)\n\n`;
|
|
151
|
+
for (const us of userStories) {
|
|
152
|
+
const checkbox = us.status === 'complete' ? '[x]' : '[ ]';
|
|
153
|
+
const statusEmoji = this.getStatusEmoji(us.status);
|
|
154
|
+
const incrementLink = us.increment
|
|
155
|
+
? `[${us.increment}](../../increments/${us.increment}/)`
|
|
156
|
+
: 'TBD';
|
|
157
|
+
section += `- ${checkbox} **${us.id}: ${us.title}** (${statusEmoji} ${us.status} | Increment: ${incrementLink})\n`;
|
|
158
|
+
}
|
|
159
|
+
return section;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Build Tasks section (grouped by User Story)
|
|
163
|
+
*/
|
|
164
|
+
buildTasksSection(userStories) {
|
|
165
|
+
const totalTasks = userStories.reduce((sum, us) => sum + us.tasks.length, 0);
|
|
166
|
+
const completedTasks = userStories.reduce((sum, us) => sum + us.tasks.filter((t) => t.status).length, 0);
|
|
167
|
+
const percentage = totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0;
|
|
168
|
+
let section = `## Tasks by User Story\n\nProgress: ${completedTasks}/${totalTasks} tasks complete (${percentage}%)\n\n`;
|
|
169
|
+
for (const us of userStories) {
|
|
170
|
+
if (us.tasks.length === 0) {
|
|
171
|
+
continue; // Skip user stories with no tasks yet
|
|
172
|
+
}
|
|
173
|
+
const incrementLink = us.increment
|
|
174
|
+
? `[${us.increment}](../../increments/${us.increment}/tasks.md)`
|
|
175
|
+
: 'TBD';
|
|
176
|
+
section += `### ${us.id}: ${us.title} (Increment: ${incrementLink})\n\n`;
|
|
177
|
+
for (const task of us.tasks) {
|
|
178
|
+
const checkbox = task.status ? '[x]' : '[ ]';
|
|
179
|
+
section += `- ${checkbox} ${task.id}: ${task.title}\n`;
|
|
180
|
+
}
|
|
181
|
+
section += '\n';
|
|
182
|
+
}
|
|
183
|
+
return section;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Normalize status values
|
|
187
|
+
*/
|
|
188
|
+
normalizeStatus(status) {
|
|
189
|
+
const normalized = status.toLowerCase();
|
|
190
|
+
if (normalized === 'complete' || normalized === 'completed')
|
|
191
|
+
return 'complete';
|
|
192
|
+
if (normalized === 'active' || normalized === 'in-progress')
|
|
193
|
+
return 'active';
|
|
194
|
+
if (normalized === 'planning')
|
|
195
|
+
return 'planning';
|
|
196
|
+
return 'not-started';
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get status emoji
|
|
200
|
+
*/
|
|
201
|
+
getStatusEmoji(status) {
|
|
202
|
+
switch (status) {
|
|
203
|
+
case 'complete':
|
|
204
|
+
return '✅';
|
|
205
|
+
case 'active':
|
|
206
|
+
return '🚧';
|
|
207
|
+
case 'planning':
|
|
208
|
+
return '📋';
|
|
209
|
+
case 'not-started':
|
|
210
|
+
return '⏳';
|
|
211
|
+
default:
|
|
212
|
+
return '❓';
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=epic-content-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"epic-content-builder.js","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/epic-content-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,7 +31,7 @@ export declare class GitHubClient {
|
|
|
31
31
|
*/
|
|
32
32
|
private getMilestoneByTitle;
|
|
33
33
|
/**
|
|
34
|
-
* Create epic issue (increment-level)
|
|
34
|
+
* Create epic issue (increment-level) with FULL DUPLICATE PROTECTION
|
|
35
35
|
*/
|
|
36
36
|
createEpicIssue(title: string, body: string, milestone?: number | string, labels?: string[]): Promise<GitHubIssue>;
|
|
37
37
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github-client.d.ts","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/github-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"github-client.d.ts","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/github-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGvD,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAS;gBAET,IAAI,CAAC,EAAE,MAAM;IAKzB;;OAEG;IACH,OAAO,CAAC,UAAU;IAalB;;OAEG;IACH,MAAM,CAAC,cAAc,IAAI;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,aAAa,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAevF;;;;;;OAMG;IACG,oBAAoB,CACxB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,WAAW,GAAE,MAAU,GACtB,OAAO,CAAC,eAAe,CAAC;IAuB3B;;OAEG;YACW,mBAAmB;IAUjC;;OAEG;IACG,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAC3B,MAAM,GAAE,MAAM,EAAO,GACpB,OAAO,CAAC,WAAW,CAAC;IA0CvB;;OAEG;IACG,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAC3B,MAAM,GAAE,MAAM,EAAO,GACpB,OAAO,CAAC,WAAW,CAAC;IAmCvB;;OAEG;IACG,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU1E;;OAEG;IACG,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAezD;;OAEG;IACG,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IActE;;OAEG;IACG,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrE;;OAEG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAarE;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,IAAI,CAAA;KAAE,CAAC;IAelF;;OAEG;IACH,OAAO,CAAC,YAAY;IAQpB;;OAEG;IACG,iBAAiB,CACrB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,EACjE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAC3B,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GACrD,OAAO,CAAC,WAAW,EAAE,CAAC;IA+BzB,OAAO,CAAC,KAAK;IAIb;;;;OAIG;WACU,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,GAAE,MAAY,GAAG,OAAO,CAAC,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;CAsBnI"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Uses `gh` command for GitHub API operations
|
|
4
4
|
*/
|
|
5
5
|
import { execSync } from 'child_process';
|
|
6
|
+
import { DuplicateDetector } from './duplicate-detector.js';
|
|
6
7
|
export class GitHubClient {
|
|
7
8
|
constructor(repo) {
|
|
8
9
|
// Auto-detect repo from git remote if not provided
|
|
@@ -83,24 +84,35 @@ export class GitHubClient {
|
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
/**
|
|
86
|
-
* Create epic issue (increment-level)
|
|
87
|
+
* Create epic issue (increment-level) with FULL DUPLICATE PROTECTION
|
|
87
88
|
*/
|
|
88
89
|
async createEpicIssue(title, body, milestone, labels = []) {
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
// Extract title pattern for duplicate detection (e.g., "[FS-031]" from "[FS-031] Feature Title")
|
|
91
|
+
const titlePattern = DuplicateDetector.extractTitlePattern(title);
|
|
92
|
+
if (!titlePattern) {
|
|
93
|
+
throw new Error(`Epic issue title must start with pattern like [FS-XXX] or [INC-XXXX]: ${title}`);
|
|
94
|
+
}
|
|
93
95
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
// Use DuplicateDetector for full 3-phase protection
|
|
97
|
+
const result = await DuplicateDetector.createWithProtection({
|
|
98
|
+
title,
|
|
99
|
+
body,
|
|
100
|
+
titlePattern,
|
|
101
|
+
labels: labels.length > 0 ? labels : ['specweave', 'increment'],
|
|
102
|
+
milestone: milestone?.toString(),
|
|
103
|
+
repo: this.repo
|
|
104
|
+
});
|
|
105
|
+
// Fetch full issue details (DuplicateDetector returns minimal info)
|
|
106
|
+
const viewCmd = `gh issue view ${result.issue.number} --repo ${this.repo} --json number,title,body,state,url,labels,milestone`;
|
|
102
107
|
const output = execSync(viewCmd, { encoding: 'utf-8' });
|
|
103
108
|
const issue = JSON.parse(output);
|
|
109
|
+
// Log duplicate detection results if any
|
|
110
|
+
if (result.wasReused) {
|
|
111
|
+
console.log(` ♻️ Reused existing issue #${result.issue.number} (duplicate prevention)`);
|
|
112
|
+
}
|
|
113
|
+
if (result.duplicatesFound > 0) {
|
|
114
|
+
console.log(` 🛡️ Duplicates detected: ${result.duplicatesFound} (auto-closed: ${result.duplicatesClosed})`);
|
|
115
|
+
}
|
|
104
116
|
return {
|
|
105
117
|
...issue,
|
|
106
118
|
html_url: issue.url,
|