@neturely/okffs 0.8.0 → 0.9.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/CHANGELOG.md +9 -1
- package/README.md +15 -2
- package/dist/cli/banner.d.ts +17 -0
- package/dist/cli/banner.d.ts.map +1 -0
- package/dist/cli/banner.js +65 -0
- package/dist/cli/banner.js.map +1 -0
- package/dist/cli/env.d.ts +30 -0
- package/dist/cli/env.d.ts.map +1 -0
- package/dist/cli/env.js +171 -0
- package/dist/cli/env.js.map +1 -0
- package/dist/cli/index.d.ts +12 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +77 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/manifest.d.ts +48 -0
- package/dist/cli/manifest.d.ts.map +1 -0
- package/dist/cli/manifest.js +303 -0
- package/dist/cli/manifest.js.map +1 -0
- package/dist/cli/probe.d.ts +32 -0
- package/dist/cli/probe.d.ts.map +1 -0
- package/dist/cli/probe.js +101 -0
- package/dist/cli/probe.js.map +1 -0
- package/dist/cli/sanity.d.ts +16 -0
- package/dist/cli/sanity.d.ts.map +1 -0
- package/dist/cli/sanity.js +99 -0
- package/dist/cli/sanity.js.map +1 -0
- package/dist/cli/setup.d.ts +2 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +254 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +4 -2
- package/dist/github.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -107
- package/dist/index.js.map +1 -1
- package/dist/prompts/setup.d.ts +18 -0
- package/dist/prompts/setup.d.ts.map +1 -0
- package/dist/prompts/setup.js +77 -0
- package/dist/prompts/setup.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +166 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/configure.d.ts +27 -0
- package/dist/tools/configure.d.ts.map +1 -0
- package/dist/tools/configure.js +91 -0
- package/dist/tools/configure.js.map +1 -0
- package/dist/tools/update_project_status.d.ts +2 -2
- package/package.json +6 -2
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { SECTIONS } from "../cli/manifest.js";
|
|
2
|
+
export const name = "setup";
|
|
3
|
+
export const description = "Configure okffs for this repo conversationally, right here in the chat — the in-Claude-Code counterpart to the `okffs setup` CLI wizard. Interviews you for the settings that apply, then writes them to .env via the `configure` tool (preserving your own variables and comments).";
|
|
4
|
+
export const argumentDefs = [
|
|
5
|
+
{
|
|
6
|
+
name: "mode",
|
|
7
|
+
description: "Optional: 'quick' (auth + repo + base branch only), 'full' (every section), or 'sync' (only options not yet configured). Defaults to sync when a .env exists, else asks.",
|
|
8
|
+
required: false,
|
|
9
|
+
},
|
|
10
|
+
];
|
|
11
|
+
// Render the manifest into a compact reference the model can drive the interview
|
|
12
|
+
// from, so the prompt is self-contained (no need to also expose the manifest as a
|
|
13
|
+
// resource). Mirrors how create_issue injects the board's real options.
|
|
14
|
+
function renderReference() {
|
|
15
|
+
const lines = [];
|
|
16
|
+
for (const s of SECTIONS) {
|
|
17
|
+
const gate = !s.gated
|
|
18
|
+
? "always ask"
|
|
19
|
+
: s.gateKey
|
|
20
|
+
? `gated — ask "${s.gatePrompt}" and record the answer as ${s.gateKey}=true/false`
|
|
21
|
+
: `gated — ask "${s.gatePrompt}"; if declined, mark its vars declined`;
|
|
22
|
+
const cond = s.onlyIf ? " [only if a protected branch is set]" : "";
|
|
23
|
+
lines.push(`\n### ${s.title} (${gate})${cond}`);
|
|
24
|
+
for (const v of s.vars) {
|
|
25
|
+
const opts = v.options ? ` options: ${v.options.map((o) => o || "(unset)").join("/")};` : "";
|
|
26
|
+
const def = v.default ? ` default: ${v.default};` : "";
|
|
27
|
+
lines.push(`- \`${v.key}\` (${v.kind});${opts}${def} ${v.description}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return lines.join("\n");
|
|
31
|
+
}
|
|
32
|
+
export function build(args) {
|
|
33
|
+
const mode = args.mode?.trim().toLowerCase();
|
|
34
|
+
const text = [
|
|
35
|
+
`Configure okffs for THIS repository by talking with the user, then persist the result by calling the \`configure\` tool. Do not edit .env yourself — \`configure\` owns the write (it preserves the user's own variables and comments, touching only okffs's marked block).`,
|
|
36
|
+
``,
|
|
37
|
+
`## 1. Assess current state`,
|
|
38
|
+
`- Read \`./.env\` in the current working directory if it exists (use your file-reading tool). Note which \`GITHUB_*\`/\`OKFFS_*\` variables are already set, and look for the \`# okffs:configured-version=…\` stamp.`,
|
|
39
|
+
`- **Never print or echo the value of GITHUB_TOKEN** (or any secret). Acknowledge it's set without showing it.`,
|
|
40
|
+
``,
|
|
41
|
+
`## 2. Choose breadth`,
|
|
42
|
+
mode
|
|
43
|
+
? `- The user requested **${mode}** mode.`
|
|
44
|
+
: `- No .env yet → ask the user: **Quick** (auth, repo, base branch only) or **Full** (every section). A .env already exists → default to **sync**: only ask about variables that are not yet set. Offer "reconfigure everything" if they want a full pass.`,
|
|
45
|
+
`- In sync/upgrade situations, only ask about variables that are missing — leave already-configured values alone unless the user asks to change them.`,
|
|
46
|
+
``,
|
|
47
|
+
`## 3. Interview`,
|
|
48
|
+
`- Go section by section using the reference below. For a **gated** section, ask its single gate question first; if the user declines, skip the whole group (and include those vars in \`declined\`).`,
|
|
49
|
+
`- For each variable: show already-set values (mask the token) with a keep/change choice; for unset ones, give the short description and default and let the user set or skip.`,
|
|
50
|
+
`- For \`GITHUB_TOKEN\`: mention they can leave it blank to use the GitHub CLI (\`gh auth token\`), and share the fine-grained PAT URL from the reference. Let them paste a token OR choose the gh fallback — don't force it.`,
|
|
51
|
+
`- Keep it brief and batch related questions; don't interrogate one variable at a time when a section can be covered together.`,
|
|
52
|
+
``,
|
|
53
|
+
`## 4. Persist`,
|
|
54
|
+
`- Call \`configure\` once with:`,
|
|
55
|
+
` - \`set\`: a map of every variable the user gave a value for (booleans as "true"/"false").`,
|
|
56
|
+
` - \`declined\`: every OPTIONAL variable the user explicitly skipped (so a later sync won't re-ask it). Don't list variables you never brought up.`,
|
|
57
|
+
`- Then relay \`configure\`'s summary and remind the user to **restart the MCP server / Claude Code** so okffs re-reads .env.`,
|
|
58
|
+
``,
|
|
59
|
+
`## 5. Notes`,
|
|
60
|
+
`- Booleans that default on (inference/metadata) should stay on unless the user wants them off.`,
|
|
61
|
+
`- If the user wants \`OKFFS_AUTO_MERGE_BASE=true\`, confirm \`OKFFS_PROTECTED_BRANCH\` is also set — the merge tool refuses without it.`,
|
|
62
|
+
`- The Projects and promotion sections only matter if the user uses a GitHub Projects board / a protected-branch promotion flow; it's fine to skip them.`,
|
|
63
|
+
``,
|
|
64
|
+
`## Variable reference`,
|
|
65
|
+
renderReference(),
|
|
66
|
+
].join("\n");
|
|
67
|
+
return {
|
|
68
|
+
description: "Configure okffs for this repo conversationally, then persist via the configure tool",
|
|
69
|
+
messages: [
|
|
70
|
+
{
|
|
71
|
+
role: "user",
|
|
72
|
+
content: { type: "text", text },
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/prompts/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC;AAE5B,MAAM,CAAC,MAAM,WAAW,GACtB,sRAAsR,CAAC;AAEzR,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B;QACE,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,0KAA0K;QACvL,QAAQ,EAAE,KAAK;KAChB;CACF,CAAC;AAEF,iFAAiF;AACjF,kFAAkF;AAClF,wEAAwE;AACxE,SAAS,eAAe;IACtB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK;YACnB,CAAC,CAAC,YAAY;YACd,CAAC,CAAC,CAAC,CAAC,OAAO;gBACT,CAAC,CAAC,gBAAgB,CAAC,CAAC,UAAU,8BAA8B,CAAC,CAAC,OAAO,aAAa;gBAClF,CAAC,CAAC,gBAAgB,CAAC,CAAC,UAAU,wCAAwC,CAAC;QAC3E,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;QAChD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7F,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,IAAwC;IAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE7C,MAAM,IAAI,GAAG;QACX,6QAA6Q;QAC7Q,EAAE;QACF,4BAA4B;QAC5B,uNAAuN;QACvN,+GAA+G;QAC/G,EAAE;QACF,sBAAsB;QACtB,IAAI;YACF,CAAC,CAAC,0BAA0B,IAAI,UAAU;YAC1C,CAAC,CAAC,0PAA0P;QAC9P,sJAAsJ;QACtJ,EAAE;QACF,iBAAiB;QACjB,sMAAsM;QACtM,+KAA+K;QAC/K,8NAA8N;QAC9N,+HAA+H;QAC/H,EAAE;QACF,eAAe;QACf,iCAAiC;QACjC,8FAA8F;QAC9F,qJAAqJ;QACrJ,8HAA8H;QAC9H,EAAE;QACF,aAAa;QACb,gGAAgG;QAChG,yIAAyI;QACzI,yJAAyJ;QACzJ,EAAE;QACF,uBAAuB;QACvB,eAAe,EAAE;KAClB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,OAAO;QACL,WAAW,EAAE,qFAAqF;QAClG,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE;aACzC;SACF;KACF,CAAC;AACJ,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAgIA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAyDjD"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// The MCP server. Split out of index.ts so the CLI entrypoint can dispatch
|
|
2
|
+
// `okffs setup` WITHOUT importing this file — importing it pulls in the tool
|
|
3
|
+
// chain (→ github.ts), which resolves the token/owner/repo at import time and
|
|
4
|
+
// throws when unconfigured, which is exactly the state `okffs setup` runs in.
|
|
5
|
+
// index.ts only dynamically imports this module for a bare (no-arg) invocation,
|
|
6
|
+
// so the MCP server's behaviour is unchanged.
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
10
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
12
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
13
|
+
import * as createIssue from "./tools/create_issue.js";
|
|
14
|
+
import * as listIssues from "./tools/list_issues.js";
|
|
15
|
+
import * as closeIssue from "./tools/close_issue.js";
|
|
16
|
+
import * as deleteIssue from "./tools/delete_issue.js";
|
|
17
|
+
import * as deleteBranch from "./tools/delete_branch.js";
|
|
18
|
+
import * as getIssue from "./tools/get_issue.js";
|
|
19
|
+
import * as commentIssue from "./tools/comment_issue.js";
|
|
20
|
+
import * as createIssuesFromList from "./tools/create_issues_from_list.js";
|
|
21
|
+
import * as plan from "./tools/plan.js";
|
|
22
|
+
import * as linkIssues from "./tools/link_issues.js";
|
|
23
|
+
import * as createPullRequest from "./tools/create_pull_request.js";
|
|
24
|
+
import * as commitAndUpdate from "./tools/commit_and_update.js";
|
|
25
|
+
import * as listPrReviewComments from "./tools/list_pr_review_comments.js";
|
|
26
|
+
import * as replyToReviewComment from "./tools/reply_to_review_comment.js";
|
|
27
|
+
import * as resolveReviewThread from "./tools/resolve_review_thread.js";
|
|
28
|
+
import * as prepareRelease from "./tools/prepare_release.js";
|
|
29
|
+
import * as updateProjectStatus from "./tools/update_project_status.js";
|
|
30
|
+
import * as setIssueFields from "./tools/set_issue_fields.js";
|
|
31
|
+
import * as updateIssue from "./tools/update_issue.js";
|
|
32
|
+
import * as promoteBranch from "./tools/promote_branch.js";
|
|
33
|
+
import * as mergePullRequest from "./tools/merge_pull_request.js";
|
|
34
|
+
import * as fixIntoBase from "./tools/fix_into_base.js";
|
|
35
|
+
import * as configure from "./tools/configure.js";
|
|
36
|
+
import * as addressPrReview from "./prompts/address_pr_review.js";
|
|
37
|
+
import * as updateGuidance from "./prompts/update_guidance.js";
|
|
38
|
+
import * as setupPrompt from "./prompts/setup.js";
|
|
39
|
+
import { parseEnv } from "./cli/env.js";
|
|
40
|
+
import { allKeys } from "./cli/manifest.js";
|
|
41
|
+
const tools = [createIssue, listIssues, closeIssue, deleteIssue, deleteBranch, getIssue, commentIssue, createIssuesFromList, plan, linkIssues, createPullRequest, commitAndUpdate, listPrReviewComments, replyToReviewComment, resolveReviewThread, prepareRelease, updateProjectStatus, setIssueFields, updateIssue, promoteBranch, mergePullRequest, fixIntoBase, configure];
|
|
42
|
+
const prompts = [addressPrReview, updateGuidance, setupPrompt];
|
|
43
|
+
// Read the package version so the server reports the real version (dist/server.js
|
|
44
|
+
// lives one level below package.json in both dev and the published package).
|
|
45
|
+
const version = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
46
|
+
// Server-level instructions: the MCP `initialize` result carries this string and
|
|
47
|
+
// hosts (Claude Code, etc.) surface it to the agent every session. It ships with
|
|
48
|
+
// the package version, so upgrading okffs automatically updates the guidance the
|
|
49
|
+
// agent sees — this is how new tools/behaviour get adopted instead of the agent
|
|
50
|
+
// defaulting to raw git/gh (#169). Keep it tight: it's always-on context. This is
|
|
51
|
+
// the machine-visible counterpart to the human-facing README/CLAUDE.md guidance.
|
|
52
|
+
const SERVER_INSTRUCTIONS = `okffs owns the GitHub issue → branch → PR → merge → close workflow (plus, when enabled, a GitHub Projects v2 board and releases).
|
|
53
|
+
|
|
54
|
+
ALWAYS reach for an okffs tool before raw git/gh/GraphQL when one covers the action — this is a correctness rule, not a style preference:
|
|
55
|
+
- Identity/permissions: okffs authenticates with the configured GITHUB_TOKEN (a PAT scoped for this repo, incl. Projects / org Issue Fields when set). Raw gh/git uses whatever ambient CLI token is signed in — often the wrong identity or missing the Projects/org scopes, so it fails or acts as the wrong user.
|
|
56
|
+
- Conventions: okffs applies branch naming ({issue}-{slug}), the **Branch:** issue link, Closes #N, board placement, changelog fragments, and the OKFFS_PROTECTED_BRANCH invariant. Hand-rolled gh/git silently skips all of that.
|
|
57
|
+
Fall back to raw git/gh ONLY when no okffs tool fits the action.
|
|
58
|
+
|
|
59
|
+
Common action → tool:
|
|
60
|
+
- Start work: create_issue (creates the issue, the linked branch, and the **Branch:** line that create_pull_request/commit_and_update rely on). Many at once: create_issues_from_list or plan.
|
|
61
|
+
- Progress: commit_and_update (stage + commit + push + issue comment) — prefer over raw git commit/push.
|
|
62
|
+
- Open/finalize an issue's PR (into the base branch): create_pull_request (always adds Closes #N).
|
|
63
|
+
- Promotion/release gate — a base→protected PR with no issue, e.g. develop→main: promote_branch (issue-less; adds the PR to the board; NEVER use raw \`gh pr create\` for this).
|
|
64
|
+
- Edit an existing issue's core fields (title, assignees, labels, milestone, body): update_issue — prefer over raw \`gh issue edit\`. (Board Priority/Effort is set_issue_fields; Status column is update_project_status — those aren't issue fields.)
|
|
65
|
+
- Board: create_issue sets an inferred priority/effort at creation; set them on an EXISTING issue with set_issue_fields; move columns with update_project_status (Backlog/Ready/In Progress/Review — Done is GitHub's own automation).
|
|
66
|
+
- PR review: list_pr_review_comments → fix → reply_to_review_comment → resolve_review_thread (honours OKFFS_RESOLVE_THREADS); or the /okffs:address_pr_review prompt.
|
|
67
|
+
- Release prep: prepare_release (bumps version + rolls the changelog; does NOT tag or publish).
|
|
68
|
+
- Land an issue PR into the BASE branch (e.g. develop): merge_pull_request — the one okffs action that merges. Opt-in (OKFFS_AUTO_MERGE_BASE=true) and heavily gated; it verifies checks/threads itself and NEVER touches OKFFS_PROTECTED_BRANCH. Off by default → it just declines.
|
|
69
|
+
- Land an ISSUE-LESS fix into the BASE branch (no issue, e.g. review-comment cleanups): fix_into_base — the mirror of promote_branch. Opens (always safe) then merges under the same OKFFS_AUTO_MERGE_BASE gating as merge_pull_request. Prefer over raw \`gh pr create\`/\`gh pr merge\`; never targets OKFFS_PROTECTED_BRANCH.
|
|
70
|
+
|
|
71
|
+
Setup/config: if the user needs to configure okffs — a missing token/repo, or turning on a feature like Projects — offer the /okffs:setup prompt, which configures okffs conversationally right here in Claude Code (it interviews the user and persists via the configure tool, no terminal needed). The equivalent terminal wizard is \`npx @neturely/okffs setup\` — a guided CLI that writes/updates .env preserving the user's own vars and comments, but being interactive it must be run in their own terminal, not via a tool or the \`!\` shell.
|
|
72
|
+
|
|
73
|
+
Rules: never merge, tag, or publish into OKFFS_PROTECTED_BRANCH autonomously — okffs may OPEN a PR into it (promote_branch), but the merge/tag are yours to hand back for. merge_pull_request only ever lands PRs into the base tier, never the protected branch. Destructive tools (delete_issue, delete_branch) require confirmed: true (call once to preview, again to act).`;
|
|
74
|
+
// Compare two dotted versions; >0 if a is newer than b. Prerelease suffixes are
|
|
75
|
+
// ignored (split on `.`/`-`), which is fine for the coarse "did we upgrade?" check.
|
|
76
|
+
function isNewer(a, b) {
|
|
77
|
+
const pa = a.split(/[.-]/).map((n) => parseInt(n, 10) || 0);
|
|
78
|
+
const pb = b.split(/[.-]/).map((n) => parseInt(n, 10) || 0);
|
|
79
|
+
for (let i = 0; i < 3; i++) {
|
|
80
|
+
const d = (pa[i] || 0) - (pb[i] || 0);
|
|
81
|
+
if (d !== 0)
|
|
82
|
+
return d > 0;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
// Upgrade nudge (#242): if this repo's .env was configured by an older okffs (or
|
|
87
|
+
// predates version stamping) AND this okffs version has config options not set
|
|
88
|
+
// here, append a one-time-per-session note so the agent can OFFER /okffs:setup.
|
|
89
|
+
// Gentle by construction — it lands in the always-on instructions read on connect,
|
|
90
|
+
// not a per-turn interruption, and self-resolves once the user runs setup (which
|
|
91
|
+
// stamps the current version and marks the new options known/declined).
|
|
92
|
+
function upgradeNudge() {
|
|
93
|
+
try {
|
|
94
|
+
const parsed = parseEnv(join(process.cwd(), ".env"));
|
|
95
|
+
if (!parsed.exists)
|
|
96
|
+
return "";
|
|
97
|
+
const stamp = parsed.configuredVersion;
|
|
98
|
+
const configuredCount = allKeys().filter((k) => parsed.known.has(k)).length;
|
|
99
|
+
// Only for repos that actually use okffs config (a stamp, or some okffs vars);
|
|
100
|
+
// don't pester a .env that just isn't an okffs-configured repo.
|
|
101
|
+
if (!stamp && configuredCount === 0)
|
|
102
|
+
return "";
|
|
103
|
+
// Only when this okffs is newer than what configured the .env (or the .env
|
|
104
|
+
// predates stamping — stamp === null).
|
|
105
|
+
if (stamp && !isNewer(version, stamp))
|
|
106
|
+
return "";
|
|
107
|
+
const newKeys = allKeys().filter((k) => !parsed.known.has(k));
|
|
108
|
+
if (newKeys.length === 0)
|
|
109
|
+
return "";
|
|
110
|
+
const from = stamp ? `from ${stamp} ` : "";
|
|
111
|
+
return `\n\nUPGRADE NUDGE: this repo's .env was configured ${from}with an older okffs; okffs ${version} has ${newKeys.length} config option(s) not set here. Once, offer to run the /okffs:setup prompt (sync) to review the new options — if the user declines, drop it, don't repeat.`;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return "";
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export async function startServer() {
|
|
118
|
+
const server = new Server({ name: "okffs", version }, { capabilities: { tools: {}, prompts: {} }, instructions: SERVER_INSTRUCTIONS + upgradeNudge() });
|
|
119
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
120
|
+
// A tool may export an async getDescription() to compute its description at
|
|
121
|
+
// list time (e.g. create_issue injects the board's real Priority/Effort options
|
|
122
|
+
// — #133). Fall back to the static description on absence or failure.
|
|
123
|
+
tools: await Promise.all(tools.map(async (t) => {
|
|
124
|
+
let description = t.description;
|
|
125
|
+
const getDescription = t.getDescription;
|
|
126
|
+
if (getDescription) {
|
|
127
|
+
try {
|
|
128
|
+
description = await getDescription();
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
console.warn(`[okffs] getDescription() failed for ${t.name}, using static description:`, err instanceof Error ? err.message : err);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
name: t.name,
|
|
136
|
+
description,
|
|
137
|
+
inputSchema: zodToJsonSchema(t.inputSchema),
|
|
138
|
+
};
|
|
139
|
+
})),
|
|
140
|
+
}));
|
|
141
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
142
|
+
const tool = tools.find((t) => t.name === req.params.name);
|
|
143
|
+
if (!tool) {
|
|
144
|
+
throw new Error(`Unknown tool: ${req.params.name}`);
|
|
145
|
+
}
|
|
146
|
+
const input = tool.inputSchema.parse(req.params.arguments);
|
|
147
|
+
return tool.handler(input);
|
|
148
|
+
});
|
|
149
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
150
|
+
prompts: prompts.map((p) => ({
|
|
151
|
+
name: p.name,
|
|
152
|
+
description: p.description,
|
|
153
|
+
arguments: p.argumentDefs,
|
|
154
|
+
})),
|
|
155
|
+
}));
|
|
156
|
+
server.setRequestHandler(GetPromptRequestSchema, async (req) => {
|
|
157
|
+
const prompt = prompts.find((p) => p.name === req.params.name);
|
|
158
|
+
if (!prompt) {
|
|
159
|
+
throw new Error(`Unknown prompt: ${req.params.name}`);
|
|
160
|
+
}
|
|
161
|
+
return prompt.build(req.params.arguments ?? {});
|
|
162
|
+
});
|
|
163
|
+
const transport = new StdioServerTransport();
|
|
164
|
+
await server.connect(transport);
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const name = "configure";
|
|
3
|
+
export declare const description: string;
|
|
4
|
+
export declare const inputSchema: z.ZodObject<{
|
|
5
|
+
set: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
6
|
+
declined: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
set?: Record<string, string> | undefined;
|
|
9
|
+
declined?: string[] | undefined;
|
|
10
|
+
}, {
|
|
11
|
+
set?: Record<string, string> | undefined;
|
|
12
|
+
declined?: string[] | undefined;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function handler(input: z.infer<typeof inputSchema>): Promise<{
|
|
15
|
+
content: {
|
|
16
|
+
type: "text";
|
|
17
|
+
text: string;
|
|
18
|
+
}[];
|
|
19
|
+
isError: boolean;
|
|
20
|
+
} | {
|
|
21
|
+
content: {
|
|
22
|
+
type: "text";
|
|
23
|
+
text: string;
|
|
24
|
+
}[];
|
|
25
|
+
isError?: undefined;
|
|
26
|
+
}>;
|
|
27
|
+
//# sourceMappingURL=configure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../../src/tools/configure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,eAAO,MAAM,IAAI,cAAc,CAAC;AAEhC,eAAO,MAAM,WAAW,QAKoI,CAAC;AAE7J,eAAO,MAAM,WAAW;;;;;;;;;EAStB,CAAC;AASH,wBAAsB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC;;;;;;;;;;;;GAmE/D"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { allKeys } from "../cli/manifest.js";
|
|
4
|
+
import { parseEnv, serializeEnv, writeEnv } from "../cli/env.js";
|
|
5
|
+
import { packageVersion } from "../cli/banner.js";
|
|
6
|
+
export const name = "configure";
|
|
7
|
+
export const description = "Persist okffs configuration to the .env file in the current working directory — the write backend for the /okffs:setup conversational wizard. " +
|
|
8
|
+
"Reuses the same manifest + serializer as the `okffs setup` CLI, so both paths produce identical files: okffs owns ONLY a marked block, and the user's own variables and comments outside it are preserved verbatim. " +
|
|
9
|
+
"Pass `set` (a map of okffs env var → value) for variables to configure, and/or `declined` (a list of keys) for variables the user explicitly chose to skip (written as commented placeholders so a later sync won't re-ask them). " +
|
|
10
|
+
"Existing configured values that you don't pass are left untouched. Keys are validated against the manifest — unknown keys are rejected. " +
|
|
11
|
+
"Typically called by the /okffs:setup prompt after interviewing the user; not usually called directly. Secrets (GITHUB_TOKEN) are masked in the response.";
|
|
12
|
+
export const inputSchema = z.object({
|
|
13
|
+
set: z
|
|
14
|
+
.record(z.string())
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("Map of okffs env var name → value to set, e.g. { OKFFS_BASE_BRANCH: \"develop\", OKFFS_AUTO_PR: \"true\" }. Booleans are the strings \"true\"/\"false\"."),
|
|
17
|
+
declined: z
|
|
18
|
+
.array(z.string())
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Env var names the user explicitly declined — written as `# KEY=` placeholders so sync mode treats them as asked-and-declined, not new."),
|
|
21
|
+
});
|
|
22
|
+
const SECRET_KEYS = new Set(["GITHUB_TOKEN"]);
|
|
23
|
+
function mask(v) {
|
|
24
|
+
if (v.length <= 8)
|
|
25
|
+
return "•".repeat(v.length);
|
|
26
|
+
return `${v.slice(0, 4)}${"•".repeat(6)}${v.slice(-4)}`;
|
|
27
|
+
}
|
|
28
|
+
export async function handler(input) {
|
|
29
|
+
const set = input.set ?? {};
|
|
30
|
+
const declined = input.declined ?? [];
|
|
31
|
+
// Validate every provided key against the manifest before touching the file.
|
|
32
|
+
const known = new Set(allKeys());
|
|
33
|
+
const unknown = [...Object.keys(set), ...declined].filter((k) => !known.has(k));
|
|
34
|
+
if (unknown.length > 0) {
|
|
35
|
+
return {
|
|
36
|
+
content: [
|
|
37
|
+
{
|
|
38
|
+
type: "text",
|
|
39
|
+
text: `[okffs] Unknown config key(s): ${unknown.join(", ")}. ` +
|
|
40
|
+
`configure only accepts okffs manifest variables (GITHUB_* / OKFFS_*). No changes were written.`,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
isError: true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const envPath = join(process.cwd(), ".env");
|
|
47
|
+
const parsed = parseEnv(envPath);
|
|
48
|
+
// Seed from the existing file so untouched vars are preserved, then apply the
|
|
49
|
+
// caller's changes on top.
|
|
50
|
+
const collected = {};
|
|
51
|
+
for (const key of parsed.known) {
|
|
52
|
+
const val = parsed.values[key];
|
|
53
|
+
collected[key] = val !== undefined && val !== "" ? { state: "set", value: val } : { state: "declined", value: "" };
|
|
54
|
+
}
|
|
55
|
+
for (const [key, value] of Object.entries(set))
|
|
56
|
+
collected[key] = { state: "set", value };
|
|
57
|
+
for (const key of declined)
|
|
58
|
+
collected[key] = { state: "declined", value: "" };
|
|
59
|
+
try {
|
|
60
|
+
const contents = serializeEnv(collected, parsed.preamble, parsed.postamble, packageVersion());
|
|
61
|
+
writeEnv(envPath, contents);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
return {
|
|
65
|
+
content: [
|
|
66
|
+
{
|
|
67
|
+
type: "text",
|
|
68
|
+
text: `[okffs] Failed to write ${envPath}: ${err instanceof Error ? err.message : String(err)}. ` +
|
|
69
|
+
`Check that the directory is writable and not read-only. No changes were made.`,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
isError: true,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Build a human-readable summary (masking secrets).
|
|
76
|
+
const setLines = Object.entries(set).map(([k, v]) => ` ${k}=${SECRET_KEYS.has(k) ? mask(v) : v}`);
|
|
77
|
+
const declinedLine = declined.length ? ` declined (left unset): ${declined.join(", ")}` : "";
|
|
78
|
+
const summary = [
|
|
79
|
+
`Wrote ${envPath} (okffs v${packageVersion()}).`,
|
|
80
|
+
parsed.exists ? "Updated the okffs-managed block; your other variables and comments were preserved." : "Created a new .env with the okffs-managed block.",
|
|
81
|
+
setLines.length ? `Set ${setLines.length} variable(s):` : "",
|
|
82
|
+
...setLines,
|
|
83
|
+
declinedLine,
|
|
84
|
+
"",
|
|
85
|
+
"Reminder: restart the MCP server (or Claude Code) so okffs re-reads .env.",
|
|
86
|
+
]
|
|
87
|
+
.filter(Boolean)
|
|
88
|
+
.join("\n");
|
|
89
|
+
return { content: [{ type: "text", text: summary }] };
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=configure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configure.js","sourceRoot":"","sources":["../../src/tools/configure.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,10 +5,10 @@ export declare const inputSchema: z.ZodObject<{
|
|
|
5
5
|
issue: z.ZodNumber;
|
|
6
6
|
status: z.ZodEnum<["Backlog", "Ready", "In Progress", "Review"]>;
|
|
7
7
|
}, "strip", z.ZodTypeAny, {
|
|
8
|
-
status: "Backlog" | "
|
|
8
|
+
status: "Backlog" | "Review" | "Ready" | "In Progress";
|
|
9
9
|
issue: number;
|
|
10
10
|
}, {
|
|
11
|
-
status: "Backlog" | "
|
|
11
|
+
status: "Backlog" | "Review" | "Ready" | "In Progress";
|
|
12
12
|
issue: number;
|
|
13
13
|
}>;
|
|
14
14
|
export declare function handler(input: z.infer<typeof inputSchema>): Promise<{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neturely/okffs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"mcpName": "io.github.neturely/okffs",
|
|
5
5
|
"description": "MCP server that connects Claude Code to GitHub — create and manage issues and branches without leaving your editor.",
|
|
6
6
|
"type": "module",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "tsc",
|
|
13
13
|
"prepublishOnly": "npm run build",
|
|
14
|
-
"postbuild": "node -e \"const fs=require('fs');const f
|
|
14
|
+
"postbuild": "node -e \"const fs=require('fs');for(const f of ['dist/index.js','dist/cli/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 dist/cli/index.js",
|
|
15
15
|
"dev": "node --env-file=.env --import tsx/esm src/index.ts",
|
|
16
16
|
"start": "node --env-file=.env dist/index.js"
|
|
17
17
|
},
|
|
@@ -35,7 +35,11 @@
|
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20.12.0"
|
|
40
|
+
},
|
|
38
41
|
"dependencies": {
|
|
42
|
+
"@clack/prompts": "^1.7.0",
|
|
39
43
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
40
44
|
"dotenv": "^17.4.2",
|
|
41
45
|
"zod": "^3.23.8",
|