@graphmemory/server 1.3.2 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/rest/graph.js +1 -1
- package/dist/api/rest/index.js +0 -1
- package/dist/api/rest/validation.js +17 -17
- package/dist/api/tools/code/get-file-symbols.js +2 -2
- package/dist/api/tools/code/get-symbol.js +2 -2
- package/dist/api/tools/code/list-files.js +2 -2
- package/dist/api/tools/code/search-code.js +2 -1
- package/dist/api/tools/code/search-files.js +2 -1
- package/dist/api/tools/docs/cross-references.js +2 -1
- package/dist/api/tools/docs/explain-symbol.js +2 -1
- package/dist/api/tools/docs/find-examples.js +2 -1
- package/dist/api/tools/docs/get-node.js +2 -2
- package/dist/api/tools/docs/get-toc.js +2 -2
- package/dist/api/tools/docs/list-snippets.js +4 -4
- package/dist/api/tools/docs/list-topics.js +2 -2
- package/dist/api/tools/docs/search-files.js +2 -1
- package/dist/api/tools/docs/search-snippets.js +3 -2
- package/dist/api/tools/docs/search.js +2 -1
- package/dist/api/tools/file-index/get-file-info.js +2 -2
- package/dist/api/tools/file-index/list-all-files.js +5 -5
- package/dist/api/tools/file-index/search-all-files.js +2 -1
- package/dist/api/tools/knowledge/add-attachment.js +26 -4
- package/dist/api/tools/knowledge/create-note.js +4 -3
- package/dist/api/tools/knowledge/create-relation.js +5 -4
- package/dist/api/tools/knowledge/delete-note.js +2 -2
- package/dist/api/tools/knowledge/delete-relation.js +4 -3
- package/dist/api/tools/knowledge/find-linked-notes.js +4 -3
- package/dist/api/tools/knowledge/get-note.js +2 -2
- package/dist/api/tools/knowledge/list-notes.js +4 -3
- package/dist/api/tools/knowledge/list-relations.js +1 -1
- package/dist/api/tools/knowledge/remove-attachment.js +1 -1
- package/dist/api/tools/knowledge/search-notes.js +2 -1
- package/dist/api/tools/knowledge/update-note.js +6 -5
- package/dist/api/tools/skills/add-attachment.js +26 -4
- package/dist/api/tools/skills/bump-usage.js +2 -2
- package/dist/api/tools/skills/create-skill-link.js +6 -5
- package/dist/api/tools/skills/create-skill.js +8 -7
- package/dist/api/tools/skills/delete-skill-link.js +4 -3
- package/dist/api/tools/skills/delete-skill.js +2 -2
- package/dist/api/tools/skills/find-linked-skills.js +4 -3
- package/dist/api/tools/skills/get-skill.js +2 -2
- package/dist/api/tools/skills/link-skill.js +2 -2
- package/dist/api/tools/skills/list-skills.js +4 -3
- package/dist/api/tools/skills/recall-skills.js +2 -1
- package/dist/api/tools/skills/remove-attachment.js +1 -1
- package/dist/api/tools/skills/search-skills.js +2 -1
- package/dist/api/tools/skills/update-skill.js +10 -9
- package/dist/api/tools/tasks/add-attachment.js +26 -4
- package/dist/api/tools/tasks/create-task-link.js +6 -5
- package/dist/api/tools/tasks/create-task.js +5 -4
- package/dist/api/tools/tasks/delete-task-link.js +4 -3
- package/dist/api/tools/tasks/delete-task.js +2 -2
- package/dist/api/tools/tasks/find-linked-tasks.js +4 -3
- package/dist/api/tools/tasks/get-task.js +2 -2
- package/dist/api/tools/tasks/link-task.js +2 -2
- package/dist/api/tools/tasks/list-tasks.js +5 -4
- package/dist/api/tools/tasks/move-task.js +2 -2
- package/dist/api/tools/tasks/remove-attachment.js +1 -1
- package/dist/api/tools/tasks/search-tasks.js +2 -1
- package/dist/api/tools/tasks/update-task.js +7 -6
- package/dist/cli/indexer.js +2 -0
- package/dist/graphs/code.js +4 -0
- package/dist/graphs/docs.js +4 -0
- package/dist/graphs/file-index.js +4 -0
- package/dist/graphs/knowledge.js +5 -0
- package/dist/graphs/skill.js +5 -0
- package/dist/graphs/task.js +5 -0
- package/dist/lib/defaults.js +1 -1
- package/dist/lib/file-import.js +8 -2
- package/dist/lib/file-mirror.js +77 -21
- package/dist/lib/graph-persistence.js +42 -0
- package/dist/lib/jwt.js +4 -3
- package/dist/lib/promise-queue.js +20 -2
- package/dist/ui/assets/{NoteForm-SQ0b93i0.js → NoteForm-D0lOYBQq.js} +1 -1
- package/dist/ui/assets/{SkillForm-BVsGrNPb.js → SkillForm-CfDWe0Nx.js} +1 -1
- package/dist/ui/assets/{TaskForm-DgPVeiI9.js → TaskForm-ltmMCEAE.js} +1 -1
- package/dist/ui/assets/{_articleId_-FqdaSeYS.js → _articleId_-mEqH7YfV.js} +1 -1
- package/dist/ui/assets/{_docId_-Q0Wmjtp6.js → _docId_-wAt8n8p4.js} +1 -1
- package/dist/ui/assets/{_filePath_-BR0gOT_z.js → _filePath_-DQMFMLQh.js} +1 -1
- package/dist/ui/assets/{_noteId_-BMWd415J.js → _noteId_-Cqxl6H5q.js} +1 -1
- package/dist/ui/assets/{_skillId_-CsHgildJ.js → _skillId_-BlJOfwm_.js} +1 -1
- package/dist/ui/assets/{_taskId_-xDHTfbQw.js → _taskId_-Cs8LaIe4.js} +1 -1
- package/dist/ui/assets/{_toolName_-BSa2uNSu.js → _toolName_-3CHUDagf.js} +1 -1
- package/dist/ui/assets/{attachments-NSvN5_0A.js → attachments-CMDVqPm_.js} +1 -1
- package/dist/ui/assets/{docs-iUK8E40J.js → docs-BuFjplSR.js} +1 -1
- package/dist/ui/assets/{edit-BzIJy_Oo.js → edit-7NV817UE.js} +1 -1
- package/dist/ui/assets/{edit-Dnc067B2.js → edit-Bflx3-cK.js} +1 -1
- package/dist/ui/assets/{edit-U_UEI361.js → edit-CdmIaFUI.js} +1 -1
- package/dist/ui/assets/{esm-BWiKNcBW.js → esm-CqydI1a6.js} +1 -1
- package/dist/ui/assets/{files-B4svJUZh.js → files-BWNbyH1X.js} +1 -1
- package/dist/ui/assets/{graph-CcNP1ckP.js → graph-B9nFxoXm.js} +1 -1
- package/dist/ui/assets/{help-BJZZtKAR.js → help-CqK0hEmf.js} +1 -1
- package/dist/ui/assets/index-80sqSHwS.js +2 -0
- package/dist/ui/assets/{knowledge-CV99ToEV.js → knowledge-g4C4l6uL.js} +1 -1
- package/dist/ui/assets/{new-Dcx8wlp4.js → new-Bqup97cu.js} +1 -1
- package/dist/ui/assets/{new-Sq3NY2oa.js → new-DC3lRvxF.js} +1 -1
- package/dist/ui/assets/{new-BypesKiP.js → new-DbsKrGJ4.js} +1 -1
- package/dist/ui/assets/{prompts-DbsIe3Pm.js → prompts-DyltFLqJ.js} +1 -1
- package/dist/ui/assets/{search-D87r7lIL.js → search-DtRoWsqW.js} +1 -1
- package/dist/ui/assets/{skill-BltAsz7M.js → skill-demt31s6.js} +1 -1
- package/dist/ui/assets/{skills-Dtmg2kDA.js → skills-DRjYPbZM.js} +1 -1
- package/dist/ui/assets/{tasks-BRqIwKCG.js → tasks-CgsSFz6X.js} +1 -1
- package/dist/ui/assets/{tools-CM3gQ4TK.js → tools-BDszA6Kh.js} +1 -1
- package/dist/ui/assets/{vendor-markdown-CT8ZVEPu.js → vendor-markdown-DngssFHR.js} +27 -27
- package/dist/ui/assets/{vendor-md-editor-DmWafJvr.js → vendor-md-editor-DC6xr_29.js} +10 -10
- package/dist/ui/assets/{vendor-mui-BPj7d3Sw.js → vendor-mui-DXUYJbRC.js} +1 -1
- package/dist/ui/assets/{vendor-mui-icons-B196sG3f.js → vendor-mui-icons-YtgP6dg2.js} +1 -1
- package/dist/ui/assets/{vendor-react-CHUjhoxh.js → vendor-react-DxfYAwYK.js} +1 -1
- package/dist/ui/index.html +6 -6
- package/package.json +1 -1
- package/dist/ui/assets/index-CEweXD9O.js +0 -2
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('search_notes', {
|
|
7
8
|
description: 'Semantic search over the knowledge graph (facts and notes). ' +
|
|
@@ -11,7 +12,7 @@ function register(server, mgr) {
|
|
|
11
12
|
'Returns an array sorted by relevance score (0–1), each with: ' +
|
|
12
13
|
'id, title, content, tags, score.',
|
|
13
14
|
inputSchema: {
|
|
14
|
-
query: zod_1.z.string().describe('Natural language search query'),
|
|
15
|
+
query: zod_1.z.string().max(defaults_1.MAX_SEARCH_QUERY_LEN).describe('Natural language search query'),
|
|
15
16
|
topK: zod_1.z.number().min(1).max(500).optional().describe('How many top similar notes to use as seeds (default 5)'),
|
|
16
17
|
bfsDepth: zod_1.z.number().min(0).max(10).optional().describe('How many hops to follow relations from each seed (default 1; 0 = no expansion)'),
|
|
17
18
|
maxResults: zod_1.z.number().min(1).max(500).optional().describe('Maximum number of results to return (default 20)'),
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const manager_types_1 = require("../../../graphs/manager-types");
|
|
6
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
6
7
|
function register(server, mgr) {
|
|
7
8
|
server.registerTool('update_note', {
|
|
8
9
|
description: 'Update an existing note in the knowledge graph. ' +
|
|
@@ -10,17 +11,17 @@ function register(server, mgr) {
|
|
|
10
11
|
'Re-embeds automatically if title or content changes. ' +
|
|
11
12
|
'Pass expectedVersion to enable optimistic locking.',
|
|
12
13
|
inputSchema: {
|
|
13
|
-
noteId: zod_1.z.string().describe('ID of the note to update'),
|
|
14
|
-
title: zod_1.z.string().optional().describe('New title'),
|
|
15
|
-
content: zod_1.z.string().optional().describe('New content'),
|
|
16
|
-
tags: zod_1.z.array(zod_1.z.string()).optional().describe('New tags (replaces existing)'),
|
|
14
|
+
noteId: zod_1.z.string().max(500).describe('ID of the note to update'),
|
|
15
|
+
title: zod_1.z.string().max(defaults_1.MAX_TITLE_LEN).optional().describe('New title'),
|
|
16
|
+
content: zod_1.z.string().max(defaults_1.MAX_NOTE_CONTENT_LEN).optional().describe('New content'),
|
|
17
|
+
tags: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_TAG_LEN)).max(defaults_1.MAX_TAGS_COUNT).optional().describe('New tags (replaces existing)'),
|
|
17
18
|
expectedVersion: zod_1.z.number().int().positive().optional().describe('Current version for optimistic locking — request fails with version_conflict if the note has been updated since'),
|
|
18
19
|
},
|
|
19
20
|
}, async ({ noteId, title, content, tags, expectedVersion }) => {
|
|
20
21
|
try {
|
|
21
22
|
const updated = await mgr.updateNote(noteId, { title, content, tags }, expectedVersion);
|
|
22
23
|
if (!updated) {
|
|
23
|
-
return { content: [{ type: 'text', text:
|
|
24
|
+
return { content: [{ type: 'text', text: 'Note not found' }], isError: true };
|
|
24
25
|
}
|
|
25
26
|
return { content: [{ type: 'text', text: JSON.stringify({ noteId, updated: true }, null, 2) }] };
|
|
26
27
|
}
|
|
@@ -14,14 +14,36 @@ function register(server, mgr) {
|
|
|
14
14
|
'The file is copied into the skill directory (.skills/{skillId}/). ' +
|
|
15
15
|
'Returns attachment metadata (filename, mimeType, size).',
|
|
16
16
|
inputSchema: {
|
|
17
|
-
skillId: zod_1.z.string().describe('ID of the skill to attach the file to'),
|
|
18
|
-
filePath: zod_1.z.string().describe('Absolute path to the file on disk'),
|
|
17
|
+
skillId: zod_1.z.string().max(500).describe('ID of the skill to attach the file to'),
|
|
18
|
+
filePath: zod_1.z.string().max(4096).describe('Absolute path to the file on disk'),
|
|
19
19
|
},
|
|
20
20
|
}, async ({ skillId, filePath }) => {
|
|
21
21
|
const resolved = path_1.default.resolve(filePath);
|
|
22
|
+
const projectDir = mgr.projectDir;
|
|
23
|
+
if (!projectDir) {
|
|
24
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'No project directory configured' }) }], isError: true };
|
|
25
|
+
}
|
|
26
|
+
let realResolved;
|
|
27
|
+
try {
|
|
28
|
+
realResolved = fs_1.default.realpathSync(resolved);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'File not found' }) }], isError: true };
|
|
32
|
+
}
|
|
33
|
+
let realProject;
|
|
34
|
+
try {
|
|
35
|
+
realProject = fs_1.default.realpathSync(path_1.default.resolve(projectDir));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Project directory not found' }) }], isError: true };
|
|
39
|
+
}
|
|
40
|
+
const normalizedProject = realProject + path_1.default.sep;
|
|
41
|
+
if (!realResolved.startsWith(normalizedProject) && realResolved !== realProject) {
|
|
42
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'File path must be within the project directory' }) }], isError: true };
|
|
43
|
+
}
|
|
22
44
|
let stat;
|
|
23
45
|
try {
|
|
24
|
-
stat = fs_1.default.statSync(
|
|
46
|
+
stat = fs_1.default.statSync(realResolved);
|
|
25
47
|
}
|
|
26
48
|
catch {
|
|
27
49
|
return { content: [{ type: 'text', text: JSON.stringify({ error: 'File not found' }) }], isError: true };
|
|
@@ -32,7 +54,7 @@ function register(server, mgr) {
|
|
|
32
54
|
if (stat.size > defaults_1.MAX_UPLOAD_SIZE) {
|
|
33
55
|
return { content: [{ type: 'text', text: JSON.stringify({ error: 'File exceeds 50 MB limit' }) }], isError: true };
|
|
34
56
|
}
|
|
35
|
-
const data = fs_1.default.readFileSync(
|
|
57
|
+
const data = fs_1.default.readFileSync(realResolved);
|
|
36
58
|
const filename = path_1.default.basename(resolved);
|
|
37
59
|
const meta = mgr.addAttachment(skillId, filename, data);
|
|
38
60
|
if (!meta) {
|
|
@@ -7,12 +7,12 @@ function register(server, mgr) {
|
|
|
7
7
|
description: 'Record that a skill was used. Increments usageCount and updates lastUsedAt timestamp. ' +
|
|
8
8
|
'Call this after successfully applying a skill.',
|
|
9
9
|
inputSchema: {
|
|
10
|
-
skillId: zod_1.z.string().describe('Skill ID to bump usage for'),
|
|
10
|
+
skillId: zod_1.z.string().max(500).describe('Skill ID to bump usage for'),
|
|
11
11
|
},
|
|
12
12
|
}, async ({ skillId }) => {
|
|
13
13
|
const ok = mgr.bumpUsage(skillId);
|
|
14
14
|
if (!ok) {
|
|
15
|
-
return { content: [{ type: 'text', text:
|
|
15
|
+
return { content: [{ type: 'text', text: 'Skill not found' }], isError: true };
|
|
16
16
|
}
|
|
17
17
|
return { content: [{ type: 'text', text: JSON.stringify({ skillId, bumped: true }, null, 2) }] };
|
|
18
18
|
});
|
|
@@ -2,23 +2,24 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('create_skill_link', {
|
|
7
8
|
description: 'Link a skill to a node in the docs, code, files, knowledge, or tasks graph. ' +
|
|
8
9
|
'Creates a cross-graph relation from the skill to the target node. ' +
|
|
9
10
|
'The kind is a free-form string, e.g. "references", "implements", "documents".',
|
|
10
11
|
inputSchema: {
|
|
11
|
-
skillId: zod_1.z.string().describe('Source skill ID'),
|
|
12
|
-
targetId: zod_1.z.string().describe('Target node ID in the external graph (e.g. "src/auth.ts::login", "api.md::Setup", "my-note", "my-task")'),
|
|
12
|
+
skillId: zod_1.z.string().max(500).describe('Source skill ID'),
|
|
13
|
+
targetId: zod_1.z.string().max(defaults_1.MAX_TARGET_NODE_ID_LEN).describe('Target node ID in the external graph (e.g. "src/auth.ts::login", "api.md::Setup", "my-note", "my-task")'),
|
|
13
14
|
targetGraph: zod_1.z.enum(['docs', 'code', 'files', 'knowledge', 'tasks'])
|
|
14
15
|
.describe('Which graph the target belongs to'),
|
|
15
|
-
kind: zod_1.z.string().describe('Relation type, e.g. "references", "implements", "documents"'),
|
|
16
|
-
projectId: zod_1.z.string().optional().describe('Project ID that the target node belongs to. Defaults to the current project.'),
|
|
16
|
+
kind: zod_1.z.string().max(defaults_1.MAX_LINK_KIND_LEN).describe('Relation type, e.g. "references", "implements", "documents"'),
|
|
17
|
+
projectId: zod_1.z.string().max(defaults_1.MAX_PROJECT_ID_LEN).optional().describe('Project ID that the target node belongs to. Defaults to the current project.'),
|
|
17
18
|
},
|
|
18
19
|
}, async ({ skillId, targetId, targetGraph, kind, projectId }) => {
|
|
19
20
|
const created = mgr.createCrossLink(skillId, targetId, targetGraph, kind, projectId);
|
|
20
21
|
if (!created) {
|
|
21
|
-
return { content: [{ type: 'text', text:
|
|
22
|
+
return { content: [{ type: 'text', text: 'Could not create cross-graph link — skill not found, target not found, or link already exists.' }], isError: true };
|
|
22
23
|
}
|
|
23
24
|
return { content: [{ type: 'text', text: JSON.stringify({ skillId, targetId, targetGraph, kind, created: true }, null, 2) }] };
|
|
24
25
|
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('create_skill', {
|
|
7
8
|
description: 'Create a new skill (reusable recipe/procedure) in the skill graph. ' +
|
|
@@ -9,13 +10,13 @@ function register(server, mgr) {
|
|
|
9
10
|
'Returns the generated skillId (slug from title). ' +
|
|
10
11
|
'Use link_skill to connect skills, or create_skill_link to link to docs/code/files/knowledge/tasks.',
|
|
11
12
|
inputSchema: {
|
|
12
|
-
title: zod_1.z.string().describe('Short title for the skill, e.g. "Deploy to staging"'),
|
|
13
|
-
description: zod_1.z.string().describe('Full description of the skill (markdown)'),
|
|
14
|
-
steps: zod_1.z.array(zod_1.z.string()).optional().describe('Ordered steps to execute this skill (default [])'),
|
|
15
|
-
triggers: zod_1.z.array(zod_1.z.string()).optional().describe('Conditions or cues that suggest using this skill (default [])'),
|
|
16
|
-
inputHints: zod_1.z.array(zod_1.z.string()).optional().describe('Expected inputs or prerequisites (default [])'),
|
|
17
|
-
filePatterns: zod_1.z.array(zod_1.z.string()).optional().describe('Glob patterns for files this skill applies to (default [])'),
|
|
18
|
-
tags: zod_1.z.array(zod_1.z.string()).optional().describe('Optional tags for filtering, e.g. ["deploy", "ci"]'),
|
|
13
|
+
title: zod_1.z.string().max(defaults_1.MAX_TITLE_LEN).describe('Short title for the skill, e.g. "Deploy to staging"'),
|
|
14
|
+
description: zod_1.z.string().max(defaults_1.MAX_DESCRIPTION_LEN).describe('Full description of the skill (markdown)'),
|
|
15
|
+
steps: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_SKILL_STEP_LEN)).max(defaults_1.MAX_SKILL_STEPS_COUNT).optional().describe('Ordered steps to execute this skill (default [])'),
|
|
16
|
+
triggers: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_SKILL_TRIGGER_LEN)).max(defaults_1.MAX_SKILL_TRIGGERS_COUNT).optional().describe('Conditions or cues that suggest using this skill (default [])'),
|
|
17
|
+
inputHints: zod_1.z.array(zod_1.z.string().max(500)).max(100).optional().describe('Expected inputs or prerequisites (default [])'),
|
|
18
|
+
filePatterns: zod_1.z.array(zod_1.z.string().max(500)).max(100).optional().describe('Glob patterns for files this skill applies to (default [])'),
|
|
19
|
+
tags: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_TAG_LEN)).max(defaults_1.MAX_TAGS_COUNT).optional().describe('Optional tags for filtering, e.g. ["deploy", "ci"]'),
|
|
19
20
|
source: zod_1.z.enum(['user', 'learned']).optional().describe('How this skill was created (default "user")'),
|
|
20
21
|
confidence: zod_1.z.number().min(0).max(1).optional().describe('Confidence score 0–1 (default 1)'),
|
|
21
22
|
},
|
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('delete_skill_link', {
|
|
7
8
|
description: 'Remove a cross-graph link from a skill to a node in the docs, code, files, knowledge, or tasks graph. ' +
|
|
8
9
|
'Orphaned proxy nodes are cleaned up automatically.',
|
|
9
10
|
inputSchema: {
|
|
10
|
-
skillId: zod_1.z.string().describe('Source skill ID'),
|
|
11
|
-
targetId: zod_1.z.string().describe('Target node ID in the external graph'),
|
|
11
|
+
skillId: zod_1.z.string().max(500).describe('Source skill ID'),
|
|
12
|
+
targetId: zod_1.z.string().max(defaults_1.MAX_TARGET_NODE_ID_LEN).describe('Target node ID in the external graph'),
|
|
12
13
|
targetGraph: zod_1.z.enum(['docs', 'code', 'files', 'knowledge', 'tasks'])
|
|
13
14
|
.describe('Which graph the target belongs to'),
|
|
14
|
-
projectId: zod_1.z.string().optional().describe('Project ID that the target node belongs to. Defaults to the current project.'),
|
|
15
|
+
projectId: zod_1.z.string().max(defaults_1.MAX_PROJECT_ID_LEN).optional().describe('Project ID that the target node belongs to. Defaults to the current project.'),
|
|
15
16
|
},
|
|
16
17
|
}, async ({ skillId, targetId, targetGraph, projectId }) => {
|
|
17
18
|
const deleted = mgr.deleteCrossLink(skillId, targetId, targetGraph, projectId);
|
|
@@ -8,12 +8,12 @@ function register(server, mgr) {
|
|
|
8
8
|
'Orphaned proxy nodes are cleaned up automatically. ' +
|
|
9
9
|
'This action is irreversible.',
|
|
10
10
|
inputSchema: {
|
|
11
|
-
skillId: zod_1.z.string().describe('Skill ID to delete'),
|
|
11
|
+
skillId: zod_1.z.string().max(500).describe('Skill ID to delete'),
|
|
12
12
|
},
|
|
13
13
|
}, async ({ skillId }) => {
|
|
14
14
|
const deleted = mgr.deleteSkill(skillId);
|
|
15
15
|
if (!deleted) {
|
|
16
|
-
return { content: [{ type: 'text', text:
|
|
16
|
+
return { content: [{ type: 'text', text: 'Skill not found' }], isError: true };
|
|
17
17
|
}
|
|
18
18
|
return { content: [{ type: 'text', text: JSON.stringify({ skillId, deleted: true }, null, 2) }] };
|
|
19
19
|
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('find_linked_skills', {
|
|
7
8
|
description: 'Find all skills that link to a specific node in the docs, code, files, knowledge, or tasks graph. ' +
|
|
@@ -11,9 +12,9 @@ function register(server, mgr) {
|
|
|
11
12
|
inputSchema: {
|
|
12
13
|
targetGraph: zod_1.z.enum(['docs', 'code', 'files', 'knowledge', 'tasks'])
|
|
13
14
|
.describe('Which graph the target belongs to'),
|
|
14
|
-
targetNodeId: zod_1.z.string().describe('Target node ID in the external graph'),
|
|
15
|
-
kind: zod_1.z.string().optional().describe('Filter by relation kind. If omitted, returns all relations.'),
|
|
16
|
-
projectId: zod_1.z.string().optional().describe('Project ID that the target node belongs to. Defaults to the current project.'),
|
|
15
|
+
targetNodeId: zod_1.z.string().max(defaults_1.MAX_TARGET_NODE_ID_LEN).describe('Target node ID in the external graph'),
|
|
16
|
+
kind: zod_1.z.string().max(defaults_1.MAX_LINK_KIND_LEN).optional().describe('Filter by relation kind. If omitted, returns all relations.'),
|
|
17
|
+
projectId: zod_1.z.string().max(defaults_1.MAX_PROJECT_ID_LEN).optional().describe('Project ID that the target node belongs to. Defaults to the current project.'),
|
|
17
18
|
},
|
|
18
19
|
}, async ({ targetGraph, targetNodeId, kind, projectId }) => {
|
|
19
20
|
const results = mgr.findLinkedSkills(targetGraph, targetNodeId, kind, projectId);
|
|
@@ -9,12 +9,12 @@ function register(server, mgr) {
|
|
|
9
9
|
'Returns: id, title, description, steps, triggers, inputHints, filePatterns, tags, ' +
|
|
10
10
|
'source, confidence, usageCount, lastUsedAt, createdAt, updatedAt, crossLinks[].',
|
|
11
11
|
inputSchema: {
|
|
12
|
-
skillId: zod_1.z.string().describe('Skill ID to retrieve'),
|
|
12
|
+
skillId: zod_1.z.string().max(500).describe('Skill ID to retrieve'),
|
|
13
13
|
},
|
|
14
14
|
}, async ({ skillId }) => {
|
|
15
15
|
const skill = mgr.getSkill(skillId);
|
|
16
16
|
if (!skill) {
|
|
17
|
-
return { content: [{ type: 'text', text:
|
|
17
|
+
return { content: [{ type: 'text', text: 'Skill not found' }], isError: true };
|
|
18
18
|
}
|
|
19
19
|
return { content: [{ type: 'text', text: JSON.stringify(skill, null, 2) }] };
|
|
20
20
|
});
|
|
@@ -9,8 +9,8 @@ function register(server, mgr) {
|
|
|
9
9
|
'"related_to": free association between skills. ' +
|
|
10
10
|
'"variant_of": fromId is a variant of toId.',
|
|
11
11
|
inputSchema: {
|
|
12
|
-
fromId: zod_1.z.string().describe('Source skill ID'),
|
|
13
|
-
toId: zod_1.z.string().describe('Target skill ID'),
|
|
12
|
+
fromId: zod_1.z.string().max(500).describe('Source skill ID'),
|
|
13
|
+
toId: zod_1.z.string().max(500).describe('Target skill ID'),
|
|
14
14
|
kind: zod_1.z.enum(['depends_on', 'related_to', 'variant_of']).describe('Relation type'),
|
|
15
15
|
},
|
|
16
16
|
}, async ({ fromId, toId, kind }) => {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('list_skills', {
|
|
7
8
|
description: 'List skills with optional filters. ' +
|
|
@@ -9,9 +10,9 @@ function register(server, mgr) {
|
|
|
9
10
|
'Use search_skills for semantic search.',
|
|
10
11
|
inputSchema: {
|
|
11
12
|
source: zod_1.z.enum(['user', 'learned']).optional().describe('Filter by source'),
|
|
12
|
-
tag: zod_1.z.string().optional().describe('Filter by tag (exact match, case-insensitive)'),
|
|
13
|
-
filter: zod_1.z.string().optional().describe('Substring match on title or ID'),
|
|
14
|
-
limit: zod_1.z.number().optional().describe('Max results (default 50)'),
|
|
13
|
+
tag: zod_1.z.string().max(defaults_1.MAX_TAG_LEN).optional().describe('Filter by tag (exact match, case-insensitive)'),
|
|
14
|
+
filter: zod_1.z.string().max(500).optional().describe('Substring match on title or ID'),
|
|
15
|
+
limit: zod_1.z.number().max(1000).optional().describe('Max results (default 50)'),
|
|
15
16
|
},
|
|
16
17
|
}, async ({ source, tag, filter, limit }) => {
|
|
17
18
|
const results = mgr.listSkills({ source, tag, filter, limit });
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('recall_skills', {
|
|
7
8
|
description: 'Recall relevant skills for a given task context. Like search_skills but with lower ' +
|
|
8
9
|
'minScore default (0.3) for higher recall. Use at the start of a task to find applicable recipes.',
|
|
9
10
|
inputSchema: {
|
|
10
|
-
context: zod_1.z.string().describe('Description of the current task or context to match skills against'),
|
|
11
|
+
context: zod_1.z.string().max(defaults_1.MAX_SEARCH_QUERY_LEN).describe('Description of the current task or context to match skills against'),
|
|
11
12
|
topK: zod_1.z.number().min(1).max(500).optional().describe('How many top similar skills to use as seeds (default 5)'),
|
|
12
13
|
minScore: zod_1.z.number().min(0).max(1).optional().describe('Minimum relevance score 0–1 (default 0.3)'),
|
|
13
14
|
},
|
|
@@ -6,7 +6,7 @@ function register(server, mgr) {
|
|
|
6
6
|
server.registerTool('remove_skill_attachment', {
|
|
7
7
|
description: 'Remove an attachment from a skill. The file is deleted from disk.',
|
|
8
8
|
inputSchema: {
|
|
9
|
-
skillId: zod_1.z.string().describe('ID of the skill'),
|
|
9
|
+
skillId: zod_1.z.string().max(500).describe('ID of the skill'),
|
|
10
10
|
filename: zod_1.z.string().min(1).max(255)
|
|
11
11
|
.refine(s => !/[/\\]/.test(s), 'Filename must not contain path separators')
|
|
12
12
|
.refine(s => !s.includes('..'), 'Filename must not contain ..')
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('search_skills', {
|
|
7
8
|
description: 'Semantic search over the skill graph. ' +
|
|
@@ -11,7 +12,7 @@ function register(server, mgr) {
|
|
|
11
12
|
'Returns an array sorted by relevance score (0–1), each with: ' +
|
|
12
13
|
'id, title, description, tags, source, confidence, usageCount, score.',
|
|
13
14
|
inputSchema: {
|
|
14
|
-
query: zod_1.z.string().describe('Natural language search query'),
|
|
15
|
+
query: zod_1.z.string().max(defaults_1.MAX_SEARCH_QUERY_LEN).describe('Natural language search query'),
|
|
15
16
|
topK: zod_1.z.number().min(1).max(500).optional().describe('How many top similar skills to use as seeds (default 5)'),
|
|
16
17
|
bfsDepth: zod_1.z.number().min(0).max(10).optional().describe('How many hops to follow relations from each seed (default 1; 0 = no expansion)'),
|
|
17
18
|
maxResults: zod_1.z.number().min(1).max(500).optional().describe('Maximum number of results to return (default 20)'),
|
|
@@ -3,20 +3,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const manager_types_1 = require("../../../graphs/manager-types");
|
|
6
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
6
7
|
function register(server, mgr) {
|
|
7
8
|
server.registerTool('update_skill', {
|
|
8
9
|
description: 'Update an existing skill. Only provided fields are changed. ' +
|
|
9
10
|
'Re-embeds automatically when title or description changes. ' +
|
|
10
11
|
'Pass expectedVersion to enable optimistic locking.',
|
|
11
12
|
inputSchema: {
|
|
12
|
-
skillId: zod_1.z.string().describe('Skill ID to update'),
|
|
13
|
-
title: zod_1.z.string().optional().describe('New title'),
|
|
14
|
-
description: zod_1.z.string().optional().describe('New description'),
|
|
15
|
-
steps: zod_1.z.array(zod_1.z.string()).optional().describe('Replace steps array'),
|
|
16
|
-
triggers: zod_1.z.array(zod_1.z.string()).optional().describe('Replace triggers array'),
|
|
17
|
-
inputHints: zod_1.z.array(zod_1.z.string()).optional().describe('Replace inputHints array'),
|
|
18
|
-
filePatterns: zod_1.z.array(zod_1.z.string()).optional().describe('Replace filePatterns array'),
|
|
19
|
-
tags: zod_1.z.array(zod_1.z.string()).optional().describe('Replace tags array'),
|
|
13
|
+
skillId: zod_1.z.string().max(500).describe('Skill ID to update'),
|
|
14
|
+
title: zod_1.z.string().max(defaults_1.MAX_TITLE_LEN).optional().describe('New title'),
|
|
15
|
+
description: zod_1.z.string().max(defaults_1.MAX_DESCRIPTION_LEN).optional().describe('New description'),
|
|
16
|
+
steps: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_SKILL_STEP_LEN)).max(defaults_1.MAX_SKILL_STEPS_COUNT).optional().describe('Replace steps array'),
|
|
17
|
+
triggers: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_SKILL_TRIGGER_LEN)).max(defaults_1.MAX_SKILL_TRIGGERS_COUNT).optional().describe('Replace triggers array'),
|
|
18
|
+
inputHints: zod_1.z.array(zod_1.z.string().max(500)).max(100).optional().describe('Replace inputHints array'),
|
|
19
|
+
filePatterns: zod_1.z.array(zod_1.z.string().max(500)).max(100).optional().describe('Replace filePatterns array'),
|
|
20
|
+
tags: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_TAG_LEN)).max(defaults_1.MAX_TAGS_COUNT).optional().describe('Replace tags array'),
|
|
20
21
|
source: zod_1.z.enum(['user', 'learned']).optional().describe('New source'),
|
|
21
22
|
confidence: zod_1.z.number().min(0).max(1).optional().describe('New confidence score 0–1'),
|
|
22
23
|
expectedVersion: zod_1.z.number().int().positive().optional().describe('Current version for optimistic locking — request fails with version_conflict if the skill has been updated since'),
|
|
@@ -44,7 +45,7 @@ function register(server, mgr) {
|
|
|
44
45
|
try {
|
|
45
46
|
const updated = await mgr.updateSkill(skillId, patch, expectedVersion);
|
|
46
47
|
if (!updated) {
|
|
47
|
-
return { content: [{ type: 'text', text:
|
|
48
|
+
return { content: [{ type: 'text', text: 'Skill not found' }], isError: true };
|
|
48
49
|
}
|
|
49
50
|
return { content: [{ type: 'text', text: JSON.stringify({ skillId, updated: true }, null, 2) }] };
|
|
50
51
|
}
|
|
@@ -14,14 +14,36 @@ function register(server, mgr) {
|
|
|
14
14
|
'The file is copied into the task directory (.tasks/{taskId}/). ' +
|
|
15
15
|
'Returns attachment metadata (filename, mimeType, size).',
|
|
16
16
|
inputSchema: {
|
|
17
|
-
taskId: zod_1.z.string().describe('ID of the task to attach the file to'),
|
|
18
|
-
filePath: zod_1.z.string().describe('Absolute path to the file on disk'),
|
|
17
|
+
taskId: zod_1.z.string().max(500).describe('ID of the task to attach the file to'),
|
|
18
|
+
filePath: zod_1.z.string().max(4096).describe('Absolute path to the file on disk'),
|
|
19
19
|
},
|
|
20
20
|
}, async ({ taskId, filePath }) => {
|
|
21
21
|
const resolved = path_1.default.resolve(filePath);
|
|
22
|
+
const projectDir = mgr.projectDir;
|
|
23
|
+
if (!projectDir) {
|
|
24
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'No project directory configured' }) }], isError: true };
|
|
25
|
+
}
|
|
26
|
+
let realResolved;
|
|
27
|
+
try {
|
|
28
|
+
realResolved = fs_1.default.realpathSync(resolved);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'File not found' }) }], isError: true };
|
|
32
|
+
}
|
|
33
|
+
let realProject;
|
|
34
|
+
try {
|
|
35
|
+
realProject = fs_1.default.realpathSync(path_1.default.resolve(projectDir));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Project directory not found' }) }], isError: true };
|
|
39
|
+
}
|
|
40
|
+
const normalizedProject = realProject + path_1.default.sep;
|
|
41
|
+
if (!realResolved.startsWith(normalizedProject) && realResolved !== realProject) {
|
|
42
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'File path must be within the project directory' }) }], isError: true };
|
|
43
|
+
}
|
|
22
44
|
let stat;
|
|
23
45
|
try {
|
|
24
|
-
stat = fs_1.default.statSync(
|
|
46
|
+
stat = fs_1.default.statSync(realResolved);
|
|
25
47
|
}
|
|
26
48
|
catch {
|
|
27
49
|
return { content: [{ type: 'text', text: JSON.stringify({ error: 'File not found' }) }], isError: true };
|
|
@@ -32,7 +54,7 @@ function register(server, mgr) {
|
|
|
32
54
|
if (stat.size > defaults_1.MAX_UPLOAD_SIZE) {
|
|
33
55
|
return { content: [{ type: 'text', text: JSON.stringify({ error: 'File exceeds 50 MB limit' }) }], isError: true };
|
|
34
56
|
}
|
|
35
|
-
const data = fs_1.default.readFileSync(
|
|
57
|
+
const data = fs_1.default.readFileSync(realResolved);
|
|
36
58
|
const filename = path_1.default.basename(resolved);
|
|
37
59
|
const meta = mgr.addAttachment(taskId, filename, data);
|
|
38
60
|
if (!meta) {
|
|
@@ -2,23 +2,24 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('create_task_link', {
|
|
7
8
|
description: 'Link a task to a node in the docs, code, files, or knowledge graph. ' +
|
|
8
9
|
'Creates a cross-graph relation from the task to the target node. ' +
|
|
9
10
|
'The kind is a free-form string, e.g. "references", "fixes", "implements", "documents".',
|
|
10
11
|
inputSchema: {
|
|
11
|
-
taskId: zod_1.z.string().describe('Source task ID'),
|
|
12
|
-
targetId: zod_1.z.string().describe('Target node ID in the external graph (e.g. "src/auth.ts::login", "api.md::Setup", "my-note")'),
|
|
12
|
+
taskId: zod_1.z.string().max(500).describe('Source task ID'),
|
|
13
|
+
targetId: zod_1.z.string().max(defaults_1.MAX_TARGET_NODE_ID_LEN).describe('Target node ID in the external graph (e.g. "src/auth.ts::login", "api.md::Setup", "my-note")'),
|
|
13
14
|
targetGraph: zod_1.z.enum(['docs', 'code', 'files', 'knowledge', 'skills'])
|
|
14
15
|
.describe('Which graph the target belongs to'),
|
|
15
|
-
kind: zod_1.z.string().describe('Relation type, e.g. "references", "fixes", "implements"'),
|
|
16
|
-
projectId: zod_1.z.string().optional().describe('Project ID that the target node belongs to. Defaults to the current project.'),
|
|
16
|
+
kind: zod_1.z.string().max(defaults_1.MAX_LINK_KIND_LEN).describe('Relation type, e.g. "references", "fixes", "implements"'),
|
|
17
|
+
projectId: zod_1.z.string().max(defaults_1.MAX_PROJECT_ID_LEN).optional().describe('Project ID that the target node belongs to. Defaults to the current project.'),
|
|
17
18
|
},
|
|
18
19
|
}, async ({ taskId, targetId, targetGraph, kind, projectId }) => {
|
|
19
20
|
const created = mgr.createCrossLink(taskId, targetId, targetGraph, kind, projectId);
|
|
20
21
|
if (!created) {
|
|
21
|
-
return { content: [{ type: 'text', text:
|
|
22
|
+
return { content: [{ type: 'text', text: 'Could not create cross-graph link — task not found, target not found, or link already exists.' }], isError: true };
|
|
22
23
|
}
|
|
23
24
|
return { content: [{ type: 'text', text: JSON.stringify({ taskId, targetId, targetGraph, kind, created: true }, null, 2) }] };
|
|
24
25
|
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('create_task', {
|
|
7
8
|
description: 'Create a new task in the task graph. ' +
|
|
@@ -9,15 +10,15 @@ function register(server, mgr) {
|
|
|
9
10
|
'Returns the generated taskId (slug from title). ' +
|
|
10
11
|
'Use link_task to connect tasks, or create_task_link to link to docs/code/files/knowledge.',
|
|
11
12
|
inputSchema: {
|
|
12
|
-
title: zod_1.z.string().describe('Short title for the task, e.g. "Fix auth redirect loop"'),
|
|
13
|
-
description: zod_1.z.string().describe('Full description of the task (markdown)'),
|
|
13
|
+
title: zod_1.z.string().max(defaults_1.MAX_TITLE_LEN).describe('Short title for the task, e.g. "Fix auth redirect loop"'),
|
|
14
|
+
description: zod_1.z.string().max(defaults_1.MAX_DESCRIPTION_LEN).describe('Full description of the task (markdown)'),
|
|
14
15
|
priority: zod_1.z.enum(['critical', 'high', 'medium', 'low']).describe('Task priority'),
|
|
15
16
|
status: zod_1.z.enum(['backlog', 'todo', 'in_progress', 'review', 'done', 'cancelled']).optional()
|
|
16
17
|
.describe('Initial status (default "backlog")'),
|
|
17
|
-
tags: zod_1.z.array(zod_1.z.string()).optional().describe('Optional tags for filtering, e.g. ["bug", "auth"]'),
|
|
18
|
+
tags: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_TAG_LEN)).max(defaults_1.MAX_TAGS_COUNT).optional().describe('Optional tags for filtering, e.g. ["bug", "auth"]'),
|
|
18
19
|
dueDate: zod_1.z.number().optional().describe('Due date as Unix timestamp in milliseconds'),
|
|
19
20
|
estimate: zod_1.z.number().optional().describe('Estimated effort in hours'),
|
|
20
|
-
assignee: zod_1.z.string().optional().describe('Team member ID to assign the task to'),
|
|
21
|
+
assignee: zod_1.z.string().max(defaults_1.MAX_ASSIGNEE_LEN).optional().describe('Team member ID to assign the task to'),
|
|
21
22
|
},
|
|
22
23
|
}, async ({ title, description, priority, status, tags, dueDate, estimate, assignee }) => {
|
|
23
24
|
const taskId = await mgr.createTask(title, description, status ?? 'backlog', priority, tags ?? [], dueDate ?? null, estimate ?? null, assignee ?? null);
|
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('delete_task_link', {
|
|
7
8
|
description: 'Remove a cross-graph link from a task to a node in the docs, code, files, or knowledge graph. ' +
|
|
8
9
|
'Orphaned proxy nodes are cleaned up automatically.',
|
|
9
10
|
inputSchema: {
|
|
10
|
-
taskId: zod_1.z.string().describe('Source task ID'),
|
|
11
|
-
targetId: zod_1.z.string().describe('Target node ID in the external graph'),
|
|
11
|
+
taskId: zod_1.z.string().max(500).describe('Source task ID'),
|
|
12
|
+
targetId: zod_1.z.string().max(defaults_1.MAX_TARGET_NODE_ID_LEN).describe('Target node ID in the external graph'),
|
|
12
13
|
targetGraph: zod_1.z.enum(['docs', 'code', 'files', 'knowledge', 'skills'])
|
|
13
14
|
.describe('Which graph the target belongs to'),
|
|
14
|
-
projectId: zod_1.z.string().optional().describe('Project ID that the target node belongs to. Defaults to the current project.'),
|
|
15
|
+
projectId: zod_1.z.string().max(defaults_1.MAX_PROJECT_ID_LEN).optional().describe('Project ID that the target node belongs to. Defaults to the current project.'),
|
|
15
16
|
},
|
|
16
17
|
}, async ({ taskId, targetId, targetGraph, projectId }) => {
|
|
17
18
|
const deleted = mgr.deleteCrossLink(taskId, targetId, targetGraph, projectId);
|
|
@@ -8,12 +8,12 @@ function register(server, mgr) {
|
|
|
8
8
|
'Orphaned proxy nodes are cleaned up automatically. ' +
|
|
9
9
|
'This action is irreversible.',
|
|
10
10
|
inputSchema: {
|
|
11
|
-
taskId: zod_1.z.string().describe('Task ID to delete'),
|
|
11
|
+
taskId: zod_1.z.string().max(500).describe('Task ID to delete'),
|
|
12
12
|
},
|
|
13
13
|
}, async ({ taskId }) => {
|
|
14
14
|
const deleted = mgr.deleteTask(taskId);
|
|
15
15
|
if (!deleted) {
|
|
16
|
-
return { content: [{ type: 'text', text:
|
|
16
|
+
return { content: [{ type: 'text', text: 'Task not found' }], isError: true };
|
|
17
17
|
}
|
|
18
18
|
return { content: [{ type: 'text', text: JSON.stringify({ taskId, deleted: true }, null, 2) }] };
|
|
19
19
|
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('find_linked_tasks', {
|
|
7
8
|
description: 'Find all tasks that link to a specific node in the docs, code, files, or knowledge graph. ' +
|
|
@@ -9,11 +10,11 @@ function register(server, mgr) {
|
|
|
9
10
|
'Returns an array of { taskId, title, kind, status, priority, tags }. ' +
|
|
10
11
|
'Use get_task to fetch full content of a returned task.',
|
|
11
12
|
inputSchema: {
|
|
12
|
-
targetId: zod_1.z.string().describe('Target node ID in the external graph'),
|
|
13
|
+
targetId: zod_1.z.string().max(defaults_1.MAX_TARGET_NODE_ID_LEN).describe('Target node ID in the external graph'),
|
|
13
14
|
targetGraph: zod_1.z.enum(['docs', 'code', 'files', 'knowledge', 'skills'])
|
|
14
15
|
.describe('Which graph the target belongs to'),
|
|
15
|
-
kind: zod_1.z.string().optional().describe('Filter by relation kind. If omitted, returns all relations.'),
|
|
16
|
-
projectId: zod_1.z.string().optional().describe('Project ID that the target node belongs to. Defaults to the current project.'),
|
|
16
|
+
kind: zod_1.z.string().max(defaults_1.MAX_LINK_KIND_LEN).optional().describe('Filter by relation kind. If omitted, returns all relations.'),
|
|
17
|
+
projectId: zod_1.z.string().max(defaults_1.MAX_PROJECT_ID_LEN).optional().describe('Project ID that the target node belongs to. Defaults to the current project.'),
|
|
17
18
|
},
|
|
18
19
|
}, async ({ targetId, targetGraph, kind, projectId }) => {
|
|
19
20
|
const results = mgr.findLinkedTasks(targetGraph, targetId, kind, projectId);
|
|
@@ -8,12 +8,12 @@ function register(server, mgr) {
|
|
|
8
8
|
'Returns: id, title, description, status, priority, tags, dueDate, estimate, ' +
|
|
9
9
|
'completedAt, createdAt, updatedAt, subtasks[], blockedBy[], blocks[], related[], crossLinks[].',
|
|
10
10
|
inputSchema: {
|
|
11
|
-
taskId: zod_1.z.string().describe('Task ID to retrieve'),
|
|
11
|
+
taskId: zod_1.z.string().max(500).describe('Task ID to retrieve'),
|
|
12
12
|
},
|
|
13
13
|
}, async ({ taskId }) => {
|
|
14
14
|
const task = mgr.getTask(taskId);
|
|
15
15
|
if (!task) {
|
|
16
|
-
return { content: [{ type: 'text', text:
|
|
16
|
+
return { content: [{ type: 'text', text: 'Task not found' }], isError: true };
|
|
17
17
|
}
|
|
18
18
|
return { content: [{ type: 'text', text: JSON.stringify(task, null, 2) }] };
|
|
19
19
|
});
|
|
@@ -9,8 +9,8 @@ function register(server, mgr) {
|
|
|
9
9
|
'"blocks": fromId blocks toId. ' +
|
|
10
10
|
'"related_to": free association between tasks.',
|
|
11
11
|
inputSchema: {
|
|
12
|
-
fromId: zod_1.z.string().describe('Source task ID'),
|
|
13
|
-
toId: zod_1.z.string().describe('Target task ID'),
|
|
12
|
+
fromId: zod_1.z.string().max(500).describe('Source task ID'),
|
|
13
|
+
toId: zod_1.z.string().max(500).describe('Target task ID'),
|
|
14
14
|
kind: zod_1.z.enum(['subtask_of', 'blocks', 'related_to']).describe('Relation type'),
|
|
15
15
|
},
|
|
16
16
|
}, async ({ fromId, toId, kind }) => {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.register = register;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const defaults_1 = require("../../../lib/defaults");
|
|
5
6
|
function register(server, mgr) {
|
|
6
7
|
server.registerTool('list_tasks', {
|
|
7
8
|
description: 'List tasks with optional filters. ' +
|
|
@@ -13,10 +14,10 @@ function register(server, mgr) {
|
|
|
13
14
|
.describe('Filter by status'),
|
|
14
15
|
priority: zod_1.z.enum(['critical', 'high', 'medium', 'low']).optional()
|
|
15
16
|
.describe('Filter by priority'),
|
|
16
|
-
tag: zod_1.z.string().optional().describe('Filter by tag (exact match, case-insensitive)'),
|
|
17
|
-
filter: zod_1.z.string().optional().describe('Substring match on title or ID'),
|
|
18
|
-
assignee: zod_1.z.string().optional().describe('Filter by assignee (team member ID)'),
|
|
19
|
-
limit: zod_1.z.number().optional().describe('Max results (default 50)'),
|
|
17
|
+
tag: zod_1.z.string().max(defaults_1.MAX_TAG_LEN).optional().describe('Filter by tag (exact match, case-insensitive)'),
|
|
18
|
+
filter: zod_1.z.string().max(500).optional().describe('Substring match on title or ID'),
|
|
19
|
+
assignee: zod_1.z.string().max(defaults_1.MAX_ASSIGNEE_LEN).optional().describe('Filter by assignee (team member ID)'),
|
|
20
|
+
limit: zod_1.z.number().max(1000).optional().describe('Max results (default 50)'),
|
|
20
21
|
},
|
|
21
22
|
}, async ({ status, priority, tag, filter, assignee, limit }) => {
|
|
22
23
|
const results = mgr.listTasks({ status, priority, tag, filter, assignee, limit });
|