@dypai-ai/mcp 1.7.3 → 1.7.4

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.3",
3
+ "version": "1.7.4",
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",
@@ -23,7 +23,10 @@ async function compileSnapshot(projectId, command, files, endpoint = undefined)
23
23
  files,
24
24
  }
25
25
  if (endpoint) args.endpoint = endpoint
26
- return proxyToolCall("backend_compile_snapshot", args)
26
+ // Compiler `ok:false` is a domain validation result, not a transport/tool
27
+ // failure. It intentionally carries valid payloads plus diagnostics so the
28
+ // push pipeline can skip only broken flows instead of dropping all source.
29
+ return proxyToolCall("backend_compile_snapshot", args, { allowFailureResult: true })
27
30
  }
28
31
 
29
32
  export async function buildSnapshotPayload(dypaiRootDir, projectRoot = null) {
@@ -209,7 +209,15 @@ async function ensureInitialized() {
209
209
  return initPromise
210
210
  }
211
211
 
212
- export async function proxyToolCall(toolName, args) {
212
+ function shouldPromoteRemoteFailure(parsed, allowFailureResult = false) {
213
+ return !allowFailureResult
214
+ && parsed
215
+ && typeof parsed === "object"
216
+ && !Array.isArray(parsed)
217
+ && (parsed.success === false || parsed.ok === false)
218
+ }
219
+
220
+ export async function proxyToolCall(toolName, args, { allowFailureResult = false } = {}) {
213
221
  async function callOnce() {
214
222
  await ensureInitialized()
215
223
 
@@ -242,11 +250,9 @@ export async function proxyToolCall(toolName, args) {
242
250
  // Other remote errors come as a JSON object with success:false but no isError
243
251
  // flag. The push pipeline was treating these as successes — promote them to
244
252
  // throws here so the caller's try/catch sees them.
245
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
246
- if (parsed.success === false || parsed.ok === false) {
247
- const msg = parsed.error || parsed.message || parsed.detail || JSON.stringify(parsed).slice(0, 300)
248
- throw new Error(typeof msg === "string" ? msg : JSON.stringify(msg))
249
- }
253
+ if (shouldPromoteRemoteFailure(parsed, allowFailureResult)) {
254
+ const msg = parsed.error || parsed.message || parsed.detail || JSON.stringify(parsed).slice(0, 300)
255
+ throw new Error(typeof msg === "string" ? msg : JSON.stringify(msg))
250
256
  }
251
257
  return parsed
252
258
  }
@@ -270,3 +276,7 @@ export async function proxyToolCall(toolName, args) {
270
276
  throw error
271
277
  }
272
278
  }
279
+
280
+ export const __testing = {
281
+ shouldPromoteRemoteFailure,
282
+ }
@@ -539,15 +539,6 @@ export async function readLocalEffectiveState(rootDir, projectId = null, deps =
539
539
  if (shadowedMeta) shadowed.push({ name: payload.name, shadowed: shadowedMeta })
540
540
  }
541
541
 
542
- for (const diagnostic of diagnostics) {
543
- if (diagnostic?.severity !== "error") continue
544
- yamlState.errors.push({
545
- file: diagnostic.file || diagnostic.endpoint,
546
- error: diagnostic.message || "Failed to build flow push payload",
547
- rule: diagnostic.rule || "flow_push_payload_failed",
548
- })
549
- }
550
-
551
542
  for (const item of rejected) {
552
543
  if (!isBackendSourcePath(item?.path)) continue
553
544
  yamlState.errors.push({
@@ -562,7 +553,14 @@ export async function readLocalEffectiveState(rootDir, projectId = null, deps =
562
553
  byName[name] = { ...entry, source: "legacy-yaml" }
563
554
  }
564
555
 
565
- return { byName, errors: yamlState.errors, shadowed, runnerWarning: null, automations: bulkResult.data?.automations ?? null }
556
+ return {
557
+ byName,
558
+ errors: yamlState.errors,
559
+ shadowed,
560
+ runnerWarning: null,
561
+ compilerDiagnostics: diagnostics,
562
+ automations: bulkResult.data?.automations ?? null,
563
+ }
566
564
  }
567
565
 
568
566
  // ─── Normalization + diff ──────────────────────────────────────────────────
@@ -310,6 +310,41 @@ function dropErroringFromPlan(plan, erroringEndpoints, skippedDiagnostics) {
310
310
  : undefined
311
311
  }
312
312
 
313
+ function skippedEndpointsFromDiagnostics(diagnostics) {
314
+ const names = [...new Set(
315
+ (diagnostics || [])
316
+ .filter((item) => item?.severity === "error" && item.endpoint)
317
+ .map((item) => item.endpoint),
318
+ )]
319
+ return names.length
320
+ ? names.map((name) => ({
321
+ endpoint: name,
322
+ errors: diagnostics
323
+ .filter((item) => item.endpoint === name && item.severity === "error")
324
+ .slice(0, 5)
325
+ .map((item) => ({
326
+ rule: item.rule,
327
+ message: item.message,
328
+ file: item.file,
329
+ loc: item.loc,
330
+ })),
331
+ }))
332
+ : undefined
333
+ }
334
+
335
+ function mergeSkippedEndpointSummaries(...groups) {
336
+ const merged = new Map()
337
+ for (const group of groups) {
338
+ for (const item of group || []) {
339
+ const current = merged.get(item.endpoint)
340
+ merged.set(item.endpoint, current
341
+ ? { ...current, errors: [...(current.errors || []), ...(item.errors || [])].slice(0, 5) }
342
+ : item)
343
+ }
344
+ }
345
+ return merged.size ? [...merged.values()] : undefined
346
+ }
347
+
313
348
  function splitBlockingConflicts(plan, conflicts) {
314
349
  const touched = new Set([
315
350
  ...(plan.update || []).map((item) => item.name),
@@ -741,6 +776,20 @@ export const dypaiPushTool = {
741
776
  error: e.message,
742
777
  }
743
778
  }
779
+ const compilerValidation = partitionValidationErrors(local.compilerDiagnostics)
780
+ if (compilerValidation.projectLevel.length) {
781
+ return {
782
+ success: false,
783
+ applied: false,
784
+ reason: "compiler_validation_failed",
785
+ diagnostics: compilerValidation.projectLevel.slice(0, 20),
786
+ hint: "The compiler reported project-level errors that cannot be isolated to one endpoint.",
787
+ }
788
+ }
789
+ for (const endpoint of compilerValidation.erroringEndpoints) {
790
+ erroringEndpoints.add(endpoint)
791
+ }
792
+ skippedDiagnostics.push(...compilerValidation.errorDiags)
744
793
  try {
745
794
  remote = await fetchRemoteState(targetProjectId)
746
795
  } catch (e) {
@@ -817,7 +866,10 @@ export const dypaiPushTool = {
817
866
  // they aren't pushed (they keep their live version). Deletes stay — a broken
818
867
  // local flow shouldn't block removing endpoints. skip_validation leaves
819
868
  // erroringEndpoints empty, so nothing is dropped.
820
- const skipped_endpoints = dropErroringFromPlan(plan, erroringEndpoints, skippedDiagnostics)
869
+ const skipped_endpoints = mergeSkippedEndpointSummaries(
870
+ dropErroringFromPlan(plan, erroringEndpoints, skippedDiagnostics),
871
+ skippedEndpointsFromDiagnostics(compilerValidation.errorDiags),
872
+ )
821
873
 
822
874
  const groupChanges = (plan.groups?.create?.length || 0) + (plan.groups?.delete?.length || 0)
823
875
  const totalChanges = plan.create.length + plan.update.length + plan.delete.length + groupChanges
@@ -830,8 +882,13 @@ export const dypaiPushTool = {
830
882
  success: false,
831
883
  applied: false,
832
884
  reason: "conflicts_detected",
885
+ summary: summaryFromPlan(plan),
833
886
  conflicts: conflictSplit.blocking,
834
887
  non_blocking_conflicts: conflictSplit.non_blocking.length ? conflictSplit.non_blocking : undefined,
888
+ skipped_endpoints,
889
+ compiler_diagnostics: local.compilerDiagnostics?.length
890
+ ? local.compilerDiagnostics.slice(0, 50)
891
+ : undefined,
835
892
  hint: "Remote changes overlap endpoints this push would update/delete. Run dypai_pull to refresh local state, resolve the overlap, then push again. To override, pass force=true.",
836
893
  }
837
894
  }
@@ -861,6 +918,9 @@ export const dypaiPushTool = {
861
918
  : totalChanges === 0 ? "no_changes" : "dry_run",
862
919
  summary: summaryFromPlan(plan),
863
920
  skipped_endpoints,
921
+ compiler_diagnostics: local.compilerDiagnostics?.length
922
+ ? local.compilerDiagnostics.slice(0, 50)
923
+ : undefined,
864
924
  plan,
865
925
  non_blocking_conflicts: conflictSplit.non_blocking.length ? conflictSplit.non_blocking : undefined,
866
926
  types: typesGenerated,
@@ -1073,6 +1133,9 @@ export const dypaiPushTool = {
1073
1133
  details: applied,
1074
1134
  endpoint_results,
1075
1135
  skipped_endpoints,
1136
+ compiler_diagnostics: local.compilerDiagnostics?.length
1137
+ ? local.compilerDiagnostics.slice(0, 50)
1138
+ : undefined,
1076
1139
  non_blocking_conflicts: conflictSplit.non_blocking.length ? conflictSplit.non_blocking : undefined,
1077
1140
  errors: errors.length ? errors : undefined,
1078
1141
  types: typesGenerated,
@@ -1131,6 +1194,8 @@ export const __testing = {
1131
1194
  syncAutomationMetadata,
1132
1195
  partitionValidationErrors,
1133
1196
  dropErroringFromPlan,
1197
+ skippedEndpointsFromDiagnostics,
1198
+ mergeSkippedEndpointSummaries,
1134
1199
  normalizeEndpointSelection,
1135
1200
  scopePlanToEndpoints,
1136
1201
  backendSourcePathsForEndpointSelection,