specweave 1.0.30 → 1.0.32

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 (79) hide show
  1. package/CLAUDE.md +140 -1235
  2. package/bin/specweave.js +23 -0
  3. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +3 -0
  4. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
  5. package/dist/plugins/specweave-github/lib/github-client-v2.js +39 -0
  6. package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
  7. package/dist/src/cli/commands/set-sync-target.d.ts +41 -0
  8. package/dist/src/cli/commands/set-sync-target.d.ts.map +1 -0
  9. package/dist/src/cli/commands/set-sync-target.js +126 -0
  10. package/dist/src/cli/commands/set-sync-target.js.map +1 -0
  11. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
  12. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +5 -8
  13. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
  14. package/dist/src/core/hooks/HookScanner.d.ts +32 -0
  15. package/dist/src/core/hooks/HookScanner.d.ts.map +1 -1
  16. package/dist/src/core/hooks/HookScanner.js +125 -1
  17. package/dist/src/core/hooks/HookScanner.js.map +1 -1
  18. package/dist/src/core/hooks/types.d.ts +10 -1
  19. package/dist/src/core/hooks/types.d.ts.map +1 -1
  20. package/dist/src/core/increment/metadata-manager.d.ts +67 -1
  21. package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
  22. package/dist/src/core/increment/metadata-manager.js +93 -0
  23. package/dist/src/core/increment/metadata-manager.js.map +1 -1
  24. package/dist/src/core/project/index.d.ts +21 -0
  25. package/dist/src/core/project/index.d.ts.map +1 -0
  26. package/dist/src/core/project/index.js +22 -0
  27. package/dist/src/core/project/index.js.map +1 -0
  28. package/dist/src/core/project/project-service.d.ts +122 -0
  29. package/dist/src/core/project/project-service.d.ts.map +1 -0
  30. package/dist/src/core/project/project-service.js +334 -0
  31. package/dist/src/core/project/project-service.js.map +1 -0
  32. package/dist/src/core/sync/external-tool-resolver.d.ts +171 -0
  33. package/dist/src/core/sync/external-tool-resolver.d.ts.map +1 -0
  34. package/dist/src/core/sync/external-tool-resolver.js +569 -0
  35. package/dist/src/core/sync/external-tool-resolver.js.map +1 -0
  36. package/dist/src/core/types/increment-metadata.d.ts +92 -0
  37. package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
  38. package/dist/src/hooks/processor.d.ts +7 -3
  39. package/dist/src/hooks/processor.d.ts.map +1 -1
  40. package/dist/src/hooks/processor.js +11 -5
  41. package/dist/src/hooks/processor.js.map +1 -1
  42. package/package.json +1 -1
  43. package/plugins/specweave/hooks/hooks.json +0 -69
  44. package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +96 -0
  45. package/plugins/specweave/hooks/v2/queue/processor.sh +13 -5
  46. package/plugins/specweave/lib/hooks/project-bridge.js +76 -0
  47. package/plugins/specweave/lib/hooks/update-tasks-md.js +0 -0
  48. package/plugins/specweave/lib/hooks/us-completion-orchestrator.js +0 -0
  49. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.d.ts +67 -1
  50. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +93 -0
  51. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
  52. package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +92 -0
  53. package/plugins/specweave-github/lib/github-client-v2.js +39 -0
  54. package/plugins/specweave-github/lib/github-client-v2.ts +44 -0
  55. package/plugins/specweave/hooks/docs-changed.sh +0 -87
  56. package/plugins/specweave/hooks/human-input-required.sh +0 -83
  57. package/plugins/specweave/hooks/post-edit-write-consolidated.sh +0 -428
  58. package/plugins/specweave/hooks/post-first-increment.sh +0 -61
  59. package/plugins/specweave/hooks/post-increment-change.sh +0 -103
  60. package/plugins/specweave/hooks/post-increment-completion.sh +0 -513
  61. package/plugins/specweave/hooks/post-increment-planning.sh +0 -1204
  62. package/plugins/specweave/hooks/post-increment-status-change.sh +0 -243
  63. package/plugins/specweave/hooks/post-metadata-change.sh +0 -246
  64. package/plugins/specweave/hooks/post-spec-update.sh +0 -158
  65. package/plugins/specweave/hooks/post-task-completion.sh +0 -557
  66. package/plugins/specweave/hooks/post-task-edit.sh +0 -47
  67. package/plugins/specweave/hooks/post-user-story-complete.sh +0 -230
  68. package/plugins/specweave/hooks/pre-command-deduplication.sh +0 -68
  69. package/plugins/specweave/hooks/pre-edit-write-consolidated.sh +0 -225
  70. package/plugins/specweave/hooks/pre-implementation.sh +0 -75
  71. package/plugins/specweave/hooks/pre-increment-start.sh +0 -173
  72. package/plugins/specweave/hooks/pre-task-completion-edit.sh +0 -355
  73. package/plugins/specweave/hooks/pre-task-completion.sh +0 -269
  74. package/plugins/specweave/hooks/pre-tool-use.sh +0 -137
  75. package/plugins/specweave/hooks/session-start-reconcile.sh +0 -139
  76. package/plugins/specweave/hooks/shared/bulk-operation-detector.sh +0 -167
  77. package/plugins/specweave/hooks/test-pretooluse-env.sh +0 -72
  78. package/plugins/specweave/hooks/validate-increment-completion.sh +0 -113
  79. package/plugins/specweave/lib/hooks/consolidated-sync.js +0 -288
@@ -0,0 +1,122 @@
1
+ /**
2
+ * ProjectService - Singleton service for project-level EDA
3
+ *
4
+ * Provides a centralized service that:
5
+ * 1. Initializes ProjectRegistry with subscribed adapters
6
+ * 2. Bridges increment-level events to project-level events
7
+ * 3. Manages adapter lifecycle (subscribe/unsubscribe)
8
+ *
9
+ * This service connects the two EDA layers:
10
+ * - Increment-level EDA (shell hooks, detectors, handlers)
11
+ * - Project-level EDA (ProjectRegistry, ProjectEventBus, Adapters)
12
+ *
13
+ * Usage:
14
+ * const service = await ProjectService.getInstance(projectRoot);
15
+ * await service.initialize(); // Subscribes adapters
16
+ * service.emitIncrementEvent('increment.done', '0145-project-registry');
17
+ */
18
+ import { Logger } from '../../utils/logger.js';
19
+ import { ProjectRegistry } from './project-registry.js';
20
+ import { ProjectEventBus } from './project-event-bus.js';
21
+ /**
22
+ * Increment event types from hooks v2
23
+ */
24
+ export type IncrementEventType = 'increment.created' | 'increment.done' | 'increment.archived' | 'increment.reopened' | 'user-story.completed' | 'user-story.reopened';
25
+ /**
26
+ * Configuration for external tool adapters
27
+ */
28
+ export interface AdapterConfig {
29
+ github?: {
30
+ enabled: boolean;
31
+ owner: string;
32
+ repo: string;
33
+ token?: string;
34
+ };
35
+ ado?: {
36
+ enabled: boolean;
37
+ organization: string;
38
+ project: string;
39
+ token?: string;
40
+ };
41
+ jira?: {
42
+ enabled: boolean;
43
+ domain: string;
44
+ email?: string;
45
+ token?: string;
46
+ };
47
+ }
48
+ /**
49
+ * ProjectService - Singleton pattern for managing project EDA
50
+ */
51
+ export declare class ProjectService {
52
+ private static instances;
53
+ private projectRoot;
54
+ private registry;
55
+ private eventBus;
56
+ private logger;
57
+ private adapters;
58
+ private initialized;
59
+ private constructor();
60
+ /**
61
+ * Get singleton instance for a project root
62
+ */
63
+ static getInstance(projectRoot: string, logger?: Logger): ProjectService;
64
+ /**
65
+ * Clear singleton instance (for testing)
66
+ */
67
+ static clearInstance(projectRoot: string): void;
68
+ /**
69
+ * Clear all instances (for testing)
70
+ */
71
+ static clearAllInstances(): void;
72
+ /**
73
+ * Initialize the service with adapters
74
+ *
75
+ * Loads adapter configuration from:
76
+ * 1. .specweave/config.json (sync section)
77
+ * 2. Environment variables (GITHUB_TOKEN, etc.)
78
+ * 3. .env file
79
+ */
80
+ initialize(): Promise<void>;
81
+ /**
82
+ * Load adapter configuration from various sources
83
+ */
84
+ private loadAdapterConfig;
85
+ /**
86
+ * Get the project registry
87
+ */
88
+ getRegistry(): ProjectRegistry;
89
+ /**
90
+ * Get the event bus
91
+ */
92
+ getEventBus(): ProjectEventBus;
93
+ /**
94
+ * Check if service is initialized
95
+ */
96
+ isInitialized(): boolean;
97
+ /**
98
+ * Bridge increment-level events to project-level events
99
+ *
100
+ * Called by the project-bridge-handler when increment events occur.
101
+ * Maps increment changes to project sync requests.
102
+ *
103
+ * @param eventType - Increment event type
104
+ * @param eventData - Increment ID or INC_ID:US_ID format
105
+ */
106
+ emitIncrementEvent(eventType: IncrementEventType, eventData: string): Promise<void>;
107
+ /**
108
+ * Get project ID associated with an increment
109
+ *
110
+ * Reads the increment's spec.md to find the project field
111
+ */
112
+ private getProjectForIncrement;
113
+ /**
114
+ * Request sync for all projects
115
+ */
116
+ syncAllProjects(): Promise<void>;
117
+ /**
118
+ * Discover projects from external tools
119
+ */
120
+ discoverProjects(): Promise<Map<string, any[]>>;
121
+ }
122
+ //# sourceMappingURL=project-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-service.d.ts","sourceRoot":"","sources":["../../../../src/core/project/project-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAAE,MAAM,EAAiB,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAKzD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B,mBAAmB,GACnB,gBAAgB,GAChB,oBAAoB,GACpB,oBAAoB,GACpB,sBAAsB,GACtB,qBAAqB,CAAC;AAE1B;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE;QACP,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,IAAI,CAAC,EAAE;QACL,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,SAAS,CAA0C;IAElE,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAIT;IACP,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO;IAUP;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,cAAc;IAaxE;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAK/C;;OAEG;IACH,MAAM,CAAC,iBAAiB,IAAI,IAAI;IAIhC;;;;;;;OAOG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgDjC;;OAEG;YACW,iBAAiB;IA4E/B;;OAEG;IACH,WAAW,IAAI,eAAe;IAI9B;;OAEG;IACH,WAAW,IAAI,eAAe;IAI9B;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;;;;;;;OAQG;IACG,kBAAkB,CAAC,SAAS,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmDzF;;;;OAIG;YACW,sBAAsB;IAwCpC;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtC;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;CAsCtD"}
@@ -0,0 +1,334 @@
1
+ /**
2
+ * ProjectService - Singleton service for project-level EDA
3
+ *
4
+ * Provides a centralized service that:
5
+ * 1. Initializes ProjectRegistry with subscribed adapters
6
+ * 2. Bridges increment-level events to project-level events
7
+ * 3. Manages adapter lifecycle (subscribe/unsubscribe)
8
+ *
9
+ * This service connects the two EDA layers:
10
+ * - Increment-level EDA (shell hooks, detectors, handlers)
11
+ * - Project-level EDA (ProjectRegistry, ProjectEventBus, Adapters)
12
+ *
13
+ * Usage:
14
+ * const service = await ProjectService.getInstance(projectRoot);
15
+ * await service.initialize(); // Subscribes adapters
16
+ * service.emitIncrementEvent('increment.done', '0145-project-registry');
17
+ */
18
+ import path from 'path';
19
+ import * as fs from '../../utils/fs-native.js';
20
+ import { consoleLogger } from '../../utils/logger.js';
21
+ import { ProjectRegistry } from './project-registry.js';
22
+ import { ProjectEventBus } from './project-event-bus.js';
23
+ import { GitHubProjectAdapter } from './adapters/github-project-adapter.js';
24
+ import { ADOProjectAdapter } from './adapters/ado-project-adapter.js';
25
+ import { JiraProjectAdapter } from './adapters/jira-project-adapter.js';
26
+ /**
27
+ * ProjectService - Singleton pattern for managing project EDA
28
+ */
29
+ export class ProjectService {
30
+ constructor(projectRoot, logger) {
31
+ this.adapters = {};
32
+ this.initialized = false;
33
+ this.projectRoot = projectRoot;
34
+ this.logger = logger ?? consoleLogger;
35
+ this.eventBus = new ProjectEventBus({ logger: this.logger });
36
+ this.registry = new ProjectRegistry(projectRoot, {
37
+ logger: this.logger,
38
+ eventBus: this.eventBus,
39
+ });
40
+ }
41
+ /**
42
+ * Get singleton instance for a project root
43
+ */
44
+ static getInstance(projectRoot, logger) {
45
+ const normalizedPath = path.normalize(projectRoot);
46
+ if (!ProjectService.instances.has(normalizedPath)) {
47
+ ProjectService.instances.set(normalizedPath, new ProjectService(normalizedPath, logger));
48
+ }
49
+ return ProjectService.instances.get(normalizedPath);
50
+ }
51
+ /**
52
+ * Clear singleton instance (for testing)
53
+ */
54
+ static clearInstance(projectRoot) {
55
+ const normalizedPath = path.normalize(projectRoot);
56
+ ProjectService.instances.delete(normalizedPath);
57
+ }
58
+ /**
59
+ * Clear all instances (for testing)
60
+ */
61
+ static clearAllInstances() {
62
+ ProjectService.instances.clear();
63
+ }
64
+ /**
65
+ * Initialize the service with adapters
66
+ *
67
+ * Loads adapter configuration from:
68
+ * 1. .specweave/config.json (sync section)
69
+ * 2. Environment variables (GITHUB_TOKEN, etc.)
70
+ * 3. .env file
71
+ */
72
+ async initialize() {
73
+ if (this.initialized) {
74
+ return;
75
+ }
76
+ this.logger.debug('Initializing ProjectService...');
77
+ // Load adapter configuration
78
+ const config = await this.loadAdapterConfig();
79
+ // Initialize and subscribe adapters
80
+ if (config.github?.enabled) {
81
+ this.adapters.github = new GitHubProjectAdapter({
82
+ logger: this.logger,
83
+ owner: config.github.owner,
84
+ repo: config.github.repo,
85
+ token: config.github.token,
86
+ });
87
+ this.adapters.github.subscribe(this.registry);
88
+ this.logger.debug('GitHub adapter subscribed');
89
+ }
90
+ if (config.ado?.enabled) {
91
+ this.adapters.ado = new ADOProjectAdapter({
92
+ logger: this.logger,
93
+ organization: config.ado.organization,
94
+ project: config.ado.project,
95
+ pat: config.ado.token, // ADO adapter uses 'pat' not 'token'
96
+ });
97
+ this.adapters.ado.subscribe(this.registry);
98
+ this.logger.debug('ADO adapter subscribed');
99
+ }
100
+ if (config.jira?.enabled) {
101
+ this.adapters.jira = new JiraProjectAdapter({
102
+ logger: this.logger,
103
+ domain: config.jira.domain,
104
+ email: config.jira.email,
105
+ apiToken: config.jira.token, // JIRA adapter uses 'apiToken' not 'token'
106
+ });
107
+ this.adapters.jira.subscribe(this.registry);
108
+ this.logger.debug('JIRA adapter subscribed');
109
+ }
110
+ this.initialized = true;
111
+ this.logger.info('ProjectService initialized');
112
+ }
113
+ /**
114
+ * Load adapter configuration from various sources
115
+ */
116
+ async loadAdapterConfig() {
117
+ const config = {};
118
+ // Load .env file if exists
119
+ const envPath = path.join(this.projectRoot, '.env');
120
+ const envVars = {};
121
+ if (fs.existsSync(envPath)) {
122
+ const envContent = fs.readFileSync(envPath, 'utf-8');
123
+ for (const line of envContent.split('\n')) {
124
+ const match = line.match(/^([^=]+)=(.*)$/);
125
+ if (match) {
126
+ const key = match[1].trim();
127
+ const value = match[2].trim().replace(/^["']|["']$/g, '');
128
+ envVars[key] = value;
129
+ }
130
+ }
131
+ }
132
+ // Load config.json
133
+ const configPath = path.join(this.projectRoot, '.specweave', 'config.json');
134
+ let specweaveConfig = {};
135
+ if (fs.existsSync(configPath)) {
136
+ try {
137
+ specweaveConfig = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
138
+ }
139
+ catch {
140
+ // Ignore parse errors
141
+ }
142
+ }
143
+ // GitHub configuration
144
+ const githubToken = envVars.GITHUB_TOKEN || process.env.GITHUB_TOKEN;
145
+ const githubOwner = specweaveConfig.sync?.github?.owner || envVars.GITHUB_OWNER || process.env.GITHUB_OWNER;
146
+ const githubRepo = specweaveConfig.sync?.github?.repo || envVars.GITHUB_REPO || process.env.GITHUB_REPO;
147
+ if (githubToken && githubOwner && githubRepo) {
148
+ config.github = {
149
+ enabled: specweaveConfig.sync?.github?.enabled !== false,
150
+ owner: githubOwner,
151
+ repo: githubRepo,
152
+ token: githubToken,
153
+ };
154
+ }
155
+ // ADO configuration
156
+ const adoToken = envVars.AZURE_DEVOPS_PAT || process.env.AZURE_DEVOPS_PAT;
157
+ const adoOrg = specweaveConfig.sync?.ado?.organization || envVars.AZURE_DEVOPS_ORG || process.env.AZURE_DEVOPS_ORG;
158
+ const adoProject = specweaveConfig.sync?.ado?.project || envVars.AZURE_DEVOPS_PROJECT || process.env.AZURE_DEVOPS_PROJECT;
159
+ if (adoToken && adoOrg && adoProject) {
160
+ config.ado = {
161
+ enabled: specweaveConfig.sync?.ado?.enabled !== false,
162
+ organization: adoOrg,
163
+ project: adoProject,
164
+ token: adoToken,
165
+ };
166
+ }
167
+ // JIRA configuration
168
+ const jiraToken = envVars.JIRA_API_TOKEN || process.env.JIRA_API_TOKEN;
169
+ const jiraDomain = specweaveConfig.sync?.jira?.domain || envVars.JIRA_DOMAIN || process.env.JIRA_DOMAIN;
170
+ const jiraEmail = envVars.JIRA_EMAIL || process.env.JIRA_EMAIL;
171
+ if (jiraToken && jiraDomain) {
172
+ config.jira = {
173
+ enabled: specweaveConfig.sync?.jira?.enabled !== false,
174
+ domain: jiraDomain,
175
+ email: jiraEmail,
176
+ token: jiraToken,
177
+ };
178
+ }
179
+ return config;
180
+ }
181
+ /**
182
+ * Get the project registry
183
+ */
184
+ getRegistry() {
185
+ return this.registry;
186
+ }
187
+ /**
188
+ * Get the event bus
189
+ */
190
+ getEventBus() {
191
+ return this.eventBus;
192
+ }
193
+ /**
194
+ * Check if service is initialized
195
+ */
196
+ isInitialized() {
197
+ return this.initialized;
198
+ }
199
+ /**
200
+ * Bridge increment-level events to project-level events
201
+ *
202
+ * Called by the project-bridge-handler when increment events occur.
203
+ * Maps increment changes to project sync requests.
204
+ *
205
+ * @param eventType - Increment event type
206
+ * @param eventData - Increment ID or INC_ID:US_ID format
207
+ */
208
+ async emitIncrementEvent(eventType, eventData) {
209
+ if (!this.initialized) {
210
+ await this.initialize();
211
+ }
212
+ // Parse event data
213
+ const incId = eventData.includes(':') ? eventData.split(':')[0] : eventData;
214
+ this.logger.debug(`Processing increment event: ${eventType} for ${incId}`);
215
+ // Get project associated with this increment
216
+ const projectId = await this.getProjectForIncrement(incId);
217
+ if (!projectId) {
218
+ this.logger.debug(`No project found for increment ${incId}`);
219
+ return;
220
+ }
221
+ // Map increment events to project sync requests
222
+ switch (eventType) {
223
+ case 'increment.done':
224
+ // When increment completes, request sync to external tools
225
+ await this.registry.requestSync(projectId, ['github', 'ado', 'jira']);
226
+ break;
227
+ case 'increment.created':
228
+ // New increment - may want to create project labels/areas
229
+ // Only sync if this is a new project
230
+ const project = await this.registry.getProject(projectId);
231
+ if (project && !project.external?.github?.lastSynced) {
232
+ await this.registry.requestSync(projectId, ['github']);
233
+ }
234
+ break;
235
+ case 'increment.archived':
236
+ // Archived increment - no immediate sync needed
237
+ break;
238
+ case 'increment.reopened':
239
+ // Reopened increment - sync status update
240
+ await this.registry.requestSync(projectId, ['github']);
241
+ break;
242
+ case 'user-story.completed':
243
+ case 'user-story.reopened':
244
+ // User story changes - could trigger issue updates
245
+ // Currently handled by living-specs-handler directly
246
+ break;
247
+ }
248
+ }
249
+ /**
250
+ * Get project ID associated with an increment
251
+ *
252
+ * Reads the increment's spec.md to find the project field
253
+ */
254
+ async getProjectForIncrement(incId) {
255
+ const specPath = path.join(this.projectRoot, '.specweave', 'increments', incId, 'spec.md');
256
+ if (!fs.existsSync(specPath)) {
257
+ return null;
258
+ }
259
+ try {
260
+ const content = fs.readFileSync(specPath, 'utf-8');
261
+ // Look for project field in YAML frontmatter or body
262
+ const projectMatch = content.match(/^project:\s*["']?([^"'\n]+)["']?/m);
263
+ if (projectMatch) {
264
+ return projectMatch[1].trim();
265
+ }
266
+ // Also check for **Project**: field
267
+ const projectFieldMatch = content.match(/\*\*Project\*\*:\s*([^\n]+)/);
268
+ if (projectFieldMatch) {
269
+ // Extract project ID from format like "project-name" or "Project Name (project-id)"
270
+ const projectField = projectFieldMatch[1].trim();
271
+ const idMatch = projectField.match(/\(([^)]+)\)$/);
272
+ if (idMatch) {
273
+ return idMatch[1];
274
+ }
275
+ return projectField.toLowerCase().replace(/\s+/g, '-');
276
+ }
277
+ return null;
278
+ }
279
+ catch {
280
+ return null;
281
+ }
282
+ }
283
+ /**
284
+ * Request sync for all projects
285
+ */
286
+ async syncAllProjects() {
287
+ if (!this.initialized) {
288
+ await this.initialize();
289
+ }
290
+ await this.registry.requestSync(undefined, ['github', 'ado', 'jira']);
291
+ }
292
+ /**
293
+ * Discover projects from external tools
294
+ */
295
+ async discoverProjects() {
296
+ const discovered = new Map();
297
+ if (this.adapters.github) {
298
+ try {
299
+ const projects = await this.adapters.github.discoverProjects();
300
+ if (projects.length > 0) {
301
+ discovered.set('github', projects);
302
+ }
303
+ }
304
+ catch (error) {
305
+ this.logger.warn(`GitHub discovery failed: ${error}`);
306
+ }
307
+ }
308
+ if (this.adapters.ado) {
309
+ try {
310
+ const projects = await this.adapters.ado.discoverProjects();
311
+ if (projects.length > 0) {
312
+ discovered.set('ado', projects);
313
+ }
314
+ }
315
+ catch (error) {
316
+ this.logger.warn(`ADO discovery failed: ${error}`);
317
+ }
318
+ }
319
+ if (this.adapters.jira) {
320
+ try {
321
+ const projects = await this.adapters.jira.discoverProjects();
322
+ if (projects.length > 0) {
323
+ discovered.set('jira', projects);
324
+ }
325
+ }
326
+ catch (error) {
327
+ this.logger.warn(`JIRA discovery failed: ${error}`);
328
+ }
329
+ }
330
+ return discovered;
331
+ }
332
+ }
333
+ ProjectService.instances = new Map();
334
+ //# sourceMappingURL=project-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-service.js","sourceRoot":"","sources":["../../../../src/core/project/project-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * External Tool Resolver Service (v1.0.31+ - ADR-0211)
3
+ *
4
+ * Single source of truth for external tool selection.
5
+ * Resolves which sync profile an increment should use based on:
6
+ * 1. Explicit syncTarget in metadata (highest priority)
7
+ * 2. Project mapping from spec.md **Project**: field
8
+ * 3. Default profile from config (fallback)
9
+ *
10
+ * @module core/sync/external-tool-resolver
11
+ */
12
+ import { SyncTarget, SyncTargetDerivation, ExternalToolValidationResult } from '../types/increment-metadata.js';
13
+ import { SyncProfile, SyncProvider } from '../types/sync-profile.js';
14
+ import { Logger } from '../../utils/logger.js';
15
+ /**
16
+ * Project mapping configuration (from config.json)
17
+ * Maps SpecWeave project IDs to external tool targets
18
+ */
19
+ export interface ProjectMapping {
20
+ github?: {
21
+ owner: string;
22
+ repo: string;
23
+ profileId?: string;
24
+ };
25
+ jira?: {
26
+ project: string;
27
+ board?: string;
28
+ profileId?: string;
29
+ };
30
+ ado?: {
31
+ project: string;
32
+ areaPath?: string;
33
+ profileId?: string;
34
+ };
35
+ }
36
+ export interface ProjectMappings {
37
+ [projectId: string]: ProjectMapping;
38
+ }
39
+ /**
40
+ * Resolution result with full context
41
+ */
42
+ export interface ResolutionResult {
43
+ /** Resolved sync target */
44
+ syncTarget: SyncTarget | null;
45
+ /** Full profile configuration (if resolved) */
46
+ profile: SyncProfile | null;
47
+ /** Resolution path for debugging */
48
+ resolutionPath: string[];
49
+ /** Any warnings during resolution */
50
+ warnings: string[];
51
+ }
52
+ /**
53
+ * External Tool Resolver
54
+ *
55
+ * Provides unified external tool selection logic.
56
+ * Use this service instead of scattered logic throughout the codebase.
57
+ */
58
+ export declare class ExternalToolResolver {
59
+ private projectRoot;
60
+ private configPath;
61
+ private config;
62
+ private logger;
63
+ constructor(projectRoot: string, options?: {
64
+ logger?: Logger;
65
+ });
66
+ /**
67
+ * Load configuration from disk
68
+ */
69
+ private loadConfig;
70
+ /**
71
+ * Get sync configuration
72
+ */
73
+ private getSyncConfig;
74
+ /**
75
+ * Get project mappings
76
+ */
77
+ private getProjectMappings;
78
+ /**
79
+ * Resolve external tool for an increment
80
+ *
81
+ * Resolution priority:
82
+ * 1. Explicit syncTarget in metadata
83
+ * 2. Project mapping from spec.md **Project**: field
84
+ * 3. Default profile from config
85
+ *
86
+ * @param incrementId - Increment ID (e.g., "0142-feature")
87
+ * @param projectId - Optional project ID from spec.md (for priority 2)
88
+ * @returns Resolution result with sync target and profile
89
+ */
90
+ resolveForIncrement(incrementId: string, projectId?: string): Promise<ResolutionResult>;
91
+ /**
92
+ * Resolve external tool for a specific project ID
93
+ *
94
+ * Looks up project in config.projectMappings and resolves to a profile.
95
+ *
96
+ * @param projectId - SpecWeave project ID (e.g., "frontend-app")
97
+ * @returns Resolution result
98
+ */
99
+ resolveForProject(projectId: string): Promise<ResolutionResult>;
100
+ /**
101
+ * Resolve for a specific provider (e.g., "get me the GitHub profile")
102
+ *
103
+ * @param provider - Provider type
104
+ * @param projectId - Optional project ID for project-specific profile
105
+ * @returns Resolution result
106
+ */
107
+ resolveForProvider(provider: SyncProvider, projectId?: string): Promise<ResolutionResult>;
108
+ /**
109
+ * Validate external tool configuration for an increment
110
+ *
111
+ * Call this at increment start to fail fast if config is missing.
112
+ *
113
+ * @param incrementId - Increment ID
114
+ * @param projectId - Project ID from spec.md
115
+ * @returns Validation result
116
+ */
117
+ validateIncrementConfig(incrementId: string, projectId?: string): Promise<ExternalToolValidationResult>;
118
+ /**
119
+ * Validate profile configuration completeness
120
+ */
121
+ private validateProfileConfig;
122
+ /**
123
+ * Check if authentication is configured for a provider
124
+ */
125
+ private checkAuthentication;
126
+ /**
127
+ * Load increment metadata
128
+ */
129
+ private loadIncrementMetadata;
130
+ /**
131
+ * Get profile by ID
132
+ */
133
+ private getProfileById;
134
+ /**
135
+ * Find profile matching a project mapping
136
+ */
137
+ private findProfileByMapping;
138
+ /**
139
+ * Create a sync target for saving to metadata
140
+ *
141
+ * @param profileId - Profile ID
142
+ * @param provider - Provider type
143
+ * @param derivedFrom - How it was determined
144
+ * @param sourceProjectId - Optional source project
145
+ * @returns SyncTarget object
146
+ */
147
+ static createSyncTarget(profileId: string, provider: SyncProvider, derivedFrom: SyncTargetDerivation, sourceProjectId?: string): SyncTarget;
148
+ /**
149
+ * Check if any external tool is configured
150
+ */
151
+ hasExternalToolConfigured(): Promise<boolean>;
152
+ /**
153
+ * Get all configured providers
154
+ */
155
+ getConfiguredProviders(): Promise<SyncProvider[]>;
156
+ /**
157
+ * Get summary of external tool configuration
158
+ */
159
+ getConfigSummary(): Promise<{
160
+ hasConfig: boolean;
161
+ providers: SyncProvider[];
162
+ profileCount: number;
163
+ defaultProfile?: string;
164
+ projectMappingCount: number;
165
+ }>;
166
+ }
167
+ /**
168
+ * Factory function for creating ExternalToolResolver
169
+ */
170
+ export declare function createExternalToolResolver(projectRoot: string, logger?: Logger): ExternalToolResolver;
171
+ //# sourceMappingURL=external-tool-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-tool-resolver.d.ts","sourceRoot":"","sources":["../../../../src/core/sync/external-tool-resolver.ts"],"names":[],"mappings":"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"}