UNPKG

touchdesigner-mcp-server

Version:
125 lines (123 loc) 3.87 kB
/** * Node List Formatter * * Formats TouchDesigner node lists with token-optimized output. * Used by GET_TD_NODES tool. */ import { DEFAULT_PRESENTER_FORMAT, presentStructuredData, } from "./presenter.js"; import { finalizeFormattedText, formatOmissionHint, limitArray, mergeFormatterOptions, } from "./responseFormatter.js"; /** * Format node list based on detail level */ export function formatNodeList(data, options) { const opts = mergeFormatterOptions(options); if (!data?.nodes || data.nodes.length === 0) { return "No nodes found."; } const nodes = data.nodes; const totalCount = nodes.length; const parentPath = data.parentPath ?? "project"; // Apply limit const { items: limitedNodes, truncated } = limitArray(nodes, opts.limit); if (opts.detailLevel === "detailed") { return formatDetailed(nodes, data, opts.responseFormat, parentPath); } let result; if (opts.detailLevel === "minimal") { result = formatMinimal(limitedNodes, parentPath, totalCount, truncated); } else { result = formatSummary(limitedNodes, parentPath, totalCount, truncated); } const hintEnabled = truncated && opts.includeHints; let output = result.text; if (hintEnabled) { output += formatOmissionHint(totalCount, limitedNodes.length, "node"); } const context = result.context; context.truncated = hintEnabled; if (!hintEnabled) { context.omittedCount = 0; } return finalizeFormattedText(output, opts, { context, structured: context, template: "nodeListSummary", }); } /** * Minimal mode: Only node paths */ function formatMinimal(nodes, parentPath, totalCount, truncated) { const paths = nodes.map((n) => n.path || n.name); const text = `Found ${nodes.length} nodes in ${parentPath}: ${paths.join("\n")}`; return { context: buildNodeListContext(nodes, parentPath, totalCount, truncated), text, }; } /** * Summary mode: Essential info with types */ function formatSummary(nodes, parentPath, totalCount, truncated) { const header = `Found ${totalCount} nodes in ${parentPath}: `; const groups = buildGroups(nodes); const sections = groups.map((group) => { const nodeLines = group.nodes.map((n) => ` • ${n.name} [${n.path}]`); return `${group.type}: ${nodeLines.join("\n")}`; }); return { context: { groups, omittedCount: Math.max(totalCount - nodes.length, 0), parentPath, totalCount, truncated, }, text: header + sections.join("\n\n"), }; } /** * Detailed mode: Full information (original behavior) */ function formatDetailed(nodes, data, format, parentPath) { const title = `Nodes in ${parentPath}`; const payloadFormat = format ?? DEFAULT_PRESENTER_FORMAT; return presentStructuredData({ context: { payloadFormat, title, }, detailLevel: "detailed", structured: { ...data, nodes }, template: "detailedPayload", text: title, }, payloadFormat); } function buildNodeListContext(nodes, parentPath, totalCount, truncated) { return { groups: buildGroups(nodes), omittedCount: Math.max(totalCount - nodes.length, 0), parentPath, totalCount, truncated, }; } function buildGroups(nodes) { const byType = new Map(); for (const node of nodes) { const type = node.opType || "unknown"; if (!byType.has(type)) { byType.set(type, []); } byType.get(type)?.push(node); } return Array.from(byType.entries()).map(([type, typeNodes]) => ({ count: typeNodes.length, nodes: typeNodes.map((n) => ({ name: n.name, path: n.path })), type, })); }