@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/index.js
CHANGED
|
@@ -14431,7 +14431,7 @@ var init_v4 = __esm({
|
|
|
14431
14431
|
}
|
|
14432
14432
|
});
|
|
14433
14433
|
|
|
14434
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
14434
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
14435
14435
|
function assertCompleteRequestPrompt(request) {
|
|
14436
14436
|
if (request.params.ref.type !== "ref/prompt") {
|
|
14437
14437
|
throw new TypeError(`Expected CompleteRequestPrompt, but got ${request.params.ref.type}`);
|
|
@@ -14446,7 +14446,7 @@ function assertCompleteRequestResourceTemplate(request) {
|
|
|
14446
14446
|
}
|
|
14447
14447
|
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;
|
|
14448
14448
|
var init_types = __esm({
|
|
14449
|
-
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
14449
|
+
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js"() {
|
|
14450
14450
|
"use strict";
|
|
14451
14451
|
init_v4();
|
|
14452
14452
|
LATEST_PROTOCOL_VERSION = "2025-11-25";
|
|
@@ -14458,10 +14458,9 @@ var init_types = __esm({
|
|
|
14458
14458
|
CursorSchema = string2();
|
|
14459
14459
|
TaskCreationParamsSchema = looseObject({
|
|
14460
14460
|
/**
|
|
14461
|
-
*
|
|
14462
|
-
* If null, the task has unlimited lifetime until manually cleaned up.
|
|
14461
|
+
* Requested duration in milliseconds to retain task from creation.
|
|
14463
14462
|
*/
|
|
14464
|
-
ttl:
|
|
14463
|
+
ttl: number2().optional(),
|
|
14465
14464
|
/**
|
|
14466
14465
|
* Time in milliseconds to wait between task status requests.
|
|
14467
14466
|
*/
|
|
@@ -14760,7 +14759,11 @@ var init_types = __esm({
|
|
|
14760
14759
|
/**
|
|
14761
14760
|
* Present if the client supports task creation.
|
|
14762
14761
|
*/
|
|
14763
|
-
tasks: ClientTasksCapabilitySchema.optional()
|
|
14762
|
+
tasks: ClientTasksCapabilitySchema.optional(),
|
|
14763
|
+
/**
|
|
14764
|
+
* Extensions that the client supports. Keys are extension identifiers (vendor-prefix/extension-name).
|
|
14765
|
+
*/
|
|
14766
|
+
extensions: record(string2(), AssertObjectSchema).optional()
|
|
14764
14767
|
});
|
|
14765
14768
|
InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
14766
14769
|
/**
|
|
@@ -14821,7 +14824,11 @@ var init_types = __esm({
|
|
|
14821
14824
|
/**
|
|
14822
14825
|
* Present if the server supports task creation.
|
|
14823
14826
|
*/
|
|
14824
|
-
tasks: ServerTasksCapabilitySchema.optional()
|
|
14827
|
+
tasks: ServerTasksCapabilitySchema.optional(),
|
|
14828
|
+
/**
|
|
14829
|
+
* Extensions that the server supports. Keys are extension identifiers (vendor-prefix/extension-name).
|
|
14830
|
+
*/
|
|
14831
|
+
extensions: record(string2(), AssertObjectSchema).optional()
|
|
14825
14832
|
});
|
|
14826
14833
|
InitializeResultSchema = ResultSchema.extend({
|
|
14827
14834
|
/**
|
|
@@ -15013,6 +15020,12 @@ var init_types = __esm({
|
|
|
15013
15020
|
* The MIME type of this resource, if known.
|
|
15014
15021
|
*/
|
|
15015
15022
|
mimeType: optional(string2()),
|
|
15023
|
+
/**
|
|
15024
|
+
* The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.
|
|
15025
|
+
*
|
|
15026
|
+
* This can be used by Hosts to display file sizes and estimate context window usage.
|
|
15027
|
+
*/
|
|
15028
|
+
size: optional(number2()),
|
|
15016
15029
|
/**
|
|
15017
15030
|
* Optional annotations for the client.
|
|
15018
15031
|
*/
|
|
@@ -22744,7 +22757,7 @@ var init_utils = __esm({
|
|
|
22744
22757
|
});
|
|
22745
22758
|
|
|
22746
22759
|
// src/internal/graphql.ts
|
|
22747
|
-
var LIST_BEANS_QUERY, CREATE_BEAN_MUTATION, UPDATE_BEAN_MUTATION, DELETE_BEAN_MUTATION;
|
|
22760
|
+
var LIST_BEANS_QUERY, CREATE_BEAN_MUTATION, UPDATE_BEAN_MUTATION, UPDATE_BEAN_MUTATION_WITH_IF_MATCH, DELETE_BEAN_MUTATION, LIST_BEANS_TIMESTAMPS_QUERY;
|
|
22748
22761
|
var init_graphql = __esm({
|
|
22749
22762
|
"src/internal/graphql.ts"() {
|
|
22750
22763
|
"use strict";
|
|
@@ -22762,11 +22775,21 @@ var init_graphql = __esm({
|
|
|
22762
22775
|
mutation($id: ID!, $input: UpdateBeanInput!) {
|
|
22763
22776
|
updateBean(id: $id, input: $input) { id slug path title body status type priority tags parentId blockingIds blockedByIds createdAt updatedAt etag }
|
|
22764
22777
|
}
|
|
22778
|
+
`;
|
|
22779
|
+
UPDATE_BEAN_MUTATION_WITH_IF_MATCH = `
|
|
22780
|
+
mutation($id: ID!, $input: UpdateBeanInput!, $ifMatch: String!) {
|
|
22781
|
+
updateBean(id: $id, input: $input, ifMatch: $ifMatch) { id slug path title body status type priority tags parentId blockingIds blockedByIds createdAt updatedAt etag }
|
|
22782
|
+
}
|
|
22765
22783
|
`;
|
|
22766
22784
|
DELETE_BEAN_MUTATION = `
|
|
22767
22785
|
mutation($id: ID!) {
|
|
22768
22786
|
deleteBean(id: $id)
|
|
22769
22787
|
}
|
|
22788
|
+
`;
|
|
22789
|
+
LIST_BEANS_TIMESTAMPS_QUERY = `
|
|
22790
|
+
query {
|
|
22791
|
+
beans { id updatedAt }
|
|
22792
|
+
}
|
|
22770
22793
|
`;
|
|
22771
22794
|
}
|
|
22772
22795
|
});
|
|
@@ -22789,12 +22812,26 @@ var init_backend = __esm({
|
|
|
22789
22812
|
init_graphql();
|
|
22790
22813
|
init_utils();
|
|
22791
22814
|
execFileAsync = promisify(execFile);
|
|
22792
|
-
BeansCliBackend = class {
|
|
22815
|
+
BeansCliBackend = class _BeansCliBackend {
|
|
22793
22816
|
constructor(workspaceRoot, cliPath, logDir) {
|
|
22794
22817
|
this.workspaceRoot = workspaceRoot;
|
|
22795
22818
|
this.cliPath = cliPath;
|
|
22796
22819
|
this.logDir = logDir;
|
|
22797
22820
|
}
|
|
22821
|
+
// ---------------------------------------------------------------------------
|
|
22822
|
+
// Cache
|
|
22823
|
+
// ---------------------------------------------------------------------------
|
|
22824
|
+
/** Full unfiltered records keyed by bean ID, stored under the fixed cache key `'all'`. */
|
|
22825
|
+
_cache = /* @__PURE__ */ new Map();
|
|
22826
|
+
/** Last time the unfiltered cache entry `'all'` was fetched (ms). */
|
|
22827
|
+
_cacheTime = /* @__PURE__ */ new Map();
|
|
22828
|
+
/** Short-circuit TTL: skip even the timestamp check within this window (ms). */
|
|
22829
|
+
static BURST_TTL_MS = 5e3;
|
|
22830
|
+
/** Invalidate the unfiltered list cache so the next call does a full fetch. */
|
|
22831
|
+
invalidateCache() {
|
|
22832
|
+
this._cache.delete("all");
|
|
22833
|
+
this._cacheTime.delete("all");
|
|
22834
|
+
}
|
|
22798
22835
|
/**
|
|
22799
22836
|
* Returns a safe environment for executing the Beans CLI,
|
|
22800
22837
|
* whitelisting only necessary variables.
|
|
@@ -22818,7 +22855,7 @@ var init_backend = __esm({
|
|
|
22818
22855
|
return resolve2(this.workspaceRoot, ".beans");
|
|
22819
22856
|
}
|
|
22820
22857
|
resolveBeanFilePath(relativePath) {
|
|
22821
|
-
const cleaned = relativePath.trim().replace(/^\/+/, "");
|
|
22858
|
+
const cleaned = relativePath.trim().replace(/^\/+/, "").replace(/^\.beans(?:[\\/]|$)/, "");
|
|
22822
22859
|
if (!cleaned) {
|
|
22823
22860
|
throw new Error("Path is required");
|
|
22824
22861
|
}
|
|
@@ -22876,10 +22913,48 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22876
22913
|
if (options?.search) {
|
|
22877
22914
|
filter.search = options.search;
|
|
22878
22915
|
}
|
|
22916
|
+
const isCacheable = !filter.status && !filter.type && !filter.search;
|
|
22917
|
+
const cacheKey = "all";
|
|
22918
|
+
if (isCacheable) {
|
|
22919
|
+
const lastFetch = this._cacheTime.get(cacheKey) ?? 0;
|
|
22920
|
+
const cached2 = this._cache.get(cacheKey);
|
|
22921
|
+
const age = Date.now() - lastFetch;
|
|
22922
|
+
if (cached2 && age < _BeansCliBackend.BURST_TTL_MS) {
|
|
22923
|
+
return Array.from(cached2.values());
|
|
22924
|
+
}
|
|
22925
|
+
if (cached2) {
|
|
22926
|
+
try {
|
|
22927
|
+
const { data: tsData } = await this.executeGraphQL(
|
|
22928
|
+
LIST_BEANS_TIMESTAMPS_QUERY
|
|
22929
|
+
);
|
|
22930
|
+
const timestamps = tsData.beans;
|
|
22931
|
+
let dirty = timestamps.length !== cached2.size;
|
|
22932
|
+
if (!dirty) {
|
|
22933
|
+
for (const { id, updatedAt } of timestamps) {
|
|
22934
|
+
const existing = cached2.get(id);
|
|
22935
|
+
if (!existing || existing.updatedAt !== updatedAt) {
|
|
22936
|
+
dirty = true;
|
|
22937
|
+
break;
|
|
22938
|
+
}
|
|
22939
|
+
}
|
|
22940
|
+
}
|
|
22941
|
+
if (!dirty) {
|
|
22942
|
+
this._cacheTime.set(cacheKey, Date.now());
|
|
22943
|
+
return Array.from(cached2.values());
|
|
22944
|
+
}
|
|
22945
|
+
} catch {
|
|
22946
|
+
}
|
|
22947
|
+
}
|
|
22948
|
+
}
|
|
22879
22949
|
const { data, errors } = await this.executeGraphQL(LIST_BEANS_QUERY, { filter });
|
|
22880
22950
|
if (errors && errors.length > 0) {
|
|
22881
22951
|
throw new Error(`GraphQL error: ${errors.map((e) => e.message).join(", ")}`);
|
|
22882
22952
|
}
|
|
22953
|
+
if (isCacheable) {
|
|
22954
|
+
const byId = new Map(data.beans.map((b) => [b.id, b]));
|
|
22955
|
+
this._cache.set(cacheKey, byId);
|
|
22956
|
+
this._cacheTime.set(cacheKey, Date.now());
|
|
22957
|
+
}
|
|
22883
22958
|
return data.beans;
|
|
22884
22959
|
}
|
|
22885
22960
|
async create(input) {
|
|
@@ -22888,7 +22963,7 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22888
22963
|
type: input.type,
|
|
22889
22964
|
status: input.status,
|
|
22890
22965
|
priority: input.priority,
|
|
22891
|
-
body: input.description,
|
|
22966
|
+
body: input.body ?? input.description,
|
|
22892
22967
|
parent: input.parent
|
|
22893
22968
|
};
|
|
22894
22969
|
const { data, errors } = await this.executeGraphQL(CREATE_BEAN_MUTATION, {
|
|
@@ -22897,6 +22972,7 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22897
22972
|
if (errors && errors.length > 0) {
|
|
22898
22973
|
throw new Error(`GraphQL error: ${errors.map((e) => e.message).join(", ")}`);
|
|
22899
22974
|
}
|
|
22975
|
+
this.invalidateCache();
|
|
22900
22976
|
return data.createBean;
|
|
22901
22977
|
}
|
|
22902
22978
|
async update(beanId, updates) {
|
|
@@ -22919,13 +22995,54 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22919
22995
|
if (updates.body !== void 0) {
|
|
22920
22996
|
updateInput.body = updates.body;
|
|
22921
22997
|
}
|
|
22922
|
-
const
|
|
22923
|
-
|
|
22924
|
-
|
|
22925
|
-
}
|
|
22998
|
+
const bodyMod = {};
|
|
22999
|
+
if (updates.bodyAppend !== void 0) {
|
|
23000
|
+
bodyMod.append = updates.bodyAppend;
|
|
23001
|
+
}
|
|
23002
|
+
if (Array.isArray(updates.bodyReplace) && updates.bodyReplace.length > 0) {
|
|
23003
|
+
bodyMod.replace = updates.bodyReplace;
|
|
23004
|
+
}
|
|
23005
|
+
if (Object.keys(bodyMod).length > 0) {
|
|
23006
|
+
updateInput.bodyMod = bodyMod;
|
|
23007
|
+
}
|
|
23008
|
+
let data;
|
|
23009
|
+
let errors;
|
|
23010
|
+
if (updates.ifMatch) {
|
|
23011
|
+
try {
|
|
23012
|
+
const res = await this.executeGraphQL(UPDATE_BEAN_MUTATION_WITH_IF_MATCH, {
|
|
23013
|
+
id: beanId,
|
|
23014
|
+
input: updateInput,
|
|
23015
|
+
ifMatch: updates.ifMatch
|
|
23016
|
+
});
|
|
23017
|
+
data = res.data;
|
|
23018
|
+
errors = res.errors;
|
|
23019
|
+
} catch (error48) {
|
|
23020
|
+
const message = error48.message || "";
|
|
23021
|
+
const unsupportedIfMatch = /unknown argument.*ifMatch|unknown field.*ifMatch|ifMatch.*not defined|field .*updateBean.* argument .*ifMatch/i.test(
|
|
23022
|
+
message
|
|
23023
|
+
);
|
|
23024
|
+
if (!unsupportedIfMatch) {
|
|
23025
|
+
throw error48;
|
|
23026
|
+
}
|
|
23027
|
+
const fallback = await this.executeGraphQL(UPDATE_BEAN_MUTATION, {
|
|
23028
|
+
id: beanId,
|
|
23029
|
+
input: updateInput
|
|
23030
|
+
});
|
|
23031
|
+
data = fallback.data;
|
|
23032
|
+
errors = fallback.errors;
|
|
23033
|
+
}
|
|
23034
|
+
} else {
|
|
23035
|
+
const res = await this.executeGraphQL(UPDATE_BEAN_MUTATION, {
|
|
23036
|
+
id: beanId,
|
|
23037
|
+
input: updateInput
|
|
23038
|
+
});
|
|
23039
|
+
data = res.data;
|
|
23040
|
+
errors = res.errors;
|
|
23041
|
+
}
|
|
22926
23042
|
if (errors && errors.length > 0) {
|
|
22927
23043
|
throw new Error(`GraphQL error: ${errors.map((e) => e.message).join(", ")}`);
|
|
22928
23044
|
}
|
|
23045
|
+
this.invalidateCache();
|
|
22929
23046
|
return data.updateBean;
|
|
22930
23047
|
}
|
|
22931
23048
|
async delete(beanId) {
|
|
@@ -22935,13 +23052,57 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22935
23052
|
if (errors && errors.length > 0) {
|
|
22936
23053
|
throw new Error(`GraphQL error: ${errors.map((e) => e.message).join(", ")}`);
|
|
22937
23054
|
}
|
|
23055
|
+
this.invalidateCache();
|
|
22938
23056
|
return { deleted: true, beanId };
|
|
22939
23057
|
}
|
|
23058
|
+
async bulkCreate(beans, defaultParent) {
|
|
23059
|
+
const results = [];
|
|
23060
|
+
for (const item of beans) {
|
|
23061
|
+
try {
|
|
23062
|
+
const bean = await this.create({
|
|
23063
|
+
...item,
|
|
23064
|
+
parent: item.parent ?? defaultParent
|
|
23065
|
+
});
|
|
23066
|
+
results.push({ bean });
|
|
23067
|
+
} catch (error48) {
|
|
23068
|
+
results.push({ error: error48.message });
|
|
23069
|
+
}
|
|
23070
|
+
}
|
|
23071
|
+
return results;
|
|
23072
|
+
}
|
|
23073
|
+
async bulkUpdate(beans, defaultParent) {
|
|
23074
|
+
const results = [];
|
|
23075
|
+
for (const { beanId, ...updates } of beans) {
|
|
23076
|
+
try {
|
|
23077
|
+
const resolvedParent = updates.parent ?? (updates.clearParent ? void 0 : defaultParent);
|
|
23078
|
+
const bean = await this.update(beanId, { ...updates, parent: resolvedParent });
|
|
23079
|
+
results.push({ beanId, bean });
|
|
23080
|
+
} catch (error48) {
|
|
23081
|
+
results.push({ beanId, error: error48.message });
|
|
23082
|
+
}
|
|
23083
|
+
}
|
|
23084
|
+
return results;
|
|
23085
|
+
}
|
|
22940
23086
|
async openConfig() {
|
|
22941
23087
|
const configPath = join(this.workspaceRoot, ".beans.yml");
|
|
22942
23088
|
const content = await readFile(configPath, "utf8");
|
|
22943
23089
|
return { configPath, content };
|
|
22944
23090
|
}
|
|
23091
|
+
async primeInstructions() {
|
|
23092
|
+
const { stdout } = await execFileAsync(this.cliPath, ["prime"], {
|
|
23093
|
+
cwd: this.workspaceRoot,
|
|
23094
|
+
env: this.getSafeEnv(),
|
|
23095
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
23096
|
+
timeout: 3e4
|
|
23097
|
+
});
|
|
23098
|
+
return stdout.trim();
|
|
23099
|
+
}
|
|
23100
|
+
async writeInstructions(instructions) {
|
|
23101
|
+
const instructionsPath = join(this.workspaceRoot, ".github", "instructions", "beans-prime.instructions.md");
|
|
23102
|
+
await mkdir(dirname(instructionsPath), { recursive: true });
|
|
23103
|
+
await writeFile(instructionsPath, instructions, "utf8");
|
|
23104
|
+
return instructionsPath;
|
|
23105
|
+
}
|
|
22945
23106
|
async graphqlSchema() {
|
|
22946
23107
|
const { stdout } = await execFileAsync(this.cliPath, ["graphql", "--schema"], {
|
|
22947
23108
|
cwd: this.workspaceRoot,
|
|
@@ -22980,6 +23141,120 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22980
23141
|
linesReturned: ringBuffer.length
|
|
22981
23142
|
};
|
|
22982
23143
|
}
|
|
23144
|
+
/**
|
|
23145
|
+
* Split a YAML scalar value from any trailing inline comment.
|
|
23146
|
+
* Understands single-quoted and double-quoted YAML strings so it won't
|
|
23147
|
+
* mistake a `#` inside a quoted value for a comment delimiter.
|
|
23148
|
+
*/
|
|
23149
|
+
splitYamlInlineComment(value) {
|
|
23150
|
+
let inSingle = false;
|
|
23151
|
+
let inDouble = false;
|
|
23152
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
23153
|
+
const char = value[i];
|
|
23154
|
+
if (inSingle) {
|
|
23155
|
+
if (char === "'") {
|
|
23156
|
+
if (value[i + 1] === "'") {
|
|
23157
|
+
i += 1;
|
|
23158
|
+
} else {
|
|
23159
|
+
inSingle = false;
|
|
23160
|
+
}
|
|
23161
|
+
}
|
|
23162
|
+
continue;
|
|
23163
|
+
}
|
|
23164
|
+
if (inDouble) {
|
|
23165
|
+
if (char === "\\") {
|
|
23166
|
+
i += 1;
|
|
23167
|
+
continue;
|
|
23168
|
+
}
|
|
23169
|
+
if (char === '"') {
|
|
23170
|
+
inDouble = false;
|
|
23171
|
+
}
|
|
23172
|
+
continue;
|
|
23173
|
+
}
|
|
23174
|
+
if (char === "'") {
|
|
23175
|
+
inSingle = true;
|
|
23176
|
+
continue;
|
|
23177
|
+
}
|
|
23178
|
+
if (char === '"') {
|
|
23179
|
+
inDouble = true;
|
|
23180
|
+
continue;
|
|
23181
|
+
}
|
|
23182
|
+
if (char === "#" && i > 0 && /\s/.test(value[i - 1])) {
|
|
23183
|
+
const valuePart = value.slice(0, i).trimEnd();
|
|
23184
|
+
return {
|
|
23185
|
+
valuePart,
|
|
23186
|
+
commentPart: value.slice(valuePart.length)
|
|
23187
|
+
};
|
|
23188
|
+
}
|
|
23189
|
+
}
|
|
23190
|
+
return { valuePart: value, commentPart: "" };
|
|
23191
|
+
}
|
|
23192
|
+
/** Returns true when `value` looks like a YAML block scalar indicator (`>`, `|`, `>-`, `|-`, etc.) */
|
|
23193
|
+
isYamlBlockScalarIndicator(value) {
|
|
23194
|
+
return /^[>|][+-]?[0-9]*$/.test(value) || /^[>|][0-9]*[+-]?$/.test(value);
|
|
23195
|
+
}
|
|
23196
|
+
/** Escape a plain string for use inside a YAML double-quoted scalar. */
|
|
23197
|
+
escapeForYamlDoubleQuoted(value) {
|
|
23198
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
23199
|
+
}
|
|
23200
|
+
/**
|
|
23201
|
+
* Normalise a raw YAML title value to a double-quoted scalar.
|
|
23202
|
+
* Handles: empty, already double-quoted, single-quoted (unescaping `''`),
|
|
23203
|
+
* block-scalar indicators, and plain unquoted values.
|
|
23204
|
+
*/
|
|
23205
|
+
normalizeFrontmatterTitleValue(value) {
|
|
23206
|
+
const trimmed = value.trim();
|
|
23207
|
+
if (trimmed === "") {
|
|
23208
|
+
return '""';
|
|
23209
|
+
}
|
|
23210
|
+
if (this.isYamlBlockScalarIndicator(trimmed)) {
|
|
23211
|
+
return value;
|
|
23212
|
+
}
|
|
23213
|
+
if (/^"(?:[^"\\]|\\[\s\S])*"$/.test(trimmed)) {
|
|
23214
|
+
return trimmed;
|
|
23215
|
+
}
|
|
23216
|
+
if (/^'(?:[^']|'')*'$/.test(trimmed)) {
|
|
23217
|
+
const inner = trimmed.slice(1, -1).replace(/''/g, "'");
|
|
23218
|
+
return `"${this.escapeForYamlDoubleQuoted(inner)}"`;
|
|
23219
|
+
}
|
|
23220
|
+
return `"${this.escapeForYamlDoubleQuoted(trimmed)}"`;
|
|
23221
|
+
}
|
|
23222
|
+
/**
|
|
23223
|
+
* Ensure every `title:` line in YAML frontmatter is double-quoted.
|
|
23224
|
+
* Handles already-quoted (single or double), multi-word, and special-char values.
|
|
23225
|
+
* Preserves inline comments and handles both LF and CRLF line endings.
|
|
23226
|
+
*/
|
|
23227
|
+
quoteFrontmatterTitles(content) {
|
|
23228
|
+
const crlfOpen = content.startsWith("---\r\n");
|
|
23229
|
+
const lfOpen = content.startsWith("---\n");
|
|
23230
|
+
if (!crlfOpen && !lfOpen) {
|
|
23231
|
+
return content;
|
|
23232
|
+
}
|
|
23233
|
+
const eol = crlfOpen ? "\r\n" : "\n";
|
|
23234
|
+
const openEnd = `---${eol}`.length;
|
|
23235
|
+
const closeMarker = `${eol}---`;
|
|
23236
|
+
const closeIdx = content.indexOf(closeMarker, openEnd);
|
|
23237
|
+
if (closeIdx === -1) {
|
|
23238
|
+
return content;
|
|
23239
|
+
}
|
|
23240
|
+
const frontmatter = content.slice(openEnd, closeIdx);
|
|
23241
|
+
const rest = content.slice(closeIdx);
|
|
23242
|
+
const lines = frontmatter.split(eol);
|
|
23243
|
+
const fixedLines = lines.map((line) => {
|
|
23244
|
+
if (!line.startsWith("title:")) {
|
|
23245
|
+
return line;
|
|
23246
|
+
}
|
|
23247
|
+
const colonIdx = line.indexOf(":");
|
|
23248
|
+
const afterColon = line.slice(colonIdx + 1);
|
|
23249
|
+
const leadingSpace = afterColon.length - afterColon.trimStart().length;
|
|
23250
|
+
const raw = afterColon.trimStart();
|
|
23251
|
+
const { valuePart, commentPart } = this.splitYamlInlineComment(raw);
|
|
23252
|
+
const normalized = this.normalizeFrontmatterTitleValue(valuePart);
|
|
23253
|
+
const prefix = `title:${" ".repeat(Math.max(1, leadingSpace))}`;
|
|
23254
|
+
return `${prefix}${normalized}${commentPart}`;
|
|
23255
|
+
});
|
|
23256
|
+
return `---${eol}${fixedLines.join(eol)}${rest}`;
|
|
23257
|
+
}
|
|
22983
23258
|
async readBeanFile(relativePath) {
|
|
22984
23259
|
const absolutePath = this.resolveBeanFilePath(relativePath);
|
|
22985
23260
|
const content = await readFile(absolutePath, "utf8");
|
|
@@ -22987,20 +23262,22 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
22987
23262
|
}
|
|
22988
23263
|
async editBeanFile(relativePath, content) {
|
|
22989
23264
|
const absolutePath = this.resolveBeanFilePath(relativePath);
|
|
23265
|
+
const fixed = this.quoteFrontmatterTitles(content);
|
|
22990
23266
|
await mkdir(dirname(absolutePath), { recursive: true });
|
|
22991
|
-
await writeFile(absolutePath,
|
|
22992
|
-
return { path: absolutePath, bytes: Buffer.byteLength(
|
|
23267
|
+
await writeFile(absolutePath, fixed, "utf8");
|
|
23268
|
+
return { path: absolutePath, bytes: Buffer.byteLength(fixed, "utf8") };
|
|
22993
23269
|
}
|
|
22994
23270
|
async createBeanFile(relativePath, content, options) {
|
|
22995
23271
|
const absolutePath = this.resolveBeanFilePath(relativePath);
|
|
23272
|
+
const fixed = this.quoteFrontmatterTitles(content);
|
|
22996
23273
|
await mkdir(dirname(absolutePath), { recursive: true });
|
|
22997
|
-
await writeFile(absolutePath,
|
|
23274
|
+
await writeFile(absolutePath, fixed, {
|
|
22998
23275
|
encoding: "utf8",
|
|
22999
23276
|
flag: options?.overwrite ? "w" : "wx"
|
|
23000
23277
|
});
|
|
23001
23278
|
return {
|
|
23002
23279
|
path: absolutePath,
|
|
23003
|
-
bytes: Buffer.byteLength(
|
|
23280
|
+
bytes: Buffer.byteLength(fixed, "utf8"),
|
|
23004
23281
|
created: true
|
|
23005
23282
|
};
|
|
23006
23283
|
}
|
|
@@ -23013,7 +23290,7 @@ Output: ${stdout.slice(0, 1e3)}`
|
|
|
23013
23290
|
}
|
|
23014
23291
|
});
|
|
23015
23292
|
|
|
23016
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
23293
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
23017
23294
|
function deserializeMessage(line) {
|
|
23018
23295
|
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
|
23019
23296
|
}
|
|
@@ -23022,7 +23299,7 @@ function serializeMessage(message) {
|
|
|
23022
23299
|
}
|
|
23023
23300
|
var ReadBuffer;
|
|
23024
23301
|
var init_stdio = __esm({
|
|
23025
|
-
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
23302
|
+
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js"() {
|
|
23026
23303
|
"use strict";
|
|
23027
23304
|
init_types();
|
|
23028
23305
|
ReadBuffer = class {
|
|
@@ -23048,7 +23325,7 @@ var init_stdio = __esm({
|
|
|
23048
23325
|
}
|
|
23049
23326
|
});
|
|
23050
23327
|
|
|
23051
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
23328
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
23052
23329
|
var stdio_exports = {};
|
|
23053
23330
|
__export(stdio_exports, {
|
|
23054
23331
|
StdioServerTransport: () => StdioServerTransport
|
|
@@ -23056,7 +23333,7 @@ __export(stdio_exports, {
|
|
|
23056
23333
|
import process3 from "process";
|
|
23057
23334
|
var StdioServerTransport;
|
|
23058
23335
|
var init_stdio2 = __esm({
|
|
23059
|
-
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
23336
|
+
"node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js"() {
|
|
23060
23337
|
"use strict";
|
|
23061
23338
|
init_stdio();
|
|
23062
23339
|
StdioServerTransport = class {
|
|
@@ -27063,7 +27340,7 @@ init_core2();
|
|
|
27063
27340
|
// node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/mini/coerce.js
|
|
27064
27341
|
init_core2();
|
|
27065
27342
|
|
|
27066
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
27343
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
27067
27344
|
function isZ4Schema(s) {
|
|
27068
27345
|
const schema = s;
|
|
27069
27346
|
return !!schema._zod;
|
|
@@ -27207,10 +27484,10 @@ function getLiteralValue(schema) {
|
|
|
27207
27484
|
return void 0;
|
|
27208
27485
|
}
|
|
27209
27486
|
|
|
27210
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
27487
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
|
|
27211
27488
|
init_types();
|
|
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/experimental/tasks/interfaces.js
|
|
27214
27491
|
function isTerminal(status) {
|
|
27215
27492
|
return status === "completed" || status === "failed" || status === "cancelled";
|
|
27216
27493
|
}
|
|
@@ -28499,7 +28776,7 @@ var zodToJsonSchema = (schema, options) => {
|
|
|
28499
28776
|
return combined;
|
|
28500
28777
|
};
|
|
28501
28778
|
|
|
28502
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
28779
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
|
|
28503
28780
|
function mapMiniTarget(t) {
|
|
28504
28781
|
if (!t)
|
|
28505
28782
|
return "draft-7";
|
|
@@ -28541,7 +28818,7 @@ function parseWithCompat(schema, data) {
|
|
|
28541
28818
|
return result.data;
|
|
28542
28819
|
}
|
|
28543
28820
|
|
|
28544
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
28821
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
|
|
28545
28822
|
var DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
|
|
28546
28823
|
var Protocol = class {
|
|
28547
28824
|
constructor(_options) {
|
|
@@ -28753,6 +29030,10 @@ var Protocol = class {
|
|
|
28753
29030
|
this._progressHandlers.clear();
|
|
28754
29031
|
this._taskProgressTokens.clear();
|
|
28755
29032
|
this._pendingDebouncedNotifications.clear();
|
|
29033
|
+
for (const info of this._timeoutInfo.values()) {
|
|
29034
|
+
clearTimeout(info.timeoutId);
|
|
29035
|
+
}
|
|
29036
|
+
this._timeoutInfo.clear();
|
|
28756
29037
|
for (const controller of this._requestHandlerAbortControllers.values()) {
|
|
28757
29038
|
controller.abort();
|
|
28758
29039
|
}
|
|
@@ -28883,7 +29164,9 @@ var Protocol = class {
|
|
|
28883
29164
|
await capturedTransport?.send(errorResponse);
|
|
28884
29165
|
}
|
|
28885
29166
|
}).catch((error48) => this._onerror(new Error(`Failed to send response: ${error48}`))).finally(() => {
|
|
28886
|
-
this._requestHandlerAbortControllers.
|
|
29167
|
+
if (this._requestHandlerAbortControllers.get(request.id) === abortController) {
|
|
29168
|
+
this._requestHandlerAbortControllers.delete(request.id);
|
|
29169
|
+
}
|
|
28887
29170
|
});
|
|
28888
29171
|
}
|
|
28889
29172
|
_onprogress(notification) {
|
|
@@ -29489,10 +29772,10 @@ function mergeCapabilities(base, additional) {
|
|
|
29489
29772
|
return result;
|
|
29490
29773
|
}
|
|
29491
29774
|
|
|
29492
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
29775
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
|
|
29493
29776
|
init_types();
|
|
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/validation/ajv-provider.js
|
|
29496
29779
|
var import_ajv = __toESM(require_ajv(), 1);
|
|
29497
29780
|
var import_ajv_formats = __toESM(require_dist(), 1);
|
|
29498
29781
|
function createDefaultAjvInstance() {
|
|
@@ -29560,7 +29843,7 @@ var AjvJsonSchemaValidator = class {
|
|
|
29560
29843
|
}
|
|
29561
29844
|
};
|
|
29562
29845
|
|
|
29563
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
29846
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
|
|
29564
29847
|
init_types();
|
|
29565
29848
|
var ExperimentalServerTasks = class {
|
|
29566
29849
|
constructor(_server) {
|
|
@@ -29774,7 +30057,7 @@ var ExperimentalServerTasks = class {
|
|
|
29774
30057
|
}
|
|
29775
30058
|
};
|
|
29776
30059
|
|
|
29777
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30060
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
|
|
29778
30061
|
function assertToolsCallTaskCapability(requests, method, entityName) {
|
|
29779
30062
|
if (!requests) {
|
|
29780
30063
|
throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
@@ -29809,7 +30092,7 @@ function assertClientRequestTaskCapability(requests, method, entityName) {
|
|
|
29809
30092
|
}
|
|
29810
30093
|
}
|
|
29811
30094
|
|
|
29812
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30095
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
|
|
29813
30096
|
var Server = class extends Protocol {
|
|
29814
30097
|
/**
|
|
29815
30098
|
* Initializes this server with the given name and version information.
|
|
@@ -30189,10 +30472,10 @@ var Server = class extends Protocol {
|
|
|
30189
30472
|
}
|
|
30190
30473
|
};
|
|
30191
30474
|
|
|
30192
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30475
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
|
|
30193
30476
|
init_types();
|
|
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/completable.js
|
|
30196
30479
|
var COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
|
|
30197
30480
|
function isCompletable(schema) {
|
|
30198
30481
|
return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
|
|
@@ -30206,7 +30489,7 @@ var McpZodTypeKind;
|
|
|
30206
30489
|
McpZodTypeKind2["Completable"] = "McpCompletable";
|
|
30207
30490
|
})(McpZodTypeKind || (McpZodTypeKind = {}));
|
|
30208
30491
|
|
|
30209
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30492
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
|
|
30210
30493
|
var TOOL_NAME_REGEX = /^[A-Za-z0-9._-]{1,128}$/;
|
|
30211
30494
|
function validateToolName(name) {
|
|
30212
30495
|
const warnings = [];
|
|
@@ -30264,7 +30547,7 @@ function validateAndWarnToolName(name) {
|
|
|
30264
30547
|
return result.isValid;
|
|
30265
30548
|
}
|
|
30266
30549
|
|
|
30267
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30550
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
|
|
30268
30551
|
var ExperimentalMcpServerTasks = class {
|
|
30269
30552
|
constructor(_mcpServer) {
|
|
30270
30553
|
this._mcpServer = _mcpServer;
|
|
@@ -30283,7 +30566,7 @@ var ExperimentalMcpServerTasks = class {
|
|
|
30283
30566
|
init_external();
|
|
30284
30567
|
init_external();
|
|
30285
30568
|
|
|
30286
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30569
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
|
|
30287
30570
|
var McpServer = class {
|
|
30288
30571
|
constructor(serverInfo, options) {
|
|
30289
30572
|
this._registeredResources = {};
|
|
@@ -30907,6 +31190,9 @@ var McpServer = class {
|
|
|
30907
31190
|
annotations = rest.shift();
|
|
30908
31191
|
}
|
|
30909
31192
|
} else if (typeof firstArg === "object" && firstArg !== null) {
|
|
31193
|
+
if (Object.values(firstArg).some((v) => typeof v === "object" && v !== null)) {
|
|
31194
|
+
throw new Error(`Tool ${name} expected a Zod schema or ToolAnnotations, but received an unrecognized object`);
|
|
31195
|
+
}
|
|
30910
31196
|
annotations = rest.shift();
|
|
30911
31197
|
}
|
|
30912
31198
|
}
|
|
@@ -31025,6 +31311,9 @@ function getZodSchemaObject(schema) {
|
|
|
31025
31311
|
if (isZodRawShapeCompat(schema)) {
|
|
31026
31312
|
return objectFromShape(schema);
|
|
31027
31313
|
}
|
|
31314
|
+
if (!isZodSchemaInstance(schema)) {
|
|
31315
|
+
throw new Error("inputSchema must be a Zod schema or raw shape, received an unrecognized object");
|
|
31316
|
+
}
|
|
31028
31317
|
return schema;
|
|
31029
31318
|
}
|
|
31030
31319
|
function promptArgumentsFromSchema(schema) {
|
|
@@ -31069,6 +31358,94 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
31069
31358
|
}
|
|
31070
31359
|
};
|
|
31071
31360
|
|
|
31361
|
+
// src/server/BeansMcpServer.ts
|
|
31362
|
+
import { execFile as execFile2 } from "child_process";
|
|
31363
|
+
import { promisify as promisify2 } from "util";
|
|
31364
|
+
|
|
31365
|
+
// package.json
|
|
31366
|
+
var package_default = {
|
|
31367
|
+
name: "@selfagency/beans-mcp",
|
|
31368
|
+
version: "0.5.0",
|
|
31369
|
+
private: false,
|
|
31370
|
+
description: "MCP (Model Context Protocol) server for Beans issue tracker",
|
|
31371
|
+
author: {
|
|
31372
|
+
name: "Daniel Sieradski",
|
|
31373
|
+
email: "daniel@self.agency",
|
|
31374
|
+
url: "https://self.agency"
|
|
31375
|
+
},
|
|
31376
|
+
homepage: "https://github.com/selfagency/beans-mcp",
|
|
31377
|
+
bugs: {
|
|
31378
|
+
url: "https://github.com/selfagency/beans-mcp/issues"
|
|
31379
|
+
},
|
|
31380
|
+
repository: {
|
|
31381
|
+
type: "git",
|
|
31382
|
+
url: "git+https://github.com/selfagency/beans-mcp.git"
|
|
31383
|
+
},
|
|
31384
|
+
mcpName: "io.github.selfagency/beans-mcp",
|
|
31385
|
+
keywords: [
|
|
31386
|
+
"beans",
|
|
31387
|
+
"mcp",
|
|
31388
|
+
"model-context-protocol",
|
|
31389
|
+
"issue-tracker",
|
|
31390
|
+
"ai"
|
|
31391
|
+
],
|
|
31392
|
+
license: "MIT",
|
|
31393
|
+
type: "module",
|
|
31394
|
+
exports: {
|
|
31395
|
+
".": {
|
|
31396
|
+
types: "./dist/index.d.ts",
|
|
31397
|
+
import: "./dist/index.js",
|
|
31398
|
+
require: "./dist/index.cjs"
|
|
31399
|
+
}
|
|
31400
|
+
},
|
|
31401
|
+
main: "./dist/index.cjs",
|
|
31402
|
+
module: "./dist/index.js",
|
|
31403
|
+
types: "./dist/index.d.ts",
|
|
31404
|
+
bin: {
|
|
31405
|
+
"beans-mcp": "dist/beans-mcp-server.cjs"
|
|
31406
|
+
},
|
|
31407
|
+
scripts: {
|
|
31408
|
+
build: "tsup",
|
|
31409
|
+
format: "oxfmt",
|
|
31410
|
+
"lint:fix": "oxlint --fix",
|
|
31411
|
+
lint: "oxlint",
|
|
31412
|
+
postbuild: "node ./scripts/write-dist-package.js",
|
|
31413
|
+
prepare: "husky",
|
|
31414
|
+
release: "zx ./scripts/release.js",
|
|
31415
|
+
"test:coverage": "vitest run --coverage",
|
|
31416
|
+
"test:watch": "vitest",
|
|
31417
|
+
test: "vitest run",
|
|
31418
|
+
"type-check": "tsc --noEmit"
|
|
31419
|
+
},
|
|
31420
|
+
devDependencies: {
|
|
31421
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
31422
|
+
"@octokit/rest": "^22.0.1",
|
|
31423
|
+
"@types/node": "25.5.2",
|
|
31424
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
31425
|
+
"@vitest/ui": "4.1.2",
|
|
31426
|
+
husky: "^9.1.7",
|
|
31427
|
+
"lint-staged": "^16.4.0",
|
|
31428
|
+
ora: "^9.3.0",
|
|
31429
|
+
oxfmt: "^0.43.0",
|
|
31430
|
+
oxlint: "^1.58.0",
|
|
31431
|
+
"oxlint-tsgolint": "^0.20.0",
|
|
31432
|
+
tsup: "8.5.1",
|
|
31433
|
+
typescript: "6.0.2",
|
|
31434
|
+
vitest: "4.1.2",
|
|
31435
|
+
zod: "4.3.6",
|
|
31436
|
+
zx: "^8.8.5"
|
|
31437
|
+
},
|
|
31438
|
+
engines: {
|
|
31439
|
+
node: ">=18"
|
|
31440
|
+
},
|
|
31441
|
+
"lint-staged": {
|
|
31442
|
+
"src/**/*.ts": [
|
|
31443
|
+
"pnpm run lint:fix",
|
|
31444
|
+
"pnpm run format"
|
|
31445
|
+
]
|
|
31446
|
+
}
|
|
31447
|
+
};
|
|
31448
|
+
|
|
31072
31449
|
// src/internal/queryHelpers.ts
|
|
31073
31450
|
function sortBeansInternal(beans, mode) {
|
|
31074
31451
|
const sorted = [...beans];
|
|
@@ -31124,15 +31501,23 @@ async function handleQueryOperation(backend, params) {
|
|
|
31124
31501
|
const { operation, mode, statuses, types, search, tags, writeToWorkspaceInstructions, includeClosed } = params;
|
|
31125
31502
|
if (operation === "llm_context") {
|
|
31126
31503
|
const graphqlSchema = typeof backend.graphqlSchema === "function" ? await backend.graphqlSchema() : "";
|
|
31127
|
-
|
|
31504
|
+
let generatedInstructions = "";
|
|
31505
|
+
if (typeof backend.primeInstructions === "function") {
|
|
31506
|
+
try {
|
|
31507
|
+
generatedInstructions = await backend.primeInstructions();
|
|
31508
|
+
} catch {
|
|
31509
|
+
generatedInstructions = "";
|
|
31510
|
+
}
|
|
31511
|
+
}
|
|
31512
|
+
const instructionsPath = writeToWorkspaceInstructions && typeof backend.writeInstructions === "function" ? await backend.writeInstructions(generatedInstructions) : null;
|
|
31128
31513
|
return {
|
|
31129
31514
|
content: [
|
|
31130
31515
|
{
|
|
31131
31516
|
type: "text",
|
|
31132
|
-
text: JSON.stringify({ graphqlSchema, generatedInstructions
|
|
31517
|
+
text: JSON.stringify({ graphqlSchema, generatedInstructions, instructionsPath }, null, 2)
|
|
31133
31518
|
}
|
|
31134
31519
|
],
|
|
31135
|
-
structuredContent: { graphqlSchema, generatedInstructions
|
|
31520
|
+
structuredContent: { graphqlSchema, generatedInstructions, instructionsPath }
|
|
31136
31521
|
};
|
|
31137
31522
|
}
|
|
31138
31523
|
if (operation === "open_config") {
|
|
@@ -31178,6 +31563,31 @@ async function handleQueryOperation(backend, params) {
|
|
|
31178
31563
|
structuredContent: { query: search, count: beans2.length, beans: beans2 }
|
|
31179
31564
|
};
|
|
31180
31565
|
}
|
|
31566
|
+
if (operation === "ready") {
|
|
31567
|
+
const allBeans = await backend.list();
|
|
31568
|
+
const byId = new Map(allBeans.map((bean) => [bean.id, bean]));
|
|
31569
|
+
const candidates = await backend.list({ status: normalizedStatuses, type: normalizedTypes, search });
|
|
31570
|
+
const readyBeans = candidates.filter((bean) => {
|
|
31571
|
+
if (bean.status !== "todo") {
|
|
31572
|
+
return false;
|
|
31573
|
+
}
|
|
31574
|
+
const blockedBy = bean.blockedByIds || [];
|
|
31575
|
+
if (blockedBy.length === 0) {
|
|
31576
|
+
return true;
|
|
31577
|
+
}
|
|
31578
|
+
return blockedBy.every((blockerId) => {
|
|
31579
|
+
const blocker = byId.get(blockerId);
|
|
31580
|
+
if (!blocker) {
|
|
31581
|
+
return false;
|
|
31582
|
+
}
|
|
31583
|
+
return blocker.status === "completed" || blocker.status === "scrapped";
|
|
31584
|
+
});
|
|
31585
|
+
});
|
|
31586
|
+
return {
|
|
31587
|
+
content: [{ type: "text", text: JSON.stringify({ count: readyBeans.length, beans: readyBeans }, null, 2) }],
|
|
31588
|
+
structuredContent: { count: readyBeans.length, beans: readyBeans }
|
|
31589
|
+
};
|
|
31590
|
+
}
|
|
31181
31591
|
const beans = await backend.list({ status: normalizedStatuses, type: normalizedTypes, search });
|
|
31182
31592
|
const sorted = sortBeansInternal(beans, mode ?? "status-priority-type-title");
|
|
31183
31593
|
return {
|
|
@@ -31196,92 +31606,45 @@ var MAX_PATH_LENGTH = 1024;
|
|
|
31196
31606
|
|
|
31197
31607
|
// src/server/BeansMcpServer.ts
|
|
31198
31608
|
init_utils();
|
|
31199
|
-
|
|
31200
|
-
|
|
31201
|
-
|
|
31202
|
-
|
|
31203
|
-
|
|
31204
|
-
|
|
31205
|
-
|
|
31206
|
-
|
|
31207
|
-
name: "Daniel Sieradski",
|
|
31208
|
-
email: "daniel@self.agency",
|
|
31209
|
-
url: "https://self.agency"
|
|
31210
|
-
},
|
|
31211
|
-
homepage: "https://github.com/hmans/beans",
|
|
31212
|
-
bugs: {
|
|
31213
|
-
url: "https://github.com/selfagency/beans-mcp/issues"
|
|
31214
|
-
},
|
|
31215
|
-
repository: {
|
|
31216
|
-
type: "git",
|
|
31217
|
-
url: "git+https://github.com/selfagency/beans-mcp.git"
|
|
31218
|
-
},
|
|
31219
|
-
mcpName: "io.github.selfagency/beans-mcp",
|
|
31220
|
-
keywords: [
|
|
31221
|
-
"beans",
|
|
31222
|
-
"mcp",
|
|
31223
|
-
"model-context-protocol",
|
|
31224
|
-
"issue-tracker",
|
|
31225
|
-
"ai"
|
|
31226
|
-
],
|
|
31227
|
-
license: "MIT",
|
|
31228
|
-
type: "module",
|
|
31229
|
-
exports: {
|
|
31230
|
-
".": {
|
|
31231
|
-
types: "./dist/index.d.ts",
|
|
31232
|
-
import: "./dist/index.js",
|
|
31233
|
-
require: "./dist/index.cjs"
|
|
31609
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
31610
|
+
var PACKAGE_VERSION = package_default.version ?? "0.0.0-dev";
|
|
31611
|
+
function getSafeCliEnv(env) {
|
|
31612
|
+
const whitelist = ["PATH", "HOME", "USER", "LANG", "LC_ALL", "LC_CTYPE", "SHELL"];
|
|
31613
|
+
const safeEnv = {};
|
|
31614
|
+
for (const key of whitelist) {
|
|
31615
|
+
if (env[key]) {
|
|
31616
|
+
safeEnv[key] = env[key];
|
|
31234
31617
|
}
|
|
31235
|
-
},
|
|
31236
|
-
main: "./dist/index.cjs",
|
|
31237
|
-
module: "./dist/index.js",
|
|
31238
|
-
types: "./dist/index.d.ts",
|
|
31239
|
-
bin: {
|
|
31240
|
-
"beans-mcp": "dist/beans-mcp-server.cjs"
|
|
31241
|
-
},
|
|
31242
|
-
scripts: {
|
|
31243
|
-
build: "tsup",
|
|
31244
|
-
format: "oxfmt",
|
|
31245
|
-
"lint:fix": "oxlint --fix",
|
|
31246
|
-
lint: "oxlint",
|
|
31247
|
-
postbuild: "node ./scripts/write-dist-package.js",
|
|
31248
|
-
prepare: "husky",
|
|
31249
|
-
release: "zx ./scripts/release.js",
|
|
31250
|
-
"test:coverage": "vitest run --coverage",
|
|
31251
|
-
"test:watch": "vitest",
|
|
31252
|
-
test: "vitest run",
|
|
31253
|
-
"type-check": "tsc --noEmit"
|
|
31254
|
-
},
|
|
31255
|
-
devDependencies: {
|
|
31256
|
-
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
31257
|
-
"@octokit/rest": "^22.0.1",
|
|
31258
|
-
"@types/node": "^20.19.0",
|
|
31259
|
-
"@vitest/coverage-v8": "^4.0.18",
|
|
31260
|
-
"@vitest/ui": "4.0.18",
|
|
31261
|
-
husky: "^9.1.7",
|
|
31262
|
-
"lint-staged": "^16.2.7",
|
|
31263
|
-
ora: "^9.3.0",
|
|
31264
|
-
oxfmt: "^0.35.0",
|
|
31265
|
-
oxlint: "^1.50.0",
|
|
31266
|
-
"oxlint-tsgolint": "^0.15.0",
|
|
31267
|
-
tsup: "8.5.1",
|
|
31268
|
-
typescript: "^5.9.3",
|
|
31269
|
-
vitest: "4.0.18",
|
|
31270
|
-
zod: "4.3.6",
|
|
31271
|
-
zx: "^8.8.5"
|
|
31272
|
-
},
|
|
31273
|
-
engines: {
|
|
31274
|
-
node: ">=18"
|
|
31275
|
-
},
|
|
31276
|
-
"lint-staged": {
|
|
31277
|
-
"src/**/*.ts": [
|
|
31278
|
-
"pnpm run lint:fix",
|
|
31279
|
-
"pnpm run format"
|
|
31280
|
-
]
|
|
31281
31618
|
}
|
|
31282
|
-
|
|
31283
|
-
|
|
31284
|
-
|
|
31619
|
+
for (const key in env) {
|
|
31620
|
+
if (key.startsWith("BEANS_")) {
|
|
31621
|
+
safeEnv[key] = env[key];
|
|
31622
|
+
}
|
|
31623
|
+
}
|
|
31624
|
+
return safeEnv;
|
|
31625
|
+
}
|
|
31626
|
+
function extractVersionFromOutput(output) {
|
|
31627
|
+
const trimmed = output.trim();
|
|
31628
|
+
if (!trimmed) {
|
|
31629
|
+
return null;
|
|
31630
|
+
}
|
|
31631
|
+
const match = trimmed.match(/(?:^|[^\d])v?(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/);
|
|
31632
|
+
return match?.[1] ?? null;
|
|
31633
|
+
}
|
|
31634
|
+
async function detectBeansCliVersion(cliPath, workspaceRoot) {
|
|
31635
|
+
try {
|
|
31636
|
+
const { stdout, stderr } = await execFileAsync2(cliPath, ["version"], {
|
|
31637
|
+
cwd: workspaceRoot,
|
|
31638
|
+
env: getSafeCliEnv(process.env),
|
|
31639
|
+
maxBuffer: 1024 * 1024,
|
|
31640
|
+
timeout: 5e3
|
|
31641
|
+
});
|
|
31642
|
+
return extractVersionFromOutput(`${stdout}
|
|
31643
|
+
${stderr}`);
|
|
31644
|
+
} catch {
|
|
31645
|
+
return null;
|
|
31646
|
+
}
|
|
31647
|
+
}
|
|
31285
31648
|
async function getBeanById(backend, beanId) {
|
|
31286
31649
|
try {
|
|
31287
31650
|
const beans = await backend.list();
|
|
@@ -31301,7 +31664,40 @@ function initHandler(backend) {
|
|
|
31301
31664
|
};
|
|
31302
31665
|
}
|
|
31303
31666
|
function viewHandler(backend) {
|
|
31304
|
-
return async ({ beanId }) =>
|
|
31667
|
+
return async ({ beanId, beanIds }) => {
|
|
31668
|
+
const ids = Array.isArray(beanIds) && beanIds.length > 0 ? beanIds : beanId ? [beanId] : [];
|
|
31669
|
+
if (ids.length === 0) {
|
|
31670
|
+
throw new Error("Either beanId or beanIds must be provided");
|
|
31671
|
+
}
|
|
31672
|
+
if (ids.length === 1) {
|
|
31673
|
+
const bean = await getBeanById(backend, ids[0]);
|
|
31674
|
+
return makeTextAndStructured({ bean });
|
|
31675
|
+
}
|
|
31676
|
+
const beans = await backend.list();
|
|
31677
|
+
const byId = new Map(beans.map((b) => [b.id, b]));
|
|
31678
|
+
const found = ids.map((id) => byId.get(id)).filter(Boolean);
|
|
31679
|
+
const missingBeanIds = ids.filter((id) => !byId.has(id));
|
|
31680
|
+
return makeTextAndStructured({
|
|
31681
|
+
beans: found,
|
|
31682
|
+
missingBeanIds,
|
|
31683
|
+
count: found.length,
|
|
31684
|
+
requestedCount: ids.length
|
|
31685
|
+
});
|
|
31686
|
+
};
|
|
31687
|
+
}
|
|
31688
|
+
async function checkVersionCompatibility(cliPath, workspaceRoot, detector) {
|
|
31689
|
+
const detectedBeansVersion = await detector(cliPath, workspaceRoot);
|
|
31690
|
+
if (!detectedBeansVersion) {
|
|
31691
|
+
console.error(
|
|
31692
|
+
`[beans-mcp] warning: unable to determine Beans CLI version from \`${cliPath}\`; proceeding without version compatibility checks.`
|
|
31693
|
+
);
|
|
31694
|
+
return;
|
|
31695
|
+
}
|
|
31696
|
+
if (detectedBeansVersion !== PACKAGE_VERSION) {
|
|
31697
|
+
console.error(
|
|
31698
|
+
`[beans-mcp] warning: version mismatch detected (beans=${detectedBeansVersion}, beans-mcp=${PACKAGE_VERSION}); continuing startup.`
|
|
31699
|
+
);
|
|
31700
|
+
}
|
|
31305
31701
|
}
|
|
31306
31702
|
function createHandler(backend) {
|
|
31307
31703
|
return async (input) => makeTextAndStructured({ bean: await backend.create(input) });
|
|
@@ -31337,17 +31733,82 @@ function updateHandler(backend) {
|
|
|
31337
31733
|
clearParent: input.clearParent,
|
|
31338
31734
|
blocking: input.blocking,
|
|
31339
31735
|
blockedBy: input.blockedBy,
|
|
31340
|
-
body: input.body
|
|
31736
|
+
body: input.body,
|
|
31737
|
+
bodyAppend: input.bodyAppend,
|
|
31738
|
+
bodyReplace: input.bodyReplace,
|
|
31739
|
+
ifMatch: input.ifMatch
|
|
31341
31740
|
})
|
|
31342
31741
|
});
|
|
31343
31742
|
}
|
|
31344
31743
|
function deleteHandler(backend) {
|
|
31345
|
-
return async ({ beanId, force }) => {
|
|
31346
|
-
const
|
|
31347
|
-
if (
|
|
31348
|
-
throw new Error("
|
|
31744
|
+
return async ({ beanId, beanIds, force }) => {
|
|
31745
|
+
const ids = Array.isArray(beanIds) && beanIds.length > 0 ? beanIds : beanId ? [beanId] : [];
|
|
31746
|
+
if (ids.length === 0) {
|
|
31747
|
+
throw new Error("Either beanId or beanIds must be provided");
|
|
31349
31748
|
}
|
|
31350
|
-
|
|
31749
|
+
if (ids.length === 1) {
|
|
31750
|
+
const bean = await getBeanById(backend, ids[0]);
|
|
31751
|
+
if (!force && bean.status !== "draft" && bean.status !== "scrapped") {
|
|
31752
|
+
throw new Error("Only draft and scrapped beans are deletable unless force=true");
|
|
31753
|
+
}
|
|
31754
|
+
return makeTextAndStructured(await backend.delete(ids[0]));
|
|
31755
|
+
}
|
|
31756
|
+
const beans = await backend.list();
|
|
31757
|
+
const byId = new Map(beans.map((b) => [b.id, b]));
|
|
31758
|
+
const results = [];
|
|
31759
|
+
for (const id of ids) {
|
|
31760
|
+
const bean = byId.get(id);
|
|
31761
|
+
if (!bean) {
|
|
31762
|
+
results.push({ beanId: id, deleted: false, error: "Bean not found" });
|
|
31763
|
+
continue;
|
|
31764
|
+
}
|
|
31765
|
+
if (!force && bean.status !== "draft" && bean.status !== "scrapped") {
|
|
31766
|
+
results.push({
|
|
31767
|
+
beanId: id,
|
|
31768
|
+
deleted: false,
|
|
31769
|
+
error: "Only draft and scrapped beans are deletable unless force=true"
|
|
31770
|
+
});
|
|
31771
|
+
continue;
|
|
31772
|
+
}
|
|
31773
|
+
try {
|
|
31774
|
+
await backend.delete(id);
|
|
31775
|
+
results.push({ beanId: id, deleted: true });
|
|
31776
|
+
} catch (error48) {
|
|
31777
|
+
results.push({
|
|
31778
|
+
beanId: id,
|
|
31779
|
+
deleted: false,
|
|
31780
|
+
error: error48.message
|
|
31781
|
+
});
|
|
31782
|
+
}
|
|
31783
|
+
}
|
|
31784
|
+
return makeTextAndStructured({
|
|
31785
|
+
results,
|
|
31786
|
+
requestedCount: ids.length,
|
|
31787
|
+
deletedCount: results.filter((r) => r.deleted).length,
|
|
31788
|
+
failedCount: results.filter((r) => !r.deleted).length
|
|
31789
|
+
});
|
|
31790
|
+
};
|
|
31791
|
+
}
|
|
31792
|
+
function bulkCreateHandler(backend) {
|
|
31793
|
+
return async (input) => {
|
|
31794
|
+
const results = await backend.bulkCreate(input.beans, input.parent);
|
|
31795
|
+
return makeTextAndStructured({
|
|
31796
|
+
results,
|
|
31797
|
+
requestedCount: input.beans.length,
|
|
31798
|
+
successCount: results.filter((r) => r.bean).length,
|
|
31799
|
+
failedCount: results.filter((r) => r.error).length
|
|
31800
|
+
});
|
|
31801
|
+
};
|
|
31802
|
+
}
|
|
31803
|
+
function bulkUpdateHandler(backend) {
|
|
31804
|
+
return async (input) => {
|
|
31805
|
+
const results = await backend.bulkUpdate(input.beans, input.parent);
|
|
31806
|
+
return makeTextAndStructured({
|
|
31807
|
+
results,
|
|
31808
|
+
requestedCount: input.beans.length,
|
|
31809
|
+
successCount: results.filter((r) => r.bean).length,
|
|
31810
|
+
failedCount: results.filter((r) => r.error).length
|
|
31811
|
+
});
|
|
31351
31812
|
};
|
|
31352
31813
|
}
|
|
31353
31814
|
function queryHandler(backend) {
|
|
@@ -31408,7 +31869,12 @@ function registerTools(server, backend) {
|
|
|
31408
31869
|
{
|
|
31409
31870
|
title: "View Bean",
|
|
31410
31871
|
description: "Fetch full bean details by ID.",
|
|
31411
|
-
inputSchema: external_exports3.object({
|
|
31872
|
+
inputSchema: external_exports3.object({
|
|
31873
|
+
beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH).optional(),
|
|
31874
|
+
beanIds: external_exports3.array(external_exports3.string().min(1).max(MAX_ID_LENGTH)).optional()
|
|
31875
|
+
}).refine((input) => Boolean(input.beanId) || Array.isArray(input.beanIds) && input.beanIds.length > 0, {
|
|
31876
|
+
message: "Either beanId or beanIds must be provided"
|
|
31877
|
+
}),
|
|
31412
31878
|
annotations: {
|
|
31413
31879
|
readOnlyHint: true,
|
|
31414
31880
|
destructiveHint: false,
|
|
@@ -31428,7 +31894,8 @@ function registerTools(server, backend) {
|
|
|
31428
31894
|
type: external_exports3.string().min(1).max(MAX_METADATA_LENGTH),
|
|
31429
31895
|
status: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
31430
31896
|
priority: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
31431
|
-
|
|
31897
|
+
body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional().describe("Body markdown content"),
|
|
31898
|
+
description: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional().describe("Deprecated alias for body"),
|
|
31432
31899
|
parent: external_exports3.string().max(MAX_ID_LENGTH).optional()
|
|
31433
31900
|
}),
|
|
31434
31901
|
annotations: {
|
|
@@ -31497,8 +31964,21 @@ function registerTools(server, backend) {
|
|
|
31497
31964
|
clearParent: external_exports3.boolean().optional(),
|
|
31498
31965
|
blocking: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
|
|
31499
31966
|
blockedBy: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
|
|
31500
|
-
body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional()
|
|
31501
|
-
|
|
31967
|
+
body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional(),
|
|
31968
|
+
bodyAppend: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional(),
|
|
31969
|
+
bodyReplace: external_exports3.array(
|
|
31970
|
+
external_exports3.object({
|
|
31971
|
+
old: external_exports3.string().max(MAX_DESCRIPTION_LENGTH),
|
|
31972
|
+
new: external_exports3.string().max(MAX_DESCRIPTION_LENGTH)
|
|
31973
|
+
})
|
|
31974
|
+
).optional(),
|
|
31975
|
+
ifMatch: external_exports3.string().max(MAX_METADATA_LENGTH).optional()
|
|
31976
|
+
}).refine(
|
|
31977
|
+
(input) => !(input.body !== void 0 && (input.bodyAppend !== void 0 || input.bodyReplace !== void 0)),
|
|
31978
|
+
{
|
|
31979
|
+
message: "body cannot be combined with bodyAppend/bodyReplace"
|
|
31980
|
+
}
|
|
31981
|
+
),
|
|
31502
31982
|
annotations: {
|
|
31503
31983
|
readOnlyHint: false,
|
|
31504
31984
|
destructiveHint: false,
|
|
@@ -31514,8 +31994,11 @@ function registerTools(server, backend) {
|
|
|
31514
31994
|
title: "Delete Bean",
|
|
31515
31995
|
description: "Delete a bean (intended for draft/scrapped beans).",
|
|
31516
31996
|
inputSchema: external_exports3.object({
|
|
31517
|
-
beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH),
|
|
31997
|
+
beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH).optional(),
|
|
31998
|
+
beanIds: external_exports3.array(external_exports3.string().min(1).max(MAX_ID_LENGTH)).optional(),
|
|
31518
31999
|
force: external_exports3.boolean().default(false)
|
|
32000
|
+
}).refine((input) => Boolean(input.beanId) || Array.isArray(input.beanIds) && input.beanIds.length > 0, {
|
|
32001
|
+
message: "Either beanId or beanIds must be provided"
|
|
31519
32002
|
}),
|
|
31520
32003
|
annotations: {
|
|
31521
32004
|
readOnlyHint: false,
|
|
@@ -31526,13 +32009,75 @@ function registerTools(server, backend) {
|
|
|
31526
32009
|
},
|
|
31527
32010
|
deleteHandler(backend)
|
|
31528
32011
|
);
|
|
32012
|
+
const beanCreateItemSchema = external_exports3.object({
|
|
32013
|
+
title: external_exports3.string().min(1).max(MAX_TITLE_LENGTH),
|
|
32014
|
+
type: external_exports3.string().min(1).max(MAX_METADATA_LENGTH),
|
|
32015
|
+
status: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
32016
|
+
priority: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
32017
|
+
body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional().describe("Body markdown content"),
|
|
32018
|
+
description: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional().describe("Deprecated alias for body"),
|
|
32019
|
+
parent: external_exports3.string().max(MAX_ID_LENGTH).optional().describe("Override the top-level parent for this item")
|
|
32020
|
+
});
|
|
32021
|
+
server.registerTool(
|
|
32022
|
+
"beans_bulk_create",
|
|
32023
|
+
{
|
|
32024
|
+
title: "Bulk Create Beans",
|
|
32025
|
+
description: "Create multiple beans in one call. Optionally assign all of them (or a subset) to a shared parent.",
|
|
32026
|
+
inputSchema: external_exports3.object({
|
|
32027
|
+
beans: external_exports3.array(beanCreateItemSchema).min(1),
|
|
32028
|
+
parent: external_exports3.string().max(MAX_ID_LENGTH).optional().describe("Default parent ID applied to any bean that does not specify its own parent")
|
|
32029
|
+
}),
|
|
32030
|
+
annotations: {
|
|
32031
|
+
readOnlyHint: false,
|
|
32032
|
+
destructiveHint: false,
|
|
32033
|
+
idempotentHint: false,
|
|
32034
|
+
openWorldHint: false
|
|
32035
|
+
}
|
|
32036
|
+
},
|
|
32037
|
+
bulkCreateHandler(backend)
|
|
32038
|
+
);
|
|
32039
|
+
const beanUpdateItemSchema = external_exports3.object({
|
|
32040
|
+
beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH),
|
|
32041
|
+
status: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
32042
|
+
type: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
32043
|
+
priority: external_exports3.string().max(MAX_METADATA_LENGTH).optional(),
|
|
32044
|
+
parent: external_exports3.string().max(MAX_ID_LENGTH).optional().describe("Override the top-level parent for this item"),
|
|
32045
|
+
clearParent: external_exports3.boolean().optional(),
|
|
32046
|
+
blocking: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
|
|
32047
|
+
blockedBy: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
|
|
32048
|
+
body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional(),
|
|
32049
|
+
bodyAppend: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional(),
|
|
32050
|
+
bodyReplace: external_exports3.array(external_exports3.object({ old: external_exports3.string().max(MAX_DESCRIPTION_LENGTH), new: external_exports3.string().max(MAX_DESCRIPTION_LENGTH) })).optional(),
|
|
32051
|
+
ifMatch: external_exports3.string().max(MAX_METADATA_LENGTH).optional()
|
|
32052
|
+
}).refine(
|
|
32053
|
+
(input) => !(input.body !== void 0 && (input.bodyAppend !== void 0 || input.bodyReplace !== void 0)),
|
|
32054
|
+
{ message: "body cannot be combined with bodyAppend/bodyReplace" }
|
|
32055
|
+
);
|
|
32056
|
+
server.registerTool(
|
|
32057
|
+
"beans_bulk_update",
|
|
32058
|
+
{
|
|
32059
|
+
title: "Bulk Update Beans",
|
|
32060
|
+
description: "Update multiple beans in one call. Optionally assign all of them (or a subset) to a shared parent.",
|
|
32061
|
+
inputSchema: external_exports3.object({
|
|
32062
|
+
beans: external_exports3.array(beanUpdateItemSchema).min(1),
|
|
32063
|
+
parent: external_exports3.string().max(MAX_ID_LENGTH).optional().describe("Default parent ID applied to any bean that does not specify its own parent")
|
|
32064
|
+
}),
|
|
32065
|
+
annotations: {
|
|
32066
|
+
readOnlyHint: false,
|
|
32067
|
+
destructiveHint: false,
|
|
32068
|
+
idempotentHint: false,
|
|
32069
|
+
openWorldHint: false
|
|
32070
|
+
}
|
|
32071
|
+
},
|
|
32072
|
+
bulkUpdateHandler(backend)
|
|
32073
|
+
);
|
|
31529
32074
|
server.registerTool(
|
|
31530
32075
|
"beans_query",
|
|
31531
32076
|
{
|
|
31532
32077
|
title: "Query Beans",
|
|
31533
32078
|
description: "Unified query tool for refresh, filter, search, and sort operations.",
|
|
31534
32079
|
inputSchema: external_exports3.object({
|
|
31535
|
-
operation: external_exports3.enum(["refresh", "filter", "search", "sort", "llm_context", "open_config"]).default("refresh"),
|
|
32080
|
+
operation: external_exports3.enum(["refresh", "filter", "search", "sort", "ready", "llm_context", "open_config"]).default("refresh"),
|
|
31536
32081
|
mode: external_exports3.enum(["status-priority-type-title", "updated", "created", "id"]).optional(),
|
|
31537
32082
|
statuses: external_exports3.array(external_exports3.string().max(MAX_METADATA_LENGTH)).nullable().optional(),
|
|
31538
32083
|
types: external_exports3.array(external_exports3.string().max(MAX_METADATA_LENGTH)).nullable().optional(),
|
|
@@ -31611,9 +32156,21 @@ var MutableBackend = class {
|
|
|
31611
32156
|
delete(id) {
|
|
31612
32157
|
return this.inner.delete(id);
|
|
31613
32158
|
}
|
|
32159
|
+
bulkCreate(beans, defaultParent) {
|
|
32160
|
+
return this.inner.bulkCreate(beans, defaultParent);
|
|
32161
|
+
}
|
|
32162
|
+
bulkUpdate(beans, defaultParent) {
|
|
32163
|
+
return this.inner.bulkUpdate(beans, defaultParent);
|
|
32164
|
+
}
|
|
31614
32165
|
openConfig() {
|
|
31615
32166
|
return this.inner.openConfig();
|
|
31616
32167
|
}
|
|
32168
|
+
primeInstructions() {
|
|
32169
|
+
return this.inner.primeInstructions?.() ?? Promise.resolve("");
|
|
32170
|
+
}
|
|
32171
|
+
writeInstructions(instructions) {
|
|
32172
|
+
return this.inner.writeInstructions?.(instructions) ?? Promise.resolve(null);
|
|
32173
|
+
}
|
|
31617
32174
|
graphqlSchema() {
|
|
31618
32175
|
return this.inner.graphqlSchema();
|
|
31619
32176
|
}
|
|
@@ -31651,7 +32208,7 @@ async function createBeansMcpServer(opts) {
|
|
|
31651
32208
|
const backend = opts.backend || new BeansCliBackend2(opts.workspaceRoot, opts.cliPath || "beans", opts.logDir);
|
|
31652
32209
|
const server = new McpServer({
|
|
31653
32210
|
name: opts.name || "beans-mcp-server",
|
|
31654
|
-
version: opts.version ||
|
|
32211
|
+
version: opts.version || PACKAGE_VERSION
|
|
31655
32212
|
});
|
|
31656
32213
|
registerTools(server, backend);
|
|
31657
32214
|
return { server, backend };
|
|
@@ -31723,17 +32280,17 @@ function parseCliArgs(argv) {
|
|
|
31723
32280
|
}
|
|
31724
32281
|
return { workspaceRoot, workspaceExplicit, cliPath, port, logDir };
|
|
31725
32282
|
}
|
|
31726
|
-
async function startBeansMcpServer(argv, _resolveRoots) {
|
|
32283
|
+
async function startBeansMcpServer(argv, _resolveRoots, _detectBeansVersion) {
|
|
31727
32284
|
const { BeansCliBackend: BeansCliBackend2 } = await Promise.resolve().then(() => (init_backend(), backend_exports));
|
|
31728
32285
|
const { StdioServerTransport: StdioServerTransport2 } = await Promise.resolve().then(() => (init_stdio2(), stdio_exports));
|
|
31729
32286
|
const { workspaceRoot, workspaceExplicit, cliPath, port, logDir } = parseCliArgs(argv);
|
|
32287
|
+
let effectiveWorkspaceRoot = workspaceRoot;
|
|
31730
32288
|
process.env.BEANS_VSCODE_MCP_PORT = String(port);
|
|
31731
32289
|
process.env.BEANS_MCP_PORT = String(port);
|
|
31732
32290
|
try {
|
|
31733
|
-
const version2 = package_default.version ?? "0.0.0-dev";
|
|
31734
32291
|
const workspaceLabel = workspaceExplicit ? workspaceRoot : "(auto from roots)";
|
|
31735
32292
|
console.error(
|
|
31736
|
-
`[beans-mcp] v${
|
|
32293
|
+
`[beans-mcp] v${PACKAGE_VERSION} starting (port=${port}, workspace=${workspaceLabel}, cli=${cliPath}, logDir=${logDir})`
|
|
31737
32294
|
);
|
|
31738
32295
|
} catch {
|
|
31739
32296
|
}
|
|
@@ -31750,13 +32307,17 @@ async function startBeansMcpServer(argv, _resolveRoots) {
|
|
|
31750
32307
|
const resolver = _resolveRoots ?? resolveWorkspaceFromRoots;
|
|
31751
32308
|
const rootPath = await resolver(server);
|
|
31752
32309
|
if (rootPath) {
|
|
31753
|
-
mutable.setInner(new BeansCliBackend2(rootPath, cliPath));
|
|
32310
|
+
mutable.setInner(new BeansCliBackend2(rootPath, cliPath, logDir));
|
|
32311
|
+
effectiveWorkspaceRoot = rootPath;
|
|
31754
32312
|
try {
|
|
31755
32313
|
console.error(`[beans-mcp] workspace resolved from roots: ${rootPath}`);
|
|
31756
32314
|
} catch {
|
|
31757
32315
|
}
|
|
31758
32316
|
}
|
|
31759
32317
|
}
|
|
32318
|
+
const beansVersionDetector = _detectBeansVersion ?? detectBeansCliVersion;
|
|
32319
|
+
void checkVersionCompatibility(cliPath, effectiveWorkspaceRoot, beansVersionDetector).catch(() => {
|
|
32320
|
+
});
|
|
31760
32321
|
}
|
|
31761
32322
|
|
|
31762
32323
|
// src/index.ts
|