@json-layout/core 2.8.2 → 2.9.1

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/package.json +4 -2
  2. package/src/compile/index.js +3 -1
  3. package/src/compile/skeleton-node.js +46 -5
  4. package/src/compile/types.ts +1 -0
  5. package/src/compile/utils/resolve-refs.js +5 -8
  6. package/src/compile/utils/x-i18n.js +15 -6
  7. package/src/state/index.js +18 -1
  8. package/src/state/state-node.js +11 -2
  9. package/src/state/utils/urls.js +2 -0
  10. package/src/utils/json-pointer.js +29 -0
  11. package/src/webmcp/README.md +144 -0
  12. package/src/webmcp/index.js +88 -82
  13. package/src/webmcp/project.js +542 -111
  14. package/src/webmcp/resolve.js +37 -1
  15. package/src/webmcp/schema.js +169 -0
  16. package/src/webmcp/suggestions-store.js +121 -0
  17. package/src/webmcp/tools/describe-state.js +20 -64
  18. package/src/webmcp/tools/edit-array.js +51 -28
  19. package/src/webmcp/tools/fill-form-skill.js +17 -41
  20. package/src/webmcp/tools/get-data.js +66 -13
  21. package/src/webmcp/tools/get-field-suggestions.js +12 -23
  22. package/src/webmcp/tools/set-data.js +79 -28
  23. package/src/webmcp/tools/set-field-value.js +88 -39
  24. package/src/webmcp/variants-memo.js +53 -0
  25. package/types/compile/index.d.ts.map +1 -1
  26. package/types/compile/skeleton-node.d.ts +9 -2
  27. package/types/compile/skeleton-node.d.ts.map +1 -1
  28. package/types/compile/types.d.ts +1 -0
  29. package/types/compile/types.d.ts.map +1 -1
  30. package/types/compile/utils/resolve-refs.d.ts.map +1 -1
  31. package/types/compile/utils/x-i18n.d.ts +1 -1
  32. package/types/compile/utils/x-i18n.d.ts.map +1 -1
  33. package/types/state/index.d.ts +10 -0
  34. package/types/state/index.d.ts.map +1 -1
  35. package/types/state/state-node.d.ts.map +1 -1
  36. package/types/state/utils/urls.d.ts.map +1 -1
  37. package/types/utils/json-pointer.d.ts +22 -0
  38. package/types/utils/json-pointer.d.ts.map +1 -0
  39. package/types/webmcp/index.d.ts +23 -15
  40. package/types/webmcp/index.d.ts.map +1 -1
  41. package/types/webmcp/project.d.ts +178 -57
  42. package/types/webmcp/project.d.ts.map +1 -1
  43. package/types/webmcp/resolve.d.ts +7 -3
  44. package/types/webmcp/resolve.d.ts.map +1 -1
  45. package/types/webmcp/schema.d.ts +44 -0
  46. package/types/webmcp/schema.d.ts.map +1 -0
  47. package/types/webmcp/suggestions-store.d.ts +82 -0
  48. package/types/webmcp/suggestions-store.d.ts.map +1 -0
  49. package/types/webmcp/tools/describe-state.d.ts +5 -57
  50. package/types/webmcp/tools/describe-state.d.ts.map +1 -1
  51. package/types/webmcp/tools/edit-array.d.ts +8 -37
  52. package/types/webmcp/tools/edit-array.d.ts.map +1 -1
  53. package/types/webmcp/tools/fill-form-skill.d.ts +10 -13
  54. package/types/webmcp/tools/fill-form-skill.d.ts.map +1 -1
  55. package/types/webmcp/tools/get-data.d.ts +17 -15
  56. package/types/webmcp/tools/get-data.d.ts.map +1 -1
  57. package/types/webmcp/tools/get-field-suggestions.d.ts +4 -30
  58. package/types/webmcp/tools/get-field-suggestions.d.ts.map +1 -1
  59. package/types/webmcp/tools/set-data.d.ts +17 -34
  60. package/types/webmcp/tools/set-data.d.ts.map +1 -1
  61. package/types/webmcp/tools/set-field-value.d.ts +20 -57
  62. package/types/webmcp/tools/set-field-value.d.ts.map +1 -1
  63. package/types/webmcp/variants-memo.d.ts +42 -0
  64. package/types/webmcp/variants-memo.d.ts.map +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"state-node.d.ts","sourceRoot":"","sources":["../../src/state/state-node.js"],"names":[],"mappings":"AAkRA;;;;;;;;;;;GAWG;AACH,4CAXW,OAAO,aAAa,EAAE,kBAAkB,EAAE,cAC1C,OAAO,yBAAyB,EAAE,UAAU,QAC5C,GAAG,WACH,OAAO,YAAY,EAAE,gBAAgB,WACrC,OAAO,oBAAoB,EAAE,OAAO,UACpC,OAAO,yBAAyB,EAAE,cAAc,aAChD,MAAM,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE,gBAAgB,CAAC,YAC9C,OAAO,iBACP,OAAO,qBAAqB,EAAE,uBAAuB,GAAG,IAAI,GAC1D,GAAG,CAsBf;AAiCD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,yCAlBW,OAAO,YAAY,EAAE,sBAAsB,iBAC3C,OAAO,YAAY,EAAE,gBAAgB,kBACrC,OAAO,aAAa,EAAE,cAAc,OACpC,MAAM,GAAG,MAAM,WACf,MAAM,iBACN,MAAM,GAAG,IAAI,YACb,MAAM,kBACN,MAAM,GAAG,IAAI,YACb,OAAO,aAAa,EAAE,YAAY,mBAClC,OAAO,yBAAyB,EAAE,KAAK,GAAG,IAAI,iBAC9C,OAAO,oBAAoB,EAAE,OAAO,QACpC,GAAG,iBACH,OAAO,qBAAqB,EAAE,uBAAuB,GAAG,IAAI,mBAC5D,OAAO,YAAY,EAAE,eAAe,cACpC,MAAM,eACN,OAAO,YAAY,EAAE,SAAS,GAC5B,OAAO,YAAY,EAAE,SAAS,CAipB1C;AAx9BM,qCALI,OAAO,UACP,OAAO,yBAAyB,EAAE,cAAc,WAChD,OAAO,YAAY,EAAE,gBAAgB,GACnC,OAAO,CAMnB;AAs9BD,uFAAuF;AACvF,iCADW,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,KAAK,GAAG,CAgBjF;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,8BAFU,CAAC,YAAY,EAAE,GAAG,EAAE,EAAE,aAAa,EAAE,OAAO,yBAAyB,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,yBAAyB,EAAE,WAAW,EAAE,aAAa,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,OAAO,KAAK,GAAG,CAkC5M"}
1
+ {"version":3,"file":"state-node.d.ts","sourceRoot":"","sources":["../../src/state/state-node.js"],"names":[],"mappings":"AAkRA;;;;;;;;;;;GAWG;AACH,4CAXW,OAAO,aAAa,EAAE,kBAAkB,EAAE,cAC1C,OAAO,yBAAyB,EAAE,UAAU,QAC5C,GAAG,WACH,OAAO,YAAY,EAAE,gBAAgB,WACrC,OAAO,oBAAoB,EAAE,OAAO,UACpC,OAAO,yBAAyB,EAAE,cAAc,aAChD,MAAM,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE,gBAAgB,CAAC,YAC9C,OAAO,iBACP,OAAO,qBAAqB,EAAE,uBAAuB,GAAG,IAAI,GAC1D,GAAG,CAsBf;AA0CD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,yCAlBW,OAAO,YAAY,EAAE,sBAAsB,iBAC3C,OAAO,YAAY,EAAE,gBAAgB,kBACrC,OAAO,aAAa,EAAE,cAAc,OACpC,MAAM,GAAG,MAAM,WACf,MAAM,iBACN,MAAM,GAAG,IAAI,YACb,MAAM,kBACN,MAAM,GAAG,IAAI,YACb,OAAO,aAAa,EAAE,YAAY,mBAClC,OAAO,yBAAyB,EAAE,KAAK,GAAG,IAAI,iBAC9C,OAAO,oBAAoB,EAAE,OAAO,QACpC,GAAG,iBACH,OAAO,qBAAqB,EAAE,uBAAuB,GAAG,IAAI,mBAC5D,OAAO,YAAY,EAAE,eAAe,cACpC,MAAM,eACN,OAAO,YAAY,EAAE,SAAS,GAC5B,OAAO,YAAY,EAAE,SAAS,CAipB1C;AAj+BM,qCALI,OAAO,UACP,OAAO,yBAAyB,EAAE,cAAc,WAChD,OAAO,YAAY,EAAE,gBAAgB,GACnC,OAAO,CAMnB;AA+9BD,uFAAuF;AACvF,iCADW,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,KAAK,GAAG,CAgBjF;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,8BAFU,CAAC,YAAY,EAAE,GAAG,EAAE,EAAE,aAAa,EAAE,OAAO,yBAAyB,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,yBAAyB,EAAE,WAAW,EAAE,aAAa,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,OAAO,KAAK,GAAG,CAkC5M"}
@@ -1 +1 @@
1
- {"version":3,"file":"urls.d.ts","sourceRoot":"","sources":["../../../src/state/utils/urls.js"],"names":[],"mappings":"AAEO,6BAA4B,MAAM,WAAoB,MAAM,OAIlE"}
1
+ {"version":3,"file":"urls.d.ts","sourceRoot":"","sources":["../../../src/state/utils/urls.js"],"names":[],"mappings":"AAEO,6BAA4B,MAAM,WAAoB,MAAM,OAMlE"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @file JSON pointer traversal, shared by the compilation step and the webmcp tools
3
+ * @description Pointers are produced by concatenation in the compilation step
4
+ * (`${refPointerPrefix}/properties/${propertyKey}` and similar), their segments are
5
+ * therefore consumed raw: they are deliberately not unescaped as RFC 6901 would
6
+ * prescribe, so that resolution stays symmetric with the way pointers are built.
7
+ */
8
+ /**
9
+ * Resolve the fragment part of a JSON pointer (what follows the '#') in a schema or any object.
10
+ * @param {unknown} root
11
+ * @param {string} fragment - e.g. '/properties/address/items', leading and empty segments are ignored
12
+ * @returns {{found: true, value: unknown} | {found: false, path: string[]}} - the resolved value, or
13
+ * the segments consumed up to and including the missing one, to report where the resolution failed
14
+ */
15
+ export function resolvePointerFragment(root: unknown, fragment: string): {
16
+ found: true;
17
+ value: unknown;
18
+ } | {
19
+ found: false;
20
+ path: string[];
21
+ };
22
+ //# sourceMappingURL=json-pointer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-pointer.d.ts","sourceRoot":"","sources":["../../src/utils/json-pointer.js"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;GAMG;AACH,6CALW,OAAO,YACP,MAAM,GACJ;IAAC,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAC,GAAG;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAC,CAgB1E"}
@@ -1,3 +1,10 @@
1
+ /**
2
+ * @typedef {object} WebMCPOptions
3
+ * @property {string} [prefixName] - Prefix for all tool names
4
+ * @property {string} [dataTitle] - Title used in descriptions (default: 'form')
5
+ * @property {boolean} [includeFillFormSkill] - Include the fillFormSkill tool (default: false)
6
+ * @property {boolean} [includeSubAgent] - Include a subagent_ tool wrapping all form tools (default: false)
7
+ */
1
8
  /**
2
9
  * WebMCP class that provides MCP tool descriptors for a StatefulLayout instance
3
10
  */
@@ -22,16 +29,6 @@ export class WebMCP {
22
29
  * @type {string}
23
30
  */
24
31
  readonly _dataTitle: string;
25
- /**
26
- * @readonly
27
- * @type {"small"|"medium"|"large"}
28
- */
29
- readonly _complexity: "small" | "medium" | "large";
30
- /**
31
- * @readonly
32
- * @type {object | null}
33
- */
34
- readonly _schema: object | null;
35
32
  /**
36
33
  * @readonly
37
34
  * @type {boolean}
@@ -46,6 +43,19 @@ export class WebMCP {
46
43
  * @type {string[]}
47
44
  */
48
45
  _registeredTools: string[];
46
+ /**
47
+ * memory of the last suggestions per node path, used by setFieldValue's suggestionIndex
48
+ * @readonly
49
+ * @type {SuggestionsStore}
50
+ */
51
+ readonly _suggestionsStore: SuggestionsStore;
52
+ /**
53
+ * Variant lists already sent to the agent. Never cleared on a write: a schema's branches
54
+ * are a constant, so unlike memorized suggestions nothing about the data can invalidate
55
+ * them.
56
+ * @type {VariantsMemo}
57
+ */
58
+ _variantsMemo: VariantsMemo;
49
59
  /**
50
60
  * @param {string} name
51
61
  * @returns {string}
@@ -64,6 +74,7 @@ export class WebMCP {
64
74
  */
65
75
  unregisterTools(): Promise<void>;
66
76
  }
77
+ export type ToolDescriptor = import("@mcp-b/webmcp-types").ToolDescriptor;
67
78
  export type WebMCPOptions = {
68
79
  /**
69
80
  * - Prefix for all tool names
@@ -73,10 +84,6 @@ export type WebMCPOptions = {
73
84
  * - Title used in descriptions (default: 'form')
74
85
  */
75
86
  dataTitle?: string | undefined;
76
- /**
77
- * - The original JSON schema
78
- */
79
- schema?: object | undefined;
80
87
  /**
81
88
  * - Include the fillFormSkill tool (default: false)
82
89
  */
@@ -86,5 +93,6 @@ export type WebMCPOptions = {
86
93
  */
87
94
  includeSubAgent?: boolean | undefined;
88
95
  };
89
- export type ToolDescriptor = import("@mcp-b/webmcp-types").ToolDescriptor;
96
+ import { SuggestionsStore } from './suggestions-store.js';
97
+ import { VariantsMemo } from './variants-memo.js';
90
98
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/webmcp/index.js"],"names":[],"mappings":"AA4DA;;GAEG;AACH;IAgDE;;;OAGG;IACH,4BAHW,OAAO,mBAAmB,EAAE,cAAc,YAC1C,aAAa,EAUvB;IA3DD;;;OAGG;IACH,0BAFU,OAAO,mBAAmB,EAAE,cAAc,CAErC;IAEf;;;OAGG;IACH,sBAFU,MAAM,CAEL;IAEX;;;OAGG;IACH,qBAFU,MAAM,CAEN;IAEV;;;OAGG;IACH,sBAFU,OAAO,GAAC,QAAQ,GAAC,OAAO,CAEvB;IAEX;;;OAGG;IACH,kBAFU,MAAM,GAAG,IAAI,CAET;IAEd;;;OAGG;IACH,gCAFU,OAAO,CAEY;IAE7B;;;OAGG;IACH,2BAFU,OAAO,CAEO;IAExB;;OAEG;IACH,kBAFU,MAAM,EAAE,CAEG;IAgBrB;;;OAGG;IACH,gBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;OAEG;IACH,YAFa,cAAc,EAAE,CA0O5B;IAED;;OAEG;IACH,iBAFa,OAAO,CAAC,IAAI,CAAC,CAczB;IAED;;OAEG;IACH,mBAFa,OAAO,CAAC,IAAI,CAAC,CAYzB;CACF;;;;;;;;;;;;;;;;;;;;;;;6BAjYa,OAAO,qBAAqB,EAAE,cAAc"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/webmcp/index.js"],"names":[],"mappings":"AA2CA;;;;;;GAMG;AAEH;;GAEG;AACH;IAmDE;;;OAGG;IACH,4BAHW,OAAO,mBAAmB,EAAE,cAAc,YAC1C,aAAa,EAQvB;IA5DD;;;OAGG;IACH,0BAFU,OAAO,mBAAmB,EAAE,cAAc,CAErC;IAEf;;;OAGG;IACH,sBAFU,MAAM,CAEL;IAEX;;;OAGG;IACH,qBAFU,MAAM,CAEN;IAEV;;;OAGG;IACH,gCAFU,OAAO,CAEY;IAE7B;;;OAGG;IACH,2BAFU,OAAO,CAEO;IAExB;;OAEG;IACH,kBAFU,MAAM,EAAE,CAEG;IAErB;;;;OAIG;IACH,4BAFU,gBAAgB,CAEgB;IAE1C;;;;;OAKG;IACH,eAFU,YAAY,CAEY;IAclC;;;OAGG;IACH,gBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;OAEG;IACH,YAFa,cAAc,EAAE,CAwP5B;IAED;;OAEG;IACH,iBAFa,OAAO,CAAC,IAAI,CAAC,CAczB;IAED;;OAEG;IACH,mBAFa,OAAO,CAAC,IAAI,CAAC,CAYzB;CACF;6BApYa,OAAO,qBAAqB,EAAE,cAAc;;;;;;;;;;;;;;;;;;;iCAHzB,wBAAwB;6BAC5B,oBAAoB"}
@@ -1,28 +1,91 @@
1
1
  /**
2
- * @typedef {{
3
- * path: string,
4
- * type: string,
5
- * data: unknown,
6
- * title?: string,
7
- * label?: string,
8
- * help?: string,
9
- * error?: string,
10
- * required?: boolean,
11
- * readOnly?: boolean,
12
- * modified?: boolean,
13
- * constraints?: Record<string, unknown>,
14
- * variants?: Array<{index: number, title: string}>,
15
- * selectedVariant?: number,
16
- * children?: Array<ProjectedNode>,
17
- * getSuggestions?: boolean
18
- * }} ProjectedNode
2
+ * Help is authored as HTML for a browser. An agent reads text, so the markup is pure cost —
3
+ * `&#39;` is not merely wasted, it is harder to read than the apostrophe it stands for —
4
+ * and the newlines between block tags break the one-line-per-node markdown the state tree
5
+ * is made of.
6
+ * @param {string} html
7
+ * @returns {string}
19
8
  */
9
+ export function helpToText(html: string): string;
20
10
  /**
11
+ * Which nodes are currently rendered, by path. A node hidden by a layout `if` stays in
12
+ * the tree as comp "none", so what a write changes there is visibility rather than the
13
+ * set of paths — comparing paths alone would report nothing. A node governed by a schema
14
+ * if/then is the other way round: it is absent until the condition holds, so the set of
15
+ * paths is all there is to compare. Recording both facts lets one diff serve both.
21
16
  * @param {import('../state/types.js').StateNode} node
22
- * @param {import('../state/index.js').StatefulLayout} statefulLayout
23
- * @returns {ProjectedNode}
17
+ * @param {Map<string, {comp: string, owns: boolean}>} [into]
18
+ * @returns {Map<string, {comp: string, owns: boolean}>}
19
+ */
20
+ export function visibilitySnapshot(node: import("../state/types.js").StateNode, into?: Map<string, {
21
+ comp: string;
22
+ owns: boolean;
23
+ }>): Map<string, {
24
+ comp: string;
25
+ owns: boolean;
26
+ }>;
27
+ /**
28
+ * What a write turned visible or invisible.
29
+ *
30
+ * A field can arrive two ways: a layout `if` toggles a node that already exists between
31
+ * comp "none" and its real component, while a schema-level if/then has no node at all
32
+ * until the condition holds and then creates one. Both are the same event to an agent —
33
+ * something it must now fill that it could not before — so both count.
34
+ *
35
+ * `activated` is the variant selector a write just switched, if any. Activating a variant
36
+ * replaces a whole branch, and setFieldValue already lists the branch it activated;
37
+ * counting those nodes here too would print the same subtree twice.
38
+ * @param {Map<string, {comp: string, owns: boolean}>} before
39
+ * @param {Map<string, {comp: string, owns: boolean}>} after
40
+ * @param {string} [activated] - fullKey of a variant selector whose subtree is reported elsewhere
41
+ * @returns {{ revealed: string[], hidden: string[] }}
42
+ */
43
+ export function diffVisibility(before: Map<string, {
44
+ comp: string;
45
+ owns: boolean;
46
+ }>, after: Map<string, {
47
+ comp: string;
48
+ owns: boolean;
49
+ }>, activated?: string): {
50
+ revealed: string[];
51
+ hidden: string[];
52
+ };
53
+ /**
54
+ * @param {{ revealed: string[], hidden: string[] }} diff
55
+ * @returns {string}
56
+ */
57
+ export function formatVisibilityDiff(diff: {
58
+ revealed: string[];
59
+ hidden: string[];
60
+ }): string;
61
+ /**
62
+ * Render a value for the agent: in full when it is small enough to be worth reading,
63
+ * otherwise named with its kind and size so the agent knows what is there without paying
64
+ * for it. It can always read a node's own subtree with describeState.
65
+ * @param {unknown} value
66
+ * @returns {string | undefined}
67
+ */
68
+ export function abbreviateValue(value: unknown): string | undefined;
69
+ /**
70
+ * Whether this field's options cannot be fetched yet because the request that would
71
+ * produce them cannot be built.
72
+ *
73
+ * The state layer resolves a remote list's URL up front and stores it as `itemsCacheKey`;
74
+ * when the expression THROWS — because it reads a field nobody has filled in — the key is
75
+ * null. That is a different situation from "your query matched nothing" and from "this
76
+ * field has no list", and all three used to arrive as the same four words. The review that
77
+ * prompted this put 45% of the option lists across thirty real applications in this state
78
+ * until some other field is written first, so it is the common case, not an edge.
79
+ * @param {import('../state/types.js').StateNode} node
80
+ * @returns {boolean}
24
81
  */
25
- export function projectNode(node: import("../state/types.js").StateNode, statefulLayout: import("../state/index.js").StatefulLayout): ProjectedNode;
82
+ export function suggestionsBlocked(node: import("../state/types.js").StateNode): boolean;
83
+ /**
84
+ * The expression a blocked list is waiting on, so the answer can say what to go and set.
85
+ * @param {import('../state/types.js').StateNode} node
86
+ * @returns {string|undefined}
87
+ */
88
+ export function suggestionsSource(node: import("../state/types.js").StateNode): string | undefined;
26
89
  /**
27
90
  * Project a single field result for slim mutation responses
28
91
  * @param {import('../state/types.js').StateNode} node
@@ -35,77 +98,135 @@ export function projectFieldResult(node: import("../state/types.js").StateNode,
35
98
  data: unknown;
36
99
  error?: string;
37
100
  };
38
- /**
39
- * @param {import('../state/types.js').StateTree} stateTree
40
- * @param {import('../state/index.js').StatefulLayout} statefulLayout
41
- * @returns {{ root: ProjectedNode, valid: boolean }}
42
- */
43
- export function projectStateTree(stateTree: import("../state/types.js").StateTree, statefulLayout: import("../state/index.js").StatefulLayout): {
44
- root: ProjectedNode;
45
- valid: boolean;
46
- };
47
101
  /**
48
102
  * Format a projected node as a markdown line for LLM-readable output.
49
103
  * @param {import('../state/types.js').StateNode} node
50
104
  * @param {import('../state/index.js').StatefulLayout} statefulLayout
51
105
  * @param {number} [depth]
106
+ * @param {Record<string, string>} [errorsByPath] - computed on the root node when not given
107
+ * @param {import('./variants-memo.js').VariantsMemo} [variantsMemo] - when given, a variant
108
+ * list already printed for the same schema node is replaced by a pointer back to it
52
109
  * @returns {string}
53
110
  */
54
- export function projectNodeToMarkdown(node: import("../state/types.js").StateNode, statefulLayout: import("../state/index.js").StatefulLayout, depth?: number): string;
111
+ export function projectNodeToMarkdown(node: import("../state/types.js").StateNode, statefulLayout: import("../state/index.js").StatefulLayout, depth?: number, errorsByPath?: Record<string, string>, variantsMemo?: import("./variants-memo.js").VariantsMemo): string;
55
112
  /**
56
113
  * Format a state tree as markdown for LLM-readable output.
57
114
  * @param {import('../state/types.js').StateTree} stateTree
58
115
  * @param {import('../state/index.js').StatefulLayout} statefulLayout
116
+ * @param {import('./variants-memo.js').VariantsMemo} [variantsMemo]
59
117
  * @returns {string}
60
118
  */
61
- export function projectStateTreeToMarkdown(stateTree: import("../state/types.js").StateTree, statefulLayout: import("../state/index.js").StatefulLayout): string;
119
+ export function projectStateTreeToMarkdown(stateTree: import("../state/types.js").StateTree, statefulLayout: import("../state/index.js").StatefulLayout, variantsMemo?: import("./variants-memo.js").VariantsMemo): string;
62
120
  /**
63
121
  * Format a mutation result as concise text for LLM-readable output.
64
122
  * @param {boolean} valid
65
- * @param {Array<{path: string, message: string}>} errors
123
+ * @param {Array<{path: string, message: string}>} errors - errors of the mutated subtree
66
124
  * @param {string} [prefix] - optional prefix line (e.g. field info)
125
+ * @param {number} [otherErrors] - number of errors of the form outside of the mutated subtree
67
126
  * @returns {string}
68
127
  */
69
128
  export function formatMutationResult(valid: boolean, errors: Array<{
70
129
  path: string;
71
130
  message: string;
72
- }>, prefix?: string): string;
131
+ }>, prefix?: string, otherErrors?: number): string;
73
132
  /**
74
- * Format field suggestions as markdown for LLM-readable output.
133
+ * @typedef {{index: number, title: string, key?: string, value?: unknown, valueOmitted?: boolean, valueLength?: number}} ProjectedSuggestion
134
+ */
135
+ /**
136
+ * Project suggestions for the tools output: anything but a short scalar is identified by
137
+ * its title and key alone, and referred to by index instead of copied around.
75
138
  * @param {Array<{value: unknown, title: string, key?: string}>} items
76
- * @returns {string}
139
+ * @param {number} [baseIndex] - index of the first item, as the store assigned it
140
+ * @returns {ProjectedSuggestion[]}
77
141
  */
78
- export function formatSuggestions(items: Array<{
142
+ export function projectSuggestions(items: Array<{
79
143
  value: unknown;
80
144
  title: string;
81
145
  key?: string;
82
- }>): string;
146
+ }>, baseIndex?: number): ProjectedSuggestion[];
83
147
  /**
84
- * @param {import('../state/types.js').StateNode} node
148
+ * Format field suggestions as markdown for LLM-readable output.
149
+ * @param {ProjectedSuggestion[]} suggestions
150
+ * @param {string} [blockedOn] - the expression the list is waiting on, when it has one
151
+ * @returns {string}
152
+ */
153
+ export function formatSuggestions(suggestions: ProjectedSuggestion[], blockedOn?: string): string;
154
+ /**
155
+ * Errors of the whole form, each named by the location it actually applies to.
156
+ *
157
+ * A node only carries an error while it is hydrated. A list shows its items in summary
158
+ * mode, so nothing below an unedited item exists as a node, and every error under it
159
+ * collapses onto the list — one message, on a path that is not the faulty one. An agent
160
+ * told "/sections must be integer" knows it is wrong and not where, and retries blind.
161
+ *
162
+ * So a node error that is standing in for deeper errors nobody names is replaced by
163
+ * those errors, addressed by data pointer. Errors a hydrated node does name keep their
164
+ * form path, which is what the mutation tools expect.
165
+ * @param {import('../state/index.js').StatefulLayout} statefulLayout
85
166
  * @returns {Array<{path: string, message: string}>}
86
167
  */
87
- export function collectErrors(node: import("../state/types.js").StateNode): Array<{
168
+ export function collectErrors(statefulLayout: import("../state/index.js").StatefulLayout): Array<{
88
169
  path: string;
89
170
  message: string;
90
171
  }>;
91
- export type ProjectedNode = {
92
- path: string;
93
- type: string;
94
- data: unknown;
95
- title?: string;
96
- label?: string;
97
- help?: string;
98
- error?: string;
99
- required?: boolean;
100
- readOnly?: boolean;
101
- modified?: boolean;
102
- constraints?: Record<string, unknown>;
103
- variants?: Array<{
104
- index: number;
105
- title: string;
172
+ /**
173
+ * Errors of the subtree of a node, and count of the errors of the rest of the form.
174
+ * @param {import('../state/index.js').StatefulLayout} statefulLayout
175
+ * @param {import('../state/types.js').StateNode} node
176
+ * @returns {{ errors: Array<{path: string, message: string}>, otherErrors: number }}
177
+ */
178
+ export function collectScopedErrors(statefulLayout: import("../state/index.js").StatefulLayout, node: import("../state/types.js").StateNode): {
179
+ errors: Array<{
180
+ path: string;
181
+ message: string;
106
182
  }>;
107
- selectedVariant?: number;
108
- children?: Array<ProjectedNode>;
109
- getSuggestions?: boolean;
183
+ otherErrors: number;
184
+ };
185
+ /**
186
+ * Suggestion values can be arbitrarily large objects (a whole dataset definition for example),
187
+ * they are kept out of the tools output and retrieved by index with setFieldValue.
188
+ */
189
+ /**
190
+ * Longest value inlined in a suggestion listing. Only scalars are ever inlined: a picker
191
+ * shows a person titles, not the objects behind them, and an agent picks a row the same
192
+ * way, by index. Printing a slice of each object cost 61-77% of every suggestion response
193
+ * measured, for bytes the tool's own description tells the agent never to copy.
194
+ */
195
+ export const SUGGESTION_VALUE_MAX_LENGTH: 100;
196
+ /**
197
+ * Longest value rendered in full anywhere the agent reads state. Beyond it a value is
198
+ * named rather than printed: a picked data-fair dataset is 4-13 KB of column schema, and
199
+ * echoing it on the write, again in the state tree and a third time from getData was the
200
+ * single largest cost in the eval — for content the agent applied by index and never had
201
+ * to handle.
202
+ */
203
+ export const DISPLAYED_VALUE_MAX_LENGTH: 1000;
204
+ /** Most revealed or hidden paths named before the list is summarised instead. */
205
+ export const REVEALED_PATHS_MAX: 10;
206
+ /**
207
+ * Longest rendered list of options inlined into a state line instead of being flagged as
208
+ * something to go and fetch. A closed enum is already in hand — the state layer resolves it
209
+ * into itemsCacheKey without a request — so flagging it sent the agent on a round trip for
210
+ * a list nobody had to look up: charts spent two of sixteen calls reading four-const enums,
211
+ * and sortBy, sortOrder, color and strValue would each have cost another.
212
+ */
213
+ export const INLINE_ITEMS_MAX_LENGTH: 200;
214
+ /**
215
+ * Longest help inlined on a node the agent did not ask about. Help is written for someone
216
+ * looking at a form, where it sits behind a "?" icon and is read on demand; inlined into
217
+ * every state read it is pushed instead, and portal-page spends 782 characters of SEO
218
+ * advice on a field no agent in the eval has ever filled. Past this length it is named and
219
+ * left to be fetched, the same bargain oversized values get. Short help stays inline
220
+ * whatever the node — it is the kind that changes what an agent writes, such as a negative
221
+ * height meaning automatic sizing.
222
+ */
223
+ export const HELP_MAX_LENGTH: 300;
224
+ export type ProjectedSuggestion = {
225
+ index: number;
226
+ title: string;
227
+ key?: string;
228
+ value?: unknown;
229
+ valueOmitted?: boolean;
230
+ valueLength?: number;
110
231
  };
111
232
  //# sourceMappingURL=project.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/webmcp/project.js"],"names":[],"mappings":"AA+CA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;GAIG;AACH,kCAJW,OAAO,mBAAmB,EAAE,SAAS,kBACrC,OAAO,mBAAmB,EAAE,cAAc,GACxC,aAAa,CAiDzB;AAED;;;;;GAKG;AACH,yCAJW,OAAO,mBAAmB,EAAE,SAAS,kBACrC,OAAO,mBAAmB,EAAE,cAAc,GACxC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAWzE;AAED;;;;GAIG;AACH,4CAJW,OAAO,mBAAmB,EAAE,SAAS,kBACrC,OAAO,mBAAmB,EAAE,cAAc,GACxC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAOnD;AAED;;;;;;GAMG;AACH,4CALW,OAAO,mBAAmB,EAAE,SAAS,kBACrC,OAAO,mBAAmB,EAAE,cAAc,UAC1C,MAAM,GACJ,MAAM,CAoElB;AAED;;;;;GAKG;AACH,sDAJW,OAAO,mBAAmB,EAAE,SAAS,kBACrC,OAAO,mBAAmB,EAAE,cAAc,GACxC,MAAM,CAsBlB;AAED;;;;;;GAMG;AACH,4CALW,OAAO,UACP,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAC,WACtC,MAAM,GACJ,MAAM,CAmBlB;AAED;;;;GAIG;AACH,yCAHW,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAC,CAAC,GAClD,MAAM,CAclB;AAED;;;GAGG;AACH,oCAHW,OAAO,mBAAmB,EAAE,SAAS,GACnC,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAC,CAOlD;4BAnQY;IACR,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IACjD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IAChC,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB"}
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/webmcp/project.js"],"names":[],"mappings":"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"}
@@ -1,6 +1,3 @@
1
- /**
2
- * @file Node resolution for webmcp tools
3
- */
4
1
  /**
5
2
  * Navigate from a root StateNode to a descendant node by path.
6
3
  * @param {import('../state/types.js').StateNode} root
@@ -8,4 +5,11 @@
8
5
  * @returns {import('../state/types.js').StateNode|undefined}
9
6
  */
10
7
  export function resolveNode(root: import("../state/types.js").StateNode, path: string): import("../state/types.js").StateNode | undefined;
8
+ /**
9
+ * Children of a node as they should be presented to an agent: hidden nodes are removed
10
+ * and the duplicated activated list item is deduplicated.
11
+ * @param {import('../state/types.js').StateNode} node
12
+ * @returns {import('../state/types.js').StateNode[]}
13
+ */
14
+ export function visibleChildren(node: import("../state/types.js").StateNode): import("../state/types.js").StateNode[];
11
15
  //# sourceMappingURL=resolve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/webmcp/resolve.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;GAKG;AACH,kCAJW,OAAO,mBAAmB,EAAE,SAAS,QACrC,MAAM,GACJ,OAAO,mBAAmB,EAAE,SAAS,GAAC,SAAS,CAgB3D"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/webmcp/resolve.js"],"names":[],"mappings":"AAkBA;;;;;GAKG;AACH,kCAJW,OAAO,mBAAmB,EAAE,SAAS,QACrC,MAAM,GACJ,OAAO,mBAAmB,EAAE,SAAS,GAAC,SAAS,CAgB3D;AAED;;;;;GAKG;AACH,sCAHW,OAAO,mBAAmB,EAAE,SAAS,GACnC,OAAO,mBAAmB,EAAE,SAAS,EAAE,CAgBnD"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Deep clone a schema fragment while removing the keys added by the compilation step.
3
+ * @param {unknown} fragment
4
+ * @returns {unknown}
5
+ */
6
+ export function cleanSchemaFragment(fragment: unknown): unknown;
7
+ /**
8
+ * Resolve a schema fragment from a skeleton pointer (ex: "_jl#/properties/filters/items").
9
+ * @param {object} schema - a JSON schema, its $id should match the pointer prefix
10
+ * @param {string} pointer
11
+ * @returns {object|undefined}
12
+ */
13
+ export function resolveSchemaPointer(schema: object, pointer: string): object | undefined;
14
+ /**
15
+ * Resolve the sub-schema that governs a node of the form.
16
+ * The schema given to the WebMCP instance is preferred (it is pristine),
17
+ * the compiled one is used as a fallback (it is cleaned up before being returned).
18
+ * @param {StateNode} node
19
+ * @param {StatefulLayout} statefulLayout
20
+ * @param {object|null} [originalSchema]
21
+ * @returns {object|undefined}
22
+ */
23
+ export function resolveNodeSchema(node: StateNode, statefulLayout: StatefulLayout, originalSchema?: object | null): object | undefined;
24
+ /**
25
+ * List the fields declared by the skeleton of a node, even when the state tree
26
+ * did not hydrate them yet (a collapsed list item for example).
27
+ * @param {StateNode} node
28
+ * @param {StatefulLayout} statefulLayout
29
+ * @param {object|null} [originalSchema]
30
+ * @returns {DeclaredField[]}
31
+ */
32
+ export function projectDeclaredFields(node: StateNode, statefulLayout: StatefulLayout, originalSchema?: object | null): DeclaredField[];
33
+ export type StateNode = import("../state/types.js").StateNode;
34
+ export type StatefulLayout = import("../state/index.js").StatefulLayout;
35
+ export type DeclaredField = {
36
+ key: string | number;
37
+ path: string;
38
+ type?: string;
39
+ title?: string;
40
+ required?: boolean;
41
+ enum?: unknown[];
42
+ declared: true;
43
+ };
44
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/webmcp/schema.js"],"names":[],"mappings":"AAwBA;;;;GAIG;AACH,8CAHW,OAAO,GACL,OAAO,CAcnB;AAeD;;;;;GAKG;AACH,6CAJW,MAAM,WACN,MAAM,GACJ,MAAM,GAAC,SAAS,CAgB5B;AAED;;;;;;;;GAQG;AACH,wCALW,SAAS,kBACT,cAAc,mBACd,MAAM,GAAC,IAAI,GACT,MAAM,GAAC,SAAS,CAkB5B;AAqBD;;;;;;;GAOG;AACH,4CALW,SAAS,kBACT,cAAc,mBACd,MAAM,GAAC,IAAI,GACT,aAAa,EAAE,CAsC3B;wBAhKa,OAAO,mBAAmB,EAAE,SAAS;6BACrC,OAAO,mBAAmB,EAAE,cAAc;4BAQ3C;IAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAA;CAAE"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @file Memory of the last suggestions returned for each node path
3
+ * @description Suggestion values can be large objects, they are not returned in full
4
+ * to the agent. They are memorized here so that setFieldValue can reuse the original
5
+ * value from its index.
6
+ *
7
+ * Searches on the same path accumulate rather than replace one another, and indices are
8
+ * absolute across them. Replacing meant a second search silently rebound every index the
9
+ * first had handed out, so an agent applying an index it had been given a moment earlier
10
+ * would set a different value with no error — the worst kind of failure this protocol can
11
+ * produce, since nothing in the transcript looks wrong. A write can change another
12
+ * field's options, so writes drop what they invalidate — see `retainFresh`.
13
+ */
14
+ /** @typedef {{value: unknown, title: string, key?: string}} SuggestionItem */
15
+ /**
16
+ * Per WebMCP instance memory of the suggestions, keyed by node path.
17
+ */
18
+ export class SuggestionsStore {
19
+ /**
20
+ * @private
21
+ * @type {Map<string, SuggestionItem[]>}
22
+ */
23
+ private _byPath;
24
+ /**
25
+ * What the node's items depended on when each path was memorized, so a write can tell
26
+ * whether it invalidated them. See `retainFresh`.
27
+ * @private
28
+ * @type {Map<string, unknown>}
29
+ */
30
+ private _cacheKeys;
31
+ /**
32
+ * Paths that HAD memorized suggestions until a write dropped them. Kept so that the
33
+ * failure can say which of the two things happened: an agent told to "call
34
+ * getFieldSuggestions first" when it did exactly that, one call ago, cannot tell that
35
+ * the list went stale, and the eval shows it stops trusting suggestionIndex entirely.
36
+ * @private
37
+ * @type {Set<string>}
38
+ */
39
+ private _invalidated;
40
+ /**
41
+ * Memorize a search's items and return the index its first item was given. Indices are
42
+ * absolute per path, so an index handed out earlier keeps meaning what the agent saw.
43
+ * @param {string} path
44
+ * @param {SuggestionItem[]} items
45
+ * @param {unknown} [cacheKey] - the node's itemsCacheKey, what its options depend on
46
+ * @returns {number} the index of the first of these items
47
+ */
48
+ add(path: string, items: SuggestionItem[], cacheKey?: unknown): number;
49
+ /**
50
+ * Drop only the paths a write actually invalidated.
51
+ *
52
+ * Clearing everything on every write was correct but far broader than the hazard it
53
+ * guarded: writing one field cannot change the options of a field whose list does not
54
+ * depend on it, and the eval caught the cost twice on the same case — once recovered in
55
+ * one call, once in three. `isFresh` is given the key recorded at `add` time so the
56
+ * caller can compare it with the node's current `itemsCacheKey`, which is what the state
57
+ * layer itself uses to decide whether to re-fetch: a resolved URL for a remote picker, so
58
+ * the comparison is exact where it matters, and a value that simply differs for an
59
+ * expression-based list, which over-invalidates in the safe direction.
60
+ * @param {(path: string, cacheKey: unknown) => boolean} isFresh
61
+ */
62
+ retainFresh(isFresh: (path: string, cacheKey: unknown) => boolean): void;
63
+ /**
64
+ * @param {string} path
65
+ * @returns {SuggestionItem[]|undefined}
66
+ */
67
+ get(path: string): SuggestionItem[] | undefined;
68
+ /**
69
+ * Get the full original value memorized for a path at a given index.
70
+ * @param {string} path
71
+ * @param {number} index
72
+ * @returns {unknown}
73
+ */
74
+ getValue(path: string, index: number): unknown;
75
+ clear(): void;
76
+ }
77
+ export type SuggestionItem = {
78
+ value: unknown;
79
+ title: string;
80
+ key?: string;
81
+ };
82
+ //# sourceMappingURL=suggestions-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggestions-store.d.ts","sourceRoot":"","sources":["../../src/webmcp/suggestions-store.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,8EAA8E;AAE9E;;GAEG;AACH;IACE;;;OAGG;IACH,gBAAmB;IAEnB;;;;;OAKG;IACH,mBAAsB;IAEtB;;;;;;;OAOG;IACH,qBAAwB;IAExB;;;;;;;OAOG;IACH,UALW,MAAM,SACN,cAAc,EAAE,aAChB,OAAO,GACL,MAAM,CAalB;IAED;;;;;;;;;;;;OAYG;IACH,qBAFW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,QAStD;IAED;;;OAGG;IACH,UAHW,MAAM,GACJ,cAAc,EAAE,GAAC,SAAS,CAItC;IAED;;;;;OAKG;IACH,eAJW,MAAM,SACN,MAAM,GACJ,OAAO,CAcnB;IAED,cAIC;CACF;6BA1Ga;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAC"}