specweave 0.17.16 → 0.18.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.
Files changed (161) hide show
  1. package/CLAUDE.md +405 -2495
  2. package/README.md +92 -2
  3. package/dist/plugins/specweave/lib/hooks/sync-living-docs.d.ts.map +1 -1
  4. package/dist/plugins/specweave/lib/hooks/sync-living-docs.js +188 -36
  5. package/dist/plugins/specweave/lib/hooks/sync-living-docs.js.map +1 -1
  6. package/dist/plugins/specweave-ado/lib/ado-status-sync.d.ts +54 -0
  7. package/dist/plugins/specweave-ado/lib/ado-status-sync.d.ts.map +1 -0
  8. package/dist/plugins/specweave-ado/lib/ado-status-sync.js +86 -0
  9. package/dist/plugins/specweave-ado/lib/ado-status-sync.js.map +1 -0
  10. package/dist/plugins/specweave-github/lib/duplicate-detector.d.ts +139 -0
  11. package/dist/plugins/specweave-github/lib/duplicate-detector.d.ts.map +1 -0
  12. package/dist/plugins/specweave-github/lib/duplicate-detector.js +389 -0
  13. package/dist/plugins/specweave-github/lib/duplicate-detector.js.map +1 -0
  14. package/dist/plugins/specweave-github/lib/enhanced-github-sync.d.ts +26 -0
  15. package/dist/plugins/specweave-github/lib/enhanced-github-sync.d.ts.map +1 -0
  16. package/dist/plugins/specweave-github/lib/enhanced-github-sync.js +249 -0
  17. package/dist/plugins/specweave-github/lib/enhanced-github-sync.js.map +1 -0
  18. package/dist/plugins/specweave-github/lib/github-client.d.ts +1 -1
  19. package/dist/plugins/specweave-github/lib/github-client.d.ts.map +1 -1
  20. package/dist/plugins/specweave-github/lib/github-client.js +25 -13
  21. package/dist/plugins/specweave-github/lib/github-client.js.map +1 -1
  22. package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts +83 -0
  23. package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts.map +1 -0
  24. package/dist/plugins/specweave-github/lib/github-epic-sync.js +451 -0
  25. package/dist/plugins/specweave-github/lib/github-epic-sync.js.map +1 -0
  26. package/dist/plugins/specweave-github/lib/github-status-sync.d.ts +43 -0
  27. package/dist/plugins/specweave-github/lib/github-status-sync.d.ts.map +1 -0
  28. package/dist/plugins/specweave-github/lib/github-status-sync.js +82 -0
  29. package/dist/plugins/specweave-github/lib/github-status-sync.js.map +1 -0
  30. package/dist/plugins/specweave-github/lib/task-sync.d.ts +5 -0
  31. package/dist/plugins/specweave-github/lib/task-sync.d.ts.map +1 -1
  32. package/dist/plugins/specweave-github/lib/task-sync.js +38 -2
  33. package/dist/plugins/specweave-github/lib/task-sync.js.map +1 -1
  34. package/dist/plugins/specweave-jira/lib/jira-epic-sync.d.ts +66 -0
  35. package/dist/plugins/specweave-jira/lib/jira-epic-sync.d.ts.map +1 -0
  36. package/dist/plugins/specweave-jira/lib/jira-epic-sync.js +274 -0
  37. package/dist/plugins/specweave-jira/lib/jira-epic-sync.js.map +1 -0
  38. package/dist/plugins/specweave-jira/lib/jira-status-sync.d.ts +56 -0
  39. package/dist/plugins/specweave-jira/lib/jira-status-sync.d.ts.map +1 -0
  40. package/dist/plugins/specweave-jira/lib/jira-status-sync.js +93 -0
  41. package/dist/plugins/specweave-jira/lib/jira-status-sync.js.map +1 -0
  42. package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
  43. package/dist/src/cli/helpers/issue-tracker/index.js +48 -3
  44. package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
  45. package/dist/src/core/living-docs/hierarchy-mapper.d.ts +142 -0
  46. package/dist/src/core/living-docs/hierarchy-mapper.d.ts.map +1 -0
  47. package/dist/src/core/living-docs/hierarchy-mapper.js +453 -0
  48. package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -0
  49. package/dist/src/core/living-docs/index.d.ts +10 -84
  50. package/dist/src/core/living-docs/index.d.ts.map +1 -1
  51. package/dist/src/core/living-docs/index.js +10 -164
  52. package/dist/src/core/living-docs/index.js.map +1 -1
  53. package/dist/src/core/living-docs/spec-distributor.d.ts +106 -0
  54. package/dist/src/core/living-docs/spec-distributor.d.ts.map +1 -0
  55. package/dist/src/core/living-docs/spec-distributor.js +823 -0
  56. package/dist/src/core/living-docs/spec-distributor.js.map +1 -0
  57. package/dist/src/core/living-docs/types.d.ts +201 -0
  58. package/dist/src/core/living-docs/types.d.ts.map +1 -0
  59. package/dist/src/core/living-docs/types.js +15 -0
  60. package/dist/src/core/living-docs/types.js.map +1 -0
  61. package/dist/src/core/logging/prompt-logger.d.ts +70 -0
  62. package/dist/src/core/logging/prompt-logger.d.ts.map +1 -0
  63. package/dist/src/core/logging/prompt-logger.js +247 -0
  64. package/dist/src/core/logging/prompt-logger.js.map +1 -0
  65. package/dist/src/core/status-line/status-line-manager.d.ts +15 -24
  66. package/dist/src/core/status-line/status-line-manager.d.ts.map +1 -1
  67. package/dist/src/core/status-line/status-line-manager.js +33 -70
  68. package/dist/src/core/status-line/status-line-manager.js.map +1 -1
  69. package/dist/src/core/status-line/types.d.ts +19 -31
  70. package/dist/src/core/status-line/types.d.ts.map +1 -1
  71. package/dist/src/core/status-line/types.js +5 -9
  72. package/dist/src/core/status-line/types.js.map +1 -1
  73. package/dist/src/core/sync/conflict-resolver.d.ts +66 -0
  74. package/dist/src/core/sync/conflict-resolver.d.ts.map +1 -0
  75. package/dist/src/core/sync/conflict-resolver.js +108 -0
  76. package/dist/src/core/sync/conflict-resolver.js.map +1 -0
  77. package/dist/src/core/sync/enhanced-content-builder.d.ts +77 -0
  78. package/dist/src/core/sync/enhanced-content-builder.d.ts.map +1 -0
  79. package/dist/src/core/sync/enhanced-content-builder.js +199 -0
  80. package/dist/src/core/sync/enhanced-content-builder.js.map +1 -0
  81. package/dist/src/core/sync/label-detector.d.ts +66 -0
  82. package/dist/src/core/sync/label-detector.d.ts.map +1 -0
  83. package/dist/src/core/sync/label-detector.js +211 -0
  84. package/dist/src/core/sync/label-detector.js.map +1 -0
  85. package/dist/src/core/sync/retry-logic.d.ts +64 -0
  86. package/dist/src/core/sync/retry-logic.d.ts.map +1 -0
  87. package/dist/src/core/sync/retry-logic.js +165 -0
  88. package/dist/src/core/sync/retry-logic.js.map +1 -0
  89. package/dist/src/core/sync/spec-increment-mapper.d.ts +100 -0
  90. package/dist/src/core/sync/spec-increment-mapper.d.ts.map +1 -0
  91. package/dist/src/core/sync/spec-increment-mapper.js +424 -0
  92. package/dist/src/core/sync/spec-increment-mapper.js.map +1 -0
  93. package/dist/src/core/sync/status-cache.d.ts +91 -0
  94. package/dist/src/core/sync/status-cache.d.ts.map +1 -0
  95. package/dist/src/core/sync/status-cache.js +140 -0
  96. package/dist/src/core/sync/status-cache.js.map +1 -0
  97. package/dist/src/core/sync/status-mapper.d.ts +69 -0
  98. package/dist/src/core/sync/status-mapper.d.ts.map +1 -0
  99. package/dist/src/core/sync/status-mapper.js +90 -0
  100. package/dist/src/core/sync/status-mapper.js.map +1 -0
  101. package/dist/src/core/sync/status-sync-engine.d.ts +162 -0
  102. package/dist/src/core/sync/status-sync-engine.d.ts.map +1 -0
  103. package/dist/src/core/sync/status-sync-engine.js +347 -0
  104. package/dist/src/core/sync/status-sync-engine.js.map +1 -0
  105. package/dist/src/core/sync/sync-event-logger.d.ts +99 -0
  106. package/dist/src/core/sync/sync-event-logger.d.ts.map +1 -0
  107. package/dist/src/core/sync/sync-event-logger.js +103 -0
  108. package/dist/src/core/sync/sync-event-logger.js.map +1 -0
  109. package/dist/src/core/sync/workflow-detector.d.ts +95 -0
  110. package/dist/src/core/sync/workflow-detector.d.ts.map +1 -0
  111. package/dist/src/core/sync/workflow-detector.js +175 -0
  112. package/dist/src/core/sync/workflow-detector.js.map +1 -0
  113. package/dist/src/core/types/config.d.ts.map +1 -1
  114. package/dist/src/core/types/config.js +31 -0
  115. package/dist/src/core/types/config.js.map +1 -1
  116. package/dist/src/utils/github-url.d.ts +53 -0
  117. package/dist/src/utils/github-url.d.ts.map +1 -0
  118. package/dist/src/utils/github-url.js +90 -0
  119. package/dist/src/utils/github-url.js.map +1 -0
  120. package/dist/src/utils/spec-parser.d.ts +145 -0
  121. package/dist/src/utils/spec-parser.d.ts.map +1 -0
  122. package/dist/src/utils/spec-parser.js +640 -0
  123. package/dist/src/utils/spec-parser.js.map +1 -0
  124. package/package.json +1 -1
  125. package/plugins/specweave/agents/pm/AGENT.md +1 -1
  126. package/plugins/specweave/agents/pm/templates/increment-spec.md +158 -0
  127. package/plugins/specweave/agents/pm/templates/living-docs-spec.md +113 -0
  128. package/plugins/specweave/commands/specweave-done.md +163 -0
  129. package/plugins/specweave/hooks/lib/update-status-line.sh +79 -111
  130. package/plugins/specweave/hooks/post-increment-planning.sh +107 -35
  131. package/plugins/specweave/lib/hooks/sync-living-docs.js +139 -34
  132. package/plugins/specweave/lib/hooks/sync-living-docs.ts +234 -38
  133. package/plugins/specweave/skills/SKILLS-INDEX.md +4 -24
  134. package/plugins/specweave/skills/increment-planner/SKILL.md +94 -0
  135. package/plugins/specweave/skills/increment-work-router/SKILL.md +466 -0
  136. package/plugins/specweave-ado/lib/ado-status-sync.js +80 -0
  137. package/plugins/specweave-ado/lib/ado-status-sync.ts +121 -0
  138. package/plugins/specweave-github/commands/specweave-github-cleanup-duplicates.md +205 -0
  139. package/plugins/specweave-github/commands/specweave-github-sync-epic.md +248 -0
  140. package/plugins/specweave-github/lib/duplicate-detector.js +370 -0
  141. package/plugins/specweave-github/lib/duplicate-detector.ts +525 -0
  142. package/plugins/specweave-github/lib/enhanced-github-sync.js +220 -0
  143. package/plugins/specweave-github/lib/enhanced-github-sync.ts +322 -0
  144. package/plugins/specweave-github/lib/github-client.js +21 -10
  145. package/plugins/specweave-github/lib/github-client.ts +27 -16
  146. package/plugins/specweave-github/lib/github-epic-sync.js +489 -0
  147. package/plugins/specweave-github/lib/github-epic-sync.ts +690 -0
  148. package/plugins/specweave-github/lib/github-status-sync.js +71 -0
  149. package/plugins/specweave-github/lib/github-status-sync.ts +107 -0
  150. package/plugins/specweave-github/lib/task-sync.js +33 -2
  151. package/plugins/specweave-github/lib/task-sync.ts +44 -2
  152. package/plugins/specweave-jira/commands/specweave-jira-sync-epic.md +267 -0
  153. package/plugins/specweave-jira/lib/enhanced-jira-sync.ts.disabled +222 -0
  154. package/plugins/specweave-jira/lib/jira-epic-sync.js +304 -0
  155. package/plugins/specweave-jira/lib/jira-epic-sync.ts +459 -0
  156. package/plugins/specweave-jira/lib/jira-status-sync.js +79 -0
  157. package/plugins/specweave-jira/lib/jira-status-sync.ts +139 -0
  158. package/src/templates/AGENTS.md.template +88 -1
  159. package/src/templates/CLAUDE.md.template +49 -0
  160. package/plugins/specweave/skills/increment-quality-judge/SKILL.md +0 -524
  161. package/plugins/specweave/skills/plugin-installer/SKILL.md +0 -353
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-cache.js","sourceRoot":"","sources":["../../../../src/core/sync/status-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Status Mapper
3
+ *
4
+ * Maps SpecWeave increment statuses to tool-specific statuses for
5
+ * GitHub, JIRA, and Azure DevOps.
6
+ *
7
+ * Supports both simple string mappings and complex mappings with
8
+ * labels/tags for more granular status representation.
9
+ */
10
+ export type ExternalTool = 'github' | 'jira' | 'ado';
11
+ export type SpecWeaveStatus = 'planning' | 'active' | 'paused' | 'completed' | 'abandoned';
12
+ export interface StatusMappingConfig {
13
+ state: string;
14
+ labels?: string[];
15
+ tags?: string[];
16
+ }
17
+ export type StatusMappingValue = string | StatusMappingConfig;
18
+ export interface ToolStatusMappings {
19
+ planning: StatusMappingValue;
20
+ active: StatusMappingValue;
21
+ paused: StatusMappingValue;
22
+ completed: StatusMappingValue;
23
+ abandoned: StatusMappingValue;
24
+ }
25
+ export interface StatusSyncConfig {
26
+ enabled: boolean;
27
+ autoSync?: boolean;
28
+ promptUser?: boolean;
29
+ conflictResolution?: 'prompt' | 'last-write-wins' | 'specweave-wins' | 'external-wins';
30
+ mappings: {
31
+ github?: ToolStatusMappings;
32
+ jira?: ToolStatusMappings;
33
+ ado?: ToolStatusMappings;
34
+ };
35
+ }
36
+ export interface ValidationResult {
37
+ valid: boolean;
38
+ errors: string[];
39
+ }
40
+ export interface SyncConfig {
41
+ sync: {
42
+ statusSync: StatusSyncConfig;
43
+ };
44
+ }
45
+ export declare class StatusMapper {
46
+ private config;
47
+ constructor(config: SyncConfig);
48
+ /**
49
+ * Map SpecWeave status to external tool status
50
+ */
51
+ mapToExternal(specweaveStatus: string, tool: ExternalTool): StatusMappingConfig;
52
+ /**
53
+ * Map external tool status to SpecWeave status (reverse lookup)
54
+ */
55
+ mapFromExternal(externalStatus: string, tool: ExternalTool): SpecWeaveStatus | null;
56
+ /**
57
+ * Validate status mapping configuration
58
+ */
59
+ validate(): ValidationResult;
60
+ /**
61
+ * Get all required SpecWeave statuses
62
+ */
63
+ getRequiredStatuses(): SpecWeaveStatus[];
64
+ /**
65
+ * Get all supported external tools
66
+ */
67
+ getSupportedTools(): ExternalTool[];
68
+ }
69
+ //# sourceMappingURL=status-mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-mapper.d.ts","sourceRoot":"","sources":["../../../../src/core/sync/status-mapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;AAErD,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC;AAE3F,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,mBAAmB,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,SAAS,EAAE,kBAAkB,CAAC;IAC9B,SAAS,EAAE,kBAAkB,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kBAAkB,CAAC,EAAE,QAAQ,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,eAAe,CAAC;IACvF,QAAQ,EAAE;QACR,MAAM,CAAC,EAAE,kBAAkB,CAAC;QAC5B,IAAI,CAAC,EAAE,kBAAkB,CAAC;QAC1B,GAAG,CAAC,EAAE,kBAAkB,CAAC;KAC1B,CAAC;CACH;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE;QACJ,UAAU,EAAE,gBAAgB,CAAC;KAC9B,CAAC;CACH;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAa;gBAEf,MAAM,EAAE,UAAU;IAI9B;;OAEG;IACI,aAAa,CAClB,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE,YAAY,GACjB,mBAAmB;IAqBtB;;OAEG;IACI,eAAe,CACpB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,YAAY,GACjB,eAAe,GAAG,IAAI;IAkBzB;;OAEG;IACI,QAAQ,IAAI,gBAAgB;IA+BnC;;OAEG;IACI,mBAAmB,IAAI,eAAe,EAAE;IAI/C;;OAEG;IACI,iBAAiB,IAAI,YAAY,EAAE;CAG3C"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Status Mapper
3
+ *
4
+ * Maps SpecWeave increment statuses to tool-specific statuses for
5
+ * GitHub, JIRA, and Azure DevOps.
6
+ *
7
+ * Supports both simple string mappings and complex mappings with
8
+ * labels/tags for more granular status representation.
9
+ */
10
+ export class StatusMapper {
11
+ constructor(config) {
12
+ this.config = config;
13
+ }
14
+ /**
15
+ * Map SpecWeave status to external tool status
16
+ */
17
+ mapToExternal(specweaveStatus, tool) {
18
+ const mappings = this.config.sync.statusSync.mappings[tool];
19
+ if (!mappings) {
20
+ throw new Error(`No status mappings configured for ${tool}`);
21
+ }
22
+ const mapping = mappings[specweaveStatus];
23
+ if (!mapping) {
24
+ throw new Error(`No mapping for status "${specweaveStatus}" in ${tool}`);
25
+ }
26
+ // Normalize to StatusMappingConfig
27
+ if (typeof mapping === 'string') {
28
+ return { state: mapping };
29
+ }
30
+ return mapping;
31
+ }
32
+ /**
33
+ * Map external tool status to SpecWeave status (reverse lookup)
34
+ */
35
+ mapFromExternal(externalStatus, tool) {
36
+ const mappings = this.config.sync.statusSync.mappings[tool];
37
+ if (!mappings) {
38
+ return null;
39
+ }
40
+ for (const [specweaveStatus, mapping] of Object.entries(mappings)) {
41
+ const state = typeof mapping === 'string' ? mapping : mapping.state;
42
+ if (state === externalStatus) {
43
+ return specweaveStatus;
44
+ }
45
+ }
46
+ return null; // Unknown external status
47
+ }
48
+ /**
49
+ * Validate status mapping configuration
50
+ */
51
+ validate() {
52
+ const errors = [];
53
+ const requiredStatuses = [
54
+ 'planning',
55
+ 'active',
56
+ 'paused',
57
+ 'completed',
58
+ 'abandoned'
59
+ ];
60
+ for (const tool of ['github', 'jira', 'ado']) {
61
+ const mappings = this.config.sync.statusSync.mappings[tool];
62
+ if (!mappings) {
63
+ errors.push(`No mappings configured for ${tool}`);
64
+ continue;
65
+ }
66
+ for (const status of requiredStatuses) {
67
+ if (!mappings[status]) {
68
+ errors.push(`Missing mapping for "${status}" in ${tool}`);
69
+ }
70
+ }
71
+ }
72
+ return {
73
+ valid: errors.length === 0,
74
+ errors
75
+ };
76
+ }
77
+ /**
78
+ * Get all required SpecWeave statuses
79
+ */
80
+ getRequiredStatuses() {
81
+ return ['planning', 'active', 'paused', 'completed', 'abandoned'];
82
+ }
83
+ /**
84
+ * Get all supported external tools
85
+ */
86
+ getSupportedTools() {
87
+ return ['github', 'jira', 'ado'];
88
+ }
89
+ }
90
+ //# sourceMappingURL=status-mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-mapper.js","sourceRoot":"","sources":["../../../../src/core/sync/status-mapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6CH,MAAM,OAAO,YAAY;IAGvB,YAAY,MAAkB;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;OAEG;IACI,aAAa,CAClB,eAAuB,EACvB,IAAkB;QAElB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE5D,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,qCAAqC,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,OAAO,GAAG,QAAQ,CAAC,eAAkC,CAAC,CAAC;QAE7D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,0BAA0B,eAAe,QAAQ,IAAI,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,mCAAmC;QACnC,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAC5B,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACI,eAAe,CACpB,cAAsB,EACtB,IAAkB;QAElB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE5D,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,MAAM,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClE,MAAM,KAAK,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;YAEpE,IAAI,KAAK,KAAK,cAAc,EAAE,CAAC;gBAC7B,OAAO,eAAkC,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,CAAC,0BAA0B;IACzC,CAAC;IAED;;OAEG;IACI,QAAQ;QACb,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,gBAAgB,GAAsB;YAC1C,UAAU;YACV,QAAQ;YACR,QAAQ;YACR,WAAW;YACX,WAAW;SACZ,CAAC;QAEF,KAAK,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAU,EAAE,CAAC;YACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAE5D,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,CAAC,IAAI,CAAC,8BAA8B,IAAI,EAAE,CAAC,CAAC;gBAClD,SAAS;YACX,CAAC;YAED,KAAK,MAAM,MAAM,IAAI,gBAAgB,EAAE,CAAC;gBACtC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;oBACtB,MAAM,CAAC,IAAI,CAAC,wBAAwB,MAAM,QAAQ,IAAI,EAAE,CAAC,CAAC;gBAC5D,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO;YACL,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;YAC1B,MAAM;SACP,CAAC;IACJ,CAAC;IAED;;OAEG;IACI,mBAAmB;QACxB,OAAO,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IACpE,CAAC;IAED;;OAEG;IACI,iBAAiB;QACtB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Status Sync Engine
3
+ *
4
+ * Core orchestration logic for status synchronization between SpecWeave
5
+ * increments and external tools (GitHub, JIRA, Azure DevOps).
6
+ *
7
+ * Responsibilities:
8
+ * - Orchestrate bidirectional status sync
9
+ * - Detect and resolve conflicts
10
+ * - Map statuses between SpecWeave and external tools
11
+ * - Respect user preferences (autoSync, promptUser, conflictResolution)
12
+ */
13
+ import { StatusMappingConfig, ExternalTool, SpecWeaveStatus } from './status-mapper';
14
+ import { StatusConflict, ConflictResolution, ConflictResolutionStrategy } from './conflict-resolver';
15
+ export type SyncDirection = 'to-external' | 'from-external' | 'bidirectional';
16
+ export type SyncAction = 'no-sync-needed' | 'sync-to-external' | 'sync-from-external';
17
+ export interface SyncInput {
18
+ incrementId: string;
19
+ tool: ExternalTool;
20
+ localStatus: SpecWeaveStatus;
21
+ remoteStatus: string;
22
+ localTimestamp: string;
23
+ remoteTimestamp: string;
24
+ }
25
+ export interface SyncResult {
26
+ success: boolean;
27
+ direction: SyncDirection;
28
+ action: SyncAction;
29
+ conflict: StatusConflict | null;
30
+ resolution: ConflictResolution | null;
31
+ externalMapping: StatusMappingConfig | null;
32
+ error?: string;
33
+ wasAutomatic?: boolean;
34
+ wasPrompted?: boolean;
35
+ }
36
+ export interface StatusSyncConfig {
37
+ sync: {
38
+ statusSync: {
39
+ enabled: boolean;
40
+ autoSync?: boolean;
41
+ promptUser?: boolean;
42
+ conflictResolution?: ConflictResolutionStrategy;
43
+ mappings: {
44
+ github?: any;
45
+ jira?: any;
46
+ ado?: any;
47
+ };
48
+ };
49
+ };
50
+ }
51
+ /**
52
+ * Bulk sync input (multiple increments)
53
+ */
54
+ export type BulkSyncInput = SyncInput;
55
+ /**
56
+ * Bulk sync options
57
+ */
58
+ export interface BulkSyncOptions {
59
+ batchSize?: number;
60
+ delayMs?: number;
61
+ }
62
+ /**
63
+ * Individual sync result with increment ID
64
+ */
65
+ export interface BulkSyncItemResult extends SyncResult {
66
+ incrementId: string;
67
+ }
68
+ /**
69
+ * Bulk sync result
70
+ */
71
+ export interface BulkSyncResult {
72
+ totalItems: number;
73
+ successCount: number;
74
+ failureCount: number;
75
+ results: BulkSyncItemResult[];
76
+ duration: string;
77
+ }
78
+ export declare class StatusSyncEngine {
79
+ private mapper;
80
+ private resolver;
81
+ private config;
82
+ constructor(config: StatusSyncConfig);
83
+ /**
84
+ * Sync SpecWeave status to external tool (one-way: SpecWeave → External)
85
+ *
86
+ * @param input - Sync input with local/remote statuses
87
+ * @returns Sync result with conflict resolution details
88
+ */
89
+ syncToExternal(input: SyncInput): Promise<SyncResult>;
90
+ /**
91
+ * Sync external status to SpecWeave (one-way: External → SpecWeave)
92
+ *
93
+ * @param input - Sync input with local/remote statuses
94
+ * @returns Sync result with conflict resolution details
95
+ */
96
+ syncFromExternal(input: SyncInput): Promise<SyncResult>;
97
+ /**
98
+ * Bidirectional sync (SpecWeave ↔ External)
99
+ *
100
+ * Detects conflict and resolves based on strategy.
101
+ * Syncs in the direction indicated by resolution.
102
+ *
103
+ * @param input - Sync input with local/remote statuses
104
+ * @returns Sync result with conflict resolution details
105
+ */
106
+ bidirectionalSync(input: SyncInput): Promise<SyncResult>;
107
+ /**
108
+ * Bulk sync multiple increments to external tools
109
+ *
110
+ * Batches requests to avoid rate limiting.
111
+ * Adds delays between batches.
112
+ * Returns aggregate results with success/failure counts.
113
+ *
114
+ * @param inputs - Array of sync inputs
115
+ * @param options - Bulk sync options (batch size, delay)
116
+ * @returns Bulk sync result
117
+ */
118
+ bulkSyncToExternal(inputs: BulkSyncInput[], options?: BulkSyncOptions): Promise<BulkSyncResult>;
119
+ /**
120
+ * Check if auto-sync is enabled
121
+ *
122
+ * @returns True if auto-sync is enabled
123
+ */
124
+ isAutoSyncEnabled(): boolean;
125
+ /**
126
+ * Check if user should be prompted
127
+ *
128
+ * @returns True if user should be prompted (default: true)
129
+ */
130
+ shouldPromptUser(): boolean;
131
+ /**
132
+ * Execute automatic sync without prompting
133
+ *
134
+ * Validates that auto-sync is enabled.
135
+ * Handles errors gracefully (doesn't throw, returns error in result).
136
+ *
137
+ * @param input - Sync input
138
+ * @returns Sync result with wasAutomatic flag
139
+ */
140
+ executeAutoSync(input: SyncInput): Promise<SyncResult>;
141
+ /**
142
+ * Calculate batches from input array
143
+ *
144
+ * @param inputs - Array of inputs
145
+ * @param batchSize - Size of each batch
146
+ * @returns Array of batches
147
+ */
148
+ private calculateBatches;
149
+ /**
150
+ * Delay execution for specified milliseconds
151
+ *
152
+ * @param ms - Milliseconds to delay
153
+ */
154
+ private delay;
155
+ /**
156
+ * Validate that status synchronization is enabled
157
+ *
158
+ * @throws Error if sync is disabled
159
+ */
160
+ private validateSyncEnabled;
161
+ }
162
+ //# sourceMappingURL=status-sync-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-sync-engine.d.ts","sourceRoot":"","sources":["../../../../src/core/sync/status-sync-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,347 @@
1
+ /**
2
+ * Status Sync Engine
3
+ *
4
+ * Core orchestration logic for status synchronization between SpecWeave
5
+ * increments and external tools (GitHub, JIRA, Azure DevOps).
6
+ *
7
+ * Responsibilities:
8
+ * - Orchestrate bidirectional status sync
9
+ * - Detect and resolve conflicts
10
+ * - Map statuses between SpecWeave and external tools
11
+ * - Respect user preferences (autoSync, promptUser, conflictResolution)
12
+ */
13
+ import { StatusMapper } from './status-mapper';
14
+ import { ConflictResolver } from './conflict-resolver';
15
+ export class StatusSyncEngine {
16
+ constructor(config) {
17
+ this.config = config;
18
+ this.mapper = new StatusMapper(config);
19
+ this.resolver = new ConflictResolver();
20
+ }
21
+ /**
22
+ * Sync SpecWeave status to external tool (one-way: SpecWeave → External)
23
+ *
24
+ * @param input - Sync input with local/remote statuses
25
+ * @returns Sync result with conflict resolution details
26
+ */
27
+ async syncToExternal(input) {
28
+ this.validateSyncEnabled();
29
+ const result = {
30
+ success: false,
31
+ direction: 'to-external',
32
+ action: 'no-sync-needed',
33
+ conflict: null,
34
+ resolution: null,
35
+ externalMapping: null
36
+ };
37
+ try {
38
+ // Detect conflict
39
+ const conflict = await this.resolver.detect({
40
+ incrementId: input.incrementId,
41
+ local: input.localStatus,
42
+ remote: input.remoteStatus,
43
+ tool: input.tool,
44
+ localTimestamp: input.localTimestamp,
45
+ remoteTimestamp: input.remoteTimestamp
46
+ });
47
+ result.conflict = conflict;
48
+ // No conflict - statuses already match
49
+ if (!conflict) {
50
+ result.success = true;
51
+ result.action = 'no-sync-needed';
52
+ return result;
53
+ }
54
+ // Resolve conflict
55
+ const strategy = this.config.sync.statusSync.conflictResolution || 'last-write-wins';
56
+ const resolution = await this.resolver.resolve(conflict, strategy);
57
+ result.resolution = resolution;
58
+ // Determine action based on resolution
59
+ if (resolution.action === 'use-local') {
60
+ result.action = 'sync-to-external';
61
+ result.externalMapping = this.mapper.mapToExternal(input.localStatus, input.tool);
62
+ }
63
+ else {
64
+ // Resolution says use-remote, but we're syncing TO external
65
+ // This means external is already correct, no sync needed
66
+ result.action = 'no-sync-needed';
67
+ }
68
+ result.success = true;
69
+ return result;
70
+ }
71
+ catch (error) {
72
+ result.success = false;
73
+ result.error = error instanceof Error ? error.message : 'Unknown error';
74
+ throw error;
75
+ }
76
+ }
77
+ /**
78
+ * Sync external status to SpecWeave (one-way: External → SpecWeave)
79
+ *
80
+ * @param input - Sync input with local/remote statuses
81
+ * @returns Sync result with conflict resolution details
82
+ */
83
+ async syncFromExternal(input) {
84
+ this.validateSyncEnabled();
85
+ const result = {
86
+ success: false,
87
+ direction: 'from-external',
88
+ action: 'no-sync-needed',
89
+ conflict: null,
90
+ resolution: null,
91
+ externalMapping: null
92
+ };
93
+ try {
94
+ // Detect conflict
95
+ const conflict = await this.resolver.detect({
96
+ incrementId: input.incrementId,
97
+ local: input.localStatus,
98
+ remote: input.remoteStatus,
99
+ tool: input.tool,
100
+ localTimestamp: input.localTimestamp,
101
+ remoteTimestamp: input.remoteTimestamp
102
+ });
103
+ result.conflict = conflict;
104
+ // No conflict - statuses already match
105
+ if (!conflict) {
106
+ result.success = true;
107
+ result.action = 'no-sync-needed';
108
+ return result;
109
+ }
110
+ // Resolve conflict
111
+ const strategy = this.config.sync.statusSync.conflictResolution || 'last-write-wins';
112
+ const resolution = await this.resolver.resolve(conflict, strategy);
113
+ result.resolution = resolution;
114
+ // Determine action based on resolution
115
+ if (resolution.action === 'use-remote') {
116
+ result.action = 'sync-from-external';
117
+ }
118
+ else {
119
+ // Resolution says use-local, but we're syncing FROM external
120
+ // This means local is already correct, no sync needed
121
+ result.action = 'no-sync-needed';
122
+ }
123
+ result.success = true;
124
+ return result;
125
+ }
126
+ catch (error) {
127
+ result.success = false;
128
+ result.error = error instanceof Error ? error.message : 'Unknown error';
129
+ throw error;
130
+ }
131
+ }
132
+ /**
133
+ * Bidirectional sync (SpecWeave ↔ External)
134
+ *
135
+ * Detects conflict and resolves based on strategy.
136
+ * Syncs in the direction indicated by resolution.
137
+ *
138
+ * @param input - Sync input with local/remote statuses
139
+ * @returns Sync result with conflict resolution details
140
+ */
141
+ async bidirectionalSync(input) {
142
+ this.validateSyncEnabled();
143
+ const result = {
144
+ success: false,
145
+ direction: 'bidirectional',
146
+ action: 'no-sync-needed',
147
+ conflict: null,
148
+ resolution: null,
149
+ externalMapping: null
150
+ };
151
+ try {
152
+ // Detect conflict
153
+ const conflict = await this.resolver.detect({
154
+ incrementId: input.incrementId,
155
+ local: input.localStatus,
156
+ remote: input.remoteStatus,
157
+ tool: input.tool,
158
+ localTimestamp: input.localTimestamp,
159
+ remoteTimestamp: input.remoteTimestamp
160
+ });
161
+ result.conflict = conflict;
162
+ // No conflict - statuses already match
163
+ if (!conflict) {
164
+ result.success = true;
165
+ result.action = 'no-sync-needed';
166
+ return result;
167
+ }
168
+ // Resolve conflict
169
+ const strategy = this.config.sync.statusSync.conflictResolution || 'last-write-wins';
170
+ const resolution = await this.resolver.resolve(conflict, strategy);
171
+ result.resolution = resolution;
172
+ // Determine action based on resolution
173
+ if (resolution.action === 'use-local') {
174
+ result.action = 'sync-to-external';
175
+ result.externalMapping = this.mapper.mapToExternal(input.localStatus, input.tool);
176
+ }
177
+ else {
178
+ result.action = 'sync-from-external';
179
+ }
180
+ result.success = true;
181
+ return result;
182
+ }
183
+ catch (error) {
184
+ result.success = false;
185
+ result.error = error instanceof Error ? error.message : 'Unknown error';
186
+ throw error;
187
+ }
188
+ }
189
+ /**
190
+ * Bulk sync multiple increments to external tools
191
+ *
192
+ * Batches requests to avoid rate limiting.
193
+ * Adds delays between batches.
194
+ * Returns aggregate results with success/failure counts.
195
+ *
196
+ * @param inputs - Array of sync inputs
197
+ * @param options - Bulk sync options (batch size, delay)
198
+ * @returns Bulk sync result
199
+ */
200
+ async bulkSyncToExternal(inputs, options) {
201
+ const startTime = Date.now();
202
+ const batchSize = options?.batchSize || 5;
203
+ const delayMs = options?.delayMs || 1000;
204
+ const results = [];
205
+ let successCount = 0;
206
+ let failureCount = 0;
207
+ // Calculate batches
208
+ const batches = this.calculateBatches(inputs, batchSize);
209
+ // Process each batch
210
+ for (let i = 0; i < batches.length; i++) {
211
+ const batch = batches[i];
212
+ // Process all items in batch concurrently
213
+ const batchResults = await Promise.allSettled(batch.map(input => this.syncToExternal(input)));
214
+ // Collect results
215
+ for (let j = 0; j < batchResults.length; j++) {
216
+ const result = batchResults[j];
217
+ const input = batch[j];
218
+ if (result.status === 'fulfilled') {
219
+ results.push({
220
+ ...result.value,
221
+ incrementId: input.incrementId
222
+ });
223
+ if (result.value.success) {
224
+ successCount++;
225
+ }
226
+ else {
227
+ failureCount++;
228
+ }
229
+ }
230
+ else {
231
+ // Rejection
232
+ results.push({
233
+ incrementId: input.incrementId,
234
+ success: false,
235
+ direction: 'to-external',
236
+ action: 'no-sync-needed',
237
+ conflict: null,
238
+ resolution: null,
239
+ externalMapping: null,
240
+ error: result.reason.message || 'Unknown error'
241
+ });
242
+ failureCount++;
243
+ }
244
+ }
245
+ // Add delay between batches (except after last batch)
246
+ if (i < batches.length - 1) {
247
+ await this.delay(delayMs);
248
+ }
249
+ }
250
+ const duration = `${Date.now() - startTime}ms`;
251
+ return {
252
+ totalItems: inputs.length,
253
+ successCount,
254
+ failureCount,
255
+ results,
256
+ duration
257
+ };
258
+ }
259
+ /**
260
+ * Check if auto-sync is enabled
261
+ *
262
+ * @returns True if auto-sync is enabled
263
+ */
264
+ isAutoSyncEnabled() {
265
+ return this.config.sync.statusSync.autoSync === true;
266
+ }
267
+ /**
268
+ * Check if user should be prompted
269
+ *
270
+ * @returns True if user should be prompted (default: true)
271
+ */
272
+ shouldPromptUser() {
273
+ // Default to true if not specified
274
+ return this.config.sync.statusSync.promptUser !== false;
275
+ }
276
+ /**
277
+ * Execute automatic sync without prompting
278
+ *
279
+ * Validates that auto-sync is enabled.
280
+ * Handles errors gracefully (doesn't throw, returns error in result).
281
+ *
282
+ * @param input - Sync input
283
+ * @returns Sync result with wasAutomatic flag
284
+ */
285
+ async executeAutoSync(input) {
286
+ // Validate auto-sync is enabled
287
+ if (!this.isAutoSyncEnabled()) {
288
+ throw new Error('Auto-sync is disabled');
289
+ }
290
+ try {
291
+ const result = await this.syncToExternal(input);
292
+ return {
293
+ ...result,
294
+ wasAutomatic: true,
295
+ wasPrompted: false
296
+ };
297
+ }
298
+ catch (error) {
299
+ // Handle errors gracefully - return error in result
300
+ // Don't throw to avoid blocking increment completion
301
+ return {
302
+ success: false,
303
+ direction: 'to-external',
304
+ action: 'no-sync-needed',
305
+ conflict: null,
306
+ resolution: null,
307
+ externalMapping: null,
308
+ error: error instanceof Error ? error.message : 'Unknown error',
309
+ wasAutomatic: true,
310
+ wasPrompted: false
311
+ };
312
+ }
313
+ }
314
+ /**
315
+ * Calculate batches from input array
316
+ *
317
+ * @param inputs - Array of inputs
318
+ * @param batchSize - Size of each batch
319
+ * @returns Array of batches
320
+ */
321
+ calculateBatches(inputs, batchSize) {
322
+ const batches = [];
323
+ for (let i = 0; i < inputs.length; i += batchSize) {
324
+ batches.push(inputs.slice(i, i + batchSize));
325
+ }
326
+ return batches;
327
+ }
328
+ /**
329
+ * Delay execution for specified milliseconds
330
+ *
331
+ * @param ms - Milliseconds to delay
332
+ */
333
+ delay(ms) {
334
+ return new Promise(resolve => setTimeout(resolve, ms));
335
+ }
336
+ /**
337
+ * Validate that status synchronization is enabled
338
+ *
339
+ * @throws Error if sync is disabled
340
+ */
341
+ validateSyncEnabled() {
342
+ if (!this.config.sync.statusSync.enabled) {
343
+ throw new Error('Status synchronization is disabled');
344
+ }
345
+ }
346
+ }
347
+ //# sourceMappingURL=status-sync-engine.js.map