@wootsup/mcp 0.1.0-rc.9 → 0.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.
Files changed (171) hide show
  1. package/README.md +7 -7
  2. package/dist/index.d.ts +19 -0
  3. package/dist/index.js +71 -5
  4. package/dist/index.js.map +1 -1
  5. package/dist/modules/apimapper/cache.d.ts +2 -2
  6. package/dist/modules/apimapper/cache.js +107 -25
  7. package/dist/modules/apimapper/cache.js.map +1 -1
  8. package/dist/modules/apimapper/client.d.ts +40 -0
  9. package/dist/modules/apimapper/client.js +82 -12
  10. package/dist/modules/apimapper/client.js.map +1 -1
  11. package/dist/modules/apimapper/connections-format.d.ts +51 -0
  12. package/dist/modules/apimapper/connections-format.js +261 -0
  13. package/dist/modules/apimapper/connections-format.js.map +1 -0
  14. package/dist/modules/apimapper/connections-trim.d.ts +82 -0
  15. package/dist/modules/apimapper/connections-trim.js +224 -0
  16. package/dist/modules/apimapper/connections-trim.js.map +1 -0
  17. package/dist/modules/apimapper/connections.d.ts +14 -2
  18. package/dist/modules/apimapper/connections.js +447 -143
  19. package/dist/modules/apimapper/connections.js.map +1 -1
  20. package/dist/modules/apimapper/credentials-format.d.ts +21 -0
  21. package/dist/modules/apimapper/credentials-format.js +145 -0
  22. package/dist/modules/apimapper/credentials-format.js.map +1 -0
  23. package/dist/modules/apimapper/credentials.d.ts +12 -2
  24. package/dist/modules/apimapper/credentials.js +253 -72
  25. package/dist/modules/apimapper/credentials.js.map +1 -1
  26. package/dist/modules/apimapper/diagnose.d.ts +54 -2
  27. package/dist/modules/apimapper/diagnose.js +193 -11
  28. package/dist/modules/apimapper/diagnose.js.map +1 -1
  29. package/dist/modules/apimapper/elicitation.d.ts +54 -0
  30. package/dist/modules/apimapper/elicitation.js +90 -0
  31. package/dist/modules/apimapper/elicitation.js.map +1 -0
  32. package/dist/modules/apimapper/flows-format.d.ts +50 -0
  33. package/dist/modules/apimapper/flows-format.js +318 -0
  34. package/dist/modules/apimapper/flows-format.js.map +1 -0
  35. package/dist/modules/apimapper/flows.d.ts +13 -2
  36. package/dist/modules/apimapper/flows.js +325 -118
  37. package/dist/modules/apimapper/flows.js.map +1 -1
  38. package/dist/modules/apimapper/gateway/advanced-tool.d.ts +9 -0
  39. package/dist/modules/apimapper/gateway/advanced-tool.js +214 -0
  40. package/dist/modules/apimapper/gateway/advanced-tool.js.map +1 -0
  41. package/dist/modules/apimapper/gateway/capturing-server.d.ts +81 -0
  42. package/dist/modules/apimapper/gateway/capturing-server.js +87 -0
  43. package/dist/modules/apimapper/gateway/capturing-server.js.map +1 -0
  44. package/dist/modules/apimapper/gateway/essentials.d.ts +4 -0
  45. package/dist/modules/apimapper/gateway/essentials.js +28 -0
  46. package/dist/modules/apimapper/gateway/essentials.js.map +1 -0
  47. package/dist/modules/apimapper/gateway/test-support.d.ts +17 -0
  48. package/dist/modules/apimapper/gateway/test-support.js +43 -0
  49. package/dist/modules/apimapper/gateway/test-support.js.map +1 -0
  50. package/dist/modules/apimapper/get-skill.d.ts +3 -3
  51. package/dist/modules/apimapper/get-skill.js +4 -2
  52. package/dist/modules/apimapper/get-skill.js.map +1 -1
  53. package/dist/modules/apimapper/graph-builder.js +1 -1
  54. package/dist/modules/apimapper/graph-builder.js.map +1 -1
  55. package/dist/modules/apimapper/graph.d.ts +2 -2
  56. package/dist/modules/apimapper/graph.js +165 -34
  57. package/dist/modules/apimapper/graph.js.map +1 -1
  58. package/dist/modules/apimapper/index.d.ts +17 -1
  59. package/dist/modules/apimapper/index.js +66 -17
  60. package/dist/modules/apimapper/index.js.map +1 -1
  61. package/dist/modules/apimapper/inspect.d.ts +3 -2
  62. package/dist/modules/apimapper/inspect.js +97 -13
  63. package/dist/modules/apimapper/inspect.js.map +1 -1
  64. package/dist/modules/apimapper/library.d.ts +2 -2
  65. package/dist/modules/apimapper/library.js +303 -60
  66. package/dist/modules/apimapper/library.js.map +1 -1
  67. package/dist/modules/apimapper/license-format.d.ts +22 -0
  68. package/dist/modules/apimapper/license-format.js +149 -0
  69. package/dist/modules/apimapper/license-format.js.map +1 -0
  70. package/dist/modules/apimapper/license.d.ts +16 -2
  71. package/dist/modules/apimapper/license.js +85 -37
  72. package/dist/modules/apimapper/license.js.map +1 -1
  73. package/dist/modules/apimapper/local-sources.d.ts +2 -2
  74. package/dist/modules/apimapper/local-sources.js +58 -30
  75. package/dist/modules/apimapper/local-sources.js.map +1 -1
  76. package/dist/modules/apimapper/misc.d.ts +30 -2
  77. package/dist/modules/apimapper/misc.js +129 -50
  78. package/dist/modules/apimapper/misc.js.map +1 -1
  79. package/dist/modules/apimapper/node-schema.d.ts +52 -0
  80. package/dist/modules/apimapper/node-schema.js +70 -2
  81. package/dist/modules/apimapper/node-schema.js.map +1 -1
  82. package/dist/modules/apimapper/normalizers.d.ts +1 -0
  83. package/dist/modules/apimapper/normalizers.js +51 -0
  84. package/dist/modules/apimapper/normalizers.js.map +1 -1
  85. package/dist/modules/apimapper/onboarding.d.ts +48 -2
  86. package/dist/modules/apimapper/onboarding.js +324 -17
  87. package/dist/modules/apimapper/onboarding.js.map +1 -1
  88. package/dist/modules/apimapper/read-cache.d.ts +31 -2
  89. package/dist/modules/apimapper/read-cache.js +20 -6
  90. package/dist/modules/apimapper/read-cache.js.map +1 -1
  91. package/dist/modules/apimapper/render/_shared.d.ts +24 -0
  92. package/dist/modules/apimapper/render/_shared.js +84 -0
  93. package/dist/modules/apimapper/render/_shared.js.map +1 -0
  94. package/dist/modules/apimapper/render/dag.d.ts +18 -0
  95. package/dist/modules/apimapper/render/dag.js +70 -0
  96. package/dist/modules/apimapper/render/dag.js.map +1 -0
  97. package/dist/modules/apimapper/render/index.d.ts +2 -0
  98. package/dist/modules/apimapper/render/index.js +112 -0
  99. package/dist/modules/apimapper/render/index.js.map +1 -0
  100. package/dist/modules/apimapper/render/renderers/chart-bar.d.ts +2 -0
  101. package/dist/modules/apimapper/render/renderers/chart-bar.js +70 -0
  102. package/dist/modules/apimapper/render/renderers/chart-bar.js.map +1 -0
  103. package/dist/modules/apimapper/render/renderers/chart-line.d.ts +2 -0
  104. package/dist/modules/apimapper/render/renderers/chart-line.js +71 -0
  105. package/dist/modules/apimapper/render/renderers/chart-line.js.map +1 -0
  106. package/dist/modules/apimapper/render/renderers/diff.d.ts +2 -0
  107. package/dist/modules/apimapper/render/renderers/diff.js +154 -0
  108. package/dist/modules/apimapper/render/renderers/diff.js.map +1 -0
  109. package/dist/modules/apimapper/render/renderers/flow-diagram.d.ts +1 -0
  110. package/dist/modules/apimapper/render/renderers/flow-diagram.js +180 -0
  111. package/dist/modules/apimapper/render/renderers/flow-diagram.js.map +1 -0
  112. package/dist/modules/apimapper/render/renderers/json-tree.d.ts +2 -0
  113. package/dist/modules/apimapper/render/renderers/json-tree.js +87 -0
  114. package/dist/modules/apimapper/render/renderers/json-tree.js.map +1 -0
  115. package/dist/modules/apimapper/render/renderers/schema-diagram.d.ts +2 -0
  116. package/dist/modules/apimapper/render/renderers/schema-diagram.js +83 -0
  117. package/dist/modules/apimapper/render/renderers/schema-diagram.js.map +1 -0
  118. package/dist/modules/apimapper/render/renderers/table.d.ts +2 -0
  119. package/dist/modules/apimapper/render/renderers/table.js +75 -0
  120. package/dist/modules/apimapper/render/renderers/table.js.map +1 -0
  121. package/dist/modules/apimapper/render/schemas.d.ts +23 -0
  122. package/dist/modules/apimapper/render/schemas.js +56 -0
  123. package/dist/modules/apimapper/render/schemas.js.map +1 -0
  124. package/dist/modules/apimapper/render/secret-masking.d.ts +5 -0
  125. package/dist/modules/apimapper/render/secret-masking.js +51 -0
  126. package/dist/modules/apimapper/render/secret-masking.js.map +1 -0
  127. package/dist/modules/apimapper/render/sidecar.d.ts +21 -0
  128. package/dist/modules/apimapper/render/sidecar.js +66 -0
  129. package/dist/modules/apimapper/render/sidecar.js.map +1 -0
  130. package/dist/modules/apimapper/render/token-cap.d.ts +21 -0
  131. package/dist/modules/apimapper/render/token-cap.js +57 -0
  132. package/dist/modules/apimapper/render/token-cap.js.map +1 -0
  133. package/dist/modules/apimapper/schema.d.ts +2 -2
  134. package/dist/modules/apimapper/schema.js +100 -32
  135. package/dist/modules/apimapper/schema.js.map +1 -1
  136. package/dist/modules/apimapper/settings-format.d.ts +23 -0
  137. package/dist/modules/apimapper/settings-format.js +135 -0
  138. package/dist/modules/apimapper/settings-format.js.map +1 -0
  139. package/dist/modules/apimapper/settings.d.ts +2 -2
  140. package/dist/modules/apimapper/settings.js +101 -40
  141. package/dist/modules/apimapper/settings.js.map +1 -1
  142. package/dist/modules/apimapper/skill-resources.d.ts +2 -2
  143. package/dist/modules/apimapper/skill-resources.js.map +1 -1
  144. package/dist/modules/apimapper/token-baseline.harness.d.ts +91 -0
  145. package/dist/modules/apimapper/token-baseline.harness.js +291 -0
  146. package/dist/modules/apimapper/token-baseline.harness.js.map +1 -0
  147. package/dist/modules/apimapper/toolslist-size.d.ts +55 -0
  148. package/dist/modules/apimapper/toolslist-size.js +190 -0
  149. package/dist/modules/apimapper/toolslist-size.js.map +1 -0
  150. package/dist/modules/apimapper/types.d.ts +23 -8
  151. package/dist/modules/apimapper/types.js +26 -1
  152. package/dist/modules/apimapper/types.js.map +1 -1
  153. package/dist/modules/apimapper/use-profile.d.ts +21 -0
  154. package/dist/modules/apimapper/use-profile.js +56 -2
  155. package/dist/modules/apimapper/use-profile.js.map +1 -1
  156. package/dist/modules/apimapper/workflows.d.ts +2 -2
  157. package/dist/modules/apimapper/workflows.js +143 -16
  158. package/dist/modules/apimapper/workflows.js.map +1 -1
  159. package/dist/platform/index.js +44 -5
  160. package/dist/platform/index.js.map +1 -1
  161. package/dist/setup-cli.d.ts +53 -0
  162. package/dist/setup-cli.js +126 -4
  163. package/dist/setup-cli.js.map +1 -1
  164. package/docs/architecture.md +1 -1
  165. package/docs/tools.md +1 -1
  166. package/manifest.json +12 -3
  167. package/package.json +9 -4
  168. package/skills/apimapper/SKILL.md +1 -1
  169. package/skills/apimapper/reference/render.md +132 -0
  170. package/skills/apimapper/reference/troubleshooting.md +1 -1
  171. package/skills/apimapper/reference/yootheme.md +1 -1
@@ -0,0 +1,154 @@
1
+ // renderers/diff.ts — { old, new } → recursive JSON diff renderer.
2
+ //
3
+ // Walks the two payloads in lock-step and classifies every leaf difference:
4
+ // + added — key/index present in `new` but not `old`
5
+ // - removed — key/index present in `old` but not `new`
6
+ // ~ changed — same key, different primitive value or type
7
+ //
8
+ // Paths use dot + bracket notation: object keys join with ".", array indices
9
+ // with "[i]" — e.g. "fields[2].type", "credential.api_key".
10
+ //
11
+ // Secret-masking (design D13): when the LAST path segment is an allowlisted
12
+ // secret field name, the value is shown as "***". Masking is on by default
13
+ // and switched off via `options.mask_secrets === false`.
14
+ import { z } from "zod";
15
+ import { isSecretFieldName } from "../secret-masking.js";
16
+ const DiffSchema = z.object({
17
+ old: z
18
+ .unknown()
19
+ .describe("Baseline dataset — fetch first (e.g. apimapper_schema_profile)."),
20
+ new: z
21
+ .unknown()
22
+ .describe("Changed dataset — fetch separately (e.g. a second apimapper_schema_profile call)."),
23
+ label_old: z.string().max(80).optional(),
24
+ label_new: z.string().max(80).optional(),
25
+ }, {
26
+ // Surfaces when `data` is not an object at all (missing / wrong type) —
27
+ // points the caller at the required shape and how to obtain each half.
28
+ error: "diff requires { old, new } — fetch both datasets first " +
29
+ "(e.g. two apimapper_schema_profile calls).",
30
+ });
31
+ /** True for a plain object (not null, not an array). */
32
+ function isPlainObject(v) {
33
+ return v !== null && typeof v === "object" && !Array.isArray(v);
34
+ }
35
+ /** Render a value for diff output, or "***" when the field is masked. */
36
+ function formatValue(v, masked) {
37
+ if (masked)
38
+ return "***";
39
+ if (v === null)
40
+ return "null";
41
+ if (v === undefined)
42
+ return "undefined";
43
+ if (typeof v === "string")
44
+ return JSON.stringify(v);
45
+ if (typeof v === "object")
46
+ return JSON.stringify(v);
47
+ return String(v);
48
+ }
49
+ /** Last path segment — used for the secret-masking field-name lookup. */
50
+ function lastSegment(path) {
51
+ return path.split(/[.[\]]/).filter(Boolean).pop() ?? "";
52
+ }
53
+ /**
54
+ * Hard recursion cap for `walk()`. MCP `data` is JSON-deserialized, hence
55
+ * acyclic — real diffs are <10 deep, so 100 is never hit by legitimate
56
+ * input. This is defense-in-depth against pathological / malicious deep
57
+ * nesting causing a stack overflow, NOT an expected path.
58
+ */
59
+ const MAX_DIFF_DEPTH = 100;
60
+ /** Recursively collect every leaf-level difference between two values. */
61
+ function walk(oldV, newV, path, changes, depth) {
62
+ if (oldV === newV)
63
+ return;
64
+ // Defense-in-depth: stop before the call stack can overflow on
65
+ // pathologically deep input. Emits one marker change and bails.
66
+ if (depth > MAX_DIFF_DEPTH) {
67
+ changes.push({ kind: "~", path, note: "max diff depth exceeded" });
68
+ return;
69
+ }
70
+ if (isPlainObject(oldV) && isPlainObject(newV)) {
71
+ const keys = new Set([...Object.keys(oldV), ...Object.keys(newV)]);
72
+ for (const key of keys) {
73
+ const subPath = path ? `${path}.${key}` : key;
74
+ const ov = oldV[key];
75
+ const nv = newV[key];
76
+ if (ov === undefined && nv !== undefined) {
77
+ changes.push({ kind: "+", path: subPath, newVal: nv });
78
+ }
79
+ else if (nv === undefined && ov !== undefined) {
80
+ changes.push({ kind: "-", path: subPath, oldVal: ov });
81
+ }
82
+ else if (JSON.stringify(ov) !== JSON.stringify(nv)) {
83
+ walk(ov, nv, subPath, changes, depth + 1);
84
+ }
85
+ }
86
+ return;
87
+ }
88
+ if (Array.isArray(oldV) && Array.isArray(newV)) {
89
+ const maxLen = Math.max(oldV.length, newV.length);
90
+ for (let i = 0; i < maxLen; i++) {
91
+ const subPath = `${path}[${i}]`;
92
+ const ov = oldV[i];
93
+ const nv = newV[i];
94
+ if (ov === undefined && nv !== undefined) {
95
+ changes.push({ kind: "+", path: subPath, newVal: nv });
96
+ }
97
+ else if (nv === undefined && ov !== undefined) {
98
+ // Symmetric with the object branch above: only emit a removal when
99
+ // the OLD slot actually held a value. Guards against a spurious "-"
100
+ // when both array slots are undefined (e.g. a sparse-array hole).
101
+ changes.push({ kind: "-", path: subPath, oldVal: ov });
102
+ }
103
+ else if (JSON.stringify(ov) !== JSON.stringify(nv)) {
104
+ walk(ov, nv, subPath, changes, depth + 1);
105
+ }
106
+ }
107
+ return;
108
+ }
109
+ // Primitive change or a structural type mismatch (object vs array vs scalar).
110
+ changes.push({ kind: "~", path, oldVal: oldV, newVal: newV });
111
+ }
112
+ const RULE_WIDTH = 60;
113
+ export function renderDiff(input, options) {
114
+ const { old: oldV, new: newV, label_old, label_new } = DiffSchema.parse(input);
115
+ const changes = [];
116
+ walk(oldV, newV, "", changes, 0);
117
+ // Masking is on unless explicitly disabled.
118
+ const maskEnabled = options.mask_secrets !== false;
119
+ const lines = [];
120
+ if (options.title)
121
+ lines.push(options.title);
122
+ lines.push(`Diff: ${label_old ?? "old"} → ${label_new ?? "new"}`);
123
+ lines.push("─".repeat(RULE_WIDTH));
124
+ if (changes.length === 0) {
125
+ lines.push("(no changes)");
126
+ }
127
+ else {
128
+ for (const change of changes) {
129
+ const masked = maskEnabled && isSecretFieldName(lastSegment(change.path));
130
+ if (change.note) {
131
+ // Structural marker (e.g. depth cap) — no old/new values to show.
132
+ lines.push(` ~ ${change.path} (${change.note})`);
133
+ }
134
+ else if (change.kind === "+") {
135
+ lines.push(` + ${change.path} ${formatValue(change.newVal, masked)}`);
136
+ }
137
+ else if (change.kind === "-") {
138
+ lines.push(` - ${change.path} ${formatValue(change.oldVal, masked)}`);
139
+ }
140
+ else {
141
+ lines.push(` ~ ${change.path} ${formatValue(change.oldVal, masked)} → ` +
142
+ formatValue(change.newVal, masked));
143
+ }
144
+ }
145
+ }
146
+ lines.push("─".repeat(RULE_WIDTH));
147
+ const added = changes.filter((c) => c.kind === "+").length;
148
+ const removed = changes.filter((c) => c.kind === "-").length;
149
+ const modified = changes.filter((c) => c.kind === "~").length;
150
+ lines.push(`${changes.length} changes • ${added} added • ${removed} removed • ` +
151
+ `${modified} modified`);
152
+ return lines.join("\n");
153
+ }
154
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../../../src/modules/apimapper/render/renderers/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function renderFlowDiagram(input: unknown): string;
@@ -0,0 +1,180 @@
1
+ // renderers/flow-diagram.ts — ASCII flow-diagram renderer.
2
+ //
3
+ // Input: a flow object with `nodes` and `edges`. Each node has an id and a
4
+ // type; the renderer derives layers via topological sort and joins them
5
+ // horizontally with arrow connectors. Multi-line node-boxes encode
6
+ // `{display-name, type}`.
7
+ //
8
+ // Layout overview:
9
+ //
10
+ // ┌──────────┐ ┌──────────┐ ┌──────────┐
11
+ // │ src_pex │ ─► │ merge_1 │ ─► │ filter_1 │
12
+ // │ source │ │ merge │ │ filter │
13
+ // └──────────┘ └──────────┘ └──────────┘
14
+ // ┌──────────┐
15
+ // │ src_ig │
16
+ // │ source │
17
+ // └──────────┘
18
+ //
19
+ // 5 nodes • 4 edges
20
+ //
21
+ // Edge-cases handled:
22
+ // - Cycle: unreachable nodes appended as a trailing layer with a footer
23
+ // warning "⚠ cycle detected".
24
+ // - 50-node soft cap: slice nodes, filter edges to the kept set,
25
+ // footer "showing first 50 of N".
26
+ // - Disconnected sub-graphs: layers contain nodes from multiple chains,
27
+ // boxes stack vertically within a layer.
28
+ // - Empty nodes array: Zod rejects (caller sees a clear validation error).
29
+ import { z } from "zod";
30
+ import { box, padRight, truncate, graphemeLength } from "../_shared.js";
31
+ import { topoLayers } from "../dag.js";
32
+ const FlowVizSchema = z
33
+ .object({
34
+ id: z.string().optional(),
35
+ name: z.string().optional(),
36
+ nodes: z
37
+ .array(z
38
+ .object({
39
+ id: z.string(),
40
+ type: z.string(),
41
+ data: z.record(z.string(), z.unknown()).optional(),
42
+ })
43
+ .passthrough())
44
+ .min(1, "flow must have at least one node"),
45
+ edges: z.array(z
46
+ .object({
47
+ source: z.string(),
48
+ target: z.string(),
49
+ })
50
+ .passthrough()),
51
+ })
52
+ .passthrough();
53
+ const MAX_NODES = 50;
54
+ // Box width math: inside = BOX_WIDTH - 2 (borders). Content takes inside - 2
55
+ // (leading space + at-least-one-trailing-pad). At BOX_WIDTH=14 content fits
56
+ // up to 10 graphemes — generous enough for typical node ids and the type
57
+ // label without sacrificing horizontal real-estate at 4 layers.
58
+ const BOX_WIDTH = 14;
59
+ // COL_SPACING must be >= 4 to fit the " ─► " arrow with leading/trailing
60
+ // breathing space.
61
+ const COL_SPACING = 4;
62
+ function nodeLabel(node) {
63
+ // Prefer `data.name` for outputs (YOOtheme source name) — falls back to the
64
+ // node id, which is always present and stable.
65
+ const dataObj = node.data && typeof node.data === "object" ? node.data : undefined;
66
+ const dataName = dataObj && typeof dataObj.name === "string" ? dataObj.name : undefined;
67
+ const primary = dataName ?? node.id;
68
+ const secondary = node.type;
69
+ // box() truncates internally too, but we pre-truncate here so the snapshot
70
+ // shows the exact label the renderer chose (and so the line2 type-label
71
+ // never out-competes line1 for width).
72
+ const contentMax = Math.max(0, BOX_WIDTH - 4);
73
+ return {
74
+ line1: truncate(primary, contentMax),
75
+ line2: truncate(secondary, contentMax),
76
+ };
77
+ }
78
+ function renderNodeBox(node) {
79
+ const { line1, line2 } = nodeLabel(node);
80
+ return box([line1, line2], BOX_WIDTH).split("\n");
81
+ }
82
+ function renderLayerBlock(nodes) {
83
+ // Stack node-boxes vertically with one blank gap line between them.
84
+ // topoLayers only ever pushes non-empty layers (it advances the frontier
85
+ // while `frontier.length > 0`) and the unreachable layer is appended only
86
+ // when it has members — so an empty `nodes` array never reaches here.
87
+ /* v8 ignore next -- topoLayers never emits an empty layer; defensive guard */
88
+ if (nodes.length === 0)
89
+ return [];
90
+ const result = [];
91
+ nodes.forEach((node, i) => {
92
+ if (i > 0)
93
+ result.push(padRight("", BOX_WIDTH));
94
+ result.push(...renderNodeBox(node));
95
+ });
96
+ return result;
97
+ }
98
+ function padBlockHeight(block, height) {
99
+ if (block.length >= height)
100
+ return block;
101
+ const pad = padRight("", BOX_WIDTH);
102
+ const out = [...block];
103
+ while (out.length < height)
104
+ out.push(pad);
105
+ return out;
106
+ }
107
+ function joinLayersHorizontally(blocks) {
108
+ // Every valid flow has >=1 node, hence >=1 topo layer, hence >=1 block —
109
+ // an empty `blocks` array never reaches here.
110
+ /* v8 ignore next -- callers always pass >=1 layer block; defensive guard */
111
+ if (blocks.length === 0)
112
+ return [];
113
+ const maxHeight = Math.max(...blocks.map((b) => b.length));
114
+ const padded = blocks.map((b) => padBlockHeight(b, maxHeight));
115
+ // Arrow appears in the geometric middle row of the tallest block, which
116
+ // visually aligns with the centre of single-node columns.
117
+ const arrowRow = Math.floor(maxHeight / 2);
118
+ const arrowGap = " ─► ";
119
+ const blankGap = padRight("", COL_SPACING);
120
+ // Defensive: confirm gap widths match COL_SPACING contract. `arrowGap`
121
+ // is the literal " ─► " whose grapheme length is exactly COL_SPACING (4),
122
+ // so `graphemeLength(arrowGap) === COL_SPACING` is statically always true
123
+ // and the padRight arm is a guard against a future literal edit only.
124
+ /* v8 ignore next 4 -- arrowGap literal is exactly COL_SPACING graphemes; false arm dead */
125
+ const arrowGapPadded = graphemeLength(arrowGap) === COL_SPACING
126
+ ? arrowGap
127
+ : padRight(arrowGap, COL_SPACING);
128
+ const lines = [];
129
+ for (let row = 0; row < maxHeight; row++) {
130
+ const parts = [];
131
+ padded.forEach((block, i) => {
132
+ parts.push(block[row]);
133
+ if (i < padded.length - 1) {
134
+ parts.push(row === arrowRow ? arrowGapPadded : blankGap);
135
+ }
136
+ });
137
+ lines.push(parts.join(""));
138
+ }
139
+ return lines;
140
+ }
141
+ export function renderFlowDiagram(input) {
142
+ const flow = FlowVizSchema.parse(input);
143
+ const totalNodes = flow.nodes.length;
144
+ const totalEdges = flow.edges.length;
145
+ // 50-node soft cap. Keep order stable (first N nodes), then filter edges to
146
+ // those whose source AND target survive the cap so topo doesn't see dangling
147
+ // refs.
148
+ let workingNodes = flow.nodes;
149
+ let truncated = false;
150
+ if (workingNodes.length > MAX_NODES) {
151
+ workingNodes = workingNodes.slice(0, MAX_NODES);
152
+ truncated = true;
153
+ }
154
+ const allowedIds = new Set(workingNodes.map((n) => n.id));
155
+ const workingEdges = flow.edges.filter((e) => allowedIds.has(e.source) && allowedIds.has(e.target));
156
+ const topo = topoLayers(workingNodes, workingEdges);
157
+ const idToNode = new Map(workingNodes.map((n) => [n.id, n]));
158
+ const layers = topo.layers.map((idList) => idList
159
+ .map((id) => idToNode.get(id))
160
+ .filter((n) => n !== undefined));
161
+ // Append unreachable nodes as a trailing layer so cycle members still
162
+ // render — annotated by the footer warning.
163
+ if (topo.unreachable.length > 0) {
164
+ layers.push(topo.unreachable
165
+ .map((id) => idToNode.get(id))
166
+ .filter((n) => n !== undefined));
167
+ }
168
+ const layerBlocks = layers.map(renderLayerBlock);
169
+ const lines = joinLayersHorizontally(layerBlocks);
170
+ // Footer: "N nodes • M edges [• ⚠ cycle detected] [• showing first 50 of K]"
171
+ const footerParts = [`${totalNodes} nodes • ${totalEdges} edges`];
172
+ if (topo.cycle)
173
+ footerParts.push("⚠ cycle detected");
174
+ if (truncated)
175
+ footerParts.push(`showing first ${MAX_NODES} of ${totalNodes}`);
176
+ lines.push("");
177
+ lines.push(footerParts.join(" • "));
178
+ return lines.join("\n");
179
+ }
180
+ //# sourceMappingURL=flow-diagram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-diagram.js","sourceRoot":"","sources":["../../../../../src/modules/apimapper/render/renderers/flow-diagram.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { RenderOptions } from "../schemas.js";
2
+ export declare function renderJsonTree(input: unknown, options: RenderOptions): string;
@@ -0,0 +1,87 @@
1
+ import { truncate } from "../_shared.js";
2
+ const DEFAULT_MAX_DEPTH = 3;
3
+ const MAX_ARRAY_ITEMS = 5;
4
+ const MAX_OBJECT_KEYS = 8;
5
+ const STRING_MAX_GRAPHEMES = 60;
6
+ const BRANCH_LAST = "└─ ";
7
+ const BRANCH_MID = "├─ ";
8
+ const PREFIX_LAST = " "; // 3 spaces — no continuation bar
9
+ const PREFIX_MID = "│ "; // bar + 2 spaces — continuation under a non-last node
10
+ /** Render a primitive (non-container) value as a compact display string. */
11
+ function formatPrimitive(value) {
12
+ if (value === null)
13
+ return "null";
14
+ if (value === undefined)
15
+ return "undefined";
16
+ if (typeof value === "string") {
17
+ return JSON.stringify(truncate(value, STRING_MAX_GRAPHEMES));
18
+ }
19
+ if (typeof value === "number" || typeof value === "boolean") {
20
+ return String(value);
21
+ }
22
+ // Functions / symbols are not valid JSON but stay defensive.
23
+ return String(value);
24
+ }
25
+ function isContainer(value) {
26
+ return value !== null && typeof value === "object";
27
+ }
28
+ export function renderJsonTree(input, options) {
29
+ const maxDepth = options.depth ?? DEFAULT_MAX_DEPTH;
30
+ const lines = [];
31
+ /**
32
+ * Emit the subtree for `value`.
33
+ *
34
+ * @param value the JSON value at this node
35
+ * @param prefix accumulated indentation (bars + spaces) for THIS line
36
+ * @param isLast whether this node is the last among its siblings
37
+ * @param label key / index label, or null for the synthetic root
38
+ * @param depth 0-based depth (root children are depth 1)
39
+ */
40
+ function walk(value, prefix, isLast, label, depth) {
41
+ const branch = label === null ? "" : isLast ? BRANCH_LAST : BRANCH_MID;
42
+ const labelPart = label === null ? "" : `${label}: `;
43
+ const childPrefix = label === null ? prefix : prefix + (isLast ? PREFIX_LAST : PREFIX_MID);
44
+ if (!isContainer(value)) {
45
+ lines.push(prefix + branch + labelPart + formatPrimitive(value));
46
+ return;
47
+ }
48
+ if (Array.isArray(value)) {
49
+ if (depth >= maxDepth) {
50
+ lines.push(`${prefix}${branch}${labelPart}[ ${value.length} items, depth-limited ]`);
51
+ return;
52
+ }
53
+ lines.push(`${prefix}${branch}${labelPart}[${value.length} items]`);
54
+ const shown = value.slice(0, MAX_ARRAY_ITEMS);
55
+ const overflow = value.length - shown.length;
56
+ shown.forEach((item, i) => {
57
+ const childIsLast = i === shown.length - 1 && overflow === 0;
58
+ walk(item, childPrefix, childIsLast, `[${i}]`, depth + 1);
59
+ });
60
+ if (overflow > 0) {
61
+ lines.push(`${childPrefix}${BRANCH_LAST}… ${overflow} more items`);
62
+ }
63
+ return;
64
+ }
65
+ // Plain object.
66
+ const obj = value;
67
+ const keys = Object.keys(obj);
68
+ if (depth >= maxDepth) {
69
+ lines.push(`${prefix}${branch}${labelPart}{ ${keys.length} fields, depth-limited }`);
70
+ return;
71
+ }
72
+ lines.push(`${prefix}${branch}${labelPart}{${keys.length} fields}`);
73
+ const shownKeys = keys.slice(0, MAX_OBJECT_KEYS);
74
+ const overflow = keys.length - shownKeys.length;
75
+ shownKeys.forEach((key, i) => {
76
+ const childIsLast = i === shownKeys.length - 1 && overflow === 0;
77
+ walk(obj[key], childPrefix, childIsLast, key, depth + 1);
78
+ });
79
+ if (overflow > 0) {
80
+ lines.push(`${childPrefix}${BRANCH_LAST}… ${overflow} more keys`);
81
+ }
82
+ }
83
+ // The root node carries no label/branch — its children start at depth 1.
84
+ walk(input, "", true, null, 0);
85
+ return lines.join("\n");
86
+ }
87
+ //# sourceMappingURL=json-tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-tree.js","sourceRoot":"","sources":["../../../../../src/modules/apimapper/render/renderers/json-tree.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { RenderOptions } from "../schemas.js";
2
+ export declare function renderSchemaDiagram(input: unknown, options: RenderOptions): string;
@@ -0,0 +1,83 @@
1
+ // renderers/schema-diagram.ts — schema-profile → text field-table renderer.
2
+ //
3
+ // Input is the shape returned by `apimapper_schema_profile`: a `fields[]`
4
+ // array where each field carries a `name`, a `type` and optional `samples`.
5
+ // The renderer projects this into a 3-column Field / Type / Sample table via
6
+ // the toolkit's `autoFormatTable`.
7
+ //
8
+ // Sample handling: the first sample value is JSON-stringified (so strings are
9
+ // quoted, numbers/booleans render literally) and truncated to 40 graphemes
10
+ // with the shared grapheme-safe `truncate`. Fields with no samples show "—".
11
+ import { z } from "zod";
12
+ import { autoFormatTable } from "@getimo/mcp-toolkit";
13
+ import { truncate } from "../_shared.js";
14
+ const SchemaProfileSchema = z
15
+ .object({
16
+ fields: z
17
+ .array(z
18
+ .object({
19
+ name: z.string(),
20
+ type: z.string(),
21
+ samples: z.array(z.unknown()).optional(),
22
+ })
23
+ .passthrough())
24
+ .min(1, "schema profile must have at least one field")
25
+ // Input cap for consistency with every other renderer (table 500,
26
+ // chart 20/64, flow 50) and as defense against a pathological
27
+ // 100k-field profile blowing up the field table.
28
+ .max(500, "schema profile is capped at 500 fields"),
29
+ item_count: z.number().optional(),
30
+ source_count: z.number().optional(),
31
+ })
32
+ .passthrough();
33
+ const SAMPLE_MAX_GRAPHEMES = 40;
34
+ const NO_SAMPLE_PLACEHOLDER = "—";
35
+ /**
36
+ * Width handed to autoFormatTable for the Sample column. Kept >=
37
+ * SAMPLE_MAX_GRAPHEMES so the toolkit's own column clip (which appends a
38
+ * bare ".") never re-truncates a cell the renderer already truncated with
39
+ * "…" — the renderer's grapheme-safe ellipsis always wins.
40
+ */
41
+ const SAMPLE_COLUMN_WIDTH = SAMPLE_MAX_GRAPHEMES + 2;
42
+ /** Render the first sample as a single truncated cell, or the placeholder. */
43
+ function sampleCell(samples) {
44
+ if (!samples || samples.length === 0 || samples[0] === undefined) {
45
+ return NO_SAMPLE_PLACEHOLDER;
46
+ }
47
+ const first = samples[0];
48
+ // `first` is never undefined here (guarded above) and `samples` is
49
+ // JSON-deserialized MCP data, so it can never hold a function or symbol.
50
+ // JSON.stringify therefore always returns a string for non-string values.
51
+ const raw = typeof first === "string" ? first : JSON.stringify(first);
52
+ return truncate(raw, SAMPLE_MAX_GRAPHEMES);
53
+ }
54
+ export function renderSchemaDiagram(input, options) {
55
+ const schema = SchemaProfileSchema.parse(input);
56
+ const rows = schema.fields.map((field) => ({
57
+ Field: field.name,
58
+ Type: field.type,
59
+ Sample: sampleCell(field.samples),
60
+ }));
61
+ const result = autoFormatTable(rows, {
62
+ columns: [
63
+ { key: "Field", label: "Field" },
64
+ { key: "Type", label: "Type" },
65
+ // Explicit width >= the renderer's truncation length so the toolkit
66
+ // never re-clips an already-truncated sample with a bare ".".
67
+ { key: "Sample", label: "Sample", width: SAMPLE_COLUMN_WIDTH },
68
+ ],
69
+ header: () => options.title ??
70
+ `${schema.fields.length} fields • profile from ${schema.item_count ?? "?"} sampled items`,
71
+ });
72
+ // autoFormatTable returns a CallToolResult — extract the text payload.
73
+ const first = result.content[0];
74
+ // The JSON.stringify arm is an unreachable defensive fallback — the
75
+ // toolkit always returns a text content block, so only the `first.text`
76
+ // arm ever executes. Kept so a future toolkit change can never make this
77
+ // renderer return `undefined`.
78
+ /* v8 ignore next 3 -- autoFormatTable always returns a text block; false arm dead */
79
+ return first && first.type === "text" && typeof first.text === "string"
80
+ ? first.text
81
+ : JSON.stringify(rows);
82
+ }
83
+ //# sourceMappingURL=schema-diagram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-diagram.js","sourceRoot":"","sources":["../../../../../src/modules/apimapper/render/renderers/schema-diagram.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { RenderOptions } from "../schemas.js";
2
+ export declare function renderTable(input: unknown, options: RenderOptions): string;
@@ -0,0 +1,75 @@
1
+ // renderers/table.ts — array-of-objects → text table renderer.
2
+ //
3
+ // Thin adapter around the toolkit's `autoFormatTable`, which already handles
4
+ // column sizing, header/footer composition and detail-level auto-scaling.
5
+ // This renderer's job is the two things the toolkit does NOT do:
6
+ // 1. Validate that `data` really is an array of objects (Zod).
7
+ // 2. Auto-detect a sensible column set from the first item when the caller
8
+ // did not pass `options.columns`.
9
+ //
10
+ // Column auto-detection rule: take the first item's top-level keys whose
11
+ // values are primitives (string / number / boolean) or null — nested
12
+ // objects/arrays do not belong in a flat table cell — and keep the first 8.
13
+ // `options.columns` (when non-empty) overrides this entirely.
14
+ import { z } from "zod";
15
+ import { autoFormatTable } from "@getimo/mcp-toolkit";
16
+ const TableSchema = z
17
+ .array(z.record(z.string(), z.unknown()), {
18
+ // Surfaces when `data` is not an array (missing / wrong type) — points
19
+ // the caller at the expected shape and a concrete tool that produces it.
20
+ error: "table requires an array of objects — e.g. the payload from " +
21
+ "apimapper_connection_data or apimapper_graph_preview.",
22
+ })
23
+ .min(0)
24
+ .max(500);
25
+ const DEFAULT_MAX_ROWS = 50;
26
+ const MAX_AUTO_COLUMNS = 8;
27
+ /** Cell value types that render cleanly in a single flat table column. */
28
+ function isPrimitiveCell(value) {
29
+ return (value === null ||
30
+ typeof value === "string" ||
31
+ typeof value === "number" ||
32
+ typeof value === "boolean");
33
+ }
34
+ /** Pick up to 8 primitive-typed top-level keys from a sample item. */
35
+ function autoDetectColumns(sample) {
36
+ return Object.keys(sample)
37
+ .filter((key) => isPrimitiveCell(sample[key]))
38
+ .slice(0, MAX_AUTO_COLUMNS);
39
+ }
40
+ export function renderTable(input, options) {
41
+ const items = TableSchema.parse(input);
42
+ const maxRows = options.max_rows ?? DEFAULT_MAX_ROWS;
43
+ const sliced = items.slice(0, maxRows);
44
+ // `options.columns` wins when non-empty; otherwise derive from the first
45
+ // surviving row. An empty array yields an empty column list — handled below.
46
+ const columns = options.columns && options.columns.length > 0
47
+ ? options.columns
48
+ : sliced[0]
49
+ ? autoDetectColumns(sliced[0])
50
+ : [];
51
+ if (columns.length === 0) {
52
+ // No rows (or a row with no primitive keys): degrade gracefully rather
53
+ // than handing autoFormatTable an empty column spec.
54
+ return options.title
55
+ ? `${options.title}\n(no rows)`
56
+ : `(no rows — 0 of ${items.length})`;
57
+ }
58
+ const result = autoFormatTable(sliced, {
59
+ columns: columns.map((key) => ({ key, label: key })),
60
+ header: (count) => options.title
61
+ ? `${options.title} (${count} of ${items.length} rows)`
62
+ : `${count} of ${items.length} rows`,
63
+ });
64
+ // autoFormatTable returns a CallToolResult — extract the text payload.
65
+ const first = result.content[0];
66
+ // The JSON.stringify arm is an unreachable defensive fallback — the
67
+ // toolkit always returns a text content block, so only the `first.text`
68
+ // arm ever executes. Kept so a future toolkit change can never make this
69
+ // renderer return `undefined`.
70
+ /* v8 ignore next 3 -- autoFormatTable always returns a text block; false arm dead */
71
+ return first && first.type === "text" && typeof first.text === "string"
72
+ ? first.text
73
+ : JSON.stringify(sliced);
74
+ }
75
+ //# sourceMappingURL=table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.js","sourceRoot":"","sources":["../../../../../src/modules/apimapper/render/renderers/table.ts"],"names":[],"mappings":"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"}