specweave 0.1.9 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/CLAUDE.md +600 -0
  2. package/README.md +263 -81
  3. package/bin/install-all.sh +1 -1
  4. package/bin/install-commands.sh +3 -3
  5. package/bin/specweave.js +39 -9
  6. package/dist/adapters/adapter-base.d.ts +1 -1
  7. package/dist/adapters/adapter-base.d.ts.map +1 -1
  8. package/dist/adapters/adapter-base.js +6 -41
  9. package/dist/adapters/adapter-base.js.map +1 -1
  10. package/dist/adapters/adapter-interface.js +1 -2
  11. package/dist/adapters/adapter-interface.js.map +1 -1
  12. package/dist/adapters/adapter-loader.d.ts +86 -0
  13. package/dist/adapters/adapter-loader.d.ts.map +1 -0
  14. package/dist/adapters/adapter-loader.js +216 -0
  15. package/dist/adapters/adapter-loader.js.map +1 -0
  16. package/dist/adapters/agents-md-generator.d.ts +48 -0
  17. package/dist/adapters/agents-md-generator.d.ts.map +1 -0
  18. package/dist/adapters/agents-md-generator.js +132 -0
  19. package/dist/adapters/agents-md-generator.js.map +1 -0
  20. package/dist/adapters/claude/adapter.d.ts +2 -2
  21. package/dist/adapters/claude/adapter.d.ts.map +1 -1
  22. package/dist/adapters/claude/adapter.js +5 -42
  23. package/dist/adapters/claude/adapter.js.map +1 -1
  24. package/dist/adapters/claude-md-generator.d.ts +78 -0
  25. package/dist/adapters/claude-md-generator.d.ts.map +1 -0
  26. package/dist/adapters/claude-md-generator.js +246 -0
  27. package/dist/adapters/claude-md-generator.js.map +1 -0
  28. package/dist/adapters/codex/adapter.d.ts +50 -0
  29. package/dist/adapters/codex/adapter.d.ts.map +1 -0
  30. package/dist/adapters/codex/adapter.js +316 -0
  31. package/dist/adapters/codex/adapter.js.map +1 -0
  32. package/dist/adapters/copilot/adapter.d.ts +10 -9
  33. package/dist/adapters/copilot/adapter.d.ts.map +1 -1
  34. package/dist/adapters/copilot/adapter.js +35 -100
  35. package/dist/adapters/copilot/adapter.js.map +1 -1
  36. package/dist/adapters/cursor/adapter.d.ts +8 -6
  37. package/dist/adapters/cursor/adapter.d.ts.map +1 -1
  38. package/dist/adapters/cursor/adapter.js +47 -130
  39. package/dist/adapters/cursor/adapter.js.map +1 -1
  40. package/dist/adapters/doc-generator.d.ts +69 -0
  41. package/dist/adapters/doc-generator.d.ts.map +1 -0
  42. package/dist/adapters/doc-generator.js +247 -0
  43. package/dist/adapters/doc-generator.js.map +1 -0
  44. package/dist/adapters/gemini/adapter.d.ts +50 -0
  45. package/dist/adapters/gemini/adapter.d.ts.map +1 -0
  46. package/dist/adapters/gemini/adapter.js +281 -0
  47. package/dist/adapters/gemini/adapter.js.map +1 -0
  48. package/dist/adapters/generic/adapter.d.ts +7 -4
  49. package/dist/adapters/generic/adapter.d.ts.map +1 -1
  50. package/dist/adapters/generic/adapter.js +60 -59
  51. package/dist/adapters/generic/adapter.js.map +1 -1
  52. package/dist/cli/commands/init.d.ts +3 -1
  53. package/dist/cli/commands/init.d.ts.map +1 -1
  54. package/dist/cli/commands/init.js +327 -177
  55. package/dist/cli/commands/init.js.map +1 -1
  56. package/dist/cli/commands/install.d.ts.map +1 -1
  57. package/dist/cli/commands/install.js +22 -58
  58. package/dist/cli/commands/install.js.map +1 -1
  59. package/dist/cli/commands/list.d.ts.map +1 -1
  60. package/dist/cli/commands/list.js +27 -64
  61. package/dist/cli/commands/list.js.map +1 -1
  62. package/dist/core/credentials-manager.d.ts +90 -0
  63. package/dist/core/credentials-manager.d.ts.map +1 -0
  64. package/dist/core/credentials-manager.js +271 -0
  65. package/dist/core/credentials-manager.js.map +1 -0
  66. package/dist/core/project-structure-detector.d.ts +92 -0
  67. package/dist/core/project-structure-detector.d.ts.map +1 -0
  68. package/dist/core/project-structure-detector.js +289 -0
  69. package/dist/core/project-structure-detector.js.map +1 -0
  70. package/dist/core/rfc-generator-v2.d.ts +149 -0
  71. package/dist/core/rfc-generator-v2.d.ts.map +1 -0
  72. package/dist/core/rfc-generator-v2.js +399 -0
  73. package/dist/core/rfc-generator-v2.js.map +1 -0
  74. package/dist/core/rfc-generator.d.ts +147 -0
  75. package/dist/core/rfc-generator.d.ts.map +1 -0
  76. package/dist/core/rfc-generator.js +434 -0
  77. package/dist/core/rfc-generator.js.map +1 -0
  78. package/dist/integrations/ado/ado-client.d.ts +123 -0
  79. package/dist/integrations/ado/ado-client.d.ts.map +1 -0
  80. package/dist/integrations/ado/ado-client.js +398 -0
  81. package/dist/integrations/ado/ado-client.js.map +1 -0
  82. package/dist/integrations/jira/jira-client.d.ts +139 -0
  83. package/dist/integrations/jira/jira-client.d.ts.map +1 -0
  84. package/dist/integrations/jira/jira-client.js +386 -0
  85. package/dist/integrations/jira/jira-client.js.map +1 -0
  86. package/dist/integrations/jira/jira-incremental-mapper.d.ts +75 -0
  87. package/dist/integrations/jira/jira-incremental-mapper.d.ts.map +1 -0
  88. package/dist/integrations/jira/jira-incremental-mapper.js +474 -0
  89. package/dist/integrations/jira/jira-incremental-mapper.js.map +1 -0
  90. package/dist/integrations/jira/jira-mapper.d.ts +105 -0
  91. package/dist/integrations/jira/jira-mapper.d.ts.map +1 -0
  92. package/dist/integrations/jira/jira-mapper.js +494 -0
  93. package/dist/integrations/jira/jira-mapper.js.map +1 -0
  94. package/dist/testing/test-generator.d.ts +117 -0
  95. package/dist/testing/test-generator.d.ts.map +1 -0
  96. package/dist/testing/test-generator.js +370 -0
  97. package/dist/testing/test-generator.js.map +1 -0
  98. package/dist/utils/auto-install.d.ts +3 -0
  99. package/dist/utils/auto-install.d.ts.map +1 -1
  100. package/dist/utils/auto-install.js +16 -82
  101. package/dist/utils/auto-install.js.map +1 -1
  102. package/dist/utils/esm-helpers.d.ts +50 -0
  103. package/dist/utils/esm-helpers.d.ts.map +1 -0
  104. package/dist/utils/esm-helpers.js +57 -0
  105. package/dist/utils/esm-helpers.js.map +1 -0
  106. package/package.json +16 -7
  107. package/src/adapters/README.md +1 -2
  108. package/src/adapters/adapter-base.ts +6 -3
  109. package/src/adapters/adapter-loader.ts +261 -0
  110. package/src/adapters/agents-md-generator.ts +162 -0
  111. package/src/adapters/claude/README.md +6 -14
  112. package/src/adapters/claude/adapter.ts +4 -4
  113. package/src/adapters/claude-md-generator.ts +311 -0
  114. package/src/adapters/codex/README.md +105 -0
  115. package/src/adapters/codex/adapter.ts +333 -0
  116. package/src/adapters/copilot/adapter.ts +36 -65
  117. package/src/adapters/cursor/README.md +0 -2
  118. package/src/adapters/cursor/adapter.ts +46 -92
  119. package/src/adapters/doc-generator.ts +331 -0
  120. package/src/adapters/gemini/README.md +97 -0
  121. package/src/adapters/gemini/adapter.ts +298 -0
  122. package/src/adapters/generic/adapter.ts +61 -57
  123. package/src/adapters/registry.yaml +86 -25
  124. package/src/agents/devops/AGENT.md +16 -18
  125. package/src/agents/docs-writer/AGENT.md +2 -2
  126. package/src/agents/pm/AGENT.md +1 -50
  127. package/src/commands/README.md +134 -111
  128. package/src/commands/{build.md → specweave.do.md} +141 -69
  129. package/src/commands/{done.md → specweave.done.md} +3 -3
  130. package/src/commands/{inc.md → specweave.inc.md} +4 -4
  131. package/src/commands/{increment.md → specweave.increment.md} +143 -76
  132. package/src/commands/specweave.md +430 -0
  133. package/src/commands/specweave.next.md +495 -0
  134. package/src/commands/{progress.md → specweave.progress.md} +12 -12
  135. package/src/commands/specweave.sync-docs.md +665 -0
  136. package/src/commands/specweave.sync-github.md +269 -0
  137. package/src/commands/specweave.sync-jira.md +197 -0
  138. package/src/commands/{validate.md → specweave.validate.md} +4 -4
  139. package/src/hooks/README.md +19 -29
  140. package/src/hooks/post-task-completion.sh +25 -30
  141. package/src/skills/ado-sync/README.md +1 -36
  142. package/src/skills/bmad-method-expert/SKILL.md +1 -3
  143. package/src/skills/brownfield-analyzer/SKILL.md +429 -23
  144. package/src/skills/brownfield-onboarder/SKILL.md +221 -8
  145. package/src/skills/context-loader/SKILL.md +239 -617
  146. package/src/skills/context-optimizer/SKILL.md +0 -30
  147. package/src/skills/github-sync/SKILL.md +1 -19
  148. package/src/skills/increment-planner/SKILL.md +64 -18
  149. package/src/skills/increment-quality-judge/SKILL.md +1 -36
  150. package/src/skills/jira-sync/README.md +1 -38
  151. package/src/skills/role-orchestrator/README.md +1 -22
  152. package/src/skills/role-orchestrator/SKILL.md +1 -59
  153. package/src/skills/skill-router/SKILL.md +0 -18
  154. package/src/skills/spec-kit-expert/SKILL.md +1 -3
  155. package/src/skills/specweave-detector/SKILL.md +225 -275
  156. package/src/skills/task-builder/README.md +1 -7
  157. package/src/templates/AGENTS.md.template +334 -0
  158. package/src/templates/CLAUDE.md.template +131 -298
  159. package/src/templates/README.md.template +115 -23
  160. package/src/templates/environments/minimal/README.md +0 -1
  161. package/INSTALL.md +0 -848
  162. package/SPECWEAVE.md +0 -743
  163. package/src/adapters/copilot/.github/copilot/instructions.md +0 -376
  164. package/src/adapters/cursor/.cursorrules +0 -325
  165. package/src/adapters/generic/SPECWEAVE-MANUAL.md +0 -676
  166. package/src/commands/create-project.md +0 -528
  167. package/src/commands/generate-docs.md +0 -623
  168. package/src/commands/review-docs.md +0 -331
  169. package/src/commands/sync-github.md +0 -115
  170. package/src/skills/ado-sync/test-cases/test-1.yaml +0 -9
  171. package/src/skills/ado-sync/test-cases/test-2.yaml +0 -8
  172. package/src/skills/ado-sync/test-cases/test-3.yaml +0 -9
  173. package/src/skills/bmad-method-expert/test-cases/test-1-placeholder.yaml +0 -12
  174. package/src/skills/bmad-method-expert/test-cases/test-2-placeholder.yaml +0 -12
  175. package/src/skills/bmad-method-expert/test-cases/test-3-placeholder.yaml +0 -12
  176. package/src/skills/brownfield-analyzer/test-cases/test-1-basic-analysis.yaml +0 -48
  177. package/src/skills/brownfield-analyzer/test-cases/test-2-placeholder.yaml +0 -12
  178. package/src/skills/brownfield-analyzer/test-cases/test-3-placeholder.yaml +0 -12
  179. package/src/skills/brownfield-onboarder/test-cases/test-1-placeholder.yaml +0 -12
  180. package/src/skills/brownfield-onboarder/test-cases/test-2-placeholder.yaml +0 -12
  181. package/src/skills/brownfield-onboarder/test-cases/test-3-placeholder.yaml +0 -12
  182. package/src/skills/calendar-system/test-cases/test-1-placeholder.yaml +0 -12
  183. package/src/skills/calendar-system/test-cases/test-2-placeholder.yaml +0 -12
  184. package/src/skills/calendar-system/test-cases/test-3-placeholder.yaml +0 -12
  185. package/src/skills/context-loader/test-cases/test-1-basic-loading.yaml +0 -39
  186. package/src/skills/context-loader/test-cases/test-2-token-budget-exceeded.yaml +0 -44
  187. package/src/skills/context-loader/test-cases/test-3-section-anchors.yaml +0 -45
  188. package/src/skills/context-optimizer/test-cases/test-1-bug-fix-narrow.yaml +0 -97
  189. package/src/skills/context-optimizer/test-cases/test-2-feature-focused.yaml +0 -109
  190. package/src/skills/context-optimizer/test-cases/test-3-architecture-broad.yaml +0 -98
  191. package/src/skills/cost-optimizer/test-cases/test-1-basic-comparison.yaml +0 -75
  192. package/src/skills/cost-optimizer/test-cases/test-2-budget-constraint.yaml +0 -52
  193. package/src/skills/cost-optimizer/test-cases/test-3-scale-requirement.yaml +0 -63
  194. package/src/skills/cost-optimizer/test-results/README.md +0 -46
  195. package/src/skills/design-system-architect/test-cases/test-1-token-structure.yaml +0 -23
  196. package/src/skills/design-system-architect/test-cases/test-2-component-hierarchy.yaml +0 -24
  197. package/src/skills/design-system-architect/test-cases/test-3-accessibility-checklist.yaml +0 -23
  198. package/src/skills/diagrams-architect/test-cases/test-1-c4-context.yaml +0 -13
  199. package/src/skills/diagrams-architect/test-cases/test-2-sequence-diagram.yaml +0 -13
  200. package/src/skills/diagrams-architect/test-cases/test-3-er-diagram.yaml +0 -13
  201. package/src/skills/diagrams-generator/test-cases/test-1.yaml +0 -9
  202. package/src/skills/diagrams-generator/test-cases/test-2.yaml +0 -9
  203. package/src/skills/diagrams-generator/test-cases/test-3.yaml +0 -8
  204. package/src/skills/docs-updater/test-cases/test-1-placeholder.yaml +0 -12
  205. package/src/skills/docs-updater/test-cases/test-2-placeholder.yaml +0 -12
  206. package/src/skills/docs-updater/test-cases/test-3-placeholder.yaml +0 -12
  207. package/src/skills/dotnet-backend/test-cases/test-1-rest-api.yaml +0 -14
  208. package/src/skills/dotnet-backend/test-cases/test-2-authentication.yaml +0 -13
  209. package/src/skills/dotnet-backend/test-cases/test-3-minimal-api.yaml +0 -13
  210. package/src/skills/e2e-playwright/test-cases/TC-001-basic-navigation.yaml +0 -54
  211. package/src/skills/e2e-playwright/test-cases/TC-002-form-interaction.yaml +0 -64
  212. package/src/skills/e2e-playwright/test-cases/TC-003-specweave-integration.yaml +0 -74
  213. package/src/skills/e2e-playwright/test-cases/TC-004-accessibility-check.yaml +0 -98
  214. package/src/skills/figma-designer/test-cases/test-1-design-system.yaml +0 -13
  215. package/src/skills/figma-designer/test-cases/test-2-component-library.yaml +0 -13
  216. package/src/skills/figma-designer/test-cases/test-3-responsive-layout.yaml +0 -13
  217. package/src/skills/figma-implementer/test-cases/test-1-design-to-react.yaml +0 -13
  218. package/src/skills/figma-implementer/test-cases/test-2-storybook.yaml +0 -13
  219. package/src/skills/figma-implementer/test-cases/test-3-design-tokens.yaml +0 -13
  220. package/src/skills/figma-mcp-connector/test-cases/test-1-read-file-desktop.yaml +0 -22
  221. package/src/skills/figma-mcp-connector/test-cases/test-2-read-file-framelink.yaml +0 -21
  222. package/src/skills/figma-mcp-connector/test-cases/test-3-error-handling.yaml +0 -18
  223. package/src/skills/figma-to-code/test-cases/test-1-token-generation.yaml +0 -29
  224. package/src/skills/figma-to-code/test-cases/test-2-component-generation.yaml +0 -27
  225. package/src/skills/figma-to-code/test-cases/test-3-typescript-generation.yaml +0 -28
  226. package/src/skills/frontend/test-cases/test-1-react-component.yaml +0 -13
  227. package/src/skills/frontend/test-cases/test-2-form-validation.yaml +0 -13
  228. package/src/skills/frontend/test-cases/test-3-state-management.yaml +0 -13
  229. package/src/skills/github-sync/test-cases/test-1-placeholder.yaml +0 -12
  230. package/src/skills/github-sync/test-cases/test-2-placeholder.yaml +0 -12
  231. package/src/skills/github-sync/test-cases/test-3-placeholder.yaml +0 -12
  232. package/src/skills/hetzner-provisioner/test-cases/test-1-basic-provision.yaml +0 -71
  233. package/src/skills/hetzner-provisioner/test-cases/test-2-postgres-provision.yaml +0 -85
  234. package/src/skills/hetzner-provisioner/test-cases/test-3-ssl-config.yaml +0 -126
  235. package/src/skills/hetzner-provisioner/test-results/README.md +0 -259
  236. package/src/skills/increment-planner/test-cases/test-1-basic-feature.yaml +0 -27
  237. package/src/skills/increment-planner/test-cases/test-2-complex-feature.yaml +0 -30
  238. package/src/skills/increment-planner/test-cases/test-3-auto-numbering.yaml +0 -24
  239. package/src/skills/increment-quality-judge/test-cases/test-1-good-spec.yaml +0 -95
  240. package/src/skills/increment-quality-judge/test-cases/test-2-poor-spec.yaml +0 -108
  241. package/src/skills/increment-quality-judge/test-cases/test-3-export-suggestions.yaml +0 -87
  242. package/src/skills/jira-sync/test-cases/test-1.yaml +0 -9
  243. package/src/skills/jira-sync/test-cases/test-2.yaml +0 -9
  244. package/src/skills/jira-sync/test-cases/test-3.yaml +0 -10
  245. package/src/skills/nextjs/test-cases/test-1-app-router.yaml +0 -13
  246. package/src/skills/nextjs/test-cases/test-2-server-actions.yaml +0 -13
  247. package/src/skills/nextjs/test-cases/test-3-api-routes.yaml +0 -13
  248. package/src/skills/nodejs-backend/test-cases/test-1-express-api.yaml +0 -13
  249. package/src/skills/nodejs-backend/test-cases/test-2-prisma-orm.yaml +0 -13
  250. package/src/skills/nodejs-backend/test-cases/test-3-authentication.yaml +0 -13
  251. package/src/skills/notification-system/test-cases/test-1-placeholder.yaml +0 -12
  252. package/src/skills/notification-system/test-cases/test-2-placeholder.yaml +0 -12
  253. package/src/skills/notification-system/test-cases/test-3-placeholder.yaml +0 -12
  254. package/src/skills/python-backend/test-cases/test-1-fastapi-crud.yaml +0 -13
  255. package/src/skills/python-backend/test-cases/test-2-sqlalchemy.yaml +0 -13
  256. package/src/skills/python-backend/test-cases/test-3-authentication.yaml +0 -13
  257. package/src/skills/role-orchestrator/test-cases/test-1-simple-product.yaml +0 -98
  258. package/src/skills/role-orchestrator/test-cases/test-2-quality-gate-failure.yaml +0 -73
  259. package/src/skills/role-orchestrator/test-cases/test-3-security-workflow.yaml +0 -121
  260. package/src/skills/role-orchestrator/test-cases/test-4-parallel-execution.yaml +0 -145
  261. package/src/skills/role-orchestrator/test-cases/test-5-feedback-loops.yaml +0 -149
  262. package/src/skills/skill-creator/test-cases/test-1-placeholder.yaml +0 -12
  263. package/src/skills/skill-creator/test-cases/test-2-placeholder.yaml +0 -12
  264. package/src/skills/skill-creator/test-cases/test-3-placeholder.yaml +0 -12
  265. package/src/skills/skill-router/test-cases/test-1-basic-routing.yaml +0 -33
  266. package/src/skills/skill-router/test-cases/test-2-ambiguous-request.yaml +0 -42
  267. package/src/skills/skill-router/test-cases/test-3-nested-orchestration.yaml +0 -50
  268. package/src/skills/spec-driven-brainstorming/test-cases/TC-001-simple-idea-to-design.yaml +0 -148
  269. package/src/skills/spec-driven-brainstorming/test-cases/TC-002-complex-ultrathink-design.yaml +0 -190
  270. package/src/skills/spec-driven-brainstorming/test-cases/TC-003-unclear-requirements-socratic.yaml +0 -233
  271. package/src/skills/spec-driven-debugging/test-cases/TC-001-simple-auth-bug.yaml +0 -212
  272. package/src/skills/spec-driven-debugging/test-cases/TC-002-race-condition-ultrathink.yaml +0 -461
  273. package/src/skills/spec-driven-debugging/test-cases/TC-003-brownfield-missing-spec.yaml +0 -366
  274. package/src/skills/spec-kit-expert/test-cases/test-1-placeholder.yaml +0 -12
  275. package/src/skills/spec-kit-expert/test-cases/test-2-placeholder.yaml +0 -12
  276. package/src/skills/spec-kit-expert/test-cases/test-3-placeholder.yaml +0 -12
  277. package/src/skills/specweave-ado-mapper/test-cases/test-1-export-to-ado.yaml +0 -13
  278. package/src/skills/specweave-ado-mapper/test-cases/test-2-import-from-ado.yaml +0 -13
  279. package/src/skills/specweave-ado-mapper/test-cases/test-3-bidirectional-sync.yaml +0 -13
  280. package/src/skills/specweave-detector/test-cases/test-1-basic-detection.yaml +0 -37
  281. package/src/skills/specweave-detector/test-cases/test-2-missing-config.yaml +0 -37
  282. package/src/skills/specweave-detector/test-cases/test-3-non-specweave-project.yaml +0 -34
  283. package/src/skills/specweave-jira-mapper/test-cases/test-1-export-to-jira.yaml +0 -13
  284. package/src/skills/specweave-jira-mapper/test-cases/test-2-import-from-jira.yaml +0 -13
  285. package/src/skills/specweave-jira-mapper/test-cases/test-3-sync-status.yaml +0 -13
  286. package/src/skills/stripe-integrator/test-cases/test-1-placeholder.yaml +0 -12
  287. package/src/skills/stripe-integrator/test-cases/test-2-placeholder.yaml +0 -12
  288. package/src/skills/stripe-integrator/test-cases/test-3-placeholder.yaml +0 -12
  289. package/src/skills/task-builder/test-cases/test-1-placeholder.yaml +0 -12
  290. package/src/skills/task-builder/test-cases/test-2-placeholder.yaml +0 -12
  291. package/src/skills/task-builder/test-cases/test-3-placeholder.yaml +0 -12
  292. package/src/templates/config.yaml +0 -351
  293. /package/src/commands/{list-increments.md → specweave.list-increments.md} +0 -0
@@ -0,0 +1,271 @@
1
+ /**
2
+ * Secure Credentials Manager
3
+ *
4
+ * Handles API keys and credentials for external integrations (Jira, ADO, etc.)
5
+ * - Loads from .env file or environment variables
6
+ * - Validates credential format
7
+ * - Never logs secrets
8
+ * - Provides masked logging for debugging
9
+ */
10
+ import * as fs from 'fs';
11
+ import * as path from 'path';
12
+ export class CredentialsManager {
13
+ constructor() {
14
+ this.credentials = {};
15
+ this.envLoaded = false;
16
+ this.loadFromEnv();
17
+ }
18
+ static getInstance() {
19
+ if (!CredentialsManager.instance) {
20
+ CredentialsManager.instance = new CredentialsManager();
21
+ }
22
+ return CredentialsManager.instance;
23
+ }
24
+ /**
25
+ * Load credentials from .env file or environment variables
26
+ */
27
+ loadFromEnv() {
28
+ // First, try to load from .env file
29
+ const envPath = path.join(process.cwd(), '.env');
30
+ if (fs.existsSync(envPath)) {
31
+ const envContent = fs.readFileSync(envPath, 'utf-8');
32
+ const envVars = this.parseEnvFile(envContent);
33
+ // Merge with process.env (process.env takes precedence)
34
+ Object.keys(envVars).forEach(key => {
35
+ if (!process.env[key]) {
36
+ process.env[key] = envVars[key];
37
+ }
38
+ });
39
+ }
40
+ // Load ADO credentials
41
+ if (process.env.AZURE_DEVOPS_PAT) {
42
+ this.credentials.ado = {
43
+ pat: process.env.AZURE_DEVOPS_PAT,
44
+ organization: process.env.AZURE_DEVOPS_ORG || '',
45
+ project: process.env.AZURE_DEVOPS_PROJECT || ''
46
+ };
47
+ }
48
+ // Load Jira credentials
49
+ if (process.env.JIRA_API_TOKEN) {
50
+ this.credentials.jira = {
51
+ apiToken: process.env.JIRA_API_TOKEN,
52
+ email: process.env.JIRA_EMAIL || '',
53
+ domain: process.env.JIRA_DOMAIN || ''
54
+ };
55
+ }
56
+ this.envLoaded = true;
57
+ }
58
+ /**
59
+ * Parse .env file content into key-value pairs
60
+ */
61
+ parseEnvFile(content) {
62
+ const result = {};
63
+ const lines = content.split('\n');
64
+ for (const line of lines) {
65
+ const trimmed = line.trim();
66
+ // Skip empty lines and comments
67
+ if (!trimmed || trimmed.startsWith('#')) {
68
+ continue;
69
+ }
70
+ // Parse KEY=VALUE
71
+ const match = trimmed.match(/^([^=]+)=(.*)$/);
72
+ if (match) {
73
+ const key = match[1].trim();
74
+ let value = match[2].trim();
75
+ // Remove quotes if present
76
+ if ((value.startsWith('"') && value.endsWith('"')) ||
77
+ (value.startsWith("'") && value.endsWith("'"))) {
78
+ value = value.slice(1, -1);
79
+ }
80
+ result[key] = value;
81
+ }
82
+ }
83
+ return result;
84
+ }
85
+ /**
86
+ * Get ADO credentials
87
+ * @throws Error if credentials not found
88
+ */
89
+ getAdoCredentials() {
90
+ if (!this.credentials.ado) {
91
+ throw new Error('Azure DevOps credentials not found. Please set AZURE_DEVOPS_PAT, ' +
92
+ 'AZURE_DEVOPS_ORG, and AZURE_DEVOPS_PROJECT in .env file or environment variables.');
93
+ }
94
+ this.validateAdoCredentials(this.credentials.ado);
95
+ return this.credentials.ado;
96
+ }
97
+ /**
98
+ * Get Jira credentials
99
+ * @throws Error if credentials not found
100
+ */
101
+ getJiraCredentials() {
102
+ if (!this.credentials.jira) {
103
+ throw new Error('Jira credentials not found. Please set JIRA_API_TOKEN, JIRA_EMAIL, ' +
104
+ 'and JIRA_DOMAIN in .env file or environment variables.');
105
+ }
106
+ this.validateJiraCredentials(this.credentials.jira);
107
+ return this.credentials.jira;
108
+ }
109
+ /**
110
+ * Check if ADO credentials are available
111
+ */
112
+ hasAdoCredentials() {
113
+ return !!this.credentials.ado?.pat;
114
+ }
115
+ /**
116
+ * Check if Jira credentials are available
117
+ */
118
+ hasJiraCredentials() {
119
+ return !!this.credentials.jira?.apiToken;
120
+ }
121
+ /**
122
+ * Validate ADO credentials format
123
+ */
124
+ validateAdoCredentials(creds) {
125
+ if (!creds.pat || creds.pat.length !== 52) {
126
+ console.warn(`⚠️ Azure DevOps PAT length unexpected. Expected: 52 characters, Got: ${creds.pat.length}`);
127
+ }
128
+ if (!creds.organization || !/^[a-zA-Z0-9-]+$/.test(creds.organization)) {
129
+ throw new Error(`Invalid Azure DevOps organization: "${creds.organization}". ` +
130
+ 'Expected: alphanumeric and hyphens only.');
131
+ }
132
+ if (!creds.project) {
133
+ throw new Error('Azure DevOps project name is required.');
134
+ }
135
+ }
136
+ /**
137
+ * Validate Jira credentials format
138
+ */
139
+ validateJiraCredentials(creds) {
140
+ const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
141
+ if (!emailRegex.test(creds.email)) {
142
+ throw new Error(`Invalid Jira email: "${creds.email}". Expected: valid email address.`);
143
+ }
144
+ if (!creds.domain.includes('.atlassian.net') && !creds.domain.includes('://')) {
145
+ console.warn(`⚠️ Jira domain format unexpected: "${creds.domain}". ` +
146
+ 'Expected: *.atlassian.net or custom domain with protocol.');
147
+ }
148
+ if (!creds.apiToken) {
149
+ throw new Error('Jira API token is required.');
150
+ }
151
+ }
152
+ /**
153
+ * Get masked version of credentials for logging (safe to display)
154
+ */
155
+ getMaskedAdoInfo() {
156
+ if (!this.credentials.ado) {
157
+ return 'ADO credentials: Not configured';
158
+ }
159
+ return [
160
+ 'ADO credentials:',
161
+ ` PAT: ${this.maskSecret(this.credentials.ado.pat)}`,
162
+ ` Organization: ${this.credentials.ado.organization}`,
163
+ ` Project: ${this.credentials.ado.project}`
164
+ ].join('\n');
165
+ }
166
+ /**
167
+ * Get masked version of credentials for logging (safe to display)
168
+ */
169
+ getMaskedJiraInfo() {
170
+ if (!this.credentials.jira) {
171
+ return 'Jira credentials: Not configured';
172
+ }
173
+ return [
174
+ 'Jira credentials:',
175
+ ` API Token: ${this.maskSecret(this.credentials.jira.apiToken)}`,
176
+ ` Email: ${this.credentials.jira.email}`,
177
+ ` Domain: ${this.credentials.jira.domain}`
178
+ ].join('\n');
179
+ }
180
+ /**
181
+ * Mask a secret for safe logging
182
+ */
183
+ maskSecret(secret) {
184
+ if (!secret)
185
+ return '[EMPTY]';
186
+ if (secret.length <= 8)
187
+ return '****';
188
+ const visibleChars = 4;
189
+ const start = secret.slice(0, visibleChars);
190
+ const end = secret.slice(-visibleChars);
191
+ return `${start}...${end} (${secret.length} chars)`;
192
+ }
193
+ /**
194
+ * Save credentials to .env file (with backup)
195
+ */
196
+ saveToEnvFile(config) {
197
+ const envPath = path.join(process.cwd(), '.env');
198
+ // Backup existing .env
199
+ if (fs.existsSync(envPath)) {
200
+ const backup = `${envPath}.backup.${Date.now()}`;
201
+ fs.copyFileSync(envPath, backup);
202
+ console.log(`📦 Backed up existing .env to: ${backup}`);
203
+ }
204
+ // Read existing content
205
+ let existingContent = '';
206
+ let existingVars = {};
207
+ if (fs.existsSync(envPath)) {
208
+ existingContent = fs.readFileSync(envPath, 'utf-8');
209
+ existingVars = this.parseEnvFile(existingContent);
210
+ }
211
+ // Update with new credentials
212
+ if (config.ado) {
213
+ existingVars.AZURE_DEVOPS_PAT = config.ado.pat;
214
+ existingVars.AZURE_DEVOPS_ORG = config.ado.organization;
215
+ existingVars.AZURE_DEVOPS_PROJECT = config.ado.project;
216
+ }
217
+ if (config.jira) {
218
+ existingVars.JIRA_API_TOKEN = config.jira.apiToken;
219
+ existingVars.JIRA_EMAIL = config.jira.email;
220
+ existingVars.JIRA_DOMAIN = config.jira.domain;
221
+ }
222
+ // Write back to .env
223
+ const newContent = Object.entries(existingVars)
224
+ .map(([key, value]) => `${key}=${value}`)
225
+ .join('\n');
226
+ fs.writeFileSync(envPath, newContent + '\n', 'utf-8');
227
+ console.log('✅ Credentials saved to .env');
228
+ // Ensure .env is in .gitignore
229
+ this.ensureGitignore();
230
+ // Reload credentials
231
+ this.loadFromEnv();
232
+ }
233
+ /**
234
+ * Ensure .env is in .gitignore
235
+ */
236
+ ensureGitignore() {
237
+ const gitignorePath = path.join(process.cwd(), '.gitignore');
238
+ let gitignoreContent = '';
239
+ if (fs.existsSync(gitignorePath)) {
240
+ gitignoreContent = fs.readFileSync(gitignorePath, 'utf-8');
241
+ }
242
+ if (!gitignoreContent.includes('.env')) {
243
+ fs.appendFileSync(gitignorePath, '\n# Environment variables\n.env\n.env.*.backup\n');
244
+ console.log('✅ Added .env to .gitignore');
245
+ }
246
+ }
247
+ /**
248
+ * Create .env.example file for team
249
+ */
250
+ createEnvExample() {
251
+ const examplePath = path.join(process.cwd(), '.env.example');
252
+ const exampleContent = `# Azure DevOps Personal Access Token
253
+ # Get from: https://dev.azure.com/{org}/_usersSettings/tokens
254
+ # Scopes: Work Items (Read, Write, Manage), Code (Read), Project (Read)
255
+ AZURE_DEVOPS_PAT=your-ado-pat-52-chars-base64
256
+ AZURE_DEVOPS_ORG=your-organization-name
257
+ AZURE_DEVOPS_PROJECT=your-project-name
258
+
259
+ # Jira API Token
260
+ # Get from: https://id.atlassian.com/manage-profile/security/api-tokens
261
+ JIRA_API_TOKEN=your-jira-api-token
262
+ JIRA_EMAIL=your-email@example.com
263
+ JIRA_DOMAIN=your-domain.atlassian.net
264
+ `;
265
+ fs.writeFileSync(examplePath, exampleContent, 'utf-8');
266
+ console.log('✅ Created .env.example (safe to commit)');
267
+ }
268
+ }
269
+ // Export singleton instance
270
+ export const credentialsManager = CredentialsManager.getInstance();
271
+ //# sourceMappingURL=credentials-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials-manager.js","sourceRoot":"","sources":["../../src/core/credentials-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Project Structure Detector
3
+ *
4
+ * Automatically detects project management structure from:
5
+ * - Existing increments and work items
6
+ * - Source system metadata (Jira, ADO, GitHub)
7
+ * - Environment variables
8
+ *
9
+ * Supports various hierarchies:
10
+ * - Jira: Epic → Story → Sub-task
11
+ * - ADO: Epic → Feature → User Story → Task
12
+ * - GitHub: Milestone → Issue (or flat Issues)
13
+ * - Custom: Detected from patterns
14
+ */
15
+ /**
16
+ * Hierarchy levels:
17
+ * - FLAT: No hierarchy (GitHub issues, flat ADO)
18
+ * - SINGLE_PARENT: Milestone/Feature → Items
19
+ * - TWO_LEVEL: Epic → Stories → Tasks
20
+ * - THREE_LEVEL: Initiative → Epic → Feature → Stories
21
+ */
22
+ export type HierarchyLevel = 'flat' | 'single_parent' | 'two_level' | 'three_level';
23
+ /**
24
+ * Work item types vary by system
25
+ */
26
+ export interface WorkItemTypes {
27
+ topLevel?: string;
28
+ parentLevel?: string;
29
+ itemLevel: string;
30
+ subItemLevel?: string;
31
+ }
32
+ /**
33
+ * Grouping strategy for RFC organization
34
+ */
35
+ export type GroupingStrategy = 'by_type' | 'by_parent' | 'by_priority' | 'by_label' | 'flat' | 'custom';
36
+ /**
37
+ * Project structure configuration
38
+ */
39
+ export interface ProjectStructure {
40
+ source: 'jira' | 'ado' | 'github' | 'manual';
41
+ hierarchyLevel: HierarchyLevel;
42
+ workItemTypes: WorkItemTypes;
43
+ groupingStrategy: GroupingStrategy;
44
+ customGrouping?: (items: any[]) => Record<string, any[]>;
45
+ epicFieldName?: string;
46
+ featureFieldName?: string;
47
+ milestoneFieldName?: string;
48
+ }
49
+ /**
50
+ * Detected structure from analysis
51
+ */
52
+ export interface DetectedStructure {
53
+ structure: ProjectStructure;
54
+ confidence: number;
55
+ evidence: string[];
56
+ sampleIncrements: string[];
57
+ }
58
+ export declare class ProjectStructureDetector {
59
+ private projectRoot;
60
+ constructor(projectRoot?: string);
61
+ /**
62
+ * Detect project structure with pure auto-detection
63
+ */
64
+ detectStructure(): Promise<ProjectStructure>;
65
+ /**
66
+ * Auto-detect structure from existing increments
67
+ */
68
+ private autoDetectStructure;
69
+ /**
70
+ * Analyze increments to detect structure
71
+ */
72
+ private analyzeIncrements;
73
+ /**
74
+ * Infer work item types from source and hierarchy
75
+ */
76
+ private inferWorkItemTypes;
77
+ /**
78
+ * Infer grouping strategy from source and hierarchy
79
+ */
80
+ private inferGroupingStrategy;
81
+ /**
82
+ * Get default structure when no increments exist
83
+ */
84
+ private getDefaultStructure;
85
+ /**
86
+ * Get structure summary for display
87
+ */
88
+ getStructureSummary(structure: ProjectStructure): string;
89
+ private getHierarchyDescription;
90
+ private getGroupingDescription;
91
+ }
92
+ //# sourceMappingURL=project-structure-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-structure-detector.d.ts","sourceRoot":"","sources":["../../src/core/project-structure-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,eAAe,GAAG,WAAW,GAAG,aAAa,CAAC;AAEpF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,WAAW,GACX,aAAa,GACb,UAAU,GACV,MAAM,GACN,QAAQ,CAAC;AAEb;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC7C,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IAGzD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,gBAAgB,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,qBAAa,wBAAwB;IACnC,OAAO,CAAC,WAAW,CAAS;gBAEhB,WAAW,GAAE,MAAsB;IAI/C;;OAEG;IACU,eAAe,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAMzD;;OAEG;YACW,mBAAmB;IA2BjC;;OAEG;YACW,iBAAiB;IA2G/B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAqC1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAwB7B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAwD3B;;OAEG;IACI,mBAAmB,CAAC,SAAS,EAAE,gBAAgB,GAAG,MAAM;IAO/D,OAAO,CAAC,uBAAuB;IAY/B,OAAO,CAAC,sBAAsB;CAY/B"}
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Project Structure Detector
3
+ *
4
+ * Automatically detects project management structure from:
5
+ * - Existing increments and work items
6
+ * - Source system metadata (Jira, ADO, GitHub)
7
+ * - Environment variables
8
+ *
9
+ * Supports various hierarchies:
10
+ * - Jira: Epic → Story → Sub-task
11
+ * - ADO: Epic → Feature → User Story → Task
12
+ * - GitHub: Milestone → Issue (or flat Issues)
13
+ * - Custom: Detected from patterns
14
+ */
15
+ import * as fs from 'fs';
16
+ import * as path from 'path';
17
+ import * as yaml from 'js-yaml';
18
+ export class ProjectStructureDetector {
19
+ constructor(projectRoot = process.cwd()) {
20
+ this.projectRoot = projectRoot;
21
+ }
22
+ /**
23
+ * Detect project structure with pure auto-detection
24
+ */
25
+ async detectStructure() {
26
+ // Auto-detect from existing increments
27
+ const detected = await this.autoDetectStructure();
28
+ return detected.structure;
29
+ }
30
+ /**
31
+ * Auto-detect structure from existing increments
32
+ */
33
+ async autoDetectStructure() {
34
+ const incrementsDir = path.join(this.projectRoot, '.specweave', 'increments');
35
+ if (!fs.existsSync(incrementsDir)) {
36
+ // No increments yet, use defaults based on source
37
+ return this.getDefaultStructure();
38
+ }
39
+ const increments = fs.readdirSync(incrementsDir)
40
+ .filter(name => /^\d{4}/.test(name))
41
+ .slice(0, 5); // Analyze first 5 increments
42
+ if (increments.length === 0) {
43
+ return this.getDefaultStructure();
44
+ }
45
+ // Analyze increments for patterns
46
+ const analysis = await this.analyzeIncrements(increments);
47
+ return {
48
+ structure: analysis.structure,
49
+ confidence: analysis.confidence,
50
+ evidence: analysis.evidence,
51
+ sampleIncrements: increments
52
+ };
53
+ }
54
+ /**
55
+ * Analyze increments to detect structure
56
+ */
57
+ async analyzeIncrements(increments) {
58
+ const evidence = [];
59
+ let hasEpics = false;
60
+ let hasFeatures = false;
61
+ let hasMilestones = false;
62
+ let hasInitiatives = false;
63
+ let source = 'manual';
64
+ const workItemTypesSeen = new Set();
65
+ for (const increment of increments) {
66
+ const specPath = path.join(this.projectRoot, '.specweave', 'increments', increment, 'spec.md');
67
+ if (!fs.existsSync(specPath))
68
+ continue;
69
+ const content = fs.readFileSync(specPath, 'utf-8');
70
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
71
+ if (!frontmatterMatch)
72
+ continue;
73
+ const frontmatter = yaml.load(frontmatterMatch[1]);
74
+ // Detect source
75
+ if (frontmatter.jira) {
76
+ source = 'jira';
77
+ evidence.push(`Found Jira metadata in ${increment}`);
78
+ if (frontmatter.jira.epic_key) {
79
+ hasEpics = true;
80
+ evidence.push(`Found Epic link: ${frontmatter.jira.epic_key}`);
81
+ }
82
+ }
83
+ if (frontmatter.ado) {
84
+ source = 'ado';
85
+ evidence.push(`Found ADO metadata in ${increment}`);
86
+ if (frontmatter.ado.feature_id) {
87
+ hasFeatures = true;
88
+ evidence.push(`Found Feature link: ${frontmatter.ado.feature_id}`);
89
+ }
90
+ if (frontmatter.ado.epic_id) {
91
+ hasEpics = true;
92
+ evidence.push(`Found Epic link in ADO`);
93
+ }
94
+ }
95
+ if (frontmatter.github) {
96
+ source = 'github';
97
+ evidence.push(`Found GitHub metadata in ${increment}`);
98
+ if (frontmatter.github.milestone) {
99
+ hasMilestones = true;
100
+ evidence.push(`Found Milestone: ${frontmatter.github.milestone}`);
101
+ }
102
+ }
103
+ // Analyze work items
104
+ if (frontmatter.work_items && Array.isArray(frontmatter.work_items)) {
105
+ frontmatter.work_items.forEach((item) => {
106
+ if (item.type) {
107
+ workItemTypesSeen.add(item.type);
108
+ }
109
+ });
110
+ }
111
+ }
112
+ // Determine hierarchy level
113
+ let hierarchyLevel;
114
+ if (hasInitiatives && hasEpics && hasFeatures) {
115
+ hierarchyLevel = 'three_level';
116
+ evidence.push('Detected 3-level hierarchy (Initiative → Epic → Feature → Stories)');
117
+ }
118
+ else if (hasEpics || hasFeatures || hasMilestones) {
119
+ hierarchyLevel = 'two_level';
120
+ evidence.push(`Detected 2-level hierarchy with ${hasEpics ? 'Epics' : hasFeatures ? 'Features' : 'Milestones'}`);
121
+ }
122
+ else if (workItemTypesSeen.size > 0) {
123
+ hierarchyLevel = 'single_parent';
124
+ evidence.push('Detected single-level grouping by type');
125
+ }
126
+ else {
127
+ hierarchyLevel = 'flat';
128
+ evidence.push('Detected flat structure (no hierarchy)');
129
+ }
130
+ // Determine work item types
131
+ const workItemTypes = this.inferWorkItemTypes(source, hierarchyLevel, workItemTypesSeen);
132
+ // Determine grouping strategy
133
+ const groupingStrategy = this.inferGroupingStrategy(source, hierarchyLevel, workItemTypesSeen);
134
+ return {
135
+ structure: {
136
+ source,
137
+ hierarchyLevel,
138
+ workItemTypes,
139
+ groupingStrategy
140
+ },
141
+ confidence: Math.min(increments.length / 5, 1), // More samples = higher confidence
142
+ evidence,
143
+ sampleIncrements: increments
144
+ };
145
+ }
146
+ /**
147
+ * Infer work item types from source and hierarchy
148
+ */
149
+ inferWorkItemTypes(source, hierarchyLevel, typesSeen) {
150
+ switch (source) {
151
+ case 'jira':
152
+ return hierarchyLevel === 'three_level'
153
+ ? { topLevel: 'Initiative', parentLevel: 'Epic', itemLevel: 'Story', subItemLevel: 'Sub-task' }
154
+ : { parentLevel: 'Epic', itemLevel: 'Story', subItemLevel: 'Sub-task' };
155
+ case 'ado':
156
+ if (hierarchyLevel === 'three_level') {
157
+ return { topLevel: 'Epic', parentLevel: 'Feature', itemLevel: 'User Story', subItemLevel: 'Task' };
158
+ }
159
+ else if (hierarchyLevel === 'two_level') {
160
+ return { parentLevel: 'Feature', itemLevel: 'User Story', subItemLevel: 'Task' };
161
+ }
162
+ else {
163
+ return { itemLevel: 'User Story', subItemLevel: 'Task' };
164
+ }
165
+ case 'github':
166
+ return hierarchyLevel === 'two_level'
167
+ ? { parentLevel: 'Milestone', itemLevel: 'Issue' }
168
+ : { itemLevel: 'Issue' };
169
+ default:
170
+ // Infer from types seen
171
+ if (typesSeen.has('story')) {
172
+ return { parentLevel: 'Epic', itemLevel: 'Story', subItemLevel: 'Task' };
173
+ }
174
+ else if (typesSeen.has('issue')) {
175
+ return { itemLevel: 'Issue' };
176
+ }
177
+ else {
178
+ return { itemLevel: 'Item' };
179
+ }
180
+ }
181
+ }
182
+ /**
183
+ * Infer grouping strategy from source and hierarchy
184
+ */
185
+ inferGroupingStrategy(source, hierarchyLevel, typesSeen) {
186
+ // If we see story/bug/task types, group by type
187
+ if (typesSeen.has('story') || typesSeen.has('bug') || typesSeen.has('task')) {
188
+ return 'by_type';
189
+ }
190
+ // If we have parent level (epic, feature, milestone), group by parent
191
+ if (hierarchyLevel === 'two_level' || hierarchyLevel === 'three_level') {
192
+ return 'by_parent';
193
+ }
194
+ // GitHub typically uses flat or by_label
195
+ if (source === 'github') {
196
+ return 'by_label';
197
+ }
198
+ // Default to by_type
199
+ return 'by_type';
200
+ }
201
+ /**
202
+ * Get default structure when no increments exist
203
+ */
204
+ getDefaultStructure() {
205
+ // Try to infer from environment or use sensible defaults
206
+ const envSource = (process.env.JIRA_DOMAIN ? 'jira' :
207
+ process.env.AZURE_DEVOPS_ORG ? 'ado' :
208
+ process.env.GITHUB_REPOSITORY ? 'github' : 'manual');
209
+ const defaultStructures = {
210
+ jira: {
211
+ source: 'jira',
212
+ hierarchyLevel: 'two_level',
213
+ workItemTypes: {
214
+ parentLevel: 'Epic',
215
+ itemLevel: 'Story',
216
+ subItemLevel: 'Sub-task'
217
+ },
218
+ groupingStrategy: 'by_type'
219
+ },
220
+ ado: {
221
+ source: 'ado',
222
+ hierarchyLevel: 'two_level',
223
+ workItemTypes: {
224
+ parentLevel: 'Feature',
225
+ itemLevel: 'User Story',
226
+ subItemLevel: 'Task'
227
+ },
228
+ groupingStrategy: 'by_type'
229
+ },
230
+ github: {
231
+ source: 'github',
232
+ hierarchyLevel: 'two_level',
233
+ workItemTypes: {
234
+ parentLevel: 'Milestone',
235
+ itemLevel: 'Issue'
236
+ },
237
+ groupingStrategy: 'by_label'
238
+ },
239
+ manual: {
240
+ source: 'manual',
241
+ hierarchyLevel: 'two_level',
242
+ workItemTypes: {
243
+ parentLevel: 'Feature',
244
+ itemLevel: 'Story',
245
+ subItemLevel: 'Task'
246
+ },
247
+ groupingStrategy: 'by_type'
248
+ }
249
+ };
250
+ return {
251
+ structure: defaultStructures[envSource],
252
+ confidence: 0.5,
253
+ evidence: ['Using default structure based on environment'],
254
+ sampleIncrements: []
255
+ };
256
+ }
257
+ /**
258
+ * Get structure summary for display
259
+ */
260
+ getStructureSummary(structure) {
261
+ const hierarchy = this.getHierarchyDescription(structure);
262
+ const grouping = this.getGroupingDescription(structure.groupingStrategy);
263
+ return `Source: ${structure.source.toUpperCase()}\nHierarchy: ${hierarchy}\nGrouping: ${grouping}`;
264
+ }
265
+ getHierarchyDescription(structure) {
266
+ const types = structure.workItemTypes;
267
+ const parts = [];
268
+ if (types.topLevel)
269
+ parts.push(types.topLevel);
270
+ if (types.parentLevel)
271
+ parts.push(types.parentLevel);
272
+ parts.push(types.itemLevel);
273
+ if (types.subItemLevel)
274
+ parts.push(types.subItemLevel);
275
+ return parts.join(' → ');
276
+ }
277
+ getGroupingDescription(strategy) {
278
+ const descriptions = {
279
+ by_type: 'Group by Type (Story, Bug, Task)',
280
+ by_parent: 'Group by Parent (Epic, Feature, Milestone)',
281
+ by_priority: 'Group by Priority (P1, P2, P3)',
282
+ by_label: 'Group by Label/Tag',
283
+ flat: 'Flat List (No Grouping)',
284
+ custom: 'Custom Grouping'
285
+ };
286
+ return descriptions[strategy];
287
+ }
288
+ }
289
+ //# sourceMappingURL=project-structure-detector.js.map