ai-sdlc 0.3.1-alpha.0-alpha.7 → 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.
@@ -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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"}
@@ -2,6 +2,7 @@ import { Config } from '../../types/index.js';
2
2
  import { TicketProvider } from './types.js';
3
3
  export * from './types.js';
4
4
  export { NullTicketProvider } from './null-provider.js';
5
+ export { GitHubTicketProvider } from './github-provider.js';
5
6
  /**
6
7
  * Create a ticket provider based on configuration.
7
8
  *
@@ -1 +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;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5C,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAoBnE"}
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"}
@@ -1,7 +1,9 @@
1
1
  import { NullTicketProvider } from './null-provider.js';
2
+ import { GitHubTicketProvider } from './github-provider.js';
2
3
  // Re-export types
3
4
  export * from './types.js';
4
5
  export { NullTicketProvider } from './null-provider.js';
6
+ export { GitHubTicketProvider } from './github-provider.js';
5
7
  /**
6
8
  * Create a ticket provider based on configuration.
7
9
  *
@@ -23,8 +25,7 @@ export function createTicketProvider(config) {
23
25
  case 'none':
24
26
  return new NullTicketProvider();
25
27
  case 'github':
26
- // Placeholder for S-0074 (GitHub provider implementation)
27
- throw new Error('GitHub provider not yet implemented');
28
+ return new GitHubTicketProvider(config.ticketing?.github);
28
29
  case 'jira':
29
30
  // Placeholder for future Jira provider implementation
30
31
  throw new Error('Jira provider not yet implemented');
@@ -1 +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;AAGxD,kBAAkB;AAClB,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD;;;;;;;;;;;;;;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,0DAA0D;YAC1D,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAEzD,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"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-sdlc",
3
- "version": "0.3.1-alpha.0-alpha.7",
3
+ "version": "0.3.1-alpha.0-alpha.8",
4
4
  "description": "Agent-first SDLC workflow manager using Claude Agent SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",