@dypai-ai/mcp 1.0.9 → 1.1.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/package.json +5 -2
- package/src/index.js +231 -66
- package/src/tools/codegen.js +362 -0
- package/src/tools/deploy.js +27 -97
- package/src/tools/domains.js +49 -52
- package/src/tools/enrich.js +17 -0
- package/src/tools/frontend.js +93 -0
- package/src/tools/project-context.js +84 -0
- package/src/tools/proxy.js +14 -6
- package/src/tools/sql-side-effects.js +97 -0
- package/src/tools/sync/codec.js +185 -0
- package/src/tools/sync/describe.js +149 -0
- package/src/tools/sync/diff.js +83 -0
- package/src/tools/sync/index.js +18 -0
- package/src/tools/sync/planner.js +426 -0
- package/src/tools/sync/pull.js +414 -0
- package/src/tools/sync/push.js +411 -0
- package/src/tools/sync/schema-dump.js +96 -0
- package/src/tools/sync/test-endpoint.js +210 -0
- package/src/tools/sync/test.js +343 -0
- package/src/tools/sync/transforms.js +157 -0
- package/src/tools/sync/validate.js +567 -0
- package/src/tools/trace-summarize.js +178 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bidirectional transformations between the DB's executable JSON workflow
|
|
3
|
+
* format and the declarative YAML/files format.
|
|
4
|
+
*
|
|
5
|
+
* CRITICAL: every transform declares its pull (DB → file) and push (file → DB)
|
|
6
|
+
* direction together. This guarantees round-trip symmetry by construction —
|
|
7
|
+
* there's no separate "push" file that can drift out of sync with "pull".
|
|
8
|
+
*
|
|
9
|
+
* Adding a new transform = edit one object here, both directions in one commit.
|
|
10
|
+
*
|
|
11
|
+
* Context shape for pull:
|
|
12
|
+
* {
|
|
13
|
+
* endpointName, nodeId,
|
|
14
|
+
* credIdToName, groupIdToName, endpointIdToName,
|
|
15
|
+
* emitFile(path, content), // collects files to write to disk
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* Context shape for push:
|
|
19
|
+
* {
|
|
20
|
+
* endpointName, nodeId,
|
|
21
|
+
* credNameToId, groupNameToId, endpointNameToId,
|
|
22
|
+
* readFile(path), // returns file contents
|
|
23
|
+
* }
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
// Only extract truly large content. Below these thresholds, SQL and prompts
|
|
27
|
+
// stay inline in the YAML so the endpoint is one self-contained file.
|
|
28
|
+
const SQL_INLINE_MAX_CHARS = 500
|
|
29
|
+
const PROMPT_INLINE_MAX_CHARS = 800
|
|
30
|
+
|
|
31
|
+
const shouldInlineSql = (q) => !q || q.length <= SQL_INLINE_MAX_CHARS
|
|
32
|
+
|
|
33
|
+
// ─── Node-level field transforms ────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
export const NODE_FIELD_TRANSFORMS = [
|
|
36
|
+
{
|
|
37
|
+
name: "credential",
|
|
38
|
+
pull(params, ctx) {
|
|
39
|
+
if (params.credential_id && ctx.credIdToName[params.credential_id]) {
|
|
40
|
+
return { credential: ctx.credIdToName[params.credential_id] }
|
|
41
|
+
}
|
|
42
|
+
return {}
|
|
43
|
+
},
|
|
44
|
+
push(params, ctx) {
|
|
45
|
+
if (params.credential && ctx.credNameToId[params.credential]) {
|
|
46
|
+
return { credential_id: ctx.credNameToId[params.credential] }
|
|
47
|
+
}
|
|
48
|
+
return {}
|
|
49
|
+
},
|
|
50
|
+
pullConsumes: ["credential_id"],
|
|
51
|
+
pushConsumes: ["credential"],
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
{
|
|
55
|
+
name: "agent_tools",
|
|
56
|
+
appliesWhen: (nodeType) => nodeType === "agent",
|
|
57
|
+
pull(params, ctx) {
|
|
58
|
+
if (Array.isArray(params.tool_ids)) {
|
|
59
|
+
return { tools: params.tool_ids.map(id => ctx.endpointIdToName[id] || id) }
|
|
60
|
+
}
|
|
61
|
+
return {}
|
|
62
|
+
},
|
|
63
|
+
push(params, ctx) {
|
|
64
|
+
if (Array.isArray(params.tools)) {
|
|
65
|
+
return { tool_ids: params.tools.map(n => ctx.endpointNameToId[n] || n) }
|
|
66
|
+
}
|
|
67
|
+
return {}
|
|
68
|
+
},
|
|
69
|
+
pullConsumes: ["tool_ids"],
|
|
70
|
+
pushConsumes: ["tools"],
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
{
|
|
74
|
+
name: "sql_extraction",
|
|
75
|
+
appliesWhen: (nodeType) => nodeType === "dypai_database",
|
|
76
|
+
pull(params, ctx) {
|
|
77
|
+
if (params.query && !shouldInlineSql(params.query)) {
|
|
78
|
+
// Flat layout: sql/<endpoint>.sql if only one SQL node, else sql/<endpoint>.<node>.sql
|
|
79
|
+
const suffix = ctx.sqlNodeCount > 1 ? `.${ctx.nodeId}` : ""
|
|
80
|
+
const path = `sql/${ctx.endpointName}${suffix}.sql`
|
|
81
|
+
ctx.emitFile(path, params.query.trim() + "\n")
|
|
82
|
+
return { query_file: path }
|
|
83
|
+
}
|
|
84
|
+
return {}
|
|
85
|
+
},
|
|
86
|
+
push(params, ctx) {
|
|
87
|
+
if (params.query_file) {
|
|
88
|
+
return { query: ctx.readFile(params.query_file).trimEnd() }
|
|
89
|
+
}
|
|
90
|
+
return {}
|
|
91
|
+
},
|
|
92
|
+
pullConsumes: ["query"],
|
|
93
|
+
pushConsumes: ["query_file"],
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
{
|
|
97
|
+
name: "prompt_extraction",
|
|
98
|
+
appliesWhen: (nodeType) => nodeType === "agent",
|
|
99
|
+
pull(params, ctx) {
|
|
100
|
+
if (params.system_prompt && params.system_prompt.length > PROMPT_INLINE_MAX_CHARS) {
|
|
101
|
+
const suffix = ctx.promptNodeCount > 1 ? `.${ctx.nodeId}` : ""
|
|
102
|
+
const path = `prompts/${ctx.endpointName}${suffix}.md`
|
|
103
|
+
ctx.emitFile(path, params.system_prompt.trim() + "\n")
|
|
104
|
+
return { system_prompt_file: path }
|
|
105
|
+
}
|
|
106
|
+
return {}
|
|
107
|
+
},
|
|
108
|
+
push(params, ctx) {
|
|
109
|
+
if (params.system_prompt_file) {
|
|
110
|
+
return { system_prompt: ctx.readFile(params.system_prompt_file).trimEnd() }
|
|
111
|
+
}
|
|
112
|
+
return {}
|
|
113
|
+
},
|
|
114
|
+
pullConsumes: ["system_prompt"],
|
|
115
|
+
pushConsumes: ["system_prompt_file"],
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
{
|
|
119
|
+
name: "code_extraction",
|
|
120
|
+
appliesWhen: (nodeType) => nodeType === "javascript_code" || nodeType === "python_code",
|
|
121
|
+
pull(params, ctx) {
|
|
122
|
+
if (params.code && params.code.length > SQL_INLINE_MAX_CHARS) {
|
|
123
|
+
const ext = ctx.nodeType === "python_code" ? "py" : "js"
|
|
124
|
+
const suffix = ctx.codeNodeCount > 1 ? `.${ctx.nodeId}` : ""
|
|
125
|
+
const path = `code/${ctx.endpointName}${suffix}.${ext}`
|
|
126
|
+
ctx.emitFile(path, params.code.trim() + "\n")
|
|
127
|
+
return { code_file: path }
|
|
128
|
+
}
|
|
129
|
+
return {}
|
|
130
|
+
},
|
|
131
|
+
push(params, ctx) {
|
|
132
|
+
if (params.code_file) {
|
|
133
|
+
return { code: ctx.readFile(params.code_file).trimEnd() }
|
|
134
|
+
}
|
|
135
|
+
return {}
|
|
136
|
+
},
|
|
137
|
+
pullConsumes: ["code"],
|
|
138
|
+
pushConsumes: ["code_file"],
|
|
139
|
+
},
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
// ─── Engine ────────────────────────────────────────────────────────────────
|
|
143
|
+
|
|
144
|
+
function applyTransforms(input, direction, ctx, nodeType) {
|
|
145
|
+
let result = { ...input }
|
|
146
|
+
for (const t of NODE_FIELD_TRANSFORMS) {
|
|
147
|
+
if (t.appliesWhen && !t.appliesWhen(nodeType)) continue
|
|
148
|
+
const added = t[direction](result, ctx) || {}
|
|
149
|
+
const consumes = direction === "pull" ? t.pullConsumes : t.pushConsumes
|
|
150
|
+
for (const f of consumes || []) delete result[f]
|
|
151
|
+
Object.assign(result, added)
|
|
152
|
+
}
|
|
153
|
+
return result
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export const pullNodeParams = (params, ctx, nodeType) => applyTransforms(params, "pull", ctx, nodeType)
|
|
157
|
+
export const pushNodeParams = (params, ctx, nodeType) => applyTransforms(params, "push", ctx, nodeType)
|