ai-sdlc 0.3.1-alpha.0-alpha.6 → 0.3.1-alpha.0-alpha.8

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 (43) hide show
  1. package/README.md +54 -0
  2. package/dist/cli/commands/import-issue.d.ts +7 -0
  3. package/dist/cli/commands/import-issue.d.ts.map +1 -0
  4. package/dist/cli/commands/import-issue.js +125 -0
  5. package/dist/cli/commands/import-issue.js.map +1 -0
  6. package/dist/cli/commands/link-issue.d.ts +11 -0
  7. package/dist/cli/commands/link-issue.d.ts.map +1 -0
  8. package/dist/cli/commands/link-issue.js +156 -0
  9. package/dist/cli/commands/link-issue.js.map +1 -0
  10. package/dist/cli/commands.d.ts +3 -0
  11. package/dist/cli/commands.d.ts.map +1 -1
  12. package/dist/cli/commands.js +4 -0
  13. package/dist/cli/commands.js.map +1 -1
  14. package/dist/core/config.d.ts +5 -1
  15. package/dist/core/config.d.ts.map +1 -1
  16. package/dist/core/config.js +73 -0
  17. package/dist/core/config.js.map +1 -1
  18. package/dist/index.js +11 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/services/gh-cli.d.ts +122 -0
  21. package/dist/services/gh-cli.d.ts.map +1 -0
  22. package/dist/services/gh-cli.js +249 -0
  23. package/dist/services/gh-cli.js.map +1 -0
  24. package/dist/services/ticket-provider/github-provider.d.ts +84 -0
  25. package/dist/services/ticket-provider/github-provider.d.ts.map +1 -0
  26. package/dist/services/ticket-provider/github-provider.js +194 -0
  27. package/dist/services/ticket-provider/github-provider.js.map +1 -0
  28. package/dist/services/ticket-provider/index.d.ts +22 -0
  29. package/dist/services/ticket-provider/index.d.ts.map +1 -0
  30. package/dist/services/ticket-provider/index.js +38 -0
  31. package/dist/services/ticket-provider/index.js.map +1 -0
  32. package/dist/services/ticket-provider/null-provider.d.ts +59 -0
  33. package/dist/services/ticket-provider/null-provider.d.ts.map +1 -0
  34. package/dist/services/ticket-provider/null-provider.js +73 -0
  35. package/dist/services/ticket-provider/null-provider.js.map +1 -0
  36. package/dist/services/ticket-provider/types.d.ts +115 -0
  37. package/dist/services/ticket-provider/types.d.ts.map +1 -0
  38. package/dist/services/ticket-provider/types.js +2 -0
  39. package/dist/services/ticket-provider/types.js.map +1 -0
  40. package/dist/types/index.d.ts +27 -0
  41. package/dist/types/index.d.ts.map +1 -1
  42. package/dist/types/index.js.map +1 -1
  43. package/package.json +1 -1
@@ -0,0 +1,249 @@
1
+ import { spawnSync } from 'child_process';
2
+ /**
3
+ * Custom error for when gh CLI is not installed.
4
+ */
5
+ export class GhNotInstalledError extends Error {
6
+ constructor() {
7
+ super('GitHub CLI (gh) is not installed.\nInstall it from: https://cli.github.com/');
8
+ this.name = 'GhNotInstalledError';
9
+ }
10
+ }
11
+ /**
12
+ * Custom error for when gh CLI is not authenticated.
13
+ */
14
+ export class GhNotAuthenticatedError extends Error {
15
+ constructor() {
16
+ super('Not authenticated to GitHub.\nRun: gh auth login');
17
+ this.name = 'GhNotAuthenticatedError';
18
+ }
19
+ }
20
+ /**
21
+ * Custom error for when a GitHub Issue is not found.
22
+ */
23
+ export class GhIssueNotFoundError extends Error {
24
+ constructor(owner, repo, number) {
25
+ super(`Issue #${number} not found in ${owner}/${repo}`);
26
+ this.name = 'GhIssueNotFoundError';
27
+ }
28
+ }
29
+ /**
30
+ * Custom error for when access to a repository is denied.
31
+ */
32
+ export class GhNoAccessError extends Error {
33
+ constructor(owner, repo) {
34
+ super(`Cannot access ${owner}/${repo}. Check your permissions.`);
35
+ this.name = 'GhNoAccessError';
36
+ }
37
+ }
38
+ /**
39
+ * Parse a GitHub issue URL into its components.
40
+ *
41
+ * Supports various formats:
42
+ * - https://github.com/owner/repo/issues/123
43
+ * - https://github.com/owner/repo/issues/123#issuecomment-456
44
+ * - github.com/owner/repo/issues/123
45
+ * - owner/repo#123
46
+ *
47
+ * @param url GitHub issue URL in various formats
48
+ * @returns Parsed components or null if invalid
49
+ */
50
+ export function parseGitHubIssueUrl(url) {
51
+ // Remove protocol and www
52
+ const normalized = url
53
+ .replace(/^https?:\/\//i, '')
54
+ .replace(/^www\./i, '');
55
+ // Match: github.com/owner/repo/issues/123
56
+ const fullMatch = normalized.match(/^github\.com\/([^\/]+)\/([^\/]+)\/issues\/(\d+)/i);
57
+ if (fullMatch) {
58
+ return {
59
+ owner: fullMatch[1],
60
+ repo: fullMatch[2],
61
+ number: parseInt(fullMatch[3], 10),
62
+ };
63
+ }
64
+ // Match: owner/repo#123
65
+ const shortMatch = url.match(/^([^\/]+)\/([^#]+)#(\d+)$/);
66
+ if (shortMatch) {
67
+ return {
68
+ owner: shortMatch[1],
69
+ repo: shortMatch[2],
70
+ number: parseInt(shortMatch[3], 10),
71
+ };
72
+ }
73
+ return null;
74
+ }
75
+ /**
76
+ * Check if the gh CLI is installed and authenticated.
77
+ *
78
+ * @returns true if gh is available and authenticated, false otherwise
79
+ */
80
+ export async function isGhAvailable() {
81
+ // Check if gh is installed
82
+ const versionResult = spawnSync('gh', ['--version'], {
83
+ encoding: 'utf-8',
84
+ shell: false,
85
+ stdio: ['ignore', 'pipe', 'pipe'],
86
+ });
87
+ if (versionResult.status !== 0 || versionResult.error) {
88
+ return false;
89
+ }
90
+ // Check if gh is authenticated
91
+ const authResult = spawnSync('gh', ['auth', 'status'], {
92
+ encoding: 'utf-8',
93
+ shell: false,
94
+ stdio: ['ignore', 'pipe', 'pipe'],
95
+ });
96
+ // gh auth status returns 0 when authenticated
97
+ return authResult.status === 0;
98
+ }
99
+ /**
100
+ * Check if gh CLI is authenticated specifically.
101
+ * Assumes gh is already installed.
102
+ *
103
+ * @returns true if authenticated, false otherwise
104
+ */
105
+ export async function isGhAuthenticated() {
106
+ const authResult = spawnSync('gh', ['auth', 'status'], {
107
+ encoding: 'utf-8',
108
+ shell: false,
109
+ stdio: ['ignore', 'pipe', 'pipe'],
110
+ });
111
+ return authResult.status === 0;
112
+ }
113
+ /**
114
+ * Fetch a single GitHub Issue by number.
115
+ *
116
+ * @param owner Repository owner
117
+ * @param repo Repository name
118
+ * @param number Issue number
119
+ * @returns GitHub Issue details
120
+ * @throws {GhNotInstalledError} If gh CLI is not installed
121
+ * @throws {GhNotAuthenticatedError} If gh CLI is not authenticated
122
+ * @throws {GhIssueNotFoundError} If issue is not found
123
+ * @throws {GhNoAccessError} If access to repo is denied
124
+ */
125
+ export async function ghIssueView(owner, repo, number) {
126
+ const result = spawnSync('gh', [
127
+ 'issue',
128
+ 'view',
129
+ number.toString(),
130
+ '-R',
131
+ `${owner}/${repo}`,
132
+ '--json',
133
+ 'number,title,body,state,labels,assignees,projectItems',
134
+ ], {
135
+ encoding: 'utf-8',
136
+ shell: false,
137
+ stdio: ['ignore', 'pipe', 'pipe'],
138
+ timeout: 30000, // 30 second timeout
139
+ maxBuffer: 10 * 1024 * 1024, // 10MB for large issue bodies
140
+ });
141
+ // Handle errors
142
+ if (result.error) {
143
+ // @ts-expect-error - error.code is not in the type definition but exists at runtime
144
+ if (result.error.code === 'ENOENT') {
145
+ throw new GhNotInstalledError();
146
+ }
147
+ throw new Error(`Failed to execute gh command: ${result.error.message}`);
148
+ }
149
+ if (result.status !== 0) {
150
+ const stderr = result.stderr || '';
151
+ const stderrLower = stderr.toLowerCase();
152
+ // Check for authentication errors
153
+ if (stderrLower.includes('not logged in') ||
154
+ stderrLower.includes('authentication') ||
155
+ stderrLower.includes('gh auth login')) {
156
+ throw new GhNotAuthenticatedError();
157
+ }
158
+ // Check for not found errors
159
+ if (stderrLower.includes('not found') || stderrLower.includes('could not resolve')) {
160
+ throw new GhIssueNotFoundError(owner, repo, number);
161
+ }
162
+ // Check for permission errors
163
+ if (stderrLower.includes('permission') || stderrLower.includes('403')) {
164
+ throw new GhNoAccessError(owner, repo);
165
+ }
166
+ // Generic error
167
+ throw new Error(`gh issue view failed: ${stderr}`);
168
+ }
169
+ // Parse JSON output
170
+ try {
171
+ return JSON.parse(result.stdout);
172
+ }
173
+ catch (error) {
174
+ throw new Error(`Failed to parse gh CLI output: ${error instanceof Error ? error.message : String(error)}`);
175
+ }
176
+ }
177
+ /**
178
+ * List GitHub Issues in a repository.
179
+ *
180
+ * @param owner Repository owner
181
+ * @param repo Repository name
182
+ * @param filter Optional filter criteria
183
+ * @returns Array of GitHub Issues
184
+ * @throws {GhNotInstalledError} If gh CLI is not installed
185
+ * @throws {GhNotAuthenticatedError} If gh CLI is not authenticated
186
+ * @throws {GhNoAccessError} If access to repo is denied
187
+ */
188
+ export async function ghIssueList(owner, repo, filter) {
189
+ const args = [
190
+ 'issue',
191
+ 'list',
192
+ '-R',
193
+ `${owner}/${repo}`,
194
+ '--json',
195
+ 'number,title,body,state,labels,assignees',
196
+ ];
197
+ // Add filter options
198
+ if (filter?.state && filter.state !== 'all') {
199
+ args.push('--state', filter.state);
200
+ }
201
+ if (filter?.labels && filter.labels.length > 0) {
202
+ args.push('--label', filter.labels.join(','));
203
+ }
204
+ if (filter?.assignee) {
205
+ args.push('--assignee', filter.assignee);
206
+ }
207
+ if (filter?.limit) {
208
+ args.push('--limit', filter.limit.toString());
209
+ }
210
+ const result = spawnSync('gh', args, {
211
+ encoding: 'utf-8',
212
+ shell: false,
213
+ stdio: ['ignore', 'pipe', 'pipe'],
214
+ timeout: 30000, // 30 second timeout
215
+ maxBuffer: 10 * 1024 * 1024, // 10MB for large responses
216
+ });
217
+ // Handle errors
218
+ if (result.error) {
219
+ // @ts-expect-error - error.code is not in the type definition but exists at runtime
220
+ if (result.error.code === 'ENOENT') {
221
+ throw new GhNotInstalledError();
222
+ }
223
+ throw new Error(`Failed to execute gh command: ${result.error.message}`);
224
+ }
225
+ if (result.status !== 0) {
226
+ const stderr = result.stderr || '';
227
+ const stderrLower = stderr.toLowerCase();
228
+ // Check for authentication errors
229
+ if (stderrLower.includes('not logged in') ||
230
+ stderrLower.includes('authentication') ||
231
+ stderrLower.includes('gh auth login')) {
232
+ throw new GhNotAuthenticatedError();
233
+ }
234
+ // Check for permission errors
235
+ if (stderrLower.includes('permission') || stderrLower.includes('403')) {
236
+ throw new GhNoAccessError(owner, repo);
237
+ }
238
+ // Generic error
239
+ throw new Error(`gh issue list failed: ${stderr}`);
240
+ }
241
+ // Parse JSON output
242
+ try {
243
+ return JSON.parse(result.stdout);
244
+ }
245
+ catch (error) {
246
+ throw new Error(`Failed to parse gh CLI output: ${error instanceof Error ? error.message : String(error)}`);
247
+ }
248
+ }
249
+ //# sourceMappingURL=gh-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gh-cli.js","sourceRoot":"","sources":["../../src/services/gh-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ import { StoryStatus } from '../../types/index.js';
2
+ import { Ticket, TicketFilter, NewTicket, TicketProvider } from './types.js';
3
+ /**
4
+ * GitHub-specific configuration for the ticket provider.
5
+ */
6
+ export interface GitHubConfig {
7
+ /** Repository in format 'owner/repo' */
8
+ repo?: string;
9
+ /** GitHub Projects v2 project number for priority sync */
10
+ projectNumber?: number;
11
+ /** Map story statuses to GitHub labels */
12
+ statusLabels?: Record<string, string>;
13
+ }
14
+ /**
15
+ * Ticket provider implementation for GitHub Issues.
16
+ *
17
+ * Integrates with GitHub Issues via the gh CLI. Supports:
18
+ * - Listing issues with filters
19
+ * - Fetching individual issues
20
+ * - Status mapping between GitHub and ai-sdlc
21
+ *
22
+ * Write operations (create, updateStatus, addComment, linkPR) will be
23
+ * implemented in story S-0075.
24
+ */
25
+ export declare class GitHubTicketProvider implements TicketProvider {
26
+ private config?;
27
+ readonly name = "github";
28
+ constructor(config?: GitHubConfig | undefined);
29
+ /**
30
+ * Get owner and repo from config.
31
+ * @throws Error if repo is not configured
32
+ */
33
+ private getOwnerRepo;
34
+ /**
35
+ * Map GitHub Issue to Ticket.
36
+ */
37
+ private mapIssueToTicket;
38
+ /**
39
+ * List tickets matching the given filter criteria.
40
+ */
41
+ list(filter?: TicketFilter): Promise<Ticket[]>;
42
+ /**
43
+ * Get a single ticket by its ID.
44
+ */
45
+ get(id: string): Promise<Ticket>;
46
+ /**
47
+ * Create a new ticket.
48
+ * @throws Error - Not yet implemented (S-0075)
49
+ */
50
+ create(_ticket: NewTicket): Promise<Ticket>;
51
+ /**
52
+ * Update the status of a ticket.
53
+ * No-op: Write operations will be implemented in S-0075.
54
+ */
55
+ updateStatus(_id: string, _status: string): Promise<void>;
56
+ /**
57
+ * Add a comment to a ticket.
58
+ * No-op: Write operations will be implemented in S-0075.
59
+ */
60
+ addComment(_id: string, _body: string): Promise<void>;
61
+ /**
62
+ * Link a pull request to a ticket.
63
+ * No-op: Write operations will be implemented in S-0075.
64
+ */
65
+ linkPR(_id: string, _prUrl: string): Promise<void>;
66
+ /**
67
+ * Map internal story status to external GitHub status.
68
+ *
69
+ * Uses label-based mapping if configured, otherwise uses state:
70
+ * - backlog, ready, in_progress, blocked → 'open'
71
+ * - done → 'closed'
72
+ */
73
+ mapStatusToExternal(status: StoryStatus): string;
74
+ /**
75
+ * Map external GitHub status to internal story status.
76
+ *
77
+ * If status labels are configured, tries to match label to status.
78
+ * Otherwise uses issue state:
79
+ * - open → ready
80
+ * - closed → done
81
+ */
82
+ mapStatusFromExternal(externalStatus: string): StoryStatus;
83
+ }
84
+ //# sourceMappingURL=github-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-provider.d.ts","sourceRoot":"","sources":["../../../src/services/ticket-provider/github-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAQ7E;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED;;;;;;;;;;GAUG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IAG7C,OAAO,CAAC,MAAM,CAAC;IAF3B,QAAQ,CAAC,IAAI,YAAY;gBAEL,MAAM,CAAC,EAAE,YAAY,YAAA;IAEzC;;;OAGG;IACH,OAAO,CAAC,YAAY;IAapB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAsCxB;;OAEG;IACG,IAAI,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAsCpD;;OAEG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAYtC;;;OAGG;IACG,MAAM,CAAC,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IAIjD;;;OAGG;IACG,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/D;;;OAGG;IACG,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D;;;OAGG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxD;;;;;;OAMG;IACH,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM;IAmBhD;;;;;;;OAOG;IACH,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,WAAW;CAoB3D"}
@@ -0,0 +1,194 @@
1
+ import { ghIssueView, ghIssueList, } from '../gh-cli.js';
2
+ /**
3
+ * Ticket provider implementation for GitHub Issues.
4
+ *
5
+ * Integrates with GitHub Issues via the gh CLI. Supports:
6
+ * - Listing issues with filters
7
+ * - Fetching individual issues
8
+ * - Status mapping between GitHub and ai-sdlc
9
+ *
10
+ * Write operations (create, updateStatus, addComment, linkPR) will be
11
+ * implemented in story S-0075.
12
+ */
13
+ export class GitHubTicketProvider {
14
+ config;
15
+ name = 'github';
16
+ constructor(config) {
17
+ this.config = config;
18
+ }
19
+ /**
20
+ * Get owner and repo from config.
21
+ * @throws Error if repo is not configured
22
+ */
23
+ getOwnerRepo() {
24
+ if (!this.config?.repo) {
25
+ throw new Error('GitHub repository not configured. Set ticketing.github.repo in config.');
26
+ }
27
+ const [owner, repo] = this.config.repo.split('/');
28
+ if (!owner || !repo) {
29
+ throw new Error(`Invalid GitHub repository format: "${this.config.repo}". Expected "owner/repo".`);
30
+ }
31
+ return { owner, repo };
32
+ }
33
+ /**
34
+ * Map GitHub Issue to Ticket.
35
+ */
36
+ mapIssueToTicket(issue) {
37
+ const { owner, repo } = this.getOwnerRepo();
38
+ const url = `https://github.com/${owner}/${repo}/issues/${issue.number}`;
39
+ const labels = issue.labels.map((l) => l.name);
40
+ const assignee = issue.assignees[0]?.login;
41
+ // Extract priority from project if available
42
+ let priority = 3; // Default priority
43
+ if (issue.projectItems && issue.projectItems.length > 0) {
44
+ for (const item of issue.projectItems) {
45
+ // Look for priority field in project
46
+ if (item.fieldValueByName) {
47
+ const priorityField = item.fieldValueByName.find((f) => f.field.name.toLowerCase() === 'priority');
48
+ if (priorityField) {
49
+ // Try to parse priority as number
50
+ const priorityValue = parseInt(priorityField.name, 10);
51
+ if (!isNaN(priorityValue)) {
52
+ priority = priorityValue;
53
+ }
54
+ }
55
+ }
56
+ }
57
+ }
58
+ return {
59
+ id: issue.number.toString(),
60
+ url,
61
+ title: issue.title,
62
+ description: issue.body || '',
63
+ status: issue.state,
64
+ priority,
65
+ labels,
66
+ assignee,
67
+ };
68
+ }
69
+ /**
70
+ * List tickets matching the given filter criteria.
71
+ */
72
+ async list(filter) {
73
+ const { owner, repo } = this.getOwnerRepo();
74
+ // Convert TicketFilter to IssueFilter
75
+ const issueFilter = {};
76
+ if (filter?.status && filter.status.length > 0) {
77
+ // Map internal statuses to GitHub state
78
+ const hasOpen = filter.status.some((s) => ['backlog', 'ready', 'in-progress', 'blocked'].includes(s));
79
+ const hasClosed = filter.status.includes('done');
80
+ if (hasOpen && hasClosed) {
81
+ issueFilter.state = 'all';
82
+ }
83
+ else if (hasOpen) {
84
+ issueFilter.state = 'open';
85
+ }
86
+ else if (hasClosed) {
87
+ issueFilter.state = 'closed';
88
+ }
89
+ }
90
+ if (filter?.labels) {
91
+ issueFilter.labels = filter.labels;
92
+ }
93
+ if (filter?.assignee) {
94
+ issueFilter.assignee = filter.assignee;
95
+ }
96
+ if (filter?.limit) {
97
+ issueFilter.limit = filter.limit;
98
+ }
99
+ const issues = await ghIssueList(owner, repo, issueFilter);
100
+ return issues.map((issue) => this.mapIssueToTicket(issue));
101
+ }
102
+ /**
103
+ * Get a single ticket by its ID.
104
+ */
105
+ async get(id) {
106
+ const { owner, repo } = this.getOwnerRepo();
107
+ const issueNumber = parseInt(id, 10);
108
+ if (isNaN(issueNumber)) {
109
+ throw new Error(`Invalid GitHub issue number: "${id}"`);
110
+ }
111
+ const issue = await ghIssueView(owner, repo, issueNumber);
112
+ return this.mapIssueToTicket(issue);
113
+ }
114
+ /**
115
+ * Create a new ticket.
116
+ * @throws Error - Not yet implemented (S-0075)
117
+ */
118
+ async create(_ticket) {
119
+ throw new Error('GitHub ticket creation not yet implemented (S-0075)');
120
+ }
121
+ /**
122
+ * Update the status of a ticket.
123
+ * No-op: Write operations will be implemented in S-0075.
124
+ */
125
+ async updateStatus(_id, _status) {
126
+ // No-op: Write operations not yet implemented
127
+ }
128
+ /**
129
+ * Add a comment to a ticket.
130
+ * No-op: Write operations will be implemented in S-0075.
131
+ */
132
+ async addComment(_id, _body) {
133
+ // No-op: Write operations not yet implemented
134
+ }
135
+ /**
136
+ * Link a pull request to a ticket.
137
+ * No-op: Write operations will be implemented in S-0075.
138
+ */
139
+ async linkPR(_id, _prUrl) {
140
+ // No-op: Write operations not yet implemented
141
+ }
142
+ /**
143
+ * Map internal story status to external GitHub status.
144
+ *
145
+ * Uses label-based mapping if configured, otherwise uses state:
146
+ * - backlog, ready, in_progress, blocked → 'open'
147
+ * - done → 'closed'
148
+ */
149
+ mapStatusToExternal(status) {
150
+ // Check for custom label mapping
151
+ if (this.config?.statusLabels && this.config.statusLabels[status]) {
152
+ return this.config.statusLabels[status];
153
+ }
154
+ // Default mapping to GitHub issue state
155
+ switch (status) {
156
+ case 'done':
157
+ return 'closed';
158
+ case 'backlog':
159
+ case 'ready':
160
+ case 'in-progress':
161
+ case 'blocked':
162
+ default:
163
+ return 'open';
164
+ }
165
+ }
166
+ /**
167
+ * Map external GitHub status to internal story status.
168
+ *
169
+ * If status labels are configured, tries to match label to status.
170
+ * Otherwise uses issue state:
171
+ * - open → ready
172
+ * - closed → done
173
+ */
174
+ mapStatusFromExternal(externalStatus) {
175
+ // Check for custom label mapping (reverse lookup)
176
+ if (this.config?.statusLabels) {
177
+ for (const [status, label] of Object.entries(this.config.statusLabels)) {
178
+ if (label === externalStatus) {
179
+ return status;
180
+ }
181
+ }
182
+ }
183
+ // Default mapping from GitHub issue state
184
+ const statusLower = externalStatus.toLowerCase();
185
+ switch (statusLower) {
186
+ case 'closed':
187
+ return 'done';
188
+ case 'open':
189
+ default:
190
+ return 'ready';
191
+ }
192
+ }
193
+ }
194
+ //# sourceMappingURL=github-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-provider.js","sourceRoot":"","sources":["../../../src/services/ticket-provider/github-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { Config } from '../../types/index.js';
2
+ import { TicketProvider } from './types.js';
3
+ export * from './types.js';
4
+ export { NullTicketProvider } from './null-provider.js';
5
+ export { GitHubTicketProvider } from './github-provider.js';
6
+ /**
7
+ * Create a ticket provider based on configuration.
8
+ *
9
+ * Factory function that instantiates the appropriate TicketProvider
10
+ * implementation based on the `ticketing.provider` configuration value.
11
+ *
12
+ * Defaults to NullTicketProvider when:
13
+ * - No ticketing configuration exists
14
+ * - ticketing.provider is 'none'
15
+ * - ticketing.provider is an unknown value
16
+ *
17
+ * @param config Application configuration
18
+ * @returns Configured ticket provider instance
19
+ * @throws Error if requesting an unimplemented provider (github, jira)
20
+ */
21
+ export declare function createTicketProvider(config: Config): TicketProvider;
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/ticket-provider/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5C,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAmBnE"}
@@ -0,0 +1,38 @@
1
+ import { NullTicketProvider } from './null-provider.js';
2
+ import { GitHubTicketProvider } from './github-provider.js';
3
+ // Re-export types
4
+ export * from './types.js';
5
+ export { NullTicketProvider } from './null-provider.js';
6
+ export { GitHubTicketProvider } from './github-provider.js';
7
+ /**
8
+ * Create a ticket provider based on configuration.
9
+ *
10
+ * Factory function that instantiates the appropriate TicketProvider
11
+ * implementation based on the `ticketing.provider` configuration value.
12
+ *
13
+ * Defaults to NullTicketProvider when:
14
+ * - No ticketing configuration exists
15
+ * - ticketing.provider is 'none'
16
+ * - ticketing.provider is an unknown value
17
+ *
18
+ * @param config Application configuration
19
+ * @returns Configured ticket provider instance
20
+ * @throws Error if requesting an unimplemented provider (github, jira)
21
+ */
22
+ export function createTicketProvider(config) {
23
+ const provider = config.ticketing?.provider ?? 'none';
24
+ switch (provider) {
25
+ case 'none':
26
+ return new NullTicketProvider();
27
+ case 'github':
28
+ return new GitHubTicketProvider(config.ticketing?.github);
29
+ case 'jira':
30
+ // Placeholder for future Jira provider implementation
31
+ throw new Error('Jira provider not yet implemented');
32
+ default:
33
+ // Unknown provider - fall back to safe default
34
+ console.warn(`Unknown ticket provider "${provider}", falling back to 'none'`);
35
+ return new NullTicketProvider();
36
+ }
37
+ }
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/ticket-provider/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG5D,kBAAkB;AAClB,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,EAAE,QAAQ,IAAI,MAAM,CAAC;IAEtD,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,MAAM;YACT,OAAO,IAAI,kBAAkB,EAAE,CAAC;QAElC,KAAK,QAAQ;YACX,OAAO,IAAI,oBAAoB,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAE5D,KAAK,MAAM;YACT,sDAAsD;YACtD,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAEvD;YACE,+CAA+C;YAC/C,OAAO,CAAC,IAAI,CAAC,4BAA4B,QAAQ,2BAA2B,CAAC,CAAC;YAC9E,OAAO,IAAI,kBAAkB,EAAE,CAAC;IACpC,CAAC;AACH,CAAC"}