draftgo-cli 3.0.33 → 3.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +220 -269
  2. package/package.json +6 -2
  3. package/resources/skill/SKILL.md +114 -55
  4. package/resources/skill/init/SKILL.md +29 -15
  5. package/resources/skill/manifest.json +13 -5
  6. package/resources/skill/push/SKILL.md +41 -29
  7. package/resources/skill/references/aihub.md +8 -5
  8. package/resources/skill/references/api-endpoints.md +5 -3
  9. package/resources/skill/references/architecture.md +1 -1
  10. package/resources/skill/references/checkout.md +116 -0
  11. package/resources/skill/references/custom-services.md +9 -10
  12. package/resources/skill/references/data.md +4 -2
  13. package/resources/skill/references/frontend.md +99 -23
  14. package/resources/skill/references/mcp.md +101 -0
  15. package/resources/skill/references/modules.md +8 -8
  16. package/resources/skill/references/parallel.md +6 -3
  17. package/resources/skill/references/runtime.md +7 -10
  18. package/resources/skill/scripts/README.md +8 -0
  19. package/resources/skill/story/SKILL.md +8 -8
  20. package/src/cli.js +5 -0
  21. package/src/commandRegistry.js +7 -1
  22. package/src/commands/api.js +24 -187
  23. package/src/commands/autoPush.js +48 -17
  24. package/src/commands/check.js +17 -47
  25. package/src/commands/checkout.js +18 -0
  26. package/src/commands/commit.js +21 -0
  27. package/src/commands/conflict.js +30 -0
  28. package/src/commands/conflicts.js +16 -0
  29. package/src/commands/connect.js +60 -48
  30. package/src/commands/delete.js +79 -64
  31. package/src/commands/deploy.js +18 -10
  32. package/src/commands/diff.js +23 -0
  33. package/src/commands/help.js +99 -75
  34. package/src/commands/init.js +4 -10
  35. package/src/commands/local.js +23 -6
  36. package/src/commands/map.js +89 -89
  37. package/src/commands/mcp.js +126 -0
  38. package/src/commands/sync.js +28 -43
  39. package/src/commands/verifyUi.js +3 -2
  40. package/src/localdev/index.js +37 -7
  41. package/src/localdev/mysqlClient.js +1 -1
  42. package/src/mcp/client.js +275 -0
  43. package/src/mcp/hosts.js +520 -0
  44. package/src/mcp/protocol.js +173 -0
  45. package/src/mcp/stdio.js +300 -0
  46. package/src/mcp/tools.js +37 -0
  47. package/src/platforms.js +3 -4
  48. package/src/projectConfig.js +91 -49
  49. package/src/projectMap.js +123 -460
  50. package/src/skill.js +6 -28
  51. package/src/worktree/backend.js +250 -0
  52. package/src/worktree/errors.js +28 -0
  53. package/src/worktree/index.js +461 -0
  54. package/src/worktree/manifest.js +75 -0
  55. package/src/worktree/streams.js +200 -0
  56. package/src/worktree/types.js +103 -0
  57. package/src/worktree/validate.js +37 -0
  58. package/resources/skill/pull/SKILL.md +0 -33
  59. package/resources/skill/references/api.json +0 -20248
  60. package/resources/skill/scripts/draftgo_delete.py +0 -149
  61. package/resources/skill/scripts/draftgo_init.py +0 -80
  62. package/resources/skill/scripts/draftgo_pull.py +0 -427
  63. package/resources/skill/scripts/draftgo_push.py +0 -1022
  64. package/src/python.js +0 -27
@@ -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
+ };