@selfagency/beans-mcp 0.4.2 → 0.6.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/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
3
  /**
4
4
  * Public types for beans-mcp-server
5
5
  */
6
- type SortMode = "status-priority-type-title" | "updated" | "created" | "id";
6
+ type SortMode = 'status-priority-type-title' | 'updated' | 'created' | 'id';
7
7
  type BeanRecord = {
8
8
  id: string;
9
9
  slug: string;
@@ -38,6 +38,7 @@ declare const DEFAULT_MCP_PORT = 39173;
38
38
  declare const MAX_ID_LENGTH = 128;
39
39
  declare const MAX_TITLE_LENGTH = 1024;
40
40
  declare const MAX_METADATA_LENGTH = 128;
41
+ declare const MAX_PATH_LENGTH = 1024;
41
42
 
42
43
  declare function sortBeansInternal(beans: BeanRecord[], mode: SortMode): BeanRecord[];
43
44
 
@@ -47,6 +48,11 @@ declare function sortBeansInternal(beans: BeanRecord[], mode: SortMode): BeanRec
47
48
  */
48
49
  interface BackendInterface {
49
50
  init(prefix?: string): Promise<Record<string, unknown>>;
51
+ archive?(): Promise<Record<string, unknown>>;
52
+ queryGraphql?(query: string, variables?: Record<string, unknown>): Promise<{
53
+ data: unknown;
54
+ errors?: GraphQLError[];
55
+ }>;
50
56
  list(options?: {
51
57
  status?: string[];
52
58
  type?: string[];
@@ -57,6 +63,8 @@ interface BackendInterface {
57
63
  type: string;
58
64
  status?: string;
59
65
  priority?: string;
66
+ /** Body markdown content. `description` is a deprecated alias. */
67
+ body?: string;
60
68
  description?: string;
61
69
  parent?: string;
62
70
  }): Promise<BeanRecord>;
@@ -77,6 +85,39 @@ interface BackendInterface {
77
85
  ifMatch?: string;
78
86
  }): Promise<BeanRecord>;
79
87
  delete(beanId: string): Promise<Record<string, unknown>>;
88
+ bulkCreate(beans: Array<{
89
+ title: string;
90
+ type: string;
91
+ status?: string;
92
+ priority?: string;
93
+ body?: string;
94
+ description?: string;
95
+ parent?: string;
96
+ }>, defaultParent?: string): Promise<Array<{
97
+ bean?: BeanRecord;
98
+ error?: string;
99
+ }>>;
100
+ bulkUpdate(beans: Array<{
101
+ beanId: string;
102
+ status?: string;
103
+ type?: string;
104
+ priority?: string;
105
+ parent?: string;
106
+ clearParent?: boolean;
107
+ blocking?: string[];
108
+ blockedBy?: string[];
109
+ body?: string;
110
+ bodyAppend?: string;
111
+ bodyReplace?: Array<{
112
+ old: string;
113
+ new: string;
114
+ }>;
115
+ ifMatch?: string;
116
+ }>, defaultParent?: string): Promise<Array<{
117
+ beanId: string;
118
+ bean?: BeanRecord;
119
+ error?: string;
120
+ }>>;
80
121
  openConfig(): Promise<{
81
122
  configPath: string;
82
123
  content: string;
@@ -99,6 +140,23 @@ interface BackendInterface {
99
140
  path: string;
100
141
  bytes: number;
101
142
  }>;
143
+ updateBeanFrontmatter(relativePath: string, updates: {
144
+ title?: string;
145
+ status?: string;
146
+ type?: string;
147
+ priority?: string;
148
+ parent_id?: string | null;
149
+ tags?: string[] | null;
150
+ blocking_ids?: string[] | null;
151
+ blocked_by_ids?: string[] | null;
152
+ pr?: string | null;
153
+ branch?: string | null;
154
+ }): Promise<{
155
+ path: string;
156
+ bytes: number;
157
+ updatedFields: string[];
158
+ frontmatter: Record<string, string | string[]>;
159
+ }>;
102
160
  createBeanFile(relativePath: string, content: string, options?: {
103
161
  overwrite?: boolean;
104
162
  }): Promise<{
@@ -120,6 +178,14 @@ declare class BeansCliBackend implements BackendInterface {
120
178
  private readonly cliPath;
121
179
  private readonly logDir?;
122
180
  constructor(workspaceRoot: string, cliPath: string, logDir?: string | undefined);
181
+ /** Full unfiltered records keyed by bean ID, stored under the fixed cache key `'all'`. */
182
+ private readonly _cache;
183
+ /** Last time the unfiltered cache entry `'all'` was fetched (ms). */
184
+ private readonly _cacheTime;
185
+ /** Short-circuit TTL: skip even the timestamp check within this window (ms). */
186
+ private static readonly BURST_TTL_MS;
187
+ /** Invalidate the unfiltered list cache so the next call does a full fetch. */
188
+ private invalidateCache;
123
189
  /**
124
190
  * Returns a safe environment for executing the Beans CLI,
125
191
  * whitelisting only necessary variables.
@@ -132,6 +198,11 @@ declare class BeansCliBackend implements BackendInterface {
132
198
  */
133
199
  private executeGraphQL;
134
200
  init(prefix?: string): Promise<Record<string, unknown>>;
201
+ archive(): Promise<Record<string, unknown>>;
202
+ queryGraphql(query: string, variables?: Record<string, unknown>): Promise<{
203
+ data: unknown;
204
+ errors?: GraphQLError[];
205
+ }>;
135
206
  list(options?: {
136
207
  status?: string[];
137
208
  type?: string[];
@@ -142,6 +213,7 @@ declare class BeansCliBackend implements BackendInterface {
142
213
  type: string;
143
214
  status?: string;
144
215
  priority?: string;
216
+ body?: string;
145
217
  description?: string;
146
218
  parent?: string;
147
219
  }): Promise<BeanRecord>;
@@ -162,6 +234,39 @@ declare class BeansCliBackend implements BackendInterface {
162
234
  ifMatch?: string;
163
235
  }): Promise<BeanRecord>;
164
236
  delete(beanId: string): Promise<Record<string, unknown>>;
237
+ bulkCreate(beans: Array<{
238
+ title: string;
239
+ type: string;
240
+ status?: string;
241
+ priority?: string;
242
+ body?: string;
243
+ description?: string;
244
+ parent?: string;
245
+ }>, defaultParent?: string): Promise<Array<{
246
+ bean?: BeanRecord;
247
+ error?: string;
248
+ }>>;
249
+ bulkUpdate(beans: Array<{
250
+ beanId: string;
251
+ status?: string;
252
+ type?: string;
253
+ priority?: string;
254
+ parent?: string;
255
+ clearParent?: boolean;
256
+ blocking?: string[];
257
+ blockedBy?: string[];
258
+ body?: string;
259
+ bodyAppend?: string;
260
+ bodyReplace?: Array<{
261
+ old: string;
262
+ new: string;
263
+ }>;
264
+ ifMatch?: string;
265
+ }>, defaultParent?: string): Promise<Array<{
266
+ beanId: string;
267
+ bean?: BeanRecord;
268
+ error?: string;
269
+ }>>;
165
270
  openConfig(): Promise<{
166
271
  configPath: string;
167
272
  content: string;
@@ -176,6 +281,36 @@ declare class BeansCliBackend implements BackendInterface {
176
281
  content: string;
177
282
  linesReturned: number;
178
283
  }>;
284
+ /**
285
+ * Split a YAML scalar value from any trailing inline comment.
286
+ * Understands single-quoted and double-quoted YAML strings so it won't
287
+ * mistake a `#` inside a quoted value for a comment delimiter.
288
+ */
289
+ private splitYamlInlineComment;
290
+ /** Returns true when `value` looks like a YAML block scalar indicator (`>`, `|`, `>-`, `|-`, etc.) */
291
+ private isYamlBlockScalarIndicator;
292
+ /** Escape a plain string for use inside a YAML double-quoted scalar. */
293
+ private escapeForYamlDoubleQuoted;
294
+ private shouldQuoteFrontmatterValue;
295
+ private parseFrontmatterLine;
296
+ private buildFrontmatterIndex;
297
+ private serializeFrontmatterValue;
298
+ private deserializeFrontmatterValue;
299
+ private splitFrontmatterDocument;
300
+ private parseFrontmatterFields;
301
+ private writeFileAtomically;
302
+ /**
303
+ * Normalise a raw YAML title value to a double-quoted scalar.
304
+ * Handles: empty, already double-quoted, single-quoted (unescaping `''`),
305
+ * block-scalar indicators, and plain unquoted values.
306
+ */
307
+ private normalizeFrontmatterTitleValue;
308
+ /**
309
+ * Ensure every `title:` line in YAML frontmatter is double-quoted.
310
+ * Handles already-quoted (single or double), multi-word, and special-char values.
311
+ * Preserves inline comments and handles both LF and CRLF line endings.
312
+ */
313
+ private quoteFrontmatterTitles;
179
314
  readBeanFile(relativePath: string): Promise<{
180
315
  path: string;
181
316
  content: string;
@@ -184,6 +319,23 @@ declare class BeansCliBackend implements BackendInterface {
184
319
  path: string;
185
320
  bytes: number;
186
321
  }>;
322
+ updateBeanFrontmatter(relativePath: string, updates: {
323
+ title?: string;
324
+ status?: string;
325
+ type?: string;
326
+ priority?: string;
327
+ parent_id?: string | null;
328
+ tags?: string[] | null;
329
+ blocking_ids?: string[] | null;
330
+ blocked_by_ids?: string[] | null;
331
+ pr?: string | null;
332
+ branch?: string | null;
333
+ }): Promise<{
334
+ path: string;
335
+ bytes: number;
336
+ updatedFields: string[];
337
+ frontmatter: Record<string, string | string[]>;
338
+ }>;
187
339
  createBeanFile(relativePath: string, content: string, options?: {
188
340
  overwrite?: boolean;
189
341
  }): Promise<{
@@ -235,4 +387,4 @@ declare function makeTextAndStructured<T extends Record<string, unknown>>(value:
235
387
  }[];
236
388
  };
237
389
 
238
- export { type BackendInterface, type BeanRecord, BeansCliBackend, DEFAULT_MCP_PORT, type GraphQLError, MAX_ID_LENGTH, MAX_METADATA_LENGTH, MAX_TITLE_LENGTH, type SortMode, createBeansMcpServer, isPathWithinRoot, makeTextAndStructured, parseCliArgs, sortBeansInternal as sortBeans, startBeansMcpServer };
390
+ export { type BackendInterface, type BeanRecord, BeansCliBackend, DEFAULT_MCP_PORT, type GraphQLError, MAX_ID_LENGTH, MAX_METADATA_LENGTH, MAX_PATH_LENGTH, MAX_TITLE_LENGTH, type SortMode, createBeansMcpServer, isPathWithinRoot, makeTextAndStructured, parseCliArgs, sortBeansInternal as sortBeans, startBeansMcpServer };