-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathcreate-issue-assigned-to-copilot.ts
More file actions
135 lines (121 loc) · 3.93 KB
/
create-issue-assigned-to-copilot.ts
File metadata and controls
135 lines (121 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import { Octokit } from '@octokit/rest';
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
const GITHUB_REPO_OWNER = process.env.GITHUB_REPO_OWNER;
const GITHUB_REPO_NAME = process.env.GITHUB_REPO_NAME;
const GRAPHQL_FEATURES_HEADER = 'issues_copilot_assignment_api_support,coding_agent_model_selection';
/**
* Creates a GitHub issue and assigns it to the Copilot Coding Agent.
* Follows the official GitHub API docs:
* 1. Query suggestedActors to find copilot-swe-agent and get its node ID
* 2. Get the repository node ID
* 3. Create issue with assigneeIds + agentAssignment, including required GraphQL-Features header
* Returns the issue URL on success, null on failure.
*/
export async function createIssueWithCopilot(description: string): Promise<string | null> {
if (!GITHUB_TOKEN || !GITHUB_REPO_OWNER || !GITHUB_REPO_NAME) {
return null;
}
if (!description.trim()) {
return null;
}
const octokit = new Octokit({ auth: GITHUB_TOKEN });
try {
// Step 1: Fetch repo ID and find copilot-swe-agent in suggestedActors
const repoInfo: any = await octokit.graphql(`
query($owner: String!, $name: String!) {
repository(owner: $owner, name: $name) {
id
suggestedActors(capabilities: [CAN_BE_ASSIGNED], first: 100) {
nodes {
login
__typename
... on Bot { id }
... on User { id }
}
}
}
}
`, {
owner: GITHUB_REPO_OWNER,
name: GITHUB_REPO_NAME,
headers: {
'GraphQL-Features': GRAPHQL_FEATURES_HEADER,
},
});
const repoId = repoInfo?.repository?.id;
if (!repoId) {
console.error('Could not fetch repository ID');
return null;
}
const copilotBot = repoInfo.repository.suggestedActors.nodes.find(
(node: any) => node.login === 'copilot-swe-agent'
);
let botId: string;
if (copilotBot) {
botId = copilotBot.id;
console.log(`Found Copilot bot: login=${copilotBot.login}, id=${botId}, type=${copilotBot.__typename}`);
} else {
// Fallback: the GITHUB_TOKEN in Actions may lack permission to see suggestedActors.
// Use the known node ID for copilot-swe-agent.
botId = 'BOT_kgDOC9w8XQ';
console.log(`copilot-swe-agent not found in suggestedActors, using known bot ID: ${botId}`);
}
const title = description.split('\n')[0].slice(0, 100);
// Step 2: Create issue with agentAssignment and required GraphQL-Features header
const response: any = await octokit.graphql(`
mutation($repoId: ID!, $title: String!, $body: String!, $assigneeIds: [ID!]) {
createIssue(input: {
repositoryId: $repoId,
title: $title,
body: $body,
assigneeIds: $assigneeIds,
agentAssignment: {
targetRepositoryId: $repoId,
baseRef: "main",
customInstructions: "",
customAgent: "",
model: ""
}
}) {
issue {
number
title
url
assignees(first: 10) { nodes { login } }
}
}
}
`, {
repoId,
title,
body: description,
assigneeIds: [botId],
headers: {
'GraphQL-Features': GRAPHQL_FEATURES_HEADER,
},
});
const issue = response?.createIssue?.issue;
if (!issue) {
return null;
}
console.log(`Assigned to: ${issue.assignees.nodes.map((a: any) => a.login).join(', ')}`);
return issue.url;
} catch (error) {
console.error('Error creating issue:', error);
return null;
}
}
// CLI entry point
const description = process.argv[2];
if (!description) {
console.error('Usage: npx tsx create-issue-assigned-to-copilot.py <description>');
process.exit(1);
}
createIssueWithCopilot(description).then((url) => {
if (url) {
console.log(`Issue created: ${url}`);
} else {
console.error('Failed to create issue');
process.exit(1);
}
});