specweave 0.8.17 → 0.8.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CLAUDE.md +119 -27
  2. package/README.md +11 -3
  3. package/dist/cli/commands/init.d.ts.map +1 -1
  4. package/dist/cli/commands/init.js +74 -20
  5. package/dist/cli/commands/init.js.map +1 -1
  6. package/dist/cli/commands/migrate-to-profiles.js +2 -2
  7. package/dist/cli/commands/migrate-to-profiles.js.map +1 -1
  8. package/dist/cli/helpers/issue-tracker/index.d.ts.map +1 -1
  9. package/dist/cli/helpers/issue-tracker/index.js +8 -3
  10. package/dist/cli/helpers/issue-tracker/index.js.map +1 -1
  11. package/dist/cli/helpers/issue-tracker/utils.d.ts +5 -2
  12. package/dist/cli/helpers/issue-tracker/utils.d.ts.map +1 -1
  13. package/dist/cli/helpers/issue-tracker/utils.js +13 -6
  14. package/dist/cli/helpers/issue-tracker/utils.js.map +1 -1
  15. package/dist/core/sync/bidirectional-engine.d.ts +110 -0
  16. package/dist/core/sync/bidirectional-engine.d.ts.map +1 -0
  17. package/dist/core/sync/bidirectional-engine.js +356 -0
  18. package/dist/core/sync/bidirectional-engine.js.map +1 -0
  19. package/dist/utils/agents-md-compiler.js +2 -2
  20. package/dist/utils/env-multi-project-parser.d.ts +210 -0
  21. package/dist/utils/env-multi-project-parser.d.ts.map +1 -0
  22. package/dist/utils/env-multi-project-parser.js +406 -0
  23. package/dist/utils/env-multi-project-parser.js.map +1 -0
  24. package/package.json +1 -1
  25. package/plugins/specweave/hooks/post-first-increment.sh +79 -0
  26. package/plugins/specweave/skills/increment-planner/SKILL.md +50 -16
  27. package/plugins/specweave/skills/plugin-expert/SKILL.md +344 -0
  28. package/plugins/specweave/skills/specweave-framework/SKILL.md +2 -2
  29. package/plugins/specweave/skills/translator/SKILL.md +29 -0
  30. package/plugins/specweave/skills/translator/SKILL.md.bak +172 -0
  31. package/plugins/specweave-jira/lib/project-selector.ts +323 -0
  32. package/plugins/specweave-jira/lib/reorganization-detector.ts +359 -0
  33. package/plugins/specweave-jira/lib/setup-wizard.ts +256 -0
  34. package/src/templates/.gitignore.template +1 -0
  35. package/plugins/specweave-jira/lib/jira-client-v2.ts +0 -529
@@ -0,0 +1,356 @@
1
+ /**
2
+ * Bidirectional Sync Engine
3
+ *
4
+ * Handles synchronization between SpecWeave increments and external systems
5
+ * (GitHub, Jira, ADO) in both directions with conflict detection and resolution.
6
+ *
7
+ * Features:
8
+ * - Bidirectional sync (to-external, from-external, both)
9
+ * - Conflict detection (field-level granularity)
10
+ * - Interactive conflict resolution
11
+ * - Change tracking (detect what changed since last sync)
12
+ * - Reorganization detection (moved issues, split/merged stories)
13
+ */
14
+ import * as fs from 'fs-extra';
15
+ import * as path from 'path';
16
+ import inquirer from 'inquirer';
17
+ // ============================================================================
18
+ // Bidirectional Sync Engine
19
+ // ============================================================================
20
+ export class BidirectionalSyncEngine {
21
+ constructor(provider, projectRoot = process.cwd()) {
22
+ this.provider = provider;
23
+ this.projectRoot = projectRoot;
24
+ }
25
+ /**
26
+ * Main sync orchestrator
27
+ */
28
+ async sync(incrementId, direction, conflictResolution = 'prompt') {
29
+ console.log(`\nšŸ”„ Starting ${direction} sync for increment ${incrementId}...\n`);
30
+ const result = {
31
+ success: false,
32
+ direction,
33
+ changes: { toExternal: [], fromExternal: [], conflicts: [] },
34
+ conflictsResolved: 0,
35
+ errors: [],
36
+ };
37
+ try {
38
+ // Step 1: Load current state
39
+ const currentState = await this.loadSyncState(incrementId);
40
+ // Step 2: Detect changes
41
+ const changes = await this.detectChanges(incrementId, currentState);
42
+ result.changes = changes;
43
+ // Step 3: Handle conflicts (if bidirectional)
44
+ if (direction === 'bidirectional' && changes.conflicts.length > 0) {
45
+ console.log(`\nāš ļø Detected ${changes.conflicts.length} conflicts\n`);
46
+ const resolved = await this.resolveConflicts(changes.conflicts, conflictResolution);
47
+ result.conflictsResolved = resolved.length;
48
+ // Apply resolutions
49
+ for (const conflict of resolved) {
50
+ if (conflict.resolution === 'local') {
51
+ changes.toExternal.push(conflict);
52
+ }
53
+ else if (conflict.resolution === 'external') {
54
+ changes.fromExternal.push(conflict);
55
+ }
56
+ else if (conflict.resolution === 'merged' && conflict.mergedValue !== undefined) {
57
+ // Apply merged value to both sides
58
+ changes.toExternal.push({
59
+ ...conflict,
60
+ localValue: conflict.mergedValue,
61
+ });
62
+ changes.fromExternal.push({
63
+ ...conflict,
64
+ externalValue: conflict.mergedValue,
65
+ });
66
+ }
67
+ }
68
+ }
69
+ // Step 4: Apply changes based on direction
70
+ if (direction === 'to-external' || direction === 'bidirectional') {
71
+ if (changes.toExternal.length > 0) {
72
+ console.log(`\nšŸ“¤ Syncing ${changes.toExternal.length} changes to ${this.provider}...`);
73
+ await this.applyToExternal(incrementId, changes.toExternal);
74
+ }
75
+ }
76
+ if (direction === 'from-external' || direction === 'bidirectional') {
77
+ if (changes.fromExternal.length > 0) {
78
+ console.log(`\nšŸ“„ Syncing ${changes.fromExternal.length} changes from ${this.provider}...`);
79
+ await this.applyToLocal(incrementId, changes.fromExternal);
80
+ }
81
+ }
82
+ // Step 5: Update sync state
83
+ await this.updateSyncState(incrementId, {
84
+ ...currentState,
85
+ lastSyncAt: new Date().toISOString(),
86
+ lastLocalChange: new Date().toISOString(),
87
+ lastExternalChange: new Date().toISOString(),
88
+ });
89
+ result.success = true;
90
+ console.log(`\nāœ… Sync complete!\n`);
91
+ this.printSyncSummary(result);
92
+ return result;
93
+ }
94
+ catch (error) {
95
+ result.success = false;
96
+ result.errors.push(error.message);
97
+ console.error(`\nāŒ Sync failed:`, error.message);
98
+ return result;
99
+ }
100
+ }
101
+ // ==========================================================================
102
+ // Change Detection
103
+ // ==========================================================================
104
+ /**
105
+ * Detect changes in both local and external state
106
+ */
107
+ async detectChanges(incrementId, currentState) {
108
+ const localState = await this.fetchLocalState(incrementId);
109
+ const externalState = await this.fetchExternalState(incrementId, currentState);
110
+ const toExternal = [];
111
+ const fromExternal = [];
112
+ const conflicts = [];
113
+ // Compare common fields
114
+ const fields = ['title', 'description', 'status', 'priority', 'assignee'];
115
+ for (const field of fields) {
116
+ const localValue = localState[field];
117
+ const externalValue = externalState[field];
118
+ const lastSyncValue = currentState.lastSyncAt
119
+ ? currentState[field]
120
+ : undefined;
121
+ // Detect changes
122
+ const localChanged = localValue !== lastSyncValue;
123
+ const externalChanged = externalValue !== lastSyncValue;
124
+ if (localChanged && externalChanged && localValue !== externalValue) {
125
+ // CONFLICT: Both changed to different values
126
+ conflicts.push({
127
+ field,
128
+ localValue,
129
+ externalValue,
130
+ lastSyncValue,
131
+ });
132
+ }
133
+ else if (localChanged) {
134
+ // Local changed, external didn't
135
+ toExternal.push({
136
+ field,
137
+ localValue,
138
+ externalValue,
139
+ lastSyncValue,
140
+ });
141
+ }
142
+ else if (externalChanged) {
143
+ // External changed, local didn't
144
+ fromExternal.push({
145
+ field,
146
+ localValue,
147
+ externalValue,
148
+ lastSyncValue,
149
+ });
150
+ }
151
+ }
152
+ return { toExternal, fromExternal, conflicts };
153
+ }
154
+ /**
155
+ * Fetch local state from increment files
156
+ */
157
+ async fetchLocalState(incrementId) {
158
+ const incrementPath = path.join(this.projectRoot, '.specweave', 'increments', incrementId);
159
+ // Read spec.md
160
+ const specPath = path.join(incrementPath, 'spec.md');
161
+ const specContent = await fs.readFile(specPath, 'utf-8');
162
+ // Parse frontmatter and content
163
+ const titleMatch = specContent.match(/^#\s+(.+)$/m);
164
+ const statusMatch = specContent.match(/Status:\s*(.+)$/m);
165
+ const priorityMatch = specContent.match(/Priority:\s*(.+)$/m);
166
+ return {
167
+ title: titleMatch ? titleMatch[1] : '',
168
+ description: specContent.substring(0, 500), // First 500 chars
169
+ status: statusMatch ? statusMatch[1].trim() : 'in-progress',
170
+ priority: priorityMatch ? priorityMatch[1].trim() : 'medium',
171
+ assignee: null,
172
+ };
173
+ }
174
+ /**
175
+ * Fetch external state from Jira/GitHub/ADO
176
+ */
177
+ async fetchExternalState(incrementId, currentState) {
178
+ if (!currentState.externalKey) {
179
+ return {}; // No external issue yet
180
+ }
181
+ // This will be implemented by provider-specific adapters
182
+ // For now, return placeholder
183
+ return {
184
+ title: '',
185
+ description: '',
186
+ status: '',
187
+ priority: '',
188
+ assignee: null,
189
+ };
190
+ }
191
+ // ==========================================================================
192
+ // Conflict Resolution
193
+ // ==========================================================================
194
+ /**
195
+ * Resolve conflicts interactively or automatically
196
+ */
197
+ async resolveConflicts(conflicts, strategy) {
198
+ const resolved = [];
199
+ for (const conflict of conflicts) {
200
+ if (strategy === 'prefer-local') {
201
+ conflict.resolution = 'local';
202
+ }
203
+ else if (strategy === 'prefer-external') {
204
+ conflict.resolution = 'external';
205
+ }
206
+ else if (strategy === 'manual' || strategy === 'prompt') {
207
+ await this.promptConflictResolution(conflict);
208
+ }
209
+ resolved.push(conflict);
210
+ }
211
+ return resolved;
212
+ }
213
+ /**
214
+ * Interactive conflict resolution prompt
215
+ */
216
+ async promptConflictResolution(conflict) {
217
+ console.log(`\nāš ļø Conflict in field: ${conflict.field}`);
218
+ console.log(` Local value: ${conflict.localValue}`);
219
+ console.log(` ${this.provider} value: ${conflict.externalValue}`);
220
+ console.log(` Last sync value: ${conflict.lastSyncValue || '(unknown)'}\n`);
221
+ const { resolution } = await inquirer.prompt([
222
+ {
223
+ type: 'list',
224
+ name: 'resolution',
225
+ message: `How should this conflict be resolved?`,
226
+ choices: [
227
+ {
228
+ name: `Use local value: "${conflict.localValue}"`,
229
+ value: 'local',
230
+ },
231
+ {
232
+ name: `Use ${this.provider} value: "${conflict.externalValue}"`,
233
+ value: 'external',
234
+ },
235
+ {
236
+ name: 'Enter custom value (merge)',
237
+ value: 'merge',
238
+ },
239
+ ],
240
+ },
241
+ ]);
242
+ if (resolution === 'merge') {
243
+ const { mergedValue } = await inquirer.prompt([
244
+ {
245
+ type: 'input',
246
+ name: 'mergedValue',
247
+ message: `Enter merged value for ${conflict.field}:`,
248
+ default: conflict.localValue,
249
+ },
250
+ ]);
251
+ conflict.resolution = 'merged';
252
+ conflict.mergedValue = mergedValue;
253
+ }
254
+ else {
255
+ conflict.resolution = resolution;
256
+ }
257
+ }
258
+ // ==========================================================================
259
+ // Apply Changes
260
+ // ==========================================================================
261
+ /**
262
+ * Apply changes to external system
263
+ */
264
+ async applyToExternal(incrementId, changes) {
265
+ // Implementation will be provider-specific
266
+ // This is a placeholder
267
+ for (const change of changes) {
268
+ console.log(` āœ“ ${change.field}: ${change.localValue}`);
269
+ }
270
+ }
271
+ /**
272
+ * Apply changes to local increment
273
+ */
274
+ async applyToLocal(incrementId, changes) {
275
+ const incrementPath = path.join(this.projectRoot, '.specweave', 'increments', incrementId);
276
+ const specPath = path.join(incrementPath, 'spec.md');
277
+ let specContent = await fs.readFile(specPath, 'utf-8');
278
+ // Apply changes to spec.md
279
+ for (const change of changes) {
280
+ if (change.field === 'title') {
281
+ specContent = specContent.replace(/^#\s+.+$/m, `# ${change.externalValue}`);
282
+ }
283
+ else if (change.field === 'status') {
284
+ specContent = specContent.replace(/Status:\s*.+$/m, `Status: ${change.externalValue}`);
285
+ }
286
+ else if (change.field === 'priority') {
287
+ specContent = specContent.replace(/Priority:\s*.+$/m, `Priority: ${change.externalValue}`);
288
+ }
289
+ console.log(` āœ“ ${change.field}: ${change.externalValue}`);
290
+ }
291
+ await fs.writeFile(specPath, specContent, 'utf-8');
292
+ }
293
+ // ==========================================================================
294
+ // Sync State Management
295
+ // ==========================================================================
296
+ /**
297
+ * Load sync state from metadata
298
+ */
299
+ async loadSyncState(incrementId) {
300
+ const metadataPath = path.join(this.projectRoot, '.specweave', 'increments', incrementId, 'metadata.json');
301
+ if (!fs.existsSync(metadataPath)) {
302
+ return { incrementId, title: '', status: '' };
303
+ }
304
+ const metadata = await fs.readJSON(metadataPath);
305
+ return {
306
+ incrementId,
307
+ title: metadata.title || '',
308
+ status: metadata.status || '',
309
+ externalId: metadata.sync?.externalId,
310
+ externalKey: metadata.sync?.externalKey,
311
+ externalUrl: metadata.sync?.externalUrl,
312
+ lastSyncAt: metadata.sync?.lastSyncAt,
313
+ lastLocalChange: metadata.sync?.lastLocalChange,
314
+ lastExternalChange: metadata.sync?.lastExternalChange,
315
+ linkedItems: metadata.sync?.linkedItems || {},
316
+ };
317
+ }
318
+ /**
319
+ * Update sync state in metadata
320
+ */
321
+ async updateSyncState(incrementId, state) {
322
+ const metadataPath = path.join(this.projectRoot, '.specweave', 'increments', incrementId, 'metadata.json');
323
+ let metadata = {};
324
+ if (fs.existsSync(metadataPath)) {
325
+ metadata = await fs.readJSON(metadataPath);
326
+ }
327
+ metadata.sync = {
328
+ ...metadata.sync,
329
+ externalId: state.externalId,
330
+ externalKey: state.externalKey,
331
+ externalUrl: state.externalUrl,
332
+ lastSyncAt: state.lastSyncAt,
333
+ lastLocalChange: state.lastLocalChange,
334
+ lastExternalChange: state.lastExternalChange,
335
+ linkedItems: state.linkedItems,
336
+ };
337
+ await fs.writeJSON(metadataPath, metadata, { spaces: 2 });
338
+ }
339
+ // ==========================================================================
340
+ // Helpers
341
+ // ==========================================================================
342
+ /**
343
+ * Print sync summary
344
+ */
345
+ printSyncSummary(result) {
346
+ console.log('šŸ“Š Sync Summary:\n');
347
+ console.log(` Direction: ${result.direction}`);
348
+ console.log(` Changes to external: ${result.changes.toExternal.length}`);
349
+ console.log(` Changes from external: ${result.changes.fromExternal.length}`);
350
+ console.log(` Conflicts detected: ${result.changes.conflicts.length}`);
351
+ console.log(` Conflicts resolved: ${result.conflictsResolved}`);
352
+ console.log(` Errors: ${result.errors.length}`);
353
+ console.log('');
354
+ }
355
+ }
356
+ //# sourceMappingURL=bidirectional-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bidirectional-engine.js","sourceRoot":"","sources":["../../../src/core/sync/bidirectional-engine.ts"],"names":[],"mappings":"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"}
@@ -257,10 +257,10 @@ This project uses SpecWeave for spec-driven development. SpecWeave provides spec
257
257
  /plugin marketplace add anton-abyzov/specweave
258
258
 
259
259
  # Install core framework
260
- /plugin install specweave@specweave
260
+ /plugin install specweave
261
261
 
262
262
  # Install GitHub plugin (optional)
263
- /plugin install specweave-github@specweave
263
+ /plugin install specweave-github
264
264
  \`\`\`
265
265
 
266
266
  ### For Other Tools (Cursor, Copilot, etc.)
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Environment Multi-Project Parser
3
+ *
4
+ * Parses comma-separated project lists from .env:
5
+ * - JIRA_PROJECT_KEYS=BACKEND,FRONTEND,MOBILE
6
+ * - GITHUB_REPOS=owner/backend-api,owner/frontend-web
7
+ * - AZURE_DEVOPS_PROJECTS=backend-api,frontend-web
8
+ *
9
+ * Auto-creates sync profiles for each project.
10
+ */
11
+ import { SyncProfile } from '../core/types/sync-profile.js';
12
+ export interface JiraProjectConfig {
13
+ projectKey: string;
14
+ domain: string;
15
+ email: string;
16
+ apiToken: string;
17
+ }
18
+ export interface GitHubRepoConfig {
19
+ owner: string;
20
+ repo: string;
21
+ token: string;
22
+ }
23
+ export interface AdoProjectConfig {
24
+ organization: string;
25
+ project: string;
26
+ pat: string;
27
+ }
28
+ export interface MultiProjectEnvConfig {
29
+ jira: JiraProjectConfig[];
30
+ github: GitHubRepoConfig[];
31
+ ado: AdoProjectConfig[];
32
+ }
33
+ /**
34
+ * Parse comma-separated list from environment variable
35
+ *
36
+ * Handles:
37
+ * - Comma separation
38
+ * - Whitespace trimming
39
+ * - Empty values filtering
40
+ *
41
+ * @example
42
+ * parseCommaSeparated("BACKEND, FRONTEND, MOBILE")
43
+ * // Returns: ["BACKEND", "FRONTEND", "MOBILE"]
44
+ */
45
+ export declare function parseCommaSeparated(value: string | undefined): string[];
46
+ /**
47
+ * Parse JIRA project keys from .env
48
+ *
49
+ * Reads:
50
+ * - JIRA_PROJECT_KEYS (comma-separated, NEW format)
51
+ * - JIRA_PROJECT_KEY (single, legacy format)
52
+ * - JIRA_DOMAIN, JIRA_EMAIL, JIRA_API_TOKEN (shared credentials)
53
+ *
54
+ * @returns Array of JIRA project configurations
55
+ *
56
+ * @example
57
+ * // .env:
58
+ * // JIRA_PROJECT_KEYS=BACKEND,FRONTEND,MOBILE
59
+ * // JIRA_DOMAIN=mycompany.atlassian.net
60
+ * // JIRA_EMAIL=user@example.com
61
+ * // JIRA_API_TOKEN=abc123
62
+ *
63
+ * parseJiraProjects()
64
+ * // Returns: [
65
+ * // { projectKey: "BACKEND", domain: "...", email: "...", apiToken: "..." },
66
+ * // { projectKey: "FRONTEND", ... },
67
+ * // { projectKey: "MOBILE", ... }
68
+ * // ]
69
+ */
70
+ export declare function parseJiraProjects(): JiraProjectConfig[];
71
+ /**
72
+ * Parse GitHub repositories from .env
73
+ *
74
+ * Reads:
75
+ * - GITHUB_REPOS (comma-separated, format: "owner/repo,owner2/repo2")
76
+ * - GITHUB_TOKEN (shared credential)
77
+ *
78
+ * @returns Array of GitHub repository configurations
79
+ *
80
+ * @example
81
+ * // .env:
82
+ * // GITHUB_REPOS=myorg/backend-api,myorg/frontend-web
83
+ * // GITHUB_TOKEN=ghp_abc123
84
+ *
85
+ * parseGitHubRepos()
86
+ * // Returns: [
87
+ * // { owner: "myorg", repo: "backend-api", token: "..." },
88
+ * // { owner: "myorg", repo: "frontend-web", token: "..." }
89
+ * // ]
90
+ */
91
+ export declare function parseGitHubRepos(): GitHubRepoConfig[];
92
+ /**
93
+ * Parse Azure DevOps projects from .env
94
+ *
95
+ * Reads:
96
+ * - AZURE_DEVOPS_PROJECTS (comma-separated)
97
+ * - AZURE_DEVOPS_ORG (shared organization)
98
+ * - AZURE_DEVOPS_PAT (shared credential)
99
+ *
100
+ * @returns Array of Azure DevOps project configurations
101
+ *
102
+ * @example
103
+ * // .env:
104
+ * // AZURE_DEVOPS_PROJECTS=backend-api,frontend-web
105
+ * // AZURE_DEVOPS_ORG=easychamp
106
+ * // AZURE_DEVOPS_PAT=xyz789
107
+ *
108
+ * parseAdoProjects()
109
+ * // Returns: [
110
+ * // { organization: "easychamp", project: "backend-api", pat: "..." },
111
+ * // { organization: "easychamp", project: "frontend-web", pat: "..." }
112
+ * // ]
113
+ */
114
+ export declare function parseAdoProjects(): AdoProjectConfig[];
115
+ /**
116
+ * Parse all multi-project configurations from .env
117
+ *
118
+ * @returns All detected project configurations
119
+ */
120
+ export declare function parseMultiProjectEnv(): MultiProjectEnvConfig;
121
+ /**
122
+ * Generate sync profile ID from project identifier
123
+ *
124
+ * Format: "{provider}-{project-id}"
125
+ *
126
+ * @example
127
+ * generateProfileId("jira", "BACKEND")
128
+ * // Returns: "jira-backend"
129
+ *
130
+ * @example
131
+ * generateProfileId("github", "backend-api")
132
+ * // Returns: "github-backend-api"
133
+ */
134
+ export declare function generateProfileId(provider: string, projectId: string): string;
135
+ /**
136
+ * Create JIRA sync profile from project configuration
137
+ */
138
+ export declare function createJiraSyncProfile(config: JiraProjectConfig): {
139
+ id: string;
140
+ profile: Omit<SyncProfile, 'id'>;
141
+ };
142
+ /**
143
+ * Create GitHub sync profile from repository configuration
144
+ */
145
+ export declare function createGitHubSyncProfile(config: GitHubRepoConfig): {
146
+ id: string;
147
+ profile: Omit<SyncProfile, 'id'>;
148
+ };
149
+ /**
150
+ * Create Azure DevOps sync profile from project configuration
151
+ */
152
+ export declare function createAdoSyncProfile(config: AdoProjectConfig): {
153
+ id: string;
154
+ profile: Omit<SyncProfile, 'id'>;
155
+ };
156
+ /**
157
+ * Generate all sync profiles from environment variables
158
+ *
159
+ * @returns Array of { id, profile } objects ready to be created
160
+ *
161
+ * @example
162
+ * // .env:
163
+ * // JIRA_PROJECT_KEYS=BACKEND,FRONTEND
164
+ * // GITHUB_REPOS=myorg/backend-api
165
+ *
166
+ * const profiles = generateSyncProfilesFromEnv();
167
+ * // Returns: [
168
+ * // { id: "jira-backend", profile: { ... } },
169
+ * // { id: "jira-frontend", profile: { ... } },
170
+ * // { id: "github-backend-api", profile: { ... } }
171
+ * // ]
172
+ */
173
+ export declare function generateSyncProfilesFromEnv(): Array<{
174
+ id: string;
175
+ profile: Omit<SyncProfile, 'id'>;
176
+ }>;
177
+ /**
178
+ * Validate JIRA project key format
179
+ *
180
+ * Rules:
181
+ * - 2-10 characters
182
+ * - Uppercase letters only
183
+ * - No special characters
184
+ *
185
+ * @example
186
+ * validateJiraProjectKey("BACKEND") // → true
187
+ * validateJiraProjectKey("backend") // → "Must be uppercase"
188
+ * validateJiraProjectKey("BACK") // → true
189
+ * validateJiraProjectKey("B") // → "Must be 2-10 characters"
190
+ */
191
+ export declare function validateJiraProjectKey(key: string): true | string;
192
+ /**
193
+ * Validate GitHub repo format
194
+ *
195
+ * Format: "owner/repo"
196
+ *
197
+ * @example
198
+ * validateGitHubRepo("myorg/backend-api") // → true
199
+ * validateGitHubRepo("backend-api") // → "Must be owner/repo format"
200
+ */
201
+ export declare function validateGitHubRepo(repo: string): true | string;
202
+ /**
203
+ * Validate Azure DevOps project name
204
+ *
205
+ * @example
206
+ * validateAdoProject("backend-api") // → true
207
+ * validateAdoProject("") // → "Project name is required"
208
+ */
209
+ export declare function validateAdoProject(project: string): true | string;
210
+ //# sourceMappingURL=env-multi-project-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-multi-project-parser.d.ts","sourceRoot":"","sources":["../../src/utils/env-multi-project-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAM5D,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAC1B,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,GAAG,EAAE,gBAAgB,EAAE,CAAC;CACzB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CASvE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,IAAI,iBAAiB,EAAE,CAoCvD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,IAAI,gBAAgB,EAAE,CA8BrD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,IAAI,gBAAgB,EAAE,CAiCrD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,qBAAqB,CAM5D;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,GAAG;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;CAClC,CAwBA;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG;IACjE,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;CAClC,CAuBA;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,gBAAgB,GAAG;IAC9D,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;CAClC,CAwBA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,2BAA2B,IAAI,KAAK,CAAC;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;CAClC,CAAC,CAoBD;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAcjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAqB9D;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAUjE"}