@selfagency/beans-mcp 0.1.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -13
- package/beans-mcp-server.cjs +705 -144
- package/index.cjs +705 -144
- package/index.d.ts +118 -1
- package/index.js +705 -144
- package/package.json +7 -6
package/beans-mcp-server.cjs
CHANGED
|
@@ -14433,7 +14433,7 @@ var init_v4 = __esm({
|
|
|
14433
14433
|
}
|
|
14434
14434
|
});
|
|
14435
14435
|
|
|
14436
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
14436
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
14437
14437
|
function assertCompleteRequestPrompt(request) {
|
|
14438
14438
|
if (request.params.ref.type !== "ref/prompt") {
|
|
14439
14439
|
throw new TypeError(`Expected CompleteRequestPrompt, but got ${request.params.ref.type}`);
|
|
@@ -14448,7 +14448,7 @@ function assertCompleteRequestResourceTemplate(request) {
|
|
|
14448
14448
|
}
|
|
14449
14449
|
var LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, RELATED_TASK_META_KEY, JSONRPC_VERSION, AssertObjectSchema, ProgressTokenSchema, CursorSchema, TaskCreationParamsSchema, TaskMetadataSchema, RelatedTaskMetadataSchema, RequestMetaSchema, BaseRequestParamsSchema, TaskAugmentedRequestParamsSchema, isTaskAugmentedRequestParams, RequestSchema, NotificationsParamsSchema, NotificationSchema, ResultSchema, RequestIdSchema, JSONRPCRequestSchema, isJSONRPCRequest, JSONRPCNotificationSchema, isJSONRPCNotification, JSONRPCResultResponseSchema, isJSONRPCResultResponse, ErrorCode, JSONRPCErrorResponseSchema, isJSONRPCErrorResponse, JSONRPCMessageSchema, JSONRPCResponseSchema, EmptyResultSchema, CancelledNotificationParamsSchema, CancelledNotificationSchema, IconSchema, IconsSchema, BaseMetadataSchema, ImplementationSchema, FormElicitationCapabilitySchema, ElicitationCapabilitySchema, ClientTasksCapabilitySchema, ServerTasksCapabilitySchema, ClientCapabilitiesSchema, InitializeRequestParamsSchema, InitializeRequestSchema, ServerCapabilitiesSchema, InitializeResultSchema, InitializedNotificationSchema, PingRequestSchema, ProgressSchema, ProgressNotificationParamsSchema, ProgressNotificationSchema, PaginatedRequestParamsSchema, PaginatedRequestSchema, PaginatedResultSchema, TaskStatusSchema, TaskSchema, CreateTaskResultSchema, TaskStatusNotificationParamsSchema, TaskStatusNotificationSchema, GetTaskRequestSchema, GetTaskResultSchema, GetTaskPayloadRequestSchema, GetTaskPayloadResultSchema, ListTasksRequestSchema, ListTasksResultSchema, CancelTaskRequestSchema, CancelTaskResultSchema, ResourceContentsSchema, TextResourceContentsSchema, Base64Schema, BlobResourceContentsSchema, RoleSchema, AnnotationsSchema, ResourceSchema, ResourceTemplateSchema, ListResourcesRequestSchema, ListResourcesResultSchema, ListResourceTemplatesRequestSchema, ListResourceTemplatesResultSchema, ResourceRequestParamsSchema, ReadResourceRequestParamsSchema, ReadResourceRequestSchema, ReadResourceResultSchema, ResourceListChangedNotificationSchema, SubscribeRequestParamsSchema, SubscribeRequestSchema, UnsubscribeRequestParamsSchema, UnsubscribeRequestSchema, ResourceUpdatedNotificationParamsSchema, ResourceUpdatedNotificationSchema, PromptArgumentSchema, PromptSchema, ListPromptsRequestSchema, ListPromptsResultSchema, GetPromptRequestParamsSchema, GetPromptRequestSchema, TextContentSchema, ImageContentSchema, AudioContentSchema, ToolUseContentSchema, EmbeddedResourceSchema, ResourceLinkSchema, ContentBlockSchema, PromptMessageSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ToolAnnotationsSchema, ToolExecutionSchema, ToolSchema, ListToolsRequestSchema, ListToolsResultSchema, CallToolResultSchema, CompatibilityCallToolResultSchema, CallToolRequestParamsSchema, CallToolRequestSchema, ToolListChangedNotificationSchema, ListChangedOptionsBaseSchema, LoggingLevelSchema, SetLevelRequestParamsSchema, SetLevelRequestSchema, LoggingMessageNotificationParamsSchema, LoggingMessageNotificationSchema, ModelHintSchema, ModelPreferencesSchema, ToolChoiceSchema, ToolResultContentSchema, SamplingContentSchema, SamplingMessageContentBlockSchema, SamplingMessageSchema, CreateMessageRequestParamsSchema, CreateMessageRequestSchema, CreateMessageResultSchema, CreateMessageResultWithToolsSchema, BooleanSchemaSchema, StringSchemaSchema, NumberSchemaSchema, UntitledSingleSelectEnumSchemaSchema, TitledSingleSelectEnumSchemaSchema, LegacyTitledEnumSchemaSchema, SingleSelectEnumSchemaSchema, UntitledMultiSelectEnumSchemaSchema, TitledMultiSelectEnumSchemaSchema, MultiSelectEnumSchemaSchema, EnumSchemaSchema, PrimitiveSchemaDefinitionSchema, ElicitRequestFormParamsSchema, ElicitRequestURLParamsSchema, ElicitRequestParamsSchema, ElicitRequestSchema, ElicitationCompleteNotificationParamsSchema, ElicitationCompleteNotificationSchema, ElicitResultSchema, ResourceTemplateReferenceSchema, PromptReferenceSchema, CompleteRequestParamsSchema, CompleteRequestSchema, CompleteResultSchema, RootSchema, ListRootsRequestSchema, ListRootsResultSchema, RootsListChangedNotificationSchema, ClientRequestSchema, ClientNotificationSchema, ClientResultSchema, ServerRequestSchema, ServerNotificationSchema, ServerResultSchema, McpError, UrlElicitationRequiredError;
|
|
14450
14450
|
var init_types = __esm({
|
|
14451
|
-
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
14451
|
+
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js"() {
|
|
14452
14452
|
"use strict";
|
|
14453
14453
|
init_v4();
|
|
14454
14454
|
LATEST_PROTOCOL_VERSION = "2025-11-25";
|
|
@@ -14460,10 +14460,9 @@ var init_types = __esm({
|
|
|
14460
14460
|
CursorSchema = string2();
|
|
14461
14461
|
TaskCreationParamsSchema = looseObject({
|
|
14462
14462
|
/**
|
|
14463
|
-
*
|
|
14464
|
-
* If null, the task has unlimited lifetime until manually cleaned up.
|
|
14463
|
+
* Requested duration in milliseconds to retain task from creation.
|
|
14465
14464
|
*/
|
|
14466
|
-
ttl:
|
|
14465
|
+
ttl: number2().optional(),
|
|
14467
14466
|
/**
|
|
14468
14467
|
* Time in milliseconds to wait between task status requests.
|
|
14469
14468
|
*/
|
|
@@ -14762,7 +14761,11 @@ var init_types = __esm({
|
|
|
14762
14761
|
/**
|
|
14763
14762
|
* Present if the client supports task creation.
|
|
14764
14763
|
*/
|
|
14765
|
-
tasks: ClientTasksCapabilitySchema.optional()
|
|
14764
|
+
tasks: ClientTasksCapabilitySchema.optional(),
|
|
14765
|
+
/**
|
|
14766
|
+
* Extensions that the client supports. Keys are extension identifiers (vendor-prefix/extension-name).
|
|
14767
|
+
*/
|
|
14768
|
+
extensions: record(string2(), AssertObjectSchema).optional()
|
|
14766
14769
|
});
|
|
14767
14770
|
InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
14768
14771
|
/**
|
|
@@ -14823,7 +14826,11 @@ var init_types = __esm({
|
|
|
14823
14826
|
/**
|
|
14824
14827
|
* Present if the server supports task creation.
|
|
14825
14828
|
*/
|
|
14826
|
-
tasks: ServerTasksCapabilitySchema.optional()
|
|
14829
|
+
tasks: ServerTasksCapabilitySchema.optional(),
|
|
14830
|
+
/**
|
|
14831
|
+
* Extensions that the server supports. Keys are extension identifiers (vendor-prefix/extension-name).
|
|
14832
|
+
*/
|
|
14833
|
+
extensions: record(string2(), AssertObjectSchema).optional()
|
|
14827
14834
|
});
|
|
14828
14835
|
InitializeResultSchema = ResultSchema.extend({
|
|
14829
14836
|
/**
|
|
@@ -15015,6 +15022,12 @@ var init_types = __esm({
|
|
|
15015
15022
|
* The MIME type of this resource, if known.
|
|
15016
15023
|
*/
|
|
15017
15024
|
mimeType: optional(string2()),
|
|
15025
|
+
/**
|
|
15026
|
+
* The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.
|
|
15027
|
+
*
|
|
15028
|
+
* This can be used by Hosts to display file sizes and estimate context window usage.
|
|
15029
|
+
*/
|
|
15030
|
+
size: optional(number2()),
|
|
15018
15031
|
/**
|
|
15019
15032
|
* Optional annotations for the client.
|
|
15020
15033
|
*/
|
|
@@ -22747,7 +22760,7 @@ var init_utils = __esm({
|
|
|
22747
22760
|
});
|
|
22748
22761
|
|
|
22749
22762
|
// src/internal/graphql.ts
|
|
22750
|
-
var LIST_BEANS_QUERY, CREATE_BEAN_MUTATION, UPDATE_BEAN_MUTATION, DELETE_BEAN_MUTATION;
|
|
22763
|
+
var LIST_BEANS_QUERY, CREATE_BEAN_MUTATION, UPDATE_BEAN_MUTATION, UPDATE_BEAN_MUTATION_WITH_IF_MATCH, DELETE_BEAN_MUTATION, LIST_BEANS_TIMESTAMPS_QUERY;
|
|
22751
22764
|
var init_graphql = __esm({
|
|
22752
22765
|
"src/internal/graphql.ts"() {
|
|
22753
22766
|
"use strict";
|
|
@@ -22765,11 +22778,21 @@ var init_graphql = __esm({
|
|
|
22765
22778
|
mutation($id: ID!, $input: UpdateBeanInput!) {
|
|
22766
22779
|
updateBean(id: $id, input: $input) { id slug path title body status type priority tags parentId blockingIds blockedByIds createdAt updatedAt etag }
|
|
22767
22780
|
}
|
|
22781
|
+
`;
|
|
22782
|
+
UPDATE_BEAN_MUTATION_WITH_IF_MATCH = `
|
|
22783
|
+
mutation($id: ID!, $input: UpdateBeanInput!, $ifMatch: String!) {
|
|
22784
|
+
updateBean(id: $id, input: $input, ifMatch: $ifMatch) { id slug path title body status type priority tags parentId blockingIds blockedByIds createdAt updatedAt etag }
|
|
22785
|
+
}
|
|
22768
22786
|
`;
|
|
22769
22787
|
DELETE_BEAN_MUTATION = `
|
|
22770
22788
|
mutation($id: ID!) {
|
|
22771
22789
|
deleteBean(id: $id)
|
|
22772
22790
|
}
|
|
22791
|
+
`;
|
|
22792
|
+
LIST_BEANS_TIMESTAMPS_QUERY = `
|
|
22793
|
+
query {
|
|
22794
|
+
beans { id updatedAt }
|
|
22795
|
+
}
|
|
22773
22796
|
`;
|
|
22774
22797
|
}
|
|
22775
22798
|
});
|
|
@@ -22792,12 +22815,26 @@ var init_backend = __esm({
|
|
|
22792
22815
|
init_graphql();
|
|
22793
22816
|
init_utils();
|
|
22794
22817
|
execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
22795
|
-
BeansCliBackend = class {
|
|
22818
|
+
BeansCliBackend = class _BeansCliBackend {
|
|
22796
22819
|
constructor(workspaceRoot, cliPath, logDir) {
|
|
22797
22820
|
this.workspaceRoot = workspaceRoot;
|
|
22798
22821
|
this.cliPath = cliPath;
|
|
22799
22822
|
this.logDir = logDir;
|
|
22800
22823
|
}
|
|
22824
|
+
// ---------------------------------------------------------------------------
|
|
22825
|
+
// Cache
|
|
22826
|
+
// ---------------------------------------------------------------------------
|
|
22827
|
+
/** Full unfiltered records keyed by bean ID, stored under the fixed cache key `'all'`. */
|
|
22828
|
+
_cache = /* @__PURE__ */ new Map();
|
|
22829
|
+
/** Last time the unfiltered cache entry `'all'` was fetched (ms). */
|
|
22830
|
+
_cacheTime = /* @__PURE__ */ new Map();
|
|
22831
|
+
/** Short-circuit TTL: skip even the timestamp check within this window (ms). */
|
|
22832
|
+
static BURST_TTL_MS = 5e3;
|
|
22833
|
+
/** Invalidate the unfiltered list cache so the next call does a full fetch. */
|
|
22834
|
+
invalidateCache() {
|
|
22835
|
+
this._cache.delete("all");
|
|
22836
|
+
this._cacheTime.delete("all");
|
|
22837
|
+
}
|
|
22801
22838
|
/**
|
|
22802
22839
|
* Returns a safe environment for executing the Beans CLI,
|
|
22803
22840
|
* whitelisting only necessary variables.
|
|
@@ -22821,7 +22858,7 @@ var init_backend = __esm({
|
|
|
22821
22858
|
return (0, import_node_path2.resolve)(this.workspaceRoot, ".beans");
|
|
22822
22859
|
}
|
|
22823
22860
|
resolveBeanFilePath(relativePath) {
|
|
22824
|
-
const cleaned = relativePath.trim().replace(/^\/+/, "");
|
|
22861
|
+
const cleaned = relativePath.trim().replace(/^\/+/, "").replace(/^\.beans(?:[\\/]|$)/, "");
|
|
22825
22862
|
if (!cleaned) {
|
|
22826
22863
|
throw new Error("Path is required");
|
|
22827
22864
|
}
|
|
@@ -22879,10 +22916,48 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22879
22916
|
if (options?.search) {
|
|
22880
22917
|
filter.search = options.search;
|
|
22881
22918
|
}
|
|
22919
|
+
const isCacheable = !filter.status && !filter.type && !filter.search;
|
|
22920
|
+
const cacheKey = "all";
|
|
22921
|
+
if (isCacheable) {
|
|
22922
|
+
const lastFetch = this._cacheTime.get(cacheKey) ?? 0;
|
|
22923
|
+
const cached2 = this._cache.get(cacheKey);
|
|
22924
|
+
const age = Date.now() - lastFetch;
|
|
22925
|
+
if (cached2 && age < _BeansCliBackend.BURST_TTL_MS) {
|
|
22926
|
+
return Array.from(cached2.values());
|
|
22927
|
+
}
|
|
22928
|
+
if (cached2) {
|
|
22929
|
+
try {
|
|
22930
|
+
const { data: tsData } = await this.executeGraphQL(
|
|
22931
|
+
LIST_BEANS_TIMESTAMPS_QUERY
|
|
22932
|
+
);
|
|
22933
|
+
const timestamps = tsData.beans;
|
|
22934
|
+
let dirty = timestamps.length !== cached2.size;
|
|
22935
|
+
if (!dirty) {
|
|
22936
|
+
for (const { id, updatedAt } of timestamps) {
|
|
22937
|
+
const existing = cached2.get(id);
|
|
22938
|
+
if (!existing || existing.updatedAt !== updatedAt) {
|
|
22939
|
+
dirty = true;
|
|
22940
|
+
break;
|
|
22941
|
+
}
|
|
22942
|
+
}
|
|
22943
|
+
}
|
|
22944
|
+
if (!dirty) {
|
|
22945
|
+
this._cacheTime.set(cacheKey, Date.now());
|
|
22946
|
+
return Array.from(cached2.values());
|
|
22947
|
+
}
|
|
22948
|
+
} catch {
|
|
22949
|
+
}
|
|
22950
|
+
}
|
|
22951
|
+
}
|
|
22882
22952
|
const { data, errors } = await this.executeGraphQL(LIST_BEANS_QUERY, { filter });
|
|
22883
22953
|
if (errors && errors.length > 0) {
|
|
22884
22954
|
throw new Error(`GraphQL error: ${errors.map((e) => e.message).join(", ")}`);
|
|
22885
22955
|
}
|
|
22956
|
+
if (isCacheable) {
|
|
22957
|
+
const byId = new Map(data.beans.map((b) => [b.id, b]));
|
|
22958
|
+
this._cache.set(cacheKey, byId);
|
|
22959
|
+
this._cacheTime.set(cacheKey, Date.now());
|
|
22960
|
+
}
|
|
22886
22961
|
return data.beans;
|
|
22887
22962
|
}
|
|
22888
22963
|
async create(input) {
|
|
@@ -22891,7 +22966,7 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22891
22966
|
type: input.type,
|
|
22892
22967
|
status: input.status,
|
|
22893
22968
|
priority: input.priority,
|
|
22894
|
-
body: input.description,
|
|
22969
|
+
body: input.body ?? input.description,
|
|
22895
22970
|
parent: input.parent
|
|
22896
22971
|
};
|
|
22897
22972
|
const { data, errors } = await this.executeGraphQL(CREATE_BEAN_MUTATION, {
|
|
@@ -22900,6 +22975,7 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22900
22975
|
if (errors && errors.length > 0) {
|
|
22901
22976
|
throw new Error(`GraphQL error: ${errors.map((e) => e.message).join(", ")}`);
|
|
22902
22977
|
}
|
|
22978
|
+
this.invalidateCache();
|
|
22903
22979
|
return data.createBean;
|
|
22904
22980
|
}
|
|
22905
22981
|
async update(beanId, updates) {
|
|
@@ -22922,13 +22998,54 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22922
22998
|
if (updates.body !== void 0) {
|
|
22923
22999
|
updateInput.body = updates.body;
|
|
22924
23000
|
}
|
|
22925
|
-
const
|
|
22926
|
-
|
|
22927
|
-
|
|
22928
|
-
}
|
|
23001
|
+
const bodyMod = {};
|
|
23002
|
+
if (updates.bodyAppend !== void 0) {
|
|
23003
|
+
bodyMod.append = updates.bodyAppend;
|
|
23004
|
+
}
|
|
23005
|
+
if (Array.isArray(updates.bodyReplace) && updates.bodyReplace.length > 0) {
|
|
23006
|
+
bodyMod.replace = updates.bodyReplace;
|
|
23007
|
+
}
|
|
23008
|
+
if (Object.keys(bodyMod).length > 0) {
|
|
23009
|
+
updateInput.bodyMod = bodyMod;
|
|
23010
|
+
}
|
|
23011
|
+
let data;
|
|
23012
|
+
let errors;
|
|
23013
|
+
if (updates.ifMatch) {
|
|
23014
|
+
try {
|
|
23015
|
+
const res = await this.executeGraphQL(UPDATE_BEAN_MUTATION_WITH_IF_MATCH, {
|
|
23016
|
+
id: beanId,
|
|
23017
|
+
input: updateInput,
|
|
23018
|
+
ifMatch: updates.ifMatch
|
|
23019
|
+
});
|
|
23020
|
+
data = res.data;
|
|
23021
|
+
errors = res.errors;
|
|
23022
|
+
} catch (error48) {
|
|
23023
|
+
const message = error48.message || "";
|
|
23024
|
+
const unsupportedIfMatch = /unknown argument.*ifMatch|unknown field.*ifMatch|ifMatch.*not defined|field .*updateBean.* argument .*ifMatch/i.test(
|
|
23025
|
+
message
|
|
23026
|
+
);
|
|
23027
|
+
if (!unsupportedIfMatch) {
|
|
23028
|
+
throw error48;
|
|
23029
|
+
}
|
|
23030
|
+
const fallback = await this.executeGraphQL(UPDATE_BEAN_MUTATION, {
|
|
23031
|
+
id: beanId,
|
|
23032
|
+
input: updateInput
|
|
23033
|
+
});
|
|
23034
|
+
data = fallback.data;
|
|
23035
|
+
errors = fallback.errors;
|
|
23036
|
+
}
|
|
23037
|
+
} else {
|
|
23038
|
+
const res = await this.executeGraphQL(UPDATE_BEAN_MUTATION, {
|
|
23039
|
+
id: beanId,
|
|
23040
|
+
input: updateInput
|
|
23041
|
+
});
|
|
23042
|
+
data = res.data;
|
|
23043
|
+
errors = res.errors;
|
|
23044
|
+
}
|
|
22929
23045
|
if (errors && errors.length > 0) {
|
|
22930
23046
|
throw new Error(`GraphQL error: ${errors.map((e) => e.message).join(", ")}`);
|
|
22931
23047
|
}
|
|
23048
|
+
this.invalidateCache();
|
|
22932
23049
|
return data.updateBean;
|
|
22933
23050
|
}
|
|
22934
23051
|
async delete(beanId) {
|
|
@@ -22938,13 +23055,57 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22938
23055
|
if (errors && errors.length > 0) {
|
|
22939
23056
|
throw new Error(`GraphQL error: ${errors.map((e) => e.message).join(", ")}`);
|
|
22940
23057
|
}
|
|
23058
|
+
this.invalidateCache();
|
|
22941
23059
|
return { deleted: true, beanId };
|
|
22942
23060
|
}
|
|
23061
|
+
async bulkCreate(beans, defaultParent) {
|
|
23062
|
+
const results = [];
|
|
23063
|
+
for (const item of beans) {
|
|
23064
|
+
try {
|
|
23065
|
+
const bean = await this.create({
|
|
23066
|
+
...item,
|
|
23067
|
+
parent: item.parent ?? defaultParent
|
|
23068
|
+
});
|
|
23069
|
+
results.push({ bean });
|
|
23070
|
+
} catch (error48) {
|
|
23071
|
+
results.push({ error: error48.message });
|
|
23072
|
+
}
|
|
23073
|
+
}
|
|
23074
|
+
return results;
|
|
23075
|
+
}
|
|
23076
|
+
async bulkUpdate(beans, defaultParent) {
|
|
23077
|
+
const results = [];
|
|
23078
|
+
for (const { beanId, ...updates } of beans) {
|
|
23079
|
+
try {
|
|
23080
|
+
const resolvedParent = updates.parent ?? (updates.clearParent ? void 0 : defaultParent);
|
|
23081
|
+
const bean = await this.update(beanId, { ...updates, parent: resolvedParent });
|
|
23082
|
+
results.push({ beanId, bean });
|
|
23083
|
+
} catch (error48) {
|
|
23084
|
+
results.push({ beanId, error: error48.message });
|
|
23085
|
+
}
|
|
23086
|
+
}
|
|
23087
|
+
return results;
|
|
23088
|
+
}
|
|
22943
23089
|
async openConfig() {
|
|
22944
23090
|
const configPath = (0, import_node_path2.join)(this.workspaceRoot, ".beans.yml");
|
|
22945
23091
|
const content = await (0, import_promises.readFile)(configPath, "utf8");
|
|
22946
23092
|
return { configPath, content };
|
|
22947
23093
|
}
|
|
23094
|
+
async primeInstructions() {
|
|
23095
|
+
const { stdout } = await execFileAsync(this.cliPath, ["prime"], {
|
|
23096
|
+
cwd: this.workspaceRoot,
|
|
23097
|
+
env: this.getSafeEnv(),
|
|
23098
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
23099
|
+
timeout: 3e4
|
|
23100
|
+
});
|
|
23101
|
+
return stdout.trim();
|
|
23102
|
+
}
|
|
23103
|
+
async writeInstructions(instructions) {
|
|
23104
|
+
const instructionsPath = (0, import_node_path2.join)(this.workspaceRoot, ".github", "instructions", "beans-prime.instructions.md");
|
|
23105
|
+
await (0, import_promises.mkdir)((0, import_node_path2.dirname)(instructionsPath), { recursive: true });
|
|
23106
|
+
await (0, import_promises.writeFile)(instructionsPath, instructions, "utf8");
|
|
23107
|
+
return instructionsPath;
|
|
23108
|
+
}
|
|
22948
23109
|
async graphqlSchema() {
|
|
22949
23110
|
const { stdout } = await execFileAsync(this.cliPath, ["graphql", "--schema"], {
|
|
22950
23111
|
cwd: this.workspaceRoot,
|
|
@@ -22983,6 +23144,120 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22983
23144
|
linesReturned: ringBuffer.length
|
|
22984
23145
|
};
|
|
22985
23146
|
}
|
|
23147
|
+
/**
|
|
23148
|
+
* Split a YAML scalar value from any trailing inline comment.
|
|
23149
|
+
* Understands single-quoted and double-quoted YAML strings so it won't
|
|
23150
|
+
* mistake a `#` inside a quoted value for a comment delimiter.
|
|
23151
|
+
*/
|
|
23152
|
+
splitYamlInlineComment(value) {
|
|
23153
|
+
let inSingle = false;
|
|
23154
|
+
let inDouble = false;
|
|
23155
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
23156
|
+
const char = value[i];
|
|
23157
|
+
if (inSingle) {
|
|
23158
|
+
if (char === "'") {
|
|
23159
|
+
if (value[i + 1] === "'") {
|
|
23160
|
+
i += 1;
|
|
23161
|
+
} else {
|
|
23162
|
+
inSingle = false;
|
|
23163
|
+
}
|
|
23164
|
+
}
|
|
23165
|
+
continue;
|
|
23166
|
+
}
|
|
23167
|
+
if (inDouble) {
|
|
23168
|
+
if (char === "\\") {
|
|
23169
|
+
i += 1;
|
|
23170
|
+
continue;
|
|
23171
|
+
}
|
|
23172
|
+
if (char === '"') {
|
|
23173
|
+
inDouble = false;
|
|
23174
|
+
}
|
|
23175
|
+
continue;
|
|
23176
|
+
}
|
|
23177
|
+
if (char === "'") {
|
|
23178
|
+
inSingle = true;
|
|
23179
|
+
continue;
|
|
23180
|
+
}
|
|
23181
|
+
if (char === '"') {
|
|
23182
|
+
inDouble = true;
|
|
23183
|
+
continue;
|
|
23184
|
+
}
|
|
23185
|
+
if (char === "#" && i > 0 && /\s/.test(value[i - 1])) {
|
|
23186
|
+
const valuePart = value.slice(0, i).trimEnd();
|
|
23187
|
+
return {
|
|
23188
|
+
valuePart,
|
|
23189
|
+
commentPart: value.slice(valuePart.length)
|
|
23190
|
+
};
|
|
23191
|
+
}
|
|
23192
|
+
}
|
|
23193
|
+
return { valuePart: value, commentPart: "" };
|
|
23194
|
+
}
|
|
23195
|
+
/** Returns true when `value` looks like a YAML block scalar indicator (`>`, `|`, `>-`, `|-`, etc.) */
|
|
23196
|
+
isYamlBlockScalarIndicator(value) {
|
|
23197
|
+
return /^[>|][+-]?[0-9]*$/.test(value) || /^[>|][0-9]*[+-]?$/.test(value);
|
|
23198
|
+
}
|
|
23199
|
+
/** Escape a plain string for use inside a YAML double-quoted scalar. */
|
|
23200
|
+
escapeForYamlDoubleQuoted(value) {
|
|
23201
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
23202
|
+
}
|
|
23203
|
+
/**
|
|
23204
|
+
* Normalise a raw YAML title value to a double-quoted scalar.
|
|
23205
|
+
* Handles: empty, already double-quoted, single-quoted (unescaping `''`),
|
|
23206
|
+
* block-scalar indicators, and plain unquoted values.
|
|
23207
|
+
*/
|
|
23208
|
+
normalizeFrontmatterTitleValue(value) {
|
|
23209
|
+
const trimmed = value.trim();
|
|
23210
|
+
if (trimmed === "") {
|
|
23211
|
+
return '""';
|
|
23212
|
+
}
|
|
23213
|
+
if (this.isYamlBlockScalarIndicator(trimmed)) {
|
|
23214
|
+
return value;
|
|
23215
|
+
}
|
|
23216
|
+
if (/^"(?:[^"\\]|\\[\s\S])*"$/.test(trimmed)) {
|
|
23217
|
+
return trimmed;
|
|
23218
|
+
}
|
|
23219
|
+
if (/^'(?:[^']|'')*'$/.test(trimmed)) {
|
|
23220
|
+
const inner = trimmed.slice(1, -1).replace(/''/g, "'");
|
|
23221
|
+
return `"${this.escapeForYamlDoubleQuoted(inner)}"`;
|
|
23222
|
+
}
|
|
23223
|
+
return `"${this.escapeForYamlDoubleQuoted(trimmed)}"`;
|
|
23224
|
+
}
|
|
23225
|
+
/**
|
|
23226
|
+
* Ensure every `title:` line in YAML frontmatter is double-quoted.
|
|
23227
|
+
* Handles already-quoted (single or double), multi-word, and special-char values.
|
|
23228
|
+
* Preserves inline comments and handles both LF and CRLF line endings.
|
|
23229
|
+
*/
|
|
23230
|
+
quoteFrontmatterTitles(content) {
|
|
23231
|
+
const crlfOpen = content.startsWith("---\r\n");
|
|
23232
|
+
const lfOpen = content.startsWith("---\n");
|
|
23233
|
+
if (!crlfOpen && !lfOpen) {
|
|
23234
|
+
return content;
|
|
23235
|
+
}
|
|
23236
|
+
const eol = crlfOpen ? "\r\n" : "\n";
|
|
23237
|
+
const openEnd = `---${eol}`.length;
|
|
23238
|
+
const closeMarker = `${eol}---`;
|
|
23239
|
+
const closeIdx = content.indexOf(closeMarker, openEnd);
|
|
23240
|
+
if (closeIdx === -1) {
|
|
23241
|
+
return content;
|
|
23242
|
+
}
|
|
23243
|
+
const frontmatter = content.slice(openEnd, closeIdx);
|
|
23244
|
+
const rest = content.slice(closeIdx);
|
|
23245
|
+
const lines = frontmatter.split(eol);
|
|
23246
|
+
const fixedLines = lines.map((line) => {
|
|
23247
|
+
if (!line.startsWith("title:")) {
|
|
23248
|
+
return line;
|
|
23249
|
+
}
|
|
23250
|
+
const colonIdx = line.indexOf(":");
|
|
23251
|
+
const afterColon = line.slice(colonIdx + 1);
|
|
23252
|
+
const leadingSpace = afterColon.length - afterColon.trimStart().length;
|
|
23253
|
+
const raw = afterColon.trimStart();
|
|
23254
|
+
const { valuePart, commentPart } = this.splitYamlInlineComment(raw);
|
|
23255
|
+
const normalized = this.normalizeFrontmatterTitleValue(valuePart);
|
|
23256
|
+
const prefix = `title:${" ".repeat(Math.max(1, leadingSpace))}`;
|
|
23257
|
+
return `${prefix}${normalized}${commentPart}`;
|
|
23258
|
+
});
|
|
23259
|
+
return `---${eol}${fixedLines.join(eol)}${rest}`;
|
|
23260
|
+
}
|
|
22986
23261
|
async readBeanFile(relativePath) {
|
|
22987
23262
|
const absolutePath = this.resolveBeanFilePath(relativePath);
|
|
22988
23263
|
const content = await (0, import_promises.readFile)(absolutePath, "utf8");
|
|
@@ -22990,20 +23265,22 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22990
23265
|
}
|
|
22991
23266
|
async editBeanFile(relativePath, content) {
|
|
22992
23267
|
const absolutePath = this.resolveBeanFilePath(relativePath);
|
|
23268
|
+
const fixed = this.quoteFrontmatterTitles(content);
|
|
22993
23269
|
await (0, import_promises.mkdir)((0, import_node_path2.dirname)(absolutePath), { recursive: true });
|
|
22994
|
-
await (0, import_promises.writeFile)(absolutePath,
|
|
22995
|
-
return { path: absolutePath, bytes: Buffer.byteLength(
|
|
23270
|
+
await (0, import_promises.writeFile)(absolutePath, fixed, "utf8");
|
|
23271
|
+
return { path: absolutePath, bytes: Buffer.byteLength(fixed, "utf8") };
|
|
22996
23272
|
}
|
|
22997
23273
|
async createBeanFile(relativePath, content, options) {
|
|
22998
23274
|
const absolutePath = this.resolveBeanFilePath(relativePath);
|
|
23275
|
+
const fixed = this.quoteFrontmatterTitles(content);
|
|
22999
23276
|
await (0, import_promises.mkdir)((0, import_node_path2.dirname)(absolutePath), { recursive: true });
|
|
23000
|
-
await (0, import_promises.writeFile)(absolutePath,
|
|
23277
|
+
await (0, import_promises.writeFile)(absolutePath, fixed, {
|
|
23001
23278
|
encoding: "utf8",
|
|
23002
23279
|
flag: options?.overwrite ? "w" : "wx"
|
|
23003
23280
|
});
|
|
23004
23281
|
return {
|
|
23005
23282
|
path: absolutePath,
|
|
23006
|
-
bytes: Buffer.byteLength(
|
|
23283
|
+
bytes: Buffer.byteLength(fixed, "utf8"),
|
|
23007
23284
|
created: true
|
|
23008
23285
|
};
|
|
23009
23286
|
}
|
|
@@ -23016,7 +23293,7 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
23016
23293
|
}
|
|
23017
23294
|
});
|
|
23018
23295
|
|
|
23019
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
23296
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
23020
23297
|
function deserializeMessage(line) {
|
|
23021
23298
|
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
|
23022
23299
|
}
|
|
@@ -23025,7 +23302,7 @@ function serializeMessage(message) {
|
|
|
23025
23302
|
}
|
|
23026
23303
|
var ReadBuffer;
|
|
23027
23304
|
var init_stdio = __esm({
|
|
23028
|
-
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
23305
|
+
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js"() {
|
|
23029
23306
|
"use strict";
|
|
23030
23307
|
init_types();
|
|
23031
23308
|
ReadBuffer = class {
|
|
@@ -23051,14 +23328,14 @@ var init_stdio = __esm({
|
|
|
23051
23328
|
}
|
|
23052
23329
|
});
|
|
23053
23330
|
|
|
23054
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
23331
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
23055
23332
|
var stdio_exports = {};
|
|
23056
23333
|
__export(stdio_exports, {
|
|
23057
23334
|
StdioServerTransport: () => StdioServerTransport
|
|
23058
23335
|
});
|
|
23059
23336
|
var import_node_process, StdioServerTransport;
|
|
23060
23337
|
var init_stdio2 = __esm({
|
|
23061
|
-
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
23338
|
+
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js"() {
|
|
23062
23339
|
"use strict";
|
|
23063
23340
|
import_node_process = __toESM(require("process"), 1);
|
|
23064
23341
|
init_stdio();
|
|
@@ -27066,7 +27343,7 @@ init_core2();
|
|
|
27066
27343
|
// node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/mini/coerce.js
|
|
27067
27344
|
init_core2();
|
|
27068
27345
|
|
|
27069
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
27346
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
27070
27347
|
function isZ4Schema(s) {
|
|
27071
27348
|
const schema = s;
|
|
27072
27349
|
return !!schema._zod;
|
|
@@ -27210,10 +27487,10 @@ function getLiteralValue(schema) {
|
|
|
27210
27487
|
return void 0;
|
|
27211
27488
|
}
|
|
27212
27489
|
|
|
27213
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
27490
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
|
|
27214
27491
|
init_types();
|
|
27215
27492
|
|
|
27216
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
27493
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
|
|
27217
27494
|
function isTerminal(status) {
|
|
27218
27495
|
return status === "completed" || status === "failed" || status === "cancelled";
|
|
27219
27496
|
}
|
|
@@ -28502,7 +28779,7 @@ var zodToJsonSchema = (schema, options) => {
|
|
|
28502
28779
|
return combined;
|
|
28503
28780
|
};
|
|
28504
28781
|
|
|
28505
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
28782
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
|
|
28506
28783
|
function mapMiniTarget(t) {
|
|
28507
28784
|
if (!t)
|
|
28508
28785
|
return "draft-7";
|
|
@@ -28544,7 +28821,7 @@ function parseWithCompat(schema, data) {
|
|
|
28544
28821
|
return result.data;
|
|
28545
28822
|
}
|
|
28546
28823
|
|
|
28547
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
28824
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
|
|
28548
28825
|
var DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
|
|
28549
28826
|
var Protocol = class {
|
|
28550
28827
|
constructor(_options) {
|
|
@@ -28756,6 +29033,10 @@ var Protocol = class {
|
|
|
28756
29033
|
this._progressHandlers.clear();
|
|
28757
29034
|
this._taskProgressTokens.clear();
|
|
28758
29035
|
this._pendingDebouncedNotifications.clear();
|
|
29036
|
+
for (const info of this._timeoutInfo.values()) {
|
|
29037
|
+
clearTimeout(info.timeoutId);
|
|
29038
|
+
}
|
|
29039
|
+
this._timeoutInfo.clear();
|
|
28759
29040
|
for (const controller of this._requestHandlerAbortControllers.values()) {
|
|
28760
29041
|
controller.abort();
|
|
28761
29042
|
}
|
|
@@ -28886,7 +29167,9 @@ var Protocol = class {
|
|
|
28886
29167
|
await capturedTransport?.send(errorResponse);
|
|
28887
29168
|
}
|
|
28888
29169
|
}).catch((error48) => this._onerror(new Error(`Failed to send response: ${error48}`))).finally(() => {
|
|
28889
|
-
this._requestHandlerAbortControllers.
|
|
29170
|
+
if (this._requestHandlerAbortControllers.get(request.id) === abortController) {
|
|
29171
|
+
this._requestHandlerAbortControllers.delete(request.id);
|
|
29172
|
+
}
|
|
28890
29173
|
});
|
|
28891
29174
|
}
|
|
28892
29175
|
_onprogress(notification) {
|
|
@@ -29492,10 +29775,10 @@ function mergeCapabilities(base, additional) {
|
|
|
29492
29775
|
return result;
|
|
29493
29776
|
}
|
|
29494
29777
|
|
|
29495
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
29778
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
|
|
29496
29779
|
init_types();
|
|
29497
29780
|
|
|
29498
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
29781
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
|
|
29499
29782
|
var import_ajv = __toESM(require_ajv(), 1);
|
|
29500
29783
|
var import_ajv_formats = __toESM(require_dist(), 1);
|
|
29501
29784
|
function createDefaultAjvInstance() {
|
|
@@ -29563,7 +29846,7 @@ var AjvJsonSchemaValidator = class {
|
|
|
29563
29846
|
}
|
|
29564
29847
|
};
|
|
29565
29848
|
|
|
29566
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
29849
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
|
|
29567
29850
|
init_types();
|
|
29568
29851
|
var ExperimentalServerTasks = class {
|
|
29569
29852
|
constructor(_server) {
|
|
@@ -29777,7 +30060,7 @@ var ExperimentalServerTasks = class {
|
|
|
29777
30060
|
}
|
|
29778
30061
|
};
|
|
29779
30062
|
|
|
29780
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30063
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
|
|
29781
30064
|
function assertToolsCallTaskCapability(requests, method, entityName) {
|
|
29782
30065
|
if (!requests) {
|
|
29783
30066
|
throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
@@ -29812,7 +30095,7 @@ function assertClientRequestTaskCapability(requests, method, entityName) {
|
|
|
29812
30095
|
}
|
|
29813
30096
|
}
|
|
29814
30097
|
|
|
29815
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30098
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
|
|
29816
30099
|
var Server = class extends Protocol {
|
|
29817
30100
|
/**
|
|
29818
30101
|
* Initializes this server with the given name and version information.
|
|
@@ -30192,10 +30475,10 @@ var Server = class extends Protocol {
|
|
|
30192
30475
|
}
|
|
30193
30476
|
};
|
|
30194
30477
|
|
|
30195
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30478
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
|
|
30196
30479
|
init_types();
|
|
30197
30480
|
|
|
30198
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30481
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
|
|
30199
30482
|
var COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
|
|
30200
30483
|
function isCompletable(schema) {
|
|
30201
30484
|
return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
|
|
@@ -30209,7 +30492,7 @@ var McpZodTypeKind;
|
|
|
30209
30492
|
McpZodTypeKind2["Completable"] = "McpCompletable";
|
|
30210
30493
|
})(McpZodTypeKind || (McpZodTypeKind = {}));
|
|
30211
30494
|
|
|
30212
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30495
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
|
|
30213
30496
|
var TOOL_NAME_REGEX = /^[A-Za-z0-9._-]{1,128}$/;
|
|
30214
30497
|
function validateToolName(name) {
|
|
30215
30498
|
const warnings = [];
|
|
@@ -30267,7 +30550,7 @@ function validateAndWarnToolName(name) {
|
|
|
30267
30550
|
return result.isValid;
|
|
30268
30551
|
}
|
|
30269
30552
|
|
|
30270
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30553
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
|
|
30271
30554
|
var ExperimentalMcpServerTasks = class {
|
|
30272
30555
|
constructor(_mcpServer) {
|
|
30273
30556
|
this._mcpServer = _mcpServer;
|
|
@@ -30286,7 +30569,7 @@ var ExperimentalMcpServerTasks = class {
|
|
|
30286
30569
|
init_external();
|
|
30287
30570
|
init_external();
|
|
30288
30571
|
|
|
30289
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30572
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
|
|
30290
30573
|
var McpServer = class {
|
|
30291
30574
|
constructor(serverInfo, options) {
|
|
30292
30575
|
this._registeredResources = {};
|
|
@@ -30910,6 +31193,9 @@ var McpServer = class {
|
|
|
30910
31193
|
annotations = rest.shift();
|
|
30911
31194
|
}
|
|
30912
31195
|
} else if (typeof firstArg === "object" && firstArg !== null) {
|
|
31196
|
+
if (Object.values(firstArg).some((v) => typeof v === "object" && v !== null)) {
|
|
31197
|
+
throw new Error(`Tool ${name} expected a Zod schema or ToolAnnotations, but received an unrecognized object`);
|
|
31198
|
+
}
|
|
30913
31199
|
annotations = rest.shift();
|
|
30914
31200
|
}
|
|
30915
31201
|
}
|
|
@@ -31028,6 +31314,9 @@ function getZodSchemaObject(schema) {
|
|
|
31028
31314
|
if (isZodRawShapeCompat(schema)) {
|
|
31029
31315
|
return objectFromShape(schema);
|
|
31030
31316
|
}
|
|
31317
|
+
if (!isZodSchemaInstance(schema)) {
|
|
31318
|
+
throw new Error("inputSchema must be a Zod schema or raw shape, received an unrecognized object");
|
|
31319
|
+
}
|
|
31031
31320
|
return schema;
|
|
31032
31321
|
}
|
|
31033
31322
|
function promptArgumentsFromSchema(schema) {
|
|
@@ -31072,6 +31361,94 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
31072
31361
|
}
|
|
31073
31362
|
};
|
|
31074
31363
|
|
|
31364
|
+
// src/server/BeansMcpServer.ts
|
|
31365
|
+
var import_node_child_process2 = require("child_process");
|
|
31366
|
+
var import_node_util2 = require("util");
|
|
31367
|
+
|
|
31368
|
+
// package.json
|
|
31369
|
+
var package_default = {
|
|
31370
|
+
name: "@selfagency/beans-mcp",
|
|
31371
|
+
version: "0.5.0",
|
|
31372
|
+
private: false,
|
|
31373
|
+
description: "MCP (Model Context Protocol) server for Beans issue tracker",
|
|
31374
|
+
author: {
|
|
31375
|
+
name: "Daniel Sieradski",
|
|
31376
|
+
email: "daniel@self.agency",
|
|
31377
|
+
url: "https://self.agency"
|
|
31378
|
+
},
|
|
31379
|
+
homepage: "https://github.com/selfagency/beans-mcp",
|
|
31380
|
+
bugs: {
|
|
31381
|
+
url: "https://github.com/selfagency/beans-mcp/issues"
|
|
31382
|
+
},
|
|
31383
|
+
repository: {
|
|
31384
|
+
type: "git",
|
|
31385
|
+
url: "git+https://github.com/selfagency/beans-mcp.git"
|
|
31386
|
+
},
|
|
31387
|
+
mcpName: "io.github.selfagency/beans-mcp",
|
|
31388
|
+
keywords: [
|
|
31389
|
+
"beans",
|
|
31390
|
+
"mcp",
|
|
31391
|
+
"model-context-protocol",
|
|
31392
|
+
"issue-tracker",
|
|
31393
|
+
"ai"
|
|
31394
|
+
],
|
|
31395
|
+
license: "MIT",
|
|
31396
|
+
type: "module",
|
|
31397
|
+
exports: {
|
|
31398
|
+
".": {
|
|
31399
|
+
types: "./dist/index.d.ts",
|
|
31400
|
+
import: "./dist/index.js",
|
|
31401
|
+
require: "./dist/index.cjs"
|
|
31402
|
+
}
|
|
31403
|
+
},
|
|
31404
|
+
main: "./dist/index.cjs",
|
|
31405
|
+
module: "./dist/index.js",
|
|
31406
|
+
types: "./dist/index.d.ts",
|
|
31407
|
+
bin: {
|
|
31408
|
+
"beans-mcp": "dist/beans-mcp-server.cjs"
|
|
31409
|
+
},
|
|
31410
|
+
scripts: {
|
|
31411
|
+
build: "tsup",
|
|
31412
|
+
format: "oxfmt",
|
|
31413
|
+
"lint:fix": "oxlint --fix",
|
|
31414
|
+
lint: "oxlint",
|
|
31415
|
+
postbuild: "node ./scripts/write-dist-package.js",
|
|
31416
|
+
prepare: "husky",
|
|
31417
|
+
release: "zx ./scripts/release.js",
|
|
31418
|
+
"test:coverage": "vitest run --coverage",
|
|
31419
|
+
"test:watch": "vitest",
|
|
31420
|
+
test: "vitest run",
|
|
31421
|
+
"type-check": "tsc --noEmit"
|
|
31422
|
+
},
|
|
31423
|
+
devDependencies: {
|
|
31424
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
31425
|
+
"@octokit/rest": "^22.0.1",
|
|
31426
|
+
"@types/node": "25.5.2",
|
|
31427
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
31428
|
+
"@vitest/ui": "4.1.2",
|
|
31429
|
+
husky: "^9.1.7",
|
|
31430
|
+
"lint-staged": "^16.4.0",
|
|
31431
|
+
ora: "^9.3.0",
|
|
31432
|
+
oxfmt: "^0.43.0",
|
|
31433
|
+
oxlint: "^1.58.0",
|
|
31434
|
+
"oxlint-tsgolint": "^0.20.0",
|
|
31435
|
+
tsup: "8.5.1",
|
|
31436
|
+
typescript: "6.0.2",
|
|
31437
|
+
vitest: "4.1.2",
|
|
31438
|
+
zod: "4.3.6",
|
|
31439
|
+
zx: "^8.8.5"
|
|
31440
|
+
},
|
|
31441
|
+
engines: {
|
|
31442
|
+
node: ">=18"
|
|
31443
|
+
},
|
|
31444
|
+
"lint-staged": {
|
|
31445
|
+
"src/**/*.ts": [
|
|
31446
|
+
"pnpm run lint:fix",
|
|
31447
|
+
"pnpm run format"
|
|
31448
|
+
]
|
|
31449
|
+
}
|
|
31450
|
+
};
|
|
31451
|
+
|
|
31075
31452
|
// src/internal/queryHelpers.ts
|
|
31076
31453
|
function sortBeansInternal(beans, mode) {
|
|
31077
31454
|
const sorted = [...beans];
|
|
@@ -31127,15 +31504,23 @@ async function handleQueryOperation(backend, params) {
|
|
|
31127
31504
|
const { operation, mode, statuses, types, search, tags, writeToWorkspaceInstructions, includeClosed } = params;
|
|
31128
31505
|
if (operation === "llm_context") {
|
|
31129
31506
|
const graphqlSchema = typeof backend.graphqlSchema === "function" ? await backend.graphqlSchema() : "";
|
|
31130
|
-
|
|
31507
|
+
let generatedInstructions = "";
|
|
31508
|
+
if (typeof backend.primeInstructions === "function") {
|
|
31509
|
+
try {
|
|
31510
|
+
generatedInstructions = await backend.primeInstructions();
|
|
31511
|
+
} catch {
|
|
31512
|
+
generatedInstructions = "";
|
|
31513
|
+
}
|
|
31514
|
+
}
|
|
31515
|
+
const instructionsPath = writeToWorkspaceInstructions && typeof backend.writeInstructions === "function" ? await backend.writeInstructions(generatedInstructions) : null;
|
|
31131
31516
|
return {
|
|
31132
31517
|
content: [
|
|
31133
31518
|
{
|
|
31134
31519
|
type: "text",
|
|
31135
|
-
text: JSON.stringify({ graphqlSchema, generatedInstructions
|
|
31520
|
+
text: JSON.stringify({ graphqlSchema, generatedInstructions, instructionsPath }, null, 2)
|
|
31136
31521
|
}
|
|
31137
31522
|
],
|
|
31138
|
-
structuredContent: { graphqlSchema, generatedInstructions
|
|
31523
|
+
structuredContent: { graphqlSchema, generatedInstructions, instructionsPath }
|
|
31139
31524
|
};
|
|
31140
31525
|
}
|
|
31141
31526
|
if (operation === "open_config") {
|
|
@@ -31181,6 +31566,31 @@ async function handleQueryOperation(backend, params) {
|
|
|
31181
31566
|
structuredContent: { query: search, count: beans2.length, beans: beans2 }
|
|
31182
31567
|
};
|
|
31183
31568
|
}
|
|
31569
|
+
if (operation === "ready") {
|
|
31570
|
+
const allBeans = await backend.list();
|
|
31571
|
+
const byId = new Map(allBeans.map((bean) => [bean.id, bean]));
|
|
31572
|
+
const candidates = await backend.list({ status: normalizedStatuses, type: normalizedTypes, search });
|
|
31573
|
+
const readyBeans = candidates.filter((bean) => {
|
|
31574
|
+
if (bean.status !== "todo") {
|
|
31575
|
+
return false;
|
|
31576
|
+
}
|
|
31577
|
+
const blockedBy = bean.blockedByIds || [];
|
|
31578
|
+
if (blockedBy.length === 0) {
|
|
31579
|
+
return true;
|
|
31580
|
+
}
|
|
31581
|
+
return blockedBy.every((blockerId) => {
|
|
31582
|
+
const blocker = byId.get(blockerId);
|
|
31583
|
+
if (!blocker) {
|
|
31584
|
+
return false;
|
|
31585
|
+
}
|
|
31586
|
+
return blocker.status === "completed" || blocker.status === "scrapped";
|
|
31587
|
+
});
|
|
31588
|
+
});
|
|
31589
|
+
return {
|
|
31590
|
+
content: [{ type: "text", text: JSON.stringify({ count: readyBeans.length, beans: readyBeans }, null, 2) }],
|
|
31591
|
+
structuredContent: { count: readyBeans.length, beans: readyBeans }
|
|
31592
|
+
};
|
|
31593
|
+
}
|
|
31184
31594
|
const beans = await backend.list({ status: normalizedStatuses, type: normalizedTypes, search });
|
|
31185
31595
|
const sorted = sortBeansInternal(beans, mode ?? "status-priority-type-title");
|
|
31186
31596
|
return {
|
|
@@ -31199,92 +31609,45 @@ var MAX_PATH_LENGTH = 1024;
|
|
|
31199
31609
|
|
|
31200
31610
|
// src/server/BeansMcpServer.ts
|
|
31201
31611
|
init_utils();
|
|
31202
|
-
|
|
31203
|
-
|
|
31204
|
-
|
|
31205
|
-
|
|
31206
|
-
|
|
31207
|
-
|
|
31208
|
-
|
|
31209
|
-
|
|
31210
|
-
name: "Daniel Sieradski",
|
|
31211
|
-
email: "daniel@self.agency",
|
|
31212
|
-
url: "https://self.agency"
|
|
31213
|
-
},
|
|
31214
|
-
homepage: "https://github.com/hmans/beans",
|
|
31215
|
-
bugs: {
|
|
31216
|
-
url: "https://github.com/selfagency/beans-mcp/issues"
|
|
31217
|
-
},
|
|
31218
|
-
repository: {
|
|
31219
|
-
type: "git",
|
|
31220
|
-
url: "git+https://github.com/selfagency/beans-mcp.git"
|
|
31221
|
-
},
|
|
31222
|
-
mcpName: "io.github.selfagency/beans-mcp",
|
|
31223
|
-
keywords: [
|
|
31224
|
-
"beans",
|
|
31225
|
-
"mcp",
|
|
31226
|
-
"model-context-protocol",
|
|
31227
|
-
"issue-tracker",
|
|
31228
|
-
"ai"
|
|
31229
|
-
],
|
|
31230
|
-
license: "MIT",
|
|
31231
|
-
type: "module",
|
|
31232
|
-
exports: {
|
|
31233
|
-
".": {
|
|
31234
|
-
types: "./dist/index.d.ts",
|
|
31235
|
-
import: "./dist/index.js",
|
|
31236
|
-
require: "./dist/index.cjs"
|
|
31612
|
+
var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
|
|
31613
|
+
var PACKAGE_VERSION = package_default.version ?? "0.0.0-dev";
|
|
31614
|
+
function getSafeCliEnv(env) {
|
|
31615
|
+
const whitelist = ["PATH", "HOME", "USER", "LANG", "LC_ALL", "LC_CTYPE", "SHELL"];
|
|
31616
|
+
const safeEnv = {};
|
|
31617
|
+
for (const key of whitelist) {
|
|
31618
|
+
if (env[key]) {
|
|
31619
|
+
safeEnv[key] = env[key];
|
|
31237
31620
|
}
|
|
31238
|
-
},
|
|
31239
|
-
main: "./dist/index.cjs",
|
|
31240
|
-
module: "./dist/index.js",
|
|
31241
|
-
types: "./dist/index.d.ts",
|
|
31242
|
-
bin: {
|
|
31243
|
-
"beans-mcp": "dist/beans-mcp-server.cjs"
|
|
31244
|
-
},
|
|
31245
|
-
scripts: {
|
|
31246
|
-
build: "tsup",
|
|
31247
|
-
format: "oxfmt",
|
|
31248
|
-
"lint:fix": "oxlint --fix",
|
|
31249
|
-
lint: "oxlint",
|
|
31250
|
-
postbuild: "node ./scripts/write-dist-package.js",
|
|
31251
|
-
prepare: "husky",
|
|
31252
|
-
release: "zx ./scripts/release.js",
|
|
31253
|
-
"test:coverage": "vitest run --coverage",
|
|
31254
|
-
"test:watch": "vitest",
|
|
31255
|
-
test: "vitest run",
|
|
31256
|
-
"type-check": "tsc --noEmit"
|
|
31257
|
-
},
|
|
31258
|
-
devDependencies: {
|
|
31259
|
-
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
31260
|
-
"@octokit/rest": "^22.0.1",
|
|
31261
|
-
"@types/node": "^20.19.0",
|
|
31262
|
-
"@vitest/coverage-v8": "^4.0.18",
|
|
31263
|
-
"@vitest/ui": "4.0.18",
|
|
31264
|
-
husky: "^9.1.7",
|
|
31265
|
-
"lint-staged": "^16.2.7",
|
|
31266
|
-
ora: "^9.3.0",
|
|
31267
|
-
oxfmt: "^0.35.0",
|
|
31268
|
-
oxlint: "^1.50.0",
|
|
31269
|
-
"oxlint-tsgolint": "^0.15.0",
|
|
31270
|
-
tsup: "8.5.1",
|
|
31271
|
-
typescript: "^5.9.3",
|
|
31272
|
-
vitest: "4.0.18",
|
|
31273
|
-
zod: "4.3.6",
|
|
31274
|
-
zx: "^8.8.5"
|
|
31275
|
-
},
|
|
31276
|
-
engines: {
|
|
31277
|
-
node: ">=18"
|
|
31278
|
-
},
|
|
31279
|
-
"lint-staged": {
|
|
31280
|
-
"src/**/*.ts": [
|
|
31281
|
-
"pnpm run lint:fix",
|
|
31282
|
-
"pnpm run format"
|
|
31283
|
-
]
|
|
31284
31621
|
}
|
|
31285
|
-
|
|
31286
|
-
|
|
31287
|
-
|
|
31622
|
+
for (const key in env) {
|
|
31623
|
+
if (key.startsWith("BEANS_")) {
|
|
31624
|
+
safeEnv[key] = env[key];
|
|
31625
|
+
}
|
|
31626
|
+
}
|
|
31627
|
+
return safeEnv;
|
|
31628
|
+
}
|
|
31629
|
+
function extractVersionFromOutput(output) {
|
|
31630
|
+
const trimmed = output.trim();
|
|
31631
|
+
if (!trimmed) {
|
|
31632
|
+
return null;
|
|
31633
|
+
}
|
|
31634
|
+
const match = trimmed.match(/(?:^|[^\d])v?(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/);
|
|
31635
|
+
return match?.[1] ?? null;
|
|
31636
|
+
}
|
|
31637
|
+
async function detectBeansCliVersion(cliPath, workspaceRoot) {
|
|
31638
|
+
try {
|
|
31639
|
+
const { stdout, stderr } = await execFileAsync2(cliPath, ["version"], {
|
|
31640
|
+
cwd: workspaceRoot,
|
|
31641
|
+
env: getSafeCliEnv(process.env),
|
|
31642
|
+
maxBuffer: 1024 * 1024,
|
|
31643
|
+
timeout: 5e3
|
|
31644
|
+
});
|
|
31645
|
+
return extractVersionFromOutput(`${stdout}
|
|
31646
|
+
${stderr}`);
|
|
31647
|
+
} catch {
|
|
31648
|
+
return null;
|
|
31649
|
+
}
|
|
31650
|
+
}
|
|
31288
31651
|
async function getBeanById(backend, beanId) {
|
|
31289
31652
|
try {
|
|
31290
31653
|
const beans = await backend.list();
|
|
@@ -31304,7 +31667,40 @@ function initHandler(backend) {
|
|
|
31304
31667
|
};
|
|
31305
31668
|
}
|
|
31306
31669
|
function viewHandler(backend) {
|
|
31307
|
-
return async ({ beanId }) =>
|
|
31670
|
+
return async ({ beanId, beanIds }) => {
|
|
31671
|
+
const ids = Array.isArray(beanIds) && beanIds.length > 0 ? beanIds : beanId ? [beanId] : [];
|
|
31672
|
+
if (ids.length === 0) {
|
|
31673
|
+
throw new Error("Either beanId or beanIds must be provided");
|
|
31674
|
+
}
|
|
31675
|
+
if (ids.length === 1) {
|
|
31676
|
+
const bean = await getBeanById(backend, ids[0]);
|
|
31677
|
+
return makeTextAndStructured({ bean });
|
|
31678
|
+
}
|
|
31679
|
+
const beans = await backend.list();
|
|
31680
|
+
const byId = new Map(beans.map((b) => [b.id, b]));
|
|
31681
|
+
const found = ids.map((id) => byId.get(id)).filter(Boolean);
|
|
31682
|
+
const missingBeanIds = ids.filter((id) => !byId.has(id));
|
|
31683
|
+
return makeTextAndStructured({
|
|
31684
|
+
beans: found,
|
|
31685
|
+
missingBeanIds,
|
|
31686
|
+
count: found.length,
|
|
31687
|
+
requestedCount: ids.length
|
|
31688
|
+
});
|
|
31689
|
+
};
|
|
31690
|
+
}
|
|
31691
|
+
async function checkVersionCompatibility(cliPath, workspaceRoot, detector) {
|
|
31692
|
+
const detectedBeansVersion = await detector(cliPath, workspaceRoot);
|
|
31693
|
+
if (!detectedBeansVersion) {
|
|
31694
|
+
console.error(
|
|
31695
|
+
`[beans-mcp] warning: unable to determine Beans CLI version from \`${cliPath}\`; proceeding without version compatibility checks.`
|
|
31696
|
+
);
|
|
31697
|
+
return;
|
|
31698
|
+
}
|
|
31699
|
+
if (detectedBeansVersion !== PACKAGE_VERSION) {
|
|
31700
|
+
console.error(
|
|
31701
|
+
`[beans-mcp] warning: version mismatch detected (beans=${detectedBeansVersion}, beans-mcp=${PACKAGE_VERSION}); continuing startup.`
|
|
31702
|
+
);
|
|
31703
|
+
}
|
|
31308
31704
|
}
|
|
31309
31705
|
function createHandler(backend) {
|
|
31310
31706
|
return async (input) => makeTextAndStructured({ bean: await backend.create(input) });
|
|
@@ -31340,17 +31736,82 @@ function updateHandler(backend) {
|
|
|
31340
31736
|
clearParent: input.clearParent,
|
|
31341
31737
|
blocking: input.blocking,
|
|
31342
31738
|
blockedBy: input.blockedBy,
|
|
31343
|
-
body: input.body
|
|
31739
|
+
body: input.body,
|
|
31740
|
+
bodyAppend: input.bodyAppend,
|
|
31741
|
+
bodyReplace: input.bodyReplace,
|
|
31742
|
+
ifMatch: input.ifMatch
|
|
31344
31743
|
})
|
|
31345
31744
|
});
|
|
31346
31745
|
}
|
|
31347
31746
|
function deleteHandler(backend) {
|
|
31348
|
-
return async ({ beanId, force }) => {
|
|
31349
|
-
const
|
|
31350
|
-
if (
|
|
31351
|
-
throw new Error("
|
|
31747
|
+
return async ({ beanId, beanIds, force }) => {
|
|
31748
|
+
const ids = Array.isArray(beanIds) && beanIds.length > 0 ? beanIds : beanId ? [beanId] : [];
|
|
31749
|
+
if (ids.length === 0) {
|
|
31750
|
+
throw new Error("Either beanId or beanIds must be provided");
|
|
31352
31751
|
}
|
|
31353
|
-
|
|
31752
|
+
if (ids.length === 1) {
|
|
31753
|
+
const bean = await getBeanById(backend, ids[0]);
|
|
31754
|
+
if (!force && bean.status !== "draft" && bean.status !== "scrapped") {
|
|
31755
|
+
throw new Error("Only draft and scrapped beans are deletable unless force=true");
|
|
31756
|
+
}
|
|
31757
|
+
return makeTextAndStructured(await backend.delete(ids[0]));
|
|
31758
|
+
}
|
|
31759
|
+
const beans = await backend.list();
|
|
31760
|
+
const byId = new Map(beans.map((b) => [b.id, b]));
|
|
31761
|
+
const results = [];
|
|
31762
|
+
for (const id of ids) {
|
|
31763
|
+
const bean = byId.get(id);
|
|
31764
|
+
if (!bean) {
|
|
31765
|
+
results.push({ beanId: id, deleted: false, error: "Bean not found" });
|
|
31766
|
+
continue;
|
|
31767
|
+
}
|
|
31768
|
+
if (!force && bean.status !== "draft" && bean.status !== "scrapped") {
|
|
31769
|
+
results.push({
|
|
31770
|
+
beanId: id,
|
|
31771
|
+
deleted: false,
|
|
31772
|
+
error: "Only draft and scrapped beans are deletable unless force=true"
|
|
31773
|
+
});
|
|
31774
|
+
continue;
|
|
31775
|
+
}
|
|
31776
|
+
try {
|
|
31777
|
+
await backend.delete(id);
|
|
31778
|
+
results.push({ beanId: id, deleted: true });
|
|
31779
|
+
} catch (error48) {
|
|
31780
|
+
results.push({
|
|
31781
|
+
beanId: id,
|
|
31782
|
+
deleted: false,
|
|
31783
|
+
error: error48.message
|
|
31784
|
+
});
|
|
31785
|
+
}
|
|
31786
|
+
}
|
|
31787
|
+
return makeTextAndStructured({
|
|
31788
|
+
results,
|
|
31789
|
+
requestedCount: ids.length,
|
|
31790
|
+
deletedCount: results.filter((r) => r.deleted).length,
|
|
31791
|
+
failedCount: results.filter((r) => !r.deleted).length
|
|
31792
|
+
});
|
|
31793
|
+
};
|
|
31794
|
+
}
|
|
31795
|
+
function bulkCreateHandler(backend) {
|
|
31796
|
+
return async (input) => {
|
|
31797
|
+
const results = await backend.bulkCreate(input.beans, input.parent);
|
|
31798
|
+
return makeTextAndStructured({
|
|
31799
|
+
results,
|
|
31800
|
+
requestedCount: input.beans.length,
|
|
31801
|
+
successCount: results.filter((r) => r.bean).length,
|
|
31802
|
+
failedCount: results.filter((r) => r.error).length
|
|
31803
|
+
});
|
|
31804
|
+
};
|
|
31805
|
+
}
|
|
31806
|
+
function bulkUpdateHandler(backend) {
|
|
31807
|
+
return async (input) => {
|
|
31808
|
+
const results = await backend.bulkUpdate(input.beans, input.parent);
|
|
31809
|
+
return makeTextAndStructured({
|
|
31810
|
+
results,
|
|
31811
|
+
requestedCount: input.beans.length,
|
|
31812
|
+
successCount: results.filter((r) => r.bean).length,
|
|
31813
|
+
failedCount: results.filter((r) => r.error).length
|
|
31814
|
+
});
|
|
31354
31815
|
};
|
|
31355
31816
|
}
|
|
31356
31817
|
function queryHandler(backend) {
|
|
@@ -31411,7 +31872,12 @@ function registerTools(server, backend) {
|
|
|
31411
31872
|
{
|
|
31412
31873
|
title: "View Bean",
|
|
31413
31874
|
description: "Fetch full bean details by ID.",
|
|
31414
|
-
inputSchema: external_exports3.object({
|
|
31875
|
+
inputSchema: external_exports3.object({
|
|
31876
|
+
beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH).optional(),
|
|
31877
|
+
beanIds: external_exports3.array(external_exports3.string().min(1).max(MAX_ID_LENGTH)).optional()
|
|
31878
|
+
}).refine((input) => Boolean(input.beanId) || Array.isArray(input.beanIds) && input.beanIds.length > 0, {
|
|
31879
|
+
message: "Either beanId or beanIds must be provided"
|
|
31880
|
+
}),
|
|
31415
31881
|
annotations: {
|
|
31416
31882
|
readOnlyHint: true,
|
|
31417
31883
|
destructiveHint: false,
|
|
@@ -31431,7 +31897,8 @@ function registerTools(server, backend) {
|
|
|
31431
31897
|
type: external_exports3.string().min(1).max(MAX_METADATA_LENGTH),
|
|
31432
31898
|
status: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
31433
31899
|
priority: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
31434
|
-
|
|
31900
|
+
body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional().describe("Body markdown content"),
|
|
31901
|
+
description: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional().describe("Deprecated alias for body"),
|
|
31435
31902
|
parent: external_exports3.string().max(MAX_ID_LENGTH).optional()
|
|
31436
31903
|
}),
|
|
31437
31904
|
annotations: {
|
|
@@ -31500,8 +31967,21 @@ function registerTools(server, backend) {
|
|
|
31500
31967
|
clearParent: external_exports3.boolean().optional(),
|
|
31501
31968
|
blocking: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
|
|
31502
31969
|
blockedBy: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
|
|
31503
|
-
body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional()
|
|
31504
|
-
|
|
31970
|
+
body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional(),
|
|
31971
|
+
bodyAppend: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional(),
|
|
31972
|
+
bodyReplace: external_exports3.array(
|
|
31973
|
+
external_exports3.object({
|
|
31974
|
+
old: external_exports3.string().max(MAX_DESCRIPTION_LENGTH),
|
|
31975
|
+
new: external_exports3.string().max(MAX_DESCRIPTION_LENGTH)
|
|
31976
|
+
})
|
|
31977
|
+
).optional(),
|
|
31978
|
+
ifMatch: external_exports3.string().max(MAX_METADATA_LENGTH).optional()
|
|
31979
|
+
}).refine(
|
|
31980
|
+
(input) => !(input.body !== void 0 && (input.bodyAppend !== void 0 || input.bodyReplace !== void 0)),
|
|
31981
|
+
{
|
|
31982
|
+
message: "body cannot be combined with bodyAppend/bodyReplace"
|
|
31983
|
+
}
|
|
31984
|
+
),
|
|
31505
31985
|
annotations: {
|
|
31506
31986
|
readOnlyHint: false,
|
|
31507
31987
|
destructiveHint: false,
|
|
@@ -31517,8 +31997,11 @@ function registerTools(server, backend) {
|
|
|
31517
31997
|
title: "Delete Bean",
|
|
31518
31998
|
description: "Delete a bean (intended for draft/scrapped beans).",
|
|
31519
31999
|
inputSchema: external_exports3.object({
|
|
31520
|
-
beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH),
|
|
32000
|
+
beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH).optional(),
|
|
32001
|
+
beanIds: external_exports3.array(external_exports3.string().min(1).max(MAX_ID_LENGTH)).optional(),
|
|
31521
32002
|
force: external_exports3.boolean().default(false)
|
|
32003
|
+
}).refine((input) => Boolean(input.beanId) || Array.isArray(input.beanIds) && input.beanIds.length > 0, {
|
|
32004
|
+
message: "Either beanId or beanIds must be provided"
|
|
31522
32005
|
}),
|
|
31523
32006
|
annotations: {
|
|
31524
32007
|
readOnlyHint: false,
|
|
@@ -31529,13 +32012,75 @@ function registerTools(server, backend) {
|
|
|
31529
32012
|
},
|
|
31530
32013
|
deleteHandler(backend)
|
|
31531
32014
|
);
|
|
32015
|
+
const beanCreateItemSchema = external_exports3.object({
|
|
32016
|
+
title: external_exports3.string().min(1).max(MAX_TITLE_LENGTH),
|
|
32017
|
+
type: external_exports3.string().min(1).max(MAX_METADATA_LENGTH),
|
|
32018
|
+
status: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
32019
|
+
priority: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
32020
|
+
body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional().describe("Body markdown content"),
|
|
32021
|
+
description: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional().describe("Deprecated alias for body"),
|
|
32022
|
+
parent: external_exports3.string().max(MAX_ID_LENGTH).optional().describe("Override the top-level parent for this item")
|
|
32023
|
+
});
|
|
32024
|
+
server.registerTool(
|
|
32025
|
+
"beans_bulk_create",
|
|
32026
|
+
{
|
|
32027
|
+
title: "Bulk Create Beans",
|
|
32028
|
+
description: "Create multiple beans in one call. Optionally assign all of them (or a subset) to a shared parent.",
|
|
32029
|
+
inputSchema: external_exports3.object({
|
|
32030
|
+
beans: external_exports3.array(beanCreateItemSchema).min(1),
|
|
32031
|
+
parent: external_exports3.string().max(MAX_ID_LENGTH).optional().describe("Default parent ID applied to any bean that does not specify its own parent")
|
|
32032
|
+
}),
|
|
32033
|
+
annotations: {
|
|
32034
|
+
readOnlyHint: false,
|
|
32035
|
+
destructiveHint: false,
|
|
32036
|
+
idempotentHint: false,
|
|
32037
|
+
openWorldHint: false
|
|
32038
|
+
}
|
|
32039
|
+
},
|
|
32040
|
+
bulkCreateHandler(backend)
|
|
32041
|
+
);
|
|
32042
|
+
const beanUpdateItemSchema = external_exports3.object({
|
|
32043
|
+
beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH),
|
|
32044
|
+
status: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
32045
|
+
type: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
32046
|
+
priority: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
32047
|
+
parent: external_exports3.string().max(MAX_ID_LENGTH).optional().describe("Override the top-level parent for this item"),
|
|
32048
|
+
clearParent: external_exports3.boolean().optional(),
|
|
32049
|
+
blocking: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
|
|
32050
|
+
blockedBy: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
|
|
32051
|
+
body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional(),
|
|
32052
|
+
bodyAppend: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional(),
|
|
32053
|
+
bodyReplace: external_exports3.array(external_exports3.object({ old: external_exports3.string().max(MAX_DESCRIPTION_LENGTH), new: external_exports3.string().max(MAX_DESCRIPTION_LENGTH) })).optional(),
|
|
32054
|
+
ifMatch: external_exports3.string().max(MAX_METADATA_LENGTH).optional()
|
|
32055
|
+
}).refine(
|
|
32056
|
+
(input) => !(input.body !== void 0 && (input.bodyAppend !== void 0 || input.bodyReplace !== void 0)),
|
|
32057
|
+
{ message: "body cannot be combined with bodyAppend/bodyReplace" }
|
|
32058
|
+
);
|
|
32059
|
+
server.registerTool(
|
|
32060
|
+
"beans_bulk_update",
|
|
32061
|
+
{
|
|
32062
|
+
title: "Bulk Update Beans",
|
|
32063
|
+
description: "Update multiple beans in one call. Optionally assign all of them (or a subset) to a shared parent.",
|
|
32064
|
+
inputSchema: external_exports3.object({
|
|
32065
|
+
beans: external_exports3.array(beanUpdateItemSchema).min(1),
|
|
32066
|
+
parent: external_exports3.string().max(MAX_ID_LENGTH).optional().describe("Default parent ID applied to any bean that does not specify its own parent")
|
|
32067
|
+
}),
|
|
32068
|
+
annotations: {
|
|
32069
|
+
readOnlyHint: false,
|
|
32070
|
+
destructiveHint: false,
|
|
32071
|
+
idempotentHint: false,
|
|
32072
|
+
openWorldHint: false
|
|
32073
|
+
}
|
|
32074
|
+
},
|
|
32075
|
+
bulkUpdateHandler(backend)
|
|
32076
|
+
);
|
|
31532
32077
|
server.registerTool(
|
|
31533
32078
|
"beans_query",
|
|
31534
32079
|
{
|
|
31535
32080
|
title: "Query Beans",
|
|
31536
32081
|
description: "Unified query tool for refresh, filter, search, and sort operations.",
|
|
31537
32082
|
inputSchema: external_exports3.object({
|
|
31538
|
-
operation: external_exports3.enum(["refresh", "filter", "search", "sort", "llm_context", "open_config"]).default("refresh"),
|
|
32083
|
+
operation: external_exports3.enum(["refresh", "filter", "search", "sort", "ready", "llm_context", "open_config"]).default("refresh"),
|
|
31539
32084
|
mode: external_exports3.enum(["status-priority-type-title", "updated", "created", "id"]).optional(),
|
|
31540
32085
|
statuses: external_exports3.array(external_exports3.string().max(MAX_METADATA_LENGTH)).nullable().optional(),
|
|
31541
32086
|
types: external_exports3.array(external_exports3.string().max(MAX_METADATA_LENGTH)).nullable().optional(),
|
|
@@ -31614,9 +32159,21 @@ var MutableBackend = class {
|
|
|
31614
32159
|
delete(id) {
|
|
31615
32160
|
return this.inner.delete(id);
|
|
31616
32161
|
}
|
|
32162
|
+
bulkCreate(beans, defaultParent) {
|
|
32163
|
+
return this.inner.bulkCreate(beans, defaultParent);
|
|
32164
|
+
}
|
|
32165
|
+
bulkUpdate(beans, defaultParent) {
|
|
32166
|
+
return this.inner.bulkUpdate(beans, defaultParent);
|
|
32167
|
+
}
|
|
31617
32168
|
openConfig() {
|
|
31618
32169
|
return this.inner.openConfig();
|
|
31619
32170
|
}
|
|
32171
|
+
primeInstructions() {
|
|
32172
|
+
return this.inner.primeInstructions?.() ?? Promise.resolve("");
|
|
32173
|
+
}
|
|
32174
|
+
writeInstructions(instructions) {
|
|
32175
|
+
return this.inner.writeInstructions?.(instructions) ?? Promise.resolve(null);
|
|
32176
|
+
}
|
|
31620
32177
|
graphqlSchema() {
|
|
31621
32178
|
return this.inner.graphqlSchema();
|
|
31622
32179
|
}
|
|
@@ -31654,7 +32211,7 @@ async function createBeansMcpServer(opts) {
|
|
|
31654
32211
|
const backend = opts.backend || new BeansCliBackend2(opts.workspaceRoot, opts.cliPath || "beans", opts.logDir);
|
|
31655
32212
|
const server = new McpServer({
|
|
31656
32213
|
name: opts.name || "beans-mcp-server",
|
|
31657
|
-
version: opts.version ||
|
|
32214
|
+
version: opts.version || PACKAGE_VERSION
|
|
31658
32215
|
});
|
|
31659
32216
|
registerTools(server, backend);
|
|
31660
32217
|
return { server, backend };
|
|
@@ -31726,17 +32283,17 @@ function parseCliArgs(argv) {
|
|
|
31726
32283
|
}
|
|
31727
32284
|
return { workspaceRoot, workspaceExplicit, cliPath, port, logDir };
|
|
31728
32285
|
}
|
|
31729
|
-
async function startBeansMcpServer(argv, _resolveRoots) {
|
|
32286
|
+
async function startBeansMcpServer(argv, _resolveRoots, _detectBeansVersion) {
|
|
31730
32287
|
const { BeansCliBackend: BeansCliBackend2 } = await Promise.resolve().then(() => (init_backend(), backend_exports));
|
|
31731
32288
|
const { StdioServerTransport: StdioServerTransport2 } = await Promise.resolve().then(() => (init_stdio2(), stdio_exports));
|
|
31732
32289
|
const { workspaceRoot, workspaceExplicit, cliPath, port, logDir } = parseCliArgs(argv);
|
|
32290
|
+
let effectiveWorkspaceRoot = workspaceRoot;
|
|
31733
32291
|
process.env.BEANS_VSCODE_MCP_PORT = String(port);
|
|
31734
32292
|
process.env.BEANS_MCP_PORT = String(port);
|
|
31735
32293
|
try {
|
|
31736
|
-
const version2 = package_default.version ?? "0.0.0-dev";
|
|
31737
32294
|
const workspaceLabel = workspaceExplicit ? workspaceRoot : "(auto from roots)";
|
|
31738
32295
|
console.error(
|
|
31739
|
-
`[beans-mcp] v${
|
|
32296
|
+
`[beans-mcp] v${PACKAGE_VERSION} starting (port=${port}, workspace=${workspaceLabel}, cli=${cliPath}, logDir=${logDir})`
|
|
31740
32297
|
);
|
|
31741
32298
|
} catch {
|
|
31742
32299
|
}
|
|
@@ -31753,13 +32310,17 @@ async function startBeansMcpServer(argv, _resolveRoots) {
|
|
|
31753
32310
|
const resolver = _resolveRoots ?? resolveWorkspaceFromRoots;
|
|
31754
32311
|
const rootPath = await resolver(server);
|
|
31755
32312
|
if (rootPath) {
|
|
31756
|
-
mutable.setInner(new BeansCliBackend2(rootPath, cliPath));
|
|
32313
|
+
mutable.setInner(new BeansCliBackend2(rootPath, cliPath, logDir));
|
|
32314
|
+
effectiveWorkspaceRoot = rootPath;
|
|
31757
32315
|
try {
|
|
31758
32316
|
console.error(`[beans-mcp] workspace resolved from roots: ${rootPath}`);
|
|
31759
32317
|
} catch {
|
|
31760
32318
|
}
|
|
31761
32319
|
}
|
|
31762
32320
|
}
|
|
32321
|
+
const beansVersionDetector = _detectBeansVersion ?? detectBeansCliVersion;
|
|
32322
|
+
void checkVersionCompatibility(cliPath, effectiveWorkspaceRoot, beansVersionDetector).catch(() => {
|
|
32323
|
+
});
|
|
31763
32324
|
}
|
|
31764
32325
|
|
|
31765
32326
|
// src/cli.ts
|