specweave 0.30.1 → 0.30.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.
- package/dist/plugins/specweave-ado/lib/ado-permission-gate.d.ts +113 -0
- package/dist/plugins/specweave-ado/lib/ado-permission-gate.d.ts.map +1 -0
- package/dist/plugins/specweave-ado/lib/ado-permission-gate.js +169 -0
- package/dist/plugins/specweave-ado/lib/ado-permission-gate.js.map +1 -0
- package/dist/plugins/specweave-ado/lib/ado-profile-resolver.d.ts +137 -0
- package/dist/plugins/specweave-ado/lib/ado-profile-resolver.d.ts.map +1 -0
- package/dist/plugins/specweave-ado/lib/ado-profile-resolver.js +200 -0
- package/dist/plugins/specweave-ado/lib/ado-profile-resolver.js.map +1 -0
- package/dist/src/cli/commands/sync-scheduled.d.ts.map +1 -1
- package/dist/src/cli/commands/sync-scheduled.js +1 -0
- package/dist/src/cli/commands/sync-scheduled.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.d.ts +3 -1
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.js +9 -7
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.js.map +1 -1
- package/dist/src/core/background/job-launcher.d.ts +5 -0
- package/dist/src/core/background/job-launcher.d.ts.map +1 -1
- package/dist/src/core/background/job-launcher.js +14 -3
- package/dist/src/core/background/job-launcher.js.map +1 -1
- package/dist/src/core/errors/index.d.ts +174 -0
- package/dist/src/core/errors/index.d.ts.map +1 -0
- package/dist/src/core/errors/index.js +238 -0
- package/dist/src/core/errors/index.js.map +1 -0
- package/dist/src/core/scheduler/session-sync-executor.d.ts +3 -0
- package/dist/src/core/scheduler/session-sync-executor.d.ts.map +1 -1
- package/dist/src/core/scheduler/session-sync-executor.js +27 -2
- package/dist/src/core/scheduler/session-sync-executor.js.map +1 -1
- package/dist/src/core/specs/spec-metadata-manager.d.ts +5 -1
- package/dist/src/core/specs/spec-metadata-manager.d.ts.map +1 -1
- package/dist/src/core/specs/spec-metadata-manager.js +4 -2
- package/dist/src/core/specs/spec-metadata-manager.js.map +1 -1
- package/dist/src/importers/item-converter.d.ts +5 -0
- package/dist/src/importers/item-converter.d.ts.map +1 -1
- package/dist/src/importers/item-converter.js +15 -4
- package/dist/src/importers/item-converter.js.map +1 -1
- package/dist/src/integrations/ado/ado-client-factory.d.ts +102 -0
- package/dist/src/integrations/ado/ado-client-factory.d.ts.map +1 -0
- package/dist/src/integrations/ado/ado-client-factory.js +115 -0
- package/dist/src/integrations/ado/ado-client-factory.js.map +1 -0
- package/dist/src/integrations/ado/ado-client.d.ts +24 -1
- package/dist/src/integrations/ado/ado-client.d.ts.map +1 -1
- package/dist/src/integrations/ado/ado-client.js +48 -17
- package/dist/src/integrations/ado/ado-client.js.map +1 -1
- package/dist/src/integrations/ado/ado-pat-provider.d.ts +45 -0
- package/dist/src/integrations/ado/ado-pat-provider.d.ts.map +1 -0
- package/dist/src/integrations/ado/ado-pat-provider.js +70 -0
- package/dist/src/integrations/ado/ado-pat-provider.js.map +1 -0
- package/dist/src/integrations/jira/jira-client.d.ts +5 -0
- package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-client.js +24 -13
- package/dist/src/integrations/jira/jira-client.js.map +1 -1
- package/dist/src/integrations/jira/jira-incremental-mapper.d.ts +5 -0
- package/dist/src/integrations/jira/jira-incremental-mapper.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-incremental-mapper.js +13 -2
- package/dist/src/integrations/jira/jira-incremental-mapper.js.map +1 -1
- package/dist/src/integrations/jira/jira-mapper.d.ts +5 -0
- package/dist/src/integrations/jira/jira-mapper.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-mapper.js +14 -3
- package/dist/src/integrations/jira/jira-mapper.js.map +1 -1
- package/dist/src/sync/sync-coordinator.d.ts +11 -0
- package/dist/src/sync/sync-coordinator.d.ts.map +1 -1
- package/dist/src/sync/sync-coordinator.js +80 -3
- package/dist/src/sync/sync-coordinator.js.map +1 -1
- package/dist/src/testing/test-generator.d.ts +5 -0
- package/dist/src/testing/test-generator.d.ts.map +1 -1
- package/dist/src/testing/test-generator.js +17 -6
- package/dist/src/testing/test-generator.js.map +1 -1
- package/dist/src/utils/fs-native.d.ts +5 -2
- package/dist/src/utils/fs-native.d.ts.map +1 -1
- package/dist/src/utils/fs-native.js +6 -2
- package/dist/src/utils/fs-native.js.map +1 -1
- package/dist/src/utils/logger.d.ts +5 -1
- package/dist/src/utils/logger.d.ts.map +1 -1
- package/dist/src/utils/logger.js +6 -3
- package/dist/src/utils/logger.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/lib/vendor/utils/fs-native.d.ts +5 -2
- package/plugins/specweave/lib/vendor/utils/fs-native.js +6 -2
- package/plugins/specweave/lib/vendor/utils/fs-native.js.map +1 -1
- package/plugins/specweave/lib/vendor/utils/logger.d.ts +5 -1
- package/plugins/specweave/lib/vendor/utils/logger.js +6 -3
- package/plugins/specweave/lib/vendor/utils/logger.js.map +1 -1
- package/plugins/specweave-ado/agents/ado-manager/AGENT.md +62 -4
- package/plugins/specweave-ado/commands/specweave-ado-close-workitem.md +197 -12
- package/plugins/specweave-ado/commands/specweave-ado-create-workitem.md +148 -24
- package/plugins/specweave-ado/commands/specweave-ado-sync.md +170 -77
- package/plugins/specweave-ado/lib/ado-permission-gate.js +127 -0
- package/plugins/specweave-ado/lib/ado-permission-gate.ts +231 -0
- package/plugins/specweave-ado/lib/ado-profile-resolver.js +153 -0
- package/plugins/specweave-ado/lib/ado-profile-resolver.ts +323 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +84 -0
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +126 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
class AdoProfileResolver {
|
|
4
|
+
constructor(projectRoot = process.cwd()) {
|
|
5
|
+
this.projectRoot = projectRoot;
|
|
6
|
+
this.configPath = path.join(projectRoot, ".specweave", "config.json");
|
|
7
|
+
this.incrementsPath = path.join(projectRoot, ".specweave", "increments");
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the ADO profile for an increment
|
|
11
|
+
*
|
|
12
|
+
* Priority:
|
|
13
|
+
* 1. Increment's metadata.json -> external_sync.ado.profile
|
|
14
|
+
* 2. Config.json -> sync.activeProfile
|
|
15
|
+
*
|
|
16
|
+
* @param incrementId - Increment ID (e.g., "0093-my-feature")
|
|
17
|
+
* @returns Profile resolution result
|
|
18
|
+
*/
|
|
19
|
+
async resolveProfile(incrementId) {
|
|
20
|
+
const config = await this.loadConfig();
|
|
21
|
+
if (!config) {
|
|
22
|
+
return {
|
|
23
|
+
success: false,
|
|
24
|
+
error: "Failed to load .specweave/config.json",
|
|
25
|
+
incrementId
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const incrementProfile = await this.getIncrementProfile(incrementId);
|
|
29
|
+
const profileName = incrementProfile || config.sync?.activeProfile;
|
|
30
|
+
if (!profileName) {
|
|
31
|
+
return {
|
|
32
|
+
success: false,
|
|
33
|
+
error: "No ADO profile configured. Set sync.activeProfile in config.json or external_sync.ado.profile in increment metadata.",
|
|
34
|
+
incrementId
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const profiles = config.sync?.profiles || {};
|
|
38
|
+
const profileConfig = profiles[profileName];
|
|
39
|
+
if (!profileConfig) {
|
|
40
|
+
return {
|
|
41
|
+
success: false,
|
|
42
|
+
error: `Profile "${profileName}" not found in config.sync.profiles`,
|
|
43
|
+
incrementId
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (profileConfig.provider !== "ado") {
|
|
47
|
+
return {
|
|
48
|
+
success: false,
|
|
49
|
+
error: `Profile "${profileName}" is not an ADO profile (provider: ${profileConfig.provider})`,
|
|
50
|
+
incrementId
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (!profileConfig.config?.organization || !profileConfig.config?.project) {
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
error: `Profile "${profileName}" missing required fields (organization, project)`,
|
|
57
|
+
incrementId
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
success: true,
|
|
62
|
+
profile: {
|
|
63
|
+
profileName,
|
|
64
|
+
organization: profileConfig.config.organization,
|
|
65
|
+
project: profileConfig.config.project,
|
|
66
|
+
displayName: profileConfig.displayName,
|
|
67
|
+
areaPath: profileConfig.config.areaPath,
|
|
68
|
+
iterationPath: profileConfig.config.iterationPath
|
|
69
|
+
},
|
|
70
|
+
source: incrementProfile ? "increment" : "global",
|
|
71
|
+
incrementId
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get increment's stored ADO profile name
|
|
76
|
+
*
|
|
77
|
+
* @param incrementId - Increment ID
|
|
78
|
+
* @returns Profile name or null if not set
|
|
79
|
+
*/
|
|
80
|
+
async getIncrementProfile(incrementId) {
|
|
81
|
+
const metadataPath = path.join(this.incrementsPath, incrementId, "metadata.json");
|
|
82
|
+
try {
|
|
83
|
+
const content = await fs.readFile(metadataPath, "utf-8");
|
|
84
|
+
const metadata = JSON.parse(content);
|
|
85
|
+
return metadata?.external_sync?.ado?.profile || null;
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Set increment's ADO profile
|
|
92
|
+
*
|
|
93
|
+
* Stores the profile name in the increment's metadata.json
|
|
94
|
+
*
|
|
95
|
+
* @param incrementId - Increment ID
|
|
96
|
+
* @param profileName - Profile name to set
|
|
97
|
+
*/
|
|
98
|
+
async setIncrementProfile(incrementId, profileName) {
|
|
99
|
+
const metadataPath = path.join(this.incrementsPath, incrementId, "metadata.json");
|
|
100
|
+
let metadata = {};
|
|
101
|
+
try {
|
|
102
|
+
const content = await fs.readFile(metadataPath, "utf-8");
|
|
103
|
+
metadata = JSON.parse(content);
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
if (!metadata.external_sync) {
|
|
107
|
+
metadata.external_sync = {};
|
|
108
|
+
}
|
|
109
|
+
if (!metadata.external_sync.ado) {
|
|
110
|
+
metadata.external_sync.ado = {};
|
|
111
|
+
}
|
|
112
|
+
metadata.external_sync.ado.profile = profileName;
|
|
113
|
+
await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2) + "\n", "utf-8");
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* List available ADO profiles
|
|
117
|
+
*
|
|
118
|
+
* @returns Array of profile names
|
|
119
|
+
*/
|
|
120
|
+
async listAdoProfiles() {
|
|
121
|
+
const config = await this.loadConfig();
|
|
122
|
+
if (!config?.sync?.profiles) {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
const profiles = config.sync.profiles;
|
|
126
|
+
return Object.entries(profiles).filter(([_, p]) => p.provider === "ado").map(([name]) => name);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Load config.json
|
|
130
|
+
*/
|
|
131
|
+
async loadConfig() {
|
|
132
|
+
try {
|
|
133
|
+
const content = await fs.readFile(this.configPath, "utf-8");
|
|
134
|
+
return JSON.parse(content);
|
|
135
|
+
} catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async function createAdoProfileResolver(projectRoot = process.cwd()) {
|
|
141
|
+
return new AdoProfileResolver(projectRoot);
|
|
142
|
+
}
|
|
143
|
+
async function resolveAdoProfile(incrementId, projectRoot = process.cwd()) {
|
|
144
|
+
const resolver = new AdoProfileResolver(projectRoot);
|
|
145
|
+
return resolver.resolveProfile(incrementId);
|
|
146
|
+
}
|
|
147
|
+
var ado_profile_resolver_default = AdoProfileResolver;
|
|
148
|
+
export {
|
|
149
|
+
AdoProfileResolver,
|
|
150
|
+
createAdoProfileResolver,
|
|
151
|
+
ado_profile_resolver_default as default,
|
|
152
|
+
resolveAdoProfile
|
|
153
|
+
};
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADO Profile Resolver
|
|
3
|
+
*
|
|
4
|
+
* Resolves the correct ADO profile to use for sync operations.
|
|
5
|
+
* Priority:
|
|
6
|
+
* 1. Increment's stored profile (metadata.json -> external_sync.ado.profile)
|
|
7
|
+
* 2. Global activeProfile (config.json -> sync.activeProfile)
|
|
8
|
+
*
|
|
9
|
+
* This allows each increment to sync to its designated ADO project
|
|
10
|
+
* without requiring manual activeProfile switching.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const resolver = await createAdoProfileResolver();
|
|
15
|
+
* const profile = await resolver.resolveProfile('0093-my-increment');
|
|
16
|
+
* // profile contains organization, project, PAT, etc.
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @module ado-profile-resolver
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { promises as fs } from 'node:fs';
|
|
23
|
+
import * as path from 'node:path';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* ADO profile configuration
|
|
27
|
+
*/
|
|
28
|
+
export interface AdoProfileConfig {
|
|
29
|
+
/**
|
|
30
|
+
* Profile name (for display/logging)
|
|
31
|
+
*/
|
|
32
|
+
profileName: string;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* ADO organization name
|
|
36
|
+
*/
|
|
37
|
+
organization: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* ADO project name
|
|
41
|
+
*/
|
|
42
|
+
project: string;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Display name (optional)
|
|
46
|
+
*/
|
|
47
|
+
displayName?: string;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Area path (optional)
|
|
51
|
+
*/
|
|
52
|
+
areaPath?: string;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Iteration path (optional)
|
|
56
|
+
*/
|
|
57
|
+
iterationPath?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Profile resolution result
|
|
62
|
+
*/
|
|
63
|
+
export interface ProfileResolutionResult {
|
|
64
|
+
/**
|
|
65
|
+
* Whether resolution succeeded
|
|
66
|
+
*/
|
|
67
|
+
success: boolean;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Resolved profile config (if success)
|
|
71
|
+
*/
|
|
72
|
+
profile?: AdoProfileConfig;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Source of the profile
|
|
76
|
+
*/
|
|
77
|
+
source?: 'increment' | 'global';
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Error message (if failed)
|
|
81
|
+
*/
|
|
82
|
+
error?: string;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Increment ID that was checked
|
|
86
|
+
*/
|
|
87
|
+
incrementId?: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Sync profile from config.json
|
|
92
|
+
*/
|
|
93
|
+
interface ConfigProfile {
|
|
94
|
+
provider: string;
|
|
95
|
+
displayName?: string;
|
|
96
|
+
config: {
|
|
97
|
+
organization: string;
|
|
98
|
+
project: string;
|
|
99
|
+
areaPath?: string;
|
|
100
|
+
iterationPath?: string;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Sync config from config.json
|
|
106
|
+
*/
|
|
107
|
+
interface SyncConfig {
|
|
108
|
+
activeProfile?: string;
|
|
109
|
+
profiles?: Record<string, ConfigProfile>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Config structure
|
|
114
|
+
*/
|
|
115
|
+
interface SpecWeaveConfig {
|
|
116
|
+
sync?: SyncConfig;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* ADO Profile Resolver
|
|
121
|
+
*/
|
|
122
|
+
export class AdoProfileResolver {
|
|
123
|
+
private projectRoot: string;
|
|
124
|
+
private configPath: string;
|
|
125
|
+
private incrementsPath: string;
|
|
126
|
+
|
|
127
|
+
constructor(projectRoot: string = process.cwd()) {
|
|
128
|
+
this.projectRoot = projectRoot;
|
|
129
|
+
this.configPath = path.join(projectRoot, '.specweave', 'config.json');
|
|
130
|
+
this.incrementsPath = path.join(projectRoot, '.specweave', 'increments');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Resolve the ADO profile for an increment
|
|
135
|
+
*
|
|
136
|
+
* Priority:
|
|
137
|
+
* 1. Increment's metadata.json -> external_sync.ado.profile
|
|
138
|
+
* 2. Config.json -> sync.activeProfile
|
|
139
|
+
*
|
|
140
|
+
* @param incrementId - Increment ID (e.g., "0093-my-feature")
|
|
141
|
+
* @returns Profile resolution result
|
|
142
|
+
*/
|
|
143
|
+
async resolveProfile(incrementId: string): Promise<ProfileResolutionResult> {
|
|
144
|
+
// Load global config
|
|
145
|
+
const config = await this.loadConfig();
|
|
146
|
+
if (!config) {
|
|
147
|
+
return {
|
|
148
|
+
success: false,
|
|
149
|
+
error: 'Failed to load .specweave/config.json',
|
|
150
|
+
incrementId,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Try to get increment-specific profile first
|
|
155
|
+
const incrementProfile = await this.getIncrementProfile(incrementId);
|
|
156
|
+
|
|
157
|
+
// Determine which profile to use
|
|
158
|
+
const profileName = incrementProfile || config.sync?.activeProfile;
|
|
159
|
+
|
|
160
|
+
if (!profileName) {
|
|
161
|
+
return {
|
|
162
|
+
success: false,
|
|
163
|
+
error: 'No ADO profile configured. Set sync.activeProfile in config.json or external_sync.ado.profile in increment metadata.',
|
|
164
|
+
incrementId,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Check if profile is for ADO provider
|
|
169
|
+
const profiles = config.sync?.profiles || {};
|
|
170
|
+
const profileConfig = profiles[profileName] as ConfigProfile | undefined;
|
|
171
|
+
|
|
172
|
+
if (!profileConfig) {
|
|
173
|
+
return {
|
|
174
|
+
success: false,
|
|
175
|
+
error: `Profile "${profileName}" not found in config.sync.profiles`,
|
|
176
|
+
incrementId,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (profileConfig.provider !== 'ado') {
|
|
181
|
+
return {
|
|
182
|
+
success: false,
|
|
183
|
+
error: `Profile "${profileName}" is not an ADO profile (provider: ${profileConfig.provider})`,
|
|
184
|
+
incrementId,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Validate required fields
|
|
189
|
+
if (!profileConfig.config?.organization || !profileConfig.config?.project) {
|
|
190
|
+
return {
|
|
191
|
+
success: false,
|
|
192
|
+
error: `Profile "${profileName}" missing required fields (organization, project)`,
|
|
193
|
+
incrementId,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
success: true,
|
|
199
|
+
profile: {
|
|
200
|
+
profileName,
|
|
201
|
+
organization: profileConfig.config.organization,
|
|
202
|
+
project: profileConfig.config.project,
|
|
203
|
+
displayName: profileConfig.displayName,
|
|
204
|
+
areaPath: profileConfig.config.areaPath,
|
|
205
|
+
iterationPath: profileConfig.config.iterationPath,
|
|
206
|
+
},
|
|
207
|
+
source: incrementProfile ? 'increment' : 'global',
|
|
208
|
+
incrementId,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get increment's stored ADO profile name
|
|
214
|
+
*
|
|
215
|
+
* @param incrementId - Increment ID
|
|
216
|
+
* @returns Profile name or null if not set
|
|
217
|
+
*/
|
|
218
|
+
async getIncrementProfile(incrementId: string): Promise<string | null> {
|
|
219
|
+
const metadataPath = path.join(this.incrementsPath, incrementId, 'metadata.json');
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
const content = await fs.readFile(metadataPath, 'utf-8');
|
|
223
|
+
const metadata = JSON.parse(content);
|
|
224
|
+
|
|
225
|
+
// Check for profile in external_sync.ado.profile
|
|
226
|
+
return metadata?.external_sync?.ado?.profile || null;
|
|
227
|
+
} catch {
|
|
228
|
+
// Metadata not found or invalid - return null
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Set increment's ADO profile
|
|
235
|
+
*
|
|
236
|
+
* Stores the profile name in the increment's metadata.json
|
|
237
|
+
*
|
|
238
|
+
* @param incrementId - Increment ID
|
|
239
|
+
* @param profileName - Profile name to set
|
|
240
|
+
*/
|
|
241
|
+
async setIncrementProfile(incrementId: string, profileName: string): Promise<void> {
|
|
242
|
+
const metadataPath = path.join(this.incrementsPath, incrementId, 'metadata.json');
|
|
243
|
+
|
|
244
|
+
// Load existing metadata
|
|
245
|
+
let metadata: Record<string, unknown> = {};
|
|
246
|
+
try {
|
|
247
|
+
const content = await fs.readFile(metadataPath, 'utf-8');
|
|
248
|
+
metadata = JSON.parse(content);
|
|
249
|
+
} catch {
|
|
250
|
+
// Start with empty metadata if not found
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Set external_sync.ado.profile
|
|
254
|
+
if (!metadata.external_sync) {
|
|
255
|
+
metadata.external_sync = {};
|
|
256
|
+
}
|
|
257
|
+
if (!(metadata.external_sync as Record<string, unknown>).ado) {
|
|
258
|
+
(metadata.external_sync as Record<string, unknown>).ado = {};
|
|
259
|
+
}
|
|
260
|
+
((metadata.external_sync as Record<string, unknown>).ado as Record<string, unknown>).profile = profileName;
|
|
261
|
+
|
|
262
|
+
// Write back
|
|
263
|
+
await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2) + '\n', 'utf-8');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* List available ADO profiles
|
|
268
|
+
*
|
|
269
|
+
* @returns Array of profile names
|
|
270
|
+
*/
|
|
271
|
+
async listAdoProfiles(): Promise<string[]> {
|
|
272
|
+
const config = await this.loadConfig();
|
|
273
|
+
if (!config?.sync?.profiles) {
|
|
274
|
+
return [];
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const profiles = config.sync.profiles as Record<string, ConfigProfile>;
|
|
278
|
+
return Object.entries(profiles)
|
|
279
|
+
.filter(([_, p]) => p.provider === 'ado')
|
|
280
|
+
.map(([name]) => name);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Load config.json
|
|
285
|
+
*/
|
|
286
|
+
private async loadConfig(): Promise<SpecWeaveConfig | null> {
|
|
287
|
+
try {
|
|
288
|
+
const content = await fs.readFile(this.configPath, 'utf-8');
|
|
289
|
+
return JSON.parse(content) as SpecWeaveConfig;
|
|
290
|
+
} catch {
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Create an AdoProfileResolver instance
|
|
298
|
+
*
|
|
299
|
+
* @param projectRoot - Project root directory (defaults to cwd)
|
|
300
|
+
* @returns AdoProfileResolver instance
|
|
301
|
+
*/
|
|
302
|
+
export async function createAdoProfileResolver(
|
|
303
|
+
projectRoot: string = process.cwd()
|
|
304
|
+
): Promise<AdoProfileResolver> {
|
|
305
|
+
return new AdoProfileResolver(projectRoot);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Quick resolve: Get ADO profile for an increment
|
|
310
|
+
*
|
|
311
|
+
* @param incrementId - Increment ID
|
|
312
|
+
* @param projectRoot - Project root directory
|
|
313
|
+
* @returns Profile resolution result
|
|
314
|
+
*/
|
|
315
|
+
export async function resolveAdoProfile(
|
|
316
|
+
incrementId: string,
|
|
317
|
+
projectRoot: string = process.cwd()
|
|
318
|
+
): Promise<ProfileResolutionResult> {
|
|
319
|
+
const resolver = new AdoProfileResolver(projectRoot);
|
|
320
|
+
return resolver.resolveProfile(incrementId);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export default AdoProfileResolver;
|
|
@@ -166,3 +166,87 @@
|
|
|
166
166
|
[Tue Dec 2 01:27:45 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
167
167
|
[Tue Dec 2 01:27:45 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
168
168
|
[Tue Dec 2 01:27:45 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
169
|
+
[Tue Dec 2 02:13:22 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
170
|
+
[Tue Dec 2 02:13:22 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
171
|
+
[Tue Dec 2 02:13:22 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
172
|
+
[Tue Dec 2 02:13:22 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
173
|
+
[Tue Dec 2 02:13:22 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
174
|
+
[Tue Dec 2 02:13:22 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
175
|
+
[Tue Dec 2 02:13:50 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
176
|
+
[Tue Dec 2 02:13:50 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
177
|
+
[Tue Dec 2 02:13:50 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
178
|
+
[Tue Dec 2 02:13:50 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
179
|
+
[Tue Dec 2 02:13:50 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
180
|
+
[Tue Dec 2 02:13:50 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
181
|
+
[Tue Dec 2 02:14:18 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
182
|
+
[Tue Dec 2 02:14:18 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
183
|
+
[Tue Dec 2 02:14:18 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
184
|
+
[Tue Dec 2 02:14:18 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
185
|
+
[Tue Dec 2 02:14:18 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
186
|
+
[Tue Dec 2 02:14:18 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
187
|
+
[Tue Dec 2 02:14:47 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
188
|
+
[Tue Dec 2 02:14:47 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
189
|
+
[Tue Dec 2 02:14:48 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
190
|
+
[Tue Dec 2 02:14:48 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
191
|
+
[Tue Dec 2 02:14:48 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
192
|
+
[Tue Dec 2 02:14:48 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
193
|
+
[Tue Dec 2 02:16:28 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
194
|
+
[Tue Dec 2 02:16:28 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
195
|
+
[Tue Dec 2 02:16:28 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
196
|
+
[Tue Dec 2 02:16:28 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
197
|
+
[Tue Dec 2 02:16:28 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
198
|
+
[Tue Dec 2 02:16:28 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
199
|
+
[Tue Dec 2 02:19:02 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
200
|
+
[Tue Dec 2 02:19:02 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
201
|
+
[Tue Dec 2 02:19:02 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
202
|
+
[Tue Dec 2 02:19:02 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
203
|
+
[Tue Dec 2 02:19:03 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
204
|
+
[Tue Dec 2 02:19:03 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
205
|
+
[Tue Dec 2 02:25:30 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
206
|
+
[Tue Dec 2 02:25:30 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
207
|
+
[Tue Dec 2 02:25:30 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
208
|
+
[Tue Dec 2 02:25:30 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
209
|
+
[Tue Dec 2 02:25:30 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
210
|
+
[Tue Dec 2 02:25:30 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
211
|
+
[Tue Dec 2 02:27:50 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
212
|
+
[Tue Dec 2 02:27:50 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
213
|
+
[Tue Dec 2 02:27:50 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
214
|
+
[Tue Dec 2 02:27:50 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
215
|
+
[Tue Dec 2 02:27:50 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
216
|
+
[Tue Dec 2 02:27:50 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
217
|
+
[Tue Dec 2 02:30:12 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
218
|
+
[Tue Dec 2 02:30:12 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
219
|
+
[Tue Dec 2 02:30:12 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
220
|
+
[Tue Dec 2 02:30:12 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
221
|
+
[Tue Dec 2 02:30:12 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
222
|
+
[Tue Dec 2 02:30:12 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
223
|
+
[Tue Dec 2 02:31:10 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
224
|
+
[Tue Dec 2 02:31:10 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
225
|
+
[Tue Dec 2 02:31:10 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
226
|
+
[Tue Dec 2 02:31:10 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
227
|
+
[Tue Dec 2 02:31:10 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
228
|
+
[Tue Dec 2 02:31:10 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
229
|
+
[Tue Dec 2 02:32:58 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
230
|
+
[Tue Dec 2 02:32:58 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
231
|
+
[Tue Dec 2 02:32:58 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
232
|
+
[Tue Dec 2 02:32:58 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
233
|
+
[Tue Dec 2 02:32:59 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
234
|
+
[Tue Dec 2 02:32:59 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
235
|
+
[Tue Dec 2 02:34:08 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
236
|
+
[Tue Dec 2 02:34:08 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
237
|
+
[Tue Dec 2 02:34:08 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
238
|
+
[Tue Dec 2 02:34:08 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
239
|
+
[Tue Dec 2 02:34:09 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
240
|
+
[Tue Dec 2 02:34:09 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
241
|
+
[Tue Dec 2 02:35:07 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
242
|
+
[Tue Dec 2 02:35:07 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
243
|
+
[Tue Dec 2 02:35:07 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
244
|
+
[Tue Dec 2 02:35:07 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
245
|
+
[Tue Dec 2 02:35:07 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
246
|
+
[Tue Dec 2 02:35:07 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
247
|
+
[Tue Dec 2 09:52:58 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
248
|
+
[Tue Dec 2 09:52:58 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
249
|
+
[Tue Dec 2 09:52:58 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
250
|
+
[Tue Dec 2 09:52:58 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
251
|
+
[Tue Dec 2 09:52:58 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
252
|
+
[Tue Dec 2 09:52:58 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|