@selfagency/beans-mcp 0.1.3 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +63 -6
  2. package/{dist/beans-mcp-server.cjs → beans-mcp-server.cjs} +269 -34
  3. package/{dist/index.cjs → index.cjs} +269 -34
  4. package/{dist/index.d.ts → index.d.ts} +19 -1
  5. package/{dist/index.js → index.js} +269 -34
  6. package/package.json +28 -64
  7. package/.beans.yml +0 -6
  8. package/.claude/settings.local.json +0 -18
  9. package/.editorconfig +0 -13
  10. package/.github/dependabot.yml +0 -11
  11. package/.github/workflows/release.yml +0 -235
  12. package/.github/workflows/test.yml +0 -84
  13. package/.husky/pre-commit +0 -1
  14. package/.nvmrc +0 -1
  15. package/.oxfmtrc.json +0 -11
  16. package/.oxlintrc.json +0 -37
  17. package/.vscode/settings.json +0 -3
  18. package/CHANGELOG.md +0 -160
  19. package/CONTRIBUTING.md +0 -139
  20. package/LICENSE.txt +0 -21
  21. package/codeql/codeql-custom-queries-actions/README.md +0 -14
  22. package/codeql/codeql-custom-queries-actions/codeql-pack.lock.yml +0 -32
  23. package/codeql/codeql-custom-queries-actions/codeql-pack.yml +0 -7
  24. package/codeql/codeql-custom-queries-actions/qlpack.yml +0 -6
  25. package/codeql/codeql-custom-queries-actions/queries/github-script-without-tojson.ql +0 -18
  26. package/codeql/codeql-custom-queries-actions/queries/strict-external-action-pinning.ql +0 -18
  27. package/codeql/codeql-custom-queries-javascript/README.md +0 -14
  28. package/codeql/codeql-custom-queries-javascript/codeql-pack.lock.yml +0 -30
  29. package/codeql/codeql-custom-queries-javascript/codeql-pack.yml +0 -7
  30. package/codeql/codeql-custom-queries-javascript/qlpack.yml +0 -6
  31. package/codeql/codeql-custom-queries-javascript/queries/child-process-shell-apis.ql +0 -26
  32. package/codeql/codeql-custom-queries-javascript/queries/innerhtml-assignment.ql +0 -24
  33. package/dist/README.md +0 -307
  34. package/dist/beans-mcp-server.cjs.map +0 -1
  35. package/dist/index.cjs.map +0 -1
  36. package/dist/index.js.map +0 -1
  37. package/dist/package.json +0 -43
  38. package/pnpm-workspace.yaml +0 -2
  39. package/scripts/release.js +0 -433
  40. package/scripts/write-dist-package.js +0 -53
  41. package/src/cli.ts +0 -14
  42. package/src/index.ts +0 -21
  43. package/src/internal/graphql.ts +0 -33
  44. package/src/internal/queryHelpers.ts +0 -157
  45. package/src/server/BeansMcpServer.ts +0 -623
  46. package/src/server/backend.ts +0 -364
  47. package/src/test/BeansMcpServer.test.ts +0 -514
  48. package/src/test/handlers.unit.test.ts +0 -201
  49. package/src/test/parseCliArgs.test.ts +0 -69
  50. package/src/test/protocol.e2e.test.ts +0 -884
  51. package/src/test/queryHelpers.test.ts +0 -524
  52. package/src/test/startBeansMcpServer.test.ts +0 -146
  53. package/src/test/tools-integration.test.ts +0 -912
  54. package/src/test/utils.test.ts +0 -81
  55. package/src/types.ts +0 -46
  56. package/src/utils.ts +0 -20
  57. package/tsconfig.json +0 -24
  58. package/tsup.config.ts +0 -42
  59. package/vitest.config.ts +0 -18
@@ -1,157 +0,0 @@
1
- import { BeanRecord, SortMode } from '../types';
2
-
3
- export type QueryBackend = {
4
- graphqlSchema?: () => Promise<string>;
5
- writeInstructions?: (instructions: string) => Promise<string | null>;
6
- openConfig?: () => Promise<Record<string, unknown>>;
7
- list(options?: { status?: string[]; type?: string[]; search?: string }): Promise<BeanRecord[]>;
8
- };
9
-
10
- function sortBeansInternal(beans: BeanRecord[], mode: SortMode): BeanRecord[] {
11
- const sorted = [...beans];
12
- const statusWeight: Record<string, number> = {
13
- 'in-progress': 0,
14
- todo: 1,
15
- draft: 2,
16
- completed: 3,
17
- scrapped: 4,
18
- };
19
- const priorityWeight: Record<string, number> = {
20
- critical: 0,
21
- high: 1,
22
- normal: 2,
23
- low: 3,
24
- deferred: 4,
25
- };
26
- const typeWeight: Record<string, number> = {
27
- milestone: 0,
28
- epic: 1,
29
- feature: 2,
30
- bug: 3,
31
- task: 4,
32
- };
33
-
34
- if (mode === 'updated') {
35
- return sorted.sort((a, b) => (b.updatedAt || '').localeCompare(a.updatedAt || ''));
36
- }
37
-
38
- if (mode === 'created') {
39
- return sorted.sort((a, b) => (b.createdAt || '').localeCompare(a.createdAt || ''));
40
- }
41
-
42
- if (mode === 'id') {
43
- return sorted.sort((a, b) => a.id.localeCompare(b.id));
44
- }
45
-
46
- return sorted.sort((a, b) => {
47
- const statusCmp = (statusWeight[a.status] ?? 99) - (statusWeight[b.status] ?? 99);
48
- if (statusCmp !== 0) {
49
- return statusCmp;
50
- }
51
-
52
- const aPriority = a.priority || 'normal';
53
- const bPriority = b.priority || 'normal';
54
- const priorityCmp = (priorityWeight[aPriority] ?? 99) - (priorityWeight[bPriority] ?? 99);
55
- if (priorityCmp !== 0) {
56
- return priorityCmp;
57
- }
58
-
59
- const typeCmp = (typeWeight[a.type] ?? 99) - (typeWeight[b.type] ?? 99);
60
- if (typeCmp !== 0) {
61
- return typeCmp;
62
- }
63
-
64
- return a.title.localeCompare(b.title);
65
- });
66
- }
67
-
68
- export async function handleQueryOperation(
69
- backend: QueryBackend,
70
- params: {
71
- operation: string;
72
- mode?: SortMode;
73
- statuses?: string[] | null;
74
- types?: string[] | null;
75
- search?: string;
76
- tags?: string[] | null;
77
- writeToWorkspaceInstructions?: boolean;
78
- includeClosed?: boolean;
79
- },
80
- ): Promise<{ content: Array<{ type: 'text'; text: string }>; structuredContent: Record<string, unknown> }> {
81
- const { operation, mode, statuses, types, search, tags, writeToWorkspaceInstructions, includeClosed } = params;
82
-
83
- if (operation === 'llm_context') {
84
- const graphqlSchema = typeof backend.graphqlSchema === 'function' ? await backend.graphqlSchema() : '';
85
- const instructionsPath =
86
- writeToWorkspaceInstructions && typeof backend.writeInstructions === 'function'
87
- ? await backend.writeInstructions('')
88
- : null;
89
- return {
90
- content: [
91
- {
92
- type: 'text',
93
- text: JSON.stringify({ graphqlSchema, generatedInstructions: '', instructionsPath }, null, 2),
94
- },
95
- ],
96
- structuredContent: { graphqlSchema, generatedInstructions: '', instructionsPath },
97
- };
98
- }
99
-
100
- if (operation === 'open_config') {
101
- const config = typeof backend.openConfig === 'function' ? await backend.openConfig() : {};
102
- return { content: [{ type: 'text', text: JSON.stringify(config, null, 2) }], structuredContent: config };
103
- }
104
-
105
- const normalizedStatuses = Array.isArray(statuses) ? statuses : undefined;
106
- const normalizedTypes = Array.isArray(types) ? types : undefined;
107
-
108
- if (operation === 'refresh') {
109
- const beans = await backend.list();
110
- return {
111
- content: [{ type: 'text', text: JSON.stringify({ count: beans.length, beans }, null, 2) }],
112
- structuredContent: { count: beans.length, beans },
113
- };
114
- }
115
-
116
- if (operation === 'filter') {
117
- let beans = await backend.list({ status: normalizedStatuses, type: normalizedTypes, search });
118
- if (Array.isArray(tags) && tags.length > 0) {
119
- const tagSet = new Set(tags);
120
- beans = beans.filter((bean: BeanRecord) => (bean.tags || []).some((tag: string) => tagSet.has(tag)));
121
- }
122
- return {
123
- content: [{ type: 'text', text: JSON.stringify({ count: beans.length, beans }, null, 2) }],
124
- structuredContent: { count: beans.length, beans },
125
- };
126
- }
127
-
128
- if (operation === 'search') {
129
- let beans = await backend.list({ search });
130
- if (typeof search === 'string' && search.length > 0) {
131
- const q = search.toLowerCase();
132
- beans = beans.filter((b: BeanRecord) => {
133
- const title = (b.title || '').toLowerCase();
134
- const id = (b.id || '').toLowerCase();
135
- const tagsStr = (b.tags || []).join(' ').toLowerCase();
136
- return title.includes(q) || id.includes(q) || tagsStr.includes(q);
137
- });
138
- }
139
- if (includeClosed === false) {
140
- beans = beans.filter((b: BeanRecord) => b.status !== 'completed' && b.status !== 'scrapped');
141
- }
142
- return {
143
- content: [{ type: 'text', text: JSON.stringify({ query: search, count: beans.length, beans }, null, 2) }],
144
- structuredContent: { query: search, count: beans.length, beans },
145
- };
146
- }
147
-
148
- // sort
149
- const beans = await backend.list({ status: normalizedStatuses, type: normalizedTypes, search });
150
- const sorted = sortBeansInternal(beans, mode ?? 'status-priority-type-title');
151
- return {
152
- content: [{ type: 'text', text: JSON.stringify({ mode, count: beans.length, beans: sorted }, null, 2) }],
153
- structuredContent: { mode, count: beans.length, beans: sorted },
154
- };
155
- }
156
-
157
- export { sortBeansInternal as sortBeans };