specweave 0.7.1 → 0.8.2

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 (137) hide show
  1. package/CLAUDE.md +307 -11
  2. package/README.md +41 -3
  3. package/bin/specweave.js +0 -27
  4. package/dist/cli/commands/import-docs.d.ts +21 -0
  5. package/dist/cli/commands/import-docs.d.ts.map +1 -0
  6. package/dist/cli/commands/import-docs.js +146 -0
  7. package/dist/cli/commands/import-docs.js.map +1 -0
  8. package/dist/cli/commands/init-multiproject.d.ts +11 -0
  9. package/dist/cli/commands/init-multiproject.d.ts.map +1 -0
  10. package/dist/cli/commands/init-multiproject.js +202 -0
  11. package/dist/cli/commands/init-multiproject.js.map +1 -0
  12. package/dist/cli/commands/init.d.ts.map +1 -1
  13. package/dist/cli/commands/init.js +4 -93
  14. package/dist/cli/commands/init.js.map +1 -1
  15. package/dist/cli/commands/migrate-to-multiproject.d.ts +37 -0
  16. package/dist/cli/commands/migrate-to-multiproject.d.ts.map +1 -0
  17. package/dist/cli/commands/migrate-to-multiproject.js +189 -0
  18. package/dist/cli/commands/migrate-to-multiproject.js.map +1 -0
  19. package/dist/cli/commands/migrate-to-profiles.d.ts +25 -0
  20. package/dist/cli/commands/migrate-to-profiles.d.ts.map +1 -0
  21. package/dist/cli/commands/migrate-to-profiles.js +350 -0
  22. package/dist/cli/commands/migrate-to-profiles.js.map +1 -0
  23. package/dist/cli/commands/switch-project.d.ts +13 -0
  24. package/dist/cli/commands/switch-project.d.ts.map +1 -0
  25. package/dist/cli/commands/switch-project.js +91 -0
  26. package/dist/cli/commands/switch-project.js.map +1 -0
  27. package/dist/cli/helpers/issue-tracker/index.js +4 -4
  28. package/dist/cli/helpers/issue-tracker/index.js.map +1 -1
  29. package/dist/cli/helpers/issue-tracker/utils.d.ts +6 -3
  30. package/dist/cli/helpers/issue-tracker/utils.d.ts.map +1 -1
  31. package/dist/cli/helpers/issue-tracker/utils.js +9 -7
  32. package/dist/cli/helpers/issue-tracker/utils.js.map +1 -1
  33. package/dist/core/brownfield/analyzer.d.ts +86 -0
  34. package/dist/core/brownfield/analyzer.d.ts.map +1 -0
  35. package/dist/core/brownfield/analyzer.js +365 -0
  36. package/dist/core/brownfield/analyzer.js.map +1 -0
  37. package/dist/core/brownfield/importer.d.ts +76 -0
  38. package/dist/core/brownfield/importer.d.ts.map +1 -0
  39. package/dist/core/brownfield/importer.js +287 -0
  40. package/dist/core/brownfield/importer.js.map +1 -0
  41. package/dist/core/config-manager.d.ts +47 -0
  42. package/dist/core/config-manager.d.ts.map +1 -0
  43. package/dist/core/config-manager.js +136 -0
  44. package/dist/core/config-manager.js.map +1 -0
  45. package/dist/core/project-manager.d.ts +127 -0
  46. package/dist/core/project-manager.d.ts.map +1 -0
  47. package/dist/core/project-manager.js +524 -0
  48. package/dist/core/project-manager.js.map +1 -0
  49. package/dist/core/sync/profile-manager.d.ts +72 -0
  50. package/dist/core/sync/profile-manager.d.ts.map +1 -0
  51. package/dist/core/sync/profile-manager.js +338 -0
  52. package/dist/core/sync/profile-manager.js.map +1 -0
  53. package/dist/core/sync/profile-selector.d.ts +52 -0
  54. package/dist/core/sync/profile-selector.d.ts.map +1 -0
  55. package/dist/core/sync/profile-selector.js +179 -0
  56. package/dist/core/sync/profile-selector.js.map +1 -0
  57. package/dist/core/sync/project-context.d.ts +81 -0
  58. package/dist/core/sync/project-context.d.ts.map +1 -0
  59. package/dist/core/sync/project-context.js +354 -0
  60. package/dist/core/sync/project-context.js.map +1 -0
  61. package/dist/core/sync/rate-limiter.d.ts +116 -0
  62. package/dist/core/sync/rate-limiter.d.ts.map +1 -0
  63. package/dist/core/sync/rate-limiter.js +308 -0
  64. package/dist/core/sync/rate-limiter.js.map +1 -0
  65. package/dist/core/sync/time-range-selector.d.ts +48 -0
  66. package/dist/core/sync/time-range-selector.d.ts.map +1 -0
  67. package/dist/core/sync/time-range-selector.js +224 -0
  68. package/dist/core/sync/time-range-selector.js.map +1 -0
  69. package/dist/core/types/config.d.ts +4 -0
  70. package/dist/core/types/config.d.ts.map +1 -1
  71. package/dist/core/types/config.js.map +1 -1
  72. package/dist/core/types/sync-profile.d.ts +205 -0
  73. package/dist/core/types/sync-profile.d.ts.map +1 -0
  74. package/dist/core/types/sync-profile.js +8 -0
  75. package/dist/core/types/sync-profile.js.map +1 -0
  76. package/dist/utils/project-detection.d.ts +141 -0
  77. package/dist/utils/project-detection.d.ts.map +1 -0
  78. package/dist/utils/project-detection.js +321 -0
  79. package/dist/utils/project-detection.js.map +1 -0
  80. package/package.json +2 -1
  81. package/plugins/specweave/agents/pm/AGENT.md +7 -4
  82. package/plugins/specweave/commands/specweave-abandon.md +17 -17
  83. package/plugins/specweave/commands/specweave-check-tests.md +14 -14
  84. package/plugins/specweave/commands/specweave-costs.md +1 -1
  85. package/plugins/specweave/commands/specweave-do.md +12 -12
  86. package/plugins/specweave/commands/specweave-done.md +28 -15
  87. package/plugins/specweave/commands/specweave-import-docs.md +212 -0
  88. package/plugins/specweave/commands/specweave-increment.md +10 -10
  89. package/plugins/specweave/commands/specweave-init-multiproject.md +146 -0
  90. package/plugins/specweave/commands/specweave-next.md +16 -16
  91. package/plugins/specweave/commands/specweave-pause.md +17 -17
  92. package/plugins/specweave/commands/specweave-progress.md +10 -10
  93. package/plugins/specweave/commands/specweave-qa.md +11 -11
  94. package/plugins/specweave/commands/specweave-resume.md +22 -22
  95. package/plugins/specweave/commands/specweave-status.md +18 -18
  96. package/plugins/specweave/commands/specweave-switch-project.md +168 -0
  97. package/plugins/specweave/commands/specweave-sync-docs.md +1 -1
  98. package/plugins/specweave/commands/specweave-sync-tasks.md +9 -9
  99. package/plugins/specweave/commands/specweave-tdd-cycle.md +7 -0
  100. package/plugins/specweave/commands/specweave-tdd-green.md +7 -0
  101. package/plugins/specweave/commands/specweave-tdd-red.md +7 -0
  102. package/plugins/specweave/commands/specweave-tdd-refactor.md +7 -0
  103. package/plugins/specweave/commands/specweave-translate.md +1 -1
  104. package/plugins/specweave/commands/specweave-update-scope.md +8 -8
  105. package/plugins/specweave/commands/specweave-validate.md +18 -20
  106. package/plugins/specweave/commands/specweave.md +5 -5
  107. package/plugins/specweave/skills/SKILLS-INDEX.md +1 -1
  108. package/plugins/specweave/skills/increment-planner/SKILL.md +40 -4
  109. package/plugins/specweave/skills/increment-quality-judge/SKILL.md +5 -5
  110. package/plugins/specweave/skills/increment-quality-judge-v2/SKILL.md +5 -5
  111. package/plugins/specweave/skills/specweave-detector/SKILL.md +3 -3
  112. package/plugins/specweave-ado/commands/{close-workitem.md → specweave-ado-close-workitem.md} +1 -1
  113. package/plugins/specweave-ado/commands/{create-workitem.md → specweave-ado-create-workitem.md} +1 -1
  114. package/plugins/specweave-ado/commands/{status.md → specweave-ado-status.md} +1 -1
  115. package/plugins/specweave-ado/commands/{sync.md → specweave-ado-sync.md} +1 -1
  116. package/plugins/specweave-ado/lib/ado-client-v2.ts +547 -0
  117. package/plugins/specweave-github/commands/{close-issue.md → specweave-github-close-issue.md} +1 -1
  118. package/plugins/specweave-github/commands/{create-issue.md → specweave-github-create-issue.md} +1 -1
  119. package/plugins/specweave-github/commands/{status.md → specweave-github-status.md} +1 -1
  120. package/plugins/specweave-github/commands/{sync-tasks.md → specweave-github-sync-tasks.md} +1 -1
  121. package/plugins/specweave-github/commands/specweave-github-sync.md +568 -0
  122. package/plugins/specweave-github/lib/github-client-v2.ts +555 -0
  123. package/plugins/specweave-infrastructure/commands/{monitor-setup.md → specweave-infrastructure-monitor-setup.md} +1 -1
  124. package/plugins/specweave-infrastructure/commands/{slo-implement.md → specweave-infrastructure-slo-implement.md} +1 -1
  125. package/plugins/specweave-jira/commands/{sync.md → specweave-jira-sync.md} +1 -1
  126. package/plugins/specweave-jira/lib/jira-client-v2.ts +529 -0
  127. package/plugins/specweave-ml/commands/{ml-deploy.md → specweave-ml-deploy.md} +1 -1
  128. package/plugins/specweave-ml/commands/{ml-evaluate.md → specweave-ml-evaluate.md} +1 -1
  129. package/plugins/specweave-ml/commands/{ml-explain.md → specweave-ml-explain.md} +1 -1
  130. package/plugins/specweave-ml/commands/{ml-pipeline.md → specweave-ml-pipeline.md} +1 -1
  131. package/src/templates/AGENTS.md.template +1 -0
  132. package/src/templates/CLAUDE.md.template +1 -0
  133. package/plugins/specweave/hooks/post-increment-plugin-detect.sh +0 -142
  134. package/plugins/specweave/hooks/pre-task-plugin-detect.sh +0 -96
  135. package/plugins/specweave/skills/plugin-detector/SKILL.md +0 -324
  136. package/plugins/specweave-github/commands/sync.md +0 -443
  137. /package/plugins/specweave/{commands/README.md → COMMANDS.md} +0 -0
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Sync Profile Types for Multi-Project External Integration
3
+ *
4
+ * Supports multiple projects per provider (GitHub, JIRA, ADO, etc.)
5
+ * with time range filtering and rate limiting protection.
6
+ */
7
+ export type SyncProvider = 'github' | 'jira' | 'ado';
8
+ export interface GitHubConfig {
9
+ owner: string;
10
+ repo: string;
11
+ }
12
+ export interface JiraConfig {
13
+ domain: string;
14
+ projectKey: string;
15
+ issueType?: 'Epic' | 'Story' | 'Task';
16
+ }
17
+ export interface AdoConfig {
18
+ organization: string;
19
+ project: string;
20
+ workItemType?: 'Epic' | 'Feature' | 'User Story';
21
+ areaPath?: string;
22
+ iterationPath?: string;
23
+ }
24
+ export type ProviderConfig = GitHubConfig | JiraConfig | AdoConfig;
25
+ export type TimeRangePreset = '1W' | '2W' | '1M' | '3M' | '6M' | '1Y' | 'ALL';
26
+ export interface TimeRangeConfig {
27
+ /** Preset time range */
28
+ preset?: TimeRangePreset;
29
+ /** Custom date range */
30
+ custom?: {
31
+ start: string;
32
+ end?: string;
33
+ };
34
+ }
35
+ export interface TimeRangeEstimate {
36
+ /** Estimated work items to sync */
37
+ items: number;
38
+ /** Estimated API requests */
39
+ apiCalls: number;
40
+ /** Estimated sync duration in minutes */
41
+ durationMinutes: number;
42
+ /** Rate limit impact level */
43
+ rateLimitImpact: 'low' | 'medium' | 'high' | 'critical';
44
+ }
45
+ export interface RateLimitConfig {
46
+ /** Maximum items to sync in one operation */
47
+ maxItemsPerSync: number;
48
+ /** Warn user when exceeding this threshold */
49
+ warnThreshold: number;
50
+ }
51
+ export interface RateLimitStatus {
52
+ /** Remaining requests in current window */
53
+ remaining: number;
54
+ /** Total limit per window */
55
+ limit: number;
56
+ /** When the rate limit resets (ISO timestamp) */
57
+ resetAt: string;
58
+ /** Percentage of limit used */
59
+ percentUsed: number;
60
+ }
61
+ export interface ProviderRateLimits {
62
+ github: {
63
+ limit: 5000;
64
+ window: '1h';
65
+ thresholds: {
66
+ low: 250;
67
+ medium: 1000;
68
+ high: 2500;
69
+ };
70
+ };
71
+ jira: {
72
+ limit: 100;
73
+ window: '1m';
74
+ thresholds: {
75
+ low: 25;
76
+ medium: 50;
77
+ high: 75;
78
+ };
79
+ };
80
+ ado: {
81
+ limit: 200;
82
+ window: '5m';
83
+ thresholds: {
84
+ low: 50;
85
+ medium: 100;
86
+ high: 150;
87
+ };
88
+ };
89
+ }
90
+ export interface SyncProfile {
91
+ /** Provider type */
92
+ provider: SyncProvider;
93
+ /** Human-readable name */
94
+ displayName: string;
95
+ /** Optional description */
96
+ description?: string;
97
+ /** Provider-specific configuration */
98
+ config: ProviderConfig;
99
+ /** Time range configuration */
100
+ timeRange: {
101
+ /** Default time range for this profile */
102
+ default: TimeRangePreset;
103
+ /** Maximum allowed time range */
104
+ max: TimeRangePreset;
105
+ };
106
+ /** Rate limiting configuration */
107
+ rateLimits?: RateLimitConfig;
108
+ /** Project context (for smart detection) */
109
+ projectContext?: {
110
+ /** Project name (e.g., "SpecWeave", "Client A Mobile") */
111
+ name: string;
112
+ /** Project description */
113
+ description?: string;
114
+ /** Keywords for auto-detection */
115
+ keywords?: string[];
116
+ /** Team/organization name */
117
+ team?: string;
118
+ };
119
+ }
120
+ export interface SyncProfiles {
121
+ /** Active profile (default selection) */
122
+ activeProfile?: string;
123
+ /** All available profiles */
124
+ profiles: Record<string, SyncProfile>;
125
+ }
126
+ export interface IncrementSyncMetadata {
127
+ /** Which profile this increment uses */
128
+ profile: string;
129
+ /** External issue/work item number */
130
+ issueNumber?: number;
131
+ /** External issue/work item key (for JIRA) */
132
+ issueKey?: string;
133
+ /** Direct URL to external issue */
134
+ issueUrl?: string;
135
+ /** Time range used for this sync */
136
+ timeRange: TimeRangePreset | 'custom';
137
+ /** Custom time range (if timeRange === 'custom') */
138
+ customTimeRange?: {
139
+ start: string;
140
+ end?: string;
141
+ };
142
+ /** When sync was created */
143
+ createdAt: string;
144
+ /** Last successful sync timestamp */
145
+ lastSyncAt?: string;
146
+ /** Sync status */
147
+ status?: 'active' | 'paused' | 'failed' | 'completed';
148
+ /** Last sync error (if any) */
149
+ lastError?: {
150
+ message: string;
151
+ timestamp: string;
152
+ rateLimited?: boolean;
153
+ };
154
+ }
155
+ export interface ProjectContext {
156
+ /** Unique project identifier (kebab-case) */
157
+ id: string;
158
+ /** Project name */
159
+ name: string;
160
+ /** Project description */
161
+ description: string;
162
+ /** Team/organization */
163
+ team?: string;
164
+ /** Keywords for auto-detection */
165
+ keywords: string[];
166
+ /** Default sync profile for this project */
167
+ defaultSyncProfile?: string;
168
+ /** Project-specific specs folder */
169
+ specsFolder: string;
170
+ /** Related increments (for tracking) */
171
+ increments?: string[];
172
+ }
173
+ export interface SyncConfiguration {
174
+ /** Active profile */
175
+ activeProfile?: string;
176
+ /** All sync profiles */
177
+ profiles: Record<string, SyncProfile>;
178
+ /** Project contexts */
179
+ projects?: Record<string, ProjectContext>;
180
+ /** Global settings */
181
+ settings?: {
182
+ /** Auto-detect project from increment description */
183
+ autoDetectProject?: boolean;
184
+ /** Default time range for new syncs */
185
+ defaultTimeRange?: TimeRangePreset;
186
+ /** Enable rate limit protection */
187
+ rateLimitProtection?: boolean;
188
+ };
189
+ }
190
+ export interface ProfileValidationResult {
191
+ valid: boolean;
192
+ errors: string[];
193
+ warnings?: string[];
194
+ }
195
+ export interface ProjectDetectionResult {
196
+ /** Matched project (if any) */
197
+ project?: ProjectContext;
198
+ /** Confidence score (0-1) */
199
+ confidence: number;
200
+ /** Matched keywords */
201
+ matchedKeywords: string[];
202
+ /** Suggested sync profile */
203
+ suggestedProfile?: string;
204
+ }
205
+ //# sourceMappingURL=sync-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-profile.d.ts","sourceRoot":"","sources":["../../../src/core/types/sync-profile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Sync Profile Types for Multi-Project External Integration
3
+ *
4
+ * Supports multiple projects per provider (GitHub, JIRA, ADO, etc.)
5
+ * with time range filtering and rate limiting protection.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=sync-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-profile.js","sourceRoot":"","sources":["../../../src/core/types/sync-profile.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Project ID Auto-Detection Utilities
3
+ *
4
+ * Detects project ID from:
5
+ * 1. Git remote (GitHub repo name)
6
+ * 2. Sync configuration (JIRA project key, ADO project name)
7
+ * 3. User prompt (fallback)
8
+ */
9
+ /**
10
+ * Auto-detect project ID from git remote URL
11
+ *
12
+ * Extracts repository name from git remote URL
13
+ *
14
+ * @param projectRoot - Project root directory
15
+ * @returns Project ID (repo name) or null if not detected
16
+ *
17
+ * @example
18
+ * // Git remote: https://github.com/anton-abyzov/specweave.git
19
+ * detectProjectIdFromGit('/path/to/project')
20
+ * // Returns: "specweave"
21
+ *
22
+ * @example
23
+ * // Git remote: git@github.com:my-org/web-app.git
24
+ * detectProjectIdFromGit('/path/to/project')
25
+ * // Returns: "web-app"
26
+ */
27
+ export declare function detectProjectIdFromGit(projectRoot: string): string | null;
28
+ /**
29
+ * Auto-detect project ID from sync configuration
30
+ *
31
+ * Checks existing sync profiles for JIRA project key or ADO project name
32
+ *
33
+ * @param projectRoot - Project root directory
34
+ * @returns Project ID from sync config or null if not detected
35
+ *
36
+ * @example
37
+ * // Config has JIRA: { projectKey: "WEBAPP" }
38
+ * detectProjectIdFromSync('/path/to/project')
39
+ * // Returns: "webapp"
40
+ */
41
+ export declare function detectProjectIdFromSync(projectRoot: string): string | null;
42
+ /**
43
+ * Prompt user for project ID
44
+ *
45
+ * Interactive prompt with validation and helpful examples
46
+ *
47
+ * @param suggestedId - Optional suggested project ID (from detection)
48
+ * @returns Project ID entered by user
49
+ *
50
+ * @example
51
+ * await promptForProjectId()
52
+ * // User sees:
53
+ * // Project ID (matches GitHub repo, JIRA project, or ADO project): █
54
+ * // User enters: "web-app"
55
+ * // Returns: "web-app"
56
+ */
57
+ export declare function promptForProjectId(suggestedId?: string): Promise<string>;
58
+ /**
59
+ * Auto-detect project ID synchronously (no prompts)
60
+ *
61
+ * Priority:
62
+ * 1. Git remote (GitHub repo name)
63
+ * 2. Sync configuration (JIRA/ADO project)
64
+ * 3. "default" (fallback)
65
+ *
66
+ * @param projectRoot - Project root directory
67
+ * @param options - Detection options
68
+ * @returns Detected project ID or "default"
69
+ *
70
+ * @example
71
+ * // In git repo: https://github.com/anton-abyzov/specweave.git
72
+ * autoDetectProjectIdSync('/path/to/project')
73
+ * // Returns: "specweave"
74
+ *
75
+ * @example
76
+ * // No git, no sync
77
+ * autoDetectProjectIdSync('/path/to/project')
78
+ * // Returns: "default"
79
+ */
80
+ export declare function autoDetectProjectIdSync(projectRoot: string, options?: {
81
+ silent?: boolean;
82
+ }): string;
83
+ /**
84
+ * Auto-detect project ID with fallback chain (async version with prompts)
85
+ *
86
+ * Priority:
87
+ * 1. Git remote (GitHub repo name)
88
+ * 2. Sync configuration (JIRA/ADO project)
89
+ * 3. User prompt (with detected suggestion)
90
+ * 4. "default" (if user accepts default in prompt)
91
+ *
92
+ * @param projectRoot - Project root directory
93
+ * @param options - Detection options
94
+ * @returns Detected or prompted project ID
95
+ *
96
+ * @example
97
+ * // In git repo: https://github.com/anton-abyzov/specweave.git
98
+ * await autoDetectProjectId('/path/to/project')
99
+ * // Output: "✅ Detected git repository: specweave"
100
+ * // Returns: "specweave"
101
+ *
102
+ * @example
103
+ * // No git, no sync, user prompted
104
+ * await autoDetectProjectId('/path/to/project')
105
+ * // Output: "📝 No git repository or sync configuration detected."
106
+ * // Prompts user for project ID
107
+ * // Returns: user input (e.g., "my-project")
108
+ */
109
+ export declare function autoDetectProjectId(projectRoot: string, options?: {
110
+ silent?: boolean;
111
+ promptIfNotDetected?: boolean;
112
+ }): Promise<string>;
113
+ /**
114
+ * Format project ID to display name
115
+ *
116
+ * Converts kebab-case/snake_case to Title Case
117
+ *
118
+ * @param projectId - Project ID (e.g., "web-app", "mobile_app")
119
+ * @returns Formatted name (e.g., "Web App", "Mobile App")
120
+ *
121
+ * @example
122
+ * formatProjectName('web-app')
123
+ * // Returns: "Web App"
124
+ *
125
+ * @example
126
+ * formatProjectName('mobile_app')
127
+ * // Returns: "Mobile App"
128
+ *
129
+ * @example
130
+ * formatProjectName('specweave')
131
+ * // Returns: "SpecWeave"
132
+ */
133
+ export declare function formatProjectName(projectId: string): string;
134
+ /**
135
+ * Validate project ID format
136
+ *
137
+ * @param projectId - Project ID to validate
138
+ * @returns True if valid, error message if invalid
139
+ */
140
+ export declare function validateProjectId(projectId: string): true | string;
141
+ //# sourceMappingURL=project-detection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-detection.d.ts","sourceRoot":"","sources":["../../src/utils/project-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCzE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsD1E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B9E;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,OAAO,CAAC;CACb,GACL,MAAM,CAuBR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC1B,GACL,OAAO,CAAC,MAAM,CAAC,CAsCjB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAkB3D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAkBlE"}
@@ -0,0 +1,321 @@
1
+ /**
2
+ * Project ID Auto-Detection Utilities
3
+ *
4
+ * Detects project ID from:
5
+ * 1. Git remote (GitHub repo name)
6
+ * 2. Sync configuration (JIRA project key, ADO project name)
7
+ * 3. User prompt (fallback)
8
+ */
9
+ import fs from 'fs-extra';
10
+ import path from 'path';
11
+ import inquirer from 'inquirer';
12
+ import { ConfigManager } from '../core/config-manager';
13
+ /**
14
+ * Auto-detect project ID from git remote URL
15
+ *
16
+ * Extracts repository name from git remote URL
17
+ *
18
+ * @param projectRoot - Project root directory
19
+ * @returns Project ID (repo name) or null if not detected
20
+ *
21
+ * @example
22
+ * // Git remote: https://github.com/anton-abyzov/specweave.git
23
+ * detectProjectIdFromGit('/path/to/project')
24
+ * // Returns: "specweave"
25
+ *
26
+ * @example
27
+ * // Git remote: git@github.com:my-org/web-app.git
28
+ * detectProjectIdFromGit('/path/to/project')
29
+ * // Returns: "web-app"
30
+ */
31
+ export function detectProjectIdFromGit(projectRoot) {
32
+ try {
33
+ const gitConfigPath = path.join(projectRoot, '.git', 'config');
34
+ // Check if .git/config exists
35
+ if (!fs.existsSync(gitConfigPath)) {
36
+ return null;
37
+ }
38
+ // Read git config
39
+ const gitConfig = fs.readFileSync(gitConfigPath, 'utf8');
40
+ // Extract remote URL (match both HTTPS and SSH formats)
41
+ // HTTPS: https://github.com/owner/repo.git
42
+ // SSH: git@github.com:owner/repo.git
43
+ const httpsMatch = gitConfig.match(/url = https?:\/\/[^\/]+\/[^\/]+\/([^\/\s]+?)(?:\.git)?$/m);
44
+ const sshMatch = gitConfig.match(/url = git@[^:]+:[^\/]+\/([^\/\s]+?)(?:\.git)?$/m);
45
+ const match = httpsMatch || sshMatch;
46
+ if (match && match[1]) {
47
+ const repoName = match[1].trim();
48
+ // Validate repo name (lowercase, alphanumeric, hyphens, underscores)
49
+ if (/^[a-z0-9_-]+$/i.test(repoName)) {
50
+ return repoName.toLowerCase();
51
+ }
52
+ }
53
+ return null;
54
+ }
55
+ catch (error) {
56
+ // Silently fail (not in git repo or permission error)
57
+ return null;
58
+ }
59
+ }
60
+ /**
61
+ * Auto-detect project ID from sync configuration
62
+ *
63
+ * Checks existing sync profiles for JIRA project key or ADO project name
64
+ *
65
+ * @param projectRoot - Project root directory
66
+ * @returns Project ID from sync config or null if not detected
67
+ *
68
+ * @example
69
+ * // Config has JIRA: { projectKey: "WEBAPP" }
70
+ * detectProjectIdFromSync('/path/to/project')
71
+ * // Returns: "webapp"
72
+ */
73
+ export function detectProjectIdFromSync(projectRoot) {
74
+ try {
75
+ const configManager = new ConfigManager(projectRoot);
76
+ const config = configManager.load();
77
+ // Check sync profiles for project identifiers
78
+ if (config.sync?.profiles) {
79
+ const profiles = Object.values(config.sync.profiles);
80
+ for (const profile of profiles) {
81
+ // GitHub profile (extract repo name)
82
+ if (profile.provider === 'github') {
83
+ const githubConfig = profile.config;
84
+ if (githubConfig?.repo) {
85
+ return githubConfig.repo.toLowerCase();
86
+ }
87
+ }
88
+ // JIRA profile (use project key)
89
+ if (profile.provider === 'jira') {
90
+ const jiraConfig = profile.config;
91
+ if (jiraConfig?.projectKey) {
92
+ return jiraConfig.projectKey.toLowerCase();
93
+ }
94
+ }
95
+ // Azure DevOps profile (use project name)
96
+ if (profile.provider === 'ado') {
97
+ const adoConfig = profile.config;
98
+ if (adoConfig?.project) {
99
+ return adoConfig.project.toLowerCase().replace(/\s+/g, '-');
100
+ }
101
+ }
102
+ }
103
+ }
104
+ // Legacy: Check old sync config format (pre-profiles)
105
+ if (config.sync?.jira?.projectKey) {
106
+ return config.sync.jira.projectKey.toLowerCase();
107
+ }
108
+ if (config.sync?.ado?.project) {
109
+ return config.sync.ado.project.toLowerCase().replace(/\s+/g, '-');
110
+ }
111
+ if (config.sync?.github?.repo) {
112
+ return config.sync.github.repo.toLowerCase();
113
+ }
114
+ return null;
115
+ }
116
+ catch (error) {
117
+ // Config doesn't exist or is invalid
118
+ return null;
119
+ }
120
+ }
121
+ /**
122
+ * Prompt user for project ID
123
+ *
124
+ * Interactive prompt with validation and helpful examples
125
+ *
126
+ * @param suggestedId - Optional suggested project ID (from detection)
127
+ * @returns Project ID entered by user
128
+ *
129
+ * @example
130
+ * await promptForProjectId()
131
+ * // User sees:
132
+ * // Project ID (matches GitHub repo, JIRA project, or ADO project): █
133
+ * // User enters: "web-app"
134
+ * // Returns: "web-app"
135
+ */
136
+ export async function promptForProjectId(suggestedId) {
137
+ const { projectId } = await inquirer.prompt([{
138
+ type: 'input',
139
+ name: 'projectId',
140
+ message: 'Project ID (matches GitHub repo, JIRA project, or ADO project):',
141
+ default: suggestedId || 'default',
142
+ validate: (input) => {
143
+ if (!input) {
144
+ return 'Project ID is required';
145
+ }
146
+ if (!/^[a-z0-9_-]+$/.test(input)) {
147
+ return 'Project ID must be lowercase, alphanumeric, with hyphens or underscores';
148
+ }
149
+ if (input.length < 2) {
150
+ return 'Project ID must be at least 2 characters';
151
+ }
152
+ if (input.length > 64) {
153
+ return 'Project ID must be at most 64 characters';
154
+ }
155
+ return true;
156
+ }
157
+ }]);
158
+ return projectId;
159
+ }
160
+ /**
161
+ * Auto-detect project ID synchronously (no prompts)
162
+ *
163
+ * Priority:
164
+ * 1. Git remote (GitHub repo name)
165
+ * 2. Sync configuration (JIRA/ADO project)
166
+ * 3. "default" (fallback)
167
+ *
168
+ * @param projectRoot - Project root directory
169
+ * @param options - Detection options
170
+ * @returns Detected project ID or "default"
171
+ *
172
+ * @example
173
+ * // In git repo: https://github.com/anton-abyzov/specweave.git
174
+ * autoDetectProjectIdSync('/path/to/project')
175
+ * // Returns: "specweave"
176
+ *
177
+ * @example
178
+ * // No git, no sync
179
+ * autoDetectProjectIdSync('/path/to/project')
180
+ * // Returns: "default"
181
+ */
182
+ export function autoDetectProjectIdSync(projectRoot, options = {}) {
183
+ const { silent = false } = options;
184
+ // 1. Try git remote
185
+ const gitProjectId = detectProjectIdFromGit(projectRoot);
186
+ if (gitProjectId) {
187
+ if (!silent) {
188
+ console.log(`✅ Detected git repository: ${gitProjectId}`);
189
+ }
190
+ return gitProjectId;
191
+ }
192
+ // 2. Try sync config
193
+ const syncProjectId = detectProjectIdFromSync(projectRoot);
194
+ if (syncProjectId) {
195
+ if (!silent) {
196
+ console.log(`✅ Detected sync configuration: ${syncProjectId}`);
197
+ }
198
+ return syncProjectId;
199
+ }
200
+ // 3. Fallback to "default"
201
+ return 'default';
202
+ }
203
+ /**
204
+ * Auto-detect project ID with fallback chain (async version with prompts)
205
+ *
206
+ * Priority:
207
+ * 1. Git remote (GitHub repo name)
208
+ * 2. Sync configuration (JIRA/ADO project)
209
+ * 3. User prompt (with detected suggestion)
210
+ * 4. "default" (if user accepts default in prompt)
211
+ *
212
+ * @param projectRoot - Project root directory
213
+ * @param options - Detection options
214
+ * @returns Detected or prompted project ID
215
+ *
216
+ * @example
217
+ * // In git repo: https://github.com/anton-abyzov/specweave.git
218
+ * await autoDetectProjectId('/path/to/project')
219
+ * // Output: "✅ Detected git repository: specweave"
220
+ * // Returns: "specweave"
221
+ *
222
+ * @example
223
+ * // No git, no sync, user prompted
224
+ * await autoDetectProjectId('/path/to/project')
225
+ * // Output: "📝 No git repository or sync configuration detected."
226
+ * // Prompts user for project ID
227
+ * // Returns: user input (e.g., "my-project")
228
+ */
229
+ export async function autoDetectProjectId(projectRoot, options = {}) {
230
+ const { silent = false, promptIfNotDetected = true } = options;
231
+ // 1. Try git remote
232
+ const gitProjectId = detectProjectIdFromGit(projectRoot);
233
+ if (gitProjectId) {
234
+ if (!silent) {
235
+ console.log(`✅ Detected git repository: ${gitProjectId}`);
236
+ }
237
+ return gitProjectId;
238
+ }
239
+ // 2. Try sync config
240
+ const syncProjectId = detectProjectIdFromSync(projectRoot);
241
+ if (syncProjectId) {
242
+ if (!silent) {
243
+ console.log(`✅ Detected sync configuration: ${syncProjectId}`);
244
+ }
245
+ return syncProjectId;
246
+ }
247
+ // 3. Prompt user (if enabled)
248
+ if (promptIfNotDetected) {
249
+ if (!silent) {
250
+ console.log('\n📝 No git repository or sync configuration detected.');
251
+ console.log(' Please enter your project identifier.\n');
252
+ console.log(' Examples:');
253
+ console.log(' • GitHub repo "web-app" → enter: web-app');
254
+ console.log(' • JIRA project "WEBAPP" → enter: webapp');
255
+ console.log(' • ADO project "Platform" → enter: platform');
256
+ console.log(' • Generic project → enter: default\n');
257
+ }
258
+ return await promptForProjectId();
259
+ }
260
+ // 4. Fallback to "default" (no prompt)
261
+ return 'default';
262
+ }
263
+ /**
264
+ * Format project ID to display name
265
+ *
266
+ * Converts kebab-case/snake_case to Title Case
267
+ *
268
+ * @param projectId - Project ID (e.g., "web-app", "mobile_app")
269
+ * @returns Formatted name (e.g., "Web App", "Mobile App")
270
+ *
271
+ * @example
272
+ * formatProjectName('web-app')
273
+ * // Returns: "Web App"
274
+ *
275
+ * @example
276
+ * formatProjectName('mobile_app')
277
+ * // Returns: "Mobile App"
278
+ *
279
+ * @example
280
+ * formatProjectName('specweave')
281
+ * // Returns: "SpecWeave"
282
+ */
283
+ export function formatProjectName(projectId) {
284
+ // Special cases (known project names)
285
+ const specialCases = {
286
+ 'specweave': 'SpecWeave',
287
+ 'webapp': 'WebApp',
288
+ 'default': 'Default Project'
289
+ };
290
+ if (specialCases[projectId.toLowerCase()]) {
291
+ return specialCases[projectId.toLowerCase()];
292
+ }
293
+ // Convert kebab-case or snake_case to Title Case
294
+ return projectId
295
+ .replace(/[-_]/g, ' ')
296
+ .split(' ')
297
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
298
+ .join(' ');
299
+ }
300
+ /**
301
+ * Validate project ID format
302
+ *
303
+ * @param projectId - Project ID to validate
304
+ * @returns True if valid, error message if invalid
305
+ */
306
+ export function validateProjectId(projectId) {
307
+ if (!projectId) {
308
+ return 'Project ID is required';
309
+ }
310
+ if (!/^[a-z0-9_-]+$/.test(projectId)) {
311
+ return 'Project ID must be lowercase, alphanumeric, with hyphens or underscores';
312
+ }
313
+ if (projectId.length < 2) {
314
+ return 'Project ID must be at least 2 characters';
315
+ }
316
+ if (projectId.length > 64) {
317
+ return 'Project ID must be at most 64 characters';
318
+ }
319
+ return true;
320
+ }
321
+ //# sourceMappingURL=project-detection.js.map