@ezmodo/mcp-server 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +305 -0
- package/config/development.js +20 -0
- package/config/endpoint-map.js +351 -0
- package/config/index.js +34 -0
- package/config/production.js +18 -0
- package/config/staging.js +18 -0
- package/handlers/access.js +141 -0
- package/handlers/activity.js +112 -0
- package/handlers/agents.js +95 -0
- package/handlers/ai-intelligence.js +55 -0
- package/handlers/attachments.js +30 -0
- package/handlers/catalogs.js +169 -0
- package/handlers/components.js +282 -0
- package/handlers/context-manifest.js +1150 -0
- package/handlers/decisions.js +114 -0
- package/handlers/designs.js +118 -0
- package/handlers/documents.js +227 -0
- package/handlers/entities.js +95 -0
- package/handlers/epics.js +190 -0
- package/handlers/facts.js +62 -0
- package/handlers/feature-flags.js +142 -0
- package/handlers/features.js +137 -0
- package/handlers/folders.js +127 -0
- package/handlers/git-context.js +917 -0
- package/handlers/github.js +72 -0
- package/handlers/graph.js +23 -0
- package/handlers/index.js +205 -0
- package/handlers/links.js +156 -0
- package/handlers/milestones.js +131 -0
- package/handlers/organizations.js +14 -0
- package/handlers/projects.js +122 -0
- package/handlers/recurring-tasks.js +33 -0
- package/handlers/tags.js +124 -0
- package/handlers/tasks.js +561 -0
- package/handlers/testing.js +116 -0
- package/handlers/todos.js +43 -0
- package/handlers/watchers.js +54 -0
- package/handlers/work-templates.js +32 -0
- package/index.js +175 -0
- package/lib/active-session.js +86 -0
- package/lib/auto-assign.js +93 -0
- package/lib/autolink.js +176 -0
- package/lib/changed-files.js +22 -0
- package/lib/env.js +45 -0
- package/lib/git-helpers.js +553 -0
- package/lib/git-utils.js +73 -0
- package/lib/http-client.js +164 -0
- package/lib/links-at-create.js +94 -0
- package/lib/local-cache.js +140 -0
- package/lib/logger.js +109 -0
- package/lib/manifest-loader.js +182 -0
- package/lib/manifest-query.js +686 -0
- package/lib/repo-config-dir.js +118 -0
- package/lib/version.js +10 -0
- package/lib/web-url.js +69 -0
- package/lib/worktree-tools.js +950 -0
- package/package.json +62 -0
- package/prompts/ai-workflow-automation.js +96 -0
- package/prompts/index.js +39 -0
- package/prompts/zephly-usage-guide-content.txt +631 -0
- package/prompts/zephly-usage-guide.js +119 -0
- package/tools/access-entity-types.js +28 -0
- package/tools/access.js +152 -0
- package/tools/activity.js +38 -0
- package/tools/agents.js +208 -0
- package/tools/ai-intelligence.js +111 -0
- package/tools/attachments.js +92 -0
- package/tools/catalogs.js +341 -0
- package/tools/components.js +249 -0
- package/tools/context-manifest.js +236 -0
- package/tools/decisions.js +168 -0
- package/tools/designs.js +222 -0
- package/tools/documents.js +287 -0
- package/tools/entities.js +223 -0
- package/tools/epics.js +267 -0
- package/tools/facts.js +70 -0
- package/tools/feature-flags.js +300 -0
- package/tools/features.js +246 -0
- package/tools/folders.js +122 -0
- package/tools/git-context.js +109 -0
- package/tools/github.js +172 -0
- package/tools/graph.js +70 -0
- package/tools/index.js +77 -0
- package/tools/link-params.js +93 -0
- package/tools/linkable-types.js +36 -0
- package/tools/links.js +199 -0
- package/tools/milestones.js +176 -0
- package/tools/organizations.js +23 -0
- package/tools/projects.js +172 -0
- package/tools/recurring-tasks.js +115 -0
- package/tools/tags.js +219 -0
- package/tools/task-item-schema.js +57 -0
- package/tools/task-type.js +33 -0
- package/tools/tasks.js +680 -0
- package/tools/testing.js +344 -0
- package/tools/todos.js +69 -0
- package/tools/watchers.js +81 -0
- package/tools/work-templates.js +96 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decision Handlers
|
|
3
|
+
* Handler functions for the Decisions / ADRs MCP tools (E-170).
|
|
4
|
+
*
|
|
5
|
+
* Decisions are org-level, durable ADR-style records (title, context, options,
|
|
6
|
+
* decision, consequences, status) that LINK to features and other artifacts via
|
|
7
|
+
* the generic link graph. These handlers are thin wrappers over
|
|
8
|
+
* /api/mcp/v1/decisions; dispatch and validation happen server-side in
|
|
9
|
+
* core/decisions.Service.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { callZephlyAPI } from '../lib/http-client.js';
|
|
13
|
+
import { attachLinks } from '../lib/links-at-create.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Dispatch manage_decision actions.
|
|
17
|
+
*/
|
|
18
|
+
export async function manageDecision(args) {
|
|
19
|
+
const { action, ...params } = args;
|
|
20
|
+
switch (action) {
|
|
21
|
+
case 'create': return createDecision(params);
|
|
22
|
+
case 'update': return updateDecision(params);
|
|
23
|
+
case 'delete': return deleteDecision(params);
|
|
24
|
+
case 'link': return linkDecisionArtifact(params);
|
|
25
|
+
case 'unlink': return unlinkDecisionArtifact(params);
|
|
26
|
+
case 'supersede': return supersedeDecision(params);
|
|
27
|
+
case 'promote_from_knowledge': return promoteFromKnowledge(params);
|
|
28
|
+
default:
|
|
29
|
+
throw new Error(`Unknown action: ${action}. Expected create, update, delete, link, unlink, supersede, or promote_from_knowledge.`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Unified get/list handler for decisions.
|
|
35
|
+
* - decisionId → single lookup (optionally + links).
|
|
36
|
+
* - linkedType + linkedId → decisions linked to that entity (e.g. a feature).
|
|
37
|
+
* - organizationId only → list (optionally filtered by projectId/status/limit).
|
|
38
|
+
*/
|
|
39
|
+
export async function getDecision(args) {
|
|
40
|
+
const { includeLinks, decisionId, organizationId, linkedType, linkedId, ...filters } = args;
|
|
41
|
+
|
|
42
|
+
if (decisionId) {
|
|
43
|
+
const result = await callZephlyAPI('mcpGetDecision', { decisionId });
|
|
44
|
+
if (includeLinks) {
|
|
45
|
+
const links = await callZephlyAPI('mcpListDecisionLinks', { decisionId });
|
|
46
|
+
result.links = links?.links ?? links;
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// List mode
|
|
52
|
+
const params = {};
|
|
53
|
+
if (organizationId) params.organizationId = organizationId;
|
|
54
|
+
if (linkedType && linkedId) {
|
|
55
|
+
params.linkedType = linkedType;
|
|
56
|
+
params.linkedId = linkedId;
|
|
57
|
+
}
|
|
58
|
+
if (filters.projectId) params.projectId = filters.projectId;
|
|
59
|
+
if (filters.status) params.status = filters.status;
|
|
60
|
+
if (filters.limit != null) params.limit = filters.limit;
|
|
61
|
+
return callZephlyAPI('mcpListDecisions', params);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// --- Private helpers ---
|
|
65
|
+
|
|
66
|
+
async function createDecision(args) {
|
|
67
|
+
// `links` is applied by the MCP layer after the decision exists (E-225).
|
|
68
|
+
const { links, ...createArgs } = args;
|
|
69
|
+
const result = await callZephlyAPI('mcpCreateDecision', createArgs);
|
|
70
|
+
|
|
71
|
+
// Attach create-time links (E-225) — best effort, never fails the create.
|
|
72
|
+
await attachLinks(result, {
|
|
73
|
+
sourceType: 'decision',
|
|
74
|
+
sourceId: result?.decisionId || result?.decision?.id,
|
|
75
|
+
links,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function updateDecision(args) {
|
|
82
|
+
return callZephlyAPI('mcpUpdateDecision', args);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function deleteDecision({ decisionId }) {
|
|
86
|
+
return callZephlyAPI('mcpDeleteDecision', { decisionId });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function linkDecisionArtifact({ decisionId, targetType, targetId }) {
|
|
90
|
+
return callZephlyAPI('mcpLinkDecisionArtifact', { decisionId, targetType, targetId });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function unlinkDecisionArtifact({ decisionId, targetType, targetId }) {
|
|
94
|
+
return callZephlyAPI('mcpUnlinkDecisionArtifact', { decisionId, targetType, targetId });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Mark a decision as superseded by another decision (records the supersession
|
|
98
|
+
// chain; the superseded decision's status moves to "superseded" server-side).
|
|
99
|
+
async function supersedeDecision({ decisionId, supersededById }) {
|
|
100
|
+
return callZephlyAPI('mcpSupersedeDecision', { decisionId, supersededById });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Elevate a task's decision-type knowledge item into a durable Decision (E-170),
|
|
104
|
+
// optionally linking the new decision to an artifact in the same call.
|
|
105
|
+
async function promoteFromKnowledge({ organizationId, taskId, knowledgeId, title, linkToType, linkToId }) {
|
|
106
|
+
return callZephlyAPI('mcpPromoteDecisionFromKnowledge', {
|
|
107
|
+
organizationId,
|
|
108
|
+
taskId,
|
|
109
|
+
knowledgeId,
|
|
110
|
+
title,
|
|
111
|
+
linkToType,
|
|
112
|
+
linkToId,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design Handlers
|
|
3
|
+
* Handler functions for the Designs MCP tools (the in-product living design system).
|
|
4
|
+
*
|
|
5
|
+
* A Design is an AI-authored HTML/CSS artifact (kind ∈ theme|component|page) that
|
|
6
|
+
* captures the house style. Designs are org-level (project_id nullable) and LINK
|
|
7
|
+
* to features and other artifacts via the generic link graph. These handlers are
|
|
8
|
+
* thin wrappers over /api/mcp/v1/designs; dispatch and validation happen
|
|
9
|
+
* server-side in core/designs.Service.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { callZephlyAPI } from '../lib/http-client.js';
|
|
13
|
+
import { attachLinks } from '../lib/links-at-create.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Dispatch manage_design actions.
|
|
17
|
+
*/
|
|
18
|
+
export async function manageDesign(args) {
|
|
19
|
+
const { action, ...params } = args;
|
|
20
|
+
switch (action) {
|
|
21
|
+
case 'create': return createDesign(params);
|
|
22
|
+
case 'update': return updateDesign(params);
|
|
23
|
+
case 'delete': return deleteDesign(params);
|
|
24
|
+
case 'link': return linkDesignArtifact(params);
|
|
25
|
+
case 'unlink': return unlinkDesignArtifact(params);
|
|
26
|
+
default:
|
|
27
|
+
throw new Error(`Unknown action: ${action}. Expected create, update, delete, link, or unlink.`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Unified get/list handler for designs.
|
|
33
|
+
* - linkedType + linkedId → designs linked to that entity (e.g. a feature).
|
|
34
|
+
* - designId → single lookup (optionally + links).
|
|
35
|
+
*/
|
|
36
|
+
export async function getDesign(args) {
|
|
37
|
+
const { includeLinks, designId, organizationId, linkedType, linkedId, ...filters } = args;
|
|
38
|
+
|
|
39
|
+
if (linkedType && linkedId) {
|
|
40
|
+
const params = { linkedType, linkedId };
|
|
41
|
+
if (organizationId) params.organizationId = organizationId;
|
|
42
|
+
if (filters.projectId) params.projectId = filters.projectId;
|
|
43
|
+
if (filters.kind) params.kind = filters.kind;
|
|
44
|
+
if (filters.status) params.status = filters.status;
|
|
45
|
+
if (filters.limit != null) params.limit = filters.limit;
|
|
46
|
+
return callZephlyAPI('mcpListDesigns', params);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (designId) {
|
|
50
|
+
const result = await callZephlyAPI('mcpGetDesign', { designId });
|
|
51
|
+
if (includeLinks) {
|
|
52
|
+
const links = await callZephlyAPI('mcpListDesignLinks', { designId });
|
|
53
|
+
result.links = links?.links ?? links;
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Fall back to list mode (organizationId + filters)
|
|
59
|
+
return listDesigns({ organizationId, ...filters });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* List designs for an organization, optionally filtered by project/kind/status.
|
|
64
|
+
*/
|
|
65
|
+
export async function listDesigns(args) {
|
|
66
|
+
const params = {};
|
|
67
|
+
if (args.organizationId) params.organizationId = args.organizationId;
|
|
68
|
+
if (args.projectId) params.projectId = args.projectId;
|
|
69
|
+
if (args.kind) params.kind = args.kind;
|
|
70
|
+
if (args.status) params.status = args.status;
|
|
71
|
+
if (args.includeOrgWide != null) params.includeOrgWide = args.includeOrgWide;
|
|
72
|
+
if (args.limit != null) params.limit = args.limit;
|
|
73
|
+
return callZephlyAPI('mcpListDesigns', params);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Retrieve the design system (theme + components) for an org/project. Call this
|
|
78
|
+
* first to learn the existing house style before authoring new UI.
|
|
79
|
+
*/
|
|
80
|
+
export async function getDesignSystem(args) {
|
|
81
|
+
const params = {};
|
|
82
|
+
if (args.organizationId) params.organizationId = args.organizationId;
|
|
83
|
+
if (args.projectId) params.projectId = args.projectId;
|
|
84
|
+
return callZephlyAPI('mcpGetDesignSystem', params);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// --- Private helpers ---
|
|
88
|
+
|
|
89
|
+
async function createDesign(args) {
|
|
90
|
+
// `links` is applied by the MCP layer after the design exists (E-225).
|
|
91
|
+
const { links, ...createArgs } = args;
|
|
92
|
+
const result = await callZephlyAPI('mcpCreateDesign', createArgs);
|
|
93
|
+
|
|
94
|
+
// Attach create-time links (E-225) — best effort, never fails the create.
|
|
95
|
+
await attachLinks(result, {
|
|
96
|
+
sourceType: 'design',
|
|
97
|
+
sourceId: result?.designId || result?.design?.id,
|
|
98
|
+
links,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function updateDesign(args) {
|
|
105
|
+
return callZephlyAPI('mcpUpdateDesign', args);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function deleteDesign({ designId }) {
|
|
109
|
+
return callZephlyAPI('mcpDeleteDesign', { designId });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function linkDesignArtifact({ designId, targetType, targetId }) {
|
|
113
|
+
return callZephlyAPI('mcpLinkDesign', { designId, targetType, targetId });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function unlinkDesignArtifact({ designId, targetType, targetId }) {
|
|
117
|
+
return callZephlyAPI('mcpUnlinkDesign', { designId, targetType, targetId });
|
|
118
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document Handlers
|
|
3
|
+
* Handler functions for documentation-related MCP tools
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs/promises';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { callZephlyAPI } from '../lib/http-client.js';
|
|
9
|
+
import { findConfigPath } from '../lib/local-cache.js';
|
|
10
|
+
import { getLogger } from '../lib/logger.js';
|
|
11
|
+
import { attachLinks } from '../lib/links-at-create.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Dispatch manage_document actions to the appropriate handler
|
|
15
|
+
*/
|
|
16
|
+
export async function manageDocument(args) {
|
|
17
|
+
const { action, ...params } = args;
|
|
18
|
+
switch (action) {
|
|
19
|
+
case 'create': return createDocument(params);
|
|
20
|
+
case 'update': return updateDocument(params);
|
|
21
|
+
case 'create_version': throw new Error('Document versioning is not yet supported. Use the "update" action to modify documents.');
|
|
22
|
+
default: throw new Error(`Unknown action: ${action}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Dispatch manage_document_template actions to the appropriate handler
|
|
28
|
+
*/
|
|
29
|
+
export async function manageDocumentTemplate(args) {
|
|
30
|
+
const { action, ...params } = args;
|
|
31
|
+
switch (action) {
|
|
32
|
+
case 'create': return createDocumentTemplate(params);
|
|
33
|
+
case 'delete': return deleteDocumentTemplate(params);
|
|
34
|
+
default: throw new Error(`Unknown action: ${action}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Unified get/list handler for documents.
|
|
40
|
+
* - If documentId or slug is provided, returns a single document.
|
|
41
|
+
* - Otherwise, lists all documents for the project with optional filters.
|
|
42
|
+
* - Optionally includes version history or fetches a specific version.
|
|
43
|
+
*/
|
|
44
|
+
export async function getDocument(args) {
|
|
45
|
+
const { docType, tags, status, includeVersions, versionNumber, versionLimit, ...rest } = args;
|
|
46
|
+
const isSingleLookup = rest.documentId || rest.slug;
|
|
47
|
+
|
|
48
|
+
if (isSingleLookup) {
|
|
49
|
+
// Specific version requested
|
|
50
|
+
if (versionNumber !== undefined) {
|
|
51
|
+
return fetchDocumentVersion({ documentId: rest.documentId, versionNumber });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const result = await fetchSingleDocument(rest);
|
|
55
|
+
|
|
56
|
+
// Include version history if requested
|
|
57
|
+
if (includeVersions) {
|
|
58
|
+
const versions = await listDocumentVersions({
|
|
59
|
+
documentId: rest.documentId || result?.document?.id,
|
|
60
|
+
limit: versionLimit,
|
|
61
|
+
});
|
|
62
|
+
result.versions = versions;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// List mode
|
|
69
|
+
const listArgs = { projectId: rest.projectId };
|
|
70
|
+
if (docType) listArgs.docType = docType;
|
|
71
|
+
if (tags) listArgs.tags = tags;
|
|
72
|
+
if (status) listArgs.status = status;
|
|
73
|
+
|
|
74
|
+
return getDocumentation(listArgs);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Unified get/list handler for document templates.
|
|
79
|
+
* - If templateId is provided, returns a single template.
|
|
80
|
+
* - Otherwise, lists all templates with optional filters.
|
|
81
|
+
*/
|
|
82
|
+
export async function getDocumentTemplate(args) {
|
|
83
|
+
const { templateId, category, type } = args;
|
|
84
|
+
|
|
85
|
+
if (templateId) {
|
|
86
|
+
return fetchSingleDocumentTemplate({ templateId });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// List mode
|
|
90
|
+
const listArgs = {};
|
|
91
|
+
if (category) listArgs.category = category;
|
|
92
|
+
if (type) listArgs.type = type;
|
|
93
|
+
|
|
94
|
+
return listDocumentTemplates(listArgs);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// --- Private helpers ---
|
|
98
|
+
|
|
99
|
+
async function getDocumentation(args) {
|
|
100
|
+
return callZephlyAPI('mcpGetDocumentation', args);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function fetchSingleDocument(args) {
|
|
104
|
+
const data = await callZephlyAPI('mcpGetDocument', args);
|
|
105
|
+
const doc = data.document;
|
|
106
|
+
|
|
107
|
+
if (!doc) {
|
|
108
|
+
return data;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!doc.content) {
|
|
112
|
+
return data;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Save content to <repo-config-dir>/docs/<slug-or-id>.md
|
|
116
|
+
const configPath = await findConfigPath();
|
|
117
|
+
if (!configPath) {
|
|
118
|
+
// No project config directory found — return as-is.
|
|
119
|
+
return data;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const configDir = path.dirname(configPath);
|
|
123
|
+
const docsDir = path.join(configDir, 'docs');
|
|
124
|
+
const filename = `${doc.slug || doc.id}.md`;
|
|
125
|
+
const filePath = path.resolve(docsDir, filename);
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
await fs.mkdir(docsDir, { recursive: true });
|
|
129
|
+
await fs.writeFile(filePath, doc.content, 'utf-8');
|
|
130
|
+
} catch (err) {
|
|
131
|
+
getLogger().warn('Failed to save document to local file', { error: err.message, filePath });
|
|
132
|
+
// Fall back to returning full content in response
|
|
133
|
+
return data;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Return metadata + file path, omit heavy content from response
|
|
137
|
+
const { content, ...metadata } = doc;
|
|
138
|
+
return {
|
|
139
|
+
...data,
|
|
140
|
+
document: metadata,
|
|
141
|
+
localFilePath: filePath,
|
|
142
|
+
message: `Document content saved to ${filePath}. Use the Read tool to access it when needed.`,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function createDocument(args) {
|
|
147
|
+
// Support both top-level summary/keyPoints and nested aiContext input.
|
|
148
|
+
// `links` is applied by the MCP layer after the document exists (E-225).
|
|
149
|
+
const { summary, keyPoints, aiContext, links, ...rest } = args;
|
|
150
|
+
const hasFlatFields = summary !== undefined || keyPoints !== undefined;
|
|
151
|
+
if (hasFlatFields || aiContext) {
|
|
152
|
+
rest.aiContext = {
|
|
153
|
+
...(aiContext || {}),
|
|
154
|
+
...(summary !== undefined ? { summary } : {}),
|
|
155
|
+
...(keyPoints !== undefined ? { keyPoints } : {}),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const result = await callZephlyAPI('mcpCreateDocument', rest);
|
|
160
|
+
|
|
161
|
+
// Attach create-time links (E-225) — best effort, never fails the create.
|
|
162
|
+
await attachLinks(result, {
|
|
163
|
+
sourceType: 'document',
|
|
164
|
+
sourceId: result?.documentId,
|
|
165
|
+
links,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function updateDocument(args) {
|
|
172
|
+
// Support both top-level summary/keyPoints and nested aiContext input
|
|
173
|
+
const { summary, keyPoints, aiContext, addRelatedItem, removeRelatedItem, ...rest } = args;
|
|
174
|
+
const hasFlatFields = summary !== undefined || keyPoints !== undefined;
|
|
175
|
+
if (hasFlatFields || aiContext) {
|
|
176
|
+
rest.aiContext = {
|
|
177
|
+
...(aiContext || {}),
|
|
178
|
+
...(summary !== undefined ? { summary } : {}),
|
|
179
|
+
...(keyPoints !== undefined ? { keyPoints } : {}),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (addRelatedItem !== undefined) {
|
|
184
|
+
rest.addRelatedItem = addRelatedItem;
|
|
185
|
+
}
|
|
186
|
+
if (removeRelatedItem !== undefined) {
|
|
187
|
+
rest.removeRelatedItem = removeRelatedItem;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return callZephlyAPI('mcpUpdateDocument', rest);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* List an organization's project-less (org-scoped) documents. (E-195)
|
|
195
|
+
* Params: organizationId (required), folderId (optional), limit (optional).
|
|
196
|
+
*/
|
|
197
|
+
export async function listOrgDocuments(args) {
|
|
198
|
+
return callZephlyAPI('mcpListOrgDocuments', args);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Document Version helpers
|
|
202
|
+
|
|
203
|
+
async function listDocumentVersions(args) {
|
|
204
|
+
return callZephlyAPI('mcpListDocumentVersions', args);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function fetchDocumentVersion(args) {
|
|
208
|
+
return callZephlyAPI('mcpGetDocumentVersion', args);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Document Template helpers
|
|
212
|
+
|
|
213
|
+
async function listDocumentTemplates(args) {
|
|
214
|
+
return callZephlyAPI('mcpListDocumentTemplates', args);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function fetchSingleDocumentTemplate(args) {
|
|
218
|
+
return callZephlyAPI('mcpGetDocumentTemplate', args);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function createDocumentTemplate(args) {
|
|
222
|
+
return callZephlyAPI('mcpCreateDocumentTemplate', args);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async function deleteDocumentTemplate(args) {
|
|
226
|
+
return callZephlyAPI('mcpDeleteDocumentTemplate', args);
|
|
227
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity Handlers
|
|
3
|
+
* Handler functions for goals, teams, and labels
|
|
4
|
+
*
|
|
5
|
+
* Consolidated: manageGoal dispatches create/update/delete.
|
|
6
|
+
* manageTeam dispatches create.
|
|
7
|
+
* getGoal unifies get (by ID or number) and list.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { callZephlyAPI } from '../lib/http-client.js';
|
|
11
|
+
import { buildGoalUrl } from '../lib/web-url.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Dispatch manage_goal actions to the appropriate handler
|
|
15
|
+
*/
|
|
16
|
+
export async function manageGoal(args) {
|
|
17
|
+
const { action, ...params } = args;
|
|
18
|
+
switch (action) {
|
|
19
|
+
case 'create': return createGoal(params);
|
|
20
|
+
case 'update': return updateGoal(params);
|
|
21
|
+
case 'delete': return deleteGoal(params);
|
|
22
|
+
case 'generate_how_it_works': return generateGoalHowItWorks(params);
|
|
23
|
+
case 'apply_how_it_works': return applyGoalHowItWorks(params);
|
|
24
|
+
default: throw new Error(`Unknown action: ${action}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Dispatch manage_team actions to the appropriate handler
|
|
30
|
+
*/
|
|
31
|
+
export async function manageTeam(args) {
|
|
32
|
+
const { action, ...params } = args;
|
|
33
|
+
switch (action) {
|
|
34
|
+
case 'create': return createTeam(params);
|
|
35
|
+
default: throw new Error(`Unknown action: ${action}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Unified get/list handler for goals
|
|
41
|
+
*/
|
|
42
|
+
export async function getGoal(args) {
|
|
43
|
+
// Single goal lookup by ID or number
|
|
44
|
+
if (args.goalId || args.goalNumber) {
|
|
45
|
+
const result = await callZephlyAPI('mcpGetGoal', args);
|
|
46
|
+
const goalId = result?.goal?.id || result?.goal?.goalId;
|
|
47
|
+
const webUrl = await buildGoalUrl(goalId);
|
|
48
|
+
if (webUrl && result?.goal) result.goal.webUrl = webUrl;
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// List mode
|
|
53
|
+
return callZephlyAPI('mcpListGoals', args);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// --- Private helpers ---
|
|
57
|
+
|
|
58
|
+
async function createGoal(args) {
|
|
59
|
+
const result = await callZephlyAPI('mcpCreateGoal', args);
|
|
60
|
+
const webUrl = await buildGoalUrl(result?.goalId);
|
|
61
|
+
if (webUrl) result.webUrl = webUrl;
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function updateGoal(args) {
|
|
66
|
+
return callZephlyAPI('mcpUpdateGoal', args);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function deleteGoal(args) {
|
|
70
|
+
return callZephlyAPI('mcpDeleteGoal', args);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Generate (and persist) the goal's grounded "how it works" living description
|
|
74
|
+
// via the model. AI-quota gated server-side (mirrors features.generateHowItWorks).
|
|
75
|
+
async function generateGoalHowItWorks({ goalId }) {
|
|
76
|
+
const result = await callZephlyAPI('mcpGenerateGoalHowItWorks', { goalId });
|
|
77
|
+
const id = result?.goal?.id || result?.goal?.goalId || goalId;
|
|
78
|
+
const webUrl = await buildGoalUrl(id);
|
|
79
|
+
if (webUrl && result?.goal) result.goal.webUrl = webUrl;
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Apply (persist) a LOCAL-agent-authored "how it works" for a goal (BYO-AI,
|
|
84
|
+
// E-190). Cited sources are validated server-side before saving; no model call.
|
|
85
|
+
async function applyGoalHowItWorks({ goalId, markdown, sources }) {
|
|
86
|
+
const result = await callZephlyAPI('mcpApplyGoalHowItWorks', { goalId, markdown, sources });
|
|
87
|
+
const id = result?.goal?.id || result?.goal?.goalId || goalId;
|
|
88
|
+
const webUrl = await buildGoalUrl(id);
|
|
89
|
+
if (webUrl && result?.goal) result.goal.webUrl = webUrl;
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function createTeam(args) {
|
|
94
|
+
return callZephlyAPI('mcpCreateTeam', args);
|
|
95
|
+
}
|