draftgo-cli 3.0.35 → 3.0.39
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 +220 -272
- package/package.json +6 -2
- package/resources/skill/SKILL.md +114 -55
- package/resources/skill/init/SKILL.md +29 -15
- package/resources/skill/manifest.json +5 -4
- package/resources/skill/push/SKILL.md +41 -29
- package/resources/skill/references/aihub.md +8 -5
- package/resources/skill/references/api-endpoints.md +5 -3
- package/resources/skill/references/architecture.md +1 -1
- package/resources/skill/references/checkout.md +116 -0
- package/resources/skill/references/custom-services.md +9 -10
- package/resources/skill/references/data.md +4 -2
- package/resources/skill/references/frontend.md +1 -1
- package/resources/skill/references/mcp.md +101 -0
- package/resources/skill/references/modules.md +8 -8
- package/resources/skill/references/parallel.md +6 -3
- package/resources/skill/references/runtime.md +7 -10
- package/resources/skill/scripts/README.md +8 -0
- package/resources/skill/story/SKILL.md +8 -8
- package/src/cli.js +5 -0
- package/src/commandRegistry.js +7 -1
- package/src/commands/api.js +24 -187
- package/src/commands/autoPush.js +48 -17
- package/src/commands/check.js +17 -47
- package/src/commands/checkout.js +18 -0
- package/src/commands/commit.js +21 -0
- package/src/commands/conflict.js +30 -0
- package/src/commands/conflicts.js +16 -0
- package/src/commands/connect.js +60 -48
- package/src/commands/delete.js +79 -64
- package/src/commands/deploy.js +18 -10
- package/src/commands/diff.js +23 -0
- package/src/commands/help.js +99 -75
- package/src/commands/init.js +4 -10
- package/src/commands/local.js +23 -6
- package/src/commands/map.js +89 -89
- package/src/commands/mcp.js +126 -0
- package/src/commands/sync.js +28 -43
- package/src/commands/verifyUi.js +3 -2
- package/src/localdev/index.js +37 -7
- package/src/localdev/mysqlClient.js +1 -1
- package/src/mcp/client.js +275 -0
- package/src/mcp/hosts.js +520 -0
- package/src/mcp/protocol.js +173 -0
- package/src/mcp/stdio.js +300 -0
- package/src/mcp/tools.js +47 -0
- package/src/platforms.js +3 -4
- package/src/projectConfig.js +91 -49
- package/src/projectMap.js +123 -460
- package/src/skill.js +6 -28
- package/src/worktree/backend.js +326 -0
- package/src/worktree/errors.js +28 -0
- package/src/worktree/index.js +461 -0
- package/src/worktree/manifest.js +75 -0
- package/src/worktree/streams.js +200 -0
- package/src/worktree/types.js +103 -0
- package/src/worktree/validate.js +37 -0
- package/resources/skill/pull/SKILL.md +0 -33
- package/resources/skill/references/api.json +0 -20248
- package/resources/skill/scripts/draftgo_delete.py +0 -149
- package/resources/skill/scripts/draftgo_init.py +0 -80
- package/resources/skill/scripts/draftgo_pull.py +0 -427
- package/resources/skill/scripts/draftgo_push.py +0 -1022
- package/src/python.js +0 -27
package/src/commands/sync.js
CHANGED
|
@@ -1,61 +1,46 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const { spawnSync } = require('child_process');
|
|
5
3
|
const log = require('../logger');
|
|
6
|
-
const {
|
|
7
|
-
const { findPython } = require('../python');
|
|
8
|
-
const { platforms } = require('../platforms');
|
|
4
|
+
const { canonicalResourceType } = require('../worktree/types');
|
|
9
5
|
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
async function sync(projectDir, command, positional, flags = {}) {
|
|
7
|
+
if (command === 'pull') {
|
|
8
|
+
log.err('`draftgo pull` no longer downloads DraftGo resources.');
|
|
9
|
+
log.dim(' Use MCP project/resource discovery. For complete pages, navigation, or docs, use `draftgo checkout <type> <id...>`.');
|
|
10
|
+
log.dim(' Existing legacy .draftgo indexes are left untouched and ignored.');
|
|
11
|
+
return 1;
|
|
16
12
|
}
|
|
17
13
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const py = findPython();
|
|
24
|
-
if (!py) {
|
|
25
|
-
log.err('未检测到 Python,无法运行 DraftGo 同步脚本。');
|
|
14
|
+
const [rawType, ...ids] = positional;
|
|
15
|
+
if (!rawType) {
|
|
16
|
+
log.err('The legacy push-all workflow has been removed.');
|
|
17
|
+
log.dim(' Use `draftgo commit <pages|nav|docs> <id...>` for checked-out long content.');
|
|
18
|
+
log.dim(' Use DraftGo MCP for structured resources.');
|
|
26
19
|
return 1;
|
|
27
20
|
}
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
let resourceType;
|
|
23
|
+
try {
|
|
24
|
+
resourceType = canonicalResourceType(rawType);
|
|
25
|
+
} catch {
|
|
26
|
+
log.err(`Legacy push for ${rawType} is no longer supported.`);
|
|
27
|
+
log.dim(' Discover the live API with `draftgo api <query>` and use MCP api_call for structured resources.');
|
|
33
28
|
return 1;
|
|
34
29
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
log.err('未找到 .draftgo/config.json。');
|
|
38
|
-
log.dim(' 请先运行 `draftgo connect`。');
|
|
30
|
+
if (!ids.length) {
|
|
31
|
+
log.err('Refusing legacy push-all behavior; specify checked-out resource ids explicitly.');
|
|
39
32
|
return 1;
|
|
40
33
|
}
|
|
41
34
|
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const r = spawnSync(py.bin, [script, ...args], {
|
|
50
|
-
cwd: projectDir,
|
|
51
|
-
stdio: 'inherit',
|
|
52
|
-
shell: false,
|
|
53
|
-
});
|
|
54
|
-
if (r.error) {
|
|
55
|
-
log.err(`${command} 启动失败:${r.error.message}`);
|
|
56
|
-
return 1;
|
|
35
|
+
log.warn('`draftgo push` is deprecated; forwarding checked-out long content to `draftgo commit`.');
|
|
36
|
+
if (flags['dry-run']) {
|
|
37
|
+
for (const id of ids) {
|
|
38
|
+
const code = require('./diff')(projectDir, [resourceType, id], flags);
|
|
39
|
+
if (code !== 0) return code;
|
|
40
|
+
}
|
|
41
|
+
return 0;
|
|
57
42
|
}
|
|
58
|
-
return
|
|
43
|
+
return require('./commit')(projectDir, [resourceType, ...ids], flags);
|
|
59
44
|
}
|
|
60
45
|
|
|
61
46
|
module.exports = sync;
|
package/src/commands/verifyUi.js
CHANGED
|
@@ -14,8 +14,9 @@ function isUiFile(file) {
|
|
|
14
14
|
if (!['.js', '.ts'].includes(ext)) return false;
|
|
15
15
|
return /(^|\/)(frontend|web|ui|components|pages|views|client)(\/|$)/.test(normalized)
|
|
16
16
|
|| /(^|\/)(app|main|client)\.(js|ts)$/.test(normalized)
|
|
17
|
-
|| normalized.startsWith('.draftgo/pages/')
|
|
18
|
-
|| normalized.startsWith('.draftgo/navigations/')
|
|
17
|
+
|| normalized.startsWith('.draftgo/worktree/pages/')
|
|
18
|
+
|| normalized.startsWith('.draftgo/worktree/navigations/')
|
|
19
|
+
|| normalized.startsWith('.draftgo/worktree/docs/');
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
function gitChangedFiles(projectDir) {
|
package/src/localdev/index.js
CHANGED
|
@@ -7,7 +7,7 @@ const { probePort, probeHttp, detectDocker } = require('./detect');
|
|
|
7
7
|
const compose = require('./compose');
|
|
8
8
|
const { ensureDatabase, testConnection, describeClient } = require('./mysqlClient');
|
|
9
9
|
const { defaults, portOpen, probeRedis, probeMilvus, startService } = require('./services');
|
|
10
|
-
const { writeProjectConfig
|
|
10
|
+
const { writeProjectConfig } = require('../projectConfig');
|
|
11
11
|
const { appendGitignoreLine } = require('../fsx');
|
|
12
12
|
|
|
13
13
|
const DEFAULT_APP_PORT = 3000;
|
|
@@ -147,7 +147,35 @@ async function waitForApp(appPort) {
|
|
|
147
147
|
return ok;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
async function
|
|
150
|
+
async function finishMcpSetup(projectDir, mcpCommands) {
|
|
151
|
+
const commands = mcpCommands || require('../commands/mcp');
|
|
152
|
+
const setupMcp = commands.setupMcp || commands.setup;
|
|
153
|
+
const testMcp = commands.testMcp || commands.test;
|
|
154
|
+
if (typeof setupMcp !== 'function' || typeof testMcp !== 'function') {
|
|
155
|
+
log.warn(' MCP setup helpers are unavailable. Run `draftgo mcp setup` after updating the CLI.');
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let setupOk = false;
|
|
160
|
+
try {
|
|
161
|
+
setupOk = await setupMcp(projectDir, [], { yes: true }) === 0;
|
|
162
|
+
} catch {
|
|
163
|
+
log.warn(' MCP host setup failed. Retry with `draftgo mcp setup`.');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let testOk = false;
|
|
167
|
+
try {
|
|
168
|
+
testOk = await testMcp(projectDir, {}) === 0;
|
|
169
|
+
} catch {
|
|
170
|
+
log.warn(' MCP validation failed. Run `draftgo mcp test` for diagnostics.');
|
|
171
|
+
}
|
|
172
|
+
if (!testOk) {
|
|
173
|
+
log.dim(' The local stack and project config are ready; MCP may still be starting.');
|
|
174
|
+
}
|
|
175
|
+
return setupOk && testOk;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function runWizard(projectDir, { yes = false, mcpCommands } = {}) {
|
|
151
179
|
log.title('draftgo local setup');
|
|
152
180
|
if (!yes && !await confirm('Continue with local DraftGo setup?', { default: true })) return 0;
|
|
153
181
|
|
|
@@ -169,14 +197,16 @@ async function runWizard(projectDir, { yes = false } = {}) {
|
|
|
169
197
|
if (!composeUp(docker, out.dir) || !await waitForApp(appPort)) return 1;
|
|
170
198
|
|
|
171
199
|
const url = `http://localhost:${appPort}`;
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
200
|
+
let token = '';
|
|
201
|
+
while (token.length < 10) {
|
|
202
|
+
token = String(await askPassword('Paste a DraftGo system access token (SAT)')).trim();
|
|
203
|
+
if (token.length < 10) log.err(' Token appears too short. Please try again.');
|
|
204
|
+
}
|
|
175
205
|
const cfgPath = writeProjectConfig(projectDir, url, token);
|
|
176
|
-
|
|
206
|
+
await finishMcpSetup(projectDir, mcpCommands);
|
|
177
207
|
log.ok(`DraftGo is ready at ${url}`);
|
|
178
208
|
log.dim(`Project config: ${cfgPath}`);
|
|
179
209
|
return 0;
|
|
180
210
|
}
|
|
181
211
|
|
|
182
|
-
module.exports = { runWizard };
|
|
212
|
+
module.exports = { finishMcpSetup, runWizard };
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const pkg = require('../../package.json');
|
|
4
|
+
const {
|
|
5
|
+
DEFAULT_PROTOCOL_VERSION,
|
|
6
|
+
McpHttpError,
|
|
7
|
+
postJsonRpc,
|
|
8
|
+
redactText,
|
|
9
|
+
} = require('./protocol');
|
|
10
|
+
|
|
11
|
+
const SAFE_TEST_TOOLS = [
|
|
12
|
+
'draftgo_project_overview',
|
|
13
|
+
'draftgo_resource_list',
|
|
14
|
+
'draftgo_api_search',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const REQUIRED_DRAFTGO_TOOLS = [
|
|
18
|
+
'draftgo_project_overview',
|
|
19
|
+
'draftgo_resource_list',
|
|
20
|
+
'draftgo_resource_search',
|
|
21
|
+
'draftgo_resource_get_metadata',
|
|
22
|
+
'draftgo_resource_read_fragment',
|
|
23
|
+
'draftgo_api_search',
|
|
24
|
+
'draftgo_api_describe',
|
|
25
|
+
'draftgo_api_call',
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
class McpRpcError extends Error {
|
|
29
|
+
constructor(message, { code = -32000, data, id = null } = {}) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = 'McpRpcError';
|
|
32
|
+
this.code = code;
|
|
33
|
+
this.data = data;
|
|
34
|
+
this.id = id;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function redactValue(value, secrets = [], seen = new WeakMap()) {
|
|
39
|
+
if (typeof value === 'string') return redactText(value, secrets);
|
|
40
|
+
if (!value || typeof value !== 'object') return value;
|
|
41
|
+
if (seen.has(value)) return seen.get(value);
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
const result = [];
|
|
44
|
+
seen.set(value, result);
|
|
45
|
+
for (const item of value) result.push(redactValue(item, secrets, seen));
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
const result = {};
|
|
49
|
+
seen.set(value, result);
|
|
50
|
+
for (const [key, item] of Object.entries(value)) {
|
|
51
|
+
result[key] = redactValue(item, secrets, seen);
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isObject(value) {
|
|
57
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function sameId(left, right) {
|
|
61
|
+
return left === right;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function findInitializeRequest(message) {
|
|
65
|
+
const messages = Array.isArray(message) ? message : [message];
|
|
66
|
+
return messages.find((item) => isObject(item) && item.method === 'initialize' && item.id != null);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function findResponse(messages, id) {
|
|
70
|
+
return messages.find((message) => isObject(message)
|
|
71
|
+
&& Object.prototype.hasOwnProperty.call(message, 'id')
|
|
72
|
+
&& sameId(message.id, id)
|
|
73
|
+
&& !message.method);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function toolMatches(name, candidate) {
|
|
77
|
+
return name === candidate || name.endsWith(`.${candidate}`)
|
|
78
|
+
|| name.endsWith(`/${candidate}`) || name.endsWith(`:${candidate}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
class DraftGoMcpClient {
|
|
82
|
+
constructor(config, options = {}) {
|
|
83
|
+
if (!config || typeof config !== 'object') throw new TypeError('DraftGo MCP config is required.');
|
|
84
|
+
const token = String(config.token || config.sat || '').trim();
|
|
85
|
+
if (!token) throw new Error('DraftGo MCP config is missing SAT.');
|
|
86
|
+
if (!config.server && !config.mcp_url) throw new Error('DraftGo MCP config is missing server.');
|
|
87
|
+
|
|
88
|
+
this.config = { ...config, token };
|
|
89
|
+
this.secrets = [token];
|
|
90
|
+
this.sessionId = null;
|
|
91
|
+
this.protocolVersion = options.protocolVersion || DEFAULT_PROTOCOL_VERSION;
|
|
92
|
+
this.nextId = 1;
|
|
93
|
+
this.onMessage = typeof options.onMessage === 'function' ? options.onMessage : null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async forward(message, options = {}) {
|
|
97
|
+
if (!isObject(message) && !Array.isArray(message)) {
|
|
98
|
+
throw new TypeError('MCP message must be a JSON object or batch.');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const initialize = findInitializeRequest(message);
|
|
102
|
+
const requestedVersion = initialize
|
|
103
|
+
&& initialize.params
|
|
104
|
+
&& initialize.params.protocolVersion;
|
|
105
|
+
const delivered = [];
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
await postJsonRpc(this.config, message, {
|
|
109
|
+
signal: options.signal,
|
|
110
|
+
timeoutMs: options.timeoutMs,
|
|
111
|
+
sessionId: this.sessionId,
|
|
112
|
+
protocolVersion: requestedVersion || this.protocolVersion,
|
|
113
|
+
onSession: (sessionId) => { this.sessionId = sessionId; },
|
|
114
|
+
onMessage: (remoteMessage) => {
|
|
115
|
+
const safe = redactValue(remoteMessage, this.secrets);
|
|
116
|
+
delivered.push(safe);
|
|
117
|
+
if (this.onMessage) this.onMessage(safe);
|
|
118
|
+
if (typeof options.onMessage === 'function') options.onMessage(safe);
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (error && error.rpc) error.rpc = redactValue(error.rpc, this.secrets);
|
|
123
|
+
if (error && error.message) error.message = redactText(error.message, this.secrets);
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (initialize) {
|
|
128
|
+
const response = findResponse(delivered, initialize.id);
|
|
129
|
+
const negotiated = response && response.result && response.result.protocolVersion;
|
|
130
|
+
if (negotiated) this.protocolVersion = negotiated;
|
|
131
|
+
}
|
|
132
|
+
return delivered;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async request(method, params, options = {}) {
|
|
136
|
+
const id = options.id == null ? this.nextId++ : options.id;
|
|
137
|
+
const message = { jsonrpc: '2.0', id, method };
|
|
138
|
+
if (params !== undefined) message.params = params;
|
|
139
|
+
const messages = await this.forward(message, options);
|
|
140
|
+
const response = findResponse(messages, id);
|
|
141
|
+
if (!response) {
|
|
142
|
+
throw new McpRpcError(`DraftGo MCP returned no response for ${method}.`, { id });
|
|
143
|
+
}
|
|
144
|
+
if (response.error) {
|
|
145
|
+
throw new McpRpcError(
|
|
146
|
+
redactText(response.error.message || `MCP error ${response.error.code}`, this.secrets),
|
|
147
|
+
{
|
|
148
|
+
code: response.error.code,
|
|
149
|
+
data: redactValue(response.error.data, this.secrets),
|
|
150
|
+
id,
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
return response.result;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async notify(method, params, options = {}) {
|
|
158
|
+
const message = { jsonrpc: '2.0', method };
|
|
159
|
+
if (params !== undefined) message.params = params;
|
|
160
|
+
await this.forward(message, options);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async initialize(options = {}) {
|
|
164
|
+
const result = await this.request('initialize', {
|
|
165
|
+
protocolVersion: options.protocolVersion || this.protocolVersion,
|
|
166
|
+
capabilities: options.capabilities || {},
|
|
167
|
+
clientInfo: options.clientInfo || {
|
|
168
|
+
name: 'draftgo-cli',
|
|
169
|
+
version: pkg.version,
|
|
170
|
+
},
|
|
171
|
+
}, options);
|
|
172
|
+
if (result && result.protocolVersion) this.protocolVersion = result.protocolVersion;
|
|
173
|
+
await this.notify('notifications/initialized', undefined, options);
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async toolsList(cursor, options = {}) {
|
|
178
|
+
const params = cursor ? { cursor } : {};
|
|
179
|
+
return this.request('tools/list', params, options);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async listAllTools(options = {}) {
|
|
183
|
+
const tools = [];
|
|
184
|
+
const seenCursors = new Set();
|
|
185
|
+
let cursor;
|
|
186
|
+
const maxPages = Number(options.maxPages || 100);
|
|
187
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
188
|
+
const result = await this.toolsList(cursor, options);
|
|
189
|
+
if (result && Array.isArray(result.tools)) tools.push(...result.tools);
|
|
190
|
+
const next = result && result.nextCursor;
|
|
191
|
+
if (!next) return tools;
|
|
192
|
+
if (seenCursors.has(next)) throw new McpRpcError('DraftGo MCP repeated a tools/list cursor.');
|
|
193
|
+
seenCursors.add(next);
|
|
194
|
+
cursor = next;
|
|
195
|
+
}
|
|
196
|
+
throw new McpRpcError(`DraftGo MCP tools/list exceeded ${maxPages} pages.`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async toolsCall(name, args = {}, options = {}) {
|
|
200
|
+
const result = await this.request('tools/call', { name, arguments: args }, options);
|
|
201
|
+
if (result && result.isError === true) {
|
|
202
|
+
const structured = result.structuredContent || result.structured_content || {};
|
|
203
|
+
const text = Array.isArray(result.content)
|
|
204
|
+
? result.content.find((part) => part && part.type === 'text' && typeof part.text === 'string')
|
|
205
|
+
: null;
|
|
206
|
+
const message = structured.message || structured.error && structured.error.message
|
|
207
|
+
|| text && text.text || `DraftGo tool failed: ${name}`;
|
|
208
|
+
throw new McpRpcError(redactText(String(message).slice(0, 4096), this.secrets), {
|
|
209
|
+
code: structured.code || structured.error && structured.error.code || -32000,
|
|
210
|
+
data: redactValue(structured, this.secrets),
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async testConnection(options = {}) {
|
|
217
|
+
const initialized = await this.initialize(options);
|
|
218
|
+
const tools = await this.listAllTools(options);
|
|
219
|
+
const requiredTools = options.requiredTools || REQUIRED_DRAFTGO_TOOLS;
|
|
220
|
+
const missing = requiredTools.filter((expected) => !tools.some((tool) =>
|
|
221
|
+
tool && typeof tool.name === 'string' && toolMatches(tool.name, expected)));
|
|
222
|
+
if (missing.length) {
|
|
223
|
+
throw new McpRpcError(`DraftGo MCP is missing required tools: ${missing.join(', ')}.`, { code: -32601 });
|
|
224
|
+
}
|
|
225
|
+
const required = options.safeTools || SAFE_TEST_TOOLS;
|
|
226
|
+
const selected = tools.find((tool) => tool && typeof tool.name === 'string'
|
|
227
|
+
&& required.some((candidate) => toolMatches(tool.name, candidate)));
|
|
228
|
+
if (!selected) {
|
|
229
|
+
throw new McpRpcError(
|
|
230
|
+
`DraftGo MCP exposes no safe diagnostic tool (${required.join(', ')}).`,
|
|
231
|
+
{ code: -32601 },
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const canonical = required.find((candidate) => toolMatches(selected.name, candidate));
|
|
236
|
+
const defaultArguments = canonical === 'draftgo_api_search' ? { query: 'project' } : {};
|
|
237
|
+
const toolResult = await this.toolsCall(
|
|
238
|
+
selected.name,
|
|
239
|
+
options.toolArguments || defaultArguments,
|
|
240
|
+
options,
|
|
241
|
+
);
|
|
242
|
+
return {
|
|
243
|
+
initialized,
|
|
244
|
+
protocolVersion: this.protocolVersion,
|
|
245
|
+
sessionId: this.sessionId,
|
|
246
|
+
tools,
|
|
247
|
+
testedTool: selected.name,
|
|
248
|
+
toolResult,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
async function testConnection(config, options = {}) {
|
|
254
|
+
const client = new DraftGoMcpClient(config, options);
|
|
255
|
+
return client.testConnection(options);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function callTool(config, name, args = {}, options = {}) {
|
|
259
|
+
const client = options.client || new DraftGoMcpClient(config, options);
|
|
260
|
+
if (!options.initialized) await client.initialize(options);
|
|
261
|
+
return client.toolsCall(name, args, options);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
module.exports = {
|
|
265
|
+
DraftGoMcpClient,
|
|
266
|
+
McpClient: DraftGoMcpClient,
|
|
267
|
+
McpRpcError,
|
|
268
|
+
McpHttpError,
|
|
269
|
+
SAFE_TEST_TOOLS,
|
|
270
|
+
REQUIRED_DRAFTGO_TOOLS,
|
|
271
|
+
redactValue,
|
|
272
|
+
testConnection,
|
|
273
|
+
callTool,
|
|
274
|
+
toolMatches,
|
|
275
|
+
};
|