@vheins/local-memory-mcp 0.9.2 → 0.9.4

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.
@@ -1,49 +1,3 @@
1
- // src/mcp/capabilities.ts
2
- import { fileURLToPath } from "url";
3
- import path from "path";
4
- var __dirname = path.dirname(fileURLToPath(import.meta.url));
5
- var pkgVersion = "0.1.0";
6
- if ("0.9.2") {
7
- pkgVersion = "0.9.2";
8
- } else {
9
- let searchDir = __dirname;
10
- for (let i = 0; i < 5; i++) {
11
- const candidate = path.join(searchDir, "package.json");
12
- try {
13
- if (fs.existsSync(candidate)) {
14
- const pkg = JSON.parse(fs.readFileSync(candidate, "utf8"));
15
- if (pkg.name === "@vheins/local-memory-mcp" && pkg.version) {
16
- pkgVersion = pkg.version;
17
- break;
18
- }
19
- }
20
- } catch {
21
- }
22
- searchDir = path.dirname(searchDir);
23
- }
24
- }
25
- var MCP_PROTOCOL_VERSION = "2025-03-26";
26
- var CAPABILITIES = {
27
- serverInfo: {
28
- name: "mcp-memory-local",
29
- version: pkgVersion
30
- },
31
- capabilities: {
32
- completions: {},
33
- logging: {},
34
- resources: {
35
- subscribe: true,
36
- listChanged: true
37
- },
38
- tools: {
39
- listChanged: false
40
- },
41
- prompts: {
42
- listChanged: true
43
- }
44
- }
45
- };
46
-
47
1
  // src/mcp/utils/logger.ts
48
2
  import fs from "fs";
49
3
  var LEVELS = {
@@ -185,6 +139,108 @@ function createFileSink(logDir, maxFiles = 5) {
185
139
  };
186
140
  }
187
141
 
142
+ // src/mcp/session.ts
143
+ import path from "path";
144
+ import { fileURLToPath } from "url";
145
+ function createSessionContext() {
146
+ return {
147
+ roots: [],
148
+ supportsRoots: false,
149
+ supportsSampling: false,
150
+ supportsSamplingTools: false,
151
+ supportsElicitation: false,
152
+ supportsElicitationForm: false,
153
+ supportsElicitationUrl: false
154
+ };
155
+ }
156
+ function updateSessionFromInitialize(session, params) {
157
+ const capabilities = params?.capabilities || {};
158
+ session.clientInfo = params?.clientInfo;
159
+ session.clientCapabilities = capabilities;
160
+ session.supportsRoots = Boolean(capabilities.roots);
161
+ session.supportsSampling = Boolean(capabilities.sampling);
162
+ const sampling = capabilities.sampling;
163
+ session.supportsSamplingTools = Boolean(sampling?.tools);
164
+ session.supportsElicitation = Boolean(capabilities.elicitation);
165
+ session.supportsElicitationForm = supportsElicitationMode(capabilities.elicitation, "form");
166
+ session.supportsElicitationUrl = supportsElicitationMode(capabilities.elicitation, "url");
167
+ }
168
+ function supportsElicitationMode(capability, mode) {
169
+ if (!capability || typeof capability !== "object") {
170
+ return false;
171
+ }
172
+ const cap = capability;
173
+ if (mode === "form") {
174
+ return Object.keys(cap).length === 0 || typeof cap.form === "object";
175
+ }
176
+ return typeof cap.url === "object";
177
+ }
178
+ function updateSessionRoots(session, roots) {
179
+ const normalized = normalizeRoots(roots);
180
+ const previous = JSON.stringify(session.roots);
181
+ const next = JSON.stringify(normalized);
182
+ session.roots = normalized;
183
+ return previous !== next;
184
+ }
185
+ function normalizeRoots(roots) {
186
+ if (!Array.isArray(roots)) return [];
187
+ const seen = /* @__PURE__ */ new Set();
188
+ const normalized = [];
189
+ for (const root of roots) {
190
+ if (!root || typeof root !== "object") continue;
191
+ const r = root;
192
+ const uri = typeof r.uri === "string" ? r.uri : void 0;
193
+ const name = typeof r.name === "string" ? r.name : void 0;
194
+ if (!uri || seen.has(uri)) continue;
195
+ seen.add(uri);
196
+ normalized.push({ uri, name });
197
+ }
198
+ return normalized;
199
+ }
200
+ function extractRootsFromResult(result) {
201
+ return normalizeRoots(result?.roots);
202
+ }
203
+ function getFilesystemRoots(session) {
204
+ if (!session) return [];
205
+ const resolved = [];
206
+ for (const root of session.roots) {
207
+ if (!root.uri.startsWith("file://")) continue;
208
+ try {
209
+ resolved.push(path.resolve(fileURLToPath(root.uri)));
210
+ } catch {
211
+ }
212
+ }
213
+ return resolved;
214
+ }
215
+ function isPathWithinRoots(targetPath, session) {
216
+ const roots = getFilesystemRoots(session);
217
+ if (roots.length === 0) return true;
218
+ const normalizedTarget = path.resolve(targetPath);
219
+ return roots.some((rootPath) => {
220
+ const relative = path.relative(rootPath, normalizedTarget);
221
+ return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
222
+ });
223
+ }
224
+ function findContainingRoot(targetPath, session) {
225
+ const roots = getFilesystemRoots(session);
226
+ if (roots.length === 0) return null;
227
+ const normalizedTarget = path.resolve(targetPath);
228
+ for (const rootPath of roots) {
229
+ const relative = path.relative(rootPath, normalizedTarget);
230
+ if (relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative)) {
231
+ return rootPath;
232
+ }
233
+ }
234
+ return null;
235
+ }
236
+ function inferRepoFromSession(session) {
237
+ const roots = getFilesystemRoots(session);
238
+ if (roots.length === 1) {
239
+ return path.basename(roots[0]);
240
+ }
241
+ return void 0;
242
+ }
243
+
188
244
  // src/mcp/storage/sqlite.ts
189
245
  import Database from "better-sqlite3";
190
246
  import path3 from "path";
@@ -2765,1323 +2821,1212 @@ var RealVectorStore = class {
2765
2821
  }
2766
2822
  };
2767
2823
 
2768
- // src/mcp/session.ts
2769
- import path4 from "path";
2824
+ // src/mcp/capabilities.ts
2770
2825
  import { fileURLToPath as fileURLToPath2 } from "url";
2771
- function createSessionContext() {
2772
- return {
2773
- roots: [],
2774
- supportsRoots: false,
2775
- supportsSampling: false,
2776
- supportsSamplingTools: false,
2777
- supportsElicitation: false,
2778
- supportsElicitationForm: false,
2779
- supportsElicitationUrl: false
2780
- };
2781
- }
2782
- function updateSessionFromInitialize(session, params) {
2783
- const capabilities = params?.capabilities || {};
2784
- session.clientInfo = params?.clientInfo;
2785
- session.clientCapabilities = capabilities;
2786
- session.supportsRoots = Boolean(capabilities.roots);
2787
- session.supportsSampling = Boolean(capabilities.sampling);
2788
- const sampling = capabilities.sampling;
2789
- session.supportsSamplingTools = Boolean(sampling?.tools);
2790
- session.supportsElicitation = Boolean(capabilities.elicitation);
2791
- session.supportsElicitationForm = supportsElicitationMode(capabilities.elicitation, "form");
2792
- session.supportsElicitationUrl = supportsElicitationMode(capabilities.elicitation, "url");
2793
- }
2794
- function supportsElicitationMode(capability, mode) {
2795
- if (!capability || typeof capability !== "object") {
2796
- return false;
2797
- }
2798
- const cap = capability;
2799
- if (mode === "form") {
2800
- return Object.keys(cap).length === 0 || typeof cap.form === "object";
2801
- }
2802
- return typeof cap.url === "object";
2803
- }
2804
- function updateSessionRoots(session, roots) {
2805
- const normalized = normalizeRoots(roots);
2806
- const previous = JSON.stringify(session.roots);
2807
- const next = JSON.stringify(normalized);
2808
- session.roots = normalized;
2809
- return previous !== next;
2810
- }
2811
- function normalizeRoots(roots) {
2812
- if (!Array.isArray(roots)) return [];
2813
- const seen = /* @__PURE__ */ new Set();
2814
- const normalized = [];
2815
- for (const root of roots) {
2816
- if (!root || typeof root !== "object") continue;
2817
- const r = root;
2818
- const uri = typeof r.uri === "string" ? r.uri : void 0;
2819
- const name = typeof r.name === "string" ? r.name : void 0;
2820
- if (!uri || seen.has(uri)) continue;
2821
- seen.add(uri);
2822
- normalized.push({ uri, name });
2823
- }
2824
- return normalized;
2825
- }
2826
- function extractRootsFromResult(result) {
2827
- return normalizeRoots(result?.roots);
2828
- }
2829
- function getFilesystemRoots(session) {
2830
- if (!session) return [];
2831
- const resolved = [];
2832
- for (const root of session.roots) {
2833
- if (!root.uri.startsWith("file://")) continue;
2826
+ import path4 from "path";
2827
+ var __dirname = path4.dirname(fileURLToPath2(import.meta.url));
2828
+ var pkgVersion = "0.1.0";
2829
+ if ("0.9.4") {
2830
+ pkgVersion = "0.9.4";
2831
+ } else {
2832
+ let searchDir = __dirname;
2833
+ for (let i = 0; i < 5; i++) {
2834
+ const candidate = path4.join(searchDir, "package.json");
2834
2835
  try {
2835
- resolved.push(path4.resolve(fileURLToPath2(root.uri)));
2836
+ if (fs.existsSync(candidate)) {
2837
+ const pkg = JSON.parse(fs.readFileSync(candidate, "utf8"));
2838
+ if (pkg.name === "@vheins/local-memory-mcp" && pkg.version) {
2839
+ pkgVersion = pkg.version;
2840
+ break;
2841
+ }
2842
+ }
2836
2843
  } catch {
2837
2844
  }
2845
+ searchDir = path4.dirname(searchDir);
2838
2846
  }
2839
- return resolved;
2840
- }
2841
- function isPathWithinRoots(targetPath, session) {
2842
- const roots = getFilesystemRoots(session);
2843
- if (roots.length === 0) return true;
2844
- const normalizedTarget = path4.resolve(targetPath);
2845
- return roots.some((rootPath) => {
2846
- const relative = path4.relative(rootPath, normalizedTarget);
2847
- return relative === "" || !relative.startsWith("..") && !path4.isAbsolute(relative);
2848
- });
2849
2847
  }
2850
- function findContainingRoot(targetPath, session) {
2851
- const roots = getFilesystemRoots(session);
2852
- if (roots.length === 0) return null;
2853
- const normalizedTarget = path4.resolve(targetPath);
2854
- for (const rootPath of roots) {
2855
- const relative = path4.relative(rootPath, normalizedTarget);
2856
- if (relative === "" || !relative.startsWith("..") && !path4.isAbsolute(relative)) {
2857
- return rootPath;
2848
+ var MCP_PROTOCOL_VERSION = "2025-03-26";
2849
+ var CAPABILITIES = {
2850
+ serverInfo: {
2851
+ name: "mcp-memory-local",
2852
+ version: pkgVersion
2853
+ },
2854
+ capabilities: {
2855
+ completions: {},
2856
+ logging: {},
2857
+ resources: {
2858
+ subscribe: true,
2859
+ listChanged: true
2860
+ },
2861
+ tools: {
2862
+ listChanged: false
2863
+ },
2864
+ prompts: {
2865
+ listChanged: true
2858
2866
  }
2859
2867
  }
2860
- return null;
2868
+ };
2869
+
2870
+ // src/mcp/utils/pagination.ts
2871
+ function encodeCursor(offset) {
2872
+ return Buffer.from(String(offset), "utf8").toString("base64");
2861
2873
  }
2862
- function inferRepoFromSession(session) {
2863
- const roots = getFilesystemRoots(session);
2864
- if (roots.length === 1) {
2865
- return path4.basename(roots[0]);
2874
+ function decodeCursor(cursor) {
2875
+ if (cursor === void 0 || cursor === null || cursor === "") {
2876
+ return 0;
2866
2877
  }
2867
- return void 0;
2878
+ if (typeof cursor !== "string" || cursor.trim() === "") {
2879
+ throw invalidPaginationParams("Invalid cursor");
2880
+ }
2881
+ let decoded;
2882
+ try {
2883
+ decoded = Buffer.from(cursor, "base64").toString("utf8");
2884
+ } catch {
2885
+ throw invalidPaginationParams("Invalid cursor");
2886
+ }
2887
+ if (!/^\d+$/.test(decoded)) {
2888
+ throw invalidPaginationParams("Invalid cursor");
2889
+ }
2890
+ const offset = Number.parseInt(decoded, 10);
2891
+ if (!Number.isFinite(offset) || offset < 0) {
2892
+ throw invalidPaginationParams("Invalid cursor");
2893
+ }
2894
+ return offset;
2895
+ }
2896
+ function invalidPaginationParams(message) {
2897
+ const error = new Error(message);
2898
+ error.code = -32602;
2899
+ return error;
2868
2900
  }
2869
2901
 
2870
- // src/mcp/tools/schemas.ts
2871
- import { z } from "zod";
2872
- var MemoryScopeSchema = z.object({
2873
- repo: z.string().min(1).transform(normalizeRepo),
2874
- branch: z.string().optional(),
2875
- folder: z.string().optional(),
2876
- language: z.string().optional()
2877
- });
2878
- var MemoryTypeSchema = z.enum([
2879
- "code_fact",
2880
- "decision",
2881
- "mistake",
2882
- "pattern",
2883
- "task_archive"
2884
- ]);
2885
- var MemoryStoreSchema = z.object({
2886
- code: z.string().max(20).optional(),
2887
- type: MemoryTypeSchema,
2888
- title: z.string().min(3).max(255),
2889
- content: z.string().min(10),
2890
- importance: z.number().min(1).max(5),
2891
- agent: z.string().min(1),
2892
- role: z.string().optional().default("unknown"),
2893
- model: z.string().min(1),
2894
- scope: MemoryScopeSchema,
2895
- ttlDays: z.number().min(1).optional(),
2896
- supersedes: z.string().uuid().optional(),
2897
- tags: z.array(z.string()).optional(),
2898
- metadata: z.record(z.string(), z.any()).optional(),
2899
- is_global: z.boolean().default(false),
2900
- structured: z.boolean().default(false)
2901
- });
2902
- var MemoryUpdateSchema = z.object({
2903
- id: z.string().uuid(),
2904
- type: MemoryTypeSchema.optional(),
2905
- title: z.string().min(3).max(255).optional(),
2906
- content: z.string().min(10).optional(),
2907
- importance: z.number().min(1).max(5).optional(),
2908
- agent: z.string().optional(),
2909
- role: z.string().optional(),
2910
- status: z.enum(["active", "archived"]).optional(),
2911
- supersedes: z.string().uuid().optional(),
2912
- tags: z.array(z.string()).optional(),
2913
- metadata: z.record(z.string(), z.any()).optional(),
2914
- is_global: z.boolean().optional(),
2915
- completed_at: z.string().optional(),
2916
- structured: z.boolean().default(false)
2917
- }).refine(
2918
- (data) => data.type !== void 0 || data.content !== void 0 || data.title !== void 0 || data.importance !== void 0 || data.status !== void 0 || data.supersedes !== void 0 || data.tags !== void 0 || data.metadata !== void 0 || data.is_global !== void 0 || data.agent !== void 0 || data.role !== void 0 || data.completed_at !== void 0,
2919
- { message: "At least one field must be provided for update" }
2920
- );
2921
- var MemorySearchSchema = z.object({
2922
- query: z.string().min(3),
2923
- prompt: z.string().optional(),
2924
- repo: z.string().min(1).transform(normalizeRepo),
2925
- types: z.array(MemoryTypeSchema).optional(),
2926
- minImportance: z.number().min(1).max(5).optional(),
2927
- limit: z.number().min(1).max(100).default(5),
2928
- offset: z.number().min(0).default(0),
2929
- includeRecap: z.boolean().default(false),
2930
- current_file_path: z.string().optional(),
2931
- include_archived: z.boolean().default(false),
2932
- current_tags: z.array(z.string()).optional(),
2933
- scope: MemoryScopeSchema.partial().optional(),
2934
- structured: z.boolean().default(false)
2935
- });
2936
- var MemoryAcknowledgeSchema = z.object({
2937
- memory_id: z.string().uuid(),
2938
- status: z.enum(["used", "irrelevant", "contradictory"]),
2939
- application_context: z.string().min(10).optional(),
2940
- structured: z.boolean().default(false)
2941
- });
2942
- var MemoryRecapSchema = z.object({
2943
- repo: z.string().min(1).transform(normalizeRepo),
2944
- limit: z.number().min(1).max(50).default(20),
2945
- offset: z.number().min(0).default(0),
2946
- structured: z.boolean().default(false)
2947
- });
2948
- var MemoryDeleteSchema = z.object({
2949
- repo: z.string().min(1).transform(normalizeRepo).optional(),
2950
- id: z.string().uuid().optional(),
2951
- ids: z.array(z.string().uuid()).min(1).optional(),
2952
- structured: z.boolean().default(false)
2953
- }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
2954
- message: "Either 'id' or 'ids' must be provided for deletion"
2955
- });
2956
- var MemorySummarizeSchema = z.object({
2957
- repo: z.string().min(1).transform(normalizeRepo),
2958
- signals: z.array(z.string().max(200)).min(1),
2959
- structured: z.boolean().default(false)
2960
- });
2961
- var MemorySynthesizeSchema = z.object({
2962
- repo: z.string().min(1).transform(normalizeRepo).optional(),
2963
- objective: z.string().min(5),
2964
- current_file_path: z.string().optional(),
2965
- include_summary: z.boolean().default(true),
2966
- include_tasks: z.boolean().default(true),
2967
- use_tools: z.boolean().default(true),
2968
- max_iterations: z.number().int().min(1).max(5).default(3),
2969
- max_tokens: z.number().int().min(128).max(4e3).default(1200),
2970
- structured: z.boolean().default(false)
2971
- });
2972
- var TaskStatusSchema = z.enum(["backlog", "pending", "in_progress", "completed", "canceled", "blocked"]);
2973
- var TaskPrioritySchema = z.number().min(1).max(5);
2974
- var SingleTaskCreateSchema = z.object({
2975
- task_code: z.string().min(1),
2976
- phase: z.string().min(1),
2977
- title: z.string().min(3).max(100),
2978
- description: z.string().min(1),
2979
- status: TaskStatusSchema.default("backlog"),
2980
- priority: TaskPrioritySchema.default(3),
2981
- agent: z.string().optional(),
2982
- role: z.string().optional(),
2983
- doc_path: z.string().optional(),
2984
- tags: z.array(z.string()).optional(),
2985
- metadata: z.record(z.string(), z.any()).optional(),
2986
- parent_id: z.string().uuid().optional(),
2987
- depends_on: z.string().uuid().optional(),
2988
- est_tokens: z.number().int().min(0).optional()
2989
- });
2990
- var TaskCreateSchema = z.object({
2991
- repo: z.string().min(1).transform(normalizeRepo),
2992
- // Allow single task fields at top level (backward compatibility & single use)
2993
- task_code: z.string().min(1).optional(),
2994
- phase: z.string().min(1).optional(),
2995
- title: z.string().min(3).max(100).optional(),
2996
- description: z.string().min(1).optional(),
2997
- status: TaskStatusSchema.optional(),
2998
- priority: TaskPrioritySchema.optional(),
2999
- agent: z.string().optional(),
3000
- role: z.string().optional(),
3001
- doc_path: z.string().optional(),
3002
- tags: z.array(z.string()).optional(),
3003
- metadata: z.record(z.string(), z.any()).optional(),
3004
- parent_id: z.string().uuid().optional(),
3005
- depends_on: z.string().uuid().optional(),
3006
- est_tokens: z.number().int().min(0).optional(),
3007
- // Allow bulk tasks
3008
- tasks: z.array(SingleTaskCreateSchema).min(1).optional(),
3009
- structured: z.boolean().default(false)
3010
- }).refine(
3011
- (data) => {
3012
- if (data.tasks) return true;
3013
- return !!(data.task_code && data.phase && data.title && data.description);
3014
- },
3015
- { message: "Either 'tasks' array or single task fields (task_code, phase, title, description) must be provided" }
3016
- );
3017
- var TaskCreateInteractiveSchema = SingleTaskCreateSchema.partial().extend({
3018
- repo: z.string().min(1).transform(normalizeRepo).optional(),
3019
- structured: z.boolean().default(false)
3020
- });
3021
- var TaskUpdateSchema = z.object({
3022
- repo: z.string().min(1).transform(normalizeRepo),
3023
- id: z.string().uuid().optional(),
3024
- ids: z.array(z.string().uuid()).min(1).optional(),
3025
- task_code: z.string().optional(),
3026
- phase: z.string().optional(),
3027
- title: z.string().min(3).max(100).optional(),
3028
- description: z.string().optional(),
3029
- status: TaskStatusSchema.optional(),
3030
- priority: TaskPrioritySchema.optional(),
3031
- agent: z.string().min(1, "agent name is required").optional(),
3032
- role: z.string().min(1, "agent role is required").optional(),
3033
- model: z.string().optional(),
3034
- comment: z.string().min(1).optional(),
3035
- doc_path: z.string().optional(),
3036
- tags: z.array(z.string()).optional(),
3037
- metadata: z.record(z.string(), z.any()).optional(),
3038
- parent_id: z.string().uuid().optional(),
3039
- depends_on: z.string().uuid().optional(),
3040
- est_tokens: z.number().int().min(0).optional(),
3041
- force: z.boolean().optional(),
3042
- structured: z.boolean().default(false)
3043
- }).refine((data) => data.id !== void 0 || data.ids !== void 0 || data.task_code !== void 0, {
3044
- message: "Either 'id', 'ids', or 'task_code' must be provided for update"
3045
- }).refine((data) => Object.keys(data).length > 2, {
3046
- message: "At least one field besides repo and id/ids must be provided for update"
3047
- });
3048
- var TaskListSchema = z.object({
3049
- repo: z.string().min(1).transform(normalizeRepo),
3050
- status: z.string().optional(),
3051
- phase: z.string().optional(),
3052
- query: z.string().optional(),
3053
- limit: z.number().min(1).max(100).default(15),
3054
- offset: z.number().min(0).default(0),
3055
- structured: z.boolean().default(false)
3056
- });
3057
- var TaskSearchSchema = z.object({
3058
- repo: z.string().min(1).transform(normalizeRepo),
3059
- query: z.string().min(1),
3060
- status: z.string().optional(),
3061
- limit: z.number().min(1).max(100).default(10),
3062
- offset: z.number().min(0).default(0),
3063
- structured: z.boolean().default(false)
3064
- });
3065
- var TaskDeleteSchema = z.object({
3066
- repo: z.string().min(1).transform(normalizeRepo),
3067
- id: z.string().uuid().optional(),
3068
- ids: z.array(z.string().uuid()).min(1).optional(),
3069
- structured: z.boolean().default(false)
3070
- }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3071
- message: "Either 'id' or 'ids' must be provided for deletion"
3072
- });
3073
- var MemoryDetailSchema = z.object({
3074
- id: z.string().uuid().optional(),
3075
- code: z.string().max(20).optional(),
3076
- structured: z.boolean().default(false)
3077
- }).refine((data) => data.id !== void 0 || data.code !== void 0, {
3078
- message: "Either id or code must be provided"
3079
- });
3080
- var StandardDetailSchema = z.object({
3081
- id: z.string().uuid(),
3082
- structured: z.boolean().default(false)
3083
- });
3084
- var StandardDeleteSchema = z.object({
3085
- repo: z.string().min(1).transform(normalizeRepo).optional(),
3086
- id: z.string().uuid().optional(),
3087
- ids: z.array(z.string().uuid()).min(1).optional(),
3088
- structured: z.boolean().default(false)
3089
- }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3090
- message: "Either 'id' or 'ids' must be provided for deletion"
3091
- });
3092
- var TaskGetSchema = z.object({
3093
- repo: z.string().min(1).transform(normalizeRepo),
3094
- id: z.string().uuid().optional(),
3095
- task_code: z.string().optional(),
3096
- structured: z.boolean().default(false)
3097
- }).refine((data) => data.id !== void 0 || data.task_code !== void 0, {
3098
- message: "Either id or task_code must be provided"
3099
- });
3100
- var HandoffStatusSchema = z.enum(["pending", "accepted", "rejected", "expired"]);
3101
- var HandoffCreateSchema = z.object({
3102
- repo: z.string().min(1).transform(normalizeRepo),
3103
- from_agent: z.string().min(1),
3104
- to_agent: z.string().min(1).optional(),
3105
- task_id: z.string().uuid().optional(),
3106
- task_code: z.string().optional(),
3107
- summary: z.string().min(1),
3108
- context: z.record(z.string(), z.any()).optional(),
3109
- expires_at: z.string().optional(),
3110
- structured: z.boolean().default(false)
3111
- }).refine((data) => !(data.task_id && data.task_code), {
3112
- message: "Provide either task_id or task_code, not both"
3113
- }).refine((data) => data.to_agent || data.task_id || data.task_code || data.context?.next_steps || data.context?.blockers || data.context?.remaining_work, {
3114
- message: "Handoffs must identify a target agent, linked task, next_steps, blockers, or remaining_work. Do not create pending handoffs for completed-work summaries."
3115
- });
3116
- var HandoffUpdateSchema = z.object({
3117
- id: z.string().uuid(),
3118
- status: HandoffStatusSchema,
3119
- structured: z.boolean().default(false)
3120
- });
3121
- var HandoffListSchema = z.object({
3122
- repo: z.string().min(1).transform(normalizeRepo),
3123
- status: HandoffStatusSchema.optional(),
3124
- from_agent: z.string().min(1).optional(),
3125
- to_agent: z.string().min(1).optional(),
3126
- limit: z.number().min(1).max(100).default(20),
3127
- offset: z.number().min(0).default(0),
3128
- structured: z.boolean().default(false)
3129
- });
3130
- var TaskClaimSchema = z.object({
3131
- repo: z.string().min(1).transform(normalizeRepo),
3132
- task_id: z.string().uuid().optional(),
3133
- task_code: z.string().optional(),
3134
- agent: z.string().min(1),
3135
- role: z.string().optional(),
3136
- metadata: z.record(z.string(), z.any()).optional(),
3137
- structured: z.boolean().default(false)
3138
- }).refine((data) => data.task_id !== void 0 || data.task_code !== void 0, {
3139
- message: "Either task_id or task_code must be provided"
3140
- }).refine((data) => !(data.task_id && data.task_code), {
3141
- message: "Provide either task_id or task_code, not both"
3142
- });
3143
- var StandardStoreSchema = z.object({
3144
- name: z.string().min(3).max(255),
3145
- content: z.string().min(10),
3146
- parent_id: z.string().uuid().optional(),
3147
- context: z.string().optional(),
3148
- version: z.string().optional(),
3149
- language: z.string().optional(),
3150
- stack: z.array(z.string()).optional(),
3151
- repo: z.string().transform(normalizeRepo).optional(),
3152
- is_global: z.boolean().optional(),
3153
- tags: z.array(z.string().min(1)).min(1),
3154
- metadata: z.record(z.string(), z.any()).refine((value) => Object.keys(value).length > 0, {
3155
- message: "metadata must contain at least one key"
3156
- }),
3157
- agent: z.string().optional(),
3158
- model: z.string().optional(),
3159
- structured: z.boolean().default(false)
3160
- }).refine((data) => data.is_global !== false || !!data.repo, {
3161
- message: "repo is required for repo-specific standards"
3162
- });
3163
- var StandardUpdateSchema = z.object({
3164
- id: z.string().uuid(),
3165
- name: z.string().min(3).max(255).optional(),
3166
- content: z.string().min(10).optional(),
3167
- parent_id: z.string().uuid().nullable().optional(),
3168
- context: z.string().optional(),
3169
- version: z.string().optional(),
3170
- language: z.string().optional(),
3171
- stack: z.array(z.string().min(1)).min(1).optional(),
3172
- repo: z.string().transform(normalizeRepo).optional(),
3173
- is_global: z.boolean().optional(),
3174
- tags: z.array(z.string().min(1)).min(1).optional(),
3175
- metadata: z.record(z.string(), z.any()).refine((value) => Object.keys(value).length > 0, { message: "metadata must contain at least one key" }).optional(),
3176
- agent: z.string().optional(),
3177
- model: z.string().optional(),
3178
- structured: z.boolean().default(false)
3179
- }).refine(
3180
- (data) => data.name !== void 0 || data.content !== void 0 || data.parent_id !== void 0 || data.context !== void 0 || data.version !== void 0 || data.language !== void 0 || data.stack !== void 0 || data.repo !== void 0 || data.is_global !== void 0 || data.tags !== void 0 || data.metadata !== void 0 || data.agent !== void 0 || data.model !== void 0,
3181
- { message: "At least one field must be provided for update" }
3182
- ).refine((data) => data.is_global !== false || !!data.repo, {
3183
- message: "repo is required for repo-specific standards"
3184
- });
3185
- var StandardSearchSchema = z.object({
3186
- query: z.string().optional(),
3187
- stack: z.array(z.string()).optional(),
3188
- tags: z.array(z.string()).optional(),
3189
- language: z.string().optional(),
3190
- context: z.string().optional(),
3191
- version: z.string().optional(),
3192
- repo: z.string().transform(normalizeRepo).optional(),
3193
- is_global: z.boolean().optional(),
3194
- limit: z.number().min(1).max(100).default(20),
3195
- offset: z.number().min(0).default(0),
3196
- structured: z.boolean().default(false)
3197
- });
3198
- var TOOL_DEFINITIONS = [
3199
- {
3200
- name: "memory-synthesize",
3201
- title: "Memory Synthesize",
3202
- description: "Use client sampling to synthesize a grounded answer from local memory and tasks. Best for project briefings, tradeoff summaries, and context-aware answers.",
3203
- annotations: {
3204
- readOnlyHint: true,
3205
- idempotentHint: true,
3206
- openWorldHint: false
2902
+ // src/mcp/utils/completion.ts
2903
+ var MAX_COMPLETION_VALUES = 100;
2904
+ function rankCompletionValues(candidates, input) {
2905
+ const unique = [...new Set(candidates.filter(Boolean))];
2906
+ const needle = input.trim().toLowerCase();
2907
+ if (!needle) {
2908
+ return unique.slice(0, MAX_COMPLETION_VALUES);
2909
+ }
2910
+ return unique.map((value) => ({ value, score: scoreCompletionValue(value, needle) })).filter((entry) => entry.score > 0).sort((a, b) => b.score - a.score || a.value.localeCompare(b.value)).map((entry) => entry.value);
2911
+ }
2912
+ function scoreCompletionValue(value, needle) {
2913
+ const haystack = value.toLowerCase();
2914
+ if (haystack === needle) return 100;
2915
+ if (haystack.startsWith(needle)) return 75;
2916
+ if (haystack.includes(needle)) return 50;
2917
+ const compactNeedle = needle.replace(/[\s_-]+/g, "");
2918
+ const compactHaystack = haystack.replace(/[\s_-]+/g, "");
2919
+ if (compactNeedle && compactHaystack.includes(compactNeedle)) return 25;
2920
+ return 0;
2921
+ }
2922
+
2923
+ // src/mcp/resources/index.ts
2924
+ var DEFAULT_PAGE_SIZE = 25;
2925
+ var MAX_PAGE_SIZE = 100;
2926
+ function listResources(session, params) {
2927
+ const resources = [
2928
+ {
2929
+ uri: "repository://index",
2930
+ name: "Repository Index",
2931
+ title: "Repository Index",
2932
+ description: "List of all known repositories with memory/task counts and last activity",
2933
+ mimeType: "application/json",
2934
+ annotations: {
2935
+ audience: ["assistant"],
2936
+ priority: 1,
2937
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
2938
+ }
3207
2939
  },
3208
- execution: {
3209
- taskSupport: "optional"
2940
+ {
2941
+ uri: "session://roots",
2942
+ name: "Session Roots",
2943
+ title: "Session Roots",
2944
+ description: session?.roots.length ? "Active workspace roots provided by the MCP client" : "No active workspace roots were provided by the MCP client",
2945
+ mimeType: "application/json",
2946
+ size: Buffer.byteLength(JSON.stringify({ roots: session?.roots ?? [] }), "utf8"),
2947
+ annotations: {
2948
+ audience: ["assistant"],
2949
+ priority: 0.95,
2950
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
2951
+ }
2952
+ }
2953
+ ];
2954
+ return paginateEntries("resources", resources, params);
2955
+ }
2956
+ function listResourceTemplates(params) {
2957
+ const templates = [
2958
+ // ── Memory ──────────────────────────────────────────────────────────────
2959
+ {
2960
+ uriTemplate: "repository://{name}/memories",
2961
+ name: "Repository Memories",
2962
+ title: "Repository Memories",
2963
+ description: "All active memory entries for a specific repository",
2964
+ mimeType: "application/json",
2965
+ annotations: { audience: ["assistant"], priority: 0.85 }
3210
2966
  },
3211
- inputSchema: {
3212
- type: "object",
3213
- properties: {
3214
- repo: { type: "string", description: "Repository name. Optional when a single MCP root is active." },
3215
- objective: { type: "string", minLength: 5, description: "Question or synthesis objective." },
3216
- current_file_path: {
3217
- type: "string",
3218
- description: "Optional absolute file path for workspace-local grounding."
3219
- },
3220
- include_summary: { type: "boolean", default: true },
3221
- include_tasks: { type: "boolean", default: true },
3222
- use_tools: {
3223
- type: "boolean",
3224
- default: true,
3225
- description: "Allow the sampled model to call local memory/task tools during synthesis when the client supports sampling.tools."
3226
- },
3227
- max_iterations: { type: "number", minimum: 1, maximum: 5, default: 3 },
3228
- max_tokens: { type: "number", minimum: 128, maximum: 4e3, default: 1200 },
3229
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON results." }
3230
- },
3231
- required: ["objective"]
2967
+ {
2968
+ uriTemplate: "repository://{name}/memories?search={search}&type={type}&tag={tag}",
2969
+ name: "Filtered Repository Memories",
2970
+ title: "Filtered Repository Memories",
2971
+ description: "Filter or search memories within a repository by keyword, type, or tag",
2972
+ mimeType: "application/json",
2973
+ annotations: { audience: ["assistant"], priority: 0.8 }
3232
2974
  },
3233
- outputSchema: {
3234
- type: "object",
3235
- properties: {
3236
- repo: { type: "string" },
3237
- objective: { type: "string" },
3238
- answer: { type: "string" },
3239
- model: { type: "string" },
3240
- stopReason: { type: "string" },
3241
- iterations: { type: "number" },
3242
- toolCalls: { type: "number" }
3243
- },
3244
- required: ["repo", "objective", "answer", "iterations", "toolCalls"]
3245
- }
3246
- },
3247
- {
3248
- name: "task-create-interactive",
3249
- title: "Interactive Task Create",
3250
- description: "Create a task with MCP elicitation fallback for any missing required fields. Best when an agent knows a task is needed but still needs user confirmation for repo, title, or phase.",
3251
- annotations: {
3252
- readOnlyHint: false,
3253
- idempotentHint: false,
3254
- destructiveHint: false,
3255
- openWorldHint: false
2975
+ {
2976
+ uriTemplate: "memory://{id}",
2977
+ name: "Memory Detail",
2978
+ title: "Memory Detail",
2979
+ description: "Full content and statistics for a specific memory UUID",
2980
+ mimeType: "application/json",
2981
+ annotations: { audience: ["assistant"], priority: 0.75 }
3256
2982
  },
3257
- inputSchema: {
3258
- type: "object",
3259
- properties: {
3260
- repo: {
3261
- type: "string",
3262
- description: "Repository name. Optional when it can be inferred from MCP roots or elicited from the user."
3263
- },
3264
- task_code: { type: "string" },
3265
- phase: { type: "string" },
3266
- title: { type: "string", minLength: 3, maxLength: 100 },
3267
- description: { type: "string", minLength: 1 },
3268
- status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
3269
- priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
3270
- agent: { type: "string" },
3271
- role: { type: "string" },
3272
- doc_path: { type: "string" },
3273
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
3274
- }
2983
+ // ── Tasks ────────────────────────────────────────────────────────────────
2984
+ {
2985
+ uriTemplate: "repository://{name}/tasks",
2986
+ name: "Repository Tasks",
2987
+ title: "Repository Tasks",
2988
+ description: "All active tasks for a specific repository",
2989
+ mimeType: "application/json",
2990
+ annotations: { audience: ["assistant"], priority: 0.9 }
3275
2991
  },
3276
- outputSchema: {
3277
- type: "object",
3278
- properties: {
3279
- repo: { type: "string" },
3280
- task_code: { type: "string" },
3281
- phase: { type: "string" },
3282
- title: { type: "string" },
3283
- status: { type: "string" },
3284
- priority: { type: "number" }
3285
- },
3286
- required: ["repo", "task_code", "phase", "title", "status", "priority"]
3287
- }
3288
- },
3289
- {
3290
- name: "memory-detail",
3291
- title: "Memory Detail",
3292
- description: "Fetch full details of a specific memory by ID or short code. Use after memory-recap or memory-search when a pointer row is relevant and full content is needed.",
3293
- inputSchema: {
3294
- type: "object",
3295
- properties: {
3296
- id: { type: "string", format: "uuid", description: "Memory entry ID. Optional if code is provided." },
3297
- code: { type: "string", description: "Short memory code. Optional if id is provided." },
3298
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON details." }
3299
- }
3300
- }
3301
- },
3302
- {
3303
- name: "standard-detail",
3304
- title: "Standard Detail",
3305
- description: "Fetch full details of a specific coding standard by ID. Use after standard-search when a result is relevant and full guidance is needed.",
3306
- inputSchema: {
3307
- type: "object",
3308
- properties: {
3309
- id: { type: "string", format: "uuid", description: "Coding standard ID." },
3310
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON details." }
3311
- },
3312
- required: ["id"]
3313
- }
3314
- },
3315
- {
3316
- name: "task-detail",
3317
- title: "Task Detail",
3318
- description: "Fetch full details of a specific task by ID or task code. Use this when you have a task ID or code and need to read the full description and comments.",
3319
- inputSchema: {
3320
- type: "object",
3321
- properties: {
3322
- repo: { type: "string", description: "Repository name" },
3323
- id: { type: "string", format: "uuid", description: "Task ID (optional if task_code is provided)" },
3324
- task_code: { type: "string", description: "Task code (e.g. TASK-001) (optional if id is provided)" },
3325
- structured: {
3326
- type: "boolean",
3327
- default: false,
3328
- description: "If true, returns structured JSON without the text content details."
3329
- }
3330
- },
3331
- required: ["repo"]
3332
- }
3333
- },
3334
- {
3335
- name: "memory-store",
3336
- title: "Memory Store",
3337
- description: "Store a new durable knowledge entry. Do not store coordination state here: task claims, file claims, agent registration, and handoffs belong to task-claim, task-update, and handoff-* tools. Keep 'title' concise and human-readable; put auxiliary context into 'metadata'.",
3338
- annotations: {
3339
- readOnlyHint: false,
3340
- idempotentHint: false,
3341
- destructiveHint: false,
3342
- openWorldHint: false
2992
+ {
2993
+ uriTemplate: "repository://{name}/tasks?status={status}&priority={priority}",
2994
+ name: "Filtered Repository Tasks",
2995
+ title: "Filtered Repository Tasks",
2996
+ description: "Filter tasks within a repository by status or priority level",
2997
+ mimeType: "application/json",
2998
+ annotations: { audience: ["assistant"], priority: 0.85 }
3343
2999
  },
3344
- inputSchema: {
3345
- type: "object",
3346
- properties: {
3347
- type: {
3348
- type: "string",
3349
- enum: [
3350
- "code_fact",
3351
- "decision",
3352
- "mistake",
3353
- "pattern",
3354
- "task_archive"
3355
- ],
3356
- description: "Type of durable knowledge being stored. Coordination types such as file_claim are intentionally unsupported."
3357
- },
3358
- title: {
3359
- type: "string",
3360
- minLength: 3,
3361
- maxLength: 100,
3362
- description: "Short human-readable title for the memory. Do not embed bracketed metadata like agent/role/date prefixes here."
3363
- },
3364
- content: {
3365
- type: "string",
3366
- minLength: 10,
3367
- description: "The memory content"
3368
- },
3369
- importance: {
3370
- type: "number",
3371
- minimum: 1,
3372
- maximum: 5,
3373
- description: "Importance score (1-5)"
3374
- },
3375
- agent: {
3376
- type: "string",
3377
- description: "Name of the agent creating this memory"
3378
- },
3379
- role: {
3380
- type: "string",
3381
- description: "Role of the agent creating this memory"
3382
- },
3383
- model: {
3384
- type: "string",
3385
- description: "AI model used by the agent"
3386
- },
3387
- scope: {
3388
- type: "object",
3389
- properties: {
3390
- repo: { type: "string", description: "Repository name" },
3391
- branch: { type: "string" },
3392
- folder: { type: "string" },
3393
- language: { type: "string" }
3394
- },
3395
- required: ["repo"]
3396
- },
3397
- tags: {
3398
- type: "array",
3399
- items: { type: "string" },
3400
- description: "Technology stack tags (e.g., ['filament', 'laravel'])"
3401
- },
3402
- metadata: {
3403
- type: "object",
3404
- description: "Structured metadata for non-title context such as source agent, claim fields, or timestamps"
3405
- },
3406
- is_global: {
3407
- type: "boolean",
3408
- description: "If true, this memory is shared across all repositories"
3409
- },
3410
- ttlDays: { type: "number", minimum: 1 },
3411
- supersedes: { type: "string", format: "uuid" },
3412
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the stored memory." }
3413
- },
3414
- required: ["type", "title", "content", "importance", "scope", "agent", "model"]
3000
+ {
3001
+ uriTemplate: "task://{id}",
3002
+ name: "Task Detail",
3003
+ title: "Task Detail",
3004
+ description: "Full content and comments for a specific task UUID",
3005
+ mimeType: "application/json",
3006
+ annotations: { audience: ["assistant"], priority: 0.8 }
3415
3007
  },
3416
- outputSchema: {
3417
- type: "object",
3418
- properties: {
3419
- success: { type: "boolean" },
3420
- id: { type: "string" },
3421
- code: { type: "string" },
3422
- repo: { type: "string" },
3423
- type: { type: "string" },
3424
- title: { type: "string" },
3425
- error: { type: "string" },
3426
- message: { type: "string" }
3427
- },
3428
- required: ["success"]
3429
- }
3430
- },
3431
- {
3432
- name: "memory-acknowledge",
3433
- title: "Memory Acknowledge",
3434
- description: "Acknowledge the use of a memory or report its irrelevance/contradiction. Mandatory after using memory to generate code.",
3435
- annotations: {
3436
- readOnlyHint: false,
3437
- idempotentHint: false,
3438
- openWorldHint: false
3008
+ // ── Repository extras ────────────────────────────────────────────────────
3009
+ {
3010
+ uriTemplate: "repository://{name}/summary",
3011
+ name: "Repository Summary",
3012
+ title: "Repository Summary",
3013
+ description: "High-level architectural summary for a repository",
3014
+ mimeType: "text/plain",
3015
+ annotations: { audience: ["assistant"], priority: 0.95 }
3439
3016
  },
3440
- inputSchema: {
3441
- type: "object",
3442
- properties: {
3443
- memory_id: { type: "string", format: "uuid" },
3444
- status: { type: "string", enum: ["used", "irrelevant", "contradictory"] },
3445
- application_context: { type: "string", minLength: 10 },
3446
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
3447
- },
3448
- required: ["memory_id", "status"]
3017
+ {
3018
+ uriTemplate: "repository://{name}/actions",
3019
+ name: "Repository Actions",
3020
+ title: "Repository Actions",
3021
+ description: "Audit log of agent tool actions scoped to a repository",
3022
+ mimeType: "application/json",
3023
+ annotations: { audience: ["assistant"], priority: 0.6 }
3449
3024
  },
3450
- outputSchema: {
3451
- type: "object",
3452
- properties: {
3453
- success: { type: "boolean" },
3454
- id: { type: "string" },
3455
- status: { type: "string" }
3456
- },
3457
- required: ["success", "id", "status"]
3025
+ // ── Action detail ────────────────────────────────────────────────────────
3026
+ {
3027
+ uriTemplate: "action://{id}",
3028
+ name: "Action Detail",
3029
+ title: "Action Detail",
3030
+ description: "Full details of a specific audit log entry by integer ID",
3031
+ mimeType: "application/json",
3032
+ annotations: { audience: ["assistant"], priority: 0.55 }
3458
3033
  }
3459
- },
3460
- {
3461
- name: "memory-update",
3462
- title: "Memory Update",
3463
- description: "Update an existing memory entry. Keep 'title' concise and move agent/role/date or claim context into 'metadata' instead of the title.",
3464
- annotations: {
3465
- readOnlyHint: false,
3466
- idempotentHint: false,
3467
- destructiveHint: false,
3468
- openWorldHint: false
3469
- },
3470
- inputSchema: {
3471
- type: "object",
3472
- properties: {
3473
- id: { type: "string", format: "uuid" },
3474
- type: {
3475
- type: "string",
3476
- enum: [
3477
- "code_fact",
3478
- "decision",
3479
- "mistake",
3480
- "pattern",
3481
- "task_archive"
3482
- ]
3483
- },
3484
- title: { type: "string", minLength: 3, maxLength: 100 },
3485
- content: { type: "string", minLength: 10 },
3486
- importance: { type: "number", minimum: 1, maximum: 5 },
3487
- agent: { type: "string" },
3488
- role: { type: "string" },
3489
- status: { type: "string", enum: ["active", "archived"] },
3490
- supersedes: { type: "string", format: "uuid" },
3491
- tags: { type: "array", items: { type: "string" } },
3492
- metadata: { type: "object" },
3493
- is_global: { type: "boolean" },
3494
- completed_at: { type: "string" },
3495
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the updated memory." }
3496
- },
3497
- required: ["id"]
3498
- },
3499
- outputSchema: {
3500
- type: "object",
3501
- properties: {
3502
- success: { type: "boolean" },
3503
- id: { type: "string" },
3504
- repo: { type: "string" },
3505
- updatedFields: {
3506
- type: "array",
3507
- items: { type: "string" }
3508
- }
3509
- },
3510
- required: ["success", "id", "repo", "updatedFields"]
3034
+ ];
3035
+ return paginateEntries("resourceTemplates", templates, params);
3036
+ }
3037
+ function completeResourceArgument(resourceUri, argumentName, argumentValue, _contextArguments, dataSources) {
3038
+ if (resourceUri === "repository://{name}/memories" || resourceUri === "repository://{name}/memories?search={search}&type={type}&tag={tag}" || resourceUri === "repository://{name}/tasks" || resourceUri === "repository://{name}/tasks?status={status}&priority={priority}" || resourceUri === "repository://{name}/summary" || resourceUri === "repository://{name}/actions") {
3039
+ if (argumentName === "name") {
3040
+ return rankCompletionValues(dataSources.repos, argumentValue);
3511
3041
  }
3512
- },
3513
- {
3514
- name: "memory-search",
3515
- title: "Memory Search",
3516
- description: "NAVIGATION LAYER: Returns a pointer table of matching memory IDs only. Returns columns [id, title, type, importance] \u2014 NO content. Retrieve full memory via memory-detail. Use 'current_tags' to find tech-stack specific knowledge from other projects.",
3517
- annotations: {
3518
- readOnlyHint: true,
3519
- idempotentHint: true,
3520
- openWorldHint: false
3521
- },
3522
- inputSchema: {
3523
- type: "object",
3524
- properties: {
3525
- query: { type: "string", minLength: 3 },
3526
- prompt: { type: "string" },
3527
- repo: { type: "string" },
3528
- current_tags: {
3529
- type: "array",
3530
- items: { type: "string" },
3531
- description: "Active tech stack tags (e.g., ['filament', 'react'])"
3532
- },
3533
- types: {
3534
- type: "array",
3535
- items: {
3536
- type: "string",
3537
- enum: [
3538
- "code_fact",
3539
- "decision",
3540
- "mistake",
3541
- "pattern",
3542
- "task_archive"
3543
- ]
3042
+ }
3043
+ if (resourceUri === "repository://{name}/memories?search={search}&type={type}&tag={tag}") {
3044
+ if (argumentName === "tag") {
3045
+ return rankCompletionValues(dataSources.tags, argumentValue);
3046
+ }
3047
+ }
3048
+ throw invalidCompletionParams(`Unknown resource template or argument: ${resourceUri} (${argumentName})`);
3049
+ }
3050
+ function readResource(uri, db, session) {
3051
+ logger.info("[Tool] resource.read", { uri });
3052
+ if (uri === "repository://index") {
3053
+ const repos = db.system.listRepoNavigation();
3054
+ const payload = JSON.stringify(repos, null, 2);
3055
+ return {
3056
+ contents: [
3057
+ {
3058
+ uri,
3059
+ mimeType: "application/json",
3060
+ text: payload,
3061
+ size: Buffer.byteLength(payload, "utf8"),
3062
+ annotations: {
3063
+ audience: ["assistant"],
3064
+ priority: 1,
3065
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
3544
3066
  }
3545
- },
3546
- minImportance: { type: "number", minimum: 1, maximum: 5 },
3547
- limit: { type: "number", minimum: 1, maximum: 100, default: 5 },
3548
- offset: { type: "number", minimum: 0, default: 0 },
3549
- includeRecap: { type: "boolean", default: false },
3550
- current_file_path: { type: "string" },
3551
- include_archived: { type: "boolean", default: false },
3552
- scope: {
3553
- type: "object",
3554
- properties: {
3555
- repo: { type: "string" },
3556
- branch: { type: "string" },
3557
- folder: { type: "string" },
3558
- language: { type: "string" }
3067
+ }
3068
+ ]
3069
+ };
3070
+ }
3071
+ if (uri === "session://roots") {
3072
+ const payload = JSON.stringify({ roots: session?.roots ?? [] }, null, 2);
3073
+ return {
3074
+ contents: [
3075
+ {
3076
+ uri,
3077
+ mimeType: "application/json",
3078
+ text: payload,
3079
+ size: Buffer.byteLength(payload, "utf8"),
3080
+ annotations: {
3081
+ audience: ["assistant"],
3082
+ priority: 0.95,
3083
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
3559
3084
  }
3560
- },
3561
- structured: {
3562
- type: "boolean",
3563
- default: false,
3564
- description: "If true, returns structured JSON without the text content summary."
3565
3085
  }
3566
- },
3567
- required: ["query", "repo"]
3568
- },
3569
- outputSchema: {
3570
- type: "object",
3571
- properties: {
3572
- schema: { type: "string", enum: ["memory-search"] },
3573
- query: { type: "string" },
3574
- count: { type: "number", description: "Number of rows returned" },
3575
- total: { type: "number", description: "Total matching memories" },
3576
- offset: { type: "number" },
3577
- limit: { type: "number" },
3578
- results: {
3579
- type: "object",
3580
- properties: {
3581
- columns: {
3582
- type: "array",
3583
- items: { type: "string" },
3584
- description: "Column names: [id, title, type, importance]"
3585
- },
3586
- rows: {
3587
- type: "array",
3588
- items: { type: "array" },
3589
- description: "Each row: [id, title, type, importance]. Fetch full content via memory-detail"
3590
- }
3591
- },
3592
- required: ["columns", "rows"]
3086
+ ]
3087
+ };
3088
+ }
3089
+ const memoryIdMatch = uri.match(/^memory:\/\/([0-9a-f-]{36})$/i);
3090
+ if (memoryIdMatch) {
3091
+ const id = memoryIdMatch[1];
3092
+ const entry = db.memories.getByIdWithStats(id);
3093
+ if (!entry) throw resourceNotFound(`Memory with ID ${id} not found.`, uri);
3094
+ const payload = JSON.stringify(entry, null, 2);
3095
+ return {
3096
+ contents: [
3097
+ {
3098
+ uri,
3099
+ mimeType: "application/json",
3100
+ text: payload,
3101
+ size: Buffer.byteLength(payload, "utf8"),
3102
+ annotations: {
3103
+ audience: ["assistant"],
3104
+ priority: 0.75,
3105
+ lastModified: entry.updated_at || entry.created_at
3106
+ }
3593
3107
  }
3594
- },
3595
- required: ["schema", "query", "count", "total", "offset", "limit", "results"]
3596
- }
3597
- },
3598
- {
3599
- name: "memory-summarize",
3600
- title: "Memory Summarize",
3601
- description: "Update the summary for a repository",
3602
- annotations: {
3603
- readOnlyHint: false,
3604
- idempotentHint: false,
3605
- openWorldHint: false
3606
- },
3607
- inputSchema: {
3608
- type: "object",
3609
- properties: {
3610
- repo: { type: "string", description: "Repository name" },
3611
- signals: {
3612
- type: "array",
3613
- items: { type: "string", maxLength: 200 },
3614
- minItems: 1,
3615
- description: "High-level signals to include in summary"
3616
- },
3617
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the summary." }
3618
- },
3619
- required: ["repo", "signals"]
3620
- },
3621
- outputSchema: {
3622
- type: "object",
3623
- properties: {
3624
- success: { type: "boolean" },
3625
- repo: { type: "string" },
3626
- summary: { type: "string" },
3627
- signalCount: { type: "number" }
3628
- },
3629
- required: ["success", "repo", "summary", "signalCount"]
3108
+ ]
3109
+ };
3110
+ }
3111
+ const taskIdMatch = uri.match(/^task:\/\/([0-9a-f-]{36})$/i);
3112
+ if (taskIdMatch) {
3113
+ const id = taskIdMatch[1];
3114
+ const task = db.tasks.getTaskById(id);
3115
+ if (!task) throw resourceNotFound(`Task with ID ${id} not found.`, uri);
3116
+ const payload = JSON.stringify(task, null, 2);
3117
+ return {
3118
+ contents: [
3119
+ {
3120
+ uri,
3121
+ mimeType: "application/json",
3122
+ text: payload,
3123
+ size: Buffer.byteLength(payload, "utf8"),
3124
+ annotations: {
3125
+ audience: ["assistant"],
3126
+ priority: 0.8,
3127
+ lastModified: task.updated_at || task.created_at
3128
+ }
3129
+ }
3130
+ ]
3131
+ };
3132
+ }
3133
+ const repoBase = parseRepoUri(uri);
3134
+ if (repoBase) {
3135
+ const { name, path: repoPath, query } = repoBase;
3136
+ if (repoPath === "summary") {
3137
+ const summary = db.summaries.getSummary(name);
3138
+ const text = summary?.summary || `No summary available for repository: ${name}`;
3139
+ return {
3140
+ contents: [
3141
+ {
3142
+ uri,
3143
+ mimeType: "text/plain",
3144
+ text,
3145
+ size: Buffer.byteLength(text, "utf8"),
3146
+ annotations: {
3147
+ audience: ["assistant"],
3148
+ priority: 0.95,
3149
+ lastModified: summary?.updated_at || (/* @__PURE__ */ new Date()).toISOString()
3150
+ }
3151
+ }
3152
+ ]
3153
+ };
3630
3154
  }
3631
- },
3632
- {
3633
- name: "memory-delete",
3634
- title: "Memory Delete",
3635
- description: "Soft-delete one or more memory entries. Supports single 'id' or bulk 'ids'.",
3636
- annotations: {
3637
- readOnlyHint: false,
3638
- idempotentHint: false,
3639
- destructiveHint: true,
3640
- openWorldHint: false
3641
- },
3642
- inputSchema: {
3643
- type: "object",
3644
- properties: {
3645
- repo: { type: "string", description: "Repository name (optional for single id)" },
3646
- id: { type: "string", format: "uuid", description: "Memory entry ID to delete" },
3647
- ids: {
3648
- type: "array",
3649
- items: { type: "string", format: "uuid" },
3650
- minItems: 1,
3651
- description: "Array of memory IDs to delete"
3652
- },
3653
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
3155
+ if (repoPath === "memories") {
3156
+ const search = query.get("search") || "";
3157
+ const type = query.get("type");
3158
+ const tag = query.get("tag");
3159
+ const result = db.memories.listMemoriesForDashboard({
3160
+ repo: name,
3161
+ type: type || void 0,
3162
+ tag: tag || void 0,
3163
+ search: search || void 0,
3164
+ limit: 50
3165
+ });
3166
+ const entries = result.items;
3167
+ const payload = JSON.stringify(entries, null, 2);
3168
+ return {
3169
+ contents: [
3170
+ {
3171
+ uri,
3172
+ mimeType: "application/json",
3173
+ text: payload,
3174
+ size: Buffer.byteLength(payload, "utf8"),
3175
+ annotations: {
3176
+ audience: ["assistant"],
3177
+ priority: 0.85,
3178
+ lastModified: deriveLastModifiedFromCollection(
3179
+ entries.map((e) => e.updated_at || e.created_at)
3180
+ )
3181
+ }
3182
+ }
3183
+ ]
3184
+ };
3185
+ }
3186
+ if (repoPath === "tasks") {
3187
+ const status = query.get("status");
3188
+ const priority = query.get("priority");
3189
+ let tasks;
3190
+ if (status && status !== "all") {
3191
+ const statuses = status.split(",").map((s) => s.trim());
3192
+ tasks = db.tasks.getTasksByMultipleStatuses(name, statuses);
3193
+ } else {
3194
+ tasks = db.tasks.getTasksByMultipleStatuses(name, ["backlog", "pending", "in_progress", "blocked"]);
3654
3195
  }
3655
- },
3656
- outputSchema: {
3657
- type: "object",
3658
- properties: {
3659
- success: { type: "boolean" },
3660
- id: { type: "string" },
3661
- ids: { type: "array", items: { type: "string" } },
3662
- repo: { type: "string" },
3663
- deletedCount: { type: "number" }
3664
- },
3665
- required: ["success"]
3196
+ if (priority) {
3197
+ const p = Number(priority);
3198
+ if (!isNaN(p)) {
3199
+ tasks = tasks.filter((t) => t.priority === p);
3200
+ }
3201
+ }
3202
+ const payload = JSON.stringify(tasks, null, 2);
3203
+ return {
3204
+ contents: [
3205
+ {
3206
+ uri,
3207
+ mimeType: "application/json",
3208
+ text: payload,
3209
+ size: Buffer.byteLength(payload, "utf8"),
3210
+ annotations: {
3211
+ audience: ["assistant"],
3212
+ priority: 0.9,
3213
+ lastModified: deriveLastModifiedFromCollection(tasks.map((t) => t.updated_at))
3214
+ }
3215
+ }
3216
+ ]
3217
+ };
3666
3218
  }
3667
- },
3668
- {
3669
- name: "standard-delete",
3670
- title: "Standard Delete",
3671
- description: "Delete one or more coding standards. Supports single 'id' or bulk 'ids'.",
3672
- annotations: {
3673
- readOnlyHint: false,
3674
- idempotentHint: false,
3675
- destructiveHint: true,
3676
- openWorldHint: false
3677
- },
3678
- inputSchema: {
3679
- type: "object",
3680
- properties: {
3681
- repo: { type: "string", description: "Repository name (optional for single id)" },
3682
- id: { type: "string", format: "uuid", description: "Coding standard ID to delete" },
3683
- ids: {
3684
- type: "array",
3685
- items: { type: "string", format: "uuid" },
3686
- minItems: 1,
3687
- description: "Array of coding standard IDs to delete"
3688
- },
3689
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
3219
+ if (repoPath === "actions") {
3220
+ const actions = db.actions.getRecentActions(name, 100);
3221
+ const payload = JSON.stringify(actions, null, 2);
3222
+ return {
3223
+ contents: [
3224
+ {
3225
+ uri,
3226
+ mimeType: "application/json",
3227
+ text: payload,
3228
+ size: Buffer.byteLength(payload, "utf8"),
3229
+ annotations: {
3230
+ audience: ["assistant"],
3231
+ priority: 0.6,
3232
+ lastModified: deriveLastModifiedFromCollection(actions.map((a) => a.created_at))
3233
+ }
3234
+ }
3235
+ ]
3236
+ };
3237
+ }
3238
+ }
3239
+ const actionIdMatch = uri.match(/^action:\/\/(\d+)$/);
3240
+ if (actionIdMatch) {
3241
+ const id = Number(actionIdMatch[1]);
3242
+ const action = db.actions.getActionById(id);
3243
+ if (!action) throw resourceNotFound(`Action with ID ${id} not found.`, uri);
3244
+ const payload = JSON.stringify(action, null, 2);
3245
+ return {
3246
+ contents: [
3247
+ {
3248
+ uri,
3249
+ mimeType: "application/json",
3250
+ text: payload,
3251
+ size: Buffer.byteLength(payload, "utf8"),
3252
+ annotations: {
3253
+ audience: ["assistant"],
3254
+ priority: 0.55,
3255
+ lastModified: action.created_at
3256
+ }
3257
+ }
3258
+ ]
3259
+ };
3260
+ }
3261
+ throw resourceNotFound(`Unknown resource URI: ${uri}`, uri);
3262
+ }
3263
+ function parseRepoUri(uri) {
3264
+ const prefix = "repository://";
3265
+ if (!uri.startsWith(prefix)) return null;
3266
+ const rest = uri.slice(prefix.length);
3267
+ const queryStart = rest.indexOf("?");
3268
+ const withoutQuery = queryStart === -1 ? rest : rest.slice(0, queryStart);
3269
+ const queryString = queryStart === -1 ? "" : rest.slice(queryStart + 1);
3270
+ const slashIdx = withoutQuery.indexOf("/");
3271
+ if (slashIdx === -1) return null;
3272
+ const name = withoutQuery.slice(0, slashIdx);
3273
+ const path6 = withoutQuery.slice(slashIdx + 1);
3274
+ if (!name || !path6) return null;
3275
+ return { name, path: path6, query: new URLSearchParams(queryString) };
3276
+ }
3277
+ function paginateEntries(key, entries, params) {
3278
+ const limit = normalizeLimit(params?.limit);
3279
+ const offset = decodeCursor(params?.cursor);
3280
+ const sliced = entries.slice(offset, offset + limit);
3281
+ const nextOffset = offset + sliced.length;
3282
+ return {
3283
+ [key]: sliced,
3284
+ nextCursor: nextOffset < entries.length ? encodeCursor(nextOffset) : void 0
3285
+ };
3286
+ }
3287
+ function normalizeLimit(limit) {
3288
+ if (typeof limit !== "number" || !Number.isFinite(limit)) {
3289
+ return DEFAULT_PAGE_SIZE;
3290
+ }
3291
+ return Math.min(MAX_PAGE_SIZE, Math.max(1, Math.trunc(limit)));
3292
+ }
3293
+ function deriveLastModifiedFromCollection(values) {
3294
+ const normalized = values.filter((value) => typeof value === "string" && value.length > 0);
3295
+ return normalized.sort().at(-1) ?? (/* @__PURE__ */ new Date()).toISOString();
3296
+ }
3297
+ function resourceNotFound(message, uri) {
3298
+ const error = new Error(message);
3299
+ error.code = -32002;
3300
+ error.data = { uri };
3301
+ return error;
3302
+ }
3303
+ function invalidCompletionParams(message) {
3304
+ const error = new Error(message);
3305
+ error.code = -32602;
3306
+ return error;
3307
+ }
3308
+
3309
+ // src/mcp/prompts/loader.ts
3310
+ import fs4 from "fs";
3311
+ import path5 from "path";
3312
+ import { fileURLToPath as fileURLToPath3 } from "url";
3313
+ import matter from "gray-matter";
3314
+ var __filename = fileURLToPath3(import.meta.url);
3315
+ var __dirname2 = path5.dirname(__filename);
3316
+ function findPromptDir() {
3317
+ const candidates = [
3318
+ // Production if chunked into dist/
3319
+ "./prompts",
3320
+ // Production if inlined into dist/mcp/
3321
+ "../prompts",
3322
+ // Dev: /src/mcp/prompts/definitions (next to loader.ts)
3323
+ "./definitions"
3324
+ ].map((relPath) => path5.resolve(__dirname2, relPath));
3325
+ for (const dir of candidates) {
3326
+ if (fs4.existsSync(dir)) {
3327
+ const files = fs4.readdirSync(dir);
3328
+ if (files.some((f) => f.endsWith(".md"))) {
3329
+ return dir;
3690
3330
  }
3691
- },
3692
- outputSchema: {
3693
- type: "object",
3694
- properties: {
3695
- success: { type: "boolean" },
3696
- id: { type: "string" },
3697
- ids: { type: "array", items: { type: "string" } },
3698
- repo: { type: "string" },
3699
- deletedCount: { type: "number" }
3700
- },
3701
- required: ["success"]
3702
3331
  }
3703
- },
3332
+ }
3333
+ return path5.resolve(__dirname2, "./definitions");
3334
+ }
3335
+ var PROMPT_DIR = findPromptDir();
3336
+ function listPromptFiles() {
3337
+ if (!fs4.existsSync(PROMPT_DIR)) return [];
3338
+ return fs4.readdirSync(PROMPT_DIR).filter((file) => file.endsWith(".md")).map((file) => file.replace(/\.md$/, "")).sort();
3339
+ }
3340
+ function loadPromptFromMarkdown(name) {
3341
+ const filePath = path5.join(PROMPT_DIR, `${name}.md`);
3342
+ if (!fs4.existsSync(filePath)) {
3343
+ throw new Error(`Prompt file not found: ${filePath}`);
3344
+ }
3345
+ const fileContent = fs4.readFileSync(filePath, "utf-8");
3346
+ const { data, content } = matter(fileContent);
3347
+ return {
3348
+ name: data.name || name,
3349
+ description: data.description || "",
3350
+ arguments: data.arguments || [],
3351
+ agent: data.agent,
3352
+ content: content.trim()
3353
+ };
3354
+ }
3355
+
3356
+ // src/mcp/prompts/registry.ts
3357
+ function createPromptDefinition(loaded) {
3358
+ return {
3359
+ name: loaded.name,
3360
+ description: loaded.description,
3361
+ arguments: loaded.arguments,
3362
+ agent: loaded.agent,
3363
+ messages: [
3364
+ {
3365
+ role: "user",
3366
+ content: {
3367
+ type: "text",
3368
+ text: loaded.content
3369
+ }
3370
+ }
3371
+ ]
3372
+ };
3373
+ }
3374
+ var PROMPTS = {};
3375
+ var promptFiles = listPromptFiles();
3376
+ for (const name of promptFiles) {
3377
+ try {
3378
+ PROMPTS[name] = createPromptDefinition(loadPromptFromMarkdown(name));
3379
+ } catch (e) {
3380
+ logger.warn(`Failed to load prompt ${name}: ${e}`);
3381
+ }
3382
+ }
3383
+ async function listPrompts(db, session, params) {
3384
+ const allPrompts = Object.values(PROMPTS).map((p) => ({
3385
+ name: p.name,
3386
+ description: p.description,
3387
+ arguments: p.arguments,
3388
+ metadata: p.agent ? { agent: p.agent } : void 0
3389
+ }));
3390
+ const rawLimit = typeof params?.limit === "number" && Number.isInteger(params?.limit) ? params.limit : 25;
3391
+ const limit = Math.max(1, Math.min(100, Math.trunc(rawLimit)));
3392
+ const offset = decodeCursor(params?.cursor);
3393
+ const sliced = allPrompts.slice(offset, offset + limit);
3394
+ const nextOffset = offset + sliced.length;
3395
+ return {
3396
+ prompts: sliced,
3397
+ nextCursor: nextOffset < allPrompts.length ? encodeCursor(nextOffset) : void 0
3398
+ };
3399
+ }
3400
+ async function getPrompt(name, args = {}, db, session) {
3401
+ const prompt = PROMPTS[name];
3402
+ if (!prompt) {
3403
+ throw new Error(`Prompt not found: ${name}`);
3404
+ }
3405
+ const inferredRepo = inferRepoFromSession(session);
3406
+ const messages = prompt.messages.map((m) => {
3407
+ let text = m.content.text;
3408
+ for (const [key, value] of Object.entries(args)) {
3409
+ text = text.replace(new RegExp(`\\{{${key}\\}}`, "g"), value);
3410
+ }
3411
+ text = text.replace(/{{current_repo}}/g, inferredRepo || "unknown-repo");
3412
+ return {
3413
+ ...m,
3414
+ content: {
3415
+ ...m.content,
3416
+ text
3417
+ }
3418
+ };
3419
+ });
3420
+ return {
3421
+ description: prompt.description,
3422
+ messages,
3423
+ metadata: prompt.agent ? { agent: prompt.agent } : void 0
3424
+ };
3425
+ }
3426
+ async function completePromptArgument(name, argName, value, contextArguments, dataSources) {
3427
+ void name;
3428
+ void contextArguments;
3429
+ if (argName === "task_id") {
3430
+ const values = dataSources.tasks.map((t) => t.id);
3431
+ return rankCompletionValues(values, value);
3432
+ }
3433
+ return [];
3434
+ }
3435
+
3436
+ // src/mcp/tools/schemas.ts
3437
+ import { z } from "zod";
3438
+ var MemoryScopeSchema = z.object({
3439
+ repo: z.string().min(1).transform(normalizeRepo),
3440
+ branch: z.string().optional(),
3441
+ folder: z.string().optional(),
3442
+ language: z.string().optional()
3443
+ });
3444
+ var MemoryTypeSchema = z.enum([
3445
+ "code_fact",
3446
+ "decision",
3447
+ "mistake",
3448
+ "pattern",
3449
+ "task_archive"
3450
+ ]);
3451
+ var MemoryStoreSchema = z.object({
3452
+ code: z.string().max(20).optional(),
3453
+ type: MemoryTypeSchema,
3454
+ title: z.string().min(3).max(255),
3455
+ content: z.string().min(10),
3456
+ importance: z.number().min(1).max(5),
3457
+ agent: z.string().min(1),
3458
+ role: z.string().optional().default("unknown"),
3459
+ model: z.string().min(1),
3460
+ scope: MemoryScopeSchema,
3461
+ ttlDays: z.number().min(1).optional(),
3462
+ supersedes: z.string().uuid().optional(),
3463
+ tags: z.array(z.string()).optional(),
3464
+ metadata: z.record(z.string(), z.any()).optional(),
3465
+ is_global: z.boolean().default(false),
3466
+ structured: z.boolean().default(false)
3467
+ });
3468
+ var MemoryUpdateSchema = z.object({
3469
+ id: z.string().uuid(),
3470
+ type: MemoryTypeSchema.optional(),
3471
+ title: z.string().min(3).max(255).optional(),
3472
+ content: z.string().min(10).optional(),
3473
+ importance: z.number().min(1).max(5).optional(),
3474
+ agent: z.string().optional(),
3475
+ role: z.string().optional(),
3476
+ status: z.enum(["active", "archived"]).optional(),
3477
+ supersedes: z.string().uuid().optional(),
3478
+ tags: z.array(z.string()).optional(),
3479
+ metadata: z.record(z.string(), z.any()).optional(),
3480
+ is_global: z.boolean().optional(),
3481
+ completed_at: z.string().optional(),
3482
+ structured: z.boolean().default(false)
3483
+ }).refine(
3484
+ (data) => data.type !== void 0 || data.content !== void 0 || data.title !== void 0 || data.importance !== void 0 || data.status !== void 0 || data.supersedes !== void 0 || data.tags !== void 0 || data.metadata !== void 0 || data.is_global !== void 0 || data.agent !== void 0 || data.role !== void 0 || data.completed_at !== void 0,
3485
+ { message: "At least one field must be provided for update" }
3486
+ );
3487
+ var MemorySearchSchema = z.object({
3488
+ query: z.string().min(3),
3489
+ prompt: z.string().optional(),
3490
+ repo: z.string().min(1).transform(normalizeRepo),
3491
+ types: z.array(MemoryTypeSchema).optional(),
3492
+ minImportance: z.number().min(1).max(5).optional(),
3493
+ limit: z.number().min(1).max(100).default(5),
3494
+ offset: z.number().min(0).default(0),
3495
+ includeRecap: z.boolean().default(false),
3496
+ current_file_path: z.string().optional(),
3497
+ include_archived: z.boolean().default(false),
3498
+ current_tags: z.array(z.string()).optional(),
3499
+ scope: MemoryScopeSchema.partial().optional(),
3500
+ structured: z.boolean().default(false)
3501
+ });
3502
+ var MemoryAcknowledgeSchema = z.object({
3503
+ memory_id: z.string().uuid(),
3504
+ status: z.enum(["used", "irrelevant", "contradictory"]),
3505
+ application_context: z.string().min(10).optional(),
3506
+ structured: z.boolean().default(false)
3507
+ });
3508
+ var MemoryRecapSchema = z.object({
3509
+ repo: z.string().min(1).transform(normalizeRepo),
3510
+ limit: z.number().min(1).max(50).default(20),
3511
+ offset: z.number().min(0).default(0),
3512
+ structured: z.boolean().default(false)
3513
+ });
3514
+ var MemoryDeleteSchema = z.object({
3515
+ repo: z.string().min(1).transform(normalizeRepo).optional(),
3516
+ id: z.string().uuid().optional(),
3517
+ ids: z.array(z.string().uuid()).min(1).optional(),
3518
+ structured: z.boolean().default(false)
3519
+ }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3520
+ message: "Either 'id' or 'ids' must be provided for deletion"
3521
+ });
3522
+ var MemorySummarizeSchema = z.object({
3523
+ repo: z.string().min(1).transform(normalizeRepo),
3524
+ signals: z.array(z.string().max(200)).min(1),
3525
+ structured: z.boolean().default(false)
3526
+ });
3527
+ var MemorySynthesizeSchema = z.object({
3528
+ repo: z.string().min(1).transform(normalizeRepo).optional(),
3529
+ objective: z.string().min(5),
3530
+ current_file_path: z.string().optional(),
3531
+ include_summary: z.boolean().default(true),
3532
+ include_tasks: z.boolean().default(true),
3533
+ use_tools: z.boolean().default(true),
3534
+ max_iterations: z.number().int().min(1).max(5).default(3),
3535
+ max_tokens: z.number().int().min(128).max(4e3).default(1200),
3536
+ structured: z.boolean().default(false)
3537
+ });
3538
+ var TaskStatusSchema = z.enum(["backlog", "pending", "in_progress", "completed", "canceled", "blocked"]);
3539
+ var TaskPrioritySchema = z.number().min(1).max(5);
3540
+ var SingleTaskCreateSchema = z.object({
3541
+ task_code: z.string().min(1),
3542
+ phase: z.string().min(1),
3543
+ title: z.string().min(3).max(100),
3544
+ description: z.string().min(1),
3545
+ status: TaskStatusSchema.default("backlog"),
3546
+ priority: TaskPrioritySchema.default(3),
3547
+ agent: z.string().optional(),
3548
+ role: z.string().optional(),
3549
+ doc_path: z.string().optional(),
3550
+ tags: z.array(z.string()).optional(),
3551
+ metadata: z.record(z.string(), z.any()).optional(),
3552
+ parent_id: z.string().uuid().optional(),
3553
+ depends_on: z.string().uuid().optional(),
3554
+ est_tokens: z.number().int().min(0).optional()
3555
+ });
3556
+ var TaskCreateSchema = z.object({
3557
+ repo: z.string().min(1).transform(normalizeRepo),
3558
+ // Allow single task fields at top level (backward compatibility & single use)
3559
+ task_code: z.string().min(1).optional(),
3560
+ phase: z.string().min(1).optional(),
3561
+ title: z.string().min(3).max(100).optional(),
3562
+ description: z.string().min(1).optional(),
3563
+ status: TaskStatusSchema.optional(),
3564
+ priority: TaskPrioritySchema.optional(),
3565
+ agent: z.string().optional(),
3566
+ role: z.string().optional(),
3567
+ doc_path: z.string().optional(),
3568
+ tags: z.array(z.string()).optional(),
3569
+ metadata: z.record(z.string(), z.any()).optional(),
3570
+ parent_id: z.string().uuid().optional(),
3571
+ depends_on: z.string().uuid().optional(),
3572
+ est_tokens: z.number().int().min(0).optional(),
3573
+ // Allow bulk tasks
3574
+ tasks: z.array(SingleTaskCreateSchema).min(1).optional(),
3575
+ structured: z.boolean().default(false)
3576
+ }).refine(
3577
+ (data) => {
3578
+ if (data.tasks) return true;
3579
+ return !!(data.task_code && data.phase && data.title && data.description);
3580
+ },
3581
+ { message: "Either 'tasks' array or single task fields (task_code, phase, title, description) must be provided" }
3582
+ );
3583
+ var TaskCreateInteractiveSchema = SingleTaskCreateSchema.partial().extend({
3584
+ repo: z.string().min(1).transform(normalizeRepo).optional(),
3585
+ structured: z.boolean().default(false)
3586
+ });
3587
+ var TaskUpdateSchema = z.object({
3588
+ repo: z.string().min(1).transform(normalizeRepo),
3589
+ id: z.string().uuid().optional(),
3590
+ ids: z.array(z.string().uuid()).min(1).optional(),
3591
+ task_code: z.string().optional(),
3592
+ phase: z.string().optional(),
3593
+ title: z.string().min(3).max(100).optional(),
3594
+ description: z.string().optional(),
3595
+ status: TaskStatusSchema.optional(),
3596
+ priority: TaskPrioritySchema.optional(),
3597
+ agent: z.string().min(1, "agent name is required").optional(),
3598
+ role: z.string().min(1, "agent role is required").optional(),
3599
+ model: z.string().optional(),
3600
+ comment: z.string().min(1).optional(),
3601
+ doc_path: z.string().optional(),
3602
+ tags: z.array(z.string()).optional(),
3603
+ metadata: z.record(z.string(), z.any()).optional(),
3604
+ parent_id: z.string().uuid().optional(),
3605
+ depends_on: z.string().uuid().optional(),
3606
+ est_tokens: z.number().int().min(0).optional(),
3607
+ force: z.boolean().optional(),
3608
+ structured: z.boolean().default(false)
3609
+ }).refine((data) => data.id !== void 0 || data.ids !== void 0 || data.task_code !== void 0, {
3610
+ message: "Either 'id', 'ids', or 'task_code' must be provided for update"
3611
+ }).refine((data) => Object.keys(data).length > 2, {
3612
+ message: "At least one field besides repo and id/ids must be provided for update"
3613
+ });
3614
+ var TaskListSchema = z.object({
3615
+ repo: z.string().min(1).transform(normalizeRepo),
3616
+ status: z.string().optional(),
3617
+ phase: z.string().optional(),
3618
+ query: z.string().optional(),
3619
+ limit: z.number().min(1).max(100).default(15),
3620
+ offset: z.number().min(0).default(0),
3621
+ structured: z.boolean().default(false)
3622
+ });
3623
+ var TaskSearchSchema = z.object({
3624
+ repo: z.string().min(1).transform(normalizeRepo),
3625
+ query: z.string().min(1),
3626
+ status: z.string().optional(),
3627
+ limit: z.number().min(1).max(100).default(10),
3628
+ offset: z.number().min(0).default(0),
3629
+ structured: z.boolean().default(false)
3630
+ });
3631
+ var TaskDeleteSchema = z.object({
3632
+ repo: z.string().min(1).transform(normalizeRepo),
3633
+ id: z.string().uuid().optional(),
3634
+ ids: z.array(z.string().uuid()).min(1).optional(),
3635
+ structured: z.boolean().default(false)
3636
+ }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3637
+ message: "Either 'id' or 'ids' must be provided for deletion"
3638
+ });
3639
+ var MemoryDetailSchema = z.object({
3640
+ id: z.string().uuid().optional(),
3641
+ code: z.string().max(20).optional(),
3642
+ structured: z.boolean().default(false)
3643
+ }).refine((data) => data.id !== void 0 || data.code !== void 0, {
3644
+ message: "Either id or code must be provided"
3645
+ });
3646
+ var StandardDetailSchema = z.object({
3647
+ id: z.string().uuid(),
3648
+ structured: z.boolean().default(false)
3649
+ });
3650
+ var StandardDeleteSchema = z.object({
3651
+ repo: z.string().min(1).transform(normalizeRepo).optional(),
3652
+ id: z.string().uuid().optional(),
3653
+ ids: z.array(z.string().uuid()).min(1).optional(),
3654
+ structured: z.boolean().default(false)
3655
+ }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3656
+ message: "Either 'id' or 'ids' must be provided for deletion"
3657
+ });
3658
+ var TaskGetSchema = z.object({
3659
+ repo: z.string().min(1).transform(normalizeRepo),
3660
+ id: z.string().uuid().optional(),
3661
+ task_code: z.string().optional(),
3662
+ structured: z.boolean().default(false)
3663
+ }).refine((data) => data.id !== void 0 || data.task_code !== void 0, {
3664
+ message: "Either id or task_code must be provided"
3665
+ });
3666
+ var HandoffStatusSchema = z.enum(["pending", "accepted", "rejected", "expired"]);
3667
+ var HandoffCreateSchema = z.object({
3668
+ repo: z.string().min(1).transform(normalizeRepo),
3669
+ from_agent: z.string().min(1),
3670
+ to_agent: z.string().min(1).optional(),
3671
+ task_id: z.string().uuid().optional(),
3672
+ task_code: z.string().optional(),
3673
+ summary: z.string().min(1),
3674
+ context: z.record(z.string(), z.any()).optional(),
3675
+ expires_at: z.string().optional(),
3676
+ structured: z.boolean().default(false)
3677
+ }).refine((data) => !(data.task_id && data.task_code), {
3678
+ message: "Provide either task_id or task_code, not both"
3679
+ }).refine((data) => data.to_agent || data.task_id || data.task_code || data.context?.next_steps || data.context?.blockers || data.context?.remaining_work, {
3680
+ message: "Handoffs must identify a target agent, linked task, next_steps, blockers, or remaining_work. Do not create pending handoffs for completed-work summaries."
3681
+ });
3682
+ var HandoffUpdateSchema = z.object({
3683
+ id: z.string().uuid(),
3684
+ status: HandoffStatusSchema,
3685
+ structured: z.boolean().default(false)
3686
+ });
3687
+ var HandoffListSchema = z.object({
3688
+ repo: z.string().min(1).transform(normalizeRepo),
3689
+ status: HandoffStatusSchema.optional(),
3690
+ from_agent: z.string().min(1).optional(),
3691
+ to_agent: z.string().min(1).optional(),
3692
+ limit: z.number().min(1).max(100).default(20),
3693
+ offset: z.number().min(0).default(0),
3694
+ structured: z.boolean().default(false)
3695
+ });
3696
+ var TaskClaimSchema = z.object({
3697
+ repo: z.string().min(1).transform(normalizeRepo),
3698
+ task_id: z.string().uuid().optional(),
3699
+ task_code: z.string().optional(),
3700
+ agent: z.string().min(1),
3701
+ role: z.string().optional(),
3702
+ metadata: z.record(z.string(), z.any()).optional(),
3703
+ structured: z.boolean().default(false)
3704
+ }).refine((data) => data.task_id !== void 0 || data.task_code !== void 0, {
3705
+ message: "Either task_id or task_code must be provided"
3706
+ }).refine((data) => !(data.task_id && data.task_code), {
3707
+ message: "Provide either task_id or task_code, not both"
3708
+ });
3709
+ var StandardStoreSchema = z.object({
3710
+ name: z.string().min(3).max(255),
3711
+ content: z.string().min(10),
3712
+ parent_id: z.string().uuid().optional(),
3713
+ context: z.string().optional(),
3714
+ version: z.string().optional(),
3715
+ language: z.string().optional(),
3716
+ stack: z.array(z.string()).optional(),
3717
+ repo: z.string().transform(normalizeRepo).optional(),
3718
+ is_global: z.boolean().optional(),
3719
+ tags: z.array(z.string().min(1)).min(1),
3720
+ metadata: z.record(z.string(), z.any()).refine((value) => Object.keys(value).length > 0, {
3721
+ message: "metadata must contain at least one key"
3722
+ }),
3723
+ agent: z.string().optional(),
3724
+ model: z.string().optional(),
3725
+ structured: z.boolean().default(false)
3726
+ }).refine((data) => data.is_global !== false || !!data.repo, {
3727
+ message: "repo is required for repo-specific standards"
3728
+ });
3729
+ var StandardUpdateSchema = z.object({
3730
+ id: z.string().uuid(),
3731
+ name: z.string().min(3).max(255).optional(),
3732
+ content: z.string().min(10).optional(),
3733
+ parent_id: z.string().uuid().nullable().optional(),
3734
+ context: z.string().optional(),
3735
+ version: z.string().optional(),
3736
+ language: z.string().optional(),
3737
+ stack: z.array(z.string().min(1)).min(1).optional(),
3738
+ repo: z.string().transform(normalizeRepo).optional(),
3739
+ is_global: z.boolean().optional(),
3740
+ tags: z.array(z.string().min(1)).min(1).optional(),
3741
+ metadata: z.record(z.string(), z.any()).refine((value) => Object.keys(value).length > 0, { message: "metadata must contain at least one key" }).optional(),
3742
+ agent: z.string().optional(),
3743
+ model: z.string().optional(),
3744
+ structured: z.boolean().default(false)
3745
+ }).refine(
3746
+ (data) => data.name !== void 0 || data.content !== void 0 || data.parent_id !== void 0 || data.context !== void 0 || data.version !== void 0 || data.language !== void 0 || data.stack !== void 0 || data.repo !== void 0 || data.is_global !== void 0 || data.tags !== void 0 || data.metadata !== void 0 || data.agent !== void 0 || data.model !== void 0,
3747
+ { message: "At least one field must be provided for update" }
3748
+ ).refine((data) => data.is_global !== false || !!data.repo, {
3749
+ message: "repo is required for repo-specific standards"
3750
+ });
3751
+ var StandardSearchSchema = z.object({
3752
+ query: z.string().optional(),
3753
+ stack: z.array(z.string()).optional(),
3754
+ tags: z.array(z.string()).optional(),
3755
+ language: z.string().optional(),
3756
+ context: z.string().optional(),
3757
+ version: z.string().optional(),
3758
+ repo: z.string().transform(normalizeRepo).optional(),
3759
+ is_global: z.boolean().optional(),
3760
+ limit: z.number().min(1).max(100).default(20),
3761
+ offset: z.number().min(0).default(0),
3762
+ structured: z.boolean().default(false)
3763
+ });
3764
+ var TOOL_DEFINITIONS = [
3704
3765
  {
3705
- name: "memory-recap",
3706
- title: "Memory Recap",
3707
- description: "AGGREGATED OVERVIEW LAYER: Returns stats (counts by type) and a pointer table of top memories [id, code, title, type, importance]. NO content. Use for orientation only \u2014 retrieve full memory via memory-detail.",
3766
+ name: "memory-synthesize",
3767
+ title: "Memory Synthesize",
3768
+ description: "Use client sampling to synthesize a grounded answer from local memory and tasks. Best for project briefings, tradeoff summaries, and context-aware answers.",
3708
3769
  annotations: {
3709
3770
  readOnlyHint: true,
3710
3771
  idempotentHint: true,
3711
3772
  openWorldHint: false
3712
3773
  },
3713
- inputSchema: {
3714
- type: "object",
3715
- properties: {
3716
- repo: { type: "string", description: "Repository name (required)" },
3717
- limit: {
3718
- type: "number",
3719
- minimum: 1,
3720
- maximum: 50,
3721
- default: 20,
3722
- description: "Maximum number of top memories to return in the pointer table"
3723
- },
3724
- offset: {
3725
- type: "number",
3726
- minimum: 0,
3727
- default: 0,
3728
- description: "Number of memories to skip for pagination (optional, default 0)"
3729
- },
3730
- structured: {
3731
- type: "boolean",
3732
- default: false,
3733
- description: "If true, returns structured JSON without the text content summary."
3734
- }
3735
- },
3736
- required: ["repo"]
3737
- },
3738
- outputSchema: {
3739
- type: "object",
3740
- properties: {
3741
- schema: { type: "string", enum: ["memory-recap"] },
3742
- repo: { type: "string" },
3743
- count: { type: "number", description: "Number of rows in the top pointer table" },
3744
- total: { type: "number", description: "Total active memories in repo" },
3745
- offset: { type: "number" },
3746
- limit: { type: "number" },
3747
- stats: {
3748
- type: "object",
3749
- properties: {
3750
- byType: {
3751
- type: "object",
3752
- description: "Count of active memories per type (e.g. { decision: 3, code_fact: 7 })"
3753
- }
3754
- },
3755
- required: ["byType"]
3756
- },
3757
- top: {
3758
- type: "object",
3759
- properties: {
3760
- columns: {
3761
- type: "array",
3762
- items: { type: "string" },
3763
- description: "Column names: [id, code, title, type, importance]"
3764
- },
3765
- rows: {
3766
- type: "array",
3767
- items: { type: "array" },
3768
- description: "Each row: [id, code, title, type, importance]. Fetch full content via memory-detail"
3769
- }
3770
- },
3771
- required: ["columns", "rows"]
3772
- }
3773
- },
3774
- required: ["schema", "repo", "count", "total", "offset", "limit", "stats", "top"]
3775
- }
3776
- },
3777
- {
3778
- name: "task-create",
3779
- title: "Task Create",
3780
- description: "Register one or more new tasks in a repository. task_code must be unique within the repository. Supports single task object or an array of tasks for bulk creation.",
3781
- annotations: {
3782
- readOnlyHint: false,
3783
- idempotentHint: false,
3784
- openWorldHint: false
3785
- },
3786
- inputSchema: {
3787
- type: "object",
3788
- properties: {
3789
- repo: { type: "string", description: "Repository name" },
3790
- task_code: { type: "string", description: "Unique task code (e.g. TASK-001) (Required for single task)" },
3791
- phase: { type: "string", description: "Project phase (Required for single task)" },
3792
- title: {
3793
- type: "string",
3794
- minLength: 3,
3795
- maxLength: 100,
3796
- description: "Task objective (Required for single task)"
3797
- },
3798
- description: { type: "string", description: "Detailed description (Required for single task)" },
3799
- status: {
3800
- type: "string",
3801
- enum: ["backlog", "pending"],
3802
- default: "backlog",
3803
- description: "New tasks MUST start in 'backlog' if there are already 10 pending tasks. Otherwise can start in 'pending'."
3804
- },
3805
- priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
3806
- agent: { type: "string" },
3807
- role: { type: "string" },
3808
- doc_path: { type: "string" },
3809
- tags: { type: "array", items: { type: "string" } },
3810
- metadata: { type: "object" },
3811
- parent_id: { type: "string", format: "uuid" },
3812
- depends_on: { type: "string", format: "uuid" },
3813
- est_tokens: { type: "number", minimum: 0, description: "Estimated tokens budget for this task" },
3814
- tasks: {
3815
- type: "array",
3816
- items: {
3817
- type: "object",
3818
- properties: {
3819
- task_code: { type: "string" },
3820
- phase: { type: "string" },
3821
- title: { type: "string", minLength: 3, maxLength: 100 },
3822
- description: { type: "string" },
3823
- status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
3824
- priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
3825
- agent: { type: "string" },
3826
- role: { type: "string" },
3827
- doc_path: { type: "string" },
3828
- tags: { type: "array", items: { type: "string" } },
3829
- metadata: { type: "object" },
3830
- parent_id: { type: "string", format: "uuid" },
3831
- depends_on: { type: "string", format: "uuid" },
3832
- est_tokens: { type: "number", minimum: 0 }
3833
- },
3834
- required: ["task_code", "phase", "title", "description"]
3835
- },
3836
- description: "Array of tasks for bulk creation"
3837
- },
3838
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
3839
- },
3840
- required: ["repo"]
3841
- },
3842
- outputSchema: {
3843
- type: "object",
3844
- properties: {
3845
- success: { type: "boolean" },
3846
- id: { type: "string" },
3847
- task_code: { type: "string" },
3848
- repo: { type: "string" },
3849
- phase: { type: "string" },
3850
- title: { type: "string" },
3851
- status: { type: "string" },
3852
- priority: { type: "number" },
3853
- createdCount: { type: "number" },
3854
- taskCodes: { type: "array", items: { type: "string" } }
3855
- },
3856
- required: ["success", "repo"]
3857
- }
3858
- },
3859
- {
3860
- name: "task-update",
3861
- title: "Task Update",
3862
- description: "Update one or more tasks. Supports single update via 'id' or bulk update via 'ids'. Provide only the fields that need to be changed. MANDATORY WORKFLOW: You cannot move a task from 'pending' or 'blocked' directly to 'completed'. You MUST move it to 'in_progress' first. When changing status to 'completed', include 'est_tokens' with the estimated total tokens actually used for the task.",
3863
- annotations: {
3864
- readOnlyHint: false,
3865
- idempotentHint: false,
3866
- openWorldHint: false
3774
+ execution: {
3775
+ taskSupport: "optional"
3867
3776
  },
3868
3777
  inputSchema: {
3869
3778
  type: "object",
3870
3779
  properties: {
3871
- repo: { type: "string", description: "Repository name" },
3872
- id: { type: "string", format: "uuid", description: "Task ID (for single update)" },
3873
- ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk update)" },
3874
- task_code: { type: "string" },
3875
- phase: { type: "string" },
3876
- title: { type: "string", minLength: 3, maxLength: 100 },
3877
- description: { type: "string" },
3878
- status: {
3879
- type: "string",
3880
- enum: ["backlog", "pending", "in_progress", "completed", "canceled", "blocked"],
3881
- description: "New status. Transitions from 'backlog', 'pending' or 'blocked' to 'completed' are NOT allowed."
3882
- },
3883
- priority: { type: "number", minimum: 1, maximum: 5 },
3884
- agent: { type: "string" },
3885
- role: { type: "string" },
3886
- model: { type: "string" },
3887
- comment: {
3780
+ repo: { type: "string", description: "Repository name. Optional when a single MCP root is active." },
3781
+ objective: { type: "string", minLength: 5, description: "Question or synthesis objective." },
3782
+ current_file_path: {
3888
3783
  type: "string",
3889
- description: "REQUIRED when changing task status. Explain WHY the status is changing (e.g., 'Starting implementation', 'Blocked by missing API docs', 'Verified fix')."
3890
- },
3891
- doc_path: { type: "string" },
3892
- tags: { type: "array", items: { type: "string" } },
3893
- metadata: { type: "object" },
3894
- parent_id: { type: "string", format: "uuid" },
3895
- depends_on: { type: "string", format: "uuid" },
3896
- est_tokens: {
3897
- type: "number",
3898
- minimum: 0,
3899
- description: "Estimated total tokens actually used for this task. Required when status changes to 'completed'."
3784
+ description: "Optional absolute file path for workspace-local grounding."
3900
3785
  },
3901
- force: {
3786
+ include_summary: { type: "boolean", default: true },
3787
+ include_tasks: { type: "boolean", default: true },
3788
+ use_tools: {
3902
3789
  type: "boolean",
3903
- description: "If true, bypasses status transition validation (e.g. pending -> completed)."
3790
+ default: true,
3791
+ description: "Allow the sampled model to call local memory/task tools during synthesis when the client supports sampling.tools."
3904
3792
  },
3905
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
3793
+ max_iterations: { type: "number", minimum: 1, maximum: 5, default: 3 },
3794
+ max_tokens: { type: "number", minimum: 128, maximum: 4e3, default: 1200 },
3795
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON results." }
3906
3796
  },
3907
- required: ["repo"]
3797
+ required: ["objective"]
3908
3798
  },
3909
3799
  outputSchema: {
3910
3800
  type: "object",
3911
3801
  properties: {
3912
- success: { type: "boolean" },
3913
- id: { type: "string" },
3914
- ids: { type: "array", items: { type: "string" } },
3915
3802
  repo: { type: "string" },
3916
- status: { type: "string" },
3917
- archivedToMemory: { type: "boolean" },
3918
- updatedFields: {
3919
- type: "array",
3920
- items: { type: "string" }
3921
- },
3922
- updatedCount: { type: "number" }
3803
+ objective: { type: "string" },
3804
+ answer: { type: "string" },
3805
+ model: { type: "string" },
3806
+ stopReason: { type: "string" },
3807
+ iterations: { type: "number" },
3808
+ toolCalls: { type: "number" }
3923
3809
  },
3924
- required: ["success", "repo"]
3810
+ required: ["repo", "objective", "answer", "iterations", "toolCalls"]
3925
3811
  }
3926
3812
  },
3927
3813
  {
3928
- name: "task-delete",
3929
- title: "Task Delete",
3930
- description: "Delete one or more tasks from a repository. Supports single 'id' or bulk 'ids'.",
3814
+ name: "task-create-interactive",
3815
+ title: "Interactive Task Create",
3816
+ description: "Create a task with MCP elicitation fallback for any missing required fields. Best when an agent knows a task is needed but still needs user confirmation for repo, title, or phase.",
3931
3817
  annotations: {
3932
3818
  readOnlyHint: false,
3933
3819
  idempotentHint: false,
3934
- destructiveHint: true,
3820
+ destructiveHint: false,
3935
3821
  openWorldHint: false
3936
3822
  },
3937
3823
  inputSchema: {
3938
3824
  type: "object",
3939
3825
  properties: {
3940
- repo: { type: "string", description: "Repository name" },
3941
- id: { type: "string", format: "uuid", description: "Task ID (for single deletion)" },
3942
- ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk deletion)" },
3826
+ repo: {
3827
+ type: "string",
3828
+ description: "Repository name. Optional when it can be inferred from MCP roots or elicited from the user."
3829
+ },
3830
+ task_code: { type: "string" },
3831
+ phase: { type: "string" },
3832
+ title: { type: "string", minLength: 3, maxLength: 100 },
3833
+ description: { type: "string", minLength: 1 },
3834
+ status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
3835
+ priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
3836
+ agent: { type: "string" },
3837
+ role: { type: "string" },
3838
+ doc_path: { type: "string" },
3943
3839
  structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
3944
- },
3945
- required: ["repo"]
3840
+ }
3946
3841
  },
3947
3842
  outputSchema: {
3948
3843
  type: "object",
3949
3844
  properties: {
3950
- success: { type: "boolean" },
3951
- id: { type: "string" },
3952
- ids: { type: "array", items: { type: "string" } },
3953
3845
  repo: { type: "string" },
3954
- deletedCount: { type: "number" }
3846
+ task_code: { type: "string" },
3847
+ phase: { type: "string" },
3848
+ title: { type: "string" },
3849
+ status: { type: "string" },
3850
+ priority: { type: "number" }
3955
3851
  },
3956
- required: ["success", "repo"]
3852
+ required: ["repo", "task_code", "phase", "title", "status", "priority"]
3957
3853
  }
3958
3854
  },
3959
3855
  {
3960
- name: "task-list",
3961
- title: "Task List",
3962
- description: "PRIMARY navigation and search tool for tasks. Returns a compact tabular list of tasks (id, task_code, title, status, priority, updated_at, comments_count). Defaults to in_progress and pending tasks. Use 'query' to filter by code, title, or description. Use 'status' (comma-separated) for specific filters. AGENTS: call this once at start, pick ONE task, then call task-detail.",
3856
+ name: "memory-detail",
3857
+ title: "Memory Detail",
3858
+ description: "Fetch full details of a specific memory by ID or short code. Use after memory-recap or memory-search when a pointer row is relevant and full content is needed.",
3859
+ inputSchema: {
3860
+ type: "object",
3861
+ properties: {
3862
+ id: { type: "string", format: "uuid", description: "Memory entry ID. Optional if code is provided." },
3863
+ code: { type: "string", description: "Short memory code. Optional if id is provided." },
3864
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON details." }
3865
+ }
3866
+ }
3867
+ },
3868
+ {
3869
+ name: "standard-detail",
3870
+ title: "Standard Detail",
3871
+ description: "Fetch full details of a specific coding standard by ID. Use after standard-search when a result is relevant and full guidance is needed.",
3872
+ inputSchema: {
3873
+ type: "object",
3874
+ properties: {
3875
+ id: { type: "string", format: "uuid", description: "Coding standard ID." },
3876
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON details." }
3877
+ },
3878
+ required: ["id"]
3879
+ }
3880
+ },
3881
+ {
3882
+ name: "task-detail",
3883
+ title: "Task Detail",
3884
+ description: "Fetch full details of a specific task by ID or task code. Use this when you have a task ID or code and need to read the full description and comments.",
3885
+ inputSchema: {
3886
+ type: "object",
3887
+ properties: {
3888
+ repo: { type: "string", description: "Repository name" },
3889
+ id: { type: "string", format: "uuid", description: "Task ID (optional if task_code is provided)" },
3890
+ task_code: { type: "string", description: "Task code (e.g. TASK-001) (optional if id is provided)" },
3891
+ structured: {
3892
+ type: "boolean",
3893
+ default: false,
3894
+ description: "If true, returns structured JSON without the text content details."
3895
+ }
3896
+ },
3897
+ required: ["repo"]
3898
+ }
3899
+ },
3900
+ {
3901
+ name: "memory-store",
3902
+ title: "Memory Store",
3903
+ description: "Store a new durable knowledge entry. Do not store coordination state here: task claims, file claims, agent registration, and handoffs belong to task-claim, task-update, and handoff-* tools. Keep 'title' concise and human-readable; put auxiliary context into 'metadata'.",
3963
3904
  annotations: {
3964
- readOnlyHint: true,
3965
- idempotentHint: true,
3905
+ readOnlyHint: false,
3906
+ idempotentHint: false,
3907
+ destructiveHint: false,
3966
3908
  openWorldHint: false
3967
3909
  },
3968
3910
  inputSchema: {
3969
3911
  type: "object",
3970
3912
  properties: {
3971
- repo: {
3972
- type: "string",
3973
- description: "Repository name"
3974
- },
3975
- status: {
3913
+ type: {
3976
3914
  type: "string",
3977
- default: "in_progress,pending",
3978
- description: "Comma-separated status filter (backlog, pending, in_progress, completed, canceled, blocked). Defaults to 'in_progress,pending'."
3915
+ enum: [
3916
+ "code_fact",
3917
+ "decision",
3918
+ "mistake",
3919
+ "pattern",
3920
+ "task_archive"
3921
+ ],
3922
+ description: "Type of durable knowledge being stored. Coordination types such as file_claim are intentionally unsupported."
3979
3923
  },
3980
- phase: {
3924
+ title: {
3981
3925
  type: "string",
3982
- description: "Filter by phase (e.g., 'research', 'implementation')"
3926
+ minLength: 3,
3927
+ maxLength: 100,
3928
+ description: "Short human-readable title for the memory. Do not embed bracketed metadata like agent/role/date prefixes here."
3983
3929
  },
3984
- query: {
3930
+ content: {
3985
3931
  type: "string",
3986
- description: "Search keyword matching task code, title, or description"
3932
+ minLength: 10,
3933
+ description: "The memory content"
3987
3934
  },
3988
- limit: {
3935
+ importance: {
3989
3936
  type: "number",
3990
3937
  minimum: 1,
3991
- maximum: 100,
3992
- default: 5,
3993
- description: "Maximum rows to return (default 5)"
3938
+ maximum: 5,
3939
+ description: "Importance score (1-5)"
3994
3940
  },
3995
- offset: {
3996
- type: "number",
3997
- minimum: 0,
3998
- default: 0,
3999
- description: "Offset for pagination"
3941
+ agent: {
3942
+ type: "string",
3943
+ description: "Name of the agent creating this memory"
4000
3944
  },
4001
- structured: {
3945
+ role: {
3946
+ type: "string",
3947
+ description: "Role of the agent creating this memory"
3948
+ },
3949
+ model: {
3950
+ type: "string",
3951
+ description: "AI model used by the agent"
3952
+ },
3953
+ scope: {
3954
+ type: "object",
3955
+ properties: {
3956
+ repo: { type: "string", description: "Repository name" },
3957
+ branch: { type: "string" },
3958
+ folder: { type: "string" },
3959
+ language: { type: "string" }
3960
+ },
3961
+ required: ["repo"]
3962
+ },
3963
+ tags: {
3964
+ type: "array",
3965
+ items: { type: "string" },
3966
+ description: "Technology stack tags (e.g., ['filament', 'laravel'])"
3967
+ },
3968
+ metadata: {
3969
+ type: "object",
3970
+ description: "Structured metadata for non-title context such as source agent, claim fields, or timestamps"
3971
+ },
3972
+ is_global: {
4002
3973
  type: "boolean",
4003
- default: false,
4004
- description: "If true, returns structured JSON without the text content summary."
4005
- }
3974
+ description: "If true, this memory is shared across all repositories"
3975
+ },
3976
+ ttlDays: { type: "number", minimum: 1 },
3977
+ supersedes: { type: "string", format: "uuid" },
3978
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the stored memory." }
4006
3979
  },
4007
- required: ["repo"]
3980
+ required: ["type", "title", "content", "importance", "scope", "agent", "model"]
4008
3981
  },
4009
3982
  outputSchema: {
4010
3983
  type: "object",
4011
3984
  properties: {
4012
- schema: { type: "string", enum: ["task-list"] },
4013
- tasks: {
4014
- type: "object",
4015
- properties: {
4016
- columns: {
4017
- type: "array",
4018
- items: { type: "string" },
4019
- description: "Column names in order: id, task_code, title, status, priority, updated_at, comments_count"
4020
- },
4021
- rows: {
4022
- type: "array",
4023
- items: { type: "array" },
4024
- description: "Each row: [id, task_code, title, status, priority, updated_at, comments_count]. Use task-detail to fetch full task."
4025
- }
4026
- },
4027
- required: ["columns", "rows"]
4028
- },
4029
- count: { type: "number" },
4030
- offset: { type: "number" }
3985
+ success: { type: "boolean" },
3986
+ id: { type: "string" },
3987
+ code: { type: "string" },
3988
+ repo: { type: "string" },
3989
+ type: { type: "string" },
3990
+ title: { type: "string" },
3991
+ error: { type: "string" },
3992
+ message: { type: "string" }
4031
3993
  },
4032
- required: ["schema", "tasks", "count"]
3994
+ required: ["success"]
4033
3995
  }
4034
3996
  },
4035
3997
  {
4036
- name: "handoff-create",
4037
- title: "Handoff Create",
4038
- description: "Create a pending handoff only when unfinished work needs context transfer between agents. Do not use this for completed-work summaries, release notes, validation notes, or archives; put those on task-update/task comments or durable memory.",
3998
+ name: "memory-acknowledge",
3999
+ title: "Memory Acknowledge",
4000
+ description: "Acknowledge the use of a memory or report its irrelevance/contradiction. Mandatory after using memory to generate code.",
4039
4001
  annotations: {
4040
4002
  readOnlyHint: false,
4041
4003
  idempotentHint: false,
4042
- destructiveHint: false,
4043
4004
  openWorldHint: false
4044
4005
  },
4045
4006
  inputSchema: {
4046
4007
  type: "object",
4047
4008
  properties: {
4048
- repo: { type: "string", description: "Repository name" },
4049
- from_agent: { type: "string", description: "Agent creating the handoff" },
4050
- to_agent: { type: "string", description: "Optional target agent" },
4051
- task_id: { type: "string", format: "uuid", description: "Optional task id to associate" },
4052
- task_code: { type: "string", description: "Optional task code to associate" },
4053
- summary: { type: "string", minLength: 1, description: "Concise human-readable transfer summary" },
4054
- context: {
4055
- type: "object",
4056
- description: "Structured handoff context. Include next_steps, blockers, or remaining_work unless a target agent or task is provided."
4057
- },
4058
- expires_at: { type: "string", description: "Optional expiration timestamp" },
4059
- structured: { type: "boolean", default: false }
4009
+ memory_id: { type: "string", format: "uuid" },
4010
+ status: { type: "string", enum: ["used", "irrelevant", "contradictory"] },
4011
+ application_context: { type: "string", minLength: 10 },
4012
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4060
4013
  },
4061
- required: ["repo", "from_agent", "summary"]
4014
+ required: ["memory_id", "status"]
4062
4015
  },
4063
4016
  outputSchema: {
4064
4017
  type: "object",
4065
4018
  properties: {
4019
+ success: { type: "boolean" },
4066
4020
  id: { type: "string" },
4067
- repo: { type: "string" },
4068
- from_agent: { type: "string" },
4069
- to_agent: { type: "string", nullable: true },
4070
- task_id: { type: "string", nullable: true },
4071
- summary: { type: "string" },
4072
- context: { type: "object" },
4073
- status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
4074
- created_at: { type: "string" },
4075
- updated_at: { type: "string" },
4076
- expires_at: { type: "string", nullable: true }
4021
+ status: { type: "string" }
4077
4022
  },
4078
- required: ["id", "repo", "from_agent", "summary", "context", "status", "created_at", "updated_at"]
4023
+ required: ["success", "id", "status"]
4079
4024
  }
4080
4025
  },
4081
4026
  {
4082
- name: "handoff-update",
4083
- title: "Handoff Update",
4084
- description: "Close or reclassify a handoff after it has been consumed or found stale. Use accepted when transfer context was consumed, rejected when intentionally declined, and expired when the handoff is obsolete or only described completed work.",
4027
+ name: "memory-update",
4028
+ title: "Memory Update",
4029
+ description: "Update an existing memory entry. Keep 'title' concise and move agent/role/date or claim context into 'metadata' instead of the title.",
4085
4030
  annotations: {
4086
4031
  readOnlyHint: false,
4087
4032
  idempotentHint: false,
@@ -4091,26 +4036,50 @@ var TOOL_DEFINITIONS = [
4091
4036
  inputSchema: {
4092
4037
  type: "object",
4093
4038
  properties: {
4094
- id: { type: "string", format: "uuid", description: "Handoff ID" },
4095
- status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
4096
- structured: { type: "boolean", default: false }
4039
+ id: { type: "string", format: "uuid" },
4040
+ type: {
4041
+ type: "string",
4042
+ enum: [
4043
+ "code_fact",
4044
+ "decision",
4045
+ "mistake",
4046
+ "pattern",
4047
+ "task_archive"
4048
+ ]
4049
+ },
4050
+ title: { type: "string", minLength: 3, maxLength: 100 },
4051
+ content: { type: "string", minLength: 10 },
4052
+ importance: { type: "number", minimum: 1, maximum: 5 },
4053
+ agent: { type: "string" },
4054
+ role: { type: "string" },
4055
+ status: { type: "string", enum: ["active", "archived"] },
4056
+ supersedes: { type: "string", format: "uuid" },
4057
+ tags: { type: "array", items: { type: "string" } },
4058
+ metadata: { type: "object" },
4059
+ is_global: { type: "boolean" },
4060
+ completed_at: { type: "string" },
4061
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the updated memory." }
4097
4062
  },
4098
- required: ["id", "status"]
4063
+ required: ["id"]
4099
4064
  },
4100
4065
  outputSchema: {
4101
4066
  type: "object",
4102
4067
  properties: {
4103
4068
  success: { type: "boolean" },
4104
4069
  id: { type: "string" },
4105
- status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] }
4070
+ repo: { type: "string" },
4071
+ updatedFields: {
4072
+ type: "array",
4073
+ items: { type: "string" }
4074
+ }
4106
4075
  },
4107
- required: ["success", "id", "status"]
4076
+ required: ["success", "id", "repo", "updatedFields"]
4108
4077
  }
4109
4078
  },
4110
4079
  {
4111
- name: "handoff-list",
4112
- title: "Handoff List",
4113
- description: "Navigation layer for handoff queues. List repository handoffs with optional status and agent filters, then inspect selected rows before acting.",
4080
+ name: "memory-search",
4081
+ title: "Memory Search",
4082
+ description: "NAVIGATION LAYER: Returns a pointer table of matching memory IDs only. Returns columns [id, title, type, importance] \u2014 NO content. Retrieve full memory via memory-detail. Use 'current_tags' to find tech-stack specific knowledge from other projects.",
4114
4083
  annotations: {
4115
4084
  readOnlyHint: true,
4116
4085
  idempotentHint: true,
@@ -4119,213 +4088,189 @@ var TOOL_DEFINITIONS = [
4119
4088
  inputSchema: {
4120
4089
  type: "object",
4121
4090
  properties: {
4122
- repo: { type: "string", description: "Repository name" },
4123
- status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
4124
- from_agent: { type: "string" },
4125
- to_agent: { type: "string" },
4126
- limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
4091
+ query: { type: "string", minLength: 3 },
4092
+ prompt: { type: "string" },
4093
+ repo: { type: "string" },
4094
+ current_tags: {
4095
+ type: "array",
4096
+ items: { type: "string" },
4097
+ description: "Active tech stack tags (e.g., ['filament', 'react'])"
4098
+ },
4099
+ types: {
4100
+ type: "array",
4101
+ items: {
4102
+ type: "string",
4103
+ enum: [
4104
+ "code_fact",
4105
+ "decision",
4106
+ "mistake",
4107
+ "pattern",
4108
+ "task_archive"
4109
+ ]
4110
+ }
4111
+ },
4112
+ minImportance: { type: "number", minimum: 1, maximum: 5 },
4113
+ limit: { type: "number", minimum: 1, maximum: 100, default: 5 },
4127
4114
  offset: { type: "number", minimum: 0, default: 0 },
4128
- structured: { type: "boolean", default: false }
4115
+ includeRecap: { type: "boolean", default: false },
4116
+ current_file_path: { type: "string" },
4117
+ include_archived: { type: "boolean", default: false },
4118
+ scope: {
4119
+ type: "object",
4120
+ properties: {
4121
+ repo: { type: "string" },
4122
+ branch: { type: "string" },
4123
+ folder: { type: "string" },
4124
+ language: { type: "string" }
4125
+ }
4126
+ },
4127
+ structured: {
4128
+ type: "boolean",
4129
+ default: false,
4130
+ description: "If true, returns structured JSON without the text content summary."
4131
+ }
4129
4132
  },
4130
- required: ["repo"]
4133
+ required: ["query", "repo"]
4131
4134
  },
4132
4135
  outputSchema: {
4133
4136
  type: "object",
4134
4137
  properties: {
4135
- schema: { type: "string", enum: ["handoff-list"] },
4136
- handoffs: {
4138
+ schema: { type: "string", enum: ["memory-search"] },
4139
+ query: { type: "string" },
4140
+ count: { type: "number", description: "Number of rows returned" },
4141
+ total: { type: "number", description: "Total matching memories" },
4142
+ offset: { type: "number" },
4143
+ limit: { type: "number" },
4144
+ results: {
4137
4145
  type: "object",
4138
4146
  properties: {
4139
4147
  columns: {
4140
4148
  type: "array",
4141
4149
  items: { type: "string" },
4142
- description: "Column names: [id, from_agent, to_agent, task_id, status, created_at, summary]"
4150
+ description: "Column names: [id, title, type, importance]"
4143
4151
  },
4144
4152
  rows: {
4145
4153
  type: "array",
4146
4154
  items: { type: "array" },
4147
- description: "Each row: [id, from_agent, to_agent, task_id, status, created_at, summary]"
4155
+ description: "Each row: [id, title, type, importance]. Fetch full content via memory-detail"
4148
4156
  }
4149
4157
  },
4150
4158
  required: ["columns", "rows"]
4151
- },
4152
- count: { type: "number" },
4153
- offset: { type: "number" }
4159
+ }
4154
4160
  },
4155
- required: ["schema", "handoffs", "count", "offset"]
4161
+ required: ["schema", "query", "count", "total", "offset", "limit", "results"]
4156
4162
  }
4157
4163
  },
4158
4164
  {
4159
- name: "task-claim",
4160
- title: "Task Claim",
4161
- description: "Claim task ownership for an agent using the dedicated claims table. Use this before taking work from task-list; provide either task_id or task_code.",
4165
+ name: "memory-summarize",
4166
+ title: "Memory Summarize",
4167
+ description: "Update the summary for a repository",
4162
4168
  annotations: {
4163
4169
  readOnlyHint: false,
4164
4170
  idempotentHint: false,
4165
- destructiveHint: false,
4166
4171
  openWorldHint: false
4167
4172
  },
4168
4173
  inputSchema: {
4169
4174
  type: "object",
4170
4175
  properties: {
4171
4176
  repo: { type: "string", description: "Repository name" },
4172
- task_id: { type: "string", format: "uuid", description: "Task id to claim. Optional if task_code is provided." },
4173
- task_code: { type: "string", description: "Task code to claim. Optional if task_id is provided." },
4174
- agent: { type: "string", description: "Claiming agent name" },
4175
- role: { type: "string", description: "Claiming agent role" },
4176
- metadata: { type: "object", description: "Optional claim metadata" },
4177
- structured: { type: "boolean", default: false }
4177
+ signals: {
4178
+ type: "array",
4179
+ items: { type: "string", maxLength: 200 },
4180
+ minItems: 1,
4181
+ description: "High-level signals to include in summary"
4182
+ },
4183
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the summary." }
4178
4184
  },
4179
- required: ["repo", "agent"]
4185
+ required: ["repo", "signals"]
4180
4186
  },
4181
4187
  outputSchema: {
4182
4188
  type: "object",
4183
4189
  properties: {
4184
- id: { type: "string" },
4190
+ success: { type: "boolean" },
4185
4191
  repo: { type: "string" },
4186
- task_id: { type: "string" },
4187
- task_code: { type: "string", nullable: true },
4188
- agent: { type: "string" },
4189
- role: { type: "string" },
4190
- claimed_at: { type: "string" },
4191
- released_at: { type: "string", nullable: true },
4192
- metadata: { type: "object" }
4192
+ summary: { type: "string" },
4193
+ signalCount: { type: "number" }
4193
4194
  },
4194
- required: ["id", "repo", "task_id", "agent", "role", "claimed_at", "metadata"]
4195
+ required: ["success", "repo", "summary", "signalCount"]
4195
4196
  }
4196
4197
  },
4197
4198
  {
4198
- name: "standard-store",
4199
- title: "Standard Store",
4200
- description: "Store one atomic coding standard. Use for durable implementation rules with explicit context, stack/language filters, and repo/global scope.",
4199
+ name: "memory-delete",
4200
+ title: "Memory Delete",
4201
+ description: "Soft-delete one or more memory entries. Supports single 'id' or bulk 'ids'.",
4201
4202
  annotations: {
4202
4203
  readOnlyHint: false,
4203
4204
  idempotentHint: false,
4204
- destructiveHint: false,
4205
+ destructiveHint: true,
4205
4206
  openWorldHint: false
4206
4207
  },
4207
4208
  inputSchema: {
4208
4209
  type: "object",
4209
4210
  properties: {
4210
- name: { type: "string", minLength: 3, maxLength: 255, description: "Human-readable standard name" },
4211
- content: { type: "string", minLength: 10, description: "One atomic, actionable standard written as concise Markdown" },
4212
- parent_id: { type: "string", format: "uuid", description: "Optional parent standard ID when this rule is a child/specialization." },
4213
- context: { type: "string", description: "Context or category (e.g., 'error-handling', 'security')" },
4214
- version: { type: "string", description: "Version of the standard (e.g., '1.0.0')" },
4215
- language: { type: "string", description: "Programming language (e.g., 'typescript', 'python')" },
4216
- stack: {
4217
- type: "array",
4218
- items: { type: "string" },
4219
- description: "Technology stack (e.g., ['react', 'nextjs'])"
4220
- },
4221
- repo: { type: "string", description: "Repository name for repo-specific standards. Omit only for global standards." },
4222
- is_global: { type: "boolean", description: "Whether standard applies globally or repo-specific" },
4223
- tags: {
4211
+ repo: { type: "string", description: "Repository name (optional for single id)" },
4212
+ id: { type: "string", format: "uuid", description: "Memory entry ID to delete" },
4213
+ ids: {
4224
4214
  type: "array",
4225
- items: { type: "string" },
4226
- description: "Tags for categorization"
4227
- },
4228
- metadata: {
4229
- type: "object",
4230
- description: "Additional metadata"
4215
+ items: { type: "string", format: "uuid" },
4216
+ minItems: 1,
4217
+ description: "Array of memory IDs to delete"
4231
4218
  },
4232
- agent: { type: "string", description: "Agent creating the standard" },
4233
- model: { type: "string", description: "AI model used" },
4234
- structured: { type: "boolean", default: false }
4235
- },
4236
- required: ["name", "content", "tags", "metadata"]
4219
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4220
+ }
4237
4221
  },
4238
4222
  outputSchema: {
4239
4223
  type: "object",
4240
4224
  properties: {
4241
4225
  success: { type: "boolean" },
4242
- standard: {
4243
- type: "object",
4244
- properties: {
4245
- id: { type: "string" },
4246
- title: { type: "string" },
4247
- content: { type: "string" },
4248
- parent_id: { type: "string", nullable: true },
4249
- context: { type: "string" },
4250
- version: { type: "string" },
4251
- language: { type: "string", nullable: true },
4252
- stack: { type: "array", items: { type: "string" } },
4253
- is_global: { type: "boolean" },
4254
- repo: { type: "string", nullable: true },
4255
- tags: { type: "array", items: { type: "string" } },
4256
- metadata: { type: "object" },
4257
- created_at: { type: "string" },
4258
- updated_at: { type: "string" },
4259
- agent: { type: "string" },
4260
- model: { type: "string" }
4261
- },
4262
- required: [
4263
- "id",
4264
- "title",
4265
- "content",
4266
- "parent_id",
4267
- "context",
4268
- "version",
4269
- "stack",
4270
- "is_global",
4271
- "tags",
4272
- "metadata",
4273
- "created_at",
4274
- "updated_at",
4275
- "agent",
4276
- "model"
4277
- ]
4278
- },
4279
- message: { type: "string" }
4226
+ id: { type: "string" },
4227
+ ids: { type: "array", items: { type: "string" } },
4228
+ repo: { type: "string" },
4229
+ deletedCount: { type: "number" }
4280
4230
  },
4281
- required: ["success", "standard", "message"]
4231
+ required: ["success"]
4282
4232
  }
4283
4233
  },
4284
4234
  {
4285
- name: "standard-update",
4286
- title: "Standard Update",
4287
- description: "Update an existing coding standard. Use this when the rule changes, expands scope, or metadata/tags need correction.",
4235
+ name: "standard-delete",
4236
+ title: "Standard Delete",
4237
+ description: "Delete one or more coding standards. Supports single 'id' or bulk 'ids'.",
4288
4238
  annotations: {
4289
4239
  readOnlyHint: false,
4290
4240
  idempotentHint: false,
4291
- destructiveHint: false,
4292
- openWorldHint: false
4293
- },
4294
- inputSchema: {
4295
- type: "object",
4296
- properties: {
4297
- id: { type: "string", description: "Standard ID to update" },
4298
- name: { type: "string", minLength: 3, maxLength: 255 },
4299
- content: { type: "string", minLength: 10 },
4300
- parent_id: { type: "string", format: "uuid", nullable: true },
4301
- context: { type: "string" },
4302
- version: { type: "string" },
4303
- language: { type: "string" },
4304
- stack: { type: "array", items: { type: "string" } },
4305
- repo: { type: "string" },
4306
- is_global: { type: "boolean" },
4307
- tags: { type: "array", items: { type: "string" } },
4308
- metadata: { type: "object" },
4309
- agent: { type: "string" },
4310
- model: { type: "string" },
4311
- structured: { type: "boolean", default: false }
4312
- },
4313
- required: ["id"]
4241
+ destructiveHint: true,
4242
+ openWorldHint: false
4243
+ },
4244
+ inputSchema: {
4245
+ type: "object",
4246
+ properties: {
4247
+ repo: { type: "string", description: "Repository name (optional for single id)" },
4248
+ id: { type: "string", format: "uuid", description: "Coding standard ID to delete" },
4249
+ ids: {
4250
+ type: "array",
4251
+ items: { type: "string", format: "uuid" },
4252
+ minItems: 1,
4253
+ description: "Array of coding standard IDs to delete"
4254
+ },
4255
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4256
+ }
4314
4257
  },
4315
4258
  outputSchema: {
4316
4259
  type: "object",
4317
4260
  properties: {
4318
4261
  success: { type: "boolean" },
4319
4262
  id: { type: "string" },
4320
- updatedFields: { type: "array", items: { type: "string" } }
4263
+ ids: { type: "array", items: { type: "string" } },
4264
+ repo: { type: "string" },
4265
+ deletedCount: { type: "number" }
4321
4266
  },
4322
- required: ["success", "id", "updatedFields"]
4267
+ required: ["success"]
4323
4268
  }
4324
4269
  },
4325
4270
  {
4326
- name: "standard-search",
4327
- title: "Standard Search",
4328
- description: "NAVIGATION LAYER: Returns a compact pointer table of matching coding standards. Use `standard-detail` to fetch full content for a selected result.",
4271
+ name: "memory-recap",
4272
+ title: "Memory Recap",
4273
+ description: "AGGREGATED OVERVIEW LAYER: Returns stats (counts by type) and a pointer table of top memories [id, code, title, type, importance]. NO content. Use for orientation only \u2014 retrieve full memory via memory-detail.",
4329
4274
  annotations: {
4330
4275
  readOnlyHint: true,
4331
4276
  idempotentHint: true,
@@ -4334,623 +4279,678 @@ var TOOL_DEFINITIONS = [
4334
4279
  inputSchema: {
4335
4280
  type: "object",
4336
4281
  properties: {
4337
- query: { type: "string", description: "Search query (optional, searches title/content)" },
4338
- stack: {
4339
- type: "array",
4340
- items: { type: "string" },
4341
- description: "Technology stack to filter by (e.g., ['react', 'nextjs'])"
4282
+ repo: { type: "string", description: "Repository name (required)" },
4283
+ limit: {
4284
+ type: "number",
4285
+ minimum: 1,
4286
+ maximum: 50,
4287
+ default: 20,
4288
+ description: "Maximum number of top memories to return in the pointer table"
4342
4289
  },
4343
- tags: {
4344
- type: "array",
4345
- items: { type: "string" },
4346
- description: "Tag filter"
4290
+ offset: {
4291
+ type: "number",
4292
+ minimum: 0,
4293
+ default: 0,
4294
+ description: "Number of memories to skip for pagination (optional, default 0)"
4347
4295
  },
4348
- language: { type: "string", description: "Programming language filter" },
4349
- context: { type: "string", description: "Context/category filter" },
4350
- version: { type: "string", description: "Version filter" },
4351
- repo: { type: "string", description: "Repository filter (optional)" },
4352
- is_global: { type: "boolean", description: "Filter by global/repo-specific" },
4353
- limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
4354
- offset: { type: "number", minimum: 0, default: 0 },
4355
- structured: { type: "boolean", default: false }
4296
+ structured: {
4297
+ type: "boolean",
4298
+ default: false,
4299
+ description: "If true, returns structured JSON without the text content summary."
4300
+ }
4356
4301
  },
4357
- required: []
4302
+ required: ["repo"]
4358
4303
  },
4359
4304
  outputSchema: {
4360
4305
  type: "object",
4361
4306
  properties: {
4362
- schema: { type: "string", enum: ["standard-search"] },
4363
- query: { type: "string" },
4364
- count: { type: "number", description: "Number of rows returned" },
4365
- total: { type: "number", description: "Total number of matches before pagination" },
4307
+ schema: { type: "string", enum: ["memory-recap"] },
4308
+ repo: { type: "string" },
4309
+ count: { type: "number", description: "Number of rows in the top pointer table" },
4310
+ total: { type: "number", description: "Total active memories in repo" },
4366
4311
  offset: { type: "number" },
4367
4312
  limit: { type: "number" },
4368
- results: {
4313
+ stats: {
4314
+ type: "object",
4315
+ properties: {
4316
+ byType: {
4317
+ type: "object",
4318
+ description: "Count of active memories per type (e.g. { decision: 3, code_fact: 7 })"
4319
+ }
4320
+ },
4321
+ required: ["byType"]
4322
+ },
4323
+ top: {
4369
4324
  type: "object",
4370
4325
  properties: {
4371
4326
  columns: {
4372
4327
  type: "array",
4373
- items: { type: "string" }
4328
+ items: { type: "string" },
4329
+ description: "Column names: [id, code, title, type, importance]"
4374
4330
  },
4375
4331
  rows: {
4376
4332
  type: "array",
4377
4333
  items: { type: "array" },
4378
- description: "Each row includes standard id and pointer metadata. Fetch full content via standard-detail."
4334
+ description: "Each row: [id, code, title, type, importance]. Fetch full content via memory-detail"
4379
4335
  }
4380
4336
  },
4381
4337
  required: ["columns", "rows"]
4382
4338
  }
4383
4339
  },
4384
- required: ["schema", "query", "count", "total", "offset", "limit", "results"]
4385
- }
4386
- }
4387
- ];
4388
-
4389
- // src/mcp/utils/pagination.ts
4390
- function encodeCursor(offset) {
4391
- return Buffer.from(String(offset), "utf8").toString("base64");
4392
- }
4393
- function decodeCursor(cursor) {
4394
- if (cursor === void 0 || cursor === null || cursor === "") {
4395
- return 0;
4396
- }
4397
- if (typeof cursor !== "string" || cursor.trim() === "") {
4398
- throw invalidPaginationParams("Invalid cursor");
4399
- }
4400
- let decoded;
4401
- try {
4402
- decoded = Buffer.from(cursor, "base64").toString("utf8");
4403
- } catch {
4404
- throw invalidPaginationParams("Invalid cursor");
4405
- }
4406
- if (!/^\d+$/.test(decoded)) {
4407
- throw invalidPaginationParams("Invalid cursor");
4408
- }
4409
- const offset = Number.parseInt(decoded, 10);
4410
- if (!Number.isFinite(offset) || offset < 0) {
4411
- throw invalidPaginationParams("Invalid cursor");
4412
- }
4413
- return offset;
4414
- }
4415
- function invalidPaginationParams(message) {
4416
- const error = new Error(message);
4417
- error.code = -32602;
4418
- return error;
4419
- }
4420
-
4421
- // src/mcp/utils/completion.ts
4422
- var MAX_COMPLETION_VALUES = 100;
4423
- function rankCompletionValues(candidates, input) {
4424
- const unique = [...new Set(candidates.filter(Boolean))];
4425
- const needle = input.trim().toLowerCase();
4426
- if (!needle) {
4427
- return unique.slice(0, MAX_COMPLETION_VALUES);
4428
- }
4429
- return unique.map((value) => ({ value, score: scoreCompletionValue(value, needle) })).filter((entry) => entry.score > 0).sort((a, b) => b.score - a.score || a.value.localeCompare(b.value)).map((entry) => entry.value);
4430
- }
4431
- function scoreCompletionValue(value, needle) {
4432
- const haystack = value.toLowerCase();
4433
- if (haystack === needle) return 100;
4434
- if (haystack.startsWith(needle)) return 75;
4435
- if (haystack.includes(needle)) return 50;
4436
- const compactNeedle = needle.replace(/[\s_-]+/g, "");
4437
- const compactHaystack = haystack.replace(/[\s_-]+/g, "");
4438
- if (compactNeedle && compactHaystack.includes(compactNeedle)) return 25;
4439
- return 0;
4440
- }
4441
-
4442
- // src/mcp/resources/index.ts
4443
- var DEFAULT_PAGE_SIZE = 25;
4444
- var MAX_PAGE_SIZE = 100;
4445
- function listResources(session, params) {
4446
- const resources = [
4447
- {
4448
- uri: "repository://index",
4449
- name: "Repository Index",
4450
- title: "Repository Index",
4451
- description: "List of all known repositories with memory/task counts and last activity",
4452
- mimeType: "application/json",
4453
- annotations: {
4454
- audience: ["assistant"],
4455
- priority: 1,
4456
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
4457
- }
4458
- },
4459
- {
4460
- uri: "session://roots",
4461
- name: "Session Roots",
4462
- title: "Session Roots",
4463
- description: session?.roots.length ? "Active workspace roots provided by the MCP client" : "No active workspace roots were provided by the MCP client",
4464
- mimeType: "application/json",
4465
- size: Buffer.byteLength(JSON.stringify({ roots: session?.roots ?? [] }), "utf8"),
4466
- annotations: {
4467
- audience: ["assistant"],
4468
- priority: 0.95,
4469
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
4470
- }
4340
+ required: ["schema", "repo", "count", "total", "offset", "limit", "stats", "top"]
4471
4341
  }
4472
- ];
4473
- return paginateEntries("resources", resources, params);
4474
- }
4475
- function listResourceTemplates(params) {
4476
- const templates = [
4477
- // ── Memory ──────────────────────────────────────────────────────────────
4478
- {
4479
- uriTemplate: "repository://{name}/memories",
4480
- name: "Repository Memories",
4481
- title: "Repository Memories",
4482
- description: "All active memory entries for a specific repository",
4483
- mimeType: "application/json",
4484
- annotations: { audience: ["assistant"], priority: 0.85 }
4485
- },
4486
- {
4487
- uriTemplate: "repository://{name}/memories?search={search}&type={type}&tag={tag}",
4488
- name: "Filtered Repository Memories",
4489
- title: "Filtered Repository Memories",
4490
- description: "Filter or search memories within a repository by keyword, type, or tag",
4491
- mimeType: "application/json",
4492
- annotations: { audience: ["assistant"], priority: 0.8 }
4493
- },
4494
- {
4495
- uriTemplate: "memory://{id}",
4496
- name: "Memory Detail",
4497
- title: "Memory Detail",
4498
- description: "Full content and statistics for a specific memory UUID",
4499
- mimeType: "application/json",
4500
- annotations: { audience: ["assistant"], priority: 0.75 }
4501
- },
4502
- // ── Tasks ────────────────────────────────────────────────────────────────
4503
- {
4504
- uriTemplate: "repository://{name}/tasks",
4505
- name: "Repository Tasks",
4506
- title: "Repository Tasks",
4507
- description: "All active tasks for a specific repository",
4508
- mimeType: "application/json",
4509
- annotations: { audience: ["assistant"], priority: 0.9 }
4510
- },
4511
- {
4512
- uriTemplate: "repository://{name}/tasks?status={status}&priority={priority}",
4513
- name: "Filtered Repository Tasks",
4514
- title: "Filtered Repository Tasks",
4515
- description: "Filter tasks within a repository by status or priority level",
4516
- mimeType: "application/json",
4517
- annotations: { audience: ["assistant"], priority: 0.85 }
4342
+ },
4343
+ {
4344
+ name: "task-create",
4345
+ title: "Task Create",
4346
+ description: "Register one or more new tasks in a repository. task_code must be unique within the repository. Supports single task object or an array of tasks for bulk creation.",
4347
+ annotations: {
4348
+ readOnlyHint: false,
4349
+ idempotentHint: false,
4350
+ openWorldHint: false
4518
4351
  },
4519
- {
4520
- uriTemplate: "task://{id}",
4521
- name: "Task Detail",
4522
- title: "Task Detail",
4523
- description: "Full content and comments for a specific task UUID",
4524
- mimeType: "application/json",
4525
- annotations: { audience: ["assistant"], priority: 0.8 }
4352
+ inputSchema: {
4353
+ type: "object",
4354
+ properties: {
4355
+ repo: { type: "string", description: "Repository name" },
4356
+ task_code: { type: "string", description: "Unique task code (e.g. TASK-001) (Required for single task)" },
4357
+ phase: { type: "string", description: "Project phase (Required for single task)" },
4358
+ title: {
4359
+ type: "string",
4360
+ minLength: 3,
4361
+ maxLength: 100,
4362
+ description: "Task objective (Required for single task)"
4363
+ },
4364
+ description: { type: "string", description: "Detailed description (Required for single task)" },
4365
+ status: {
4366
+ type: "string",
4367
+ enum: ["backlog", "pending"],
4368
+ default: "backlog",
4369
+ description: "New tasks MUST start in 'backlog' if there are already 10 pending tasks. Otherwise can start in 'pending'."
4370
+ },
4371
+ priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
4372
+ agent: { type: "string" },
4373
+ role: { type: "string" },
4374
+ doc_path: { type: "string" },
4375
+ tags: { type: "array", items: { type: "string" } },
4376
+ metadata: { type: "object" },
4377
+ parent_id: { type: "string", format: "uuid" },
4378
+ depends_on: { type: "string", format: "uuid" },
4379
+ est_tokens: { type: "number", minimum: 0, description: "Estimated tokens budget for this task" },
4380
+ tasks: {
4381
+ type: "array",
4382
+ items: {
4383
+ type: "object",
4384
+ properties: {
4385
+ task_code: { type: "string" },
4386
+ phase: { type: "string" },
4387
+ title: { type: "string", minLength: 3, maxLength: 100 },
4388
+ description: { type: "string" },
4389
+ status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
4390
+ priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
4391
+ agent: { type: "string" },
4392
+ role: { type: "string" },
4393
+ doc_path: { type: "string" },
4394
+ tags: { type: "array", items: { type: "string" } },
4395
+ metadata: { type: "object" },
4396
+ parent_id: { type: "string", format: "uuid" },
4397
+ depends_on: { type: "string", format: "uuid" },
4398
+ est_tokens: { type: "number", minimum: 0 }
4399
+ },
4400
+ required: ["task_code", "phase", "title", "description"]
4401
+ },
4402
+ description: "Array of tasks for bulk creation"
4403
+ },
4404
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4405
+ },
4406
+ required: ["repo"]
4526
4407
  },
4527
- // ── Repository extras ────────────────────────────────────────────────────
4528
- {
4529
- uriTemplate: "repository://{name}/summary",
4530
- name: "Repository Summary",
4531
- title: "Repository Summary",
4532
- description: "High-level architectural summary for a repository",
4533
- mimeType: "text/plain",
4534
- annotations: { audience: ["assistant"], priority: 0.95 }
4408
+ outputSchema: {
4409
+ type: "object",
4410
+ properties: {
4411
+ success: { type: "boolean" },
4412
+ id: { type: "string" },
4413
+ task_code: { type: "string" },
4414
+ repo: { type: "string" },
4415
+ phase: { type: "string" },
4416
+ title: { type: "string" },
4417
+ status: { type: "string" },
4418
+ priority: { type: "number" },
4419
+ createdCount: { type: "number" },
4420
+ taskCodes: { type: "array", items: { type: "string" } }
4421
+ },
4422
+ required: ["success", "repo"]
4423
+ }
4424
+ },
4425
+ {
4426
+ name: "task-update",
4427
+ title: "Task Update",
4428
+ description: "Update one or more tasks. Supports single update via 'id' or bulk update via 'ids'. Provide only the fields that need to be changed. MANDATORY WORKFLOW: You cannot move a task from 'pending' or 'blocked' directly to 'completed'. You MUST move it to 'in_progress' first. When changing status to 'completed', include 'est_tokens' with the estimated total tokens actually used for the task.",
4429
+ annotations: {
4430
+ readOnlyHint: false,
4431
+ idempotentHint: false,
4432
+ openWorldHint: false
4535
4433
  },
4536
- {
4537
- uriTemplate: "repository://{name}/actions",
4538
- name: "Repository Actions",
4539
- title: "Repository Actions",
4540
- description: "Audit log of agent tool actions scoped to a repository",
4541
- mimeType: "application/json",
4542
- annotations: { audience: ["assistant"], priority: 0.6 }
4434
+ inputSchema: {
4435
+ type: "object",
4436
+ properties: {
4437
+ repo: { type: "string", description: "Repository name" },
4438
+ id: { type: "string", format: "uuid", description: "Task ID (for single update)" },
4439
+ ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk update)" },
4440
+ task_code: { type: "string" },
4441
+ phase: { type: "string" },
4442
+ title: { type: "string", minLength: 3, maxLength: 100 },
4443
+ description: { type: "string" },
4444
+ status: {
4445
+ type: "string",
4446
+ enum: ["backlog", "pending", "in_progress", "completed", "canceled", "blocked"],
4447
+ description: "New status. Transitions from 'backlog', 'pending' or 'blocked' to 'completed' are NOT allowed."
4448
+ },
4449
+ priority: { type: "number", minimum: 1, maximum: 5 },
4450
+ agent: { type: "string" },
4451
+ role: { type: "string" },
4452
+ model: { type: "string" },
4453
+ comment: {
4454
+ type: "string",
4455
+ description: "REQUIRED when changing task status. Explain WHY the status is changing (e.g., 'Starting implementation', 'Blocked by missing API docs', 'Verified fix')."
4456
+ },
4457
+ doc_path: { type: "string" },
4458
+ tags: { type: "array", items: { type: "string" } },
4459
+ metadata: { type: "object" },
4460
+ parent_id: { type: "string", format: "uuid" },
4461
+ depends_on: { type: "string", format: "uuid" },
4462
+ est_tokens: {
4463
+ type: "number",
4464
+ minimum: 0,
4465
+ description: "Estimated total tokens actually used for this task. Required when status changes to 'completed'."
4466
+ },
4467
+ force: {
4468
+ type: "boolean",
4469
+ description: "If true, bypasses status transition validation (e.g. pending -> completed)."
4470
+ },
4471
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4472
+ },
4473
+ required: ["repo"]
4543
4474
  },
4544
- // ── Action detail ────────────────────────────────────────────────────────
4545
- {
4546
- uriTemplate: "action://{id}",
4547
- name: "Action Detail",
4548
- title: "Action Detail",
4549
- description: "Full details of a specific audit log entry by integer ID",
4550
- mimeType: "application/json",
4551
- annotations: { audience: ["assistant"], priority: 0.55 }
4552
- }
4553
- ];
4554
- return paginateEntries("resourceTemplates", templates, params);
4555
- }
4556
- function completeResourceArgument(resourceUri, argumentName, argumentValue, _contextArguments, dataSources) {
4557
- if (resourceUri === "repository://{name}/memories" || resourceUri === "repository://{name}/memories?search={search}&type={type}&tag={tag}" || resourceUri === "repository://{name}/tasks" || resourceUri === "repository://{name}/tasks?status={status}&priority={priority}" || resourceUri === "repository://{name}/summary" || resourceUri === "repository://{name}/actions") {
4558
- if (argumentName === "name") {
4559
- return rankCompletionValues(dataSources.repos, argumentValue);
4560
- }
4561
- }
4562
- if (resourceUri === "repository://{name}/memories?search={search}&type={type}&tag={tag}") {
4563
- if (argumentName === "tag") {
4564
- return rankCompletionValues(dataSources.tags, argumentValue);
4475
+ outputSchema: {
4476
+ type: "object",
4477
+ properties: {
4478
+ success: { type: "boolean" },
4479
+ id: { type: "string" },
4480
+ ids: { type: "array", items: { type: "string" } },
4481
+ repo: { type: "string" },
4482
+ status: { type: "string" },
4483
+ archivedToMemory: { type: "boolean" },
4484
+ updatedFields: {
4485
+ type: "array",
4486
+ items: { type: "string" }
4487
+ },
4488
+ updatedCount: { type: "number" }
4489
+ },
4490
+ required: ["success", "repo"]
4565
4491
  }
4566
- }
4567
- throw invalidCompletionParams(`Unknown resource template or argument: ${resourceUri} (${argumentName})`);
4568
- }
4569
- function readResource(uri, db, session) {
4570
- logger.info("[Tool] resource.read", { uri });
4571
- if (uri === "repository://index") {
4572
- const repos = db.system.listRepoNavigation();
4573
- const payload = JSON.stringify(repos, null, 2);
4574
- return {
4575
- contents: [
4576
- {
4577
- uri,
4578
- mimeType: "application/json",
4579
- text: payload,
4580
- size: Buffer.byteLength(payload, "utf8"),
4581
- annotations: {
4582
- audience: ["assistant"],
4583
- priority: 1,
4584
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
4585
- }
4586
- }
4587
- ]
4588
- };
4589
- }
4590
- if (uri === "session://roots") {
4591
- const payload = JSON.stringify({ roots: session?.roots ?? [] }, null, 2);
4592
- return {
4593
- contents: [
4594
- {
4595
- uri,
4596
- mimeType: "application/json",
4597
- text: payload,
4598
- size: Buffer.byteLength(payload, "utf8"),
4599
- annotations: {
4600
- audience: ["assistant"],
4601
- priority: 0.95,
4602
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
4603
- }
4604
- }
4605
- ]
4606
- };
4607
- }
4608
- const memoryIdMatch = uri.match(/^memory:\/\/([0-9a-f-]{36})$/i);
4609
- if (memoryIdMatch) {
4610
- const id = memoryIdMatch[1];
4611
- const entry = db.memories.getByIdWithStats(id);
4612
- if (!entry) throw resourceNotFound(`Memory with ID ${id} not found.`, uri);
4613
- const payload = JSON.stringify(entry, null, 2);
4614
- return {
4615
- contents: [
4616
- {
4617
- uri,
4618
- mimeType: "application/json",
4619
- text: payload,
4620
- size: Buffer.byteLength(payload, "utf8"),
4621
- annotations: {
4622
- audience: ["assistant"],
4623
- priority: 0.75,
4624
- lastModified: entry.updated_at || entry.created_at
4625
- }
4626
- }
4627
- ]
4628
- };
4629
- }
4630
- const taskIdMatch = uri.match(/^task:\/\/([0-9a-f-]{36})$/i);
4631
- if (taskIdMatch) {
4632
- const id = taskIdMatch[1];
4633
- const task = db.tasks.getTaskById(id);
4634
- if (!task) throw resourceNotFound(`Task with ID ${id} not found.`, uri);
4635
- const payload = JSON.stringify(task, null, 2);
4636
- return {
4637
- contents: [
4638
- {
4639
- uri,
4640
- mimeType: "application/json",
4641
- text: payload,
4642
- size: Buffer.byteLength(payload, "utf8"),
4643
- annotations: {
4644
- audience: ["assistant"],
4645
- priority: 0.8,
4646
- lastModified: task.updated_at || task.created_at
4647
- }
4492
+ },
4493
+ {
4494
+ name: "task-delete",
4495
+ title: "Task Delete",
4496
+ description: "Delete one or more tasks from a repository. Supports single 'id' or bulk 'ids'.",
4497
+ annotations: {
4498
+ readOnlyHint: false,
4499
+ idempotentHint: false,
4500
+ destructiveHint: true,
4501
+ openWorldHint: false
4502
+ },
4503
+ inputSchema: {
4504
+ type: "object",
4505
+ properties: {
4506
+ repo: { type: "string", description: "Repository name" },
4507
+ id: { type: "string", format: "uuid", description: "Task ID (for single deletion)" },
4508
+ ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk deletion)" },
4509
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4510
+ },
4511
+ required: ["repo"]
4512
+ },
4513
+ outputSchema: {
4514
+ type: "object",
4515
+ properties: {
4516
+ success: { type: "boolean" },
4517
+ id: { type: "string" },
4518
+ ids: { type: "array", items: { type: "string" } },
4519
+ repo: { type: "string" },
4520
+ deletedCount: { type: "number" }
4521
+ },
4522
+ required: ["success", "repo"]
4523
+ }
4524
+ },
4525
+ {
4526
+ name: "task-list",
4527
+ title: "Task List",
4528
+ description: "PRIMARY navigation and search tool for tasks. Returns a compact tabular list of tasks (id, task_code, title, status, priority, updated_at, comments_count). Defaults to in_progress and pending tasks. Use 'query' to filter by code, title, or description. Use 'status' (comma-separated) for specific filters. AGENTS: call this once at start, pick ONE task, then call task-detail.",
4529
+ annotations: {
4530
+ readOnlyHint: true,
4531
+ idempotentHint: true,
4532
+ openWorldHint: false
4533
+ },
4534
+ inputSchema: {
4535
+ type: "object",
4536
+ properties: {
4537
+ repo: {
4538
+ type: "string",
4539
+ description: "Repository name"
4540
+ },
4541
+ status: {
4542
+ type: "string",
4543
+ default: "in_progress,pending",
4544
+ description: "Comma-separated status filter (backlog, pending, in_progress, completed, canceled, blocked). Defaults to 'in_progress,pending'."
4545
+ },
4546
+ phase: {
4547
+ type: "string",
4548
+ description: "Filter by phase (e.g., 'research', 'implementation')"
4549
+ },
4550
+ query: {
4551
+ type: "string",
4552
+ description: "Search keyword matching task code, title, or description"
4553
+ },
4554
+ limit: {
4555
+ type: "number",
4556
+ minimum: 1,
4557
+ maximum: 100,
4558
+ default: 5,
4559
+ description: "Maximum rows to return (default 5)"
4560
+ },
4561
+ offset: {
4562
+ type: "number",
4563
+ minimum: 0,
4564
+ default: 0,
4565
+ description: "Offset for pagination"
4566
+ },
4567
+ structured: {
4568
+ type: "boolean",
4569
+ default: false,
4570
+ description: "If true, returns structured JSON without the text content summary."
4648
4571
  }
4649
- ]
4650
- };
4651
- }
4652
- const repoBase = parseRepoUri(uri);
4653
- if (repoBase) {
4654
- const { name, path: repoPath, query } = repoBase;
4655
- if (repoPath === "summary") {
4656
- const summary = db.summaries.getSummary(name);
4657
- const text = summary?.summary || `No summary available for repository: ${name}`;
4658
- return {
4659
- contents: [
4660
- {
4661
- uri,
4662
- mimeType: "text/plain",
4663
- text,
4664
- size: Buffer.byteLength(text, "utf8"),
4665
- annotations: {
4666
- audience: ["assistant"],
4667
- priority: 0.95,
4668
- lastModified: summary?.updated_at || (/* @__PURE__ */ new Date()).toISOString()
4572
+ },
4573
+ required: ["repo"]
4574
+ },
4575
+ outputSchema: {
4576
+ type: "object",
4577
+ properties: {
4578
+ schema: { type: "string", enum: ["task-list"] },
4579
+ tasks: {
4580
+ type: "object",
4581
+ properties: {
4582
+ columns: {
4583
+ type: "array",
4584
+ items: { type: "string" },
4585
+ description: "Column names in order: id, task_code, title, status, priority, updated_at, comments_count"
4586
+ },
4587
+ rows: {
4588
+ type: "array",
4589
+ items: { type: "array" },
4590
+ description: "Each row: [id, task_code, title, status, priority, updated_at, comments_count]. Use task-detail to fetch full task."
4669
4591
  }
4670
- }
4671
- ]
4672
- };
4592
+ },
4593
+ required: ["columns", "rows"]
4594
+ },
4595
+ count: { type: "number" },
4596
+ offset: { type: "number" }
4597
+ },
4598
+ required: ["schema", "tasks", "count"]
4673
4599
  }
4674
- if (repoPath === "memories") {
4675
- const search = query.get("search") || "";
4676
- const type = query.get("type");
4677
- const tag = query.get("tag");
4678
- const result = db.memories.listMemoriesForDashboard({
4679
- repo: name,
4680
- type: type || void 0,
4681
- tag: tag || void 0,
4682
- search: search || void 0,
4683
- limit: 50
4684
- });
4685
- const entries = result.items;
4686
- const payload = JSON.stringify(entries, null, 2);
4687
- return {
4688
- contents: [
4689
- {
4690
- uri,
4691
- mimeType: "application/json",
4692
- text: payload,
4693
- size: Buffer.byteLength(payload, "utf8"),
4694
- annotations: {
4695
- audience: ["assistant"],
4696
- priority: 0.85,
4697
- lastModified: deriveLastModifiedFromCollection(
4698
- entries.map((e) => e.updated_at || e.created_at)
4699
- )
4700
- }
4701
- }
4702
- ]
4703
- };
4600
+ },
4601
+ {
4602
+ name: "handoff-create",
4603
+ title: "Handoff Create",
4604
+ description: "Create a pending handoff only when unfinished work needs context transfer between agents. Do not use this for completed-work summaries, release notes, validation notes, or archives; put those on task-update/task comments or durable memory.",
4605
+ annotations: {
4606
+ readOnlyHint: false,
4607
+ idempotentHint: false,
4608
+ destructiveHint: false,
4609
+ openWorldHint: false
4610
+ },
4611
+ inputSchema: {
4612
+ type: "object",
4613
+ properties: {
4614
+ repo: { type: "string", description: "Repository name" },
4615
+ from_agent: { type: "string", description: "Agent creating the handoff" },
4616
+ to_agent: { type: "string", description: "Optional target agent" },
4617
+ task_id: { type: "string", format: "uuid", description: "Optional task id to associate" },
4618
+ task_code: { type: "string", description: "Optional task code to associate" },
4619
+ summary: { type: "string", minLength: 1, description: "Concise human-readable transfer summary" },
4620
+ context: {
4621
+ type: "object",
4622
+ description: "Structured handoff context. Include next_steps, blockers, or remaining_work unless a target agent or task is provided."
4623
+ },
4624
+ expires_at: { type: "string", description: "Optional expiration timestamp" },
4625
+ structured: { type: "boolean", default: false }
4626
+ },
4627
+ required: ["repo", "from_agent", "summary"]
4628
+ },
4629
+ outputSchema: {
4630
+ type: "object",
4631
+ properties: {
4632
+ id: { type: "string" },
4633
+ repo: { type: "string" },
4634
+ from_agent: { type: "string" },
4635
+ to_agent: { type: "string", nullable: true },
4636
+ task_id: { type: "string", nullable: true },
4637
+ summary: { type: "string" },
4638
+ context: { type: "object" },
4639
+ status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
4640
+ created_at: { type: "string" },
4641
+ updated_at: { type: "string" },
4642
+ expires_at: { type: "string", nullable: true }
4643
+ },
4644
+ required: ["id", "repo", "from_agent", "summary", "context", "status", "created_at", "updated_at"]
4704
4645
  }
4705
- if (repoPath === "tasks") {
4706
- const status = query.get("status");
4707
- const priority = query.get("priority");
4708
- let tasks;
4709
- if (status && status !== "all") {
4710
- const statuses = status.split(",").map((s) => s.trim());
4711
- tasks = db.tasks.getTasksByMultipleStatuses(name, statuses);
4712
- } else {
4713
- tasks = db.tasks.getTasksByMultipleStatuses(name, ["backlog", "pending", "in_progress", "blocked"]);
4714
- }
4715
- if (priority) {
4716
- const p = Number(priority);
4717
- if (!isNaN(p)) {
4718
- tasks = tasks.filter((t) => t.priority === p);
4719
- }
4720
- }
4721
- const payload = JSON.stringify(tasks, null, 2);
4722
- return {
4723
- contents: [
4724
- {
4725
- uri,
4726
- mimeType: "application/json",
4727
- text: payload,
4728
- size: Buffer.byteLength(payload, "utf8"),
4729
- annotations: {
4730
- audience: ["assistant"],
4731
- priority: 0.9,
4732
- lastModified: deriveLastModifiedFromCollection(tasks.map((t) => t.updated_at))
4646
+ },
4647
+ {
4648
+ name: "handoff-update",
4649
+ title: "Handoff Update",
4650
+ description: "Close or reclassify a handoff after it has been consumed or found stale. Use accepted when transfer context was consumed, rejected when intentionally declined, and expired when the handoff is obsolete or only described completed work.",
4651
+ annotations: {
4652
+ readOnlyHint: false,
4653
+ idempotentHint: false,
4654
+ destructiveHint: false,
4655
+ openWorldHint: false
4656
+ },
4657
+ inputSchema: {
4658
+ type: "object",
4659
+ properties: {
4660
+ id: { type: "string", format: "uuid", description: "Handoff ID" },
4661
+ status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
4662
+ structured: { type: "boolean", default: false }
4663
+ },
4664
+ required: ["id", "status"]
4665
+ },
4666
+ outputSchema: {
4667
+ type: "object",
4668
+ properties: {
4669
+ success: { type: "boolean" },
4670
+ id: { type: "string" },
4671
+ status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] }
4672
+ },
4673
+ required: ["success", "id", "status"]
4674
+ }
4675
+ },
4676
+ {
4677
+ name: "handoff-list",
4678
+ title: "Handoff List",
4679
+ description: "Navigation layer for handoff queues. List repository handoffs with optional status and agent filters, then inspect selected rows before acting.",
4680
+ annotations: {
4681
+ readOnlyHint: true,
4682
+ idempotentHint: true,
4683
+ openWorldHint: false
4684
+ },
4685
+ inputSchema: {
4686
+ type: "object",
4687
+ properties: {
4688
+ repo: { type: "string", description: "Repository name" },
4689
+ status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
4690
+ from_agent: { type: "string" },
4691
+ to_agent: { type: "string" },
4692
+ limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
4693
+ offset: { type: "number", minimum: 0, default: 0 },
4694
+ structured: { type: "boolean", default: false }
4695
+ },
4696
+ required: ["repo"]
4697
+ },
4698
+ outputSchema: {
4699
+ type: "object",
4700
+ properties: {
4701
+ schema: { type: "string", enum: ["handoff-list"] },
4702
+ handoffs: {
4703
+ type: "object",
4704
+ properties: {
4705
+ columns: {
4706
+ type: "array",
4707
+ items: { type: "string" },
4708
+ description: "Column names: [id, from_agent, to_agent, task_id, status, created_at, summary]"
4709
+ },
4710
+ rows: {
4711
+ type: "array",
4712
+ items: { type: "array" },
4713
+ description: "Each row: [id, from_agent, to_agent, task_id, status, created_at, summary]"
4733
4714
  }
4734
- }
4735
- ]
4736
- };
4715
+ },
4716
+ required: ["columns", "rows"]
4717
+ },
4718
+ count: { type: "number" },
4719
+ offset: { type: "number" }
4720
+ },
4721
+ required: ["schema", "handoffs", "count", "offset"]
4737
4722
  }
4738
- if (repoPath === "actions") {
4739
- const actions = db.actions.getRecentActions(name, 100);
4740
- const payload = JSON.stringify(actions, null, 2);
4741
- return {
4742
- contents: [
4743
- {
4744
- uri,
4745
- mimeType: "application/json",
4746
- text: payload,
4747
- size: Buffer.byteLength(payload, "utf8"),
4748
- annotations: {
4749
- audience: ["assistant"],
4750
- priority: 0.6,
4751
- lastModified: deriveLastModifiedFromCollection(actions.map((a) => a.created_at))
4752
- }
4753
- }
4754
- ]
4755
- };
4723
+ },
4724
+ {
4725
+ name: "task-claim",
4726
+ title: "Task Claim",
4727
+ description: "Claim task ownership for an agent using the dedicated claims table. Use this before taking work from task-list; provide either task_id or task_code.",
4728
+ annotations: {
4729
+ readOnlyHint: false,
4730
+ idempotentHint: false,
4731
+ destructiveHint: false,
4732
+ openWorldHint: false
4733
+ },
4734
+ inputSchema: {
4735
+ type: "object",
4736
+ properties: {
4737
+ repo: { type: "string", description: "Repository name" },
4738
+ task_id: { type: "string", format: "uuid", description: "Task id to claim. Optional if task_code is provided." },
4739
+ task_code: { type: "string", description: "Task code to claim. Optional if task_id is provided." },
4740
+ agent: { type: "string", description: "Claiming agent name" },
4741
+ role: { type: "string", description: "Claiming agent role" },
4742
+ metadata: { type: "object", description: "Optional claim metadata" },
4743
+ structured: { type: "boolean", default: false }
4744
+ },
4745
+ required: ["repo", "agent"]
4746
+ },
4747
+ outputSchema: {
4748
+ type: "object",
4749
+ properties: {
4750
+ id: { type: "string" },
4751
+ repo: { type: "string" },
4752
+ task_id: { type: "string" },
4753
+ task_code: { type: "string", nullable: true },
4754
+ agent: { type: "string" },
4755
+ role: { type: "string" },
4756
+ claimed_at: { type: "string" },
4757
+ released_at: { type: "string", nullable: true },
4758
+ metadata: { type: "object" }
4759
+ },
4760
+ required: ["id", "repo", "task_id", "agent", "role", "claimed_at", "metadata"]
4756
4761
  }
4757
- }
4758
- const actionIdMatch = uri.match(/^action:\/\/(\d+)$/);
4759
- if (actionIdMatch) {
4760
- const id = Number(actionIdMatch[1]);
4761
- const action = db.actions.getActionById(id);
4762
- if (!action) throw resourceNotFound(`Action with ID ${id} not found.`, uri);
4763
- const payload = JSON.stringify(action, null, 2);
4764
- return {
4765
- contents: [
4766
- {
4767
- uri,
4768
- mimeType: "application/json",
4769
- text: payload,
4770
- size: Buffer.byteLength(payload, "utf8"),
4771
- annotations: {
4772
- audience: ["assistant"],
4773
- priority: 0.55,
4774
- lastModified: action.created_at
4775
- }
4776
- }
4777
- ]
4778
- };
4779
- }
4780
- throw resourceNotFound(`Unknown resource URI: ${uri}`, uri);
4781
- }
4782
- function parseRepoUri(uri) {
4783
- const prefix = "repository://";
4784
- if (!uri.startsWith(prefix)) return null;
4785
- const rest = uri.slice(prefix.length);
4786
- const queryStart = rest.indexOf("?");
4787
- const withoutQuery = queryStart === -1 ? rest : rest.slice(0, queryStart);
4788
- const queryString = queryStart === -1 ? "" : rest.slice(queryStart + 1);
4789
- const slashIdx = withoutQuery.indexOf("/");
4790
- if (slashIdx === -1) return null;
4791
- const name = withoutQuery.slice(0, slashIdx);
4792
- const path6 = withoutQuery.slice(slashIdx + 1);
4793
- if (!name || !path6) return null;
4794
- return { name, path: path6, query: new URLSearchParams(queryString) };
4795
- }
4796
- function paginateEntries(key, entries, params) {
4797
- const limit = normalizeLimit(params?.limit);
4798
- const offset = decodeCursor(params?.cursor);
4799
- const sliced = entries.slice(offset, offset + limit);
4800
- const nextOffset = offset + sliced.length;
4801
- return {
4802
- [key]: sliced,
4803
- nextCursor: nextOffset < entries.length ? encodeCursor(nextOffset) : void 0
4804
- };
4805
- }
4806
- function normalizeLimit(limit) {
4807
- if (typeof limit !== "number" || !Number.isFinite(limit)) {
4808
- return DEFAULT_PAGE_SIZE;
4809
- }
4810
- return Math.min(MAX_PAGE_SIZE, Math.max(1, Math.trunc(limit)));
4811
- }
4812
- function deriveLastModifiedFromCollection(values) {
4813
- const normalized = values.filter((value) => typeof value === "string" && value.length > 0);
4814
- return normalized.sort().at(-1) ?? (/* @__PURE__ */ new Date()).toISOString();
4815
- }
4816
- function resourceNotFound(message, uri) {
4817
- const error = new Error(message);
4818
- error.code = -32002;
4819
- error.data = { uri };
4820
- return error;
4821
- }
4822
- function invalidCompletionParams(message) {
4823
- const error = new Error(message);
4824
- error.code = -32602;
4825
- return error;
4826
- }
4827
-
4828
- // src/mcp/prompts/loader.ts
4829
- import fs4 from "fs";
4830
- import path5 from "path";
4831
- import { fileURLToPath as fileURLToPath3 } from "url";
4832
- import matter from "gray-matter";
4833
- var __filename = fileURLToPath3(import.meta.url);
4834
- var __dirname2 = path5.dirname(__filename);
4835
- function findPromptDir() {
4836
- const candidates = [
4837
- // Production if chunked into dist/
4838
- "./prompts",
4839
- // Production if inlined into dist/mcp/
4840
- "../prompts",
4841
- // Dev: /src/mcp/prompts/definitions (next to loader.ts)
4842
- "./definitions"
4843
- ].map((relPath) => path5.resolve(__dirname2, relPath));
4844
- for (const dir of candidates) {
4845
- if (fs4.existsSync(dir)) {
4846
- const files = fs4.readdirSync(dir);
4847
- if (files.some((f) => f.endsWith(".md"))) {
4848
- return dir;
4849
- }
4762
+ },
4763
+ {
4764
+ name: "standard-store",
4765
+ title: "Standard Store",
4766
+ description: "Store one atomic coding standard. Use for durable implementation rules with explicit context, stack/language filters, and repo/global scope.",
4767
+ annotations: {
4768
+ readOnlyHint: false,
4769
+ idempotentHint: false,
4770
+ destructiveHint: false,
4771
+ openWorldHint: false
4772
+ },
4773
+ inputSchema: {
4774
+ type: "object",
4775
+ properties: {
4776
+ name: { type: "string", minLength: 3, maxLength: 255, description: "Human-readable standard name" },
4777
+ content: { type: "string", minLength: 10, description: "One atomic, actionable standard written as concise Markdown" },
4778
+ parent_id: { type: "string", format: "uuid", description: "Optional parent standard ID when this rule is a child/specialization." },
4779
+ context: { type: "string", description: "Context or category (e.g., 'error-handling', 'security')" },
4780
+ version: { type: "string", description: "Version of the standard (e.g., '1.0.0')" },
4781
+ language: { type: "string", description: "Programming language (e.g., 'typescript', 'python')" },
4782
+ stack: {
4783
+ type: "array",
4784
+ items: { type: "string" },
4785
+ description: "Technology stack (e.g., ['react', 'nextjs'])"
4786
+ },
4787
+ repo: { type: "string", description: "Repository name for repo-specific standards. Omit only for global standards." },
4788
+ is_global: { type: "boolean", description: "Whether standard applies globally or repo-specific" },
4789
+ tags: {
4790
+ type: "array",
4791
+ items: { type: "string" },
4792
+ description: "Tags for categorization"
4793
+ },
4794
+ metadata: {
4795
+ type: "object",
4796
+ description: "Additional metadata"
4797
+ },
4798
+ agent: { type: "string", description: "Agent creating the standard" },
4799
+ model: { type: "string", description: "AI model used" },
4800
+ structured: { type: "boolean", default: false }
4801
+ },
4802
+ required: ["name", "content", "tags", "metadata"]
4803
+ },
4804
+ outputSchema: {
4805
+ type: "object",
4806
+ properties: {
4807
+ success: { type: "boolean" },
4808
+ standard: {
4809
+ type: "object",
4810
+ properties: {
4811
+ id: { type: "string" },
4812
+ title: { type: "string" },
4813
+ content: { type: "string" },
4814
+ parent_id: { type: "string", nullable: true },
4815
+ context: { type: "string" },
4816
+ version: { type: "string" },
4817
+ language: { type: "string", nullable: true },
4818
+ stack: { type: "array", items: { type: "string" } },
4819
+ is_global: { type: "boolean" },
4820
+ repo: { type: "string", nullable: true },
4821
+ tags: { type: "array", items: { type: "string" } },
4822
+ metadata: { type: "object" },
4823
+ created_at: { type: "string" },
4824
+ updated_at: { type: "string" },
4825
+ agent: { type: "string" },
4826
+ model: { type: "string" }
4827
+ },
4828
+ required: [
4829
+ "id",
4830
+ "title",
4831
+ "content",
4832
+ "parent_id",
4833
+ "context",
4834
+ "version",
4835
+ "stack",
4836
+ "is_global",
4837
+ "tags",
4838
+ "metadata",
4839
+ "created_at",
4840
+ "updated_at",
4841
+ "agent",
4842
+ "model"
4843
+ ]
4844
+ },
4845
+ message: { type: "string" }
4846
+ },
4847
+ required: ["success", "standard", "message"]
4850
4848
  }
4851
- }
4852
- return path5.resolve(__dirname2, "./definitions");
4853
- }
4854
- var PROMPT_DIR = findPromptDir();
4855
- function listPromptFiles() {
4856
- if (!fs4.existsSync(PROMPT_DIR)) return [];
4857
- return fs4.readdirSync(PROMPT_DIR).filter((file) => file.endsWith(".md")).map((file) => file.replace(/\.md$/, "")).sort();
4858
- }
4859
- function loadPromptFromMarkdown(name) {
4860
- const filePath = path5.join(PROMPT_DIR, `${name}.md`);
4861
- if (!fs4.existsSync(filePath)) {
4862
- throw new Error(`Prompt file not found: ${filePath}`);
4863
- }
4864
- const fileContent = fs4.readFileSync(filePath, "utf-8");
4865
- const { data, content } = matter(fileContent);
4866
- return {
4867
- name: data.name || name,
4868
- description: data.description || "",
4869
- arguments: data.arguments || [],
4870
- agent: data.agent,
4871
- content: content.trim()
4872
- };
4873
- }
4874
-
4875
- // src/mcp/prompts/registry.ts
4876
- function createPromptDefinition(loaded) {
4877
- return {
4878
- name: loaded.name,
4879
- description: loaded.description,
4880
- arguments: loaded.arguments,
4881
- agent: loaded.agent,
4882
- messages: [
4883
- {
4884
- role: "user",
4885
- content: {
4886
- type: "text",
4887
- text: loaded.content
4849
+ },
4850
+ {
4851
+ name: "standard-update",
4852
+ title: "Standard Update",
4853
+ description: "Update an existing coding standard. Use this when the rule changes, expands scope, or metadata/tags need correction.",
4854
+ annotations: {
4855
+ readOnlyHint: false,
4856
+ idempotentHint: false,
4857
+ destructiveHint: false,
4858
+ openWorldHint: false
4859
+ },
4860
+ inputSchema: {
4861
+ type: "object",
4862
+ properties: {
4863
+ id: { type: "string", description: "Standard ID to update" },
4864
+ name: { type: "string", minLength: 3, maxLength: 255 },
4865
+ content: { type: "string", minLength: 10 },
4866
+ parent_id: { type: "string", format: "uuid", nullable: true },
4867
+ context: { type: "string" },
4868
+ version: { type: "string" },
4869
+ language: { type: "string" },
4870
+ stack: { type: "array", items: { type: "string" } },
4871
+ repo: { type: "string" },
4872
+ is_global: { type: "boolean" },
4873
+ tags: { type: "array", items: { type: "string" } },
4874
+ metadata: { type: "object" },
4875
+ agent: { type: "string" },
4876
+ model: { type: "string" },
4877
+ structured: { type: "boolean", default: false }
4878
+ },
4879
+ required: ["id"]
4880
+ },
4881
+ outputSchema: {
4882
+ type: "object",
4883
+ properties: {
4884
+ success: { type: "boolean" },
4885
+ id: { type: "string" },
4886
+ updatedFields: { type: "array", items: { type: "string" } }
4887
+ },
4888
+ required: ["success", "id", "updatedFields"]
4889
+ }
4890
+ },
4891
+ {
4892
+ name: "standard-search",
4893
+ title: "Standard Search",
4894
+ description: "NAVIGATION LAYER: Returns a compact pointer table of matching coding standards. Use `standard-detail` to fetch full content for a selected result.",
4895
+ annotations: {
4896
+ readOnlyHint: true,
4897
+ idempotentHint: true,
4898
+ openWorldHint: false
4899
+ },
4900
+ inputSchema: {
4901
+ type: "object",
4902
+ properties: {
4903
+ query: { type: "string", description: "Search query (optional, searches title/content)" },
4904
+ stack: {
4905
+ type: "array",
4906
+ items: { type: "string" },
4907
+ description: "Technology stack to filter by (e.g., ['react', 'nextjs'])"
4908
+ },
4909
+ tags: {
4910
+ type: "array",
4911
+ items: { type: "string" },
4912
+ description: "Tag filter"
4913
+ },
4914
+ language: { type: "string", description: "Programming language filter" },
4915
+ context: { type: "string", description: "Context/category filter" },
4916
+ version: { type: "string", description: "Version filter" },
4917
+ repo: { type: "string", description: "Repository filter (optional)" },
4918
+ is_global: { type: "boolean", description: "Filter by global/repo-specific" },
4919
+ limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
4920
+ offset: { type: "number", minimum: 0, default: 0 },
4921
+ structured: { type: "boolean", default: false }
4922
+ },
4923
+ required: []
4924
+ },
4925
+ outputSchema: {
4926
+ type: "object",
4927
+ properties: {
4928
+ schema: { type: "string", enum: ["standard-search"] },
4929
+ query: { type: "string" },
4930
+ count: { type: "number", description: "Number of rows returned" },
4931
+ total: { type: "number", description: "Total number of matches before pagination" },
4932
+ offset: { type: "number" },
4933
+ limit: { type: "number" },
4934
+ results: {
4935
+ type: "object",
4936
+ properties: {
4937
+ columns: {
4938
+ type: "array",
4939
+ items: { type: "string" }
4940
+ },
4941
+ rows: {
4942
+ type: "array",
4943
+ items: { type: "array" },
4944
+ description: "Each row includes standard id and pointer metadata. Fetch full content via standard-detail."
4945
+ }
4946
+ },
4947
+ required: ["columns", "rows"]
4888
4948
  }
4889
- }
4890
- ]
4891
- };
4892
- }
4893
- var PROMPTS = {};
4894
- var promptFiles = listPromptFiles();
4895
- for (const name of promptFiles) {
4896
- try {
4897
- PROMPTS[name] = createPromptDefinition(loadPromptFromMarkdown(name));
4898
- } catch (e) {
4899
- logger.warn(`Failed to load prompt ${name}: ${e}`);
4900
- }
4901
- }
4902
- async function listPrompts(db, session, params) {
4903
- const allPrompts = Object.values(PROMPTS).map((p) => ({
4904
- name: p.name,
4905
- description: p.description,
4906
- arguments: p.arguments,
4907
- metadata: p.agent ? { agent: p.agent } : void 0
4908
- }));
4909
- const rawLimit = typeof params?.limit === "number" && Number.isInteger(params?.limit) ? params.limit : 25;
4910
- const limit = Math.max(1, Math.min(100, Math.trunc(rawLimit)));
4911
- const offset = decodeCursor(params?.cursor);
4912
- const sliced = allPrompts.slice(offset, offset + limit);
4913
- const nextOffset = offset + sliced.length;
4914
- return {
4915
- prompts: sliced,
4916
- nextCursor: nextOffset < allPrompts.length ? encodeCursor(nextOffset) : void 0
4917
- };
4918
- }
4919
- async function getPrompt(name, args = {}, db, session) {
4920
- const prompt = PROMPTS[name];
4921
- if (!prompt) {
4922
- throw new Error(`Prompt not found: ${name}`);
4923
- }
4924
- const inferredRepo = inferRepoFromSession(session);
4925
- const messages = prompt.messages.map((m) => {
4926
- let text = m.content.text;
4927
- for (const [key, value] of Object.entries(args)) {
4928
- text = text.replace(new RegExp(`\\{{${key}\\}}`, "g"), value);
4949
+ },
4950
+ required: ["schema", "query", "count", "total", "offset", "limit", "results"]
4929
4951
  }
4930
- text = text.replace(/{{current_repo}}/g, inferredRepo || "unknown-repo");
4931
- return {
4932
- ...m,
4933
- content: {
4934
- ...m.content,
4935
- text
4936
- }
4937
- };
4938
- });
4939
- return {
4940
- description: prompt.description,
4941
- messages,
4942
- metadata: prompt.agent ? { agent: prompt.agent } : void 0
4943
- };
4944
- }
4945
- async function completePromptArgument(name, argName, value, contextArguments, dataSources) {
4946
- void name;
4947
- void contextArguments;
4948
- if (argName === "task_id") {
4949
- const values = dataSources.tasks.map((t) => t.id);
4950
- return rankCompletionValues(values, value);
4951
4952
  }
4952
- return [];
4953
- }
4953
+ ];
4954
4954
 
4955
4955
  // src/mcp/tools/standard.shared.ts
4956
4956
  function buildStandardVectorText(standard) {
@@ -4967,17 +4967,31 @@ function buildStandardVectorText(standard) {
4967
4967
  }
4968
4968
 
4969
4969
  export {
4970
- MCP_PROTOCOL_VERSION,
4971
- CAPABILITIES,
4972
4970
  logger,
4973
4971
  setLogLevel,
4974
4972
  getLogLevel,
4975
4973
  addLogSink,
4976
4974
  LOG_LEVEL_VALUES,
4977
4975
  createFileSink,
4976
+ encodeCursor,
4977
+ decodeCursor,
4978
+ listResources,
4979
+ listResourceTemplates,
4980
+ completeResourceArgument,
4981
+ readResource,
4982
+ createSessionContext,
4983
+ updateSessionFromInitialize,
4984
+ updateSessionRoots,
4985
+ extractRootsFromResult,
4986
+ getFilesystemRoots,
4987
+ isPathWithinRoots,
4988
+ findContainingRoot,
4989
+ inferRepoFromSession,
4990
+ PROMPTS,
4991
+ listPrompts,
4992
+ getPrompt,
4993
+ completePromptArgument,
4978
4994
  normalizeRepo,
4979
- SQLiteStore,
4980
- RealVectorStore,
4981
4995
  MemoryStoreSchema,
4982
4996
  MemoryUpdateSchema,
4983
4997
  MemorySearchSchema,
@@ -5003,23 +5017,9 @@ export {
5003
5017
  StandardUpdateSchema,
5004
5018
  StandardSearchSchema,
5005
5019
  TOOL_DEFINITIONS,
5006
- encodeCursor,
5007
- decodeCursor,
5008
- listResources,
5009
- listResourceTemplates,
5010
- completeResourceArgument,
5011
- readResource,
5012
- createSessionContext,
5013
- updateSessionFromInitialize,
5014
- updateSessionRoots,
5015
- extractRootsFromResult,
5016
- getFilesystemRoots,
5017
- isPathWithinRoots,
5018
- findContainingRoot,
5019
- inferRepoFromSession,
5020
- PROMPTS,
5021
- listPrompts,
5022
- getPrompt,
5023
- completePromptArgument,
5024
- buildStandardVectorText
5020
+ buildStandardVectorText,
5021
+ SQLiteStore,
5022
+ RealVectorStore,
5023
+ MCP_PROTOCOL_VERSION,
5024
+ CAPABILITIES
5025
5025
  };