@neturely/okffs 0.2.1

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.
Files changed (96) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/LICENSE +21 -0
  3. package/README.md +251 -0
  4. package/dist/config.d.ts +13 -0
  5. package/dist/config.d.ts.map +1 -0
  6. package/dist/config.js +27 -0
  7. package/dist/config.js.map +1 -0
  8. package/dist/docs.d.ts +11 -0
  9. package/dist/docs.d.ts.map +1 -0
  10. package/dist/docs.js +203 -0
  11. package/dist/docs.js.map +1 -0
  12. package/dist/git.d.ts +7 -0
  13. package/dist/git.d.ts.map +1 -0
  14. package/dist/git.js +22 -0
  15. package/dist/git.js.map +1 -0
  16. package/dist/github.d.ts +111 -0
  17. package/dist/github.d.ts.map +1 -0
  18. package/dist/github.js +301 -0
  19. package/dist/github.js.map +1 -0
  20. package/dist/index.d.ts +3 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +63 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/prompts/address_pr_review.d.ts +18 -0
  25. package/dist/prompts/address_pr_review.d.ts.map +1 -0
  26. package/dist/prompts/address_pr_review.js +35 -0
  27. package/dist/prompts/address_pr_review.js.map +1 -0
  28. package/dist/prompts/update_guidance.d.ts +18 -0
  29. package/dist/prompts/update_guidance.d.ts.map +1 -0
  30. package/dist/prompts/update_guidance.js +47 -0
  31. package/dist/prompts/update_guidance.js.map +1 -0
  32. package/dist/tools/close_issue.d.ts +17 -0
  33. package/dist/tools/close_issue.d.ts.map +1 -0
  34. package/dist/tools/close_issue.js +28 -0
  35. package/dist/tools/close_issue.js.map +1 -0
  36. package/dist/tools/comment_issue.d.ts +20 -0
  37. package/dist/tools/comment_issue.d.ts.map +1 -0
  38. package/dist/tools/comment_issue.js +23 -0
  39. package/dist/tools/comment_issue.js.map +1 -0
  40. package/dist/tools/commit_and_update.d.ts +20 -0
  41. package/dist/tools/commit_and_update.d.ts.map +1 -0
  42. package/dist/tools/commit_and_update.js +80 -0
  43. package/dist/tools/commit_and_update.js.map +1 -0
  44. package/dist/tools/create_issue.d.ts +29 -0
  45. package/dist/tools/create_issue.d.ts.map +1 -0
  46. package/dist/tools/create_issue.js +82 -0
  47. package/dist/tools/create_issue.js.map +1 -0
  48. package/dist/tools/create_issues_from_list.d.ts +50 -0
  49. package/dist/tools/create_issues_from_list.d.ts.map +1 -0
  50. package/dist/tools/create_issues_from_list.js +48 -0
  51. package/dist/tools/create_issues_from_list.js.map +1 -0
  52. package/dist/tools/create_pull_request.d.ts +20 -0
  53. package/dist/tools/create_pull_request.d.ts.map +1 -0
  54. package/dist/tools/create_pull_request.js +170 -0
  55. package/dist/tools/create_pull_request.js.map +1 -0
  56. package/dist/tools/delete_branch.d.ts +20 -0
  57. package/dist/tools/delete_branch.d.ts.map +1 -0
  58. package/dist/tools/delete_branch.js +39 -0
  59. package/dist/tools/delete_branch.js.map +1 -0
  60. package/dist/tools/delete_issue.d.ts +20 -0
  61. package/dist/tools/delete_issue.d.ts.map +1 -0
  62. package/dist/tools/delete_issue.js +46 -0
  63. package/dist/tools/delete_issue.js.map +1 -0
  64. package/dist/tools/get_issue.d.ts +17 -0
  65. package/dist/tools/get_issue.d.ts.map +1 -0
  66. package/dist/tools/get_issue.js +27 -0
  67. package/dist/tools/get_issue.js.map +1 -0
  68. package/dist/tools/link_issues.d.ts +23 -0
  69. package/dist/tools/link_issues.d.ts.map +1 -0
  70. package/dist/tools/link_issues.js +42 -0
  71. package/dist/tools/link_issues.js.map +1 -0
  72. package/dist/tools/list_issues.d.ts +11 -0
  73. package/dist/tools/list_issues.d.ts.map +1 -0
  74. package/dist/tools/list_issues.js +61 -0
  75. package/dist/tools/list_issues.js.map +1 -0
  76. package/dist/tools/list_pr_review_comments.d.ts +17 -0
  77. package/dist/tools/list_pr_review_comments.d.ts.map +1 -0
  78. package/dist/tools/list_pr_review_comments.js +43 -0
  79. package/dist/tools/list_pr_review_comments.js.map +1 -0
  80. package/dist/tools/plan.d.ts +79 -0
  81. package/dist/tools/plan.d.ts.map +1 -0
  82. package/dist/tools/plan.js +159 -0
  83. package/dist/tools/plan.js.map +1 -0
  84. package/dist/tools/prepare_release.d.ts +23 -0
  85. package/dist/tools/prepare_release.d.ts.map +1 -0
  86. package/dist/tools/prepare_release.js +172 -0
  87. package/dist/tools/prepare_release.js.map +1 -0
  88. package/dist/tools/reply_to_review_comment.d.ts +23 -0
  89. package/dist/tools/reply_to_review_comment.d.ts.map +1 -0
  90. package/dist/tools/reply_to_review_comment.js +25 -0
  91. package/dist/tools/reply_to_review_comment.js.map +1 -0
  92. package/dist/tools/resolve_review_thread.d.ts +17 -0
  93. package/dist/tools/resolve_review_thread.d.ts.map +1 -0
  94. package/dist/tools/resolve_review_thread.js +27 -0
  95. package/dist/tools/resolve_review_thread.js.map +1 -0
  96. package/package.json +48 -0
@@ -0,0 +1,79 @@
1
+ import { z } from "zod";
2
+ export declare const name = "plan";
3
+ export declare const description = "Plan a piece of work and create all the resulting GitHub issues (with branches, and draft PRs when OKFFS_AUTO_PR=true) in one shot. Given a free-text description of the work, break it down yourself into a structured list of issues \u2014 each with a title, description, inferred labels, and any relationships between them \u2014 and pass that breakdown as the tasks array. Infer labels from GitHub's defaults: bug, documentation, duplicate, enhancement, good first issue, help wanted, invalid, question, wontfix. Express dependencies via per-task relationships, referencing other tasks by their 1-based position in the list. Two-step confirmation: call once to preview the plan, then re-call with confirmed: true to create everything.";
4
+ export declare const inputSchema: z.ZodObject<{
5
+ description: z.ZodString;
6
+ tasks: z.ZodArray<z.ZodObject<{
7
+ title: z.ZodString;
8
+ description: z.ZodString;
9
+ assignees: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
10
+ labels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
11
+ milestone: z.ZodOptional<z.ZodNumber>;
12
+ relationships: z.ZodOptional<z.ZodArray<z.ZodObject<{
13
+ type: z.ZodEnum<["blocked_by", "blocking", "parent"]>;
14
+ target: z.ZodNumber;
15
+ }, "strip", z.ZodTypeAny, {
16
+ type: "blocking" | "parent" | "blocked_by";
17
+ target: number;
18
+ }, {
19
+ type: "blocking" | "parent" | "blocked_by";
20
+ target: number;
21
+ }>, "many">>;
22
+ }, "strip", z.ZodTypeAny, {
23
+ title: string;
24
+ description: string;
25
+ assignees?: string[] | undefined;
26
+ labels?: string[] | undefined;
27
+ milestone?: number | undefined;
28
+ relationships?: {
29
+ type: "blocking" | "parent" | "blocked_by";
30
+ target: number;
31
+ }[] | undefined;
32
+ }, {
33
+ title: string;
34
+ description: string;
35
+ assignees?: string[] | undefined;
36
+ labels?: string[] | undefined;
37
+ milestone?: number | undefined;
38
+ relationships?: {
39
+ type: "blocking" | "parent" | "blocked_by";
40
+ target: number;
41
+ }[] | undefined;
42
+ }>, "many">;
43
+ confirmed: z.ZodOptional<z.ZodBoolean>;
44
+ }, "strip", z.ZodTypeAny, {
45
+ description: string;
46
+ tasks: {
47
+ title: string;
48
+ description: string;
49
+ assignees?: string[] | undefined;
50
+ labels?: string[] | undefined;
51
+ milestone?: number | undefined;
52
+ relationships?: {
53
+ type: "blocking" | "parent" | "blocked_by";
54
+ target: number;
55
+ }[] | undefined;
56
+ }[];
57
+ confirmed?: boolean | undefined;
58
+ }, {
59
+ description: string;
60
+ tasks: {
61
+ title: string;
62
+ description: string;
63
+ assignees?: string[] | undefined;
64
+ labels?: string[] | undefined;
65
+ milestone?: number | undefined;
66
+ relationships?: {
67
+ type: "blocking" | "parent" | "blocked_by";
68
+ target: number;
69
+ }[] | undefined;
70
+ }[];
71
+ confirmed?: boolean | undefined;
72
+ }>;
73
+ export declare function handler(input: z.infer<typeof inputSchema>): Promise<{
74
+ content: {
75
+ type: "text";
76
+ text: string;
77
+ }[];
78
+ }>;
79
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/tools/plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB,eAAO,MAAM,IAAI,SAAS,CAAC;AAE3B,eAAO,MAAM,WAAW,muBACgsB,CAAC;AA2BztB,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAStB,CAAC;AAQH,wBAAsB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC;;;;;GAwJ/D"}
@@ -0,0 +1,159 @@
1
+ import { z } from "zod";
2
+ import { createIssue, updateIssueBody, getDefaultBranch, getRef, createBranch, buildBranchName, createDraftPullRequest, } from "../github.js";
3
+ import { config } from "../config.js";
4
+ import { git, currentBranch } from "../git.js";
5
+ export const name = "plan";
6
+ export const description = "Plan a piece of work and create all the resulting GitHub issues (with branches, and draft PRs when OKFFS_AUTO_PR=true) in one shot. Given a free-text description of the work, break it down yourself into a structured list of issues — each with a title, description, inferred labels, and any relationships between them — and pass that breakdown as the tasks array. Infer labels from GitHub's defaults: bug, documentation, duplicate, enhancement, good first issue, help wanted, invalid, question, wontfix. Express dependencies via per-task relationships, referencing other tasks by their 1-based position in the list. Two-step confirmation: call once to preview the plan, then re-call with confirmed: true to create everything.";
7
+ const relationshipSchema = z.object({
8
+ type: z
9
+ .enum(["blocked_by", "blocking", "parent"])
10
+ .describe("blocked_by: this task is blocked by the target. blocking: this task is blocking the target. parent: the target is the parent of this task."),
11
+ target: z
12
+ .number()
13
+ .int()
14
+ .positive()
15
+ .describe("1-based index of the related task within this same tasks list"),
16
+ });
17
+ const taskSchema = z.object({
18
+ title: z.string().describe("Issue title"),
19
+ description: z.string().describe("Issue body / description"),
20
+ assignees: z.array(z.string()).optional().describe("GitHub usernames to assign"),
21
+ labels: z.array(z.string()).optional().describe("Labels to apply to this issue"),
22
+ milestone: z.number().int().optional().describe("Milestone number to assign"),
23
+ relationships: z
24
+ .array(relationshipSchema)
25
+ .optional()
26
+ .describe("Relationships to other tasks in this list, referenced by 1-based index"),
27
+ });
28
+ export const inputSchema = z.object({
29
+ description: z
30
+ .string()
31
+ .describe("Free-text description of the work to plan and break down into issues"),
32
+ tasks: z
33
+ .array(taskSchema)
34
+ .min(1)
35
+ .describe("The issue breakdown you generated from the description"),
36
+ confirmed: z.boolean().optional().describe("Must be true to proceed with creation"),
37
+ });
38
+ const RELATIONSHIP_LABELS = {
39
+ blocked_by: "Blocked by",
40
+ blocking: "Blocking",
41
+ parent: "Parent:",
42
+ };
43
+ export async function handler(input) {
44
+ if (!input.confirmed) {
45
+ const preview = input.tasks
46
+ .map((t, i) => {
47
+ const labels = t.labels?.length ? ` [${t.labels.join(", ")}]` : "";
48
+ const rels = t.relationships?.length
49
+ ? "\n" +
50
+ t.relationships
51
+ .map((r) => ` ↳ ${RELATIONSHIP_LABELS[r.type]} task ${r.target}`)
52
+ .join("\n")
53
+ : "";
54
+ return `${i + 1}. ${t.title}${labels}${rels}`;
55
+ })
56
+ .join("\n");
57
+ return {
58
+ content: [
59
+ {
60
+ type: "text",
61
+ text: `Plan for: ${input.description}\n\n` +
62
+ `About to create ${input.tasks.length} issue(s):\n\n${preview}\n\n` +
63
+ `Re-call plan with confirmed: true to create them.`,
64
+ },
65
+ ],
66
+ };
67
+ }
68
+ const defaultBranch = await getDefaultBranch();
69
+ const ref = await getRef(defaultBranch);
70
+ // First pass: create every issue and its branch so we have real issue numbers
71
+ // before wiring up relationships (which reference tasks by list index).
72
+ const created = [];
73
+ for (const task of input.tasks) {
74
+ const resolvedAssignees = task.assignees ?? config.defaultAssignees;
75
+ const resolvedLabels = [...new Set([...(task.labels ?? []), ...config.defaultLabels])];
76
+ const issue = await createIssue(task.title, task.description, resolvedAssignees, resolvedLabels, task.milestone);
77
+ const branchName = buildBranchName(issue.number, task.title);
78
+ await createBranch(branchName, ref.object.sha);
79
+ const body = `${task.description}\n\n**Branch:** \`${branchName}\``;
80
+ await updateIssueBody(issue.number, body);
81
+ created.push({
82
+ number: issue.number,
83
+ html_url: issue.html_url,
84
+ branchName,
85
+ body,
86
+ relationships: task.relationships ?? [],
87
+ });
88
+ }
89
+ // Second pass: resolve relationship targets (1-based task indices) to issue
90
+ // numbers and append a Relationships section to the relevant issue bodies.
91
+ for (let i = 0; i < created.length; i++) {
92
+ const entry = created[i];
93
+ const lines = entry.relationships
94
+ .filter((r) => r.target >= 1 && r.target <= created.length && r.target !== i + 1)
95
+ .map((r) => `- ${RELATIONSHIP_LABELS[r.type]} #${created[r.target - 1].number}`);
96
+ if (lines.length === 0)
97
+ continue;
98
+ const newBody = `${entry.body}\n\n## Relationships\n${lines.join("\n")}`;
99
+ await updateIssueBody(entry.number, newBody);
100
+ }
101
+ // Optionally open a draft PR per branch. Mirrors create_issue: push an empty
102
+ // init commit so the branch diverges from base, then open the draft PR.
103
+ const draftPRs = {};
104
+ if (config.autoPR) {
105
+ const previousBranch = currentBranch();
106
+ try {
107
+ git(["fetch", "origin"]);
108
+ for (const entry of created) {
109
+ try {
110
+ git(["checkout", entry.branchName]);
111
+ git(["commit", "--allow-empty", "-m", `chore: init branch for #${entry.number}`]);
112
+ git(["push", "origin", entry.branchName]);
113
+ }
114
+ catch (err) {
115
+ console.warn(`[okffs] Failed to push init commit for #${entry.number}:`, err instanceof Error ? err.message : err);
116
+ }
117
+ }
118
+ }
119
+ finally {
120
+ if (previousBranch && !created.some((e) => e.branchName === previousBranch)) {
121
+ try {
122
+ git(["checkout", previousBranch]);
123
+ }
124
+ catch (err) {
125
+ console.warn("[okffs] Failed to restore branch:", err instanceof Error ? err.message : err);
126
+ }
127
+ }
128
+ }
129
+ for (const entry of created) {
130
+ try {
131
+ const pr = await createDraftPullRequest(`WIP: #${entry.number} - ${input.tasks[created.indexOf(entry)].title}`, `Closes #${entry.number}`, entry.branchName, defaultBranch);
132
+ draftPRs[entry.number] = pr.html_url;
133
+ }
134
+ catch (err) {
135
+ console.warn(`[okffs] Failed to create draft PR for #${entry.number}:`, err instanceof Error ? err.message : err);
136
+ }
137
+ }
138
+ }
139
+ const results = created.map((entry) => {
140
+ const lines = [
141
+ `#${entry.number} — ${input.tasks[created.indexOf(entry)].title}`,
142
+ ` Branch: \`${entry.branchName}\``,
143
+ ` ${entry.html_url}`,
144
+ ];
145
+ if (draftPRs[entry.number]) {
146
+ lines.push(` Draft PR: ${draftPRs[entry.number]}`);
147
+ }
148
+ return lines.join("\n");
149
+ });
150
+ return {
151
+ content: [
152
+ {
153
+ type: "text",
154
+ text: `Created ${results.length} issue(s) from the plan:\n\n${results.join("\n\n")}`,
155
+ },
156
+ ],
157
+ };
158
+ }
159
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/tools/plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ export declare const name = "prepare_release";
3
+ export declare const description = "Prepare a release: bump the version in package.json and package-lock.json, roll the CHANGELOG ([Unreleased] \u2192 a dated version section with a fresh empty [Unreleased] and updated compare links), commit on a release branch, and open a PR. It does NOT tag or publish \u2014 tagging vX.Y.Z (which triggers the CI npm publish) stays a manual step after merge. Provide an explicit `version` or a `bump` level; if neither is given, a level is inferred from the [Unreleased] entries (### Added \u2192 minor, otherwise patch) and surfaced for confirmation. Two-step: call once to preview, re-call with confirmed: true to apply.";
4
+ export declare const inputSchema: z.ZodObject<{
5
+ version: z.ZodOptional<z.ZodString>;
6
+ bump: z.ZodOptional<z.ZodEnum<["patch", "minor", "major"]>>;
7
+ confirmed: z.ZodOptional<z.ZodBoolean>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ confirmed?: boolean | undefined;
10
+ version?: string | undefined;
11
+ bump?: "patch" | "minor" | "major" | undefined;
12
+ }, {
13
+ confirmed?: boolean | undefined;
14
+ version?: string | undefined;
15
+ bump?: "patch" | "minor" | "major" | undefined;
16
+ }>;
17
+ export declare function handler(input: z.infer<typeof inputSchema>): Promise<{
18
+ content: {
19
+ type: "text";
20
+ text: string;
21
+ }[];
22
+ }>;
23
+ //# sourceMappingURL=prepare_release.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare_release.d.ts","sourceRoot":"","sources":["../../src/tools/prepare_release.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,eAAO,MAAM,IAAI,oBAAoB,CAAC;AAEtC,eAAO,MAAM,WAAW,onBAC4kB,CAAC;AAErmB,eAAO,MAAM,WAAW;;;;;;;;;;;;EAItB,CAAC;AA4BH,wBAAsB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC;;;;;GAkJ/D"}
@@ -0,0 +1,172 @@
1
+ import { z } from "zod";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { createPullRequest, getDefaultBranch } from "../github.js";
5
+ import { getUnreleasedSection, rollChangelogForRelease } from "../docs.js";
6
+ import { git, currentBranch } from "../git.js";
7
+ export const name = "prepare_release";
8
+ export const description = "Prepare a release: bump the version in package.json and package-lock.json, roll the CHANGELOG ([Unreleased] → a dated version section with a fresh empty [Unreleased] and updated compare links), commit on a release branch, and open a PR. It does NOT tag or publish — tagging vX.Y.Z (which triggers the CI npm publish) stays a manual step after merge. Provide an explicit `version` or a `bump` level; if neither is given, a level is inferred from the [Unreleased] entries (### Added → minor, otherwise patch) and surfaced for confirmation. Two-step: call once to preview, re-call with confirmed: true to apply.";
9
+ export const inputSchema = z.object({
10
+ version: z.string().optional().describe("Explicit target version, e.g. 0.1.7 (takes precedence over bump)"),
11
+ bump: z.enum(["patch", "minor", "major"]).optional().describe("Semver bump level if version is not given"),
12
+ confirmed: z.boolean().optional().describe("Must be true to apply (otherwise previews)"),
13
+ });
14
+ function bumpVersion(v, type) {
15
+ const m = v.match(/^(\d+)\.(\d+)\.(\d+)$/);
16
+ if (!m)
17
+ throw new Error(`Cannot parse current version "${v}".`);
18
+ const [maj, min, pat] = [Number(m[1]), Number(m[2]), Number(m[3])];
19
+ if (type === "major")
20
+ return `${maj + 1}.0.0`;
21
+ if (type === "minor")
22
+ return `${maj}.${min + 1}.0`;
23
+ return `${maj}.${min}.${pat + 1}`;
24
+ }
25
+ // Replace the first `count` occurrences of an exact substring. Throws if fewer
26
+ // than `count` occurrences exist — a partial version bump must never proceed.
27
+ function replaceExactly(content, search, replace, count, label) {
28
+ const found = content.split(search).length - 1;
29
+ if (found < count) {
30
+ throw new Error(`Expected at least ${count} occurrence(s) of \`${search}\` in ${label} but found ${found}. Aborting to avoid an inconsistent version bump.`);
31
+ }
32
+ let out = content;
33
+ let from = 0;
34
+ for (let i = 0; i < count; i++) {
35
+ const at = out.indexOf(search, from);
36
+ out = out.slice(0, at) + replace + out.slice(at + search.length);
37
+ from = at + replace.length;
38
+ }
39
+ return out;
40
+ }
41
+ export async function handler(input) {
42
+ const base = process.cwd();
43
+ const pkg = JSON.parse(fs.readFileSync(path.join(base, "package.json"), "utf8"));
44
+ const currentVersion = pkg.version;
45
+ const changelog = fs.readFileSync(path.join(base, "CHANGELOG.md"), "utf8");
46
+ const unreleased = getUnreleasedSection(changelog);
47
+ if (unreleased === null) {
48
+ return { content: [{ type: "text", text: "CHANGELOG.md has no ## [Unreleased] section — nothing to release." }] };
49
+ }
50
+ if (!/^[-*] /m.test(unreleased)) {
51
+ return { content: [{ type: "text", text: "The ## [Unreleased] section has no entries — nothing to release." }] };
52
+ }
53
+ // Resolve the target version.
54
+ let targetVersion;
55
+ let how;
56
+ if (input.version) {
57
+ if (!/^\d+\.\d+\.\d+$/.test(input.version)) {
58
+ return { content: [{ type: "text", text: `Invalid version "${input.version}" — expected X.Y.Z.` }] };
59
+ }
60
+ targetVersion = input.version;
61
+ how = "explicit version";
62
+ }
63
+ else {
64
+ const level = input.bump ?? (/###\s+Added/.test(unreleased) ? "minor" : "patch");
65
+ targetVersion = bumpVersion(currentVersion, level);
66
+ how = input.bump ? `${level} bump` : `inferred ${level} bump (### Added present → minor, else patch)`;
67
+ }
68
+ const branch = `release/${targetVersion}`;
69
+ if (!input.confirmed) {
70
+ return {
71
+ content: [{
72
+ type: "text",
73
+ text: `Release preview\n` +
74
+ ` current: ${currentVersion}\n` +
75
+ ` target: ${targetVersion} (${how})\n` +
76
+ ` branch: ${branch}\n\n` +
77
+ `Will: bump package.json + package-lock.json, roll the CHANGELOG into "## [${targetVersion}]", ` +
78
+ `commit on ${branch}, and open a PR. It will NOT tag or publish.\n\n` +
79
+ `[Unreleased] entries to be released:\n${unreleased}\n\n` +
80
+ `Re-call prepare_release with confirmed: true to apply.`,
81
+ }],
82
+ };
83
+ }
84
+ const baseBranch = await getDefaultBranch();
85
+ const previousBranch = currentBranch();
86
+ let prepared = false;
87
+ try {
88
+ git(["fetch", "origin"]);
89
+ git(["checkout", "-B", branch, `origin/${baseBranch}`]);
90
+ // Re-read on the base branch so edits apply to the correct content.
91
+ const pkgPath = path.join(base, "package.json");
92
+ const lockPath = path.join(base, "package-lock.json");
93
+ const clPath = path.join(base, "CHANGELOG.md");
94
+ const pkgRaw = fs.readFileSync(pkgPath, "utf8");
95
+ const lockRaw = fs.readFileSync(lockPath, "utf8");
96
+ const clRaw = fs.readFileSync(clPath, "utf8");
97
+ const fromVersion = JSON.parse(pkgRaw).version;
98
+ // The preview computed targetVersion from the working tree's version. If the
99
+ // base branch is actually at a different version and no explicit version was
100
+ // given, the inferred target would be wrong — abort rather than bump blindly.
101
+ if (!input.version && fromVersion !== currentVersion) {
102
+ throw new Error(`Base branch ${baseBranch} is at version ${fromVersion}, but the preview was based on ${currentVersion}. ` +
103
+ `Re-run with an explicit \`version\` to proceed.`);
104
+ }
105
+ const date = new Date().toISOString().slice(0, 10);
106
+ // Compute all new contents up front (with validation) so a failure can't
107
+ // leave a partial bump written to disk. Targeted version-field edits avoid
108
+ // reformatting; package-lock has two self-version fields (root + packages[""]).
109
+ const newPkg = replaceExactly(pkgRaw, `"version": "${fromVersion}"`, `"version": "${targetVersion}"`, 1, "package.json");
110
+ const newLock = replaceExactly(lockRaw, `"version": "${fromVersion}"`, `"version": "${targetVersion}"`, 2, "package-lock.json");
111
+ const newCl = rollChangelogForRelease(clRaw, targetVersion, fromVersion, date);
112
+ fs.writeFileSync(pkgPath, newPkg);
113
+ fs.writeFileSync(lockPath, newLock);
114
+ fs.writeFileSync(clPath, newCl);
115
+ git(["add", "package.json", "package-lock.json", "CHANGELOG.md"]);
116
+ git(["commit", "-m", `release: ${targetVersion}`]);
117
+ git(["push", "-u", "origin", branch]);
118
+ prepared = true;
119
+ }
120
+ catch (err) {
121
+ return {
122
+ content: [{ type: "text", text: `Release prep failed: ${err instanceof Error ? err.message : String(err)}` }],
123
+ };
124
+ }
125
+ finally {
126
+ if (previousBranch && previousBranch !== branch) {
127
+ try {
128
+ git(["checkout", previousBranch]);
129
+ }
130
+ catch (err) {
131
+ console.warn(`[okffs] Failed to restore branch ${previousBranch}:`, err instanceof Error ? err.message : err);
132
+ }
133
+ }
134
+ }
135
+ if (!prepared) {
136
+ return { content: [{ type: "text", text: "Release prep did not complete." }] };
137
+ }
138
+ const prBody = [
139
+ `## Release ${targetVersion}`,
140
+ ``,
141
+ `- Bumped \`package.json\` and \`package-lock.json\` to ${targetVersion}.`,
142
+ `- Rolled the CHANGELOG \`[Unreleased]\` section into \`## [${targetVersion}]\` and refreshed the compare links.`,
143
+ ``,
144
+ `After merging, tag \`v${targetVersion}\` and push it — CI (\`publish.yml\`) publishes to npm on the tag. This PR does not tag or publish.`,
145
+ ].join("\n");
146
+ let pr;
147
+ try {
148
+ pr = await createPullRequest(`Release ${targetVersion}`, prBody, branch, baseBranch);
149
+ }
150
+ catch (err) {
151
+ // The release branch is already pushed; only PR creation failed.
152
+ return {
153
+ content: [{
154
+ type: "text",
155
+ text: `Release branch \`${branch}\` was prepared and pushed (version ${targetVersion}, CHANGELOG rolled), ` +
156
+ `but opening the PR failed: ${err instanceof Error ? err.message : String(err)}\n\n` +
157
+ `Open a PR from \`${branch}\` into \`${baseBranch}\` manually (e.g. \`gh pr create --base ${baseBranch} --head ${branch}\`). ` +
158
+ `After it merges, tag \`v${targetVersion}\` and push it to trigger the CI publish.`,
159
+ }],
160
+ };
161
+ }
162
+ return {
163
+ content: [{
164
+ type: "text",
165
+ text: `Prepared release ${targetVersion} (from ${currentVersion}).\n` +
166
+ `Branch: ${branch}\nPR: ${pr.html_url}\n\n` +
167
+ `Next: review & merge the PR, then tag \`v${targetVersion}\` and push it — CI publishes to npm. ` +
168
+ `prepare_release does not tag or publish.`,
169
+ }],
170
+ };
171
+ }
172
+ //# sourceMappingURL=prepare_release.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare_release.js","sourceRoot":"","sources":["../../src/tools/prepare_release.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ export declare const name = "reply_to_review_comment";
3
+ export declare const description = "Reply to an inline PR review comment thread. Pass the pull request number, the comment id (from list_pr_review_comments), and the reply body. Use after addressing a review comment to record what was changed (e.g. reference the fix commit).";
4
+ export declare const inputSchema: z.ZodObject<{
5
+ pr_number: z.ZodNumber;
6
+ comment_id: z.ZodNumber;
7
+ body: z.ZodString;
8
+ }, "strip", z.ZodTypeAny, {
9
+ body: string;
10
+ pr_number: number;
11
+ comment_id: number;
12
+ }, {
13
+ body: string;
14
+ pr_number: number;
15
+ comment_id: number;
16
+ }>;
17
+ export declare function handler(input: z.infer<typeof inputSchema>): Promise<{
18
+ content: {
19
+ type: "text";
20
+ text: string;
21
+ }[];
22
+ }>;
23
+ //# sourceMappingURL=reply_to_review_comment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply_to_review_comment.d.ts","sourceRoot":"","sources":["../../src/tools/reply_to_review_comment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,IAAI,4BAA4B,CAAC;AAE9C,eAAO,MAAM,WAAW,oPAC2N,CAAC;AAEpP,eAAO,MAAM,WAAW;;;;;;;;;;;;EAQtB,CAAC;AAEH,wBAAsB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC;;;;;GAU/D"}
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ import { replyToReviewComment } from "../github.js";
3
+ export const name = "reply_to_review_comment";
4
+ export const description = "Reply to an inline PR review comment thread. Pass the pull request number, the comment id (from list_pr_review_comments), and the reply body. Use after addressing a review comment to record what was changed (e.g. reference the fix commit).";
5
+ export const inputSchema = z.object({
6
+ pr_number: z.number().int().positive().describe("The pull request number"),
7
+ comment_id: z
8
+ .number()
9
+ .int()
10
+ .positive()
11
+ .describe("The review comment id to reply to (from list_pr_review_comments)"),
12
+ body: z.string().describe("Reply body"),
13
+ });
14
+ export async function handler(input) {
15
+ const reply = await replyToReviewComment(input.pr_number, input.comment_id, input.body);
16
+ return {
17
+ content: [
18
+ {
19
+ type: "text",
20
+ text: `Replied to comment #${input.comment_id} on PR #${input.pr_number}: ${reply.html_url}`,
21
+ },
22
+ ],
23
+ };
24
+ }
25
+ //# sourceMappingURL=reply_to_review_comment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply_to_review_comment.js","sourceRoot":"","sources":["../../src/tools/reply_to_review_comment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,CAAC,MAAM,IAAI,GAAG,yBAAyB,CAAC;AAE9C,MAAM,CAAC,MAAM,WAAW,GACtB,iPAAiP,CAAC;AAEpP,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;IAC1E,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,QAAQ,CAAC,kEAAkE,CAAC;IAC/E,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC;CACxC,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAAkC;IAC9D,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACxF,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,uBAAuB,KAAK,CAAC,UAAU,WAAW,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,QAAQ,EAAE;aAC7F;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { z } from "zod";
2
+ export declare const name = "resolve_review_thread";
3
+ export declare const description = "Mark an inline PR review thread as resolved. Pass the thread_id from list_pr_review_comments. Gated by OKFFS_RESOLVE_THREADS: when that env var is not 'true', this tool declines and leaves the thread open for the user to read and resolve manually.";
4
+ export declare const inputSchema: z.ZodObject<{
5
+ thread_id: z.ZodString;
6
+ }, "strip", z.ZodTypeAny, {
7
+ thread_id: string;
8
+ }, {
9
+ thread_id: string;
10
+ }>;
11
+ export declare function handler(input: z.infer<typeof inputSchema>): Promise<{
12
+ content: {
13
+ type: "text";
14
+ text: string;
15
+ }[];
16
+ }>;
17
+ //# sourceMappingURL=resolve_review_thread.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve_review_thread.d.ts","sourceRoot":"","sources":["../../src/tools/resolve_review_thread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,IAAI,0BAA0B,CAAC;AAE5C,eAAO,MAAM,WAAW,4PACmO,CAAC;AAE5P,eAAO,MAAM,WAAW;;;;;;EAItB,CAAC;AAEH,wBAAsB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC;;;;;GAiB/D"}
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ import { resolveReviewThread } from "../github.js";
3
+ import { config } from "../config.js";
4
+ export const name = "resolve_review_thread";
5
+ export const description = "Mark an inline PR review thread as resolved. Pass the thread_id from list_pr_review_comments. Gated by OKFFS_RESOLVE_THREADS: when that env var is not 'true', this tool declines and leaves the thread open for the user to read and resolve manually.";
6
+ export const inputSchema = z.object({
7
+ thread_id: z
8
+ .string()
9
+ .describe("The review thread id to resolve (from list_pr_review_comments)"),
10
+ });
11
+ export async function handler(input) {
12
+ if (!config.resolveThreads) {
13
+ return {
14
+ content: [
15
+ {
16
+ type: "text",
17
+ text: "Not resolving — OKFFS_RESOLVE_THREADS is not enabled. The thread is left open for you to read and resolve on GitHub. Set OKFFS_RESOLVE_THREADS=true to allow okffs to resolve threads automatically.",
18
+ },
19
+ ],
20
+ };
21
+ }
22
+ await resolveReviewThread(input.thread_id);
23
+ return {
24
+ content: [{ type: "text", text: `Resolved review thread ${input.thread_id}.` }],
25
+ };
26
+ }
27
+ //# sourceMappingURL=resolve_review_thread.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve_review_thread.js","sourceRoot":"","sources":["../../src/tools/resolve_review_thread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,CAAC,MAAM,IAAI,GAAG,uBAAuB,CAAC;AAE5C,MAAM,CAAC,MAAM,WAAW,GACtB,yPAAyP,CAAC;AAE5P,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,CAAC,gEAAgE,CAAC;CAC9E,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAAkC;IAC9D,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC3B,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EACF,sMAAsM;iBACzM;aACF;SACF,CAAC;IACJ,CAAC;IAED,MAAM,mBAAmB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC3C,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,0BAA0B,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC;KACzF,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@neturely/okffs",
3
+ "version": "0.2.1",
4
+ "description": "MCP server that connects Claude Code to GitHub — create and manage issues and branches without leaving your editor.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "okffs": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "prepublishOnly": "npm run build",
13
+ "postbuild": "node -e \"const fs=require('fs');const f='dist/index.js';const c=fs.readFileSync(f,'utf8');if(!c.startsWith('#!/usr/bin/env node'))fs.writeFileSync(f,'#!/usr/bin/env node\\n'+c);\" && chmod +x dist/index.js",
14
+ "dev": "node --env-file=.env --import tsx/esm src/index.ts",
15
+ "start": "node --env-file=.env dist/index.js"
16
+ },
17
+ "keywords": [
18
+ "mcp",
19
+ "github",
20
+ "issues",
21
+ "branches",
22
+ "claude",
23
+ "claude-code",
24
+ "model-context-protocol",
25
+ "developer-tools"
26
+ ],
27
+ "author": "neturely",
28
+ "license": "MIT",
29
+ "homepage": "https://github.com/neturely/okffs#readme",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/neturely/okffs.git"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "dependencies": {
38
+ "@modelcontextprotocol/sdk": "^1.12.0",
39
+ "dotenv": "^17.4.2",
40
+ "zod": "^3.23.8",
41
+ "zod-to-json-schema": "^3.23.2"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^20.0.0",
45
+ "tsx": "^4.19.0",
46
+ "typescript": "^5.4.0"
47
+ }
48
+ }