specweave 0.32.2 → 0.32.5

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 (244) hide show
  1. package/CLAUDE.md +51 -9
  2. package/bin/specweave.js +34 -0
  3. package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.d.ts +100 -0
  4. package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.d.ts.map +1 -0
  5. package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.js +291 -0
  6. package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.js.map +1 -0
  7. package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.d.ts +103 -0
  8. package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.d.ts.map +1 -0
  9. package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.js +310 -0
  10. package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.js.map +1 -0
  11. package/dist/plugins/specweave-jira/lib/jira-permission-gate.d.ts +126 -0
  12. package/dist/plugins/specweave-jira/lib/jira-permission-gate.d.ts.map +1 -0
  13. package/dist/plugins/specweave-jira/lib/jira-permission-gate.js +207 -0
  14. package/dist/plugins/specweave-jira/lib/jira-permission-gate.js.map +1 -0
  15. package/dist/src/adapters/codex/README.md +1 -1
  16. package/dist/src/adapters/codex/adapter.js +1 -1
  17. package/dist/src/cli/commands/archive.d.ts +2 -0
  18. package/dist/src/cli/commands/archive.d.ts.map +1 -1
  19. package/dist/src/cli/commands/archive.js +33 -0
  20. package/dist/src/cli/commands/archive.js.map +1 -1
  21. package/dist/src/cli/commands/context.d.ts +92 -0
  22. package/dist/src/cli/commands/context.d.ts.map +1 -0
  23. package/dist/src/cli/commands/context.js +205 -0
  24. package/dist/src/cli/commands/context.js.map +1 -0
  25. package/dist/src/cli/commands/init-multiproject.js +1 -1
  26. package/dist/src/cli/commands/init-multiproject.js.map +1 -1
  27. package/dist/src/cli/commands/init.d.ts.map +1 -1
  28. package/dist/src/cli/commands/init.js +111 -69
  29. package/dist/src/cli/commands/init.js.map +1 -1
  30. package/dist/src/cli/commands/migrate-to-multiproject.js +2 -2
  31. package/dist/src/cli/commands/migrate-to-multiproject.js.map +1 -1
  32. package/dist/src/cli/helpers/init/external-import.d.ts +3 -0
  33. package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -1
  34. package/dist/src/cli/helpers/init/external-import.js +17 -4
  35. package/dist/src/cli/helpers/init/external-import.js.map +1 -1
  36. package/dist/src/cli/helpers/init/index.d.ts +1 -0
  37. package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
  38. package/dist/src/cli/helpers/init/index.js +2 -0
  39. package/dist/src/cli/helpers/init/index.js.map +1 -1
  40. package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts +70 -0
  41. package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts.map +1 -1
  42. package/dist/src/cli/helpers/init/jira-ado-auto-detect.js +214 -4
  43. package/dist/src/cli/helpers/init/jira-ado-auto-detect.js.map +1 -1
  44. package/dist/src/cli/helpers/init/living-docs-preflight.d.ts +4 -0
  45. package/dist/src/cli/helpers/init/living-docs-preflight.d.ts.map +1 -1
  46. package/dist/src/cli/helpers/init/living-docs-preflight.js +34 -3
  47. package/dist/src/cli/helpers/init/living-docs-preflight.js.map +1 -1
  48. package/dist/src/cli/helpers/init/testing-config.d.ts +3 -0
  49. package/dist/src/cli/helpers/init/testing-config.d.ts.map +1 -1
  50. package/dist/src/cli/helpers/init/testing-config.js +9 -2
  51. package/dist/src/cli/helpers/init/testing-config.js.map +1 -1
  52. package/dist/src/cli/helpers/init/translation-config.d.ts +3 -0
  53. package/dist/src/cli/helpers/init/translation-config.d.ts.map +1 -1
  54. package/dist/src/cli/helpers/init/translation-config.js +21 -4
  55. package/dist/src/cli/helpers/init/translation-config.js.map +1 -1
  56. package/dist/src/cli/helpers/init/wizard-navigation.d.ts +45 -0
  57. package/dist/src/cli/helpers/init/wizard-navigation.d.ts.map +1 -0
  58. package/dist/src/cli/helpers/init/wizard-navigation.js +97 -0
  59. package/dist/src/cli/helpers/init/wizard-navigation.js.map +1 -0
  60. package/dist/src/core/increment/increment-archiver.d.ts +25 -4
  61. package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
  62. package/dist/src/core/increment/increment-archiver.js +64 -20
  63. package/dist/src/core/increment/increment-archiver.js.map +1 -1
  64. package/dist/src/core/increment/increment-utils.d.ts +65 -0
  65. package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
  66. package/dist/src/core/increment/increment-utils.js +114 -0
  67. package/dist/src/core/increment/increment-utils.js.map +1 -1
  68. package/dist/src/core/living-docs/cross-project-sync.d.ts +97 -0
  69. package/dist/src/core/living-docs/cross-project-sync.d.ts.map +1 -0
  70. package/dist/src/core/living-docs/cross-project-sync.js +135 -0
  71. package/dist/src/core/living-docs/cross-project-sync.js.map +1 -0
  72. package/dist/src/core/living-docs/external-sync-orchestrator.d.ts +106 -0
  73. package/dist/src/core/living-docs/external-sync-orchestrator.d.ts.map +1 -0
  74. package/dist/src/core/living-docs/external-sync-orchestrator.js +146 -0
  75. package/dist/src/core/living-docs/external-sync-orchestrator.js.map +1 -0
  76. package/dist/src/core/living-docs/feature-archiver.d.ts +4 -0
  77. package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
  78. package/dist/src/core/living-docs/feature-archiver.js +32 -10
  79. package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
  80. package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -1
  81. package/dist/src/core/living-docs/feature-id-manager.js +7 -3
  82. package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
  83. package/dist/src/core/living-docs/governance/ecosystem-detector.d.ts +38 -0
  84. package/dist/src/core/living-docs/governance/ecosystem-detector.d.ts.map +1 -0
  85. package/dist/src/core/living-docs/governance/ecosystem-detector.js +325 -0
  86. package/dist/src/core/living-docs/governance/ecosystem-detector.js.map +1 -0
  87. package/dist/src/core/living-docs/governance/frontend-standards-parser.d.ts +74 -0
  88. package/dist/src/core/living-docs/governance/frontend-standards-parser.d.ts.map +1 -0
  89. package/dist/src/core/living-docs/governance/frontend-standards-parser.js +366 -0
  90. package/dist/src/core/living-docs/governance/frontend-standards-parser.js.map +1 -0
  91. package/dist/src/core/living-docs/governance/go-standards-parser.d.ts +64 -0
  92. package/dist/src/core/living-docs/governance/go-standards-parser.d.ts.map +1 -0
  93. package/dist/src/core/living-docs/governance/go-standards-parser.js +229 -0
  94. package/dist/src/core/living-docs/governance/go-standards-parser.js.map +1 -0
  95. package/dist/src/core/living-docs/governance/index.d.ts +50 -0
  96. package/dist/src/core/living-docs/governance/index.d.ts.map +1 -0
  97. package/dist/src/core/living-docs/governance/index.js +56 -0
  98. package/dist/src/core/living-docs/governance/index.js.map +1 -0
  99. package/dist/src/core/living-docs/governance/java-standards-parser.d.ts +89 -0
  100. package/dist/src/core/living-docs/governance/java-standards-parser.d.ts.map +1 -0
  101. package/dist/src/core/living-docs/governance/java-standards-parser.js +356 -0
  102. package/dist/src/core/living-docs/governance/java-standards-parser.js.map +1 -0
  103. package/dist/src/core/living-docs/governance/python-standards-parser.d.ts +83 -0
  104. package/dist/src/core/living-docs/governance/python-standards-parser.d.ts.map +1 -0
  105. package/dist/src/core/living-docs/governance/python-standards-parser.js +347 -0
  106. package/dist/src/core/living-docs/governance/python-standards-parser.js.map +1 -0
  107. package/dist/src/core/living-docs/governance/standards-generator.d.ts +38 -0
  108. package/dist/src/core/living-docs/governance/standards-generator.d.ts.map +1 -0
  109. package/dist/src/core/living-docs/governance/standards-generator.js +476 -0
  110. package/dist/src/core/living-docs/governance/standards-generator.js.map +1 -0
  111. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -1
  112. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +54 -2
  113. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -1
  114. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts +5 -1
  115. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -1
  116. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +358 -30
  117. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -1
  118. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +44 -0
  119. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -1
  120. package/dist/src/core/living-docs/living-docs-sync.d.ts +7 -3
  121. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  122. package/dist/src/core/living-docs/living-docs-sync.js +94 -10
  123. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  124. package/dist/src/core/living-docs/module-analyzer.d.ts +22 -0
  125. package/dist/src/core/living-docs/module-analyzer.d.ts.map +1 -1
  126. package/dist/src/core/living-docs/module-analyzer.js +123 -19
  127. package/dist/src/core/living-docs/module-analyzer.js.map +1 -1
  128. package/dist/src/core/living-docs/sync-helpers/generators.d.ts +8 -1
  129. package/dist/src/core/living-docs/sync-helpers/generators.d.ts.map +1 -1
  130. package/dist/src/core/living-docs/sync-helpers/generators.js +18 -1
  131. package/dist/src/core/living-docs/sync-helpers/generators.js.map +1 -1
  132. package/dist/src/core/living-docs/sync-helpers/index.d.ts +1 -1
  133. package/dist/src/core/living-docs/sync-helpers/index.d.ts.map +1 -1
  134. package/dist/src/core/living-docs/sync-helpers/index.js.map +1 -1
  135. package/dist/src/core/living-docs/sync-helpers/parsers.d.ts +3 -1
  136. package/dist/src/core/living-docs/sync-helpers/parsers.d.ts.map +1 -1
  137. package/dist/src/core/living-docs/sync-helpers/parsers.js +24 -2
  138. package/dist/src/core/living-docs/sync-helpers/parsers.js.map +1 -1
  139. package/dist/src/core/living-docs/types.d.ts +6 -0
  140. package/dist/src/core/living-docs/types.d.ts.map +1 -1
  141. package/dist/src/core/living-docs/validators/index.d.ts +7 -0
  142. package/dist/src/core/living-docs/validators/index.d.ts.map +1 -0
  143. package/dist/src/core/living-docs/validators/index.js +7 -0
  144. package/dist/src/core/living-docs/validators/index.js.map +1 -0
  145. package/dist/src/core/living-docs/validators/project-validator.d.ts +92 -0
  146. package/dist/src/core/living-docs/validators/project-validator.d.ts.map +1 -0
  147. package/dist/src/core/living-docs/validators/project-validator.js +142 -0
  148. package/dist/src/core/living-docs/validators/project-validator.js.map +1 -0
  149. package/dist/src/core/llm/provider-factory.js +2 -2
  150. package/dist/src/core/llm/provider-factory.js.map +1 -1
  151. package/dist/src/core/llm/providers/anthropic-provider.js +1 -1
  152. package/dist/src/core/llm/providers/bedrock-provider.d.ts.map +1 -1
  153. package/dist/src/core/llm/providers/bedrock-provider.js +8 -4
  154. package/dist/src/core/llm/providers/bedrock-provider.js.map +1 -1
  155. package/dist/src/core/project/project-manager.d.ts.map +1 -1
  156. package/dist/src/core/project/project-manager.js +19 -17
  157. package/dist/src/core/project/project-manager.js.map +1 -1
  158. package/dist/src/core/types/config.d.ts +4 -2
  159. package/dist/src/core/types/config.d.ts.map +1 -1
  160. package/dist/src/core/types/config.js.map +1 -1
  161. package/dist/src/core/types/increment-metadata.d.ts +34 -0
  162. package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
  163. package/dist/src/importers/jira-importer.d.ts +14 -0
  164. package/dist/src/importers/jira-importer.d.ts.map +1 -1
  165. package/dist/src/importers/jira-importer.js +75 -0
  166. package/dist/src/importers/jira-importer.js.map +1 -1
  167. package/dist/src/integrations/jira/jira-token-provider.d.ts +93 -0
  168. package/dist/src/integrations/jira/jira-token-provider.d.ts.map +1 -0
  169. package/dist/src/integrations/jira/jira-token-provider.js +160 -0
  170. package/dist/src/integrations/jira/jira-token-provider.js.map +1 -0
  171. package/dist/src/sync/ado-reconciler.d.ts +92 -0
  172. package/dist/src/sync/ado-reconciler.d.ts.map +1 -0
  173. package/dist/src/sync/ado-reconciler.js +335 -0
  174. package/dist/src/sync/ado-reconciler.js.map +1 -0
  175. package/dist/src/sync/jira-reconciler.d.ts +106 -0
  176. package/dist/src/sync/jira-reconciler.d.ts.map +1 -0
  177. package/dist/src/sync/jira-reconciler.js +405 -0
  178. package/dist/src/sync/jira-reconciler.js.map +1 -0
  179. package/dist/src/types/model-selection.d.ts +6 -4
  180. package/dist/src/types/model-selection.d.ts.map +1 -1
  181. package/dist/src/types/model-selection.js +3 -1
  182. package/dist/src/types/model-selection.js.map +1 -1
  183. package/dist/src/utils/cross-cutting-detector.d.ts +66 -0
  184. package/dist/src/utils/cross-cutting-detector.d.ts.map +1 -0
  185. package/dist/src/utils/cross-cutting-detector.js +179 -0
  186. package/dist/src/utils/cross-cutting-detector.js.map +1 -0
  187. package/dist/src/utils/external-tool-drift-detector.d.ts +1 -1
  188. package/dist/src/utils/external-tool-drift-detector.d.ts.map +1 -1
  189. package/dist/src/utils/external-tool-drift-detector.js +5 -4
  190. package/dist/src/utils/external-tool-drift-detector.js.map +1 -1
  191. package/dist/src/utils/feature-id-derivation.d.ts +8 -3
  192. package/dist/src/utils/feature-id-derivation.d.ts.map +1 -1
  193. package/dist/src/utils/feature-id-derivation.js +14 -6
  194. package/dist/src/utils/feature-id-derivation.js.map +1 -1
  195. package/dist/src/utils/model-selection.d.ts +3 -4
  196. package/dist/src/utils/model-selection.d.ts.map +1 -1
  197. package/dist/src/utils/model-selection.js +3 -4
  198. package/dist/src/utils/model-selection.js.map +1 -1
  199. package/dist/src/utils/project-detection.d.ts +12 -8
  200. package/dist/src/utils/project-detection.d.ts.map +1 -1
  201. package/dist/src/utils/project-detection.js +13 -19
  202. package/dist/src/utils/project-detection.js.map +1 -1
  203. package/package.json +1 -1
  204. package/plugins/specweave/agents/code-standards-detective/AGENT.md +48 -0
  205. package/plugins/specweave/commands/specweave-costs.md +4 -4
  206. package/plugins/specweave/commands/specweave-do.md +9 -9
  207. package/plugins/specweave/commands/specweave-done.md +13 -0
  208. package/plugins/specweave/commands/specweave-status.md +64 -0
  209. package/plugins/specweave/commands/specweave-validate.md +27 -1
  210. package/plugins/specweave/hooks/hooks.json +11 -1
  211. package/plugins/specweave/hooks/spec-project-validator.sh +81 -25
  212. package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +135 -0
  213. package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +34 -0
  214. package/plugins/specweave/scripts/read-costs.sh +3 -3
  215. package/plugins/specweave/skills/code-standards-analyzer/SKILL.md +58 -6
  216. package/plugins/specweave/skills/increment-planner/SKILL.md +135 -29
  217. package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +4 -2
  218. package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +2 -1
  219. package/plugins/specweave/skills/increment-planner/templates/tasks-multi-project.md +1 -1
  220. package/plugins/specweave/skills/increment-planner/templates/tasks-single-project.md +1 -1
  221. package/plugins/specweave/skills/spec-generator/SKILL.md +78 -7
  222. package/plugins/specweave-ado/commands/cleanup-duplicates.md +212 -0
  223. package/plugins/specweave-ado/commands/reconcile.md +120 -0
  224. package/plugins/specweave-ado/lib/ado-duplicate-detector.js +279 -0
  225. package/plugins/specweave-ado/lib/ado-duplicate-detector.ts +407 -0
  226. package/plugins/specweave-github/agents/github-manager/AGENT.md +2 -2
  227. package/plugins/specweave-infrastructure/skills/hetzner-provisioner/README.md +1 -1
  228. package/plugins/specweave-jira/agents/jira-manager/AGENT.md +1 -1
  229. package/plugins/specweave-jira/agents/jira-multi-project-mapper/AGENT.md +530 -0
  230. package/plugins/specweave-jira/agents/jira-sync-judge/AGENT.md +438 -0
  231. package/plugins/specweave-jira/commands/cleanup-duplicates.md +219 -0
  232. package/plugins/specweave-jira/commands/close.md +297 -0
  233. package/plugins/specweave-jira/commands/create.md +198 -0
  234. package/plugins/specweave-jira/commands/reconcile.md +123 -0
  235. package/plugins/specweave-jira/commands/status.md +215 -0
  236. package/plugins/specweave-jira/lib/jira-duplicate-detector.js +296 -0
  237. package/plugins/specweave-jira/lib/jira-duplicate-detector.ts +434 -0
  238. package/plugins/specweave-jira/lib/jira-permission-gate.js +160 -0
  239. package/plugins/specweave-jira/lib/jira-permission-gate.ts +276 -0
  240. package/plugins/specweave-jira/lib/jira-profile-resolver.js +222 -0
  241. package/plugins/specweave-jira/lib/jira-profile-resolver.ts +427 -0
  242. package/plugins/specweave-jira/reference/jira-specweave-mapping.md +16 -11
  243. package/plugins/specweave-release/commands/specweave-release-npm.md +140 -14
  244. package/plugins/specweave/commands/specweave-switch-project.md +0 -168
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Cross-Project Sync Orchestrator
3
+ *
4
+ * Handles syncing increments that span multiple projects.
5
+ * Groups user stories by their target project and syncs each group
6
+ * to the appropriate project folder in living docs.
7
+ *
8
+ * @module core/living-docs/cross-project-sync
9
+ * @since v0.33.0
10
+ */
11
+ import * as path from 'node:path';
12
+ import { consoleLogger } from '../../utils/logger.js';
13
+ import { ensureDir } from '../../utils/fs-native.js';
14
+ /**
15
+ * Cross-Project Sync Orchestrator
16
+ */
17
+ export class CrossProjectSync {
18
+ constructor(projectRoot, options = {}) {
19
+ this.projectRoot = projectRoot;
20
+ this.logger = options.logger ?? consoleLogger;
21
+ }
22
+ /**
23
+ * Group user stories by their target project
24
+ *
25
+ * @param userStories - User stories to group
26
+ * @param defaultProject - Default project for USs without explicit project
27
+ * @returns Map of project ID to user stories
28
+ */
29
+ groupByProject(userStories, defaultProject) {
30
+ const groups = new Map();
31
+ for (const us of userStories) {
32
+ const project = us.project || defaultProject;
33
+ if (!groups.has(project)) {
34
+ groups.set(project, []);
35
+ }
36
+ groups.get(project).push(us);
37
+ }
38
+ return groups;
39
+ }
40
+ /**
41
+ * Check if an increment is cross-project (spans multiple projects)
42
+ */
43
+ isCrossProject(userStories, defaultProject) {
44
+ const groups = this.groupByProject(userStories, defaultProject);
45
+ return groups.size > 1;
46
+ }
47
+ /**
48
+ * Get the specs folder path for a project
49
+ */
50
+ getProjectSpecsPath(projectId) {
51
+ return path.join(this.projectRoot, '.specweave/docs/internal/specs', projectId);
52
+ }
53
+ /**
54
+ * Get the feature folder path for a project and feature
55
+ */
56
+ getFeaturePath(projectId, featureId) {
57
+ return path.join(this.getProjectSpecsPath(projectId), featureId);
58
+ }
59
+ /**
60
+ * Ensure project specs folder exists
61
+ */
62
+ async ensureProjectFolder(projectId) {
63
+ const folderPath = this.getProjectSpecsPath(projectId);
64
+ await ensureDir(folderPath);
65
+ return folderPath;
66
+ }
67
+ /**
68
+ * Ensure feature folder exists within a project
69
+ */
70
+ async ensureFeatureFolder(projectId, featureId) {
71
+ const folderPath = this.getFeaturePath(projectId, featureId);
72
+ await ensureDir(folderPath);
73
+ return folderPath;
74
+ }
75
+ /**
76
+ * Generate cross-references section for FEATURE.md
77
+ *
78
+ * @param featureId - The feature ID (e.g., "FS-125")
79
+ * @param allProjects - All projects this feature spans
80
+ * @param currentProject - The current project being generated
81
+ * @returns Markdown content for "Related Projects" section
82
+ */
83
+ generateCrossReferences(featureId, allProjects, currentProject) {
84
+ const otherProjects = allProjects.filter(p => p !== currentProject);
85
+ if (otherProjects.length === 0) {
86
+ return '';
87
+ }
88
+ const lines = [
89
+ '',
90
+ '## Related Projects',
91
+ '',
92
+ 'This feature spans multiple projects:',
93
+ ''
94
+ ];
95
+ for (const projectId of otherProjects) {
96
+ // Relative path from current project to other project
97
+ const relativePath = `../../${projectId}/${featureId}/`;
98
+ lines.push(`- [${projectId}](${relativePath})`);
99
+ }
100
+ lines.push('');
101
+ return lines.join('\n');
102
+ }
103
+ /**
104
+ * Generate cross-reference frontmatter for US files
105
+ */
106
+ generateRelatedProjectsFrontmatter(allProjects, currentProject) {
107
+ const otherProjects = allProjects.filter(p => p !== currentProject);
108
+ if (otherProjects.length === 0) {
109
+ return '';
110
+ }
111
+ return `related_projects: [${otherProjects.join(', ')}]`;
112
+ }
113
+ /**
114
+ * Log cross-project sync summary
115
+ */
116
+ logSyncSummary(result) {
117
+ this.logger.log('');
118
+ this.logger.log('📦 Cross-Project Sync Summary:');
119
+ this.logger.log(` Projects: ${result.projectCount}`);
120
+ this.logger.log(` User Stories: ${result.totalUserStories}`);
121
+ for (const project of result.projects) {
122
+ const status = project.success ? '✅' : '❌';
123
+ this.logger.log(` ${status} ${project.projectId}: ${project.userStories.length} USs`);
124
+ if (project.errors.length > 0) {
125
+ for (const error of project.errors) {
126
+ this.logger.warn(` ⚠️ ${error}`);
127
+ }
128
+ }
129
+ }
130
+ if (result.crossReferences.length > 0) {
131
+ this.logger.log(` 🔗 Cross-references: ${result.crossReferences.length} links created`);
132
+ }
133
+ }
134
+ }
135
+ //# sourceMappingURL=cross-project-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-project-sync.js","sourceRoot":"","sources":["../../../../src/core/living-docs/cross-project-sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * External Sync Orchestrator
3
+ *
4
+ * Coordinates syncing user stories to multiple external tools based on
5
+ * per-US project targeting. Groups USs by their target project and
6
+ * syncs each group to the appropriate external system.
7
+ *
8
+ * @module core/living-docs/external-sync-orchestrator
9
+ * @since v0.33.0
10
+ */
11
+ import type { UserStoryData } from './types.js';
12
+ import type { USExternalRefsMap } from '../types/increment-metadata.js';
13
+ import { Logger } from '../../utils/logger.js';
14
+ /**
15
+ * Project mapping configuration
16
+ */
17
+ export interface ProjectMapping {
18
+ github?: {
19
+ owner: string;
20
+ repo: string;
21
+ };
22
+ jira?: {
23
+ project: string;
24
+ board?: string;
25
+ };
26
+ ado?: {
27
+ project: string;
28
+ areaPath?: string;
29
+ };
30
+ }
31
+ /**
32
+ * Result of syncing a single US to an external tool
33
+ */
34
+ export interface USSyncResult {
35
+ usId: string;
36
+ provider: 'github' | 'jira' | 'ado';
37
+ success: boolean;
38
+ issueNumber?: number | string;
39
+ url?: string;
40
+ error?: string;
41
+ }
42
+ /**
43
+ * Result of syncing all USs in a project group
44
+ */
45
+ export interface ProjectSyncResult {
46
+ projectId: string;
47
+ provider: 'github' | 'jira' | 'ado';
48
+ success: boolean;
49
+ synced: USSyncResult[];
50
+ errors: string[];
51
+ }
52
+ /**
53
+ * Result of complete cross-project sync
54
+ */
55
+ export interface CrossProjectExternalSyncResult {
56
+ success: boolean;
57
+ projects: ProjectSyncResult[];
58
+ externalRefs: USExternalRefsMap;
59
+ summary: {
60
+ totalUSs: number;
61
+ syncedUSs: number;
62
+ failedUSs: number;
63
+ projectCount: number;
64
+ };
65
+ }
66
+ /**
67
+ * External Sync Orchestrator
68
+ */
69
+ export declare class ExternalSyncOrchestrator {
70
+ private projectRoot;
71
+ private logger;
72
+ private projectMappings;
73
+ constructor(projectRoot: string, options?: {
74
+ logger?: Logger;
75
+ });
76
+ /**
77
+ * Load project mappings from config
78
+ */
79
+ loadProjectMappings(): Promise<void>;
80
+ /**
81
+ * Get project mapping for a project ID
82
+ */
83
+ getProjectMapping(projectId: string): ProjectMapping | undefined;
84
+ /**
85
+ * Group user stories by their target project
86
+ */
87
+ groupUSsByProject(userStories: UserStoryData[], defaultProject: string): Map<string, UserStoryData[]>;
88
+ /**
89
+ * Get preferred provider for a US
90
+ * Priority: US.externalProvider > first available in mapping
91
+ */
92
+ getPreferredProvider(us: UserStoryData, mapping: ProjectMapping): 'github' | 'jira' | 'ado' | null;
93
+ /**
94
+ * Build external refs map from sync results
95
+ */
96
+ buildExternalRefsMap(results: ProjectSyncResult[]): USExternalRefsMap;
97
+ /**
98
+ * Log sync summary
99
+ */
100
+ logSyncSummary(result: CrossProjectExternalSyncResult): void;
101
+ /**
102
+ * Create placeholder sync result for dry-run or when sync is skipped
103
+ */
104
+ createPlaceholderResult(userStories: UserStoryData[], defaultProject: string): CrossProjectExternalSyncResult;
105
+ }
106
+ //# sourceMappingURL=external-sync-orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-sync-orchestrator.d.ts","sourceRoot":"","sources":["../../../../src/core/living-docs/external-sync-orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAiB,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACvF,OAAO,EAAE,MAAM,EAAiB,MAAM,uBAAuB,CAAC;AAG9D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,IAAI,CAAC,EAAE;QACL,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,YAAY,EAAE,iBAAiB,CAAC;IAChC,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED;;GAEG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,eAAe,CAAsC;gBAEjD,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO;IAKlE;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAa1C;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAIhE;;OAEG;IACH,iBAAiB,CACf,WAAW,EAAE,aAAa,EAAE,EAC5B,cAAc,EAAE,MAAM,GACrB,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC;IAe/B;;;OAGG;IACH,oBAAoB,CAClB,EAAE,EAAE,aAAa,EACjB,OAAO,EAAE,cAAc,GACtB,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,IAAI;IAcnC;;OAEG;IACH,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,iBAAiB;IAwBrE;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,8BAA8B,GAAG,IAAI;IAkB5D;;OAEG;IACH,uBAAuB,CACrB,WAAW,EAAE,aAAa,EAAE,EAC5B,cAAc,EAAE,MAAM,GACrB,8BAA8B;CA0BlC"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * External Sync Orchestrator
3
+ *
4
+ * Coordinates syncing user stories to multiple external tools based on
5
+ * per-US project targeting. Groups USs by their target project and
6
+ * syncs each group to the appropriate external system.
7
+ *
8
+ * @module core/living-docs/external-sync-orchestrator
9
+ * @since v0.33.0
10
+ */
11
+ import * as path from 'node:path';
12
+ import { consoleLogger } from '../../utils/logger.js';
13
+ import { pathExists, readJson } from './sync-helpers/file-utils.js';
14
+ /**
15
+ * External Sync Orchestrator
16
+ */
17
+ export class ExternalSyncOrchestrator {
18
+ constructor(projectRoot, options = {}) {
19
+ this.projectMappings = {};
20
+ this.projectRoot = projectRoot;
21
+ this.logger = options.logger ?? consoleLogger;
22
+ }
23
+ /**
24
+ * Load project mappings from config
25
+ */
26
+ async loadProjectMappings() {
27
+ const configPath = path.join(this.projectRoot, '.specweave/config.json');
28
+ if (await pathExists(configPath)) {
29
+ try {
30
+ const config = await readJson(configPath);
31
+ this.projectMappings = config.projectMappings || {};
32
+ }
33
+ catch (error) {
34
+ this.logger.warn('Failed to load projectMappings from config');
35
+ }
36
+ }
37
+ }
38
+ /**
39
+ * Get project mapping for a project ID
40
+ */
41
+ getProjectMapping(projectId) {
42
+ return this.projectMappings[projectId];
43
+ }
44
+ /**
45
+ * Group user stories by their target project
46
+ */
47
+ groupUSsByProject(userStories, defaultProject) {
48
+ const groups = new Map();
49
+ for (const us of userStories) {
50
+ const project = us.project || defaultProject;
51
+ if (!groups.has(project)) {
52
+ groups.set(project, []);
53
+ }
54
+ groups.get(project).push(us);
55
+ }
56
+ return groups;
57
+ }
58
+ /**
59
+ * Get preferred provider for a US
60
+ * Priority: US.externalProvider > first available in mapping
61
+ */
62
+ getPreferredProvider(us, mapping) {
63
+ // Explicit preference in US
64
+ if (us.externalProvider && mapping[us.externalProvider]) {
65
+ return us.externalProvider;
66
+ }
67
+ // Fall back to first available in mapping
68
+ if (mapping.github)
69
+ return 'github';
70
+ if (mapping.jira)
71
+ return 'jira';
72
+ if (mapping.ado)
73
+ return 'ado';
74
+ return null;
75
+ }
76
+ /**
77
+ * Build external refs map from sync results
78
+ */
79
+ buildExternalRefsMap(results) {
80
+ const refsMap = {};
81
+ for (const projectResult of results) {
82
+ for (const usResult of projectResult.synced) {
83
+ if (!usResult.success)
84
+ continue;
85
+ if (!refsMap[usResult.usId]) {
86
+ refsMap[usResult.usId] = {};
87
+ }
88
+ refsMap[usResult.usId][usResult.provider] = {
89
+ provider: usResult.provider,
90
+ issueNumber: usResult.issueNumber,
91
+ url: usResult.url,
92
+ targetProject: projectResult.projectId,
93
+ lastSynced: new Date().toISOString()
94
+ };
95
+ }
96
+ }
97
+ return refsMap;
98
+ }
99
+ /**
100
+ * Log sync summary
101
+ */
102
+ logSyncSummary(result) {
103
+ this.logger.log('');
104
+ this.logger.log('🔗 Cross-Project External Sync Summary:');
105
+ this.logger.log(` Projects: ${result.summary.projectCount}`);
106
+ this.logger.log(` User Stories: ${result.summary.syncedUSs}/${result.summary.totalUSs} synced`);
107
+ for (const project of result.projects) {
108
+ const status = project.success ? '✅' : '❌';
109
+ this.logger.log(` ${status} ${project.projectId} (${project.provider}): ${project.synced.length} USs`);
110
+ if (project.errors.length > 0) {
111
+ for (const error of project.errors) {
112
+ this.logger.warn(` ⚠️ ${error}`);
113
+ }
114
+ }
115
+ }
116
+ }
117
+ /**
118
+ * Create placeholder sync result for dry-run or when sync is skipped
119
+ */
120
+ createPlaceholderResult(userStories, defaultProject) {
121
+ const groups = this.groupUSsByProject(userStories, defaultProject);
122
+ return {
123
+ success: true,
124
+ projects: [...groups.entries()].map(([projectId, stories]) => ({
125
+ projectId,
126
+ provider: 'github',
127
+ success: true,
128
+ synced: stories.map(us => ({
129
+ usId: us.id,
130
+ provider: 'github',
131
+ success: false,
132
+ error: 'Sync skipped (dry-run or SKIP_EXTERNAL_SYNC)'
133
+ })),
134
+ errors: []
135
+ })),
136
+ externalRefs: {},
137
+ summary: {
138
+ totalUSs: userStories.length,
139
+ syncedUSs: 0,
140
+ failedUSs: 0,
141
+ projectCount: groups.size
142
+ }
143
+ };
144
+ }
145
+ }
146
+ //# sourceMappingURL=external-sync-orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-sync-orchestrator.js","sourceRoot":"","sources":["../../../../src/core/living-docs/external-sync-orchestrator.ts"],"names":[],"mappings":"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"}
@@ -106,7 +106,11 @@ export declare class FeatureArchiver {
106
106
  * Examples:
107
107
  * - "0041-living-docs-test-fixes" → "FS-041"
108
108
  * - "0123-my-feature" → "FS-123"
109
+ * - "0111E-external-issue" → "FS-111E" (external increment → external feature)
109
110
  * - "temp-experiment" → null (no number)
111
+ *
112
+ * CRITICAL (v0.33.0): External increments (with E suffix like 0111E-...)
113
+ * MUST map to external features (FS-111E), not internal ones (FS-111).
110
114
  */
111
115
  private inferFeatureIdFromIncrement;
112
116
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"feature-archiver.d.ts","sourceRoot":"","sources":["../../../../src/core/living-docs/feature-archiver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"feature-archiver.d.ts","sourceRoot":"","sources":["../../../../src/core/living-docs/feature-archiver.ts"],"names":[],"mappings":"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"}
@@ -100,6 +100,14 @@ export class FeatureArchiver {
100
100
  // Empty array .every() returns true, so we must explicitly check length
101
101
  // Archive orphaned features ONLY if option is set
102
102
  const isOrphaned = linkedIncrements.length === 0 && options.archiveOrphanedFeatures;
103
+ // v0.33.0: External features (FS-XXXE) are NOT orphaned - they're imported from
104
+ // external tools and should be handled by archiveExternalFeatures() separately!
105
+ // Skip external features in the normal archiving flow.
106
+ const isExternalFeature = featureId.endsWith('E');
107
+ if (isExternalFeature && linkedIncrements.length === 0) {
108
+ console.log(`⏭️ Skipping ${featureId}: external feature (use --external flag to archive)`);
109
+ continue;
110
+ }
103
111
  // Check if all linked increments are archived (EXACT MATCH, not partial)
104
112
  // CRITICAL: Use exact match (===) not .includes() to avoid false positives
105
113
  // SAFETY: If no linked increments and archiveOrphanedFeatures is false, skip
@@ -557,17 +565,24 @@ export class FeatureArchiver {
557
565
  * Examples:
558
566
  * - "0041-living-docs-test-fixes" → "FS-041"
559
567
  * - "0123-my-feature" → "FS-123"
568
+ * - "0111E-external-issue" → "FS-111E" (external increment → external feature)
560
569
  * - "temp-experiment" → null (no number)
570
+ *
571
+ * CRITICAL (v0.33.0): External increments (with E suffix like 0111E-...)
572
+ * MUST map to external features (FS-111E), not internal ones (FS-111).
561
573
  */
562
574
  inferFeatureIdFromIncrement(increment) {
563
- // Extract 4-digit number prefix
564
- const match = increment.match(/^(\d{4})/);
575
+ // Extract 4-digit number prefix and optional E suffix
576
+ // Pattern: NNNN or NNNNE (e.g., 0041, 0111E)
577
+ const match = increment.match(/^(\d{4})(E)?/);
565
578
  if (!match) {
566
579
  return null; // Can't infer (no number prefix)
567
580
  }
568
581
  const number = parseInt(match[1], 10);
569
- // Convert to feature ID format: 41 → "FS-041"
570
- return `FS-${number.toString().padStart(3, '0')}`;
582
+ const isExternal = match[2] === 'E';
583
+ // Convert to feature ID format: 41 → "FS-041", 111E → "FS-111E"
584
+ const featureId = `FS-${number.toString().padStart(3, '0')}`;
585
+ return isExternal ? `${featureId}E` : featureId;
571
586
  }
572
587
  /**
573
588
  * Get features linked to an epic
@@ -687,16 +702,23 @@ export class FeatureArchiver {
687
702
  }
688
703
  try {
689
704
  const content = await fs.readFile(featureMdPath, 'utf-8');
690
- // Extract increment number from Implementation History
691
- const match = content.match(/\[(\d{4})-[^\]]+\]\([^)]*increments/);
705
+ // Extract increment number and optional E suffix from Implementation History
706
+ // CRITICAL (v0.33.0): Handle external increments like [0111E-name](...)
707
+ const match = content.match(/\[(\d{4})(E)?-[^\]]+\]\([^)]*increments/);
692
708
  if (!match) {
693
709
  continue; // No increment reference found
694
710
  }
695
711
  const referencedIncrementNum = parseInt(match[1]);
696
- const currentFeatureNum = parseInt(featureId.slice(3));
697
- // Check if feature ID matches referenced increment
698
- if (referencedIncrementNum !== currentFeatureNum) {
699
- const expectedFeatureId = `FS-${referencedIncrementNum.toString().padStart(3, '0')}`;
712
+ const isExternalIncrement = match[2] === 'E';
713
+ // Parse current feature ID - handle both FS-111 and FS-111E
714
+ const currentFeatureNum = parseInt(featureId.replace('FS-', '').replace('E', ''));
715
+ const isCurrentExternal = featureId.endsWith('E');
716
+ // Check if feature ID matches referenced increment (both number AND external status)
717
+ const numberMismatch = referencedIncrementNum !== currentFeatureNum;
718
+ const externalMismatch = isExternalIncrement !== isCurrentExternal;
719
+ if (numberMismatch || externalMismatch) {
720
+ const baseId = `FS-${referencedIncrementNum.toString().padStart(3, '0')}`;
721
+ const expectedFeatureId = isExternalIncrement ? `${baseId}E` : baseId;
700
722
  console.log(` ⚠️ Mismatch: ${featureId} references increment ${match[1]}`);
701
723
  console.log(` Renaming ${featureId} → ${expectedFeatureId}`);
702
724
  // Rename the feature folder