@neturely/okffs 0.2.2 → 0.4.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.
- package/.changes/README.md +29 -0
- package/CHANGELOG.md +30 -1
- package/README.md +62 -4
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +45 -0
- package/dist/config.js.map +1 -1
- package/dist/docs.d.ts +6 -0
- package/dist/docs.d.ts.map +1 -1
- package/dist/docs.js +78 -15
- package/dist/docs.js.map +1 -1
- package/dist/github.d.ts +2 -0
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +1 -1
- package/dist/github.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/projects.d.ts +27 -0
- package/dist/projects.d.ts.map +1 -0
- package/dist/projects.js +281 -0
- package/dist/projects.js.map +1 -0
- package/dist/tools/create_issue.d.ts +7 -1
- package/dist/tools/create_issue.d.ts.map +1 -1
- package/dist/tools/create_issue.js +154 -1
- package/dist/tools/create_issue.js.map +1 -1
- package/dist/tools/create_pull_request.d.ts +1 -1
- package/dist/tools/create_pull_request.d.ts.map +1 -1
- package/dist/tools/create_pull_request.js +1 -1
- package/dist/tools/create_pull_request.js.map +1 -1
- package/dist/tools/list_issues.d.ts +1 -1
- package/dist/tools/list_issues.d.ts.map +1 -1
- package/dist/tools/list_issues.js +70 -2
- package/dist/tools/list_issues.js.map +1 -1
- package/dist/tools/prepare_release.d.ts.map +1 -1
- package/dist/tools/prepare_release.js +22 -5
- package/dist/tools/prepare_release.js.map +1 -1
- package/dist/tools/update_project_status.d.ts +20 -0
- package/dist/tools/update_project_status.d.ts.map +1 -0
- package/dist/tools/update_project_status.js +39 -0
- package/dist/tools/update_project_status.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface ProjectSingleSelect {
|
|
2
|
+
fieldId: string;
|
|
3
|
+
options: Map<string, string>;
|
|
4
|
+
}
|
|
5
|
+
export interface ProjectMetadata {
|
|
6
|
+
statusFieldId: string | null;
|
|
7
|
+
statusOptions: Map<string, string>;
|
|
8
|
+
singleSelectByName: Map<string, ProjectSingleSelect>;
|
|
9
|
+
}
|
|
10
|
+
export declare function getProjectMetadata(): Promise<ProjectMetadata>;
|
|
11
|
+
export declare function addIssueToProject(issueNodeId: string): Promise<string>;
|
|
12
|
+
export declare function setProjectFieldValue(itemId: string, fieldId: string, optionId: string): Promise<void>;
|
|
13
|
+
export interface OrgIssueField {
|
|
14
|
+
fieldId: string;
|
|
15
|
+
options: Map<string, string>;
|
|
16
|
+
}
|
|
17
|
+
export declare function getOrgIssueField(name: string): Promise<OrgIssueField | null>;
|
|
18
|
+
export declare function setIssueFieldSingleSelect(issueNodeId: string, fieldId: string, optionId: string): Promise<void>;
|
|
19
|
+
export declare function getProjectItemForIssue(issueNumber: number): Promise<string | null>;
|
|
20
|
+
export interface ProjectItemFields {
|
|
21
|
+
status?: string;
|
|
22
|
+
priority?: string;
|
|
23
|
+
effort?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function getProjectFieldsByIssueNumber(): Promise<Map<number, ProjectItemFields>>;
|
|
26
|
+
export declare function getOrgIssueFieldValuesByNumber(): Promise<Map<number, Map<string, string>>>;
|
|
27
|
+
//# sourceMappingURL=projects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../src/projects.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAM9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CACtD;AA0CD,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,eAAe,CAAC,CAQ7D;AA8DD,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW5E;AAGD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAaf;AA+BD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAUD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAW5E;AA8CD,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAYf;AAGD,wBAAsB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAsBxF;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAkD7F;AASD,wBAAsB,8BAA8B,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAkDhG"}
|
package/dist/projects.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// GitHub Projects v2 integration (Phase 5).
|
|
2
|
+
//
|
|
3
|
+
// Projects v2 has no REST API, so everything here goes through GraphQL, reusing
|
|
4
|
+
// the shared `graphqlRequest` helper from github.ts. Field and single-select
|
|
5
|
+
// option node IDs differ per board, so they are discovered at runtime (and
|
|
6
|
+
// memoized) rather than hardcoded. All calls no-op / throw clearly when the
|
|
7
|
+
// feature is disabled or the token lacks Projects permission.
|
|
8
|
+
import { graphqlRequest, owner, repo } from "./github.js";
|
|
9
|
+
import { config } from "./config.js";
|
|
10
|
+
// Throw a clear, actionable message when the token can't reach Projects, rather
|
|
11
|
+
// than leaking a raw GraphQL blob. Permission errors arrive in several shapes:
|
|
12
|
+
// an HTTP 403, a 200 with a FORBIDDEN error, or — the common gh-CLI-fallback
|
|
13
|
+
// case — an INSUFFICIENT_SCOPES error because the CLI's OAuth token lacks the
|
|
14
|
+
// `project` scope that Projects v2 requires.
|
|
15
|
+
async function projectCall(fn) {
|
|
16
|
+
try {
|
|
17
|
+
return await fn();
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
21
|
+
if (/\b403\b|FORBIDDEN|INSUFFICIENT_SCOPES|not accessible|requires .*\bproject\b/i.test(msg)) {
|
|
22
|
+
throw new Error("[okffs] GitHub denied a Projects API call (insufficient scope / forbidden). " +
|
|
23
|
+
"Projects v2 (GraphQL) needs a token with Projects access: " +
|
|
24
|
+
'fine-grained PAT → Organization permissions → "Projects: Read and write"; ' +
|
|
25
|
+
"classic PAT → the `project` scope. " +
|
|
26
|
+
"Note: the GitHub CLI fallback token (used when GITHUB_TOKEN is unset) usually " +
|
|
27
|
+
"lacks `project` scope — grant it with `gh auth refresh -s project,read:project`. " +
|
|
28
|
+
`Original error: ${msg}`);
|
|
29
|
+
}
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function requireProjectId() {
|
|
34
|
+
if (!config.projectId) {
|
|
35
|
+
throw new Error("[okffs] OKFFS_PROJECT_ID is not set — cannot talk to a GitHub Project board. " +
|
|
36
|
+
"Set it to the board's GraphQL node ID (e.g. PVT_kwHO...).");
|
|
37
|
+
}
|
|
38
|
+
return config.projectId;
|
|
39
|
+
}
|
|
40
|
+
let metadataCache = null;
|
|
41
|
+
// Discover the board's single-select fields and options once per process.
|
|
42
|
+
// The promise itself is cached so concurrent callers share one request; on
|
|
43
|
+
// failure the cache is cleared so a later call can retry.
|
|
44
|
+
export function getProjectMetadata() {
|
|
45
|
+
if (!metadataCache) {
|
|
46
|
+
metadataCache = fetchProjectMetadata().catch((err) => {
|
|
47
|
+
metadataCache = null;
|
|
48
|
+
throw err;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return metadataCache;
|
|
52
|
+
}
|
|
53
|
+
async function fetchProjectMetadata() {
|
|
54
|
+
const projectId = requireProjectId();
|
|
55
|
+
const data = await projectCall(() => graphqlRequest(`query($project:ID!){
|
|
56
|
+
node(id:$project){
|
|
57
|
+
... on ProjectV2 {
|
|
58
|
+
fields(first:100){
|
|
59
|
+
nodes{
|
|
60
|
+
... on ProjectV2SingleSelectField { id name options { id name } }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}`, { project: projectId }));
|
|
66
|
+
if (!data.node) {
|
|
67
|
+
throw new Error(`[okffs] Project ${projectId} not found (or not visible to this token). Check OKFFS_PROJECT_ID.`);
|
|
68
|
+
}
|
|
69
|
+
const meta = {
|
|
70
|
+
statusFieldId: null,
|
|
71
|
+
statusOptions: new Map(),
|
|
72
|
+
singleSelectByName: new Map(),
|
|
73
|
+
};
|
|
74
|
+
for (const field of data.node.fields.nodes) {
|
|
75
|
+
// Non-single-select fields come back as empty objects from the inline
|
|
76
|
+
// fragment — skip anything without a name and options.
|
|
77
|
+
if (!field.id || !field.name || !field.options)
|
|
78
|
+
continue;
|
|
79
|
+
const optionMap = new Map(field.options.map((o) => [o.name, o.id]));
|
|
80
|
+
const name = field.name.toLowerCase();
|
|
81
|
+
meta.singleSelectByName.set(name, { fieldId: field.id, options: optionMap });
|
|
82
|
+
if (name === "status") {
|
|
83
|
+
meta.statusFieldId = field.id;
|
|
84
|
+
meta.statusOptions = optionMap;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return meta;
|
|
88
|
+
}
|
|
89
|
+
// Add an issue (by its GraphQL node id) to the configured board. Returns the
|
|
90
|
+
// project *item* id — distinct from the issue node id, and required to set
|
|
91
|
+
// field values on the item.
|
|
92
|
+
export async function addIssueToProject(issueNodeId) {
|
|
93
|
+
const projectId = requireProjectId();
|
|
94
|
+
const data = await projectCall(() => graphqlRequest(`mutation($project:ID!,$content:ID!){
|
|
95
|
+
addProjectV2ItemById(input:{projectId:$project,contentId:$content}){ item{ id } }
|
|
96
|
+
}`, { project: projectId, content: issueNodeId }));
|
|
97
|
+
return data.addProjectV2ItemById.item.id;
|
|
98
|
+
}
|
|
99
|
+
// Set a single-select field (Status, Priority) on a project item.
|
|
100
|
+
export async function setProjectFieldValue(itemId, fieldId, optionId) {
|
|
101
|
+
const projectId = requireProjectId();
|
|
102
|
+
await projectCall(() => graphqlRequest(`mutation($project:ID!,$item:ID!,$field:ID!,$opt:String!){
|
|
103
|
+
updateProjectV2ItemFieldValue(input:{
|
|
104
|
+
projectId:$project,itemId:$item,fieldId:$field,
|
|
105
|
+
value:{ singleSelectOptionId:$opt }
|
|
106
|
+
}){ projectV2Item{ id } }
|
|
107
|
+
}`, { project: projectId, item: itemId, field: fieldId, opt: optionId }));
|
|
108
|
+
}
|
|
109
|
+
// --- Org-level Issue Fields (Phase 5.1, #91) -------------------------------
|
|
110
|
+
// GitHub's newer org-level "Issue Fields" (e.g. Priority, Effort) are NOT the
|
|
111
|
+
// same as a project-native single-select field: their options live under
|
|
112
|
+
// organization.issueFields, and values are written on the *issue* (not the
|
|
113
|
+
// project item) via setIssueFieldValue. On such boards the project single-select
|
|
114
|
+
// field reports empty options, which is the signal to fall back to this path.
|
|
115
|
+
//
|
|
116
|
+
// Access needs a different permission than Projects: a classic PAT with the
|
|
117
|
+
// `admin:org` scope works; fine-grained PATs currently get FORBIDDEN for this
|
|
118
|
+
// preview API. Translate that into an actionable message rather than the
|
|
119
|
+
// Projects-scope one.
|
|
120
|
+
async function orgFieldCall(fn) {
|
|
121
|
+
try {
|
|
122
|
+
return await fn();
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
126
|
+
if (/\b403\b|FORBIDDEN|not accessible/i.test(msg)) {
|
|
127
|
+
throw new Error("[okffs] GitHub denied access to org-level Issue Fields (organization.issueFields). " +
|
|
128
|
+
"This is a separate permission from Projects: a classic PAT with the `admin:org` scope works; " +
|
|
129
|
+
"fine-grained PATs currently return FORBIDDEN for this preview API. Use an org-capable GITHUB_TOKEN " +
|
|
130
|
+
"or set the field manually in the board UI. " +
|
|
131
|
+
`Original error: ${msg}`);
|
|
132
|
+
}
|
|
133
|
+
throw err;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Per-field-name cache so each org Issue Field (Priority, Effort, …) is fetched
|
|
137
|
+
// at most once per process. On failure the entry is cleared so a later call can
|
|
138
|
+
// retry.
|
|
139
|
+
const orgFieldCache = new Map();
|
|
140
|
+
// Discover an org single-select Issue Field by name (case-insensitive) and its
|
|
141
|
+
// options. Returns null if the owner isn't an org, has no such field, or it
|
|
142
|
+
// isn't a single-select. Throws (via orgFieldCall) on a permission error.
|
|
143
|
+
export function getOrgIssueField(name) {
|
|
144
|
+
const key = name.toLowerCase();
|
|
145
|
+
let cached = orgFieldCache.get(key);
|
|
146
|
+
if (!cached) {
|
|
147
|
+
cached = fetchOrgIssueField(key).catch((err) => {
|
|
148
|
+
orgFieldCache.delete(key);
|
|
149
|
+
throw err;
|
|
150
|
+
});
|
|
151
|
+
orgFieldCache.set(key, cached);
|
|
152
|
+
}
|
|
153
|
+
return cached;
|
|
154
|
+
}
|
|
155
|
+
async function fetchOrgIssueField(nameLower) {
|
|
156
|
+
const data = await orgFieldCall(() => graphqlRequest(`query($org:String!){
|
|
157
|
+
organization(login:$org){
|
|
158
|
+
issueFields(first:100){
|
|
159
|
+
nodes{
|
|
160
|
+
__typename
|
|
161
|
+
... on IssueFieldSingleSelect { id name options { id name } }
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}`, { org: owner }));
|
|
166
|
+
const nodes = data.organization?.issueFields?.nodes ?? [];
|
|
167
|
+
const match = nodes.find((n) => n.__typename === "IssueFieldSingleSelect" &&
|
|
168
|
+
(n.name ?? "").toLowerCase() === nameLower &&
|
|
169
|
+
n.id &&
|
|
170
|
+
n.options);
|
|
171
|
+
if (!match?.id || !match.options)
|
|
172
|
+
return null;
|
|
173
|
+
return {
|
|
174
|
+
fieldId: match.id,
|
|
175
|
+
options: new Map(match.options.map((o) => [o.name, o.id])),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
// Set an org Issue Field single-select value on an issue (by its node id).
|
|
179
|
+
export async function setIssueFieldSingleSelect(issueNodeId, fieldId, optionId) {
|
|
180
|
+
await orgFieldCall(() => graphqlRequest(`mutation($iss:ID!,$field:ID!,$opt:ID!){
|
|
181
|
+
setIssueFieldValue(input:{
|
|
182
|
+
issueId:$iss,
|
|
183
|
+
issueFields:[{ fieldId:$field, singleSelectOptionId:$opt }]
|
|
184
|
+
}){ issue{ number } }
|
|
185
|
+
}`, { iss: issueNodeId, field: fieldId, opt: optionId }));
|
|
186
|
+
}
|
|
187
|
+
// Find the project item id for an issue already on the board (null if absent).
|
|
188
|
+
export async function getProjectItemForIssue(issueNumber) {
|
|
189
|
+
const projectId = requireProjectId();
|
|
190
|
+
const data = await projectCall(() => graphqlRequest(`query($owner:String!,$repo:String!,$num:Int!){
|
|
191
|
+
repository(owner:$owner,name:$repo){
|
|
192
|
+
issue(number:$num){
|
|
193
|
+
projectItems(first:20){ nodes{ id project{ id } } }
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}`, { owner, repo, num: issueNumber }));
|
|
197
|
+
const nodes = data.repository?.issue?.projectItems.nodes ?? [];
|
|
198
|
+
return nodes.find((n) => n.project.id === projectId)?.id ?? null;
|
|
199
|
+
}
|
|
200
|
+
// Map of issue number → its board Status + project-native Priority/Effort, for
|
|
201
|
+
// list_issues enrichment. Capped at the first 100 board items (matches
|
|
202
|
+
// list_issues' own page size).
|
|
203
|
+
export async function getProjectFieldsByIssueNumber() {
|
|
204
|
+
const projectId = requireProjectId();
|
|
205
|
+
const data = await projectCall(() => graphqlRequest(`query($project:ID!){
|
|
206
|
+
node(id:$project){
|
|
207
|
+
... on ProjectV2 {
|
|
208
|
+
items(first:100){
|
|
209
|
+
nodes{
|
|
210
|
+
content{ ... on Issue { number } }
|
|
211
|
+
status:fieldValueByName(name:"Status"){
|
|
212
|
+
... on ProjectV2ItemFieldSingleSelectValue { name }
|
|
213
|
+
}
|
|
214
|
+
priority:fieldValueByName(name:"Priority"){
|
|
215
|
+
... on ProjectV2ItemFieldSingleSelectValue { name }
|
|
216
|
+
}
|
|
217
|
+
effort:fieldValueByName(name:"Effort"){
|
|
218
|
+
... on ProjectV2ItemFieldSingleSelectValue { name }
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}`, { project: projectId }));
|
|
225
|
+
const result = new Map();
|
|
226
|
+
for (const item of data.node?.items.nodes ?? []) {
|
|
227
|
+
const number = item.content?.number;
|
|
228
|
+
if (number == null)
|
|
229
|
+
continue;
|
|
230
|
+
const fields = {};
|
|
231
|
+
if (item.status?.name)
|
|
232
|
+
fields.status = item.status.name;
|
|
233
|
+
if (item.priority?.name)
|
|
234
|
+
fields.priority = item.priority.name;
|
|
235
|
+
if (item.effort?.name)
|
|
236
|
+
fields.effort = item.effort.name;
|
|
237
|
+
if (fields.status || fields.priority || fields.effort)
|
|
238
|
+
result.set(number, fields);
|
|
239
|
+
}
|
|
240
|
+
return result;
|
|
241
|
+
}
|
|
242
|
+
// Map of issue number → its org-level Issue Field single-select values, keyed by
|
|
243
|
+
// lowercased field name (e.g. "priority" → "High", "effort" → "Medium"). For
|
|
244
|
+
// boards whose Priority/Effort are org Issue Fields (not project-native fields —
|
|
245
|
+
// those aren't readable off the project item). One batched query over open
|
|
246
|
+
// issues. Needs the org-field permission, so callers gate this on
|
|
247
|
+
// OKFFS_CLASSIC_PAT. Throws (via orgFieldCall) on a permission error; list_issues
|
|
248
|
+
// treats that as non-fatal.
|
|
249
|
+
export async function getOrgIssueFieldValuesByNumber() {
|
|
250
|
+
const data = await orgFieldCall(() => graphqlRequest(`query($owner:String!,$repo:String!){
|
|
251
|
+
repository(owner:$owner,name:$repo){
|
|
252
|
+
issues(first:100,states:OPEN){
|
|
253
|
+
nodes{
|
|
254
|
+
number
|
|
255
|
+
issueFieldValues(first:50){
|
|
256
|
+
nodes{
|
|
257
|
+
__typename
|
|
258
|
+
... on IssueFieldSingleSelectValue {
|
|
259
|
+
name
|
|
260
|
+
field{ ... on IssueFieldSingleSelect { name } }
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}`, { owner, repo }));
|
|
268
|
+
const result = new Map();
|
|
269
|
+
for (const issue of data.repository?.issues.nodes ?? []) {
|
|
270
|
+
const values = new Map();
|
|
271
|
+
for (const v of issue.issueFieldValues.nodes) {
|
|
272
|
+
const fname = v.field?.name;
|
|
273
|
+
if (fname && v.name)
|
|
274
|
+
values.set(fname.toLowerCase(), v.name);
|
|
275
|
+
}
|
|
276
|
+
if (values.size)
|
|
277
|
+
result.set(issue.number, values);
|
|
278
|
+
}
|
|
279
|
+
return result;
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../src/projects.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export declare const name = "create_issue";
|
|
3
|
-
export declare const description
|
|
3
|
+
export declare const description: string;
|
|
4
4
|
export declare const inputSchema: z.ZodObject<{
|
|
5
5
|
title: z.ZodString;
|
|
6
6
|
description: z.ZodString;
|
|
7
7
|
assignees: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
8
8
|
labels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
9
9
|
milestone: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
priority: z.ZodOptional<z.ZodString>;
|
|
11
|
+
effort: z.ZodOptional<z.ZodString>;
|
|
10
12
|
}, "strip", z.ZodTypeAny, {
|
|
11
13
|
title: string;
|
|
12
14
|
description: string;
|
|
13
15
|
assignees?: string[] | undefined;
|
|
14
16
|
labels?: string[] | undefined;
|
|
15
17
|
milestone?: number | undefined;
|
|
18
|
+
priority?: string | undefined;
|
|
19
|
+
effort?: string | undefined;
|
|
16
20
|
}, {
|
|
17
21
|
title: string;
|
|
18
22
|
description: string;
|
|
19
23
|
assignees?: string[] | undefined;
|
|
20
24
|
labels?: string[] | undefined;
|
|
21
25
|
milestone?: number | undefined;
|
|
26
|
+
priority?: string | undefined;
|
|
27
|
+
effort?: string | undefined;
|
|
22
28
|
}>;
|
|
23
29
|
export declare function handler(input: z.infer<typeof inputSchema>): Promise<{
|
|
24
30
|
content: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create_issue.d.ts","sourceRoot":"","sources":["../../src/tools/create_issue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"create_issue.d.ts","sourceRoot":"","sources":["../../src/tools/create_issue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA8DxB,eAAO,MAAM,IAAI,iBAAiB,CAAC;AAyBnC,eAAO,MAAM,WAAW,QAGiM,CAAC;AAE1N,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;EAYtB,CAAC;AAEH,wBAAsB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC;;;;;GAwL/D"}
|
|
@@ -2,20 +2,93 @@ import { z } from "zod";
|
|
|
2
2
|
import { createIssue, updateIssueBody, getDefaultBranch, getRef, createBranch, buildBranchName, createDraftPullRequest } from "../github.js";
|
|
3
3
|
import { config } from "../config.js";
|
|
4
4
|
import { git, currentBranch } from "../git.js";
|
|
5
|
+
import { addIssueToProject, getProjectMetadata, setProjectFieldValue, getOrgIssueField, setIssueFieldSingleSelect } from "../projects.js";
|
|
6
|
+
// Set a board single-select field (Priority, Effort, …) to `value`. Handles both
|
|
7
|
+
// shapes: a project-native single-select (set on the project item), and a GitHub
|
|
8
|
+
// org-level Issue Field (project field reports no options → set on the issue via
|
|
9
|
+
// setIssueFieldValue, gated on OKFFS_CLASSIC_PAT — #91). Non-fatal: warns and
|
|
10
|
+
// returns null on any miss. Returns the applied value on success.
|
|
11
|
+
async function applyBoardSingleSelect(label, value, itemId, issueNodeId, meta) {
|
|
12
|
+
const native = meta.singleSelectByName.get(label.toLowerCase());
|
|
13
|
+
if (!native) {
|
|
14
|
+
console.warn(`[okffs] ${label} "${value}" not set: the board has no ${label} field.`);
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
// Project-native single-select with resolvable options.
|
|
18
|
+
if (native.options.size > 0) {
|
|
19
|
+
const optionId = native.options.get(value);
|
|
20
|
+
if (optionId) {
|
|
21
|
+
await setProjectFieldValue(itemId, native.fieldId, optionId);
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
console.warn(`[okffs] ${label} "${value}" not set — no matching option. Board ${label} options: ${[...native.options.keys()].join(", ")}.`);
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
// No options via the project API → it's a GitHub org-level Issue Field.
|
|
28
|
+
if (!config.classicPat) {
|
|
29
|
+
console.warn(`[okffs] ${label} "${value}" not set: the board's ${label} is an org-level Issue Field, ` +
|
|
30
|
+
`which okffs can only set with a classic PAT (\`admin:org\`) and OKFFS_CLASSIC_PAT=true (security tradeoff — see docs). ` +
|
|
31
|
+
`Set it manually in the board UI for now.`);
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const orgField = await getOrgIssueField(label);
|
|
36
|
+
if (!orgField) {
|
|
37
|
+
console.warn(`[okffs] ${label} "${value}" not set: no org-level ${label} Issue Field found.`);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const orgOptionId = orgField.options.get(value);
|
|
41
|
+
if (!orgOptionId) {
|
|
42
|
+
console.warn(`[okffs] ${label} "${value}" not set — no matching org Issue Field option. Options: ${[...orgField.options.keys()].join(", ")}.`);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
await setIssueFieldSingleSelect(issueNodeId, orgField.fieldId, orgOptionId);
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
// Permission (fine-grained PAT FORBIDDEN) / preview-API errors — never fatal.
|
|
50
|
+
console.warn(`[okffs] ${label} not set via org Issue Field:`, err instanceof Error ? err.message : err);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
5
54
|
export const name = "create_issue";
|
|
6
|
-
|
|
55
|
+
// Priority/Effort inference guidance is woven into the tool description so Claude
|
|
56
|
+
// uses its own judgement to triage the issue it's creating (like it already does
|
|
57
|
+
// for labels), falling back to OKFFS_DEFAULT_* only when it can't tell. Toggle per
|
|
58
|
+
// field with OKFFS_INFER_PRIORITY / OKFFS_INFER_EFFORT (default on).
|
|
59
|
+
function inferenceGuidance() {
|
|
60
|
+
const bits = [];
|
|
61
|
+
if (config.inferPriority) {
|
|
62
|
+
bits.push("infer a `priority` for the issue from its urgency and impact (typical scale: Urgent, High, Medium, Low)");
|
|
63
|
+
}
|
|
64
|
+
if (config.inferEffort) {
|
|
65
|
+
bits.push("infer an `effort` from the expected amount of work (typical scale: High, Medium, Low)");
|
|
66
|
+
}
|
|
67
|
+
if (bits.length === 0)
|
|
68
|
+
return "";
|
|
69
|
+
return (` Also ${bits.join(" and ")}, passing the value(s) in the matching parameter. ` +
|
|
70
|
+
"okffs matches these against the board's actual options and falls back to OKFFS_DEFAULT_PRIORITY / OKFFS_DEFAULT_EFFORT when you omit them — so if you genuinely can't judge, omit the field rather than guessing.");
|
|
71
|
+
}
|
|
72
|
+
export const description = "Create a GitHub issue and automatically create a matching branch. Before calling this tool, infer appropriate labels from the issue title and description using GitHub's default labels: bug, documentation, duplicate, enhancement, good first issue, help wanted, invalid, question, wontfix. Pass the inferred labels in the labels parameter unless the user has specified their own." +
|
|
73
|
+
inferenceGuidance() +
|
|
74
|
+
" If the user mentions that this issue is blocked by, blocking, or a child of another issue, call link_issues after creating this issue to set the relationship. Returns the issue URL, issue number, and branch name.";
|
|
7
75
|
export const inputSchema = z.object({
|
|
8
76
|
title: z.string().describe("Issue title"),
|
|
9
77
|
description: z.string().describe("Issue body / description"),
|
|
10
78
|
assignees: z.array(z.string()).optional().describe("GitHub usernames to assign"),
|
|
11
79
|
labels: z.array(z.string()).optional().describe("Labels to apply e.g. bug, feature"),
|
|
12
80
|
milestone: z.number().int().optional().describe("Milestone number to assign"),
|
|
81
|
+
priority: z.string().optional().describe("Optional Project board Priority (e.g. Urgent, High, Medium, Low) — matched against the board's Priority options (project-native field, or a GitHub org Issue Field when OKFFS_CLASSIC_PAT is set). Only applied when OKFFS_PROJECT_AUTO_ADD=true and a Priority field exists. If omitted, OKFFS_DEFAULT_PRIORITY is used when set."),
|
|
82
|
+
effort: z.string().optional().describe("Optional Project board Effort (e.g. High, Medium, Low) — matched against the board's Effort options (project-native field, or a GitHub org Issue Field when OKFFS_CLASSIC_PAT is set). Only applied when OKFFS_PROJECT_AUTO_ADD=true and an Effort field exists. If omitted, OKFFS_DEFAULT_EFFORT is used when set."),
|
|
13
83
|
});
|
|
14
84
|
export async function handler(input) {
|
|
15
85
|
const resolvedAssignees = input.assignees ?? config.defaultAssignees;
|
|
16
86
|
const resolvedLabels = [
|
|
17
87
|
...new Set([...(input.labels ?? []), ...config.defaultLabels])
|
|
18
88
|
];
|
|
89
|
+
// Fall back to OKFFS_DEFAULT_PRIORITY / OKFFS_DEFAULT_EFFORT when not given.
|
|
90
|
+
const resolvedPriority = input.priority ?? config.defaultPriority;
|
|
91
|
+
const resolvedEffort = input.effort ?? config.defaultEffort;
|
|
19
92
|
const issue = await createIssue(input.title, input.description, resolvedAssignees, resolvedLabels, input.milestone);
|
|
20
93
|
const branchName = buildBranchName(issue.number, input.title);
|
|
21
94
|
const defaultBranch = await getDefaultBranch();
|
|
@@ -23,6 +96,36 @@ export async function handler(input) {
|
|
|
23
96
|
await createBranch(branchName, ref.object.sha);
|
|
24
97
|
const updatedBody = `${input.description}\n\n**Branch:** \`${branchName}\``;
|
|
25
98
|
await updateIssueBody(issue.number, updatedBody);
|
|
99
|
+
// Add the issue to the configured Project board (fallback for users without
|
|
100
|
+
// native board automation). Non-fatal, mirroring the autoPR block below: any
|
|
101
|
+
// failure warns with an [okffs] prefix and never blocks issue creation.
|
|
102
|
+
let addedToBoard = false;
|
|
103
|
+
let priorityApplied = null;
|
|
104
|
+
let effortApplied = null;
|
|
105
|
+
let boardError = null;
|
|
106
|
+
let boardItemId = null;
|
|
107
|
+
if (config.projectAutoAdd && config.projectEnabled) {
|
|
108
|
+
try {
|
|
109
|
+
const itemId = await addIssueToProject(issue.node_id);
|
|
110
|
+
boardItemId = itemId;
|
|
111
|
+
addedToBoard = true;
|
|
112
|
+
// Priority and Effort are set the same way — project-native single-select,
|
|
113
|
+
// or a GitHub org-level Issue Field when OKFFS_CLASSIC_PAT is on (#91).
|
|
114
|
+
if (resolvedPriority || resolvedEffort) {
|
|
115
|
+
const meta = await getProjectMetadata();
|
|
116
|
+
if (resolvedPriority) {
|
|
117
|
+
priorityApplied = await applyBoardSingleSelect("Priority", resolvedPriority, itemId, issue.node_id, meta);
|
|
118
|
+
}
|
|
119
|
+
if (resolvedEffort) {
|
|
120
|
+
effortApplied = await applyBoardSingleSelect("Effort", resolvedEffort, itemId, issue.node_id, meta);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
boardError = err instanceof Error ? err.message : String(err);
|
|
126
|
+
console.warn("[okffs] Failed to add issue to project board:", boardError);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
26
129
|
let draftPRUrl = null;
|
|
27
130
|
if (config.autoPR) {
|
|
28
131
|
// Push an empty init commit so the branch diverges from base, allowing
|
|
@@ -56,6 +159,35 @@ export async function handler(input) {
|
|
|
56
159
|
console.warn("[okffs] Failed to create draft PR:", err instanceof Error ? err.message : err);
|
|
57
160
|
}
|
|
58
161
|
}
|
|
162
|
+
// Pin the board Status to the configured initial column (e.g. Backlog). This
|
|
163
|
+
// runs LAST — after the draft PR is created — on purpose: the PR's `Closes #N`
|
|
164
|
+
// link fires GitHub's "PR linked to issue" workflow, which flips a scaffolded
|
|
165
|
+
// issue to "In Progress". Setting our intended status here lets it win that
|
|
166
|
+
// race so freshly-created issues land where okffs means them to (#103).
|
|
167
|
+
// Non-fatal, like the rest of the board handling.
|
|
168
|
+
let initialStatusApplied = null;
|
|
169
|
+
if (config.projectInitialStatus && boardItemId) {
|
|
170
|
+
try {
|
|
171
|
+
const meta = await getProjectMetadata();
|
|
172
|
+
const optionId = meta.statusFieldId
|
|
173
|
+
? meta.statusOptions.get(config.projectInitialStatus)
|
|
174
|
+
: undefined;
|
|
175
|
+
if (meta.statusFieldId && optionId) {
|
|
176
|
+
await setProjectFieldValue(boardItemId, meta.statusFieldId, optionId);
|
|
177
|
+
initialStatusApplied = config.projectInitialStatus;
|
|
178
|
+
}
|
|
179
|
+
else if (!meta.statusFieldId) {
|
|
180
|
+
console.warn(`[okffs] OKFFS_PROJECT_INITIAL_STATUS set but the board has no Status field.`);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
const opts = [...meta.statusOptions.keys()].join(", ");
|
|
184
|
+
console.warn(`[okffs] OKFFS_PROJECT_INITIAL_STATUS "${config.projectInitialStatus}" doesn't match a board Status option. Options: ${opts}.`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
console.warn("[okffs] Failed to set initial board status:", err instanceof Error ? err.message : err);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
59
191
|
const lines = [
|
|
60
192
|
`Issue #${issue.number} created: ${issue.html_url}`,
|
|
61
193
|
`Branch: \`${branchName}\``,
|
|
@@ -71,7 +203,28 @@ export async function handler(input) {
|
|
|
71
203
|
const source = input.labels ? "" : " (default)";
|
|
72
204
|
lines.push(`Labels: ${resolvedLabels.join(", ")}${source}`);
|
|
73
205
|
}
|
|
206
|
+
if (addedToBoard) {
|
|
207
|
+
const bits = [
|
|
208
|
+
priorityApplied ? `priority: ${priorityApplied}` : null,
|
|
209
|
+
effortApplied ? `effort: ${effortApplied}` : null,
|
|
210
|
+
initialStatusApplied ? `status: ${initialStatusApplied}` : null,
|
|
211
|
+
].filter(Boolean);
|
|
212
|
+
lines.push(`Board: added to the project${bits.length ? ` (${bits.join(", ")})` : ""}`);
|
|
213
|
+
}
|
|
214
|
+
else if (boardError) {
|
|
215
|
+
// Auto-add was enabled but failed. Surface it here (not just the server log)
|
|
216
|
+
// so it isn't invisible — the issue was still created successfully, which
|
|
217
|
+
// otherwise makes an empty board look like it worked. See #101.
|
|
218
|
+
lines.push(`Board: NOT added — auto-add is on but failed. The issue itself was created fine.`, ` ${boardError}`);
|
|
219
|
+
}
|
|
74
220
|
lines.push(``, `To start work:`, ` git fetch origin`, ` git checkout ${branchName}`);
|
|
221
|
+
// Conversational nudge: prompt the host LLM to offer moving the issue into
|
|
222
|
+
// the "In Progress" column via update_project_status once work begins.
|
|
223
|
+
if (addedToBoard) {
|
|
224
|
+
const where = initialStatusApplied ? `"${initialStatusApplied}"` : "its default column";
|
|
225
|
+
lines.push(``, `This issue is on the board in ${where}. Want me to move it to "In Progress" and start? ` +
|
|
226
|
+
`(I can call update_project_status for #${issue.number}.)`);
|
|
227
|
+
}
|
|
75
228
|
if (config.promptForMetadata && !input.assignees && !input.labels) {
|
|
76
229
|
lines.push(``, `Tip: You can include assignees and labels next time:`, ` assignees: ["your-github-username"]`, ` labels: ["feature", "bug"]`, `Or set OKFFS_PROMPT_METADATA=false in .env to hide this tip.`);
|
|
77
230
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create_issue.js","sourceRoot":"","sources":["../../src/tools/create_issue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,EAAE,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC7I,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"create_issue.js","sourceRoot":"","sources":["../../src/tools/create_issue.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export declare const name = "create_pull_request";
|
|
3
|
-
export declare const description = "Create a pull request for the current issue branch. Reads the issue, its comments, and commits to generate a PR title and body. Always includes Closes #N. If OKFFS_UPDATE_DOCS is true,
|
|
3
|
+
export declare const description = "Create a pull request for the current issue branch. Reads the issue, its comments, and commits to generate a PR title and body. Always includes Closes #N. If OKFFS_UPDATE_DOCS is true, writes a per-issue changelog fragment under .changes/unreleased/ (assembled into CHANGELOG.md at release time by prepare_release \u2014 not a direct CHANGELOG.md edit), plus SECURITY.md for security-related changes, and commits them onto the branch before creating the PR. If a PR already exists for the branch (e.g. a draft opened by create_issue under OKFFS_AUTO_PR=true), it is updated and marked ready for review instead of erroring. Posts a summary comment to the issue.";
|
|
4
4
|
export declare const inputSchema: z.ZodObject<{
|
|
5
5
|
issue_number: z.ZodNumber;
|
|
6
6
|
summary: z.ZodOptional<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create_pull_request.d.ts","sourceRoot":"","sources":["../../src/tools/create_pull_request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAkBxB,eAAO,MAAM,IAAI,wBAAwB,CAAC;AAE1C,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"create_pull_request.d.ts","sourceRoot":"","sources":["../../src/tools/create_pull_request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAkBxB,eAAO,MAAM,IAAI,wBAAwB,CAAC;AAE1C,eAAO,MAAM,WAAW,ypBAC2nB,CAAC;AAEppB,eAAO,MAAM,WAAW;;;;;;;;;EAGtB,CAAC;AAEH,wBAAsB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC;;;;;GAkM/D"}
|
|
@@ -4,7 +4,7 @@ import { config } from "../config.js";
|
|
|
4
4
|
import { updateProjectDocs } from "../docs.js";
|
|
5
5
|
import { git, currentBranch } from "../git.js";
|
|
6
6
|
export const name = "create_pull_request";
|
|
7
|
-
export const description = "Create a pull request for the current issue branch. Reads the issue, its comments, and commits to generate a PR title and body. Always includes Closes #N. If OKFFS_UPDATE_DOCS is true,
|
|
7
|
+
export const description = "Create a pull request for the current issue branch. Reads the issue, its comments, and commits to generate a PR title and body. Always includes Closes #N. If OKFFS_UPDATE_DOCS is true, writes a per-issue changelog fragment under .changes/unreleased/ (assembled into CHANGELOG.md at release time by prepare_release — not a direct CHANGELOG.md edit), plus SECURITY.md for security-related changes, and commits them onto the branch before creating the PR. If a PR already exists for the branch (e.g. a draft opened by create_issue under OKFFS_AUTO_PR=true), it is updated and marked ready for review instead of erroring. Posts a summary comment to the issue.";
|
|
8
8
|
export const inputSchema = z.object({
|
|
9
9
|
issue_number: z.number().int().positive().describe("The issue number to create a PR for"),
|
|
10
10
|
summary: z.string().optional().describe("Optional summary of what was done — used in PR body and issue comment"),
|