@dpesch/mantisbt-mcp-server 1.10.3 → 1.10.6

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 (43) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/package.json +1 -1
  3. package/server.json +2 -2
  4. package/.gitea/PULL_REQUEST_TEMPLATE.md +0 -17
  5. package/.gitea/workflows/ci.yml +0 -95
  6. package/.github/workflows/ci.yml +0 -32
  7. package/scripts/hooks/pre-push.mjs +0 -220
  8. package/scripts/init.mjs +0 -95
  9. package/scripts/record-fixtures.ts +0 -160
  10. package/tests/cache.test.ts +0 -265
  11. package/tests/client.test.ts +0 -372
  12. package/tests/config.test.ts +0 -263
  13. package/tests/fixtures/get_current_user.json +0 -40
  14. package/tests/fixtures/get_issue.json +0 -133
  15. package/tests/fixtures/get_issue_enums.json +0 -67
  16. package/tests/fixtures/get_issue_fields_sample.json +0 -76
  17. package/tests/fixtures/get_project_categories.json +0 -157
  18. package/tests/fixtures/get_project_versions.json +0 -3
  19. package/tests/fixtures/get_project_versions_with_data.json +0 -52
  20. package/tests/fixtures/list_issues.json +0 -95
  21. package/tests/fixtures/list_projects.json +0 -65
  22. package/tests/helpers/mock-server.ts +0 -166
  23. package/tests/helpers/search-mocks.ts +0 -84
  24. package/tests/prompts/prompts.test.ts +0 -242
  25. package/tests/resources/resources.test.ts +0 -309
  26. package/tests/search/embedder.test.ts +0 -81
  27. package/tests/search/highlight.test.ts +0 -129
  28. package/tests/search/store.test.ts +0 -193
  29. package/tests/search/sync.test.ts +0 -249
  30. package/tests/search/tools.test.ts +0 -661
  31. package/tests/tools/config.test.ts +0 -212
  32. package/tests/tools/files.test.ts +0 -343
  33. package/tests/tools/issues.test.ts +0 -1180
  34. package/tests/tools/metadata.test.ts +0 -509
  35. package/tests/tools/monitors.test.ts +0 -101
  36. package/tests/tools/projects.test.ts +0 -338
  37. package/tests/tools/relationships.test.ts +0 -177
  38. package/tests/tools/string-coercion.test.ts +0 -317
  39. package/tests/tools/users.test.ts +0 -62
  40. package/tests/utils/date-filter.test.ts +0 -169
  41. package/tests/version-hint.test.ts +0 -230
  42. package/tsconfig.build.json +0 -8
  43. package/vitest.config.ts +0 -8
@@ -1,157 +0,0 @@
1
- {
2
- "categories": [
3
- {
4
- "id": 369,
5
- "name": "API",
6
- "project": { "id": 0, "name": null },
7
- "status": "1"
8
- },
9
- {
10
- "id": 176,
11
- "name": "Außenbereich / GaLaBau",
12
- "project": { "id": 30, "name": "Project 1" },
13
- "status": "1",
14
- "default_handler": { "id": 4, "name": "user_3" }
15
- },
16
- {
17
- "id": 170,
18
- "name": "Außenhülle",
19
- "project": { "id": 30, "name": "Project 1" },
20
- "status": "1"
21
- },
22
- {
23
- "id": 372,
24
- "name": "Automatisierung",
25
- "project": { "id": 0, "name": null },
26
- "status": "1"
27
- },
28
- {
29
- "id": 351,
30
- "name": "Build-Stack",
31
- "project": { "id": 0, "name": null },
32
- "status": "1"
33
- },
34
- {
35
- "id": 352,
36
- "name": "CI (Jenkins)",
37
- "project": { "id": 0, "name": null },
38
- "status": "1"
39
- },
40
- {
41
- "id": 349,
42
- "name": "code cleanup",
43
- "project": { "id": 0, "name": null },
44
- "status": "1"
45
- },
46
- {
47
- "id": 366,
48
- "name": "Code-Review",
49
- "project": { "id": 0, "name": null },
50
- "status": "1"
51
- },
52
- {
53
- "id": 177,
54
- "name": "Dach",
55
- "project": { "id": 30, "name": "Project 1" },
56
- "status": "1"
57
- },
58
- {
59
- "id": 371,
60
- "name": "Datenbank",
61
- "project": { "id": 0, "name": null },
62
- "status": "1"
63
- },
64
- {
65
- "id": 367,
66
- "name": "Datenschutz",
67
- "project": { "id": 0, "name": null },
68
- "status": "1"
69
- },
70
- {
71
- "id": 391,
72
- "name": "E-Mail / Kommunikation",
73
- "project": { "id": 0, "name": null },
74
- "status": "1"
75
- },
76
- {
77
- "id": 171,
78
- "name": "Elektro",
79
- "project": { "id": 30, "name": "Project 1" },
80
- "status": "1",
81
- "default_handler": { "id": 2, "name": "user_4" }
82
- },
83
- {
84
- "id": 174,
85
- "name": "Fliesen/Bodenbeläge",
86
- "project": { "id": 30, "name": "Project 1" },
87
- "status": "1"
88
- },
89
- {
90
- "id": 172,
91
- "name": "Heizung",
92
- "project": { "id": 30, "name": "Project 1" },
93
- "status": "1"
94
- },
95
- {
96
- "id": 392,
97
- "name": "IT-Sicherheit/Security",
98
- "project": { "id": 0, "name": null },
99
- "status": "1"
100
- },
101
- {
102
- "id": 169,
103
- "name": "KNX/Bussystem",
104
- "project": { "id": 30, "name": "Project 1" },
105
- "status": "1",
106
- "default_handler": { "id": 2, "name": "user_4" }
107
- },
108
- {
109
- "id": 350,
110
- "name": "Konfiguration",
111
- "project": { "id": 0, "name": null },
112
- "status": "1"
113
- },
114
- {
115
- "id": 353,
116
- "name": "Modell",
117
- "project": { "id": 0, "name": null },
118
- "status": "1"
119
- },
120
- {
121
- "id": 364,
122
- "name": "QS (Qualitätssicherung)",
123
- "project": { "id": 0, "name": null },
124
- "status": "1"
125
- },
126
- {
127
- "id": 173,
128
- "name": "Sanitär",
129
- "project": { "id": 30, "name": "Project 1" },
130
- "status": "1"
131
- },
132
- {
133
- "id": 398,
134
- "name": "TODO: passende Kategorie zuordnen",
135
- "project": { "id": 0, "name": null },
136
- "status": "1"
137
- },
138
- {
139
- "id": 178,
140
- "name": "Türen / Fenster",
141
- "project": { "id": 30, "name": "Project 1" },
142
- "status": "1"
143
- },
144
- {
145
- "id": 175,
146
- "name": "Wände/Decken",
147
- "project": { "id": 30, "name": "Project 1" },
148
- "status": "1"
149
- },
150
- {
151
- "id": 365,
152
- "name": "Wartung (u. a. Vendors)",
153
- "project": { "id": 0, "name": null },
154
- "status": "1"
155
- }
156
- ]
157
- }
@@ -1,3 +0,0 @@
1
- {
2
- "versions": []
3
- }
@@ -1,52 +0,0 @@
1
- {
2
- "versions": [
3
- {
4
- "id": 416,
5
- "name": "5.x",
6
- "description": "",
7
- "released": false,
8
- "obsolete": false,
9
- "timestamp": "2025-12-31T08:02:00+01:00"
10
- },
11
- {
12
- "id": 332,
13
- "name": "4.x",
14
- "description": "",
15
- "released": false,
16
- "obsolete": false,
17
- "timestamp": "2024-12-31T13:31:00+01:00"
18
- },
19
- {
20
- "id": 148,
21
- "name": "3.x",
22
- "description": "",
23
- "released": false,
24
- "obsolete": false,
25
- "timestamp": "2022-10-31T22:31:00+01:00"
26
- },
27
- {
28
- "id": 17,
29
- "name": "2.x",
30
- "description": "",
31
- "released": true,
32
- "obsolete": true,
33
- "timestamp": "2009-09-18T07:20:00+02:00"
34
- },
35
- {
36
- "id": 9,
37
- "name": "1.x",
38
- "description": "",
39
- "released": true,
40
- "obsolete": true,
41
- "timestamp": "2008-09-04T09:26:00+02:00"
42
- },
43
- {
44
- "id": 10,
45
- "name": "2.0",
46
- "description": "",
47
- "released": true,
48
- "obsolete": true,
49
- "timestamp": "2008-09-04T09:26:00+02:00"
50
- }
51
- ]
52
- }
@@ -1,95 +0,0 @@
1
- {
2
- "issues": [
3
- {
4
- "id": 7860,
5
- "summary": "Issue summary 1",
6
- "description": "Issue description 1",
7
- "project": { "id": 54, "name": "Project 2" },
8
- "category": { "id": 393, "name": "Skills" },
9
- "reporter": {
10
- "id": 51,
11
- "name": "user_1",
12
- "real_name": "User One",
13
- "email": "user1@example.com"
14
- },
15
- "handler": {
16
- "id": 51,
17
- "name": "user_1",
18
- "real_name": "User One",
19
- "email": "user1@example.com"
20
- },
21
- "status": { "id": 50, "name": "assigned", "label": "zugewiesen", "color": "#afbed5" },
22
- "resolution": { "id": 10, "name": "open", "label": "offen" },
23
- "view_state": { "id": 10, "name": "public", "label": "öffentlich" },
24
- "priority": { "id": 30, "name": "normal", "label": "normal" },
25
- "severity": { "id": 200, "name": "Technische Schuld", "label": "Technische Schuld" },
26
- "reproducibility": { "id": 70, "name": "have not tried", "label": "nicht getestet" },
27
- "sticky": false,
28
- "created_at": "2026-03-16T15:40:38+01:00",
29
- "updated_at": "2026-03-16T15:40:38+01:00"
30
- },
31
- {
32
- "id": 7859,
33
- "summary": "Issue summary 2",
34
- "description": "Issue description 2",
35
- "project": { "id": 54, "name": "Project 2" },
36
- "category": { "id": 394, "name": "Hooks" },
37
- "reporter": {
38
- "id": 51,
39
- "name": "user_1",
40
- "real_name": "User One",
41
- "email": "user1@example.com"
42
- },
43
- "handler": {
44
- "id": 51,
45
- "name": "user_1",
46
- "real_name": "User One",
47
- "email": "user1@example.com"
48
- },
49
- "status": { "id": 50, "name": "assigned", "label": "zugewiesen", "color": "#afbed5" },
50
- "resolution": { "id": 10, "name": "open", "label": "offen" },
51
- "view_state": { "id": 10, "name": "public", "label": "öffentlich" },
52
- "priority": { "id": 30, "name": "normal", "label": "normal" },
53
- "severity": { "id": 50, "name": "minor", "label": "minor" },
54
- "reproducibility": { "id": 70, "name": "have not tried", "label": "nicht getestet" },
55
- "sticky": false,
56
- "created_at": "2026-03-16T14:43:52+01:00",
57
- "updated_at": "2026-03-16T14:43:52+01:00"
58
- },
59
- {
60
- "id": 7858,
61
- "summary": "Issue summary 3",
62
- "description": "Issue description 3",
63
- "project": { "id": 54, "name": "Project 2" },
64
- "category": { "id": 395, "name": "Installer" },
65
- "reporter": { "id": 52, "name": "user_2" },
66
- "handler": { "id": 52, "name": "user_2" },
67
- "status": { "id": 20, "name": "feedback", "label": "Rückmeldung", "color": "#f5e5b8" },
68
- "resolution": { "id": 10, "name": "open", "label": "offen" },
69
- "view_state": { "id": 10, "name": "public", "label": "öffentlich" },
70
- "priority": { "id": 30, "name": "normal", "label": "normal" },
71
- "severity": { "id": 50, "name": "minor", "label": "minor" },
72
- "reproducibility": { "id": 70, "name": "have not tried", "label": "nicht getestet" },
73
- "sticky": false,
74
- "created_at": "2026-03-16T12:33:12+01:00",
75
- "updated_at": "2026-03-16T12:54:59+01:00",
76
- "notes": [
77
- {
78
- "id": 3985,
79
- "reporter": {
80
- "id": 51,
81
- "name": "user_1",
82
- "real_name": "User One",
83
- "email": "user1@example.com"
84
- },
85
- "text": "Note text 1",
86
- "view_state": { "id": 10, "name": "public", "label": "öffentlich" },
87
- "attachments": [],
88
- "type": "note",
89
- "created_at": "2026-03-16T12:54:56+01:00",
90
- "updated_at": "2026-03-16T12:54:56+01:00"
91
- }
92
- ]
93
- }
94
- ]
95
- }
@@ -1,65 +0,0 @@
1
- {
2
- "projects": [
3
- {
4
- "id": 30,
5
- "name": "Project 1",
6
- "status": { "id": 10, "name": "development" },
7
- "enabled": true,
8
- "view_state": { "id": 50, "name": "private" },
9
- "access_level": { "id": 70, "name": "manager" },
10
- "versions": [],
11
- "categories": [],
12
- "subprojects": []
13
- },
14
- {
15
- "id": 54,
16
- "name": "Project 2",
17
- "status": { "id": 10, "name": "development" },
18
- "enabled": true,
19
- "view_state": { "id": 10, "name": "public" },
20
- "access_level": { "id": 70, "name": "manager" },
21
- "versions": [],
22
- "categories": [],
23
- "subprojects": []
24
- },
25
- {
26
- "id": 2,
27
- "name": "Project 3",
28
- "status": { "id": 10, "name": "development" },
29
- "enabled": true,
30
- "view_state": { "id": 10, "name": "public" },
31
- "access_level": { "id": 70, "name": "manager" },
32
- "versions": [
33
- { "id": 416, "name": "5.x", "description": "", "released": false, "obsolete": false, "timestamp": "2025-12-31T08:02:00+01:00" },
34
- { "id": 332, "name": "4.x", "description": "", "released": false, "obsolete": false, "timestamp": "2024-12-31T13:31:00+01:00" },
35
- { "id": 148, "name": "3.x", "description": "", "released": false, "obsolete": false, "timestamp": "2022-10-31T22:31:00+01:00" },
36
- { "id": 17, "name": "2.x", "description": "", "released": true, "obsolete": true, "timestamp": "2009-09-18T07:20:00+02:00" },
37
- { "id": 9, "name": "1.x", "description": "", "released": true, "obsolete": true, "timestamp": "2008-09-04T09:26:00+02:00" },
38
- { "id": 10, "name": "2.0", "description": "", "released": true, "obsolete": true, "timestamp": "2008-09-04T09:26:00+02:00" }
39
- ],
40
- "categories": [],
41
- "subprojects": []
42
- },
43
- { "id": 48, "name": "Project 4", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
44
- { "id": 25, "name": "Project 5", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
45
- { "id": 39, "name": "Project 6", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
46
- { "id": 44, "name": "Project 7", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
47
- { "id": 52, "name": "Project 8", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
48
- { "id": 5, "name": "Project 9", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
49
- { "id": 27, "name": "Project 10", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
50
- { "id": 3, "name": "Project 11", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
51
- { "id": 11, "name": "Project 12", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
52
- { "id": 38, "name": "Project 13", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
53
- { "id": 28, "name": "Project 14", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
54
- { "id": 45, "name": "Project 15", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
55
- { "id": 40, "name": "Project 16", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
56
- { "id": 26, "name": "Project 17", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
57
- { "id": 8, "name": "Project 18", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
58
- { "id": 14, "name": "Project 19", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
59
- { "id": 42, "name": "Project 20", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
60
- { "id": 49, "name": "Project 21", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
61
- { "id": 21, "name": "Project 22", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
62
- { "id": 53, "name": "Project 23", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] },
63
- { "id": 47, "name": "Project 24", "status": { "id": 10, "name": "development" }, "enabled": true, "view_state": { "id": 10, "name": "public" }, "access_level": { "id": 70, "name": "manager" }, "versions": [], "categories": [], "subprojects": [] }
64
- ]
65
- }
@@ -1,166 +0,0 @@
1
- export function makeResponse(status: number, body: string): Response {
2
- return {
3
- ok: status >= 200 && status < 300,
4
- status,
5
- statusText: `Status ${status}`,
6
- text: () => Promise.resolve(body),
7
- headers: { get: (_key: string) => null },
8
- } as unknown as Response;
9
- }
10
-
11
- // Typ für das Result-Objekt das die Tools zurückgeben
12
- export interface ToolResult {
13
- content: Array<{ type: string; text: string }>;
14
- isError?: boolean;
15
- }
16
-
17
- import { z } from 'zod';
18
-
19
- // Handler-Typ (args ist der Zod-geparste Input)
20
- type ToolHandler = (args: Record<string, unknown>) => Promise<ToolResult>;
21
-
22
- interface ToolDefinition {
23
- inputSchema?: z.ZodTypeAny;
24
- [key: string]: unknown;
25
- }
26
-
27
- export interface PromptMessage {
28
- role: string;
29
- content: { type: string; text: string };
30
- }
31
-
32
- export interface PromptResult {
33
- messages: PromptMessage[];
34
- }
35
-
36
- export interface ResourceResult {
37
- contents: Array<{ uri: string; mimeType?: string; text: string }>;
38
- }
39
-
40
- type PromptHandler = (args: Record<string, unknown>) => PromptResult;
41
-
42
- type ResourceHandler = (uri: URL, variables?: Record<string, string>) => Promise<ResourceResult>;
43
-
44
- interface ResourceEntry {
45
- handler: ResourceHandler;
46
- /** URI template pattern, e.g. 'mantis://projects/{id}'. Present for template resources only. */
47
- template?: string;
48
- }
49
-
50
- function matchTemplate(template: string, uri: string): Record<string, string> | null {
51
- const names = [...template.matchAll(/\{([^}]+)\}/g)].map((m) => m[1]!);
52
- const pattern = template.replace(/\{[^}]+\}/g, '([^/]+)');
53
- const match = uri.match(new RegExp(`^${pattern}$`));
54
- if (!match) return null;
55
- return Object.fromEntries(names.map((name, i) => [name, match[i + 1]!]));
56
- }
57
-
58
- interface PromptDefinition {
59
- argsSchema?: Record<string, z.ZodTypeAny>;
60
- [key: string]: unknown;
61
- }
62
-
63
- export class MockMcpServer {
64
- private readonly handlers = new Map<string, ToolHandler>();
65
- private readonly schemas = new Map<string, z.ZodTypeAny>();
66
- private readonly promptHandlers = new Map<string, PromptHandler>();
67
- private readonly resourceEntries = new Map<string, ResourceEntry>();
68
-
69
- // Nachahmt McpServer.registerTool – fängt Handler und Schema ein
70
- registerTool(name: string, definition: ToolDefinition, handler: ToolHandler): void {
71
- this.handlers.set(name, handler);
72
- if (definition.inputSchema) {
73
- this.schemas.set(name, definition.inputSchema);
74
- }
75
- }
76
-
77
- // Nachahmt McpServer.registerPrompt
78
- registerPrompt(name: string, _definition: PromptDefinition, handler: PromptHandler): void {
79
- this.promptHandlers.set(name, handler);
80
- }
81
-
82
- /**
83
- * Ruft den Handler auf. Wenn `validate: true`, wird der Input zuerst
84
- * durch das Zod-Schema geparst (wie der echte MCP-Server es tut).
85
- * Das ermöglicht Tests für Coercion und Validierungsfehler.
86
- */
87
- async callTool(
88
- name: string,
89
- args: Record<string, unknown> = {},
90
- options: { validate?: boolean } = {},
91
- ): Promise<ToolResult> {
92
- const handler = this.handlers.get(name);
93
- if (!handler) throw new Error(`Tool not registered: ${name}`);
94
-
95
- const schema = this.schemas.get(name);
96
- if (schema) {
97
- const parsed = schema.safeParse(args);
98
- if (!parsed.success) {
99
- if (options.validate) {
100
- return {
101
- content: [{ type: 'text', text: `Validation error: ${parsed.error.message}` }],
102
- isError: true,
103
- };
104
- }
105
- } else {
106
- return handler(parsed.data as Record<string, unknown>);
107
- }
108
- }
109
-
110
- return handler(args);
111
- }
112
-
113
- callPrompt(name: string, args: Record<string, unknown> = {}): PromptResult {
114
- const handler = this.promptHandlers.get(name);
115
- if (!handler) throw new Error(`Prompt not registered: ${name}`);
116
- return handler(args);
117
- }
118
-
119
- hasToolRegistered(name: string): boolean {
120
- return this.handlers.has(name);
121
- }
122
-
123
- hasPromptRegistered(name: string): boolean {
124
- return this.promptHandlers.has(name);
125
- }
126
-
127
- registeredToolNames(): string[] {
128
- return [...this.handlers.keys()];
129
- }
130
-
131
- registeredPromptNames(): string[] {
132
- return [...this.promptHandlers.keys()];
133
- }
134
-
135
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
136
- registerResource(name: string, uriOrTemplate: any, _config: unknown, handler: ResourceHandler): void {
137
- if (typeof uriOrTemplate === 'string') {
138
- this.resourceEntries.set(uriOrTemplate, { handler });
139
- } else {
140
- // ResourceTemplate — uriTemplate getter returns a UriTemplate object; .toString() gives the pattern string
141
- const templateStr: string = uriOrTemplate.uriTemplate?.toString() ?? name;
142
- this.resourceEntries.set(templateStr, { handler, template: templateStr });
143
- }
144
- }
145
-
146
- async callResource(uri: string): Promise<ResourceResult> {
147
- const exact = this.resourceEntries.get(uri);
148
- if (exact) return exact.handler(new URL(uri), {});
149
-
150
- for (const entry of this.resourceEntries.values()) {
151
- if (!entry.template) continue;
152
- const variables = matchTemplate(entry.template, uri);
153
- if (variables) return entry.handler(new URL(uri), variables);
154
- }
155
-
156
- throw new Error(`Resource not registered: ${uri}`);
157
- }
158
-
159
- hasResourceRegistered(uri: string): boolean {
160
- return this.resourceEntries.has(uri);
161
- }
162
-
163
- registeredResourceUris(): string[] {
164
- return [...this.resourceEntries.keys()];
165
- }
166
- }
@@ -1,84 +0,0 @@
1
- import { vi } from 'vitest';
2
- import type { VectorStore, VectorStoreItem } from '../../src/search/store.js';
3
- import type { Embedder } from '../../src/search/embedder.js';
4
-
5
- // ---------------------------------------------------------------------------
6
- // Shared constants
7
- // ---------------------------------------------------------------------------
8
-
9
- export const MOCK_VECTOR = Array(384).fill(0.1) as number[];
10
-
11
- // ---------------------------------------------------------------------------
12
- // makeMockStore
13
- // ---------------------------------------------------------------------------
14
-
15
- export interface MockStoreItem {
16
- id: number;
17
- score?: number;
18
- updated_at?: string;
19
- }
20
-
21
- export function makeMockStore(options?: {
22
- lastSyncedAt?: string | null;
23
- itemCount?: number;
24
- lastKnownTotal?: number | null;
25
- items?: MockStoreItem[];
26
- }): VectorStore {
27
- const lastSyncedAt = options?.lastSyncedAt ?? null;
28
- const seedItems = options?.items ?? null;
29
- const addedItems: VectorStoreItem[] = [];
30
- const itemMap = new Map<number, VectorStoreItem>(
31
- (seedItems ?? []).map(i => [i.id, {
32
- id: i.id,
33
- vector: MOCK_VECTOR,
34
- metadata: { summary: `Issue ${i.id}`, updated_at: i.updated_at },
35
- }])
36
- );
37
- let count = options?.itemCount ?? seedItems?.length ?? 0;
38
-
39
- return {
40
- add: vi.fn(async (item: VectorStoreItem) => {
41
- addedItems.push(item);
42
- count++;
43
- }),
44
- addBatch: vi.fn(async (items: VectorStoreItem[]) => {
45
- for (const item of items) {
46
- addedItems.push(item);
47
- }
48
- count += items.length;
49
- }),
50
- search: vi.fn(async (_vec: number[], topN: number) => {
51
- if (seedItems) {
52
- return seedItems.slice(0, topN).map(i => ({ id: i.id, score: i.score ?? 0.9 }));
53
- }
54
- return Array.from({ length: Math.min(topN, count) }, (_, i) => ({
55
- id: i + 1,
56
- score: 1 - i * 0.1,
57
- }));
58
- }),
59
- getItem: vi.fn(async (id: number) => itemMap.get(id) ?? null),
60
- delete: vi.fn(async () => {}),
61
- count: vi.fn(async () => count),
62
- clear: vi.fn(async () => {
63
- addedItems.splice(0);
64
- count = 0;
65
- }),
66
- getLastSyncedAt: vi.fn(async () => lastSyncedAt),
67
- setLastSyncedAt: vi.fn(async () => {}),
68
- resetLastSyncedAt: vi.fn(async () => {}),
69
- getLastKnownTotal: vi.fn(async () => options?.lastKnownTotal ?? null),
70
- setLastKnownTotal: vi.fn(async () => {}),
71
- flush: vi.fn(async () => {}),
72
- };
73
- }
74
-
75
- // ---------------------------------------------------------------------------
76
- // makeMockEmbedder
77
- // ---------------------------------------------------------------------------
78
-
79
- export function makeMockEmbedder(): Embedder {
80
- return {
81
- embed: vi.fn(async () => MOCK_VECTOR),
82
- embedBatch: vi.fn(async (texts: string[]) => texts.map(() => MOCK_VECTOR)),
83
- } as unknown as Embedder;
84
- }