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.
- package/CLAUDE.md +140 -1235
- package/bin/specweave.js +23 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +3 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.js +39 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
- package/dist/src/cli/commands/set-sync-target.d.ts +41 -0
- package/dist/src/cli/commands/set-sync-target.d.ts.map +1 -0
- package/dist/src/cli/commands/set-sync-target.js +126 -0
- package/dist/src/cli/commands/set-sync-target.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +5 -8
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
- package/dist/src/core/hooks/HookScanner.d.ts +32 -0
- package/dist/src/core/hooks/HookScanner.d.ts.map +1 -1
- package/dist/src/core/hooks/HookScanner.js +125 -1
- package/dist/src/core/hooks/HookScanner.js.map +1 -1
- package/dist/src/core/hooks/types.d.ts +10 -1
- package/dist/src/core/hooks/types.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.d.ts +67 -1
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +93 -0
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/project/index.d.ts +21 -0
- package/dist/src/core/project/index.d.ts.map +1 -0
- package/dist/src/core/project/index.js +22 -0
- package/dist/src/core/project/index.js.map +1 -0
- package/dist/src/core/project/project-service.d.ts +122 -0
- package/dist/src/core/project/project-service.d.ts.map +1 -0
- package/dist/src/core/project/project-service.js +334 -0
- package/dist/src/core/project/project-service.js.map +1 -0
- package/dist/src/core/sync/external-tool-resolver.d.ts +171 -0
- package/dist/src/core/sync/external-tool-resolver.d.ts.map +1 -0
- package/dist/src/core/sync/external-tool-resolver.js +569 -0
- package/dist/src/core/sync/external-tool-resolver.js.map +1 -0
- package/dist/src/core/types/increment-metadata.d.ts +92 -0
- package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
- package/dist/src/hooks/processor.d.ts +7 -3
- package/dist/src/hooks/processor.d.ts.map +1 -1
- package/dist/src/hooks/processor.js +11 -5
- package/dist/src/hooks/processor.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/hooks/hooks.json +0 -69
- package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +96 -0
- package/plugins/specweave/hooks/v2/queue/processor.sh +13 -5
- package/plugins/specweave/lib/hooks/project-bridge.js +76 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.js +0 -0
- package/plugins/specweave/lib/hooks/us-completion-orchestrator.js +0 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.d.ts +67 -1
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +93 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +92 -0
- package/plugins/specweave-github/lib/github-client-v2.js +39 -0
- package/plugins/specweave-github/lib/github-client-v2.ts +44 -0
- package/plugins/specweave/hooks/docs-changed.sh +0 -87
- package/plugins/specweave/hooks/human-input-required.sh +0 -83
- package/plugins/specweave/hooks/post-edit-write-consolidated.sh +0 -428
- package/plugins/specweave/hooks/post-first-increment.sh +0 -61
- package/plugins/specweave/hooks/post-increment-change.sh +0 -103
- package/plugins/specweave/hooks/post-increment-completion.sh +0 -513
- package/plugins/specweave/hooks/post-increment-planning.sh +0 -1204
- package/plugins/specweave/hooks/post-increment-status-change.sh +0 -243
- package/plugins/specweave/hooks/post-metadata-change.sh +0 -246
- package/plugins/specweave/hooks/post-spec-update.sh +0 -158
- package/plugins/specweave/hooks/post-task-completion.sh +0 -557
- package/plugins/specweave/hooks/post-task-edit.sh +0 -47
- package/plugins/specweave/hooks/post-user-story-complete.sh +0 -230
- package/plugins/specweave/hooks/pre-command-deduplication.sh +0 -68
- package/plugins/specweave/hooks/pre-edit-write-consolidated.sh +0 -225
- package/plugins/specweave/hooks/pre-implementation.sh +0 -75
- package/plugins/specweave/hooks/pre-increment-start.sh +0 -173
- package/plugins/specweave/hooks/pre-task-completion-edit.sh +0 -355
- package/plugins/specweave/hooks/pre-task-completion.sh +0 -269
- package/plugins/specweave/hooks/pre-tool-use.sh +0 -137
- package/plugins/specweave/hooks/session-start-reconcile.sh +0 -139
- package/plugins/specweave/hooks/shared/bulk-operation-detector.sh +0 -167
- package/plugins/specweave/hooks/test-pretooluse-env.sh +0 -72
- package/plugins/specweave/hooks/validate-increment-completion.sh +0 -113
- 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":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,4BAA4B,EAE7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,WAAW,EAEX,YAAY,EAIb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,MAAM,EAAiB,MAAM,uBAAuB,CAAC;AAE9D;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,IAAI,CAAC,EAAE;QACL,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B;IAC3B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAE9B,+CAA+C;IAC/C,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAE5B,oCAAoC;IACpC,cAAc,EAAE,MAAM,EAAE,CAAC;IAEzB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;GAKG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,MAAM,CAAS;gBAEX,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO;IAUlE;;OAEG;YACW,UAAU;IAkBxB;;OAEG;YACW,aAAa;IAK3B;;OAEG;YACW,kBAAkB;IAShC;;;;;;;;;;;OAWG;IACG,mBAAmB,CACvB,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,gBAAgB,CAAC;IAuE5B;;;;;;;OAOG;IACG,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA6ErE;;;;;;OAMG;IACG,kBAAkB,CACtB,QAAQ,EAAE,YAAY,EACtB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,gBAAgB,CAAC;IAiE5B;;;;;;;;OAQG;IACG,uBAAuB,CAC3B,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,4BAA4B,CAAC;IA+DxC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAwC7B;;OAEG;YACW,mBAAmB;IAwCjC;;OAEG;YACW,qBAAqB;IAoBnC;;OAEG;YACW,cAAc;IAK5B;;OAEG;YACW,oBAAoB;IA8ClC;;;;;;;;OAQG;IACH,MAAM,CAAC,gBAAgB,CACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,YAAY,EACtB,WAAW,EAAE,oBAAoB,EACjC,eAAe,CAAC,EAAE,MAAM,GACvB,UAAU;IAcb;;OAEG;IACG,yBAAyB,IAAI,OAAO,CAAC,OAAO,CAAC;IAKnD;;OAEG;IACG,sBAAsB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAWvD;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC;QAChC,SAAS,EAAE,OAAO,CAAC;QACnB,SAAS,EAAE,YAAY,EAAE,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;CAkBH;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,GACd,oBAAoB,CAEtB"}
|