@dypai-ai/mcp 1.7.7 → 1.7.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dypai-ai/mcp",
3
- "version": "1.7.7",
3
+ "version": "1.7.9",
4
4
  "description": "DYPAI MCP Server — AI agent toolkit for building and deploying full-stack apps",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -98,6 +98,16 @@ const BLOCKED = new Set([
98
98
 
99
99
  const ROOT_CONFIG_RE = /^(package\.json|package-lock\.json|pnpm-lock\.yaml|bun\.lockb|yarn\.lock|vite\.config|vitest\.config|tsconfig|tailwind\.config|postcss\.config|next\.config|vinext\.config|astro\.config|nuxt\.config|svelte\.config|remix\.config|gatsby-config|angular\.json|docusaurus\.config|wrangler\.toml|wrangler\.json|vercel\.json|netlify\.toml|turbo\.json|components\.json|uno\.config|eslint\.config|prettier\.config|jest\.config|playwright\.config|\.prettierrc|\.eslintrc|\.browserslistrc|\.nvmrc|\.node-version|index\.html)/
100
100
 
101
+ const ROOT_DYPAI_FILES = new Set([
102
+ "dypai/schema.sql",
103
+ "dypai/realtime.yaml",
104
+ "dypai/dypai.config.yaml",
105
+ "dypai/capability-catalog.json",
106
+ "dypai/capability-brief.md",
107
+ "dypai/node-catalog.json",
108
+ "dypai/README.md",
109
+ ])
110
+
101
111
  // ─── Helpers ────────────────────────────────────────────────────────────────
102
112
 
103
113
  function extOf(entry) {
@@ -203,12 +213,16 @@ function isAllowedRootDypaiSourcePath(path) {
203
213
  if (!path.startsWith("dypai/")) return true
204
214
  if (
205
215
  path.startsWith("dypai/flows/")
216
+ || path.startsWith("dypai/automations/")
206
217
  || path.startsWith("dypai/endpoints/")
207
218
  || path.startsWith("dypai/migrations/")
219
+ || path.startsWith("dypai/prompts/")
220
+ || path.startsWith("dypai/code/")
221
+ || path.startsWith("dypai/sql/")
208
222
  || path.startsWith("dypai/types/")
209
223
  || path.startsWith("dypai/lib/")
210
224
  ) return true
211
- return path === "dypai/schema.sql" || path === "dypai/realtime.yaml"
225
+ return ROOT_DYPAI_FILES.has(path)
212
226
  }
213
227
 
214
228
  function isSkippedRootDypaiDirectory(path) {
@@ -223,6 +223,69 @@ async function refreshBackendSourceBaseline(projectId, rootDir, sourceCheckpoint
223
223
  }
224
224
  }
225
225
 
226
+ async function readComputePolicy(rootDir) {
227
+ try {
228
+ const raw = await readFile(join(rootDir, "compute.json"), "utf8")
229
+ const parsed = JSON.parse(raw)
230
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
231
+ throw new Error("dypai/compute.json must contain an object")
232
+ }
233
+ return parsed
234
+ } catch (error) {
235
+ if (error?.code === "ENOENT") return null
236
+ if (error instanceof SyntaxError) {
237
+ throw new Error("dypai/compute.json is not valid JSON")
238
+ }
239
+ throw error
240
+ }
241
+ }
242
+
243
+ async function prepareEndpointPayloadsForCompute(projectId, rootDir, names, local, mapsCtx) {
244
+ if (!names.length) {
245
+ return { ok: true, payloadsByName: {}, compute: { artifacts: 0, uploaded: 0, registered: 0 } }
246
+ }
247
+ const payloads = names.map((name) => {
248
+ const entry = local.byName[name]
249
+ if (!entry) throw new Error(`Compute preparation is missing local endpoint '${name}'`)
250
+ return localToCanonical(entry, mapsCtx)
251
+ })
252
+ const computePolicy = await readComputePolicy(rootDir)
253
+ const result = await api.post(
254
+ `/api/engine/${projectId}/backend/snapshot/prepare-push-payloads`,
255
+ {
256
+ payloads,
257
+ ...(computePolicy ? { compute_policy: computePolicy } : {}),
258
+ },
259
+ )
260
+ if (!result || result.ok !== true || !Array.isArray(result.payloads)) {
261
+ throw new Error("Core API returned an invalid Compute preparation response")
262
+ }
263
+ const payloadsByName = {}
264
+ for (const payload of result.payloads) {
265
+ const name = typeof payload?.name === "string" ? payload.name : ""
266
+ if (!name || payloadsByName[name]) {
267
+ throw new Error("Core API returned duplicate or unnamed Compute payloads")
268
+ }
269
+ payloadsByName[name] = payload
270
+ }
271
+ const missing = names.filter((name) => !payloadsByName[name])
272
+ if (missing.length) {
273
+ throw new Error(`Core API omitted Compute payloads: ${missing.slice(0, 5).join(", ")}`)
274
+ }
275
+ return { ok: true, payloadsByName, compute: result.compute || {} }
276
+ }
277
+
278
+ function canonicalPreparedEndpoint(name, local, preparedByName, mapsCtx) {
279
+ const prepared = preparedByName[name]
280
+ if (!prepared) return localToCanonical(local.byName[name], mapsCtx)
281
+ const entry = local.byName[name]
282
+ return localToCanonical({
283
+ source: "flow",
284
+ group: entry?.group || prepared.group_name || null,
285
+ pushPayload: prepared,
286
+ }, mapsCtx)
287
+ }
288
+
226
289
  /**
227
290
  * Run an async worker over an array with bounded concurrency. Workers never
228
291
  * throw (they handle their own errors via the push errors[] accumulator),
@@ -947,6 +1010,33 @@ export const dypaiPushTool = {
947
1010
  // pushing 50 endpoints doesn't take 50 * 200ms = 10s — drops to ~2s.
948
1011
  // Group operations are sequential because they're fast (a handful of
949
1012
  // groups typically) and we need mapsCtx mutations to be race-free.
1013
+ const endpointNamesToWrite = [...new Set([
1014
+ ...plan.create.map((item) => item.name),
1015
+ ...plan.update.map((item) => item.name),
1016
+ ])]
1017
+ let computePreparation
1018
+ try {
1019
+ computePreparation = await prepareEndpointPayloadsForCompute(
1020
+ targetProjectId,
1021
+ rootDir,
1022
+ endpointNamesToWrite,
1023
+ local,
1024
+ remote.mapsCtx,
1025
+ )
1026
+ } catch (error) {
1027
+ return {
1028
+ success: false,
1029
+ applied: false,
1030
+ phase: "prepare_compute",
1031
+ error: error?.body?.detail?.message
1032
+ || error?.detail?.message
1033
+ || error?.detail
1034
+ || error?.message
1035
+ || String(error),
1036
+ hint: "No backend drafts were written. Update/retry after the Compute preparation path is healthy.",
1037
+ }
1038
+ }
1039
+ const preparedByName = computePreparation.payloadsByName
950
1040
  const CONCURRENCY = PUSH_CONCURRENCY
951
1041
  // `applied.*_drafts` tracks the per-op subset that the API staged as
952
1042
  // drafts (default behavior). The lists in `created/updated/deleted`
@@ -974,7 +1064,7 @@ export const dypaiPushTool = {
974
1064
 
975
1065
  await runWithConcurrency(plan.create, CONCURRENCY, async (item) => {
976
1066
  try {
977
- const canonical = localToCanonical(local.byName[item.name], remote.mapsCtx)
1067
+ const canonical = canonicalPreparedEndpoint(item.name, local, preparedByName, remote.mapsCtx)
978
1068
  const res = await applyCreate(canonical, targetProjectId)
979
1069
  applied.created.push(item.name)
980
1070
  if (isDraftResponse(res)) applied.created_drafts.push(item.name)
@@ -989,7 +1079,7 @@ export const dypaiPushTool = {
989
1079
 
990
1080
  await runWithConcurrency(plan.update, CONCURRENCY, async (item) => {
991
1081
  try {
992
- const canonical = localToCanonical(local.byName[item.name], remote.mapsCtx)
1082
+ const canonical = canonicalPreparedEndpoint(item.name, local, preparedByName, remote.mapsCtx)
993
1083
  const endpointId = remote.byName[item.name]?.id
994
1084
  const res = endpointId
995
1085
  ? await applyUpdate(canonical, endpointId, targetProjectId, remote.byName[item.name]?.revision)
@@ -1139,6 +1229,7 @@ export const dypaiPushTool = {
1139
1229
  non_blocking_conflicts: conflictSplit.non_blocking.length ? conflictSplit.non_blocking : undefined,
1140
1230
  errors: errors.length ? errors : undefined,
1141
1231
  types: typesGenerated,
1232
+ compute: computePreparation.compute,
1142
1233
  automation_sync: automationSync,
1143
1234
  source_checkpoint: sourceCheckpoint,
1144
1235
  source_baseline: sourceBaseline,
@@ -1199,5 +1290,8 @@ export const __testing = {
1199
1290
  normalizeEndpointSelection,
1200
1291
  scopePlanToEndpoints,
1201
1292
  backendSourcePathsForEndpointSelection,
1293
+ readComputePolicy,
1294
+ prepareEndpointPayloadsForCompute,
1295
+ canonicalPreparedEndpoint,
1202
1296
  PUSH_CONCURRENCY,
1203
1297
  }