linear-github-cli 1.0.0

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,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.commitFirst = commitFirst;
4
+ const child_process_1 = require("child_process");
5
+ const dotenv_1 = require("dotenv");
6
+ const path_1 = require("path");
7
+ const branch_utils_1 = require("../branch-utils");
8
+ const linear_client_1 = require("../linear-client");
9
+ // Load .env file from the project root
10
+ // __dirname points to dist/commands/ in compiled output, so we go up two levels
11
+ (0, dotenv_1.config)({ path: (0, path_1.resolve)(__dirname, '../..', '.env') });
12
+ /**
13
+ * Creates the first commit with proper message format
14
+ * - Extracts branch prefix (commit type) and Linear issue ID from current branch name
15
+ * - Fetches Linear issue title and GitHub issue number
16
+ * - Generates commit message: "{prefix}: {linearId} {title}" with body "solve: #{githubIssueNumber}"
17
+ */
18
+ async function commitFirst() {
19
+ const linearApiKey = process.env.LINEAR_API_KEY;
20
+ if (!linearApiKey) {
21
+ console.error('āŒ LINEAR_API_KEY environment variable is required');
22
+ console.error('');
23
+ console.error(' Option 1: Create a .env file in the project root:');
24
+ console.error(' echo "LINEAR_API_KEY=lin_api_..." > .env');
25
+ console.error('');
26
+ console.error(' Option 2: Export in your shell:');
27
+ console.error(' export LINEAR_API_KEY="lin_api_..."');
28
+ console.error('');
29
+ console.error(' Get your API key from: https://linear.app/settings/api');
30
+ process.exit(1);
31
+ }
32
+ try {
33
+ // Step 1: Get current branch name
34
+ let branchName;
35
+ try {
36
+ branchName = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim();
37
+ }
38
+ catch (error) {
39
+ console.error('āŒ Error: Not in a git repository or unable to get branch name');
40
+ process.exit(1);
41
+ }
42
+ // Step 2: Extract branch prefix and Linear issue ID from branch name
43
+ const prefix = (0, branch_utils_1.extractBranchPrefix)(branchName);
44
+ const linearId = (0, branch_utils_1.extractLinearIssueId)(branchName);
45
+ if (!linearId) {
46
+ console.error(`āŒ Error: Could not extract Linear issue ID from branch name: ${branchName}`);
47
+ console.error(' Branch name should follow pattern: prefix/LEA-123-title');
48
+ process.exit(1);
49
+ }
50
+ console.log(`šŸ“‹ Found Linear issue ID: ${linearId}`);
51
+ console.log(`šŸ“‹ Using commit type: ${prefix}`);
52
+ // Step 3: Initialize Linear client and fetch issue data
53
+ const linearClient = new linear_client_1.LinearClientWrapper(linearApiKey);
54
+ console.log('šŸ” Fetching Linear issue title...');
55
+ const title = await linearClient.getIssueTitle(linearId);
56
+ if (!title) {
57
+ console.error(`āŒ Error: Linear issue ${linearId} not found`);
58
+ process.exit(1);
59
+ }
60
+ console.log('šŸ” Fetching GitHub issue number...');
61
+ const githubIssueNumber = await linearClient.getGitHubIssueNumber(linearId);
62
+ if (!githubIssueNumber) {
63
+ console.error(`āŒ Error: GitHub issue number not found for Linear issue ${linearId}`);
64
+ console.error(' Make sure the Linear issue is linked to a GitHub issue');
65
+ process.exit(1);
66
+ }
67
+ // Step 4: Generate commit message
68
+ const commitTitle = `${prefix}: ${linearId} ${title}`;
69
+ const commitBody = `solve: #${githubIssueNumber}`;
70
+ console.log('\nšŸ“ Commit message:');
71
+ console.log(` ${commitTitle}`);
72
+ console.log(` ${commitBody}\n`);
73
+ // Step 5: Execute commit
74
+ try {
75
+ (0, child_process_1.execSync)(`git commit --allow-empty -m "${commitTitle.replace(/"/g, '\\"')}" -m "${commitBody.replace(/"/g, '\\"')}"`, { stdio: 'inherit' });
76
+ console.log('āœ… Commit created successfully!');
77
+ }
78
+ catch (error) {
79
+ console.error('āŒ Error: Failed to create commit');
80
+ console.error(error instanceof Error ? error.message : error);
81
+ process.exit(1);
82
+ }
83
+ }
84
+ catch (error) {
85
+ console.error('āŒ Error:', error instanceof Error ? error.message : error);
86
+ process.exit(1);
87
+ }
88
+ }
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createParentIssue = createParentIssue;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ const branch_utils_1 = require("../branch-utils");
9
+ const github_client_1 = require("../github-client");
10
+ const input_handler_1 = require("../input-handler");
11
+ const linear_client_1 = require("../linear-client");
12
+ async function createParentIssue() {
13
+ const linearApiKey = process.env.LINEAR_API_KEY;
14
+ if (!linearApiKey) {
15
+ console.error('āŒ LINEAR_API_KEY environment variable is required');
16
+ console.error('');
17
+ console.error(' Option 1: Create a .env file in the project root:');
18
+ console.error(' echo "LINEAR_API_KEY=lin_api_..." > .env');
19
+ console.error('');
20
+ console.error(' Option 2: Export in your shell:');
21
+ console.error(' export LINEAR_API_KEY="lin_api_..."');
22
+ console.error('');
23
+ console.error(' Get your API key from: https://linear.app/settings/api');
24
+ process.exit(1);
25
+ }
26
+ const linearClient = new linear_client_1.LinearClientWrapper(linearApiKey);
27
+ // Step 1: Select repository
28
+ console.log('šŸ“¦ Fetching repositories...');
29
+ const githubClient = new github_client_1.GitHubClientWrapper('');
30
+ const inputHandler = new input_handler_1.InputHandler(linearClient, githubClient);
31
+ const repo = await inputHandler.selectRepository();
32
+ githubClient.repo = repo;
33
+ // Check for unpushed commits on current branch
34
+ const unpushedCheck = (0, branch_utils_1.checkUnpushedCommitsOnCurrentBranch)();
35
+ if (unpushedCheck.hasUnpushed) {
36
+ console.log('\nāš ļø Warning: There are unpushed commits on the current branch.');
37
+ console.log(` Found ${unpushedCheck.count} unpushed commit(s):`);
38
+ unpushedCheck.commits.forEach(commit => {
39
+ console.log(` - ${commit}`);
40
+ });
41
+ console.log('\n If you create a branch from this state, these commits will be included in PR body.');
42
+ console.log(' Please push commits first:');
43
+ console.log(' git push');
44
+ console.log('\n Then re-run this command.');
45
+ process.exit(1);
46
+ }
47
+ else {
48
+ console.log('āœ“ No unpushed commits on current branch');
49
+ }
50
+ // Step 2: Get issue details
51
+ const details = await inputHandler.promptIssueDetails(repo);
52
+ // Step 3: Select GitHub project (optional)
53
+ const githubProject = await inputHandler.selectProject(repo);
54
+ // Step 4: Create GitHub issue
55
+ console.log('\nšŸš€ Creating GitHub issue...');
56
+ const body = details.dueDate
57
+ ? `Due Date: ${details.dueDate}\n\n${details.description}`
58
+ : details.description;
59
+ const issue = await githubClient.createIssue({
60
+ repo,
61
+ title: details.title,
62
+ body,
63
+ labels: details.labels,
64
+ assignees: ['@me'],
65
+ project: githubProject || undefined,
66
+ });
67
+ console.log(`āœ… GitHub Issue #${issue.number} created: ${issue.url}`);
68
+ // Step 5: Wait for Linear sync, then update metadata
69
+ console.log('\nā³ Waiting for Linear sync (5 seconds)...');
70
+ await new Promise(resolve => setTimeout(resolve, 5000));
71
+ const linearIssueId = await linearClient.findIssueByGitHubUrl(issue.url);
72
+ if (linearIssueId) {
73
+ console.log('āœ… Found Linear issue, updating metadata...');
74
+ // Auto-find Linear project if GitHub project was selected
75
+ let linearProjectId = null;
76
+ if (githubProject) {
77
+ console.log(` Looking for Linear project matching "${githubProject}"...`);
78
+ linearProjectId = await linearClient.findProjectByName(githubProject);
79
+ if (linearProjectId) {
80
+ console.log(` āœ… Found matching Linear project: ${githubProject}`);
81
+ }
82
+ else {
83
+ console.log(` āš ļø No matching Linear project found. You can set it manually.`);
84
+ }
85
+ }
86
+ // If no auto-match, ask user (only if GitHub project wasn't selected)
87
+ if (!linearProjectId && !githubProject) {
88
+ linearProjectId = await inputHandler.selectLinearProject();
89
+ }
90
+ // Set labels on Linear issue
91
+ if (details.labels && details.labels.length > 0) {
92
+ console.log(` Setting labels: ${details.labels.join(', ')}`);
93
+ const labelIds = await linearClient.setIssueLabels(linearIssueId, details.labels);
94
+ if (labelIds.length > 0) {
95
+ console.log(` āœ… ${labelIds.length} label(s) set on Linear issue`);
96
+ }
97
+ else {
98
+ console.log(' āš ļø Failed to set labels. You can set them manually in Linear.');
99
+ }
100
+ }
101
+ // Update issue metadata (due date and project, but not status)
102
+ const success = await linearClient.updateIssueMetadata(linearIssueId, details.dueDate || undefined, linearProjectId || undefined);
103
+ if (success) {
104
+ console.log('āœ… Linear issue metadata updated!');
105
+ if (linearProjectId) {
106
+ console.log(` Project: ${githubProject || 'selected project'}`);
107
+ }
108
+ if (details.dueDate) {
109
+ console.log(` Due date: ${details.dueDate}`);
110
+ }
111
+ console.log(' Status: Will be updated automatically via PR integration');
112
+ }
113
+ else {
114
+ console.log('āš ļø Failed to update Linear issue metadata. You can update it manually in Linear.');
115
+ }
116
+ // Step 6: Create branch
117
+ if (linearIssueId) {
118
+ const { createBranch } = await inquirer_1.default.prompt([
119
+ {
120
+ type: 'confirm',
121
+ name: 'createBranch',
122
+ message: 'Create git branch for this issue?',
123
+ default: true,
124
+ },
125
+ ]);
126
+ if (createBranch) {
127
+ // Get Linear issue identifier (e.g., LEA-123) instead of UUID
128
+ const linearIssueIdentifier = await linearClient.getIssueIdentifier(linearIssueId);
129
+ if (!linearIssueIdentifier) {
130
+ console.log('āš ļø Could not get Linear issue identifier. Branch creation skipped.');
131
+ console.log(` Linear issue ID: ${linearIssueId}`);
132
+ console.log(` GitHub issue #${issue.number}`);
133
+ }
134
+ else {
135
+ const branchPrefix = await (0, branch_utils_1.selectBranchPrefix)(details.labels);
136
+ if (branchPrefix) {
137
+ const branchName = (0, branch_utils_1.generateBranchName)(branchPrefix, linearIssueIdentifier, details.title);
138
+ const success = await (0, branch_utils_1.createGitBranch)(branchName);
139
+ if (success) {
140
+ console.log(`āœ… Branch created: ${branchName}`);
141
+ console.log(` Linear issue ID: ${linearIssueIdentifier}`);
142
+ console.log(` GitHub issue #${issue.number}`);
143
+ }
144
+ }
145
+ else {
146
+ console.log('āš ļø No suitable label found for branch prefix. Branch creation skipped.');
147
+ console.log(` Linear issue ID: ${linearIssueIdentifier}`);
148
+ console.log(` GitHub issue #${issue.number}`);
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ else {
155
+ console.log('āš ļø Linear issue not found yet. Metadata will be set by GitHub Actions.');
156
+ }
157
+ console.log('\nšŸ’” Next steps:');
158
+ console.log(` Create sub-issues: lg create-sub`);
159
+ console.log(` Then select issue #${issue.number}`);
160
+ }
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createSubIssue = createSubIssue;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ const branch_utils_1 = require("../branch-utils");
9
+ const github_client_1 = require("../github-client");
10
+ const input_handler_1 = require("../input-handler");
11
+ const linear_client_1 = require("../linear-client");
12
+ async function createSubIssue() {
13
+ const linearApiKey = process.env.LINEAR_API_KEY;
14
+ if (!linearApiKey) {
15
+ console.error('āŒ LINEAR_API_KEY environment variable is required');
16
+ console.error('');
17
+ console.error(' Option 1: Create a .env file in the project root:');
18
+ console.error(' echo "LINEAR_API_KEY=lin_api_..." > .env');
19
+ console.error('');
20
+ console.error(' Option 2: Export in your shell:');
21
+ console.error(' export LINEAR_API_KEY="lin_api_..."');
22
+ console.error('');
23
+ console.error(' Get your API key from: https://linear.app/settings/api');
24
+ process.exit(1);
25
+ }
26
+ const linearClient = new linear_client_1.LinearClientWrapper(linearApiKey);
27
+ const githubClient = new github_client_1.GitHubClientWrapper('');
28
+ const inputHandler = new input_handler_1.InputHandler(linearClient, githubClient);
29
+ // Step 1: Select repository
30
+ console.log('šŸ“¦ Fetching repositories...');
31
+ const repo = await inputHandler.selectRepository();
32
+ githubClient.repo = repo;
33
+ // Check for unpushed commits on current branch
34
+ const unpushedCheck = (0, branch_utils_1.checkUnpushedCommitsOnCurrentBranch)();
35
+ if (unpushedCheck.hasUnpushed) {
36
+ console.log('\nāš ļø Warning: There are unpushed commits on the current branch.');
37
+ console.log(` Found ${unpushedCheck.count} unpushed commit(s):`);
38
+ unpushedCheck.commits.forEach(commit => {
39
+ console.log(` - ${commit}`);
40
+ });
41
+ console.log('\n If you create a branch from this state, these commits will be included in PR body.');
42
+ console.log(' Please push commits first:');
43
+ console.log(' git push');
44
+ console.log('\n Then re-run this command.');
45
+ process.exit(1);
46
+ }
47
+ else {
48
+ console.log('āœ“ No unpushed commits on current branch');
49
+ }
50
+ // Step 2: Select parent issue
51
+ console.log('\nšŸ“‹ Fetching issues...');
52
+ const parentIssueNumber = await inputHandler.selectParentIssue(repo);
53
+ // Step 3: Get sub-issue details
54
+ const details = await inputHandler.promptIssueDetails(repo);
55
+ // Step 4: Create sub-issue
56
+ console.log('\nšŸš€ Creating sub-issue...');
57
+ const body = details.dueDate
58
+ ? `Due Date: ${details.dueDate}\n\n${details.description}`
59
+ : details.description;
60
+ const subIssue = await githubClient.createSubIssue({
61
+ repo,
62
+ parentIssueNumber,
63
+ title: details.title,
64
+ body,
65
+ labels: details.labels,
66
+ assignees: ['@me'],
67
+ });
68
+ console.log(`āœ… Sub-Issue #${subIssue.number} created: ${subIssue.url}`);
69
+ console.log(` Parent: #${parentIssueNumber}`);
70
+ // Step 5: Wait for Linear sync, then update metadata
71
+ console.log('\nā³ Waiting for Linear sync (5 seconds)...');
72
+ await new Promise(resolve => setTimeout(resolve, 5000));
73
+ const linearIssueId = await linearClient.findIssueByGitHubUrl(subIssue.url);
74
+ if (linearIssueId) {
75
+ console.log('āœ… Found Linear issue, updating metadata...');
76
+ // Get parent issue to check if it has a project
77
+ const parentIssueUrl = `https://github.com/${repo}/issues/${parentIssueNumber}`;
78
+ console.log(` Looking for parent issue's Linear project...`);
79
+ const parentLinearIssueId = await linearClient.findIssueByGitHubUrl(parentIssueUrl);
80
+ let linearProjectId = null;
81
+ let parentProjectName = null;
82
+ if (parentLinearIssueId) {
83
+ console.log(` āœ… Found parent Linear issue: ${parentLinearIssueId}`);
84
+ // Try to get parent issue's project
85
+ const parentProject = await linearClient.getIssueProject(parentLinearIssueId);
86
+ if (parentProject) {
87
+ linearProjectId = parentProject.id;
88
+ parentProjectName = parentProject.name;
89
+ console.log(` āœ… Found parent issue's project: ${parentProjectName}`);
90
+ }
91
+ else {
92
+ console.log(` āš ļø Parent issue has no project set`);
93
+ }
94
+ }
95
+ else {
96
+ console.log(` āš ļø Parent Linear issue not found yet (may need more time to sync)`);
97
+ }
98
+ // If no parent project, ask user (only if no parent project found)
99
+ if (!linearProjectId) {
100
+ linearProjectId = await inputHandler.selectLinearProject();
101
+ }
102
+ // Set labels on Linear issue
103
+ if (details.labels && details.labels.length > 0) {
104
+ console.log(` Setting labels: ${details.labels.join(', ')}`);
105
+ const labelIds = await linearClient.setIssueLabels(linearIssueId, details.labels);
106
+ if (labelIds.length > 0) {
107
+ console.log(` āœ… ${labelIds.length} label(s) set on Linear issue`);
108
+ }
109
+ else {
110
+ console.log(' āš ļø Failed to set labels. You can set them manually in Linear.');
111
+ }
112
+ }
113
+ // Update issue metadata (due date and project, but not status)
114
+ const success = await linearClient.updateIssueMetadata(linearIssueId, details.dueDate || undefined, linearProjectId || undefined);
115
+ if (success) {
116
+ console.log('āœ… Linear issue metadata updated!');
117
+ if (linearProjectId) {
118
+ if (parentProjectName) {
119
+ console.log(` Project: ${parentProjectName} (inherited from parent)`);
120
+ }
121
+ else {
122
+ console.log(` Project: linked`);
123
+ }
124
+ }
125
+ if (details.dueDate) {
126
+ console.log(` Due date: ${details.dueDate}`);
127
+ }
128
+ console.log(' Status: Will be updated automatically via PR integration');
129
+ }
130
+ else {
131
+ console.log('āš ļø Failed to update Linear issue metadata. You can update it manually in Linear.');
132
+ }
133
+ // Step 6: Create branch
134
+ if (linearIssueId) {
135
+ const { createBranch } = await inquirer_1.default.prompt([
136
+ {
137
+ type: 'confirm',
138
+ name: 'createBranch',
139
+ message: 'Create git branch for this issue?',
140
+ default: true,
141
+ },
142
+ ]);
143
+ if (createBranch) {
144
+ // Get Linear issue identifier (e.g., LEA-123) instead of UUID
145
+ const linearIssueIdentifier = await linearClient.getIssueIdentifier(linearIssueId);
146
+ if (!linearIssueIdentifier) {
147
+ console.log('āš ļø Could not get Linear issue identifier. Branch creation skipped.');
148
+ console.log(` Linear issue ID: ${linearIssueId}`);
149
+ console.log(` GitHub issue #${subIssue.number}`);
150
+ }
151
+ else {
152
+ const branchPrefix = await (0, branch_utils_1.selectBranchPrefix)(details.labels);
153
+ if (branchPrefix) {
154
+ const branchName = (0, branch_utils_1.generateBranchName)(branchPrefix, linearIssueIdentifier, details.title);
155
+ const success = await (0, branch_utils_1.createGitBranch)(branchName);
156
+ if (success) {
157
+ console.log(`āœ… Branch created: ${branchName}`);
158
+ console.log(` Linear issue ID: ${linearIssueIdentifier}`);
159
+ console.log(` GitHub issue #${subIssue.number}`);
160
+ }
161
+ }
162
+ else {
163
+ console.log('āš ļø No suitable label found for branch prefix. Branch creation skipped.');
164
+ console.log(` Linear issue ID: ${linearIssueIdentifier}`);
165
+ console.log(` GitHub issue #${subIssue.number}`);
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
171
+ else {
172
+ console.log('āš ļø Linear issue not found yet. Metadata will be set by GitHub Actions.');
173
+ }
174
+ }
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitHubClientWrapper = void 0;
4
+ const rest_1 = require("@octokit/rest");
5
+ const child_process_1 = require("child_process");
6
+ class GitHubClientWrapper {
7
+ octokit;
8
+ repo;
9
+ constructor(repo, token) {
10
+ this.repo = repo;
11
+ if (token) {
12
+ this.octokit = new rest_1.Octokit({ auth: token });
13
+ }
14
+ }
15
+ async getRepositories() {
16
+ // Use gh CLI to get accessible repos
17
+ const output = (0, child_process_1.execSync)('gh repo list --limit 100 --json nameWithOwner', {
18
+ encoding: 'utf-8',
19
+ });
20
+ const repos = JSON.parse(output);
21
+ return repos.map((r) => {
22
+ const [owner, name] = r.nameWithOwner.split('/');
23
+ return { owner, name, fullName: r.nameWithOwner };
24
+ });
25
+ }
26
+ async getProjects(repo) {
27
+ // Extract owner from repo (format: owner/repo)
28
+ const [owner] = repo.split('/');
29
+ // Use gh CLI to get projects - note: gh project list uses --owner, not --repo
30
+ // Output format: {"projects": [...], "totalCount": N}
31
+ const output = (0, child_process_1.execSync)(`gh project list --owner ${owner} --limit 50 --format json`, { encoding: 'utf-8', stdio: 'pipe' });
32
+ const result = JSON.parse(output);
33
+ // Handle both array format and object format
34
+ const projects = Array.isArray(result) ? result : (result.projects || []);
35
+ return projects.map((p) => ({
36
+ id: p.number.toString(),
37
+ name: p.title,
38
+ }));
39
+ }
40
+ async createIssue(params) {
41
+ // gh issue create doesn't support --json flag, so we parse the URL from output
42
+ // Output format: "https://github.com/owner/repo/issues/123"
43
+ const command = `gh issue create --repo ${params.repo} ` +
44
+ `--title "${params.title.replace(/"/g, '\\"')}" ` +
45
+ `--body "${params.body.replace(/"/g, '\\"')}" ` +
46
+ (params.labels && params.labels.length > 0 ? `--label "${params.labels.join(',')}" ` : '') +
47
+ (params.assignees && params.assignees.length > 0 ? `--assignee "${params.assignees.join(',')}" ` : '') +
48
+ (params.project ? `--project "${params.project}" ` : '');
49
+ const output = (0, child_process_1.execSync)(command, { encoding: 'utf-8' });
50
+ // Parse URL from output: "https://github.com/owner/repo/issues/123"
51
+ const urlMatch = output.match(/https:\/\/github\.com\/[^\/]+\/[^\/]+\/issues\/(\d+)/);
52
+ if (!urlMatch) {
53
+ throw new Error(`Failed to parse issue URL from output: ${output}`);
54
+ }
55
+ const issueNumber = parseInt(urlMatch[1], 10);
56
+ const issueUrl = urlMatch[0];
57
+ // Get issue ID using GraphQL API
58
+ const issueId = await this.getIssueIdByNumber(params.repo, issueNumber);
59
+ return {
60
+ number: issueNumber,
61
+ url: issueUrl,
62
+ id: issueId,
63
+ };
64
+ }
65
+ async createSubIssue(params) {
66
+ // First create the issue
67
+ const issue = await this.createIssue({
68
+ repo: params.repo,
69
+ title: params.title,
70
+ body: params.body,
71
+ labels: params.labels,
72
+ assignees: params.assignees,
73
+ });
74
+ // Then set parent-child relationship via GraphQL
75
+ const parentIssue = await this.getIssueById(params.repo, params.parentIssueNumber);
76
+ (0, child_process_1.execSync)(`gh api graphql -H "GraphQL-Features: sub_issues" -f query="
77
+ mutation {
78
+ addSubIssue(input: {
79
+ issueId: \\\"${parentIssue.id}\\\",
80
+ subIssueId: \\\"${issue.id}\\\"
81
+ }) {
82
+ issue { title }
83
+ subIssue { title }
84
+ }
85
+ }
86
+ "`, { encoding: 'utf-8' });
87
+ return issue;
88
+ }
89
+ async getIssueIdByNumber(repo, issueNumber) {
90
+ // Use GraphQL API to get issue ID
91
+ const [owner, name] = repo.split('/');
92
+ const query = `query { repository(owner: "${owner}", name: "${name}") { issue(number: ${issueNumber}) { id } } }`;
93
+ const output = (0, child_process_1.execSync)(`gh api graphql -f query="${query.replace(/"/g, '\\"')}"`, { encoding: 'utf-8' });
94
+ const result = JSON.parse(output);
95
+ return result.data.repository.issue.id;
96
+ }
97
+ async getIssueById(repo, issueNumber) {
98
+ const id = await this.getIssueIdByNumber(repo, issueNumber);
99
+ return { id };
100
+ }
101
+ async getLabels(repo) {
102
+ try {
103
+ // Use gh CLI to get labels from repository
104
+ const output = (0, child_process_1.execSync)(`gh label list --repo ${repo} --limit 100 --json name`, { encoding: 'utf-8', stdio: 'pipe' });
105
+ const labels = JSON.parse(output);
106
+ return labels.map((l) => l.name).sort();
107
+ }
108
+ catch (error) {
109
+ // Fallback to standard labels if API call fails
110
+ console.error('āš ļø Failed to fetch labels from GitHub, using default labels');
111
+ return [
112
+ 'feat',
113
+ 'fix',
114
+ 'chore',
115
+ 'docs',
116
+ 'refactor',
117
+ 'test',
118
+ 'research',
119
+ ];
120
+ }
121
+ }
122
+ }
123
+ exports.GitHubClientWrapper = GitHubClientWrapper;