@selfagency/beans-mcp 0.1.4 → 0.4.2
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/README.md +63 -6
- package/beans-mcp-server.cjs +268 -34
- package/index.cjs +268 -34
- package/index.d.ts +19 -1
- package/index.js +268 -34
- package/package.json +1 -1
package/index.cjs
CHANGED
|
@@ -22747,7 +22747,7 @@ var init_utils = __esm({
|
|
|
22747
22747
|
});
|
|
22748
22748
|
|
|
22749
22749
|
// src/internal/graphql.ts
|
|
22750
|
-
var LIST_BEANS_QUERY, CREATE_BEAN_MUTATION, UPDATE_BEAN_MUTATION, DELETE_BEAN_MUTATION;
|
|
22750
|
+
var LIST_BEANS_QUERY, CREATE_BEAN_MUTATION, UPDATE_BEAN_MUTATION, UPDATE_BEAN_MUTATION_WITH_IF_MATCH, DELETE_BEAN_MUTATION;
|
|
22751
22751
|
var init_graphql = __esm({
|
|
22752
22752
|
"src/internal/graphql.ts"() {
|
|
22753
22753
|
"use strict";
|
|
@@ -22765,6 +22765,11 @@ var init_graphql = __esm({
|
|
|
22765
22765
|
mutation($id: ID!, $input: UpdateBeanInput!) {
|
|
22766
22766
|
updateBean(id: $id, input: $input) { id slug path title body status type priority tags parentId blockingIds blockedByIds createdAt updatedAt etag }
|
|
22767
22767
|
}
|
|
22768
|
+
`;
|
|
22769
|
+
UPDATE_BEAN_MUTATION_WITH_IF_MATCH = `
|
|
22770
|
+
mutation($id: ID!, $input: UpdateBeanInput!, $ifMatch: String!) {
|
|
22771
|
+
updateBean(id: $id, input: $input, ifMatch: $ifMatch) { id slug path title body status type priority tags parentId blockingIds blockedByIds createdAt updatedAt etag }
|
|
22772
|
+
}
|
|
22768
22773
|
`;
|
|
22769
22774
|
DELETE_BEAN_MUTATION = `
|
|
22770
22775
|
mutation($id: ID!) {
|
|
@@ -22922,10 +22927,50 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22922
22927
|
if (updates.body !== void 0) {
|
|
22923
22928
|
updateInput.body = updates.body;
|
|
22924
22929
|
}
|
|
22925
|
-
const
|
|
22926
|
-
|
|
22927
|
-
|
|
22928
|
-
}
|
|
22930
|
+
const bodyMod = {};
|
|
22931
|
+
if (updates.bodyAppend !== void 0) {
|
|
22932
|
+
bodyMod.append = updates.bodyAppend;
|
|
22933
|
+
}
|
|
22934
|
+
if (Array.isArray(updates.bodyReplace) && updates.bodyReplace.length > 0) {
|
|
22935
|
+
bodyMod.replace = updates.bodyReplace;
|
|
22936
|
+
}
|
|
22937
|
+
if (Object.keys(bodyMod).length > 0) {
|
|
22938
|
+
updateInput.bodyMod = bodyMod;
|
|
22939
|
+
}
|
|
22940
|
+
let data;
|
|
22941
|
+
let errors;
|
|
22942
|
+
if (updates.ifMatch) {
|
|
22943
|
+
try {
|
|
22944
|
+
const res = await this.executeGraphQL(UPDATE_BEAN_MUTATION_WITH_IF_MATCH, {
|
|
22945
|
+
id: beanId,
|
|
22946
|
+
input: updateInput,
|
|
22947
|
+
ifMatch: updates.ifMatch
|
|
22948
|
+
});
|
|
22949
|
+
data = res.data;
|
|
22950
|
+
errors = res.errors;
|
|
22951
|
+
} catch (error48) {
|
|
22952
|
+
const message = error48.message || "";
|
|
22953
|
+
const unsupportedIfMatch = /unknown argument.*ifMatch|unknown field.*ifMatch|ifMatch.*not defined|field .*updateBean.* argument .*ifMatch/i.test(
|
|
22954
|
+
message
|
|
22955
|
+
);
|
|
22956
|
+
if (!unsupportedIfMatch) {
|
|
22957
|
+
throw error48;
|
|
22958
|
+
}
|
|
22959
|
+
const fallback = await this.executeGraphQL(UPDATE_BEAN_MUTATION, {
|
|
22960
|
+
id: beanId,
|
|
22961
|
+
input: updateInput
|
|
22962
|
+
});
|
|
22963
|
+
data = fallback.data;
|
|
22964
|
+
errors = fallback.errors;
|
|
22965
|
+
}
|
|
22966
|
+
} else {
|
|
22967
|
+
const res = await this.executeGraphQL(UPDATE_BEAN_MUTATION, {
|
|
22968
|
+
id: beanId,
|
|
22969
|
+
input: updateInput
|
|
22970
|
+
});
|
|
22971
|
+
data = res.data;
|
|
22972
|
+
errors = res.errors;
|
|
22973
|
+
}
|
|
22929
22974
|
if (errors && errors.length > 0) {
|
|
22930
22975
|
throw new Error(`GraphQL error: ${errors.map((e) => e.message).join(", ")}`);
|
|
22931
22976
|
}
|
|
@@ -22945,6 +22990,21 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22945
22990
|
const content = await (0, import_promises.readFile)(configPath, "utf8");
|
|
22946
22991
|
return { configPath, content };
|
|
22947
22992
|
}
|
|
22993
|
+
async primeInstructions() {
|
|
22994
|
+
const { stdout } = await execFileAsync(this.cliPath, ["prime"], {
|
|
22995
|
+
cwd: this.workspaceRoot,
|
|
22996
|
+
env: this.getSafeEnv(),
|
|
22997
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
22998
|
+
timeout: 3e4
|
|
22999
|
+
});
|
|
23000
|
+
return stdout.trim();
|
|
23001
|
+
}
|
|
23002
|
+
async writeInstructions(instructions) {
|
|
23003
|
+
const instructionsPath = (0, import_node_path2.join)(this.workspaceRoot, ".github", "instructions", "beans-prime.instructions.md");
|
|
23004
|
+
await (0, import_promises.mkdir)((0, import_node_path2.dirname)(instructionsPath), { recursive: true });
|
|
23005
|
+
await (0, import_promises.writeFile)(instructionsPath, instructions, "utf8");
|
|
23006
|
+
return instructionsPath;
|
|
23007
|
+
}
|
|
22948
23008
|
async graphqlSchema() {
|
|
22949
23009
|
const { stdout } = await execFileAsync(this.cliPath, ["graphql", "--schema"], {
|
|
22950
23010
|
cwd: this.workspaceRoot,
|
|
@@ -31089,6 +31149,10 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
31089
31149
|
}
|
|
31090
31150
|
};
|
|
31091
31151
|
|
|
31152
|
+
// src/server/BeansMcpServer.ts
|
|
31153
|
+
var import_node_child_process2 = require("child_process");
|
|
31154
|
+
var import_node_util2 = require("util");
|
|
31155
|
+
|
|
31092
31156
|
// src/internal/queryHelpers.ts
|
|
31093
31157
|
function sortBeansInternal(beans, mode) {
|
|
31094
31158
|
const sorted = [...beans];
|
|
@@ -31144,15 +31208,23 @@ async function handleQueryOperation(backend, params) {
|
|
|
31144
31208
|
const { operation, mode, statuses, types, search, tags, writeToWorkspaceInstructions, includeClosed } = params;
|
|
31145
31209
|
if (operation === "llm_context") {
|
|
31146
31210
|
const graphqlSchema = typeof backend.graphqlSchema === "function" ? await backend.graphqlSchema() : "";
|
|
31147
|
-
|
|
31211
|
+
let generatedInstructions = "";
|
|
31212
|
+
if (typeof backend.primeInstructions === "function") {
|
|
31213
|
+
try {
|
|
31214
|
+
generatedInstructions = await backend.primeInstructions();
|
|
31215
|
+
} catch {
|
|
31216
|
+
generatedInstructions = "";
|
|
31217
|
+
}
|
|
31218
|
+
}
|
|
31219
|
+
const instructionsPath = writeToWorkspaceInstructions && typeof backend.writeInstructions === "function" ? await backend.writeInstructions(generatedInstructions) : null;
|
|
31148
31220
|
return {
|
|
31149
31221
|
content: [
|
|
31150
31222
|
{
|
|
31151
31223
|
type: "text",
|
|
31152
|
-
text: JSON.stringify({ graphqlSchema, generatedInstructions
|
|
31224
|
+
text: JSON.stringify({ graphqlSchema, generatedInstructions, instructionsPath }, null, 2)
|
|
31153
31225
|
}
|
|
31154
31226
|
],
|
|
31155
|
-
structuredContent: { graphqlSchema, generatedInstructions
|
|
31227
|
+
structuredContent: { graphqlSchema, generatedInstructions, instructionsPath }
|
|
31156
31228
|
};
|
|
31157
31229
|
}
|
|
31158
31230
|
if (operation === "open_config") {
|
|
@@ -31198,6 +31270,31 @@ async function handleQueryOperation(backend, params) {
|
|
|
31198
31270
|
structuredContent: { query: search, count: beans2.length, beans: beans2 }
|
|
31199
31271
|
};
|
|
31200
31272
|
}
|
|
31273
|
+
if (operation === "ready") {
|
|
31274
|
+
const allBeans = await backend.list();
|
|
31275
|
+
const byId = new Map(allBeans.map((bean) => [bean.id, bean]));
|
|
31276
|
+
const candidates = await backend.list({ status: normalizedStatuses, type: normalizedTypes, search });
|
|
31277
|
+
const readyBeans = candidates.filter((bean) => {
|
|
31278
|
+
if (bean.status !== "todo") {
|
|
31279
|
+
return false;
|
|
31280
|
+
}
|
|
31281
|
+
const blockedBy = bean.blockedByIds || [];
|
|
31282
|
+
if (blockedBy.length === 0) {
|
|
31283
|
+
return true;
|
|
31284
|
+
}
|
|
31285
|
+
return blockedBy.every((blockerId) => {
|
|
31286
|
+
const blocker = byId.get(blockerId);
|
|
31287
|
+
if (!blocker) {
|
|
31288
|
+
return false;
|
|
31289
|
+
}
|
|
31290
|
+
return blocker.status === "completed" || blocker.status === "scrapped";
|
|
31291
|
+
});
|
|
31292
|
+
});
|
|
31293
|
+
return {
|
|
31294
|
+
content: [{ type: "text", text: JSON.stringify({ count: readyBeans.length, beans: readyBeans }, null, 2) }],
|
|
31295
|
+
structuredContent: { count: readyBeans.length, beans: readyBeans }
|
|
31296
|
+
};
|
|
31297
|
+
}
|
|
31201
31298
|
const beans = await backend.list({ status: normalizedStatuses, type: normalizedTypes, search });
|
|
31202
31299
|
const sorted = sortBeansInternal(beans, mode ?? "status-priority-type-title");
|
|
31203
31300
|
return {
|
|
@@ -31220,7 +31317,7 @@ init_utils();
|
|
|
31220
31317
|
// package.json
|
|
31221
31318
|
var package_default = {
|
|
31222
31319
|
name: "@selfagency/beans-mcp",
|
|
31223
|
-
version: "0.
|
|
31320
|
+
version: "0.4.2",
|
|
31224
31321
|
private: false,
|
|
31225
31322
|
description: "MCP (Model Context Protocol) server for Beans issue tracker",
|
|
31226
31323
|
author: {
|
|
@@ -31275,18 +31372,18 @@ var package_default = {
|
|
|
31275
31372
|
devDependencies: {
|
|
31276
31373
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
31277
31374
|
"@octokit/rest": "^22.0.1",
|
|
31278
|
-
"@types/node": "
|
|
31279
|
-
"@vitest/coverage-v8": "^4.0
|
|
31280
|
-
"@vitest/ui": "4.0
|
|
31375
|
+
"@types/node": "25.5.0",
|
|
31376
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
31377
|
+
"@vitest/ui": "4.1.0",
|
|
31281
31378
|
husky: "^9.1.7",
|
|
31282
|
-
"lint-staged": "^16.
|
|
31379
|
+
"lint-staged": "^16.3.3",
|
|
31283
31380
|
ora: "^9.3.0",
|
|
31284
|
-
oxfmt: "^0.
|
|
31285
|
-
oxlint: "^1.
|
|
31286
|
-
"oxlint-tsgolint": "^0.
|
|
31381
|
+
oxfmt: "^0.40.0",
|
|
31382
|
+
oxlint: "^1.55.0",
|
|
31383
|
+
"oxlint-tsgolint": "^0.16.0",
|
|
31287
31384
|
tsup: "8.5.1",
|
|
31288
31385
|
typescript: "^5.9.3",
|
|
31289
|
-
vitest: "4.0
|
|
31386
|
+
vitest: "4.1.0",
|
|
31290
31387
|
zod: "4.3.6",
|
|
31291
31388
|
zx: "^8.8.5"
|
|
31292
31389
|
},
|
|
@@ -31302,6 +31399,45 @@ var package_default = {
|
|
|
31302
31399
|
};
|
|
31303
31400
|
|
|
31304
31401
|
// src/server/BeansMcpServer.ts
|
|
31402
|
+
var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
|
|
31403
|
+
var PACKAGE_VERSION = package_default.version ?? "0.0.0-dev";
|
|
31404
|
+
function getSafeCliEnv(env) {
|
|
31405
|
+
const whitelist = ["PATH", "HOME", "USER", "LANG", "LC_ALL", "LC_CTYPE", "SHELL"];
|
|
31406
|
+
const safeEnv = {};
|
|
31407
|
+
for (const key of whitelist) {
|
|
31408
|
+
if (env[key]) {
|
|
31409
|
+
safeEnv[key] = env[key];
|
|
31410
|
+
}
|
|
31411
|
+
}
|
|
31412
|
+
for (const key in env) {
|
|
31413
|
+
if (key.startsWith("BEANS_")) {
|
|
31414
|
+
safeEnv[key] = env[key];
|
|
31415
|
+
}
|
|
31416
|
+
}
|
|
31417
|
+
return safeEnv;
|
|
31418
|
+
}
|
|
31419
|
+
function extractVersionFromOutput(output) {
|
|
31420
|
+
const trimmed = output.trim();
|
|
31421
|
+
if (!trimmed) {
|
|
31422
|
+
return null;
|
|
31423
|
+
}
|
|
31424
|
+
const match = trimmed.match(/(?:^|[^\d])v?(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/);
|
|
31425
|
+
return match?.[1] ?? null;
|
|
31426
|
+
}
|
|
31427
|
+
async function detectBeansCliVersion(cliPath, workspaceRoot) {
|
|
31428
|
+
try {
|
|
31429
|
+
const { stdout, stderr } = await execFileAsync2(cliPath, ["version"], {
|
|
31430
|
+
cwd: workspaceRoot,
|
|
31431
|
+
env: getSafeCliEnv(process.env),
|
|
31432
|
+
maxBuffer: 1024 * 1024,
|
|
31433
|
+
timeout: 5e3
|
|
31434
|
+
});
|
|
31435
|
+
return extractVersionFromOutput(`${stdout}
|
|
31436
|
+
${stderr}`);
|
|
31437
|
+
} catch {
|
|
31438
|
+
return null;
|
|
31439
|
+
}
|
|
31440
|
+
}
|
|
31305
31441
|
async function getBeanById(backend, beanId) {
|
|
31306
31442
|
try {
|
|
31307
31443
|
const beans = await backend.list();
|
|
@@ -31321,7 +31457,35 @@ function initHandler(backend) {
|
|
|
31321
31457
|
};
|
|
31322
31458
|
}
|
|
31323
31459
|
function viewHandler(backend) {
|
|
31324
|
-
return async ({ beanId }) =>
|
|
31460
|
+
return async ({ beanId, beanIds }) => {
|
|
31461
|
+
const ids = Array.isArray(beanIds) && beanIds.length > 0 ? beanIds : beanId ? [beanId] : [];
|
|
31462
|
+
if (ids.length === 0) {
|
|
31463
|
+
throw new Error("Either beanId or beanIds must be provided");
|
|
31464
|
+
}
|
|
31465
|
+
if (ids.length === 1) {
|
|
31466
|
+
const bean = await getBeanById(backend, ids[0]);
|
|
31467
|
+
return makeTextAndStructured({ bean });
|
|
31468
|
+
}
|
|
31469
|
+
const beans = await backend.list();
|
|
31470
|
+
const byId = new Map(beans.map((b) => [b.id, b]));
|
|
31471
|
+
const found = ids.map((id) => byId.get(id)).filter(Boolean);
|
|
31472
|
+
const missingBeanIds = ids.filter((id) => !byId.has(id));
|
|
31473
|
+
return makeTextAndStructured({ beans: found, missingBeanIds, count: found.length, requestedCount: ids.length });
|
|
31474
|
+
};
|
|
31475
|
+
}
|
|
31476
|
+
async function checkVersionCompatibility(cliPath, workspaceRoot, detector) {
|
|
31477
|
+
const detectedBeansVersion = await detector(cliPath, workspaceRoot);
|
|
31478
|
+
if (!detectedBeansVersion) {
|
|
31479
|
+
console.error(
|
|
31480
|
+
`[beans-mcp] warning: unable to determine Beans CLI version from \`${cliPath}\`; proceeding without version compatibility checks.`
|
|
31481
|
+
);
|
|
31482
|
+
return;
|
|
31483
|
+
}
|
|
31484
|
+
if (detectedBeansVersion !== PACKAGE_VERSION) {
|
|
31485
|
+
console.error(
|
|
31486
|
+
`[beans-mcp] warning: version mismatch detected (beans=${detectedBeansVersion}, beans-mcp=${PACKAGE_VERSION}); continuing startup.`
|
|
31487
|
+
);
|
|
31488
|
+
}
|
|
31325
31489
|
}
|
|
31326
31490
|
function createHandler(backend) {
|
|
31327
31491
|
return async (input) => makeTextAndStructured({ bean: await backend.create(input) });
|
|
@@ -31357,17 +31521,56 @@ function updateHandler(backend) {
|
|
|
31357
31521
|
clearParent: input.clearParent,
|
|
31358
31522
|
blocking: input.blocking,
|
|
31359
31523
|
blockedBy: input.blockedBy,
|
|
31360
|
-
body: input.body
|
|
31524
|
+
body: input.body,
|
|
31525
|
+
bodyAppend: input.bodyAppend,
|
|
31526
|
+
bodyReplace: input.bodyReplace,
|
|
31527
|
+
ifMatch: input.ifMatch
|
|
31361
31528
|
})
|
|
31362
31529
|
});
|
|
31363
31530
|
}
|
|
31364
31531
|
function deleteHandler(backend) {
|
|
31365
|
-
return async ({ beanId, force }) => {
|
|
31366
|
-
const
|
|
31367
|
-
if (
|
|
31368
|
-
throw new Error("
|
|
31532
|
+
return async ({ beanId, beanIds, force }) => {
|
|
31533
|
+
const ids = Array.isArray(beanIds) && beanIds.length > 0 ? beanIds : beanId ? [beanId] : [];
|
|
31534
|
+
if (ids.length === 0) {
|
|
31535
|
+
throw new Error("Either beanId or beanIds must be provided");
|
|
31536
|
+
}
|
|
31537
|
+
if (ids.length === 1) {
|
|
31538
|
+
const bean = await getBeanById(backend, ids[0]);
|
|
31539
|
+
if (!force && bean.status !== "draft" && bean.status !== "scrapped") {
|
|
31540
|
+
throw new Error("Only draft and scrapped beans are deletable unless force=true");
|
|
31541
|
+
}
|
|
31542
|
+
return makeTextAndStructured(await backend.delete(ids[0]));
|
|
31369
31543
|
}
|
|
31370
|
-
|
|
31544
|
+
const beans = await backend.list();
|
|
31545
|
+
const byId = new Map(beans.map((b) => [b.id, b]));
|
|
31546
|
+
const results = [];
|
|
31547
|
+
for (const id of ids) {
|
|
31548
|
+
const bean = byId.get(id);
|
|
31549
|
+
if (!bean) {
|
|
31550
|
+
results.push({ beanId: id, deleted: false, error: "Bean not found" });
|
|
31551
|
+
continue;
|
|
31552
|
+
}
|
|
31553
|
+
if (!force && bean.status !== "draft" && bean.status !== "scrapped") {
|
|
31554
|
+
results.push({
|
|
31555
|
+
beanId: id,
|
|
31556
|
+
deleted: false,
|
|
31557
|
+
error: "Only draft and scrapped beans are deletable unless force=true"
|
|
31558
|
+
});
|
|
31559
|
+
continue;
|
|
31560
|
+
}
|
|
31561
|
+
try {
|
|
31562
|
+
await backend.delete(id);
|
|
31563
|
+
results.push({ beanId: id, deleted: true });
|
|
31564
|
+
} catch (error48) {
|
|
31565
|
+
results.push({ beanId: id, deleted: false, error: error48.message });
|
|
31566
|
+
}
|
|
31567
|
+
}
|
|
31568
|
+
return makeTextAndStructured({
|
|
31569
|
+
results,
|
|
31570
|
+
requestedCount: ids.length,
|
|
31571
|
+
deletedCount: results.filter((r) => r.deleted).length,
|
|
31572
|
+
failedCount: results.filter((r) => !r.deleted).length
|
|
31573
|
+
});
|
|
31371
31574
|
};
|
|
31372
31575
|
}
|
|
31373
31576
|
function queryHandler(backend) {
|
|
@@ -31428,7 +31631,12 @@ function registerTools(server, backend) {
|
|
|
31428
31631
|
{
|
|
31429
31632
|
title: "View Bean",
|
|
31430
31633
|
description: "Fetch full bean details by ID.",
|
|
31431
|
-
inputSchema: external_exports3.object({
|
|
31634
|
+
inputSchema: external_exports3.object({
|
|
31635
|
+
beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH).optional(),
|
|
31636
|
+
beanIds: external_exports3.array(external_exports3.string().min(1).max(MAX_ID_LENGTH)).optional()
|
|
31637
|
+
}).refine((input) => Boolean(input.beanId) || Array.isArray(input.beanIds) && input.beanIds.length > 0, {
|
|
31638
|
+
message: "Either beanId or beanIds must be provided"
|
|
31639
|
+
}),
|
|
31432
31640
|
annotations: {
|
|
31433
31641
|
readOnlyHint: true,
|
|
31434
31642
|
destructiveHint: false,
|
|
@@ -31517,8 +31725,21 @@ function registerTools(server, backend) {
|
|
|
31517
31725
|
clearParent: external_exports3.boolean().optional(),
|
|
31518
31726
|
blocking: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
|
|
31519
31727
|
blockedBy: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
|
|
31520
|
-
body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional()
|
|
31521
|
-
|
|
31728
|
+
body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional(),
|
|
31729
|
+
bodyAppend: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional(),
|
|
31730
|
+
bodyReplace: external_exports3.array(
|
|
31731
|
+
external_exports3.object({
|
|
31732
|
+
old: external_exports3.string().max(MAX_DESCRIPTION_LENGTH),
|
|
31733
|
+
new: external_exports3.string().max(MAX_DESCRIPTION_LENGTH)
|
|
31734
|
+
})
|
|
31735
|
+
).optional(),
|
|
31736
|
+
ifMatch: external_exports3.string().max(MAX_METADATA_LENGTH).optional()
|
|
31737
|
+
}).refine(
|
|
31738
|
+
(input) => !(input.body !== void 0 && (input.bodyAppend !== void 0 || input.bodyReplace !== void 0)),
|
|
31739
|
+
{
|
|
31740
|
+
message: "body cannot be combined with bodyAppend/bodyReplace"
|
|
31741
|
+
}
|
|
31742
|
+
),
|
|
31522
31743
|
annotations: {
|
|
31523
31744
|
readOnlyHint: false,
|
|
31524
31745
|
destructiveHint: false,
|
|
@@ -31534,8 +31755,11 @@ function registerTools(server, backend) {
|
|
|
31534
31755
|
title: "Delete Bean",
|
|
31535
31756
|
description: "Delete a bean (intended for draft/scrapped beans).",
|
|
31536
31757
|
inputSchema: external_exports3.object({
|
|
31537
|
-
beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH),
|
|
31758
|
+
beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH).optional(),
|
|
31759
|
+
beanIds: external_exports3.array(external_exports3.string().min(1).max(MAX_ID_LENGTH)).optional(),
|
|
31538
31760
|
force: external_exports3.boolean().default(false)
|
|
31761
|
+
}).refine((input) => Boolean(input.beanId) || Array.isArray(input.beanIds) && input.beanIds.length > 0, {
|
|
31762
|
+
message: "Either beanId or beanIds must be provided"
|
|
31539
31763
|
}),
|
|
31540
31764
|
annotations: {
|
|
31541
31765
|
readOnlyHint: false,
|
|
@@ -31552,7 +31776,7 @@ function registerTools(server, backend) {
|
|
|
31552
31776
|
title: "Query Beans",
|
|
31553
31777
|
description: "Unified query tool for refresh, filter, search, and sort operations.",
|
|
31554
31778
|
inputSchema: external_exports3.object({
|
|
31555
|
-
operation: external_exports3.enum(["refresh", "filter", "search", "sort", "llm_context", "open_config"]).default("refresh"),
|
|
31779
|
+
operation: external_exports3.enum(["refresh", "filter", "search", "sort", "ready", "llm_context", "open_config"]).default("refresh"),
|
|
31556
31780
|
mode: external_exports3.enum(["status-priority-type-title", "updated", "created", "id"]).optional(),
|
|
31557
31781
|
statuses: external_exports3.array(external_exports3.string().max(MAX_METADATA_LENGTH)).nullable().optional(),
|
|
31558
31782
|
types: external_exports3.array(external_exports3.string().max(MAX_METADATA_LENGTH)).nullable().optional(),
|
|
@@ -31634,6 +31858,12 @@ var MutableBackend = class {
|
|
|
31634
31858
|
openConfig() {
|
|
31635
31859
|
return this.inner.openConfig();
|
|
31636
31860
|
}
|
|
31861
|
+
primeInstructions() {
|
|
31862
|
+
return this.inner.primeInstructions?.() ?? Promise.resolve("");
|
|
31863
|
+
}
|
|
31864
|
+
writeInstructions(instructions) {
|
|
31865
|
+
return this.inner.writeInstructions?.(instructions) ?? Promise.resolve(null);
|
|
31866
|
+
}
|
|
31637
31867
|
graphqlSchema() {
|
|
31638
31868
|
return this.inner.graphqlSchema();
|
|
31639
31869
|
}
|
|
@@ -31671,7 +31901,7 @@ async function createBeansMcpServer(opts) {
|
|
|
31671
31901
|
const backend = opts.backend || new BeansCliBackend2(opts.workspaceRoot, opts.cliPath || "beans", opts.logDir);
|
|
31672
31902
|
const server = new McpServer({
|
|
31673
31903
|
name: opts.name || "beans-mcp-server",
|
|
31674
|
-
version: opts.version ||
|
|
31904
|
+
version: opts.version || PACKAGE_VERSION
|
|
31675
31905
|
});
|
|
31676
31906
|
registerTools(server, backend);
|
|
31677
31907
|
return { server, backend };
|
|
@@ -31743,17 +31973,17 @@ function parseCliArgs(argv) {
|
|
|
31743
31973
|
}
|
|
31744
31974
|
return { workspaceRoot, workspaceExplicit, cliPath, port, logDir };
|
|
31745
31975
|
}
|
|
31746
|
-
async function startBeansMcpServer(argv, _resolveRoots) {
|
|
31976
|
+
async function startBeansMcpServer(argv, _resolveRoots, _detectBeansVersion) {
|
|
31747
31977
|
const { BeansCliBackend: BeansCliBackend2 } = await Promise.resolve().then(() => (init_backend(), backend_exports));
|
|
31748
31978
|
const { StdioServerTransport: StdioServerTransport2 } = await Promise.resolve().then(() => (init_stdio2(), stdio_exports));
|
|
31749
31979
|
const { workspaceRoot, workspaceExplicit, cliPath, port, logDir } = parseCliArgs(argv);
|
|
31980
|
+
let effectiveWorkspaceRoot = workspaceRoot;
|
|
31750
31981
|
process.env.BEANS_VSCODE_MCP_PORT = String(port);
|
|
31751
31982
|
process.env.BEANS_MCP_PORT = String(port);
|
|
31752
31983
|
try {
|
|
31753
|
-
const version2 = package_default.version ?? "0.0.0-dev";
|
|
31754
31984
|
const workspaceLabel = workspaceExplicit ? workspaceRoot : "(auto from roots)";
|
|
31755
31985
|
console.error(
|
|
31756
|
-
`[beans-mcp] v${
|
|
31986
|
+
`[beans-mcp] v${PACKAGE_VERSION} starting (port=${port}, workspace=${workspaceLabel}, cli=${cliPath}, logDir=${logDir})`
|
|
31757
31987
|
);
|
|
31758
31988
|
} catch {
|
|
31759
31989
|
}
|
|
@@ -31770,13 +32000,17 @@ async function startBeansMcpServer(argv, _resolveRoots) {
|
|
|
31770
32000
|
const resolver = _resolveRoots ?? resolveWorkspaceFromRoots;
|
|
31771
32001
|
const rootPath = await resolver(server);
|
|
31772
32002
|
if (rootPath) {
|
|
31773
|
-
mutable.setInner(new BeansCliBackend2(rootPath, cliPath));
|
|
32003
|
+
mutable.setInner(new BeansCliBackend2(rootPath, cliPath, logDir));
|
|
32004
|
+
effectiveWorkspaceRoot = rootPath;
|
|
31774
32005
|
try {
|
|
31775
32006
|
console.error(`[beans-mcp] workspace resolved from roots: ${rootPath}`);
|
|
31776
32007
|
} catch {
|
|
31777
32008
|
}
|
|
31778
32009
|
}
|
|
31779
32010
|
}
|
|
32011
|
+
const beansVersionDetector = _detectBeansVersion ?? detectBeansCliVersion;
|
|
32012
|
+
void checkVersionCompatibility(cliPath, effectiveWorkspaceRoot, beansVersionDetector).catch(() => {
|
|
32013
|
+
});
|
|
31780
32014
|
}
|
|
31781
32015
|
|
|
31782
32016
|
// src/index.ts
|
package/index.d.ts
CHANGED
|
@@ -69,12 +69,20 @@ interface BackendInterface {
|
|
|
69
69
|
blocking?: string[];
|
|
70
70
|
blockedBy?: string[];
|
|
71
71
|
body?: string;
|
|
72
|
+
bodyAppend?: string;
|
|
73
|
+
bodyReplace?: Array<{
|
|
74
|
+
old: string;
|
|
75
|
+
new: string;
|
|
76
|
+
}>;
|
|
77
|
+
ifMatch?: string;
|
|
72
78
|
}): Promise<BeanRecord>;
|
|
73
79
|
delete(beanId: string): Promise<Record<string, unknown>>;
|
|
74
80
|
openConfig(): Promise<{
|
|
75
81
|
configPath: string;
|
|
76
82
|
content: string;
|
|
77
83
|
}>;
|
|
84
|
+
primeInstructions?(): Promise<string>;
|
|
85
|
+
writeInstructions?(instructions: string): Promise<string | null>;
|
|
78
86
|
graphqlSchema(): Promise<string>;
|
|
79
87
|
readOutputLog(options?: {
|
|
80
88
|
lines?: number;
|
|
@@ -146,12 +154,20 @@ declare class BeansCliBackend implements BackendInterface {
|
|
|
146
154
|
blocking?: string[];
|
|
147
155
|
blockedBy?: string[];
|
|
148
156
|
body?: string;
|
|
157
|
+
bodyAppend?: string;
|
|
158
|
+
bodyReplace?: Array<{
|
|
159
|
+
old: string;
|
|
160
|
+
new: string;
|
|
161
|
+
}>;
|
|
162
|
+
ifMatch?: string;
|
|
149
163
|
}): Promise<BeanRecord>;
|
|
150
164
|
delete(beanId: string): Promise<Record<string, unknown>>;
|
|
151
165
|
openConfig(): Promise<{
|
|
152
166
|
configPath: string;
|
|
153
167
|
content: string;
|
|
154
168
|
}>;
|
|
169
|
+
primeInstructions(): Promise<string>;
|
|
170
|
+
writeInstructions(instructions: string): Promise<string>;
|
|
155
171
|
graphqlSchema(): Promise<string>;
|
|
156
172
|
readOutputLog(options?: {
|
|
157
173
|
lines?: number;
|
|
@@ -202,7 +218,9 @@ declare function parseCliArgs(argv: string[]): {
|
|
|
202
218
|
};
|
|
203
219
|
declare function startBeansMcpServer(argv: string[],
|
|
204
220
|
/** For testing only: override the roots resolver so tests can cover the setInner branch. */
|
|
205
|
-
_resolveRoots?: (server: McpServer) => Promise<string | null
|
|
221
|
+
_resolveRoots?: (server: McpServer) => Promise<string | null>,
|
|
222
|
+
/** For testing only: override Beans CLI version detection. */
|
|
223
|
+
_detectBeansVersion?: (cliPath: string, workspaceRoot: string) => Promise<string | null>): Promise<void>;
|
|
206
224
|
|
|
207
225
|
/**
|
|
208
226
|
* Check whether `target` is contained within `root` after resolving both paths.
|