@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.
- package/README.md +63 -6
- package/{dist/beans-mcp-server.cjs → beans-mcp-server.cjs} +269 -34
- package/{dist/index.cjs → index.cjs} +269 -34
- package/{dist/index.d.ts → index.d.ts} +19 -1
- package/{dist/index.js → index.js} +269 -34
- package/package.json +28 -64
- package/.beans.yml +0 -6
- package/.claude/settings.local.json +0 -18
- package/.editorconfig +0 -13
- package/.github/dependabot.yml +0 -11
- package/.github/workflows/release.yml +0 -235
- package/.github/workflows/test.yml +0 -84
- package/.husky/pre-commit +0 -1
- package/.nvmrc +0 -1
- package/.oxfmtrc.json +0 -11
- package/.oxlintrc.json +0 -37
- package/.vscode/settings.json +0 -3
- package/CHANGELOG.md +0 -160
- package/CONTRIBUTING.md +0 -139
- package/LICENSE.txt +0 -21
- package/codeql/codeql-custom-queries-actions/README.md +0 -14
- package/codeql/codeql-custom-queries-actions/codeql-pack.lock.yml +0 -32
- package/codeql/codeql-custom-queries-actions/codeql-pack.yml +0 -7
- package/codeql/codeql-custom-queries-actions/qlpack.yml +0 -6
- package/codeql/codeql-custom-queries-actions/queries/github-script-without-tojson.ql +0 -18
- package/codeql/codeql-custom-queries-actions/queries/strict-external-action-pinning.ql +0 -18
- package/codeql/codeql-custom-queries-javascript/README.md +0 -14
- package/codeql/codeql-custom-queries-javascript/codeql-pack.lock.yml +0 -30
- package/codeql/codeql-custom-queries-javascript/codeql-pack.yml +0 -7
- package/codeql/codeql-custom-queries-javascript/qlpack.yml +0 -6
- package/codeql/codeql-custom-queries-javascript/queries/child-process-shell-apis.ql +0 -26
- package/codeql/codeql-custom-queries-javascript/queries/innerhtml-assignment.ql +0 -24
- package/dist/README.md +0 -307
- package/dist/beans-mcp-server.cjs.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/package.json +0 -43
- package/pnpm-workspace.yaml +0 -2
- package/scripts/release.js +0 -433
- package/scripts/write-dist-package.js +0 -53
- package/src/cli.ts +0 -14
- package/src/index.ts +0 -21
- package/src/internal/graphql.ts +0 -33
- package/src/internal/queryHelpers.ts +0 -157
- package/src/server/BeansMcpServer.ts +0 -623
- package/src/server/backend.ts +0 -364
- package/src/test/BeansMcpServer.test.ts +0 -514
- package/src/test/handlers.unit.test.ts +0 -201
- package/src/test/parseCliArgs.test.ts +0 -69
- package/src/test/protocol.e2e.test.ts +0 -884
- package/src/test/queryHelpers.test.ts +0 -524
- package/src/test/startBeansMcpServer.test.ts +0 -146
- package/src/test/tools-integration.test.ts +0 -912
- package/src/test/utils.test.ts +0 -81
- package/src/types.ts +0 -46
- package/src/utils.ts +0 -20
- package/tsconfig.json +0 -24
- package/tsup.config.ts +0 -42
- 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 };
|