@dforge-core/dforge-mcp 0.2.3 → 0.2.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/dist/server.js CHANGED
@@ -3641,7 +3641,12 @@ var require_fast_uri = __commonJS({
3641
3641
  }
3642
3642
  function resolve8(baseURI, relativeURI, options) {
3643
3643
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3644
- const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
3644
+ const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
3645
+ const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
3646
+ if (baseMalformed || relativeMalformed) {
3647
+ throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
3648
+ }
3649
+ const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
3645
3650
  schemelessOptions.skipEscape = true;
3646
3651
  return serialize2(resolved, schemelessOptions);
3647
3652
  }
@@ -3766,6 +3771,8 @@ var require_fast_uri = __commonJS({
3766
3771
  return uriTokens.join("");
3767
3772
  }
3768
3773
  var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
3774
+ var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
3775
+ var AUTHORITY_INTRODUCER_REGION = /^(?:[^#/:?]+:)?([/\\\t\n\r]*)/;
3769
3776
  function getParseError(parsed, matches) {
3770
3777
  if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
3771
3778
  return 'URI path must start with "/" when authority is present.';
@@ -3795,6 +3802,25 @@ var require_fast_uri = __commonJS({
3795
3802
  uri = "//" + uri;
3796
3803
  }
3797
3804
  }
3805
+ const authorityMatch = uri.match(AUTHORITY_PREFIX);
3806
+ if (authorityMatch !== null && authorityMatch[1].indexOf("\\") !== -1) {
3807
+ parsed.error = "URI authority must not contain a literal backslash.";
3808
+ malformedAuthorityOrPort = true;
3809
+ }
3810
+ const introducerMatch = uri.match(AUTHORITY_INTRODUCER_REGION);
3811
+ if (introducerMatch !== null) {
3812
+ const region = introducerMatch[1];
3813
+ const normalizedRegion = region.replace(/[\t\n\r]/g, "");
3814
+ if (normalizedRegion.length >= 2) {
3815
+ if (normalizedRegion.slice(0, 2) !== "//") {
3816
+ parsed.error = parsed.error || "URI authority must not contain a literal backslash.";
3817
+ malformedAuthorityOrPort = true;
3818
+ } else if (region.length !== normalizedRegion.length) {
3819
+ parsed.error = parsed.error || "URI authority introducer must not contain whitespace.";
3820
+ malformedAuthorityOrPort = true;
3821
+ }
3822
+ }
3823
+ }
3798
3824
  const matches = uri.match(URI_PARSE);
3799
3825
  if (matches) {
3800
3826
  parsed.scheme = matches[1];
@@ -23039,17 +23065,33 @@ function normalizeObjectSchema(schema2) {
23039
23065
  }
23040
23066
  return void 0;
23041
23067
  }
23068
+ function getDotPath(path17) {
23069
+ if (path17.length === 0) {
23070
+ return "object root";
23071
+ }
23072
+ return path17.reduce((acc, seg, index) => {
23073
+ if (index === 0) {
23074
+ return String(seg);
23075
+ }
23076
+ if (typeof seg === "number") {
23077
+ return `${acc}[${seg}]`;
23078
+ }
23079
+ return `${acc}.${seg}`;
23080
+ }, "");
23081
+ }
23042
23082
  function getParseErrorMessage(error51) {
23043
23083
  if (error51 && typeof error51 === "object") {
23084
+ if ("issues" in error51 && Array.isArray(error51.issues) && error51.issues.length > 0) {
23085
+ return error51.issues.map((i) => {
23086
+ if (!i.path?.length) {
23087
+ return i.message;
23088
+ }
23089
+ return `${i.message} at ${getDotPath(i.path)}`;
23090
+ }).join("\n");
23091
+ }
23044
23092
  if ("message" in error51 && typeof error51.message === "string") {
23045
23093
  return error51.message;
23046
23094
  }
23047
- if ("issues" in error51 && Array.isArray(error51.issues) && error51.issues.length > 0) {
23048
- const firstIssue = error51.issues[0];
23049
- if (firstIssue && typeof firstIssue === "object" && "message" in firstIssue) {
23050
- return String(firstIssue.message);
23051
- }
23052
- }
23053
23095
  try {
23054
23096
  return JSON.stringify(error51);
23055
23097
  } catch {
@@ -29664,16 +29706,7 @@ var Server = class extends Protocol {
29664
29706
  if (!methodSchema) {
29665
29707
  throw new Error("Schema is missing a method literal");
29666
29708
  }
29667
- let methodValue;
29668
- if (isZ4Schema(methodSchema)) {
29669
- const v4Schema = methodSchema;
29670
- const v4Def = v4Schema._zod?.def;
29671
- methodValue = v4Def?.value ?? v4Schema.value;
29672
- } else {
29673
- const v3Schema = methodSchema;
29674
- const legacyDef = v3Schema._def;
29675
- methodValue = legacyDef?.value ?? v3Schema.value;
29676
- }
29709
+ const methodValue = getLiteralValue(methodSchema);
29677
29710
  if (typeof methodValue !== "string") {
29678
29711
  throw new Error("Schema method literal must be a string");
29679
29712
  }
@@ -30861,8 +30894,17 @@ var EMPTY_COMPLETION_RESULT = {
30861
30894
  var import_node_process = __toESM(require("process"), 1);
30862
30895
 
30863
30896
  // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
30897
+ var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
30864
30898
  var ReadBuffer = class {
30899
+ constructor(options) {
30900
+ this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
30901
+ }
30865
30902
  append(chunk) {
30903
+ const newSize = (this._buffer?.length ?? 0) + chunk.length;
30904
+ if (newSize > this._maxBufferSize) {
30905
+ this.clear();
30906
+ throw new Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);
30907
+ }
30866
30908
  this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
30867
30909
  }
30868
30910
  readMessage() {
@@ -30890,18 +30932,24 @@ function serializeMessage(message) {
30890
30932
 
30891
30933
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
30892
30934
  var StdioServerTransport = class {
30893
- constructor(_stdin = import_node_process.default.stdin, _stdout = import_node_process.default.stdout) {
30935
+ constructor(_stdin = import_node_process.default.stdin, _stdout = import_node_process.default.stdout, options) {
30894
30936
  this._stdin = _stdin;
30895
30937
  this._stdout = _stdout;
30896
- this._readBuffer = new ReadBuffer();
30897
30938
  this._started = false;
30898
30939
  this._ondata = (chunk) => {
30899
- this._readBuffer.append(chunk);
30900
- this.processReadBuffer();
30940
+ try {
30941
+ this._readBuffer.append(chunk);
30942
+ this.processReadBuffer();
30943
+ } catch (error51) {
30944
+ this.onerror?.(error51);
30945
+ this.close().catch(() => {
30946
+ });
30947
+ }
30901
30948
  };
30902
30949
  this._onerror = (error51) => {
30903
30950
  this.onerror?.(error51);
30904
30951
  };
30952
+ this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
30905
30953
  }
30906
30954
  /**
30907
30955
  * Starts listening for messages on stdin.
@@ -31166,7 +31214,7 @@ function buildZedSettings() {
31166
31214
  var fs = __toESM(require("fs"));
31167
31215
  var path = __toESM(require("path"));
31168
31216
 
31169
- // node_modules/@dforge-core/metadata/dist/aggregation.js
31217
+ // node_modules/@dforge-core/metadata/dist/index.js
31170
31218
  var AggType = {
31171
31219
  Sum: "sum",
31172
31220
  Count: "count",
@@ -31176,8 +31224,6 @@ var AggType = {
31176
31224
  Group: "group"
31177
31225
  };
31178
31226
  var AGG_TYPE_LIST = Object.values(AggType);
31179
-
31180
- // node_modules/@dforge-core/metadata/dist/field-types.js
31181
31227
  var fieldTypes = [
31182
31228
  { cd: "text", name: "Text", columnType: "D", baseDatatypeCd: "string", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },
31183
31229
  { cd: "avatar", name: "Avatar Name", columnType: "D", baseDatatypeCd: "string", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },
@@ -31217,8 +31263,6 @@ function isFieldTypeCd(cd) {
31217
31263
  function getFieldType(cd) {
31218
31264
  return byCd.get(cd);
31219
31265
  }
31220
-
31221
- // node_modules/@dforge-core/metadata/dist/base-datatypes.js
31222
31266
  var BASE_TO_DB = {
31223
31267
  binary: "bytea",
31224
31268
  bool: "bool",
@@ -31240,8 +31284,6 @@ var BASE_TO_DB = {
31240
31284
  function baseToDbDatatype(base) {
31241
31285
  return BASE_TO_DB[base] ?? null;
31242
31286
  }
31243
-
31244
- // node_modules/@dforge-core/metadata/dist/column-types.js
31245
31287
  var columnTypes = [
31246
31288
  { cd: "D", name: "Value", description: "A plain data column stored on this entity." },
31247
31289
  { cd: "R", name: "Reference", description: "An N:1 lookup to another entity (foreign key)." },
@@ -31255,8 +31297,6 @@ var byCd2 = new Map(columnTypes.map((ct) => [ct.cd, ct]));
31255
31297
  function getColumnType(cd) {
31256
31298
  return byCd2.get(cd);
31257
31299
  }
31258
-
31259
- // node_modules/@dforge-core/metadata/dist/traits.js
31260
31300
  var traits = [
31261
31301
  {
31262
31302
  cd: "identity",
@@ -31331,16 +31371,14 @@ function templateFields(fields, entity) {
31331
31371
  for (const [name, def] of Object.entries(fields)) {
31332
31372
  const key = applyTemplate(name, entity);
31333
31373
  const next = { ...def };
31334
- if (typeof next.description === "string")
31335
- next.description = applyTemplate(next.description, entity);
31374
+ if (typeof next.description === "string") next.description = applyTemplate(next.description, entity);
31336
31375
  out[key] = next;
31337
31376
  }
31338
31377
  return out;
31339
31378
  }
31340
31379
  function expandTrait(traitCd, entityName) {
31341
31380
  const trait = byCd3.get(traitCd);
31342
- if (!trait)
31343
- return {};
31381
+ if (!trait) return {};
31344
31382
  const result = {};
31345
31383
  for (const included of trait.includes ?? []) {
31346
31384
  Object.assign(result, expandTrait(included, entityName));
@@ -31350,12 +31388,9 @@ function expandTrait(traitCd, entityName) {
31350
31388
  }
31351
31389
  function expandTraits(traitCds, entityName) {
31352
31390
  const result = {};
31353
- for (const cd of traitCds)
31354
- Object.assign(result, expandTrait(cd, entityName));
31391
+ for (const cd of traitCds) Object.assign(result, expandTrait(cd, entityName));
31355
31392
  return result;
31356
31393
  }
31357
-
31358
- // node_modules/@dforge-core/metadata/dist/derive.js
31359
31394
  var NUMERIC_TOTAL = 18;
31360
31395
  var TEXT_BACKED = /* @__PURE__ */ new Set(["textarea", "markdown", "richtext", "code"]);
31361
31396
  var DB_DATATYPE_OVERRIDE = {
@@ -31364,23 +31399,18 @@ var DB_DATATYPE_OVERRIDE = {
31364
31399
  };
31365
31400
  function deriveDbDatatype(fieldTypeCd, options = {}) {
31366
31401
  const ft = getFieldType(fieldTypeCd);
31367
- if (!ft)
31368
- return "varchar";
31369
- if (ft.columnType === "R" || ft.columnType === "S")
31370
- return null;
31402
+ if (!ft) return "varchar";
31403
+ if (ft.columnType === "R" || ft.columnType === "S") return null;
31371
31404
  const override = DB_DATATYPE_OVERRIDE[ft.cd];
31372
- if (override)
31373
- return override;
31405
+ if (override) return override;
31374
31406
  const base = baseToDbDatatype(ft.baseDatatypeCd);
31375
- if (base === null)
31376
- return null;
31407
+ if (base === null) return null;
31377
31408
  if (ft.baseDatatypeCd === "number") {
31378
31409
  const precision = options.precision ?? ft.precision;
31379
31410
  return precision != null ? `numeric(${NUMERIC_TOTAL},${precision})` : "numeric";
31380
31411
  }
31381
31412
  if (ft.baseDatatypeCd === "string") {
31382
- if (TEXT_BACKED.has(ft.cd))
31383
- return "text";
31413
+ if (TEXT_BACKED.has(ft.cd)) return "text";
31384
31414
  const maxLen = options.maxLen ?? ft.maxLen;
31385
31415
  return maxLen != null ? `varchar(${maxLen})` : "varchar";
31386
31416
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dforge-core/dforge-mcp",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "MCP server for dForge module authoring. Exposes 34 scaffold/patch/validate/pack/install tools and schema resources so AI agents (Claude Code, Cursor, Zed) can create and ship dForge modules.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/iash44/dForge-core",
@@ -34,9 +34,9 @@
34
34
  "install-skills": "node scripts/install-skills.mjs"
35
35
  },
36
36
  "dependencies": {
37
- "@dforge-core/dforge-cli": "^0.2.10",
38
- "@dforge-core/metadata": "^0.0.12",
39
- "@modelcontextprotocol/sdk": "^1.29.0",
37
+ "@dforge-core/dforge-cli": "^0.2.12",
38
+ "@dforge-core/metadata": "^0.0.13",
39
+ "@modelcontextprotocol/sdk": "^1.30.0",
40
40
  "zod": "^4.4.3"
41
41
  },
42
42
  "devDependencies": {
@@ -492,7 +492,20 @@
492
492
  },
493
493
  "o": {
494
494
  "type": "string",
495
- "description": "Operator: eq, neq, =, !=, gt, gtEq, grEq, lt, ltEq, in, nIn, like, isNull, isNotNull, etc."
495
+ "enum": [
496
+ "=", "eq", "!=", "notEq",
497
+ ">", "gr", ">=", "grEq", "<", "less", "<=", "lessEq",
498
+ "eqRef",
499
+ "contains", "!contains", "nContain",
500
+ "start", "!start", "nStart",
501
+ "end", "!end", "nEnd",
502
+ "mask", "!mask", "nMask",
503
+ "null", "empty", "!null", "nEmpty",
504
+ "in", "!in", "nIn",
505
+ "between", "btw", "!between", "nBetween",
506
+ "f", "func"
507
+ ],
508
+ "description": "Operator. Closed set — this is exactly what the server's FilterBuilder translates, and an operator outside it is rejected at install. Symbolic forms and their word aliases are equivalent ('=' / 'eq', '!=' / 'notEq', '>' / 'gr', '>=' / 'grEq', '<' / 'less', '<=' / 'lessEq'); a leading '!' negates, with 'n'-prefixed spellings as the alias ('!in' / 'nIn'). Null checks are 'null' / 'empty' and '!null' / 'nEmpty' (NOT 'isNull' / 'isNotNull'); substring matching is 'contains' (NOT 'like'). 'eqRef' compares against another column (v = column code), 'f' / 'func' takes v = {fn: 'isToday' | 'isYesterday' | 'isThisWeek' | 'isThisMonth' | 'isThisYear' | 'isPast' | 'isFuture' | 'isCurrentUser'}."
496
509
  },
497
510
  "v": {
498
511
  "description": "Comparison value. Scalars, arrays (for in/nIn), or parameter references like '@param_code'."
@@ -506,8 +519,8 @@
506
519
  "properties": {
507
520
  "g": {
508
521
  "type": "string",
509
- "enum": ["and", "or"],
510
- "description": "Group combinator"
522
+ "enum": ["and", "or", "!and", "nAnd", "!or", "nOr"],
523
+ "description": "Group combinator. '!and' / '!or' negate the whole group ('nAnd' / 'nOr' are the alias spellings). Closed set — an unknown combinator is rejected at install (at query time it would silently fall back to AND)."
511
524
  },
512
525
  "i": {
513
526
  "type": "array",
@@ -87,7 +87,23 @@
87
87
  "required": ["c", "o"],
88
88
  "properties": {
89
89
  "c": { "type": "string" },
90
- "o": { "type": "string" },
90
+ "o": {
91
+ "type": "string",
92
+ "enum": [
93
+ "=", "eq", "!=", "notEq",
94
+ ">", "gr", ">=", "grEq", "<", "less", "<=", "lessEq",
95
+ "eqRef",
96
+ "contains", "!contains", "nContain",
97
+ "start", "!start", "nStart",
98
+ "end", "!end", "nEnd",
99
+ "mask", "!mask", "nMask",
100
+ "null", "empty", "!null", "nEmpty",
101
+ "in", "!in", "nIn",
102
+ "between", "btw", "!between", "nBetween",
103
+ "f", "func"
104
+ ],
105
+ "description": "Operator — same closed set as data_views.json. Null checks are 'null' / '!null' (NOT 'isNull' / 'isNotNull'); substring matching is 'contains' (NOT 'like'). An operator outside this set is rejected at install; at query time it would be dropped, widening the row filter it was meant to enforce."
106
+ },
91
107
  "v": {}
92
108
  },
93
109
  "additionalProperties": false
@@ -96,7 +112,7 @@
96
112
  "type": "object",
97
113
  "required": ["g", "i"],
98
114
  "properties": {
99
- "g": { "type": "string", "enum": ["and", "or"] },
115
+ "g": { "type": "string", "enum": ["and", "or", "!and", "nAnd", "!or", "nOr"] },
100
116
  "i": {
101
117
  "type": "array",
102
118
  "items": { "$ref": "#/$defs/filter" }
@@ -366,7 +366,23 @@
366
366
  "required": ["c", "o"],
367
367
  "properties": {
368
368
  "c": { "type": "string" },
369
- "o": { "type": "string" },
369
+ "o": {
370
+ "type": "string",
371
+ "enum": [
372
+ "=", "eq", "!=", "notEq",
373
+ ">", "gr", ">=", "grEq", "<", "less", "<=", "lessEq",
374
+ "eqRef",
375
+ "contains", "!contains", "nContain",
376
+ "start", "!start", "nStart",
377
+ "end", "!end", "nEnd",
378
+ "mask", "!mask", "nMask",
379
+ "null", "empty", "!null", "nEmpty",
380
+ "in", "!in", "nIn",
381
+ "between", "btw", "!between", "nBetween",
382
+ "f", "func"
383
+ ],
384
+ "description": "Operator — same closed set as data_views.json. Null checks are 'null' / '!null' (NOT 'isNull' / 'isNotNull'); substring matching is 'contains' (NOT 'like'). An operator outside this set is rejected at install; at query time it would be dropped, silently widening the dataset."
385
+ },
370
386
  "v": {}
371
387
  },
372
388
  "additionalProperties": false
@@ -375,7 +391,7 @@
375
391
  "type": "object",
376
392
  "required": ["g", "i"],
377
393
  "properties": {
378
- "g": { "type": "string", "enum": ["and", "or"] },
394
+ "g": { "type": "string", "enum": ["and", "or", "!and", "nAnd", "!or", "nOr"] },
379
395
  "i": {
380
396
  "type": "array",
381
397
  "items": { "$ref": "#/$defs/filter" }
@@ -61,7 +61,7 @@ A report has `description`, a `datasets` map, a `layout` object (`{ panels: [...
61
61
  "query": {
62
62
  "entityCd": "opportunity",
63
63
  "columns": ["stage", "amount", "close_date", "customer.name"],
64
- "filter": { "c": "stage", "o": "ne", "v": "Closed Lost" },
64
+ "filter": { "c": "stage", "o": "!=", "v": "Closed Lost" },
65
65
  "sort": [ { "c": "close_date", "d": "desc" } ]
66
66
  },
67
67
  "columnsDef": { "amount": { "label": "Deal Value" }, "customer.name": { "label": "Account" } }