@neturely/okffs 0.4.0 → 0.5.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/dist/board.js ADDED
@@ -0,0 +1,171 @@
1
+ // Shared GitHub Projects v2 board placement for issue-creating tools
2
+ // (create_issue, create_issues_from_list, plan). Centralises: adding an issue to
3
+ // the board, setting Priority/Effort (project-native single-select OR org-level
4
+ // Issue Field — #91), applying the initial Status, and rendering the outcome.
5
+ //
6
+ // Every skip/failure is returned as data and surfaced in the tool response, never
7
+ // only console.warn'd to stderr (which the host/user never sees) — #146. The add
8
+ // itself throwing is the one fatal-to-board case; callers catch it into
9
+ // `boardError`. Field writes are always non-fatal.
10
+ import { config } from "./config.js";
11
+ import { addIssueToProject, getProjectMetadata, setProjectFieldValue, getOrgIssueField, setIssueFieldSingleSelect, } from "./projects.js";
12
+ // Whether create_* tools should attempt board auto-add at all.
13
+ export function boardAutoAddEnabled() {
14
+ return Boolean(config.projectAutoAdd && config.projectEnabled);
15
+ }
16
+ // The board's real option names for a single-select field (e.g. "Priority") —
17
+ // project-native options if present, otherwise the org-level Issue Field options
18
+ // (only readable with a classic PAT). Returns null when the board is unreachable,
19
+ // the field is absent, or its options can't be read — callers then fall back to a
20
+ // generic scale. Cheap after the first call (metadata + org field are memoized).
21
+ // Used to inject real options into create_issue's inference guidance (#133).
22
+ export async function getBoardFieldOptions(label) {
23
+ try {
24
+ const meta = await getProjectMetadata();
25
+ const native = meta.singleSelectByName.get(label.toLowerCase());
26
+ if (native && native.options.size > 0)
27
+ return [...native.options.keys()];
28
+ // No project-native options → it's an org-level Issue Field, readable only
29
+ // with a classic admin:org PAT (#91). Skip otherwise.
30
+ if (config.classicPat) {
31
+ const orgField = await getOrgIssueField(label);
32
+ if (orgField && orgField.options.size > 0)
33
+ return [...orgField.options.keys()];
34
+ }
35
+ return null;
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ // Set a board single-select field (Priority, Effort, …) to `value`. Handles both
42
+ // shapes: a project-native single-select (set on the project item), and a GitHub
43
+ // org-level Issue Field (project field reports no options → set on the issue via
44
+ // setIssueFieldSingleSelect, gated on OKFFS_CLASSIC_PAT — #91). Returns
45
+ // { skipped: reason } on any miss and { applied } on success; also warns to
46
+ // stderr for server logs, but the returned reason is what the caller surfaces.
47
+ async function applyBoardSingleSelect(label, value, itemId, issueNodeId, meta) {
48
+ const skip = (reason) => {
49
+ console.warn(`[okffs] ${label} "${value}" not set: ${reason}`);
50
+ return { skipped: reason };
51
+ };
52
+ const native = meta.singleSelectByName.get(label.toLowerCase());
53
+ if (!native) {
54
+ return skip(`the board has no ${label} field.`);
55
+ }
56
+ // Project-native single-select with resolvable options.
57
+ if (native.options.size > 0) {
58
+ const optionId = native.options.get(value);
59
+ if (!optionId) {
60
+ return skip(`no matching option. Board ${label} options: ${[...native.options.keys()].join(", ")}.`);
61
+ }
62
+ // Catch write failures here too — addIssueToBoard's contract is that field
63
+ // writes never throw, so a failed set must degrade to a surfaced skip rather
64
+ // than turning a successful board add into a full boardError.
65
+ try {
66
+ await setProjectFieldValue(itemId, native.fieldId, optionId);
67
+ return { applied: value };
68
+ }
69
+ catch (err) {
70
+ return skip(`write failed — ${err instanceof Error ? err.message : String(err)}`);
71
+ }
72
+ }
73
+ // No options via the project API → it's a GitHub org-level Issue Field.
74
+ if (!config.classicPat) {
75
+ return skip(`the board's ${label} is an org-level Issue Field, which okffs can only set with a classic ` +
76
+ `PAT (\`admin:org\`) and OKFFS_CLASSIC_PAT=true (security tradeoff — see docs). Set it in the board UI for now.`);
77
+ }
78
+ try {
79
+ const orgField = await getOrgIssueField(label);
80
+ if (!orgField) {
81
+ return skip(`no org-level ${label} Issue Field found.`);
82
+ }
83
+ const orgOptionId = orgField.options.get(value);
84
+ if (!orgOptionId) {
85
+ return skip(`no matching org Issue Field option. Options: ${[...orgField.options.keys()].join(", ")}.`);
86
+ }
87
+ await setIssueFieldSingleSelect(issueNodeId, orgField.fieldId, orgOptionId);
88
+ return { applied: value };
89
+ }
90
+ catch (err) {
91
+ // Permission (fine-grained PAT FORBIDDEN) / preview-API errors — never fatal.
92
+ return skip(`org Issue Field write failed — ${err instanceof Error ? err.message : String(err)}`);
93
+ }
94
+ }
95
+ // Add an issue to the configured board and set Priority/Effort. Throws if the add
96
+ // itself fails (caller catches into boardError). Field writes never throw. Does
97
+ // NOT set the initial Status — that must run after any draft PR (see
98
+ // applyInitialStatus) so it wins GitHub's linked-PR "In Progress" promotion (#103).
99
+ export async function addIssueToBoard(issueNodeId, opts) {
100
+ const itemId = await addIssueToProject(issueNodeId);
101
+ let priority = null;
102
+ let effort = null;
103
+ if (opts.priority || opts.effort) {
104
+ const meta = await getProjectMetadata();
105
+ if (opts.priority) {
106
+ priority = await applyBoardSingleSelect("Priority", opts.priority, itemId, issueNodeId, meta);
107
+ }
108
+ if (opts.effort) {
109
+ effort = await applyBoardSingleSelect("Effort", opts.effort, itemId, issueNodeId, meta);
110
+ }
111
+ }
112
+ return { itemId, priority, effort };
113
+ }
114
+ // Pin the board Status to OKFFS_PROJECT_INITIAL_STATUS for a freshly-added item.
115
+ // No-op (returns nulls) when the env var is unset. Non-fatal: any miss is returned
116
+ // as `skipped` and warned to stderr. Call AFTER the draft PR so it wins the race
117
+ // with GitHub's linked-PR automation (#103).
118
+ export async function applyInitialStatus(itemId) {
119
+ if (!config.projectInitialStatus)
120
+ return { applied: null, skipped: null };
121
+ const wanted = config.projectInitialStatus;
122
+ try {
123
+ const meta = await getProjectMetadata();
124
+ const optionId = meta.statusFieldId ? meta.statusOptions.get(wanted) : undefined;
125
+ if (meta.statusFieldId && optionId) {
126
+ await setProjectFieldValue(itemId, meta.statusFieldId, optionId);
127
+ return { applied: wanted, skipped: null };
128
+ }
129
+ const skipped = !meta.statusFieldId
130
+ ? "the board has no Status field."
131
+ : `no matching Status option. Board Status options: ${[...meta.statusOptions.keys()].join(", ")}.`;
132
+ console.warn(`[okffs] initial status "${wanted}" not set: ${skipped}`);
133
+ return { applied: null, skipped };
134
+ }
135
+ catch (err) {
136
+ const skipped = `Status write failed — ${err instanceof Error ? err.message : String(err)}`;
137
+ console.warn(`[okffs] initial status "${wanted}" not set: ${skipped}`);
138
+ return { applied: null, skipped };
139
+ }
140
+ }
141
+ // Render board outcome lines for a tool response — shared by all three creators so
142
+ // applied fields and every skip read identically. `indent` prefixes each line
143
+ // (batch tools nest board lines under their per-issue entry).
144
+ export function renderBoardLines(args) {
145
+ const ind = args.indent ?? "";
146
+ const lines = [];
147
+ if (args.addedToBoard) {
148
+ const bits = [
149
+ args.priority && "applied" in args.priority ? `priority: ${args.priority.applied}` : null,
150
+ args.effort && "applied" in args.effort ? `effort: ${args.effort.applied}` : null,
151
+ args.initialStatus?.applied ? `status: ${args.initialStatus.applied}` : null,
152
+ ].filter(Boolean);
153
+ lines.push(`${ind}Board: added to the project${bits.length ? ` (${bits.join(", ")})` : ""}`);
154
+ // Surface any requested-but-not-applied field so an enabled board step is
155
+ // never silently dropped (the issue is still created fine) — see #146.
156
+ const skips = [
157
+ args.priority && "skipped" in args.priority ? `Priority "${args.requestedPriority}" not set — ${args.priority.skipped}` : null,
158
+ args.effort && "skipped" in args.effort ? `Effort "${args.requestedEffort}" not set — ${args.effort.skipped}` : null,
159
+ args.initialStatus?.skipped ? `Initial status "${args.requestedStatus}" not set — ${args.initialStatus.skipped}` : null,
160
+ ].filter(Boolean);
161
+ for (const s of skips)
162
+ lines.push(`${ind} ⚠ ${s}`);
163
+ }
164
+ else if (args.boardError) {
165
+ // Auto-add was enabled but the add itself failed. Surface it (not just the
166
+ // server log) so an empty board doesn't look like success — see #101.
167
+ lines.push(`${ind}Board: NOT added — auto-add is on but failed. The issue itself was created fine.`, `${ind} ${args.boardError}`);
168
+ }
169
+ return lines;
170
+ }
171
+ //# sourceMappingURL=board.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board.js","sourceRoot":"","sources":["../src/board.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -31,10 +31,25 @@ const prompts = [addressPrReview, updateGuidance];
31
31
  const version = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
32
32
  const server = new Server({ name: "okffs", version }, { capabilities: { tools: {}, prompts: {} } });
33
33
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
34
- tools: tools.map((t) => ({
35
- name: t.name,
36
- description: t.description,
37
- inputSchema: zodToJsonSchema(t.inputSchema),
34
+ // A tool may export an async getDescription() to compute its description at
35
+ // list time (e.g. create_issue injects the board's real Priority/Effort options
36
+ // — #133). Fall back to the static description on absence or failure.
37
+ tools: await Promise.all(tools.map(async (t) => {
38
+ let description = t.description;
39
+ const getDescription = t.getDescription;
40
+ if (getDescription) {
41
+ try {
42
+ description = await getDescription();
43
+ }
44
+ catch (err) {
45
+ console.warn(`[okffs] getDescription() failed for ${t.name}, using static description:`, err instanceof Error ? err.message : err);
46
+ }
47
+ }
48
+ return {
49
+ name: t.name,
50
+ description,
51
+ inputSchema: zodToJsonSchema(t.inputSchema),
52
+ };
38
53
  })),
39
54
  }));
40
55
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1 +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"}
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;AAqDD,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 CHANGED
@@ -117,21 +117,39 @@ export async function setProjectFieldValue(itemId, fieldId, optionId) {
117
117
  // `admin:org` scope works; fine-grained PATs currently get FORBIDDEN for this
118
118
  // preview API. Translate that into an actionable message rather than the
119
119
  // Projects-scope one.
120
+ // The org-level Issue Fields API is a GitHub preview and is noticeably flaky —
121
+ // transient 5xx / timeouts / secondary-rate blips are common. Retry those a
122
+ // couple of times with a short backoff (#137). Permission errors (403/FORBIDDEN)
123
+ // are deterministic, so they are translated and thrown immediately, never retried.
124
+ const ORG_FIELD_MAX_ATTEMPTS = 3;
125
+ const ORG_FIELD_RETRY_BASE_MS = 300;
126
+ function isOrgFieldPermissionError(msg) {
127
+ return /\b403\b|FORBIDDEN|not accessible/i.test(msg);
128
+ }
120
129
  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}`);
130
+ let lastErr;
131
+ for (let attempt = 1; attempt <= ORG_FIELD_MAX_ATTEMPTS; attempt++) {
132
+ try {
133
+ return await fn();
134
+ }
135
+ catch (err) {
136
+ const msg = err instanceof Error ? err.message : String(err);
137
+ if (isOrgFieldPermissionError(msg)) {
138
+ throw new Error("[okffs] GitHub denied access to org-level Issue Fields (organization.issueFields). " +
139
+ "This is a separate permission from Projects: a classic PAT with the `admin:org` scope works; " +
140
+ "fine-grained PATs currently return FORBIDDEN for this preview API. Use an org-capable GITHUB_TOKEN " +
141
+ "or set the field manually in the board UI. " +
142
+ `Original error: ${msg}`);
143
+ }
144
+ lastErr = err;
145
+ if (attempt < ORG_FIELD_MAX_ATTEMPTS) {
146
+ console.warn(`[okffs] org Issue Fields API call failed (attempt ${attempt}/${ORG_FIELD_MAX_ATTEMPTS}), retrying: ${msg}`);
147
+ await new Promise((resolve) => setTimeout(resolve, ORG_FIELD_RETRY_BASE_MS * attempt));
148
+ }
132
149
  }
133
- throw err;
134
150
  }
151
+ // Normalize to an Error so callers' `err instanceof Error` handling is reliable.
152
+ throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
135
153
  }
136
154
  // Per-field-name cache so each org Issue Field (Priority, Effort, …) is fetched
137
155
  // at most once per process. On failure the entry is cleared so a later call can
@@ -1 +1 @@
1
- {"version":3,"file":"projects.js","sourceRoot":"","sources":["../src/projects.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../src/projects.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  export declare const name = "create_issue";
3
3
  export declare const description: string;
4
+ export declare function getDescription(): Promise<string>;
4
5
  export declare const inputSchema: z.ZodObject<{
5
6
  title: z.ZodString;
6
7
  description: z.ZodString;
@@ -12,19 +13,19 @@ export declare const inputSchema: z.ZodObject<{
12
13
  }, "strip", z.ZodTypeAny, {
13
14
  title: string;
14
15
  description: string;
16
+ priority?: string | undefined;
17
+ effort?: string | undefined;
15
18
  assignees?: string[] | undefined;
16
19
  labels?: string[] | undefined;
17
20
  milestone?: number | undefined;
18
- priority?: string | undefined;
19
- effort?: string | undefined;
20
21
  }, {
21
22
  title: string;
22
23
  description: string;
24
+ priority?: string | undefined;
25
+ effort?: string | undefined;
23
26
  assignees?: string[] | undefined;
24
27
  labels?: string[] | undefined;
25
28
  milestone?: number | undefined;
26
- priority?: string | undefined;
27
- effort?: string | undefined;
28
29
  }>;
29
30
  export declare function handler(input: z.infer<typeof inputSchema>): Promise<{
30
31
  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;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"}
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;AAcxB,eAAO,MAAM,IAAI,iBAAiB,CAAC;AAiCnC,eAAO,MAAM,WAAW,QAA4D,CAAC;AAMrF,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAStD;AAED,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;EAYtB,CAAC;AAEH,wBAAsB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC;;;;;GAmJ/D"}
@@ -2,76 +2,51 @@ 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
+ import { boardAutoAddEnabled, addIssueToBoard, applyInitialStatus, renderBoardLines, getBoardFieldOptions, } from "../board.js";
54
6
  export const name = "create_issue";
7
+ const DESCRIPTION_HEAD = "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.";
8
+ const DESCRIPTION_TAIL = " 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.";
55
9
  // Priority/Effort inference guidance is woven into the tool description so Claude
56
10
  // uses its own judgement to triage the issue it's creating (like it already does
57
11
  // 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() {
12
+ // field with OKFFS_INFER_PRIORITY / OKFFS_INFER_EFFORT (default on). When the
13
+ // board's real option names are known they replace the generic scale so Claude
14
+ // infers against the actual options (#133) — e.g. a P0/P1/P2 board.
15
+ function inferenceGuidance(priorityOpts, effortOpts) {
60
16
  const bits = [];
61
17
  if (config.inferPriority) {
62
- bits.push("infer a `priority` for the issue from its urgency and impact (typical scale: Urgent, High, Medium, Low)");
18
+ const scale = priorityOpts?.length ? priorityOpts.join(", ") : "Urgent, High, Medium, Low";
19
+ bits.push(`infer a \`priority\` for the issue from its urgency and impact (board options: ${scale})`);
63
20
  }
64
21
  if (config.inferEffort) {
65
- bits.push("infer an `effort` from the expected amount of work (typical scale: High, Medium, Low)");
22
+ const scale = effortOpts?.length ? effortOpts.join(", ") : "High, Medium, Low";
23
+ bits.push(`infer an \`effort\` from the expected amount of work (board options: ${scale})`);
66
24
  }
67
25
  if (bits.length === 0)
68
26
  return "";
69
27
  return (` Also ${bits.join(" and ")}, passing the value(s) in the matching parameter. ` +
70
28
  "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
29
  }
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.";
30
+ // Static description (generic scale) the safe fallback used before the board is
31
+ // reachable and whenever real options can't be read.
32
+ export const description = DESCRIPTION_HEAD + inferenceGuidance() + DESCRIPTION_TAIL;
33
+ // Dynamic description resolved at tools/list time (index.ts awaits this). When
34
+ // auto-add is on and inference is enabled, inject the board's real Priority/Effort
35
+ // option names so Claude infers against them (#133). Any miss falls back to the
36
+ // static description. Cheap after the first call — board metadata is memoized.
37
+ export async function getDescription() {
38
+ if (!boardAutoAddEnabled())
39
+ return description;
40
+ if (!config.inferPriority && !config.inferEffort)
41
+ return description;
42
+ const [priorityOpts, effortOpts] = await Promise.all([
43
+ config.inferPriority ? getBoardFieldOptions("Priority") : Promise.resolve(null),
44
+ config.inferEffort ? getBoardFieldOptions("Effort") : Promise.resolve(null),
45
+ ]);
46
+ if (!priorityOpts && !effortOpts)
47
+ return description;
48
+ return DESCRIPTION_HEAD + inferenceGuidance(priorityOpts, effortOpts) + DESCRIPTION_TAIL;
49
+ }
75
50
  export const inputSchema = z.object({
76
51
  title: z.string().describe("Issue title"),
77
52
  description: z.string().describe("Issue body / description"),
@@ -97,29 +72,15 @@ export async function handler(input) {
97
72
  const updatedBody = `${input.description}\n\n**Branch:** \`${branchName}\``;
98
73
  await updateIssueBody(issue.number, updatedBody);
99
74
  // 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;
75
+ // native board automation) and set Priority/Effort. Non-fatal, mirroring the
76
+ // autoPR block below: any failure warns with an [okffs] prefix, is surfaced in
77
+ // the response, and never blocks issue creation. Initial Status is applied
78
+ // later (after the draft PR) — see the applyInitialStatus call below.
79
+ let boardAdd = null;
105
80
  let boardError = null;
106
- let boardItemId = null;
107
- if (config.projectAutoAdd && config.projectEnabled) {
81
+ if (boardAutoAddEnabled()) {
108
82
  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
- }
83
+ boardAdd = await addIssueToBoard(issue.node_id, { priority: resolvedPriority, effort: resolvedEffort });
123
84
  }
124
85
  catch (err) {
125
86
  boardError = err instanceof Error ? err.message : String(err);
@@ -165,28 +126,9 @@ export async function handler(input) {
165
126
  // issue to "In Progress". Setting our intended status here lets it win that
166
127
  // race so freshly-created issues land where okffs means them to (#103).
167
128
  // 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
- }
129
+ let initialStatus = null;
130
+ if (boardAdd) {
131
+ initialStatus = await applyInitialStatus(boardAdd.itemId);
190
132
  }
191
133
  const lines = [
192
134
  `Issue #${issue.number} created: ${issue.html_url}`,
@@ -203,25 +145,22 @@ export async function handler(input) {
203
145
  const source = input.labels ? "" : " (default)";
204
146
  lines.push(`Labels: ${resolvedLabels.join(", ")}${source}`);
205
147
  }
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
- }
148
+ const addedToBoard = Boolean(boardAdd);
149
+ lines.push(...renderBoardLines({
150
+ addedToBoard,
151
+ boardError,
152
+ requestedPriority: resolvedPriority,
153
+ priority: boardAdd?.priority ?? null,
154
+ requestedEffort: resolvedEffort,
155
+ effort: boardAdd?.effort ?? null,
156
+ requestedStatus: config.projectInitialStatus,
157
+ initialStatus,
158
+ }));
220
159
  lines.push(``, `To start work:`, ` git fetch origin`, ` git checkout ${branchName}`);
221
160
  // Conversational nudge: prompt the host LLM to offer moving the issue into
222
161
  // the "In Progress" column via update_project_status once work begins.
223
162
  if (addedToBoard) {
224
- const where = initialStatusApplied ? `"${initialStatusApplied}"` : "its default column";
163
+ const where = initialStatus?.applied ? `"${initialStatus.applied}"` : "its default column";
225
164
  lines.push(``, `This issue is on the board in ${where}. Want me to move it to "In Progress" and start? ` +
226
165
  `(I can call update_project_status for #${issue.number}.)`);
227
166
  }