@dpantani/tdmcp 0.2.0 → 0.3.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/agent.ts","../../src/knowledge/index.ts","../../src/utils/logger.ts","../../src/utils/paths.ts","../../src/knowledge/normalize.ts","../../src/recipes/loader.ts","../../src/recipes/schema.ts","../../src/tools/layer2/createControlPanel.ts","../../src/td-client/types.ts","../../src/tools/result.ts","../../src/td-client/validators.ts","../../src/td-client/touchDesignerClient.ts","../../src/utils/config.ts","../../src/server/connectionManager.ts","../../src/server/context.ts","../../src/tools/layer3/compareTdNodes.ts","../../src/tools/layer3/createTdNode.ts","../../src/tools/layer3/deleteTdNode.ts","../../src/tools/layer3/execNodeMethod.ts","../../src/tools/layer3/executePythonScript.ts","../../src/tools/layer3/findTdNodes.ts","../../src/tools/layer3/nodeMatch.ts","../../src/tools/layer3/getModuleHelp.ts","../../src/tools/layer3/getTdClassDetails.ts","../../src/tools/layer3/getTdClasses.ts","../../src/tools/layer3/getTdInfo.ts","../../src/tools/layer3/getTdNodeErrors.ts","../../src/tools/layer3/getTdNodeParameters.ts","../../src/tools/layer3/getTdNodes.ts","../../src/tools/layer3/getTdPerformance.ts","../../src/feedback/performanceMonitor.ts","../../src/tools/layer3/getTdTopology.ts","../../src/feedback/networkVerifier.ts","../../src/tools/layer3/snapshotTdGraph.ts","../../src/tools/layer3/summarizeTdErrors.ts","../../src/tools/layer3/updateTdNodeParameters.ts"],"sourcesContent":["import { pathToFileURL } from \"node:url\";\nimport { parseArgs } from \"node:util\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport { buildToolContext } from \"../server/context.js\";\nimport { compareTdNodesImpl, compareTdNodesSchema } from \"../tools/layer3/compareTdNodes.js\";\nimport { createTdNodeImpl, createTdNodeSchema } from \"../tools/layer3/createTdNode.js\";\nimport { deleteTdNodeImpl, deleteTdNodeSchema } from \"../tools/layer3/deleteTdNode.js\";\nimport { execNodeMethodImpl, execNodeMethodSchema } from \"../tools/layer3/execNodeMethod.js\";\nimport {\n executePythonScriptImpl,\n executePythonScriptSchema,\n} from \"../tools/layer3/executePythonScript.js\";\nimport { findTdNodesImpl, findTdNodesSchema } from \"../tools/layer3/findTdNodes.js\";\nimport { getModuleHelpImpl, getModuleHelpSchema } from \"../tools/layer3/getModuleHelp.js\";\nimport {\n getTdClassDetailsImpl,\n getTdClassDetailsSchema,\n} from \"../tools/layer3/getTdClassDetails.js\";\nimport { getTdClassesImpl, getTdClassesSchema } from \"../tools/layer3/getTdClasses.js\";\nimport { getTdInfoImpl } from \"../tools/layer3/getTdInfo.js\";\nimport { getTdNodeErrorsImpl, getTdNodeErrorsSchema } from \"../tools/layer3/getTdNodeErrors.js\";\nimport {\n getTdNodeParametersImpl,\n getTdNodeParametersSchema,\n} from \"../tools/layer3/getTdNodeParameters.js\";\nimport { getTdNodesImpl, getTdNodesSchema } from \"../tools/layer3/getTdNodes.js\";\nimport { getTdPerformanceImpl, getTdPerformanceSchema } from \"../tools/layer3/getTdPerformance.js\";\nimport { getTdTopologyImpl, getTdTopologySchema } from \"../tools/layer3/getTdTopology.js\";\nimport { snapshotTdGraphImpl, snapshotTdGraphSchema } from \"../tools/layer3/snapshotTdGraph.js\";\nimport {\n summarizeTdErrorsImpl,\n summarizeTdErrorsSchema,\n} from \"../tools/layer3/summarizeTdErrors.js\";\nimport {\n updateTdNodeParametersImpl,\n updateTdNodeParametersSchema,\n} from \"../tools/layer3/updateTdNodeParameters.js\";\nimport type { ToolContext } from \"../tools/types.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { silentLogger } from \"../utils/logger.js\";\n\n// biome-ignore lint/suspicious/noExplicitAny: args are validated by each command's zod schema before use.\ntype Runner = (ctx: ToolContext, args: any) => CallToolResult | Promise<CallToolResult>;\n\ninterface Command {\n schema: z.ZodTypeAny;\n run: Runner;\n summary: string;\n mutates: boolean;\n unsafe: boolean;\n}\n\nconst r = (\n schema: z.ZodTypeAny,\n run: Runner,\n summary: string,\n opts: { mutates?: boolean; unsafe?: boolean } = {},\n): Command => ({ schema, run, summary, mutates: !!opts.mutates, unsafe: !!opts.unsafe });\n\n/** Static command tree — each entry maps 1:1 onto an existing MCP tool handler. */\nconst COMMANDS: Record<string, Command> = {\n info: r(z.object({}), (ctx) => getTdInfoImpl(ctx), \"Health check + TD/bridge info.\"),\n \"nodes list\": r(\n getTdNodesSchema,\n getTdNodesImpl,\n \"List a COMP's child nodes (summary by default).\",\n ),\n \"nodes find\": r(findTdNodesSchema, findTdNodesImpl, \"Search nodes by name pattern and/or type.\"),\n \"nodes get\": r(getTdNodeParametersSchema, getTdNodeParametersImpl, \"Read a node's parameters.\"),\n \"nodes errors\": r(getTdNodeErrorsSchema, getTdNodeErrorsImpl, \"Check a node/network for errors.\"),\n \"nodes compare\": r(compareTdNodesSchema, compareTdNodesImpl, \"Diff two nodes' parameters.\"),\n \"nodes snapshot\": r(snapshotTdGraphSchema, snapshotTdGraphImpl, \"Capture a network snapshot.\"),\n \"nodes topology\": r(getTdTopologySchema, getTdTopologyImpl, \"Map nodes + connections.\"),\n \"nodes performance\": r(getTdPerformanceSchema, getTdPerformanceImpl, \"Report cook times.\"),\n \"nodes update\": r(\n updateTdNodeParametersSchema,\n updateTdNodeParametersImpl,\n \"Set node parameters.\",\n { mutates: true },\n ),\n \"nodes create\": r(createTdNodeSchema, createTdNodeImpl, \"Create an operator.\", { mutates: true }),\n \"nodes delete\": r(deleteTdNodeSchema, deleteTdNodeImpl, \"Delete a node.\", { mutates: true }),\n \"errors summarize\": r(\n summarizeTdErrorsSchema,\n summarizeTdErrorsImpl,\n \"Cluster network errors by cause.\",\n ),\n \"classes list\": r(getTdClassesSchema, getTdClassesImpl, \"List TD Python API classes (offline).\"),\n \"classes get\": r(\n getTdClassDetailsSchema,\n getTdClassDetailsImpl,\n \"Get one Python class (offline).\",\n ),\n \"module help\": r(\n getModuleHelpSchema,\n getModuleHelpImpl,\n \"Human-readable help for a class (offline).\",\n ),\n \"exec python\": r(\n executePythonScriptSchema,\n executePythonScriptImpl,\n \"Escape hatch: run arbitrary Python in TD.\",\n { mutates: true, unsafe: true },\n ),\n \"exec node-method\": r(\n execNodeMethodSchema,\n execNodeMethodImpl,\n \"Escape hatch: call a Python method on a node.\",\n { mutates: true, unsafe: true },\n ),\n};\n\nexport interface CliResult {\n stdout: string;\n stderr: string;\n code: number;\n}\n\nfunction textOf(result: CallToolResult): string {\n return result.content\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\\n\");\n}\n\n/** Prefer the structured channel; fall back to a JSON code-fence, then to the raw text. */\nfunction extractData(result: CallToolResult): unknown {\n if (result.structuredContent !== undefined) return result.structuredContent;\n const text = textOf(result);\n const fence = text.match(/```json\\n([\\s\\S]*?)\\n```/);\n if (fence) {\n try {\n return JSON.parse(fence[1] as string);\n } catch {\n // fall through\n }\n }\n return { message: text };\n}\n\nfunction firstArray(data: unknown): unknown[] | null {\n if (Array.isArray(data)) return data;\n if (data && typeof data === \"object\") {\n for (const value of Object.values(data)) if (Array.isArray(value)) return value;\n }\n return null;\n}\n\nfunction resolveCommand(positionals: string[]): { key: string; cmd: Command } | undefined {\n const key2 = positionals.slice(0, 2).join(\" \");\n if (COMMANDS[key2]) return { key: key2, cmd: COMMANDS[key2] };\n const key1 = positionals[0] ?? \"\";\n if (COMMANDS[key1]) return { key: key1, cmd: COMMANDS[key1] };\n return undefined;\n}\n\nfunction usage(): string {\n const lines = [\"tdmcp-agent — drive TouchDesigner from a shell (machine-readable output).\", \"\"];\n lines.push(\"Usage: tdmcp-agent <command> [--params '<json>'] [--json '<json>'] [flags]\", \"\");\n lines.push(\"Flags:\");\n lines.push(\n \" --params <json> Arguments object (validated against the command's input schema).\",\n );\n lines.push(\" --json <json> Merged into --params (e.g. for request bodies).\");\n lines.push(\" --output <fmt> json (default) | ndjson | text.\");\n lines.push(\" --dry-run Validate and print the intended call without executing.\");\n lines.push(\" --allow-unsafe Required for `exec` escape-hatch commands.\");\n lines.push(\" -h, --help Show this help.\", \"\");\n lines.push(\"Commands:\");\n for (const [key, cmd] of Object.entries(COMMANDS)) {\n const tags = [cmd.mutates ? \"mutates\" : \"\", cmd.unsafe ? \"unsafe\" : \"\"]\n .filter(Boolean)\n .join(\",\");\n lines.push(` ${key.padEnd(20)} ${cmd.summary}${tags ? ` [${tags}]` : \"\"}`);\n }\n lines.push(\" schema <command> Print a command's JSON Schema and metadata.\");\n return lines.join(\"\\n\");\n}\n\nexport interface RunCliOptions {\n /** Inject a context (used by tests); production builds one from env config. */\n makeCtx?: () => ToolContext;\n}\n\nfunction parseCliArgs(argv: string[]) {\n return parseArgs({\n args: argv,\n allowPositionals: true,\n options: {\n params: { type: \"string\" },\n json: { type: \"string\" },\n output: { type: \"string\", default: \"json\" },\n \"dry-run\": { type: \"boolean\", default: false },\n \"allow-unsafe\": { type: \"boolean\", default: false },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n });\n}\n\nexport async function runCli(argv: string[], opts: RunCliOptions = {}): Promise<CliResult> {\n let parsed: ReturnType<typeof parseCliArgs>;\n try {\n parsed = parseCliArgs(argv);\n } catch (err) {\n return { stdout: \"\", stderr: `${(err as Error).message}\\n`, code: 2 };\n }\n\n const { values, positionals } = parsed;\n if (values.help || positionals.length === 0) {\n return { stdout: `${usage()}\\n`, stderr: \"\", code: 0 };\n }\n\n // `schema <command>` — emit the input contract without touching TD.\n if (positionals[0] === \"schema\") {\n const target = positionals.slice(1).join(\" \");\n const cmd = COMMANDS[target];\n if (!cmd) return { stdout: \"\", stderr: `Unknown command for schema: \"${target}\".\\n`, code: 2 };\n const doc = {\n command: target,\n summary: cmd.summary,\n mutates: cmd.mutates,\n unsafe: cmd.unsafe,\n input: z.toJSONSchema(cmd.schema),\n };\n return { stdout: `${JSON.stringify(doc, null, 2)}\\n`, stderr: \"\", code: 0 };\n }\n\n const resolved = resolveCommand(positionals);\n if (!resolved) {\n return {\n stdout: \"\",\n stderr: `Unknown command: \"${positionals.join(\" \")}\". Run with --help.\\n`,\n code: 2,\n };\n }\n const { key, cmd } = resolved;\n\n const raw: Record<string, unknown> = {};\n try {\n if (typeof values.params === \"string\") Object.assign(raw, JSON.parse(values.params));\n if (typeof values.json === \"string\") Object.assign(raw, JSON.parse(values.json));\n } catch (err) {\n return {\n stdout: \"\",\n stderr: `Invalid JSON in --params/--json: ${(err as Error).message}\\n`,\n code: 2,\n };\n }\n\n const args = cmd.schema.safeParse(raw);\n if (!args.success) {\n return {\n stdout: \"\",\n stderr: `Invalid arguments for \"${key}\": ${args.error.message}\\n`,\n code: 2,\n };\n }\n\n if (values[\"dry-run\"]) {\n const doc = {\n dryRun: true,\n command: key,\n mutates: cmd.mutates,\n unsafe: cmd.unsafe,\n args: args.data,\n };\n return { stdout: `${JSON.stringify(doc, null, 2)}\\n`, stderr: \"\", code: 0 };\n }\n\n const ctx = opts.makeCtx\n ? opts.makeCtx()\n : buildToolContext(loadConfig(), { logger: silentLogger });\n\n if (cmd.unsafe) {\n if (ctx.allowRawPython === false) {\n return { stdout: \"\", stderr: `\"${key}\" is disabled (TDMCP_RAW_PYTHON=off).\\n`, code: 2 };\n }\n if (!values[\"allow-unsafe\"]) {\n return {\n stdout: \"\",\n stderr: `\"${key}\" is an escape hatch. Re-run with --allow-unsafe to execute.\\n`,\n code: 2,\n };\n }\n }\n\n const result = await cmd.run(ctx, args.data);\n const summary = textOf(result).split(\"\\n\")[0] ?? \"\";\n if (result.isError) return { stdout: \"\", stderr: `${textOf(result)}\\n`, code: 1 };\n\n const output = String(values.output);\n const data = extractData(result);\n if (output === \"text\") return { stdout: `${textOf(result)}\\n`, stderr: \"\", code: 0 };\n if (output === \"ndjson\") {\n const arr = firstArray(data);\n const body = arr ? arr.map((item) => JSON.stringify(item)).join(\"\\n\") : JSON.stringify(data);\n return { stdout: `${body}\\n`, stderr: summary ? `${summary}\\n` : \"\", code: 0 };\n }\n return {\n stdout: `${JSON.stringify(data, null, 2)}\\n`,\n stderr: summary ? `${summary}\\n` : \"\",\n code: 0,\n };\n}\n\nasync function main(): Promise<void> {\n const result = await runCli(process.argv.slice(2));\n if (result.stdout) process.stdout.write(result.stdout);\n if (result.stderr) process.stderr.write(result.stderr);\n process.exitCode = result.code;\n}\n\nconst invokedDirectly =\n process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href;\nif (invokedDirectly) void main();\n","import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type Logger, silentLogger } from \"../utils/logger.js\";\nimport { bottobotPackageDir, knowledgeDataDir } from \"../utils/paths.js\";\nimport {\n compactKey,\n normalizeGlsl,\n normalizePatterns,\n slugify,\n toOperatorSummary,\n toPythonSummary,\n toTutorialSummary,\n} from \"./normalize.js\";\nimport type {\n GlslSummary,\n GlslTechnique,\n KnowledgeStats,\n OperatorDoc,\n OperatorSummary,\n Pattern,\n PatternSummary,\n PythonClass,\n PythonClassSummary,\n Tutorial,\n TutorialSummary,\n} from \"./types.js\";\n\nexport interface KnowledgeBaseOptions {\n dataDir?: string;\n logger?: Logger;\n}\n\ninterface ResolvedSource {\n kind: \"local\" | \"bottobot\" | \"empty\";\n operatorsDir: string;\n operatorsIndex?: string;\n pythonDir: string;\n tutorialsDir: string;\n patternsFile: string;\n glslFile: string;\n}\n\nconst EMPTY_SOURCE: ResolvedSource = {\n kind: \"empty\",\n operatorsDir: \"\",\n pythonDir: \"\",\n tutorialsDir: \"\",\n patternsFile: \"\",\n glslFile: \"\",\n};\n\n/**\n * Read-only accessor over the embedded TouchDesigner knowledge base. Prefers the\n * imported local data directory; falls back to reading directly from an installed\n * `@bottobot/td-mcp`; otherwise degrades to empty results (never throws on lookup).\n */\nexport class KnowledgeBase {\n private readonly logger: Logger;\n private readonly source: ResolvedSource;\n\n private opIndexCache?: OperatorSummary[];\n private opLookupCache?: Map<string, string>;\n private readonly opDocCache = new Map<string, OperatorDoc | null>();\n private pyIndexCache?: PythonClassSummary[];\n private pyLookupCache?: Map<string, string>;\n private readonly pyDocCache = new Map<string, PythonClass | null>();\n private tutIndexCache?: TutorialSummary[];\n private tutLookupCache?: Map<string, string>;\n private readonly tutDocCache = new Map<string, Tutorial | null>();\n private patternsCache?: Pattern[];\n private glslCache?: GlslTechnique[];\n\n constructor(options: KnowledgeBaseOptions = {}) {\n this.logger = options.logger ?? silentLogger;\n this.source = KnowledgeBase.resolveSource(options.dataDir ?? knowledgeDataDir());\n this.logger.debug(\"knowledge source resolved\", { kind: this.source.kind });\n }\n\n private static resolveSource(localDir: string): ResolvedSource {\n if (existsSync(join(localDir, \"operators\"))) {\n return {\n kind: \"local\",\n operatorsDir: join(localDir, \"operators\"),\n operatorsIndex: join(localDir, \"operators\", \"index.json\"),\n pythonDir: join(localDir, \"python-api\"),\n tutorialsDir: join(localDir, \"tutorials\"),\n patternsFile: join(localDir, \"patterns.json\"),\n glslFile: join(localDir, \"glsl.json\"),\n };\n }\n const bb = bottobotPackageDir();\n if (bb) {\n return {\n kind: \"bottobot\",\n operatorsDir: join(bb, \"wiki/data/processed\"),\n pythonDir: join(bb, \"wiki/data/python-api\"),\n tutorialsDir: join(bb, \"wiki/data/tutorials\"),\n patternsFile: join(bb, \"data/patterns.json\"),\n glslFile: join(bb, \"wiki/data/experimental/glsl.json\"),\n };\n }\n return EMPTY_SOURCE;\n }\n\n private readJson(path: string): unknown {\n try {\n return JSON.parse(readFileSync(path, \"utf8\"));\n } catch (err) {\n this.logger.debug(\"knowledge readJson failed\", { path, error: String(err) });\n return undefined;\n }\n }\n\n private listJsonFiles(dir: string): string[] {\n if (!dir || !existsSync(dir)) return [];\n try {\n return readdirSync(dir).filter((f) => f.endsWith(\".json\") && f !== \"index.json\");\n } catch {\n return [];\n }\n }\n\n // ---- Operators -----------------------------------------------------------\n\n private operatorIndex(): OperatorSummary[] {\n if (this.opIndexCache) return this.opIndexCache;\n if (this.source.kind === \"empty\") {\n this.opIndexCache = [];\n return this.opIndexCache;\n }\n if (this.source.operatorsIndex && existsSync(this.source.operatorsIndex)) {\n const data = this.readJson(this.source.operatorsIndex);\n if (Array.isArray(data)) {\n this.opIndexCache = data as OperatorSummary[];\n return this.opIndexCache;\n }\n }\n const summaries: OperatorSummary[] = [];\n for (const file of this.listJsonFiles(this.source.operatorsDir)) {\n const doc = this.readJson(join(this.source.operatorsDir, file)) as OperatorDoc | undefined;\n if (doc?.name) summaries.push(toOperatorSummary(file.replace(/\\.json$/, \"\"), doc));\n }\n this.opIndexCache = summaries;\n return this.opIndexCache;\n }\n\n private operatorLookup(): Map<string, string> {\n if (this.opLookupCache) return this.opLookupCache;\n const map = new Map<string, string>();\n for (const summary of this.operatorIndex()) {\n map.set(compactKey(summary.slug), summary.slug);\n map.set(compactKey(summary.name), summary.slug);\n map.set(compactKey(summary.displayName), summary.slug);\n }\n this.opLookupCache = map;\n return map;\n }\n\n listOperatorCategories(): string[] {\n const set = new Set<string>();\n for (const summary of this.operatorIndex()) set.add(summary.category);\n return [...set].sort();\n }\n\n listOperators(category?: string): OperatorSummary[] {\n const all = this.operatorIndex();\n if (!category) return all;\n const wanted = compactKey(category);\n return all.filter((s) => compactKey(s.category) === wanted);\n }\n\n getOperator(nameOrSlug: string): OperatorDoc | undefined {\n if (this.source.kind === \"empty\") return undefined;\n const slug = this.operatorLookup().get(compactKey(nameOrSlug)) ?? slugify(nameOrSlug);\n const cached = this.opDocCache.get(slug);\n if (cached !== undefined) return cached ?? undefined;\n const file = join(this.source.operatorsDir, `${slug}.json`);\n const doc = existsSync(file) ? (this.readJson(file) as OperatorDoc | undefined) : undefined;\n this.opDocCache.set(slug, doc ?? null);\n return doc;\n }\n\n /** Soft existence check (by operator type, display name, or slug). */\n operatorExists(typeOrName: string): boolean {\n return this.operatorLookup().has(compactKey(typeOrName));\n }\n\n searchOperators(query: string, limit = 25): OperatorSummary[] {\n const q = query.trim().toLowerCase();\n if (!q) return [];\n const terms = q.split(/\\s+/);\n const scored: Array<{ summary: OperatorSummary; score: number }> = [];\n for (const summary of this.operatorIndex()) {\n const haystack =\n `${summary.name} ${summary.displayName} ${summary.summary} ${summary.keywords.join(\" \")}`.toLowerCase();\n let score = 0;\n for (const term of terms) {\n if (haystack.includes(term)) score += 1;\n if (summary.name.toLowerCase().includes(term)) score += 1;\n }\n if (score > 0) scored.push({ summary, score });\n }\n scored.sort((a, b) => b.score - a.score);\n return scored.slice(0, limit).map((s) => s.summary);\n }\n\n // ---- Python API ----------------------------------------------------------\n\n private pythonIndex(): PythonClassSummary[] {\n if (this.pyIndexCache) return this.pyIndexCache;\n if (this.source.kind === \"empty\") {\n this.pyIndexCache = [];\n return this.pyIndexCache;\n }\n const indexPath = join(this.source.pythonDir, \"index.json\");\n if (existsSync(indexPath)) {\n const data = this.readJson(indexPath);\n if (Array.isArray(data)) {\n this.pyIndexCache = data as PythonClassSummary[];\n return this.pyIndexCache;\n }\n }\n const summaries: PythonClassSummary[] = [];\n for (const file of this.listJsonFiles(this.source.pythonDir)) {\n const cls = this.readJson(join(this.source.pythonDir, file)) as PythonClass | undefined;\n if (cls?.className) summaries.push(toPythonSummary(cls));\n }\n this.pyIndexCache = summaries;\n return this.pyIndexCache;\n }\n\n private pythonLookup(): Map<string, string> {\n if (this.pyLookupCache) return this.pyLookupCache;\n const map = new Map<string, string>();\n for (const summary of this.pythonIndex()) {\n map.set(compactKey(summary.className), summary.className);\n map.set(compactKey(summary.displayName), summary.className);\n }\n this.pyLookupCache = map;\n return map;\n }\n\n listPythonClasses(): PythonClassSummary[] {\n return this.pythonIndex();\n }\n\n getPythonClass(name: string): PythonClass | undefined {\n if (this.source.kind === \"empty\") return undefined;\n const className = this.pythonLookup().get(compactKey(name)) ?? name;\n const cached = this.pyDocCache.get(className);\n if (cached !== undefined) return cached ?? undefined;\n const file = join(this.source.pythonDir, `${className}.json`);\n const cls = existsSync(file) ? (this.readJson(file) as PythonClass | undefined) : undefined;\n this.pyDocCache.set(className, cls ?? null);\n return cls;\n }\n\n // ---- Patterns ------------------------------------------------------------\n\n private patterns(): Pattern[] {\n if (this.patternsCache) return this.patternsCache;\n if (this.source.kind === \"empty\") {\n this.patternsCache = [];\n return this.patternsCache;\n }\n const data = this.readJson(this.source.patternsFile);\n if (Array.isArray(data) && data.length > 0 && typeof (data[0] as Pattern).id === \"string\") {\n this.patternsCache = data as Pattern[];\n } else {\n this.patternsCache = normalizePatterns(data);\n }\n return this.patternsCache;\n }\n\n listPatterns(): PatternSummary[] {\n return this.patterns().map((p) => ({\n id: p.id,\n name: p.name,\n category: p.category ?? \"Unknown\",\n description: p.description ?? \"\",\n }));\n }\n\n getPattern(name: string): Pattern | undefined {\n const key = compactKey(name);\n return this.patterns().find((p) => compactKey(p.id) === key || compactKey(p.name) === key);\n }\n\n // ---- GLSL ----------------------------------------------------------------\n\n private glsl(): GlslTechnique[] {\n if (this.glslCache) return this.glslCache;\n if (this.source.kind === \"empty\") {\n this.glslCache = [];\n return this.glslCache;\n }\n const data = this.readJson(this.source.glslFile);\n this.glslCache = Array.isArray(data) ? (data as GlslTechnique[]) : normalizeGlsl(data);\n return this.glslCache;\n }\n\n listGlslPatterns(): GlslSummary[] {\n return this.glsl().map((g) => ({\n id: g.id,\n name: g.name,\n description: g.description ?? \"\",\n difficulty: g.difficulty ?? \"unknown\",\n }));\n }\n\n getGlslPattern(name: string): GlslTechnique | undefined {\n const key = compactKey(name);\n return this.glsl().find((g) => compactKey(g.id) === key || compactKey(g.name) === key);\n }\n\n // ---- Tutorials -----------------------------------------------------------\n\n private tutorialIndex(): TutorialSummary[] {\n if (this.tutIndexCache) return this.tutIndexCache;\n if (this.source.kind === \"empty\") {\n this.tutIndexCache = [];\n return this.tutIndexCache;\n }\n const indexPath = join(this.source.tutorialsDir, \"index.json\");\n if (existsSync(indexPath)) {\n const data = this.readJson(indexPath);\n if (Array.isArray(data)) {\n this.tutIndexCache = data as TutorialSummary[];\n return this.tutIndexCache;\n }\n }\n const summaries: TutorialSummary[] = [];\n for (const file of this.listJsonFiles(this.source.tutorialsDir)) {\n const tut = this.readJson(join(this.source.tutorialsDir, file)) as Tutorial | undefined;\n if (tut?.id || tut?.name) {\n const normalized: Tutorial = {\n ...tut,\n id: tut.id ?? file.replace(/\\.json$/, \"\"),\n name: tut.name ?? file,\n };\n summaries.push(toTutorialSummary(normalized));\n }\n }\n this.tutIndexCache = summaries;\n return this.tutIndexCache;\n }\n\n private tutorialLookup(): Map<string, string> {\n if (this.tutLookupCache) return this.tutLookupCache;\n const map = new Map<string, string>();\n for (const file of this.listJsonFiles(this.source.tutorialsDir)) {\n const slug = file.replace(/\\.json$/, \"\");\n map.set(compactKey(slug), slug);\n }\n for (const summary of this.tutorialIndex()) {\n map.set(compactKey(summary.id), summary.id);\n map.set(compactKey(summary.name), summary.id);\n }\n this.tutLookupCache = map;\n return map;\n }\n\n listTutorials(): TutorialSummary[] {\n return this.tutorialIndex();\n }\n\n getTutorial(name: string): Tutorial | undefined {\n if (this.source.kind === \"empty\") return undefined;\n const slug = this.tutorialLookup().get(compactKey(name)) ?? slugify(name);\n const cached = this.tutDocCache.get(slug);\n if (cached !== undefined) return cached ?? undefined;\n const file = join(this.source.tutorialsDir, `${slug}.json`);\n const tut = existsSync(file) ? (this.readJson(file) as Tutorial | undefined) : undefined;\n this.tutDocCache.set(slug, tut ?? null);\n return tut;\n }\n\n // ---- Meta ----------------------------------------------------------------\n\n get sourceKind(): KnowledgeStats[\"source\"] {\n return this.source.kind;\n }\n\n stats(): KnowledgeStats {\n return {\n source: this.source.kind,\n operators: this.operatorIndex().length,\n pythonClasses: this.pythonIndex().length,\n patterns: this.patterns().length,\n glsl: this.glsl().length,\n tutorials: this.tutorialIndex().length,\n };\n }\n}\n","export type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"silent\";\n\nconst LEVELS: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n silent: 99,\n};\n\nexport interface Logger {\n debug(message: string, meta?: Record<string, unknown>): void;\n info(message: string, meta?: Record<string, unknown>): void;\n warn(message: string, meta?: Record<string, unknown>): void;\n error(message: string, meta?: Record<string, unknown>): void;\n}\n\n/**\n * Creates a leveled logger. All output goes to **stderr** so that stdout stays\n * reserved for the MCP stdio protocol stream.\n */\nexport function createLogger(level: LogLevel = \"info\"): Logger {\n const threshold = LEVELS[level];\n\n const emit = (\n lvl: Exclude<LogLevel, \"silent\">,\n message: string,\n meta?: Record<string, unknown>,\n ) => {\n if (LEVELS[lvl] < threshold) return;\n const stamp = new Date().toISOString();\n const suffix = meta && Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : \"\";\n process.stderr.write(`[tdmcp] ${stamp} ${lvl.toUpperCase()} ${message}${suffix}\\n`);\n };\n\n return {\n debug: (message, meta) => emit(\"debug\", message, meta),\n info: (message, meta) => emit(\"info\", message, meta),\n warn: (message, meta) => emit(\"warn\", message, meta),\n error: (message, meta) => emit(\"error\", message, meta),\n };\n}\n\n/** A logger that discards everything — handy for tests. */\nexport const silentLogger: Logger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n","import { existsSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst moduleDir = dirname(fileURLToPath(import.meta.url));\n\nfunction firstExisting(candidates: string[], fallback: string): string {\n for (const candidate of candidates) {\n if (existsSync(candidate)) return candidate;\n }\n return fallback;\n}\n\n/**\n * Directory holding the imported knowledge base JSON.\n * - dev (tsx): `<root>/src/knowledge/data`\n * - build (node): `<root>/dist/knowledge/data` (copied by `copy-assets.mjs`)\n */\nexport function knowledgeDataDir(): string {\n return firstExisting(\n [resolve(moduleDir, \"../knowledge/data\"), resolve(moduleDir, \"knowledge/data\")],\n resolve(moduleDir, \"../knowledge/data\"),\n );\n}\n\n/**\n * Directory holding recipe JSON files.\n * - dev: `<root>/recipes`\n * - build: `<root>/dist/recipes`\n */\nexport function recipesDir(): string {\n return firstExisting(\n [resolve(moduleDir, \"../../recipes\"), resolve(moduleDir, \"recipes\")],\n resolve(moduleDir, \"../../recipes\"),\n );\n}\n\n/**\n * Directory holding the TouchDesigner-side Python bridge modules that ship with\n * the package (the `td/modules` tree). Used by the `install-bridge` CLI to copy\n * them somewhere TouchDesigner can import from.\n * - dev (tsx): `<root>/td/modules`\n * - installed package (node): `<pkgroot>/td/modules`\n */\nexport function bridgeModulesDir(): string {\n return firstExisting(\n [resolve(moduleDir, \"../td/modules\"), resolve(moduleDir, \"../../td/modules\")],\n resolve(moduleDir, \"../td/modules\"),\n );\n}\n\n/**\n * Resolves the installed `@bottobot/td-mcp` package root (the source of operator\n * data), if present. Used as a fallback when local knowledge data is missing.\n */\nexport function bottobotPackageDir(): string | undefined {\n const candidates = [\n resolve(moduleDir, \"../../node_modules/@bottobot/td-mcp\"),\n resolve(moduleDir, \"../node_modules/@bottobot/td-mcp\"),\n resolve(process.cwd(), \"node_modules/@bottobot/td-mcp\"),\n ];\n for (const candidate of candidates) {\n if (existsSync(resolve(candidate, \"wiki/data/processed\"))) return candidate;\n }\n return undefined;\n}\n","import type {\n GlslTechnique,\n OperatorDoc,\n OperatorSummary,\n Pattern,\n PythonClass,\n PythonClassSummary,\n Tutorial,\n TutorialSummary,\n} from \"./types.js\";\n\n/** Filename-style slug: lowercase, non-alphanumerics collapse to underscores. */\nexport function slugify(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n}\n\n/** Lookup key that unifies \"Noise TOP\", \"noiseTOP\" and \"noise_top\" → \"noisetop\". */\nexport function compactKey(value: string): string {\n return value.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n}\n\nexport function toOperatorSummary(slug: string, doc: OperatorDoc): OperatorSummary {\n return {\n slug,\n name: doc.name,\n displayName: doc.displayName ?? doc.name,\n category: doc.category ?? \"Unknown\",\n subcategory: doc.subcategory ?? \"\",\n summary: doc.summary ?? doc.description ?? \"\",\n keywords: doc.keywords ?? [],\n };\n}\n\nexport function toPythonSummary(cls: PythonClass): PythonClassSummary {\n return {\n className: cls.className,\n displayName: cls.displayName ?? cls.className,\n category: cls.category ?? \"Unknown\",\n methodCount: cls.methods?.length ?? 0,\n memberCount: cls.members?.length ?? 0,\n };\n}\n\nexport function toTutorialSummary(tut: Tutorial): TutorialSummary {\n return {\n id: tut.id,\n name: tut.name,\n category: tut.category ?? \"Unknown\",\n summary: tut.summary ?? tut.description ?? \"\",\n };\n}\n\ninterface RawPattern {\n name?: string;\n description?: string;\n category?: string;\n workflow?: string[];\n use_case?: string;\n}\n\n/**\n * The bottobot patterns file is an object with a `patterns` array (plus extra\n * metadata keys). Normalizes it into a flat, id-keyed array.\n */\nexport function normalizePatterns(raw: unknown): Pattern[] {\n let list: RawPattern[] = [];\n if (Array.isArray(raw)) {\n list = raw as RawPattern[];\n } else if (raw && typeof raw === \"object\") {\n const obj = raw as Record<string, unknown>;\n if (Array.isArray(obj.patterns)) {\n list = obj.patterns as RawPattern[];\n } else {\n list = Object.values(obj).filter((v): v is RawPattern => !!v && typeof v === \"object\");\n }\n }\n return list\n .filter((p) => typeof p.name === \"string\")\n .map((p) => ({\n id: slugify(p.name as string),\n name: p.name as string,\n description: p.description,\n category: p.category,\n workflow: Array.isArray(p.workflow) ? p.workflow : undefined,\n use_case: p.use_case,\n }));\n}\n\ninterface RawGlslFile {\n techniques?: unknown;\n}\n\n/** Extracts GLSL techniques from bottobot's `experimental/glsl.json`. */\nexport function normalizeGlsl(raw: unknown): GlslTechnique[] {\n const file = (raw ?? {}) as RawGlslFile;\n const techniques = Array.isArray(file.techniques) ? file.techniques : [];\n return techniques\n .filter((t): t is Record<string, unknown> => !!t && typeof t === \"object\")\n .map((t) => {\n const name = typeof t.name === \"string\" ? t.name : \"Untitled\";\n const id = typeof t.id === \"string\" && t.id.length > 0 ? t.id : slugify(name);\n return {\n id,\n name,\n subcategory: typeof t.subcategory === \"string\" ? t.subcategory : undefined,\n description: typeof t.description === \"string\" ? t.description : undefined,\n difficulty: typeof t.difficulty === \"string\" ? t.difficulty : undefined,\n operators: Array.isArray(t.operators) ? (t.operators as string[]) : undefined,\n tags: Array.isArray(t.tags) ? (t.tags as string[]) : undefined,\n notes: typeof t.notes === \"string\" ? t.notes : undefined,\n code: (t.code ?? undefined) as GlslTechnique[\"code\"],\n setup: typeof t.setup === \"string\" ? t.setup : undefined,\n };\n });\n}\n","import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { compactKey } from \"../knowledge/normalize.js\";\nimport { type Logger, silentLogger } from \"../utils/logger.js\";\nimport { recipesDir } from \"../utils/paths.js\";\nimport { type Recipe, RecipeSchema, type RecipeSummary } from \"./schema.js\";\n\nexport interface RecipeLibraryOptions {\n dir?: string;\n logger?: Logger;\n}\n\n/** Loads and validates recipe JSON files from the recipes directory. */\nexport class RecipeLibrary {\n private readonly dir: string;\n private readonly logger: Logger;\n private cache?: Recipe[];\n\n constructor(options: RecipeLibraryOptions = {}) {\n this.dir = options.dir ?? recipesDir();\n this.logger = options.logger ?? silentLogger;\n }\n\n private load(): Recipe[] {\n if (this.cache) return this.cache;\n const recipes: Recipe[] = [];\n if (existsSync(this.dir)) {\n for (const file of readdirSync(this.dir)) {\n if (!file.endsWith(\".json\")) continue;\n try {\n const raw = JSON.parse(readFileSync(join(this.dir, file), \"utf8\"));\n const parsed = RecipeSchema.safeParse(raw);\n if (parsed.success) {\n recipes.push(parsed.data);\n } else {\n this.logger.warn(`Invalid recipe ${file}`, { issues: parsed.error.issues.length });\n }\n } catch (err) {\n this.logger.warn(`Failed to read recipe ${file}`, { error: String(err) });\n }\n }\n }\n this.cache = recipes;\n return recipes;\n }\n\n all(): Recipe[] {\n return this.load();\n }\n\n list(): RecipeSummary[] {\n return this.load().map((r) => ({\n id: r.id,\n name: r.name,\n description: r.description,\n tags: r.tags,\n difficulty: r.difficulty,\n }));\n }\n\n get(id: string): Recipe | undefined {\n const key = compactKey(id);\n return this.load().find((r) => compactKey(r.id) === key || compactKey(r.name) === key);\n }\n\n /** Finds the best recipe whose tags/name/description match any of the given terms. */\n findByTags(terms: string[]): Recipe | undefined {\n const wanted = terms.map((t) => t.toLowerCase()).filter(Boolean);\n if (wanted.length === 0) return undefined;\n let best: { recipe: Recipe; score: number } | undefined;\n for (const recipe of this.load()) {\n const haystack =\n `${recipe.name} ${recipe.description} ${recipe.tags.join(\" \")}`.toLowerCase();\n let score = 0;\n for (const term of wanted) {\n if (recipe.tags.some((tag) => tag.toLowerCase() === term)) score += 2;\n else if (haystack.includes(term)) score += 1;\n }\n if (score > 0 && (!best || score > best.score)) best = { recipe, score };\n }\n return best?.recipe;\n }\n}\n","import { z } from \"zod\";\nimport { controlSchema } from \"../tools/layer2/createControlPanel.js\";\n\nexport const RecipeNodeSchema = z.object({\n name: z.string().describe(\"Unique node name within the recipe (used for wiring).\"),\n type: z.string().describe(\"Operator type, e.g. 'noiseTOP'.\"),\n parameters: z.record(z.string(), z.unknown()).default({}),\n parent: z\n .string()\n .optional()\n .describe(\n \"Name of another recipe node (a COMP, e.g. a geometryCOMP) to nest this node inside of. \" +\n \"The parent must appear earlier in `nodes`. Used to place SOPs inside a Geometry COMP.\",\n ),\n render: z\n .boolean()\n .optional()\n .describe(\n \"For a SOP nested in a geometryCOMP: make this the rendered geometry. Sets the render/display \" +\n \"flags on it and clears its siblings, so the COMP renders this instead of its default torus.\",\n ),\n comment: z.string().optional(),\n});\n\nexport const RecipeConnectionSchema = z.object({\n from: z.string().describe(\"Source node name.\"),\n to: z.string().describe(\"Target node name.\"),\n from_output: z.number().int().nonnegative().default(0),\n to_input: z.number().int().nonnegative().default(0),\n});\n\nexport const RecipeParameterSchema = z.object({\n name: z.string().describe(\"Friendly name of the exposed control.\"),\n node: z.string().describe(\"Recipe node name the parameter belongs to.\"),\n param: z.string().describe(\"TD parameter name on that node.\"),\n value: z.unknown().optional(),\n label: z.string().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n description: z.string().optional(),\n});\n\n/**\n * A uniform exposed by a GLSL TOP. On the GLSL TOP these live in *parameter\n * sequences*, not normal parameters, so they cannot be set the usual way: the block\n * count (`op.seq.<seq>.numBlocks`) has to be raised first, after which the per-block\n * name/value sub-parameters exist. `float`/`vec` uniforms bind through the \"Vectors\"\n * page (the `vec` sequence); `color` binds through the \"Colors\" page (the `color`\n * sequence). The \"Constants\" page does NOT feed a runtime `uniform float`, so it is\n * not used here. `buildFromRecipe` handles the translation; authors just declare the\n * uniform.\n */\nexport const RecipeGlslUniformSchema = z.object({\n node: z.string().describe(\"Recipe node name of the GLSL TOP that declares the uniform.\"),\n name: z.string().describe(\"Uniform name as referenced in the shader, e.g. 'uFeed'.\"),\n kind: z\n .enum([\"float\", \"vec\", \"color\"])\n .default(\"float\")\n .describe(\n \"Uniform kind: float (uniform float), vec (uniform vec2/3/4), color (rgba). \" +\n \"float/vec use the Vectors page; color uses the Colors page.\",\n ),\n value: z\n .union([z.number(), z.array(z.number())])\n .optional()\n .describe(\"Initial value: a number for float, or an array of components for vec/color.\"),\n label: z.string().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n description: z.string().optional(),\n});\nexport type RecipeGlslUniform = z.infer<typeof RecipeGlslUniformSchema>;\n\nexport const RecipeSchema = z.object({\n id: z.string(),\n name: z.string(),\n description: z.string().default(\"\"),\n tags: z.array(z.string()).default([]),\n difficulty: z.enum([\"beginner\", \"intermediate\", \"advanced\"]).default(\"intermediate\"),\n td_version_min: z.string().default(\"2023\"),\n nodes: z.array(RecipeNodeSchema).min(1),\n connections: z.array(RecipeConnectionSchema).default([]),\n parameters: z.array(RecipeParameterSchema).default([]),\n glsl_uniforms: z.array(RecipeGlslUniformSchema).default([]),\n glsl_code: z.record(z.string(), z.string()).optional(),\n python_code: z.record(z.string(), z.string()).optional(),\n /**\n * Live controls to auto-expose on the system container: custom parameters (knobs/\n * sliders/toggles) bound to node parameters so the built system is immediately\n * playable. Each control's `bind_to` uses recipe node *names* (\"nodeName.parName\");\n * buildFromRecipe rewrites them to the real created paths.\n */\n controls: z.array(controlSchema).default([]),\n preview_description: z.string().default(\"\"),\n});\nexport type Recipe = z.infer<typeof RecipeSchema>;\n\nexport interface RecipeSummary {\n id: string;\n name: string;\n description: string;\n tags: string[];\n difficulty: Recipe[\"difficulty\"];\n}\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const controlSchema = z.object({\n name: z\n .string()\n .describe(\n \"Control label; also sanitized into a valid TD custom-parameter name (e.g. 'blur amount' → 'Bluramount').\",\n ),\n type: z\n .enum([\"float\", \"int\", \"toggle\", \"menu\", \"rgb\", \"pulse\", \"string\"])\n .default(\"float\")\n .describe(\n \"Widget kind: float/int sliders, a toggle, a dropdown menu, an RGB swatch, a momentary pulse, or a text field.\",\n ),\n label: z.string().optional().describe(\"Display label (defaults to `name`).\"),\n min: z.coerce.number().optional().describe(\"Slider lower bound (float/int) — also hard-clamped.\"),\n max: z.coerce.number().optional().describe(\"Slider upper bound (float/int) — also hard-clamped.\"),\n default: z.union([z.number(), z.boolean(), z.string()]).optional().describe(\"Initial value.\"),\n menu_items: z.array(z.string()).optional().describe(\"Options for a 'menu' control.\"),\n bind_to: z\n .array(z.string())\n .optional()\n .describe(\n \"Parameters this control should drive, each written as 'nodePath.parName' (e.g. '/project1/sys/blur1.size'). Each target is switched to expression mode so moving the control moves the parameter live. Not supported for 'rgb'/'pulse'.\",\n ),\n});\n\n/** One control spec (knob/slider/toggle/menu/…), reused by Layer 1 tools that auto-expose a panel. */\nexport type ControlSpec = z.infer<typeof controlSchema>;\n\nexport const createControlPanelSchema = z.object({\n comp_path: z\n .string()\n .default(\"/project1\")\n .describe(\n \"COMP that will receive the custom parameters — usually a generated system's container.\",\n ),\n page: z\n .string()\n .default(\"Controls\")\n .describe(\"Name of the custom-parameter page to add the controls to.\"),\n controls: z\n .array(controlSchema)\n .min(1)\n .describe(\"The controls (knobs/sliders/toggles/menus) to expose.\"),\n});\ntype CreateControlPanelArgs = z.infer<typeof createControlPanelSchema>;\n\ninterface ControlReport {\n comp: string;\n page: string;\n created: Array<{ control: string; name: string; type: string; pars: string[]; value: unknown }>;\n bound: Array<{ control: string; target: string }>;\n warnings: string[];\n fatal?: string;\n}\n\n// The whole panel is built in one Python pass: appending custom parameters is an\n// attribute-level operation with no structured bridge endpoint, and doing it in a\n// single script keeps the page/parameter/binding work atomic. `ParMode` is *not*\n// injected into the bridge's exec globals, so the expression-mode enum is derived\n// from a live parameter (`type(par.mode)`) instead of imported.\nconst PANEL_SCRIPT = `\nimport json, base64, traceback\n_payload = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\n_comp = op(_payload[\"comp\"]); _page_name = _payload[\"page\"]; _controls = _payload[\"controls\"]\nreport = {\"comp\": _payload[\"comp\"], \"page\": _page_name, \"created\": [], \"bound\": [], \"warnings\": []}\n\ndef _parname(s):\n s = \"\".join(ch for ch in s if ch.isalnum())\n if not s:\n s = \"Par\"\n if not s[0].isalpha():\n s = \"P\" + s\n # TD custom-parameter names must be a leading uppercase letter followed by lowercase\n # letters/digits only, so lowercase the tail — otherwise camelCase input like \"CamZoom\"\n # keeps its internal capital and TouchDesigner rejects the name.\n return s[0].upper() + s[1:].lower()\n\nif _comp is None:\n report[\"fatal\"] = \"COMP not found: \" + _payload[\"comp\"]\nelif not hasattr(_comp, \"appendCustomPage\"):\n report[\"fatal\"] = _payload[\"comp\"] + \" is not a COMP, so it cannot hold custom parameters.\"\nelse:\n _page = None\n for _pg in _comp.customPages:\n if _pg.name == _page_name:\n _page = _pg\n break\n if _page is None:\n _page = _comp.appendCustomPage(_page_name)\n for _spec in _controls:\n try:\n _name = _parname(_spec[\"name\"]); _typ = _spec.get(\"type\", \"float\"); _label = _spec.get(\"label\") or _spec[\"name\"]\n if _typ == \"float\":\n _pg = _page.appendFloat(_name, label=_label)\n elif _typ == \"int\":\n _pg = _page.appendInt(_name, label=_label)\n elif _typ == \"toggle\":\n _pg = _page.appendToggle(_name, label=_label)\n elif _typ == \"menu\":\n _pg = _page.appendMenu(_name, label=_label)\n elif _typ == \"rgb\":\n _pg = _page.appendRGB(_name, label=_label)\n elif _typ == \"pulse\":\n _pg = _page.appendPulse(_name, label=_label)\n elif _typ in (\"string\", \"str\"):\n _pg = _page.appendStr(_name, label=_label)\n else:\n report[\"warnings\"].append(\"Unknown control type '%s' for '%s'.\" % (_typ, _spec[\"name\"]))\n continue\n _p0 = _pg[0]; _dflt = _spec.get(\"default\", None)\n if _typ in (\"float\", \"int\"):\n _mn = _spec.get(\"min\", None); _mx = _spec.get(\"max\", None)\n if _mn is not None:\n _p0.normMin = _mn; _p0.min = _mn; _p0.clampMin = True\n if _mx is not None:\n _p0.normMax = _mx; _p0.max = _mx; _p0.clampMax = True\n if _dflt is not None:\n _p0.default = _dflt; _p0.val = _dflt\n elif _typ == \"toggle\":\n if _dflt is not None:\n _p0.default = bool(_dflt); _p0.val = bool(_dflt)\n elif _typ == \"menu\":\n _items = _spec.get(\"menu_items\") or []\n if _items:\n _names = [str(x) for x in _items]\n _p0.menuNames = _names; _p0.menuLabels = _names\n if _dflt is not None and str(_dflt) in [str(x) for x in _items]:\n _p0.default = str(_dflt); _p0.val = str(_dflt)\n elif _typ in (\"string\", \"str\"):\n if _dflt is not None:\n _p0.default = str(_dflt); _p0.val = str(_dflt)\n report[\"created\"].append({\"control\": _spec[\"name\"], \"name\": _name, \"type\": _typ, \"pars\": [pp.name for pp in _pg], \"value\": _p0.eval()})\n _binds = _spec.get(\"bind_to\") or []\n if _binds and _typ in (\"rgb\", \"pulse\"):\n report[\"warnings\"].append(\"bind_to ignored for '%s' (a %s control cannot drive a single parameter).\" % (_spec[\"name\"], _typ))\n _binds = []\n for _t in _binds:\n try:\n _dot = _t.rfind(\".\")\n if _dot <= 0:\n report[\"warnings\"].append(\"Invalid bind target '%s' (expected 'nodePath.parName').\" % _t)\n continue\n _np = _t[:_dot]; _pn = _t[_dot + 1:]; _tn = op(_np)\n if _tn is None:\n report[\"warnings\"].append(\"Bind target node not found: %s\" % _np)\n continue\n _tp = getattr(_tn.par, _pn, None)\n if _tp is None:\n report[\"warnings\"].append(\"Bind target parameter not found: %s.%s\" % (_np, _pn))\n continue\n _PM = type(_tp.mode)\n _tp.expr = \"op(%s).par.%s\" % (repr(_payload[\"comp\"]), _name)\n _tp.mode = _PM.EXPRESSION\n report[\"bound\"].append({\"control\": _name, \"target\": _np + \".\" + _pn})\n except Exception:\n report[\"warnings\"].append(\"Failed to bind '%s' to '%s': %s\" % (_name, _t, traceback.format_exc().splitlines()[-1]))\n except Exception:\n report[\"warnings\"].append(\"Failed to create control '%s': %s\" % (_spec.get(\"name\", \"?\"), traceback.format_exc().splitlines()[-1]))\nprint(json.dumps(report))\n`;\n\nexport function buildPanelScript(payload: object): string {\n return buildPayloadScript(PANEL_SCRIPT, payload);\n}\n\nexport function parseReport(stdout: string | undefined): ControlReport {\n return parsePythonReport<ControlReport>(stdout);\n}\n\nexport async function createControlPanelImpl(ctx: ToolContext, args: CreateControlPanelArgs) {\n return guardTd(\n async () => {\n const script = buildPanelScript({\n comp: args.comp_path,\n page: args.page,\n controls: args.controls,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parseReport(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return jsonResult(`Could not build control panel: ${report.fatal}`, report);\n }\n const summary = `Added ${report.created.length} control(s) on page \"${report.page}\" of ${report.comp}, ${report.bound.length} bound to live parameter(s)${\n report.warnings.length ? `, ${report.warnings.length} warning(s)` : \"\"\n }.`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerCreateControlPanel: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_control_panel\",\n {\n title: \"Create control panel\",\n description:\n \"Expose live controls on a COMP: append custom parameters (sliders, toggles, menus, RGB, pulse) and bind them to node parameters so the artist can drive a generated system in real time. Point `comp_path` at a system container and list the controls; use each control's `bind_to` to wire it to one or more 'nodePath.parName' targets.\",\n inputSchema: createControlPanelSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createControlPanelImpl(ctx, args),\n );\n};\n","/** Base error for all TouchDesigner bridge failures. */\nexport class TdError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"TdError\";\n this.code = code;\n }\n}\n\n/** The bridge could not be reached (TD not running, wrong host/port, etc.). */\nexport class TdConnectionError extends TdError {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, \"TD_CONNECTION\", options);\n this.name = \"TdConnectionError\";\n }\n}\n\n/** The request exceeded the configured timeout. */\nexport class TdTimeoutError extends TdError {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, \"TD_TIMEOUT\", options);\n this.name = \"TdTimeoutError\";\n }\n}\n\n/** The bridge responded but reported an error (HTTP non-2xx or `ok: false`). */\nexport class TdApiError extends TdError {\n readonly status: number | undefined;\n readonly apiCode: string | undefined;\n\n constructor(message: string, options?: { status?: number; apiCode?: string; cause?: unknown }) {\n super(message, \"TD_API\", options);\n this.name = \"TdApiError\";\n this.status = options?.status;\n this.apiCode = options?.apiCode;\n }\n}\n\n/** Produces a human-friendly, single-line description of any error. */\nexport function friendlyTdError(err: unknown): string {\n if (err instanceof TdError) return err.message;\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\nexport type {\n ApiEnvelope,\n CreateNodeInput,\n TdBatchOperation,\n TdBatchResult,\n TdConnection,\n TdDeleteResult,\n TdExecResult,\n TdInfo,\n TdMethodResult,\n TdNodeDetail,\n TdNodeError,\n TdNodeErrors,\n TdNodeList,\n TdNodeRef,\n TdPerformance,\n TdPreview,\n TdTopology,\n} from \"./validators.js\";\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { friendlyTdError } from \"../td-client/types.js\";\n\ntype Content = CallToolResult[\"content\"];\n\nexport function textResult(text: string): CallToolResult {\n return { content: [{ type: \"text\", text }] };\n}\n\nexport function errorResult(message: string): CallToolResult {\n return { isError: true, content: [{ type: \"text\", text: message }] };\n}\n\n/** A text block followed by a pretty-printed JSON code fence. */\nexport function jsonResult(summary: string, data: unknown): CallToolResult {\n const text = `${summary}\\n\\n\\`\\`\\`json\\n${JSON.stringify(data, null, 2)}\\n\\`\\`\\``;\n return { content: [{ type: \"text\", text }] };\n}\n\n/**\n * A short text summary plus a machine-readable `structuredContent` payload.\n *\n * Use this (with an `outputSchema` on the tool) for read tools so agents can\n * process the data with code instead of re-parsing a JSON code fence out of the\n * conversation. The text block stays small on purpose — it is only a summary;\n * the full data travels on the `structuredContent` channel.\n */\nexport function structuredResult(summary: string, data: object): CallToolResult {\n return {\n content: [{ type: \"text\", text: summary }],\n structuredContent: data as { [key: string]: unknown },\n };\n}\n\n/** An image block (base64), optionally preceded by a caption. */\nexport function imageResult(\n base64: string,\n mimeType = \"image/png\",\n caption?: string,\n): CallToolResult {\n const content: Content = [];\n if (caption) content.push({ type: \"text\", text: caption });\n content.push({ type: \"image\", data: base64, mimeType });\n return { content };\n}\n\n/**\n * Runs a client call and formats the result, converting any TD error into a\n * friendly `isError` result instead of throwing out of the MCP handler.\n */\nexport async function guardTd<T>(\n fn: () => Promise<T>,\n onOk: (value: T) => CallToolResult,\n): Promise<CallToolResult> {\n try {\n return onOk(await fn());\n } catch (err) {\n return errorResult(friendlyTdError(err));\n }\n}\n","import { z } from \"zod\";\n\n/** Standard response envelope every bridge endpoint returns. */\nexport const ApiEnvelopeSchema = z.object({\n ok: z.boolean(),\n data: z.unknown().optional(),\n error: z.object({ code: z.string().optional(), message: z.string() }).optional(),\n});\nexport type ApiEnvelope = z.infer<typeof ApiEnvelopeSchema>;\n\nexport const NodeRefSchema = z.object({\n path: z.string(),\n type: z.string().default(\"\"),\n name: z.string().default(\"\"),\n /** Parameters that could not be applied at create time (unknown name or bad value). */\n parameter_warnings: z.array(z.string()).optional(),\n});\nexport type TdNodeRef = z.infer<typeof NodeRefSchema>;\n\nexport const NodeDetailSchema = NodeRefSchema.extend({\n parameters: z.record(z.string(), z.unknown()).default({}),\n inputs: z.array(z.string()).optional(),\n outputs: z.array(z.string()).optional(),\n family: z.string().optional(),\n errors: z.array(z.string()).optional(),\n});\nexport type TdNodeDetail = z.infer<typeof NodeDetailSchema>;\n\nexport const NodeListSchema = z.object({ nodes: z.array(NodeRefSchema).default([]) });\nexport type TdNodeList = z.infer<typeof NodeListSchema>;\n\nexport const InfoSchema = z.object({\n td_version: z.string().optional(),\n python_version: z.string().optional(),\n build: z.string().optional(),\n bridge_version: z.string().optional(),\n project: z.string().optional(),\n});\nexport type TdInfo = z.infer<typeof InfoSchema>;\n\nexport const NodeErrorSchema = z.object({\n path: z.string(),\n message: z.string(),\n type: z.string().optional(),\n});\nexport type TdNodeError = z.infer<typeof NodeErrorSchema>;\n\nexport const NodeErrorsSchema = z.object({ errors: z.array(NodeErrorSchema).default([]) });\nexport type TdNodeErrors = z.infer<typeof NodeErrorsSchema>;\n\nexport const PreviewSchema = z.object({\n path: z.string(),\n width: z.number().int().positive(),\n height: z.number().int().positive(),\n format: z.string().default(\"png\"),\n base64: z.string(),\n});\nexport type TdPreview = z.infer<typeof PreviewSchema>;\n\nexport const ExecResultSchema = z.object({\n result: z.unknown().optional(),\n stdout: z.string().optional(),\n printed: z.array(z.string()).optional(),\n});\nexport type TdExecResult = z.infer<typeof ExecResultSchema>;\n\nexport const MethodResultSchema = z.object({ result: z.unknown() });\nexport type TdMethodResult = z.infer<typeof MethodResultSchema>;\n\nexport const DeleteResultSchema = z.object({ deleted: z.string() });\nexport type TdDeleteResult = z.infer<typeof DeleteResultSchema>;\n\nexport const ConnectionSchema = z.object({\n source_path: z.string(),\n source_output: z.number().int().default(0),\n target_path: z.string(),\n target_input: z.number().int().default(0),\n});\nexport type TdConnection = z.infer<typeof ConnectionSchema>;\n\nexport const TopologySchema = z.object({\n nodes: z.array(NodeRefSchema).default([]),\n connections: z.array(ConnectionSchema).default([]),\n});\nexport type TdTopology = z.infer<typeof TopologySchema>;\n\nexport const PerformanceSchema = z.object({\n nodes: z\n .array(\n z.object({\n path: z.string(),\n cook_time_ms: z.number().default(0),\n cook_count: z.number().optional(),\n }),\n )\n .default([]),\n total_cook_time_ms: z.number().optional(),\n gpu_memory_mb: z.number().optional(),\n});\nexport type TdPerformance = z.infer<typeof PerformanceSchema>;\n\nexport const BatchOpResultSchema = z.object({\n action: z.string(),\n ok: z.boolean(),\n path: z.string().optional(),\n data: z.unknown().optional(),\n error: z.string().optional(),\n});\nexport const BatchResultSchema = z.object({ results: z.array(BatchOpResultSchema).default([]) });\nexport type TdBatchResult = z.infer<typeof BatchResultSchema>;\n\n/** Input shape for creating a node (used by the client and Layer 3 tool). */\nexport const CreateNodeInputSchema = z.object({\n parent_path: z.string(),\n type: z.string(),\n name: z.string().optional(),\n parameters: z.record(z.string(), z.unknown()).optional(),\n});\nexport type CreateNodeInput = z.infer<typeof CreateNodeInputSchema>;\n\n/** A single atomic operation accepted by `POST /api/batch`. */\nexport const BatchOperationSchema = z.discriminatedUnion(\"action\", [\n z.object({\n action: z.literal(\"create\"),\n parent_path: z.string(),\n type: z.string(),\n name: z.string().optional(),\n parameters: z.record(z.string(), z.unknown()).optional(),\n }),\n z.object({\n action: z.literal(\"update\"),\n path: z.string(),\n parameters: z.record(z.string(), z.unknown()),\n }),\n z.object({ action: z.literal(\"delete\"), path: z.string() }),\n z.object({\n action: z.literal(\"connect\"),\n source_path: z.string(),\n target_path: z.string(),\n source_output: z.number().int().default(0),\n target_input: z.number().int().default(0),\n }),\n]);\nexport type TdBatchOperation = z.infer<typeof BatchOperationSchema>;\n","import type { z } from \"zod\";\nimport { type Logger, silentLogger } from \"../utils/logger.js\";\nimport { TdApiError, TdConnectionError, TdTimeoutError } from \"./types.js\";\nimport {\n ApiEnvelopeSchema,\n BatchResultSchema,\n type CreateNodeInput,\n CreateNodeInputSchema,\n DeleteResultSchema,\n ExecResultSchema,\n InfoSchema,\n MethodResultSchema,\n NodeDetailSchema,\n NodeErrorsSchema,\n NodeListSchema,\n NodeRefSchema,\n PerformanceSchema,\n PreviewSchema,\n type TdBatchOperation,\n TopologySchema,\n} from \"./validators.js\";\n\nexport interface TouchDesignerClientOptions {\n baseUrl: string;\n timeoutMs?: number;\n logger?: Logger;\n /** Optional shared bearer token; sent as `Authorization: Bearer <token>` when set. */\n token?: string;\n /** Overridable for tests (defaults to global `fetch`). */\n fetchImpl?: typeof fetch;\n}\n\ntype QueryParams = Record<string, string | number | boolean | undefined>;\n\nfunction extractErrorMessage(json: unknown): string | undefined {\n if (json && typeof json === \"object\") {\n const obj = json as Record<string, unknown>;\n const error = obj.error;\n if (\n error &&\n typeof error === \"object\" &&\n typeof (error as Record<string, unknown>).message === \"string\"\n ) {\n return (error as Record<string, string>).message;\n }\n if (typeof obj.message === \"string\") return obj.message;\n }\n return undefined;\n}\n\n/** Encodes a TD node path (which contains slashes) into a single URL segment. */\nfunction segment(path: string): string {\n return encodeURIComponent(path);\n}\n\n/**\n * HTTP client for the TouchDesigner REST bridge. Every method maps to one of the\n * endpoints in the bridge spec. All failures surface as typed `TdError`s so MCP\n * tool handlers can convert them into friendly messages without crashing.\n */\nexport class TouchDesignerClient {\n private readonly baseUrl: string;\n private readonly timeoutMs: number;\n private readonly logger: Logger;\n private readonly token: string | undefined;\n private readonly fetchImpl: typeof fetch;\n\n constructor(options: TouchDesignerClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.timeoutMs = options.timeoutMs ?? 10000;\n this.logger = options.logger ?? silentLogger;\n this.token = options.token;\n this.fetchImpl = options.fetchImpl ?? fetch;\n }\n\n get endpoint(): string {\n return this.baseUrl;\n }\n\n private async request<T>(\n method: string,\n path: string,\n schema: z.ZodType<T>,\n body?: unknown,\n query?: QueryParams,\n ): Promise<T> {\n const url = new URL(`${this.baseUrl}${path}`);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined) url.searchParams.set(key, String(value));\n }\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n let response: Response;\n try {\n this.logger.debug(`TD ${method} ${path}`);\n const headers: Record<string, string> = {};\n if (body !== undefined) headers[\"content-type\"] = \"application/json\";\n if (this.token) headers.authorization = `Bearer ${this.token}`;\n response = await this.fetchImpl(url, {\n method,\n signal: controller.signal,\n headers: Object.keys(headers).length > 0 ? headers : undefined,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new TdTimeoutError(\n `TouchDesigner request timed out after ${this.timeoutMs}ms (${method} ${path}).`,\n { cause: err },\n );\n }\n throw new TdConnectionError(\n `Cannot reach TouchDesigner at ${this.baseUrl}. Make sure TD is running with the tdmcp bridge (WebServer DAT) installed and listening on that port.`,\n { cause: err },\n );\n } finally {\n clearTimeout(timer);\n }\n\n const text = await response.text();\n let json: unknown;\n if (text) {\n try {\n json = JSON.parse(text);\n } catch {\n json = undefined;\n }\n }\n\n if (!response.ok) {\n const message =\n extractErrorMessage(json) ??\n `TouchDesigner bridge returned HTTP ${response.status} for ${method} ${path}.`;\n throw new TdApiError(message, { status: response.status });\n }\n\n const envelope = ApiEnvelopeSchema.safeParse(json);\n if (!envelope.success) {\n throw new TdApiError(`Malformed response from TouchDesigner bridge for ${method} ${path}.`, {\n status: response.status,\n });\n }\n if (!envelope.data.ok) {\n throw new TdApiError(\n envelope.data.error?.message ?? `TouchDesigner reported an error for ${method} ${path}.`,\n { status: response.status, apiCode: envelope.data.error?.code },\n );\n }\n\n const parsed = schema.safeParse(envelope.data.data);\n if (!parsed.success) {\n throw new TdApiError(\n `Unexpected data shape from TouchDesigner bridge for ${method} ${path}: ${parsed.error.message}`,\n { status: response.status },\n );\n }\n return parsed.data;\n }\n\n getInfo() {\n return this.request(\"GET\", \"/api/info\", InfoSchema);\n }\n\n createNode(input: CreateNodeInput) {\n return this.request(\"POST\", \"/api/nodes\", NodeRefSchema, CreateNodeInputSchema.parse(input));\n }\n\n deleteNode(path: string) {\n return this.request(\"DELETE\", `/api/nodes/${segment(path)}`, DeleteResultSchema);\n }\n\n getNodes(parentPath?: string) {\n return this.request(\"GET\", \"/api/nodes\", NodeListSchema, undefined, { parent: parentPath });\n }\n\n getNode(path: string) {\n return this.request(\"GET\", `/api/nodes/${segment(path)}`, NodeDetailSchema);\n }\n\n updateNodeParameters(path: string, parameters: Record<string, unknown>) {\n return this.request(\"PATCH\", `/api/nodes/${segment(path)}`, NodeDetailSchema, { parameters });\n }\n\n executePythonScript(script: string, returnOutput = true) {\n return this.request(\"POST\", \"/api/exec\", ExecResultSchema, {\n script,\n return_output: returnOutput,\n });\n }\n\n execNodeMethod(\n path: string,\n method: string,\n args: unknown[] = [],\n kwargs: Record<string, unknown> = {},\n ) {\n return this.request(\"POST\", `/api/nodes/${segment(path)}/method`, MethodResultSchema, {\n method,\n args,\n kwargs,\n });\n }\n\n getNodeErrors(path: string) {\n return this.request(\"GET\", `/api/nodes/${segment(path)}/errors`, NodeErrorsSchema);\n }\n\n getPreview(path: string, width = 640, height = 360) {\n return this.request(\"GET\", `/api/preview/${segment(path)}`, PreviewSchema, undefined, {\n width,\n height,\n });\n }\n\n batch(operations: TdBatchOperation[]) {\n return this.request(\"POST\", \"/api/batch\", BatchResultSchema, { operations });\n }\n\n getNetworkErrors(path: string) {\n return this.request(\"GET\", `/api/network/${segment(path)}/errors`, NodeErrorsSchema);\n }\n\n getNetworkTopology(path: string, recursive = false) {\n return this.request(\n \"GET\",\n `/api/network/${segment(path)}/topology`,\n TopologySchema,\n undefined,\n recursive ? { recursive: true } : undefined,\n );\n }\n\n getNetworkPerformance(path: string, recursive = false) {\n return this.request(\n \"GET\",\n `/api/network/${segment(path)}/performance`,\n PerformanceSchema,\n undefined,\n recursive ? { recursive: true } : undefined,\n );\n }\n}\n","import { z } from \"zod\";\n\nexport const ConfigSchema = z.object({\n /** TouchDesigner bridge host. */\n tdHost: z.string().min(1).default(\"127.0.0.1\"),\n /** TouchDesigner bridge port (WebServer DAT). */\n tdPort: z.coerce.number().int().positive().max(65535).default(9980),\n /** MCP transport: `stdio` (default, for local clients) or `http` (Streamable HTTP, loopback-only). */\n transport: z.enum([\"stdio\", \"http\"]).default(\"stdio\"),\n /** Log verbosity (written to stderr). */\n logLevel: z.enum([\"debug\", \"info\", \"warn\", \"error\", \"silent\"]).default(\"info\"),\n /** Per-request timeout against the TD bridge, in milliseconds. */\n requestTimeoutMs: z.coerce.number().int().positive().default(10000),\n /** HTTP transport port (only used when transport=http). */\n httpPort: z.coerce.number().int().positive().max(65535).default(3939),\n /** Subscribe to TD WebSocket events and forward them as MCP logging notifications. */\n events: z.enum([\"on\", \"off\"]).default(\"on\"),\n /**\n * Raw Python escape-hatch tools (`execute_python_script`, `exec_node_method`).\n * Set to \"off\" to lock them out for restricted setups; on by default.\n */\n rawPython: z.enum([\"on\", \"off\"]).default(\"on\"),\n /**\n * Optional shared bearer token for the TD bridge. When set, the server sends it\n * as `Authorization: Bearer <token>` and the bridge requires a match. Leave unset\n * (default) for the zero-config local flow. Set the SAME value in TouchDesigner's\n * environment (`TDMCP_BRIDGE_TOKEN`) to turn enforcement on.\n */\n bridgeToken: z.string().min(1).optional(),\n});\n\nexport type TdmcpConfig = z.infer<typeof ConfigSchema>;\n\n/**\n * Loads and validates configuration from environment variables. Missing values\n * fall back to sensible defaults; invalid values throw a descriptive ZodError.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv = process.env): TdmcpConfig {\n return ConfigSchema.parse({\n tdHost: env.TDMCP_TD_HOST,\n tdPort: env.TDMCP_TD_PORT,\n transport: env.TDMCP_TRANSPORT,\n logLevel: env.TDMCP_LOG_LEVEL,\n requestTimeoutMs: env.TDMCP_REQUEST_TIMEOUT_MS,\n httpPort: env.TDMCP_HTTP_PORT,\n events: env.TDMCP_EVENTS,\n rawPython: env.TDMCP_RAW_PYTHON,\n bridgeToken: env.TDMCP_BRIDGE_TOKEN || undefined,\n });\n}\n\n/** Base URL for the TouchDesigner REST bridge. */\nexport function tdBaseUrl(config: Pick<TdmcpConfig, \"tdHost\" | \"tdPort\">): string {\n return `http://${config.tdHost}:${config.tdPort}`;\n}\n","import { TouchDesignerClient } from \"../td-client/touchDesignerClient.js\";\nimport { type TdmcpConfig, tdBaseUrl } from \"../utils/config.js\";\nimport type { Logger } from \"../utils/logger.js\";\n\n/**\n * Owns the TouchDesigner client and exposes a cheap health probe. The MCP server\n * stays alive whether or not TD is reachable.\n */\nexport class ConnectionManager {\n readonly client: TouchDesignerClient;\n\n constructor(config: TdmcpConfig, logger: Logger) {\n this.client = new TouchDesignerClient({\n baseUrl: tdBaseUrl(config),\n timeoutMs: config.requestTimeoutMs,\n token: config.bridgeToken,\n logger,\n });\n }\n\n async isReachable(): Promise<boolean> {\n try {\n await this.client.getInfo();\n return true;\n } catch {\n return false;\n }\n }\n}\n","import { KnowledgeBase } from \"../knowledge/index.js\";\nimport { RecipeLibrary } from \"../recipes/loader.js\";\nimport type { ToolContext } from \"../tools/types.js\";\nimport type { TdmcpConfig } from \"../utils/config.js\";\nimport { createLogger, type Logger } from \"../utils/logger.js\";\nimport { ConnectionManager } from \"./connectionManager.js\";\n\nexport interface ToolContextOverrides {\n logger?: Logger;\n knowledge?: KnowledgeBase;\n recipes?: RecipeLibrary;\n connection?: ConnectionManager;\n}\n\n/**\n * Assembles the shared {@link ToolContext} that backs every tool handler. Both\n * the MCP server and the agent CLI build their context here, so the two surfaces\n * stay on the same core (client + knowledge + recipes) without duplicating wiring.\n */\nexport function buildToolContext(\n config: TdmcpConfig,\n overrides: ToolContextOverrides = {},\n): ToolContext {\n const logger = overrides.logger ?? createLogger(config.logLevel);\n const connection = overrides.connection ?? new ConnectionManager(config, logger);\n const knowledge = overrides.knowledge ?? new KnowledgeBase({ logger });\n const recipes = overrides.recipes ?? new RecipeLibrary({ logger });\n return {\n client: connection.client,\n knowledge,\n recipes,\n logger,\n allowRawPython: config.rawPython !== \"off\",\n };\n}\n","import { z } from \"zod\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const compareTdNodesSchema = z.object({\n path_a: z.string().describe(\"First node path.\"),\n path_b: z.string().describe(\"Second node path.\"),\n only_diff: z\n .boolean()\n .default(true)\n .describe(\"Return only the parameters that differ (true) or also list the identical ones.\"),\n});\ntype CompareTdNodesArgs = z.infer<typeof compareTdNodesSchema>;\n\nexport const compareTdNodesOutputSchema = z.object({\n a: z.string(),\n b: z.string(),\n type_a: z.string(),\n type_b: z.string(),\n type_match: z.boolean(),\n differing_count: z.number(),\n same_count: z.number(),\n differing: z.array(z.object({ param: z.string(), a: z.unknown(), b: z.unknown() })),\n identical: z.array(z.string()).optional(),\n});\n\nexport async function compareTdNodesImpl(ctx: ToolContext, args: CompareTdNodesArgs) {\n return guardTd(\n async () => {\n const [a, b] = await Promise.all([\n ctx.client.getNode(args.path_a),\n ctx.client.getNode(args.path_b),\n ]);\n return { a, b };\n },\n ({ a, b }) => {\n const keys = new Set([...Object.keys(a.parameters), ...Object.keys(b.parameters)]);\n const differing: Array<{ param: string; a: unknown; b: unknown }> = [];\n const identical: string[] = [];\n for (const key of [...keys].sort()) {\n const va = a.parameters[key];\n const vb = b.parameters[key];\n if (JSON.stringify(va) === JSON.stringify(vb)) identical.push(key);\n else differing.push({ param: key, a: va, b: vb });\n }\n const data: Record<string, unknown> = {\n a: a.path,\n b: b.path,\n type_a: a.type,\n type_b: b.type,\n type_match: a.type === b.type,\n differing_count: differing.length,\n same_count: identical.length,\n differing,\n };\n if (!args.only_diff) data.identical = identical;\n return structuredResult(\n `${differing.length} differing parameter(s) between ${a.path} and ${b.path}${a.type === b.type ? \"\" : ` (types differ: ${a.type} vs ${b.type})`}.`,\n data,\n );\n },\n );\n}\n\nexport const registerCompareTdNodes: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"compare_td_nodes\",\n {\n title: \"Compare two nodes\",\n description:\n \"Diff the parameters of two nodes, returning only the values that differ (by default). Useful for aligning settings across similar operators.\",\n inputSchema: compareTdNodesSchema.shape,\n outputSchema: compareTdNodesOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => compareTdNodesImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const createTdNodeSchema = z.object({\n parent_path: z\n .string()\n .default(\"/project1\")\n .describe(\"Parent COMP path to create the node inside.\"),\n type: z\n .string()\n .describe(\"Operator type string, e.g. 'noiseTOP', 'feedbackTOP', 'nullTOP', 'constantCHOP'.\"),\n name: z.string().optional().describe(\"Optional node name (auto-generated if omitted).\"),\n parameters: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\"Optional initial parameter overrides as key→value pairs.\"),\n});\ntype CreateTdNodeArgs = z.infer<typeof createTdNodeSchema>;\n\nexport async function createTdNodeImpl(ctx: ToolContext, args: CreateTdNodeArgs) {\n const warnings: string[] = [];\n if (!ctx.knowledge.operatorExists(args.type)) {\n const suggestions = ctx.knowledge.searchOperators(args.type, 3).map((s) => s.name);\n warnings.push(\n `Operator type \"${args.type}\" was not found in the knowledge base.${\n suggestions.length ? ` Did you mean: ${suggestions.join(\", \")}?` : \"\"\n }`,\n );\n }\n return guardTd(\n () =>\n ctx.client.createNode({\n parent_path: args.parent_path,\n type: args.type,\n name: args.name,\n parameters: args.parameters,\n }),\n (node) => {\n const allWarnings = [...warnings];\n if (node.parameter_warnings?.length) {\n allWarnings.push(\n `These parameter(s) were not applied (unknown name or bad value): ${node.parameter_warnings.join(\", \")}.`,\n );\n }\n return jsonResult(`Created ${node.type || args.type} at ${node.path}.`, {\n node,\n warnings: allWarnings,\n });\n },\n );\n}\n\nexport const registerCreateTdNode: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_td_node\",\n {\n title: \"Create TouchDesigner node\",\n description:\n \"Create a single operator (node) inside a parent COMP. Validates the operator type against the knowledge base and warns (without blocking) on unknown types.\",\n inputSchema: createTdNodeSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createTdNodeImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const deleteTdNodeSchema = z.object({\n path: z.string().describe(\"Full path of the node to delete, e.g. '/project1/noise1'.\"),\n});\ntype DeleteTdNodeArgs = z.infer<typeof deleteTdNodeSchema>;\n\nexport async function deleteTdNodeImpl(ctx: ToolContext, args: DeleteTdNodeArgs) {\n return guardTd(\n () => ctx.client.deleteNode(args.path),\n (result) => jsonResult(`Deleted ${result.deleted}.`, result),\n );\n}\n\nexport const registerDeleteTdNode: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"delete_td_node\",\n {\n title: \"Delete TouchDesigner node\",\n description:\n \"Delete a single node by path. Destructive — only call this when the user explicitly asks to remove a node.\",\n inputSchema: deleteTdNodeSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n },\n (args) => deleteTdNodeImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const execNodeMethodSchema = z.object({\n path: z.string().describe(\"Full path of the node to call the method on.\"),\n method: z.string().describe(\"Method name to call, e.g. 'cook', 'par', 'destroy', 'copy'.\"),\n args: z.array(z.unknown()).default([]).describe(\"Positional arguments.\"),\n kwargs: z.record(z.string(), z.unknown()).default({}).describe(\"Keyword arguments.\"),\n});\ntype ExecNodeMethodArgs = z.infer<typeof execNodeMethodSchema>;\n\nexport async function execNodeMethodImpl(ctx: ToolContext, args: ExecNodeMethodArgs) {\n return guardTd(\n () => ctx.client.execNodeMethod(args.path, args.method, args.args, args.kwargs),\n (result) => jsonResult(`Called ${args.path}.${args.method}().`, result),\n );\n}\n\nexport const registerExecNodeMethod: ToolRegistrar = (server, ctx) => {\n if (ctx.allowRawPython === false) return;\n server.registerTool(\n \"exec_node_method\",\n {\n title: \"Call node method\",\n description:\n \"Escape hatch — invoke an arbitrary Python method on a node (operator). Prefer structured tools where one exists; use this for operations they don't cover (e.g. .cook(), .copy(), .destroy()).\",\n inputSchema: execNodeMethodSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n },\n (args) => execNodeMethodImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const executePythonScriptSchema = z.object({\n script: z\n .string()\n .min(1)\n .describe(\n \"Python source to execute inside TouchDesigner (runs in the TD process, not locally).\",\n ),\n return_output: z\n .boolean()\n .default(true)\n .describe(\"Capture stdout / the value of the last expression and return it.\"),\n});\ntype ExecutePythonScriptArgs = z.infer<typeof executePythonScriptSchema>;\n\nexport async function executePythonScriptImpl(ctx: ToolContext, args: ExecutePythonScriptArgs) {\n return guardTd(\n () => ctx.client.executePythonScript(args.script, args.return_output),\n (result) => jsonResult(\"Python executed in TouchDesigner.\", result),\n );\n}\n\nexport const registerExecutePythonScript: ToolRegistrar = (server, ctx) => {\n if (ctx.allowRawPython === false) return;\n server.registerTool(\n \"execute_python_script\",\n {\n title: \"Execute Python in TouchDesigner\",\n description:\n \"Escape hatch — run an arbitrary Python script inside the TouchDesigner process. Prefer the structured tools (find_td_nodes, get_td_node_parameters, update_td_node_parameters, summarize_td_errors, snapshot_td_graph, …); reach for this only when no structured tool can express the operation. Code runs in TD only, never on the local machine.\",\n inputSchema: executePythonScriptSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n },\n (args) => executePythonScriptImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { NodeRefSchema } from \"../../td-client/validators.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { globToRegExp } from \"./nodeMatch.js\";\n\nexport const findTdNodesSchema = z.object({\n parent_path: z.string().default(\"/project1\").describe(\"Where to search from.\"),\n pattern: z\n .string()\n .optional()\n .describe(\"Case-insensitive name/path filter with '*' wildcards (e.g. 'text*', '*noise*').\"),\n type: z\n .string()\n .optional()\n .describe(\"Case-insensitive operator-type substring (e.g. 'TOP', 'noise').\"),\n recursive: z\n .boolean()\n .default(true)\n .describe(\"Search the whole sub-network (true) or only direct children (false).\"),\n path_only: z.boolean().default(false).describe(\"Return only matching paths.\"),\n limit: z.number().int().positive().default(50).describe(\"Max matches to return.\"),\n});\ntype FindTdNodesArgs = z.infer<typeof findTdNodesSchema>;\n\nexport const findTdNodesOutputSchema = z.object({\n parent_path: z.string(),\n recursive: z.boolean(),\n count: z.number(),\n truncated: z.boolean(),\n paths: z.array(z.string()).optional(),\n matches: z.array(NodeRefSchema).optional(),\n});\n\nexport async function findTdNodesImpl(ctx: ToolContext, args: FindTdNodesArgs) {\n const fetch = args.recursive\n ? async () => (await ctx.client.getNetworkTopology(args.parent_path, true)).nodes\n : async () => (await ctx.client.getNodes(args.parent_path)).nodes;\n\n return guardTd(fetch, (allNodes) => {\n let nodes = allNodes;\n if (args.pattern) {\n const re = globToRegExp(args.pattern);\n nodes = nodes.filter((n) => re.test(n.name) || re.test(n.path));\n }\n if (args.type) {\n const t = args.type.toLowerCase();\n nodes = nodes.filter((n) => n.type.toLowerCase().includes(t));\n }\n const count = nodes.length;\n const truncated = count > args.limit;\n nodes = nodes.slice(0, args.limit);\n const summary = `${count} match(es) under ${args.parent_path}${truncated ? ` (showing ${args.limit})` : \"\"}.`;\n const base = { parent_path: args.parent_path, recursive: args.recursive, count, truncated };\n return args.path_only\n ? structuredResult(summary, { ...base, paths: nodes.map((n) => n.path) })\n : structuredResult(summary, { ...base, matches: nodes });\n });\n}\n\nexport const registerFindTdNodes: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"find_td_nodes\",\n {\n title: \"Find TouchDesigner nodes\",\n description:\n \"Search a network for nodes by name pattern and/or operator type. Recursive by default; pass path_only:true for a compact path list. Prefer this over get_td_nodes when you are looking for specific nodes.\",\n inputSchema: findTdNodesSchema.shape,\n outputSchema: findTdNodesOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => findTdNodesImpl(ctx, args),\n );\n};\n","/** Turns a `*`-glob into a case-insensitive RegExp (other regex metachars are escaped). */\nexport function globToRegExp(pattern: string): RegExp {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(escaped, \"i\");\n}\n\n/** The parent path of a TD node path, e.g. `/project1/moviein1` -> `/project1`. */\nexport function parentOf(path: string): string {\n const idx = path.lastIndexOf(\"/\");\n return idx <= 0 ? \"/\" : path.slice(0, idx);\n}\n","import { z } from \"zod\";\nimport { jsonResult, textResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getModuleHelpSchema = z.object({\n name: z.string().describe(\"Class or module name to get help for, e.g. 'OP', 'App', 'Project'.\"),\n});\ntype GetModuleHelpArgs = z.infer<typeof getModuleHelpSchema>;\n\nexport function getModuleHelpImpl(ctx: ToolContext, args: GetModuleHelpArgs) {\n const cls = ctx.knowledge.getPythonClass(args.name);\n if (!cls) {\n const suggestions = ctx.knowledge\n .listPythonClasses()\n .filter((c) => c.className.toLowerCase().includes(args.name.toLowerCase()))\n .slice(0, 5)\n .map((c) => c.className);\n return jsonResult(`No help found for \"${args.name}\".`, { found: false, suggestions });\n }\n\n const lines: string[] = [`# ${cls.displayName || cls.className}`, \"\"];\n if (cls.description) lines.push(cls.description, \"\");\n if (cls.members && cls.members.length > 0) {\n lines.push(\"## Members\");\n for (const m of cls.members) {\n const ro = m.readOnly ? \" (read-only)\" : \"\";\n lines.push(`- ${m.name}${m.returnType ? `: ${m.returnType}` : \"\"}${ro}`);\n }\n lines.push(\"\");\n }\n if (cls.methods && cls.methods.length > 0) {\n lines.push(\"## Methods\");\n for (const method of cls.methods) {\n const sig = method.signature || method.name || \"\";\n lines.push(`- ${sig}${method.returns ? ` -> ${method.returns}` : \"\"}`);\n }\n }\n return textResult(lines.join(\"\\n\"));\n}\n\nexport const registerGetModuleHelp: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_module_help\",\n {\n title: \"Get module/class help\",\n description:\n \"Human-readable help (description, members, method signatures) for a TouchDesigner Python class or module, from the knowledge base.\",\n inputSchema: getModuleHelpSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n (args) => getModuleHelpImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getTdClassDetailsSchema = z.object({\n class_name: z.string().describe(\"Python class name, e.g. 'OP', 'TOP', 'App', 'CHOP'.\"),\n});\ntype GetTdClassDetailsArgs = z.infer<typeof getTdClassDetailsSchema>;\n\nexport function getTdClassDetailsImpl(ctx: ToolContext, args: GetTdClassDetailsArgs) {\n const cls = ctx.knowledge.getPythonClass(args.class_name);\n if (!cls) {\n const suggestions = ctx.knowledge\n .listPythonClasses()\n .filter((c) => c.className.toLowerCase().includes(args.class_name.toLowerCase()))\n .slice(0, 5)\n .map((c) => c.className);\n return structuredResult(`Python class \"${args.class_name}\" not found.`, {\n found: false,\n suggestions,\n });\n }\n return structuredResult(\n `${cls.className} — ${cls.methods?.length ?? 0} methods, ${cls.members?.length ?? 0} members.`,\n cls,\n );\n}\n\nexport const registerGetTdClassDetails: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_class_details\",\n {\n title: \"Get TD Python class details\",\n description:\n \"Full documentation for one TouchDesigner Python class (members + methods) from the knowledge base.\",\n inputSchema: getTdClassDetailsSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n (args) => getTdClassDetailsImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getTdClassesSchema = z.object({\n filter: z\n .string()\n .optional()\n .describe(\"Optional case-insensitive substring to filter class names by.\"),\n});\ntype GetTdClassesArgs = z.infer<typeof getTdClassesSchema>;\n\nexport function getTdClassesImpl(ctx: ToolContext, args: GetTdClassesArgs) {\n let classes = ctx.knowledge.listPythonClasses();\n if (args.filter) {\n const needle = args.filter.toLowerCase();\n classes = classes.filter(\n (c) =>\n c.className.toLowerCase().includes(needle) || c.displayName.toLowerCase().includes(needle),\n );\n }\n return structuredResult(`Found ${classes.length} TouchDesigner Python API class(es).`, {\n classes,\n });\n}\n\nexport const registerGetTdClasses: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_classes\",\n {\n title: \"List TD Python classes\",\n description:\n \"List TouchDesigner Python API classes from the embedded knowledge base (works offline). Optionally filter by name.\",\n inputSchema: getTdClassesSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n (args) => getTdClassesImpl(ctx, args),\n );\n};\n","import { friendlyTdError } from \"../../td-client/types.js\";\nimport { jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nconst DESCRIPTION =\n \"Health check + TouchDesigner server info. Returns TD/Python version and bridge status when connected, plus the embedded knowledge-base stats. Use this first to confirm the bridge is reachable.\";\n\nexport async function getTdInfoImpl(ctx: ToolContext) {\n const knowledge = ctx.knowledge.stats();\n try {\n const info = await ctx.client.getInfo();\n return jsonResult(\"TouchDesigner is connected.\", {\n connected: true,\n endpoint: ctx.client.endpoint,\n touchdesigner: info,\n knowledge,\n });\n } catch (err) {\n return jsonResult(\"TouchDesigner is not reachable (the server is still running).\", {\n connected: false,\n endpoint: ctx.client.endpoint,\n reason: friendlyTdError(err),\n knowledge,\n });\n }\n}\n\nexport const registerGetTdInfo: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_info\",\n {\n title: \"Get TouchDesigner info\",\n description: DESCRIPTION,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n () => getTdInfoImpl(ctx),\n );\n};\n","import { z } from \"zod\";\nimport { NodeErrorSchema } from \"../../td-client/validators.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getTdNodeErrorsSchema = z.object({\n path: z.string().describe(\"Full path of the node (or network root) to check for errors.\"),\n recursive: z\n .boolean()\n .default(false)\n .describe(\"If true, check the whole network under `path`; otherwise just that node.\"),\n summary: z\n .boolean()\n .default(false)\n .describe(\"Return only counts grouped by error type instead of the full error list.\"),\n});\ntype GetTdNodeErrorsArgs = z.infer<typeof getTdNodeErrorsSchema>;\n\nexport const getTdNodeErrorsOutputSchema = z.object({\n path: z.string(),\n total: z.number(),\n errors: z.array(NodeErrorSchema).optional(),\n by_type: z.record(z.string(), z.number()).optional(),\n});\n\nexport async function getTdNodeErrorsImpl(ctx: ToolContext, args: GetTdNodeErrorsArgs) {\n return guardTd(\n () =>\n args.recursive ? ctx.client.getNetworkErrors(args.path) : ctx.client.getNodeErrors(args.path),\n (result) => {\n const errors = result.errors;\n const total = errors.length;\n const none = total === 0;\n if (args.summary) {\n const byType: Record<string, number> = {};\n for (const e of errors) {\n const key = e.type || \"error\";\n byType[key] = (byType[key] ?? 0) + 1;\n }\n return structuredResult(\n none ? `No errors found at ${args.path}.` : `${total} error(s) at ${args.path}.`,\n { path: args.path, total, by_type: byType },\n );\n }\n return structuredResult(\n none ? `No errors found at ${args.path}.` : `Found ${total} error(s) at ${args.path}.`,\n { path: args.path, total, errors },\n );\n },\n );\n}\n\nexport const registerGetTdNodeErrors: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_node_errors\",\n {\n title: \"Get node errors\",\n description:\n \"Check a node (or its whole sub-network) for cook/compile errors and warnings. Pass `summary:true` for grouped counts instead of the full list.\",\n inputSchema: getTdNodeErrorsSchema.shape,\n outputSchema: getTdNodeErrorsOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => getTdNodeErrorsImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { NodeDetailSchema } from \"../../td-client/validators.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getTdNodeParametersSchema = z.object({\n path: z.string().describe(\"Full path of the node to inspect.\"),\n keys: z\n .array(z.string())\n .optional()\n .describe(\"Only return these parameter names (case-sensitive). Omit to return all parameters.\"),\n omit_io: z\n .boolean()\n .default(false)\n .describe(\"Drop the inputs/outputs lists from the result to save context.\"),\n});\ntype GetTdNodeParametersArgs = z.infer<typeof getTdNodeParametersSchema>;\n\nexport async function getTdNodeParametersImpl(ctx: ToolContext, args: GetTdNodeParametersArgs) {\n return guardTd(\n () => ctx.client.getNode(args.path),\n (node) => {\n let parameters = node.parameters;\n if (args.keys && args.keys.length > 0) {\n const wanted = new Set(args.keys);\n parameters = Object.fromEntries(\n Object.entries(node.parameters).filter(([k]) => wanted.has(k)),\n );\n }\n const data: Record<string, unknown> = {\n path: node.path,\n type: node.type,\n name: node.name,\n parameters,\n };\n if (!args.omit_io) {\n data.inputs = node.inputs;\n data.outputs = node.outputs;\n }\n const count = Object.keys(parameters).length;\n return structuredResult(`${count} parameter(s) for ${node.path} (${node.type}).`, data);\n },\n );\n}\n\nexport const registerGetTdNodeParameters: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_node_parameters\",\n {\n title: \"Get node parameters\",\n description:\n \"Read the current parameters (and I/O) of a node. Pass `keys` to project specific parameters or `omit_io:true` to drop the inputs/outputs lists.\",\n inputSchema: getTdNodeParametersSchema.shape,\n outputSchema: NodeDetailSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => getTdNodeParametersImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { NodeRefSchema } from \"../../td-client/validators.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { globToRegExp } from \"./nodeMatch.js\";\n\nexport const getTdNodesSchema = z.object({\n parent_path: z\n .string()\n .default(\"/project1\")\n .describe(\"Parent COMP whose direct children should be listed.\"),\n pattern: z\n .string()\n .optional()\n .describe(\n \"Case-insensitive filter on node name/path. Supports '*' wildcards (e.g. 'text*', '*noise*').\",\n ),\n path_only: z\n .boolean()\n .default(false)\n .describe(\"Return only the list of node paths, dropping type/name.\"),\n limit: z.number().int().positive().optional().describe(\"Cap the number of nodes returned.\"),\n detail_level: z\n .enum([\"summary\", \"full\"])\n .default(\"summary\")\n .describe(\n \"'summary' (default) returns a count, a type breakdown and the first few paths; 'full' returns every node. Use 'full' (or path_only) when you need the complete list.\",\n ),\n});\ntype GetTdNodesArgs = z.infer<typeof getTdNodesSchema>;\n\nconst SAMPLE_SIZE = 10;\n\nexport const getTdNodesOutputSchema = z.object({\n parent_path: z.string(),\n count: z.number(),\n detail_level: z.enum([\"summary\", \"full\"]),\n truncated: z.boolean(),\n by_type: z.record(z.string(), z.number()).optional(),\n sample: z.array(z.string()).optional(),\n paths: z.array(z.string()).optional(),\n nodes: z.array(NodeRefSchema).optional(),\n hint: z.string().optional(),\n});\n\nexport async function getTdNodesImpl(ctx: ToolContext, args: GetTdNodesArgs) {\n return guardTd(\n () => ctx.client.getNodes(args.parent_path),\n (list) => {\n let nodes = list.nodes;\n if (args.pattern) {\n const re = globToRegExp(args.pattern);\n nodes = nodes.filter((n) => re.test(n.name) || re.test(n.path));\n }\n const matched = nodes.length;\n const truncated = args.limit !== undefined && matched > args.limit;\n if (args.limit !== undefined) nodes = nodes.slice(0, args.limit);\n const where = args.pattern ? ` matching \"${args.pattern}\"` : \"\";\n const base = {\n parent_path: args.parent_path,\n count: matched,\n detail_level: args.detail_level,\n truncated,\n };\n\n if (args.path_only) {\n return structuredResult(`${matched} node(s) under ${args.parent_path}${where}.`, {\n ...base,\n paths: nodes.map((n) => n.path),\n });\n }\n\n if (args.detail_level === \"summary\") {\n const byType: Record<string, number> = {};\n for (const n of nodes) {\n const key = n.type || \"unknown\";\n byType[key] = (byType[key] ?? 0) + 1;\n }\n const sample = nodes.slice(0, SAMPLE_SIZE).map((n) => n.path);\n return structuredResult(\n `${matched} node(s) under ${args.parent_path}${where}. Summary only — pass detail_level:\"full\" or path_only:true for the full list.`,\n {\n ...base,\n by_type: byType,\n sample,\n ...(matched > sample.length\n ? {\n hint: `Showing first ${sample.length} of ${matched}. Use detail_level:\"full\" for all.`,\n }\n : {}),\n },\n );\n }\n\n return structuredResult(`${matched} node(s) under ${args.parent_path}${where}.`, {\n ...base,\n nodes,\n });\n },\n );\n}\n\nexport const registerGetTdNodes: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_nodes\",\n {\n title: \"List TouchDesigner nodes\",\n description:\n 'List the direct child nodes of a COMP. Defaults to a compact summary (count + type breakdown + sample paths); pass detail_level:\"full\" or path_only:true for the complete list, and `pattern` to filter by name.',\n inputSchema: getTdNodesSchema.shape,\n outputSchema: getTdNodesOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => getTdNodesImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { checkPerformance } from \"../../feedback/performanceMonitor.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getTdPerformanceSchema = z.object({\n root_path: z.string().default(\"/project1\").describe(\"Network root to measure cook times under.\"),\n target_fps: z\n .number()\n .positive()\n .default(60)\n .describe(\"Frame-rate target used to flag slow nodes.\"),\n recursive: z\n .boolean()\n .default(true)\n .describe(\n \"Measure every descendant (true, default) so cook time inside generated containers is counted, not just the root's direct children.\",\n ),\n});\ntype GetTdPerformanceArgs = z.infer<typeof getTdPerformanceSchema>;\n\nexport const getTdPerformanceOutputSchema = z.object({\n path: z.string(),\n targetFps: z.number(),\n frameBudgetMs: z.number(),\n totalCookMs: z.number(),\n nodes: z.array(\n z.object({\n path: z.string(),\n cook_time_ms: z.number(),\n cook_count: z.number().optional(),\n }),\n ),\n warnings: z.array(z.string()),\n});\n\nexport async function getTdPerformanceImpl(ctx: ToolContext, args: GetTdPerformanceArgs) {\n return guardTd(\n () => checkPerformance(ctx.client, args.root_path, args.target_fps, args.recursive),\n (report) =>\n structuredResult(\n report.warnings.length === 0\n ? `Within budget: ${report.totalCookMs.toFixed(2)}ms total under ${args.root_path} (${args.target_fps}fps).`\n : `${report.warnings.length} performance warning(s) under ${args.root_path}.`,\n report,\n ),\n );\n}\n\nexport const registerGetTdPerformance: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_performance\",\n {\n title: \"Get network performance\",\n description:\n \"Report cook times under a network (recursively by default, slowest node first) and warn about nodes that exceed the frame budget.\",\n inputSchema: getTdPerformanceSchema.shape,\n outputSchema: getTdPerformanceOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => getTdPerformanceImpl(ctx, args),\n );\n};\n","import type { TouchDesignerClient } from \"../td-client/touchDesignerClient.js\";\n\nexport interface PerformanceReport {\n path: string;\n targetFps: number;\n frameBudgetMs: number;\n totalCookMs: number;\n nodes: Array<{ path: string; cook_time_ms: number; cook_count?: number }>;\n warnings: string[];\n}\n\n/**\n * Reports cook times against the frame budget implied by `targetFps`. `recursive`\n * measures every descendant (so cook time inside generated containers is counted, not\n * just the root's direct children). Nodes are returned slowest-first.\n */\nexport async function checkPerformance(\n client: TouchDesignerClient,\n path: string,\n targetFps = 60,\n recursive = true,\n): Promise<PerformanceReport> {\n const perf = await client.getNetworkPerformance(path, recursive);\n const frameBudgetMs = 1000 / targetFps;\n const warnings: string[] = [];\n\n for (const node of perf.nodes) {\n if (node.cook_time_ms > frameBudgetMs) {\n warnings.push(\n `${node.path} cooks in ${node.cook_time_ms.toFixed(2)}ms, exceeding the ${frameBudgetMs.toFixed(2)}ms budget at ${targetFps}fps.`,\n );\n }\n }\n\n const totalCookMs =\n perf.total_cook_time_ms ?? perf.nodes.reduce((sum, node) => sum + node.cook_time_ms, 0);\n if (totalCookMs > frameBudgetMs) {\n warnings.push(\n `Total cook time ${totalCookMs.toFixed(2)}ms exceeds the ${frameBudgetMs.toFixed(2)}ms budget at ${targetFps}fps.`,\n );\n }\n\n // Surface the slowest nodes first so the real bottlenecks are obvious.\n const nodes = [...perf.nodes].sort((a, b) => b.cook_time_ms - a.cook_time_ms);\n return { path, targetFps, frameBudgetMs, totalCookMs, nodes, warnings };\n}\n","import { z } from \"zod\";\nimport { verifyNetwork } from \"../../feedback/networkVerifier.js\";\nimport { TopologySchema } from \"../../td-client/validators.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getTdTopologySchema = z.object({\n root_path: z.string().default(\"/project1\").describe(\"Network root to map.\"),\n});\ntype GetTdTopologyArgs = z.infer<typeof getTdTopologySchema>;\n\nexport const getTdTopologyOutputSchema = z.object({\n path: z.string(),\n nodeCount: z.number(),\n connectionCount: z.number(),\n issues: z.array(z.string()),\n topology: TopologySchema,\n});\n\nexport async function getTdTopologyImpl(ctx: ToolContext, args: GetTdTopologyArgs) {\n return guardTd(\n () => verifyNetwork(ctx.client, args.root_path),\n (report) =>\n structuredResult(\n `${report.nodeCount} node(s), ${report.connectionCount} connection(s) under ${args.root_path}.`,\n report,\n ),\n );\n}\n\nexport const registerGetTdTopology: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_topology\",\n {\n title: \"Get network topology\",\n description:\n \"Return the nodes and connections under a network root, flagging obvious structural issues.\",\n inputSchema: getTdTopologySchema.shape,\n outputSchema: getTdTopologyOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => getTdTopologyImpl(ctx, args),\n );\n};\n","import type { TouchDesignerClient } from \"../td-client/touchDesignerClient.js\";\nimport type { TdTopology } from \"../td-client/types.js\";\n\nexport interface VerifyReport {\n path: string;\n nodeCount: number;\n connectionCount: number;\n issues: string[];\n topology: TdTopology;\n}\n\n/** Inspects the topology under `path` and flags obvious structural issues. */\nexport async function verifyNetwork(\n client: TouchDesignerClient,\n path: string,\n): Promise<VerifyReport> {\n const topology = await client.getNetworkTopology(path);\n const issues: string[] = [];\n if (topology.nodes.length === 0) {\n issues.push(`No nodes were found under ${path}.`);\n } else if (topology.nodes.length > 1 && topology.connections.length === 0) {\n issues.push(\"Multiple nodes exist but none are connected.\");\n }\n return {\n path,\n nodeCount: topology.nodes.length,\n connectionCount: topology.connections.length,\n issues,\n topology,\n };\n}\n","import { z } from \"zod\";\nimport { verifyNetwork } from \"../../feedback/networkVerifier.js\";\nimport { ConnectionSchema } from \"../../td-client/validators.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\n/** Cap on per-node parameter fetches so a big graph can't fan out into hundreds of requests. */\nconst MAX_PARAM_NODES = 60;\n\nexport const snapshotTdGraphSchema = z.object({\n path: z.string().default(\"/project1\").describe(\"Network root to snapshot.\"),\n include_params: z\n .boolean()\n .default(false)\n .describe(\"Also fetch each node's parameters (one request per node; capped for large graphs).\"),\n});\ntype SnapshotTdGraphArgs = z.infer<typeof snapshotTdGraphSchema>;\n\nexport const snapshotTdGraphOutputSchema = z.object({\n path: z.string(),\n nodeCount: z.number(),\n connectionCount: z.number(),\n issues: z.array(z.string()),\n params_truncated: z.boolean(),\n nodes: z.array(\n z.object({\n path: z.string(),\n type: z.string(),\n name: z.string(),\n parameters: z.record(z.string(), z.unknown()).optional(),\n }),\n ),\n connections: z.array(ConnectionSchema),\n});\n\nexport async function snapshotTdGraphImpl(ctx: ToolContext, args: SnapshotTdGraphArgs) {\n return guardTd(\n async () => {\n const report = await verifyNetwork(ctx.client, args.path);\n const refs = report.topology.nodes;\n let paramsTruncated = false;\n const params = new Map<string, Record<string, unknown>>();\n if (args.include_params) {\n const targets = refs.slice(0, MAX_PARAM_NODES);\n paramsTruncated = refs.length > MAX_PARAM_NODES;\n // Fail-forward: one unreadable node shouldn't sink the whole snapshot.\n const details = await Promise.allSettled(targets.map((n) => ctx.client.getNode(n.path)));\n for (const detail of details) {\n if (detail.status === \"fulfilled\") params.set(detail.value.path, detail.value.parameters);\n }\n }\n const nodes = refs.map((n) => ({\n path: n.path,\n type: n.type,\n name: n.name,\n ...(args.include_params ? { parameters: params.get(n.path) ?? {} } : {}),\n }));\n return { report, nodes, paramsTruncated };\n },\n ({ report, nodes, paramsTruncated }) =>\n structuredResult(\n `Snapshot of ${args.path}: ${report.nodeCount} node(s), ${report.connectionCount} connection(s)${report.issues.length ? `, ${report.issues.length} issue(s)` : \"\"}.`,\n {\n path: report.path,\n nodeCount: report.nodeCount,\n connectionCount: report.connectionCount,\n issues: report.issues,\n params_truncated: paramsTruncated,\n nodes,\n connections: report.topology.connections,\n },\n ),\n );\n}\n\nexport const registerSnapshotTdGraph: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"snapshot_td_graph\",\n {\n title: \"Snapshot network graph\",\n description:\n \"Capture a compact, serializable snapshot of a network — nodes, connections, structural issues, and optionally each node's parameters — for review, diffing, or documentation.\",\n inputSchema: snapshotTdGraphSchema.shape,\n outputSchema: snapshotTdGraphOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => snapshotTdGraphImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { parentOf } from \"./nodeMatch.js\";\n\nexport const summarizeTdErrorsSchema = z.object({\n path: z.string().default(\"/project1\").describe(\"Network root to collect errors under.\"),\n group_by: z\n .enum([\"message\", \"type\", \"parent\"])\n .default(\"message\")\n .describe(\n \"How to cluster errors: by exact message, by error type, or by parent container (to find a common upstream cause).\",\n ),\n});\ntype SummarizeTdErrorsArgs = z.infer<typeof summarizeTdErrorsSchema>;\n\nexport const summarizeTdErrorsOutputSchema = z.object({\n path: z.string(),\n total: z.number(),\n group_by: z.enum([\"message\", \"type\", \"parent\"]),\n groups: z.array(\n z.object({\n key: z.string(),\n count: z.number(),\n sample: z.object({ path: z.string(), message: z.string() }),\n }),\n ),\n suggestions: z.array(z.string()),\n});\n\nexport async function summarizeTdErrorsImpl(ctx: ToolContext, args: SummarizeTdErrorsArgs) {\n return guardTd(\n () => ctx.client.getNetworkErrors(args.path),\n (result) => {\n const errors = result.errors;\n const total = errors.length;\n if (total === 0) {\n return structuredResult(`No errors found under ${args.path}.`, {\n path: args.path,\n total: 0,\n group_by: args.group_by,\n groups: [],\n suggestions: [],\n });\n }\n\n const keyOf = (e: { path: string; message: string; type?: string }): string =>\n args.group_by === \"message\"\n ? e.message\n : args.group_by === \"type\"\n ? e.type || \"error\"\n : parentOf(e.path);\n\n const grouped = new Map<\n string,\n { count: number; sample: { path: string; message: string } }\n >();\n const byPath = new Map<string, number>();\n for (const e of errors) {\n const key = keyOf(e);\n const g = grouped.get(key);\n if (g) g.count += 1;\n else grouped.set(key, { count: 1, sample: { path: e.path, message: e.message } });\n byPath.set(e.path, (byPath.get(e.path) ?? 0) + 1);\n }\n\n const groups = [...grouped.entries()]\n .map(([key, g]) => ({ key, count: g.count, sample: g.sample }))\n .sort((a, b) => b.count - a.count);\n\n const worstNodes = [...byPath.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 3)\n .map(([p, c]) => `${p} (${c} error${c === 1 ? \"\" : \"s\"})`);\n\n const suggestions: string[] = [];\n if (groups[0] && groups[0].count > 1) {\n suggestions.push(\n `${groups[0].count} errors share ${args.group_by} \"${groups[0].key}\" — fixing the common cause clears them at once.`,\n );\n }\n if (worstNodes.length > 0) {\n suggestions.push(`Check first: ${worstNodes.join(\", \")}.`);\n }\n\n return structuredResult(\n `${total} error(s) under ${args.path} in ${groups.length} ${args.group_by} group(s).`,\n { path: args.path, total, group_by: args.group_by, groups, suggestions },\n );\n },\n );\n}\n\nexport const registerSummarizeTdErrors: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"summarize_td_errors\",\n {\n title: \"Summarize network errors\",\n description:\n \"Collect errors across a network and cluster them by message, type, or parent container, with the worst-offending nodes and a suggested order to investigate. Use this instead of reading every node's errors one by one.\",\n inputSchema: summarizeTdErrorsSchema.shape,\n outputSchema: summarizeTdErrorsOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => summarizeTdErrorsImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const updateTdNodeParametersSchema = z.object({\n path: z.string().describe(\"Full path of the node whose parameters to update.\"),\n parameters: z\n .record(z.string(), z.unknown())\n .describe(\"Parameter overrides as key→value pairs, e.g. { period: 4, amplitude: 0.5 }.\"),\n});\ntype UpdateTdNodeParametersArgs = z.infer<typeof updateTdNodeParametersSchema>;\n\nexport async function updateTdNodeParametersImpl(\n ctx: ToolContext,\n args: UpdateTdNodeParametersArgs,\n) {\n return guardTd(\n () => ctx.client.updateNodeParameters(args.path, args.parameters),\n (node) =>\n jsonResult(`Updated ${Object.keys(args.parameters).length} parameter(s) on ${node.path}.`, {\n node,\n }),\n );\n}\n\nexport const registerUpdateTdNodeParameters: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"update_td_node_parameters\",\n {\n title: \"Update node parameters\",\n description: \"Set one or more parameters on an existing node.\",\n inputSchema: updateTdNodeParametersSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => updateTdNodeParametersImpl(ctx, args),\n );\n};\n"],"mappings":"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","names":["z","existsSync","existsSync","existsSync","readdirSync","readFileSync","join","z","z","existsSync","readdirSync","readFileSync","join","r","z","z","z","z","z","z","z","z","z","z","z","z","z","z","fetch","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","cmd"]}
1
+ {"version":3,"sources":["../../src/cli/agent.ts","../../src/feedback/previewCapture.ts","../../src/knowledge/index.ts","../../src/utils/logger.ts","../../src/utils/paths.ts","../../src/knowledge/normalize.ts","../../src/recipes/loader.ts","../../src/vault/frontmatter.ts","../../src/recipes/schema.ts","../../src/tools/layer2/createControlPanel.ts","../../src/td-client/types.ts","../../src/tools/pythonReport.ts","../../src/tools/result.ts","../../src/recipes/markdown.ts","../../src/vault/index.ts","../../src/td-client/validators.ts","../../src/td-client/touchDesignerClient.ts","../../src/utils/config.ts","../../src/server/connectionManager.ts","../../src/server/context.ts","../../src/td-client/eventStream.ts","../../src/tools/layer1/applyPostProcessing.ts","../../src/feedback/errorChecker.ts","../../src/tools/layer2/connectHelper.ts","../../src/tools/layout.ts","../../src/tools/layer1/orchestration.ts","../../src/tools/layer1/applyRecipe.ts","../../src/tools/layer1/create3dAudioReactive.ts","../../src/tools/layer1/create3dScene.ts","../../src/tools/layer1/createAudioReactive.ts","../../src/tools/layer1/createAutopilot.ts","../../src/tools/layer1/createColorGrade.ts","../../src/tools/layer1/createDataVisualization.ts","../../src/tools/layer1/createDepthDisplacement.ts","../../src/tools/layer1/createDepthSilhouette.ts","../../src/tools/layer1/createDomeOutput.ts","../../src/tools/layer1/createFeedbackNetwork.ts","../../src/tools/layer1/createGenerativeArt.ts","../../src/tools/layer1/createGlitch.ts","../../src/tools/layer1/createGpuParticleField.ts","../../src/tools/layer1/createKaleidoscope.ts","../../src/tools/layer1/createKeyframeAnimation.ts","../../src/tools/layer1/createKineticText.ts","../../src/tools/layer1/createLayerMixer.ts","../../src/tools/layer1/createMeshWarp.ts","../../src/tools/layer1/createMotionReactive.ts","../../src/tools/layer1/createMultiOutput.ts","../../src/tools/layer1/createParticleSystem.ts","../../src/tools/layer1/createProjectionMapping.ts","../../src/tools/layer1/createShaderLib.ts","../../src/tools/layer1/createSimulation.ts","../../src/tools/layer1/createSpectrum.ts","../../src/tools/layer1/createStrobe.ts","../../src/tools/layer1/createSyncExternalClock.ts","../../src/tools/layer1/createTempoSync.ts","../../src/tools/layer1/createTextOverlay.ts","../../src/tools/layer1/createVideoPlayer.ts","../../src/tools/layer1/createVideoSynth.ts","../../src/tools/layer1/createVisualSystem.ts","../../src/tools/layer1/intent.ts","../../src/tools/layer1/createWaveform.ts","../../src/tools/layer1/describeProject.ts","../../src/tools/layer1/detectOnsets.ts","../../src/tools/layer1/detectPitch.ts","../../src/tools/layer1/extractAudioFeatures.ts","../../src/tools/layer1/getPreview.ts","../../src/tools/layer1/importModel.ts","../../src/tools/layer1/listRecipes.ts","../../src/tools/layer1/scaffoldShow.ts","../../src/tools/layer1/setupOutput.ts","../../src/tools/layer2/animateParameter.ts","../../src/tools/layer2/arrangeNetwork.ts","../../src/tools/layer2/bindToChannel.ts","../../src/tools/layer2/connectNodes.ts","../../src/tools/layer2/createClipLauncher.ts","../../src/tools/layer2/manageCue.ts","../../src/tools/layer2/createContainer.ts","../../src/tools/layer2/createControlSurface.ts","../../src/tools/layer2/createDecks.ts","../../src/tools/layer2/createExternalIo.ts","../../src/tools/layer2/createGlslShader.ts","../../src/tools/layer2/createMacro.ts","../../src/tools/layer2/createNodeChain.ts","../../src/tools/layer2/createPanic.ts","../../src/tools/layer2/createPhoneRemote.ts","../../src/tools/layer2/createPythonScript.ts","../../src/tools/layer2/duplicateNetwork.ts","../../src/tools/layer2/learnControl.ts","../../src/tools/layer2/manageCheckpoint.ts","../../src/tools/layer2/manageComponent.ts","../../src/tools/layer2/managePresets.ts","../../src/tools/layer2/randomizeControls.ts","../../src/tools/layer2/setParametersBatch.ts","../../src/tools/layer3/compareTdNodes.ts","../../src/tools/layer3/createTdNode.ts","../../src/tools/layer3/deleteTdNode.ts","../../src/tools/layer3/diffSnapshots.ts","../../src/tools/layer3/documentNetwork.ts","../../src/tools/layer3/execNodeMethod.ts","../../src/tools/layer3/executePythonScript.ts","../../src/tools/layer3/findTdNodes.ts","../../src/tools/layer3/nodeMatch.ts","../../src/tools/layer3/getModuleHelp.ts","../../src/tools/layer3/getTdClassDetails.ts","../../src/tools/layer3/getTdClasses.ts","../../src/tools/layer3/getTdInfo.ts","../../src/tools/layer3/getTdNodeErrors.ts","../../src/tools/layer3/getTdNodeParameters.ts","../../src/tools/layer3/getTdNodes.ts","../../src/tools/layer3/getTdPerformance.ts","../../src/feedback/performanceMonitor.ts","../../src/tools/layer3/getTdTopology.ts","../../src/feedback/networkVerifier.ts","../../src/tools/layer3/optimizePerformance.ts","../../src/tools/layer3/recordMovie.ts","../../src/tools/layer3/reloadBridge.ts","../../src/tools/layer3/renderOutput.ts","../../src/tools/layer3/searchOperators.ts","../../src/knowledge/embeddings.ts","../../src/tools/layer3/snapshotTdGraph.ts","../../src/tools/layer3/summarizeTdErrors.ts","../../src/tools/layer3/updateTdNodeParameters.ts","../../src/cli/doctor.ts","../../src/llm/client.ts"],"sourcesContent":["import { writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { pathToFileURL } from \"node:url\";\nimport { parseArgs } from \"node:util\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport { capturePreview } from \"../feedback/previewCapture.js\";\nimport { buildToolContext } from \"../server/context.js\";\nimport { type TdEventHandler, TdEventStream } from \"../td-client/eventStream.js\";\nimport { friendlyTdError } from \"../td-client/types.js\";\nimport {\n applyPostProcessingImpl,\n applyPostProcessingSchema,\n} from \"../tools/layer1/applyPostProcessing.js\";\nimport { applyRecipeImpl, applyRecipeSchema } from \"../tools/layer1/applyRecipe.js\";\nimport {\n create3dAudioReactiveImpl,\n create3dAudioReactiveSchema,\n} from \"../tools/layer1/create3dAudioReactive.js\";\nimport { create3dSceneImpl, create3dSceneSchema } from \"../tools/layer1/create3dScene.js\";\nimport {\n createAudioReactiveImpl,\n createAudioReactiveSchema,\n} from \"../tools/layer1/createAudioReactive.js\";\nimport { createAutopilotImpl, createAutopilotSchema } from \"../tools/layer1/createAutopilot.js\";\nimport { createColorGradeImpl, createColorGradeSchema } from \"../tools/layer1/createColorGrade.js\";\nimport {\n createDataVisualizationImpl,\n createDataVisualizationSchema,\n} from \"../tools/layer1/createDataVisualization.js\";\nimport {\n createDepthDisplacementImpl,\n createDepthDisplacementSchema,\n} from \"../tools/layer1/createDepthDisplacement.js\";\nimport {\n createDepthSilhouetteImpl,\n createDepthSilhouetteSchema,\n} from \"../tools/layer1/createDepthSilhouette.js\";\nimport { createDomeOutputImpl, createDomeOutputSchema } from \"../tools/layer1/createDomeOutput.js\";\nimport {\n createFeedbackNetworkImpl,\n createFeedbackNetworkSchema,\n} from \"../tools/layer1/createFeedbackNetwork.js\";\nimport {\n createGenerativeArtImpl,\n createGenerativeArtSchema,\n} from \"../tools/layer1/createGenerativeArt.js\";\nimport { createGlitchImpl, createGlitchSchema } from \"../tools/layer1/createGlitch.js\";\nimport {\n createGpuParticleFieldImpl,\n createGpuParticleFieldSchema,\n} from \"../tools/layer1/createGpuParticleField.js\";\nimport {\n createKaleidoscopeImpl,\n createKaleidoscopeSchema,\n} from \"../tools/layer1/createKaleidoscope.js\";\nimport {\n createKeyframeAnimationImpl,\n createKeyframeAnimationSchema,\n} from \"../tools/layer1/createKeyframeAnimation.js\";\nimport {\n createKineticTextImpl,\n createKineticTextSchema,\n} from \"../tools/layer1/createKineticText.js\";\nimport { createLayerMixerImpl, createLayerMixerSchema } from \"../tools/layer1/createLayerMixer.js\";\nimport { createMeshWarpImpl, createMeshWarpSchema } from \"../tools/layer1/createMeshWarp.js\";\nimport {\n createMotionReactiveImpl,\n createMotionReactiveSchema,\n} from \"../tools/layer1/createMotionReactive.js\";\nimport {\n createMultiOutputImpl,\n createMultiOutputSchema,\n} from \"../tools/layer1/createMultiOutput.js\";\nimport {\n createParticleSystemImpl,\n createParticleSystemSchema,\n} from \"../tools/layer1/createParticleSystem.js\";\nimport {\n createProjectionMappingImpl,\n createProjectionMappingSchema,\n} from \"../tools/layer1/createProjectionMapping.js\";\nimport { createShaderLibImpl, createShaderLibSchema } from \"../tools/layer1/createShaderLib.js\";\nimport { createSimulationImpl, createSimulationSchema } from \"../tools/layer1/createSimulation.js\";\nimport { createSpectrumImpl, createSpectrumSchema } from \"../tools/layer1/createSpectrum.js\";\nimport { createStrobeImpl, createStrobeSchema } from \"../tools/layer1/createStrobe.js\";\nimport {\n createSyncExternalClockImpl,\n createSyncExternalClockSchema,\n} from \"../tools/layer1/createSyncExternalClock.js\";\nimport { createTempoSyncImpl, createTempoSyncSchema } from \"../tools/layer1/createTempoSync.js\";\nimport {\n createTextOverlayImpl,\n createTextOverlaySchema,\n} from \"../tools/layer1/createTextOverlay.js\";\nimport {\n createVideoPlayerImpl,\n createVideoPlayerSchema,\n} from \"../tools/layer1/createVideoPlayer.js\";\nimport { createVideoSynthImpl, createVideoSynthSchema } from \"../tools/layer1/createVideoSynth.js\";\nimport {\n createVisualSystemImpl,\n createVisualSystemSchema,\n} from \"../tools/layer1/createVisualSystem.js\";\nimport { createWaveformImpl, createWaveformSchema } from \"../tools/layer1/createWaveform.js\";\nimport { describeProjectImpl, describeProjectSchema } from \"../tools/layer1/describeProject.js\";\nimport { detectOnsetsImpl, detectOnsetsSchema } from \"../tools/layer1/detectOnsets.js\";\nimport { detectPitchImpl, detectPitchSchema } from \"../tools/layer1/detectPitch.js\";\nimport {\n extractAudioFeaturesImpl,\n extractAudioFeaturesSchema,\n} from \"../tools/layer1/extractAudioFeatures.js\";\nimport { getPreviewSchema } from \"../tools/layer1/getPreview.js\";\nimport { importModelImpl, importModelSchema } from \"../tools/layer1/importModel.js\";\nimport { listRecipesImpl, listRecipesSchema } from \"../tools/layer1/listRecipes.js\";\nimport { scaffoldShowImpl, scaffoldShowSchema } from \"../tools/layer1/scaffoldShow.js\";\nimport { setupOutputImpl, setupOutputSchema } from \"../tools/layer1/setupOutput.js\";\nimport { animateParameterImpl, animateParameterSchema } from \"../tools/layer2/animateParameter.js\";\nimport { arrangeNetworkImpl, arrangeNetworkSchema } from \"../tools/layer2/arrangeNetwork.js\";\nimport { bindToChannelImpl, bindToChannelSchema } from \"../tools/layer2/bindToChannel.js\";\nimport { connectNodesImpl, connectNodesSchema } from \"../tools/layer2/connectNodes.js\";\nimport {\n createClipLauncherImpl,\n createClipLauncherSchema,\n} from \"../tools/layer2/createClipLauncher.js\";\nimport { createContainerImpl, createContainerSchema } from \"../tools/layer2/createContainer.js\";\nimport {\n createControlPanelImpl,\n createControlPanelSchema,\n} from \"../tools/layer2/createControlPanel.js\";\nimport {\n createControlSurfaceImpl,\n createControlSurfaceSchema,\n} from \"../tools/layer2/createControlSurface.js\";\nimport { createDecksImpl, createDecksSchema } from \"../tools/layer2/createDecks.js\";\nimport { createExternalIoImpl, createExternalIoSchema } from \"../tools/layer2/createExternalIo.js\";\nimport { createGlslShaderImpl, createGlslShaderSchema } from \"../tools/layer2/createGlslShader.js\";\nimport { createMacroImpl, createMacroSchema } from \"../tools/layer2/createMacro.js\";\nimport { createNodeChainImpl, createNodeChainSchema } from \"../tools/layer2/createNodeChain.js\";\nimport { createPanicImpl, createPanicSchema } from \"../tools/layer2/createPanic.js\";\nimport {\n createPhoneRemoteImpl,\n createPhoneRemoteSchema,\n} from \"../tools/layer2/createPhoneRemote.js\";\nimport {\n createPythonScriptImpl,\n createPythonScriptSchema,\n} from \"../tools/layer2/createPythonScript.js\";\nimport { duplicateNetworkImpl, duplicateNetworkSchema } from \"../tools/layer2/duplicateNetwork.js\";\nimport { learnControlImpl, learnControlSchema } from \"../tools/layer2/learnControl.js\";\nimport { manageCheckpointImpl, manageCheckpointSchema } from \"../tools/layer2/manageCheckpoint.js\";\nimport { manageComponentImpl, manageComponentSchema } from \"../tools/layer2/manageComponent.js\";\nimport { manageCueImpl, manageCueSchema } from \"../tools/layer2/manageCue.js\";\nimport { managePresetsImpl, managePresetsSchema } from \"../tools/layer2/managePresets.js\";\nimport {\n randomizeControlsImpl,\n randomizeControlsSchema,\n} from \"../tools/layer2/randomizeControls.js\";\nimport {\n setParametersBatchImpl,\n setParametersBatchSchema,\n} from \"../tools/layer2/setParametersBatch.js\";\nimport { compareTdNodesImpl, compareTdNodesSchema } from \"../tools/layer3/compareTdNodes.js\";\nimport { createTdNodeImpl, createTdNodeSchema } from \"../tools/layer3/createTdNode.js\";\nimport { deleteTdNodeImpl, deleteTdNodeSchema } from \"../tools/layer3/deleteTdNode.js\";\nimport { diffSnapshotsImpl, diffSnapshotsSchema } from \"../tools/layer3/diffSnapshots.js\";\nimport { documentNetworkImpl, documentNetworkSchema } from \"../tools/layer3/documentNetwork.js\";\nimport { execNodeMethodImpl, execNodeMethodSchema } from \"../tools/layer3/execNodeMethod.js\";\nimport {\n executePythonScriptImpl,\n executePythonScriptSchema,\n} from \"../tools/layer3/executePythonScript.js\";\nimport { findTdNodesImpl, findTdNodesSchema } from \"../tools/layer3/findTdNodes.js\";\nimport { getModuleHelpImpl, getModuleHelpSchema } from \"../tools/layer3/getModuleHelp.js\";\nimport {\n getTdClassDetailsImpl,\n getTdClassDetailsSchema,\n} from \"../tools/layer3/getTdClassDetails.js\";\nimport { getTdClassesImpl, getTdClassesSchema } from \"../tools/layer3/getTdClasses.js\";\nimport { getTdInfoImpl } from \"../tools/layer3/getTdInfo.js\";\nimport { getTdNodeErrorsImpl, getTdNodeErrorsSchema } from \"../tools/layer3/getTdNodeErrors.js\";\nimport {\n getTdNodeParametersImpl,\n getTdNodeParametersSchema,\n} from \"../tools/layer3/getTdNodeParameters.js\";\nimport { getTdNodesImpl, getTdNodesSchema } from \"../tools/layer3/getTdNodes.js\";\nimport { getTdPerformanceImpl, getTdPerformanceSchema } from \"../tools/layer3/getTdPerformance.js\";\nimport { getTdTopologyImpl, getTdTopologySchema } from \"../tools/layer3/getTdTopology.js\";\nimport {\n optimizePerformanceImpl,\n optimizePerformanceSchema,\n} from \"../tools/layer3/optimizePerformance.js\";\nimport { recordMovieImpl, recordMovieSchema } from \"../tools/layer3/recordMovie.js\";\nimport { reloadBridgeImpl, reloadBridgeSchema } from \"../tools/layer3/reloadBridge.js\";\nimport { renderOutputImpl, renderOutputSchema } from \"../tools/layer3/renderOutput.js\";\nimport { searchOperatorsImpl, searchOperatorsSchema } from \"../tools/layer3/searchOperators.js\";\nimport { snapshotTdGraphImpl, snapshotTdGraphSchema } from \"../tools/layer3/snapshotTdGraph.js\";\nimport {\n summarizeTdErrorsImpl,\n summarizeTdErrorsSchema,\n} from \"../tools/layer3/summarizeTdErrors.js\";\nimport {\n updateTdNodeParametersImpl,\n updateTdNodeParametersSchema,\n} from \"../tools/layer3/updateTdNodeParameters.js\";\nimport type { ToolContext } from \"../tools/types.js\";\nimport { loadConfig, type TdmcpConfig, tdBaseUrl } from \"../utils/config.js\";\nimport { silentLogger } from \"../utils/logger.js\";\nimport { runDoctor } from \"./doctor.js\";\n\n// biome-ignore lint/suspicious/noExplicitAny: args are validated by each command's zod schema before use.\ntype Runner = (ctx: ToolContext, args: any) => CallToolResult | Promise<CallToolResult>;\n\ninterface Command {\n schema: z.ZodTypeAny;\n run: Runner;\n summary: string;\n mutates: boolean;\n unsafe: boolean;\n}\n\nconst r = (\n schema: z.ZodTypeAny,\n run: Runner,\n summary: string,\n opts: { mutates?: boolean; unsafe?: boolean } = {},\n): Command => ({ schema, run, summary, mutates: !!opts.mutates, unsafe: !!opts.unsafe });\n\n/** Static command tree — each entry maps 1:1 onto an existing MCP tool handler. */\nconst COMMANDS: Record<string, Command> = {\n info: r(z.object({}), (ctx) => getTdInfoImpl(ctx), \"Health check + TD/bridge info.\"),\n reload: r(\n reloadBridgeSchema,\n reloadBridgeImpl,\n \"Hot-reload the bridge's Python after editing td/.\",\n ),\n \"nodes list\": r(\n getTdNodesSchema,\n getTdNodesImpl,\n \"List a COMP's child nodes (summary by default).\",\n ),\n \"nodes find\": r(findTdNodesSchema, findTdNodesImpl, \"Search nodes by name pattern and/or type.\"),\n \"nodes get\": r(getTdNodeParametersSchema, getTdNodeParametersImpl, \"Read a node's parameters.\"),\n \"nodes errors\": r(getTdNodeErrorsSchema, getTdNodeErrorsImpl, \"Check a node/network for errors.\"),\n \"nodes compare\": r(compareTdNodesSchema, compareTdNodesImpl, \"Diff two nodes' parameters.\"),\n \"nodes snapshot\": r(snapshotTdGraphSchema, snapshotTdGraphImpl, \"Capture a network snapshot.\"),\n \"nodes topology\": r(getTdTopologySchema, getTdTopologyImpl, \"Map nodes + connections.\"),\n \"nodes performance\": r(getTdPerformanceSchema, getTdPerformanceImpl, \"Report cook times.\"),\n \"nodes update\": r(\n updateTdNodeParametersSchema,\n updateTdNodeParametersImpl,\n \"Set node parameters.\",\n { mutates: true },\n ),\n \"nodes create\": r(createTdNodeSchema, createTdNodeImpl, \"Create an operator.\", { mutates: true }),\n \"nodes delete\": r(deleteTdNodeSchema, deleteTdNodeImpl, \"Delete a node.\", { mutates: true }),\n \"errors summarize\": r(\n summarizeTdErrorsSchema,\n summarizeTdErrorsImpl,\n \"Cluster network errors by cause.\",\n ),\n \"classes list\": r(getTdClassesSchema, getTdClassesImpl, \"List TD Python API classes (offline).\"),\n \"classes get\": r(\n getTdClassDetailsSchema,\n getTdClassDetailsImpl,\n \"Get one Python class (offline).\",\n ),\n \"module help\": r(\n getModuleHelpSchema,\n getModuleHelpImpl,\n \"Human-readable help for a class (offline).\",\n ),\n operators: r(\n searchOperatorsSchema,\n searchOperatorsImpl,\n \"Search the operator knowledge base by keyword (offline).\",\n ),\n document: r(\n documentNetworkSchema,\n documentNetworkImpl,\n \"Document a network (summary + mermaid).\",\n ),\n diff: r(diffSnapshotsSchema, diffSnapshotsImpl, \"Diff two network snapshots (offline).\"),\n optimize: r(\n optimizePerformanceSchema,\n optimizePerformanceImpl,\n \"Find (and optionally fix) cook-time bottlenecks.\",\n { mutates: true },\n ),\n render: r(renderOutputSchema, renderOutputImpl, \"Save a TOP to a file at full resolution.\"),\n movie: r(recordMovieSchema, recordMovieImpl, \"Record a TOP to a movie/sequence (start/stop).\", {\n mutates: true,\n }),\n recipes: r(listRecipesSchema, listRecipesImpl, \"List the built-in recipe library (offline).\"),\n recipe: r(applyRecipeSchema, applyRecipeImpl, \"Build a recipe by id.\", { mutates: true }),\n init: r(\n scaffoldShowSchema,\n scaffoldShowImpl,\n \"Scaffold a show skeleton (master output + beat clock).\",\n {\n mutates: true,\n },\n ),\n \"exec python\": r(\n executePythonScriptSchema,\n executePythonScriptImpl,\n \"Escape hatch: run arbitrary Python in TD.\",\n { mutates: true, unsafe: true },\n ),\n \"exec node-method\": r(\n execNodeMethodSchema,\n execNodeMethodImpl,\n \"Escape hatch: call a Python method on a node.\",\n { mutates: true, unsafe: true },\n ),\n // Layer 1 — high-level generators (each builds a whole network, verifies, previews).\n visual: r(\n createVisualSystemSchema,\n createVisualSystemImpl,\n \"Build a visual system from a description.\",\n { mutates: true },\n ),\n feedback: r(createFeedbackNetworkSchema, createFeedbackNetworkImpl, \"Build a feedback network.\", {\n mutates: true,\n }),\n generative: r(\n createGenerativeArtSchema,\n createGenerativeArtImpl,\n \"Build a generative-art system.\",\n { mutates: true },\n ),\n particles: r(createParticleSystemSchema, createParticleSystemImpl, \"Build a particle system.\", {\n mutates: true,\n }),\n \"audio-reactive\": r(\n createAudioReactiveSchema,\n createAudioReactiveImpl,\n \"Build an audio-reactive visual.\",\n { mutates: true },\n ),\n \"audio-features\": r(\n extractAudioFeaturesSchema,\n extractAudioFeaturesImpl,\n \"Extract reactive channels (level/bass/mid/treble) to bind to params.\",\n { mutates: true },\n ),\n \"motion-reactive\": r(\n createMotionReactiveSchema,\n createMotionReactiveImpl,\n \"Extract camera reactive channels (brightness/motion) to bind to params.\",\n { mutates: true },\n ),\n \"tempo-sync\": r(\n createTempoSyncSchema,\n createTempoSyncImpl,\n \"Create a beat clock (ramp/pulse/beat/bar/bpm) + optional beat events.\",\n { mutates: true },\n ),\n \"clock-sync\": r(\n createSyncExternalClockSchema,\n createSyncExternalClockImpl,\n \"Drive the global tempo from a Bpm knob + tap-tempo (beat-match the DJ).\",\n { mutates: true },\n ),\n dataviz: r(\n createDataVisualizationSchema,\n createDataVisualizationImpl,\n \"Build a data visualization.\",\n { mutates: true },\n ),\n mixer: r(\n createLayerMixerSchema,\n createLayerMixerImpl,\n \"Build a VJ layer mixer (crossfade/blend).\",\n {\n mutates: true,\n },\n ),\n video: r(\n createVideoPlayerSchema,\n createVideoPlayerImpl,\n \"Build a movie/clip player (+playlist).\",\n {\n mutates: true,\n },\n ),\n scene3d: r(create3dSceneSchema, create3dSceneImpl, \"Build a renderable 3D scene.\", {\n mutates: true,\n }),\n // Phase 12 — dimensional (3D, depth & spatial mapping):\n audio3d: r(\n create3dAudioReactiveSchema,\n create3dAudioReactiveImpl,\n \"Build a 3D scene that reacts to sound (instanced FFT bars / bass pulse).\",\n { mutates: true },\n ),\n dome: r(\n createDomeOutputSchema,\n createDomeOutputImpl,\n \"Remap a source to fisheye/equirectangular for dome / 360 output.\",\n { mutates: true },\n ),\n \"mesh-warp\": r(\n createMeshWarpSchema,\n createMeshWarpImpl,\n \"Map a source onto a deformable curved grid (dome/column/sculpture).\",\n { mutates: true },\n ),\n \"depth-displace\": r(\n createDepthDisplacementSchema,\n createDepthDisplacementImpl,\n \"Displace a plane into 3D by a depth/luminance map (2.5D relief).\",\n { mutates: true },\n ),\n \"gpu-particles\": r(\n createGpuParticleFieldSchema,\n createGpuParticleFieldImpl,\n \"GPU particle field via feedback TOPs + instancing (experimental).\",\n { mutates: true },\n ),\n text: r(\n createTextOverlaySchema,\n createTextOverlayImpl,\n \"Composite styled text over a visual (lyrics/titles/credits).\",\n { mutates: true },\n ),\n mapping: r(\n createProjectionMappingSchema,\n createProjectionMappingImpl,\n \"Wrap a source in a corner-pin for projection mapping.\",\n { mutates: true },\n ),\n keyframe: r(\n createKeyframeAnimationSchema,\n createKeyframeAnimationImpl,\n \"Animate parameters along a keyframed curve (synced/looping).\",\n { mutates: true },\n ),\n simulation: r(\n createSimulationSchema,\n createSimulationImpl,\n \"Build a GPU simulation (RD/slime/fluid).\",\n {\n mutates: true,\n },\n ),\n \"post-fx\": r(\n applyPostProcessingSchema,\n applyPostProcessingImpl,\n \"Apply post-processing (bloom/blur/…).\",\n { mutates: true },\n ),\n output: r(setupOutputSchema, setupOutputImpl, \"Set up a window / NDI / Syphon-Spout output.\", {\n mutates: true,\n }),\n \"multi-output\": r(\n createMultiOutputSchema,\n createMultiOutputImpl,\n \"Fan a master TOP across N projectors (cropped tiles + optional windows).\",\n { mutates: true },\n ),\n plan: r(\n describeProjectSchema,\n describeProjectImpl,\n \"Plan which tool/recipe builds a described visual (creates nothing).\",\n ),\n // Layer 2 — building blocks.\n animate: r(animateParameterSchema, animateParameterImpl, \"Drive parameters with an LFO.\", {\n mutates: true,\n }),\n bind: r(\n bindToChannelSchema,\n bindToChannelImpl,\n \"Bind parameters to a CHOP channel (audio feature / beat) by expression.\",\n { mutates: true },\n ),\n arrange: r(arrangeNetworkSchema, arrangeNetworkImpl, \"Auto-arrange a network left→right.\", {\n mutates: true,\n }),\n connect: r(connectNodesSchema, connectNodesImpl, \"Wire two nodes together.\", { mutates: true }),\n container: r(createContainerSchema, createContainerImpl, \"Create a COMP container.\", {\n mutates: true,\n }),\n \"control-panel\": r(\n createControlPanelSchema,\n createControlPanelImpl,\n \"Add bound custom-parameter controls to a COMP.\",\n { mutates: true },\n ),\n surface: r(\n createControlSurfaceSchema,\n createControlSurfaceImpl,\n \"Build a playable panel: faders + cue buttons.\",\n { mutates: true },\n ),\n remote: r(\n createPhoneRemoteSchema,\n createPhoneRemoteImpl,\n \"Serve a phone web panel for a COMP's controls.\",\n { mutates: true },\n ),\n io: r(\n createExternalIoSchema,\n createExternalIoImpl,\n \"Bridge OSC/MIDI in, DMX out, NDI/Syphon in.\",\n {\n mutates: true,\n },\n ),\n glsl: r(createGlslShaderSchema, createGlslShaderImpl, \"Create a GLSL TOP shader.\", {\n mutates: true,\n }),\n chain: r(createNodeChainSchema, createNodeChainImpl, \"Create a chain of connected nodes.\", {\n mutates: true,\n }),\n script: r(\n createPythonScriptSchema,\n createPythonScriptImpl,\n \"Create a DAT preloaded with Python.\",\n {\n mutates: true,\n },\n ),\n duplicate: r(duplicateNetworkSchema, duplicateNetworkImpl, \"Duplicate a network.\", {\n mutates: true,\n }),\n component: r(manageComponentSchema, manageComponentImpl, \"Save/load a COMP as a .tox.\", {\n mutates: true,\n }),\n checkpoint: r(\n manageCheckpointSchema,\n manageCheckpointImpl,\n \"Store/restore a full sub-network snapshot (undo point).\",\n { mutates: true },\n ),\n preset: r(managePresetsSchema, managePresetsImpl, \"Store/recall/list/delete COMP presets.\", {\n mutates: true,\n }),\n cue: r(\n manageCueSchema,\n manageCueImpl,\n \"Scene system: store/recall/morph/list/delete cues (timed crossfade).\",\n { mutates: true },\n ),\n macro: r(createMacroSchema, createMacroImpl, \"Add one knob that drives many parameters.\", {\n mutates: true,\n }),\n randomize: r(\n randomizeControlsSchema,\n randomizeControlsImpl,\n \"Randomize a COMP's numeric controls within range.\",\n { mutates: true },\n ),\n autopilot: r(\n createAutopilotSchema,\n createAutopilotImpl,\n \"Beat-driven auto-VJ: every N beats randomize controls or cycle cues.\",\n { mutates: true },\n ),\n params: r(\n setParametersBatchSchema,\n setParametersBatchImpl,\n \"Set many parameters across nodes at once.\",\n { mutates: true },\n ),\n // Signature effects, deeper reactivity, creation, live control (waves 1–5).\n strobe: r(createStrobeSchema, createStrobeImpl, \"Build a beat-syncable strobe/flash layer.\", {\n mutates: true,\n }),\n kaleidoscope: r(\n createKaleidoscopeSchema,\n createKaleidoscopeImpl,\n \"Wrap a source in an N-fold kaleidoscope (radial mirror).\",\n { mutates: true },\n ),\n glitch: r(\n createGlitchSchema,\n createGlitchImpl,\n \"Apply a glitch look (RGB-shift + noise displacement).\",\n { mutates: true },\n ),\n spectrum: r(\n createSpectrumSchema,\n createSpectrumImpl,\n \"Extract an N-band FFT spectrum to bind per-band.\",\n { mutates: true },\n ),\n onsets: r(\n detectOnsetsSchema,\n detectOnsetsImpl,\n \"Detect kick/snare/hat onsets (per-band pulse + optional events).\",\n { mutates: true },\n ),\n waveform: r(\n createWaveformSchema,\n createWaveformImpl,\n \"Render a time-domain audio oscilloscope/waveform.\",\n { mutates: true },\n ),\n colorgrade: r(\n createColorGradeSchema,\n createColorGradeImpl,\n \"Color-grade a source (lift/gamma/gain + saturation/hue + LUT).\",\n { mutates: true },\n ),\n model: r(importModelSchema, importModelImpl, \"Import a 3D model file and render it.\", {\n mutates: true,\n }),\n shaderlib: r(\n createShaderLibSchema,\n createShaderLibImpl,\n \"Instantiate a curated GLSL shader (tunnel/raymarch/fractal/…).\",\n { mutates: true },\n ),\n videosynth: r(\n createVideoSynthSchema,\n createVideoSynthImpl,\n \"Analog video-synth patterns (lissajous/interference/scanlines).\",\n { mutates: true },\n ),\n silhouette: r(\n createDepthSilhouetteSchema,\n createDepthSilhouetteImpl,\n \"Extract a silhouette/body mask from a depth or video source.\",\n { mutates: true },\n ),\n kinetictext: r(\n createKineticTextSchema,\n createKineticTextImpl,\n \"Animated/beat-flashed kinetic typography (lyric flashes).\",\n { mutates: true },\n ),\n panic: r(\n createPanicSchema,\n createPanicImpl,\n \"Live safety: instant Blackout + Freeze over an output.\",\n { mutates: true },\n ),\n launcher: r(\n createClipLauncherSchema,\n createClipLauncherImpl,\n \"Build an Ableton-style grid of cue-trigger buttons.\",\n { mutates: true },\n ),\n decks: r(\n createDecksSchema,\n createDecksImpl,\n \"Build DJ-style A/B decks with a master crossfader.\",\n { mutates: true },\n ),\n pitch: r(\n detectPitchSchema,\n detectPitchImpl,\n \"Detect monophonic pitch (Hz/note) from the FFT (experimental).\",\n { mutates: true },\n ),\n learn: r(\n learnControlSchema,\n learnControlImpl,\n \"MIDI/OSC learn: snapshot an input CHOP, then bind the moved control (experimental).\",\n { mutates: true },\n ),\n};\n\nexport interface CliResult {\n stdout: string;\n stderr: string;\n code: number;\n}\n\nfunction textOf(result: CallToolResult): string {\n return result.content\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\\n\");\n}\n\n/** Prefer the structured channel; fall back to a JSON code-fence, then to the raw text. */\nfunction extractData(result: CallToolResult): unknown {\n if (result.structuredContent !== undefined) return result.structuredContent;\n const text = textOf(result);\n const fence = text.match(/```json\\n([\\s\\S]*?)\\n```/);\n if (fence) {\n try {\n return JSON.parse(fence[1] as string);\n } catch {\n // fall through\n }\n }\n return { message: text };\n}\n\nfunction firstArray(data: unknown): unknown[] | null {\n if (Array.isArray(data)) return data;\n if (data && typeof data === \"object\") {\n for (const value of Object.values(data)) if (Array.isArray(value)) return value;\n }\n return null;\n}\n\nfunction resolveCommand(positionals: string[]): { key: string; cmd: Command } | undefined {\n const key2 = positionals.slice(0, 2).join(\" \");\n if (COMMANDS[key2]) return { key: key2, cmd: COMMANDS[key2] };\n const key1 = positionals[0] ?? \"\";\n if (COMMANDS[key1]) return { key: key1, cmd: COMMANDS[key1] };\n return undefined;\n}\n\nfunction usage(): string {\n const lines = [\"tdmcp-agent — drive TouchDesigner from a shell (machine-readable output).\", \"\"];\n lines.push(\"Usage: tdmcp-agent <command> [--params '<json>'] [--json '<json>'] [flags]\", \"\");\n lines.push(\"Flags:\");\n lines.push(\n \" --params <json> Arguments object (validated against the command's input schema).\",\n );\n lines.push(\" --json <json> Merged into --params (e.g. for request bodies).\");\n lines.push(\" --output <fmt> json (default) | ndjson | text.\");\n lines.push(\" --dry-run Validate and print the intended call without executing.\");\n lines.push(\" --allow-unsafe Required for `exec` escape-hatch commands.\");\n lines.push(\" -o, --out <file> (preview) Output PNG path. Defaults to ./preview.png.\");\n lines.push(\" --include-high-frequency (watch) Also stream timeline.frame / node.cook events.\");\n lines.push(\" -h, --help Show this help.\", \"\");\n lines.push(\"Commands:\");\n for (const [key, cmd] of Object.entries(COMMANDS)) {\n const tags = [cmd.mutates ? \"mutates\" : \"\", cmd.unsafe ? \"unsafe\" : \"\"]\n .filter(Boolean)\n .join(\",\");\n lines.push(` ${key.padEnd(20)} ${cmd.summary}${tags ? ` [${tags}]` : \"\"}`);\n }\n lines.push(\" schema <command> Print a command's JSON Schema and metadata.\");\n lines.push(\" preview <nodePath> Capture a TOP to a PNG file (-o/--out). [writes a file]\");\n lines.push(\" watch Stream TD events as ndjson until Ctrl-C. [long-running]\");\n lines.push(\" repl Interactive mode: run commands line-by-line. [interactive]\");\n lines.push(\" doctor Diagnose your setup (TD bridge, LLM, vault, config).\");\n return lines.join(\"\\n\");\n}\n\nexport interface RunCliOptions {\n /** Inject a context (used by tests); production builds one from env config. */\n makeCtx?: () => ToolContext;\n}\n\nfunction buildCtx(opts: RunCliOptions): ToolContext {\n return opts.makeCtx ? opts.makeCtx() : buildToolContext(loadConfig(), { logger: silentLogger });\n}\n\nfunction parseCliArgs(argv: string[]) {\n return parseArgs({\n args: argv,\n allowPositionals: true,\n options: {\n params: { type: \"string\" },\n json: { type: \"string\" },\n output: { type: \"string\", default: \"json\" },\n \"dry-run\": { type: \"boolean\", default: false },\n \"allow-unsafe\": { type: \"boolean\", default: false },\n out: { type: \"string\", short: \"o\" },\n \"include-high-frequency\": { type: \"boolean\", default: false },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n });\n}\n\nexport async function runCli(argv: string[], opts: RunCliOptions = {}): Promise<CliResult> {\n let parsed: ReturnType<typeof parseCliArgs>;\n try {\n parsed = parseCliArgs(argv);\n } catch (err) {\n return { stdout: \"\", stderr: `${(err as Error).message}\\n`, code: 2 };\n }\n\n const { values, positionals } = parsed;\n if (values.help || positionals.length === 0) {\n return { stdout: `${usage()}\\n`, stderr: \"\", code: 0 };\n }\n\n // `schema <command>` — emit the input contract without touching TD.\n if (positionals[0] === \"schema\") {\n const target = positionals.slice(1).join(\" \");\n const cmd = COMMANDS[target];\n if (!cmd) return { stdout: \"\", stderr: `Unknown command for schema: \"${target}\".\\n`, code: 2 };\n const doc = {\n command: target,\n summary: cmd.summary,\n mutates: cmd.mutates,\n unsafe: cmd.unsafe,\n input: z.toJSONSchema(cmd.schema),\n };\n return { stdout: `${JSON.stringify(doc, null, 2)}\\n`, stderr: \"\", code: 0 };\n }\n\n // `preview <nodePath> -o file.png` — capture a TOP and write it to disk. This is a\n // side effect that doesn't fit the CallToolResult command table, so it's handled here.\n if (positionals[0] === \"preview\") {\n const raw: Record<string, unknown> = {};\n try {\n if (typeof values.params === \"string\") Object.assign(raw, JSON.parse(values.params));\n if (typeof values.json === \"string\") Object.assign(raw, JSON.parse(values.json));\n } catch (err) {\n return {\n stdout: \"\",\n stderr: `Invalid JSON in --params/--json: ${(err as Error).message}\\n`,\n code: 2,\n };\n }\n if (positionals[1]) raw.node_path = positionals[1];\n const parsed = getPreviewSchema.safeParse(raw);\n if (!parsed.success) {\n return {\n stdout: \"\",\n stderr: `Invalid arguments for \"preview\": ${parsed.error.message}\\n`,\n code: 2,\n };\n }\n const outPath = typeof values.out === \"string\" && values.out ? values.out : \"preview.png\";\n if (values[\"dry-run\"]) {\n const doc = { dryRun: true, command: \"preview\", args: parsed.data, out: resolve(outPath) };\n return { stdout: `${JSON.stringify(doc, null, 2)}\\n`, stderr: \"\", code: 0 };\n }\n const ctx = buildCtx(opts);\n try {\n const preview = await capturePreview(\n ctx.client,\n parsed.data.node_path,\n parsed.data.width,\n parsed.data.height,\n );\n const bytes = Buffer.from(preview.base64, \"base64\");\n writeFileSync(outPath, bytes);\n const doc = {\n node_path: preview.path,\n file: resolve(outPath),\n width: preview.width,\n height: preview.height,\n bytes: bytes.length,\n mimeType: preview.mimeType,\n };\n return {\n stdout: `${JSON.stringify(doc, null, 2)}\\n`,\n stderr: `Saved preview of ${preview.path} to ${outPath} (${bytes.length} bytes).\\n`,\n code: 0,\n };\n } catch (err) {\n return { stdout: \"\", stderr: `${friendlyTdError(err)}\\n`, code: 1 };\n }\n }\n\n // `doctor` — environment diagnostic (TD bridge, LLM copilot, vault, config). Read-only and\n // reachable even when TD is offline, so it bypasses the CallToolResult command table.\n if (positionals[0] === \"doctor\") {\n const make = opts.makeCtx;\n const { stdout, stderr, code } = await runDoctor(make ? { makeCtx: () => make() } : {});\n return { stdout, stderr, code };\n }\n\n const resolved = resolveCommand(positionals);\n if (!resolved) {\n return {\n stdout: \"\",\n stderr: `Unknown command: \"${positionals.join(\" \")}\". Run with --help.\\n`,\n code: 2,\n };\n }\n const { key, cmd } = resolved;\n\n const raw: Record<string, unknown> = {};\n try {\n if (typeof values.params === \"string\") Object.assign(raw, JSON.parse(values.params));\n if (typeof values.json === \"string\") Object.assign(raw, JSON.parse(values.json));\n } catch (err) {\n return {\n stdout: \"\",\n stderr: `Invalid JSON in --params/--json: ${(err as Error).message}\\n`,\n code: 2,\n };\n }\n\n const args = cmd.schema.safeParse(raw);\n if (!args.success) {\n return {\n stdout: \"\",\n stderr: `Invalid arguments for \"${key}\": ${args.error.message}\\n`,\n code: 2,\n };\n }\n\n if (values[\"dry-run\"]) {\n const doc = {\n dryRun: true,\n command: key,\n mutates: cmd.mutates,\n unsafe: cmd.unsafe,\n args: args.data,\n };\n return { stdout: `${JSON.stringify(doc, null, 2)}\\n`, stderr: \"\", code: 0 };\n }\n\n const ctx = buildCtx(opts);\n\n if (cmd.unsafe) {\n if (ctx.allowRawPython === false) {\n return { stdout: \"\", stderr: `\"${key}\" is disabled (TDMCP_RAW_PYTHON=off).\\n`, code: 2 };\n }\n if (!values[\"allow-unsafe\"]) {\n return {\n stdout: \"\",\n stderr: `\"${key}\" is an escape hatch. Re-run with --allow-unsafe to execute.\\n`,\n code: 2,\n };\n }\n }\n\n const result = await cmd.run(ctx, args.data);\n const summary = textOf(result).split(\"\\n\")[0] ?? \"\";\n if (result.isError) return { stdout: \"\", stderr: `${textOf(result)}\\n`, code: 1 };\n\n const output = String(values.output);\n const data = extractData(result);\n if (output === \"text\") return { stdout: `${textOf(result)}\\n`, stderr: \"\", code: 0 };\n if (output === \"ndjson\") {\n const arr = firstArray(data);\n const body = arr ? arr.map((item) => JSON.stringify(item)).join(\"\\n\") : JSON.stringify(data);\n return { stdout: `${body}\\n`, stderr: summary ? `${summary}\\n` : \"\", code: 0 };\n }\n return {\n stdout: `${JSON.stringify(data, null, 2)}\\n`,\n stderr: summary ? `${summary}\\n` : \"\",\n code: 0,\n };\n}\n\nexport interface RunWatchOptions {\n config?: TdmcpConfig;\n includeHighFrequency?: boolean;\n /** Where each event line goes; defaults to stdout. Overridable for tests. */\n write?: (line: string) => void;\n /** Inject a stream factory for tests; defaults to a real `TdEventStream`. */\n makeStream?: (args: { url: string; onEvent: TdEventHandler; includeHighFrequency: boolean }) => {\n start: () => void;\n close: () => void;\n };\n /** Resolve the returned promise when aborted; defaults to listening for SIGINT. */\n signal?: AbortSignal;\n}\n\n/**\n * Streams TouchDesigner bridge events to stdout as ndjson until interrupted.\n * Runs outside `runCli` because it is a long-lived stream, not a request/response.\n */\nexport function runWatch(opts: RunWatchOptions = {}): Promise<void> {\n const config = opts.config ?? loadConfig();\n const url = `${tdBaseUrl(config).replace(/^http/, \"ws\")}/`;\n const write = opts.write ?? ((line: string) => process.stdout.write(`${line}\\n`));\n const includeHighFrequency = opts.includeHighFrequency ?? false;\n const onEvent: TdEventHandler = (event) => write(JSON.stringify(event));\n const stream = opts.makeStream\n ? opts.makeStream({ url, onEvent, includeHighFrequency })\n : new TdEventStream({ url, onEvent, includeHighFrequency });\n stream.start();\n process.stderr.write(`Watching ${url} for TouchDesigner events (Ctrl-C to stop)…\\n`);\n return new Promise<void>((resolveDone) => {\n const stop = () => {\n stream.close();\n resolveDone();\n };\n if (opts.signal) {\n if (opts.signal.aborted) return stop();\n opts.signal.addEventListener(\"abort\", stop, { once: true });\n } else {\n process.once(\"SIGINT\", stop);\n }\n });\n}\n\n/** Splits a REPL line into argv, respecting single/double quotes (so JSON --params works). */\nfunction tokenizeLine(line: string): string[] {\n const tokens: string[] = [];\n const re = /\"([^\"]*)\"|'([^']*)'|(\\S+)/g;\n let m: RegExpExecArray | null = re.exec(line);\n while (m !== null) {\n tokens.push(m[1] ?? m[2] ?? m[3] ?? \"\");\n m = re.exec(line);\n }\n return tokens;\n}\n\n/** Interactive read-eval-print loop: each line is tokenized and run through runCli. */\nexport async function runRepl(opts: RunCliOptions = {}): Promise<void> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n process.stderr.write(\n \"tdmcp REPL — enter a command (e.g. `info`, `nodes list`); `help` for commands, `exit` to quit.\\n> \",\n );\n for await (const line of rl) {\n const trimmed = line.trim();\n if (trimmed === \"exit\" || trimmed === \"quit\") break;\n if (trimmed === \"help\") {\n process.stdout.write(`${usage()}\\n`);\n } else if (trimmed) {\n const result = await runCli(tokenizeLine(trimmed), opts);\n if (result.stdout) process.stdout.write(result.stdout);\n if (result.stderr) process.stderr.write(result.stderr);\n }\n process.stderr.write(\"> \");\n }\n rl.close();\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n const wantsHelp = argv.includes(\"--help\") || argv.includes(\"-h\");\n // `watch` (a long-lived stream) and `repl` (interactive) bypass runCli's request/response model.\n if (argv[0] === \"watch\" && !wantsHelp) {\n await runWatch({ includeHighFrequency: argv.includes(\"--include-high-frequency\") });\n return;\n }\n if (argv[0] === \"repl\" && !wantsHelp) {\n await runRepl();\n return;\n }\n const result = await runCli(argv);\n if (result.stdout) process.stdout.write(result.stdout);\n if (result.stderr) process.stderr.write(result.stderr);\n process.exitCode = result.code;\n}\n\nconst invokedDirectly =\n process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href;\nif (invokedDirectly) void main();\n","import type { TouchDesignerClient } from \"../td-client/touchDesignerClient.js\";\n\nexport interface PreviewResult {\n path: string;\n width: number;\n height: number;\n base64: string;\n mimeType: string;\n}\n\n/** Captures a TOP as a base64 image via the bridge preview endpoint. */\nexport async function capturePreview(\n client: TouchDesignerClient,\n path: string,\n width = 640,\n height = 360,\n): Promise<PreviewResult> {\n const preview = await client.getPreview(path, width, height);\n return {\n path: preview.path,\n width: preview.width,\n height: preview.height,\n base64: preview.base64,\n mimeType: `image/${preview.format || \"png\"}`,\n };\n}\n","import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type Logger, silentLogger } from \"../utils/logger.js\";\nimport { bottobotPackageDir, knowledgeDataDir } from \"../utils/paths.js\";\nimport {\n compactKey,\n normalizeGlsl,\n normalizePatterns,\n slugify,\n toOperatorSummary,\n toPythonSummary,\n toTutorialSummary,\n} from \"./normalize.js\";\nimport type {\n GlslSummary,\n GlslTechnique,\n KnowledgeStats,\n OperatorDoc,\n OperatorSummary,\n Pattern,\n PatternSummary,\n PythonClass,\n PythonClassSummary,\n Tutorial,\n TutorialSummary,\n} from \"./types.js\";\n\nexport interface KnowledgeBaseOptions {\n dataDir?: string;\n logger?: Logger;\n}\n\ninterface ResolvedSource {\n kind: \"local\" | \"bottobot\" | \"empty\";\n operatorsDir: string;\n operatorsIndex?: string;\n pythonDir: string;\n tutorialsDir: string;\n patternsFile: string;\n glslFile: string;\n}\n\nconst EMPTY_SOURCE: ResolvedSource = {\n kind: \"empty\",\n operatorsDir: \"\",\n pythonDir: \"\",\n tutorialsDir: \"\",\n patternsFile: \"\",\n glslFile: \"\",\n};\n\n/**\n * Read-only accessor over the embedded TouchDesigner knowledge base. Prefers the\n * imported local data directory; falls back to reading directly from an installed\n * `@bottobot/td-mcp`; otherwise degrades to empty results (never throws on lookup).\n */\nexport class KnowledgeBase {\n private readonly logger: Logger;\n private readonly source: ResolvedSource;\n\n private opIndexCache?: OperatorSummary[];\n private opLookupCache?: Map<string, string>;\n private readonly opDocCache = new Map<string, OperatorDoc | null>();\n private pyIndexCache?: PythonClassSummary[];\n private pyLookupCache?: Map<string, string>;\n private readonly pyDocCache = new Map<string, PythonClass | null>();\n private tutIndexCache?: TutorialSummary[];\n private tutLookupCache?: Map<string, string>;\n private readonly tutDocCache = new Map<string, Tutorial | null>();\n private patternsCache?: Pattern[];\n private glslCache?: GlslTechnique[];\n\n constructor(options: KnowledgeBaseOptions = {}) {\n this.logger = options.logger ?? silentLogger;\n this.source = KnowledgeBase.resolveSource(options.dataDir ?? knowledgeDataDir());\n this.logger.debug(\"knowledge source resolved\", { kind: this.source.kind });\n }\n\n private static resolveSource(localDir: string): ResolvedSource {\n if (existsSync(join(localDir, \"operators\"))) {\n return {\n kind: \"local\",\n operatorsDir: join(localDir, \"operators\"),\n operatorsIndex: join(localDir, \"operators\", \"index.json\"),\n pythonDir: join(localDir, \"python-api\"),\n tutorialsDir: join(localDir, \"tutorials\"),\n patternsFile: join(localDir, \"patterns.json\"),\n glslFile: join(localDir, \"glsl.json\"),\n };\n }\n const bb = bottobotPackageDir();\n if (bb) {\n return {\n kind: \"bottobot\",\n operatorsDir: join(bb, \"wiki/data/processed\"),\n pythonDir: join(bb, \"wiki/data/python-api\"),\n tutorialsDir: join(bb, \"wiki/data/tutorials\"),\n patternsFile: join(bb, \"data/patterns.json\"),\n glslFile: join(bb, \"wiki/data/experimental/glsl.json\"),\n };\n }\n return EMPTY_SOURCE;\n }\n\n private readJson(path: string): unknown {\n try {\n return JSON.parse(readFileSync(path, \"utf8\"));\n } catch (err) {\n this.logger.debug(\"knowledge readJson failed\", { path, error: String(err) });\n return undefined;\n }\n }\n\n private listJsonFiles(dir: string): string[] {\n if (!dir || !existsSync(dir)) return [];\n try {\n return readdirSync(dir).filter((f) => f.endsWith(\".json\") && f !== \"index.json\");\n } catch {\n return [];\n }\n }\n\n // ---- Operators -----------------------------------------------------------\n\n private operatorIndex(): OperatorSummary[] {\n if (this.opIndexCache) return this.opIndexCache;\n if (this.source.kind === \"empty\") {\n this.opIndexCache = [];\n return this.opIndexCache;\n }\n if (this.source.operatorsIndex && existsSync(this.source.operatorsIndex)) {\n const data = this.readJson(this.source.operatorsIndex);\n if (Array.isArray(data)) {\n this.opIndexCache = data as OperatorSummary[];\n return this.opIndexCache;\n }\n }\n const summaries: OperatorSummary[] = [];\n for (const file of this.listJsonFiles(this.source.operatorsDir)) {\n const doc = this.readJson(join(this.source.operatorsDir, file)) as OperatorDoc | undefined;\n if (doc?.name) summaries.push(toOperatorSummary(file.replace(/\\.json$/, \"\"), doc));\n }\n this.opIndexCache = summaries;\n return this.opIndexCache;\n }\n\n private operatorLookup(): Map<string, string> {\n if (this.opLookupCache) return this.opLookupCache;\n const map = new Map<string, string>();\n for (const summary of this.operatorIndex()) {\n map.set(compactKey(summary.slug), summary.slug);\n map.set(compactKey(summary.name), summary.slug);\n map.set(compactKey(summary.displayName), summary.slug);\n }\n this.opLookupCache = map;\n return map;\n }\n\n listOperatorCategories(): string[] {\n const set = new Set<string>();\n for (const summary of this.operatorIndex()) set.add(summary.category);\n return [...set].sort();\n }\n\n listOperators(category?: string): OperatorSummary[] {\n const all = this.operatorIndex();\n if (!category) return all;\n const wanted = compactKey(category);\n return all.filter((s) => compactKey(s.category) === wanted);\n }\n\n getOperator(nameOrSlug: string): OperatorDoc | undefined {\n if (this.source.kind === \"empty\") return undefined;\n const slug = this.operatorLookup().get(compactKey(nameOrSlug)) ?? slugify(nameOrSlug);\n const cached = this.opDocCache.get(slug);\n if (cached !== undefined) return cached ?? undefined;\n const file = join(this.source.operatorsDir, `${slug}.json`);\n const doc = existsSync(file) ? (this.readJson(file) as OperatorDoc | undefined) : undefined;\n this.opDocCache.set(slug, doc ?? null);\n return doc;\n }\n\n /** Soft existence check (by operator type, display name, or slug). */\n operatorExists(typeOrName: string): boolean {\n return this.operatorLookup().has(compactKey(typeOrName));\n }\n\n searchOperators(query: string, limit = 25): OperatorSummary[] {\n const q = query.trim().toLowerCase();\n if (!q) return [];\n const terms = q.split(/\\s+/);\n const scored: Array<{ summary: OperatorSummary; score: number }> = [];\n for (const summary of this.operatorIndex()) {\n const haystack =\n `${summary.name} ${summary.displayName} ${summary.summary} ${summary.keywords.join(\" \")}`.toLowerCase();\n let score = 0;\n for (const term of terms) {\n if (haystack.includes(term)) score += 1;\n if (summary.name.toLowerCase().includes(term)) score += 1;\n }\n if (score > 0) scored.push({ summary, score });\n }\n scored.sort((a, b) => b.score - a.score);\n return scored.slice(0, limit).map((s) => s.summary);\n }\n\n // ---- Python API ----------------------------------------------------------\n\n private pythonIndex(): PythonClassSummary[] {\n if (this.pyIndexCache) return this.pyIndexCache;\n if (this.source.kind === \"empty\") {\n this.pyIndexCache = [];\n return this.pyIndexCache;\n }\n const indexPath = join(this.source.pythonDir, \"index.json\");\n if (existsSync(indexPath)) {\n const data = this.readJson(indexPath);\n if (Array.isArray(data)) {\n this.pyIndexCache = data as PythonClassSummary[];\n return this.pyIndexCache;\n }\n }\n const summaries: PythonClassSummary[] = [];\n for (const file of this.listJsonFiles(this.source.pythonDir)) {\n const cls = this.readJson(join(this.source.pythonDir, file)) as PythonClass | undefined;\n if (cls?.className) summaries.push(toPythonSummary(cls));\n }\n this.pyIndexCache = summaries;\n return this.pyIndexCache;\n }\n\n private pythonLookup(): Map<string, string> {\n if (this.pyLookupCache) return this.pyLookupCache;\n const map = new Map<string, string>();\n for (const summary of this.pythonIndex()) {\n map.set(compactKey(summary.className), summary.className);\n map.set(compactKey(summary.displayName), summary.className);\n }\n this.pyLookupCache = map;\n return map;\n }\n\n listPythonClasses(): PythonClassSummary[] {\n return this.pythonIndex();\n }\n\n getPythonClass(name: string): PythonClass | undefined {\n if (this.source.kind === \"empty\") return undefined;\n const className = this.pythonLookup().get(compactKey(name)) ?? name;\n const cached = this.pyDocCache.get(className);\n if (cached !== undefined) return cached ?? undefined;\n const file = join(this.source.pythonDir, `${className}.json`);\n const cls = existsSync(file) ? (this.readJson(file) as PythonClass | undefined) : undefined;\n this.pyDocCache.set(className, cls ?? null);\n return cls;\n }\n\n // ---- Patterns ------------------------------------------------------------\n\n private patterns(): Pattern[] {\n if (this.patternsCache) return this.patternsCache;\n if (this.source.kind === \"empty\") {\n this.patternsCache = [];\n return this.patternsCache;\n }\n const data = this.readJson(this.source.patternsFile);\n if (Array.isArray(data) && data.length > 0 && typeof (data[0] as Pattern).id === \"string\") {\n this.patternsCache = data as Pattern[];\n } else {\n this.patternsCache = normalizePatterns(data);\n }\n return this.patternsCache;\n }\n\n listPatterns(): PatternSummary[] {\n return this.patterns().map((p) => ({\n id: p.id,\n name: p.name,\n category: p.category ?? \"Unknown\",\n description: p.description ?? \"\",\n }));\n }\n\n getPattern(name: string): Pattern | undefined {\n const key = compactKey(name);\n return this.patterns().find((p) => compactKey(p.id) === key || compactKey(p.name) === key);\n }\n\n // ---- GLSL ----------------------------------------------------------------\n\n private glsl(): GlslTechnique[] {\n if (this.glslCache) return this.glslCache;\n if (this.source.kind === \"empty\") {\n this.glslCache = [];\n return this.glslCache;\n }\n const data = this.readJson(this.source.glslFile);\n this.glslCache = Array.isArray(data) ? (data as GlslTechnique[]) : normalizeGlsl(data);\n return this.glslCache;\n }\n\n listGlslPatterns(): GlslSummary[] {\n return this.glsl().map((g) => ({\n id: g.id,\n name: g.name,\n description: g.description ?? \"\",\n difficulty: g.difficulty ?? \"unknown\",\n }));\n }\n\n getGlslPattern(name: string): GlslTechnique | undefined {\n const key = compactKey(name);\n return this.glsl().find((g) => compactKey(g.id) === key || compactKey(g.name) === key);\n }\n\n // ---- Tutorials -----------------------------------------------------------\n\n private tutorialIndex(): TutorialSummary[] {\n if (this.tutIndexCache) return this.tutIndexCache;\n if (this.source.kind === \"empty\") {\n this.tutIndexCache = [];\n return this.tutIndexCache;\n }\n const indexPath = join(this.source.tutorialsDir, \"index.json\");\n if (existsSync(indexPath)) {\n const data = this.readJson(indexPath);\n if (Array.isArray(data)) {\n this.tutIndexCache = data as TutorialSummary[];\n return this.tutIndexCache;\n }\n }\n const summaries: TutorialSummary[] = [];\n for (const file of this.listJsonFiles(this.source.tutorialsDir)) {\n const tut = this.readJson(join(this.source.tutorialsDir, file)) as Tutorial | undefined;\n if (tut?.id || tut?.name) {\n const normalized: Tutorial = {\n ...tut,\n id: tut.id ?? file.replace(/\\.json$/, \"\"),\n name: tut.name ?? file,\n };\n summaries.push(toTutorialSummary(normalized));\n }\n }\n this.tutIndexCache = summaries;\n return this.tutIndexCache;\n }\n\n private tutorialLookup(): Map<string, string> {\n if (this.tutLookupCache) return this.tutLookupCache;\n const map = new Map<string, string>();\n for (const file of this.listJsonFiles(this.source.tutorialsDir)) {\n const slug = file.replace(/\\.json$/, \"\");\n map.set(compactKey(slug), slug);\n }\n for (const summary of this.tutorialIndex()) {\n map.set(compactKey(summary.id), summary.id);\n map.set(compactKey(summary.name), summary.id);\n }\n this.tutLookupCache = map;\n return map;\n }\n\n listTutorials(): TutorialSummary[] {\n return this.tutorialIndex();\n }\n\n getTutorial(name: string): Tutorial | undefined {\n if (this.source.kind === \"empty\") return undefined;\n const slug = this.tutorialLookup().get(compactKey(name)) ?? slugify(name);\n const cached = this.tutDocCache.get(slug);\n if (cached !== undefined) return cached ?? undefined;\n const file = join(this.source.tutorialsDir, `${slug}.json`);\n const tut = existsSync(file) ? (this.readJson(file) as Tutorial | undefined) : undefined;\n this.tutDocCache.set(slug, tut ?? null);\n return tut;\n }\n\n // ---- Meta ----------------------------------------------------------------\n\n get sourceKind(): KnowledgeStats[\"source\"] {\n return this.source.kind;\n }\n\n stats(): KnowledgeStats {\n return {\n source: this.source.kind,\n operators: this.operatorIndex().length,\n pythonClasses: this.pythonIndex().length,\n patterns: this.patterns().length,\n glsl: this.glsl().length,\n tutorials: this.tutorialIndex().length,\n };\n }\n}\n","export type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"silent\";\n\nconst LEVELS: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n silent: 99,\n};\n\nexport interface Logger {\n debug(message: string, meta?: Record<string, unknown>): void;\n info(message: string, meta?: Record<string, unknown>): void;\n warn(message: string, meta?: Record<string, unknown>): void;\n error(message: string, meta?: Record<string, unknown>): void;\n}\n\n/**\n * Creates a leveled logger. All output goes to **stderr** so that stdout stays\n * reserved for the MCP stdio protocol stream.\n */\nexport function createLogger(level: LogLevel = \"info\"): Logger {\n const threshold = LEVELS[level];\n\n const emit = (\n lvl: Exclude<LogLevel, \"silent\">,\n message: string,\n meta?: Record<string, unknown>,\n ) => {\n if (LEVELS[lvl] < threshold) return;\n const stamp = new Date().toISOString();\n const suffix = meta && Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : \"\";\n process.stderr.write(`[tdmcp] ${stamp} ${lvl.toUpperCase()} ${message}${suffix}\\n`);\n };\n\n return {\n debug: (message, meta) => emit(\"debug\", message, meta),\n info: (message, meta) => emit(\"info\", message, meta),\n warn: (message, meta) => emit(\"warn\", message, meta),\n error: (message, meta) => emit(\"error\", message, meta),\n };\n}\n\n/** A logger that discards everything — handy for tests. */\nexport const silentLogger: Logger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n","import { existsSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst moduleDir = dirname(fileURLToPath(import.meta.url));\n\nfunction firstExisting(candidates: string[], fallback: string): string {\n for (const candidate of candidates) {\n if (existsSync(candidate)) return candidate;\n }\n return fallback;\n}\n\n/**\n * Directory holding the imported knowledge base JSON.\n * - dev (tsx): `<root>/src/knowledge/data`\n * - build (node): `<root>/dist/knowledge/data` (copied by `copy-assets.mjs`)\n */\nexport function knowledgeDataDir(): string {\n return firstExisting(\n [resolve(moduleDir, \"../knowledge/data\"), resolve(moduleDir, \"knowledge/data\")],\n resolve(moduleDir, \"../knowledge/data\"),\n );\n}\n\n/**\n * Directory holding recipe JSON files.\n * - dev: `<root>/recipes`\n * - build: `<root>/dist/recipes`\n */\nexport function recipesDir(): string {\n return firstExisting(\n [resolve(moduleDir, \"../../recipes\"), resolve(moduleDir, \"recipes\")],\n resolve(moduleDir, \"../../recipes\"),\n );\n}\n\n/**\n * Directory holding the TouchDesigner-side Python bridge modules that ship with\n * the package (the `td/modules` tree). Used by the `install-bridge` CLI to copy\n * them somewhere TouchDesigner can import from.\n * - dev (tsx): `<root>/td/modules`\n * - installed package (node): `<pkgroot>/td/modules`\n */\nexport function bridgeModulesDir(): string {\n return firstExisting(\n [resolve(moduleDir, \"../td/modules\"), resolve(moduleDir, \"../../td/modules\")],\n resolve(moduleDir, \"../td/modules\"),\n );\n}\n\n/**\n * Resolves the installed `@bottobot/td-mcp` package root (the source of operator\n * data), if present. Used as a fallback when local knowledge data is missing.\n */\nexport function bottobotPackageDir(): string | undefined {\n const candidates = [\n resolve(moduleDir, \"../../node_modules/@bottobot/td-mcp\"),\n resolve(moduleDir, \"../node_modules/@bottobot/td-mcp\"),\n resolve(process.cwd(), \"node_modules/@bottobot/td-mcp\"),\n ];\n for (const candidate of candidates) {\n if (existsSync(resolve(candidate, \"wiki/data/processed\"))) return candidate;\n }\n return undefined;\n}\n","import type {\n GlslTechnique,\n OperatorDoc,\n OperatorSummary,\n Pattern,\n PythonClass,\n PythonClassSummary,\n Tutorial,\n TutorialSummary,\n} from \"./types.js\";\n\n/** Filename-style slug: lowercase, non-alphanumerics collapse to underscores. */\nexport function slugify(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n}\n\n/** Lookup key that unifies \"Noise TOP\", \"noiseTOP\" and \"noise_top\" → \"noisetop\". */\nexport function compactKey(value: string): string {\n return value.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n}\n\nexport function toOperatorSummary(slug: string, doc: OperatorDoc): OperatorSummary {\n return {\n slug,\n name: doc.name,\n displayName: doc.displayName ?? doc.name,\n category: doc.category ?? \"Unknown\",\n subcategory: doc.subcategory ?? \"\",\n summary: doc.summary ?? doc.description ?? \"\",\n keywords: doc.keywords ?? [],\n };\n}\n\nexport function toPythonSummary(cls: PythonClass): PythonClassSummary {\n return {\n className: cls.className,\n displayName: cls.displayName ?? cls.className,\n category: cls.category ?? \"Unknown\",\n methodCount: cls.methods?.length ?? 0,\n memberCount: cls.members?.length ?? 0,\n };\n}\n\nexport function toTutorialSummary(tut: Tutorial): TutorialSummary {\n return {\n id: tut.id,\n name: tut.name,\n category: tut.category ?? \"Unknown\",\n summary: tut.summary ?? tut.description ?? \"\",\n };\n}\n\ninterface RawPattern {\n name?: string;\n description?: string;\n category?: string;\n workflow?: string[];\n use_case?: string;\n}\n\n/**\n * The bottobot patterns file is an object with a `patterns` array (plus extra\n * metadata keys). Normalizes it into a flat, id-keyed array.\n */\nexport function normalizePatterns(raw: unknown): Pattern[] {\n let list: RawPattern[] = [];\n if (Array.isArray(raw)) {\n list = raw as RawPattern[];\n } else if (raw && typeof raw === \"object\") {\n const obj = raw as Record<string, unknown>;\n if (Array.isArray(obj.patterns)) {\n list = obj.patterns as RawPattern[];\n } else {\n list = Object.values(obj).filter((v): v is RawPattern => !!v && typeof v === \"object\");\n }\n }\n return list\n .filter((p) => typeof p.name === \"string\")\n .map((p) => ({\n id: slugify(p.name as string),\n name: p.name as string,\n description: p.description,\n category: p.category,\n workflow: Array.isArray(p.workflow) ? p.workflow : undefined,\n use_case: p.use_case,\n }));\n}\n\ninterface RawGlslFile {\n techniques?: unknown;\n}\n\n/** Extracts GLSL techniques from bottobot's `experimental/glsl.json`. */\nexport function normalizeGlsl(raw: unknown): GlslTechnique[] {\n const file = (raw ?? {}) as RawGlslFile;\n const techniques = Array.isArray(file.techniques) ? file.techniques : [];\n return techniques\n .filter((t): t is Record<string, unknown> => !!t && typeof t === \"object\")\n .map((t) => {\n const name = typeof t.name === \"string\" ? t.name : \"Untitled\";\n const id = typeof t.id === \"string\" && t.id.length > 0 ? t.id : slugify(name);\n return {\n id,\n name,\n subcategory: typeof t.subcategory === \"string\" ? t.subcategory : undefined,\n description: typeof t.description === \"string\" ? t.description : undefined,\n difficulty: typeof t.difficulty === \"string\" ? t.difficulty : undefined,\n operators: Array.isArray(t.operators) ? (t.operators as string[]) : undefined,\n tags: Array.isArray(t.tags) ? (t.tags as string[]) : undefined,\n notes: typeof t.notes === \"string\" ? t.notes : undefined,\n code: (t.code ?? undefined) as GlslTechnique[\"code\"],\n setup: typeof t.setup === \"string\" ? t.setup : undefined,\n };\n });\n}\n","import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { compactKey } from \"../knowledge/normalize.js\";\nimport { type Logger, silentLogger } from \"../utils/logger.js\";\nimport { recipesDir } from \"../utils/paths.js\";\nimport type { Vault } from \"../vault/index.js\";\nimport { recipeFromMarkdown } from \"./markdown.js\";\nimport { type Recipe, RecipeSchema, type RecipeSummary } from \"./schema.js\";\n\nexport interface RecipeLibraryOptions {\n dir?: string;\n logger?: Logger;\n /** Optional Obsidian vault; recipes in `<vault>/Recipes/*.md` are merged in (and override built-ins by id). */\n vault?: Vault;\n}\n\n/** Loads and validates recipe JSON files from the recipes directory, plus any vault recipes. */\nexport class RecipeLibrary {\n private readonly dir: string;\n private readonly logger: Logger;\n private readonly vault?: Vault;\n private cache?: Recipe[];\n\n constructor(options: RecipeLibraryOptions = {}) {\n this.dir = options.dir ?? recipesDir();\n this.logger = options.logger ?? silentLogger;\n this.vault = options.vault;\n }\n\n private load(): Recipe[] {\n if (this.cache) return this.cache;\n // Keyed by id so a vault recipe (loaded second) cleanly overrides a built-in.\n const byId = new Map<string, Recipe>();\n\n if (existsSync(this.dir)) {\n for (const file of readdirSync(this.dir)) {\n if (!file.endsWith(\".json\")) continue;\n try {\n const raw = JSON.parse(readFileSync(join(this.dir, file), \"utf8\"));\n const parsed = RecipeSchema.safeParse(raw);\n if (parsed.success) {\n byId.set(compactKey(parsed.data.id), parsed.data);\n } else {\n this.logger.warn(`Invalid recipe ${file}`, { issues: parsed.error.issues.length });\n }\n } catch (err) {\n this.logger.warn(`Failed to read recipe ${file}`, { error: String(err) });\n }\n }\n }\n\n if (this.vault) {\n for (const file of this.vault.list(\"Recipes\", \".md\")) {\n try {\n const recipe = recipeFromMarkdown(this.vault.read(join(\"Recipes\", file)));\n byId.set(compactKey(recipe.id), recipe);\n } catch (err) {\n this.logger.warn(`Invalid vault recipe ${file}`, { error: String(err) });\n }\n }\n }\n\n this.cache = [...byId.values()];\n return this.cache;\n }\n\n all(): Recipe[] {\n return this.load();\n }\n\n list(): RecipeSummary[] {\n return this.load().map((r) => ({\n id: r.id,\n name: r.name,\n description: r.description,\n tags: r.tags,\n difficulty: r.difficulty,\n }));\n }\n\n get(id: string): Recipe | undefined {\n const key = compactKey(id);\n return this.load().find((r) => compactKey(r.id) === key || compactKey(r.name) === key);\n }\n\n /** Finds the best recipe whose tags/name/description match any of the given terms. */\n findByTags(terms: string[]): Recipe | undefined {\n const wanted = terms.map((t) => t.toLowerCase()).filter(Boolean);\n if (wanted.length === 0) return undefined;\n let best: { recipe: Recipe; score: number } | undefined;\n for (const recipe of this.load()) {\n const haystack =\n `${recipe.name} ${recipe.description} ${recipe.tags.join(\" \")}`.toLowerCase();\n let score = 0;\n for (const term of wanted) {\n if (recipe.tags.some((tag) => tag.toLowerCase() === term)) score += 2;\n else if (haystack.includes(term)) score += 1;\n }\n if (score > 0 && (!best || score > best.score)) best = { recipe, score };\n }\n return best?.recipe;\n }\n}\n","import matter from \"gray-matter\";\n\nexport interface ParsedNote {\n /** Parsed YAML frontmatter (empty object when the note has none). */\n data: Record<string, unknown>;\n /** Markdown body with the frontmatter stripped. */\n body: string;\n}\n\n/** Splits a markdown string into its YAML frontmatter and body. */\nexport function parseNote(raw: string): ParsedNote {\n const file = matter(raw);\n return { data: file.data, body: file.content };\n}\n\n/** Serializes frontmatter + body back into a markdown string. */\nexport function buildNote(data: Record<string, unknown>, body: string): string {\n return matter.stringify(body, data);\n}\n\n/**\n * Extracts the first fenced code block tagged with `lang` (e.g. ```json or\n * ```glsl). Returns the block's inner text, or undefined when absent. The `lang`\n * tag may carry an extra info word (```json tdmcp-recipe) — only the first token\n * is matched.\n */\nexport function extractFencedBlock(body: string, lang: string): string | undefined {\n const fence = new RegExp(`\\`\\`\\`${lang}(?:[^\\\\n]*)\\\\n([\\\\s\\\\S]*?)\\`\\`\\``, \"i\");\n const match = body.match(fence);\n return match?.[1]?.replace(/\\n$/, \"\");\n}\n","import { z } from \"zod\";\nimport { controlSchema } from \"../tools/layer2/createControlPanel.js\";\n\nexport const RecipeNodeSchema = z.object({\n name: z.string().describe(\"Unique node name within the recipe (used for wiring).\"),\n type: z.string().describe(\"Operator type, e.g. 'noiseTOP'.\"),\n parameters: z.record(z.string(), z.unknown()).default({}),\n parent: z\n .string()\n .optional()\n .describe(\n \"Name of another recipe node (a COMP, e.g. a geometryCOMP) to nest this node inside of. \" +\n \"The parent must appear earlier in `nodes`. Used to place SOPs inside a Geometry COMP.\",\n ),\n render: z\n .boolean()\n .optional()\n .describe(\n \"For a SOP nested in a geometryCOMP: make this the rendered geometry. Sets the render/display \" +\n \"flags on it and clears its siblings, so the COMP renders this instead of its default torus.\",\n ),\n comment: z.string().optional(),\n});\n\nexport const RecipeConnectionSchema = z.object({\n from: z.string().describe(\"Source node name.\"),\n to: z.string().describe(\"Target node name.\"),\n from_output: z.number().int().nonnegative().default(0),\n to_input: z.number().int().nonnegative().default(0),\n});\n\nexport const RecipeParameterSchema = z.object({\n name: z.string().describe(\"Friendly name of the exposed control.\"),\n node: z.string().describe(\"Recipe node name the parameter belongs to.\"),\n param: z.string().describe(\"TD parameter name on that node.\"),\n value: z.unknown().optional(),\n label: z.string().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n description: z.string().optional(),\n});\n\n/**\n * A uniform exposed by a GLSL TOP. On the GLSL TOP these live in *parameter\n * sequences*, not normal parameters, so they cannot be set the usual way: the block\n * count (`op.seq.<seq>.numBlocks`) has to be raised first, after which the per-block\n * name/value sub-parameters exist. `float`/`vec` uniforms bind through the \"Vectors\"\n * page (the `vec` sequence); `color` binds through the \"Colors\" page (the `color`\n * sequence). The \"Constants\" page does NOT feed a runtime `uniform float`, so it is\n * not used here. `buildFromRecipe` handles the translation; authors just declare the\n * uniform.\n */\nexport const RecipeGlslUniformSchema = z.object({\n node: z.string().describe(\"Recipe node name of the GLSL TOP that declares the uniform.\"),\n name: z.string().describe(\"Uniform name as referenced in the shader, e.g. 'uFeed'.\"),\n kind: z\n .enum([\"float\", \"vec\", \"color\"])\n .default(\"float\")\n .describe(\n \"Uniform kind: float (uniform float), vec (uniform vec2/3/4), color (rgba). \" +\n \"float/vec use the Vectors page; color uses the Colors page.\",\n ),\n value: z\n .union([z.number(), z.array(z.number())])\n .optional()\n .describe(\"Initial value: a number for float, or an array of components for vec/color.\"),\n label: z.string().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n description: z.string().optional(),\n});\nexport type RecipeGlslUniform = z.infer<typeof RecipeGlslUniformSchema>;\n\nexport const RecipeSchema = z.object({\n id: z.string(),\n name: z.string(),\n description: z.string().default(\"\"),\n tags: z.array(z.string()).default([]),\n difficulty: z.enum([\"beginner\", \"intermediate\", \"advanced\"]).default(\"intermediate\"),\n td_version_min: z.string().default(\"2023\"),\n nodes: z.array(RecipeNodeSchema).min(1),\n connections: z.array(RecipeConnectionSchema).default([]),\n parameters: z.array(RecipeParameterSchema).default([]),\n glsl_uniforms: z.array(RecipeGlslUniformSchema).default([]),\n glsl_code: z.record(z.string(), z.string()).optional(),\n python_code: z.record(z.string(), z.string()).optional(),\n /**\n * Live controls to auto-expose on the system container: custom parameters (knobs/\n * sliders/toggles) bound to node parameters so the built system is immediately\n * playable. Each control's `bind_to` uses recipe node *names* (\"nodeName.parName\");\n * buildFromRecipe rewrites them to the real created paths.\n */\n controls: z.array(controlSchema).default([]),\n preview_description: z.string().default(\"\"),\n});\nexport type Recipe = z.infer<typeof RecipeSchema>;\n\nexport interface RecipeSummary {\n id: string;\n name: string;\n description: string;\n tags: string[];\n difficulty: Recipe[\"difficulty\"];\n}\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const controlSchema = z.object({\n name: z\n .string()\n .describe(\n \"Control label; also sanitized into a valid TD custom-parameter name (e.g. 'blur amount' → 'Bluramount').\",\n ),\n type: z\n .enum([\"float\", \"int\", \"toggle\", \"menu\", \"rgb\", \"pulse\", \"string\"])\n .default(\"float\")\n .describe(\n \"Widget kind: float/int sliders, a toggle, a dropdown menu, an RGB swatch, a momentary pulse, or a text field.\",\n ),\n label: z.string().optional().describe(\"Display label (defaults to `name`).\"),\n min: z.coerce.number().optional().describe(\"Slider lower bound (float/int) — also hard-clamped.\"),\n max: z.coerce.number().optional().describe(\"Slider upper bound (float/int) — also hard-clamped.\"),\n default: z.union([z.number(), z.boolean(), z.string()]).optional().describe(\"Initial value.\"),\n menu_items: z.array(z.string()).optional().describe(\"Options for a 'menu' control.\"),\n bind_to: z\n .array(z.string())\n .optional()\n .describe(\n \"Parameters this control should drive, each written as 'nodePath.parName' (e.g. '/project1/sys/blur1.size'). Each target is switched to expression mode so moving the control moves the parameter live. Not supported for 'rgb'/'pulse'.\",\n ),\n});\n\n/** One control spec (knob/slider/toggle/menu/…), reused by Layer 1 tools that auto-expose a panel. */\nexport type ControlSpec = z.infer<typeof controlSchema>;\n\nexport const createControlPanelSchema = z.object({\n comp_path: z\n .string()\n .default(\"/project1\")\n .describe(\n \"COMP that will receive the custom parameters — usually a generated system's container.\",\n ),\n page: z\n .string()\n .default(\"Controls\")\n .describe(\"Name of the custom-parameter page to add the controls to.\"),\n controls: z\n .array(controlSchema)\n .min(1)\n .describe(\"The controls (knobs/sliders/toggles/menus) to expose.\"),\n});\ntype CreateControlPanelArgs = z.infer<typeof createControlPanelSchema>;\n\ninterface ControlReport {\n comp: string;\n page: string;\n created: Array<{ control: string; name: string; type: string; pars: string[]; value: unknown }>;\n bound: Array<{ control: string; target: string }>;\n warnings: string[];\n fatal?: string;\n}\n\n// The whole panel is built in one Python pass: appending custom parameters is an\n// attribute-level operation with no structured bridge endpoint, and doing it in a\n// single script keeps the page/parameter/binding work atomic. `ParMode` is *not*\n// injected into the bridge's exec globals, so the expression-mode enum is derived\n// from a live parameter (`type(par.mode)`) instead of imported.\nconst PANEL_SCRIPT = `\nimport json, base64, traceback\n_payload = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\n_comp = op(_payload[\"comp\"]); _page_name = _payload[\"page\"]; _controls = _payload[\"controls\"]\nreport = {\"comp\": _payload[\"comp\"], \"page\": _page_name, \"created\": [], \"bound\": [], \"warnings\": []}\n\ndef _parname(s):\n s = \"\".join(ch for ch in s if ch.isalnum())\n if not s:\n s = \"Par\"\n if not s[0].isalpha():\n s = \"P\" + s\n # TD custom-parameter names must be a leading uppercase letter followed by lowercase\n # letters/digits only, so lowercase the tail — otherwise camelCase input like \"CamZoom\"\n # keeps its internal capital and TouchDesigner rejects the name.\n return s[0].upper() + s[1:].lower()\n\ndef _parse_rgb(v):\n # Accept a hex string (\"#rrggbb\"/\"rrggbb\") or a [r,g,b] list of 0..1 floats → 0..1 RGB.\n try:\n if isinstance(v, (list, tuple)) and len(v) >= 3:\n return [float(v[0]), float(v[1]), float(v[2])]\n s = str(v).strip().lstrip(\"#\")\n if len(s) == 6:\n return [int(s[0:2], 16) / 255.0, int(s[2:4], 16) / 255.0, int(s[4:6], 16) / 255.0]\n except Exception:\n pass\n return None\n\nif _comp is None:\n report[\"fatal\"] = \"COMP not found: \" + _payload[\"comp\"]\nelif not hasattr(_comp, \"appendCustomPage\"):\n report[\"fatal\"] = _payload[\"comp\"] + \" is not a COMP, so it cannot hold custom parameters.\"\nelse:\n _page = None\n for _pg in _comp.customPages:\n if _pg.name == _page_name:\n _page = _pg\n break\n if _page is None:\n _page = _comp.appendCustomPage(_page_name)\n for _spec in _controls:\n try:\n _name = _parname(_spec[\"name\"]); _typ = _spec.get(\"type\", \"float\"); _label = _spec.get(\"label\") or _spec[\"name\"]\n if _typ == \"float\":\n _pg = _page.appendFloat(_name, label=_label)\n elif _typ == \"int\":\n _pg = _page.appendInt(_name, label=_label)\n elif _typ == \"toggle\":\n _pg = _page.appendToggle(_name, label=_label)\n elif _typ == \"menu\":\n _pg = _page.appendMenu(_name, label=_label)\n elif _typ == \"rgb\":\n _pg = _page.appendRGB(_name, label=_label)\n elif _typ == \"pulse\":\n _pg = _page.appendPulse(_name, label=_label)\n elif _typ in (\"string\", \"str\"):\n _pg = _page.appendStr(_name, label=_label)\n else:\n report[\"warnings\"].append(\"Unknown control type '%s' for '%s'.\" % (_typ, _spec[\"name\"]))\n continue\n _p0 = _pg[0]; _dflt = _spec.get(\"default\", None)\n if _typ in (\"float\", \"int\"):\n _mn = _spec.get(\"min\", None); _mx = _spec.get(\"max\", None)\n if _mn is not None:\n _p0.normMin = _mn; _p0.min = _mn; _p0.clampMin = True\n if _mx is not None:\n _p0.normMax = _mx; _p0.max = _mx; _p0.clampMax = True\n if _dflt is not None:\n _p0.default = _dflt; _p0.val = _dflt\n elif _typ == \"toggle\":\n if _dflt is not None:\n _p0.default = bool(_dflt); _p0.val = bool(_dflt)\n elif _typ == \"menu\":\n _items = _spec.get(\"menu_items\") or []\n if _items:\n _names = [str(x) for x in _items]\n _p0.menuNames = _names; _p0.menuLabels = _names\n if _dflt is not None and str(_dflt) in [str(x) for x in _items]:\n _p0.default = str(_dflt); _p0.val = str(_dflt)\n elif _typ in (\"string\", \"str\"):\n if _dflt is not None:\n _p0.default = str(_dflt); _p0.val = str(_dflt)\n elif _typ == \"rgb\":\n # An RGB swatch defaults to black; set its r/g/b components from the spec's\n # default (hex or [r,g,b]) so colour-driven shaders don't start out black.\n if _dflt is not None:\n _rgb = _parse_rgb(_dflt)\n if _rgb is not None:\n for _i in range(min(3, len(_pg))):\n _pg[_i].default = _rgb[_i]; _pg[_i].val = _rgb[_i]\n report[\"created\"].append({\"control\": _spec[\"name\"], \"name\": _name, \"type\": _typ, \"pars\": [pp.name for pp in _pg], \"value\": _p0.eval()})\n _binds = _spec.get(\"bind_to\") or []\n if _binds and _typ in (\"rgb\", \"pulse\"):\n report[\"warnings\"].append(\"bind_to ignored for '%s' (a %s control cannot drive a single parameter).\" % (_spec[\"name\"], _typ))\n _binds = []\n for _t in _binds:\n try:\n _dot = _t.rfind(\".\")\n if _dot <= 0:\n report[\"warnings\"].append(\"Invalid bind target '%s' (expected 'nodePath.parName').\" % _t)\n continue\n _np = _t[:_dot]; _pn = _t[_dot + 1:]; _tn = op(_np)\n if _tn is None:\n report[\"warnings\"].append(\"Bind target node not found: %s\" % _np)\n continue\n _tp = getattr(_tn.par, _pn, None)\n if _tp is None:\n report[\"warnings\"].append(\"Bind target parameter not found: %s.%s\" % (_np, _pn))\n continue\n _PM = type(_tp.mode)\n _tp.expr = \"op(%s).par.%s\" % (repr(_payload[\"comp\"]), _name)\n _tp.mode = _PM.EXPRESSION\n report[\"bound\"].append({\"control\": _name, \"target\": _np + \".\" + _pn})\n except Exception:\n report[\"warnings\"].append(\"Failed to bind '%s' to '%s': %s\" % (_name, _t, traceback.format_exc().splitlines()[-1]))\n except Exception:\n report[\"warnings\"].append(\"Failed to create control '%s': %s\" % (_spec.get(\"name\", \"?\"), traceback.format_exc().splitlines()[-1]))\nprint(json.dumps(report))\n`;\n\nexport function buildPanelScript(payload: object): string {\n return buildPayloadScript(PANEL_SCRIPT, payload);\n}\n\nexport function parseReport(stdout: string | undefined): ControlReport {\n return parsePythonReport<ControlReport>(stdout);\n}\n\nexport async function createControlPanelImpl(ctx: ToolContext, args: CreateControlPanelArgs) {\n return guardTd(\n async () => {\n const script = buildPanelScript({\n comp: args.comp_path,\n page: args.page,\n controls: args.controls,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parseReport(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Could not build control panel: ${report.fatal}`, report);\n }\n const summary = `Added ${report.created.length} control(s) on page \"${report.page}\" of ${report.comp}, ${report.bound.length} bound to live parameter(s)${\n report.warnings.length ? `, ${report.warnings.length} warning(s)` : \"\"\n }.`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerCreateControlPanel: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_control_panel\",\n {\n title: \"Create control panel\",\n description:\n \"Expose live controls on a COMP: append custom parameters (sliders, toggles, menus, RGB, pulse) and bind them to node parameters so the artist can drive a generated system in real time. Point `comp_path` at a system container and list the controls; use each control's `bind_to` to wire it to one or more 'nodePath.parName' targets.\",\n inputSchema: createControlPanelSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createControlPanelImpl(ctx, args),\n );\n};\n","/** Base error for all TouchDesigner bridge failures. */\nexport class TdError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"TdError\";\n this.code = code;\n }\n}\n\n/** The bridge could not be reached (TD not running, wrong host/port, etc.). */\nexport class TdConnectionError extends TdError {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, \"TD_CONNECTION\", options);\n this.name = \"TdConnectionError\";\n }\n}\n\n/** The request exceeded the configured timeout. */\nexport class TdTimeoutError extends TdError {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, \"TD_TIMEOUT\", options);\n this.name = \"TdTimeoutError\";\n }\n}\n\n/** The bridge responded but reported an error (HTTP non-2xx or `ok: false`). */\nexport class TdApiError extends TdError {\n readonly status: number | undefined;\n readonly apiCode: string | undefined;\n\n constructor(message: string, options?: { status?: number; apiCode?: string; cause?: unknown }) {\n super(message, \"TD_API\", options);\n this.name = \"TdApiError\";\n this.status = options?.status;\n this.apiCode = options?.apiCode;\n }\n}\n\n/** Produces a human-friendly, single-line description of any error. */\nexport function friendlyTdError(err: unknown): string {\n if (err instanceof TdError) return err.message;\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\nexport type {\n ApiEnvelope,\n CreateNodeInput,\n TdBatchOperation,\n TdBatchResult,\n TdConnection,\n TdDeleteResult,\n TdExecResult,\n TdInfo,\n TdMethodResult,\n TdNodeDetail,\n TdNodeError,\n TdNodeErrors,\n TdNodeList,\n TdNodeRef,\n TdPerformance,\n TdPreview,\n TdTopology,\n} from \"./validators.js\";\n","import { TdApiError } from \"../td-client/types.js\";\n\n/**\n * Helpers for tools that drive a single Python pass inside TouchDesigner and read\n * back a structured JSON report. The payload travels as base64 so arbitrary user\n * strings (quotes, newlines, unicode) can never break Python's quoting; the report\n * is recovered from stdout even if TD interleaves its own log lines.\n */\n\n/** Base64-embeds a JSON payload into a Python template (replacing `__PAYLOAD_B64__`). */\nexport function buildPayloadScript(template: string, payload: object): string {\n const b64 = Buffer.from(JSON.stringify(payload), \"utf8\").toString(\"base64\");\n return template.replace(\"__PAYLOAD_B64__\", b64);\n}\n\n/** Pulls the JSON report object out of a script's stdout. */\nexport function parsePythonReport<T>(stdout: string | undefined): T {\n if (!stdout) throw new TdApiError(\"The TouchDesigner script returned no output.\");\n // The report is emitted as the final `print(json.dumps(...))`, so it is the\n // last non-empty line. Parse that first: it is robust to TD interleaving its\n // own log lines before the report — lines that may carry stray braces that\n // would otherwise widen (and corrupt) the `{` … `}` span heuristic below.\n const lines = stdout.split(\"\\n\");\n for (let i = lines.length - 1; i >= 0; i--) {\n const line = lines[i]?.trim();\n if (!line) continue;\n if (line.startsWith(\"{\") && line.endsWith(\"}\")) {\n try {\n return JSON.parse(line) as T;\n } catch {\n // not valid JSON on its own — fall through to the span heuristic\n }\n }\n break; // only the last non-empty line qualifies for the single-line fast path\n }\n // Fallback: widest `{` … `}` span (covers a report printed across lines).\n const start = stdout.indexOf(\"{\");\n const end = stdout.lastIndexOf(\"}\");\n if (start >= 0 && end > start) {\n try {\n return JSON.parse(stdout.slice(start, end + 1)) as T;\n } catch {\n // fall through to the shared error below\n }\n }\n throw new TdApiError(`Could not parse the TouchDesigner script result: ${stdout.slice(0, 200)}`);\n}\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { friendlyTdError } from \"../td-client/types.js\";\n\ntype Content = CallToolResult[\"content\"];\n\nexport function textResult(text: string): CallToolResult {\n return { content: [{ type: \"text\", text }] };\n}\n\n/**\n * An `isError` result. When `data` is supplied it is appended as a JSON code\n * fence (mirroring `jsonResult`) so a hard failure can still carry its structured\n * report — the difference from `jsonResult` is that `isError` is set, so the CLI\n * exits non-zero and MCP clients see the failure instead of a false success.\n */\nexport function errorResult(message: string, data?: unknown): CallToolResult {\n const text =\n data === undefined\n ? message\n : `${message}\\n\\n\\`\\`\\`json\\n${JSON.stringify(data, null, 2)}\\n\\`\\`\\``;\n return { isError: true, content: [{ type: \"text\", text }] };\n}\n\n/** A text block followed by a pretty-printed JSON code fence. */\nexport function jsonResult(summary: string, data: unknown): CallToolResult {\n const text = `${summary}\\n\\n\\`\\`\\`json\\n${JSON.stringify(data, null, 2)}\\n\\`\\`\\``;\n return { content: [{ type: \"text\", text }] };\n}\n\n/**\n * A short text summary plus a machine-readable `structuredContent` payload.\n *\n * Use this (with an `outputSchema` on the tool) for read tools so agents can\n * process the data with code instead of re-parsing a JSON code fence out of the\n * conversation. The text block stays small on purpose — it is only a summary;\n * the full data travels on the `structuredContent` channel.\n */\nexport function structuredResult(summary: string, data: object): CallToolResult {\n return {\n content: [{ type: \"text\", text: summary }],\n structuredContent: data as { [key: string]: unknown },\n };\n}\n\n/** An image block (base64), optionally preceded by a caption. */\nexport function imageResult(\n base64: string,\n mimeType = \"image/png\",\n caption?: string,\n): CallToolResult {\n const content: Content = [];\n if (caption) content.push({ type: \"text\", text: caption });\n content.push({ type: \"image\", data: base64, mimeType });\n return { content };\n}\n\n/**\n * Runs a client call and formats the result, converting any TD error into a\n * friendly `isError` result instead of throwing out of the MCP handler.\n */\nexport async function guardTd<T>(\n fn: () => Promise<T>,\n onOk: (value: T) => CallToolResult,\n): Promise<CallToolResult> {\n try {\n return onOk(await fn());\n } catch (err) {\n return errorResult(friendlyTdError(err));\n }\n}\n","import { buildNote, extractFencedBlock, parseNote } from \"../vault/frontmatter.js\";\nimport { type Recipe, RecipeSchema } from \"./schema.js\";\n\n/**\n * Recipes round-trip to Obsidian notes as: searchable YAML frontmatter (so the\n * vault's search and graph view see the id/name/tags) + an authoritative fenced\n * `json tdmcp-recipe` block holding the full recipe. The block is the source of\n * truth; the frontmatter is for the human and Obsidian.\n */\nconst RECIPE_FENCE = \"json tdmcp-recipe\";\n\n/** Serializes a recipe to an Obsidian note. */\nexport function recipeToMarkdown(recipe: Recipe): string {\n const data = {\n id: recipe.id,\n name: recipe.name,\n description: recipe.description,\n tags: recipe.tags,\n difficulty: recipe.difficulty,\n type: \"tdmcp-recipe\",\n };\n const intro = recipe.preview_description || recipe.description || recipe.name;\n const body = `${intro}\\n\\n\\`\\`\\`${RECIPE_FENCE}\\n${JSON.stringify(recipe, null, 2)}\\n\\`\\`\\`\\n`;\n return buildNote(data, body);\n}\n\n/** Parses a recipe note. Throws if the JSON block is missing or invalid. */\nexport function recipeFromMarkdown(raw: string): Recipe {\n const { body } = parseNote(raw);\n const json = extractFencedBlock(body, \"json\");\n if (!json) {\n throw new Error(\"recipe note has no ```json tdmcp-recipe code block\");\n }\n let data: unknown;\n try {\n data = JSON.parse(json);\n } catch (err) {\n throw new Error(`recipe note has invalid JSON: ${String(err)}`);\n }\n const parsed = RecipeSchema.safeParse(data);\n if (!parsed.success) {\n throw new Error(`recipe note failed validation (${parsed.error.issues.length} issue(s))`);\n }\n return parsed.data;\n}\n","import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve, sep } from \"node:path\";\nimport { type Logger, silentLogger } from \"../utils/logger.js\";\nimport { buildNote, type ParsedNote, parseNote } from \"./frontmatter.js\";\n\n/**\n * A thin, safe wrapper over an Obsidian vault (a folder of markdown files on the\n * local filesystem). Every path is resolved relative to the vault root and is\n * refused if it escapes that root, so user-supplied note names cannot reach\n * outside the vault.\n */\nexport class Vault {\n readonly root: string;\n private readonly logger: Logger;\n\n constructor(root: string, logger: Logger = silentLogger) {\n this.root = resolve(expandHome(root));\n this.logger = logger;\n this.logger.debug(\"vault ready\", { root: this.root });\n }\n\n /** Resolves a vault-relative path, throwing if it would escape the vault root. */\n resolve(relPath: string): string {\n const full = resolve(this.root, relPath);\n if (full !== this.root && !full.startsWith(this.root + sep)) {\n throw new Error(`Path escapes the vault: ${relPath}`);\n }\n return full;\n }\n\n exists(relPath: string): boolean {\n return existsSync(this.resolve(relPath));\n }\n\n read(relPath: string): string {\n return readFileSync(this.resolve(relPath), \"utf8\");\n }\n\n write(relPath: string, content: string): void {\n const full = this.resolve(relPath);\n mkdirSync(dirname(full), { recursive: true });\n writeFileSync(full, content, \"utf8\");\n }\n\n writeBinary(relPath: string, data: Buffer): void {\n const full = this.resolve(relPath);\n mkdirSync(dirname(full), { recursive: true });\n writeFileSync(full, data);\n }\n\n ensureDir(relPath: string): void {\n mkdirSync(this.resolve(relPath), { recursive: true });\n }\n\n /** Lists file names directly inside `subdir`, optionally filtered by extension. */\n list(subdir: string, ext?: string): string[] {\n const full = this.resolve(subdir);\n if (!existsSync(full)) return [];\n return readdirSync(full)\n .filter((f) => (ext ? f.endsWith(ext) : true))\n .sort();\n }\n\n /** Reads a markdown note and splits its frontmatter from its body. */\n readNote(relPath: string): ParsedNote {\n return parseNote(this.read(relPath));\n }\n\n /** Writes a markdown note from frontmatter data + body. */\n writeNote(relPath: string, data: Record<string, unknown>, body: string): void {\n this.write(relPath, buildNote(data, body));\n }\n}\n\nfunction expandHome(p: string): string {\n if (p === \"~\") return homedir();\n if (p.startsWith(\"~/\") || p.startsWith(`~${sep}`)) return join(homedir(), p.slice(2));\n return p;\n}\n","import { z } from \"zod\";\n\n/** Standard response envelope every bridge endpoint returns. */\nexport const ApiEnvelopeSchema = z.object({\n ok: z.boolean(),\n data: z.unknown().optional(),\n error: z.object({ code: z.string().optional(), message: z.string() }).optional(),\n});\nexport type ApiEnvelope = z.infer<typeof ApiEnvelopeSchema>;\n\nexport const NodeRefSchema = z.object({\n path: z.string(),\n type: z.string().default(\"\"),\n name: z.string().default(\"\"),\n /** Parameters that could not be applied at create time (unknown name or bad value). */\n parameter_warnings: z.array(z.string()).optional(),\n});\nexport type TdNodeRef = z.infer<typeof NodeRefSchema>;\n\nexport const NodeDetailSchema = NodeRefSchema.extend({\n parameters: z.record(z.string(), z.unknown()).default({}),\n inputs: z.array(z.string()).optional(),\n outputs: z.array(z.string()).optional(),\n family: z.string().optional(),\n errors: z.array(z.string()).optional(),\n});\nexport type TdNodeDetail = z.infer<typeof NodeDetailSchema>;\n\nexport const NodeListSchema = z.object({ nodes: z.array(NodeRefSchema).default([]) });\nexport type TdNodeList = z.infer<typeof NodeListSchema>;\n\nexport const InfoSchema = z.object({\n td_version: z.string().optional(),\n python_version: z.string().optional(),\n build: z.string().optional(),\n bridge_version: z.string().optional(),\n project: z.string().optional(),\n});\nexport type TdInfo = z.infer<typeof InfoSchema>;\n\nexport const NodeErrorSchema = z.object({\n path: z.string(),\n message: z.string(),\n type: z.string().optional(),\n});\nexport type TdNodeError = z.infer<typeof NodeErrorSchema>;\n\nexport const NodeErrorsSchema = z.object({ errors: z.array(NodeErrorSchema).default([]) });\nexport type TdNodeErrors = z.infer<typeof NodeErrorsSchema>;\n\nexport const PreviewSchema = z.object({\n path: z.string(),\n width: z.number().int().positive(),\n height: z.number().int().positive(),\n format: z.string().default(\"png\"),\n base64: z.string(),\n});\nexport type TdPreview = z.infer<typeof PreviewSchema>;\n\nexport const ExecResultSchema = z.object({\n result: z.unknown().optional(),\n stdout: z.string().optional(),\n printed: z.array(z.string()).optional(),\n});\nexport type TdExecResult = z.infer<typeof ExecResultSchema>;\n\nexport const MethodResultSchema = z.object({ result: z.unknown() });\nexport type TdMethodResult = z.infer<typeof MethodResultSchema>;\n\nexport const DeleteResultSchema = z.object({ deleted: z.string() });\nexport type TdDeleteResult = z.infer<typeof DeleteResultSchema>;\n\nexport const ConnectionSchema = z.object({\n source_path: z.string(),\n source_output: z.number().int().default(0),\n target_path: z.string(),\n target_input: z.number().int().default(0),\n});\nexport type TdConnection = z.infer<typeof ConnectionSchema>;\n\nexport const TopologySchema = z.object({\n nodes: z.array(NodeRefSchema).default([]),\n connections: z.array(ConnectionSchema).default([]),\n});\nexport type TdTopology = z.infer<typeof TopologySchema>;\n\nexport const PerformanceSchema = z.object({\n nodes: z\n .array(\n z.object({\n path: z.string(),\n cook_time_ms: z.number().default(0),\n cook_count: z.number().optional(),\n }),\n )\n .default([]),\n total_cook_time_ms: z.number().optional(),\n gpu_memory_mb: z.number().optional(),\n});\nexport type TdPerformance = z.infer<typeof PerformanceSchema>;\n\nexport const BatchOpResultSchema = z.object({\n action: z.string(),\n ok: z.boolean(),\n path: z.string().optional(),\n data: z.unknown().optional(),\n error: z.string().optional(),\n});\nexport const BatchResultSchema = z.object({ results: z.array(BatchOpResultSchema).default([]) });\nexport type TdBatchResult = z.infer<typeof BatchResultSchema>;\n\n/** Input shape for creating a node (used by the client and Layer 3 tool). */\nexport const CreateNodeInputSchema = z.object({\n parent_path: z.string(),\n type: z.string(),\n name: z.string().optional(),\n parameters: z.record(z.string(), z.unknown()).optional(),\n});\nexport type CreateNodeInput = z.infer<typeof CreateNodeInputSchema>;\n\n/** A single atomic operation accepted by `POST /api/batch`. */\nexport const BatchOperationSchema = z.discriminatedUnion(\"action\", [\n z.object({\n action: z.literal(\"create\"),\n parent_path: z.string(),\n type: z.string(),\n name: z.string().optional(),\n parameters: z.record(z.string(), z.unknown()).optional(),\n }),\n z.object({\n action: z.literal(\"update\"),\n path: z.string(),\n parameters: z.record(z.string(), z.unknown()),\n }),\n z.object({ action: z.literal(\"delete\"), path: z.string() }),\n z.object({\n action: z.literal(\"connect\"),\n source_path: z.string(),\n target_path: z.string(),\n source_output: z.number().int().default(0),\n target_input: z.number().int().default(0),\n }),\n]);\nexport type TdBatchOperation = z.infer<typeof BatchOperationSchema>;\n","import type { z } from \"zod\";\nimport { type Logger, silentLogger } from \"../utils/logger.js\";\nimport { TdApiError, TdConnectionError, TdTimeoutError } from \"./types.js\";\nimport {\n ApiEnvelopeSchema,\n BatchResultSchema,\n type CreateNodeInput,\n CreateNodeInputSchema,\n DeleteResultSchema,\n ExecResultSchema,\n InfoSchema,\n MethodResultSchema,\n NodeDetailSchema,\n NodeErrorsSchema,\n NodeListSchema,\n NodeRefSchema,\n PerformanceSchema,\n PreviewSchema,\n type TdBatchOperation,\n TopologySchema,\n} from \"./validators.js\";\n\nexport interface TouchDesignerClientOptions {\n baseUrl: string;\n timeoutMs?: number;\n logger?: Logger;\n /** Optional shared bearer token; sent as `Authorization: Bearer <token>` when set. */\n token?: string;\n /** Overridable for tests (defaults to global `fetch`). */\n fetchImpl?: typeof fetch;\n /**\n * Extra attempts for a transient connection failure on an **idempotent** (GET)\n * request — e.g. TD briefly stalls mid-build. Default 2 (so up to 3 tries).\n * Only `TdConnectionError` is retried; timeouts and bridge errors are not (a\n * timeout may mean the request was received, and non-GET methods aren't safe\n * to repeat). Set 0 to disable.\n */\n retries?: number;\n /** Base backoff between retries, in ms (linear: delay × attempt). Default 150. */\n retryDelayMs?: number;\n}\n\ntype QueryParams = Record<string, string | number | boolean | undefined>;\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nfunction extractErrorMessage(json: unknown): string | undefined {\n if (json && typeof json === \"object\") {\n const obj = json as Record<string, unknown>;\n const error = obj.error;\n if (\n error &&\n typeof error === \"object\" &&\n typeof (error as Record<string, unknown>).message === \"string\"\n ) {\n return (error as Record<string, string>).message;\n }\n if (typeof obj.message === \"string\") return obj.message;\n }\n return undefined;\n}\n\n/** Encodes a TD node path (which contains slashes) into a single URL segment. */\nfunction segment(path: string): string {\n return encodeURIComponent(path);\n}\n\n/**\n * HTTP client for the TouchDesigner REST bridge. Every method maps to one of the\n * endpoints in the bridge spec. All failures surface as typed `TdError`s so MCP\n * tool handlers can convert them into friendly messages without crashing.\n */\nexport class TouchDesignerClient {\n private readonly baseUrl: string;\n private readonly timeoutMs: number;\n private readonly logger: Logger;\n private readonly token: string | undefined;\n private readonly fetchImpl: typeof fetch;\n private readonly retries: number;\n private readonly retryDelayMs: number;\n\n constructor(options: TouchDesignerClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.timeoutMs = options.timeoutMs ?? 10000;\n this.logger = options.logger ?? silentLogger;\n this.token = options.token;\n this.fetchImpl = options.fetchImpl ?? fetch;\n this.retries = Math.max(0, options.retries ?? 2);\n this.retryDelayMs = Math.max(0, options.retryDelayMs ?? 150);\n }\n\n get endpoint(): string {\n return this.baseUrl;\n }\n\n private async request<T>(\n method: string,\n path: string,\n schema: z.ZodType<T>,\n body?: unknown,\n query?: QueryParams,\n ): Promise<T> {\n const url = new URL(`${this.baseUrl}${path}`);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined) url.searchParams.set(key, String(value));\n }\n }\n\n // Retry a transient connection failure only for idempotent GETs — a TD that\n // briefly stalls mid-build shouldn't abort the whole operation. Timeouts and\n // bridge/API errors are never retried (a timeout may mean the request was\n // received; non-GET methods aren't safe to repeat).\n const maxAttempts = method === \"GET\" ? this.retries + 1 : 1;\n let lastError: unknown;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await this.attemptRequest(method, url, path, schema, body);\n } catch (err) {\n lastError = err;\n if (err instanceof TdConnectionError && attempt < maxAttempts) {\n this.logger.debug(\n `TD ${method} ${path} connection failed (attempt ${attempt}/${maxAttempts}); retrying`,\n );\n await sleep(this.retryDelayMs * attempt);\n continue;\n }\n throw err;\n }\n }\n throw lastError;\n }\n\n private async attemptRequest<T>(\n method: string,\n url: URL,\n path: string,\n schema: z.ZodType<T>,\n body?: unknown,\n ): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n let response: Response;\n try {\n this.logger.debug(`TD ${method} ${path}`);\n const headers: Record<string, string> = {};\n if (body !== undefined) headers[\"content-type\"] = \"application/json\";\n if (this.token) headers.authorization = `Bearer ${this.token}`;\n response = await this.fetchImpl(url, {\n method,\n signal: controller.signal,\n headers: Object.keys(headers).length > 0 ? headers : undefined,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new TdTimeoutError(\n `TouchDesigner request timed out after ${this.timeoutMs}ms (${method} ${path}).`,\n { cause: err },\n );\n }\n throw new TdConnectionError(\n `Cannot reach TouchDesigner at ${this.baseUrl}. Make sure TD is running with the tdmcp bridge (WebServer DAT) installed and listening on that port.`,\n { cause: err },\n );\n } finally {\n clearTimeout(timer);\n }\n\n const text = await response.text();\n let json: unknown;\n if (text) {\n try {\n json = JSON.parse(text);\n } catch {\n json = undefined;\n }\n }\n\n if (!response.ok) {\n const message =\n extractErrorMessage(json) ??\n `TouchDesigner bridge returned HTTP ${response.status} for ${method} ${path}.`;\n throw new TdApiError(message, { status: response.status });\n }\n\n const envelope = ApiEnvelopeSchema.safeParse(json);\n if (!envelope.success) {\n throw new TdApiError(`Malformed response from TouchDesigner bridge for ${method} ${path}.`, {\n status: response.status,\n });\n }\n if (!envelope.data.ok) {\n throw new TdApiError(\n envelope.data.error?.message ?? `TouchDesigner reported an error for ${method} ${path}.`,\n { status: response.status, apiCode: envelope.data.error?.code },\n );\n }\n\n const parsed = schema.safeParse(envelope.data.data);\n if (!parsed.success) {\n throw new TdApiError(\n `Unexpected data shape from TouchDesigner bridge for ${method} ${path}: ${parsed.error.message}`,\n { status: response.status },\n );\n }\n return parsed.data;\n }\n\n getInfo() {\n return this.request(\"GET\", \"/api/info\", InfoSchema);\n }\n\n createNode(input: CreateNodeInput) {\n return this.request(\"POST\", \"/api/nodes\", NodeRefSchema, CreateNodeInputSchema.parse(input));\n }\n\n deleteNode(path: string) {\n return this.request(\"DELETE\", `/api/nodes/${segment(path)}`, DeleteResultSchema);\n }\n\n getNodes(parentPath?: string) {\n return this.request(\"GET\", \"/api/nodes\", NodeListSchema, undefined, { parent: parentPath });\n }\n\n getNode(path: string) {\n return this.request(\"GET\", `/api/nodes/${segment(path)}`, NodeDetailSchema);\n }\n\n updateNodeParameters(path: string, parameters: Record<string, unknown>) {\n return this.request(\"PATCH\", `/api/nodes/${segment(path)}`, NodeDetailSchema, { parameters });\n }\n\n executePythonScript(script: string, returnOutput = true) {\n return this.request(\"POST\", \"/api/exec\", ExecResultSchema, {\n script,\n return_output: returnOutput,\n });\n }\n\n execNodeMethod(\n path: string,\n method: string,\n args: unknown[] = [],\n kwargs: Record<string, unknown> = {},\n ) {\n return this.request(\"POST\", `/api/nodes/${segment(path)}/method`, MethodResultSchema, {\n method,\n args,\n kwargs,\n });\n }\n\n getNodeErrors(path: string) {\n return this.request(\"GET\", `/api/nodes/${segment(path)}/errors`, NodeErrorsSchema);\n }\n\n getPreview(path: string, width = 640, height = 360) {\n return this.request(\"GET\", `/api/preview/${segment(path)}`, PreviewSchema, undefined, {\n width,\n height,\n });\n }\n\n batch(operations: TdBatchOperation[]) {\n return this.request(\"POST\", \"/api/batch\", BatchResultSchema, { operations });\n }\n\n getNetworkErrors(path: string) {\n return this.request(\"GET\", `/api/network/${segment(path)}/errors`, NodeErrorsSchema);\n }\n\n getNetworkTopology(path: string, recursive = false) {\n return this.request(\n \"GET\",\n `/api/network/${segment(path)}/topology`,\n TopologySchema,\n undefined,\n recursive ? { recursive: true } : undefined,\n );\n }\n\n getNetworkPerformance(path: string, recursive = false) {\n return this.request(\n \"GET\",\n `/api/network/${segment(path)}/performance`,\n PerformanceSchema,\n undefined,\n recursive ? { recursive: true } : undefined,\n );\n }\n}\n","import { z } from \"zod\";\n\nexport const ConfigSchema = z.object({\n /** TouchDesigner bridge host. */\n tdHost: z.string().min(1).default(\"127.0.0.1\"),\n /** TouchDesigner bridge port (WebServer DAT). */\n tdPort: z.coerce.number().int().positive().max(65535).default(9980),\n /** MCP transport: `stdio` (default, for local clients) or `http` (Streamable HTTP, loopback-only). */\n transport: z.enum([\"stdio\", \"http\"]).default(\"stdio\"),\n /** Log verbosity (written to stderr). */\n logLevel: z.enum([\"debug\", \"info\", \"warn\", \"error\", \"silent\"]).default(\"info\"),\n /** Per-request timeout against the TD bridge, in milliseconds. */\n requestTimeoutMs: z.coerce.number().int().positive().default(10000),\n /** HTTP transport port (only used when transport=http). */\n httpPort: z.coerce.number().int().positive().max(65535).default(3939),\n /** Subscribe to TD WebSocket events and forward them as MCP logging notifications. */\n events: z.enum([\"on\", \"off\"]).default(\"on\"),\n /**\n * Raw Python escape-hatch tools (`execute_python_script`, `exec_node_method`).\n * Set to \"off\" to lock them out for restricted setups; on by default.\n */\n rawPython: z.enum([\"on\", \"off\"]).default(\"on\"),\n /**\n * Optional shared bearer token for the TD bridge. When set, the server sends it\n * as `Authorization: Bearer <token>` and the bridge requires a match. Leave unset\n * (default) for the zero-config local flow. Set the SAME value in TouchDesigner's\n * environment (`TDMCP_BRIDGE_TOKEN`) to turn enforcement on.\n */\n bridgeToken: z.string().min(1).optional(),\n /**\n * Base URL of an OpenAI-compatible chat endpoint used by `tdmcp chat` (the local\n * LLM copilot). Defaults to Ollama's local server. Point it at LM Studio, a cloud\n * GPU, or any OpenAI-compatible API to swap the model without code changes.\n */\n llmBaseUrl: z.string().min(1).default(\"http://127.0.0.1:11434/v1\"),\n /**\n * Model id the local copilot asks for (must be pulled in the backend, e.g.\n * `ollama pull qwen2.5:3b`). Default is `qwen2.5:3b`: in benchmarking it matched\n * the 7B/14B at 100% tool-calling on the copilot's simple-task workload while being\n * ~2x faster and <half the size — the sweet spot for the artist audience. Bump to\n * `qwen2.5:7b` for more answer-quality headroom; avoid sub-3B (flaky at tool use).\n */\n llmModel: z.string().min(1).default(\"qwen2.5:3b\"),\n /** Optional bearer token for the LLM endpoint (ignored by local Ollama; needed for paid/cloud APIs). */\n llmApiKey: z.string().min(1).optional(),\n /** Loopback port the `tdmcp chat` web UI binds to. */\n chatPort: z.coerce.number().int().positive().max(65535).default(4141),\n /**\n * Absolute path to an Obsidian vault (a folder of markdown notes) that backs\n * the vault integration tools. A leading `~/` is expanded to the home dir.\n * Leave unset (default) to disable those tools.\n */\n vaultPath: z.string().min(1).optional(),\n});\n\nexport type TdmcpConfig = z.infer<typeof ConfigSchema>;\n\n/**\n * Loads and validates configuration from environment variables. Missing values\n * fall back to sensible defaults; invalid values throw a descriptive ZodError.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv = process.env): TdmcpConfig {\n return ConfigSchema.parse({\n tdHost: env.TDMCP_TD_HOST,\n tdPort: env.TDMCP_TD_PORT,\n transport: env.TDMCP_TRANSPORT,\n logLevel: env.TDMCP_LOG_LEVEL,\n requestTimeoutMs: env.TDMCP_REQUEST_TIMEOUT_MS,\n httpPort: env.TDMCP_HTTP_PORT,\n events: env.TDMCP_EVENTS,\n rawPython: env.TDMCP_RAW_PYTHON,\n bridgeToken: env.TDMCP_BRIDGE_TOKEN || undefined,\n llmBaseUrl: env.TDMCP_LLM_BASE_URL,\n llmModel: env.TDMCP_LLM_MODEL,\n llmApiKey: env.TDMCP_LLM_API_KEY || undefined,\n chatPort: env.TDMCP_CHAT_PORT,\n vaultPath: env.TDMCP_VAULT_PATH || undefined,\n });\n}\n\n/** Base URL for the TouchDesigner REST bridge. */\nexport function tdBaseUrl(config: Pick<TdmcpConfig, \"tdHost\" | \"tdPort\">): string {\n return `http://${config.tdHost}:${config.tdPort}`;\n}\n","import { TouchDesignerClient } from \"../td-client/touchDesignerClient.js\";\nimport { type TdmcpConfig, tdBaseUrl } from \"../utils/config.js\";\nimport type { Logger } from \"../utils/logger.js\";\n\n/**\n * Owns the TouchDesigner client and exposes a cheap health probe. The MCP server\n * stays alive whether or not TD is reachable.\n */\nexport class ConnectionManager {\n readonly client: TouchDesignerClient;\n\n constructor(config: TdmcpConfig, logger: Logger) {\n this.client = new TouchDesignerClient({\n baseUrl: tdBaseUrl(config),\n timeoutMs: config.requestTimeoutMs,\n token: config.bridgeToken,\n logger,\n });\n }\n\n async isReachable(): Promise<boolean> {\n try {\n await this.client.getInfo();\n return true;\n } catch {\n return false;\n }\n }\n}\n","import { KnowledgeBase } from \"../knowledge/index.js\";\nimport { RecipeLibrary } from \"../recipes/loader.js\";\nimport type { ToolContext } from \"../tools/types.js\";\nimport type { TdmcpConfig } from \"../utils/config.js\";\nimport { createLogger, type Logger } from \"../utils/logger.js\";\nimport { Vault } from \"../vault/index.js\";\nimport { ConnectionManager } from \"./connectionManager.js\";\n\nexport interface ToolContextOverrides {\n logger?: Logger;\n knowledge?: KnowledgeBase;\n recipes?: RecipeLibrary;\n connection?: ConnectionManager;\n vault?: Vault;\n}\n\n/**\n * Assembles the shared {@link ToolContext} that backs every tool handler. Both\n * the MCP server and the agent CLI build their context here, so the two surfaces\n * stay on the same core (client + knowledge + recipes) without duplicating wiring.\n */\nexport function buildToolContext(\n config: TdmcpConfig,\n overrides: ToolContextOverrides = {},\n): ToolContext {\n const logger = overrides.logger ?? createLogger(config.logLevel);\n const connection = overrides.connection ?? new ConnectionManager(config, logger);\n const knowledge = overrides.knowledge ?? new KnowledgeBase({ logger });\n const vault =\n overrides.vault ?? (config.vaultPath ? new Vault(config.vaultPath, logger) : undefined);\n const recipes = overrides.recipes ?? new RecipeLibrary({ logger, vault });\n return {\n client: connection.client,\n knowledge,\n recipes,\n logger,\n vault,\n allowRawPython: config.rawPython !== \"off\",\n };\n}\n","import { type Logger, silentLogger } from \"../utils/logger.js\";\n\nexport interface TdEvent {\n event: string;\n data?: unknown;\n}\n\nexport type TdEventHandler = (event: TdEvent) => void;\n\n/** High-frequency events are dropped unless explicitly opted in, to avoid flooding. */\nconst HIGH_FREQUENCY = new Set([\"timeline.frame\", \"node.cook\"]);\n\n/**\n * Parses a raw WebSocket message into a `TdEvent`, applying the high-frequency\n * filter. Returns `undefined` for messages that should be ignored.\n */\nexport function parseEventMessage(raw: unknown, includeHighFrequency = false): TdEvent | undefined {\n if (typeof raw !== \"string\") return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return undefined;\n }\n if (!parsed || typeof parsed !== \"object\") return undefined;\n const event = (parsed as { event?: unknown }).event;\n if (typeof event !== \"string\") return undefined;\n if (!includeHighFrequency && HIGH_FREQUENCY.has(event)) return undefined;\n return { event, data: (parsed as { data?: unknown }).data };\n}\n\nexport interface TdEventStreamOptions {\n url: string;\n onEvent: TdEventHandler;\n logger?: Logger;\n includeHighFrequency?: boolean;\n}\n\n/**\n * Connects to the TouchDesigner bridge WebSocket and forwards events. Uses the\n * built-in global `WebSocket` (Node 22+), reconnects with exponential backoff,\n * and is fully optional — the server works whether or not this connects.\n */\nexport class TdEventStream {\n private socket?: WebSocket;\n private closed = false;\n private backoffMs = 1000;\n private readonly url: string;\n private readonly onEvent: TdEventHandler;\n private readonly logger: Logger;\n private readonly includeHighFrequency: boolean;\n\n constructor(options: TdEventStreamOptions) {\n this.url = options.url;\n this.onEvent = options.onEvent;\n this.logger = options.logger ?? silentLogger;\n this.includeHighFrequency = options.includeHighFrequency ?? false;\n }\n\n start(): void {\n this.connect();\n }\n\n private connect(): void {\n if (this.closed) return;\n let socket: WebSocket;\n try {\n socket = new WebSocket(this.url);\n } catch {\n this.scheduleReconnect();\n return;\n }\n this.socket = socket;\n socket.addEventListener(\"open\", () => {\n this.backoffMs = 1000;\n this.logger.debug(\"event stream connected\", { url: this.url });\n });\n socket.addEventListener(\"message\", (ev) => {\n const event = parseEventMessage((ev as { data?: unknown }).data, this.includeHighFrequency);\n if (!event) return;\n try {\n this.onEvent(event);\n } catch (err) {\n this.logger.debug(\"event handler failed\", { error: String(err) });\n }\n });\n socket.addEventListener(\"close\", () => this.scheduleReconnect());\n socket.addEventListener(\"error\", () => {\n // a \"close\" event follows; reconnection is handled there\n });\n }\n\n private scheduleReconnect(): void {\n if (this.closed) return;\n const delay = this.backoffMs;\n this.backoffMs = Math.min(this.backoffMs * 2, 30000);\n const timer = setTimeout(() => this.connect(), delay);\n timer.unref?.();\n }\n\n close(): void {\n this.closed = true;\n try {\n this.socket?.close();\n } catch {\n // ignore\n }\n }\n}\n","import { z } from \"zod\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nconst DIRECT_EFFECTS: Record<string, { type: string; parameters?: Record<string, unknown> }> = {\n // bloomTOP defaults bloom everything above 0.01 and adds it back, which blows bright\n // sources out to solid white. Raise the threshold so only highlights bloom, and soften the\n // intensity for a tasteful glow that preserves the underlying image.\n bloom: {\n type: \"bloomTOP\",\n parameters: { bloomthreshold: 0.8, bloomintensity: 0.6, bloomfill: 0.5 },\n },\n blur: { type: \"blurTOP\", parameters: { size: 4 } },\n edge_detect: { type: \"edgeTOP\" },\n sharpen: { type: \"sharpenTOP\" },\n threshold: { type: \"thresholdTOP\", parameters: { threshold: 0.5 } },\n invert: { type: \"levelTOP\", parameters: { invert: 1 } },\n color_grade: { type: \"levelTOP\", parameters: { gamma1: 1.1, blacklevel: 0.02 } },\n};\n\nconst GLSL_EFFECTS: Record<string, string> = {\n rgb_split: `out vec4 fragColor;\nvoid main(){ vec2 uv=vUV.st; vec2 o=vec2(0.004,0.0);\n float r=texture(sTD2DInputs[0],uv+o).r; float g=texture(sTD2DInputs[0],uv).g; float b=texture(sTD2DInputs[0],uv-o).b;\n fragColor=TDOutputSwizzle(vec4(r,g,b,1.0)); }\n`,\n chromatic_aberration: `out vec4 fragColor;\nvoid main(){ vec2 uv=vUV.st; vec2 o=(uv-0.5)*0.02;\n float r=texture(sTD2DInputs[0],uv+o).r; float g=texture(sTD2DInputs[0],uv).g; float b=texture(sTD2DInputs[0],uv-o).b;\n fragColor=TDOutputSwizzle(vec4(r,g,b,1.0)); }\n`,\n scanlines: `out vec4 fragColor;\nvoid main(){ vec2 uv=vUV.st; vec4 c=texture(sTD2DInputs[0],uv);\n float s=0.85+0.15*step(0.5,fract(uv.y*uTD2DInfos[0].res.w*0.5));\n fragColor=TDOutputSwizzle(vec4(c.rgb*s,c.a)); }\n`,\n vignette: `out vec4 fragColor;\nvoid main(){ vec2 uv=vUV.st; vec4 c=texture(sTD2DInputs[0],uv);\n float v=smoothstep(0.8,0.35,distance(uv,vec2(0.5)));\n fragColor=TDOutputSwizzle(vec4(c.rgb*v,c.a)); }\n`,\n posterize: `out vec4 fragColor;\nvoid main(){ vec2 uv=vUV.st; vec4 c=texture(sTD2DInputs[0],uv);\n vec3 p=floor(c.rgb*6.0)/6.0; fragColor=TDOutputSwizzle(vec4(p,c.a)); }\n`,\n film_grain: `out vec4 fragColor;\nfloat hash(vec2 p){return fract(sin(dot(p,vec2(12.9898,78.233)))*43758.5453);}\nvoid main(){ vec2 uv=vUV.st; vec4 c=texture(sTD2DInputs[0],uv);\n float g=hash(uv*uTD2DInfos[0].res.zw)*0.12-0.06; fragColor=TDOutputSwizzle(vec4(c.rgb+g,c.a)); }\n`,\n glitch: `out vec4 fragColor;\nfloat hash(float x){return fract(sin(x*127.1)*43758.5453);}\nvoid main(){ vec2 uv=vUV.st; float band=floor(uv.y*24.0);\n float off=(hash(band)-0.5)*0.06*step(0.7,hash(band*1.7));\n fragColor=TDOutputSwizzle(texture(sTD2DInputs[0],uv+vec2(off,0.0))); }\n`,\n};\n\nconst EFFECTS = [\n \"bloom\",\n \"chromatic_aberration\",\n \"film_grain\",\n \"vignette\",\n \"color_grade\",\n \"sharpen\",\n \"blur\",\n \"edge_detect\",\n \"invert\",\n \"threshold\",\n \"posterize\",\n \"glitch\",\n \"rgb_split\",\n \"scanlines\",\n] as const;\n\nexport const applyPostProcessingSchema = z.object({\n source_path: z.string().describe(\"Path of the TOP to post-process.\"),\n effects: z.array(z.enum(EFFECTS)).min(1).describe(\"Effects to apply in order.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype ApplyPostProcessingArgs = z.infer<typeof applyPostProcessingSchema>;\n\nasync function addGlslEffect(\n builder: NetworkBuilder,\n name: string,\n fragment: string,\n): Promise<string> {\n const glsl = await builder.add(\"glslTOP\", name);\n const frag = await builder.add(\"textDAT\", `${name}_frag`);\n await builder.python(\n `op(${q(frag)}).text = ${q(fragment)}\\nop(${q(glsl)}).par.pixeldat = op(${q(frag)}).name`,\n );\n return glsl;\n}\n\nexport async function applyPostProcessingImpl(ctx: ToolContext, args: ApplyPostProcessingArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"post_fx\");\n // Wires can't cross COMPs, so pull the external source in via a Select TOP (references by path).\n const source = await builder.add(\"selectTOP\", \"source\");\n await builder.setParams(source, { top: args.source_path });\n let previous = source;\n let applied = 0;\n\n for (let i = 0; i < args.effects.length; i++) {\n const effect = args.effects[i];\n if (!effect) continue;\n let nodePath: string | undefined;\n const direct = DIRECT_EFFECTS[effect];\n if (direct) {\n nodePath = await builder.add(direct.type, `${effect}${i}`, direct.parameters);\n } else if (GLSL_EFFECTS[effect]) {\n nodePath = await addGlslEffect(builder, `${effect}${i}`, GLSL_EFFECTS[effect]);\n }\n if (!nodePath) {\n builder.warnings.push(`Effect \"${effect}\" is not supported and was skipped.`);\n continue;\n }\n await builder.connect(previous, nodePath);\n previous = nodePath;\n applied++;\n }\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(previous, out);\n\n return finalize(ctx, {\n summary: `Applied ${applied}/${args.effects.length} post-processing effect(s) to ${args.source_path}.`,\n builder,\n outputPath: out,\n extra: { source_path: args.source_path, effects: args.effects },\n });\n });\n}\n\nexport const registerApplyPostProcessing: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"apply_post_processing\",\n {\n title: \"Apply post-processing\",\n description:\n \"Chain post-processing effects (bloom, glitch, rgb_split, vignette, etc.) onto an existing TOP. Returns the processed output.\",\n inputSchema: applyPostProcessingSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => applyPostProcessingImpl(ctx, args),\n );\n};\n","import type { TouchDesignerClient } from \"../td-client/touchDesignerClient.js\";\nimport type { TdNodeError } from \"../td-client/types.js\";\n\nexport interface ErrorReport {\n path: string;\n hasErrors: boolean;\n errors: TdNodeError[];\n}\n\n/** Checks a node (or its whole sub-network) for errors after building. */\nexport async function checkErrors(\n client: TouchDesignerClient,\n path: string,\n recursive = true,\n): Promise<ErrorReport> {\n const result = recursive ? await client.getNetworkErrors(path) : await client.getNodeErrors(path);\n return { path, hasErrors: result.errors.length > 0, errors: result.errors };\n}\n","import type { TouchDesignerClient } from \"../../td-client/touchDesignerClient.js\";\nimport { TdApiError } from \"../../td-client/types.js\";\n\nexport interface ConnectResult {\n method: \"batch\" | \"python\";\n}\n\n/**\n * Connects two nodes. Prefers the bridge `/api/batch` connect op; if the bridge\n * responds with an API error (e.g. batch not supported), falls back to a Python\n * `inputConnectors[...].connect(...)` call. Connection/timeout errors propagate.\n */\nexport async function connectNodesViaBridge(\n client: TouchDesignerClient,\n sourcePath: string,\n targetPath: string,\n sourceOutput = 0,\n targetInput = 0,\n): Promise<ConnectResult> {\n try {\n const result = await client.batch([\n {\n action: \"connect\",\n source_path: sourcePath,\n target_path: targetPath,\n source_output: sourceOutput,\n target_input: targetInput,\n },\n ]);\n if (result.results[0]?.ok) return { method: \"batch\" };\n } catch (err) {\n if (!(err instanceof TdApiError)) throw err;\n }\n\n // Fallback: wire via Python inside TD. Validate first so a cross-container\n // wire (which TD silently no-ops) or a missing op raises instead of reporting\n // a phantom success.\n const src = JSON.stringify(sourcePath);\n const dst = JSON.stringify(targetPath);\n const python = [\n `__s = op(${src}); __d = op(${dst})`,\n `if __s is None or __d is None: raise LookupError('connect: source or target not found (%s -> %s)' % (${src}, ${dst}))`,\n `if __s.parent() is None or __d.parent() is None or __s.parent().path != __d.parent().path: raise ValueError('connect: cannot wire across containers (%s -> %s); use a Select/In OP to bring an operator across networks' % (${src}, ${dst}))`,\n `__d.inputConnectors[${targetInput}].connect(__s.outputConnectors[${sourceOutput}])`,\n ].join(\"\\n\");\n await client.executePythonScript(python, false);\n return { method: \"python\" };\n}\n","/**\n * Network-editor auto-layout. Arranges nodes left→right along their data flow so\n * a generated (or existing) network reads as sources-on-the-left, output-on-the-right\n * instead of every node piling up at the same coordinate.\n *\n * Positions are written through TouchDesigner's `nodeX`/`nodeY` *attributes* (not\n * parameters), so they have no structured setter and are applied via a small Python\n * snippet — the same exec-for-attributes pattern used elsewhere for `numBlocks`.\n */\n\n/** Horizontal gap between successive data-flow layers, in TD network units. */\nconst X_STEP = 200;\n/** Vertical gap between sibling nodes within a layer, in TD network units. */\nconst Y_STEP = 140;\n/** Breathing room left between an existing cluster and a newly placed node. */\nconst SIBLING_GAP = 80;\n\nexport interface LayoutEdge {\n from: string;\n to: string;\n}\n\n/** Map of node path → `[nodeX, nodeY]`. */\nexport type Positions = Record<string, [number, number]>;\n\nfunction pushTo<K, V>(map: Map<K, V[]>, key: K, value: V): void {\n const existing = map.get(key);\n if (existing) existing.push(value);\n else map.set(key, [value]);\n}\n\n/** Parent network path of a node path (everything before the last \"/\"). */\nexport function parentOf(path: string): string {\n const i = path.lastIndexOf(\"/\");\n return i <= 0 ? \"/\" : path.slice(0, i);\n}\n\n/**\n * Assigns each node a layer = the longest data-flow path leading into it, so\n * sources land at layer 0 and each node sits one column right of its deepest input.\n * Back-edges (feedback loops) contribute nothing, which keeps cyclic networks\n * finite and readable.\n */\nfunction layerByLongestPath(\n nodes: readonly string[],\n preds: Map<string, string[]>,\n): Map<string, number> {\n const memo = new Map<string, number>();\n const visiting = new Set<string>();\n const depth = (node: string): number => {\n const cached = memo.get(node);\n if (cached !== undefined) return cached;\n if (visiting.has(node)) return 0; // back-edge inside a cycle\n visiting.add(node);\n let best = 0;\n for (const pred of preds.get(node) ?? []) best = Math.max(best, depth(pred) + 1);\n visiting.delete(node);\n memo.set(node, best);\n return best;\n };\n const layers = new Map<string, number>();\n for (const node of nodes) layers.set(node, depth(node));\n return layers;\n}\n\n/**\n * Computes left→right data-flow coordinates for one set of sibling nodes. Edges\n * touching a node outside the set are ignored, so callers spanning nested COMPs\n * must group by parent first (see {@link computeLayoutByParent}). Within a layer,\n * nodes are stacked vertically and centered, preserving their input order.\n */\nexport function computeDataflowLayout(\n nodes: readonly string[],\n edges: readonly LayoutEdge[],\n): Positions {\n const set = new Set(nodes);\n const preds = new Map<string, string[]>();\n for (const { from, to } of edges) {\n if (from === to || !set.has(from) || !set.has(to)) continue;\n pushTo(preds, to, from);\n }\n\n const layerOf = layerByLongestPath(nodes, preds);\n const byLayer = new Map<number, string[]>();\n for (const node of nodes) pushTo(byLayer, layerOf.get(node) ?? 0, node);\n\n const positions: Positions = {};\n for (const [layer, members] of byLayer) {\n const center = (members.length - 1) / 2;\n members.forEach((node, i) => {\n positions[node] = [layer * X_STEP, (center - i) * Y_STEP];\n });\n }\n return positions;\n}\n\n/**\n * Groups node paths by parent network and lays out each group independently,\n * merging the results. Use when a node set may span nested COMPs (e.g. a system\n * container holding child COMPs that have their own internal networks).\n */\nexport function computeLayoutByParent(\n nodes: readonly string[],\n edges: readonly LayoutEdge[],\n): Positions {\n const groups = new Map<string, string[]>();\n for (const node of nodes) pushTo(groups, parentOf(node), node);\n\n const merged: Positions = {};\n for (const members of groups.values()) {\n Object.assign(merged, computeDataflowLayout(members, edges));\n }\n return merged;\n}\n\n/**\n * Builds a Python snippet that writes `nodeX`/`nodeY` for each path. The position\n * map is JSON-encoded (a valid Python literal for this string/number subset) and\n * applied defensively, so a stale path can't abort the rest of the batch.\n */\nexport function layoutScript(positions: Positions): string {\n return [\n `_pos = ${JSON.stringify(positions)}`,\n \"for _p, _xy in _pos.items():\",\n \" _n = op(_p)\",\n \" if _n is not None:\",\n \" _n.nodeX = _xy[0]\",\n \" _n.nodeY = _xy[1]\",\n ].join(\"\\n\");\n}\n\n/**\n * Builds a Python snippet that drops a just-created node clear of its existing\n * siblings — left-aligned with the current cluster and one gap below its lowest\n * node — so repeated top-level creations stack into a tidy column instead of\n * piling up at the origin. The first node in an empty network lands at (0, 0).\n */\nexport function placeBelowSiblingsScript(parentPath: string, nodePath: string): string {\n const q = JSON.stringify;\n return [\n `_parent = op(${q(parentPath)})`,\n `_new = op(${q(nodePath)})`,\n \"if _parent is not None and _new is not None:\",\n \" _sibs = [c for c in _parent.children if c is not _new]\",\n \" if _sibs:\",\n \" _new.nodeX = min(c.nodeX for c in _sibs)\",\n ` _new.nodeY = min(c.nodeY for c in _sibs) - _new.nodeHeight - ${SIBLING_GAP}`,\n \" else:\",\n \" _new.nodeX = 0\",\n \" _new.nodeY = 0\",\n ].join(\"\\n\");\n}\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { checkErrors } from \"../../feedback/errorChecker.js\";\nimport { capturePreview } from \"../../feedback/previewCapture.js\";\nimport type { Recipe, RecipeGlslUniform } from \"../../recipes/schema.js\";\nimport { friendlyTdError } from \"../../td-client/types.js\";\nimport { connectNodesViaBridge } from \"../layer2/connectHelper.js\";\nimport { buildPanelScript, type ControlSpec } from \"../layer2/createControlPanel.js\";\nimport {\n computeLayoutByParent,\n type LayoutEdge,\n layoutScript,\n placeBelowSiblingsScript,\n} from \"../layout.js\";\nimport { parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult } from \"../result.js\";\nimport type { ToolContext } from \"../types.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\n/**\n * Maps each GLSL TOP uniform kind to the parameter *sequence* that binds it and the\n * per-block value sub-parameter suffixes (verified against a live GLSL TOP). A scalar\n * `uniform float` and a `uniform vecN` both bind through the \"Vectors\" page (the `vec`\n * sequence) — a float just fills the first (`valuex`) component; `color` binds through\n * the \"Colors\" page (the `color` sequence). The block name lives at `<seq><i>name`,\n * the values at `<seq><i><suffix>`. (The \"Constants\" page does not feed `uniform float`.)\n */\nconst UNIFORM_KINDS: Record<\n RecipeGlslUniform[\"kind\"],\n { seq: \"vec\" | \"color\"; fields: readonly string[] }\n> = {\n float: { seq: \"vec\", fields: [\"valuex\"] },\n vec: { seq: \"vec\", fields: [\"valuex\", \"valuey\", \"valuez\", \"valuew\"] },\n color: { seq: \"color\", fields: [\"rgbr\", \"rgbg\", \"rgbb\", \"alpha\"] },\n};\n\ninterface UniformGroup {\n node: string;\n seq: \"vec\" | \"color\";\n items: RecipeGlslUniform[];\n}\n\n/**\n * Groups uniforms by node + binding sequence, preserving order (block index = position\n * in group). `float` and `vec` share the `vec` sequence, so they land in one group and\n * receive distinct block indices.\n */\nfunction groupUniforms(uniforms: readonly RecipeGlslUniform[]): UniformGroup[] {\n const groups = new Map<string, UniformGroup>();\n for (const uniform of uniforms) {\n const { seq } = UNIFORM_KINDS[uniform.kind];\n const key = `${uniform.node} ${seq}`;\n let group = groups.get(key);\n if (!group) {\n group = { node: uniform.node, seq, items: [] };\n groups.set(key, group);\n }\n group.items.push(uniform);\n }\n return [...groups.values()];\n}\n\n/**\n * Conversion operators (e.g. `choptoTOP`, `dattoCHOP`, `toptoCHOP`, `soptoDAT`)\n * read their source from a parameter named after the source family, not from a\n * connector wire. Returns that parameter name (`chop`/`dat`/`top`/`sop`) or undefined.\n */\nfunction converterSourceParam(type: string): string | undefined {\n const match = /^(chop|dat|top|sop)to/i.exec(type);\n return match?.[1]?.toLowerCase();\n}\n\n/** Wraps a Layer 1 build, converting any thrown TD error into a friendly result. */\nexport async function runBuild(fn: () => Promise<CallToolResult>): Promise<CallToolResult> {\n try {\n return await fn();\n } catch (err) {\n return errorResult(friendlyTdError(err));\n }\n}\n\nexport interface CreatedNode {\n name: string;\n path: string;\n type: string;\n}\n\n/**\n * Stateful helper for building a network inside a container. Connection / param\n * failures are collected as warnings rather than thrown, so a partial build still\n * returns useful information (fail-forward).\n */\nexport class NetworkBuilder {\n readonly created: CreatedNode[] = [];\n readonly warnings: string[] = [];\n private readonly nameToPath = new Map<string, string>();\n private readonly pathToType = new Map<string, string>();\n // Intended data-flow wires, recorded even when the physical connect fails or is\n // satisfied via a source parameter, so auto-layout still reflects the flow.\n private readonly edges: LayoutEdge[] = [];\n\n constructor(\n private readonly ctx: ToolContext,\n readonly containerPath: string,\n ) {}\n\n async add(\n type: string,\n name?: string,\n parameters?: Record<string, unknown>,\n parentPath?: string,\n ): Promise<string> {\n const ref = await this.ctx.client.createNode({\n parent_path: parentPath ?? this.containerPath,\n type,\n name,\n parameters,\n });\n if (name) this.nameToPath.set(name, ref.path);\n if (ref.name) this.nameToPath.set(ref.name, ref.path);\n this.pathToType.set(ref.path, ref.type || type);\n this.created.push({ name: ref.name || name || \"\", path: ref.path, type: ref.type || type });\n // A fresh geometryCOMP ships with a default torus1 that renders over the real\n // geometry; clear its default children before the builder populates it.\n if (/geometrycomp/i.test(type)) {\n await this.python(`_g = op(${q(ref.path)})\\nfor _c in list(_g.children):\\n _c.destroy()`);\n }\n return ref.path;\n }\n\n pathOf(name: string): string | undefined {\n return this.nameToPath.get(name);\n }\n\n async connect(fromPath: string, toPath: string, fromOutput = 0, toInput = 0): Promise<void> {\n this.edges.push({ from: fromPath, to: toPath });\n // Conversion ops (choptoTOP, dattoCHOP, …) take their source via a parameter.\n const targetType = this.pathToType.get(toPath);\n const param = targetType ? converterSourceParam(targetType) : undefined;\n if (param) {\n await this.setParams(toPath, { [param]: fromPath });\n return;\n }\n try {\n await connectNodesViaBridge(this.ctx.client, fromPath, toPath, fromOutput, toInput);\n } catch (err) {\n this.warnings.push(`Failed to connect ${fromPath} → ${toPath}: ${friendlyTdError(err)}`);\n }\n }\n\n async setParams(path: string, parameters: Record<string, unknown>): Promise<void> {\n try {\n await this.ctx.client.updateNodeParameters(path, parameters);\n } catch (err) {\n this.warnings.push(`Failed to set parameters on ${path}: ${friendlyTdError(err)}`);\n }\n }\n\n async python(code: string): Promise<void> {\n try {\n await this.ctx.client.executePythonScript(code, false);\n } catch (err) {\n this.warnings.push(`Python step failed: ${friendlyTdError(err)}`);\n }\n }\n\n /** Arranges every created node left→right along the recorded data flow. */\n async layout(): Promise<void> {\n const positions = computeLayoutByParent(\n this.created.map((c) => c.path),\n this.edges,\n );\n if (Object.keys(positions).length === 0) return;\n try {\n await this.ctx.client.executePythonScript(layoutScript(positions), false);\n } catch (err) {\n this.warnings.push(`Auto-layout skipped: ${friendlyTdError(err)}`);\n }\n }\n}\n\n/** Creates a fresh base COMP to hold a visual system and returns a builder for it. */\nexport async function createSystemContainer(\n ctx: ToolContext,\n parentPath: string,\n name: string,\n): Promise<NetworkBuilder> {\n const container = await ctx.client.createNode({\n parent_path: parentPath,\n type: \"baseCOMP\",\n name,\n });\n // Drop the container clear of any existing siblings so repeated generations\n // stack into a column instead of overlapping at the origin. Cosmetic only —\n // a failure here must never abort the build.\n try {\n await ctx.client.executePythonScript(\n placeBelowSiblingsScript(parentPath, container.path),\n false,\n );\n } catch (err) {\n ctx.logger.debug(\"container placement skipped\", { err: String(err) });\n }\n return new NetworkBuilder(ctx, container.path);\n}\n\nexport interface RecipeBuildResult {\n builder: NetworkBuilder;\n outputPath?: string;\n /** Controls to auto-expose, with `bind_to` already resolved to real node paths. */\n controls?: ControlSpec[];\n}\n\n/** Instantiates a recipe inside a new container under `parentPath`. */\nexport async function buildFromRecipe(\n ctx: ToolContext,\n recipe: Recipe,\n parentPath: string,\n): Promise<RecipeBuildResult> {\n const builder = await createSystemContainer(ctx, parentPath, recipe.id);\n\n for (const node of recipe.nodes) {\n let parentPath: string | undefined;\n if (node.parent) {\n parentPath = builder.pathOf(node.parent);\n if (!parentPath) {\n builder.warnings.push(\n `Node \"${node.name}\" references unknown parent \"${node.parent}\" (it must appear earlier in nodes).`,\n );\n }\n }\n await builder.add(node.type, node.name, node.parameters, parentPath);\n }\n\n // Inline GLSL: place each shader in a Text DAT and point the GLSL TOP's pixeldat at it.\n if (recipe.glsl_code) {\n for (const [nodeName, code] of Object.entries(recipe.glsl_code)) {\n const target = builder.pathOf(nodeName);\n if (!target) {\n builder.warnings.push(`glsl_code references unknown node \"${nodeName}\".`);\n continue;\n }\n const fragPath = await builder.add(\"textDAT\", `${nodeName}_frag`);\n await builder.python(\n `op(${q(fragPath)}).text = ${q(code)}\\nop(${q(target)}).par.pixeldat = op(${q(fragPath)}).name`,\n );\n }\n }\n\n // GLSL TOP uniforms: these live in parameter sequences, so the block count must be\n // raised (op.seq.<seq>.numBlocks, which has no structured setter) before the\n // per-block name/value sub-parameters exist and can be set the normal way.\n for (const group of groupUniforms(recipe.glsl_uniforms)) {\n const target = builder.pathOf(group.node);\n if (!target) {\n builder.warnings.push(`glsl_uniforms references unknown node \"${group.node}\".`);\n continue;\n }\n await builder.python(\n `_seq = op(${q(target)}).seq.${group.seq}\\n_seq.numBlocks = max(_seq.numBlocks, ${group.items.length})`,\n );\n for (const [i, uniform] of group.items.entries()) {\n const { fields } = UNIFORM_KINDS[uniform.kind];\n const params: Record<string, unknown> = { [`${group.seq}${i}name`]: uniform.name };\n const values = Array.isArray(uniform.value)\n ? uniform.value\n : uniform.value === undefined\n ? []\n : [uniform.value];\n for (const [j, field] of fields.entries()) {\n const value = values[j];\n if (value !== undefined) params[`${group.seq}${i}${field}`] = value;\n }\n await builder.setParams(target, params);\n }\n }\n\n // Inline Python: set the target DAT's text.\n if (recipe.python_code) {\n for (const [nodeName, code] of Object.entries(recipe.python_code)) {\n const target = builder.pathOf(nodeName);\n if (!target) {\n builder.warnings.push(`python_code references unknown node \"${nodeName}\".`);\n continue;\n }\n await builder.python(`op(${q(target)}).text = ${q(code)}`);\n }\n }\n\n // Exposed parameters; a string value matching a node name resolves to that node's path.\n for (const param of recipe.parameters) {\n const target = builder.pathOf(param.node);\n if (!target) {\n builder.warnings.push(`Parameter \"${param.name}\" references unknown node \"${param.node}\".`);\n continue;\n }\n if (param.value === undefined) continue;\n let value = param.value;\n if (typeof value === \"string\") {\n const referenced = builder.pathOf(value);\n if (referenced) value = referenced;\n }\n await builder.setParams(target, { [param.param]: value });\n }\n\n for (const connection of recipe.connections) {\n const from = builder.pathOf(connection.from);\n const to = builder.pathOf(connection.to);\n if (!from || !to) {\n builder.warnings.push(\n `Connection ${connection.from} → ${connection.to} references an unknown node.`,\n );\n continue;\n }\n await builder.connect(from, to, connection.from_output, connection.to_input);\n }\n\n // Nested render geometry: make each flagged SOP the one its parent COMP renders,\n // clearing its siblings (including the COMP's default torus).\n for (const node of recipe.nodes) {\n if (!node.render) continue;\n const target = builder.pathOf(node.name);\n if (!target) continue;\n await builder.python(\n `_n = op(${q(target)})\\n_p = _n.parent()\\nfor _c in _p.children:\\n _c.render = False\\n _c.display = False\\n_n.render = True\\n_n.display = True`,\n );\n }\n\n const outNode =\n recipe.nodes.find((n) => /^out/i.test(n.name)) ?? recipe.nodes[recipe.nodes.length - 1];\n const outputPath = outNode ? builder.pathOf(outNode.name) : undefined;\n\n // Resolve each control's bind targets from recipe node *names* to the real created\n // paths, so the panel can bind them. An unresolved name is left as-is (it surfaces as\n // a warning when the panel runs).\n const controls: ControlSpec[] = recipe.controls.map((control) => ({\n ...control,\n bind_to: control.bind_to?.map((target) => {\n const dot = target.lastIndexOf(\".\");\n if (dot <= 0) return target;\n const path = builder.pathOf(target.slice(0, dot));\n return path ? `${path}.${target.slice(dot + 1)}` : target;\n }),\n }));\n\n return { builder, outputPath, controls };\n}\n\nexport interface FinalizeOptions {\n summary: string;\n builder: NetworkBuilder;\n outputPath?: string;\n recipeId?: string;\n capturePreviewImage?: boolean;\n /**\n * Controls to expose on the system container so the generated network is immediately\n * playable (knobs/sliders bound to its key parameters). Failures are folded into the\n * response warnings — they never abort the build.\n */\n controls?: ControlSpec[];\n extra?: Record<string, unknown>;\n}\n\ninterface ExposeControlsResult {\n created: Array<{ name: string }>;\n bound: Array<{ control: string; target: string }>;\n warnings: string[];\n fatal?: string;\n}\n\n/**\n * Appends a control panel (custom parameters bound to node parameters) to the system\n * container, reusing the same Python pass as the create_control_panel tool. Fail-forward:\n * any error is returned as a warning rather than thrown.\n */\nasync function exposeControls(\n ctx: ToolContext,\n compPath: string,\n controls: ControlSpec[],\n): Promise<ExposeControlsResult> {\n try {\n const script = buildPanelScript({ comp: compPath, page: \"Controls\", controls });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<ExposeControlsResult>(exec.stdout);\n } catch (err) {\n return { created: [], bound: [], warnings: [`Control panel skipped: ${friendlyTdError(err)}`] };\n }\n}\n\n/**\n * Shared \"verify → preview → respond\" step for Layer 1 tools: runs an error check,\n * captures a preview of the output TOP, and returns a structured result with an\n * inline preview image when available.\n */\nexport async function finalize(\n ctx: ToolContext,\n options: FinalizeOptions,\n): Promise<CallToolResult> {\n const { builder } = options;\n await builder.layout();\n const warnings = [...builder.warnings];\n\n // Expose live controls on the container so the generated system is playable on arrival.\n let controlsSummary: { added: string[]; bound: number } | undefined;\n if (options.controls?.length) {\n const result = await exposeControls(ctx, builder.containerPath, options.controls);\n warnings.push(...result.warnings);\n if (result.fatal) warnings.push(`Control panel skipped: ${result.fatal}`);\n else controlsSummary = { added: result.created.map((c) => c.name), bound: result.bound.length };\n }\n\n let errors: Array<{ path: string; message: string }> = [];\n try {\n const report = await checkErrors(ctx.client, builder.containerPath);\n errors = report.errors;\n if (report.hasErrors)\n warnings.push(`${report.errors.length} node error(s) detected after build.`);\n } catch (err) {\n warnings.push(`Error check unavailable: ${friendlyTdError(err)}`);\n }\n\n let previewBase64: string | undefined;\n let previewMime: string | undefined;\n if (options.capturePreviewImage !== false && options.outputPath) {\n try {\n const preview = await capturePreview(ctx.client, options.outputPath);\n previewBase64 = preview.base64;\n previewMime = preview.mimeType;\n } catch (err) {\n warnings.push(`Preview unavailable: ${friendlyTdError(err)}`);\n }\n }\n\n const data = {\n container: builder.containerPath,\n created: builder.created.map((c) => c.path),\n output: options.outputPath,\n recipe: options.recipeId,\n controls: controlsSummary,\n errors,\n warnings,\n ...options.extra,\n };\n\n const content: CallToolResult[\"content\"] = [\n {\n type: \"text\",\n text: `${options.summary}\\n\\n\\`\\`\\`json\\n${JSON.stringify(data, null, 2)}\\n\\`\\`\\``,\n },\n ];\n if (previewBase64) {\n content.push({ type: \"image\", data: previewBase64, mimeType: previewMime ?? \"image/png\" });\n }\n return { content };\n}\n","import { z } from \"zod\";\nimport { errorResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { buildFromRecipe, finalize, runBuild } from \"./orchestration.js\";\n\nexport const applyRecipeSchema = z.object({\n id: z.string().describe(\"Recipe id to build (see list_recipes).\"),\n parent_path: z.string().default(\"/project1\").describe(\"COMP to build the recipe inside.\"),\n});\ntype ApplyRecipeArgs = z.infer<typeof applyRecipeSchema>;\n\nexport async function applyRecipeImpl(ctx: ToolContext, args: ApplyRecipeArgs) {\n const recipe = ctx.recipes.get(args.id);\n if (!recipe) {\n const available = ctx.recipes\n .list()\n .map((r) => r.id)\n .join(\", \");\n return errorResult(`Recipe '${args.id}' not found. Available: ${available || \"none\"}.`);\n }\n return runBuild(async () => {\n const built = await buildFromRecipe(ctx, recipe, args.parent_path);\n return finalize(ctx, {\n summary: `Built recipe \"${recipe.name}\" (${recipe.id}).`,\n builder: built.builder,\n outputPath: built.outputPath,\n controls: built.controls,\n recipeId: recipe.id,\n extra: { recipe: recipe.id },\n });\n });\n}\n\nexport const registerApplyRecipe: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"apply_recipe\",\n {\n title: \"Apply recipe\",\n description:\n \"Instantiate a built-in recipe by id (from list_recipes) inside a COMP — a tested, ready-made network you can build in one call, then tweak. Verifies and previews the result.\",\n inputSchema: applyRecipeSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => applyRecipeImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nconst PRIMITIVE_SOP: Record<string, string> = {\n box: \"boxSOP\",\n sphere: \"sphereSOP\",\n};\n\nexport const create3dAudioReactiveSchema = z.object({\n source: z\n .enum([\"device\", \"file\", \"oscillator\", \"existing_chop\"])\n .default(\"device\")\n .describe(\n \"Audio source. 'device' = live microphone/line in (the real-world default; creating it may pop a one-time macOS microphone-permission dialog — click Allow). 'file' = an audio file. 'oscillator' = a synthetic tone (white noise → energy in every band, handy for testing without any device permission). 'existing_chop' = reuse a CHOP you already have.\",\n ),\n audio_file_path: z.string().optional().describe(\"Audio file path (source='file').\"),\n existing_chop_path: z\n .string()\n .optional()\n .describe(\"Path of an existing audio CHOP to analyze (source='existing_chop').\"),\n mode: z\n .enum([\"instanced_bars\", \"bass_pulse\"])\n .default(\"instanced_bars\")\n .describe(\n \"'instanced_bars' = a row of `bands` boxes/spheres, each one's height driven by one frequency bin (a 3D spectrum bar-graph). 'bass_pulse' = a single primitive that swells with the low-frequency energy (the guaranteed-visible fallback).\",\n ),\n bands: z.coerce\n .number()\n .int()\n .min(1)\n .max(64)\n .default(16)\n .describe(\"Number of bars in 'instanced_bars' mode — one per frequency bin.\"),\n primitive: z\n .enum([\"box\", \"sphere\"])\n .default(\"box\")\n .describe(\"Geometry rendered for each bar / the pulsing object.\"),\n spin: z.coerce\n .number()\n .min(0)\n .default(0)\n .describe(\n \"Whole-scene rotation around Y in degrees/sec (0 = still). Spins the entire bar row / object over time.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose live Sensitivity (audio gain), Zoom (camera distance), and Spin knobs.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype Create3dAudioReactiveArgs = z.infer<typeof create3dAudioReactiveSchema>;\n\n/** Builds the audio input CHOP, mirroring createSpectrum's source semantics. */\nasync function buildSource(\n builder: NetworkBuilder,\n args: Create3dAudioReactiveArgs,\n): Promise<string> {\n if (args.source === \"existing_chop\" && args.existing_chop_path) {\n return args.existing_chop_path;\n }\n if (args.source === \"file\") {\n return builder.add(\"audiofileinCHOP\", \"audioin\", {\n ...(args.audio_file_path ? { file: args.audio_file_path } : {}),\n play: 1,\n });\n }\n if (args.source === \"oscillator\") {\n // White noise has energy across all frequencies, so every band reads non-zero —\n // a self-contained signal for verifying the chain without any audio device.\n return builder.add(\"audiooscillatorCHOP\", \"audioin\", { wavetype: \"whitenoise\", amp: 0.5 });\n }\n return builder.add(\"audiodeviceinCHOP\", \"audioin\");\n}\n\nexport async function create3dAudioReactiveImpl(ctx: ToolContext, args: Create3dAudioReactiveArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"audio3d\");\n const source = await buildSource(builder, args);\n\n // FFT spectrum tail (same shape as create_spectrum): one channel of magnitude bins,\n // rebinned to exactly `bands` samples, then a Sensitivity gain and a Null bind point.\n // TouchDesigner clamps `outlength` into 128–4096, so request a comfortable FFT and\n // resample it down. Kept as 1 channel × N *samples* (NOT shuffled to channels): this\n // is the per-instance driver — bar i reads sample i of this single channel.\n const fftLength = Math.min(Math.max(args.bands, 128), 4096);\n const fft = await builder.add(\"audiospectrumCHOP\", \"spectrum_fft\", {\n outputmenu: \"setmanually\",\n outlength: fftLength,\n });\n await builder.connect(source, fft);\n\n const rebin = await builder.add(\"resampleCHOP\", \"rebin\", {\n relative: \"abs\",\n start: 0,\n end: args.bands - 1,\n startunit: \"samples\",\n endunit: \"samples\",\n interp: \"linear\",\n });\n await builder.connect(fft, rebin);\n\n const gain = await builder.add(\"mathCHOP\", \"sensitivity\", { gain: 1 });\n await builder.connect(rebin, gain);\n const spectrum = await builder.add(\"nullCHOP\", \"spectrum\");\n await builder.connect(gain, spectrum);\n\n // Geometry COMP (the builder clears its default torus on creation).\n const geo = await builder.add(\"geometryCOMP\", \"geo\");\n const primSop = PRIMITIVE_SOP[args.primitive] as string;\n const bar = await builder.add(primSop, \"bar\", {}, geo);\n await builder.python(`_s = op(${q(bar)})\\n_s.render = True\\n_s.display = True`);\n\n let camDist: number;\n\n if (args.mode === \"instanced_bars\") {\n // Per-bar layout and height both come from a CHOP instance source: one *sample* per bar,\n // carrying a `tx` channel (the X position) and a `sy` channel (the bar height = that band's\n // magnitude). The Geometry COMP instances `bar` once per sample, reading tx/sy by channel\n // name. This is what actually gives each bar its own height — a per-instance *expression*\n // is evaluated only once, so instancesy must read a channel, not an indexed expression\n // (validated live in TD: a ramp source produces a staircase of bars).\n const spacing = 1.0;\n const span = Math.max(1, args.bands - 1) * spacing;\n\n // X positions: a ramp across the row, centred on the origin. The pattern's length tracks the\n // spectrum's actual sample count (the FFT rebin may not land on exactly `bands`), so the\n // position channel always matches the height channel sample-for-sample.\n const barx = await builder.add(\"patternCHOP\", \"bar_x\", {\n wavetype: \"ramp\",\n amp: span,\n offset: -span / 2,\n channelname: \"tx\",\n });\n await builder.python(`op(${q(barx)}).par.length.expr = \"op('spectrum').numSamples\"`);\n\n // Heights: lift the tiny FFT magnitudes into a visible bar range, then rename the channel to\n // `sy` so the instancer reads it as per-bar Y scale. (Sensitivity still scales the source.)\n const heights = await builder.add(\"mathCHOP\", \"bar_height\", { gain: 12 });\n await builder.connect(spectrum, heights);\n const barsy = await builder.add(\"renameCHOP\", \"bar_sy\", { renamefrom: \"*\", renameto: \"sy\" });\n await builder.connect(heights, barsy);\n\n // Merge tx + sy into one N-sample instance source. align=\"start\" lines both channels up\n // from sample 0 — the spectrum chain and the pattern start at different sample indices, and\n // the default \"auto\" align would rotate the bins (scrambling the bar order).\n const inst = await builder.add(\"mergeCHOP\", \"bar_inst\", { align: \"start\" });\n await builder.connect(barx, inst, 0, 0);\n await builder.connect(barsy, inst, 0, 1);\n\n await builder.setParams(geo, {\n instancing: 1,\n instanceop: inst,\n instancetx: \"tx\",\n instancety: \"\",\n instancetz: \"\",\n instancesx: 0.4,\n instancesy: \"sy\",\n instancesz: 0.4,\n });\n\n camDist = span + 8;\n } else {\n // bass_pulse: a single rendered primitive (no instancing). An Analyze CHOP takes the\n // RMS of the source as a bass-energy proxy; the geo's uniform scale swells with it.\n const bass = await builder.add(\"analyzeCHOP\", \"bass\", { function: \"rmspower\" });\n await builder.connect(source, bass);\n const bassNull = await builder.add(\"nullCHOP\", \"bass_level\");\n await builder.connect(bass, bassNull);\n\n // Bind overall scale to 1 + bass * k. sx/sy/sz auto-switch to EXPRESSION mode.\n const k = 6;\n const scaleExpr = `1 + op(${q(bassNull)})[0] * ${k}`;\n await builder.python(\n `_g = op(${q(geo)})\\nfor _ax in (\"sx\", \"sy\", \"sz\"):\\n getattr(_g.par, _ax).expr = ${q(scaleExpr)}`,\n );\n builder.warnings.push(\n `Bass pulse mapping may need tuning for your material: geo sx/sy/sz are bound to '${scaleExpr}' (Analyze CHOP RMS Power of the source). Adjust the ×${k} multiplier, or swap the driver to a low-band reference like op('${spectrum}')[0] if you want a specific frequency to drive the swell.`,\n );\n\n camDist = 6;\n }\n\n const cam = await builder.add(\"cameraCOMP\", \"cam\", { tz: camDist });\n const light = await builder.add(\"lightCOMP\", \"light\", { tx: 3, ty: 3, tz: 5 });\n // Render TOP reads its scene from parameters (paths), not wires.\n const render = await builder.add(\"renderTOP\", \"render\", {\n camera: cam,\n geometry: geo,\n lights: light,\n });\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(render, out);\n\n // Whole-scene spin: an expression on the Geometry COMP's ry (auto-switches to\n // EXPRESSION mode) rotates the entire bar row / object over time.\n if (args.spin > 0) {\n await builder.python(`op(${q(geo)}).par.ry.expr = ${q(`absTime.seconds * ${args.spin}`)}`);\n }\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Sensitivity\",\n type: \"float\",\n min: 0,\n max: 8,\n default: 1,\n bind_to: [`${gain}.gain`],\n },\n {\n name: \"Zoom\",\n type: \"float\",\n min: 1,\n max: camDist * 3,\n default: camDist,\n bind_to: [`${cam}.tz`],\n },\n ...(args.spin > 0\n ? [\n {\n name: \"Spin\",\n type: \"float\" as const,\n min: 0,\n max: 360,\n default: args.spin,\n bind_to: [`${geo}.ry`],\n },\n ]\n : []),\n ]\n : [];\n\n const modeNote =\n args.mode === \"instanced_bars\"\n ? `${args.bands} ${args.primitive} bars`\n : `a pulsing ${args.primitive}`;\n return finalize(ctx, {\n summary: `Built a 3D audio-reactive scene (${modeNote}, source: ${args.source}) rendered to ${out} — FFT spectrum → Geometry + Camera + Light + Render TOP.${args.spin > 0 ? ` Whole scene spins ${args.spin}°/s.` : \"\"}`,\n builder,\n outputPath: out,\n controls,\n extra: {\n mode: args.mode,\n bands: args.bands,\n source: args.source,\n spin: args.spin,\n audio_source: source,\n spectrum_path: spectrum,\n geometry: geo,\n camera: cam,\n render,\n output_path: out,\n },\n });\n });\n}\n\nexport const registerCreate3dAudioReactive: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_3d_audio_reactive\",\n {\n title: \"Create 3D audio-reactive scene\",\n description:\n \"Build a 3D scene that reacts to sound — the 3D counterpart of create_audio_reactive. An FFT spectrum chain feeds geometry: 'instanced_bars' renders a row of `bands` boxes/spheres whose individual heights track each frequency bin (a 3D spectrum bar-graph), while 'bass_pulse' swells a single primitive with the low-frequency energy. Includes a Camera, Light, and Render TOP, output as a Null TOP. Exposes Sensitivity (audio gain), Zoom (camera distance), and Spin (whole-scene rotation) knobs. Source can be the live device (mic/line — may prompt for macOS permission), an audio file, a synthetic oscillator (for testing), or an existing CHOP.\",\n inputSchema: create3dAudioReactiveSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => create3dAudioReactiveImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nconst PRIMITIVE_SOP: Record<string, string> = {\n sphere: \"sphereSOP\",\n box: \"boxSOP\",\n grid: \"gridSOP\",\n};\n\nexport const create3dSceneSchema = z.object({\n primitive: z.enum([\"sphere\", \"box\", \"grid\"]).default(\"sphere\").describe(\"Geometry to render.\"),\n instances: z.coerce\n .number()\n .int()\n .positive()\n .default(1)\n .describe(\"Copies to scatter via GPU instancing on a grid (1 = a single object).\"),\n spin: z.coerce\n .number()\n .min(0)\n .default(0)\n .describe(\n \"Per-instance spin around Y in degrees/sec (0 = still). Each copy rotates in place over time; needs instances > 1.\",\n ),\n scale_variation: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(0)\n .describe(\n \"Per-instance size variation: 0 = all the same size, 1 = sizes range from 0 to full. Needs instances > 1.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose live RotateY (spin) and Zoom (camera distance) knobs.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype Create3dSceneArgs = z.infer<typeof create3dSceneSchema>;\n\nexport async function create3dSceneImpl(ctx: ToolContext, args: Create3dSceneArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"scene3d\");\n\n // Geometry COMP (the builder clears its default torus), with the chosen primitive SOP\n // inside it, flagged for render + display so the COMP renders it.\n const geo = await builder.add(\"geometryCOMP\", \"geo\");\n const shape = await builder.add(PRIMITIVE_SOP[args.primitive] as string, \"shape\", {}, geo);\n await builder.python(`_s = op(${q(shape)})\\n_s.render = True\\n_s.display = True`);\n\n // Instancing: scatter `instances` copies over a grid of points; the Geometry COMP renders the\n // shape once per point. instanceop needs the full path, and tx/ty/tz map to the point P attrs.\n const cols = Math.ceil(Math.sqrt(args.instances));\n const rows = Math.ceil(args.instances / cols);\n const spacing = 2.5;\n if (args.instances > 1) {\n const points = await builder.add(\n \"gridSOP\",\n \"points\",\n {\n rows,\n cols,\n sizex: Math.max(1, cols - 1) * spacing,\n sizey: Math.max(1, rows - 1) * spacing,\n },\n geo,\n );\n await builder.python(`_p = op(${q(points)})\\n_p.render = False\\n_p.display = False`);\n\n // Scale variation: a Point SOP writes a per-point `pscale` attribute (random per point via\n // tdu.rand), and instancesx/sy/sz read it so each copy gets its own size. Range is\n // [1 - variation, 1] — at variation 1 some copies shrink toward 0, at 0 it stays uniform.\n let instanceSrc = points;\n if (args.scale_variation > 0) {\n const pscale = await builder.add(\"pointSOP\", \"pscale\", {}, geo);\n await builder.connect(points, pscale);\n const lo = Number((1 - args.scale_variation).toFixed(4));\n const rng = Number(args.scale_variation.toFixed(4));\n await builder.python(\n `_p = op(${q(pscale)})\\n_p.par.dopscale = True\\n_p.par.pscale.expr = ${q(`${lo} + ${rng}*tdu.rand(me.inputPoint.index)`)}\\n_p.render = False\\n_p.display = False`,\n );\n instanceSrc = pscale;\n }\n\n const instanceParams: Record<string, unknown> = {\n instancing: 1,\n instanceop: instanceSrc,\n instancetx: \"P(0)\",\n instancety: \"P(1)\",\n instancetz: \"P(2)\",\n };\n if (args.scale_variation > 0) {\n instanceParams.instancesx = \"pscale\";\n instanceParams.instancesy = \"pscale\";\n instanceParams.instancesz = \"pscale\";\n }\n await builder.setParams(geo, instanceParams);\n\n // Per-instance spin: an expression on instancery (auto-switches the param to EXPRESSION mode)\n // rotates every copy around its own Y axis over time.\n if (args.spin > 0) {\n await builder.python(\n `op(${q(geo)}).par.instancery.expr = ${q(`absTime.seconds * ${args.spin}`)}`,\n );\n }\n }\n\n const camDist = args.instances > 1 ? Math.max(cols, rows) * spacing + 6 : 5;\n const cam = await builder.add(\"cameraCOMP\", \"cam\", { tz: camDist });\n const light = await builder.add(\"lightCOMP\", \"light\", { tx: 3, ty: 3, tz: 5 });\n // Render TOP reads its scene from parameters (not wires): camera, geometry, lights.\n const render = await builder.add(\"renderTOP\", \"render\", {\n camera: cam,\n geometry: geo,\n lights: light,\n });\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(render, out);\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n { name: \"RotateY\", type: \"float\", min: 0, max: 360, default: 0, bind_to: [`${geo}.ry`] },\n {\n name: \"Zoom\",\n type: \"float\",\n min: 1,\n max: camDist * 3,\n default: camDist,\n bind_to: [`${cam}.tz`],\n },\n ]\n : [];\n\n const instanceNote =\n args.instances > 1\n ? ` ×${args.instances} instanced${args.scale_variation > 0 ? \", varied scale\" : \"\"}${args.spin > 0 ? `, ${args.spin}°/s spin` : \"\"}`\n : \"\";\n return finalize(ctx, {\n summary: `Built a 3D scene (${args.primitive}${instanceNote}) rendered to ${out} — Geometry + Camera + Light + Render TOP.`,\n builder,\n outputPath: out,\n controls,\n extra: {\n primitive: args.primitive,\n instances: args.instances,\n spin: args.spin,\n scale_variation: args.scale_variation,\n geometry: geo,\n camera: cam,\n render,\n output_path: out,\n },\n });\n });\n}\n\nexport const registerCreate3dScene: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_3d_scene\",\n {\n title: \"Create 3D scene\",\n description:\n \"Build a renderable 3D scene: a Geometry COMP holding the chosen primitive (sphere/box/grid), a Camera, a Light, and a Render TOP, output as a Null — optionally instanced into a grid of `instances` copies via GPU instancing, with `scale_variation` for per-copy random sizes and `spin` for per-copy rotation over time. Exposes RotateY (whole-scene spin) and Zoom (camera distance) knobs. The starting point for 3D visuals — bind RotateY to a tempo ramp or an audio feature to make it move.\",\n inputSchema: create3dSceneSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => create3dSceneImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nconst AUDIO_SPECTRUM_SHADER = `out vec4 fragColor;\nvoid main(){\n vec2 uv = vUV.st;\n // Audio Spectrum CHOP magnitudes are tiny (~0.01–0.1); scale into the [0,1] bar\n // range so realistic input renders visible bars instead of a near-black frame.\n float amp = texture(sTD2DInputs[0], vec2(uv.x, 0.5)).r * 20.0;\n float bar = step(uv.y, clamp(amp, 0.0, 1.0));\n vec3 col = mix(vec3(0.02, 0.0, 0.08), vec3(0.1, 0.8, 1.0), uv.x) * bar;\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`;\n\n// Each non-\"glsl\" style gets its own spectrum visual (so they are not all the same shape).\n// All sample the spectrum texture (sTD2DInputs[0]); the *20 lifts the tiny magnitudes into a\n// visible range. Validated live in TD (all compile and render distinct content).\nconst STYLE_SHADERS: Record<string, string> = {\n // Radial spectrum bars emanating from the centre by angle.\n geometric: `out vec4 fragColor;\nvoid main(){\n vec2 pos = vUV.st - 0.5;\n float ang = atan(pos.y, pos.x) * 0.159155 + 0.5;\n float rad = length(pos) * 2.0;\n float amp = texture(sTD2DInputs[0], vec2(ang, 0.5)).r * 20.0;\n float bar = step(rad, clamp(amp, 0.0, 1.0));\n vec3 col = mix(vec3(0.05, 0.0, 0.15), vec3(0.2, 0.9, 1.0), ang) * bar;\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`,\n // A grid of dots whose size tracks each column's spectrum bin.\n particle: `out vec4 fragColor;\nvoid main(){\n vec2 uv = vUV.st;\n vec2 cell = fract(uv * 16.0) - 0.5;\n float colx = floor(uv.x * 16.0) / 16.0;\n float amp = texture(sTD2DInputs[0], vec2(colx, 0.5)).r * 20.0;\n float dot = smoothstep(0.45 * clamp(amp, 0.05, 1.0), 0.0, length(cell));\n vec3 col = dot * mix(vec3(0.1, 0.4, 1.0), vec3(1.0, 0.3, 0.6), uv.y);\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`,\n // Concentric rings warped by the spectrum — a tunnel/echo look.\n feedback: `out vec4 fragColor;\nvoid main(){\n vec2 pos = vUV.st - 0.5;\n float rad = length(pos);\n float ang = atan(pos.y, pos.x);\n float amp = texture(sTD2DInputs[0], vec2(rad, 0.5)).r * 20.0;\n float rings = 0.5 + 0.5 * sin(rad * 40.0 - amp * 12.0 + ang * 3.0);\n vec3 col = rings * mix(vec3(0.6, 0.1, 0.8), vec3(0.1, 0.8, 0.9), rad * 2.0);\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`,\n // An LED matrix: columns light up to a height set by their spectrum bin.\n instancing: `out vec4 fragColor;\nvoid main(){\n vec2 uv = vUV.st;\n vec2 cell = floor(uv * vec2(16.0, 8.0));\n vec2 fr = fract(uv * vec2(16.0, 8.0));\n float amp = texture(sTD2DInputs[0], vec2(cell.x / 16.0, 0.5)).r * 20.0;\n float lit = step((cell.y + 0.5) / 8.0, clamp(amp, 0.0, 1.0));\n float pad = step(0.1, fr.x) * step(fr.x, 0.9) * step(0.1, fr.y) * step(fr.y, 0.9);\n vec3 col = lit * pad * mix(vec3(0.0, 1.0, 0.4), vec3(1.0, 0.8, 0.0), cell.y / 8.0);\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`,\n};\n\nexport const createAudioReactiveSchema = z.object({\n audio_source: z.enum([\"microphone\", \"file\", \"device_in\", \"existing_chop\"]).default(\"microphone\"),\n audio_file_path: z.string().optional().describe(\"Audio file path (audio_source='file').\"),\n existing_chop_path: z\n .string()\n .optional()\n .describe(\"Existing CHOP path (audio_source='existing_chop').\"),\n visual_style: z.enum([\"geometric\", \"particle\", \"feedback\", \"glsl\", \"instancing\"]),\n frequency_bands: z.coerce\n .number()\n .int()\n .positive()\n .default(8)\n .describe(\n \"Spectrum resolution: sets the Audio Spectrum CHOP output length (TouchDesigner clamps it to 128–4096 bins). Higher = finer spectrum.\",\n ),\n beat_detection: z.boolean().default(true),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose a live 'Sensitivity' knob (how strongly the audio drives the visual).\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateAudioReactiveArgs = z.infer<typeof createAudioReactiveSchema>;\n\nasync function buildAudioSource(\n builder: NetworkBuilder,\n args: CreateAudioReactiveArgs,\n): Promise<string> {\n if (args.audio_source === \"existing_chop\" && args.existing_chop_path) {\n return args.existing_chop_path;\n }\n if (args.audio_source === \"file\") {\n return builder.add(\"audiofileinCHOP\", \"audioin\", {\n ...(args.audio_file_path ? { file: args.audio_file_path } : {}),\n play: 1,\n });\n }\n return builder.add(\"audiodeviceinCHOP\", \"audioin\");\n}\n\nexport async function createAudioReactiveImpl(ctx: ToolContext, args: CreateAudioReactiveArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"audio_reactive\");\n\n const audioSource = await buildAudioSource(builder, args);\n // Cap the spectrum output length so the downstream CHOP-to-TOP texture stays within\n // GPU limits. Left on \"Match Length To Frequency\", the spectrum emits ~22050 samples,\n // which overflows the 16384 max texture width and triggers a clamp warning. TouchDesigner\n // clamps outlength to 128–4096, so frequency_bands maps into that range.\n const outLength = Math.min(Math.max(args.frequency_bands, 128), 4096);\n const spectrum = await builder.add(\"audiospectrumCHOP\", \"spectrum\", {\n outputmenu: \"setmanually\",\n outlength: outLength,\n });\n await builder.connect(audioSource, spectrum);\n\n const analyze = await builder.add(\"analyzeCHOP\", \"level\", { function: 6 });\n await builder.connect(audioSource, analyze);\n\n if (args.beat_detection) {\n const beat = await builder.add(\"beatCHOP\", \"beat\");\n await builder.connect(audioSource, beat);\n }\n\n const audioTex = await builder.add(\"choptoTOP\", \"audio_tex\");\n await builder.connect(spectrum, audioTex);\n // A Sensitivity gain on the spectrum texture lets one knob scale how strongly the audio\n // drives every visual style — it multiplies the bins before the shaders' fixed *20 lift.\n // brightness1 = 1 is a passthrough, so the default leaves the look unchanged.\n const sensitivity = await builder.add(\"levelTOP\", \"sensitivity\", { brightness1: 1 });\n await builder.connect(audioTex, sensitivity);\n\n // Every style renders a GLSL spectrum visual: \"glsl\" is the classic horizontal bars;\n // geometric/particle/feedback/instancing each get their own shader (radial bars / dot\n // field / ring tunnel / LED grid). A fixed RGBA canvas avoids inheriting the audio\n // texture's Nx1 mono resolution, which would collapse the output to a 1px gray strip.\n const shader =\n args.visual_style === \"glsl\"\n ? AUDIO_SPECTRUM_SHADER\n : (STYLE_SHADERS[args.visual_style] ?? AUDIO_SPECTRUM_SHADER);\n const visual = await builder.add(\"glslTOP\", \"visual\", {\n outputresolution: \"custom\",\n resolutionw: 1280,\n resolutionh: 720,\n format: \"rgba8fixed\",\n });\n const frag = await builder.add(\"textDAT\", \"visual_frag\");\n await builder.python(\n `op(${q(frag)}).text = ${q(shader)}\\nop(${q(visual)}).par.pixeldat = op(${q(frag)}).name`,\n );\n await builder.connect(sensitivity, visual);\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(visual, out);\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Sensitivity\",\n type: \"float\",\n min: 0,\n max: 4,\n default: 1,\n bind_to: [`${sensitivity}.brightness1`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Created an audio-reactive system (source: ${args.audio_source}, style: ${args.visual_style}, ${args.frequency_bands} bands).`,\n builder,\n outputPath: out,\n controls,\n extra: {\n audio_source: args.audio_source,\n visual_style: args.visual_style,\n beat_detection: args.beat_detection,\n },\n });\n });\n}\n\nexport const registerCreateAudioReactive: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_audio_reactive\",\n {\n title: \"Create audio-reactive visual\",\n description:\n \"Build an audio analysis chain (spectrum + level + optional beat) and a spectrum visual driven by it. Each visual_style renders the spectrum its own way: glsl=horizontal bars, geometric=radial bars, particle=dot field, feedback=ring tunnel, instancing=LED grid.\",\n inputSchema: createAudioReactiveSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createAudioReactiveImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport const createAutopilotSchema = z.object({\n comp_path: z\n .string()\n .default(\"/project1\")\n .describe(\n \"COMP the autopilot drives — its numeric custom controls (randomize mode) or its stored cues (cue mode). Usually a generated system container or a control panel.\",\n ),\n mode: z\n .enum([\"randomize\", \"cue\"])\n .default(\"randomize\")\n .describe(\n \"'randomize' nudges the COMP's numeric controls toward new random values each trigger (works on any COMP with controls). 'cue' cycles through the COMP's stored cues (needs cues from manage_cue).\",\n ),\n beats: z.coerce\n .number()\n .int()\n .positive()\n .default(4)\n .describe(\"Fire an action every N beats (4 = once per bar at 4/4).\"),\n amount: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(0.5)\n .describe(\n \"(randomize) How far to move toward random each trigger: 1 = full scramble, low = gentle drift.\",\n ),\n parent_path: z.string().default(\"/project1\").describe(\"Where to create the autopilot engine.\"),\n});\ntype CreateAutopilotArgs = z.infer<typeof createAutopilotSchema>;\n\n// CHOP Execute callback (runs in TD's normal op context, so it imports td). It fires once per\n// beat on the Beat CHOP's cumulative `count` channel; every Nth beat (N = the live Beats knob,\n// while Active is on) it either scrambles the target COMP's numeric controls toward random by\n// the Amount knob, or recalls the next stored cue. __COMP__ / __MODE__ are filled in on build.\nconst ENGINE = `import td, random\n\ndef onValueChange(channel, sampleIndex, val, prev):\n if channel.name != 'count':\n return\n ap = me.parent()\n act = getattr(ap.par, 'Active', None)\n if act is not None and not act.eval():\n return\n bn = getattr(ap.par, 'Beats', None)\n n = int(bn.eval()) if bn is not None else 4\n if n < 1:\n n = 1\n if int(val) % n != 0:\n return\n target = op('__COMP__')\n if target is None:\n return\n if '__MODE__' == 'cue':\n cues = target.fetch('tdmcp_cues', {})\n names = sorted(cues.keys())\n if not names:\n return\n idx = (ap.fetch('tdmcp_cue_idx', -1) + 1) % len(names)\n ap.store('tdmcp_cue_idx', idx)\n for pn, v in cues[names[idx]].items():\n par = getattr(target.par, pn, None)\n if par is not None and not par.readOnly:\n try:\n par.val = v\n except Exception:\n pass\n else:\n an = getattr(ap.par, 'Amount', None)\n amt = float(an.eval()) if an is not None else 0.5\n if not hasattr(target, 'customPars'):\n return\n for par in target.customPars:\n if not getattr(par, 'isNumber', False) or par.readOnly:\n continue\n lo = par.normMin\n hi = par.normMax\n if lo is None or hi is None or hi <= lo:\n continue\n try:\n old = float(par.eval())\n except Exception:\n old = lo\n r = random.uniform(lo, hi)\n new = old * (1 - amt) + r * amt\n if par.style == 'Int':\n new = int(round(new))\n try:\n par.val = new\n except Exception:\n pass\n return\n`;\n\nexport async function createAutopilotImpl(ctx: ToolContext, args: CreateAutopilotArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"autopilot\");\n\n // A Beat CHOP on the global tempo, with the cumulative `count` channel turned on; the engine\n // watches it so an action fires exactly once per beat.\n const beat = await builder.add(\"beatCHOP\", \"beat\", { count: 1, beat: 1 });\n const engine = await builder.add(\"chopexecuteDAT\", \"engine\", {\n chop: beat,\n channel: \"count\",\n valuechange: 1,\n offtoon: 0,\n active: 1,\n });\n const text = ENGINE.replaceAll(\"__COMP__\", args.comp_path).replaceAll(\"__MODE__\", args.mode);\n await builder.python(`op(${q(engine)}).text = ${q(text)}`);\n\n // Live knobs the engine reads each beat: pause without deleting, retune the cadence, dial the\n // scramble amount. (No bind_to — they just expose the custom parameters.)\n const controls: ControlSpec[] = [\n { name: \"Active\", type: \"toggle\", default: 1, bind_to: [] },\n { name: \"Beats\", type: \"int\", min: 1, max: 32, default: args.beats, bind_to: [] },\n { name: \"Amount\", type: \"float\", min: 0, max: 1, default: args.amount, bind_to: [] },\n ];\n\n return finalize(ctx, {\n summary: `Built an autopilot driving ${args.comp_path} in ${args.mode} mode, every ${args.beats} beat(s). Toggle Active to pause; tune Beats/Amount live. ${\n args.mode === \"cue\"\n ? \"Store cues on the target with manage_cue first.\"\n : \"Randomizes the target's numeric controls.\"\n }`,\n builder,\n outputPath: beat,\n // The output is a CHOP engine, not a TOP, so there is no image to capture.\n capturePreviewImage: false,\n controls,\n extra: {\n target: args.comp_path,\n mode: args.mode,\n beats: args.beats,\n amount: args.amount,\n engine,\n },\n });\n });\n}\n\nexport const registerCreateAutopilot: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_autopilot\",\n {\n title: \"Create autopilot\",\n description:\n \"Build a beat-driven auto-VJ: a Beat CHOP + a CHOP Execute DAT that, every N beats, either randomizes a target COMP's numeric controls (a hands-free drift, set by Amount) or cycles through its stored cues — so a set keeps evolving on its own. Live Active/Beats/Amount knobs let you pause or retune on stage. Reuses the tempo clock, randomize_controls and manage_cue mechanisms. Pair with a generated system (or a control panel) as the target.\",\n inputSchema: createAutopilotSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createAutopilotImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nexport const createColorGradeSchema = z.object({\n brightness: z.coerce\n .number()\n .min(0)\n .default(1)\n .describe(\n \"Overall brightness / gain multiplier (1 = unchanged). Drives the Level TOP's `brightness1` (this is the gain control — the param is `brightness1`, NOT `gain`).\",\n ),\n gamma: z.coerce\n .number()\n .positive()\n .default(1)\n .describe(\n \"Gamma / mid-tone curve (1 = linear, <1 brightens mids, >1 darkens mids). Drives the Level TOP's `gamma1`.\",\n ),\n contrast: z.coerce\n .number()\n .min(0)\n .default(1)\n .describe(\"Contrast around mid-grey (1 = unchanged). Drives the Level TOP's `contrast`.\"),\n black_level: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(0)\n .describe(\n \"Lift the black point (0 = unchanged); raises the darkest pixels for a faded / filmic 'lift'. Drives the Level TOP's `blacklevel`.\",\n ),\n saturation: z.coerce\n .number()\n .min(0)\n .default(1)\n .describe(\n \"Colour saturation multiplier (0 = greyscale, 1 = unchanged, >1 = punchier). Drives the HSV Adjust TOP's `saturationmult`.\",\n ),\n hue: z.coerce\n .number()\n .default(0)\n .describe(\n \"Hue rotation in degrees (0 = unchanged, 0..360 wraps the colour wheel). Drives the HSV Adjust TOP's `hueoffset`.\",\n ),\n lut_path: z\n .string()\n .optional()\n .describe(\n \"Optional absolute path to a LUT image file (e.g. a 256x1 / 512x512 colour ramp). When given, a Movie File In TOP loads it and feeds the SECOND input of a Lookup TOP; the graded image is the first input, so each pixel is remapped through the LUT. Omit to skip LUT remapping.\",\n ),\n input_path: z\n .string()\n .optional()\n .describe(\n \"Optional absolute path of the source TOP to grade. Pulled in via a Select TOP (TD wires don't cross containers). If omitted, a Ramp TOP test gradient is graded so the chain still builds and previews without any device or external source.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\n \"Expose live Brightness / Gamma / Contrast / Saturation / Hue knobs bound to the right node parameters.\",\n ),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateColorGradeArgs = z.infer<typeof createColorGradeSchema>;\n\nexport async function createColorGradeImpl(ctx: ToolContext, args: CreateColorGradeArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"color_grade\");\n\n // Source: pull an external TOP in via a Select TOP (wires can't cross COMPs, so the\n // `top` param references it by ABSOLUTE path). With no input, grade a Ramp TOP test\n // gradient so the chain builds and previews standalone (no device / external source).\n let source: string;\n if (args.input_path) {\n source = await builder.add(\"selectTOP\", \"source\", { top: args.input_path });\n } else {\n // A horizontal gradient spans the full tonal/colour range, so brightness/gamma/\n // contrast/saturation/hue changes are all immediately visible in the preview.\n source = await builder.add(\"rampTOP\", \"source\", { type: \"horizontal\" });\n }\n\n // Lift / gamma / gain via the Level TOP. NOTE the TD param tokens: brightness is\n // `brightness1` (NOT `gain`), gamma is `gamma1`, plus `contrast` and `blacklevel`.\n const level = await builder.add(\"levelTOP\", \"grade_level\", {\n brightness1: args.brightness,\n gamma1: args.gamma,\n contrast: args.contrast,\n blacklevel: args.black_level,\n });\n await builder.connect(source, level);\n\n // Saturation + hue via the HSV Adjust TOP: `saturationmult` (Saturation Multiplier)\n // and `hueoffset` (Hue Offset, in degrees).\n const hsv = await builder.add(\"hsvadjustTOP\", \"grade_hsv\", {\n saturationmult: args.saturation,\n hueoffset: args.hue,\n });\n await builder.connect(level, hsv);\n\n // Optional LUT remap. The Lookup TOP recolours its FIRST input (the graded image)\n // through a lookup table built from its SECOND input. So load the LUT file with a\n // Movie File In TOP and wire it into input 1 (the 2nd input); the graded HSV output\n // is input 0. `lookup` selects the 2nd-input method (vs building the table from a CHOP).\n let output = hsv;\n if (args.lut_path) {\n const lut = await builder.add(\"moviefileinTOP\", \"lut_file\", { file: args.lut_path });\n const lookup = await builder.add(\"lookupTOP\", \"grade_lookup\", { lookup: \"input\" });\n await builder.connect(hsv, lookup, 0, 0);\n await builder.connect(lut, lookup, 0, 1);\n output = lookup;\n }\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(output, out);\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Brightness\",\n type: \"float\",\n min: 0,\n max: 4,\n default: args.brightness,\n bind_to: [`${level}.brightness1`],\n },\n {\n name: \"Gamma\",\n type: \"float\",\n min: 0.1,\n max: 4,\n default: args.gamma,\n bind_to: [`${level}.gamma1`],\n },\n {\n name: \"Contrast\",\n type: \"float\",\n min: 0,\n max: 4,\n default: args.contrast,\n bind_to: [`${level}.contrast`],\n },\n {\n name: \"Saturation\",\n type: \"float\",\n min: 0,\n max: 4,\n default: args.saturation,\n bind_to: [`${hsv}.saturationmult`],\n },\n {\n name: \"Hue\",\n type: \"float\",\n min: 0,\n max: 360,\n default: args.hue,\n bind_to: [`${hsv}.hueoffset`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Built a colour grade (brightness ${args.brightness}, gamma ${args.gamma}, contrast ${args.contrast}, saturation ${args.saturation}, hue ${args.hue}deg)${\n args.lut_path ? ` with LUT ${args.lut_path}` : \"\"\n }${args.input_path ? ` over ${args.input_path}` : \" over a test ramp\"} → ${out}.`,\n builder,\n outputPath: out,\n // Output is a TOP (the Null), so a preview image is captured.\n capturePreviewImage: true,\n controls,\n extra: {\n brightness: args.brightness,\n gamma: args.gamma,\n contrast: args.contrast,\n black_level: args.black_level,\n saturation: args.saturation,\n hue: args.hue,\n lut_path: args.lut_path,\n input_path: args.input_path,\n level_path: level,\n hsv_path: hsv,\n output_path: out,\n },\n });\n });\n}\n\nexport const registerCreateColorGrade: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_color_grade\",\n {\n title: \"Create color grade\",\n description:\n \"Build a colour-grading / LUT finishing stage over a source — the 'make the final output look graded' tool for VJ sets. A Level TOP applies lift/gamma/gain (brightness1 / gamma1 / contrast + black level), then an HSV Adjust TOP applies saturation + hue rotation; an optional LUT image file is loaded via a Movie File In TOP and fed into a Lookup TOP's second input to remap every colour. With an input_path the source is pulled in via a Select TOP (so it can live in another container); without one, a Ramp TOP test gradient is graded so it builds and previews standalone. Live Brightness / Gamma / Contrast / Saturation / Hue knobs are exposed. Output is a Null TOP.\",\n inputSchema: createColorGradeSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createColorGradeImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nconst BARS_SHADER = `out vec4 fragColor;\nvoid main(){\n vec2 uv = vUV.st;\n float v = texture(sTD2DInputs[0], vec2(uv.x, 0.5)).r;\n float bar = step(uv.y, clamp(v, 0.0, 1.0));\n vec3 col = mix(vec3(0.03, 0.05, 0.1), vec3(0.2, 0.9, 0.6), uv.x) * bar;\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`;\n\nconst SOURCE_TYPE = {\n table: \"tableDAT\",\n file: \"fileinDAT\",\n chop: \"constantCHOP\",\n} as const;\n\nexport const createDataVisualizationSchema = z.object({\n data_source: z.enum([\"table\", \"file\", \"chop\"]).default(\"table\"),\n chart_style: z.enum([\"bars\", \"graph\", \"points\"]).default(\"bars\"),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose a live 'Scale' knob that amplifies the data values feeding the chart.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateDataVisualizationArgs = z.infer<typeof createDataVisualizationSchema>;\n\nexport async function createDataVisualizationImpl(\n ctx: ToolContext,\n args: CreateDataVisualizationArgs,\n) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"data_viz\");\n const source = await builder.add(SOURCE_TYPE[args.data_source], \"data\");\n\n // Seed the placeholder table so the chart shows sample bars immediately instead of a\n // blank 1x1 output; an empty table yields a single zero-valued sample.\n if (args.data_source === \"table\") {\n const rows = Array.from({ length: 16 }, (_, i) =>\n (0.5 + 0.45 * Math.sin(i * 0.6)).toFixed(3),\n );\n await builder.python(\n `d = op(${q(source)})\\nd.clear()\\nfor v in ${JSON.stringify(rows)}:\\n d.appendRow([v])`,\n );\n }\n\n let chop = source;\n if (args.data_source !== \"chop\") {\n // dattoCHOP defaults firstcolumn to \"names\", which turns a single numeric column into\n // channel *names* with value 0; read the column as values (one channel, N samples).\n chop = await builder.add(\"dattoCHOP\", \"datto\", {\n firstrow: \"values\",\n firstcolumn: \"values\",\n output: \"chanpercol\",\n });\n await builder.connect(source, chop);\n }\n\n const tex = await builder.add(\"choptoTOP\", \"data_tex\");\n await builder.connect(chop, tex);\n // A Scale gain on the data texture lets one knob amplify the values feeding the chart;\n // brightness1 = 1 is a passthrough, so the default leaves the chart unchanged.\n const scale = await builder.add(\"levelTOP\", \"scale\", { brightness1: 1 });\n await builder.connect(tex, scale);\n\n let visual = scale;\n if (args.chart_style === \"bars\") {\n // Fixed canvas + RGBA. Left on \"use input\", the chart inherits the data texture's\n // tiny Nx1 mono resolution, collapsing the output to a grayscale speck.\n const glsl = await builder.add(\"glslTOP\", \"chart\", {\n outputresolution: \"custom\",\n resolutionw: 1280,\n resolutionh: 720,\n format: \"rgba8fixed\",\n });\n const frag = await builder.add(\"textDAT\", \"chart_frag\");\n await builder.python(\n `op(${q(frag)}).text = ${q(BARS_SHADER)}\\nop(${q(glsl)}).par.pixeldat = op(${q(frag)}).name`,\n );\n await builder.connect(scale, glsl);\n visual = glsl;\n } else {\n builder.warnings.push(\n `Chart style \"${args.chart_style}\" renders the data as a texture strip; richer plotting needs customization.`,\n );\n }\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(visual, out);\n builder.warnings.push(\n \"Wire your real data into the 'data' node — a placeholder source was created.\",\n );\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Scale\",\n type: \"float\",\n min: 0,\n max: 4,\n default: 1,\n bind_to: [`${scale}.brightness1`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Created a data visualization (source: ${args.data_source}, style: ${args.chart_style}).`,\n builder,\n outputPath: out,\n controls,\n extra: { data_source: args.data_source, chart_style: args.chart_style },\n });\n });\n}\n\nexport const registerCreateDataVisualization: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_data_visualization\",\n {\n title: \"Create data visualization\",\n description:\n \"Build a data-driven visualization: a data source feeds a CHOP that drives a chart TOP. Wire your real data into the created 'data' node.\",\n inputSchema: createDataVisualizationSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createDataVisualizationImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport const createDepthDisplacementSchema = z.object({\n source: z\n .enum([\"camera\", \"file\", \"synthetic\", \"existing_top\"])\n .default(\"synthetic\")\n .describe(\n \"Depth/luminance source that drives the relief. 'camera' = live webcam/capture device (creating it may pop a one-time macOS camera-permission dialog — click Allow). 'file' = a movie file. 'synthetic' = an animated noise pattern, so the relief moves and the chain is testable without any device permission (the default). 'existing_top' = displace by a TOP you already have (e.g. a real depth map).\",\n ),\n movie_file_path: z.string().optional().describe(\"Movie file path (source='file').\"),\n existing_top_path: z\n .string()\n .optional()\n .describe(\"Path of an existing TOP to sample as the height map (source='existing_top').\"),\n subdivisions: z.coerce\n .number()\n .int()\n .min(2)\n .default(100)\n .describe(\n \"Grid resolution (rows = cols). Higher = finer relief and smoother displacement, but more vertices to push. 100 gives a 100×100 plane.\",\n ),\n depth: z.coerce\n .number()\n .min(0)\n .default(1)\n .describe(\n \"Displacement amount along Z: how far bright (or dark, if inverted) pixels push the surface out of the plane. 0 = flat.\",\n ),\n invert: z\n .boolean()\n .default(false)\n .describe(\n \"Flip the height mapping. false = bright pixels push toward the camera (bright = near); true = dark pixels push toward the camera (dark = near).\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose live Depth (displacement amount) and Zoom (camera distance) knobs.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateDepthDisplacementArgs = z.infer<typeof createDepthDisplacementSchema>;\n\n/**\n * Builds the depth/luminance source TOP, mirroring create_motion_reactive's buildSource:\n * camera → Video Device In, file → Movie File In (playing), synthetic → an animated Noise\n * (a tz expression scrolls it so the relief breathes), existing_top → the given path.\n */\nasync function buildSource(\n builder: NetworkBuilder,\n args: CreateDepthDisplacementArgs,\n): Promise<string> {\n if (args.source === \"existing_top\" && args.existing_top_path) {\n return args.existing_top_path;\n }\n if (args.source === \"file\") {\n return builder.add(\"moviefileinTOP\", \"videoin\", {\n ...(args.movie_file_path ? { file: args.movie_file_path } : {}),\n play: 1,\n });\n }\n if (args.source === \"synthetic\") {\n // A scrolling noise field: a moving height map so the relief animates and the chain is\n // verifiable without any camera permission.\n const noise = await builder.add(\"noiseTOP\", \"videoin\");\n await builder.python(`op(${q(noise)}).par.tz.expr = \"absTime.seconds * 0.5\"`);\n return noise;\n }\n return builder.add(\"videodeviceinTOP\", \"videoin\");\n}\n\nexport async function createDepthDisplacementImpl(\n ctx: ToolContext,\n args: CreateDepthDisplacementArgs,\n) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"depth_displacement\");\n const source = await buildSource(builder, args);\n\n // A monochrome version of the source is the height map: one luminance value per pixel,\n // sampled by the displacement material to offset each vertex along Z.\n const heightmap = await builder.add(\"monochromeTOP\", \"heightmap\");\n await builder.connect(source, heightmap);\n\n // Geometry COMP (the builder clears its default torus) holding a subdivided grid. A finer\n // grid resolves finer relief. The grid SOP is flagged render + display so the COMP renders it.\n const geo = await builder.add(\"geometryCOMP\", \"geo\");\n const surface = await builder.add(\n \"gridSOP\",\n \"surface\",\n { rows: args.subdivisions, cols: args.subdivisions },\n geo,\n );\n await builder.python(`_s = op(${q(surface)})\\n_s.render = True\\n_s.display = True`);\n\n // Displacement material: a GLSL MAT (`glslMAT`) whose vertex stage samples the height map TOP\n // and offsets P.z by (luminance × depth). This is the real-geometry path (a true 2.5D relief),\n // unlike a flat displace TOP. The grid is built on the XY plane, so we push along +Z.\n const mat = await builder.add(\"glslMAT\", \"displace\");\n\n // Vertex shader: sample the height map at the grid's UVs and offset position along Z by\n // luminance × uDepth (real geometry displacement). TouchDesigner MAT conventions: deform the\n // point position through TDDeform/TDWorldToProj, no built-in uTime, explicit uniforms.\n // `uInvert` flips bright↔near; the sampler is `sHeight`; iLum carries the height to the pixel\n // stage so the relief is shaded by elevation.\n const vertexShader = [\n // A GLSL MAT does not auto-declare named samplers (unlike a GLSL TOP's sTD2DInputs) — the\n // `sampler0name` par binds the height map to this explicitly-declared uniform.\n \"uniform sampler2D sHeight;\",\n \"uniform float uDepth;\",\n \"uniform float uInvert;\",\n \"out float iLum;\",\n \"void main() {\",\n \"\\tfloat lum = texture(sHeight, uv[0].st).r;\",\n \"\\tlum = mix(lum, 1.0 - lum, uInvert);\",\n \"\\tiLum = lum;\",\n \"\\tvec3 p = P;\",\n \"\\tp.z += lum * uDepth;\",\n \"\\tgl_Position = TDWorldToProj(TDDeform(vec4(p, 1.0)));\",\n \"}\",\n ].join(\"\\n\");\n const vertDat = await builder.add(\"textDAT\", \"displace_vert\");\n\n // Pixel shader: shade the surface by elevation (dark valleys → bright peaks) so the relief\n // reads even on a flat-lit scene. A GLSL MAT needs both a vertex and a pixel stage.\n const pixelShader = [\n \"in float iLum;\",\n \"out vec4 fragColor;\",\n \"void main() {\",\n \"\\tvec3 col = vec3(0.15 + 0.85 * iLum);\",\n \"\\tfragColor = TDOutputSwizzle(vec4(col, 1.0));\",\n \"}\",\n ].join(\"\\n\");\n const fragDat = await builder.add(\"textDAT\", \"displace_pixel\");\n\n // Wire the GLSL MAT: vertex DAT (`vdat`), pixel DAT (`pdat`), sampler 0 → the height map TOP\n // named `sHeight` (`sampler0top` / `sampler0name`), and the uDepth/uInvert float uniforms via\n // the \"Vectors\" sequence (`vec0..`) — all par names verified live against a real GLSL MAT.\n await builder.python(\n [\n `op(${q(vertDat)}).text = ${q(vertexShader)}`,\n `op(${q(fragDat)}).text = ${q(pixelShader)}`,\n `_m = op(${q(mat)})`,\n `_m.par.vdat = op(${q(vertDat)}).name`,\n `_m.par.pdat = op(${q(fragDat)}).name`,\n `_m.par.sampler0top = ${q(heightmap)}`,\n '_m.par.sampler0name = \"sHeight\"',\n \"_seq = _m.seq.vec\",\n \"_seq.numBlocks = max(_seq.numBlocks, 2)\",\n '_m.par.vec0name = \"uDepth\"',\n `_m.par.vec0valuex = ${args.depth}`,\n '_m.par.vec1name = \"uInvert\"',\n `_m.par.vec1valuex = ${args.invert ? 1 : 0}`,\n ].join(\"\\n\"),\n );\n\n // Assign the material to the Geometry COMP (mirrors create_3d_scene / create_waveform).\n await builder.python(`op(${q(geo)}).par.material = ${q(mat)}`);\n\n // Camera pulled back and angled down so the relief reads as depth, not a flat plane. A light\n // for the render scene; the displaced surface catches it. Render TOP reads its scene from\n // PARAMETERS (camera/geometry/lights), not wires.\n const cam = await builder.add(\"cameraCOMP\", \"cam\", { tz: 4, ty: 2, rx: -28 });\n const light = await builder.add(\"lightCOMP\", \"light\", { tx: 3, ty: 4, tz: 5 });\n const render = await builder.add(\"renderTOP\", \"render\", {\n camera: cam,\n geometry: geo,\n lights: light,\n });\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(render, out);\n\n // Keep-alive: a still source (e.g. a paused movie or an existing static depth map) leaves the\n // height map cold, so the surface would never re-displace. A tiny Execute DAT force-cooks the\n // output each frame so the relief stays live even before anything is bound (mirrors\n // create_motion_reactive's cooker idiom).\n const cooker = await builder.add(\"executeDAT\", \"cooker\");\n await builder.python(\n `_c = op(${q(cooker)})\\n_c.text = \"def onFrameStart(frame):\\\\n\\\\tparent().op('out1').cook(force=True)\\\\n\\\\treturn\\\\n\"\\n_c.par.framestart = True\\n_c.par.active = True`,\n );\n\n // Depth knob binds to the GLSL MAT's uDepth uniform value (vec0valuex, verified live).\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Depth\",\n type: \"float\",\n min: 0,\n max: Math.max(4, args.depth * 3),\n default: args.depth,\n bind_to: [`${mat}.vec0valuex`],\n },\n { name: \"Zoom\", type: \"float\", min: 1, max: 20, default: 4, bind_to: [`${cam}.tz`] },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Built a depth-displacement relief (source: ${args.source}) — a ${args.subdivisions}×${args.subdivisions} grid pushed into 3D by a luminance/depth map via a GLSL MAT, rendered to ${out}.`,\n builder,\n outputPath: out,\n controls,\n extra: {\n source: args.source,\n subdivisions: args.subdivisions,\n depth: args.depth,\n invert: args.invert,\n output_path: out,\n },\n });\n });\n}\n\nexport const registerCreateDepthDisplacement: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_depth_displacement\",\n {\n title: \"Create depth displacement\",\n description:\n \"Push a flat plane into real 3D relief by a depth/luminance map: a subdivided grid whose vertices are offset along Z by a GLSL displacement material sampling the source's brightness, rendered with a camera + light so it reads as depth that shifts with the view. Unlike create_depth_silhouette (a flat 2D mask), this is true geometry — a 2.5D landscape. Source can be the live camera (may prompt for macOS permission), a movie file, an animated synthetic pattern (testable without a camera), or an existing TOP (e.g. a real depth map). `subdivisions` sets the relief resolution, `depth` the push amount, `invert` flips bright↔near. Exposes Depth and Zoom knobs — bind Depth to a tempo ramp or an audio feature to make the surface heave.\",\n inputSchema: createDepthDisplacementSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createDepthDisplacementImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\n/**\n * Depth/IR capture devices whose TOPs were confirmed to exist in this build's knowledge base\n * (kinect_azure_top → kinectazureTOP, kinect_top → kinectTOP, realsense_top → realsenseTOP).\n * Selecting one of these creates the live sensor op, which on macOS may pop a one-time\n * camera/depth permission modal that can hang TD until the artist clicks Allow — so none of\n * these is the default. The exact per-device parameter names (which feed depth vs. colour, the\n * player/body index, etc.) still need live confirmation; we create the op with defaults and let\n * the threshold chain isolate the body from whatever single-channel signal it emits.\n */\nconst DEPTH_DEVICE_OPS: Record<string, string> = {\n kinect_azure: \"kinectazureTOP\",\n kinect: \"kinectTOP\",\n realsense: \"realsenseTOP\",\n};\n\nexport const createDepthSilhouetteSchema = z.object({\n source: z\n .enum([\"synthetic\", \"file\", \"kinect_azure\", \"kinect\", \"realsense\"])\n .default(\"synthetic\")\n .describe(\n \"Where the depth/luma signal comes from. 'synthetic' (the default) = a self-contained animated noise/ramp field that needs ZERO device permissions, so the network builds and previews immediately — use it to dial in the look. 'file' = a movie/image file (source_file_path). 'kinect_azure' | 'kinect' | 'realsense' = a live depth/IR sensor (the real installation source); creating it may pop a one-time macOS camera/depth-permission dialog — click Allow. (The depth-device op names are confirmed to exist; their per-device params still need live confirmation.)\",\n ),\n source_file_path: z\n .string()\n .optional()\n .describe(\n \"Movie/image file path for source='file' (e.g. a pre-recorded depth or IR clip). Ignored for other sources.\",\n ),\n threshold: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(0.5)\n .describe(\n \"Depth/luma cutoff (0..1) that separates the body from the background: pixels brighter than this become the white silhouette, the rest go black. The headline 'Threshold' knob and the parameter to bind to audio/beat/proximity later.\",\n ),\n smooth: z.coerce\n .number()\n .min(0)\n .default(0.5)\n .describe(\n \"Edge smoothing — a Blur TOP filter size applied to the raw mask to round off jagged sensor edges before the silhouette is keyed. 0 = hard, aliased edges; higher = softer outline.\",\n ),\n invert: z\n .boolean()\n .default(false)\n .describe(\n \"Invert the mask (swap silhouette and background). Off = white body on black; on = black body on white. Drives a Level TOP's invert.\",\n ),\n fill_color: z\n .string()\n .optional()\n .describe(\n \"Optional hex colour ('#rrggbb') to fill the silhouette with instead of plain white — keyed through the mask via a Constant TOP composited (multiply) against it. Omit for a white-on-black mask.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\n \"Expose live Threshold / Smooth / Invert (+ FillColor) controls on the system container.\",\n ),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateDepthSilhouetteArgs = z.infer<typeof createDepthSilhouetteSchema>;\n\n/** Parses '#rrggbb' / 'rrggbb' (3- or 6-digit) into 0..1 RGB. Falls back to white. */\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());\n if (!m) return { r: 1, g: 1, b: 1 };\n let h = m[1] as string;\n if (h.length === 3)\n h = h\n .split(\"\")\n .map((c) => c + c)\n .join(\"\");\n const int = Number.parseInt(h, 16);\n return {\n r: ((int >> 16) & 0xff) / 255,\n g: ((int >> 8) & 0xff) / 255,\n b: (int & 0xff) / 255,\n };\n}\n\n/**\n * The single-channel source the silhouette is keyed from. The default 'synthetic' source is a\n * self-contained animated monochrome noise field — no device, no permissions — that gives the\n * threshold something with bright/dark structure to isolate (mimicking a near/far depth signal),\n * and a slow drift so the preview is alive. 'file' brings in a movie/image via a Movie File In\n * TOP. The depth-device kinds create the confirmed sensor op directly (live, permission-gated).\n */\nasync function buildSource(\n builder: NetworkBuilder,\n args: CreateDepthSilhouetteArgs,\n): Promise<string> {\n if (args.source === \"file\") {\n return builder.add(\"moviefileinTOP\", \"source\", {\n ...(args.source_file_path ? { file: args.source_file_path } : {}),\n play: 1,\n });\n }\n const deviceOp = DEPTH_DEVICE_OPS[args.source];\n if (deviceOp) {\n // Live sensor — created with defaults; the threshold chain isolates the body from whatever\n // single-channel (depth/IR/player-index) signal it emits. May prompt for macOS permission.\n return builder.add(deviceOp, \"source\");\n }\n // Monochrome noise = a device-free stand-in for a depth/IR feed: bright blobs read as\n // \"near\" (the body) against a darker field, so the threshold isolates a moving silhouette.\n const src = await builder.add(\"noiseTOP\", \"source\", { monochrome: 1, period: 3 });\n await builder.python(\n `_p = op(${q(src)}).par.tz\\n_PM = type(_p.mode)\\n_p.expr = ${q(\"absTime.seconds * 0.15\")}\\n_p.mode = _PM.EXPRESSION`,\n );\n return src;\n}\n\nexport async function createDepthSilhouetteImpl(ctx: ToolContext, args: CreateDepthSilhouetteArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"depth_silhouette\");\n\n const source = await buildSource(builder, args);\n\n // Smooth the raw signal first so the keyed edge is clean rather than per-pixel noisy.\n // blurTOP size is the filter width (0 = no blur). Smooth maps straight to it.\n const blur = await builder.add(\"blurTOP\", \"smooth\", { size: args.smooth });\n await builder.connect(source, blur);\n\n // Key the body out of the (smoothed) signal: a Threshold TOP emits white where the input is\n // brighter than `threshold`, black elsewhere — the silhouette mask. comparator='greater'\n // makes \"near/bright = body\"; soften gives the mask edge a little feather. This is the\n // headline knob (Threshold) and the bind target for reactive proximity.\n const mask = await builder.add(\"thresholdTOP\", \"mask\", {\n threshold: args.threshold,\n comparator: \"greater\",\n soften: 0.05,\n });\n await builder.connect(blur, mask);\n\n // Optional invert (swap body/background). levelTOP's `invert` (0/1) flips black<->white;\n // it sits in the chain always so the Invert toggle can drive it live regardless of the\n // build-time default. brightness1=1 keeps it a clean pass-through otherwise.\n const level = await builder.add(\"levelTOP\", \"invert\", {\n invert: args.invert ? 1 : 0,\n brightness1: 1,\n });\n await builder.connect(mask, level);\n\n // Optional coloured fill: a flat Constant TOP keyed THROUGH the mask via a multiply\n // composite (input 0 = colour, input 1 = mask → colour survives only where the mask is\n // white). Without a fill_color the white-on-black mask itself is the output.\n let output = level;\n let fillRgb: { r: number; g: number; b: number } | undefined;\n if (args.fill_color) {\n fillRgb = hexToRgb(args.fill_color);\n const fill = await builder.add(\"constantTOP\", \"fill\", {\n colorr: fillRgb.r,\n colorg: fillRgb.g,\n colorb: fillRgb.b,\n alpha: 1,\n });\n const keyed = await builder.add(\"compositeTOP\", \"keyed\", { operand: \"multiply\" });\n await builder.connect(fill, keyed, 0, 0);\n await builder.connect(level, keyed, 0, 1);\n output = keyed;\n }\n\n // Null = the stable output bind point (other tools/composites reference op('…/out1')).\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(output, out);\n\n // Threshold is the headline knob; Smooth the blur size; Invert toggles the level invert.\n // FillColor is an RGB swatch (the ControlSpec 'rgb' type does not support bind_to, so it\n // is a convenience display of the build-time fill — only shown when a fill was set).\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Threshold\",\n type: \"float\",\n min: 0,\n max: 1,\n default: args.threshold,\n bind_to: [`${mask}.threshold`],\n },\n {\n name: \"Smooth\",\n type: \"float\",\n min: 0,\n max: 32,\n default: args.smooth,\n bind_to: [`${blur}.size`],\n },\n {\n name: \"Invert\",\n type: \"toggle\",\n default: args.invert,\n bind_to: [`${level}.invert`],\n },\n ...(fillRgb\n ? [\n {\n name: \"FillColor\",\n type: \"rgb\" as const,\n default: args.fill_color,\n },\n ]\n : []),\n ]\n : [];\n\n const sourceLabel =\n args.source === \"synthetic\"\n ? \"device-free synthetic noise\"\n : args.source === \"file\"\n ? `file ${args.source_file_path ?? \"(unset)\"}`\n : `${args.source} sensor`;\n\n return finalize(ctx, {\n summary: `Built a depth silhouette / body mask (source: ${sourceLabel}, threshold ${args.threshold}) → ${out}. White silhouette on black${\n args.fill_color ? ` filled ${args.fill_color}` : \"\"\n }${args.invert ? \" (inverted)\" : \"\"}. Bind op('${mask}').par.threshold to proximity/audio to make it react, or use ${out} as a mask for other visuals.`,\n builder,\n outputPath: out,\n // Output is a TOP (the Null), so a preview image is captured.\n capturePreviewImage: true,\n controls,\n extra: {\n source: args.source,\n source_file_path: args.source_file_path,\n threshold: args.threshold,\n smooth: args.smooth,\n invert: args.invert,\n fill_color: args.fill_color,\n mask_path: mask,\n output_path: out,\n },\n });\n });\n}\n\nexport const registerCreateDepthSilhouette: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_depth_silhouette\",\n {\n title: \"Create depth silhouette\",\n description:\n \"Extract a silhouette / body mask from a depth or video source — a person's white outline on black you can composite, fill with colour, or use as a mask for reactive visuals (interactive installations / camera-reactive sets). The signal is smoothed (Blur TOP), keyed to a mask (Threshold TOP), optionally inverted (Level TOP) and optionally filled with a colour keyed through the mask (Constant + multiply Composite). Source defaults to a self-contained synthetic noise field so it builds and previews with ZERO device permissions; pick 'file' for a clip, or a 'kinect_azure'/'kinect'/'realsense' sensor for the live installation (may prompt for macOS permission). Exposes Threshold (bind to proximity/audio), Smooth, Invert (+ FillColor) and outputs a Null TOP.\",\n inputSchema: createDepthSilhouetteSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createDepthSilhouetteImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nconst RESOLUTIONS = {\n \"1024\": 1024,\n \"2048\": 2048,\n \"4096\": 4096,\n} as const;\n\nexport const createDomeOutputSchema = z.object({\n source_path: z\n .string()\n .describe(\n \"The master TOP to remap, treated as an equirectangular / panoramic source (the full 360°×180° latlong image the dome warps from).\",\n ),\n projection: z\n .enum([\"fisheye\", \"equirectangular\"])\n .default(\"fisheye\")\n .describe(\n \"fisheye: warp the equirectangular source into a centred dome disc (planetarium fulldome master). equirectangular: near-passthrough identity remap, so an already-equirect source still yields a valid output.\",\n ),\n resolution: z\n .enum([\"1024\", \"2048\", \"4096\"])\n .default(\"2048\")\n .describe(\"Square dome-master resolution (width = height).\"),\n fov: z.coerce\n .number()\n .min(1)\n .max(360)\n .default(180)\n .describe(\n \"Fisheye coverage in degrees (the angular diameter the disc spans). 180 = full hemisphere (standard fulldome); larger over-fills, smaller zooms in. Used by the fisheye shader.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\n \"Expose a Rotation knob bound to the shader uniform that spins the dome horizon (degrees).\",\n ),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateDomeOutputArgs = z.infer<typeof createDomeOutputSchema>;\n\n/**\n * A GLSL fragment shader that remaps an equirectangular source TOP (sTD2DInputs[0]) into a\n * dome master. For \"fisheye\": the output disc (centred vUV) is read as a polar angle (radius →\n * polar angle θ via `fov`, vUV angle → azimuth φ), turned into a spherical direction, and that\n * direction samples the latlong source at `(φ/2π+0.5, θ/π+0.5)`; pixels outside the unit disc are\n * black. `uRotation` (a `uniform float`, radians) spins the azimuth so the dome horizon can turn.\n * For \"equirectangular\": a near-passthrough identity remap sampling sTD2DInputs[0] at vUV.st (with\n * the same `uRotation` horizontal wrap), so an already-equirect source still produces valid output.\n */\nfunction remapShader(projection: \"fisheye\" | \"equirectangular\", fovDeg: number): string {\n const PI = \"3.14159265359\";\n const TWO_PI = \"6.28318530718\";\n if (projection === \"fisheye\") {\n // Half the fisheye coverage, in radians: the polar angle at the disc edge (radius 1).\n const halfFov = ((fovDeg * Math.PI) / 360).toFixed(6);\n return [\n \"uniform float uRotation;\",\n \"out vec4 fragColor;\",\n \"void main() {\",\n \" // Output disc: centre the UVs, radius 1 at the disc edge.\",\n \" vec2 p = vUV.st * 2.0 - 1.0;\",\n \" float r = length(p);\",\n \" if (r > 1.0) {\",\n \" fragColor = TDOutputSwizzle(vec4(0.0, 0.0, 0.0, 1.0));\",\n \" return;\",\n \" }\",\n \" // Disc radius → polar angle (0 at zenith); disc angle → azimuth (+ rotation).\",\n ` float theta = r * ${halfFov};`,\n \" float phi = atan(p.y, p.x) + uRotation;\",\n \" // Spherical direction, then back to longitude/latitude for the latlong source.\",\n \" vec3 dir = vec3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));\",\n \" float lon = atan(dir.z, dir.x);\",\n \" float lat = asin(clamp(dir.y, -1.0, 1.0));\",\n ` vec2 uv = vec2(lon / ${TWO_PI} + 0.5, lat / ${PI} + 0.5);`,\n \" fragColor = TDOutputSwizzle(texture(sTD2DInputs[0], uv));\",\n \"}\",\n ].join(\"\\n\");\n }\n // Equirectangular: identity remap with a horizontal wrap driven by uRotation.\n return [\n \"uniform float uRotation;\",\n \"out vec4 fragColor;\",\n \"void main() {\",\n ` vec2 uv = vec2(fract(vUV.s + uRotation / ${TWO_PI}), vUV.t);`,\n \" fragColor = TDOutputSwizzle(texture(sTD2DInputs[0], uv));\",\n \"}\",\n ].join(\"\\n\");\n}\n\nexport async function createDomeOutputImpl(ctx: ToolContext, args: CreateDomeOutputArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"dome_output\");\n const res = RESOLUTIONS[args.resolution];\n\n // Pull the master in through a Select TOP (works across COMP boundaries).\n const src = await builder.add(\"selectTOP\", \"src\", { top: args.source_path });\n\n // Remap shader → Text DAT → GLSL TOP (square dome master).\n const frag = await builder.add(\"textDAT\", \"remap_frag\");\n const remap = await builder.add(\"glslTOP\", \"remap\", {\n outputresolution: \"custom\",\n resolutionw: res,\n resolutionh: res,\n });\n await builder.connect(src, remap);\n const shader = remapShader(args.projection, args.fov);\n await builder.python(\n `op(${q(frag)}).text = ${q(shader)}\\nop(${q(remap)}).par.pixeldat = op(${q(frag)}).name`,\n );\n\n // Expose the uRotation uniform (a \"Vectors\" block) so the Rotation control can drive it.\n if (args.expose_controls) {\n await builder.python(\n `_seq = op(${q(remap)}).seq.vec\\n_seq.numBlocks = max(_seq.numBlocks, 1)\\nop(${q(remap)}).par.vec0name = \"uRotation\"`,\n );\n }\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(remap, out);\n\n builder.warnings.push(\n \"⚠ This GLSL-remaps an existing (ideally equirectangular) source into a dome master — the exact fisheye math + fov mapping needs live tuning against your real source and dome. For higher fidelity, a true cubemap render (Render TOP cube-map mode, or a 6-camera rig feeding the latlong source) is the recommended follow-up.\",\n );\n\n const controls = args.expose_controls\n ? [\n {\n name: \"Rotation\",\n label: \"Rotation\",\n type: \"float\" as const,\n default: 0,\n min: -180,\n max: 180,\n bind_to: [`${remap}.vec0valuex`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Remapped ${args.source_path} to a ${args.projection} dome master at ${res}×${res} (fov ${args.fov}°) → ${out}.`,\n builder,\n outputPath: out,\n controls,\n extra: {\n source_path: args.source_path,\n projection: args.projection,\n resolution: args.resolution,\n fov: args.fov,\n output_path: out,\n },\n });\n });\n}\n\nexport const registerCreateDomeOutput: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_dome_output\",\n {\n title: \"Create dome output\",\n description:\n \"Remap a source TOP (treated as an equirectangular / panoramic master) into a square single-output dome master for planetarium fulldomes / 360 — the curved complement to create_multi_output's flat tiling. A Select TOP pulls the master in, a GLSL TOP warps it (fisheye: equirect → centred dome disc using `fov`; equirectangular: near-passthrough identity remap) via a shader held in a Text DAT, ending on a Null ready for setup_output. With expose_controls a Rotation knob spins the dome horizon. Note: this GLSL-remaps an existing source — a true cubemap render is the higher-fidelity follow-up.\",\n inputSchema: createDomeOutputSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createDomeOutputImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\n// Builds a GLSL fragment that maps the grayscale luminance through a 1- or 2-color\n// gradient, so a described palette (\"blues and magentas\") survives to the output.\nfunction colorizeShader(colors: string[]): string {\n const toVec3 = (hex: string | undefined): string => {\n const m = hex ? /^#?([0-9a-fA-F]{6})$/.exec(hex.trim()) : null;\n if (!m?.[1]) return \"vec3(1.0)\";\n const n = Number.parseInt(m[1], 16);\n const r = ((n >> 16) & 255) / 255;\n const g = ((n >> 8) & 255) / 255;\n const b = (n & 255) / 255;\n return `vec3(${r.toFixed(4)}, ${g.toFixed(4)}, ${b.toFixed(4)})`;\n };\n const lo = colors.length >= 2 ? toVec3(colors[0]) : \"vec3(0.0)\";\n const hi = toVec3(colors[colors.length - 1]);\n return `out vec4 fragColor;\nvoid main(){\n float l = texture(sTD2DInputs[0], vUV.st).r;\n fragColor = TDOutputSwizzle(vec4(mix(${lo}, ${hi}, l), 1.0));\n}\n`;\n}\n\n// A self-contained generative pattern for the \"glsl\" seed type. A bare glslTOP ships TD's\n// boilerplate shader (solid white `vec4(1.0)`), which would feed the loop pure white; this\n// gives it a varied colour field to evolve instead.\nconst SEED_GLSL = `out vec4 fragColor;\nvoid main(){\n vec2 uv = vUV.st;\n float v = sin(uv.x * 12.0) + sin(uv.y * 12.0) + sin((uv.x + uv.y) * 8.0);\n vec3 col = 0.5 + 0.5 * cos(vec3(0.0, 2.0, 4.0) + v);\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`;\n\nconst SEED_TYPES = {\n noise: \"noiseTOP\",\n shape: \"circleTOP\",\n image: \"moviefileinTOP\",\n video: \"moviefileinTOP\",\n webcam: \"videodeviceinTOP\",\n glsl: \"glslTOP\",\n} as const;\n\nconst TRANSFORM_TYPES = {\n blur: \"blurTOP\",\n displace: \"displaceTOP\",\n edge: \"edgeTOP\",\n level: \"levelTOP\",\n hsv_adjust: \"hsvadjustTOP\",\n transform: \"transformTOP\",\n mirror: \"mirrorTOP\",\n tile: \"tileTOP\",\n luma_blur: \"lumablurTOP\",\n} as const;\n\nexport const createFeedbackNetworkSchema = z.object({\n seed_type: z.enum([\"noise\", \"shape\", \"image\", \"video\", \"webcam\", \"glsl\"]).default(\"noise\"),\n transformations: z\n .array(\n z.enum([\n \"blur\",\n \"displace\",\n \"edge\",\n \"level\",\n \"hsv_adjust\",\n \"transform\",\n \"mirror\",\n \"tile\",\n \"luma_blur\",\n ]),\n )\n .default([\"blur\", \"displace\", \"level\"]),\n feedback_gain: z.coerce.number().min(0).max(1).default(0.95),\n colors: z\n .array(z.string())\n .max(2)\n .optional()\n .describe(\"Up to two hex colors to colorize the otherwise-grayscale output.\"),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose a live 'Feedback' knob on the system container, bound to the loop's decay.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateFeedbackNetworkArgs = z.infer<typeof createFeedbackNetworkSchema>;\n\nexport async function createFeedbackNetworkImpl(ctx: ToolContext, args: CreateFeedbackNetworkArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"feedback_system\");\n\n const seed = await builder.add(SEED_TYPES[args.seed_type], \"seed\", {\n ...(args.seed_type === \"noise\" ? { monochrome: 1, period: 4 } : {}),\n });\n if (args.seed_type === \"glsl\") {\n // Replace the glslTOP's default white boilerplate with a real generative pattern.\n const seedFrag = await builder.add(\"textDAT\", \"seed_frag\");\n await builder.python(\n `op(${q(seedFrag)}).text = ${q(SEED_GLSL)}\\nop(${q(seed)}).par.pixeldat = op(${q(seedFrag)}).name`,\n );\n }\n const feedback = await builder.add(\"feedbackTOP\", \"feedback1\");\n const comp = await builder.add(\"compositeTOP\", \"comp1\");\n // The TD default operand (multiply) collapses the loop to black; an additive\n // operand injects the seed each frame, and \"maximum\" stays bounded under feedback gain.\n await builder.setParams(comp, { operand: \"maximum\" });\n await builder.connect(seed, comp, 0, 0);\n await builder.connect(feedback, comp, 0, 1);\n // feedbackTOP needs an input for its first frame; seed it before the loop closes.\n await builder.connect(seed, feedback);\n\n let last = comp;\n for (const transformation of args.transformations) {\n const node = await builder.add(TRANSFORM_TYPES[transformation], transformation);\n await builder.connect(last, node);\n // displaceTOP and lumablurTOP need a second input (the displacement / luma map).\n if (transformation === \"displace\" || transformation === \"luma_blur\") {\n await builder.connect(seed, node, 0, 1);\n }\n last = node;\n }\n\n const gain = await builder.add(\"levelTOP\", \"gain\");\n // A levelTOP has no \"gain\" parameter (setting it is a silent no-op), so the loop never\n // decayed and the \"maximum\" composite saturated to solid white. \"brightness1\" multiplies\n // RGB, so set it to feedback_gain to actually fade the fed-back frame each cycle.\n await builder.setParams(gain, { brightness1: args.feedback_gain });\n await builder.connect(last, gain);\n\n // Colorize only the final output; the loop keeps sampling the grayscale gain node\n // so the feedback stays clean.\n let output = gain;\n if (args.colors && args.colors.length > 0) {\n const colorize = await builder.add(\"glslTOP\", \"colorize\");\n const frag = await builder.add(\"textDAT\", \"colorize_frag\");\n await builder.python(\n `op(${q(frag)}).text = ${q(colorizeShader(args.colors))}\\nop(${q(colorize)}).par.pixeldat = op(${q(frag)}).name`,\n );\n await builder.connect(gain, colorize);\n output = colorize;\n }\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(output, out);\n\n // Close the loop: feedbackTOP samples the gain node's output.\n await builder.python(`op(${q(feedback)}).par.top = op(${q(gain)}).name`);\n\n // The decay multiplier (gain.brightness1) is the one knob a feedback system lives by.\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Feedback\",\n type: \"float\",\n min: 0,\n max: 1,\n default: args.feedback_gain,\n bind_to: [`${gain}.brightness1`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Created a feedback network (seed: ${args.seed_type}, gain: ${args.feedback_gain}, ${args.transformations.length} transform(s)).`,\n builder,\n outputPath: out,\n controls,\n extra: { seed_type: args.seed_type, transformations: args.transformations },\n });\n });\n}\n\nexport const registerCreateFeedbackNetwork: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_feedback_network\",\n {\n title: \"Create feedback network\",\n description:\n \"Build a feedback-based visual system: a seed feeds a loop that is transformed (blur/displace/etc.) and fed back each frame. Great for evolving, hypnotic visuals.\",\n inputSchema: createFeedbackNetworkSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createFeedbackNetworkImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport {\n buildFromRecipe,\n createSystemContainer,\n finalize,\n type NetworkBuilder,\n runBuild,\n} from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nconst DEFAULT_PLASMA = `out vec4 fragColor;\nuniform float uTime;\nvoid main(){\n vec2 uv = vUV.st;\n float v = sin(uv.x * 10.0 + uTime) + sin(uv.y * 10.0 + uTime * 0.7);\n v += sin((uv.x + uv.y) * 8.0 + uTime * 1.3);\n vec3 col = 0.5 + 0.5 * cos(vec3(0.0, 2.0, 4.0) + v);\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`;\n\n// Self-contained, TouchDesigner-ready generative shaders, keyed by technique. They each\n// declare their own `out vec4 fragColor` and read a `uTime` uniform (bound to absTime by\n// buildGlslGenerative). Variable names avoid single letters / F1-style names that collide\n// with macros in TD's auto-prepended GLSL preamble. These replace the knowledge-base GLSL\n// snippets, which are documentation fragments (no output declaration, unbound uniforms) and\n// are not directly compilable.\nconst VORONOI_SHADER = `out vec4 fragColor;\nuniform float uTime;\nvec2 hash2(vec2 p){ return fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453); }\nvec2 cellNoise(vec2 p){\n vec2 ip=floor(p); vec2 fp=fract(p);\n float d1=8.0; float d2=8.0;\n for(int yy=-1; yy<=1; yy++){\n for(int xx=-1; xx<=1; xx++){\n vec2 nb=vec2(float(xx),float(yy));\n vec2 pt=hash2(ip+nb);\n pt=0.5+0.5*sin(uTime*0.5+6.2831*pt);\n vec2 diff=nb+pt-fp; float dd=length(diff);\n if(dd<d1){ d2=d1; d1=dd; } else if(dd<d2){ d2=dd; }\n }\n }\n return vec2(d1,d2);\n}\nvoid main(){\n vec2 uv=vUV.st*8.0;\n vec2 fc=cellNoise(uv);\n float edge=smoothstep(0.0,0.08,fc.y-fc.x);\n float cell=fc.x;\n vec3 col=mix(vec3(0.02),vec3(0.5+0.5*cell,0.7,0.9),edge);\n fragColor=TDOutputSwizzle(vec4(col,1.0));\n}\n`;\n\nconst FBM_SHADER = `out vec4 fragColor;\nuniform float uTime;\nfloat hashF(vec2 p){ return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453); }\nfloat vnoise(vec2 p){\n vec2 ip=floor(p); vec2 fp=fract(p);\n vec2 uu=fp*fp*(3.0-2.0*fp);\n float na=hashF(ip+vec2(0.0,0.0));\n float nb=hashF(ip+vec2(1.0,0.0));\n float nc=hashF(ip+vec2(0.0,1.0));\n float nd=hashF(ip+vec2(1.0,1.0));\n return mix(mix(na,nb,uu.x),mix(nc,nd,uu.x),uu.y);\n}\nfloat fbm(vec2 p){\n float acc=0.0; float amp=0.5;\n for(int oc=0; oc<6; oc++){ acc+=amp*vnoise(p); p*=2.0; amp*=0.5; }\n return acc;\n}\nvoid main(){\n vec2 uv=vUV.st*3.0;\n float val=fbm(uv+vec2(uTime*0.1, uTime*0.05));\n vec3 col=mix(vec3(0.02,0.05,0.15), vec3(0.95,0.6,0.25), val);\n fragColor=TDOutputSwizzle(vec4(col,1.0));\n}\n`;\n\n// A real de Jong strange attractor, iterated per pixel and splatted as glowing points on\n// black: each pixel sums a tight Gaussian over thousands of orbit samples (fine particle\n// filaments) plus a faint wide halo (glow). The four coefficients are FIXED at a known dense,\n// robustly-chaotic set — de Jong has periodic windows scattered through coefficient space, so\n// animating the coefficients can collapse the figure to a few dots; motion instead comes from\n// slowly rotating and breathing the framing. `uTime` is bound to absTime by buildGlslGenerative;\n// lowercase var names dodge the preamble #define collisions (see CLAUDE.md / GLSL gotchas).\nconst STRANGE_ATTRACTOR_SHADER = `out vec4 fragColor;\nuniform float uTime;\nvec2 dejong(vec2 z, float a, float b, float c, float d){\n return vec2(sin(a*z.y)-cos(b*z.x), sin(c*z.x)-cos(d*z.y));\n}\nvoid main(){\n const float pa = 1.4, pb = -2.3, pc = 2.4, pd = -2.1;\n const vec2 ctr = vec2(-0.185, -0.227); // orbit centroid -> recenter on canvas\n float ang = uTime * 0.05;\n float ca = cos(ang), sa = sin(ang);\n vec2 p = mat2(ca, -sa, sa, ca) * (vUV.st - 0.5);\n float scale = 0.18 * (1.0 + 0.04 * sin(uTime * 0.11));\n vec2 z = vec2(0.10, 0.10);\n for(int i=0;i<40;i++){ z = dejong(z,pa,pb,pc,pd); } // settle onto the attractor\n float glow = 0.0;\n const int STEPS = 3600;\n for(int i=0;i<STEPS;i++){\n z = dejong(z,pa,pb,pc,pd);\n vec2 d2 = p - (z - ctr) * scale;\n float r = dot(d2, d2);\n glow += exp(-r*22000.0); // tight core -> particle filaments\n glow += 0.08*exp(-r*1200.0); // faint halo -> glow\n }\n glow *= 0.02;\n vec3 col = vec3(0.10,0.35,1.00)*glow;\n col += vec3(0.30,0.95,1.00)*pow(glow,1.5)*0.7;\n col += vec3(1.00,0.80,0.45)*pow(glow,3.0)*0.9;\n fragColor = TDOutputSwizzle(vec4(col,1.0));\n}\n`;\n\ninterface InlineTechnique {\n shader: string;\n // Generator GLSL TOPs default to 256×256 (no input to size from). Fine attractor filaments\n // need a real canvas, so this pins a fixed square resolution; undefined keeps the default.\n squareRes?: number;\n}\n\n// Techniques that map to a faithful inline shader. The rest fall back to animated noise.\nconst TECHNIQUE_SHADERS: Record<string, InlineTechnique> = {\n voronoi: { shader: VORONOI_SHADER },\n fractal: { shader: FBM_SHADER },\n strange_attractor: { shader: STRANGE_ATTRACTOR_SHADER, squareRes: 720 },\n};\n\nconst RECIPE_FOR = new Map<string, string>([\n [\"reaction_diffusion\", \"reaction_diffusion\"],\n [\"noise_landscape\", \"noise_landscape\"],\n]);\n\nexport const createGenerativeArtSchema = z.object({\n technique: z.enum([\n \"noise_landscape\",\n \"reaction_diffusion\",\n \"strange_attractor\",\n \"l_system\",\n \"cellular_automata\",\n \"flow_field\",\n \"voronoi\",\n \"fractal\",\n \"custom_glsl\",\n ]),\n color_palette: z.string().optional().describe(\"Free-text palette hint (best-effort).\"),\n evolution_speed: z.coerce.number().positive().default(1.0),\n custom_glsl_code: z\n .string()\n .optional()\n .describe(\"Fragment shader (only for technique 'custom_glsl').\"),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose a live 'Speed' knob (evolution speed) on the system container.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateGenerativeArtArgs = z.infer<typeof createGenerativeArtSchema>;\n\nasync function buildGlslGenerative(\n ctx: ToolContext,\n parentPath: string,\n name: string,\n fragment: string,\n speed = 1.0,\n squareRes?: number,\n): Promise<{ builder: NetworkBuilder; outputPath: string }> {\n const builder = await createSystemContainer(ctx, parentPath, name);\n const glsl = await builder.add(\"glslTOP\", \"glsl1\");\n const frag = await builder.add(\"textDAT\", \"glsl1_frag\");\n await builder.python(\n `op(${q(frag)}).text = ${q(fragment)}\\nop(${q(glsl)}).par.pixeldat = op(${q(frag)}).name`,\n );\n if (squareRes !== undefined) {\n await builder.python(\n `_r = op(${q(glsl)})\\n_r.par.outputresolution = 'custom'\\n_r.par.resolutionw = ${squareRes}\\n_r.par.resolutionh = ${squareRes}`,\n );\n }\n // Bind a `uTime` uniform to absTime so time-driven shaders animate. The uniform lives in\n // the GLSL TOP's \"Vectors\" sequence, whose block count has no structured setter; raise it\n // via numBlocks, then set the block name and an expression on its first component.\n // uTime advances with absTime; a defensive `Speed` lookup lets an auto-exposed control\n // (parent().par.Speed) drive evolution speed live, and falls back to the build-time constant\n // when no control is present — so the expression never errors.\n await builder.python(\n `_g = op(${q(glsl)})\\n_g.seq.vec.numBlocks = max(_g.seq.vec.numBlocks, 1)\\n_g.par.vec0name = 'uTime'\\n_g.par.vec0valuex.expr = ${q(`absTime.seconds * (parent().par.Speed.eval() if hasattr(parent().par, 'Speed') else ${speed})`)}`,\n );\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(glsl, out);\n return { builder, outputPath: out };\n}\n\nexport async function createGenerativeArtImpl(ctx: ToolContext, args: CreateGenerativeArtArgs) {\n return runBuild(async () => {\n // A single \"Speed\" knob drives evolution speed (the time-driving expressions reference it).\n // Recipe-built techniques don't use that expression, so they don't get the control.\n const speedControls: ControlSpec[] = args.expose_controls\n ? [{ name: \"Speed\", type: \"float\", min: 0, max: 4, default: args.evolution_speed }]\n : [];\n const recipeId = RECIPE_FOR.get(args.technique);\n if (recipeId) {\n const recipe = ctx.recipes.get(recipeId);\n if (recipe) {\n const { builder, outputPath, controls } = await buildFromRecipe(\n ctx,\n recipe,\n args.parent_path,\n );\n return finalize(ctx, {\n summary: `Created \"${recipe.name}\" generative system.`,\n builder,\n outputPath,\n recipeId,\n controls,\n extra: { technique: args.technique, color_palette: args.color_palette },\n });\n }\n }\n\n if (args.technique === \"custom_glsl\") {\n const fragment = args.custom_glsl_code ?? DEFAULT_PLASMA;\n const { builder, outputPath } = await buildGlslGenerative(\n ctx,\n args.parent_path,\n \"generative_custom_glsl\",\n fragment,\n args.evolution_speed,\n );\n if (!args.custom_glsl_code) {\n builder.warnings.push(\"No custom_glsl_code provided; used a default plasma shader.\");\n }\n return finalize(ctx, {\n summary: \"Created a custom GLSL generative system.\",\n builder,\n outputPath,\n controls: speedControls,\n extra: { technique: args.technique },\n });\n }\n\n // Techniques with a faithful inline shader render the real thing (animated via uTime);\n // the rest fall back to animated noise below.\n const inline = TECHNIQUE_SHADERS[args.technique];\n if (inline) {\n const { builder, outputPath } = await buildGlslGenerative(\n ctx,\n args.parent_path,\n `generative_${args.technique}`,\n inline.shader,\n args.evolution_speed,\n inline.squareRes,\n );\n return finalize(ctx, {\n summary: `Created a \"${args.technique}\" generative system (GLSL).`,\n builder,\n outputPath,\n controls: speedControls,\n extra: { technique: args.technique, color_palette: args.color_palette },\n });\n }\n\n const builder = await createSystemContainer(\n ctx,\n args.parent_path,\n `generative_${args.technique}`,\n );\n const noise = await builder.add(\"noiseTOP\", \"noise1\", { monochrome: 0, period: 6 });\n const level = await builder.add(\"levelTOP\", \"level1\");\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(noise, level);\n await builder.connect(level, out);\n await builder.python(\n `p = op(${q(noise)}).par.tz\\np.expr = ${q(`absTime.seconds * (parent().par.Speed.eval() if hasattr(parent().par, 'Speed') else ${args.evolution_speed})`)}`,\n );\n builder.warnings.push(\n `Technique \"${args.technique}\" is approximated with an animated-noise generator in this version.`,\n );\n return finalize(ctx, {\n summary: `Created an approximate \"${args.technique}\" generative system.`,\n builder,\n outputPath: out,\n controls: speedControls,\n extra: { technique: args.technique, evolution_speed: args.evolution_speed },\n });\n });\n}\n\nexport const registerCreateGenerativeArt: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_generative_art\",\n {\n title: \"Create generative art\",\n description:\n \"Create an evolving generative visual. reaction_diffusion/noise_landscape use validated recipes; strange_attractor, voronoi, and fractal render real GLSL; custom_glsl uses your shader; the rest fall back to animated noise.\",\n inputSchema: createGenerativeArtSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createGenerativeArtImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\n/**\n * The glitch look itself: per-channel horizontal RGB displacement plus noise-driven\n * horizontal band tearing, all scaled by a master amount. This is a self-contained,\n * TouchDesigner-ready fragment shader:\n * - declares its own `out vec4 fragColor` and writes through `TDOutputSwizzle(...)`\n * (required by the GLSL TOP);\n * - reads the input via `sTD2DInputs[0]` and aspect via `uTD2DInfos[0].res` (built in,\n * no binding needed);\n * - reads three bound uniforms — `uShift` (per-channel offset in UV), `uAmount` (master\n * intensity 0..1) and `uTime` (advances with absTime) — bound by buildGlsl below.\n * Variable names are lowercase to avoid colliding with macros in TD's auto-prepended GLSL\n * preamble (UPPERCASE short names like F1/F2 are reserved there).\n */\nconst GLITCH_SHADER = `out vec4 fragColor;\nuniform float uShift;\nuniform float uAmount;\nuniform float uTime;\nfloat hash11(float x){ return fract(sin(x * 127.1) * 43758.5453); }\nvoid main(){\n vec2 uv = vUV.st;\n\n // Horizontal band tearing: quantise Y into bands, jump a subset of them sideways.\n // The active set drifts with uTime so the corruption flickers rather than holds still.\n float band = floor(uv.y * 24.0);\n // NB: 'active' is a reserved word in TD's GLSL — use a non-reserved name.\n float bandOn = step(0.72, hash11(band * 1.7 + floor(uTime * 8.0)));\n float tear = (hash11(band + floor(uTime * 8.0)) - 0.5) * 0.18 * bandOn;\n vec2 tuv = uv + vec2(tear * uAmount, 0.0);\n\n // Chromatic RGB split: sample R/G/B at increasing horizontal offsets. uShift is the\n // base channel offset in UV; uAmount scales the whole effect so 0 is a clean passthrough.\n float o = uShift * uAmount;\n float r = texture(sTD2DInputs[0], tuv + vec2(o, 0.0)).r;\n float g = texture(sTD2DInputs[0], tuv).g;\n float b = texture(sTD2DInputs[0], tuv - vec2(o, 0.0)).b;\n float a = texture(sTD2DInputs[0], tuv).a;\n fragColor = TDOutputSwizzle(vec4(r, g, b, a));\n}\n`;\n\nexport const createGlitchSchema = z.object({\n amount: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(0.5)\n .describe(\n \"Master glitch intensity (0..1). Scales both the block/slice displacement and the RGB channel split — 0 is a clean passthrough. Exposed as the 'Amount' knob and is the parameter to bind to audio/beat later.\",\n ),\n speed: z.coerce\n .number()\n .min(0)\n .default(1)\n .describe(\n \"Animation speed of the noise that drives the blocky tearing (drives the noise's tz).\",\n ),\n rgb_shift: z.coerce\n .number()\n .min(0)\n .default(0.02)\n .describe(\n \"Base per-channel horizontal offset in UV space (0..~0.1 is a useful range). Multiplied by Amount.\",\n ),\n block_size: z.coerce\n .number()\n .positive()\n .default(8)\n .describe(\n \"Scale of the displacement noise — smaller = larger, blockier tears; larger = finer grain. Sets the noise's period.\",\n ),\n seed: z.coerce.number().default(1).describe(\"Random seed for the displacement noise.\"),\n input_path: z\n .string()\n .optional()\n .describe(\n \"Absolute path of an existing TOP to glitch (e.g. '/project1/render/out1'). Pulled in via a Select TOP because wires cannot cross COMPs. If omitted, a self-contained animated colour-noise source is used so the system builds with zero device permissions (NOT a live webcam).\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose live Amount/Speed/RGBShift/BlockSize knobs on the system container.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateGlitchArgs = z.infer<typeof createGlitchSchema>;\n\n/**\n * The source TOP the glitch stack operates on. With an input_path we bring the external TOP\n * in by reference through a Select TOP (wires can't cross COMPs). Otherwise we synthesise a\n * coloured, animated noise field — a non-device source that needs no permissions and gives\n * the RGB-split/displace something with structure and hue to chew on (unlike a live webcam,\n * which can hang TD on a macOS permission modal).\n */\nasync function buildSource(builder: NetworkBuilder, args: CreateGlitchArgs): Promise<string> {\n if (args.input_path) {\n const select = await builder.add(\"selectTOP\", \"source\");\n await builder.setParams(select, { top: args.input_path });\n return select;\n }\n // Coloured (non-monochrome) noise so the per-channel RGB split reads as colour fringing,\n // not just a grayscale smear. A slow drift keeps the test source alive on screen.\n const src = await builder.add(\"noiseTOP\", \"source\", { monochrome: 0, period: 4 });\n await builder.python(\n `_p = op(${q(src)}).par.tz\\n_PM = type(_p.mode)\\n_p.expr = ${q(\"absTime.seconds * 0.15\")}\\n_p.mode = _PM.EXPRESSION`,\n );\n return src;\n}\n\nexport async function createGlitchImpl(ctx: ToolContext, args: CreateGlitchArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"glitch\");\n\n const source = await buildSource(builder, args);\n\n // Low-res, animated monochrome noise drives the blocky displacement. block_size sets its\n // period (spatial scale → block size); seed seeds it; tz drifts it over time at `speed`\n // so the tears move. A small resolution keeps the blocks chunky and the cook cheap.\n const driver = await builder.add(\"noiseTOP\", \"driver\", {\n monochrome: 1,\n period: args.block_size,\n seed: args.seed,\n resolutionw: 64,\n resolutionh: 64,\n outputresolution: \"custom\",\n });\n await builder.python(\n `_p = op(${q(driver)}).par.tz\\n_PM = type(_p.mode)\\n_p.expr = ${q(`absTime.seconds * (parent().par.Speed.eval() if hasattr(parent().par, 'Speed') else ${args.speed})`)}\\n_p.mode = _PM.EXPRESSION`,\n );\n\n // Block/slice displacement: input 0 = the source, input 1 = the noise driver (both wired —\n // a displaceTOP reads its displacement from input 1, not a source parameter). uvweight scales\n // how far pixels are pushed; bind it to Amount so the master knob drives the tearing strength.\n const displace = await builder.add(\"displaceTOP\", \"displace\", { uvweight: args.amount * 0.2 });\n await builder.connect(source, displace, 0, 0);\n await builder.connect(driver, displace, 0, 1);\n // Let the Amount control drive displacement strength live (defensive lookup so the\n // expression never errors when no control is exposed). 0.2 keeps the max push tasteful.\n await builder.python(\n `_p = op(${q(displace)}).par.uvweight\\n_PM = type(_p.mode)\\n_p.expr = ${q(`0.2 * (parent().par.Amount.eval() if hasattr(parent().par, 'Amount') else ${args.amount})`)}\\n_p.mode = _PM.EXPRESSION`,\n );\n\n // RGB channel split + horizontal band tearing in one GLSL pass over the displaced image.\n const rgbshift = await builder.add(\"glslTOP\", \"rgbshift\");\n const frag = await builder.add(\"textDAT\", \"rgbshift_frag\");\n await builder.python(\n `op(${q(frag)}).text = ${q(GLITCH_SHADER)}\\nop(${q(rgbshift)}).par.pixeldat = op(${q(frag)}).name`,\n );\n await builder.connect(displace, rgbshift);\n // Bind the three uniforms. They live in the GLSL TOP's \"Vectors\" sequence (the `vec`\n // sequence), whose block count has no structured setter — raise numBlocks, then set each\n // block's name and its first component. uShift/uAmount get expressions referencing the\n // auto-exposed controls (defensive `parent().par.X` lookups, falling back to build-time\n // constants); uTime advances with absTime so the tearing animates.\n await builder.python(\n [\n `_g = op(${q(rgbshift)})`,\n `_g.seq.vec.numBlocks = max(_g.seq.vec.numBlocks, 3)`,\n `_g.par.vec0name = 'uShift'`,\n `_g.par.vec0valuex.expr = ${q(`(parent().par.Rgbshift.eval() if hasattr(parent().par, 'Rgbshift') else ${args.rgb_shift})`)}`,\n `_g.par.vec0valuex.mode = type(_g.par.vec0valuex.mode).EXPRESSION`,\n `_g.par.vec1name = 'uAmount'`,\n `_g.par.vec1valuex.expr = ${q(`(parent().par.Amount.eval() if hasattr(parent().par, 'Amount') else ${args.amount})`)}`,\n `_g.par.vec1valuex.mode = type(_g.par.vec1valuex.mode).EXPRESSION`,\n `_g.par.vec2name = 'uTime'`,\n `_g.par.vec2valuex.expr = 'absTime.seconds'`,\n `_g.par.vec2valuex.mode = type(_g.par.vec2valuex.mode).EXPRESSION`,\n ].join(\"\\n\"),\n );\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(rgbshift, out);\n\n // Amount is the headline knob (and the audio/beat bind target). Speed drives the noise\n // animation; RGBShift the channel offset; BlockSize the noise scale. Amount/Speed/RGBShift\n // are referenced by the expressions set above via their sanitized custom-par names\n // (Amount, Speed, Rgbshift) — so they are bare custom pars here (no bind_to, the\n // expressions read parent().par.<Name>). BlockSize has no expression of its own, so it\n // binds directly to the driver noise's period.\n const controls: ControlSpec[] = args.expose_controls\n ? [\n { name: \"Amount\", type: \"float\", min: 0, max: 1, default: args.amount },\n { name: \"Speed\", type: \"float\", min: 0, max: 4, default: args.speed },\n { name: \"RGBShift\", type: \"float\", min: 0, max: 0.1, default: args.rgb_shift },\n {\n name: \"BlockSize\",\n type: \"float\",\n min: 1,\n max: 64,\n default: args.block_size,\n bind_to: [`${driver}.period`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Created a glitch system (${args.input_path ? `source: ${args.input_path}` : \"self-contained noise source\"}, amount ${args.amount}) → ${out}. Bind op('${builder.containerPath}').par.Amount to audio/beat to make the glitch pulse.`,\n builder,\n outputPath: out,\n capturePreviewImage: true,\n controls,\n extra: {\n amount: args.amount,\n speed: args.speed,\n rgb_shift: args.rgb_shift,\n block_size: args.block_size,\n seed: args.seed,\n source: args.input_path ?? \"noise\",\n output_path: out,\n },\n });\n });\n}\n\nexport const registerCreateGlitch: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_glitch\",\n {\n title: \"Create glitch\",\n description:\n \"Build a glitch / corrupted-signal visual: RGB channel split, noise-driven blocky/slice displacement and horizontal band tearing over a source. With input_path it glitches an existing TOP (pulled in via a Select TOP); otherwise it uses a self-contained animated colour-noise source (no device permissions). Exposes Amount (master intensity — bind to audio/beat), Speed, RGBShift and BlockSize knobs. A signature live VJ look.\",\n inputSchema: createGlitchSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createGlitchImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\n/**\n * GLSL ping-pong helpers — each \"buffer\" is an RGBA32float TOP that a feedbackTOP\n * holds frame-to-frame (the same trick createFeedbackNetwork uses for an image loop),\n * except here the texels are *data* (particle velocity / position) not pixels:\n * - sTD2DInputs[0] in vel_update = previous velocity (from vel_fb)\n * - sTD2DInputs[0] in pos_update = previous position (from pos_fb)\n * - sTD2DInputs[1] in pos_update = current velocity (from vel_update)\n *\n * TouchDesigner GLSL TOP conventions used throughout (verified in createAudioReactive /\n * createMultiOutput): declare `out vec4 fragColor;`, sample `sTD2DInputs[i]`, write via\n * `TDOutputSwizzle(...)`, and there is NO built-in uTime — so this integrates with a fixed\n * dt rather than reading a clock. The shader text goes in a textDAT wired with\n * `op(glsl).par.pixeldat = op(frag).name`.\n */\n\n// A cheap hash → pseudo-random vec3 in [-1,1], used both to seed positions and to drive the\n// \"noise\" force without a noiseTOP input (keeps the default path fully self-contained).\nconst GLSL_HASH = `\nvec3 hash33(vec3 p){\n p = fract(p * vec3(0.1031, 0.1030, 0.0973));\n p += dot(p, p.yxz + 33.33);\n return fract((p.xxy + p.yxx) * p.zyx) * 2.0 - 1.0;\n}\n`;\n\n/**\n * Velocity-update fragment. Reads previous velocity from the feedback (sTD2DInputs[0]) and\n * adds the requested forces, then writes the new velocity. `vUV.st` is the particle's slot\n * in the side×side grid, used as a stable per-particle seed.\n *\n * Forces (all tuned in-shader, no external inputs on the default path):\n * - \"noise\": a per-particle hash nudges velocity (Brownian-ish drift).\n * - \"curl\": a finite-difference curl of the hash field → swirling motion.\n * - \"gravity\": a constant pull along -Y.\n * `damp` keeps velocities bounded so the sim does not blow up under feedback.\n */\nfunction velocityShader(forces: readonly string[], reactive: boolean): string {\n const lines = [\n \"out vec4 fragColor;\",\n // uReact (0 when idle) is driven live from the audio/motion analysis when reactivity is on.\n ...(reactive ? [\"uniform float uReact;\"] : []),\n GLSL_HASH.trim(),\n \"const float dt = 1.0 / 60.0;\",\n \"const float damp = 0.98;\",\n \"void main(){\",\n \" vec2 uv = vUV.st;\",\n \" vec3 vel = texture(sTD2DInputs[0], uv).xyz;\",\n \" vec3 seed = vec3(uv, 0.0);\",\n \" vec3 force = vec3(0.0);\",\n ];\n if (forces.includes(\"noise\")) {\n lines.push(\" force += hash33(seed * 17.0) * 0.5;\");\n }\n if (forces.includes(\"curl\")) {\n // Curl of the hash field via central differences — divergence-free swirling.\n lines.push(\n \" float e = 0.01;\",\n \" vec3 dx = hash33(seed + vec3(e, 0.0, 0.0)) - hash33(seed - vec3(e, 0.0, 0.0));\",\n \" vec3 dy = hash33(seed + vec3(0.0, e, 0.0)) - hash33(seed - vec3(0.0, e, 0.0));\",\n \" vec3 dz = hash33(seed + vec3(0.0, 0.0, e)) - hash33(seed - vec3(0.0, 0.0, e));\",\n \" vec3 curl = vec3(dy.z - dz.y, dz.x - dx.z, dx.y - dy.x);\",\n \" force += curl * 1.5;\",\n );\n }\n if (forces.includes(\"gravity\")) {\n lines.push(\" force += vec3(0.0, -0.6, 0.0);\");\n }\n if (reactive) {\n // A per-particle impulse scaled by the live signal: louder audio / more camera motion\n // energises the whole field (uReact stays 0 when the source is quiet, so the field settles).\n lines.push(\" force += hash33(seed * 31.0 + vec3(7.0)) * uReact * 6.0;\");\n }\n lines.push(\n \" vel = vel * damp + force * dt;\",\n \" fragColor = TDOutputSwizzle(vec4(vel, 1.0));\",\n \"}\",\n );\n return `${lines.join(\"\\n\")}\\n`;\n}\n\n/**\n * Position-update fragment. Reads previous position (sTD2DInputs[0], from pos_fb) and current\n * velocity (sTD2DInputs[1], from vel_update) and integrates position += velocity * dt.\n *\n * Seeding: a feedbackTOP starts black (all zeros) on its first frame, which would pile every\n * particle at the origin. While the previous position is still ~0 we substitute a hash-spread\n * initial position so the field starts as a cloud. This is a best-effort first-frame seed —\n * see the ⚠ warnings; a more robust seed uses a Reset pulse on pos_fb or a separate seed TOP.\n */\nconst POSITION_SHADER = `out vec4 fragColor;\n${GLSL_HASH.trim()}\nconst float dt = 1.0 / 60.0;\nvoid main(){\n vec2 uv = vUV.st;\n vec3 pos = texture(sTD2DInputs[0], uv).xyz;\n vec3 vel = texture(sTD2DInputs[1], uv).xyz;\n // First-frame seed: when the feedback buffer is still empty, scatter from a hash.\n if (dot(pos, pos) < 1e-8) {\n pos = hash33(vec3(uv, 1.0)) * 2.0;\n }\n pos += vel * dt;\n fragColor = TDOutputSwizzle(vec4(pos, 1.0));\n}\n`;\n\nconst FORCE_VALUES = [\"noise\", \"gravity\", \"curl\"] as const;\n\nexport const createGpuParticleFieldSchema = z.object({\n side: z.coerce\n .number()\n .int()\n .min(16)\n .max(512)\n .default(256)\n .describe(\n \"Edge of the square particle buffer; the field is side×side particles (count = side², e.g. 256 → 65 536). Each particle is one texel of the RGBA32float position/velocity buffers.\",\n ),\n forces: z\n .array(z.enum(FORCE_VALUES))\n .default([\"noise\"])\n .describe(\n \"In-shader forces added to velocity each frame: 'noise' (per-particle random drift), 'gravity' (constant -Y pull), 'curl' (divergence-free swirling).\",\n ),\n reactivity: z\n .enum([\"none\", \"audio\", \"motion\"])\n .default(\"none\")\n .describe(\n \"Optional external push that energises the field live, bound to the velocity shader's uReact uniform. 'none' (default) is fully self-contained. 'audio' drives it from mic/line RMS (Audio Device In → Analyze), 'motion' from camera frame-difference energy (Video Device In → mono → cache/difference → average). Either may pop a one-time macOS device-permission dialog — click Allow.\",\n ),\n point_size: z.coerce\n .number()\n .positive()\n .default(0.02)\n .describe(\"Radius of each instanced dot (the sphere/circle SOP scale).\"),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose live PointSize and Zoom (camera distance) knobs on the system container.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateGpuParticleFieldArgs = z.infer<typeof createGpuParticleFieldSchema>;\n\nexport async function createGpuParticleFieldImpl(\n ctx: ToolContext,\n args: CreateGpuParticleFieldArgs,\n) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"gpu_particle_field\");\n const { side } = args;\n const bufParams = {\n outputresolution: \"custom\",\n resolutionw: side,\n resolutionh: side,\n format: \"rgba32float\",\n } as const;\n\n // --- VELOCITY loop ---------------------------------------------------------------------\n // vel_fb holds the previous velocity; vel_update reads it, adds forces, writes the new\n // velocity. Close the loop with feedbackTOP.par.top = vel_update (same trick as\n // createFeedbackNetwork). vel_fb is seeded from vel_update so its first frame has an input.\n const velFb = await builder.add(\"feedbackTOP\", \"vel_fb\");\n const velUpdate = await builder.add(\"glslTOP\", \"vel_update\", bufParams);\n const velFrag = await builder.add(\"textDAT\", \"vel_frag\");\n const reactive = args.reactivity !== \"none\";\n await builder.python(\n `op(${q(velFrag)}).text = ${q(velocityShader(args.forces, reactive))}\\nop(${q(velUpdate)}).par.pixeldat = op(${q(velFrag)}).name`,\n );\n await builder.connect(velFb, velUpdate, 0, 0);\n await builder.python(`op(${q(velFb)}).par.top = op(${q(velUpdate)}).name`);\n\n // --- POSITION loop ---------------------------------------------------------------------\n // pos_fb holds the previous position; pos_update reads it (input 0) plus the current\n // velocity (input 1) and integrates. Close with feedbackTOP.par.top = pos_update.\n const posFb = await builder.add(\"feedbackTOP\", \"pos_fb\");\n const posUpdate = await builder.add(\"glslTOP\", \"pos_update\", bufParams);\n const posFrag = await builder.add(\"textDAT\", \"pos_frag\");\n await builder.python(\n `op(${q(posFrag)}).text = ${q(POSITION_SHADER)}\\nop(${q(posUpdate)}).par.pixeldat = op(${q(posFrag)}).name`,\n );\n await builder.connect(posFb, posUpdate, 0, 0);\n await builder.connect(velUpdate, posUpdate, 0, 1);\n await builder.python(`op(${q(posFb)}).par.top = op(${q(posUpdate)}).name`);\n\n builder.warnings.push(\n \"Feedback-loop seeding: both feedbackTOPs start at zero on frame 1; the position shader detects that and hash-scatters the particles into a cloud (validated live). If a fresh load ever collapses to the origin, pulse pos_fb/vel_fb's reset.\",\n );\n\n // --- INSTANCING from the position TOP --------------------------------------------------\n // A Geometry COMP renders a tiny dot once per particle, instanced from the position buffer:\n // each texel's RGB becomes that instance's XYZ translate. The builder clears the COMP's\n // default torus on creation.\n const geo = await builder.add(\"geometryCOMP\", \"geo\");\n // The dot size lives on the SOP itself (radx/y/z), not on per-instance scale: TOP instancing\n // applies translate but not scale here, so a unit sphere would render full-size and the cloud\n // would collapse into a solid white mass (validated live). A small radius keeps each particle\n // a crisp point.\n const dot = await builder.add(\n \"sphereSOP\",\n \"dot\",\n { radx: args.point_size, rady: args.point_size, radz: args.point_size },\n geo,\n );\n await builder.python(`_s = op(${q(dot)})\\n_s.render = True\\n_s.display = True`);\n\n // TOP instancing (validated live): instanceop = the position TOP sets the instance COUNT from\n // its texel grid (side² instances); instancetop names the TOP the per-instance translate reads\n // from; instancetx/ty/tz select its R/G/B channels for X/Y/Z. Scale is NOT set here — TOP\n // instancing applies translate only, so per-particle size lives on the dot SOP's radius above.\n await builder.setParams(geo, {\n instancing: 1,\n instanceop: posUpdate,\n instancetop: posUpdate,\n instancetx: \"r\",\n instancety: \"g\",\n instancetz: \"b\",\n });\n\n // A single near-white material so the dots read against the dark background.\n const mat = await builder.add(\"constantMAT\", \"mat\");\n await builder.setParams(geo, { material: mat });\n\n const camDist = 6;\n const cam = await builder.add(\"cameraCOMP\", \"cam\", { tz: camDist });\n const light = await builder.add(\"lightCOMP\", \"light\", { tx: 3, ty: 4, tz: 4 });\n // Opaque near-black background so the bright dots are visible (same convention as\n // createParticleSystem). Set bgcolora back to 0 to composite the field over other layers.\n const render = await builder.add(\"renderTOP\", \"render\", {\n camera: cam,\n geometry: geo,\n lights: light,\n bgcolorr: 0.02,\n bgcolorg: 0.02,\n bgcolorb: 0.05,\n bgcolora: 1,\n });\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(render, out);\n\n // --- Optional reactivity: drive the velocity shader's uReact uniform from a live signal ----\n // \"none\" leaves uReact unset (0) → the field is self-contained. audio/motion build a small\n // analysis chain ending on a single-value CHOP \"react_level\", then bind vel_update's uReact\n // uniform to it by expression so it updates every frame (the GLSL TOP's per-frame cook pulls\n // the chain, keeping it warm without a separate Execute DAT).\n let reactExpr: string | undefined;\n if (args.reactivity === \"audio\") {\n // Live mic/line → RMS Power = current loudness. (Creating the device may pop a one-time\n // macOS microphone-permission dialog — click Allow.)\n const audioIn = await builder.add(\"audiodeviceinCHOP\", \"audio_in\");\n const rms = await builder.add(\"analyzeCHOP\", \"audio_rms\", { function: \"rmspower\" });\n await builder.connect(audioIn, rms);\n await builder.add(\"nullCHOP\", \"react_level\");\n await builder.connect(rms, builder.pathOf(\"react_level\") as string);\n reactExpr = \"op('react_level')[0] * 8.0\";\n } else if (args.reactivity === \"motion\") {\n // Camera → frame-to-frame difference → average = motion energy (the create_motion_reactive\n // chain). Creating the camera may pop a one-time macOS camera-permission dialog — click Allow.\n const motionIn = await builder.add(\"videodeviceinTOP\", \"motion_in\");\n const mono = await builder.add(\"monochromeTOP\", \"motion_mono\", {\n outputresolution: \"custom\",\n resolutionw: 160,\n resolutionh: 160,\n });\n await builder.connect(motionIn, mono);\n const cache = await builder.add(\"cacheTOP\", \"motion_prev\", {\n active: 1,\n cachesize: 2,\n outputindexunit: \"indices\",\n outputindex: -1,\n });\n await builder.connect(mono, cache);\n const diff = await builder.add(\"differenceTOP\", \"motion_diff\");\n await builder.connect(mono, diff, 0, 0);\n await builder.connect(cache, diff, 0, 1);\n const energy = await builder.add(\"analyzeTOP\", \"motion_energy\", { op: \"average\" });\n await builder.connect(diff, energy);\n await builder.add(\"toptoCHOP\", \"react_level\", {\n top: energy,\n r: \"motion\",\n g: \"\",\n b: \"\",\n a: \"\",\n });\n reactExpr = \"op('react_level')['motion'] * 40.0\";\n }\n if (reactExpr) {\n // Name vel_update's first float uniform \"uReact\" and drive it from the analysis each frame.\n await builder.python(\n [\n `_v = op(${q(velUpdate)})`,\n \"_seq = _v.seq.vec\",\n \"_seq.numBlocks = max(_seq.numBlocks, 1)\",\n '_v.par.vec0name = \"uReact\"',\n `_v.par.vec0valuex.expr = ${q(reactExpr)}`,\n ].join(\"\\n\"),\n );\n }\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n // Resizes every particle by driving the dot SOP's radius (TOP instancing does not\n // apply per-instance scale, so size lives on the source sphere).\n name: \"PointSize\",\n type: \"float\",\n min: 0.001,\n max: 0.5,\n default: args.point_size,\n bind_to: [`${dot}.radx`, `${dot}.rady`, `${dot}.radz`],\n },\n {\n name: \"Zoom\",\n type: \"float\",\n min: 1,\n max: camDist * 3,\n default: camDist,\n bind_to: [`${cam}.tz`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Built a GPU particle field: ${side}×${side} = ${side * side} particles via position/velocity feedback TOPs + TOP-instancing (forces: ${args.forces.join(\", \") || \"none\"}, reactivity: ${args.reactivity}), rendered to ${out}.`,\n builder,\n outputPath: out,\n controls,\n extra: {\n side,\n count: side * side,\n forces: args.forces,\n reactivity: args.reactivity,\n output_path: out,\n },\n });\n });\n}\n\nexport const registerCreateGpuParticleField: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_gpu_particle_field\",\n {\n title: \"Create GPU particle field\",\n description:\n \"Build a high-count GPU particle / point field: position and velocity are simulated entirely on the GPU in two RGBA32float feedback-TOP loops (velocity integrates forces — noise/curl/gravity; position integrates velocity), then a Geometry COMP instances a tiny dot once per texel, reading XYZ from the position texture. Reaches counts (side², up to 512²≈262k) well beyond the CPU create_particle_system, flowing as curl-noise streams. Exposes PointSize and Zoom knobs. Optional reactivity energises the field live: 'audio' drives it from mic/line RMS, 'motion' from camera frame-difference energy (both bound to the velocity shader's uReact uniform).\",\n inputSchema: createGpuParticleFieldSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createGpuParticleFieldImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\n// Single-pass kaleidoscope / radial-mirror fold. TouchDesigner has no native polar (cartesian↔\n// polar) TOP — confirmed absent from the knowledge base — so the classic polarTOP→mirror→polarTOP\n// chain isn't available; this does the whole fold in one GLSL TOP, which is self-contained and has\n// no per-op compile risk beyond this shader. It samples the source via sTD2DInputs[0] (the wired\n// input), converts each pixel to polar (atan/length around the centre), folds the angle into one\n// wedge with mod()+mirror so N identical mirrored segments tile the circle, then samples the source\n// back. Uniforms are bound to parent().par.* by the builder so the exposed knobs drive it live.\n//\n// GLSL gotchas obeyed: declares `out vec4 fragColor`, writes via TDOutputSwizzle(); no built-in\n// uTime is used (rotation is a uniform/control, not time); variable names are lowercase (no F1/F2\n// that collide with the TD preamble #defines).\nconst KALEIDOSCOPE_SHADER = `out vec4 fragColor;\nuniform float uSegments;\nuniform float uRotation;\nuniform float uZoom;\nuniform vec2 uCenter;\n\nconst float kPi = 3.14159265359;\nconst float kTau = 6.28318530718;\n\nvoid main(){\n // Centre the coordinates on the kaleidoscope origin and apply zoom.\n vec2 pos = (vUV.st - uCenter) / max(uZoom, 0.0001);\n\n // To polar.\n float radius = length(pos);\n float angle = atan(pos.y, pos.x) + uRotation;\n\n // Fold the angle into a single wedge, then mirror every other wedge so adjacent\n // segments meet edge-to-edge (a true kaleidoscope mirror rather than a plain repeat).\n float segments = max(uSegments, 2.0);\n float wedge = kTau / segments;\n angle = mod(angle, wedge);\n angle = abs(angle - 0.5 * wedge);\n\n // Back to cartesian, re-centred so we re-sample the original source texture.\n vec2 uv = uCenter + radius * vec2(cos(angle), sin(angle));\n\n // Outside [0,1] the source has no data; mirror-wrap so the look stays filled and seamless.\n uv = abs(fract(uv * 0.5) * 2.0 - 1.0);\n\n fragColor = TDOutputSwizzle(texture(sTD2DInputs[0], uv));\n}\n`;\n\nexport const createKaleidoscopeSchema = z.object({\n segments: z.coerce\n .number()\n .int()\n .min(2)\n .default(6)\n .describe(\n \"Number of mirrored wedges (N-fold symmetry). 6 is the classic look; higher = finer.\",\n ),\n rotation: z.coerce\n .number()\n .default(0)\n .describe(\"Rotation of the whole kaleidoscope, in radians. Animate/bind this to spin it.\"),\n zoom: z.coerce\n .number()\n .positive()\n .default(1)\n .describe(\"Zoom into the source — >1 magnifies the pattern, <1 pulls more of the source in.\"),\n center_x: z.coerce\n .number()\n .default(0.5)\n .describe(\"Kaleidoscope centre X in normalized UV (0–1). 0.5 is the middle of the frame.\"),\n center_y: z.coerce\n .number()\n .default(0.5)\n .describe(\"Kaleidoscope centre Y in normalized UV (0–1). 0.5 is the middle of the frame.\"),\n input_path: z\n .string()\n .optional()\n .describe(\n \"Absolute path of a source TOP to kaleidoscope. Brought in via a Select TOP (cross-container wiring silently no-ops). If omitted, a coloured noise source is generated so the network previews on its own.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\n \"Expose live Segments / Rotation / Zoom / Center X / Center Y knobs on the container.\",\n ),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateKaleidoscopeArgs = z.infer<typeof createKaleidoscopeSchema>;\n\n/**\n * Brings in the source: a Select TOP referencing `input_path` by absolute path (you cannot wire\n * across containers), or — with no input — a coloured animated noise so the system previews and\n * tests with zero external dependencies.\n */\nasync function buildSource(builder: NetworkBuilder, args: CreateKaleidoscopeArgs): Promise<string> {\n if (args.input_path) {\n return builder.add(\"selectTOP\", \"source\", { top: args.input_path });\n }\n // Coloured (non-monochrome) noise gives the fold something with structure and hue to mirror.\n const noise = await builder.add(\"noiseTOP\", \"source\", { monochrome: 0, period: 4 });\n // Drift the noise over time so the default look is alive even before any control is touched.\n await builder.python(`op(${q(noise)}).par.tz.expr = ${q(\"absTime.seconds * 0.2\")}`);\n return noise;\n}\n\nexport async function createKaleidoscopeImpl(ctx: ToolContext, args: CreateKaleidoscopeArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"kaleidoscope\");\n\n const source = await buildSource(builder, args);\n\n // The fold itself. A fixed RGBA canvas keeps the output a clean full-res frame regardless of\n // the source's resolution (the GLSL TOP otherwise inherits input 0's size).\n const kaleido = await builder.add(\"glslTOP\", \"kaleido\", {\n outputresolution: \"custom\",\n resolutionw: 1280,\n resolutionh: 720,\n format: \"rgba8fixed\",\n });\n const frag = await builder.add(\"textDAT\", \"kaleido_frag\");\n await builder.python(\n `op(${q(frag)}).text = ${q(KALEIDOSCOPE_SHADER)}\\nop(${q(kaleido)}).par.pixeldat = op(${q(frag)}).name`,\n );\n await builder.connect(source, kaleido);\n\n // Bind the four uniforms. uSegments/uRotation/uZoom are scalar floats and uCenter is a vec2 —\n // both kinds live in the GLSL TOP's \"Vectors\" sequence (a float fills valuex; the vec2 fills\n // valuex/valuey). The sequence block count has no structured setter, so raise numBlocks first,\n // then name each block and drive its components by expression off parent().par.* so the\n // exposed knobs move them live. A defensive hasattr() fallback uses the build-time constant\n // when no control is present, so the expression never errors.\n const segExpr = `(parent().par.Segments.eval() if hasattr(parent().par, 'Segments') else ${args.segments})`;\n const rotExpr = `(parent().par.Rotation.eval() if hasattr(parent().par, 'Rotation') else ${args.rotation})`;\n const zoomExpr = `(parent().par.Zoom.eval() if hasattr(parent().par, 'Zoom') else ${args.zoom})`;\n const cxExpr = `(parent().par.Centerx.eval() if hasattr(parent().par, 'Centerx') else ${args.center_x})`;\n const cyExpr = `(parent().par.Centery.eval() if hasattr(parent().par, 'Centery') else ${args.center_y})`;\n await builder.python(\n [\n `_g = op(${q(kaleido)})`,\n `_g.seq.vec.numBlocks = max(_g.seq.vec.numBlocks, 4)`,\n `_g.par.vec0name = 'uSegments'`,\n `_g.par.vec0valuex.expr = ${q(segExpr)}`,\n `_g.par.vec1name = 'uRotation'`,\n `_g.par.vec1valuex.expr = ${q(rotExpr)}`,\n `_g.par.vec2name = 'uZoom'`,\n `_g.par.vec2valuex.expr = ${q(zoomExpr)}`,\n `_g.par.vec3name = 'uCenter'`,\n `_g.par.vec3valuex.expr = ${q(cxExpr)}`,\n `_g.par.vec3valuey.expr = ${q(cyExpr)}`,\n ].join(\"\\n\"),\n );\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(kaleido, out);\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n { name: \"Segments\", type: \"int\", min: 2, max: 32, default: args.segments },\n { name: \"Rotation\", type: \"float\", min: 0, max: 6.2832, default: args.rotation },\n { name: \"Zoom\", type: \"float\", min: 0.1, max: 4, default: args.zoom },\n { name: \"Center X\", type: \"float\", min: 0, max: 1, default: args.center_x },\n { name: \"Center Y\", type: \"float\", min: 0, max: 1, default: args.center_y },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Created a ${args.segments}-fold kaleidoscope ${\n args.input_path ? `over ${args.input_path}` : \"over a generated noise source\"\n } → ${out}. Bind a parameter to op('${out}').par.Rotation (on the container) — or feed input_path — to drive it.`,\n builder,\n outputPath: out,\n capturePreviewImage: true,\n controls,\n extra: {\n segments: args.segments,\n rotation: args.rotation,\n zoom: args.zoom,\n center: [args.center_x, args.center_y],\n input_path: args.input_path ?? null,\n },\n });\n });\n}\n\nexport const registerCreateKaleidoscope: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_kaleidoscope\",\n {\n title: \"Create kaleidoscope\",\n description:\n \"Wrap a source in a kaleidoscope / radial-mirror symmetry effect — a signature VJ look. Folds the image into N identical mirrored wedges around a centre, with live Segments / Rotation / Zoom / Center controls. Pass input_path (an absolute TOP path) to kaleidoscope an existing visual, or omit it to generate a self-contained noise source that previews on its own. Output is a TOP.\",\n inputSchema: createKaleidoscopeSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createKaleidoscopeImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nconst keyframeSchema = z.object({\n time: z.coerce.number().min(0).describe(\"Time of this key, in seconds from the loop start.\"),\n value: z.coerce.number().describe(\"Parameter value at this time.\"),\n});\n\nexport const createKeyframeAnimationSchema = z.object({\n targets: z\n .array(z.string())\n .min(1)\n .describe(\"Parameters to animate, each written as 'nodePath.parName'.\"),\n keyframes: z\n .array(keyframeSchema)\n .min(2)\n .describe(\"Keyframes (time + value); the curve interpolates between them in order.\"),\n loop: z\n .boolean()\n .default(true)\n .describe(\"Loop the animation; otherwise it holds the last value.\"),\n easing: z\n .enum([\"linear\", \"smooth\"])\n .default(\"smooth\")\n .describe(\"Interpolation between keys: linear, or smooth (eased) for organic motion.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateKeyframeAnimationArgs = z.infer<typeof createKeyframeAnimationSchema>;\n\ninterface KeyframeReport {\n container?: string;\n hook?: string;\n duration?: number;\n targets?: string[];\n warnings: string[];\n fatal?: string;\n}\n\n// Execute DAT body: each frame, interpolate the keyframes at the (optionally looping) current\n// time and write the value onto every target parameter. Self-contained — reads its config from\n// the container's storage.\nconst KEYFRAME_HOOK = `import td\n\ndef _interp(keys, t, easing):\n if not keys:\n return None\n if t <= keys[0][0]:\n return keys[0][1]\n if t >= keys[-1][0]:\n return keys[-1][1]\n for i in range(len(keys) - 1):\n t0, v0 = keys[i]\n t1, v1 = keys[i + 1]\n if t0 <= t <= t1:\n f = (t - t0) / (t1 - t0) if t1 > t0 else 0.0\n if easing == 'smooth':\n f = f * f * (3.0 - 2.0 * f)\n return v0 + (v1 - v0) * f\n return keys[-1][1]\n\ndef onFrameStart(frame):\n comp = me.parent()\n cfg = comp.fetch('tdmcp_keyframes', None)\n if not cfg:\n return\n dur = cfg.get('duration') or 0.0001\n now = td.absTime.seconds\n t = (now % dur) if cfg.get('loop') else min(now, dur)\n val = _interp(cfg.get('keys', []), t, cfg.get('easing', 'smooth'))\n if val is None:\n return\n for tgt in cfg.get('targets', []):\n try:\n dot = tgt.rfind('.')\n n = op(tgt[:dot])\n par = getattr(n.par, tgt[dot + 1:], None) if n is not None else None\n if par is not None and not par.readOnly:\n par.val = val\n except Exception:\n pass\n return\n`;\n\nconst KEYFRAME_SCRIPT = `\nimport json, base64, traceback\nimport td\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nreport = {\"warnings\": []}\ntry:\n _parent = op(_p[\"parent\"])\n if _parent is None:\n report[\"fatal\"] = \"Parent COMP not found: \" + str(_p[\"parent\"])\n else:\n _cont = _parent.create(td.baseCOMP, \"keyframe_anim\")\n _cont.store(\"tdmcp_keyframes\", {\n \"keys\": _p[\"keys\"], \"targets\": _p[\"targets\"],\n \"duration\": _p[\"duration\"], \"loop\": _p[\"loop\"], \"easing\": _p[\"easing\"],\n })\n _hook = _cont.create(td.executeDAT, \"anim\")\n _hook.text = _p[\"hook\"]\n if hasattr(_hook.par, \"framestart\"):\n _hook.par.framestart = True\n _hook.par.active = True\n report[\"container\"] = _cont.path; report[\"hook\"] = _hook.path\n report[\"duration\"] = _p[\"duration\"]; report[\"targets\"] = _p[\"targets\"]\n # surface any targets that don't resolve, as a warning\n for _t in _p[\"targets\"]:\n _dot = _t.rfind(\".\")\n _n = op(_t[:_dot]) if _dot > 0 else None\n if _n is None or getattr(_n.par, _t[_dot + 1:], None) is None:\n report[\"warnings\"].append(\"Target not found: \" + _t)\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildKeyframeScript(payload: object): string {\n return buildPayloadScript(KEYFRAME_SCRIPT, payload);\n}\n\nexport async function createKeyframeAnimationImpl(\n ctx: ToolContext,\n args: CreateKeyframeAnimationArgs,\n) {\n // Sort keys by time and derive the loop duration from the last key.\n const keys = [...args.keyframes]\n .sort((a, b) => a.time - b.time)\n .map((k) => [k.time, k.value] as [number, number]);\n const duration = keys[keys.length - 1]?.[0] ?? 1;\n if (duration <= 0) {\n return errorResult(\n \"Keyframes must span a positive duration (the last key's time must be > 0).\",\n );\n }\n return guardTd(\n async () => {\n const script = buildKeyframeScript({\n parent: args.parent_path,\n keys,\n targets: args.targets,\n duration,\n loop: args.loop,\n easing: args.easing,\n hook: KEYFRAME_HOOK,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<KeyframeReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Could not create keyframe animation: ${report.fatal}`, report);\n }\n const summary = `Keyframe animation at ${report.container} drives ${report.targets?.length ?? 0} parameter(s) over a ${report.duration}s ${args.loop ? \"loop\" : \"one-shot\"} (${args.easing})${\n report.warnings.length ? `, ${report.warnings.length} warning(s)` : \"\"\n }.`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerCreateKeyframeAnimation: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_keyframe_animation\",\n {\n title: \"Create keyframe animation\",\n description:\n \"Animate parameters along a keyframed curve synced to the timeline — structured motion beyond animate_parameter's LFO. Give time/value keyframes and the targets; an Execute DAT interpolates the curve each frame (linear or smooth easing) and loops it. Use it for choreographed moves (a build-up, a drop, a sweep) rather than continuous oscillation.\",\n inputSchema: createKeyframeAnimationSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createKeyframeAnimationImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport const createKineticTextSchema = z.object({\n text: z\n .string()\n .default(\"DUQUESA\")\n .describe(\n \"The word or line to animate (the lyric flash). Rendered by a Text TOP. For multiple lines use \\\\n.\",\n ),\n mode: z\n .enum([\"flash\", \"pulse\", \"slide\"])\n .default(\"flash\")\n .describe(\n \"Animation style: 'flash' = hard on/off blink (a square LFO gates the alpha/opacity — the classic lyric-flash, the text vanishes between flashes rather than going black); 'pulse' = breathing scale-up + alpha fade driven by a sine LFO; 'slide' = the text scrolls horizontally across the frame.\",\n ),\n size: z.coerce\n .number()\n .positive()\n .default(120)\n .describe(\"Font size in pixels (drives the Text TOP's fontsizex / fontsizey).\"),\n color: z\n .string()\n .default(\"#ffffff\")\n .describe(\n \"Text colour as a hex string ('#ffffff' = white). Sets the Text TOP's fontcolorr/g/b.\",\n ),\n rate_hz: z.coerce\n .number()\n .positive()\n .default(2)\n .describe(\n \"Animation rate in cycles per second (Hz) — the LFO frequency. Free-running for v1; bind it to a beat CHOP to fire on the actual beat.\",\n ),\n input_path: z\n .string()\n .optional()\n .describe(\n \"Optional absolute path of a source TOP to lay the text OVER. Pulled in via a Select TOP (TD wires don't cross containers) and composited under the text. If omitted, the text animates on a transparent frame.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\n \"Expose live Text / Size / Color / Rate controls bound to the right node parameters.\",\n ),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateKineticTextArgs = z.infer<typeof createKineticTextSchema>;\n\n/** Parses '#rrggbb' / 'rrggbb' (3- or 6-digit) into 0..1 RGB. Falls back to white. */\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());\n if (!m) return { r: 1, g: 1, b: 1 };\n let h = m[1] as string;\n if (h.length === 3)\n h = h\n .split(\"\")\n .map((c) => c + c)\n .join(\"\");\n const int = Number.parseInt(h, 16);\n return {\n r: ((int >> 16) & 0xff) / 255,\n g: ((int >> 8) & 0xff) / 255,\n b: (int & 0xff) / 255,\n };\n}\n\nexport async function createKineticTextImpl(ctx: ToolContext, args: CreateKineticTextArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"kinetic_text\");\n const rgb = hexToRgb(args.color);\n\n // The word itself. Text TOP param names (verified against text_top.json): `text`,\n // `fontsizex`/`fontsizey`, `fontcolorr/g/b`, `alignx`/`aligny` (centre it in frame).\n const textTop = await builder.add(\"textTOP\", \"text\", {\n text: args.text,\n fontsizex: args.size,\n fontsizey: args.size,\n fontcolorr: rgb.r,\n fontcolorg: rgb.g,\n fontcolorb: rgb.b,\n alignx: \"center\",\n aligny: \"center\",\n });\n\n // The animation driver. flash uses a square wave (hard gate); pulse/slide use a sine\n // (smooth motion). channelname 'chan1' so the brightness/transform expressions can\n // reference op(lfo)['chan1'] by ABSOLUTE path (param expressions evaluate relative to\n // the node's PARENT, so a relative name would not resolve).\n const lfo = await builder.add(\"lfoCHOP\", \"anim_lfo\", {\n wavetype: args.mode === \"flash\" ? \"square\" : \"sine\",\n frequency: args.rate_hz,\n amp: 1,\n offset: 0,\n channelname: \"chan1\",\n });\n\n // Build the animation per mode. `animated` is the TOP carrying the moving text; the\n // node whose opacity the flash/fade gates is `level` (when present).\n let animated = textTop;\n let levelNode: string | undefined;\n let transformNode: string | undefined;\n\n if (args.mode === \"flash\") {\n // Hard on/off: the square LFO swings [-1, 1]; treat >0 as \"on\" so the text snaps\n // fully on then fully off (a crisp flash, not a fade). Gate the Level TOP's `opacity`\n // (the alpha multiplier — verified in level_top.json: `level.par.opacity`), NOT\n // brightness1: brightness only darkens the RGB, so \"off\" left a BLACK text silhouette\n // composited over a background. opacity 0 multiplies the glyph alpha to zero, so the\n // whole layer truly vanishes (RGB / font colour is untouched). Switch it to EXPRESSION\n // mode the way animate_parameter does — `type(par.mode).EXPRESSION` (ParMode isn't a\n // bridge global).\n const level = await builder.add(\"levelTOP\", \"level\", { opacity: 1 });\n await builder.connect(textTop, level);\n const expr = `(1 if op(${q(lfo)})['chan1'] > 0 else 0)`;\n await builder.python(\n `_p = op(${q(level)}).par.opacity\\n_p.expr = ${q(expr)}\\n_p.mode = type(_p.mode).EXPRESSION`,\n );\n levelNode = level;\n animated = level;\n } else if (args.mode === \"pulse\") {\n // Breathing scale + fade. The sine LFO (chan1, [-1, 1]) drives a Transform TOP's\n // sx/sy (scale, NOT scalex/scaley) between ~0.8 and ~1.2, and a Level TOP's `opacity`\n // between ~0.4 and 1.0 — the word swells and fades in/out, then recedes. Fading the\n // alpha (opacity), not brightness1, so the text fades to transparent (not to black)\n // over a background; RGB / font colour stays intact.\n const transform = await builder.add(\"transformTOP\", \"scale\", { sx: 1, sy: 1 });\n await builder.connect(textTop, transform);\n const scaleExpr = `(1 + 0.2 * op(${q(lfo)})['chan1'])`;\n await builder.python(\n [\n `_t = op(${q(transform)})`,\n `for _name in ('sx', 'sy'):`,\n ` _p = getattr(_t.par, _name)`,\n ` _p.expr = ${q(scaleExpr)}`,\n ` _p.mode = type(_p.mode).EXPRESSION`,\n ].join(\"\\n\"),\n );\n const level = await builder.add(\"levelTOP\", \"level\", { opacity: 1 });\n await builder.connect(transform, level);\n const fadeExpr = `(0.7 + 0.3 * op(${q(lfo)})['chan1'])`;\n await builder.python(\n `_p = op(${q(level)}).par.opacity\\n_p.expr = ${q(fadeExpr)}\\n_p.mode = type(_p.mode).EXPRESSION`,\n );\n transformNode = transform;\n levelNode = level;\n animated = level;\n } else {\n // Horizontal scroll. Drive the Transform TOP's tx (translate X, NOT translatex) with\n // the sine LFO so the word slides left↔right across the frame (±0.5 of the frame\n // width). For a continuous one-way scroll, bind tx to a Speed CHOP/ramp instead.\n const transform = await builder.add(\"transformTOP\", \"slide\", { tx: 0, ty: 0 });\n await builder.connect(textTop, transform);\n const slideExpr = `(0.5 * op(${q(lfo)})['chan1'])`;\n await builder.python(\n `_p = op(${q(transform)}).par.tx\\n_p.expr = ${q(slideExpr)}\\n_p.mode = type(_p.mode).EXPRESSION`,\n );\n transformNode = transform;\n animated = transform;\n }\n\n // Optionally composite the animated text OVER an external source. The source can live\n // in another container, so it must be pulled in by a Select TOP (`top` = absolute path)\n // rather than a (cross-container-illegal) wire. operand 'over' = alpha compositing,\n // with the text on input 1 (on top) and the source on input 0 (background).\n let output = animated;\n if (args.input_path) {\n const src = await builder.add(\"selectTOP\", \"src\", { top: args.input_path });\n const comp = await builder.add(\"compositeTOP\", \"comp\", { operand: \"over\" });\n await builder.connect(src, comp, 0, 0);\n await builder.connect(animated, comp, 0, 1);\n output = comp;\n }\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(output, out);\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Text\",\n type: \"string\",\n default: args.text,\n bind_to: [`${textTop}.text`],\n },\n {\n name: \"Size\",\n type: \"float\",\n min: 0,\n max: 500,\n default: args.size,\n // Keep X and Y in lockstep so the knob scales the glyphs uniformly.\n bind_to: [`${textTop}.fontsizex`, `${textTop}.fontsizey`],\n },\n {\n // A single float over all three RGB components (a whiteness / brightness knob);\n // the build-time `color` sets the actual hue. 'rgb' controls can't bind, so a\n // float driving fontcolorr/g/b is the bindable way to live-tweak the colour.\n name: \"Color\",\n type: \"float\",\n min: 0,\n max: 1,\n default: Math.max(rgb.r, rgb.g, rgb.b),\n bind_to: [`${textTop}.fontcolorr`, `${textTop}.fontcolorg`, `${textTop}.fontcolorb`],\n },\n {\n name: \"Rate\",\n type: \"float\",\n min: 0,\n max: 30,\n default: args.rate_hz,\n bind_to: [`${lfo}.frequency`],\n },\n ]\n : [];\n\n const modeBlurb =\n args.mode === \"flash\"\n ? `flashing on/off at ${args.rate_hz} Hz`\n : args.mode === \"pulse\"\n ? `pulsing (scale + fade) at ${args.rate_hz} Hz`\n : `sliding horizontally at ${args.rate_hz} Hz`;\n\n return finalize(ctx, {\n summary: `Built kinetic text \"${args.text}\" ${modeBlurb}${\n args.input_path ? ` over ${args.input_path}` : \"\"\n } → ${out}. Rate is free-running for v1 — bind op('${lfo}').par.frequency to a beat CHOP, or bind a Trigger to a detect_onsets channel, to fire on the actual beat.`,\n builder,\n outputPath: out,\n // Output is a TOP (the Null), so a preview image is captured.\n capturePreviewImage: true,\n controls,\n extra: {\n text: args.text,\n mode: args.mode,\n size: args.size,\n color: { r: rgb.r, g: rgb.g, b: rgb.b },\n rate_hz: args.rate_hz,\n text_path: textTop,\n lfo_path: lfo,\n level_path: levelNode,\n transform_path: transformNode,\n output_path: out,\n input_path: args.input_path,\n },\n });\n });\n}\n\nexport const registerCreateKineticText: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_kinetic_text\",\n {\n title: \"Create kinetic text\",\n description:\n \"Build a self-contained animated / kinetic typography layer — a word or line that flashes, pulses, or slides, the signature live-VJ lyric-flash effect. A Text TOP renders the text; an LFO CHOP at the given Rate (Hz) drives the animation: 'flash' gates a Level TOP's alpha/opacity hard on/off (a square wave — the text vanishes between flashes rather than turning black, so it pops cleanly in and out over a background), 'pulse' drives a Transform TOP's scale plus a Level TOP alpha fade (a sine, the text breathes), and 'slide' scrolls the Transform TOP's translate-X. With an input_path the text is composited OVER that source (pulled in by a Select TOP, so it can live in another container); without one it animates on a transparent frame. Output is a Null TOP. Rate is free-running for v1 — bind the LFO's frequency to a beat CHOP (or a Trigger to a detect_onsets channel) to lock the flashes to the tempo.\",\n inputSchema: createKineticTextSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createKineticTextImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nexport const createLayerMixerSchema = z.object({\n inputs: z\n .array(z.string())\n .default([])\n .describe(\n \"Paths of source TOPs to mix (brought in via Select TOPs, so they can live in other containers). With fewer than 2, demo sources (noise + ramp) are created so you can see it working.\",\n ),\n blend: z\n .enum([\n \"crossfade\",\n \"add\",\n \"difference\",\n \"hardlight\",\n \"glow\",\n \"lightercolor\",\n \"darkercolor\",\n \"average\",\n \"exclude\",\n ])\n .default(\"crossfade\")\n .describe(\n \"'crossfade' = an A/B Cross TOP with a Crossfade knob; any other value composites all inputs with that blend mode.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose a live 'Crossfade' knob (crossfade mode only).\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateLayerMixerArgs = z.infer<typeof createLayerMixerSchema>;\n\nexport async function createLayerMixerImpl(ctx: ToolContext, args: CreateLayerMixerArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"layer_mixer\");\n\n // Bring each external source in through a Select TOP (TD wires don't cross containers).\n // With fewer than two real inputs, drop in two distinct demo sources so the mix is visible.\n const sources: string[] = [];\n if (args.inputs.length >= 2) {\n for (const input of args.inputs) {\n sources.push(await builder.add(\"selectTOP\", undefined, { top: input }));\n }\n } else {\n sources.push(await builder.add(\"noiseTOP\", \"srcA\"));\n sources.push(await builder.add(\"rampTOP\", \"srcB\"));\n }\n\n let output: string;\n const controls: ControlSpec[] = [];\n if (args.blend === \"crossfade\" && sources.length === 2) {\n const cross = await builder.add(\"crossTOP\", \"mix\", { cross: 0.5 });\n await builder.connect(sources[0] as string, cross, 0, 0);\n await builder.connect(sources[1] as string, cross, 0, 1);\n output = cross;\n if (args.expose_controls) {\n controls.push({\n name: \"Crossfade\",\n type: \"float\",\n min: 0,\n max: 1,\n default: 0.5,\n bind_to: [`${cross}.cross`],\n });\n }\n } else {\n const operand = args.blend === \"crossfade\" ? \"add\" : args.blend;\n const composite = await builder.add(\"compositeTOP\", \"mix\", { operand });\n for (const [i, source] of sources.entries()) {\n await builder.connect(source, composite, 0, i);\n }\n output = composite;\n }\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(output, out);\n\n return finalize(ctx, {\n summary: `Built a layer mixer (${args.blend}) over ${sources.length} source(s) → ${out}.`,\n builder,\n outputPath: out,\n controls,\n extra: { blend: args.blend, sources, output_path: out },\n });\n });\n}\n\nexport const registerCreateLayerMixer: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_layer_mixer\",\n {\n title: \"Create layer mixer\",\n description:\n \"Build a VJ-style layer mixer: combine source TOPs into one output. 'crossfade' makes an A/B Cross TOP with a Crossfade knob (the classic two-deck mix); any other blend mode composites the inputs (add, difference, hardlight, glow, …). Sources are pulled in via Select TOPs so they can live anywhere; with fewer than two, demo sources are created. Output is a Null ready for post-processing or setup_output.\",\n inputSchema: createLayerMixerSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createLayerMixerImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\n/**\n * Per-warp expression that drives a grid point's Z from its planar (X, Y) position. `A`\n * is substituted with the deformation amount. The grid lives in the XY plane, so pushing\n * Pz bends a flat sheet into a curved surface. These are *expressions* evaluated per point\n * (TouchDesigner exposes the incoming point as `me.inputPoint`), so the source X/Y are read\n * via `me.inputPoint.x` / `me.inputPoint.y`.\n */\nconst WARP_PZ_EXPR: Record<\"bulge\" | \"wave\" | \"cylinder\", (amount: string) => string> = {\n // Dome: highest at centre, falling to the rim (a paraboloid).\n bulge: (a) => `${a} * (1 - (me.inputPoint.x*me.inputPoint.x + me.inputPoint.y*me.inputPoint.y))`,\n // Ripples running across X.\n wave: (a) => `${a} * sin(me.inputPoint.x * 6.283185)`,\n // Half-cylinder: the sheet wraps around the X axis.\n cylinder: (a) => `${a} * cos(me.inputPoint.x * 3.141593)`,\n};\n\nexport const createMeshWarpSchema = z.object({\n source_path: z\n .string()\n .describe(\"Path of the TOP to map onto the surface (brought in through a Select TOP).\"),\n rows: z.coerce\n .number()\n .int()\n .min(2)\n .default(20)\n .describe(\"Grid rows — more rows give a smoother curve but a heavier mesh.\"),\n cols: z.coerce\n .number()\n .int()\n .min(2)\n .default(20)\n .describe(\"Grid columns — more columns give a smoother curve but a heavier mesh.\"),\n warp: z\n .enum([\"bulge\", \"wave\", \"cylinder\", \"flat\"])\n .default(\"bulge\")\n .describe(\n \"Surface shape: bulge (dome), wave (ripples across X), cylinder (half-cylinder wrap), or flat (no deform).\",\n ),\n amount: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(0.3)\n .describe(\"Deformation strength (0 = flat, 1 = full bend). Ignored when warp is 'flat'.\"),\n expose_controls: z.boolean().default(true).describe(\"Expose a live Zoom (camera distance) knob.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateMeshWarpArgs = z.infer<typeof createMeshWarpSchema>;\n\nexport async function createMeshWarpImpl(ctx: ToolContext, args: CreateMeshWarpArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"mesh_warp\");\n\n // Source texture brought in via a Select TOP so it can live in another container.\n const src = await builder.add(\"selectTOP\", \"src\", { top: args.source_path });\n\n // Geometry COMP (the builder clears its default torus) holding a grid in the XY plane.\n const geo = await builder.add(\"geometryCOMP\", \"geo\");\n const surface = await builder.add(\n \"gridSOP\",\n \"surface\",\n { rows: args.rows, cols: args.cols, orient: \"xy\" },\n geo,\n );\n\n // Deform the grid by pushing each point's Z from its planar position, bending the flat\n // sheet into the chosen curved surface. The deformed SOP becomes the one the COMP renders.\n if (args.warp !== \"flat\") {\n const deform = await builder.add(\"pointSOP\", \"deform\", {}, geo);\n await builder.connect(surface, deform);\n const amount = Number(args.amount.toFixed(4)).toString();\n const pzExpr = WARP_PZ_EXPR[args.warp](amount);\n // The Point SOP's tx/ty/tz are per-point translate expressions (the incoming point is\n // `me.inputPoint`), so the Z translate alone bends the flat sheet — no enable toggle needed.\n await builder.python(\n `_p = op(${q(deform)})\\n_p.par.tz.expr = ${q(pzExpr)}\\n_p.render = True\\n_p.display = True`,\n );\n // The undeformed grid must stop being rendered so only the deformed surface shows.\n await builder.python(`_s = op(${q(surface)})\\n_s.render = False\\n_s.display = False`);\n } else {\n // Flat: render the grid directly.\n await builder.python(`_s = op(${q(surface)})\\n_s.render = True\\n_s.display = True`);\n }\n\n // Texture the surface with the source via a Constant MAT (its Color Map = the src TOP).\n const mat = await builder.add(\"constantMAT\", \"mat\");\n await builder.python(`op(${q(mat)}).par.colormap = ${q(src)}`);\n await builder.setParams(geo, { material: mat });\n\n // Orthographic camera (no perspective distortion, which reads better for surface mapping),\n // tilted down a little so the curvature of the warped surface is visible rather than hidden\n // behind a head-on view. Reset rx/ty to 0 for a flat, projector-aligned mapping render.\n const cam = await builder.add(\"cameraCOMP\", \"cam\", {\n tz: 5,\n ty: 1.4,\n rx: -22,\n projection: \"ortho\",\n });\n const light = await builder.add(\"lightCOMP\", \"light\", { tx: 3, ty: 3, tz: 5 });\n // Render TOP reads its scene from parameters (not wires): camera, geometry, lights.\n const render = await builder.add(\"renderTOP\", \"render\", {\n camera: cam,\n geometry: geo,\n lights: light,\n });\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(render, out);\n\n // Zoom (camera distance) binds cleanly. WarpAmount is driven by a per-point SOP expression,\n // not a single bindable parameter, so we do not fake a knob for it.\n const controls: ControlSpec[] = args.expose_controls\n ? [{ name: \"Zoom\", type: \"float\", min: 1, max: 20, default: 5, bind_to: [`${cam}.tz`] }]\n : [];\n if (args.expose_controls && args.warp !== \"flat\") {\n builder.warnings.push(\n \"⚠ WarpAmount is baked into the deform expression (no single bindable param) — to make it live-tunable, add a custom WarpAmount par on the container and reference it inside the tz expression.\",\n );\n }\n\n const warpNote = args.warp === \"flat\" ? \"flat (no deform)\" : `${args.warp} @ ${args.amount}`;\n return finalize(ctx, {\n summary: `Built a mesh-warp surface (${warpNote}, ${args.rows}×${args.cols} grid) rendered to ${out} — Select → Geometry(grid+deform, textured by Constant MAT) → Camera + Light + Render TOP. Send ${out} to setup_output.`,\n builder,\n outputPath: out,\n controls,\n extra: {\n source_path: args.source_path,\n rows: args.rows,\n cols: args.cols,\n warp: args.warp,\n amount: args.amount,\n output_path: out,\n },\n });\n });\n}\n\nexport const registerCreateMeshWarp: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_mesh_warp\",\n {\n title: \"Create mesh warp\",\n description:\n \"Map a source TOP onto a curved or irregular surface via a deformable textured grid — the curved-surface upgrade to create_projection_mapping's flat corner-pin, for domes, columns, and sculptures. Builds a Geometry COMP holding a grid that is bent into a dome (bulge), ripples (wave), half-cylinder (cylinder), or left flat, textured with the source through a Constant MAT, and rendered through an orthographic Camera + Light + Render TOP. Output is a Null ready for setup_output; exposes a Zoom knob.\",\n inputSchema: createMeshWarpSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createMeshWarpImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport const createMotionReactiveSchema = z.object({\n source: z\n .enum([\"camera\", \"file\", \"synthetic\", \"existing_top\"])\n .default(\"camera\")\n .describe(\n \"Video source. 'camera' = live webcam/capture device (the real-world default; creating it may pop a one-time macOS camera-permission dialog — click Allow). 'file' = a movie file. 'synthetic' = an animated noise pattern, handy for testing without any device permission. 'existing_top' = analyze a TOP you already have.\",\n ),\n movie_file_path: z.string().optional().describe(\"Movie file path (source='file').\"),\n existing_top_path: z\n .string()\n .optional()\n .describe(\"Path of an existing TOP to analyze (source='existing_top').\"),\n analysis_resolution: z.coerce\n .number()\n .int()\n .positive()\n .default(160)\n .describe(\n \"The video is downsized to this square resolution before analysis — small keeps it cheap (the reactive values barely change with size).\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose a live 'Sensitivity' knob (a gain over every feature channel).\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateMotionReactiveArgs = z.infer<typeof createMotionReactiveSchema>;\n\nasync function buildSource(\n builder: NetworkBuilder,\n args: CreateMotionReactiveArgs,\n): Promise<string> {\n if (args.source === \"existing_top\" && args.existing_top_path) {\n return args.existing_top_path;\n }\n if (args.source === \"file\") {\n return builder.add(\"moviefileinTOP\", \"videoin\", {\n ...(args.movie_file_path ? { file: args.movie_file_path } : {}),\n play: 1,\n });\n }\n if (args.source === \"synthetic\") {\n // A scrolling noise pattern: consecutive frames differ, so 'motion' reads non-zero —\n // a self-contained signal for verifying the chain without any camera permission.\n const noise = await builder.add(\"noiseTOP\", \"videoin\", {\n resolutionw: args.analysis_resolution,\n resolutionh: args.analysis_resolution,\n });\n await builder.python(`op(${q(noise)}).par.tz.expr = \"absTime.seconds * 2\"`);\n return noise;\n }\n return builder.add(\"videodeviceinTOP\", \"videoin\");\n}\n\nexport async function createMotionReactiveImpl(ctx: ToolContext, args: CreateMotionReactiveArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"motion_reactive\");\n const source = await buildSource(builder, args);\n\n // Downsize to a small monochrome image once; both branches read it (cheap, and the\n // reactive averages are resolution-independent).\n const mono = await builder.add(\"monochromeTOP\", \"mono\", {\n outputresolution: \"custom\",\n resolutionw: args.analysis_resolution,\n resolutionh: args.analysis_resolution,\n });\n await builder.connect(source, mono);\n\n // brightness = average luminance of the current frame.\n const brightA = await builder.add(\"analyzeTOP\", \"bright_a\", { op: \"average\" });\n await builder.connect(mono, brightA);\n const brightC = await builder.add(\"toptoCHOP\", \"bright_c\", {\n top: brightA,\n r: \"brightness\",\n g: \"\",\n b: \"\",\n a: \"\",\n });\n\n // motion = average per-pixel change vs the previous frame. A Cache TOP holds the frame one\n // step back (outputindex -1; index 0 is newest), a Difference TOP subtracts, and Analyze\n // reduces to one value. Static input ⇒ 0; movement ⇒ > 0 (validated live).\n const cache = await builder.add(\"cacheTOP\", \"prevframe\", {\n active: 1,\n cachesize: 2,\n outputindexunit: \"indices\",\n outputindex: -1,\n });\n await builder.connect(mono, cache);\n const diff = await builder.add(\"differenceTOP\", \"framediff\");\n await builder.connect(mono, diff, 0, 0);\n await builder.connect(cache, diff, 0, 1);\n const motionA = await builder.add(\"analyzeTOP\", \"motion_a\", { op: \"average\" });\n await builder.connect(diff, motionA);\n const motionC = await builder.add(\"toptoCHOP\", \"motion_c\", {\n top: motionA,\n r: \"motion\",\n g: \"\",\n b: \"\",\n a: \"\",\n });\n\n // Merge the two single-channel CHOPs, apply a Sensitivity gain, and end on a Null as the\n // stable bind point. Expressions read op('…/features')['motion'] / ['brightness'].\n const merge = await builder.add(\"mergeCHOP\", \"merged\");\n await builder.connect(brightC, merge, 0, 0);\n await builder.connect(motionC, merge, 0, 1);\n const gain = await builder.add(\"mathCHOP\", \"sensitivity\", { gain: 1 });\n await builder.connect(merge, gain);\n const features = await builder.add(\"nullCHOP\", \"features\");\n await builder.connect(gain, features);\n\n // The analysis is TOP-based, so without something pulling it every frame the Cache/Difference\n // chain goes cold and motion freezes. A tiny Execute DAT cooks the Null each frame so the\n // signals stay live even before anything is bound (binding a parameter would also pull it).\n const cooker = await builder.add(\"executeDAT\", \"cooker\");\n await builder.python(\n `_c = op(${q(cooker)})\\n_c.text = \"def onFrameStart(frame):\\\\n\\\\tparent().op('features').cook(force=True)\\\\n\\\\treturn\\\\n\"\\n_c.par.framestart = True\\n_c.par.active = True`,\n );\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Sensitivity\",\n type: \"float\",\n min: 0,\n max: 8,\n default: 1,\n bind_to: [`${gain}.gain`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Built a motion-reactive chain (source: ${args.source}) → ${features} with channels brightness/motion. Bind a parameter to op('${features}')['motion'] (or ['brightness']) to make it react to the camera.`,\n builder,\n outputPath: features,\n // The output is a CHOP, not a TOP, so there is no image to capture.\n capturePreviewImage: false,\n controls,\n extra: {\n source: args.source,\n features_path: features,\n channels: [\"brightness\", \"motion\"],\n analysis_resolution: args.analysis_resolution,\n },\n });\n });\n}\n\nexport const registerCreateMotionReactive: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_motion_reactive\",\n {\n title: \"Create motion reactive\",\n description:\n \"Build a video-analysis chain that exposes ready-to-bind reactive channels — overall brightness plus frame-to-frame motion energy — on a Null CHOP. The camera counterpart to extract_audio_features: bind any parameter to op('…/motion_reactive/features')['motion'] and it responds to movement in front of the camera, or ['brightness'] to ambient light. A Sensitivity knob scales both. Source can be the live camera (may prompt for macOS permission), a movie file, an animated synthetic pattern (for testing without a camera), or an existing TOP. Optical flow is unavailable on macOS, so direction isn't exposed.\",\n inputSchema: createMotionReactiveSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createMotionReactiveImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nconst RESOLUTIONS = {\n \"720p\": [1280, 720],\n \"1080p\": [1920, 1080],\n \"4K\": [3840, 2160],\n} as const;\n\nexport const createMultiOutputSchema = z.object({\n source_path: z.string().describe(\"The master TOP to fan out across the projectors/displays.\"),\n count: z.coerce\n .number()\n .int()\n .min(1)\n .default(2)\n .describe(\"How many outputs to split the master into (one per projector/display).\"),\n layout: z\n .enum([\"horizontal\", \"vertical\"])\n .default(\"horizontal\")\n .describe(\"Slice the master side-by-side (horizontal) or stacked (vertical).\"),\n overlap: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(0)\n .describe(\n \"Edge-blend: overlap each tile into its neighbor by this fraction of a tile's width, with a linear feather at the shared seams so physically-overlapping projectors blend smoothly (0 = abutting tiles, no blend). Try 0.1–0.3.\",\n ),\n resolution: z\n .enum([\"720p\", \"1080p\", \"4K\"])\n .default(\"1080p\")\n .describe(\"Per-output (per-projector) resolution.\"),\n as_windows: z\n .boolean()\n .default(false)\n .describe(\n \"Also create a borderless Window COMP per tile, offset across the desktop so each lands on its own display. Left closed — open them in Perform mode when ready.\",\n ),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateMultiOutputArgs = z.infer<typeof createMultiOutputSchema>;\n\n/** A GLSL fragment shader that multiplies the input tile by a linear edge feather: it fades in\n * over the first `wLow` of the axis (if > 0) and out over the last `wHigh` (if > 0). `axis` is\n * \"s\" for horizontal seams, \"t\" for vertical. */\nfunction featherShader(axis: \"s\" | \"t\", wLow: number, wHigh: number): string {\n const lines = [\n \"out vec4 fragColor;\",\n \"void main() {\",\n \" vec4 c = texture(sTD2DInputs[0], vUV.st);\",\n ` float p = vUV.${axis};`,\n \" float a = 1.0;\",\n ];\n if (wLow > 0) lines.push(` a *= clamp(p / ${wLow.toFixed(5)}, 0.0, 1.0);`);\n if (wHigh > 0) lines.push(` a *= clamp((1.0 - p) / ${wHigh.toFixed(5)}, 0.0, 1.0);`);\n lines.push(\" fragColor = c * a;\", \"}\");\n return lines.join(\"\\n\");\n}\n\nexport async function createMultiOutputImpl(ctx: ToolContext, args: CreateMultiOutputArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"multi_output\");\n const [tw, th] = RESOLUTIONS[args.resolution];\n const horizontal = args.layout === \"horizontal\";\n const base = 1 / args.count;\n const ov = args.overlap * base; // overlap width per seam, in source fraction\n\n // Pull the master in once through a Select TOP (works across COMP boundaries).\n const src = await builder.add(\"selectTOP\", \"src\", { top: args.source_path });\n\n const outputs: string[] = [];\n const windows: string[] = [];\n let blended = false;\n for (let i = 0; i < args.count; i++) {\n const hasLow = i > 0; // a neighbor on the low side (left/bottom)\n const hasHigh = i < args.count - 1; // a neighbor on the high side (right/top)\n // Widen the tile into its neighbours by the overlap, clamped to the canvas edges.\n const loSrc = Math.max(0, i * base - (hasLow ? ov : 0));\n const hiSrc = Math.min(1, (i + 1) * base + (hasHigh ? ov : 0));\n const span = hiSrc - loSrc;\n // Feather widths in the tile's own UV space (only on edges that touch a neighbour).\n const wLow = hasLow && ov > 0 && span > 0 ? ov / span : 0;\n const wHigh = hasHigh && ov > 0 && span > 0 ? ov / span : 0;\n\n // Crop the master to this tile's region (fractions, origin bottom-left), resized to the full\n // projector resolution.\n const tile = await builder.add(\"cropTOP\", `tile${i + 1}`, {\n cropleftunit: \"fraction\",\n croprightunit: \"fraction\",\n cropbottomunit: \"fraction\",\n croptopunit: \"fraction\",\n cropleft: horizontal ? loSrc : 0,\n cropright: horizontal ? hiSrc : 1,\n cropbottom: horizontal ? 0 : loSrc,\n croptop: horizontal ? 1 : hiSrc,\n outputresolution: \"custom\",\n resolutionw: tw,\n resolutionh: th,\n });\n await builder.connect(src, tile);\n\n // Edge-blend: a GLSL TOP multiplies the tile by a linear feather at the shared seams, so two\n // overlapping projectors sum to full brightness across the blend.\n let tileOut = tile;\n if (wLow > 0 || wHigh > 0) {\n const frag = await builder.add(\"textDAT\", `feather${i + 1}`);\n const glsl = await builder.add(\"glslTOP\", `blend${i + 1}`);\n await builder.connect(tile, glsl);\n const shader = featherShader(horizontal ? \"s\" : \"t\", wLow, wHigh);\n await builder.python(\n `op(${q(frag)}).text = ${q(shader)}\\nop(${q(glsl)}).par.pixeldat = op(${q(frag)}).name`,\n );\n tileOut = glsl;\n blended = true;\n }\n\n const out = await builder.add(\"nullTOP\", `out${i + 1}`);\n await builder.connect(tileOut, out);\n outputs.push(out);\n\n if (args.as_windows) {\n const win = await builder.add(\"windowCOMP\", `win${i + 1}`, {\n winop: out,\n winw: tw,\n winh: th,\n winoffsetx: horizontal ? i * tw : 0,\n winoffsety: horizontal ? 0 : i * th,\n borders: 0,\n winopen: 0,\n });\n windows.push(win);\n }\n }\n\n return finalize(ctx, {\n summary: `Split ${args.source_path} into ${args.count} ${args.layout} output(s) at ${args.resolution}${\n blended ? ` with edge-blend (overlap ${args.overlap})` : \"\"\n } → ${outputs.join(\", \")}${args.as_windows ? ` (+${windows.length} window(s), left closed)` : \"\"}.`,\n builder,\n outputPath: outputs[0] as string,\n controls: [],\n extra: {\n source_path: args.source_path,\n count: args.count,\n layout: args.layout,\n overlap: args.overlap,\n blended,\n outputs,\n windows,\n resolution: args.resolution,\n },\n });\n });\n}\n\nexport const registerCreateMultiOutput: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_multi_output\",\n {\n title: \"Create multi-output\",\n description:\n \"Fan a master TOP across N projectors/displays: each output is a cropped slice (horizontal or vertical) resized to full projector resolution and ended on a Null, ready for setup_output. Set `overlap` for edge-blending — tiles widen into their neighbours and a GLSL feather fades the shared seams so physically-overlapping projectors blend smoothly. With as_windows, each tile also gets a borderless Window COMP offset across the desktop so it lands on its own display (left closed — open in Perform mode). The multi-projector counterpart to setup_output's single window.\",\n inputSchema: createMultiOutputSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createMultiOutputImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nconst EMITTER_SOP = {\n point: \"addSOP\",\n line: \"lineSOP\",\n circle: \"circleSOP\",\n sphere: \"sphereSOP\",\n mesh: \"boxSOP\",\n image: \"gridSOP\",\n} as const;\n\nconst q2 = (n: number): string => (Number.isFinite(n) ? n.toString() : \"0\");\n\n/**\n * Builds the Python that turns a bare Particle SOP into a real, immediately-visible system:\n * - `normals = True` makes each particle inherit its source point's normal as initial\n * velocity, so a sphere/circle/box emitter actually sprays into a cloud (a single-point\n * emitter has no normal, so it stays a turbulence-driven stream — that's expected).\n * - `timepreroll = lifetime` pre-simulates the sim so frame 1 is already fully populated\n * instead of slowly filling in over the first few seconds.\n * - A baseline drag keeps the cloud contained within the camera frame.\n * - `birth` is derived from particle_count so the requested count is honored at steady state.\n * Forces map to native params where the legacy Particle SOP supports them (gravity → external,\n * noise/turbulence → turbulence, drag → drag); attract/repel/vortex have no native equivalent\n * and are approximated with turbulence (+ a little wind for vortex).\n */\ninterface ParticleDynamics {\n birth: number;\n drag: number;\n turb: number;\n gravity: number;\n wind: number;\n lifevar: number;\n}\n\n/** Single source of truth for the Particle SOP dynamics derived from the requested forces. */\nfunction computeParticleDynamics(args: CreateParticleSystemArgs): ParticleDynamics {\n const f = new Set(args.forces);\n const birth = Math.max(1, Math.round(args.particle_count / args.lifetime));\n let drag = 2.0;\n if (f.has(\"drag\")) drag = 3.5;\n if (f.has(\"repel\")) drag = 1.0;\n let turb = 0;\n if (f.has(\"noise\")) turb = 1.0;\n if (f.has(\"turbulence\")) turb = 1.8;\n if (f.has(\"attract\") || f.has(\"repel\") || f.has(\"vortex\")) turb = Math.max(turb, 1.2);\n const gravity = f.has(\"gravity\") ? -0.6 : 0;\n const wind = f.has(\"vortex\") ? 0.5 : 0;\n const lifevar = Number((args.lifetime * 0.25).toFixed(3));\n return { birth, drag, turb, gravity, wind, lifevar };\n}\n\nfunction particleDynamicsPython(\n particlePath: string,\n args: CreateParticleSystemArgs,\n dyn: ParticleDynamics,\n): string {\n return [\n `_p = op(${q(particlePath)})`,\n `_p.par.birth = ${dyn.birth}`,\n `_p.par.lifevar = ${q2(dyn.lifevar)}`,\n \"_p.par.normals = True\",\n \"_p.par.jitter = True\",\n `_p.par.timepreroll = ${q2(args.lifetime)}`,\n \"_p.par.dodrag = True\",\n `_p.par.drag = ${q2(dyn.drag)}`,\n `_p.par.turbx = ${q2(dyn.turb)}`,\n `_p.par.turby = ${q2(dyn.turb)}`,\n `_p.par.turbz = ${q2(dyn.turb)}`,\n \"_p.par.period = 3.0\",\n `_p.par.externaly = ${q2(dyn.gravity)}`,\n `_p.par.windx = ${q2(dyn.wind)}`,\n \"_p.par.reset.pulse()\",\n ].join(\"\\n\");\n}\n\nexport const createParticleSystemSchema = z.object({\n // Default to \"sphere\": its varied normals give particles a radial initial velocity, so the\n // out-of-the-box system is a full cloud. (\"point\" has no normals and stays a thin stream.)\n emitter_shape: z.enum([\"point\", \"line\", \"circle\", \"sphere\", \"mesh\", \"image\"]).default(\"sphere\"),\n particle_count: z.coerce.number().int().positive().default(10000),\n forces: z\n .array(z.enum([\"gravity\", \"noise\", \"attract\", \"repel\", \"vortex\", \"turbulence\", \"drag\"]))\n .default([\"noise\", \"gravity\"]),\n render_style: z\n .enum([\"points\", \"sprites\", \"lines\", \"trails\", \"instanced_geo\"])\n .default(\"sprites\"),\n lifetime: z.coerce.number().positive().default(3),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose live Drag / Turbulence / Gravity / Lifetime knobs on the system container.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateParticleSystemArgs = z.infer<typeof createParticleSystemSchema>;\n\nexport async function createParticleSystemImpl(ctx: ToolContext, args: CreateParticleSystemArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"particle_system\");\n\n // Geometry COMP holds the particle SOP chain so the renderer can see it.\n const geo = await builder.add(\"geometryCOMP\", \"geo\");\n\n const emitter = await ctx.client.createNode({\n parent_path: geo,\n type: EMITTER_SOP[args.emitter_shape],\n name: \"emitter\",\n });\n const particle = await ctx.client.createNode({\n parent_path: geo,\n type: \"particleSOP\",\n name: \"particle\",\n parameters: { life: args.lifetime },\n });\n builder.created.push(\n { name: \"emitter\", path: emitter.path, type: emitter.type },\n { name: \"particle\", path: particle.path, type: particle.type },\n );\n // The \"point\" emitter is an Add SOP, which ships with zero points — so the particle\n // SOP would have no source to birth from and the system renders empty. Enable a point\n // (its count is a parameter *sequence*, set via numBlocks rather than a plain par).\n if (args.emitter_shape === \"point\") {\n await builder.python(\n `_e = op(${q(emitter.path)})\\n_e.par.addpts = True\\n_e.seq.point.numBlocks = max(_e.seq.point.numBlocks, 1)`,\n );\n }\n await builder.connect(emitter.path, particle.path);\n\n // Turn the bare Particle SOP into an immediately-visible, moving system (initial velocity\n // from normals, pre-roll population, force mapping, containment drag).\n const dynamics = computeParticleDynamics(args);\n await builder.python(particleDynamicsPython(particle.path, args, dynamics));\n\n const mat = await builder.add(\n args.render_style === \"sprites\" ? \"pointspriteMAT\" : \"constantMAT\",\n \"mat\",\n );\n const cam = await builder.add(\"cameraCOMP\", \"cam\", { tz: 6 });\n const light = await builder.add(\"lightCOMP\", \"light\", { tx: 3, ty: 4, tz: 4 });\n // Opaque near-black background so the (white, point-sized) particles are visible.\n // Left transparent, white particles vanish against a light compositing backdrop; set\n // bgcolora back to 0 if you want to composite the particles over other layers.\n const render = await builder.add(\"renderTOP\", \"render\", {\n bgcolorr: 0.02,\n bgcolorg: 0.02,\n bgcolorb: 0.05,\n bgcolora: 1,\n });\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(render, out);\n\n await builder.python(\n [\n `g = op(${q(geo)})`,\n \"p = op(g.path + '/particle')\",\n \"p.render = True\",\n \"p.display = True\",\n `g.par.material = ${q(mat)}`,\n `r = op(${q(render)})`,\n `r.par.geometry = ${q(geo)}`,\n `r.par.camera = ${q(cam)}`,\n `r.par.lights = ${q(light)}`,\n ].join(\"\\n\"),\n );\n\n const approximated = args.forces.filter(\n (x) => x === \"attract\" || x === \"repel\" || x === \"vortex\",\n );\n if (approximated.length > 0) {\n builder.warnings.push(\n `Forces ${approximated.join(\", \")} have no native Particle SOP equivalent and are approximated with turbulence.`,\n );\n }\n if (args.render_style !== \"points\" && args.render_style !== \"sprites\") {\n builder.warnings.push(\n `Render style \"${args.render_style}\" falls back to point/sprite rendering in this version.`,\n );\n }\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Drag\",\n type: \"float\",\n min: 0,\n max: 8,\n default: dynamics.drag,\n bind_to: [`${particle.path}.drag`],\n },\n {\n name: \"Turbulence\",\n type: \"float\",\n min: 0,\n max: 4,\n default: dynamics.turb,\n bind_to: [`${particle.path}.turbx`, `${particle.path}.turby`, `${particle.path}.turbz`],\n },\n {\n name: \"Gravity\",\n type: \"float\",\n min: -3,\n max: 3,\n default: dynamics.gravity,\n bind_to: [`${particle.path}.externaly`],\n },\n {\n name: \"Lifetime\",\n type: \"float\",\n min: 0.1,\n max: 10,\n default: args.lifetime,\n bind_to: [`${particle.path}.life`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Created a particle system (emitter: ${args.emitter_shape}, ~${args.particle_count} particles, render: ${args.render_style}).`,\n builder,\n outputPath: out,\n controls,\n extra: {\n emitter_shape: args.emitter_shape,\n forces: args.forces,\n render_style: args.render_style,\n },\n });\n });\n}\n\nexport const registerCreateParticleSystem: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_particle_system\",\n {\n title: \"Create particle system\",\n description:\n \"Build a particle system: an emitter feeds a particle SOP inside a Geometry COMP, rendered with a camera + light. Forces and render style are scaffolded for further tuning.\",\n inputSchema: createParticleSystemSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createParticleSystemImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nexport const createProjectionMappingSchema = z.object({\n source_path: z\n .string()\n .optional()\n .describe(\"TOP to map (brought in via a Select TOP). Omit for a demo grid source.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateProjectionMappingArgs = z.infer<typeof createProjectionMappingSchema>;\n\nexport async function createProjectionMappingImpl(\n ctx: ToolContext,\n args: CreateProjectionMappingArgs,\n) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"projection\");\n\n // Bring the source in via a Select TOP (so it can live in another container); fall back\n // to a grid so the warp handles are visible against a reference pattern.\n const source = args.source_path\n ? await builder.add(\"selectTOP\", \"source\", { top: args.source_path })\n : await builder.add(\"rampTOP\", \"source\", { type: \"radial\" });\n\n // Corner Pin TOP — drag its four pin handles (pintopleft…/pinbottomright…) in the viewer\n // to line the image up with a real surface. The corners are ordinary parameters too.\n const warp = await builder.add(\"cornerpinTOP\", \"warp\", { extend: \"hold\" });\n await builder.connect(source, warp);\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(warp, out);\n\n return finalize(ctx, {\n summary: `Built a projection-mapping warp → ${out}. Adjust the Corner Pin's four handles to fit your surface, then send ${out} to setup_output.`,\n builder,\n outputPath: out,\n extra: { warp, output_path: out },\n });\n });\n}\n\nexport const registerCreateProjectionMapping: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_projection_mapping\",\n {\n title: \"Create projection mapping\",\n description:\n \"Wrap a source TOP in a Corner Pin warp for projection mapping: drag the four corner handles to line the image up with a physical surface (wall, object, screen). The source comes in through a Select TOP so it can live anywhere; output is a Null ready for setup_output. The corner positions are parameters, so you can also drive or save them.\",\n inputSchema: createProjectionMappingSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createProjectionMappingImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\n/**\n * Curated, self-contained full-screen GLSL shaders for instant VJ eye-candy. Each one is\n * written for a TouchDesigner GLSL TOP and follows the rules verified in\n * createGenerativeArt.ts / applyPostProcessing.ts:\n * - declares its own `out vec4 fragColor` and writes through `TDOutputSwizzle(...)`,\n * - reads animation time from a `uniform float uTime` (bound to absTime by the Vectors\n * sequence — there is NO built-in uTime in TD),\n * - reads `uniform float uScale` and `uniform vec3 uColor` (also bound via the sequences),\n * - uses only lowercase descriptive identifiers (short UPPERCASE names like F1/F2 collide\n * with macros in TD's auto-prepended GLSL preamble),\n * - samples nothing external (generative — no input TOP).\n * The fragment-local UV comes from the GLSL TOP built-in `vUV.st` (same idiom the repo's\n * working voronoi/fbm shaders use).\n *\n * Provenance (compile-risk notes live with the export at the bottom):\n * - tunnel / metaballs / plasma: freshly written here (classic, low-complexity bodies).\n * - fractal: a Julia-set zoom adapted from the iteration/coloring style of the verified\n * fbm/voronoi shaders in createGenerativeArt.ts (same structure, no texture reads).\n * - raymarch_sphere: a minimal sphere+ground sphere-trace with a single light; newly\n * written, the highest-complexity body in the set.\n */\n\nconst TUNNEL_SHADER = `out vec4 fragColor;\nuniform float uTime;\nuniform float uScale;\nuniform vec3 uColor;\nvoid main(){\n vec2 uv = (vUV.st - 0.5) * 2.0;\n float radius = length(uv) * max(uScale, 0.0001);\n float angle = atan(uv.y, uv.x);\n float depth = 0.3 / (radius + 0.05) + uTime;\n float bands = 0.5 + 0.5 * sin(depth * 6.2831 + angle * 3.0);\n float rings = 0.5 + 0.5 * sin(angle * 8.0 + uTime * 2.0);\n float shade = bands * rings;\n vec3 col = uColor * shade + 0.05;\n col *= smoothstep(0.0, 0.25, radius);\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`;\n\nconst RAYMARCH_SPHERE_SHADER = `out vec4 fragColor;\nuniform float uTime;\nuniform float uScale;\nuniform vec3 uColor;\nfloat sceneDist(vec3 pos){\n float sphere = length(pos - vec3(0.0, 0.0, 0.0)) - max(uScale, 0.0001);\n float ground = pos.y + 1.0;\n return min(sphere, ground);\n}\nvec3 sceneNormal(vec3 pos){\n vec2 eps = vec2(0.001, 0.0);\n return normalize(vec3(\n sceneDist(pos + eps.xyy) - sceneDist(pos - eps.xyy),\n sceneDist(pos + eps.yxy) - sceneDist(pos - eps.yxy),\n sceneDist(pos + eps.yyx) - sceneDist(pos - eps.yyx)));\n}\nvoid main(){\n vec2 uv = (vUV.st - 0.5) * 2.0;\n vec3 rayOrigin = vec3(sin(uTime) * 3.0, 1.0, cos(uTime) * 3.0);\n vec3 forward = normalize(vec3(0.0) - rayOrigin);\n vec3 right = normalize(cross(vec3(0.0, 1.0, 0.0), forward));\n vec3 up = cross(forward, right);\n vec3 rayDir = normalize(forward + uv.x * right + uv.y * up);\n float traveled = 0.0;\n float hit = 0.0;\n for(int step = 0; step < 64; step++){\n vec3 pos = rayOrigin + rayDir * traveled;\n float dist = sceneDist(pos);\n if(dist < 0.001){ hit = 1.0; break; }\n traveled += dist;\n if(traveled > 20.0){ break; }\n }\n vec3 col = vec3(0.02, 0.03, 0.06);\n if(hit > 0.5){\n vec3 pos = rayOrigin + rayDir * traveled;\n vec3 normal = sceneNormal(pos);\n vec3 lightDir = normalize(vec3(0.6, 0.8, 0.2));\n float diffuse = max(dot(normal, lightDir), 0.0);\n float ambient = 0.15;\n col = uColor * (ambient + diffuse);\n }\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`;\n\nconst FRACTAL_SHADER = `out vec4 fragColor;\nuniform float uTime;\nuniform float uScale;\nuniform vec3 uColor;\nvoid main(){\n float zoom = max(uScale, 0.0001);\n vec2 coord = (vUV.st - 0.5) * (3.0 / zoom);\n vec2 seed = vec2(0.7885 * cos(uTime * 0.3), 0.7885 * sin(uTime * 0.3));\n vec2 zval = coord;\n float iter = 0.0;\n const float maxIter = 100.0;\n for(int i = 0; i < 100; i++){\n zval = vec2(zval.x * zval.x - zval.y * zval.y, 2.0 * zval.x * zval.y) + seed;\n if(dot(zval, zval) > 4.0){ break; }\n iter += 1.0;\n }\n float norm = iter / maxIter;\n vec3 col = 0.5 + 0.5 * cos(6.2831 * (norm + uColor));\n col *= smoothstep(0.0, 0.05, norm);\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`;\n\nconst METABALLS_SHADER = `out vec4 fragColor;\nuniform float uTime;\nuniform float uScale;\nuniform vec3 uColor;\nvoid main(){\n vec2 uv = vUV.st;\n float field = 0.0;\n float radius = 0.12 * max(uScale, 0.0001);\n for(int i = 0; i < 5; i++){\n float fi = float(i);\n vec2 center = vec2(\n 0.5 + 0.35 * sin(uTime * (0.5 + fi * 0.15) + fi * 1.7),\n 0.5 + 0.35 * cos(uTime * (0.4 + fi * 0.12) + fi * 2.3));\n float dist = length(uv - center);\n field += radius * radius / (dist * dist + 0.0005);\n }\n float surface = smoothstep(0.8, 1.2, field);\n vec3 col = mix(vec3(0.02, 0.02, 0.05), uColor, surface);\n col += uColor * smoothstep(0.95, 1.05, field) * 0.5;\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`;\n\nconst PLASMA_SHADER = `out vec4 fragColor;\nuniform float uTime;\nuniform float uScale;\nuniform vec3 uColor;\nvoid main(){\n vec2 uv = vUV.st * (6.0 * max(uScale, 0.0001));\n float wave = sin(uv.x + uTime);\n wave += sin(uv.y + uTime * 0.8);\n wave += sin((uv.x + uv.y) * 0.7 + uTime * 1.3);\n wave += sin(length(uv - 3.0) + uTime * 1.1);\n float value = wave * 0.25;\n vec3 col = 0.5 + 0.5 * cos(6.2831 * (value + uColor));\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`;\n\nconst SHADER_NAMES = [\"tunnel\", \"raymarch_sphere\", \"fractal\", \"metaballs\", \"plasma\"] as const;\ntype ShaderName = (typeof SHADER_NAMES)[number];\n\n// Keyed by the enum so a lookup with a validated `shader` arg is always a `string`.\nconst SHADERS: Record<ShaderName, string> = {\n tunnel: TUNNEL_SHADER,\n raymarch_sphere: RAYMARCH_SPHERE_SHADER,\n fractal: FRACTAL_SHADER,\n metaballs: METABALLS_SHADER,\n plasma: PLASMA_SHADER,\n};\n\nconst HEX_COLOR = /^#?([0-9a-fA-F]{6})$/;\n\n/** Parses \"#rrggbb\" (or \"rrggbb\") into linear-ish 0..1 RGB; undefined for malformed input. */\nfunction parseHexColor(hex: string): [number, number, number] | undefined {\n const match = HEX_COLOR.exec(hex.trim());\n const group = match?.[1];\n if (!group) return undefined;\n const int = Number.parseInt(group, 16);\n return [((int >> 16) & 0xff) / 255, ((int >> 8) & 0xff) / 255, (int & 0xff) / 255];\n}\n\nexport const createShaderLibSchema = z.object({\n shader: z\n .enum(SHADER_NAMES)\n .default(SHADER_NAMES[0])\n .describe(\"Which curated built-in shader to instantiate.\"),\n speed: z.coerce\n .number()\n .default(1)\n .describe(\"Animation speed multiplier (drives uTime). Exposed as a live 'Speed' control.\"),\n scale: z.coerce\n .number()\n .positive()\n .default(1)\n .describe(\"Pattern scale/zoom multiplier (uScale). Exposed as a live 'Scale' control.\"),\n color: z\n .string()\n .optional()\n .describe(\"Base color as hex (e.g. '#33ccff'); parsed to 0..1 RGB and exposed as 'Color'.\"),\n resolution: z\n .tuple([z.coerce.number().int().positive(), z.coerce.number().int().positive()])\n .default([1280, 720])\n .describe(\"Output resolution [width, height] of the GLSL TOP.\"),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose live Speed / Scale / Color controls on the system container.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateShaderLibArgs = z.infer<typeof createShaderLibSchema>;\n\n/**\n * Builds the GLSL TOP + Text DAT (fragment via pixeldat) → Null TOP network and binds the\n * uTime / uScale / uColor uniforms through the GLSL TOP's parameter sequences, mirroring\n * createGenerativeArt.buildGlslGenerative exactly.\n *\n * Binding strategy (matches the verified Speed idiom): every uniform expression reads its\n * matching custom parameter on the parent COMP with a defensive `hasattr` guard, falling\n * back to the build-time constant when no control is present — so the expression never\n * errors whether or not `expose_controls` ran. The Color control is an RGB swatch, which\n * cannot use `bind_to` (createControlPanel ignores it for rgb), so uColor reads the swatch's\n * Colorr/Colorg/Colorb components directly instead.\n */\nasync function buildShaderNetwork(\n ctx: ToolContext,\n parentPath: string,\n name: string,\n fragment: string,\n speed: number,\n scale: number,\n color: [number, number, number],\n resolution: [number, number],\n): Promise<{ builder: NetworkBuilder; outputPath: string }> {\n const builder = await createSystemContainer(ctx, parentPath, name);\n const glsl = await builder.add(\"glslTOP\", \"glsl1\", {\n resolutionw: resolution[0],\n resolutionh: resolution[1],\n outputresolution: \"custom\",\n });\n const frag = await builder.add(\"textDAT\", \"glsl1_frag\");\n await builder.python(\n `op(${q(frag)}).text = ${q(fragment)}\\nop(${q(glsl)}).par.pixeldat = op(${q(frag)}).name`,\n );\n\n // Uniforms live in the GLSL TOP's parameter sequences; the block count has no structured\n // setter, so raise it via numBlocks, then set each block's name + value expression.\n // The \"Vectors\" page (vec sequence) carries the float scalars uTime (block 0) and uScale\n // (block 1); the \"Colors\" page (color sequence) carries the vec3 uColor (block 0).\n const speedExpr = `absTime.seconds * (parent().par.Speed.eval() if hasattr(parent().par, 'Speed') else ${speed})`;\n const scaleExpr = `parent().par.Scale.eval() if hasattr(parent().par, 'Scale') else ${scale}`;\n await builder.python(\n [\n `_g = op(${q(glsl)})`,\n `_g.seq.vec.numBlocks = max(_g.seq.vec.numBlocks, 2)`,\n `_g.par.vec0name = 'uTime'`,\n `_g.par.vec0valuex.expr = ${q(speedExpr)}`,\n `_g.par.vec1name = 'uScale'`,\n `_g.par.vec1valuex.expr = ${q(scaleExpr)}`,\n `_g.seq.color.numBlocks = max(_g.seq.color.numBlocks, 1)`,\n `_g.par.color0name = 'uColor'`,\n `_g.par.color0rgbr.expr = ${q(`parent().par.Colorr.eval() if hasattr(parent().par, 'Colorr') else ${color[0]}`)}`,\n `_g.par.color0rgbg.expr = ${q(`parent().par.Colorg.eval() if hasattr(parent().par, 'Colorg') else ${color[1]}`)}`,\n `_g.par.color0rgbb.expr = ${q(`parent().par.Colorb.eval() if hasattr(parent().par, 'Colorb') else ${color[2]}`)}`,\n ].join(\"\\n\"),\n );\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(glsl, out);\n return { builder, outputPath: out };\n}\n\nexport async function createShaderLibImpl(ctx: ToolContext, args: CreateShaderLibArgs) {\n return runBuild(async () => {\n const fragment = SHADERS[args.shader];\n\n const color = parseHexColor(args.color ?? \"\") ?? ([0.2, 0.8, 1.0] as [number, number, number]);\n const colorWarning =\n args.color !== undefined && parseHexColor(args.color) === undefined\n ? `Could not parse color \"${args.color}\" (expected hex like '#33ccff'); used the default.`\n : undefined;\n\n const { builder, outputPath } = await buildShaderNetwork(\n ctx,\n args.parent_path,\n `shader_lib_${args.shader}`,\n fragment,\n args.speed,\n args.scale,\n color,\n args.resolution,\n );\n if (colorWarning) builder.warnings.push(colorWarning);\n\n // Live controls bound to the uniforms. Speed/Scale drive their uniform expressions via\n // the defensive parent() lookups above; Color is an RGB swatch whose components those\n // expressions read directly (bind_to is unsupported for rgb).\n const controls: ControlSpec[] = args.expose_controls\n ? [\n { name: \"Speed\", type: \"float\", min: 0, max: 4, default: args.speed },\n { name: \"Scale\", type: \"float\", min: 0.1, max: 4, default: args.scale },\n // Seed the RGB swatch with the build-time colour (a swatch defaults to black, which\n // would make every uColor-driven shader render black/dark).\n {\n name: \"Color\",\n type: \"rgb\",\n default: `#${color\n .map((c) =>\n Math.round(c * 255)\n .toString(16)\n .padStart(2, \"0\"),\n )\n .join(\"\")}`,\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Created a \"${args.shader}\" shader from the curated library (GLSL).`,\n builder,\n outputPath,\n controls,\n capturePreviewImage: true,\n extra: {\n shader: args.shader,\n speed: args.speed,\n scale: args.scale,\n color,\n resolution: args.resolution,\n },\n });\n });\n}\n\nexport const registerCreateShaderLib: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_shader_lib\",\n {\n title: \"Create shader from library\",\n description:\n \"Instantiate a curated, ready-to-run full-screen GLSL shader (tunnel, raymarch_sphere, fractal, metaballs, plasma) into a GLSL TOP with live Speed / Scale / Color controls. High-value VJ eye-candy; unlike create_glsl_shader it ships robust built-in shaders rather than taking arbitrary code.\",\n inputSchema: createShaderLibSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createShaderLibImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport { errorResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { buildFromRecipe, createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport const createSimulationSchema = z.object({\n type: z\n .enum([\"reaction_diffusion\", \"slime\", \"fluid\"])\n .default(\"reaction_diffusion\")\n .describe(\n \"reaction_diffusion = Gray-Scott patterns (uses the validated recipe); slime = drifting decaying trails; fluid = advected smear.\",\n ),\n speed: z.coerce\n .number()\n .positive()\n .default(1)\n .describe(\"(slime/fluid) How fast the flow field evolves.\"),\n decay: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(0.96)\n .describe(\"(slime/fluid) Trail persistence — higher holds longer.\"),\n expose_controls: z.boolean().default(true),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateSimulationArgs = z.infer<typeof createSimulationSchema>;\n\nexport async function createSimulationImpl(ctx: ToolContext, args: CreateSimulationArgs) {\n return runBuild(async () => {\n // Reaction-diffusion has a battle-tested recipe already; reuse it rather than ship a new shader.\n if (args.type === \"reaction_diffusion\") {\n const recipe = ctx.recipes.get(\"reaction_diffusion\");\n if (!recipe) {\n return errorResult(\"The 'reaction_diffusion' recipe is unavailable in this build.\");\n }\n const built = await buildFromRecipe(ctx, recipe, args.parent_path);\n return finalize(ctx, {\n summary: \"Built a reaction-diffusion simulation (Gray-Scott).\",\n builder: built.builder,\n outputPath: built.outputPath,\n controls: built.controls,\n recipeId: recipe.id,\n extra: { type: args.type },\n });\n }\n\n // slime / fluid: a feedback loop displaced by an evolving noise flow field, then decayed.\n const builder = await createSystemContainer(ctx, args.parent_path, `sim_${args.type}`);\n\n const seed = await builder.add(\"noiseTOP\", \"seed\", {\n monochrome: 1,\n period: args.type === \"slime\" ? 2 : 6,\n });\n // An animated 3D-noise flow field (its Z drifts with time) drives the displacement.\n const flow = await builder.add(\"noiseTOP\", \"flow\", { monochrome: 1, period: 4 });\n await builder.python(\n `_n = op(${q(flow)})\\n_pz = _n.par.tz\\n_PM = type(_pz.mode)\\n_pz.expr = ${q(`absTime.seconds * ${args.speed}`)}\\n_pz.mode = _PM.EXPRESSION`,\n );\n\n const feedback = await builder.add(\"feedbackTOP\", \"feedback1\");\n const comp = await builder.add(\"compositeTOP\", \"comp1\", { operand: \"maximum\" });\n await builder.connect(seed, comp, 0, 0);\n await builder.connect(feedback, comp, 0, 1);\n await builder.connect(seed, feedback); // first-frame input\n\n const displace = await builder.add(\"displaceTOP\", \"displace\");\n await builder.connect(comp, displace, 0, 0);\n await builder.connect(flow, displace, 0, 1);\n\n const blur = await builder.add(\"blurTOP\", \"blur\", { size: args.type === \"slime\" ? 1 : 3 });\n await builder.connect(displace, blur);\n\n const gain = await builder.add(\"levelTOP\", \"gain\", { brightness1: args.decay });\n await builder.connect(blur, gain);\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(gain, out);\n await builder.python(`op(${q(feedback)}).par.top = op(${q(gain)}).name`);\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Decay\",\n type: \"float\",\n min: 0,\n max: 1,\n default: args.decay,\n bind_to: [`${gain}.brightness1`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Built a ${args.type} simulation (feedback flow field, decay ${args.decay}) → ${out}.`,\n builder,\n outputPath: out,\n controls,\n extra: { type: args.type, output_path: out },\n });\n });\n}\n\nexport const registerCreateSimulation: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_simulation\",\n {\n title: \"Create simulation\",\n description:\n \"Build a GPU simulation: 'reaction_diffusion' grows Gray-Scott patterns (via the validated recipe), while 'slime' and 'fluid' run a feedback loop displaced by an evolving noise flow field — drifting trails and advected smears. Exposes a Decay knob (trail persistence). For more procedural techniques (cellular automata, flow fields, strange attractors) see create_generative_art.\",\n inputSchema: createSimulationSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createSimulationImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nexport const createSpectrumSchema = z.object({\n source: z\n .enum([\"device\", \"file\", \"oscillator\", \"existing_chop\"])\n .default(\"device\")\n .describe(\n \"Audio source. 'device' = live microphone/line in (the real-world default; creating it may pop a one-time macOS microphone-permission dialog — click Allow). 'file' = an audio file. 'oscillator' = a synthetic tone (white noise → energy in every band, handy for testing without any device permission). 'existing_chop' = reuse a CHOP you already have.\",\n ),\n audio_file_path: z.string().optional().describe(\"Audio file path (source='file').\"),\n existing_chop_path: z\n .string()\n .optional()\n .describe(\"Path of an existing audio CHOP to analyze (source='existing_chop').\"),\n bands: z.coerce\n .number()\n .int()\n .min(1)\n .max(512)\n .default(16)\n .describe(\n \"Number of frequency bins to expose as separate, bindable channels (band0..band{N-1}). 16 or 32 is typical; higher = finer frequency resolution.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose a live 'Sensitivity' knob (a gain over every band channel).\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateSpectrumArgs = z.infer<typeof createSpectrumSchema>;\n\nasync function buildSource(builder: NetworkBuilder, args: CreateSpectrumArgs): Promise<string> {\n if (args.source === \"existing_chop\" && args.existing_chop_path) {\n return args.existing_chop_path;\n }\n if (args.source === \"file\") {\n return builder.add(\"audiofileinCHOP\", \"audioin\", {\n ...(args.audio_file_path ? { file: args.audio_file_path } : {}),\n play: 1,\n });\n }\n if (args.source === \"oscillator\") {\n // White noise has energy across all frequencies, so every band reads non-zero —\n // a self-contained signal for verifying the chain without any audio device.\n return builder.add(\"audiooscillatorCHOP\", \"audioin\", { wavetype: \"whitenoise\", amp: 0.5 });\n }\n return builder.add(\"audiodeviceinCHOP\", \"audioin\");\n}\n\nexport async function createSpectrumImpl(ctx: ToolContext, args: CreateSpectrumArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"spectrum\");\n const source = await buildSource(builder, args);\n\n // FFT. The Audio Spectrum CHOP emits one channel of magnitude bins. TouchDesigner\n // clamps `outlength` into 128–4096, so a small `bands` value (e.g. 16) can NOT be set\n // here directly — we request a comfortably-sized FFT and rebin it down below.\n // Use audiospectrumCHOP — `spectrumCHOP` is not a createable operator.\n const fftLength = Math.min(Math.max(args.bands, 128), 4096);\n const fft = await builder.add(\"audiospectrumCHOP\", \"spectrum_fft\", {\n outputmenu: \"setmanually\",\n outlength: fftLength,\n });\n await builder.connect(source, fft);\n\n // Rebin to exactly `bands` samples by resampling the single spectrum channel onto a\n // fixed sample interval [0, bands-1]. Linear interpolation averages neighbouring FFT\n // bins when reducing, giving smooth per-band energy regardless of the FFT length above.\n const rebin = await builder.add(\"resampleCHOP\", \"rebin\", {\n relative: \"abs\",\n start: 0,\n end: args.bands - 1,\n startunit: \"samples\",\n endunit: \"samples\",\n interp: \"linear\",\n });\n await builder.connect(fft, rebin);\n\n // Transpose: 1 channel × N samples → N channels × 1 sample. The Shuffle CHOP's\n // \"Sequence to Channels\" method stores every sample index in its own channel.\n const split = await builder.add(\"shuffleCHOP\", \"split\", { method: \"seqtochan\" });\n await builder.connect(rebin, split);\n\n // Name the N channels band0..band{N-1}. The Rename CHOP's numbered pattern expands\n // `band[0-K]` positionally across the matched channels.\n const rename = await builder.add(\"renameCHOP\", \"bands\", {\n renamefrom: \"*\",\n renameto: `band[0-${args.bands - 1}]`,\n });\n await builder.connect(split, rename);\n\n // A Sensitivity gain over every band, then a Null as the stable bind point —\n // exactly like extract_audio_features' sensitivity→features tail.\n const gain = await builder.add(\"mathCHOP\", \"sensitivity\", { gain: 1 });\n await builder.connect(rename, gain);\n const spectrum = await builder.add(\"nullCHOP\", \"spectrum\");\n await builder.connect(gain, spectrum);\n\n const channels = Array.from({ length: args.bands }, (_, i) => `band${i}`);\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Sensitivity\",\n type: \"float\",\n min: 0,\n max: 8,\n default: 1,\n bind_to: [`${gain}.gain`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Built an FFT spectrum analyzer (source: ${args.source}) → ${spectrum} with ${args.bands} per-band channels band0..band${args.bands - 1}. Bind a parameter to op('${spectrum}')['band0'] (or any band) to make it react to that frequency.`,\n builder,\n outputPath: spectrum,\n // The output is a CHOP, not a TOP, so there is no image to capture.\n capturePreviewImage: false,\n controls,\n extra: {\n source: args.source,\n spectrum_path: spectrum,\n bands: args.bands,\n channels,\n },\n });\n });\n}\n\nexport const registerCreateSpectrum: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_spectrum\",\n {\n title: \"Create audio spectrum\",\n description:\n \"Build an FFT audio-spectrum analyzer that exposes N separate, ready-to-bind frequency-bin channels (band0..band{N-1}) on a Null CHOP. This is the per-band complement to extract_audio_features (which only gives overall level + bass/mid/treble): bind a row of parameters to op('…/spectrum/spectrum')['band0'], ['band1'], … to drive a bank of bars, or pick one frequency. A Sensitivity knob scales every band. Source can be the live device (mic/line — may prompt for macOS permission), an audio file, a synthetic oscillator (for testing), or an existing CHOP.\",\n inputSchema: createSpectrumSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createSpectrumImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport const createStrobeSchema = z.object({\n rate_hz: z.coerce\n .number()\n .positive()\n .default(8)\n .describe(\"Strobe rate in flashes per second (Hz) — the LFO CHOP square-wave frequency.\"),\n intensity: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(1)\n .describe(\"Brightness of the flash when it is on (0..1). Drives the Level TOP's brightness1.\"),\n color: z\n .string()\n .default(\"#ffffff\")\n .describe(\n \"Flash colour as a hex string ('#ffffff' = white, the classic strobe). Sets the Constant TOP's RGB.\",\n ),\n duty: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(0.5)\n .describe(\n \"On-time fraction of each cycle (0..1, 0.5 = even on/off). Mapped to the LFO CHOP's Bias, which rectangularises the square wave.\",\n ),\n input_path: z\n .string()\n .optional()\n .describe(\n \"Optional absolute path of a source TOP to flash OVER. Pulled in via a Select TOP (TD wires don't cross containers) and composited under the flash. If omitted, the bare flash is output.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose live Rate / Intensity / Duty knobs bound to the right node parameters.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateStrobeArgs = z.infer<typeof createStrobeSchema>;\n\n/** Parses '#rrggbb' / 'rrggbb' (3- or 6-digit) into 0..1 RGB. Falls back to white. */\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());\n if (!m) return { r: 1, g: 1, b: 1 };\n let h = m[1] as string;\n if (h.length === 3)\n h = h\n .split(\"\")\n .map((c) => c + c)\n .join(\"\");\n const int = Number.parseInt(h, 16);\n return {\n r: ((int >> 16) & 0xff) / 255,\n g: ((int >> 8) & 0xff) / 255,\n b: (int & 0xff) / 255,\n };\n}\n\nexport async function createStrobeImpl(ctx: ToolContext, args: CreateStrobeArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"strobe\");\n const rgb = hexToRgb(args.color);\n\n // The flash colour (a flat, full-frame TOP). Default white = the classic strobe.\n const flash = await builder.add(\"constantTOP\", \"flash\", {\n colorr: rgb.r,\n colorg: rgb.g,\n colorb: rgb.b,\n alpha: 1,\n });\n\n // The strobe signal: a square-wave LFO whose Bias controls duty (rectangularity).\n // square swings [-1, 1] (verified in animate_parameter); the brightness expression\n // below treats anything > 0 as \"on\", giving a crisp hard on/off rather than a fade.\n // Bias 0 = even 50% duty; map duty 0..1 → bias -1..1.\n const bias = (args.duty - 0.5) * 2;\n const lfo = await builder.add(\"lfoCHOP\", \"strobe_lfo\", {\n wavetype: \"square\",\n frequency: args.rate_hz,\n amp: 1,\n offset: 0,\n bias,\n channelname: \"chan1\",\n });\n\n // Drive the flash brightness on/off from the LFO. Param expressions evaluate relative\n // to the node's PARENT, so reference the LFO channel by ABSOLUTE path. The Level TOP's\n // brightness param is `brightness1` (NOT `gain`). Switch the param to EXPRESSION mode\n // the same way animate_parameter does: `type(par.mode).EXPRESSION` (ParMode isn't in\n // the bridge exec globals).\n const blink = await builder.add(\"levelTOP\", \"blink\", { brightness1: args.intensity });\n await builder.connect(flash, blink);\n const expr = `(${args.intensity} if op(${q(lfo)})['chan1'] > 0 else 0)`;\n await builder.python(\n `_p = op(${q(blink)}).par.brightness1\\n_p.expr = ${q(expr)}\\n_p.mode = type(_p.mode).EXPRESSION`,\n );\n\n // Optionally composite the blinking flash OVER an external source. The source can live\n // in another container, so it must be pulled in by a Select TOP (`top` = absolute path)\n // rather than a (cross-container-illegal) wire. operand 'over' = alpha compositing.\n let output = blink;\n if (args.input_path) {\n const src = await builder.add(\"selectTOP\", \"src\", { top: args.input_path });\n const comp = await builder.add(\"compositeTOP\", \"comp\", { operand: \"over\" });\n // Input 0 = background (the source), input 1 = the flash on top.\n await builder.connect(src, comp, 0, 0);\n await builder.connect(blink, comp, 0, 1);\n output = comp;\n }\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(output, out);\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Rate\",\n type: \"float\",\n min: 0,\n max: 30,\n default: args.rate_hz,\n bind_to: [`${lfo}.frequency`],\n },\n {\n name: \"Intensity\",\n type: \"float\",\n min: 0,\n max: 1,\n default: args.intensity,\n // brightness1 is driven by the expression above; the knob is its multiplier\n // input (the expression's `intensity` literal is the build-time default).\n bind_to: [`${blink}.brightness1`],\n },\n {\n // Duty maps to the LFO's Bias (square-wave rectangularity): -1 = mostly off,\n // 0 = even 50/50, +1 = mostly on. Exposed across the full bias range.\n name: \"Duty\",\n type: \"float\",\n min: -1,\n max: 1,\n default: bias,\n bind_to: [`${lfo}.bias`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Built a strobe (${args.rate_hz} Hz square-wave LFO, duty ${args.duty})${\n args.input_path ? ` flashing over ${args.input_path}` : \"\"\n } → ${out}. Bind op('${lfo}').par.frequency to a beat CHOP to lock it to the tempo.`,\n builder,\n outputPath: out,\n // Output is a TOP (the Null), so a preview image is captured.\n capturePreviewImage: true,\n controls,\n extra: {\n rate_hz: args.rate_hz,\n intensity: args.intensity,\n duty: args.duty,\n color: { r: rgb.r, g: rgb.g, b: rgb.b },\n lfo_path: lfo,\n flash_path: flash,\n output_path: out,\n input_path: args.input_path,\n },\n });\n });\n}\n\nexport const registerCreateStrobe: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_strobe\",\n {\n title: \"Create strobe\",\n description:\n \"Build a beat-syncable strobe / flash layer — a full-frame colour flash that pulses hard on/off, the signature live-VJ strobe effect. A square-wave LFO CHOP at the given Rate (Hz) drives a Level TOP's brightness so a Constant TOP (the flash colour, white by default) blinks; Duty sets the on-time fraction. With an input_path the flash is composited OVER that source (pulled in by a Select TOP, so it can live in another container); without one, the bare flash is output. Output is a Null TOP. Rate is free-running for v1 — bind the LFO's frequency to a beat CHOP later to lock it to the tempo.\",\n inputSchema: createStrobeSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createStrobeImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport const createSyncExternalClockSchema = z.object({\n bpm: z.coerce\n .number()\n .min(40)\n .max(220)\n .default(120)\n .describe(\"Starting tempo in BPM (match the DJ's displayed BPM, then fine-tune by tapping).\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateSyncExternalClockArgs = z.infer<typeof createSyncExternalClockSchema>;\n\n// Parameter Execute callback (runs in TD's normal op context, so it imports td). The Bpm knob\n// writes the project's global tempo (op('/').time.tempo), which every Beat CHOP — and so every\n// beat-synced visual (create_tempo_sync, create_autopilot) — follows. The Tap pulse beat-matches\n// by ear: it averages the last few tap intervals into a BPM and feeds the Bpm knob.\nconst ENGINE = `import td\n\ndef onValueChange(par, prev):\n if par.name == 'Bpm':\n try:\n op('/').time.tempo = max(40.0, min(220.0, float(par.eval())))\n except Exception:\n pass\n return\n\ndef onPulse(par):\n if par.name != 'Tap':\n return\n ap = par.owner\n now = absTime.seconds\n taps = list(ap.fetch('tdmcp_taps', []))\n if taps and now - taps[-1] > 2.0:\n taps = []\n taps.append(now)\n taps = taps[-4:]\n ap.store('tdmcp_taps', taps)\n if len(taps) >= 2:\n diffs = [taps[i + 1] - taps[i] for i in range(len(taps) - 1)]\n avg = sum(diffs) / len(diffs)\n if avg > 0:\n ap.par.Bpm = round(max(40.0, min(220.0, 60.0 / avg)), 1)\n return\n`;\n\nexport async function createSyncExternalClockImpl(\n ctx: ToolContext,\n args: CreateSyncExternalClockArgs,\n) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"tempo_clock\");\n\n // A Parameter Execute DAT watches this container's custom knobs and pushes the tempo to the\n // global clock. (Its `op` is set to its own parent so it follows wherever the container lands.)\n const engine = await builder.add(\"parameterexecuteDAT\", \"engine\");\n await builder.python(\n `_e = op(${q(engine)})\\n_e.par.op = _e.parent().path\\n_e.par.pars = '*'\\n_e.par.custom = True\\n_e.par.builtin = False\\n_e.par.valuechange = True\\n_e.par.onpulse = True\\n_e.par.active = True\\n_e.text = ${q(ENGINE)}\\nop('/').time.tempo = ${args.bpm}`,\n );\n\n const controls: ControlSpec[] = [\n { name: \"Bpm\", type: \"float\", min: 40, max: 220, default: args.bpm, bind_to: [] },\n { name: \"Tap\", type: \"pulse\", bind_to: [] },\n ];\n\n return finalize(ctx, {\n summary: `Built a tempo clock at ${args.bpm} BPM driving the global tempo. Dial the Bpm knob to the DJ's BPM, or hit Tap on the beat to match by ear — every beat-synced visual follows.`,\n builder,\n outputPath: engine,\n // No visual output (it drives the global tempo), so nothing to capture.\n capturePreviewImage: false,\n controls,\n extra: {\n bpm: args.bpm,\n engine,\n drives: \"op('/').time.tempo (global)\",\n },\n });\n });\n}\n\nexport const registerCreateSyncExternalClock: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"sync_external_clock\",\n {\n title: \"Sync external clock (tempo)\",\n description:\n \"Lock the project tempo to a live source so beat-synced visuals follow the music: a Bpm knob writes the global tempo (op('/').time.tempo), and a Tap pulse beat-matches by ear (averaging your taps into a BPM). Drives every Beat CHOP downstream — create_tempo_sync clocks and create_autopilot all follow. Dedicated MIDI-clock / Ableton-Link sync is a planned follow-up; for now match the DJ by tapping or dialing their BPM.\",\n inputSchema: createSyncExternalClockSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createSyncExternalClockImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport const createTempoSyncSchema = z.object({\n period: z.coerce\n .number()\n .positive()\n .default(4)\n .describe(\"Beats per bar / beat period — how the ramp and bar channels divide the tempo.\"),\n emit_events: z\n .boolean()\n .default(true)\n .describe(\n \"Also broadcast a `beat` event over the bridge WebSocket on every beat, so `tdmcp-agent watch` and the AI can react to beats live.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose a live 'Period' knob to retune the beat division on the fly.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateTempoSyncArgs = z.infer<typeof createTempoSyncSchema>;\n\n// CHOP Execute callback (lives in TD, runs in the normal op context — not the exec\n// namespace — so it imports `td` for the operator classes). The integer `beat` channel\n// steps 0→1→2→…→0 once per beat, so watching it for value changes fires exactly once per\n// beat (whatever the period). On each beat it broadcasts a \\`beat\\` event through the\n// bridge's Web Server DAT (located by type so it works wherever the bridge was installed).\nconst BEAT_EMITTER = `import td\n\ndef _webserver():\n for w in op('/').findChildren(type=td.webserverDAT):\n return w\n return None\n\ndef onValueChange(channel, sampleIndex, val, prev):\n if channel.name != 'beat':\n return\n ws = _webserver()\n if ws is None:\n return\n try:\n from mcp import events\n owner = channel.owner\n names = [c.name for c in owner.chans()]\n data = {'beat': int(val)}\n if 'bar' in names:\n data['bar'] = int(owner['bar'][0])\n if 'count' in names:\n data['count'] = int(owner['count'][0])\n if 'bpm' in names:\n data['bpm'] = round(float(owner['bpm'][0]), 2)\n events.broadcast(ws, 'beat', data)\n except Exception:\n pass\n return\n`;\n\nexport async function createTempoSyncImpl(ctx: ToolContext, args: CreateTempoSyncArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"tempo_sync\");\n\n // A Beat CHOP driven by TouchDesigner's global tempo; the toggles turn on the useful\n // sync channels (a per-beat 0→1 ramp, a pulse spike, integer beat/bar counters, BPM).\n const beat = await builder.add(\"beatCHOP\", \"beat\", {\n period: args.period,\n ramp: 1,\n pulse: 1,\n count: 1,\n beat: 1,\n bar: 1,\n bpm: 1,\n });\n const tempo = await builder.add(\"nullCHOP\", \"tempo\");\n await builder.connect(beat, tempo);\n\n let emitter: string | undefined;\n if (args.emit_events) {\n emitter = await builder.add(\"chopexecuteDAT\", \"beat_emitter\", {\n chop: tempo,\n channel: \"beat\",\n valuechange: 1,\n offtoon: 0,\n active: 1,\n });\n await builder.python(`op(${q(emitter)}).text = ${q(BEAT_EMITTER)}`);\n }\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Period\",\n type: \"float\",\n min: 0.25,\n max: 16,\n default: args.period,\n bind_to: [`${beat}.period`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Created a tempo clock at ${tempo} (channels ramp/pulse/beat/bar/bpm)${args.emit_events ? \", broadcasting `beat` events\" : \"\"}. Bind a parameter to op('${tempo}')['ramp'] for a per-beat sweep, or ['pulse'] for a hit on each beat.`,\n builder,\n outputPath: tempo,\n // The output is a CHOP, not a TOP, so there is no image to capture.\n capturePreviewImage: false,\n controls,\n extra: {\n tempo_path: tempo,\n channels: [\"ramp\", \"pulse\", \"count\", \"beat\", \"bar\", \"bpm\"],\n emits_beat_events: args.emit_events,\n emitter,\n },\n });\n });\n}\n\nexport const registerCreateTempoSync: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_tempo_sync\",\n {\n title: \"Create tempo sync\",\n description:\n \"Create a tempo clock (Beat CHOP driven by TouchDesigner's global tempo) exposing beat-synced channels on a Null CHOP: a per-beat 0→1 `ramp`, a `pulse` spike on each beat, integer `beat`/`bar` counters, and `bpm`. Bind any parameter to these to lock visuals to the beat. With emit_events on, it also broadcasts a `beat` event over the bridge WebSocket each beat, so `tdmcp-agent watch` and the AI can see the pulse live. Pair with extract_audio_features for full musical reactivity.\",\n inputSchema: createTempoSyncSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createTempoSyncImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst RESOLUTIONS = {\n \"720p\": [1280, 720],\n \"1080p\": [1920, 1080],\n \"4K\": [3840, 2160],\n} as const;\n\n/** \"#rrggbb\" (or \"rrggbb\") → [r,g,b] in 0..1; falls back to white on anything malformed. */\nfunction hexToRgb(hex: string): [number, number, number] {\n const h = hex.replace(/^#/, \"\");\n if (!/^[0-9a-fA-F]{6}$/.test(h)) return [1, 1, 1];\n return [\n Number.parseInt(h.slice(0, 2), 16) / 255,\n Number.parseInt(h.slice(2, 4), 16) / 255,\n Number.parseInt(h.slice(4, 6), 16) / 255,\n ];\n}\n\nexport const createTextOverlaySchema = z.object({\n text: z.string().default(\"TEXT\").describe(\"The text to display.\"),\n source_path: z\n .string()\n .optional()\n .describe(\n \"Optional TOP to composite the text over (e.g. a finished visual). Omit to get the text alone on a transparent background, ready to composite later.\",\n ),\n font_size: z.coerce.number().positive().default(64).describe(\"Font size in pixels.\"),\n color: z.string().default(\"#ffffff\").describe(\"Text color as a hex string, e.g. '#ff3366'.\"),\n align: z.enum([\"left\", \"center\", \"right\"]).default(\"center\").describe(\"Horizontal alignment.\"),\n valign: z.enum([\"top\", \"center\", \"bottom\"]).default(\"center\").describe(\"Vertical alignment.\"),\n resolution: z.enum([\"720p\", \"1080p\", \"4K\"]).default(\"1080p\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateTextOverlayArgs = z.infer<typeof createTextOverlaySchema>;\n\nexport async function createTextOverlayImpl(ctx: ToolContext, args: CreateTextOverlayArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"text_overlay\");\n const [width, height] = RESOLUTIONS[args.resolution];\n const [r, g, b] = hexToRgb(args.color);\n\n // Transparent-background Text TOP: only the glyphs are opaque, so it composites cleanly.\n const text = await builder.add(\"textTOP\", \"text\", {\n text: args.text,\n fontsizex: args.font_size,\n fontsizey: args.font_size,\n fontcolorr: r,\n fontcolorg: g,\n fontcolorb: b,\n fontalpha: 1,\n alignx: args.align,\n aligny: args.valign,\n bgalpha: 0,\n outputresolution: \"custom\",\n resolutionw: width,\n resolutionh: height,\n });\n\n let output = text;\n if (args.source_path) {\n // Pull the source in through a Select TOP (works across COMP boundaries), then composite\n // the text 'over' it — input 0 is the top layer.\n const src = await builder.add(\"selectTOP\", \"src\", { top: args.source_path });\n const comp = await builder.add(\"compositeTOP\", \"comp\", { operand: \"over\" });\n await builder.connect(text, comp, 0, 0);\n await builder.connect(src, comp, 0, 1);\n output = comp;\n }\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(output, out);\n\n return finalize(ctx, {\n summary: `Built a text overlay (\"${args.text}\") → ${out}${\n args.source_path ? ` composited over ${args.source_path}` : \" on a transparent background\"\n }.`,\n builder,\n outputPath: out,\n extra: {\n text: args.text,\n text_node: text,\n output_path: out,\n over_source: args.source_path ?? null,\n resolution: args.resolution,\n },\n });\n });\n}\n\nexport const registerCreateTextOverlay: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_text_overlay\",\n {\n title: \"Create text overlay\",\n description:\n \"Composite styled text over a visual (or on its own transparent background) — a Text TOP with font size, color, and alignment, optionally laid 'over' a source TOP through a Composite TOP, output as a Null. For lyrics, titles, song names, or credits in a set. Distinct from the vault's bind_vault_text (which data-syncs a Text DAT to a note); this is a finished visual layer ready for setup_output.\",\n inputSchema: createTextOverlaySchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createTextOverlayImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nexport const createVideoPlayerSchema = z.object({\n files: z\n .array(z.string())\n .default([])\n .describe(\n \"Movie file path(s). 0 = an empty player you can point at a file later; 1 = a single clip; 2+ = a playlist with a Switch TOP and a Clip selector.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose live Play / Speed (and Clip, for a playlist) controls.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateVideoPlayerArgs = z.infer<typeof createVideoPlayerSchema>;\n\nexport async function createVideoPlayerImpl(ctx: ToolContext, args: CreateVideoPlayerArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"video_player\");\n\n const clips: string[] = [];\n if (args.files.length === 0) {\n clips.push(await builder.add(\"moviefileinTOP\", \"clip1\", { play: 1 }));\n } else {\n for (const [i, file] of args.files.entries()) {\n clips.push(await builder.add(\"moviefileinTOP\", `clip${i + 1}`, { file, play: 1 }));\n }\n }\n\n let output: string;\n const controls: ControlSpec[] = [];\n if (clips.length > 1) {\n const sw = await builder.add(\"switchTOP\", \"switch\", { index: 0 });\n for (const [i, clip] of clips.entries()) await builder.connect(clip, sw, 0, i);\n output = sw;\n if (args.expose_controls) {\n controls.push({\n name: \"Clip\",\n type: \"int\",\n min: 0,\n max: clips.length - 1,\n default: 0,\n bind_to: [`${sw}.index`],\n });\n }\n } else {\n output = clips[0] as string;\n }\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(output, out);\n\n if (args.expose_controls) {\n controls.push(\n {\n name: \"Speed\",\n type: \"float\",\n min: -2,\n max: 2,\n default: 1,\n bind_to: clips.map((c) => `${c}.speed`),\n },\n { name: \"Play\", type: \"toggle\", default: true, bind_to: clips.map((c) => `${c}.play`) },\n );\n }\n\n return finalize(ctx, {\n summary: `Built a video player with ${clips.length} clip(s) → ${out}${args.files.length === 0 ? \" (set the Movie File In's file to load a clip)\" : \"\"}.`,\n builder,\n outputPath: out,\n controls,\n extra: { clips, output_path: out, playlist: clips.length > 1 },\n });\n });\n}\n\nexport const registerCreateVideoPlayer: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_video_player\",\n {\n title: \"Create video player\",\n description:\n \"Build a movie/clip player: one Movie File In TOP, or a playlist of clips fed through a Switch TOP with a Clip selector. Exposes live Play / Speed (and Clip) controls, output as a Null. Pass file paths, or none to get an empty player you point at a file in TD. For VJ clip playback — mix it with create_layer_mixer or make it react with bind_to_channel.\",\n inputSchema: createVideoPlayerSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createVideoPlayerImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\n/**\n * Analog video-synthesizer style generators: oscillator / interference looks reminiscent of\n * Lissajous figures, Rutt-Etra fringes and scanline-modulated CRT fields. Deliberately\n * distinct from create_shader_lib (tunnel / raymarch / fractal / metaballs): this set is\n * built from two sine oscillators on X/Y, moving sine interference and scanline modulation —\n * no raymarching, no fractal iteration.\n *\n * Each shader is written for a TouchDesigner GLSL TOP and follows the rules verified in\n * createGenerativeArt.ts / createShaderLib.ts:\n * - declares its own `out vec4 fragColor` and writes through `TDOutputSwizzle(...)`,\n * - reads animation time from a `uniform float uTime` (bound to absTime via the Vectors\n * sequence — there is NO built-in uTime in TD),\n * - reads `uniform float uFreqX`, `uniform float uFreqY`, `uniform float uScale` and a\n * `uniform vec3 uColor` (also bound via the sequences),\n * - uses only lowercase descriptive identifiers (short UPPERCASE names like F1/F2 collide\n * with macros in TD's auto-prepended GLSL preamble),\n * - samples nothing external (generative — no input TOP).\n * The fragment-local UV comes from the GLSL TOP built-in `vUV.st` (same idiom the repo's\n * working voronoi/fbm/shader-lib shaders use). Math is kept to sin/cos/length/smoothstep so\n * the compile risk per mode stays low.\n */\n\n// Two sine oscillators trace an X/Y path (classic oscilloscope Lissajous figure). uFreqX /\n// uFreqY are the per-axis oscillator frequencies; the glowing curve is drawn by measuring the\n// distance from each pixel to the swept point along the time-parameterised path.\nconst LISSAJOUS_SHADER = `out vec4 fragColor;\nuniform float uTime;\nuniform float uScale;\nuniform float uFreqX;\nuniform float uFreqY;\nuniform vec3 uColor;\nvoid main(){\n vec2 uv = (vUV.st - 0.5) * 2.0 * max(uScale, 0.0001);\n float glow = 0.0;\n for(int i = 0; i < 96; i++){\n float phase = float(i) / 96.0 * 6.2831853;\n vec2 point = vec2(sin(phase * uFreqX + uTime), sin(phase * uFreqY + uTime * 0.7)) * 0.8;\n float dist = length(uv - point);\n glow += 0.006 / (dist * dist + 0.0008);\n }\n vec3 col = uColor * glow;\n col += uColor * 0.04;\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`;\n\n// Two travelling sine wave fields beat against each other to form moving interference fringes\n// (Rutt-Etra / moire flavour). uFreqX / uFreqY set the spatial frequency of each field; the\n// product of the two wave trains gives the fringe pattern, animated by uTime.\nconst INTERFERENCE_SHADER = `out vec4 fragColor;\nuniform float uTime;\nuniform float uScale;\nuniform float uFreqX;\nuniform float uFreqY;\nuniform vec3 uColor;\nvoid main(){\n vec2 uv = (vUV.st - 0.5) * 2.0;\n float scale = max(uScale, 0.0001);\n float waveA = sin(uv.x * uFreqX * 6.2831853 * scale + uTime);\n float waveB = sin(uv.y * uFreqY * 6.2831853 * scale - uTime * 0.8);\n float radial = sin(length(uv) * (uFreqX + uFreqY) * 3.1415927 * scale - uTime * 1.3);\n float fringe = (waveA * waveB + radial) * 0.5;\n float shade = 0.5 + 0.5 * fringe;\n vec3 col = uColor * shade;\n col += uColor * smoothstep(0.96, 1.0, shade) * 0.4;\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`;\n\n// Horizontal scanlines modulated by a vertical sine oscillator, with a slow rolling sweep —\n// an analog CRT / signal-bar look. uFreqY sets the scanline density, uFreqX the horizontal\n// modulation, and the bright bar rolls with uTime.\nconst SCANLINES_SHADER = `out vec4 fragColor;\nuniform float uTime;\nuniform float uScale;\nuniform float uFreqX;\nuniform float uFreqY;\nuniform vec3 uColor;\nvoid main(){\n vec2 uv = vUV.st;\n float scale = max(uScale, 0.0001);\n float lines = 0.5 + 0.5 * sin(uv.y * uFreqY * 120.0 * scale);\n float modulation = 0.5 + 0.5 * sin(uv.x * uFreqX * 6.2831853 + uTime);\n float roll = fract(uv.y - uTime * 0.1);\n float bar = smoothstep(0.0, 0.15, roll) * smoothstep(0.4, 0.15, roll);\n float shade = lines * modulation + bar * 0.5;\n vec3 col = uColor * shade;\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n`;\n\nconst SHADERS: Record<string, string> = {\n lissajous: LISSAJOUS_SHADER,\n interference: INTERFERENCE_SHADER,\n scanlines: SCANLINES_SHADER,\n};\n\nconst MODE_NAMES = [\"lissajous\", \"interference\", \"scanlines\"] as const;\n\nconst HEX_COLOR = /^#?([0-9a-fA-F]{6})$/;\n\nconst DEFAULT_COLOR: [number, number, number] = [0.2, 0.9, 1.0];\n\n/** Parses \"#rrggbb\" (or \"rrggbb\") into 0..1 RGB; undefined for malformed input. */\nfunction parseHexColor(hex: string): [number, number, number] | undefined {\n const match = HEX_COLOR.exec(hex.trim());\n const digits = match?.[1];\n if (!digits) return undefined;\n const int = Number.parseInt(digits, 16);\n return [((int >> 16) & 0xff) / 255, ((int >> 8) & 0xff) / 255, (int & 0xff) / 255];\n}\n\nexport const createVideoSynthSchema = z.object({\n mode: z\n .enum(MODE_NAMES)\n .default(MODE_NAMES[0])\n .describe(\n \"Oscillator look: 'lissajous' (two-oscillator X/Y curve), 'interference' (moving sine fringes), or 'scanlines' (analog CRT scanline modulation).\",\n ),\n speed: z.coerce\n .number()\n .default(1)\n .describe(\"Animation speed multiplier (drives uTime). Exposed as a live 'Speed' control.\"),\n freq_x: z.coerce\n .number()\n .default(3)\n .describe(\"X-axis oscillator frequency (uFreqX). Exposed as a live 'FreqX' control.\"),\n freq_y: z.coerce\n .number()\n .default(2)\n .describe(\"Y-axis oscillator frequency (uFreqY). Exposed as a live 'FreqY' control.\"),\n scale: z.coerce\n .number()\n .positive()\n .default(1)\n .describe(\"Pattern scale/zoom multiplier (uScale). Exposed as a live 'Scale' control.\"),\n color: z\n .string()\n .optional()\n .describe(\"Base color as hex (e.g. '#33ccff'); parsed to 0..1 RGB and exposed as 'Color'.\"),\n resolution: z\n .tuple([z.coerce.number().int().positive(), z.coerce.number().int().positive()])\n .default([1280, 720])\n .describe(\"Output resolution [width, height] of the GLSL TOP.\"),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\n \"Expose live Speed / FreqX / FreqY / Scale / Color controls on the system container.\",\n ),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateVideoSynthArgs = z.infer<typeof createVideoSynthSchema>;\n\n/**\n * Builds the GLSL TOP + Text DAT (fragment via pixeldat) → Null TOP network and binds the\n * uTime / uScale / uFreqX / uFreqY / uColor uniforms through the GLSL TOP's parameter\n * sequences, mirroring createShaderLib.buildShaderNetwork exactly.\n *\n * Binding strategy (matches the verified Speed idiom): every uniform expression reads its\n * matching custom parameter on the parent COMP with a defensive `hasattr` guard, falling back\n * to the build-time constant when no control is present — so the expression never errors\n * whether or not `expose_controls` ran. The Color control is an RGB swatch, which cannot use\n * `bind_to` (createControlPanel ignores it for rgb), so uColor reads the swatch's\n * Colorr/Colorg/Colorb components directly instead.\n */\nasync function buildSynthNetwork(\n ctx: ToolContext,\n parentPath: string,\n name: string,\n fragment: string,\n speed: number,\n freqX: number,\n freqY: number,\n scale: number,\n color: [number, number, number],\n resolution: [number, number],\n): Promise<{ builder: NetworkBuilder; outputPath: string }> {\n const builder = await createSystemContainer(ctx, parentPath, name);\n const glsl = await builder.add(\"glslTOP\", \"glsl1\", {\n resolutionw: resolution[0],\n resolutionh: resolution[1],\n outputresolution: \"custom\",\n });\n const frag = await builder.add(\"textDAT\", \"glsl1_frag\");\n await builder.python(\n `op(${q(frag)}).text = ${q(fragment)}\\nop(${q(glsl)}).par.pixeldat = op(${q(frag)}).name`,\n );\n\n // Uniforms live in the GLSL TOP's parameter sequences; the block count has no structured\n // setter, so raise it via numBlocks, then set each block's name + value expression. The\n // \"Vectors\" page (vec sequence) carries the float scalars uTime (block 0), uScale (block 1),\n // uFreqX (block 2) and uFreqY (block 3); the \"Colors\" page (color sequence) carries the\n // vec3 uColor (block 0).\n const speedExpr = `absTime.seconds * (parent().par.Speed.eval() if hasattr(parent().par, 'Speed') else ${speed})`;\n const scaleExpr = `parent().par.Scale.eval() if hasattr(parent().par, 'Scale') else ${scale}`;\n const freqXExpr = `parent().par.Freqx.eval() if hasattr(parent().par, 'Freqx') else ${freqX}`;\n const freqYExpr = `parent().par.Freqy.eval() if hasattr(parent().par, 'Freqy') else ${freqY}`;\n await builder.python(\n [\n `_g = op(${q(glsl)})`,\n `_g.seq.vec.numBlocks = max(_g.seq.vec.numBlocks, 4)`,\n `_g.par.vec0name = 'uTime'`,\n `_g.par.vec0valuex.expr = ${q(speedExpr)}`,\n `_g.par.vec1name = 'uScale'`,\n `_g.par.vec1valuex.expr = ${q(scaleExpr)}`,\n `_g.par.vec2name = 'uFreqX'`,\n `_g.par.vec2valuex.expr = ${q(freqXExpr)}`,\n `_g.par.vec3name = 'uFreqY'`,\n `_g.par.vec3valuex.expr = ${q(freqYExpr)}`,\n `_g.seq.color.numBlocks = max(_g.seq.color.numBlocks, 1)`,\n `_g.par.color0name = 'uColor'`,\n `_g.par.color0rgbr.expr = ${q(`parent().par.Colorr.eval() if hasattr(parent().par, 'Colorr') else ${color[0]}`)}`,\n `_g.par.color0rgbg.expr = ${q(`parent().par.Colorg.eval() if hasattr(parent().par, 'Colorg') else ${color[1]}`)}`,\n `_g.par.color0rgbb.expr = ${q(`parent().par.Colorb.eval() if hasattr(parent().par, 'Colorb') else ${color[2]}`)}`,\n ].join(\"\\n\"),\n );\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(glsl, out);\n return { builder, outputPath: out };\n}\n\nexport async function createVideoSynthImpl(ctx: ToolContext, args: CreateVideoSynthArgs) {\n return runBuild(async () => {\n const fragment = SHADERS[args.mode] ?? LISSAJOUS_SHADER;\n\n const color = parseHexColor(args.color ?? \"\") ?? DEFAULT_COLOR;\n const colorWarning =\n args.color !== undefined && parseHexColor(args.color) === undefined\n ? `Could not parse color \"${args.color}\" (expected hex like '#33ccff'); used the default.`\n : undefined;\n\n const { builder, outputPath } = await buildSynthNetwork(\n ctx,\n args.parent_path,\n `video_synth_${args.mode}`,\n fragment,\n args.speed,\n args.freq_x,\n args.freq_y,\n args.scale,\n color,\n args.resolution,\n );\n if (colorWarning) builder.warnings.push(colorWarning);\n\n // Live controls bound to the uniforms. Speed/FreqX/FreqY/Scale drive their uniform\n // expressions via the defensive parent() lookups above (referenced by their sanitized\n // custom-par names Speed/Freqx/Freqy/Scale); Color is an RGB swatch whose components those\n // expressions read directly (bind_to is unsupported for rgb).\n const controls: ControlSpec[] = args.expose_controls\n ? [\n { name: \"Speed\", type: \"float\", min: 0, max: 4, default: args.speed },\n { name: \"FreqX\", type: \"float\", min: 0, max: 16, default: args.freq_x },\n { name: \"FreqY\", type: \"float\", min: 0, max: 16, default: args.freq_y },\n { name: \"Scale\", type: \"float\", min: 0.1, max: 4, default: args.scale },\n // Seed the RGB swatch with the build-time colour (a swatch defaults to black, which\n // would make the uColor-driven pattern render black/dark).\n {\n name: \"Color\",\n type: \"rgb\",\n default: `#${color\n .map((c) =>\n Math.round(c * 255)\n .toString(16)\n .padStart(2, \"0\"),\n )\n .join(\"\")}`,\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Created a \"${args.mode}\" analog video-synth pattern (GLSL).`,\n builder,\n outputPath,\n controls,\n capturePreviewImage: true,\n extra: {\n mode: args.mode,\n speed: args.speed,\n freq_x: args.freq_x,\n freq_y: args.freq_y,\n scale: args.scale,\n color,\n resolution: args.resolution,\n },\n });\n });\n}\n\nexport const registerCreateVideoSynth: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_video_synth\",\n {\n title: \"Create video synth\",\n description:\n \"Instantiate an analog video-synthesizer pattern (lissajous oscillator curve, moving interference fringes, or CRT scanline modulation) into a GLSL TOP with live Speed / FreqX / FreqY / Scale / Color controls. An oscillator/interference generator for VJ work — distinct from create_shader_lib's tunnel/raymarch/fractal/metaball looks.\",\n inputSchema: createVideoSynthSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createVideoSynthImpl(ctx, args),\n );\n};\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createAudioReactiveImpl } from \"./createAudioReactive.js\";\nimport { createFeedbackNetworkImpl } from \"./createFeedbackNetwork.js\";\nimport { createGenerativeArtImpl } from \"./createGenerativeArt.js\";\nimport { createParticleSystemImpl } from \"./createParticleSystem.js\";\nimport { significantTerms } from \"./intent.js\";\nimport { buildFromRecipe, finalize, runBuild } from \"./orchestration.js\";\n\nexport const createVisualSystemSchema = z.object({\n description: z.string().min(1).describe(\"Natural-language description of the visual system.\"),\n parent_path: z.string().default(\"/project1\"),\n resolution: z\n .enum([\"720p\", \"1080p\", \"4K\", \"custom\"])\n .default(\"1080p\")\n .describe(\n \"Advisory target resolution. Recorded in the build note; the sub-builders use their own internal sizes and do not enforce this per-node.\",\n ),\n target_fps: z.coerce\n .number()\n .positive()\n .default(60)\n .describe(\n \"Advisory target frame rate (informational only — TD's real cook rate is a project-level setting, not set here).\",\n ),\n});\ntype CreateVisualSystemArgs = z.infer<typeof createVisualSystemSchema>;\n\ntype Kind =\n | \"audio\"\n | \"particle\"\n | \"feedback\"\n | \"reaction_diffusion\"\n | \"noise_landscape\"\n | \"default\";\n\nfunction classify(description: string): { kind: Kind; label: string } {\n const d = description.toLowerCase();\n const has = (...words: string[]) => words.some((w) => d.includes(w));\n if (has(\"audio\", \"sound\", \"music\", \"beat\", \"frequenc\", \"spectrum\", \"reactive\")) {\n return { kind: \"audio\", label: \"audio-reactive\" };\n }\n if (has(\"particle\", \"swarm\", \"galaxy\", \"sparkle\", \"emitter\")) {\n return { kind: \"particle\", label: \"particle\" };\n }\n if (has(\"reaction\", \"diffusion\", \"gray-scott\", \"gray scott\")) {\n return { kind: \"reaction_diffusion\", label: \"reaction-diffusion\" };\n }\n if (has(\"landscape\", \"terrain\", \"mountain\", \"heightfield\")) {\n return { kind: \"noise_landscape\", label: \"noise landscape\" };\n }\n if (has(\"feedback\", \"tunnel\", \"echo\", \"trail\", \"infinite\", \"kaleido\")) {\n return { kind: \"feedback\", label: \"feedback\" };\n }\n return { kind: \"default\", label: \"generative\" };\n}\n\nfunction pickAudioStyle(\n description: string,\n): \"geometric\" | \"particle\" | \"feedback\" | \"glsl\" | \"instancing\" {\n const d = description.toLowerCase();\n if (d.includes(\"particle\")) return \"particle\";\n if (d.includes(\"feedback\") || d.includes(\"tunnel\")) return \"feedback\";\n if (d.includes(\"geometr\") || d.includes(\"shape\")) return \"geometric\";\n if (d.includes(\"instanc\")) return \"instancing\";\n return \"glsl\";\n}\n\nfunction pickEmitter(\n description: string,\n): \"point\" | \"line\" | \"circle\" | \"sphere\" | \"mesh\" | \"image\" {\n const d = description.toLowerCase();\n if (d.includes(\"galaxy\") || d.includes(\"sphere\") || d.includes(\"orbit\")) return \"sphere\";\n if (d.includes(\"ring\") || d.includes(\"circle\")) return \"circle\";\n if (d.includes(\"line\")) return \"line\";\n return \"point\";\n}\n\nconst COLOR_WORDS: Record<string, string> = {\n red: \"#e03030\",\n crimson: \"#c01040\",\n orange: \"#ff7a18\",\n amber: \"#ffb000\",\n yellow: \"#f5e050\",\n gold: \"#e8c020\",\n green: \"#30c050\",\n lime: \"#9be025\",\n teal: \"#10b0a0\",\n cyan: \"#20d0e0\",\n blue: \"#1840d0\",\n navy: \"#0a1a66\",\n indigo: \"#3010a0\",\n purple: \"#7a20c0\",\n violet: \"#8a40e0\",\n magenta: \"#d020a0\",\n pink: \"#ff60b0\",\n white: \"#f0f0f0\",\n black: \"#101015\",\n};\n\n// Best-effort: pull up to two named colors from the description so a feedback system\n// can honor a requested palette instead of rendering grayscale.\nfunction parseColors(description: string): string[] {\n const d = description.toLowerCase();\n const found: string[] = [];\n for (const [word, hex] of Object.entries(COLOR_WORDS)) {\n if (new RegExp(`\\\\b${word}`).test(d) && !found.includes(hex)) found.push(hex);\n if (found.length >= 2) break;\n }\n return found;\n}\n\nfunction withNote(result: CallToolResult, note: string): CallToolResult {\n return { ...result, content: [{ type: \"text\", text: note }, ...result.content] };\n}\n\nexport async function createVisualSystemImpl(ctx: ToolContext, args: CreateVisualSystemArgs) {\n const { kind, label } = classify(args.description);\n const note = `Interpreted \"${args.description}\" as a ${label} system (advisory target ${args.resolution} @ ${args.target_fps}fps).`;\n ctx.logger.info(\"create_visual_system classified\", { kind, description: args.description });\n\n switch (kind) {\n case \"audio\":\n return withNote(\n await createAudioReactiveImpl(ctx, {\n audio_source: \"microphone\",\n visual_style: pickAudioStyle(args.description),\n frequency_bands: 8,\n beat_detection: true,\n expose_controls: true,\n parent_path: args.parent_path,\n }),\n note,\n );\n case \"particle\":\n return withNote(\n await createParticleSystemImpl(ctx, {\n emitter_shape: pickEmitter(args.description),\n particle_count: 10000,\n forces: [\"noise\", \"gravity\"],\n render_style: \"sprites\",\n lifetime: 3,\n expose_controls: true,\n parent_path: args.parent_path,\n }),\n note,\n );\n case \"feedback\":\n return withNote(\n await createFeedbackNetworkImpl(ctx, {\n seed_type: \"noise\",\n transformations: [\"blur\", \"displace\", \"level\"],\n feedback_gain: 0.95,\n colors: parseColors(args.description),\n expose_controls: true,\n parent_path: args.parent_path,\n }),\n note,\n );\n case \"reaction_diffusion\":\n case \"noise_landscape\":\n return withNote(\n await createGenerativeArtImpl(ctx, {\n technique: kind,\n evolution_speed: 1.0,\n expose_controls: true,\n parent_path: args.parent_path,\n }),\n note,\n );\n default: {\n // Try to match a recipe by keywords before falling back to generative GLSL.\n const recipe = ctx.recipes.findByTags(significantTerms(args.description));\n if (recipe) {\n return runBuild(async () => {\n const { builder, outputPath, controls } = await buildFromRecipe(\n ctx,\n recipe,\n args.parent_path,\n );\n return withNote(\n await finalize(ctx, {\n summary: `Built \"${recipe.name}\" from a matching recipe.`,\n builder,\n outputPath,\n recipeId: recipe.id,\n controls,\n }),\n note,\n );\n });\n }\n return withNote(\n await createGenerativeArtImpl(ctx, {\n technique: \"custom_glsl\",\n evolution_speed: 1.0,\n expose_controls: true,\n parent_path: args.parent_path,\n }),\n note,\n );\n }\n }\n}\n\nexport const registerCreateVisualSystem: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_visual_system\",\n {\n title: \"Create visual system\",\n description:\n \"Create a complete visual system from a natural-language description. Classifies intent (audio-reactive, particle, feedback, reaction-diffusion, landscape, generative) and builds it in a self-contained COMP, then verifies and previews it.\",\n inputSchema: createVisualSystemSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createVisualSystemImpl(ctx, args),\n );\n};\n","/**\n * Words that describe almost any visual and so must not drive recipe matching.\n * \"generative\", for instance, is a tag on most recipes, so leaving it in makes\n * findByTags pick an unrelated recipe (e.g. \"glowing generative plasma\" → particle galaxy).\n */\nconst GENERIC_TERMS = new Set([\n \"generative\",\n \"visual\",\n \"visuals\",\n \"glow\",\n \"glowing\",\n \"abstract\",\n \"field\",\n \"system\",\n \"animated\",\n \"evolving\",\n \"dynamic\",\n \"background\",\n \"colorful\",\n \"colourful\",\n \"bright\",\n \"beautiful\",\n]);\n\n/** Splits a description into discriminating lowercase terms for recipe tag matching. */\nexport function significantTerms(description: string): string[] {\n return description\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length > 3 && !GENERIC_TERMS.has(t));\n}\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport const createWaveformSchema = z.object({\n source: z\n .enum([\"device\", \"file\", \"oscillator\", \"existing_chop\"])\n .default(\"device\")\n .describe(\n \"Audio source. 'device' = live microphone/line in (the real-world default; creating it may pop a one-time macOS microphone-permission dialog — click Allow). 'file' = an audio file. 'oscillator' = a synthetic tone, handy for testing the scope without any device permission. 'existing_chop' = reuse a CHOP you already have.\",\n ),\n audio_file_path: z.string().optional().describe(\"Audio file path (source='file').\"),\n existing_chop_path: z\n .string()\n .optional()\n .describe(\"Path of an existing audio CHOP to scope (source='existing_chop').\"),\n color: z\n .string()\n .default(\"#00ff88\")\n .describe(\n \"Waveform colour as a hex string ('#00ff88' = classic phosphor green). Tints the rendered scope line via a Constant TOP multiplied over the Render TOP image.\",\n ),\n scale: z.coerce\n .number()\n .positive()\n .default(1)\n .describe(\n \"Amplitude gain on the signal before it is drawn — the vertical zoom of the trace. Drives a Math CHOP's gain (1 = raw signal).\",\n ),\n time_window: z.coerce\n .number()\n .positive()\n .default(1)\n .describe(\n \"How much recent history the scrolling trace holds, in seconds — the horizontal time span. Drives the Trail CHOP's Window Length (wlength, units = seconds).\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\n \"Expose live Color / Scale / TimeWindow controls bound to the right node parameters.\",\n ),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateWaveformArgs = z.infer<typeof createWaveformSchema>;\n\n/** Parses '#rrggbb' / 'rrggbb' (3- or 6-digit) into 0..1 RGB. Falls back to green. */\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());\n if (!m) return { r: 0, g: 1, b: 0.53 };\n let h = m[1] as string;\n if (h.length === 3)\n h = h\n .split(\"\")\n .map((c) => c + c)\n .join(\"\");\n const int = Number.parseInt(h, 16);\n return {\n r: ((int >> 16) & 0xff) / 255,\n g: ((int >> 8) & 0xff) / 255,\n b: (int & 0xff) / 255,\n };\n}\n\n/** Mirrors extractAudioFeatures.buildSource so the source enum behaves identically. */\nasync function buildSource(builder: NetworkBuilder, args: CreateWaveformArgs): Promise<string> {\n if (args.source === \"existing_chop\" && args.existing_chop_path) {\n return args.existing_chop_path;\n }\n if (args.source === \"file\") {\n return builder.add(\"audiofileinCHOP\", \"audioin\", {\n ...(args.audio_file_path ? { file: args.audio_file_path } : {}),\n play: 1,\n });\n }\n if (args.source === \"oscillator\") {\n // A clean sine gives a textbook scrolling waveform, so the scope reads as a recognisable\n // wave with no audio device (and no microphone-permission prompt) attached.\n return builder.add(\"audiooscillatorCHOP\", \"audioin\", { wavetype: \"sine\", amp: 0.5 });\n }\n return builder.add(\"audiodeviceinCHOP\", \"audioin\");\n}\n\nexport async function createWaveformImpl(ctx: ToolContext, args: CreateWaveformArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"waveform\");\n const source = await buildSource(builder, args);\n\n // Amplitude gain (the vertical zoom of the trace). Math CHOP gain = `gain`.\n const gain = await builder.add(\"mathCHOP\", \"scale\", { gain: args.scale });\n await builder.connect(source, gain);\n\n // Keep a scrolling buffer of the recent signal — this is what makes the trace move.\n // Trail CHOP window length is `wlength`; `wlengthunit` switches it to seconds so\n // time_window reads directly as a duration.\n const trail = await builder.add(\"trailCHOP\", \"trail\", {\n wlength: args.time_window,\n wlengthunit: \"seconds\",\n });\n await builder.connect(gain, trail);\n\n // The Trail buffers at the audio rate (time_window × ~44.1k samples) — far more than a\n // texture can hold, so CHOP-to-TOP would clamp to 256px and warn. Resample down to a fixed\n // display rate first, so the whole window becomes a clean full-width trace with no warning.\n const rebin = await builder.add(\"resampleCHOP\", \"rebin\", { rate: 1024 });\n await builder.connect(trail, rebin);\n\n // CHOP-to-SOP maps channels to point attributes BY NAME. Rename the single signal channel to\n // \"ty\" (the per-point Y translate) so the sample value deflects each point vertically — the\n // trace. X is laid out left→right by startposx→endposx below. (Live-verified with a sine\n // pattern: a channel named \"ty\" deflects Y; \"P(1)\"/\"chan1\" leave the line flat.)\n const ypos = await builder.add(\"renameCHOP\", \"ypos\", { renamefrom: \"*\", renameto: \"ty\" });\n await builder.connect(rebin, ypos);\n\n // Render the buffered samples as a real oscilloscope LINE rather than a brightness strip.\n // A flat/constant material lets the line render at full, unlit brightness (no shading\n // falloff that would dim the trace). Kept white here; the chosen colour is applied as a\n // tint after the render so the live Color control still drives one Constant TOP swatch.\n const mat = await builder.add(\"constantMAT\", \"mat\", {\n colorr: 1,\n colorg: 1,\n colorb: 1,\n alpha: 1,\n });\n\n // A Geometry COMP renders the line SOP, so the SOP must live INSIDE the COMP.\n // createSystemContainer's builder cleared the COMP's default torus on add.\n const geo = await builder.add(\"geometryCOMP\", \"geo\");\n\n // CHOP-to-SOP in DEFAULT mode: one point per sample, auto-spread across X in [-1, 1] by sample\n // index, with the \"ty\" channel (renamed above) deflecting each point's Y — a real scope trace.\n // (Live-verified: default mode gives X-spread + Y-deflection; setting startposx/endposx forces\n // explicit positions that OVERRIDE the ty deflection and flatten the line, so we leave the\n // positions at their defaults.) CHOP-to-SOP reads its source from a `chop` PARAMETER (not a\n // wire); NetworkBuilder.connect() detects the converter and patches it, so connect(ypos, line)\n // points the SOP at the renamed signal.\n const line = await builder.add(\"choptoSOP\", \"line\", {}, geo);\n await builder.connect(ypos, line);\n\n // Flag the line SOP render+display and point the COMP's `material` param at the constant\n // MAT (mirrors create_3d_scene / create_particle_system).\n await builder.python(\n [\n `_l = op(${q(line)})`,\n \"_l.render = True\",\n \"_l.display = True\",\n `op(${q(geo)}).par.material = ${q(mat)}`,\n ].join(\"\\n\"),\n );\n\n // Orthographic camera so the trace keeps its true left→right / up-down shape with no\n // perspective foreshortening (a scope must not bow). orthowidth ≈ the X span (2) plus a\n // little margin frames [-1,1] full-width; default tz=1 already looks down -Z at origin,\n // and the line sits at z=0 so it faces the camera. A light is created for the render\n // scene even though the constant MAT is unlit.\n const cam = await builder.add(\"cameraCOMP\", \"cam\", {\n projection: \"ortho\",\n orthowidth: 2.2,\n tz: 5,\n });\n const lightComp = await builder.add(\"lightCOMP\", \"light\", { tx: 0, ty: 0, tz: 5 });\n // Render TOP reads its scene from PARAMETERS (camera/geometry/lights), not wires — and an\n // opaque near-black background gives the classic dark-scope look (and contrast for the\n // multiply tint). The custom resolution keeps a wide scope aspect.\n const render = await builder.add(\"renderTOP\", \"render\", {\n camera: cam,\n geometry: geo,\n lights: lightComp,\n bgcolorr: 0.01,\n bgcolorg: 0.02,\n bgcolorb: 0.02,\n bgcolora: 1,\n outputresolution: \"custom\",\n resolutionw: 1024,\n resolutionh: 256,\n });\n\n // Tint the white line to the chosen colour: a flat Constant TOP of the colour multiplied\n // over the render (operand 'multiply') stains the trace without touching its shape, and\n // leaves the dark background dark. Input 0 = the render, input 1 = the flat colour.\n const rgb = hexToRgb(args.color);\n const tintColor = await builder.add(\"constantTOP\", \"tint\", {\n colorr: rgb.r,\n colorg: rgb.g,\n colorb: rgb.b,\n alpha: 1,\n });\n const tint = await builder.add(\"compositeTOP\", \"tinted\", { operand: \"multiply\" });\n await builder.connect(render, tint, 0, 0);\n await builder.connect(tintColor, tint, 0, 1);\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(tint, out);\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Color\",\n type: \"rgb\",\n default: args.color,\n // rgb controls bind to the Constant TOP's RGB swatch via the panel builder.\n bind_to: [`${tintColor}.colorr`, `${tintColor}.colorg`, `${tintColor}.colorb`],\n },\n {\n name: \"Scale\",\n type: \"float\",\n min: 0,\n max: 8,\n default: args.scale,\n bind_to: [`${gain}.gain`],\n },\n {\n name: \"TimeWindow\",\n type: \"float\",\n min: 0.05,\n max: 10,\n default: args.time_window,\n bind_to: [`${trail}.wlength`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Built a waveform oscilloscope (source: ${args.source}, ${args.time_window}s window) → ${out}. The Trail CHOP scrolls the recent signal, a CHOP-to-SOP turns the samples into a deflected scope line (x=time, y=amplitude), and a Render TOP draws it as a glowing trace tinted to ${args.color}.`,\n builder,\n outputPath: out,\n // Output is a TOP (the Null), so a preview image is captured.\n capturePreviewImage: true,\n controls,\n extra: {\n source: args.source,\n scale: args.scale,\n time_window: args.time_window,\n color: { r: rgb.r, g: rgb.g, b: rgb.b },\n trail_path: trail,\n line_path: line,\n render_path: render,\n output_path: out,\n },\n });\n });\n}\n\nexport const registerCreateWaveform: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_waveform\",\n {\n title: \"Create waveform oscilloscope\",\n description:\n \"Build a time-domain audio waveform / oscilloscope — the actual audio signal scrolling left-to-right as a moving trace (the time-domain companion to create_spectrum's frequency bins and detect_onsets' transients). A Trail CHOP keeps a rolling buffer of recent samples (time_window seconds), a CHOP-to-SOP turns those samples into a real scope LINE (x=time, y=amplitude) rendered by a Geometry COMP through an orthographic Camera + Render TOP, and a Constant TOP tints the trace to the chosen colour. Unlike create_audio_reactive (which renders a spectrum), this shows the raw waveform. Source can be the live device (mic/line — may prompt for macOS permission), an audio file, a synthetic oscillator (for testing), or an existing CHOP. Output is a Null TOP. Scale is the vertical amplitude zoom; TimeWindow is the horizontal time span.\",\n inputSchema: createWaveformSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createWaveformImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { textResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { significantTerms } from \"./intent.js\";\n\nexport const describeProjectSchema = z.object({\n description: z.string().min(1).describe(\"Natural-language description of the visual you want.\"),\n});\ntype DescribeProjectArgs = z.infer<typeof describeProjectSchema>;\n\nexport function describeProjectImpl(ctx: ToolContext, args: DescribeProjectArgs) {\n const d = args.description.toLowerCase();\n const has = (...words: string[]) => words.some((w) => d.includes(w));\n\n let tool: string;\n let summary: string;\n let recipeId: string | undefined;\n\n if (has(\"audio\", \"sound\", \"music\", \"beat\", \"frequenc\", \"spectrum\", \"reactive\")) {\n tool = \"create_audio_reactive\";\n summary = \"audio-reactive visual\";\n } else if (has(\"particle\", \"swarm\", \"galaxy\", \"sparkle\", \"emitter\")) {\n tool = \"create_particle_system\";\n summary = \"particle system\";\n } else if (has(\"reaction\", \"diffusion\", \"gray-scott\", \"gray scott\")) {\n tool = \"create_generative_art\";\n summary = \"reaction-diffusion simulation\";\n recipeId = \"reaction_diffusion\";\n } else if (has(\"landscape\", \"terrain\", \"mountain\", \"heightfield\")) {\n tool = \"create_generative_art\";\n summary = \"3D noise landscape\";\n recipeId = \"noise_landscape\";\n } else if (has(\"feedback\", \"tunnel\", \"echo\", \"trail\", \"kaleido\")) {\n tool = \"create_feedback_network\";\n summary = \"feedback network\";\n } else {\n tool = \"create_visual_system\";\n summary = \"generative visual\";\n recipeId = ctx.recipes.findByTags(significantTerms(d))?.id;\n }\n\n const lines: string[] = [\n `Plan for: \"${args.description}\"`,\n \"\",\n `Interpreted as: ${summary}.`,\n `Recommended tool: ${tool}${recipeId ? ` (recipe: ${recipeId})` : \"\"}.`,\n ];\n\n if (recipeId) {\n const recipe = ctx.recipes.get(recipeId);\n if (recipe) {\n lines.push(\"\", `Recipe \"${recipe.name}\" would create:`);\n for (const node of recipe.nodes) {\n lines.push(` - ${node.name} (${node.type})${node.comment ? ` — ${node.comment}` : \"\"}`);\n }\n }\n }\n\n lines.push(\"\", \"Next: call the recommended tool, then check get_td_node_errors and get_preview.\");\n return textResult(lines.join(\"\\n\"));\n}\n\nexport const registerDescribeProject: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"plan_visual\",\n {\n title: \"Plan a visual from a description\",\n description:\n \"Turn a natural-language description of a visual you WANT into a build plan (which tool/recipe and nodes) — a dry run that creates nothing. Note: this does NOT inspect the current TouchDesigner project; to read existing nodes use get_td_nodes / get_td_topology / find_td_nodes.\",\n inputSchema: describeProjectSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n (args) => describeProjectImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport const detectOnsetsSchema = z.object({\n source: z\n .enum([\"device\", \"file\", \"oscillator\", \"existing_chop\"])\n .default(\"device\")\n .describe(\n \"Audio source. 'device' = live microphone/line in (the real-world default; creating it may pop a one-time macOS microphone-permission dialog — click Allow). 'file' = an audio file. 'oscillator' = a synthetic tone, handy for testing without any device permission. 'existing_chop' = reuse a CHOP you already have.\",\n ),\n audio_file_path: z.string().optional().describe(\"Audio file path (source='file').\"),\n existing_chop_path: z\n .string()\n .optional()\n .describe(\"Path of an existing audio CHOP to analyze (source='existing_chop').\"),\n kick_hz: z.coerce\n .number()\n .positive()\n .default(120)\n .describe(\"Low-pass cutoff (Hz) isolating the kick/bass-drum band.\"),\n snare_hz: z.coerce\n .number()\n .positive()\n .default(1500)\n .describe(\"Band-pass centre (Hz) isolating the snare/body band.\"),\n hat_hz: z.coerce\n .number()\n .positive()\n .default(6000)\n .describe(\"High-pass cutoff (Hz) isolating the hi-hat/cymbal band.\"),\n threshold: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(0.01)\n .describe(\n \"How far an instant's band energy must rise above its own moving baseline (in RMS units) to count as a hit. Band-RMS magnitudes are small (a steady tone reads ~0.002 live), so the default is 0.01 — the old 0.15 was unreachable and never fired. Lower = more sensitive; raise it if a loud track double-triggers. Tune live per source (needs real percussive audio to dial in).\",\n ),\n emit_events: z\n .boolean()\n .default(false)\n .describe(\n \"Also broadcast an `onset` event over the bridge WebSocket on every detected hit (with the band name), so `tdmcp-agent watch` and the AI can react to drum hits live.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose live 'Sensitivity' (output gain) and 'Threshold' (hit sensitivity) knobs.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype DetectOnsetsArgs = z.infer<typeof detectOnsetsSchema>;\n\n// CHOP Execute callback (lives in TD, runs in the normal op context — not the exec\n// namespace — so it imports `td` for the operator classes). It watches every channel of\n// the onsets Null (kick/snare/hat), each a 0/1 pulse, and fires once on the rising edge\n// (prev <= 0, val > 0) of a hit. On each onset it broadcasts an `onset` event through the\n// bridge's Web Server DAT (located by type so it works wherever the bridge was installed),\n// mirroring the tempo-sync `beat` emitter exactly.\nconst ONSET_EMITTER = `import td\n\ndef _webserver():\n for w in op('/').findChildren(type=td.webserverDAT):\n return w\n return None\n\ndef onValueChange(channel, sampleIndex, val, prev):\n if val <= 0 or prev > 0:\n return\n ws = _webserver()\n if ws is None:\n return\n try:\n from mcp import events\n events.broadcast(ws, 'onset', {'band': channel.name, 'value': 1})\n except Exception:\n pass\n return\n`;\n\nasync function buildSource(builder: NetworkBuilder, args: DetectOnsetsArgs): Promise<string> {\n if (args.source === \"existing_chop\" && args.existing_chop_path) {\n return args.existing_chop_path;\n }\n if (args.source === \"file\") {\n return builder.add(\"audiofileinCHOP\", \"audioin\", {\n ...(args.audio_file_path ? { file: args.audio_file_path } : {}),\n play: 1,\n });\n }\n if (args.source === \"oscillator\") {\n // White noise has energy across all bands, so kick/snare/hat all read non-zero —\n // a self-contained signal for verifying the chain without any audio device.\n return builder.add(\"audiooscillatorCHOP\", \"audioin\", { wavetype: \"whitenoise\", amp: 0.5 });\n }\n return builder.add(\"audiodeviceinCHOP\", \"audioin\");\n}\n\n/**\n * One onset detector for a drum band, built entirely from primitives (no audioenvelope /\n * pitch CHOP — not creatable in this build). Returns both the gate node (the 0/1 pulse\n * output, channel renamed to `name`) and the Logic CHOP whose `boundmin` is the live\n * Threshold knob target.\n *\n * Chain: audiofilter (band) → analyze rmspower = instantaneous energy `env`.\n * `env` splits two ways:\n * • fast = `env` itself (this frame's level)\n * • slow = lagCHOP(env), a trailing moving baseline (longer lag)\n * math \"sub\" (fast − slow) = the transient *excess* over the baseline. A steady tone\n * sits near zero (fast ≈ slow); a hit spikes the excess.\n * logic convert=\"bound\", boundmin=threshold, boundmax=huge → emits 1 only while the\n * excess ≥ threshold, i.e. a clean 0→1 spike on the attack, 0 otherwise.\n * A short lag (down only) on the gate widens the one-frame spike enough to be seen.\n */\nasync function buildOnsetBand(\n builder: NetworkBuilder,\n source: string,\n name: string,\n filter: \"lowpass\" | \"bandpass\" | \"highpass\",\n cutoffHz: number,\n threshold: number,\n): Promise<{ gate: string; logic: string }> {\n const filt = await builder.add(\"audiofilterCHOP\", `${name}_filter`, {\n filter,\n units: \"frequency\",\n cutofffrequency: cutoffHz,\n });\n await builder.connect(source, filt);\n\n // Instantaneous band energy, named after the band so the channel survives downstream.\n const env = await builder.add(\"analyzeCHOP\", `${name}_env`, {\n function: \"rmspower\",\n renamefrom: \"*\",\n renameto: name,\n });\n await builder.connect(filt, env);\n\n // Slow moving baseline: a long lag trails the energy, so a transient briefly exceeds it.\n const baseline = await builder.add(\"lagCHOP\", `${name}_baseline`, {\n lag1: 0.12,\n lag2: 0.25,\n lagunit: \"seconds\",\n });\n await builder.connect(env, baseline);\n\n // excess = instantaneous − baseline (Combine CHOPs: subtract). Same channel name on both\n // inputs, so name/index matching collapses them to one channel still named `name`.\n const excess = await builder.add(\"mathCHOP\", `${name}_excess`, { chopop: \"sub\" });\n await builder.connect(env, excess, 0, 0);\n await builder.connect(baseline, excess, 0, 1);\n\n // Threshold compare → clean 0/1. \"bound\" returns 1 only when the value is within\n // [boundmin, boundmax]; with boundmin = Threshold and a huge boundmax that means\n // \"excess ≥ Threshold\". boundmin is the live Threshold knob target.\n const logic = await builder.add(\"logicCHOP\", `${name}_gate`, {\n convert: \"bound\",\n boundmin: threshold,\n boundmax: 1000000,\n });\n await builder.connect(excess, logic);\n\n // Shape the spike: hold the pulse very briefly on the way down so a single-frame hit is\n // visible / catchable, without smearing it into a sustained level.\n const gate = await builder.add(\"lagCHOP\", name, {\n lag1: 0,\n lag2: 0.04,\n lagunit: \"seconds\",\n });\n await builder.connect(logic, gate);\n return { gate, logic };\n}\n\nexport async function detectOnsetsImpl(ctx: ToolContext, args: DetectOnsetsArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"onsets\");\n const source = await buildSource(builder, args);\n\n const kick = await buildOnsetBand(\n builder,\n source,\n \"kick\",\n \"lowpass\",\n args.kick_hz,\n args.threshold,\n );\n const snare = await buildOnsetBand(\n builder,\n source,\n \"snare\",\n \"bandpass\",\n args.snare_hz,\n args.threshold,\n );\n const hat = await buildOnsetBand(\n builder,\n source,\n \"hat\",\n \"highpass\",\n args.hat_hz,\n args.threshold,\n );\n\n // Merge the three pulse channels into one, then a Sensitivity gain, then a Null as the\n // stable bind point. Expressions read op('…/onsets/onsets')['kick'] etc.\n const merge = await builder.add(\"mergeCHOP\", \"merged\");\n await builder.connect(kick.gate, merge, 0, 0);\n await builder.connect(snare.gate, merge, 0, 1);\n await builder.connect(hat.gate, merge, 0, 2);\n\n const gain = await builder.add(\"mathCHOP\", \"sensitivity\", { gain: 1 });\n await builder.connect(merge, gain);\n const onsets = await builder.add(\"nullCHOP\", \"onsets\");\n await builder.connect(gain, onsets);\n\n let emitter: string | undefined;\n if (args.emit_events) {\n // Watch every channel of the onsets Null; the Python callback fires on the rising\n // edge of any band. Same Execute-DAT + events.broadcast mechanism as create_tempo_sync.\n emitter = await builder.add(\"chopexecuteDAT\", \"onset_emitter\", {\n chop: onsets,\n valuechange: 1,\n offtoon: 0,\n active: 1,\n });\n await builder.python(`op(${q(emitter)}).text = ${q(ONSET_EMITTER)}`);\n }\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Sensitivity\",\n type: \"float\",\n min: 0,\n max: 8,\n default: 1,\n bind_to: [`${gain}.gain`],\n },\n {\n name: \"Threshold\",\n type: \"float\",\n min: 0,\n max: 1,\n default: args.threshold,\n // One knob retunes the hit sensitivity of all three bands at once.\n bind_to: [`${kick.logic}.boundmin`, `${snare.logic}.boundmin`, `${hat.logic}.boundmin`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Built onset detection (source: ${args.source}) → ${onsets} with per-band pulse channels kick/snare/hat (0→1 spike on each hit)${args.emit_events ? \", broadcasting `onset` events\" : \"\"}. Bind a parameter to op('${onsets}')['kick'] (etc.) to flash/cut on the actual drum hit. Raise Threshold for fewer/stronger hits, lower it for more.`,\n builder,\n outputPath: onsets,\n // The output is a CHOP, not a TOP, so there is no image to capture.\n capturePreviewImage: false,\n controls,\n extra: {\n source: args.source,\n onsets_path: onsets,\n channels: [\"kick\", \"snare\", \"hat\"],\n bands_hz: { kick: args.kick_hz, snare: args.snare_hz, hat: args.hat_hz },\n threshold: args.threshold,\n emits_onset_events: args.emit_events,\n emitter,\n },\n });\n });\n}\n\nexport const registerDetectOnsets: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"detect_onsets\",\n {\n title: \"Detect onsets\",\n description:\n \"Build a transient/onset detector that flags kick/snare/hi-hat hits in live audio and exposes a per-band pulse channel (a 0→1 spike on each hit) on a Null CHOP. Unlike create_tempo_sync (a fixed internal clock), this follows the ACTUAL audio: bind a parameter to op('…/onsets/onsets')['kick'] to flash or cut exactly on the kick drum. Each band is built from primitives (band filter → RMS energy → moving-baseline compare → threshold), so a Threshold knob tunes hit sensitivity and a Sensitivity knob scales the output. Source can be the live device (mic/line — may prompt for macOS permission), an audio file, a synthetic oscillator (for testing), or an existing CHOP. With emit_events on, it also broadcasts an `onset` event over the bridge WebSocket on each hit. The audio-following complement to create_tempo_sync.\",\n inputSchema: detectOnsetsSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => detectOnsetsImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nexport const detectPitchSchema = z.object({\n source: z\n .enum([\"device\", \"file\", \"oscillator\", \"existing_chop\"])\n .default(\"device\")\n .describe(\n \"Audio source. 'device' = live microphone/line in (the real-world default; creating it may pop a one-time macOS microphone-permission dialog — click Allow). 'file' = an audio file. 'oscillator' = a synthetic tone (a SINE wave at a fixed frequency → a clean single peak, the ideal device-free test for pitch tracking). 'existing_chop' = reuse a CHOP you already have.\",\n ),\n audio_file_path: z.string().optional().describe(\"Audio file path (source='file').\"),\n existing_chop_path: z\n .string()\n .optional()\n .describe(\"Path of an existing audio CHOP to analyze (source='existing_chop').\"),\n min_hz: z.coerce\n .number()\n .positive()\n .default(80)\n .describe(\n \"Bottom of the frequency search range (Hz). The dominant-bin search ignores everything below this, so sub-bass rumble / DC offset can't masquerade as the pitch. 80 Hz ≈ low male voice / bass guitar E.\",\n ),\n max_hz: z.coerce\n .number()\n .positive()\n .default(2000)\n .describe(\n \"Top of the frequency search range (Hz). The search ignores everything above this. 2000 Hz comfortably covers the fundamental of most melodic instruments and voice; raise it for piccolo/whistle, lower it to reject high harmonics.\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\n \"Expose live 'Sensitivity' (magnitude gain) and 'Threshold' (minimum peak magnitude below which the pitch is treated as silence) knobs.\",\n ),\n parent_path: z.string().default(\"/project1\"),\n});\ntype DetectPitchArgs = z.infer<typeof detectPitchSchema>;\n\nasync function buildSource(builder: NetworkBuilder, args: DetectPitchArgs): Promise<string> {\n if (args.source === \"existing_chop\" && args.existing_chop_path) {\n return args.existing_chop_path;\n }\n if (args.source === \"file\") {\n return builder.add(\"audiofileinCHOP\", \"audioin\", {\n ...(args.audio_file_path ? { file: args.audio_file_path } : {}),\n play: 1,\n });\n }\n if (args.source === \"oscillator\") {\n // A pure SINE tone gives one clean spectral peak (unlike white noise, which has NO\n // single dominant bin) — the right self-contained signal to verify pitch tracking\n // without any audio device. ~440 Hz lands inside the default 80–2000 Hz search range,\n // so pitch_hz should read ≈440 immediately.\n return builder.add(\"audiooscillatorCHOP\", \"audioin\", {\n wavetype: \"sine\",\n frequency: 440,\n amp: 0.5,\n });\n }\n return builder.add(\"audiodeviceinCHOP\", \"audioin\");\n}\n\nexport async function detectPitchImpl(ctx: ToolContext, args: DetectPitchArgs) {\n return runBuild(async () => {\n // Clamp the search range to a sane order (min < max) without rejecting the call.\n const minHz = Math.max(1, Math.min(args.min_hz, args.max_hz));\n const maxHz = Math.max(minHz + 1, Math.max(args.min_hz, args.max_hz));\n\n const builder = await createSystemContainer(ctx, args.parent_path, \"pitch\");\n const source = await buildSource(builder, args);\n\n // FFT in \"1 sample == 1 Hz\" mode. The Audio Spectrum CHOP, with Mode=visual and\n // Frequency<->Log Scaling=0, emits ONE magnitude sample per Hz (per TD docs: \"the level\n // you see at sample 5000 is the level at 5 KHz\"). So the SAMPLE INDEX of a bin IS its\n // frequency in Hz — which is what makes a stock-CHOP argmax→Hz possible at all.\n // We request outlength = max_hz so the channel spans 0..max_hz Hz, one sample each.\n // TD clamps outlength into 128..16384, so a tiny max_hz is widened (harmless — the extra\n // high bins are simply never searched) and an extreme one is capped (see flag below).\n const fftLength = Math.min(Math.max(Math.ceil(maxHz), 128), 16384);\n const fft = await builder.add(\"audiospectrumCHOP\", \"spectrum_fft\", {\n mode: \"visual\",\n frequencylog: 0,\n outputmenu: \"setmanually\",\n outlength: fftLength,\n });\n await builder.connect(source, fft);\n\n // Restrict the argmax to the [min_hz, max_hz] band. The Trim CHOP re-bases indices to 0 at the\n // window start, so the peak index read back is relative to bandStart — added back in the\n // index→Hz conversion below.\n // The Audio Spectrum (visual) spans [0, rate/2] across `fftLength` bins, so Hz ≈\n // index * (rate/2)/fftLength — NOT 1 Hz per sample (live-verified: a 440 Hz tone peaks\n // near bin 40, not 440). Convert the Hz search band to sample indices (assume 44.1 kHz for\n // the build-time window bounds; the index→Hz expression below reads the live rate for accuracy).\n const nyquistAssumed = 44100 / 2;\n const hzToSample = (hz: number) => Math.round((hz * fftLength) / nyquistAssumed);\n const bandStart = Math.max(0, Math.min(hzToSample(minHz), fftLength - 2));\n const bandEnd = Math.max(bandStart + 1, Math.min(hzToSample(maxHz), fftLength - 1));\n const band = await builder.add(\"trimCHOP\", \"search_band\", {\n relative: \"abs\",\n start: bandStart,\n end: bandEnd,\n startunit: \"samples\",\n endunit: \"samples\",\n discard: \"exterior\",\n });\n await builder.connect(fft, band);\n\n // ARGMAX. \"highestpeakindex\" returns the sample index of the highest *peak* (a local\n // maximum) — more robust for a spectrum than \"maximumindex\" (the global max sample),\n // since a true fundamental is a peak, whereas the global max can sit on a broad shelf.\n // nopeakvalue=-1 means \"no peak found\" (e.g. silence) → surfaces as a negative Hz that\n // the Threshold gate below zeroes out. The result is one sample long.\n const peakIndex = await builder.add(\"analyzeCHOP\", \"peak_index\", {\n function: \"highestpeakindex\",\n nopeakvalue: -1,\n renamefrom: \"*\",\n renameto: \"pitch_hz\",\n });\n await builder.connect(band, peakIndex);\n\n // index → Hz: (band-relative index + bandStart) × Hz-per-bin, where Hz-per-bin = (rate/2)/\n // fftLength. A Math CHOP does it as in×gain + postoff: gain = Hz-per-bin, postoff =\n // bandStart × Hz-per-bin. (Assumes 44.1 kHz — the live-verified device rate; an Expression\n // CHOP reading the live rate was tried but TD passed the input through unchanged, so the\n // robust Math CHOP form is used instead.) Live-verified: a 440 Hz tone → bin 40 → ~441 Hz out.\n const hzPerBin = nyquistAssumed / fftLength;\n const toHz = await builder.add(\"mathCHOP\", \"to_hz\", {\n gain: hzPerBin,\n postoff: bandStart * hzPerBin,\n integer: \"round\",\n });\n await builder.connect(peakIndex, toHz);\n\n // Peak MAGNITUDE in the same band (parallel branch): a confidence signal. Loud, clearly-\n // pitched input → large magnitude; silence/noise → small. Drives the Threshold gate and\n // is exposed as `confidence` so callers can ignore the pitch when nothing is playing.\n const peakMag = await builder.add(\"analyzeCHOP\", \"peak_mag\", {\n function: \"maximum\",\n renamefrom: \"*\",\n renameto: \"confidence\",\n });\n await builder.connect(band, peakMag);\n\n // Sensitivity knob: a gain over the magnitude so the Threshold reads on a comfortable\n // scale regardless of input level. (Applied to the confidence branch only — scaling Hz\n // would corrupt the pitch.)\n const sensitivity = await builder.add(\"mathCHOP\", \"sensitivity\", { gain: 1 });\n await builder.connect(peakMag, sensitivity);\n\n // Threshold gate: 1 while the (scaled) magnitude is above `threshold`, else 0. boundmin\n // is the live Threshold knob target; a huge boundmax makes it a one-sided \"≥\" test.\n // Audio Spectrum (visual) magnitudes are tiny (a clear tone peaks ~0.001–0.01, noise floor\n // ~0.0001), so the gate threshold must sit between them — 0.02 muted everything. Tune live.\n const DEFAULT_THRESHOLD = 0.0005;\n const gate = await builder.add(\"logicCHOP\", \"gate\", {\n convert: \"bound\",\n boundmin: DEFAULT_THRESHOLD,\n boundmax: 1000000,\n renamefrom: \"*\",\n renameto: \"gate\",\n });\n await builder.connect(sensitivity, gate);\n\n // Gated Hz: pitch_hz × gate. When the gate is 0 (silence / below threshold) the reported\n // pitch_hz collapses to 0 instead of holding a stale or garbage frequency. Same channel\n // name on both inputs (pitch_hz) so Combine multiply keeps one channel named pitch_hz.\n const gateHz = await builder.add(\"renameCHOP\", \"gate_as_hz\", {\n renamefrom: \"gate\",\n renameto: \"pitch_hz\",\n });\n await builder.connect(gate, gateHz);\n const gatedHz = await builder.add(\"mathCHOP\", \"gated_hz\", { chopop: \"mul\" });\n await builder.connect(toHz, gatedHz, 0, 0);\n await builder.connect(gateHz, gatedHz, 0, 1);\n\n // MIDI note number from Hz: note = 69 + 12*log2(hz/440). The Expression CHOP's `expr0expr`\n // is a PARAMETER whose EXPRESSION (not its value) defines the output — it MUST be set via\n // `.expr` + EXPRESSION mode (setting the value casts to numeric and fails; live-verified).\n // math.log(x, 2) is log base 2; guard hz<=0 (gated silence) → 0. me.inputVal = this sample's\n // gated pitch_hz. Renamed to `note` below.\n const note = await builder.add(\"expressionCHOP\", \"to_note\");\n await builder.connect(gatedHz, note);\n await builder.python(\n [\n `_p = op(${JSON.stringify(note)}).par.expr0expr`,\n `_p.expr = ${JSON.stringify(\"69 + 12*math.log(me.inputVal/440.0, 2) if me.inputVal > 0 else 0\")}`,\n \"_p.mode = type(_p.mode).EXPRESSION\",\n ].join(\"\\n\"),\n );\n const noteRename = await builder.add(\"renameCHOP\", \"note_named\", {\n renamefrom: \"*\",\n renameto: \"note\",\n });\n await builder.connect(note, noteRename);\n\n // Merge the three single-sample channels (pitch_hz, note, confidence) into one CHOP,\n // then a Null as the stable bind point — exactly like the spectrum / audio-features tail.\n const merge = await builder.add(\"mergeCHOP\", \"merged\");\n await builder.connect(gatedHz, merge, 0, 0);\n await builder.connect(noteRename, merge, 0, 1);\n await builder.connect(sensitivity, merge, 0, 2);\n const pitch = await builder.add(\"nullCHOP\", \"pitch\");\n await builder.connect(merge, pitch);\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Sensitivity\",\n type: \"float\",\n min: 0,\n max: 32,\n default: 1,\n bind_to: [`${sensitivity}.gain`],\n },\n {\n name: \"Threshold\",\n type: \"float\",\n min: 0,\n max: 1,\n default: DEFAULT_THRESHOLD,\n bind_to: [`${gate}.boundmin`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Built an EXPERIMENTAL monophonic pitch tracker (source: ${args.source}) → ${pitch} with channels pitch_hz / note / confidence. It finds the dominant FFT bin in the ${minHz}–${maxHz} Hz range and maps it to Hz (and a MIDI note). Bind a parameter to op('${pitch}')['pitch_hz'] to drive colour/params from the melody. Sensitivity scales the confidence; Threshold mutes the pitch (→0) when nothing is clearly playing. NOTE: this is approximate (resolution ≈1 Hz, no harmonic/octave correction) and must be tuned live per source.`,\n builder,\n outputPath: pitch,\n // The output is a CHOP, not a TOP, so there is no image to capture.\n capturePreviewImage: false,\n controls,\n extra: {\n source: args.source,\n pitch_path: pitch,\n channels: [\"pitch_hz\", \"note\", \"confidence\"],\n search_range_hz: { min: minHz, max: maxHz },\n argmax_method:\n \"audiospectrum(visual,frequencylog=0 → 1 sample/Hz) → trim to band → analyze highestpeakindex → +min_hz\",\n experimental: true,\n // True when max_hz exceeded TD's 16384-sample spectrum cap: bins above ~16 kHz can't\n // be represented, so the effective search ceiling was clamped to fftLength.\n search_ceiling_clamped: Math.ceil(maxHz) > 16384,\n notes: [\n \"Resolution is ~1 Hz per bin (coarser musically at low frequencies — a semitone near 80 Hz is <5 Hz).\",\n \"No octave/harmonic correction: a strong overtone can be picked instead of the fundamental, or the fundamental's octave reported.\",\n \"Monophonic only — a chord/polyphonic input yields whichever partial is loudest, not a meaningful single pitch.\",\n \"Threshold default (0.02) and Sensitivity (1.0) are starting guesses; tune live against the real source.\",\n ],\n },\n });\n });\n}\n\nexport const registerDetectPitch: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"detect_pitch\",\n {\n title: \"Detect pitch (experimental)\",\n description:\n \"EXPERIMENTAL monophonic pitch tracker. Estimates the dominant musical pitch of live audio and exposes pitch_hz (frequency in Hz), note (MIDI note number), and confidence (peak magnitude) on a Null CHOP — bind a colour/parameter to op('…/pitch/pitch')['pitch_hz'] to drive visuals from a melody. Built entirely from stock CHOPs (the Pitch CHOP isn't createable in this build): an Audio Spectrum CHOP in 1-sample-per-Hz mode, trimmed to a [min_hz, max_hz] search band, then an Analyze CHOP argmax (highestpeakindex) whose index IS the frequency. A Threshold knob mutes the pitch when nothing is clearly playing and a Sensitivity knob scales the magnitude. Source can be the live device (mic/line — may prompt for macOS permission), an audio file, a synthetic sine oscillator (for testing), or an existing CHOP. Caveats: ~1 Hz resolution, no harmonic/octave correction, monophonic only — approximate and best tuned live.\",\n inputSchema: detectPitchSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => detectPitchImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, type NetworkBuilder, runBuild } from \"./orchestration.js\";\n\nexport const extractAudioFeaturesSchema = z.object({\n source: z\n .enum([\"device\", \"file\", \"oscillator\", \"existing_chop\"])\n .default(\"device\")\n .describe(\n \"Audio source. 'device' = live microphone/line in (the real-world default; creating it may pop a one-time macOS microphone-permission dialog — click Allow). 'file' = an audio file. 'oscillator' = a synthetic tone, handy for testing without any device permission. 'existing_chop' = reuse a CHOP you already have.\",\n ),\n audio_file_path: z.string().optional().describe(\"Audio file path (source='file').\"),\n existing_chop_path: z\n .string()\n .optional()\n .describe(\"Path of an existing audio CHOP to analyze (source='existing_chop').\"),\n bass_hz: z.coerce.number().positive().default(200).describe(\"Low-pass cutoff for the bass band.\"),\n mid_hz: z.coerce.number().positive().default(1500).describe(\"Band-pass centre for the mid band.\"),\n treble_hz: z.coerce\n .number()\n .positive()\n .default(4000)\n .describe(\"High-pass cutoff for the treble band.\"),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose a live 'Sensitivity' knob (a gain over every feature channel).\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype ExtractAudioFeaturesArgs = z.infer<typeof extractAudioFeaturesSchema>;\n\nasync function buildSource(\n builder: NetworkBuilder,\n args: ExtractAudioFeaturesArgs,\n): Promise<string> {\n if (args.source === \"existing_chop\" && args.existing_chop_path) {\n return args.existing_chop_path;\n }\n if (args.source === \"file\") {\n return builder.add(\"audiofileinCHOP\", \"audioin\", {\n ...(args.audio_file_path ? { file: args.audio_file_path } : {}),\n play: 1,\n });\n }\n if (args.source === \"oscillator\") {\n // White noise has energy across all bands, so bass/mid/treble all read non-zero —\n // a self-contained signal for verifying the chain without any audio device.\n return builder.add(\"audiooscillatorCHOP\", \"audioin\", { wavetype: \"whitenoise\", amp: 0.5 });\n }\n return builder.add(\"audiodeviceinCHOP\", \"audioin\");\n}\n\n/** A band = audio filter → RMS analyze, with the output channel renamed to the band name. */\nasync function buildBand(\n builder: NetworkBuilder,\n source: string,\n name: string,\n filter: \"lowpass\" | \"bandpass\" | \"highpass\",\n cutoffHz: number,\n): Promise<string> {\n const filt = await builder.add(\"audiofilterCHOP\", `${name}_filter`, {\n filter,\n units: \"frequency\",\n cutofffrequency: cutoffHz,\n });\n await builder.connect(source, filt);\n const analyze = await builder.add(\"analyzeCHOP\", name, {\n function: \"rmspower\",\n renamefrom: \"*\",\n renameto: name,\n });\n await builder.connect(filt, analyze);\n return analyze;\n}\n\nexport async function extractAudioFeaturesImpl(ctx: ToolContext, args: ExtractAudioFeaturesArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"audio_features\");\n const source = await buildSource(builder, args);\n\n // Overall loudness (RMS of the full-band signal), then three band energies.\n const level = await builder.add(\"analyzeCHOP\", \"level\", {\n function: \"rmspower\",\n renamefrom: \"*\",\n renameto: \"level\",\n });\n await builder.connect(source, level);\n const bass = await buildBand(builder, source, \"bass\", \"lowpass\", args.bass_hz);\n const mid = await buildBand(builder, source, \"mid\", \"bandpass\", args.mid_hz);\n const treble = await buildBand(builder, source, \"treble\", \"highpass\", args.treble_hz);\n\n // Merge the four single-channel CHOPs into one, then a Sensitivity gain, then a Null as\n // the stable bind point. Other tools/expressions read op('…/features')['bass'] etc.\n const merge = await builder.add(\"mergeCHOP\", \"merged\");\n await builder.connect(level, merge, 0, 0);\n await builder.connect(bass, merge, 0, 1);\n await builder.connect(mid, merge, 0, 2);\n await builder.connect(treble, merge, 0, 3);\n\n const gain = await builder.add(\"mathCHOP\", \"sensitivity\", { gain: 1 });\n await builder.connect(merge, gain);\n const features = await builder.add(\"nullCHOP\", \"features\");\n await builder.connect(gain, features);\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"Sensitivity\",\n type: \"float\",\n min: 0,\n max: 8,\n default: 1,\n bind_to: [`${gain}.gain`],\n },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Extracted audio features (source: ${args.source}) → ${features} with channels level/bass/mid/treble. Bind a parameter to op('${features}')['bass'] (etc.) to make it react.`,\n builder,\n outputPath: features,\n // The output is a CHOP, not a TOP, so there is no image to capture.\n capturePreviewImage: false,\n controls,\n extra: {\n source: args.source,\n features_path: features,\n channels: [\"level\", \"bass\", \"mid\", \"treble\"],\n bands_hz: { bass: args.bass_hz, mid: args.mid_hz, treble: args.treble_hz },\n },\n });\n });\n}\n\nexport const registerExtractAudioFeatures: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"extract_audio_features\",\n {\n title: \"Extract audio features\",\n description:\n \"Build an audio-analysis chain that exposes ready-to-bind reactive channels — overall level plus bass/mid/treble band energies — on a Null CHOP. Unlike create_audio_reactive (which renders a spectrum visual), this produces the raw signals so you can drive ANY parameter: bind a node parameter to op('…/audio_features/features')['bass'] and it pulses with the music. A Sensitivity knob scales all channels. Source can be the live device (mic/line — may prompt for macOS permission), an audio file, a synthetic oscillator (for testing), or an existing CHOP.\",\n inputSchema: extractAudioFeaturesSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => extractAudioFeaturesImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { capturePreview } from \"../../feedback/previewCapture.js\";\nimport { guardTd, imageResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getPreviewSchema = z.object({\n node_path: z.string().describe(\"Path of the TOP node to capture.\"),\n width: z.coerce.number().int().positive().max(4096).default(640),\n height: z.coerce.number().int().positive().max(4096).default(360),\n});\ntype GetPreviewArgs = z.infer<typeof getPreviewSchema>;\n\nexport async function getPreviewImpl(ctx: ToolContext, args: GetPreviewArgs) {\n return guardTd(\n () => capturePreview(ctx.client, args.node_path, args.width, args.height),\n (preview) =>\n imageResult(\n preview.base64,\n preview.mimeType,\n `Preview of ${args.node_path} (${preview.width}×${preview.height}).`,\n ),\n );\n}\n\nexport const registerGetPreview: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_preview\",\n {\n title: \"Preview a TOP\",\n description: \"Capture a TOP node as an inline image so you can see what was created.\",\n inputSchema: getPreviewSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => getPreviewImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport type { ControlSpec } from \"../layer2/createControlPanel.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\n// SOP used when no model_path is supplied, so the network still builds and previews\n// with zero file dependencies (matches create_3d_scene's default primitive).\nconst FALLBACK_SOP = \"sphereSOP\";\n\nexport const importModelSchema = z.object({\n model_path: z\n .string()\n .optional()\n .describe(\n \"Path to a 3D model file (.obj/.fbx/.usd) read by a File In SOP. Omit to fall back to a default primitive so the network still builds and previews with no file dependency.\",\n ),\n rotate_y: z.coerce\n .number()\n .min(0)\n .max(360)\n .default(0)\n .describe(\"Initial rotation of the model around Y in degrees (exposed as the RotateY knob).\"),\n zoom: z.coerce\n .number()\n .min(1)\n .default(5)\n .describe(\"Camera distance from the model along Z (exposed as the Zoom knob).\"),\n scale: z.coerce\n .number()\n .positive()\n .default(1)\n .describe(\"Uniform scale applied to the model (1 = imported size).\"),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\"Expose live RotateY (spin), Zoom (camera distance) and Scale knobs.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype ImportModelArgs = z.infer<typeof importModelSchema>;\n\nexport async function importModelImpl(ctx: ToolContext, args: ImportModelArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"model\");\n\n // Geometry COMP (the builder clears its default torus). When a model_path is given we\n // feed a File In SOP into it; otherwise we drop in a default primitive so the COMP still\n // has something renderable. Either source SOP is flagged render + display so the COMP\n // renders it. The File In SOP reads the geometry file via its `file` parameter.\n const geo = await builder.add(\"geometryCOMP\", \"geo\");\n const hasModel = typeof args.model_path === \"string\" && args.model_path.length > 0;\n const source = hasModel\n ? await builder.add(\"fileinSOP\", \"model\", { file: args.model_path }, geo)\n : await builder.add(FALLBACK_SOP, \"model\", {}, geo);\n await builder.python(`_s = op(${q(source)})\\n_s.render = True\\n_s.display = True`);\n\n // Uniform scale + initial rotation live on the Geometry COMP's transform.\n const geoParams: Record<string, unknown> = { ry: args.rotate_y };\n if (args.scale !== 1) {\n geoParams.scale = args.scale;\n geoParams.sx = args.scale;\n geoParams.sy = args.scale;\n geoParams.sz = args.scale;\n }\n await builder.setParams(geo, geoParams);\n\n const cam = await builder.add(\"cameraCOMP\", \"cam\", { tz: args.zoom });\n const light = await builder.add(\"lightCOMP\", \"light\", { tx: 3, ty: 3, tz: 5 });\n // Render TOP reads its scene from parameters (not wires): camera, geometry, lights.\n const render = await builder.add(\"renderTOP\", \"render\", {\n camera: cam,\n geometry: geo,\n lights: light,\n });\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(render, out);\n\n const controls: ControlSpec[] = args.expose_controls\n ? [\n {\n name: \"RotateY\",\n type: \"float\",\n min: 0,\n max: 360,\n default: args.rotate_y,\n bind_to: [`${geo}.ry`],\n },\n {\n name: \"Zoom\",\n type: \"float\",\n min: 1,\n max: args.zoom * 3,\n default: args.zoom,\n bind_to: [`${cam}.tz`],\n },\n {\n name: \"Scale\",\n type: \"float\",\n min: 0.01,\n max: Math.max(2, args.scale * 3),\n default: args.scale,\n bind_to: [`${geo}.scale`],\n },\n ]\n : [];\n\n const sourceNote = hasModel\n ? `model \"${args.model_path}\"`\n : \"default primitive (no model_path)\";\n return finalize(ctx, {\n summary: `Imported ${sourceNote} rendered to ${out} — Geometry (File In SOP) + Camera + Light + Render TOP.`,\n builder,\n outputPath: out,\n controls,\n extra: {\n model_path: args.model_path,\n has_model: hasModel,\n rotate_y: args.rotate_y,\n zoom: args.zoom,\n scale: args.scale,\n source_sop: source,\n geometry: geo,\n camera: cam,\n render,\n output_path: out,\n },\n });\n });\n}\n\nexport const registerImportModel: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"import_model\",\n {\n title: \"Import 3D model\",\n description:\n \"Import a 3D model file (.obj/.fbx/.usd) and render it to a TOP: a File In SOP reading `model_path`, fed into a Geometry COMP, with a Camera, a Light, and a Render TOP output as a Null. Omit `model_path` to fall back to a default primitive so the network still builds with no dependencies. Exposes RotateY (spin), Zoom (camera distance) and Scale knobs — the imported-model sibling of create_3d_scene.\",\n inputSchema: importModelSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => importModelImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const listRecipesSchema = z.object({\n tag: z\n .string()\n .optional()\n .describe(\"Optional tag/keyword to filter recipes by (matches tags or name).\"),\n});\ntype ListRecipesArgs = z.infer<typeof listRecipesSchema>;\n\nexport function listRecipesImpl(ctx: ToolContext, args: ListRecipesArgs) {\n let recipes = ctx.recipes.list();\n if (args.tag) {\n const needle = args.tag.toLowerCase();\n recipes = recipes.filter(\n (r) =>\n r.name.toLowerCase().includes(needle) ||\n r.tags.some((t) => t.toLowerCase().includes(needle)),\n );\n }\n return structuredResult(`${recipes.length} recipe(s) available.`, {\n count: recipes.length,\n recipes,\n });\n}\n\nexport const registerListRecipes: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"list_recipes\",\n {\n title: \"List recipes\",\n description:\n \"List the built-in recipe library — ready-made network templates (feedback tunnel, particle galaxy, reaction-diffusion, projection mapping, …) with their id, name, tags and difficulty. Offline. Apply one with apply_recipe.\",\n inputSchema: listRecipesSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n (args) => listRecipesImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { createSystemContainer, finalize, runBuild } from \"./orchestration.js\";\n\nexport const scaffoldShowSchema = z.object({\n name: z.string().default(\"show\").describe(\"Name of the show container to create.\"),\n parent_path: z.string().default(\"/project1\"),\n});\ntype ScaffoldShowArgs = z.infer<typeof scaffoldShowSchema>;\n\nexport async function scaffoldShowImpl(ctx: ToolContext, args: ScaffoldShowArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, args.name);\n\n // A master output Null (where the mix lands) and a beat clock to drive reactivity — the\n // skeleton of a live show; the artist fills in scenes and wires them to the master.\n const master = await builder.add(\"nullTOP\", \"master\");\n const beat = await builder.add(\"beatCHOP\", \"beat\", {\n ramp: 1,\n pulse: 1,\n count: 1,\n beat: 1,\n bar: 1,\n bpm: 1,\n });\n const tempo = await builder.add(\"nullCHOP\", \"tempo\");\n await builder.connect(beat, tempo);\n\n return finalize(ctx, {\n summary: `Scaffolded a show at ${builder.containerPath}: a \"master\" output Null and a \"tempo\" beat clock. Next: build scenes (visual / generative / feedback / 3d / simulation), extract_audio_features for reactivity, create_layer_mixer into ${master}, store looks with manage_cue, and create_control_surface to play it.`,\n builder,\n outputPath: master,\n capturePreviewImage: false,\n extra: { show: builder.containerPath, master, tempo },\n });\n });\n}\n\nexport const registerScaffoldShow: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"scaffold_show\",\n {\n title: \"Scaffold a show\",\n description:\n \"Create a starting skeleton for a live show: a container with a 'master' output Null (where your mix lands) and a 'tempo' beat clock for reactivity. A blank-canvas starting point — then add scenes, audio features, a layer mixer into master, cues and a control surface.\",\n inputSchema: scaffoldShowSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => scaffoldShowImpl(ctx, args),\n );\n};\n\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n","import { z } from \"zod\";\nimport { friendlyTdError } from \"../../td-client/types.js\";\nimport { connectNodesViaBridge } from \"../layer2/connectHelper.js\";\nimport { jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { runBuild } from \"./orchestration.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nconst OUTPUT_MAP = {\n window: \"windowCOMP\",\n ndi: \"ndioutTOP\",\n syphon_spout: \"syphonspoutoutTOP\",\n record: \"moviefileoutTOP\",\n touch_out: \"touchoutTOP\",\n} as const;\n\nconst RESOLUTIONS = {\n \"720p\": [1280, 720],\n \"1080p\": [1920, 1080],\n \"4K\": [3840, 2160],\n} as const;\n\nexport const setupOutputSchema = z.object({\n source_path: z.string().describe(\"Path of the final TOP to output.\"),\n output_type: z.enum([\"window\", \"ndi\", \"syphon_spout\", \"record\", \"touch_out\"]).default(\"window\"),\n resolution: z.enum([\"720p\", \"1080p\", \"4K\"]).default(\"1080p\"),\n record_format: z.enum([\"mp4\", \"mov\", \"image_sequence\"]).optional(),\n parent_path: z.string().default(\"/project1\"),\n});\ntype SetupOutputArgs = z.infer<typeof setupOutputSchema>;\n\nexport async function setupOutputImpl(ctx: ToolContext, args: SetupOutputArgs) {\n return runBuild(async () => {\n const warnings: string[] = [];\n const node = await ctx.client.createNode({\n parent_path: args.parent_path,\n type: OUTPUT_MAP[args.output_type],\n name: `${args.output_type}_out`,\n });\n\n if (args.output_type === \"window\") {\n // windowCOMP references its source via the `winop` path parameter, which\n // works across COMP boundaries — no wire needed.\n const [width, height] = RESOLUTIONS[args.resolution];\n try {\n await ctx.client.executePythonScript(\n `w = op(${q(node.path)})\\nw.par.winop = ${q(args.source_path)}\\nw.par.winw = ${width}\\nw.par.winh = ${height}`,\n false,\n );\n } catch (err) {\n warnings.push(`Could not configure window: ${friendlyTdError(err)}`);\n }\n } else {\n // The other outputs need a real wired input. A direct wire fails when the\n // source lives in a different COMP (TD wires can't cross COMP boundaries),\n // so bridge it through a Select TOP that references the source by path.\n try {\n const select = await ctx.client.createNode({\n parent_path: args.parent_path,\n type: \"selectTOP\",\n name: `${args.output_type}_src`,\n });\n await ctx.client.updateNodeParameters(select.path, { top: args.source_path });\n await connectNodesViaBridge(ctx.client, select.path, node.path);\n } catch (err) {\n warnings.push(`Could not connect source to output: ${friendlyTdError(err)}`);\n }\n }\n\n if (args.output_type === \"record\" && args.record_format) {\n try {\n await ctx.client.updateNodeParameters(node.path, { type: args.record_format });\n } catch (err) {\n warnings.push(`Could not set record format: ${friendlyTdError(err)}`);\n }\n }\n\n return jsonResult(`Configured ${args.output_type} output for ${args.source_path}.`, {\n output: node.path,\n output_type: args.output_type,\n source_path: args.source_path,\n resolution: args.resolution,\n warnings,\n });\n });\n}\n\nexport const registerSetupOutput: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"setup_output\",\n {\n title: \"Set up output\",\n description:\n \"Route a TOP to an output: a display window, NDI stream, Syphon/Spout, a recording, or Touch Out.\",\n inputSchema: setupOutputSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => setupOutputImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\n/** Friendly waveform names → the lfoCHOP `wavetype` menu values. */\nconst WAVE_MAP = {\n sine: \"sin\",\n triangle: \"tri\",\n ramp: \"ramp\",\n square: \"square\",\n pulse: \"pulse\",\n random: \"normal\",\n} as const;\n\nexport const animateParameterSchema = z.object({\n targets: z\n .array(z.string())\n .min(1)\n .describe(\n \"Parameters to animate, each written as 'nodePath.parName' (e.g. '/project1/sys/blur1.size'). Each is switched to expression mode so it tracks the oscillator live.\",\n ),\n waveform: z\n .enum([\"sine\", \"triangle\", \"ramp\", \"square\", \"pulse\", \"random\"])\n .default(\"sine\")\n .describe(\"Oscillator shape. Every waveform sweeps the full min–max range.\"),\n min: z.coerce.number().default(0).describe(\"Low end of the value sweep.\"),\n max: z.coerce.number().default(1).describe(\"High end of the value sweep.\"),\n period_seconds: z.coerce\n .number()\n .positive()\n .default(4)\n .describe(\"Seconds for one full cycle (lower = faster).\"),\n container_path: z\n .string()\n .optional()\n .describe(\"Where to create the LFO CHOP; defaults to the first target's parent network.\"),\n name: z.string().default(\"lfo_anim\").describe(\"Name for the LFO CHOP.\"),\n});\ntype AnimateParameterArgs = z.infer<typeof animateParameterSchema>;\n\ninterface AnimateReport {\n lfo?: string;\n container?: string;\n channel?: string;\n frequency?: number;\n targets_bound: string[];\n warnings: string[];\n fatal?: string;\n}\n\n// One Python pass creates the lfoCHOP and binds each target parameter to its channel\n// value by expression. `ParMode` is not in the bridge's exec globals, so the\n// expression-mode enum is derived from a live parameter (`type(par.mode)`).\nconst ANIMATE_SCRIPT = `\nimport json, base64, traceback\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nreport = {\"targets_bound\": [], \"warnings\": []}\ntry:\n _targets = _p[\"targets\"]\n _first = _targets[0]; _dot0 = _first.rfind(\".\")\n if _dot0 <= 0:\n report[\"fatal\"] = \"Invalid target '%s' (expected 'nodePath.parName').\" % _first\n else:\n _np0 = _first[:_dot0]; _firstnode = op(_np0)\n if _firstnode is None:\n report[\"fatal\"] = \"Target node not found: %s\" % _np0\n else:\n _cont = _p.get(\"container\") or _firstnode.parent().path\n _parent = op(_cont)\n if _parent is None:\n report[\"fatal\"] = \"Container not found: %s\" % _cont\n else:\n _lfo = _parent.create(lfoCHOP, _p[\"name\"])\n _lfo.par.wavetype = _p[\"wavetype\"]\n _lfo.par.frequency = _p[\"frequency\"]\n _lfo.par.amp = _p[\"amp\"]\n _lfo.par.offset = _p[\"offset\"]\n _ch = _lfo.par.channelname.eval() or \"chan1\"\n report[\"lfo\"] = _lfo.path; report[\"container\"] = _cont\n report[\"channel\"] = _ch; report[\"frequency\"] = _p[\"frequency\"]\n for _t in _targets:\n try:\n _dot = _t.rfind(\".\")\n if _dot <= 0:\n report[\"warnings\"].append(\"Invalid target '%s' (expected 'nodePath.parName').\" % _t); continue\n _npth = _t[:_dot]; _pn = _t[_dot + 1:]; _tn = op(_npth)\n if _tn is None:\n report[\"warnings\"].append(\"Target node not found: %s\" % _npth); continue\n _tp = getattr(_tn.par, _pn, None)\n if _tp is None:\n report[\"warnings\"].append(\"Target parameter not found: %s.%s\" % (_npth, _pn)); continue\n _PM = type(_tp.mode)\n _tp.expr = \"op(%s)[%s]\" % (repr(_lfo.path), repr(_ch))\n _tp.mode = _PM.EXPRESSION\n report[\"targets_bound\"].append(_npth + \".\" + _pn)\n except Exception:\n report[\"warnings\"].append(\"Failed to bind '%s': %s\" % (_t, traceback.format_exc().splitlines()[-1]))\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildAnimateScript(payload: object): string {\n return buildPayloadScript(ANIMATE_SCRIPT, payload);\n}\n\n// lfoCHOP wave shapes are not uniformly bipolar: sin/tri/square swing [-1, 1],\n// but ramp/pulse/random(normal) output [0, 1] (verified live, build 2025.32820).\n// amp/offset must branch on that, else unipolar waves only sweep [midpoint, max].\nconst BIPOLAR_WAVEFORMS = new Set([\"sine\", \"triangle\", \"square\"]);\n\nexport async function animateParameterImpl(ctx: ToolContext, args: AnimateParameterArgs) {\n const span = args.max - args.min;\n const bipolar = BIPOLAR_WAVEFORMS.has(args.waveform);\n const amp = bipolar ? span / 2 : span;\n const offset = bipolar ? (args.max + args.min) / 2 : args.min;\n const frequency = 1 / args.period_seconds;\n return guardTd(\n async () => {\n const script = buildAnimateScript({\n targets: args.targets,\n name: args.name,\n wavetype: WAVE_MAP[args.waveform],\n frequency,\n amp,\n offset,\n container: args.container_path ?? null,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<AnimateReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Could not set up animation: ${report.fatal}`, report);\n }\n const summary = `Animating ${report.targets_bound.length} parameter(s) with a ${args.waveform} LFO (period ${args.period_seconds}s, range ${args.min}–${args.max}) at ${report.lfo}${\n report.warnings.length ? `, ${report.warnings.length} warning(s)` : \"\"\n }.`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerAnimateParameter: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"animate_parameter\",\n {\n title: \"Animate parameter\",\n description:\n \"Drive one or more node parameters over time with an LFO (sine/triangle/ramp/square/pulse/random). Creates an LFO CHOP and binds each target so it oscillates between min and max with the given period — movement without manual keyframing.\",\n inputSchema: animateParameterSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => animateParameterImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { computeLayoutByParent, layoutScript } from \"../layout.js\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const arrangeNetworkSchema = z.object({\n path: z\n .string()\n .describe(\"COMP whose children to arrange, e.g. '/project1' or a container path.\"),\n recursive: z\n .boolean()\n .default(false)\n .describe(\"Also arrange the nodes inside nested COMPs (each network is tidied on its own).\"),\n});\ntype ArrangeNetworkArgs = z.infer<typeof arrangeNetworkSchema>;\n\nexport async function arrangeNetworkImpl(ctx: ToolContext, args: ArrangeNetworkArgs) {\n return guardTd(\n async () => {\n const topology = await ctx.client.getNetworkTopology(args.path, args.recursive);\n const nodes = topology.nodes.map((n) => n.path);\n const edges = topology.connections.map((c) => ({ from: c.source_path, to: c.target_path }));\n const positions = computeLayoutByParent(nodes, edges);\n if (nodes.length > 0) {\n await ctx.client.executePythonScript(layoutScript(positions), false);\n }\n return Object.keys(positions).length;\n },\n (arranged) =>\n jsonResult(\n arranged === 0\n ? `No nodes to arrange under ${args.path}.`\n : `Arranged ${arranged} node(s) under ${args.path} into a left→right data-flow layout.`,\n { path: args.path, arranged, recursive: args.recursive },\n ),\n );\n}\n\nexport const registerArrangeNetwork: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"arrange_network\",\n {\n title: \"Arrange network layout\",\n description:\n \"Tidy an existing network: reposition a COMP's children into a readable left→right data-flow layout (sources on the left, output on the right). Use this to clean up nodes that are piled on top of each other. Set recursive to also arrange the contents of nested COMPs.\",\n inputSchema: arrangeNetworkSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => arrangeNetworkImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const bindToChannelSchema = z.object({\n targets: z\n .array(z.string())\n .min(1)\n .describe(\n \"Parameters to drive, each written as 'nodePath.parName' (e.g. '/project1/sys/transform1.scale'). Each is switched to expression mode so it tracks the channel live.\",\n ),\n source_chop: z\n .string()\n .describe(\"Path of the CHOP that carries the driving channel (e.g. an audio_features Null).\"),\n channel: z\n .string()\n .describe(\"Channel name to read from the source CHOP (e.g. 'bass', 'level', 'ramp', 'pulse').\"),\n scale: z.coerce.number().default(1).describe(\"Multiply the channel value (mapping gain).\"),\n offset: z.coerce.number().default(0).describe(\"Add to the scaled value (mapping offset).\"),\n attack: z.coerce\n .number()\n .min(0)\n .optional()\n .describe(\n \"Smoothing rise time in seconds — how slowly the bound value follows the channel UP. 0 = instant (no smoothing on the way up). A small attack with a larger release gives a snappy hit that decays smoothly (envelope follow).\",\n ),\n release: z.coerce\n .number()\n .min(0)\n .optional()\n .describe(\n \"Smoothing fall time in seconds — how slowly the bound value follows the channel DOWN. 0 = instant (no smoothing on the way down). Set release > attack to remove flicker while keeping transients punchy.\",\n ),\n smooth: z.coerce\n .number()\n .min(0)\n .optional()\n .describe(\n \"Convenience: symmetric smoothing time in seconds applied to BOTH rise and fall (sets attack=release=smooth). Use this for simple low-pass-style de-jitter; use attack/release separately for an envelope follower.\",\n ),\n smoothing_container: z\n .string()\n .optional()\n .describe(\n \"Where to create the Select+Lag smoothing CHOPs when smoothing is active; defaults to the first target's parent network. Ignored when no smoothing is requested.\",\n ),\n});\ntype BindToChannelArgs = z.infer<typeof bindToChannelSchema>;\n\ninterface BindReport {\n bound: string[];\n expression?: string;\n channel_present?: boolean;\n smoothed?: boolean;\n smoothing_select?: string;\n smoothing_lag?: string;\n attack?: number;\n release?: number;\n warnings: string[];\n fatal?: string;\n}\n\n// One Python pass: build the expression op('chop')['chan'] (* scale) (+ offset) and switch\n// each target parameter to expression mode tracking it. ParMode isn't in the exec globals,\n// so the expression-mode enum is derived from a live parameter (type(par.mode)), mirroring\n// animate_parameter.\n//\n// Optional smoothing (attack/release > 0): instead of reading the raw channel, insert a\n// Select CHOP that isolates the single source channel (by absolute path — no cross-container\n// wire needed) feeding a Lag CHOP (lag1=attack, lag2=release, lagunit=seconds). The bind\n// expression then references the LAGGED channel, so a fast attack + slow release follows the\n// audio envelope smoothly instead of flickering on the raw value. This mirrors the lag\n// primitive chain in detect_onsets. The smoothing nodes are created in the first target's\n// parent network (overridable) — near what they drive — and read the source by absolute path.\nconst BIND_SCRIPT = `\nimport json, base64, traceback\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nreport = {\"bound\": [], \"warnings\": []}\ntry:\n _src = _p[\"source_chop\"]; _ch = _p[\"channel\"]\n _scale = _p[\"scale\"]; _offset = _p[\"offset\"]\n _lag1 = _p[\"lag1\"]; _lag2 = _p[\"lag2\"]; _smooth = (_lag1 > 0 or _lag2 > 0)\n _srcop = op(_src)\n if _srcop is None:\n report[\"fatal\"] = \"Source CHOP not found: %s\" % _src\n else:\n try:\n report[\"channel_present\"] = _ch in [c.name for c in _srcop.chans()]\n except Exception:\n report[\"channel_present\"] = None\n if report.get(\"channel_present\") is False:\n report[\"warnings\"].append(\"Channel '%s' not present on %s yet; binding anyway (it will track once it exists).\" % (_ch, _src))\n # The CHOP+channel the expression reads from: the raw source by default, or the\n # lagged null when smoothing is on. Built before the target loop so every target\n # binds to the same (possibly smoothed) channel.\n _read_op = _src; _read_ch = _ch\n report[\"smoothed\"] = False\n if _smooth:\n # Resolve a container for the smoothing nodes: explicit override, else the\n # first target's parent network (so the lag lives beside what it drives).\n _cont = _p.get(\"smoothing_container\")\n if not _cont:\n _first = _p[\"targets\"][0]; _fdot = _first.rfind(\".\")\n _fnode = op(_first[:_fdot]) if _fdot > 0 else None\n _cont = _fnode.parent().path if _fnode is not None else \"/project1\"\n _parent = op(_cont)\n if _parent is None:\n report[\"warnings\"].append(\"Smoothing container not found: %s; binding to the raw channel instead.\" % _cont)\n else:\n # Select CHOP isolates the single source channel by absolute path (expressions\n # eval relative to PARENT, so an absolute path is required and no cross-container\n # wire is needed). Lag CHOP then smooths that one channel: lag1=attack rise,\n # lag2=release fall, in seconds. Channel name survives, so the bind reads it back.\n _sel = _parent.create(selectCHOP, _p[\"select_name\"])\n _sel.par.chop = _src\n _sel.par.channames = _ch\n _lag = _parent.create(lagCHOP, _p[\"lag_name\"])\n _lag.inputConnectors[0].connect(_sel)\n _lag.par.lagunit = \"seconds\"\n _lag.par.lag1 = _lag1\n _lag.par.lag2 = _lag2\n _read_op = _lag.path; _read_ch = _ch\n report[\"smoothed\"] = True\n report[\"smoothing_select\"] = _sel.path\n report[\"smoothing_lag\"] = _lag.path\n report[\"attack\"] = _lag1; report[\"release\"] = _lag2\n _expr = \"op(%s)[%s]\" % (repr(_read_op), repr(_read_ch))\n if _scale != 1:\n _expr = \"(%s) * %s\" % (_expr, repr(_scale))\n if _offset != 0:\n _expr = \"%s + %s\" % (_expr, repr(_offset))\n report[\"expression\"] = _expr\n for _t in _p[\"targets\"]:\n try:\n _dot = _t.rfind(\".\")\n if _dot <= 0:\n report[\"warnings\"].append(\"Invalid target '%s' (expected 'nodePath.parName').\" % _t); continue\n _np = _t[:_dot]; _pn = _t[_dot + 1:]; _n = op(_np)\n if _n is None:\n report[\"warnings\"].append(\"Target node not found: %s\" % _np); continue\n _par = getattr(_n.par, _pn, None)\n if _par is None:\n report[\"warnings\"].append(\"Target parameter not found: %s\" % _t); continue\n _PM = type(_par.mode)\n _par.expr = _expr; _par.mode = _PM.EXPRESSION\n report[\"bound\"].append(_t)\n except Exception:\n report[\"warnings\"].append(\"Failed to bind '%s': %s\" % (_t, traceback.format_exc().splitlines()[-1]))\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildBindScript(payload: object): string {\n return buildPayloadScript(BIND_SCRIPT, payload);\n}\n\nexport async function bindToChannelImpl(ctx: ToolContext, args: BindToChannelArgs) {\n // `smooth` is a convenience for symmetric attack=release; explicit attack/release win\n // when given. Resolving to lag1/lag2 here keeps the Python pass simple and means the\n // no-smoothing case (both 0) reproduces the original raw-channel bind byte-for-byte.\n // The `?? 0` makes a missing attack/release (e.g. unparsed args) behave as off, matching\n // the schema defaults, so the Python `_lag1 > 0` test never sees a missing key.\n const lag1 = args.smooth ?? args.attack ?? 0;\n const lag2 = args.smooth ?? args.release ?? 0;\n return guardTd(\n async () => {\n const script = buildBindScript({\n targets: args.targets,\n source_chop: args.source_chop,\n channel: args.channel,\n scale: args.scale,\n offset: args.offset,\n lag1,\n lag2,\n select_name: `${args.channel}_sel`,\n lag_name: `${args.channel}_lag`,\n smoothing_container: args.smoothing_container ?? null,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<BindReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Could not bind to channel: ${report.fatal}`, report);\n }\n const smoothNote = report.smoothed\n ? ` with smoothing (attack ${report.attack}s / release ${report.release}s via ${report.smoothing_lag})`\n : \"\";\n const summary = `Bound ${report.bound.length} parameter(s) to ${args.source_chop}['${args.channel}']${smoothNote} (${report.expression})${\n report.warnings.length ? `, ${report.warnings.length} warning(s)` : \"\"\n }.`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerBindToChannel: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"bind_to_channel\",\n {\n title: \"Bind parameter to channel\",\n description:\n \"Drive one or more node parameters from a CHOP channel by expression — the link that makes a visual react. Point it at an audio_features channel (bass/mid/treble/level) or a tempo_sync channel (ramp/pulse/beat) with a scale and offset, and each target parameter tracks that signal live. This is how you wire extract_audio_features / create_tempo_sync into a visual system. Optionally add attack/release smoothing (in seconds) — or a single `smooth` time — to insert a Lag CHOP between the channel and the parameter so reactivity follows a clean envelope instead of flickering on raw audio (e.g. a fast attack + slow release for a punchy hit that decays smoothly).\",\n inputSchema: bindToChannelSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => bindToChannelImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { connectNodesViaBridge } from \"./connectHelper.js\";\n\nexport const connectNodesSchema = z.object({\n source_path: z.string().describe(\"Path of the source node (output side).\"),\n target_path: z.string().describe(\"Path of the target node (input side).\"),\n source_output: z.number().int().nonnegative().default(0),\n target_input: z.number().int().nonnegative().default(0),\n});\ntype ConnectNodesArgs = z.infer<typeof connectNodesSchema>;\n\nexport async function connectNodesImpl(ctx: ToolContext, args: ConnectNodesArgs) {\n return guardTd(\n () =>\n connectNodesViaBridge(\n ctx.client,\n args.source_path,\n args.target_path,\n args.source_output,\n args.target_input,\n ),\n (result) =>\n jsonResult(`Connected ${args.source_path} → ${args.target_path} (via ${result.method}).`, {\n source: args.source_path,\n target: args.target_path,\n source_output: args.source_output,\n target_input: args.target_input,\n method: result.method,\n }),\n );\n}\n\nexport const registerConnectNodes: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"connect_nodes\",\n {\n title: \"Connect two nodes\",\n description:\n \"Wire one node's output into another node's input. Uses the batch endpoint when available, with a Python fallback.\",\n inputSchema: connectNodesSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => connectNodesImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { MORPH_HOOK } from \"./manageCue.js\";\n\nexport const createClipLauncherSchema = z.object({\n comp_path: z\n .string()\n .default(\"/project1\")\n .describe(\n \"Control COMP that holds the cues (manage_cue) and custom params. The launcher panel is built inside it and its buttons fire that COMP's cues.\",\n ),\n name: z.string().default(\"launcher\").describe(\"Name of the launcher panel container to build.\"),\n cues: z\n .array(z.string())\n .min(1)\n .describe(\n \"Cue names (stored with manage_cue) to lay out in the grid, in order. Each becomes a clip button labelled with its cue name.\",\n ),\n rows: z.coerce\n .number()\n .int()\n .positive()\n .optional()\n .describe(\"Grid row count. Defaults so rows*cols covers all cues (derived from cues length).\"),\n cols: z.coerce\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n \"Grid column count. Defaults to ceil(sqrt(cues)) when omitted (derived from cues length).\",\n ),\n morph_time: z.coerce\n .number()\n .min(0)\n .default(0)\n .describe(\n \"0 = each button jumps instantly to its cue; >0 = every button crossfades to its cue over this many seconds (eased morph, same engine as manage_cue).\",\n ),\n});\ntype CreateClipLauncherArgs = z.infer<typeof createClipLauncherSchema>;\n\ninterface LauncherReport {\n comp: string;\n launcher?: string;\n rows?: number;\n cols?: number;\n morph_time?: number;\n buttons: Array<{ button: string; cue: string }>;\n warnings: string[];\n fatal?: string;\n}\n\n// Fixed callback for the single Panel Execute DAT that watches every clip button. On a press\n// it looks the button up in the launcher's stored button→cue map and either snaps the cue's\n// values onto the control COMP or, when a morph time is set, writes a transition record and\n// kicks the cue_morph hook (the same engine manage_cue's recall/morph uses).\nconst LAUNCHER_BUTTON_CB = `import td\n\ndef onOffToOn(panelValue):\n btn = panelValue.owner\n surf = btn.parent()\n cmap = surf.fetch('tdmcp_launcher_cues', {})\n info = cmap.get(btn.path)\n if not info:\n return\n comp = op(info.get('comp'))\n if comp is None:\n return\n to = comp.fetch('tdmcp_cues', {}).get(info.get('cue'))\n if not to:\n return\n dur = info.get('dur', 0) or 0\n if dur > 0:\n frm = {}\n for k in to:\n pr = getattr(comp.par, k, None)\n if pr is not None:\n try:\n frm[k] = pr.eval()\n except Exception:\n pass\n comp.store('tdmcp_cue_transition', {'active': True, 'from': frm, 'to': to, 'start': td.absTime.seconds, 'duration': dur})\n h = comp.op('cue_morph')\n if h is not None:\n h.par.active = True\n else:\n for k, v in to.items():\n pr = getattr(comp.par, k, None)\n if pr is not None and not pr.readOnly:\n try:\n pr.val = v\n except Exception:\n pass\n return\n`;\n\nconst LAUNCHER_SCRIPT = `\nimport json, base64, traceback\nimport td\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nreport = {\"comp\": _p[\"comp\"], \"warnings\": [], \"buttons\": []}\n_c = op(_p[\"comp\"])\ntry:\n if _c is None:\n report[\"fatal\"] = \"COMP not found: \" + _p[\"comp\"]\n elif not hasattr(_c, \"create\"):\n report[\"fatal\"] = _p[\"comp\"] + \" is not a COMP.\"\n else:\n _cues = _p.get(\"cues\", [])\n _cols = int(_p[\"cols\"]); _rows = int(_p[\"rows\"]); _dur = float(_p.get(\"morph_time\") or 0)\n _surf = _c.op(_p[\"name\"]) or _c.create(td.containerCOMP, _p[\"name\"])\n try:\n # Wrap the buttons into a grid of fixed column count, top-to-bottom rows.\n _surf.par.align = \"gridcols\"\n if hasattr(_surf.par, \"fixedcols\"):\n _surf.par.fixedcols = _cols\n if hasattr(_surf.par, \"w\"):\n _surf.par.w = _cols * 130\n if hasattr(_surf.par, \"h\"):\n _surf.par.h = _rows * 130\n except Exception:\n pass\n report[\"launcher\"] = _surf.path; report[\"rows\"] = _rows; report[\"cols\"] = _cols; report[\"morph_time\"] = _dur\n # A morph time needs the cue_morph Execute DAT (the manage_cue engine) running on the\n # control COMP so the per-frame transition can be animated.\n if _dur > 0:\n _hook = _c.op(\"cue_morph\") or _c.create(td.executeDAT, \"cue_morph\")\n _hook.text = _p[\"morph_hook\"]\n if hasattr(_hook.par, \"framestart\"):\n _hook.par.framestart = True\n _hook.par.active = True\n _cmap = {}\n _btn_paths = []\n for _cue in _cues:\n try:\n _bt = _surf.create(td.buttonCOMP)\n try:\n _bt.par.w = 120; _bt.par.h = 120\n _bt.par.label = _cue\n if hasattr(_bt.par, \"buttontype\"):\n _bt.par.buttontype = \"momentary\"\n except Exception:\n pass\n _cmap[_bt.path] = {\"comp\": _c.path, \"cue\": _cue, \"dur\": _dur}\n _btn_paths.append(_bt.path)\n report[\"buttons\"].append({\"button\": _bt.path, \"cue\": _cue})\n except Exception:\n report[\"warnings\"].append(\"Clip button failed: \" + traceback.format_exc().splitlines()[-1])\n if _btn_paths:\n _surf.store(\"tdmcp_launcher_cues\", _cmap)\n _pe = _surf.op(\"clip_dispatch\") or _surf.create(td.panelexecuteDAT, \"clip_dispatch\")\n _pe.text = _p[\"button_cb\"]\n try:\n _pe.par.panels = \" \".join(_btn_paths)\n if hasattr(_pe.par, \"offtoon\"):\n _pe.par.offtoon = True\n _pe.par.active = True\n except Exception:\n report[\"warnings\"].append(\"Could not wire the clip dispatcher.\")\n else:\n report[\"warnings\"].append(\"No clip buttons were created.\")\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildLauncherScript(payload: object): string {\n return buildPayloadScript(LAUNCHER_SCRIPT, payload);\n}\n\n/** Resolves the grid dimensions from explicit rows/cols or derives a near-square grid. */\nfunction resolveGrid(count: number, rows?: number, cols?: number): { rows: number; cols: number } {\n if (cols && rows) return { rows, cols };\n if (cols) return { cols, rows: Math.ceil(count / cols) };\n if (rows) return { rows, cols: Math.ceil(count / rows) };\n const c = Math.ceil(Math.sqrt(count));\n return { cols: c, rows: Math.ceil(count / c) };\n}\n\nexport async function createClipLauncherImpl(ctx: ToolContext, args: CreateClipLauncherArgs) {\n const { rows, cols } = resolveGrid(args.cues.length, args.rows, args.cols);\n return guardTd(\n async () => {\n const script = buildLauncherScript({\n comp: args.comp_path,\n name: args.name,\n cues: args.cues,\n rows,\n cols,\n morph_time: args.morph_time,\n morph_hook: MORPH_HOOK,\n button_cb: LAUNCHER_BUTTON_CB,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<LauncherReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Could not build clip launcher: ${report.fatal}`, report);\n }\n const mode =\n (report.morph_time ?? 0) > 0 ? `morphing over ${report.morph_time}s` : \"instant recall\";\n const summary = `Built clip launcher ${report.launcher} — ${report.buttons.length} clip(s) in a ${report.rows}×${report.cols} grid (${mode})${\n report.warnings.length ? `, ${report.warnings.length} warning(s)` : \"\"\n }.`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerCreateClipLauncher: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_clip_launcher\",\n {\n title: \"Create clip launcher\",\n description:\n \"Build an Ableton-style clip launcher: a grid panel (Container COMP) of clip buttons, one per named cue (from manage_cue), for fast hands-on scene switching during a live set. Open the container in Perform/Panel mode and tap a clip to fire its cue — instantly, or (with morph_time) crossfading to it over N seconds (eased, the same engine manage_cue uses). Store the cues with manage_cue / create_control_panel first.\",\n inputSchema: createClipLauncherSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createClipLauncherImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const manageCueSchema = z.object({\n action: z\n .enum([\"store\", \"recall\", \"morph\", \"list\", \"delete\"])\n .describe(\n \"store a cue (snapshot of the COMP's custom params), recall it instantly, morph to it over time, list, or delete.\",\n ),\n comp_path: z\n .string()\n .default(\"/project1\")\n .describe(\"COMP whose custom-parameter values the cue captures (a control-panel container).\"),\n name: z.string().optional().describe(\"Cue name (required for store/recall/morph/delete).\"),\n duration: z.coerce\n .number()\n .positive()\n .default(2)\n .describe(\"(morph) Crossfade time in seconds from the current look to the cue.\"),\n quantize: z\n .enum([\"off\", \"beat\", \"bar\"])\n .optional()\n .describe(\n \"(recall/morph) Snap the scene change to the music. 'off' (the default) fires immediately. 'beat' defers the recall/morph until the next beat boundary; 'bar' until the next bar (measure) boundary — read from the project tempo (op('/').time.tempo) and time signature. The change is scheduled, not blocking.\",\n ),\n});\ntype ManageCueArgs = z.infer<typeof manageCueSchema>;\n\ninterface CueReport {\n action: string;\n comp: string;\n name?: string;\n cues?: string[];\n captured?: string[];\n restored?: string[];\n morphing?: string[];\n duration?: number;\n deleted?: string;\n quantize?: \"beat\" | \"bar\";\n scheduled_in?: number;\n warnings: string[];\n fatal?: string;\n}\n\n// Execute DAT body (runs in TD's normal op context). Each frame, if a transition is active\n// it eases the COMP's custom params from the stored `from` values to the cue's `to` values\n// (smoothstep), then deactivates itself when done. Numeric params are interpolated; any\n// non-numeric ones snap at the end.\nexport const MORPH_HOOK = `import td\n\ndef onFrameStart(frame):\n comp = me.parent()\n st = comp.fetch('tdmcp_cue_transition', None)\n if not st or not st.get('active'):\n return\n now = td.absTime.seconds\n start = st.get('start', now)\n # Beat-quantized recalls/morphs schedule a future start (the next beat/bar in absTime\n # seconds). Until that boundary arrives, leave the look completely untouched so the\n # scene change snaps to the music instead of easing early. Records written by an\n # immediate (quantize 'off') recall/morph always have start <= now, so this never\n # fires for them — current behavior is unchanged.\n if now < start:\n return\n dur = st.get('duration') or 0.0001\n t = (now - start) / dur\n if t < 0:\n t = 0.0\n done = t >= 1.0\n if done:\n t = 1.0\n e = t * t * (3.0 - 2.0 * t)\n frm = st.get('from', {})\n to = st.get('to', {})\n for k, vt in to.items():\n try:\n par = getattr(comp.par, k, None)\n if par is None or par.readOnly:\n continue\n vf = frm.get(k, vt)\n if isinstance(vt, (int, float)) and isinstance(vf, (int, float)) and not isinstance(vt, bool):\n val = vf + (vt - vf) * e\n par.val = int(round(val)) if getattr(par, 'style', '') == 'Int' else val\n elif done:\n par.val = vt\n except Exception:\n pass\n if done:\n st['active'] = False\n comp.store('tdmcp_cue_transition', st)\n return\n\ndef onFrameEnd(frame):\n return\n`;\n\n// One Python pass for store/recall/morph/list/delete. Cues live in the COMP's storage under\n// 'tdmcp_cues'. A morph writes a transition record to 'tdmcp_cue_transition' and ensures a\n// 'cue_morph' Execute DAT (its text passed in via the payload) is running to animate it.\nconst CUE_SCRIPT = `\nimport json, base64, traceback\nimport td\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nKEY = \"tdmcp_cues\"\nreport = {\"action\": _p[\"action\"], \"comp\": _p[\"comp\"], \"warnings\": []}\n_c = op(_p[\"comp\"])\n\ndef _next_boundary_delay(quant):\n # Seconds from now (in absTime) until the next beat/bar boundary, read from the project\n # timeline's tempo + signature. Returns 0.0 for 'off' or on any failure, so a quantize\n # that can't read the clock degrades to an immediate (current-behavior) change.\n if quant not in (\"beat\", \"bar\"):\n return 0.0\n try:\n _t = op('/').time\n _tempo = float(getattr(_t, 'tempo', 0.0) or 0.0)\n if _tempo <= 0.0:\n return 0.0\n _spb = 60.0 / _tempo # seconds per beat\n # Current musical position in beats. Prefer the timeline's own beat counter; fall\n # back to deriving it from elapsed timeline seconds when .beat isn't exposed.\n _beat = getattr(_t, 'beat', None)\n if _beat is None:\n _secs = float(getattr(_t, 'seconds', 0.0) or 0.0)\n _beat = _secs / _spb\n _beat = float(_beat)\n if quant == \"beat\":\n _period = 1.0\n else:\n _bpb = int(round(float(getattr(_t, 'signature1', 4) or 4)))\n if _bpb < 1:\n _bpb = 4\n _period = float(_bpb)\n _phase = _beat % _period # beats already elapsed into the current beat/bar\n _remaining = _period - _phase\n # On an exact boundary, snap to the *next* one rather than firing instantly.\n if _remaining <= 1e-6:\n _remaining = _period\n return _remaining * _spb\n except Exception:\n return 0.0\ntry:\n if _c is None:\n report[\"fatal\"] = \"COMP not found: \" + _p[\"comp\"]\n elif not hasattr(_c, \"customPars\"):\n report[\"fatal\"] = _p[\"comp\"] + \" is not a COMP, so it has no custom parameters to snapshot.\"\n else:\n _store = dict(_c.fetch(KEY, {}))\n _action = _p[\"action\"]; _name = _p.get(\"name\")\n if _action == \"list\":\n report[\"cues\"] = sorted(_store.keys())\n elif _action == \"store\":\n _vals = {}\n for _pr in _c.customPars:\n try:\n _vals[_pr.name] = _pr.eval()\n except Exception:\n pass\n _store[_name] = _vals; _c.store(KEY, _store)\n report[\"name\"] = _name; report[\"captured\"] = sorted(_vals.keys()); report[\"cues\"] = sorted(_store.keys())\n elif _action == \"delete\":\n if _name in _store:\n _store.pop(_name, None); _c.store(KEY, _store); report[\"deleted\"] = _name\n else:\n report[\"warnings\"].append(\"Cue not found: \" + str(_name))\n report[\"cues\"] = sorted(_store.keys())\n elif _action in (\"recall\", \"morph\"):\n if _name not in _store:\n report[\"fatal\"] = \"Cue not found: '%s' (available: %s)\" % (_name, \", \".join(sorted(_store.keys())) or \"none\")\n else:\n _to = _store[_name]\n _quant = _p.get(\"quantize\") or \"off\"\n _delay = _next_boundary_delay(_quant)\n if _action == \"recall\" and _delay <= 0.0:\n # Immediate recall (quantize 'off', or no readable tempo): snap params now.\n _restored = []\n for _k, _v in _to.items():\n _pr = getattr(_c.par, _k, None)\n if _pr is None or _pr.readOnly:\n report[\"warnings\"].append(\"skipped \" + _k); continue\n try:\n _pr.val = _v; _restored.append(_k)\n except Exception:\n report[\"warnings\"].append(\"could not set \" + _k)\n report[\"name\"] = _name; report[\"restored\"] = sorted(_restored)\n else:\n # Morph, OR a beat/bar-quantized recall. Both ride the frame-driven\n # transition engine: a quantized recall is just a snap (tiny duration)\n # scheduled at the next boundary; a morph eases over its duration. A\n # future start time keeps the look untouched until the boundary arrives.\n _from = {}\n for _k in _to.keys():\n _pr = getattr(_c.par, _k, None)\n if _pr is not None:\n try:\n _from[_k] = _pr.eval()\n except Exception:\n pass\n _dur = (_p.get(\"duration\") or 0.0001) if _action == \"morph\" else 0.0001\n _start = td.absTime.seconds + _delay\n _c.store(\"tdmcp_cue_transition\", {\"active\": True, \"from\": _from, \"to\": _to, \"start\": _start, \"duration\": _dur})\n _hook = _c.op(\"cue_morph\") or _c.create(td.executeDAT, \"cue_morph\")\n _hook.text = _p[\"morph_text\"]\n if hasattr(_hook.par, \"framestart\"):\n _hook.par.framestart = True\n _hook.par.active = True\n report[\"name\"] = _name\n if _action == \"morph\":\n report[\"morphing\"] = sorted(_from.keys()); report[\"duration\"] = _dur\n else:\n report[\"restored\"] = sorted(_from.keys())\n if _delay > 0.0:\n report[\"quantize\"] = _quant; report[\"scheduled_in\"] = round(_delay, 4)\n else:\n report[\"fatal\"] = \"Unknown action: \" + str(_action)\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildCueScript(payload: object): string {\n return buildPayloadScript(CUE_SCRIPT, payload);\n}\n\nexport async function manageCueImpl(ctx: ToolContext, args: ManageCueArgs) {\n if (args.action !== \"list\" && !args.name) {\n return errorResult(`A cue name is required for the '${args.action}' action.`);\n }\n return guardTd(\n async () => {\n const script = buildCueScript({\n action: args.action,\n comp: args.comp_path,\n name: args.name,\n duration: args.duration,\n quantize: args.quantize ?? \"off\",\n morph_text: MORPH_HOOK,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<CueReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Cue ${report.action} failed: ${report.fatal}`, report);\n }\n let summary: string;\n switch (report.action) {\n case \"store\":\n summary = `Stored cue \"${report.name}\" (${report.captured?.length ?? 0} control(s)) on ${report.comp}.`;\n break;\n case \"recall\":\n summary = report.quantize\n ? `Cue \"${report.name}\" (${report.restored?.length ?? 0} control(s)) will snap on ${report.comp} at the next ${report.quantize} (~${report.scheduled_in}s).`\n : `Recalled cue \"${report.name}\" (${report.restored?.length ?? 0} control(s)) on ${report.comp}.`;\n break;\n case \"morph\":\n summary = report.quantize\n ? `Morph to cue \"${report.name}\" over ${report.duration}s (${report.morphing?.length ?? 0} control(s)) on ${report.comp} starts at the next ${report.quantize} (~${report.scheduled_in}s).`\n : `Morphing to cue \"${report.name}\" over ${report.duration}s (${report.morphing?.length ?? 0} control(s)) on ${report.comp}.`;\n break;\n case \"delete\":\n summary = report.deleted\n ? `Deleted cue \"${report.deleted}\" on ${report.comp}.`\n : `No cue to delete on ${report.comp}.`;\n break;\n default:\n summary = `${report.cues?.length ?? 0} cue(s) on ${report.comp}: ${report.cues?.join(\", \") || \"none\"}.`;\n }\n if (report.warnings.length) summary += ` ${report.warnings.length} warning(s).`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerManageCue: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"manage_cue\",\n {\n title: \"Manage cue\",\n description:\n \"Live-performance scene system: store / recall / morph / list / delete named cues (snapshots of a COMP's custom-parameter values). Unlike manage_presets, a cue can be reached with a timed `morph` that crossfades every numeric control from the current look to the cue over N seconds (eased), via a small Execute DAT — so you can glide between looks on stage instead of hard-cutting. Recall and morph also take an optional `quantize` ('beat'/'bar') that defers the change to the next musical boundary (from the project tempo) so scene changes land on the downbeat. Build cues with create_control_panel, then jump or morph between them.\",\n inputSchema: manageCueSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => manageCueImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { placeBelowSiblingsScript } from \"../layout.js\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nconst COMP_MAP = {\n container: \"containerCOMP\",\n base: \"baseCOMP\",\n} as const;\n\nexport const createContainerSchema = z.object({\n parent_path: z.string().default(\"/project1\").describe(\"Parent COMP to create the container in.\"),\n name: z.string().optional(),\n comp_type: z\n .enum([\"container\", \"base\"])\n .default(\"container\")\n .describe(\"'container' (2D panel COMP) or 'base' (generic COMP).\"),\n});\ntype CreateContainerArgs = z.infer<typeof createContainerSchema>;\n\nexport async function createContainerImpl(ctx: ToolContext, args: CreateContainerArgs) {\n return guardTd(\n async () => {\n const node = await ctx.client.createNode({\n parent_path: args.parent_path,\n type: COMP_MAP[args.comp_type],\n name: args.name,\n });\n // Place it clear of existing siblings (cosmetic — never block creation).\n try {\n await ctx.client.executePythonScript(\n placeBelowSiblingsScript(args.parent_path, node.path),\n false,\n );\n } catch (err) {\n ctx.logger.debug(\"container placement skipped\", { err: String(err) });\n }\n return node;\n },\n (node) => jsonResult(`Created ${args.comp_type} COMP at ${node.path}.`, { node }),\n );\n}\n\nexport const registerCreateContainer: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_container\",\n {\n title: \"Create container COMP\",\n description: \"Create a self-contained COMP to hold a visual system.\",\n inputSchema: createContainerSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createContainerImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { MORPH_HOOK } from \"./manageCue.js\";\n\nconst faderSchema = z.object({\n param: z.string().describe(\"Parameter the fader drives, written as 'nodePath.parName'.\"),\n label: z.string().optional(),\n min: z.coerce.number().default(0).describe(\"Value at the bottom of the fader.\"),\n max: z.coerce.number().default(1).describe(\"Value at the top of the fader.\"),\n});\n\nconst cueButtonSchema = z.object({\n cue: z.string().describe(\"Name of a cue (stored with manage_cue) to fire.\"),\n label: z.string().optional(),\n morph_seconds: z.coerce\n .number()\n .min(0)\n .default(0)\n .describe(\"0 = jump instantly to the cue; >0 = crossfade over this many seconds.\"),\n});\n\nexport const createControlSurfaceSchema = z.object({\n comp_path: z\n .string()\n .default(\"/project1\")\n .describe(\n \"Control COMP that holds the cues (manage_cue) and custom params. The surface is built inside it and its buttons fire that COMP's cues.\",\n ),\n name: z.string().default(\"surface\").describe(\"Name of the panel container to build.\"),\n align: z\n .enum([\"horizlr\", \"verttb\", \"gridcols\", \"gridrows\", \"none\"])\n .default(\"horizlr\")\n .describe(\"How the panel lays out its widgets.\"),\n faders: z.array(faderSchema).default([]).describe(\"Vertical faders, each driving a parameter.\"),\n cue_buttons: z\n .array(cueButtonSchema)\n .default([])\n .describe(\"Buttons that recall or morph to named cues.\"),\n});\ntype CreateControlSurfaceArgs = z.infer<typeof createControlSurfaceSchema>;\n\ninterface SurfaceReport {\n comp: string;\n surface?: string;\n faders: Array<{ slider: string; param: string }>;\n cue_buttons: Array<{ button: string; cue: string; morph_seconds: number }>;\n warnings: string[];\n fatal?: string;\n}\n\n// Fixed callback for the single Panel Execute DAT that watches every cue button. On a\n// press it looks the button up in the surface's stored button→cue map and either snaps the\n// cue's values onto the control COMP or, when a morph time is set, writes a transition record\n// and kicks the cue_morph hook (the same engine manage_cue uses).\nconst SURFACE_BUTTON_CB = `import td\n\ndef onOffToOn(panelValue):\n btn = panelValue.owner\n surf = btn.parent()\n cmap = surf.fetch('tdmcp_surface_cues', {})\n info = cmap.get(btn.path)\n if not info:\n return\n comp = op(info.get('comp'))\n if comp is None:\n return\n to = comp.fetch('tdmcp_cues', {}).get(info.get('cue'))\n if not to:\n return\n dur = info.get('dur', 0) or 0\n if dur > 0:\n frm = {}\n for k in to:\n pr = getattr(comp.par, k, None)\n if pr is not None:\n try:\n frm[k] = pr.eval()\n except Exception:\n pass\n comp.store('tdmcp_cue_transition', {'active': True, 'from': frm, 'to': to, 'start': td.absTime.seconds, 'duration': dur})\n h = comp.op('cue_morph')\n if h is not None:\n h.par.active = True\n else:\n for k, v in to.items():\n pr = getattr(comp.par, k, None)\n if pr is not None and not pr.readOnly:\n try:\n pr.val = v\n except Exception:\n pass\n return\n`;\n\nconst SURFACE_SCRIPT = `\nimport json, base64, traceback\nimport td\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nreport = {\"comp\": _p[\"comp\"], \"warnings\": [], \"faders\": [], \"cue_buttons\": []}\n_c = op(_p[\"comp\"])\ntry:\n if _c is None:\n report[\"fatal\"] = \"COMP not found: \" + _p[\"comp\"]\n elif not hasattr(_c, \"create\"):\n report[\"fatal\"] = _p[\"comp\"] + \" is not a COMP.\"\n else:\n _surf = _c.op(_p[\"name\"]) or _c.create(td.containerCOMP, _p[\"name\"])\n try:\n _surf.par.align = _p[\"align\"]\n except Exception:\n pass\n report[\"surface\"] = _surf.path\n _buttons = _p.get(\"cue_buttons\", [])\n if any((b.get(\"morph_seconds\") or 0) > 0 for b in _buttons):\n _hook = _c.op(\"cue_morph\") or _c.create(td.executeDAT, \"cue_morph\")\n _hook.text = _p[\"morph_hook\"]\n if hasattr(_hook.par, \"framestart\"):\n _hook.par.framestart = True\n _hook.par.active = True\n for _f in _p.get(\"faders\", []):\n try:\n _path = _f[\"param\"]; _dot = _path.rfind(\".\")\n if _dot <= 0:\n report[\"warnings\"].append(\"Invalid fader target '%s'.\" % _path); continue\n _np = _path[:_dot]; _prn = _path[_dot + 1:]; _tn = op(_np)\n if _tn is None:\n report[\"warnings\"].append(\"Fader target node not found: \" + _np); continue\n _tp = getattr(_tn.par, _prn, None)\n if _tp is None:\n report[\"warnings\"].append(\"Fader target parameter not found: \" + _path); continue\n _lo = _f[\"min\"]; _hi = _f[\"max\"]\n _sl = _surf.create(td.sliderCOMP)\n try:\n _sl.par.w = 80; _sl.par.h = 240\n if _f.get(\"label\"):\n _sl.par.label = _f[\"label\"]\n except Exception:\n pass\n try:\n _cur = float(_tp.eval())\n _sl.par.value0 = max(0.0, min(1.0, (_cur - _lo) / (_hi - _lo))) if _hi > _lo else 0.0\n except Exception:\n pass\n _expr = \"%s + (%s) * op(%r).par.value0\" % (repr(_lo), repr(_hi - _lo), _sl.path)\n _PM = type(_tp.mode); _tp.expr = _expr; _tp.mode = _PM.EXPRESSION\n report[\"faders\"].append({\"slider\": _sl.path, \"param\": _path})\n except Exception:\n report[\"warnings\"].append(\"Fader failed: \" + traceback.format_exc().splitlines()[-1])\n _cmap = {}\n _btn_paths = []\n for _b in _buttons:\n try:\n _cue = _b[\"cue\"]; _dur = float(_b.get(\"morph_seconds\") or 0)\n _bt = _surf.create(td.buttonCOMP)\n try:\n _bt.par.w = 110; _bt.par.h = 240\n _bt.par.label = _b.get(\"label\") or _cue\n if hasattr(_bt.par, \"buttontype\"):\n _bt.par.buttontype = \"momentary\"\n except Exception:\n pass\n _cmap[_bt.path] = {\"comp\": _c.path, \"cue\": _cue, \"dur\": _dur}\n _btn_paths.append(_bt.path)\n report[\"cue_buttons\"].append({\"button\": _bt.path, \"cue\": _cue, \"morph_seconds\": _dur})\n except Exception:\n report[\"warnings\"].append(\"Cue button failed: \" + traceback.format_exc().splitlines()[-1])\n if _btn_paths:\n _surf.store(\"tdmcp_surface_cues\", _cmap)\n _pe = _surf.op(\"cue_dispatch\") or _surf.create(td.panelexecuteDAT, \"cue_dispatch\")\n _pe.text = _p[\"button_cb\"]\n try:\n _pe.par.panels = \" \".join(_btn_paths)\n if hasattr(_pe.par, \"offtoon\"):\n _pe.par.offtoon = True\n _pe.par.active = True\n except Exception:\n report[\"warnings\"].append(\"Could not wire the cue dispatcher.\")\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildSurfaceScript(payload: object): string {\n return buildPayloadScript(SURFACE_SCRIPT, payload);\n}\n\nexport async function createControlSurfaceImpl(ctx: ToolContext, args: CreateControlSurfaceArgs) {\n return guardTd(\n async () => {\n const script = buildSurfaceScript({\n comp: args.comp_path,\n name: args.name,\n align: args.align,\n faders: args.faders,\n cue_buttons: args.cue_buttons,\n morph_hook: MORPH_HOOK,\n button_cb: SURFACE_BUTTON_CB,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<SurfaceReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Could not build control surface: ${report.fatal}`, report);\n }\n const summary = `Built control surface ${report.surface} with ${report.faders.length} fader(s) and ${report.cue_buttons.length} cue button(s)${\n report.warnings.length ? `, ${report.warnings.length} warning(s)` : \"\"\n }.`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerCreateControlSurface: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_control_surface\",\n {\n title: \"Create control surface\",\n description:\n \"Build a playable performance panel (a Container COMP of visual widgets) for live use, beyond the parameter dialog: vertical faders that drive parameters, and buttons that recall or morph to named cues (from manage_cue). Open the container in Perform/Panel mode for a touchable surface — faders move their parameters, cue buttons fire scenes (instantly or with a crossfade).\",\n inputSchema: createControlSurfaceSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createControlSurfaceImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { createSystemContainer, finalize, runBuild } from \"../layer1/orchestration.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport type { ControlSpec } from \"./createControlPanel.js\";\n\nexport const createDecksSchema = z.object({\n deck_a: z\n .string()\n .optional()\n .describe(\n \"Absolute path of the source TOP for deck A (pulled in via a Select TOP, so it can live in another container). If omitted, a built-in test source (Noise TOP) is created so the mixer builds standalone.\",\n ),\n deck_b: z\n .string()\n .optional()\n .describe(\n \"Absolute path of the source TOP for deck B (pulled in via a Select TOP). If omitted, a built-in test source (Ramp TOP) is created so the mixer builds standalone.\",\n ),\n crossfade: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(0.5)\n .describe(\"Master crossfader position: 0 = full deck A, 1 = full deck B, 0.5 = even blend.\"),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\n \"Expose live 'Crossfader' + per-deck 'GainA'/'GainB' knobs on the container so the mix is playable on arrival.\",\n ),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreateDecksArgs = z.infer<typeof createDecksSchema>;\n\n/**\n * DJ-style two-deck VJ mixer. Each deck is a small labeled sub-chain — a Select TOP that\n * pulls its source (TD wires don't cross containers) into a per-deck Level TOP for\n * gain/opacity — and both decks feed a master Cross TOP whose `cross` parameter is the\n * crossfader (0 = A, 1 = B). A master Level TOP after the Cross gives a single output FX /\n * trim, terminating in a Null ready for post-processing or setup_output.\n */\nexport async function createDecksImpl(ctx: ToolContext, args: CreateDecksArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"decks\");\n\n // --- Deck A ---------------------------------------------------------------\n // Pull the source in (or drop in a distinct test source) → per-deck gain/opacity Level.\n const srcA = args.deck_a\n ? await builder.add(\"selectTOP\", \"deckA_src\", { top: args.deck_a })\n : await builder.add(\"noiseTOP\", \"deckA_src\");\n const deckA = await builder.add(\"levelTOP\", \"deckA_gain\", { brightness1: 1, opacity: 1 });\n await builder.connect(srcA, deckA);\n\n // --- Deck B ---------------------------------------------------------------\n const srcB = args.deck_b\n ? await builder.add(\"selectTOP\", \"deckB_src\", { top: args.deck_b })\n : await builder.add(\"rampTOP\", \"deckB_src\");\n const deckB = await builder.add(\"levelTOP\", \"deckB_gain\", { brightness1: 1, opacity: 1 });\n await builder.connect(srcB, deckB);\n\n // --- Master crossfader ----------------------------------------------------\n // Cross TOP blends input 0 (A) → input 1 (B). `cross` is the crossfader: 0 = A, 1 = B.\n const cross = await builder.add(\"crossTOP\", \"crossfader\", { cross: args.crossfade });\n await builder.connect(deckA, cross, 0, 0);\n await builder.connect(deckB, cross, 0, 1);\n\n // Master FX / output trim after the blend, then the output Null.\n const master = await builder.add(\"levelTOP\", \"master_fx\", { brightness1: 1, opacity: 1 });\n await builder.connect(cross, master);\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(master, out);\n\n const controls: ControlSpec[] = [];\n if (args.expose_controls) {\n controls.push(\n {\n name: \"Crossfader\",\n type: \"float\",\n min: 0,\n max: 1,\n default: args.crossfade,\n bind_to: [`${cross}.cross`],\n },\n {\n name: \"GainA\",\n label: \"Gain A\",\n type: \"float\",\n min: 0,\n max: 2,\n default: 1,\n bind_to: [`${deckA}.brightness1`],\n },\n {\n name: \"GainB\",\n label: \"Gain B\",\n type: \"float\",\n min: 0,\n max: 2,\n default: 1,\n bind_to: [`${deckB}.brightness1`],\n },\n );\n }\n\n return finalize(ctx, {\n summary: `Built DJ-style A/B decks with a crossfader (${args.crossfade}) → ${out}.`,\n builder,\n outputPath: out,\n capturePreviewImage: true,\n controls,\n extra: {\n deck_a: { source: srcA, gain: deckA, external: Boolean(args.deck_a) },\n deck_b: { source: srcB, gain: deckB, external: Boolean(args.deck_b) },\n crossfader: cross,\n master: master,\n crossfade: args.crossfade,\n output_path: out,\n },\n });\n });\n}\n\nexport const registerCreateDecks: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_decks\",\n {\n title: \"Create DJ-style A/B decks\",\n description:\n \"Build a DJ-style VJ mixer: deck A and deck B each pull in a source TOP (via a Select TOP, so sources can live anywhere) through a per-deck gain/opacity Level, and a master Crossfader (a Cross TOP, 0 = A, 1 = B) blends them, followed by a master FX Level and an output Null. Either deck falls back to a built-in test source (Noise for A, Ramp for B) so it builds standalone. Exposes live 'Crossfader' + per-deck 'GainA'/'GainB' knobs. Output is a Null ready for post-processing or setup_output.\",\n inputSchema: createDecksSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createDecksImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nconst bindSchema = z.object({\n channel: z\n .string()\n .describe(\n \"Channel name produced by the input (e.g. an OSC address tail 'fader1', or a MIDI channel name).\",\n ),\n target: z.string().describe(\"Parameter to drive, written as 'nodePath.parName'.\"),\n});\n\nexport const createExternalIoSchema = z.object({\n kind: z\n .enum([\n \"osc_in\",\n \"midi_in\",\n \"keyboard_in\",\n \"gamepad_in\",\n \"mouse_in\",\n \"osc_out\",\n \"midi_out\",\n \"dmx_out\",\n \"artnet_out\",\n \"rtmp_out\",\n \"ndi_in\",\n \"syphon_spout_in\",\n ])\n .describe(\n \"What to bridge: OSC/MIDI/keyboard/gamepad/mouse input (a control surface — bind channels to parameters), OSC/MIDI output (send a CHOP's channels back out for bidirectional feedback — pass source_path), DMX/Art-Net output for lighting (dmx_out is the general DMX desk; artnet_out is a network-only Art-Net/sACN preset for pixel-mapping LED strips & stage fixtures — both send a CHOP's 0-255 channels and need source_path), RTMP output to live-stream a TOP to Twitch/YouTube/OBS-ingest (rtmp_out — pass source_path = the TOP to stream and url; needs an NVIDIA GPU on Windows), or NDI / Syphon-Spout video input. (Window/recording/NDI/Syphon *video outputs* live in setup_output.)\",\n ),\n parent_path: z.string().default(\"/project1\").describe(\"COMP to create the I/O operator in.\"),\n name: z.string().optional(),\n port: z.coerce\n .number()\n .int()\n .optional()\n .describe(\"(osc_in) UDP port to listen on / (osc_out) port to send to. Defaults to 7000.\"),\n normalize: z\n .enum([\"off\", \"0to1\", \"-1to1\", \"onoff\"])\n .default(\"0to1\")\n .describe(\"(midi_in) How to scale incoming MIDI values.\"),\n bind_to: z\n .array(bindSchema)\n .optional()\n .describe(\n \"(osc_in/midi_in) Map incoming channels to parameters. Each binding tolerates a channel that hasn't arrived yet (falls back to 0 instead of erroring).\",\n ),\n source_path: z\n .string()\n .optional()\n .describe(\n \"(dmx_out/artnet_out/osc_out/midi_out) CHOP whose channel values are sent out, or (rtmp_out) the TOP to stream. Should live in the same COMP as parent_path so the wire/source connects.\",\n ),\n interface: z\n .enum([\"artnet\", \"sacn\", \"enttecusbpro\", \"enttecusbpromk2\", \"serial\", \"kinet\"])\n .default(\"artnet\")\n .describe(\"(dmx_out) DMX transport. (artnet_out forces a network protocol via `net`.)\"),\n net: z\n .enum([\"artnet\", \"sacn\"])\n .optional()\n .describe(\n \"(artnet_out) Network DMX protocol: Art-Net or sACN (streaming ACN). Defaults to Art-Net.\",\n ),\n universe: z.coerce.number().int().default(1).describe(\"(dmx_out/artnet_out) DMX universe.\"),\n net_address: z\n .string()\n .optional()\n .describe(\"(dmx_out/artnet_out) Target IP address for Art-Net / sACN.\"),\n url: z\n .string()\n .optional()\n .describe(\n \"(rtmp_out) Full RTMP destination as {service url}/{stream key}, e.g. 'rtmp://live.twitch.tv/app/live_xxx'. If omitted but stream_key is given, prefix with rtmp_base.\",\n ),\n rtmp_base: z\n .string()\n .optional()\n .describe(\n \"(rtmp_out) Ingest base URL to combine with stream_key when url is not given (defaults to YouTube's primary ingest).\",\n ),\n stream_key: z\n .string()\n .optional()\n .describe(\"(rtmp_out) Stream key, appended to rtmp_base as '{rtmp_base}/{stream_key}'.\"),\n fps: z.coerce.number().optional().describe(\"(rtmp_out) Frame rate to stream at. Defaults to 30.\"),\n active: z\n .boolean()\n .optional()\n .describe(\n \"(rtmp_out) Start streaming immediately. Defaults off so the artist can confirm the URL before going live.\",\n ),\n source_name: z\n .string()\n .optional()\n .describe(\"(ndi_in/syphon_spout_in) Name of the NDI source or Spout sender to receive.\"),\n});\ntype CreateExternalIoArgs = z.infer<typeof createExternalIoSchema>;\n\ninterface IoReport {\n kind: string;\n node?: string;\n type?: string;\n source?: string;\n bound?: Array<{ channel: string; target: string }>;\n errors?: string[];\n warnings: string[];\n fatal?: string;\n}\n\n// One Python pass creates and configures the right operator per kind. Control-surface\n// inputs (OSC/MIDI) bind channels to parameters with a guard so a channel that hasn't\n// arrived yet evaluates to 0 instead of leaving the target in an error state. The\n// expression-mode enum is derived from a live parameter (`ParMode` is not in scope here).\nconst IO_SCRIPT = `\nimport json, base64, traceback\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nreport = {\"kind\": _p[\"kind\"], \"warnings\": []}\n_TYPEMAP = {\"osc_in\": oscinCHOP, \"midi_in\": midiinCHOP, \"keyboard_in\": keyboardinCHOP, \"gamepad_in\": joystickCHOP, \"mouse_in\": mouseinCHOP, \"osc_out\": oscoutCHOP, \"midi_out\": midioutCHOP, \"dmx_out\": dmxoutCHOP, \"artnet_out\": dmxoutCHOP, \"rtmp_out\": videostreamoutTOP, \"ndi_in\": ndiinTOP, \"syphon_spout_in\": syphonspoutinTOP}\ntry:\n _kind = _p[\"kind\"]; _parent = op(_p[\"parent\"])\n if _parent is None:\n report[\"fatal\"] = \"Parent COMP not found: \" + str(_p[\"parent\"])\n else:\n _name = _p.get(\"name\")\n _node = _parent.create(_TYPEMAP[_kind], _name) if _name else _parent.create(_TYPEMAP[_kind])\n report[\"node\"] = _node.path; report[\"type\"] = _node.type\n def _setpar(parname, val):\n if val is None:\n return\n pr = getattr(_node.par, parname, None)\n if pr is None:\n report[\"warnings\"].append(\"No parameter '%s' on %s\" % (parname, _node.type)); return\n try:\n pr.val = val\n except Exception:\n report[\"warnings\"].append(\"Could not set parameter '%s'\" % parname)\n def _connect_source():\n _src = _p.get(\"source\")\n _what = \"the TOP to stream\" if _kind == \"rtmp_out\" else \"the CHOP whose channels to send\"\n if not _src:\n report[\"warnings\"].append(\"This kind needs a source_path (%s).\" % _what); return\n _s = op(_src)\n if _s is None:\n report[\"warnings\"].append(\"Source operator not found: \" + _src); return\n try:\n _node.inputConnectors[0].connect(_s); report[\"source\"] = _s.path\n except Exception:\n report[\"warnings\"].append(\"Could not connect source \" + _src)\n if _kind == \"osc_in\":\n _setpar(\"port\", _p.get(\"port\"))\n elif _kind == \"midi_in\":\n _setpar(\"norm\", _p.get(\"normalize\"))\n elif _kind == \"osc_out\":\n _setpar(\"netaddress\", _p.get(\"net_address\") or \"127.0.0.1\"); _setpar(\"port\", _p.get(\"port\"))\n _connect_source()\n elif _kind == \"midi_out\":\n _connect_source()\n elif _kind == \"dmx_out\":\n _setpar(\"interface\", _p.get(\"interface\")); _setpar(\"universe\", _p.get(\"universe\")); _setpar(\"netaddress\", _p.get(\"net_address\"))\n _connect_source()\n elif _kind == \"artnet_out\":\n _setpar(\"interface\", _p.get(\"net\")); _setpar(\"universe\", _p.get(\"universe\")); _setpar(\"netaddress\", _p.get(\"net_address\"))\n _connect_source()\n elif _kind == \"rtmp_out\":\n _setpar(\"mode\", \"rtmpsender\"); _setpar(\"url\", _p.get(\"url\")); _setpar(\"fps\", _p.get(\"fps\"))\n _connect_source()\n _setpar(\"active\", _p.get(\"active\"))\n elif _kind == \"ndi_in\":\n _setpar(\"name\", _p.get(\"source_name\"))\n elif _kind == \"syphon_spout_in\":\n _setpar(\"sendername\", _p.get(\"source_name\"))\n _bound = []\n if _kind in (\"osc_in\", \"midi_in\", \"keyboard_in\", \"gamepad_in\", \"mouse_in\"):\n for _b in (_p.get(\"bind_to\") or []):\n try:\n _ch = _b[\"channel\"]; _t = _b[\"target\"]; _dot = _t.rfind(\".\")\n if _dot <= 0:\n report[\"warnings\"].append(\"Invalid bind target '%s' (expected 'nodePath.parName').\" % _t); continue\n _np = _t[:_dot]; _pn = _t[_dot + 1:]; _tn = op(_np)\n if _tn is None:\n report[\"warnings\"].append(\"Bind target node not found: \" + _np); continue\n _tp = getattr(_tn.par, _pn, None)\n if _tp is None:\n report[\"warnings\"].append(\"Bind target parameter not found: %s.%s\" % (_np, _pn)); continue\n _expr = \"op(%r)[%r] if %r in [c.name for c in op(%r).chans()] else 0\" % (_node.path, _ch, _ch, _node.path)\n _PM = type(_tp.mode); _tp.expr = _expr; _tp.mode = _PM.EXPRESSION\n _bound.append({\"channel\": _ch, \"target\": _np + \".\" + _pn})\n except Exception:\n report[\"warnings\"].append(\"Bind failed: \" + traceback.format_exc().splitlines()[-1])\n report[\"bound\"] = _bound\n report[\"errors\"] = [str(e) for e in _node.errors()][:3]\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildIoScript(payload: object): string {\n return buildPayloadScript(IO_SCRIPT, payload);\n}\n\nexport async function createExternalIoImpl(ctx: ToolContext, args: CreateExternalIoArgs) {\n return guardTd(\n async () => {\n // Compose the RTMP destination: an explicit url wins, otherwise stitch the\n // ingest base to the stream key (the Video Stream Out TOP wants one combined URL).\n const rtmpUrl =\n args.kind === \"rtmp_out\"\n ? (args.url ??\n (args.stream_key\n ? `${args.rtmp_base ?? \"rtmp://a.rtmp.youtube.com/live2\"}/${args.stream_key}`\n : null))\n : null;\n const script = buildIoScript({\n kind: args.kind,\n parent: args.parent_path,\n name: args.name ?? null,\n port: args.kind === \"osc_in\" || args.kind === \"osc_out\" ? (args.port ?? 7000) : null,\n normalize: args.normalize,\n bind_to: args.bind_to ?? null,\n source: args.source_path ?? null,\n interface: args.interface,\n net: args.net ?? \"artnet\",\n universe: args.universe,\n net_address: args.net_address ?? null,\n url: rtmpUrl,\n fps: args.kind === \"rtmp_out\" ? (args.fps ?? 30) : null,\n active: args.kind === \"rtmp_out\" ? (args.active ?? false) : null,\n source_name: args.source_name ?? null,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<IoReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Could not create ${report.kind}: ${report.fatal}`, report);\n }\n const bound = report.bound?.length ? `, ${report.bound.length} binding(s)` : \"\";\n const errs = report.errors?.length ? `, ${report.errors.length} node error(s)` : \"\";\n const warns = report.warnings.length ? `, ${report.warnings.length} warning(s)` : \"\";\n return jsonResult(\n `Created ${report.kind} (${report.type}) at ${report.node}${bound}${errs}${warns}.`,\n report,\n );\n },\n );\n}\n\nexport const registerCreateExternalIo: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_external_io\",\n {\n title: \"Create external I/O\",\n description:\n \"Bridge TouchDesigner to the outside world: OSC/MIDI input (a control surface — bind incoming channels straight to parameters), OSC/MIDI output (send a CHOP's channels back out for bidirectional feedback to lighting desks, other apps or hardware — pass source_path), DMX/Art-Net output for lighting (dmx_out for any DMX desk; artnet_out for network Art-Net/sACN pixel-mapping of LED strips & stage fixtures), RTMP output to live-stream a TOP to Twitch/YouTube/OBS (rtmp_out — NVIDIA GPU on Windows only), or NDI / Syphon-Spout video input. To discover which channel a control sends (a 'MIDI learn'), wiggle it and read the input CHOP with get_td_nodes, then bind_to that channel. Validate live where possible, but real signal needs the hardware/sender present.\",\n inputSchema: createExternalIoSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createExternalIoImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nconst UniformSchema = z.object({\n name: z.string(),\n type: z.enum([\"float\", \"vec2\", \"vec3\", \"vec4\", \"int\", \"sampler2D\"]),\n default_value: z.string().optional(),\n});\n\nexport const createGlslShaderSchema = z.object({\n parent_path: z.string().describe(\"Parent COMP to create the GLSL TOP inside.\"),\n name: z.string().optional().describe(\"Name for the GLSL TOP (default 'glsl1').\"),\n fragment_shader: z.string().min(1).describe(\"GLSL fragment (pixel) shader source.\"),\n vertex_shader: z.string().optional().describe(\"Optional GLSL vertex shader source.\"),\n uniforms: z\n .array(UniformSchema)\n .optional()\n .describe(\"Optional uniform declarations to best-effort bind on the GLSL TOP.\"),\n resolution: z.enum([\"720p\", \"1080p\", \"4K\", \"input\"]).default(\"input\"),\n});\ntype CreateGlslShaderArgs = z.infer<typeof createGlslShaderSchema>;\n\nconst RESOLUTIONS = {\n \"720p\": [1280, 720],\n \"1080p\": [1920, 1080],\n \"4K\": [3840, 2160],\n} as const;\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport async function createGlslShaderImpl(ctx: ToolContext, args: CreateGlslShaderArgs) {\n const desiredName = args.name ?? \"glsl1\";\n return guardTd(\n async () => {\n const warnings: string[] = [];\n const glsl = await ctx.client.createNode({\n parent_path: args.parent_path,\n type: \"glslTOP\",\n name: desiredName,\n });\n const glslName = glsl.name || desiredName;\n\n const fragName = `${glslName}_frag`;\n const frag = await ctx.client.createNode({\n parent_path: args.parent_path,\n type: \"textDAT\",\n name: fragName,\n });\n\n const wiring = [\n `op(${q(frag.path)}).text = ${q(args.fragment_shader)}`,\n `op(${q(glsl.path)}).par.pixeldat = ${q(frag.name || fragName)}`,\n ];\n\n let vertexPath: string | undefined;\n if (args.vertex_shader) {\n const vertName = `${glslName}_vert`;\n const vert = await ctx.client.createNode({\n parent_path: args.parent_path,\n type: \"textDAT\",\n name: vertName,\n });\n vertexPath = vert.path;\n wiring.push(`op(${q(vert.path)}).text = ${q(args.vertex_shader)}`);\n wiring.push(`op(${q(glsl.path)}).par.vertexdat = ${q(vert.name || vertName)}`);\n }\n\n await ctx.client.executePythonScript(wiring.join(\"\\n\"), false);\n\n if (args.uniforms && args.uniforms.length > 0) {\n // sampler2D uniforms bind to TOP inputs (the Samplers page), not numeric\n // values, so they can't be auto-set here — flag them for manual wiring.\n const samplers = args.uniforms.filter((u) => u.type === \"sampler2D\");\n if (samplers.length > 0) {\n warnings.push(\n `sampler2D uniform(s) ${samplers.map((u) => u.name).join(\", \")} must be wired manually (GLSL TOP Samplers page / TOP inputs).`,\n );\n }\n // Numeric uniforms bind through the GLSL TOP \"Vectors\" sequence\n // (vec<i>name + vec<i>value{x,y,z,w}). The flat uniname<i>/value<i>x params\n // the old path targeted don't exist on the GLSL TOP, so it silently\n // no-opped multi-component uniforms (only the X channel ever stuck).\n const specs = args.uniforms\n .filter((u) => u.type !== \"sampler2D\")\n .map((u) => ({\n name: u.name,\n comps: (u.default_value ?? \"\")\n .split(\",\")\n .map((s) => Number(s.trim()))\n .filter((n) => Number.isFinite(n))\n .slice(0, 4),\n }))\n .filter((s) => s.comps.length > 0);\n if (specs.length > 0) {\n const bind = [\n `g = op(${q(glsl.path)})`,\n `_specs = ${JSON.stringify(specs)}`,\n \"g.seq.vec.numBlocks = max(g.seq.vec.numBlocks, len(_specs))\",\n \"for i, s in enumerate(_specs):\",\n \" setattr(g.par, 'vec%dname' % i, s['name'])\",\n \" for axis, val in zip('xyzw', s['comps']):\",\n \" try: setattr(g.par, 'vec%dvalue%s' % (i, axis), val)\",\n \" except Exception: pass\",\n ].join(\"\\n\");\n try {\n await ctx.client.executePythonScript(bind, false);\n } catch {\n warnings.push(\n \"Could not auto-bind uniforms; declare them in the shader and set them on the GLSL TOP's Vectors page manually.\",\n );\n }\n }\n }\n\n if (args.resolution !== \"input\") {\n const [width, height] = RESOLUTIONS[args.resolution];\n await ctx.client.updateNodeParameters(glsl.path, {\n outputresolution: \"custom\",\n resolutionw: width,\n resolutionh: height,\n });\n }\n\n return { glsl, fragmentDat: frag.path, vertexDat: vertexPath, warnings };\n },\n (result) => jsonResult(`Created GLSL TOP at ${result.glsl.path}.`, result),\n );\n}\n\nexport const registerCreateGlslShader: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_glsl_shader\",\n {\n title: \"Create GLSL shader\",\n description:\n \"Create a GLSL TOP with a fragment shader (and optional vertex shader) supplied via Text DATs, with optional uniform binding and output resolution.\",\n inputSchema: createGlslShaderSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createGlslShaderImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nconst macroTargetSchema = z.object({\n param: z.string().describe(\"Parameter to drive, written as 'nodePath.parName'.\"),\n min: z.coerce.number().describe(\"Value this target takes when the macro is at 0.\"),\n max: z.coerce.number().describe(\"Value this target takes when the macro is at 1.\"),\n curve: z.coerce\n .number()\n .positive()\n .default(1)\n .describe(\"Response curve exponent: 1 = linear, >1 = ease-in, <1 = ease-out.\"),\n});\n\nexport const createMacroSchema = z.object({\n comp_path: z\n .string()\n .default(\"/project1\")\n .describe(\"COMP that will hold the macro knob (usually a control-panel container).\"),\n name: z.string().describe(\"Macro control name, e.g. 'Energy' or 'Intensity'.\"),\n default: z.coerce.number().min(0).max(1).default(0).describe(\"Initial macro value (0–1).\"),\n targets: z\n .array(macroTargetSchema)\n .min(1)\n .describe(\"Parameters this macro drives, each remapped from the macro's 0–1 into [min,max].\"),\n});\ntype CreateMacroArgs = z.infer<typeof createMacroSchema>;\n\ninterface MacroReport {\n comp: string;\n macro?: string;\n bound: string[];\n warnings: string[];\n fatal?: string;\n}\n\n// One Python pass: find-or-create a 0..1 float custom parameter (the macro knob), then bind\n// each target parameter by expression to a remap of the macro into that target's [min,max]\n// (with an optional curve exponent). ParMode isn't in the exec globals, so the expression\n// enum is derived from a live parameter (type(par.mode)).\nconst MACRO_SCRIPT = `\nimport json, base64, traceback\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nreport = {\"comp\": _p[\"comp\"], \"bound\": [], \"warnings\": []}\n_c = op(_p[\"comp\"])\ntry:\n if _c is None:\n report[\"fatal\"] = \"COMP not found: \" + _p[\"comp\"]\n elif not hasattr(_c, \"appendCustomPage\"):\n report[\"fatal\"] = _p[\"comp\"] + \" is not a COMP, so it cannot hold a macro knob.\"\n else:\n _raw = _p[\"name\"]\n _pn = \"\".join(ch for ch in _raw if ch.isalnum())\n _pn = (_pn[0].upper() + _pn[1:]) if _pn else \"Macro\"\n _par = getattr(_c.par, _pn, None)\n if _par is None:\n _page = None\n for _pg in _c.customPages:\n if _pg.name == \"Macros\":\n _page = _pg; break\n if _page is None:\n _page = _c.appendCustomPage(\"Macros\")\n _par = _page.appendFloat(_pn, label=_raw)[0]\n _par.normMin = 0.0; _par.normMax = 1.0\n _par.default = _p[\"default\"]; _par.val = _p[\"default\"]\n report[\"macro\"] = _pn\n _mref = \"op(%s).par.%s\" % (repr(_c.path), _pn)\n for _t in _p[\"targets\"]:\n try:\n _path = _t[\"param\"]; _dot = _path.rfind(\".\")\n if _dot <= 0:\n report[\"warnings\"].append(\"Invalid target '%s' (expected 'nodePath.parName').\" % _path); continue\n _np = _path[:_dot]; _prn = _path[_dot + 1:]; _n = op(_np)\n if _n is None:\n report[\"warnings\"].append(\"Target node not found: \" + _np); continue\n _tp = getattr(_n.par, _prn, None)\n if _tp is None:\n report[\"warnings\"].append(\"Target parameter not found: \" + _path); continue\n _lo = _t[\"min\"]; _hi = _t[\"max\"]; _curve = _t.get(\"curve\", 1.0)\n _m = _mref if _curve == 1.0 else \"(%s ** %s)\" % (_mref, repr(_curve))\n _expr = \"%s + (%s) * (%s)\" % (repr(_lo), repr(_hi - _lo), _m)\n _PM = type(_tp.mode)\n _tp.expr = _expr; _tp.mode = _PM.EXPRESSION\n report[\"bound\"].append(_path)\n except Exception:\n report[\"warnings\"].append(\"Failed to bind %s: %s\" % (_t.get(\"param\", \"?\"), traceback.format_exc().splitlines()[-1]))\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildMacroScript(payload: object): string {\n return buildPayloadScript(MACRO_SCRIPT, payload);\n}\n\nexport async function createMacroImpl(ctx: ToolContext, args: CreateMacroArgs) {\n return guardTd(\n async () => {\n const script = buildMacroScript({\n comp: args.comp_path,\n name: args.name,\n default: args.default,\n targets: args.targets,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<MacroReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Could not create macro: ${report.fatal}`, report);\n }\n const summary = `Macro \"${report.macro}\" on ${report.comp} drives ${report.bound.length} parameter(s)${\n report.warnings.length ? `, ${report.warnings.length} warning(s)` : \"\"\n }.`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerCreateMacro: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_macro\",\n {\n title: \"Create macro control\",\n description:\n \"Add one macro knob (a 0–1 custom parameter) to a COMP that drives many parameters at once, each remapped into its own [min,max] range with an optional response curve — a one-to-many control for sweeping a whole look from a single fader. Targets are bound by expression so they track the macro live.\",\n inputSchema: createMacroSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createMacroImpl(ctx, args),\n );\n};\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport { friendlyTdError } from \"../../td-client/types.js\";\nimport { computeDataflowLayout, type LayoutEdge, layoutScript } from \"../layout.js\";\nimport { errorResult, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { connectNodesViaBridge } from \"./connectHelper.js\";\n\nconst ChainNodeSchema = z.object({\n type: z.string().describe(\"Operator type, e.g. 'noiseTOP'.\"),\n name: z.string().optional(),\n parameters: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport const createNodeChainSchema = z.object({\n parent_path: z.string().describe(\"Parent COMP to create the chain inside.\"),\n nodes: z.array(ChainNodeSchema).min(1).describe(\"Ordered list of nodes to create.\"),\n connect_sequentially: z\n .boolean()\n .default(true)\n .describe(\"Wire output[0] → input[0] for each consecutive pair.\"),\n});\ntype CreateNodeChainArgs = z.infer<typeof createNodeChainSchema>;\n\ninterface CreatedNode {\n path: string;\n type: string;\n name: string;\n}\n\nexport async function createNodeChainImpl(\n ctx: ToolContext,\n args: CreateNodeChainArgs,\n): Promise<CallToolResult> {\n const created: CreatedNode[] = [];\n const warnings: string[] = [];\n\n for (const node of args.nodes) {\n if (!ctx.knowledge.operatorExists(node.type)) {\n warnings.push(`Operator type \"${node.type}\" was not found in the knowledge base.`);\n }\n }\n\n for (const node of args.nodes) {\n try {\n const ref = await ctx.client.createNode({\n parent_path: args.parent_path,\n type: node.type,\n name: node.name,\n parameters: node.parameters,\n });\n created.push({\n path: ref.path,\n type: ref.type || node.type,\n name: ref.name || node.name || \"\",\n });\n } catch (err) {\n return errorResult(\n `Stopped after creating ${created.length}/${args.nodes.length} node(s). ` +\n `Failed to create \"${node.type}\": ${friendlyTdError(err)}. ` +\n `Created so far: ${created.map((c) => c.path).join(\", \") || \"(none)\"}. ` +\n \"No nodes were deleted.\",\n );\n }\n }\n\n const connections: Array<{ from: string; to: string; method: string }> = [];\n if (args.connect_sequentially && created.length > 1) {\n for (let i = 0; i < created.length - 1; i++) {\n const from = created[i];\n const to = created[i + 1];\n if (!from || !to) continue;\n try {\n const result = await connectNodesViaBridge(ctx.client, from.path, to.path);\n connections.push({ from: from.path, to: to.path, method: result.method });\n } catch (err) {\n warnings.push(`Failed to connect ${from.path} → ${to.path}: ${friendlyTdError(err)}`);\n }\n }\n }\n\n const edges: LayoutEdge[] = [];\n if (args.connect_sequentially) {\n for (let i = 0; i < created.length - 1; i++) {\n const from = created[i];\n const to = created[i + 1];\n if (from && to) edges.push({ from: from.path, to: to.path });\n }\n }\n const positions = computeDataflowLayout(\n created.map((c) => c.path),\n edges,\n );\n if (Object.keys(positions).length > 0) {\n try {\n await ctx.client.executePythonScript(layoutScript(positions), false);\n } catch (err) {\n warnings.push(`Auto-layout skipped: ${friendlyTdError(err)}`);\n }\n }\n\n return jsonResult(\n `Created ${created.length} node(s) and ${connections.length} connection(s) under ${args.parent_path}.`,\n { created, connections, warnings },\n );\n}\n\nexport const registerCreateNodeChain: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_node_chain\",\n {\n title: \"Create node chain\",\n description:\n \"Create multiple nodes and (optionally) connect them in sequence. Returns all created paths; on failure it stops and reports partial progress without deleting anything.\",\n inputSchema: createNodeChainSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createNodeChainImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { createSystemContainer, finalize, runBuild } from \"../layer1/orchestration.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport type { ControlSpec } from \"./createControlPanel.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport const createPanicSchema = z.object({\n input_path: z\n .string()\n .optional()\n .describe(\n \"Optional absolute path of the live source TOP to protect. Pulled in via a Select TOP (TD wires can't cross containers, so it's referenced by path). If omitted, a built-in test source (Ramp TOP) is used so the panic COMP still builds and previews on its own.\",\n ),\n blackout: z\n .boolean()\n .default(false)\n .describe(\n \"Initial Blackout state. When on, the output is forced to black (Level TOP brightness1 = 0) — the instant kill switch.\",\n ),\n freeze: z\n .boolean()\n .default(false)\n .describe(\n \"Initial Freeze state. When on, the last frame is held instead of passing the live input (Cache TOP stops capturing — active = 0).\",\n ),\n expose_controls: z\n .boolean()\n .default(true)\n .describe(\n \"Expose big Blackout and Freeze toggle buttons on the container so a performer can hit them instantly.\",\n ),\n parent_path: z.string().default(\"/project1\"),\n});\ntype CreatePanicArgs = z.infer<typeof createPanicSchema>;\n\nexport async function createPanicImpl(ctx: ToolContext, args: CreatePanicArgs) {\n return runBuild(async () => {\n const builder = await createSystemContainer(ctx, args.parent_path, \"panic\");\n const container = builder.containerPath;\n\n // The Blackout / Freeze custom toggle params live on the container. When controls are\n // exposed they're created (with their initial states + panel buttons) by the control\n // panel in finalize() below — appending them here too would collide. When controls are\n // NOT exposed we append them directly so the COMP is still usable via op().par. Either\n // way the effect expressions reference them by ABSOLUTE path; TD resolves that lazily,\n // so it's fine that the panel appends them after these expressions are set. ParMode\n // isn't in the bridge exec globals, so expression mode is set via `type(par.mode)`.\n if (!args.expose_controls) {\n await builder.python(\n [\n `_c = op(${q(container)})`,\n `_pg = None`,\n `for _p in _c.customPages:`,\n ` if _p.name == \"Panic\":`,\n ` _pg = _p; break`,\n `if _pg is None:`,\n ` _pg = _c.appendCustomPage(\"Panic\")`,\n `if getattr(_c.par, \"Blackout\", None) is None:`,\n ` _bp = _pg.appendToggle(\"Blackout\", label=\"Blackout\")[0]`,\n ` _bp.default = ${args.blackout ? \"True\" : \"False\"}; _bp.val = ${args.blackout ? \"True\" : \"False\"}`,\n `if getattr(_c.par, \"Freeze\", None) is None:`,\n ` _fp = _pg.appendToggle(\"Freeze\", label=\"Freeze\")[0]`,\n ` _fp.default = ${args.freeze ? \"True\" : \"False\"}; _fp.val = ${args.freeze ? \"True\" : \"False\"}`,\n ].join(\"\\n\"),\n );\n }\n\n // The source to protect. With input_path it's pulled in by a Select TOP (`top` =\n // absolute path), since wires can't cross COMPs. Without one, a Ramp TOP gives a\n // non-device test image so the panic COMP builds + previews standalone.\n let source: string;\n if (args.input_path) {\n source = await builder.add(\"selectTOP\", \"src\", { top: args.input_path });\n } else {\n source = await builder.add(\"rampTOP\", \"src\");\n }\n\n // FREEZE — a Cache TOP holds the last frame. While its `active` param is on the Cache\n // captures live frames (passes the source through); when Freeze is on we drive `active`\n // to 0, so it stops capturing and outputs the last frame it held — an instant freeze.\n // Expression references the container's Freeze par by ABSOLUTE path. `cachesize` 1 keeps\n // it to a single held frame.\n const freeze = await builder.add(\"cacheTOP\", \"freeze\", {\n cachesize: 1,\n active: args.freeze ? 0 : 1,\n });\n await builder.connect(source, freeze);\n const freezeExpr = `(0 if op(${q(container)}).par.Freeze else 1)`;\n await builder.python(\n `_p = op(${q(freeze)}).par.active\\n_p.expr = ${q(freezeExpr)}\\n_p.mode = type(_p.mode).EXPRESSION`,\n );\n\n // BLACKOUT — a Level TOP whose brightness1 is driven to 0 when Blackout is on (→ black)\n // and 1 otherwise (→ pass-through). brightness1 is the brightness param (NOT `gain`).\n // Expression references the container's Blackout par by ABSOLUTE path.\n const blackout = await builder.add(\"levelTOP\", \"blackout\", {\n brightness1: args.blackout ? 0 : 1,\n });\n await builder.connect(freeze, blackout);\n const blackoutExpr = `(0 if op(${q(container)}).par.Blackout else 1)`;\n await builder.python(\n `_p = op(${q(blackout)}).par.brightness1\\n_p.expr = ${q(blackoutExpr)}\\n_p.mode = type(_p.mode).EXPRESSION`,\n );\n\n const out = await builder.add(\"nullTOP\", \"out1\");\n await builder.connect(blackout, out);\n\n // Big togglable Blackout / Freeze buttons on the container, so a performer can hit them\n // instantly. These are the SOURCE-OF-TRUTH pars that the freeze/blackout node expressions\n // above read by absolute path — so they must NOT use bind_to: a control panel bind sets the\n // target's expr to `op(container).par.<Name>`, and binding Blackout/Freeze to themselves\n // creates a self-referential expression (\"Recursion/loop error in evaluation of parameter\").\n // Created unbound here, they're plain toggles the expressions consume.\n const controls: ControlSpec[] = args.expose_controls\n ? [\n { name: \"Blackout\", type: \"toggle\", default: args.blackout },\n { name: \"Freeze\", type: \"toggle\", default: args.freeze },\n ]\n : [];\n\n return finalize(ctx, {\n summary: `Built a panic / safety control → ${out}: Blackout kills the output to black and Freeze holds the last frame${\n args.input_path ? ` of ${args.input_path}` : \" (built-in test source)\"\n }. Hit op('${container}').par.Blackout / .par.Freeze (or the panel buttons) live.`,\n builder,\n outputPath: out,\n // Output is a TOP (the Null), so a preview image is captured.\n capturePreviewImage: true,\n controls,\n extra: {\n blackout: args.blackout,\n freeze: args.freeze,\n source_path: source,\n freeze_path: freeze,\n blackout_path: blackout,\n output_path: out,\n input_path: args.input_path,\n },\n });\n });\n}\n\nexport const registerCreatePanic: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_panic\",\n {\n title: \"Create panic control\",\n description:\n \"Build a live-performance safety control — the 'oh no' button every VJ needs. Wraps a source in a small COMP with two instant kill switches: Blackout forces the output to black (a Level TOP's brightness1 driven to 0) and Freeze holds the last frame (a Cache TOP stops capturing, active → 0). With an input_path the source is pulled in by a Select TOP (so it can live in another container); without one a built-in Ramp TOP test source is used so it builds and previews standalone. Output is a Null TOP. Big Blackout / Freeze toggle buttons are exposed on the container so a performer can hit them instantly.\",\n inputSchema: createPanicSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createPanicImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const createPhoneRemoteSchema = z.object({\n comp_path: z\n .string()\n .default(\"/project1\")\n .describe(\"Control COMP whose numeric custom parameters the phone page exposes.\"),\n port: z.coerce\n .number()\n .int()\n .positive()\n .max(65535)\n .default(9981)\n .describe(\"TCP port for the remote web server (keep it distinct from the bridge's 9980).\"),\n});\ntype CreatePhoneRemoteArgs = z.infer<typeof createPhoneRemoteSchema>;\n\ninterface RemoteReport {\n comp: string;\n server?: string;\n port?: number;\n url?: string;\n controls?: string[];\n warnings: string[];\n fatal?: string;\n}\n\n// Web Server DAT callbacks (run in TD). GET / serves a mobile page of range sliders, one per\n// numeric custom parameter of the COMP the server lives in; each slider POSTs /set?param=&value=\n// back, which writes the parameter. No build step on the client — the artist just opens the URL.\nconst REMOTE_CALLBACKS = `from urllib.parse import urlparse, parse_qs\n\ndef _build_html(comp):\n rows = \"\"\n for p in comp.customPars:\n if not getattr(p, \"isNumber\", False) or p.readOnly:\n continue\n lo = p.normMin if p.normMin is not None else 0\n hi = p.normMax if p.normMax is not None else 1\n try:\n v = float(p.eval())\n except Exception:\n v = lo\n rows += ('<div class=\"r\"><label>' + p.name + '</label>'\n '<input type=\"range\" data-p=\"' + p.name + '\" min=\"' + str(lo) + '\" max=\"' + str(hi)\n + '\" step=\"any\" value=\"' + str(v) + '\"></div>')\n head = ('<!doctype html><html><head><meta name=\"viewport\" content=\"width=device-width,initial-scale=1,maximum-scale=1\">'\n '<title>tdmcp remote</title><style>'\n 'body{background:#0d0d10;color:#eee;font-family:-apple-system,system-ui,sans-serif;margin:0;padding:18px}'\n '.r{margin:22px 0}label{display:block;margin-bottom:10px;font-size:15px;opacity:.85}'\n 'input[type=range]{width:100%;height:42px;accent-color:#6cf}h1{font-size:17px;opacity:.6;font-weight:600}'\n '</style></head><body><h1>' + comp.name + ' — tdmcp remote</h1>')\n script = ('<script>document.querySelectorAll(\"input[type=range]\").forEach(function(el){'\n 'el.addEventListener(\"input\",function(){'\n 'fetch(\"/set?param=\"+encodeURIComponent(el.dataset.p)+\"&value=\"+el.value)})})</script>')\n return head + rows + script + \"</body></html>\"\n\ndef onHTTPRequest(webServerDAT, request, response):\n comp = webServerDAT.parent()\n parsed = urlparse(request.get(\"uri\", \"/\"))\n # /set is served on any method (GET keeps the client trivial and avoids POST quirks).\n if parsed.path.rstrip(\"/\") == \"/set\":\n # TouchDesigner's WebServer DAT surfaces the query as a dict under request['pars'],\n # not in the uri, so read that first and fall back to parsing the uri query.\n pars = request.get(\"pars\")\n pars = pars if isinstance(pars, dict) else {}\n name = pars.get(\"param\", \"\")\n val = pars.get(\"value\", \"\")\n if not name:\n q = parse_qs(parsed.query)\n name = (q.get(\"param\") or [\"\"])[0]\n val = (q.get(\"value\") or [\"\"])[0]\n par = getattr(comp.par, name, None)\n if par is not None and not par.readOnly:\n try:\n par.val = float(val)\n except Exception:\n pass\n response[\"statusCode\"] = 200\n response[\"content-type\"] = \"text/plain\"\n response[\"data\"] = \"ok\"\n return response\n response[\"statusCode\"] = 200\n response[\"content-type\"] = \"text/html\"\n response[\"data\"] = _build_html(comp)\n return response\n\ndef onWebSocketOpen(webServerDAT, client, uri): return\ndef onWebSocketReceiveText(webServerDAT, client, data): return\ndef onWebSocketReceiveBinary(webServerDAT, client, data): return\ndef onWebSocketReceivePing(webServerDAT, client, data):\n webServerDAT.webSocketSendPong(client, data=data)\ndef onWebSocketReceivePong(webServerDAT, client, data): return\ndef onServerStart(webServerDAT): return\ndef onServerStop(webServerDAT): return\n`;\n\nconst REMOTE_SCRIPT = `\nimport json, base64, traceback, socket\nimport td\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nreport = {\"comp\": _p[\"comp\"], \"warnings\": []}\n_c = op(_p[\"comp\"])\ntry:\n if _c is None:\n report[\"fatal\"] = \"COMP not found: \" + _p[\"comp\"]\n elif not hasattr(_c, \"create\") or not hasattr(_c, \"customPars\"):\n report[\"fatal\"] = _p[\"comp\"] + \" is not a COMP.\"\n else:\n _cb = _c.op(\"remote_callbacks\") or _c.create(td.textDAT, \"remote_callbacks\")\n _cb.text = _p[\"callbacks\"]\n _server = _c.op(\"remote_server\") or _c.create(td.webserverDAT, \"remote_server\")\n _server.par.port = _p[\"port\"]\n _server.par.callbacks = _cb\n _server.par.active = True\n report[\"server\"] = _server.path; report[\"port\"] = _p[\"port\"]\n report[\"controls\"] = [p.name for p in _c.customPars if getattr(p, \"isNumber\", False) and not p.readOnly]\n try:\n _ip = socket.gethostbyname(socket.gethostname())\n except Exception:\n _ip = \"<this-machine-ip>\"\n report[\"url\"] = \"http://%s:%s/\" % (_ip, _p[\"port\"])\n _server.cook(force=True)\n _err = _server.errors(recurse=False) or \"\"\n if _err:\n report[\"warnings\"].append(\"Web Server DAT: \" + _err[:160])\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildRemoteScript(payload: object): string {\n return buildPayloadScript(REMOTE_SCRIPT, payload);\n}\n\nexport async function createPhoneRemoteImpl(ctx: ToolContext, args: CreatePhoneRemoteArgs) {\n return guardTd(\n async () => {\n const script = buildRemoteScript({\n comp: args.comp_path,\n port: args.port,\n callbacks: REMOTE_CALLBACKS,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<RemoteReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Could not start phone remote: ${report.fatal}`, report);\n }\n const summary = `Phone remote serving ${report.controls?.length ?? 0} control(s) at ${report.url} (open it on a phone on the same network)${\n report.warnings.length ? `, ${report.warnings.length} warning(s)` : \"\"\n }.`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerCreatePhoneRemote: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_phone_remote\",\n {\n title: \"Create phone remote\",\n description:\n \"Serve a mobile-friendly web panel from a Web Server DAT so you can control a COMP's numeric custom parameters from a phone — just open the URL, no app to install. Each parameter becomes a touch slider that writes back live. SECURITY: like the bridge, this listens on all interfaces and accepts writes with no auth, so use it only on a trusted network. Pair with create_control_panel (the params to expose) and manage_cue (snapshot looks you dial in from the phone).\",\n inputSchema: createPhoneRemoteSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createPhoneRemoteImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nconst TYPE_MAP = {\n text: \"textDAT\",\n execute: \"executeDAT\",\n script: \"scriptDAT\",\n} as const;\n\nexport const createPythonScriptSchema = z.object({\n parent_path: z.string().describe(\"Parent COMP to create the DAT inside.\"),\n name: z.string().optional(),\n code: z.string().min(1).describe(\"Python source to place in the DAT.\"),\n dat_type: z\n .enum([\"text\", \"execute\", \"script\"])\n .default(\"text\")\n .describe(\"Kind of DAT: 'text' (plain), 'execute' (event hooks), or 'script' (table builder).\"),\n});\ntype CreatePythonScriptArgs = z.infer<typeof createPythonScriptSchema>;\n\nexport async function createPythonScriptImpl(ctx: ToolContext, args: CreatePythonScriptArgs) {\n return guardTd(\n async () => {\n const dat = await ctx.client.createNode({\n parent_path: args.parent_path,\n type: TYPE_MAP[args.dat_type],\n name: args.name,\n });\n const path = JSON.stringify(dat.path);\n const code = JSON.stringify(args.code);\n // A Script DAT's own .text is read-only (\"operator is not editable\").\n // Creating a scriptDAT auto-creates a companion text-editable callbacks\n // DAT (<name>_callbacks) referenced by its `callbacks` parameter, so the\n // code must be written there. text/execute DATs are .text-editable.\n const script =\n args.dat_type === \"script\"\n ? [\n `_op = op(${path})`,\n \"_cb = None\",\n \"try:\",\n \" _cb = _op.par.callbacks.eval()\",\n \"except Exception:\",\n \" _cb = None\",\n \"if _cb is None:\",\n \" _cb = _op.parent().op(_op.name + '_callbacks')\",\n `_cb.text = ${code}`,\n ].join(\"\\n\")\n : `op(${path}).text = ${code}`;\n await ctx.client.executePythonScript(script, false);\n return dat;\n },\n (dat) => jsonResult(`Created ${args.dat_type} DAT at ${dat.path}.`, { node: dat }),\n );\n}\n\nexport const registerCreatePythonScript: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_python_script\",\n {\n title: \"Create Python DAT\",\n description: \"Create a DAT (text/execute/script) preloaded with Python code.\",\n inputSchema: createPythonScriptSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createPythonScriptImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nconst q = (value: string): string => JSON.stringify(value);\n\nexport const duplicateNetworkSchema = z.object({\n source_path: z.string().describe(\"Path of the node/COMP to duplicate.\"),\n name: z.string().optional().describe(\"Name for the copy (auto-generated if omitted).\"),\n parent_path: z\n .string()\n .optional()\n .describe(\"Where to place the copy (defaults to the source's parent).\"),\n});\ntype DuplicateNetworkArgs = z.infer<typeof duplicateNetworkSchema>;\n\nexport async function duplicateNetworkImpl(ctx: ToolContext, args: DuplicateNetworkArgs) {\n const script = [\n `src = op(${q(args.source_path)})`,\n `if src is None: raise Exception('source not found: ' + ${q(args.source_path)})`,\n args.parent_path ? `parent = op(${q(args.parent_path)})` : \"parent = src.parent()\",\n \"if parent is None: raise Exception('parent not found')\",\n args.name ? `new = parent.copy(src, name=${q(args.name)})` : \"new = parent.copy(src)\",\n \"result = new.path\",\n ].join(\"\\n\");\n\n return guardTd(\n () => ctx.client.executePythonScript(script, true),\n (res) =>\n jsonResult(`Duplicated ${args.source_path} → ${res.result ?? \"(see stdout)\"}.`, {\n source: args.source_path,\n copy: res.result,\n }),\n );\n}\n\nexport const registerDuplicateNetwork: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"duplicate_network\",\n {\n title: \"Duplicate a network\",\n description:\n \"Copy a node or whole COMP (and its contents) to a new node, optionally into another parent.\",\n inputSchema: duplicateNetworkSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => duplicateNetworkImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const learnControlSchema = z.object({\n mode: z\n .enum([\"snapshot\", \"bind\"])\n .describe(\n \"snapshot: record the current value of every channel of source_chop. bind: re-read source_chop, find the channel that moved the most since the snapshot, and bind target to it. Call snapshot first (controls at rest), wiggle one hardware control, then call bind.\",\n ),\n source_chop: z\n .string()\n .describe(\n \"Absolute path of the input CHOP carrying the hardware controls (e.g. a midiin/oscin CHOP or a Null fed by one).\",\n ),\n target: z\n .string()\n .optional()\n .describe(\n \"Parameter to drive, written as 'nodePath.parName' (e.g. '/project1/sys/transform1.scale'). Required for mode:'bind'; switched to expression mode so it tracks the matched channel live.\",\n ),\n scale: z.coerce\n .number()\n .default(1)\n .describe(\"Multiply the matched channel value (mapping gain).\"),\n offset: z.coerce.number().default(0).describe(\"Add to the scaled value (mapping offset).\"),\n min_delta: z.coerce\n .number()\n .optional()\n .describe(\n \"mode:'bind' minimum NORMALIZED movement (default 0.05). The winning channel's delta is normalized by max(|old|, |new|, epsilon) — a unit-free relative change — so a 0–127 MIDI CC and a 0–1 OSC float compare fairly. If the top channel moved less than this, nothing is bound and you're told to wiggle the control harder. Raise it to reject controller jitter; lower it for very small/slow knobs.\",\n ),\n parent_path: z\n .string()\n .default(\"/project1\")\n .describe(\n \"COMP whose storage persists the snapshot between the snapshot and bind calls (defaults to /project1).\",\n ),\n});\ntype LearnControlArgs = z.infer<typeof learnControlSchema>;\n\ninterface LearnReport {\n mode: string;\n source_chop: string;\n // snapshot\n channels?: string[];\n channel_count?: number;\n // bind\n matched_channel?: string;\n matched_delta?: number; // raw |new - old| of the winning channel (for display)\n matched_norm?: number; // normalized delta the pick was actually made on\n min_delta?: number; // the normalized threshold that was applied\n bound?: string;\n expression?: string;\n ranking?: Array<{ channel: string; delta: number; norm: number }>;\n warnings: string[];\n fatal?: string;\n}\n\n// One Python pass. State lives in the parent COMP's storage under KEY, namespaced by the\n// source CHOP path: { source_chop: { chanName: value } }. Storage persists with the .toe,\n// so the snapshot survives between the two calls (and a save/reload).\n//\n// snapshot: read every channel's current value and store it.\n// bind: re-read the same channels, diff against the stored snapshot, pick the channel that\n// moved the most (the one the artist just wiggled), then switch the target parameter to\n// expression mode tracking op('chop')['chan'] (* scale) (+ offset) — mirroring\n// bind_to_channel. Expressions evaluate relative to the PARENT, so the source path is\n// embedded as an absolute path via repr().\n//\n// The pick is made on a NORMALIZED delta, not the raw |new - old|, so channels of\n// different ranges compare fairly:\n// norm = |new - old| / max(|old|, |new|, EPS)\n// This is a unit-free relative change (roughly \"fraction of the channel's own magnitude\n// that it moved\"), so a 0–127 MIDI CC no longer dwarfs a 0–1 OSC float just by living on\n// a bigger scale — e.g. a CC 0→64 and a float 0.0→0.5 both normalize to ~1.0. EPS keeps a\n// channel resting at exactly 0 from dividing by zero (it then reads as a full move).\n// If the winning channel's normalized delta is below MIN_DELTA, nothing is bound — the\n// move was jitter/too small. The raw delta is still reported for display.\nconst LEARN_SCRIPT = `\nimport json, base64, traceback\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nKEY = \"tdmcp_learn\"\n_mode = _p[\"mode\"]; _src = _p[\"source_chop\"]; _parent = _p[\"parent_path\"]\nreport = {\"mode\": _mode, \"source_chop\": _src, \"warnings\": []}\ntry:\n _srcop = op(_src)\n _store_op = op(_parent)\n if _srcop is None:\n report[\"fatal\"] = \"Source CHOP not found: %s\" % _src\n elif _store_op is None:\n report[\"fatal\"] = \"Parent COMP not found: %s\" % _parent\n elif not hasattr(_srcop, \"chans\"):\n report[\"fatal\"] = \"%s is not a CHOP (no channels to read).\" % _src\n else:\n # Current channel values, keyed by name. A channel may briefly have no samples.\n _now = {}\n for _c in _srcop.chans():\n try:\n _now[_c.name] = float(_c.eval())\n except Exception:\n report[\"warnings\"].append(\"Could not read channel '%s'; skipped.\" % _c.name)\n if _mode == \"snapshot\":\n _store = dict(_store_op.fetch(KEY, {}))\n _store[_src] = _now\n _store_op.store(KEY, _store)\n report[\"channels\"] = sorted(_now.keys())\n report[\"channel_count\"] = len(_now)\n if not _now:\n report[\"warnings\"].append(\"Source CHOP has no readable channels yet.\")\n elif _mode == \"bind\":\n _target = _p.get(\"target\")\n if not _target:\n report[\"fatal\"] = \"A target ('nodePath.parName') is required for mode 'bind'.\"\n else:\n _store = dict(_store_op.fetch(KEY, {}))\n _prev = _store.get(_src)\n if _prev is None:\n report[\"fatal\"] = \"No snapshot recorded for %s yet — run mode 'snapshot' first.\" % _src\n else:\n # Normalized diff: rank by relative change, not raw |new - old|, so\n # channels of different ranges compare fairly. Each entry is\n # (name, raw_delta, norm_delta) where\n # norm = raw / max(|old|, |new|, EPS).\n # EPS guards a channel resting at exactly 0 (it reads as a full move).\n _EPS = 1e-6\n _min_norm = _p.get(\"min_delta\")\n if _min_norm is None:\n _min_norm = 0.05\n _min_norm = float(_min_norm)\n _deltas = []\n for _name, _val in _now.items():\n if _name in _prev:\n _old = float(_prev[_name])\n _raw = abs(_val - _old)\n _norm = _raw / max(abs(_old), abs(_val), _EPS)\n _deltas.append((_name, _raw, _norm))\n # Rank by the normalized delta (the value the pick is made on).\n _deltas.sort(key=lambda kv: kv[2], reverse=True)\n report[\"ranking\"] = [{\"channel\": n, \"delta\": r, \"norm\": nm} for n, r, nm in _deltas[:8]]\n report[\"min_delta\"] = _min_norm\n if not _deltas:\n report[\"fatal\"] = \"No channels in common between the snapshot and the current reading.\"\n elif _deltas[0][2] <= 0.0:\n report[\"fatal\"] = \"No channel changed since the snapshot — wiggle a control, then call bind again.\"\n elif _deltas[0][2] < _min_norm:\n report[\"fatal\"] = \"Top channel '%s' moved only %.4f (normalized; threshold %.4f) — that's within jitter. Wiggle the control harder, or lower min_delta, then call bind again.\" % (_deltas[0][0], _deltas[0][2], _min_norm)\n else:\n _ch, _delta, _norm = _deltas[0]\n report[\"matched_channel\"] = _ch\n report[\"matched_delta\"] = _delta\n report[\"matched_norm\"] = _norm\n # Warn on an ambiguous match (a near-tie between the top two, on the\n # normalized scale the pick was made on).\n if len(_deltas) > 1 and _deltas[1][2] > 0 and (_deltas[0][2] - _deltas[1][2]) < (0.25 * _deltas[0][2]):\n report[\"warnings\"].append(\"Top two channels moved by similar amounts ('%s' vs '%s'); the match may be wrong — re-snapshot and wiggle only one control.\" % (_deltas[0][0], _deltas[1][0]))\n _scale = _p[\"scale\"]; _offset = _p[\"offset\"]\n _expr = \"op(%s)[%s]\" % (repr(_src), repr(_ch))\n if _scale != 1:\n _expr = \"(%s) * %s\" % (_expr, repr(_scale))\n if _offset != 0:\n _expr = \"%s + %s\" % (_expr, repr(_offset))\n report[\"expression\"] = _expr\n _dot = _target.rfind(\".\")\n if _dot <= 0:\n report[\"fatal\"] = \"Invalid target '%s' (expected 'nodePath.parName').\" % _target\n else:\n _np = _target[:_dot]; _pn = _target[_dot + 1:]; _n = op(_np)\n if _n is None:\n report[\"fatal\"] = \"Target node not found: %s\" % _np\n else:\n _par = getattr(_n.par, _pn, None)\n if _par is None:\n report[\"fatal\"] = \"Target parameter not found: %s\" % _target\n else:\n _PM = type(_par.mode)\n _par.expr = _expr; _par.mode = _PM.EXPRESSION\n report[\"bound\"] = _target\n else:\n report[\"fatal\"] = \"Unknown mode: %s\" % str(_mode)\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildLearnScript(payload: object): string {\n return buildPayloadScript(LEARN_SCRIPT, payload);\n}\n\nexport async function learnControlImpl(ctx: ToolContext, args: LearnControlArgs) {\n if (args.mode === \"bind\" && !args.target) {\n return errorResult(\"A target ('nodePath.parName') is required for mode 'bind'.\");\n }\n return guardTd(\n async () => {\n const script = buildLearnScript({\n mode: args.mode,\n source_chop: args.source_chop,\n target: args.target ?? null,\n scale: args.scale,\n offset: args.offset,\n parent_path: args.parent_path,\n // Normalized minimum-movement gate for mode:'bind'. Default lives here (kept out of\n // the schema so the field stays .optional() and doesn't become required in z.infer).\n min_delta: args.min_delta ?? 0.05,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<LearnReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`learn_control (${report.mode}) failed: ${report.fatal}`, report);\n }\n let summary: string;\n if (report.mode === \"snapshot\") {\n summary = `Snapshotted ${report.channel_count ?? 0} channel(s) of ${report.source_chop}. Wiggle one hardware control, then call learn_control mode:'bind'.`;\n } else {\n const delta =\n typeof report.matched_delta === \"number\" ? report.matched_delta.toFixed(4) : \"?\";\n const norm =\n typeof report.matched_norm === \"number\"\n ? ` / ${report.matched_norm.toFixed(4)} normalized`\n : \"\";\n summary = `Matched channel '${report.matched_channel}' (moved by ${delta}${norm}) and bound ${report.bound} to it (${report.expression}).`;\n }\n if (report.warnings.length) summary += ` ${report.warnings.length} warning(s).`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerLearnControl: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"learn_control\",\n {\n title: \"Learn control (MIDI/OSC learn)\",\n description:\n \"EXPERIMENTAL two-step 'MIDI learn'. Call once with mode:'snapshot' (controls at rest) to record every channel of an input CHOP (a midiin/oscin CHOP or a Null fed by one); then wiggle one hardware knob/fader and call again with mode:'bind' — it diffs against the snapshot, finds the channel that moved the most, and binds your target parameter to it by expression (with optional scale/offset). The snapshot is kept in the parent COMP's storage between the two calls. This is live/stateful: verify the matched channel in the report.\",\n inputSchema: learnControlSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => learnControlImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const manageCheckpointSchema = z.object({\n action: z\n .enum([\"store\", \"restore\", \"list\", \"delete\"])\n .describe(\n \"store a full snapshot of a sub-network, restore one, list all, or delete one. A checkpoint is an 'undo point' before risky live edits.\",\n ),\n comp_path: z\n .string()\n .default(\"/project1\")\n .describe(\"Root COMP whose whole sub-network the checkpoint captures.\"),\n name: z.string().optional().describe(\"Checkpoint name (required for store/restore/delete).\"),\n prune_created: z\n .boolean()\n .default(true)\n .describe(\"(restore) Destroy nodes that were created after the checkpoint was stored.\"),\n recreate_deleted: z\n .boolean()\n .default(true)\n .describe(\n \"(restore) Recreate nodes that were deleted after the checkpoint (type + params + wiring, best-effort).\",\n ),\n});\ntype ManageCheckpointArgs = z.infer<typeof manageCheckpointSchema>;\n\ninterface CheckpointReport {\n action: string;\n comp: string;\n name?: string;\n nodes?: number;\n connections?: number;\n checkpoints?: string[];\n deleted?: string;\n restored_params?: number;\n recreated?: string[];\n rewired?: number;\n pruned?: string[];\n warnings: string[];\n fatal?: string;\n}\n\n// One Python pass. Checkpoints live in the root COMP's storage under one key, as\n// { name: { nodes: [{rel,type,x,y,params}], connections: [{src,so,dst,ti}] } }, so they\n// persist with the .toe. Paths are stored relative to the COMP so a restore is robust to\n// the COMP itself moving. Only constant-mode, non-read-only parameters are captured —\n// expression/exported parameters are derived and restore themselves.\nconst CHECKPOINT_SCRIPT = `\nimport json, base64, traceback\nimport td # operator classes for recreate live on the td module; exec globals don't expose 'td'\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nKEY = \"tdmcp_checkpoints\"\nreport = {\"action\": _p[\"action\"], \"comp\": _p[\"comp\"], \"warnings\": []}\n_c = op(_p[\"comp\"])\ntry:\n if _c is None:\n report[\"fatal\"] = \"COMP not found: \" + _p[\"comp\"]\n elif not hasattr(_c, \"store\") or not hasattr(_c, \"findChildren\"):\n report[\"fatal\"] = _p[\"comp\"] + \" cannot hold checkpoints (not a COMP).\"\n else:\n _store = dict(_c.fetch(KEY, {}))\n _base = _c.path\n _action = _p[\"action\"]; _name = _p.get(\"name\")\n def _rel(path):\n return path[len(_base):].lstrip(\"/\")\n def _optype(n):\n return getattr(n, \"OPType\", None) or getattr(n, \"type\", \"\") or \"\"\n if _action == \"list\":\n report[\"checkpoints\"] = sorted(_store.keys())\n elif _action == \"delete\":\n if _name in _store:\n _store.pop(_name, None); _c.store(KEY, _store); report[\"deleted\"] = _name\n else:\n report[\"warnings\"].append(\"Checkpoint not found: \" + str(_name))\n report[\"checkpoints\"] = sorted(_store.keys())\n elif _action == \"store\":\n _children = _c.findChildren()\n _nodes = []\n for _ch in _children:\n _params = {}\n try:\n for _par in _ch.pars():\n try:\n _PM = type(_par.mode)\n if _par.mode != _PM.CONSTANT or getattr(_par, \"readOnly\", False):\n continue\n _v = _par.eval()\n try:\n json.dumps(_v)\n except Exception:\n _v = str(_v)\n _params[_par.name] = _v\n except Exception:\n pass\n except Exception:\n pass\n _nodes.append({\n \"rel\": _rel(_ch.path), \"type\": _optype(_ch),\n \"x\": getattr(_ch, \"nodeX\", 0), \"y\": getattr(_ch, \"nodeY\", 0),\n \"params\": _params,\n })\n _conns = []\n for _ch in _children:\n for _i, _conn in enumerate(getattr(_ch, \"inputConnectors\", [])):\n for _src in getattr(_conn, \"connections\", []):\n _owner = getattr(_src, \"owner\", None)\n if _owner is None:\n continue\n _conns.append({\n \"src\": _rel(_owner.path), \"so\": int(getattr(_src, \"index\", 0) or 0),\n \"dst\": _rel(_ch.path), \"ti\": _i,\n })\n _store[_name] = {\"nodes\": _nodes, \"connections\": _conns}\n _c.store(KEY, _store)\n report[\"name\"] = _name; report[\"nodes\"] = len(_nodes); report[\"connections\"] = len(_conns)\n elif _action == \"restore\":\n if _name not in _store:\n report[\"fatal\"] = \"Checkpoint not found: '%s' (available: %s)\" % (_name, \", \".join(sorted(_store.keys())) or \"none\")\n else:\n _snap = _store[_name]\n _snap_nodes = _snap.get(\"nodes\", [])\n _snap_rels = set(_n[\"rel\"] for _n in _snap_nodes)\n _cur = {}\n for _ch in _c.findChildren():\n _cur[_rel(_ch.path)] = _ch\n _recreated = []\n if _p.get(\"recreate_deleted\", True):\n _missing = [_n for _n in _snap_nodes if _n[\"rel\"] not in _cur]\n _missing.sort(key=lambda _n: _n[\"rel\"].count(\"/\"))\n for _n in _missing:\n _rl = _n[\"rel\"]\n _pr = _rl.rsplit(\"/\", 1)[0] if \"/\" in _rl else \"\"\n _nm = _rl.rsplit(\"/\", 1)[-1]\n _parent = _c if _pr == \"\" else op(_base + \"/\" + _pr)\n if _parent is None:\n report[\"warnings\"].append(\"Could not recreate %s (parent missing).\" % _rl); continue\n _cls = getattr(td, _n[\"type\"], None)\n if _cls is None:\n report[\"warnings\"].append(\"Could not recreate %s (unknown type %s).\" % (_rl, _n[\"type\"])); continue\n try:\n _new = _parent.create(_cls, _nm)\n try:\n _new.nodeX = _n.get(\"x\", 0); _new.nodeY = _n.get(\"y\", 0)\n except Exception:\n pass\n _cur[_rl] = _new; _recreated.append(_rl)\n except Exception:\n report[\"warnings\"].append(\"Failed to recreate %s: %s\" % (_rl, traceback.format_exc().splitlines()[-1]))\n _restored = 0\n for _n in _snap_nodes:\n _node = _cur.get(_n[\"rel\"])\n if _node is None:\n continue\n for _pn, _pv in (_n.get(\"params\") or {}).items():\n try:\n _par = getattr(_node.par, _pn, None)\n if _par is None:\n continue\n _PM = type(_par.mode)\n if _par.mode != _PM.CONSTANT or getattr(_par, \"readOnly\", False):\n continue\n _par.val = _pv; _restored += 1\n except Exception:\n pass\n _rewired = 0\n if _recreated:\n _rset = set(_recreated)\n for _cn in _snap.get(\"connections\", []):\n if _cn[\"src\"] not in _rset and _cn[\"dst\"] not in _rset:\n continue\n _s = _cur.get(_cn[\"src\"]); _d = _cur.get(_cn[\"dst\"])\n if _s is None or _d is None:\n continue\n try:\n _d.inputConnectors[_cn[\"ti\"]].connect(_s.outputConnectors[_cn[\"so\"]]); _rewired += 1\n except Exception:\n report[\"warnings\"].append(\"Could not rewire %s -> %s.\" % (_cn[\"src\"], _cn[\"dst\"]))\n _pruned = []\n if _p.get(\"prune_created\", True):\n _extra = [_r for _r in _cur.keys() if _r not in _snap_rels]\n _extra.sort(key=lambda _r: _r.count(\"/\"), reverse=True)\n for _r in _extra:\n _node = op(_base + \"/\" + _r)\n if _node is None:\n continue\n try:\n _node.destroy(); _pruned.append(_r)\n except Exception:\n report[\"warnings\"].append(\"Could not prune %s.\" % _r)\n report[\"name\"] = _name; report[\"restored_params\"] = _restored\n report[\"recreated\"] = _recreated; report[\"rewired\"] = _rewired; report[\"pruned\"] = _pruned\n else:\n report[\"fatal\"] = \"Unknown action: \" + str(_action)\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildCheckpointScript(payload: object): string {\n return buildPayloadScript(CHECKPOINT_SCRIPT, payload);\n}\n\nexport async function manageCheckpointImpl(ctx: ToolContext, args: ManageCheckpointArgs) {\n if (args.action !== \"list\" && !args.name) {\n return errorResult(`A checkpoint name is required for the '${args.action}' action.`);\n }\n return guardTd(\n async () => {\n const script = buildCheckpointScript({\n action: args.action,\n comp: args.comp_path,\n name: args.name,\n prune_created: args.prune_created,\n recreate_deleted: args.recreate_deleted,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<CheckpointReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Checkpoint ${report.action} failed: ${report.fatal}`, report);\n }\n let summary: string;\n switch (report.action) {\n case \"store\":\n summary = `Stored checkpoint \"${report.name}\" on ${report.comp}: ${report.nodes ?? 0} node(s), ${report.connections ?? 0} connection(s).`;\n break;\n case \"restore\": {\n const parts = [`${report.restored_params ?? 0} parameter(s) restored`];\n if (report.recreated?.length) parts.push(`${report.recreated.length} node(s) recreated`);\n if (report.rewired) parts.push(`${report.rewired} wire(s) reconnected`);\n if (report.pruned?.length) parts.push(`${report.pruned.length} node(s) pruned`);\n summary = `Restored checkpoint \"${report.name}\" on ${report.comp}: ${parts.join(\", \")}.`;\n break;\n }\n case \"delete\":\n summary = report.deleted\n ? `Deleted checkpoint \"${report.deleted}\" on ${report.comp}.`\n : `No checkpoint to delete on ${report.comp}.`;\n break;\n default:\n summary = `${report.checkpoints?.length ?? 0} checkpoint(s) on ${report.comp}: ${report.checkpoints?.join(\", \") || \"none\"}.`;\n }\n if (report.warnings.length) summary += ` ${report.warnings.length} warning(s).`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerManageCheckpoint: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"manage_checkpoint\",\n {\n title: \"Manage checkpoint\",\n description:\n \"Store / restore / list / delete a full snapshot of a sub-network — an 'undo point' to take before risky live edits. A checkpoint captures every node's constant parameters, the wiring, and node positions. Restoring reapplies parameters, recreates nodes that were deleted since (with their wiring), and prunes nodes that were created since. Unlike manage_presets (custom-parameter looks for performance), this captures the whole network for safe experimentation.\",\n inputSchema: manageCheckpointSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n },\n (args) => manageCheckpointImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const manageComponentSchema = z.object({\n action: z\n .enum([\"save\", \"load\"])\n .describe(\"save a COMP to a .tox file, or load a .tox into the project.\"),\n file_path: z\n .string()\n .describe(\"Absolute path to the .tox file (e.g. '/Users/me/components/widget.tox').\"),\n comp_path: z\n .string()\n .optional()\n .describe(\"(save) The COMP to save as a reusable .tox component.\"),\n parent_path: z\n .string()\n .default(\"/project1\")\n .describe(\"(load) COMP to place the loaded component inside.\"),\n linked: z\n .boolean()\n .default(false)\n .describe(\n \"(load) Create a live-linked instance (externaltox) that re-reads the file on change, instead of an independent copy.\",\n ),\n name: z\n .string()\n .optional()\n .describe(\"(load, linked) Name for the linked COMP; defaults to the file name.\"),\n create_folders: z\n .boolean()\n .default(false)\n .describe(\"(save) Create the parent folders if they do not exist.\"),\n});\ntype ManageComponentArgs = z.infer<typeof manageComponentSchema>;\n\ninterface ComponentReport {\n action: string;\n file_path: string;\n saved?: string;\n size?: number | null;\n loaded?: string;\n linked?: boolean;\n type?: string;\n children?: string[];\n warnings: string[];\n fatal?: string;\n}\n\n// .tox save/load is a COMP file operation with no structured bridge endpoint.\n// `loadTox` drops an independent copy under the parent; `externaltox` makes a\n// live-linked instance that re-reads the file. The file runs inside TouchDesigner,\n// so paths are on the machine running TD.\nconst COMPONENT_SCRIPT = `\nimport json, base64, traceback, os\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nreport = {\"action\": _p[\"action\"], \"file_path\": _p[\"file_path\"], \"warnings\": []}\ntry:\n _action = _p[\"action\"]; _fp = _p[\"file_path\"]\n if _action == \"save\":\n _c = op(_p.get(\"comp\"))\n if _c is None:\n report[\"fatal\"] = \"COMP not found: \" + str(_p.get(\"comp\"))\n elif not _c.isCOMP:\n report[\"fatal\"] = str(_p.get(\"comp\")) + \" is not a COMP, so it cannot be saved as a .tox.\"\n else:\n _saved = _c.save(_fp, createFolders=bool(_p.get(\"create_folders\")))\n report[\"saved\"] = str(_saved)\n report[\"size\"] = os.path.getsize(_fp) if os.path.isfile(_fp) else None\n elif _action == \"load\":\n if not os.path.isfile(_fp):\n report[\"fatal\"] = \"File not found: \" + _fp\n else:\n _parent = op(_p[\"parent\"])\n if _parent is None:\n report[\"fatal\"] = \"Parent COMP not found: \" + str(_p[\"parent\"])\n elif _p.get(\"linked\"):\n _stem = os.path.splitext(os.path.basename(_fp))[0]\n _new = _parent.create(baseCOMP, _p.get(\"name\") or _stem)\n _new.par.externaltox = _fp\n try:\n _new.par.reinitnet.pulse()\n except Exception:\n pass\n report[\"loaded\"] = _new.path; report[\"linked\"] = True\n report[\"type\"] = _new.type; report[\"children\"] = sorted([c.name for c in _new.children])\n else:\n _new = _parent.loadTox(_fp)\n if _new is None:\n report[\"fatal\"] = \"loadTox produced no component from \" + _fp\n else:\n report[\"loaded\"] = _new.path; report[\"linked\"] = False\n report[\"type\"] = _new.type; report[\"children\"] = sorted([c.name for c in _new.children])\n else:\n report[\"fatal\"] = \"Unknown action: \" + str(_action)\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildComponentScript(payload: object): string {\n return buildPayloadScript(COMPONENT_SCRIPT, payload);\n}\n\nexport async function manageComponentImpl(ctx: ToolContext, args: ManageComponentArgs) {\n if (args.action === \"save\" && !args.comp_path) {\n return errorResult(\"A `comp_path` is required to save a component.\");\n }\n return guardTd(\n async () => {\n const script = buildComponentScript({\n action: args.action,\n file_path: args.file_path,\n comp: args.comp_path ?? null,\n parent: args.parent_path,\n linked: args.linked,\n name: args.name ?? null,\n create_folders: args.create_folders,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<ComponentReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Component ${report.action} failed: ${report.fatal}`, report);\n }\n const summary =\n report.action === \"save\"\n ? `Saved ${args.comp_path} to ${report.saved}${report.size != null ? ` (${report.size} bytes)` : \"\"}.`\n : `Loaded ${report.loaded}${report.linked ? \" (live-linked)\" : \"\"} from ${report.file_path}${\n report.children?.length ? ` — ${report.children.length} child node(s)` : \"\"\n }.`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerManageComponent: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"manage_component\",\n {\n title: \"Save / load component (.tox)\",\n description:\n \"Build a reusable component library: save any COMP as a .tox file, or load a .tox back into the project (as an independent copy, or a live-linked instance via `linked`). Paths are on the machine running TouchDesigner.\",\n inputSchema: manageComponentSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => manageComponentImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const managePresetsSchema = z.object({\n action: z\n .enum([\"store\", \"recall\", \"list\", \"delete\"])\n .describe(\"store a snapshot, recall one, list all, or delete one.\"),\n comp_path: z\n .string()\n .default(\"/project1\")\n .describe(\n \"COMP whose parameter values the preset captures — usually a control-panel container.\",\n ),\n name: z.string().optional().describe(\"Preset name (required for store/recall/delete).\"),\n params: z\n .array(z.string())\n .optional()\n .describe(\n \"Specific custom-parameter names to capture/restore. Defaults to every custom parameter on the COMP.\",\n ),\n});\ntype ManagePresetsArgs = z.infer<typeof managePresetsSchema>;\n\ninterface PresetReport {\n action: string;\n comp: string;\n name?: string;\n captured?: string[];\n restored?: string[];\n deleted?: string;\n presets?: string[];\n warnings: string[];\n fatal?: string;\n}\n\n// Presets live in the COMP's storage under one key, as { presetName: { parName: value } }.\n// Storage persists with the .toe, so snapshots survive a save/reload. Recalling writes\n// values back onto the (constant-mode) custom parameters, which propagates through any\n// bindings created by create_control_panel.\nconst PRESETS_SCRIPT = `\nimport json, base64, traceback\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nKEY = \"tdmcp_presets\"\nreport = {\"action\": _p[\"action\"], \"comp\": _p[\"comp\"], \"warnings\": []}\n_c = op(_p[\"comp\"])\ntry:\n if _c is None:\n report[\"fatal\"] = \"COMP not found: \" + _p[\"comp\"]\n elif not hasattr(_c, \"customPars\"):\n report[\"fatal\"] = _p[\"comp\"] + \" is not a COMP, so it has no custom parameters to snapshot.\"\n else:\n _store = dict(_c.fetch(KEY, {}))\n _action = _p[\"action\"]; _name = _p.get(\"name\")\n if _action == \"list\":\n report[\"presets\"] = sorted(_store.keys())\n elif _action == \"store\":\n _wanted = _p.get(\"params\") or None\n _pars = list(_c.customPars) if _wanted is None else [getattr(_c.par, n, None) for n in _wanted]\n _vals = {}\n for _pr in _pars:\n if _pr is None:\n continue\n _vals[_pr.name] = _pr.eval()\n _store[_name] = _vals; _c.store(KEY, _store)\n report[\"name\"] = _name; report[\"captured\"] = sorted(_vals.keys()); report[\"presets\"] = sorted(_store.keys())\n elif _action == \"recall\":\n if _name not in _store:\n report[\"fatal\"] = \"Preset not found: '%s' (available: %s)\" % (_name, \", \".join(sorted(_store.keys())) or \"none\")\n else:\n _restored = []\n for _nm, _v in _store[_name].items():\n _pr = getattr(_c.par, _nm, None)\n if _pr is None:\n report[\"warnings\"].append(\"Parameter no longer exists: \" + _nm); continue\n if _pr.readOnly:\n report[\"warnings\"].append(\"Parameter is read-only: \" + _nm); continue\n try:\n _pr.val = _v; _restored.append(_nm)\n except Exception:\n report[\"warnings\"].append(\"Could not restore \" + _nm)\n report[\"name\"] = _name; report[\"restored\"] = sorted(_restored)\n elif _action == \"delete\":\n if _name in _store:\n _store.pop(_name, None); _c.store(KEY, _store); report[\"deleted\"] = _name\n else:\n report[\"warnings\"].append(\"Preset not found: \" + str(_name))\n report[\"presets\"] = sorted(_store.keys())\n else:\n report[\"fatal\"] = \"Unknown action: \" + str(_action)\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildPresetsScript(payload: object): string {\n return buildPayloadScript(PRESETS_SCRIPT, payload);\n}\n\nexport async function managePresetsImpl(ctx: ToolContext, args: ManagePresetsArgs) {\n if (args.action !== \"list\" && !args.name) {\n return errorResult(`A preset name is required for the '${args.action}' action.`);\n }\n return guardTd(\n async () => {\n const script = buildPresetsScript({\n action: args.action,\n comp: args.comp_path,\n name: args.name,\n params: args.params ?? null,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<PresetReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Preset ${report.action} failed: ${report.fatal}`, report);\n }\n let summary: string;\n switch (report.action) {\n case \"store\":\n summary = `Stored preset \"${report.name}\" (${report.captured?.length ?? 0} parameter(s)) on ${report.comp}.`;\n break;\n case \"recall\":\n summary = `Recalled preset \"${report.name}\" (${report.restored?.length ?? 0} parameter(s) restored) on ${report.comp}.`;\n break;\n case \"delete\":\n summary = report.deleted\n ? `Deleted preset \"${report.deleted}\" on ${report.comp}.`\n : `No preset to delete on ${report.comp}.`;\n break;\n default:\n summary = `${report.presets?.length ?? 0} preset(s) on ${report.comp}: ${report.presets?.join(\", \") || \"none\"}.`;\n }\n if (report.warnings.length) summary += ` ${report.warnings.length} warning(s).`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerManagePresets: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"manage_presets\",\n {\n title: \"Manage presets\",\n description:\n \"Store, recall, list, or delete named snapshots of a COMP's parameter values — the live-performance preset system. Pair with create_control_panel: snapshot the knob positions and jump between looks. Snapshots are saved in the COMP's storage so they persist with the project.\",\n inputSchema: managePresetsSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => managePresetsImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const randomizeControlsSchema = z.object({\n comp_path: z\n .string()\n .default(\"/project1\")\n .describe(\"COMP whose custom parameters to randomize (usually a control-panel container).\"),\n params: z\n .array(z.string())\n .optional()\n .describe(\"Specific custom-parameter names to randomize. Defaults to every numeric one.\"),\n amount: z.coerce\n .number()\n .min(0)\n .max(1)\n .default(1)\n .describe(\n \"How far to move toward a random value in range: 1 = fully random, 0.2 = a gentle nudge from the current value. Lets you improvise without losing the current look.\",\n ),\n seed: z.coerce.number().int().optional().describe(\"Optional RNG seed for repeatable results.\"),\n});\ntype RandomizeControlsArgs = z.infer<typeof randomizeControlsSchema>;\n\ninterface RandomizeReport {\n comp: string;\n randomized: Array<{ name: string; value: number }>;\n skipped: string[];\n warnings: string[];\n fatal?: string;\n}\n\n// One Python pass: for each numeric custom parameter, pick a value in its slider range\n// (normMin..normMax) and blend toward it by `amount`. Non-numeric params (toggles, menus,\n// strings) are skipped, so a randomize is always safe to fire live.\nconst RANDOMIZE_SCRIPT = `\nimport json, base64, traceback, random\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nreport = {\"comp\": _p[\"comp\"], \"randomized\": [], \"skipped\": [], \"warnings\": []}\n_c = op(_p[\"comp\"])\ntry:\n if _c is None:\n report[\"fatal\"] = \"COMP not found: \" + _p[\"comp\"]\n elif not hasattr(_c, \"customPars\"):\n report[\"fatal\"] = _p[\"comp\"] + \" is not a COMP, so it has no custom parameters.\"\n else:\n if _p.get(\"seed\") is not None:\n random.seed(_p[\"seed\"])\n _amt = _p[\"amount\"]\n _wanted = _p.get(\"params\")\n _pars = list(_c.customPars) if not _wanted else [getattr(_c.par, n, None) for n in _wanted]\n for _par in _pars:\n if _par is None:\n continue\n if not getattr(_par, \"isNumber\", False) or _par.readOnly:\n report[\"skipped\"].append(getattr(_par, \"name\", \"?\")); continue\n _lo = _par.normMin; _hi = _par.normMax\n if _lo is None or _hi is None or _hi <= _lo:\n report[\"skipped\"].append(_par.name); continue\n try:\n _old = float(_par.eval())\n except Exception:\n _old = _lo\n _r = random.uniform(_lo, _hi)\n _new = _old * (1 - _amt) + _r * _amt\n if _par.style == \"Int\":\n _new = int(round(_new))\n try:\n _par.val = _new\n report[\"randomized\"].append({\"name\": _par.name, \"value\": _new})\n except Exception:\n report[\"warnings\"].append(\"Could not set \" + _par.name)\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildRandomizeScript(payload: object): string {\n return buildPayloadScript(RANDOMIZE_SCRIPT, payload);\n}\n\nexport async function randomizeControlsImpl(ctx: ToolContext, args: RandomizeControlsArgs) {\n return guardTd(\n async () => {\n const script = buildRandomizeScript({\n comp: args.comp_path,\n params: args.params ?? null,\n amount: args.amount,\n seed: args.seed ?? null,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<RandomizeReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Randomize failed: ${report.fatal}`, report);\n }\n const summary = `Randomized ${report.randomized.length} control(s) on ${report.comp} (amount ${args.amount})${\n report.skipped.length ? `, skipped ${report.skipped.length} non-numeric` : \"\"\n }.`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerRandomizeControls: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"randomize_controls\",\n {\n title: \"Randomize controls\",\n description:\n \"Randomize a COMP's numeric custom parameters within their slider ranges — an instant new variation for live improvisation. `amount` blends toward random (1 = fully random, low values nudge the current look). Non-numeric controls (toggles, menus) are left untouched, so it is always safe to fire. Pair with manage_presets/manage_cue to snapshot a happy accident.\",\n inputSchema: randomizeControlsSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => randomizeControlsImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nconst UpdateSchema = z.object({\n path: z.string(),\n parameters: z.record(z.string(), z.unknown()),\n});\n\nexport const setParametersBatchSchema = z.object({\n updates: z\n .array(UpdateSchema)\n .min(1)\n .describe(\n \"List of { path, parameters } updates sent in one batch request (per-update results; not transactional — a failed update does not roll back the others).\",\n ),\n});\ntype SetParametersBatchArgs = z.infer<typeof setParametersBatchSchema>;\n\nexport async function setParametersBatchImpl(ctx: ToolContext, args: SetParametersBatchArgs) {\n return guardTd(\n () =>\n ctx.client.batch(\n args.updates.map((update) => ({\n action: \"update\" as const,\n path: update.path,\n parameters: update.parameters,\n })),\n ),\n (result) => {\n const failed = result.results.filter((r) => !r.ok);\n const okCount = result.results.length - failed.length;\n const summary = failed.length\n ? `Applied ${okCount}/${result.results.length} parameter update(s); ${failed.length} failed (see results).`\n : `Applied ${okCount} parameter update(s) in one batch.`;\n return jsonResult(summary, result);\n },\n );\n}\n\nexport const registerSetParametersBatch: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"set_parameters_batch\",\n {\n title: \"Set parameters (batch)\",\n description:\n \"Update parameters on multiple nodes in a single batch request. Each update reports its own success; a failure does not roll back the others.\",\n inputSchema: setParametersBatchSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => setParametersBatchImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const compareTdNodesSchema = z.object({\n path_a: z.string().describe(\"First node path.\"),\n path_b: z.string().describe(\"Second node path.\"),\n only_diff: z\n .boolean()\n .default(true)\n .describe(\"Return only the parameters that differ (true) or also list the identical ones.\"),\n});\ntype CompareTdNodesArgs = z.infer<typeof compareTdNodesSchema>;\n\nexport const compareTdNodesOutputSchema = z.object({\n a: z.string(),\n b: z.string(),\n type_a: z.string(),\n type_b: z.string(),\n type_match: z.boolean(),\n differing_count: z.number(),\n same_count: z.number(),\n differing: z.array(z.object({ param: z.string(), a: z.unknown(), b: z.unknown() })),\n identical: z.array(z.string()).optional(),\n});\n\nexport async function compareTdNodesImpl(ctx: ToolContext, args: CompareTdNodesArgs) {\n return guardTd(\n async () => {\n const [a, b] = await Promise.all([\n ctx.client.getNode(args.path_a),\n ctx.client.getNode(args.path_b),\n ]);\n return { a, b };\n },\n ({ a, b }) => {\n const keys = new Set([...Object.keys(a.parameters), ...Object.keys(b.parameters)]);\n const differing: Array<{ param: string; a: unknown; b: unknown }> = [];\n const identical: string[] = [];\n for (const key of [...keys].sort()) {\n const va = a.parameters[key];\n const vb = b.parameters[key];\n if (JSON.stringify(va) === JSON.stringify(vb)) identical.push(key);\n else differing.push({ param: key, a: va, b: vb });\n }\n const data: Record<string, unknown> = {\n a: a.path,\n b: b.path,\n type_a: a.type,\n type_b: b.type,\n type_match: a.type === b.type,\n differing_count: differing.length,\n same_count: identical.length,\n differing,\n };\n if (!args.only_diff) data.identical = identical;\n return structuredResult(\n `${differing.length} differing parameter(s) between ${a.path} and ${b.path}${a.type === b.type ? \"\" : ` (types differ: ${a.type} vs ${b.type})`}.`,\n data,\n );\n },\n );\n}\n\nexport const registerCompareTdNodes: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"compare_td_nodes\",\n {\n title: \"Compare two nodes\",\n description:\n \"Diff the parameters of two nodes, returning only the values that differ (by default). Useful for aligning settings across similar operators.\",\n inputSchema: compareTdNodesSchema.shape,\n outputSchema: compareTdNodesOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => compareTdNodesImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const createTdNodeSchema = z.object({\n parent_path: z\n .string()\n .default(\"/project1\")\n .describe(\"Parent COMP path to create the node inside.\"),\n type: z\n .string()\n .describe(\"Operator type string, e.g. 'noiseTOP', 'feedbackTOP', 'nullTOP', 'constantCHOP'.\"),\n name: z.string().optional().describe(\"Optional node name (auto-generated if omitted).\"),\n parameters: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\"Optional initial parameter overrides as key→value pairs.\"),\n});\ntype CreateTdNodeArgs = z.infer<typeof createTdNodeSchema>;\n\nexport async function createTdNodeImpl(ctx: ToolContext, args: CreateTdNodeArgs) {\n const warnings: string[] = [];\n if (!ctx.knowledge.operatorExists(args.type)) {\n const suggestions = ctx.knowledge.searchOperators(args.type, 3).map((s) => s.name);\n warnings.push(\n `Operator type \"${args.type}\" was not found in the knowledge base.${\n suggestions.length ? ` Did you mean: ${suggestions.join(\", \")}?` : \"\"\n }`,\n );\n }\n return guardTd(\n () =>\n ctx.client.createNode({\n parent_path: args.parent_path,\n type: args.type,\n name: args.name,\n parameters: args.parameters,\n }),\n (node) => {\n const allWarnings = [...warnings];\n if (node.parameter_warnings?.length) {\n allWarnings.push(\n `These parameter(s) were not applied (unknown name or bad value): ${node.parameter_warnings.join(\", \")}.`,\n );\n }\n return jsonResult(`Created ${node.type || args.type} at ${node.path}.`, {\n node,\n warnings: allWarnings,\n });\n },\n );\n}\n\nexport const registerCreateTdNode: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"create_td_node\",\n {\n title: \"Create TouchDesigner node\",\n description:\n \"Create a single operator (node) inside a parent COMP. Validates the operator type against the knowledge base and warns (without blocking) on unknown types.\",\n inputSchema: createTdNodeSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => createTdNodeImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const deleteTdNodeSchema = z.object({\n path: z.string().describe(\"Full path of the node to delete, e.g. '/project1/noise1'.\"),\n});\ntype DeleteTdNodeArgs = z.infer<typeof deleteTdNodeSchema>;\n\nexport async function deleteTdNodeImpl(ctx: ToolContext, args: DeleteTdNodeArgs) {\n return guardTd(\n () => ctx.client.deleteNode(args.path),\n (result) => jsonResult(`Deleted ${result.deleted}.`, result),\n );\n}\n\nexport const registerDeleteTdNode: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"delete_td_node\",\n {\n title: \"Delete TouchDesigner node\",\n description:\n \"Delete a single node by path. Destructive — only call this when the user explicitly asks to remove a node.\",\n inputSchema: deleteTdNodeSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n },\n (args) => deleteTdNodeImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nconst snapshotNodeSchema = z.object({\n path: z.string(),\n type: z.string().optional(),\n parameters: z.record(z.string(), z.unknown()).optional(),\n});\nconst snapshotConnSchema = z.object({\n source_path: z.string(),\n source_output: z.number().optional(),\n target_path: z.string(),\n target_input: z.number().optional(),\n});\nconst snapshotSchema = z.object({\n nodes: z.array(snapshotNodeSchema).default([]),\n connections: z.array(snapshotConnSchema).default([]),\n});\n\nexport const diffSnapshotsSchema = z.object({\n before: snapshotSchema.describe(\n \"Earlier snapshot (from snapshot_td_graph, include_params for param diffs).\",\n ),\n after: snapshotSchema.describe(\"Later snapshot to compare against.\"),\n});\ntype DiffSnapshotsArgs = z.infer<typeof diffSnapshotsSchema>;\n\ntype Snapshot = z.infer<typeof snapshotSchema>;\nconst connKey = (c: z.infer<typeof snapshotConnSchema>): string =>\n `${c.source_path}:${c.source_output ?? 0} -> ${c.target_path}:${c.target_input ?? 0}`;\n\nexport function diffSnapshots(before: Snapshot, after: Snapshot) {\n const beforeNodes = new Map(before.nodes.map((n) => [n.path, n]));\n const afterNodes = new Map(after.nodes.map((n) => [n.path, n]));\n\n const added = after.nodes.filter((n) => !beforeNodes.has(n.path)).map((n) => n.path);\n const removed = before.nodes.filter((n) => !afterNodes.has(n.path)).map((n) => n.path);\n\n const paramChanges: Array<{\n path: string;\n changes: Record<string, { from: unknown; to: unknown }>;\n }> = [];\n for (const [path, a] of afterNodes) {\n const b = beforeNodes.get(path);\n if (!b?.parameters || !a.parameters) continue;\n const changes: Record<string, { from: unknown; to: unknown }> = {};\n for (const [key, toVal] of Object.entries(a.parameters)) {\n const fromVal = b.parameters[key];\n if (JSON.stringify(fromVal) !== JSON.stringify(toVal))\n changes[key] = { from: fromVal, to: toVal };\n }\n if (Object.keys(changes).length > 0) paramChanges.push({ path, changes });\n }\n\n const beforeConns = new Set(before.connections.map(connKey));\n const afterConns = new Set(after.connections.map(connKey));\n const connectionsAdded = [...afterConns].filter((c) => !beforeConns.has(c));\n const connectionsRemoved = [...beforeConns].filter((c) => !afterConns.has(c));\n\n return {\n nodes_added: added,\n nodes_removed: removed,\n parameter_changes: paramChanges,\n connections_added: connectionsAdded,\n connections_removed: connectionsRemoved,\n unchanged:\n added.length + removed.length + paramChanges.length === 0 &&\n connectionsAdded.length + connectionsRemoved.length === 0,\n };\n}\n\nexport function diffSnapshotsImpl(_ctx: ToolContext, args: DiffSnapshotsArgs) {\n const diff = diffSnapshots(args.before, args.after);\n const summary = diff.unchanged\n ? \"No differences between the two snapshots.\"\n : `Diff: +${diff.nodes_added.length} / -${diff.nodes_removed.length} node(s), ${diff.parameter_changes.length} node(s) with parameter changes, +${diff.connections_added.length} / -${diff.connections_removed.length} connection(s).`;\n return structuredResult(summary, diff);\n}\n\nexport const registerDiffSnapshots: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"diff_snapshots\",\n {\n title: \"Diff snapshots\",\n description:\n \"Compare two network snapshots (from snapshot_td_graph) and return a readable diff: which nodes were added or removed, which connections changed, and which parameters changed (with before/after values). Snapshot before an edit and after to see exactly what changed, or to version a patch over time. Pure analysis — touches nothing in TouchDesigner.\",\n inputSchema: diffSnapshotsSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n (args) => diffSnapshotsImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nconst MAX_NODES = 150;\n\nexport const documentNetworkSchema = z.object({\n path: z.string().default(\"/project1\").describe(\"Network root to document.\"),\n recursive: z\n .boolean()\n .default(false)\n .describe(\"Include all descendants (otherwise just the direct children).\"),\n});\ntype DocumentNetworkArgs = z.infer<typeof documentNetworkSchema>;\n\n/** Operator family from a type like 'noiseTOP' → 'TOP'. */\nfunction family(type: string): string {\n const m = /(TOP|CHOP|SOP|COMP|DAT|MAT|POP)$/.exec(type);\n return m?.[1] ?? \"other\";\n}\n\n/** Builds a Mermaid flowchart + a grouped summary from a topology. */\nexport function buildDocument(\n path: string,\n nodes: Array<{ path: string; type: string; name: string }>,\n connections: Array<{ source_path: string; target_path: string }>,\n) {\n const truncated = nodes.length > MAX_NODES;\n const shown = nodes.slice(0, MAX_NODES);\n const id = new Map<string, string>();\n shown.forEach((n, i) => {\n id.set(n.path, `n${i}`);\n });\n\n const lines = [\"flowchart LR\"];\n for (const n of shown) {\n const label = `${n.name} (${n.type})`.replace(/\"/g, \"'\");\n lines.push(` ${id.get(n.path)}[\"${label}\"]`);\n }\n for (const c of connections) {\n const from = id.get(c.source_path);\n const to = id.get(c.target_path);\n if (from && to) lines.push(` ${from} --> ${to}`);\n }\n const mermaid = lines.join(\"\\n\");\n\n const byFamily: Record<string, number> = {};\n const byType: Record<string, number> = {};\n for (const n of nodes) {\n byFamily[family(n.type)] = (byFamily[family(n.type)] ?? 0) + 1;\n byType[n.type] = (byType[n.type] ?? 0) + 1;\n }\n const topTypes = Object.entries(byType)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 8)\n .map(([t, n]) => `${t}×${n}`);\n\n return {\n path,\n nodeCount: nodes.length,\n connectionCount: connections.length,\n families: byFamily,\n top_types: topTypes,\n truncated,\n mermaid,\n };\n}\n\nexport async function documentNetworkImpl(ctx: ToolContext, args: DocumentNetworkArgs) {\n return guardTd(\n () => ctx.client.getNetworkTopology(args.path, args.recursive),\n (topology) => {\n const doc = buildDocument(args.path, topology.nodes, topology.connections);\n const summary = `${args.path}: ${doc.nodeCount} node(s), ${doc.connectionCount} connection(s) — ${doc.top_types.join(\", \")}${\n doc.truncated ? ` (diagram capped at ${MAX_NODES})` : \"\"\n }.`;\n return structuredResult(summary, doc);\n },\n );\n}\n\nexport const registerDocumentNetwork: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"document_network\",\n {\n title: \"Document network\",\n description:\n \"Document an EXISTING network: read its nodes and connections and return a readable map — counts by operator family and type, plus a Mermaid flowchart of the data flow you can paste into docs. Unlike plan_visual (which plans from a description), this describes what's actually in the project. Use it to explain or hand off a patch.\",\n inputSchema: documentNetworkSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => documentNetworkImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const execNodeMethodSchema = z.object({\n path: z.string().describe(\"Full path of the node to call the method on.\"),\n method: z.string().describe(\"Method name to call, e.g. 'cook', 'par', 'destroy', 'copy'.\"),\n args: z.array(z.unknown()).default([]).describe(\"Positional arguments.\"),\n kwargs: z.record(z.string(), z.unknown()).default({}).describe(\"Keyword arguments.\"),\n});\ntype ExecNodeMethodArgs = z.infer<typeof execNodeMethodSchema>;\n\nexport async function execNodeMethodImpl(ctx: ToolContext, args: ExecNodeMethodArgs) {\n return guardTd(\n () => ctx.client.execNodeMethod(args.path, args.method, args.args, args.kwargs),\n (result) => jsonResult(`Called ${args.path}.${args.method}().`, result),\n );\n}\n\nexport const registerExecNodeMethod: ToolRegistrar = (server, ctx) => {\n if (ctx.allowRawPython === false) return;\n server.registerTool(\n \"exec_node_method\",\n {\n title: \"Call node method\",\n description:\n \"Escape hatch — invoke an arbitrary Python method on a node (operator). Prefer structured tools where one exists; use this for operations they don't cover (e.g. .cook(), .copy(), .destroy()).\",\n inputSchema: execNodeMethodSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n },\n (args) => execNodeMethodImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const executePythonScriptSchema = z.object({\n script: z\n .string()\n .min(1)\n .describe(\n \"Python source to execute inside TouchDesigner (runs in the TD process, not locally).\",\n ),\n return_output: z\n .boolean()\n .default(true)\n .describe(\"Capture stdout / the value of the last expression and return it.\"),\n});\ntype ExecutePythonScriptArgs = z.infer<typeof executePythonScriptSchema>;\n\nexport async function executePythonScriptImpl(ctx: ToolContext, args: ExecutePythonScriptArgs) {\n return guardTd(\n () => ctx.client.executePythonScript(args.script, args.return_output),\n (result) => jsonResult(\"Python executed in TouchDesigner.\", result),\n );\n}\n\nexport const registerExecutePythonScript: ToolRegistrar = (server, ctx) => {\n if (ctx.allowRawPython === false) return;\n server.registerTool(\n \"execute_python_script\",\n {\n title: \"Execute Python in TouchDesigner\",\n description:\n \"Escape hatch — run an arbitrary Python script inside the TouchDesigner process. Prefer the structured tools (find_td_nodes, get_td_node_parameters, update_td_node_parameters, summarize_td_errors, snapshot_td_graph, …); reach for this only when no structured tool can express the operation. Code runs in TD only, never on the local machine.\",\n inputSchema: executePythonScriptSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n },\n (args) => executePythonScriptImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { NodeRefSchema } from \"../../td-client/validators.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { globToRegExp } from \"./nodeMatch.js\";\n\nexport const findTdNodesSchema = z.object({\n parent_path: z.string().default(\"/project1\").describe(\"Where to search from.\"),\n pattern: z\n .string()\n .optional()\n .describe(\"Case-insensitive name/path filter with '*' wildcards (e.g. 'text*', '*noise*').\"),\n type: z\n .string()\n .optional()\n .describe(\"Case-insensitive operator-type substring (e.g. 'TOP', 'noise').\"),\n recursive: z\n .boolean()\n .default(true)\n .describe(\"Search the whole sub-network (true) or only direct children (false).\"),\n path_only: z.boolean().default(false).describe(\"Return only matching paths.\"),\n limit: z.number().int().positive().default(50).describe(\"Max matches to return.\"),\n});\ntype FindTdNodesArgs = z.infer<typeof findTdNodesSchema>;\n\nexport const findTdNodesOutputSchema = z.object({\n parent_path: z.string(),\n recursive: z.boolean(),\n count: z.number(),\n truncated: z.boolean(),\n paths: z.array(z.string()).optional(),\n matches: z.array(NodeRefSchema).optional(),\n});\n\nexport async function findTdNodesImpl(ctx: ToolContext, args: FindTdNodesArgs) {\n const fetch = args.recursive\n ? async () => (await ctx.client.getNetworkTopology(args.parent_path, true)).nodes\n : async () => (await ctx.client.getNodes(args.parent_path)).nodes;\n\n return guardTd(fetch, (allNodes) => {\n let nodes = allNodes;\n if (args.pattern) {\n const re = globToRegExp(args.pattern);\n nodes = nodes.filter((n) => re.test(n.name) || re.test(n.path));\n }\n if (args.type) {\n const t = args.type.toLowerCase();\n nodes = nodes.filter((n) => n.type.toLowerCase().includes(t));\n }\n const count = nodes.length;\n const truncated = count > args.limit;\n nodes = nodes.slice(0, args.limit);\n const summary = `${count} match(es) under ${args.parent_path}${truncated ? ` (showing ${args.limit})` : \"\"}.`;\n const base = { parent_path: args.parent_path, recursive: args.recursive, count, truncated };\n return args.path_only\n ? structuredResult(summary, { ...base, paths: nodes.map((n) => n.path) })\n : structuredResult(summary, { ...base, matches: nodes });\n });\n}\n\nexport const registerFindTdNodes: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"find_td_nodes\",\n {\n title: \"Find TouchDesigner nodes\",\n description:\n \"Search a network for nodes by name pattern and/or operator type. Recursive by default; pass path_only:true for a compact path list. Prefer this over get_td_nodes when you are looking for specific nodes.\",\n inputSchema: findTdNodesSchema.shape,\n outputSchema: findTdNodesOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => findTdNodesImpl(ctx, args),\n );\n};\n","/** Turns a `*`-glob into a case-insensitive RegExp (other regex metachars are escaped). */\nexport function globToRegExp(pattern: string): RegExp {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(escaped, \"i\");\n}\n\n/** The parent path of a TD node path, e.g. `/project1/moviein1` -> `/project1`. */\nexport function parentOf(path: string): string {\n const idx = path.lastIndexOf(\"/\");\n return idx <= 0 ? \"/\" : path.slice(0, idx);\n}\n","import { z } from \"zod\";\nimport { jsonResult, textResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getModuleHelpSchema = z.object({\n name: z.string().describe(\"Class or module name to get help for, e.g. 'OP', 'App', 'Project'.\"),\n});\ntype GetModuleHelpArgs = z.infer<typeof getModuleHelpSchema>;\n\nexport function getModuleHelpImpl(ctx: ToolContext, args: GetModuleHelpArgs) {\n const cls = ctx.knowledge.getPythonClass(args.name);\n if (!cls) {\n const suggestions = ctx.knowledge\n .listPythonClasses()\n .filter((c) => c.className.toLowerCase().includes(args.name.toLowerCase()))\n .slice(0, 5)\n .map((c) => c.className);\n return jsonResult(`No help found for \"${args.name}\".`, { found: false, suggestions });\n }\n\n const lines: string[] = [`# ${cls.displayName || cls.className}`, \"\"];\n if (cls.description) lines.push(cls.description, \"\");\n if (cls.members && cls.members.length > 0) {\n lines.push(\"## Members\");\n for (const m of cls.members) {\n const ro = m.readOnly ? \" (read-only)\" : \"\";\n lines.push(`- ${m.name}${m.returnType ? `: ${m.returnType}` : \"\"}${ro}`);\n }\n lines.push(\"\");\n }\n if (cls.methods && cls.methods.length > 0) {\n lines.push(\"## Methods\");\n for (const method of cls.methods) {\n const sig = method.signature || method.name || \"\";\n lines.push(`- ${sig}${method.returns ? ` -> ${method.returns}` : \"\"}`);\n }\n }\n return textResult(lines.join(\"\\n\"));\n}\n\nexport const registerGetModuleHelp: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_module_help\",\n {\n title: \"Get module/class help\",\n description:\n \"Human-readable help (description, members, method signatures) for a TouchDesigner Python class or module, from the knowledge base.\",\n inputSchema: getModuleHelpSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n (args) => getModuleHelpImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getTdClassDetailsSchema = z.object({\n class_name: z.string().describe(\"Python class name, e.g. 'OP', 'TOP', 'App', 'CHOP'.\"),\n});\ntype GetTdClassDetailsArgs = z.infer<typeof getTdClassDetailsSchema>;\n\nexport function getTdClassDetailsImpl(ctx: ToolContext, args: GetTdClassDetailsArgs) {\n const cls = ctx.knowledge.getPythonClass(args.class_name);\n if (!cls) {\n const suggestions = ctx.knowledge\n .listPythonClasses()\n .filter((c) => c.className.toLowerCase().includes(args.class_name.toLowerCase()))\n .slice(0, 5)\n .map((c) => c.className);\n return structuredResult(`Python class \"${args.class_name}\" not found.`, {\n found: false,\n suggestions,\n });\n }\n return structuredResult(\n `${cls.className} — ${cls.methods?.length ?? 0} methods, ${cls.members?.length ?? 0} members.`,\n cls,\n );\n}\n\nexport const registerGetTdClassDetails: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_class_details\",\n {\n title: \"Get TD Python class details\",\n description:\n \"Full documentation for one TouchDesigner Python class (members + methods) from the knowledge base.\",\n inputSchema: getTdClassDetailsSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n (args) => getTdClassDetailsImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getTdClassesSchema = z.object({\n filter: z\n .string()\n .optional()\n .describe(\"Optional case-insensitive substring to filter class names by.\"),\n});\ntype GetTdClassesArgs = z.infer<typeof getTdClassesSchema>;\n\nexport function getTdClassesImpl(ctx: ToolContext, args: GetTdClassesArgs) {\n let classes = ctx.knowledge.listPythonClasses();\n if (args.filter) {\n const needle = args.filter.toLowerCase();\n classes = classes.filter(\n (c) =>\n c.className.toLowerCase().includes(needle) || c.displayName.toLowerCase().includes(needle),\n );\n }\n return structuredResult(`Found ${classes.length} TouchDesigner Python API class(es).`, {\n classes,\n });\n}\n\nexport const registerGetTdClasses: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_classes\",\n {\n title: \"List TD Python classes\",\n description:\n \"List TouchDesigner Python API classes from the embedded knowledge base (works offline). Optionally filter by name.\",\n inputSchema: getTdClassesSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n (args) => getTdClassesImpl(ctx, args),\n );\n};\n","import { friendlyTdError } from \"../../td-client/types.js\";\nimport { jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nconst DESCRIPTION =\n \"Health check + TouchDesigner server info. Returns TD/Python version and bridge status when connected, plus the embedded knowledge-base stats. Use this first to confirm the bridge is reachable.\";\n\nexport async function getTdInfoImpl(ctx: ToolContext) {\n const knowledge = ctx.knowledge.stats();\n try {\n const info = await ctx.client.getInfo();\n return jsonResult(\"TouchDesigner is connected.\", {\n connected: true,\n endpoint: ctx.client.endpoint,\n touchdesigner: info,\n knowledge,\n });\n } catch (err) {\n return jsonResult(\"TouchDesigner is not reachable (the server is still running).\", {\n connected: false,\n endpoint: ctx.client.endpoint,\n reason: friendlyTdError(err),\n knowledge,\n });\n }\n}\n\nexport const registerGetTdInfo: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_info\",\n {\n title: \"Get TouchDesigner info\",\n description: DESCRIPTION,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n () => getTdInfoImpl(ctx),\n );\n};\n","import { z } from \"zod\";\nimport { NodeErrorSchema } from \"../../td-client/validators.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getTdNodeErrorsSchema = z.object({\n path: z.string().describe(\"Full path of the node (or network root) to check for errors.\"),\n recursive: z\n .boolean()\n .default(false)\n .describe(\"If true, check the whole network under `path`; otherwise just that node.\"),\n summary: z\n .boolean()\n .default(false)\n .describe(\"Return only counts grouped by error type instead of the full error list.\"),\n});\ntype GetTdNodeErrorsArgs = z.infer<typeof getTdNodeErrorsSchema>;\n\nexport const getTdNodeErrorsOutputSchema = z.object({\n path: z.string(),\n total: z.number(),\n errors: z.array(NodeErrorSchema).optional(),\n by_type: z.record(z.string(), z.number()).optional(),\n});\n\nexport async function getTdNodeErrorsImpl(ctx: ToolContext, args: GetTdNodeErrorsArgs) {\n return guardTd(\n () =>\n args.recursive ? ctx.client.getNetworkErrors(args.path) : ctx.client.getNodeErrors(args.path),\n (result) => {\n const errors = result.errors;\n const total = errors.length;\n const none = total === 0;\n if (args.summary) {\n const byType: Record<string, number> = {};\n for (const e of errors) {\n const key = e.type || \"error\";\n byType[key] = (byType[key] ?? 0) + 1;\n }\n return structuredResult(\n none ? `No errors found at ${args.path}.` : `${total} error(s) at ${args.path}.`,\n { path: args.path, total, by_type: byType },\n );\n }\n return structuredResult(\n none ? `No errors found at ${args.path}.` : `Found ${total} error(s) at ${args.path}.`,\n { path: args.path, total, errors },\n );\n },\n );\n}\n\nexport const registerGetTdNodeErrors: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_node_errors\",\n {\n title: \"Get node errors\",\n description:\n \"Check a node (or its whole sub-network) for cook/compile errors and warnings. Pass `summary:true` for grouped counts instead of the full list.\",\n inputSchema: getTdNodeErrorsSchema.shape,\n outputSchema: getTdNodeErrorsOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => getTdNodeErrorsImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { NodeDetailSchema } from \"../../td-client/validators.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getTdNodeParametersSchema = z.object({\n path: z.string().describe(\"Full path of the node to inspect.\"),\n keys: z\n .array(z.string())\n .optional()\n .describe(\"Only return these parameter names (case-sensitive). Omit to return all parameters.\"),\n omit_io: z\n .boolean()\n .default(false)\n .describe(\"Drop the inputs/outputs lists from the result to save context.\"),\n});\ntype GetTdNodeParametersArgs = z.infer<typeof getTdNodeParametersSchema>;\n\nexport async function getTdNodeParametersImpl(ctx: ToolContext, args: GetTdNodeParametersArgs) {\n return guardTd(\n () => ctx.client.getNode(args.path),\n (node) => {\n let parameters = node.parameters;\n if (args.keys && args.keys.length > 0) {\n const wanted = new Set(args.keys);\n parameters = Object.fromEntries(\n Object.entries(node.parameters).filter(([k]) => wanted.has(k)),\n );\n }\n const data: Record<string, unknown> = {\n path: node.path,\n type: node.type,\n name: node.name,\n parameters,\n };\n if (!args.omit_io) {\n data.inputs = node.inputs;\n data.outputs = node.outputs;\n }\n const count = Object.keys(parameters).length;\n return structuredResult(`${count} parameter(s) for ${node.path} (${node.type}).`, data);\n },\n );\n}\n\nexport const registerGetTdNodeParameters: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_node_parameters\",\n {\n title: \"Get node parameters\",\n description:\n \"Read the current parameters (and I/O) of a node. Pass `keys` to project specific parameters or `omit_io:true` to drop the inputs/outputs lists.\",\n inputSchema: getTdNodeParametersSchema.shape,\n outputSchema: NodeDetailSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => getTdNodeParametersImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { NodeRefSchema } from \"../../td-client/validators.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { globToRegExp } from \"./nodeMatch.js\";\n\nexport const getTdNodesSchema = z.object({\n parent_path: z\n .string()\n .default(\"/project1\")\n .describe(\"Parent COMP whose direct children should be listed.\"),\n pattern: z\n .string()\n .optional()\n .describe(\n \"Case-insensitive filter on node name/path. Supports '*' wildcards (e.g. 'text*', '*noise*').\",\n ),\n path_only: z\n .boolean()\n .default(false)\n .describe(\"Return only the list of node paths, dropping type/name.\"),\n limit: z.number().int().positive().optional().describe(\"Cap the number of nodes returned.\"),\n detail_level: z\n .enum([\"summary\", \"full\"])\n .default(\"summary\")\n .describe(\n \"'summary' (default) returns a count, a type breakdown and the first few paths; 'full' returns every node. Use 'full' (or path_only) when you need the complete list.\",\n ),\n});\ntype GetTdNodesArgs = z.infer<typeof getTdNodesSchema>;\n\nconst SAMPLE_SIZE = 10;\n\nexport const getTdNodesOutputSchema = z.object({\n parent_path: z.string(),\n count: z.number(),\n detail_level: z.enum([\"summary\", \"full\"]),\n truncated: z.boolean(),\n by_type: z.record(z.string(), z.number()).optional(),\n sample: z.array(z.string()).optional(),\n paths: z.array(z.string()).optional(),\n nodes: z.array(NodeRefSchema).optional(),\n hint: z.string().optional(),\n});\n\nexport async function getTdNodesImpl(ctx: ToolContext, args: GetTdNodesArgs) {\n return guardTd(\n () => ctx.client.getNodes(args.parent_path),\n (list) => {\n let nodes = list.nodes;\n if (args.pattern) {\n const re = globToRegExp(args.pattern);\n nodes = nodes.filter((n) => re.test(n.name) || re.test(n.path));\n }\n const matched = nodes.length;\n const truncated = args.limit !== undefined && matched > args.limit;\n if (args.limit !== undefined) nodes = nodes.slice(0, args.limit);\n const where = args.pattern ? ` matching \"${args.pattern}\"` : \"\";\n const base = {\n parent_path: args.parent_path,\n count: matched,\n detail_level: args.detail_level,\n truncated,\n };\n\n if (args.path_only) {\n return structuredResult(`${matched} node(s) under ${args.parent_path}${where}.`, {\n ...base,\n paths: nodes.map((n) => n.path),\n });\n }\n\n if (args.detail_level === \"summary\") {\n const byType: Record<string, number> = {};\n for (const n of nodes) {\n const key = n.type || \"unknown\";\n byType[key] = (byType[key] ?? 0) + 1;\n }\n const sample = nodes.slice(0, SAMPLE_SIZE).map((n) => n.path);\n return structuredResult(\n `${matched} node(s) under ${args.parent_path}${where}. Summary only — pass detail_level:\"full\" or path_only:true for the full list.`,\n {\n ...base,\n by_type: byType,\n sample,\n ...(matched > sample.length\n ? {\n hint: `Showing first ${sample.length} of ${matched}. Use detail_level:\"full\" for all.`,\n }\n : {}),\n },\n );\n }\n\n return structuredResult(`${matched} node(s) under ${args.parent_path}${where}.`, {\n ...base,\n nodes,\n });\n },\n );\n}\n\nexport const registerGetTdNodes: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_nodes\",\n {\n title: \"List TouchDesigner nodes\",\n description:\n 'List the direct child nodes of a COMP. Defaults to a compact summary (count + type breakdown + sample paths); pass detail_level:\"full\" or path_only:true for the complete list, and `pattern` to filter by name.',\n inputSchema: getTdNodesSchema.shape,\n outputSchema: getTdNodesOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => getTdNodesImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { checkPerformance } from \"../../feedback/performanceMonitor.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getTdPerformanceSchema = z.object({\n root_path: z.string().default(\"/project1\").describe(\"Network root to measure cook times under.\"),\n target_fps: z\n .number()\n .positive()\n .default(60)\n .describe(\"Frame-rate target used to flag slow nodes.\"),\n recursive: z\n .boolean()\n .default(true)\n .describe(\n \"Measure every descendant (true, default) so cook time inside generated containers is counted, not just the root's direct children.\",\n ),\n});\ntype GetTdPerformanceArgs = z.infer<typeof getTdPerformanceSchema>;\n\nexport const getTdPerformanceOutputSchema = z.object({\n path: z.string(),\n targetFps: z.number(),\n frameBudgetMs: z.number(),\n totalCookMs: z.number(),\n nodes: z.array(\n z.object({\n path: z.string(),\n cook_time_ms: z.number(),\n cook_count: z.number().optional(),\n }),\n ),\n warnings: z.array(z.string()),\n});\n\nexport async function getTdPerformanceImpl(ctx: ToolContext, args: GetTdPerformanceArgs) {\n return guardTd(\n () => checkPerformance(ctx.client, args.root_path, args.target_fps, args.recursive),\n (report) =>\n structuredResult(\n report.warnings.length === 0\n ? `Within budget: ${report.totalCookMs.toFixed(2)}ms total under ${args.root_path} (${args.target_fps}fps).`\n : `${report.warnings.length} performance warning(s) under ${args.root_path}.`,\n report,\n ),\n );\n}\n\nexport const registerGetTdPerformance: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_performance\",\n {\n title: \"Get network performance\",\n description:\n \"Report cook times under a network (recursively by default, slowest node first) and warn about nodes that exceed the frame budget.\",\n inputSchema: getTdPerformanceSchema.shape,\n outputSchema: getTdPerformanceOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => getTdPerformanceImpl(ctx, args),\n );\n};\n","import type { TouchDesignerClient } from \"../td-client/touchDesignerClient.js\";\n\nexport interface PerformanceReport {\n path: string;\n targetFps: number;\n frameBudgetMs: number;\n totalCookMs: number;\n nodes: Array<{ path: string; cook_time_ms: number; cook_count?: number }>;\n warnings: string[];\n}\n\n/**\n * Reports cook times against the frame budget implied by `targetFps`. `recursive`\n * measures every descendant (so cook time inside generated containers is counted, not\n * just the root's direct children). Nodes are returned slowest-first.\n */\nexport async function checkPerformance(\n client: TouchDesignerClient,\n path: string,\n targetFps = 60,\n recursive = true,\n): Promise<PerformanceReport> {\n const perf = await client.getNetworkPerformance(path, recursive);\n const frameBudgetMs = 1000 / targetFps;\n const warnings: string[] = [];\n\n for (const node of perf.nodes) {\n if (node.cook_time_ms > frameBudgetMs) {\n warnings.push(\n `${node.path} cooks in ${node.cook_time_ms.toFixed(2)}ms, exceeding the ${frameBudgetMs.toFixed(2)}ms budget at ${targetFps}fps.`,\n );\n }\n }\n\n const totalCookMs =\n perf.total_cook_time_ms ?? perf.nodes.reduce((sum, node) => sum + node.cook_time_ms, 0);\n if (totalCookMs > frameBudgetMs) {\n warnings.push(\n `Total cook time ${totalCookMs.toFixed(2)}ms exceeds the ${frameBudgetMs.toFixed(2)}ms budget at ${targetFps}fps.`,\n );\n }\n\n // Surface the slowest nodes first so the real bottlenecks are obvious.\n const nodes = [...perf.nodes].sort((a, b) => b.cook_time_ms - a.cook_time_ms);\n return { path, targetFps, frameBudgetMs, totalCookMs, nodes, warnings };\n}\n","import { z } from \"zod\";\nimport { verifyNetwork } from \"../../feedback/networkVerifier.js\";\nimport { TopologySchema } from \"../../td-client/validators.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const getTdTopologySchema = z.object({\n root_path: z.string().default(\"/project1\").describe(\"Network root to map.\"),\n});\ntype GetTdTopologyArgs = z.infer<typeof getTdTopologySchema>;\n\nexport const getTdTopologyOutputSchema = z.object({\n path: z.string(),\n nodeCount: z.number(),\n connectionCount: z.number(),\n issues: z.array(z.string()),\n topology: TopologySchema,\n});\n\nexport async function getTdTopologyImpl(ctx: ToolContext, args: GetTdTopologyArgs) {\n return guardTd(\n () => verifyNetwork(ctx.client, args.root_path),\n (report) =>\n structuredResult(\n `${report.nodeCount} node(s), ${report.connectionCount} connection(s) under ${args.root_path}.`,\n report,\n ),\n );\n}\n\nexport const registerGetTdTopology: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"get_td_topology\",\n {\n title: \"Get network topology\",\n description:\n \"Return the nodes and connections under a network root, flagging obvious structural issues.\",\n inputSchema: getTdTopologySchema.shape,\n outputSchema: getTdTopologyOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => getTdTopologyImpl(ctx, args),\n );\n};\n","import type { TouchDesignerClient } from \"../td-client/touchDesignerClient.js\";\nimport type { TdTopology } from \"../td-client/types.js\";\n\nexport interface VerifyReport {\n path: string;\n nodeCount: number;\n connectionCount: number;\n issues: string[];\n topology: TdTopology;\n}\n\n/** Inspects the topology under `path` and flags obvious structural issues. */\nexport async function verifyNetwork(\n client: TouchDesignerClient,\n path: string,\n): Promise<VerifyReport> {\n const topology = await client.getNetworkTopology(path);\n const issues: string[] = [];\n if (topology.nodes.length === 0) {\n issues.push(`No nodes were found under ${path}.`);\n } else if (topology.nodes.length > 1 && topology.connections.length === 0) {\n issues.push(\"Multiple nodes exist but none are connected.\");\n }\n return {\n path,\n nodeCount: topology.nodes.length,\n connectionCount: topology.connections.length,\n issues,\n topology,\n };\n}\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const optimizePerformanceSchema = z.object({\n path: z.string().default(\"/project1\").describe(\"Network to analyze (recursively).\"),\n threshold_ms: z.coerce\n .number()\n .positive()\n .default(2)\n .describe(\"Flag nodes whose last cook took at least this many milliseconds.\"),\n apply: z\n .boolean()\n .default(false)\n .describe(\n \"If true, actually lower the resolution of the flagged TOPs by `scale`. Default false = just report the bottlenecks and suggestions.\",\n ),\n scale: z.coerce\n .number()\n .min(0.1)\n .max(1)\n .default(0.5)\n .describe(\"(apply) Resolution multiplier for flagged TOPs (0.5 = half on each axis).\"),\n});\ntype OptimizePerformanceArgs = z.infer<typeof optimizePerformanceSchema>;\n\ninterface OptimizeReport {\n path: string;\n slow: Array<{ path: string; type: string; cook_ms: number }>;\n optimized: Array<{ path: string; from: [number, number]; to: [number, number] }>;\n suggestions: string[];\n warnings: string[];\n fatal?: string;\n}\n\n// One Python pass: rank descendants by last cook time, list the slow ones with a suggestion,\n// and (when apply) halve the resolution of flagged TOPs that expose a custom resolution.\nconst OPTIMIZE_SCRIPT = `\nimport json, base64, traceback\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nreport = {\"path\": _p[\"path\"], \"slow\": [], \"optimized\": [], \"suggestions\": [], \"warnings\": []}\n_root = op(_p[\"path\"])\ntry:\n if _root is None or not hasattr(_root, \"findChildren\"):\n report[\"fatal\"] = \"Network not found: \" + _p[\"path\"]\n else:\n _scored = []\n for _c in _root.findChildren():\n try:\n _ct = float(getattr(_c, \"cookTime\", 0.0) or 0.0)\n except Exception:\n _ct = 0.0\n if _ct >= _p[\"threshold\"]:\n _scored.append((_ct, _c))\n _scored.sort(key=lambda x: x[0], reverse=True)\n for _ct, _c in _scored[:20]:\n _ty = getattr(_c, \"OPType\", None) or getattr(_c, \"type\", \"\") or \"\"\n report[\"slow\"].append({\"path\": _c.path, \"type\": _ty, \"cook_ms\": round(_ct, 3)})\n if _ty.endswith(\"TOP\"):\n report[\"suggestions\"].append(\"%s (%s, %.1fms): lower its resolution or pre-shrink.\" % (_c.path, _ty, _ct))\n else:\n report[\"suggestions\"].append(\"%s (%s, %.1fms): simplify or cache this branch.\" % (_c.path, _ty, _ct))\n if _p[\"apply\"]:\n _scale = _p[\"scale\"]\n for _ct, _c in _scored:\n _ty = getattr(_c, \"OPType\", \"\") or \"\"\n if not _ty.endswith(\"TOP\"):\n continue\n _rw = getattr(_c.par, \"resolutionw\", None)\n _rh = getattr(_c.par, \"resolutionh\", None)\n _ores = getattr(_c.par, \"outputresolution\", None)\n if _rw is None or _rh is None:\n continue\n try:\n _fw = int(_c.width); _fh = int(_c.height)\n if _ores is not None:\n try:\n _ores.val = \"custom\"\n except Exception:\n pass\n _nw = max(64, int(_fw * _scale)); _nh = max(64, int(_fh * _scale))\n _rw.val = _nw; _rh.val = _nh\n report[\"optimized\"].append({\"path\": _c.path, \"from\": [_fw, _fh], \"to\": [_nw, _nh]})\n except Exception:\n report[\"warnings\"].append(\"Could not resize \" + _c.path)\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildOptimizeScript(payload: object): string {\n return buildPayloadScript(OPTIMIZE_SCRIPT, payload);\n}\n\nexport async function optimizePerformanceImpl(ctx: ToolContext, args: OptimizePerformanceArgs) {\n return guardTd(\n async () => {\n const script = buildOptimizeScript({\n path: args.path,\n threshold: args.threshold_ms,\n apply: args.apply,\n scale: args.scale,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<OptimizeReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) {\n return errorResult(`Performance scan failed: ${report.fatal}`, report);\n }\n const summary = args.apply\n ? `Found ${report.slow.length} slow node(s) over ${args.threshold_ms}ms; resized ${report.optimized.length} TOP(s) to ${Math.round(args.scale * 100)}%.`\n : `Found ${report.slow.length} node(s) over ${args.threshold_ms}ms. Re-run with apply:true to halve the flagged TOPs' resolution.`;\n return jsonResult(summary, report);\n },\n );\n}\n\nexport const registerOptimizePerformance: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"optimize_performance\",\n {\n title: \"Optimize performance\",\n description:\n \"Scan a network for cook-time bottlenecks and (optionally) fix them. By default it reports the slowest nodes with a concrete suggestion each. With apply:true it lowers the resolution of the flagged TOPs by `scale` to claw back GPU time. Run get_td_performance first if you just want the numbers; use this to act on them.\",\n inputSchema: optimizePerformanceSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => optimizePerformanceImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const recordMovieSchema = z.object({\n action: z\n .enum([\"start\", \"stop\"])\n .default(\"start\")\n .describe(\"start recording the TOP to a file, or stop the current recording.\"),\n node_path: z.string().describe(\"Path of the TOP to record.\"),\n file: z\n .string()\n .optional()\n .describe(\n \"(start) Output movie path on the TD machine, with a .mov or .mp4 extension. Absolute path recommended.\",\n ),\n fps: z.coerce.number().positive().default(30).describe(\"(start) Frames per second.\"),\n seconds: z.coerce\n .number()\n .positive()\n .optional()\n .describe(\n \"(start) If set, auto-stop after this many seconds (records a fixed-length loop); otherwise record until you call stop.\",\n ),\n});\ntype RecordMovieArgs = z.infer<typeof recordMovieSchema>;\n\ninterface RecordReport {\n action: string;\n recording?: string;\n stopped?: string;\n auto_stop_seconds?: number;\n warnings: string[];\n fatal?: string;\n}\n\n// Execute DAT that turns recording off once `seconds` have elapsed (records a fixed-length loop).\nconst REC_HOOK = `import td\n\ndef onFrameStart(frame):\n comp = me.parent()\n cfg = comp.fetch('tdmcp_record_cfg', None)\n if not cfg or not cfg.get('active'):\n return\n if td.absTime.seconds - cfg.get('start', 0) >= cfg.get('seconds', 0):\n mov = comp.op('tdmcp_record')\n if mov is not None:\n try:\n mov.par.record = False\n except Exception:\n pass\n cfg['active'] = False\n comp.store('tdmcp_record_cfg', cfg)\n return\n`;\n\n// One Python pass: a Movie File Out TOP named tdmcp_record is created in the source's parent and\n// wired to it; record toggles on (start) / off (stop). With `seconds`, a small Execute DAT turns\n// it off after the duration so you capture a fixed-length loop in one call.\nconst REC_SCRIPT = `\nimport json, base64, traceback\nimport td\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\nreport = {\"action\": _p[\"action\"], \"warnings\": []}\ntry:\n _src = op(_p[\"node\"])\n if _src is None:\n report[\"fatal\"] = \"Source TOP not found: \" + _p[\"node\"]\n else:\n _parent = _src.parent()\n if _p[\"action\"] == \"stop\":\n _mov = _parent.op(\"tdmcp_record\")\n if _mov is None:\n report[\"warnings\"].append(\"No active recording (tdmcp_record) found.\")\n else:\n _mov.par.record = False\n report[\"stopped\"] = _mov.par.file.eval()\n # Recording is finished (the file is written); remove the recorder + auto-stop\n # hook so they don't linger in the project.\n _mov.destroy()\n _hook = _parent.op(\"tdmcp_record_stop\")\n if _hook is not None:\n _hook.destroy()\n else:\n if not _p.get(\"file\"):\n report[\"fatal\"] = \"A file path is required to start recording.\"\n else:\n _mov = _parent.op(\"tdmcp_record\") or _parent.create(td.moviefileoutTOP, \"tdmcp_record\")\n _mov.par.file = _p[\"file\"]\n try:\n _mov.par.fps = _p[\"fps\"]\n except Exception:\n pass\n try:\n _mov.inputConnectors[0].connect(_src)\n except Exception:\n report[\"warnings\"].append(\"Could not wire the source TOP.\")\n _mov.par.record = True\n report[\"recording\"] = _p[\"file\"]\n _secs = _p.get(\"seconds\")\n if _secs and _secs > 0:\n _parent.store(\"tdmcp_record_cfg\", {\"active\": True, \"start\": td.absTime.seconds, \"seconds\": _secs})\n _hook = _parent.op(\"tdmcp_record_stop\") or _parent.create(td.executeDAT, \"tdmcp_record_stop\")\n _hook.text = _p[\"hook\"]\n if hasattr(_hook.par, \"framestart\"):\n _hook.par.framestart = True\n _hook.par.active = True\n report[\"auto_stop_seconds\"] = _secs\nexcept Exception:\n report[\"fatal\"] = traceback.format_exc().splitlines()[-1]\nprint(json.dumps(report))\n`;\n\nexport function buildRecordScript(payload: object): string {\n return buildPayloadScript(REC_SCRIPT, payload);\n}\n\nexport async function recordMovieImpl(ctx: ToolContext, args: RecordMovieArgs) {\n return guardTd(\n async () => {\n const script = buildRecordScript({\n action: args.action,\n node: args.node_path,\n file: args.file ?? null,\n fps: args.fps,\n seconds: args.seconds ?? null,\n hook: REC_HOOK,\n });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<RecordReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal)\n return errorResult(`Record ${report.action} failed: ${report.fatal}`, report);\n if (report.action === \"stop\") {\n return jsonResult(\n `Stopped recording${report.stopped ? ` → ${report.stopped}` : \"\"}.`,\n report,\n );\n }\n const auto = report.auto_stop_seconds\n ? ` (auto-stops after ${report.auto_stop_seconds}s)`\n : \" (call stop to finish)\";\n return jsonResult(`Recording ${args.node_path} → ${report.recording}${auto}.`, report);\n },\n );\n}\n\nexport const registerRecordMovie: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"record_movie\",\n {\n title: \"Record movie / sequence\",\n description:\n \"Record a TOP to a movie file (.mov/.mp4) via a Movie File Out TOP — for exporting a clip or a loop, where render_output only saves a single frame. start begins recording (pass file, fps); pass `seconds` to auto-stop after a fixed length, or call stop to finish (stop also cleans up the recorder node). The file is written by TouchDesigner on the TD machine. For individual numbered frames, use render_output per frame.\",\n inputSchema: recordMovieSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => recordMovieImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { parsePythonReport } from \"../pythonReport.js\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\n// Takes no arguments; the empty object keeps the CLI/schema plumbing uniform.\nexport const reloadBridgeSchema = z.object({});\n\ninterface ReloadReport {\n reloaded: string[];\n count: number;\n}\n\n// Editing files under td/ does NOT reload the modules a running TouchDesigner\n// already imported, so the bridge keeps serving stale code until reopened. This\n// reimports every loaded mcp.*/utils.* module in place (deepest-first), so the\n// next request runs the edited code without reopening the project.\nconst RELOAD_SCRIPT = `\nimport json\nfrom mcp import dev\n_reloaded = dev.reload_bridge()\nprint(json.dumps({\"reloaded\": _reloaded, \"count\": len(_reloaded)}))\n`;\n\nexport async function reloadBridgeImpl(ctx: ToolContext) {\n return guardTd(\n async () => {\n const exec = await ctx.client.executePythonScript(RELOAD_SCRIPT, true);\n return parsePythonReport<ReloadReport>(exec.stdout);\n },\n (report) =>\n jsonResult(\n `Reloaded ${report.count} bridge module(s) in place — edits under td/ are now live.`,\n report,\n ),\n );\n}\n\nexport const registerReloadBridge: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"reload_bridge\",\n {\n title: \"Reload bridge\",\n description:\n \"Hot-reload the bridge's Python inside the running TouchDesigner, so edits to the td/ modules take effect without reopening the project. Reimports every loaded mcp.*/utils.* module in place and returns the list reloaded. Use after editing bridge code.\",\n inputSchema: reloadBridgeSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n () => reloadBridgeImpl(ctx),\n );\n};\n","import { z } from \"zod\";\nimport { buildPayloadScript, parsePythonReport } from \"../pythonReport.js\";\nimport { errorResult, guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const renderOutputSchema = z.object({\n node_path: z.string().describe(\"Path of the TOP to render to a file.\"),\n file: z\n .string()\n .describe(\n \"Output file path (written by TouchDesigner, so on the TD machine). Extension picks the format: .png/.jpg/.exr/.tiff. Use an absolute path.\",\n ),\n});\ntype RenderOutputArgs = z.infer<typeof renderOutputSchema>;\n\ninterface RenderReport {\n saved?: string;\n width?: number;\n height?: number;\n fatal?: string;\n}\n\n// Save a TOP straight to disk at its native resolution (unlike get_preview, which transfers a\n// small composited PNG over the bridge). TOP.save writes on the TD machine.\nconst RENDER_SCRIPT = `\nimport json, base64\n_p = json.loads(base64.b64decode(\"__PAYLOAD_B64__\").decode(\"utf-8\"))\n_n = op(_p[\"node\"])\nif _n is None:\n print(json.dumps({\"fatal\": \"Node not found: \" + _p[\"node\"]}))\nelif not hasattr(_n, \"save\"):\n print(json.dumps({\"fatal\": _p[\"node\"] + \" cannot be saved (not a TOP?).\"}))\nelse:\n try:\n _saved = _n.save(_p[\"file\"], createFolders=True)\n print(json.dumps({\"saved\": str(_saved) if _saved else _p[\"file\"], \"width\": int(_n.width), \"height\": int(_n.height)}))\n except Exception as _e:\n print(json.dumps({\"fatal\": str(_e)}))\n`;\n\nexport function buildRenderScript(payload: object): string {\n return buildPayloadScript(RENDER_SCRIPT, payload);\n}\n\nexport async function renderOutputImpl(ctx: ToolContext, args: RenderOutputArgs) {\n return guardTd(\n async () => {\n const script = buildRenderScript({ node: args.node_path, file: args.file });\n const exec = await ctx.client.executePythonScript(script, true);\n return parsePythonReport<RenderReport>(exec.stdout);\n },\n (report) => {\n if (report.fatal) return errorResult(`Render failed: ${report.fatal}`, report);\n return jsonResult(\n `Rendered ${args.node_path} (${report.width}×${report.height}) to ${report.saved}.`,\n report,\n );\n },\n );\n}\n\nexport const registerRenderOutput: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"render_output\",\n {\n title: \"Render output to file\",\n description:\n \"Save a TOP to an image file at its native, full resolution (PNG/JPG/EXR/TIFF by extension) — for exporting a finished frame, unlike get_preview which only transfers a small inline thumbnail. The file is written by TouchDesigner on the TD machine; pass an absolute path.\",\n inputSchema: renderOutputSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => renderOutputImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { cosineSimilarity, embedTextsCached } from \"../../knowledge/embeddings.js\";\nimport { loadConfig } from \"../../utils/config.js\";\nimport { structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const searchOperatorsSchema = z.object({\n query: z\n .string()\n .min(1)\n .describe(\n \"What you're looking for — words from a name, family, or description (e.g. 'blur edge', 'audio spectrum', 'instance geometry').\",\n ),\n limit: z.coerce.number().int().positive().max(100).default(20).describe(\"Max results to return.\"),\n semantic: z\n .boolean()\n .default(false)\n .describe(\n \"Opt-in: re-rank keyword candidates by embedding similarity via the configured LLM endpoint (TDMCP_LLM_BASE_URL / _MODEL, Ollama by default). Better for fuzzy/conceptual queries. Falls back to keyword ranking if the endpoint is unavailable — the default (false) needs nothing.\",\n ),\n});\ntype SearchOperatorsArgs = z.infer<typeof searchOperatorsSchema>;\n\nexport async function searchOperatorsImpl(ctx: ToolContext, args: SearchOperatorsArgs) {\n // Keyword search always runs: it's the result in default mode and the candidate pool in\n // semantic mode (recall first, then embedding re-rank for precision).\n const poolSize = args.semantic ? Math.max(args.limit * 4, 40) : args.limit;\n const keyword = ctx.knowledge.searchOperators(args.query, poolSize);\n\n if (!args.semantic || keyword.length === 0) {\n const operators = keyword.slice(0, args.limit);\n return structuredResult(`Found ${operators.length} operator(s) matching \"${args.query}\".`, {\n query: args.query,\n mode: \"keyword\",\n count: operators.length,\n operators,\n });\n }\n\n try {\n const config = loadConfig();\n const texts = [args.query, ...keyword.map((o) => `${o.name}. ${o.summary}`)];\n // Cached: operator-summary embeddings are reused across queries; only the query and any\n // not-yet-seen candidate actually hit the endpoint.\n const vectors = await embedTextsCached(texts, config);\n const queryVec = vectors[0] as number[];\n const operators = keyword\n .map((o, i) => ({ o, score: cosineSimilarity(queryVec, vectors[i + 1] as number[]) }))\n .sort((a, b) => b.score - a.score)\n .slice(0, args.limit)\n .map((x) => x.o);\n return structuredResult(\n `Found ${operators.length} operator(s) for \"${args.query}\" (semantic re-rank of ${keyword.length} candidates).`,\n { query: args.query, mode: \"semantic\", count: operators.length, operators },\n );\n } catch (err) {\n const operators = keyword.slice(0, args.limit);\n return structuredResult(\n `Found ${operators.length} operator(s) matching \"${args.query}\" (semantic unavailable: ${String(err).slice(0, 80)}; using keyword ranking).`,\n { query: args.query, mode: \"keyword_fallback\", count: operators.length, operators },\n );\n }\n}\n\nexport const registerSearchOperators: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"search_operators\",\n {\n title: \"Search operators\",\n description:\n \"Search the embedded operator knowledge base (629 operators) by keyword — name, family or description — ranked by relevance, fully offline. Use it to discover the right operator before creating nodes instead of guessing a type (e.g. 'what sends DMX?', 'particle', 'corner pin'). Returns name, family and a one-line summary per hit. Pass semantic:true to re-rank by embedding similarity (needs an LLM endpoint; falls back to keyword).\",\n inputSchema: searchOperatorsSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => searchOperatorsImpl(ctx, args),\n );\n};\n","/**\n * Optional embedding support for semantic operator search. Talks to an OpenAI-compatible\n * `/embeddings` endpoint (the same `TDMCP_LLM_BASE_URL` the local copilot uses — Ollama by\n * default). It is strictly opt-in: search_operators only calls this when `semantic: true`,\n * and falls back to keyword ranking if the endpoint is unavailable, so the zero-config\n * install is never affected.\n */\n\nexport interface EmbedConfig {\n llmBaseUrl: string;\n llmModel: string;\n llmApiKey?: string;\n}\n\n/** Embeds a batch of texts; returns one vector per input. Throws if the endpoint is unreachable. */\nexport async function embedTexts(\n texts: string[],\n config: EmbedConfig,\n timeoutMs = 20000,\n): Promise<number[][]> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const res = await fetch(`${config.llmBaseUrl.replace(/\\/$/, \"\")}/embeddings`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n ...(config.llmApiKey ? { authorization: `Bearer ${config.llmApiKey}` } : {}),\n },\n body: JSON.stringify({ model: config.llmModel, input: texts }),\n signal: controller.signal,\n });\n if (!res.ok) throw new Error(`embeddings endpoint returned HTTP ${res.status}`);\n const json = (await res.json()) as { data?: Array<{ embedding: number[] }> };\n if (!json.data?.length) throw new Error(\"embeddings endpoint returned no data\");\n return json.data.map((d) => d.embedding);\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Process-lifetime cache of text → embedding, keyed by `model \\u0000 text` so switching the\n * configured model never returns stale vectors. Operator summaries are static, so after the\n * first semantic search their embeddings are reused across every later query — only the\n * query itself (and any newly-surfaced candidate) hits the endpoint. Bounded with LRU\n * eviction so a flood of unique queries can't grow it without limit, while the heavily-reused\n * operator embeddings stay resident.\n */\nconst EMBED_CACHE = new Map<string, number[]>();\nconst EMBED_CACHE_MAX = 4096;\n\nfunction cacheKey(model: string, text: string): string {\n return `${model}\\u0000${text}`;\n}\n\nfunction cacheGet(key: string): number[] | undefined {\n const hit = EMBED_CACHE.get(key);\n if (hit) {\n // Touch: move to most-recently-used so it survives eviction.\n EMBED_CACHE.delete(key);\n EMBED_CACHE.set(key, hit);\n }\n return hit;\n}\n\nfunction cacheSet(key: string, vec: number[]): void {\n if (EMBED_CACHE.size >= EMBED_CACHE_MAX) {\n const oldest = EMBED_CACHE.keys().next().value;\n if (oldest !== undefined) EMBED_CACHE.delete(oldest);\n }\n EMBED_CACHE.set(key, vec);\n}\n\n/** Clears the embedding cache. For tests, and after a model/endpoint change. */\nexport function clearEmbedCache(): void {\n EMBED_CACHE.clear();\n}\n\n/**\n * Like {@link embedTexts}, but serves known texts from the in-memory cache and only sends the\n * cache misses to the endpoint (then caches them). Results stay in the original input order.\n * Failures propagate exactly as embedTexts so the caller's keyword fallback still applies, and\n * nothing is cached on failure (transient outages retry next call).\n */\nexport async function embedTextsCached(\n texts: string[],\n config: EmbedConfig,\n timeoutMs = 20000,\n): Promise<number[][]> {\n const out: Array<number[] | undefined> = new Array(texts.length);\n const missIdx: number[] = [];\n const missTexts: string[] = [];\n for (let i = 0; i < texts.length; i++) {\n const text = texts[i] as string;\n const hit = cacheGet(cacheKey(config.llmModel, text));\n if (hit) out[i] = hit;\n else {\n missIdx.push(i);\n missTexts.push(text);\n }\n }\n if (missTexts.length > 0) {\n const fresh = await embedTexts(missTexts, config, timeoutMs);\n for (let j = 0; j < missIdx.length; j++) {\n const idx = missIdx[j] as number;\n const vec = fresh[j] as number[];\n out[idx] = vec;\n cacheSet(cacheKey(config.llmModel, texts[idx] as string), vec);\n }\n }\n return out as number[][];\n}\n\n/** Cosine similarity of two equal-length vectors (0 when either is degenerate). */\nexport function cosineSimilarity(a: number[], b: number[]): number {\n const n = Math.min(a.length, b.length);\n let dot = 0;\n let na = 0;\n let nb = 0;\n for (let i = 0; i < n; i++) {\n const x = a[i] as number;\n const y = b[i] as number;\n dot += x * y;\n na += x * x;\n nb += y * y;\n }\n return na > 0 && nb > 0 ? dot / (Math.sqrt(na) * Math.sqrt(nb)) : 0;\n}\n","import { z } from \"zod\";\nimport { verifyNetwork } from \"../../feedback/networkVerifier.js\";\nimport { ConnectionSchema } from \"../../td-client/validators.js\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\n/** Cap on per-node parameter fetches so a big graph can't fan out into hundreds of requests. */\nconst MAX_PARAM_NODES = 60;\n\nexport const snapshotTdGraphSchema = z.object({\n path: z.string().default(\"/project1\").describe(\"Network root to snapshot.\"),\n include_params: z\n .boolean()\n .default(false)\n .describe(\"Also fetch each node's parameters (one request per node; capped for large graphs).\"),\n});\ntype SnapshotTdGraphArgs = z.infer<typeof snapshotTdGraphSchema>;\n\nexport const snapshotTdGraphOutputSchema = z.object({\n path: z.string(),\n nodeCount: z.number(),\n connectionCount: z.number(),\n issues: z.array(z.string()),\n params_truncated: z.boolean(),\n nodes: z.array(\n z.object({\n path: z.string(),\n type: z.string(),\n name: z.string(),\n parameters: z.record(z.string(), z.unknown()).optional(),\n }),\n ),\n connections: z.array(ConnectionSchema),\n});\n\nexport async function snapshotTdGraphImpl(ctx: ToolContext, args: SnapshotTdGraphArgs) {\n return guardTd(\n async () => {\n const report = await verifyNetwork(ctx.client, args.path);\n const refs = report.topology.nodes;\n let paramsTruncated = false;\n const params = new Map<string, Record<string, unknown>>();\n if (args.include_params) {\n const targets = refs.slice(0, MAX_PARAM_NODES);\n paramsTruncated = refs.length > MAX_PARAM_NODES;\n // Fail-forward: one unreadable node shouldn't sink the whole snapshot.\n const details = await Promise.allSettled(targets.map((n) => ctx.client.getNode(n.path)));\n for (const detail of details) {\n if (detail.status === \"fulfilled\") params.set(detail.value.path, detail.value.parameters);\n }\n }\n const nodes = refs.map((n) => ({\n path: n.path,\n type: n.type,\n name: n.name,\n ...(args.include_params ? { parameters: params.get(n.path) ?? {} } : {}),\n }));\n return { report, nodes, paramsTruncated };\n },\n ({ report, nodes, paramsTruncated }) =>\n structuredResult(\n `Snapshot of ${args.path}: ${report.nodeCount} node(s), ${report.connectionCount} connection(s)${report.issues.length ? `, ${report.issues.length} issue(s)` : \"\"}.`,\n {\n path: report.path,\n nodeCount: report.nodeCount,\n connectionCount: report.connectionCount,\n issues: report.issues,\n params_truncated: paramsTruncated,\n nodes,\n connections: report.topology.connections,\n },\n ),\n );\n}\n\nexport const registerSnapshotTdGraph: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"snapshot_td_graph\",\n {\n title: \"Snapshot network graph\",\n description:\n \"Capture a compact, serializable snapshot of a network — nodes, connections, structural issues, and optionally each node's parameters — for review, diffing, or documentation.\",\n inputSchema: snapshotTdGraphSchema.shape,\n outputSchema: snapshotTdGraphOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => snapshotTdGraphImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, structuredResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\nimport { parentOf } from \"./nodeMatch.js\";\n\nexport const summarizeTdErrorsSchema = z.object({\n path: z.string().default(\"/project1\").describe(\"Network root to collect errors under.\"),\n group_by: z\n .enum([\"message\", \"type\", \"parent\"])\n .default(\"message\")\n .describe(\n \"How to cluster errors: by exact message, by error type, or by parent container (to find a common upstream cause).\",\n ),\n});\ntype SummarizeTdErrorsArgs = z.infer<typeof summarizeTdErrorsSchema>;\n\nexport const summarizeTdErrorsOutputSchema = z.object({\n path: z.string(),\n total: z.number(),\n group_by: z.enum([\"message\", \"type\", \"parent\"]),\n groups: z.array(\n z.object({\n key: z.string(),\n count: z.number(),\n sample: z.object({ path: z.string(), message: z.string() }),\n }),\n ),\n suggestions: z.array(z.string()),\n});\n\nexport async function summarizeTdErrorsImpl(ctx: ToolContext, args: SummarizeTdErrorsArgs) {\n return guardTd(\n () => ctx.client.getNetworkErrors(args.path),\n (result) => {\n const errors = result.errors;\n const total = errors.length;\n if (total === 0) {\n return structuredResult(`No errors found under ${args.path}.`, {\n path: args.path,\n total: 0,\n group_by: args.group_by,\n groups: [],\n suggestions: [],\n });\n }\n\n const keyOf = (e: { path: string; message: string; type?: string }): string =>\n args.group_by === \"message\"\n ? e.message\n : args.group_by === \"type\"\n ? e.type || \"error\"\n : parentOf(e.path);\n\n const grouped = new Map<\n string,\n { count: number; sample: { path: string; message: string } }\n >();\n const byPath = new Map<string, number>();\n for (const e of errors) {\n const key = keyOf(e);\n const g = grouped.get(key);\n if (g) g.count += 1;\n else grouped.set(key, { count: 1, sample: { path: e.path, message: e.message } });\n byPath.set(e.path, (byPath.get(e.path) ?? 0) + 1);\n }\n\n const groups = [...grouped.entries()]\n .map(([key, g]) => ({ key, count: g.count, sample: g.sample }))\n .sort((a, b) => b.count - a.count);\n\n const worstNodes = [...byPath.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 3)\n .map(([p, c]) => `${p} (${c} error${c === 1 ? \"\" : \"s\"})`);\n\n const suggestions: string[] = [];\n if (groups[0] && groups[0].count > 1) {\n suggestions.push(\n `${groups[0].count} errors share ${args.group_by} \"${groups[0].key}\" — fixing the common cause clears them at once.`,\n );\n }\n if (worstNodes.length > 0) {\n suggestions.push(`Check first: ${worstNodes.join(\", \")}.`);\n }\n\n return structuredResult(\n `${total} error(s) under ${args.path} in ${groups.length} ${args.group_by} group(s).`,\n { path: args.path, total, group_by: args.group_by, groups, suggestions },\n );\n },\n );\n}\n\nexport const registerSummarizeTdErrors: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"summarize_td_errors\",\n {\n title: \"Summarize network errors\",\n description:\n \"Collect errors across a network and cluster them by message, type, or parent container, with the worst-offending nodes and a suggested order to investigate. Use this instead of reading every node's errors one by one.\",\n inputSchema: summarizeTdErrorsSchema.shape,\n outputSchema: summarizeTdErrorsOutputSchema.shape,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n (args) => summarizeTdErrorsImpl(ctx, args),\n );\n};\n","import { z } from \"zod\";\nimport { guardTd, jsonResult } from \"../result.js\";\nimport type { ToolContext, ToolRegistrar } from \"../types.js\";\n\nexport const updateTdNodeParametersSchema = z.object({\n path: z.string().describe(\"Full path of the node whose parameters to update.\"),\n parameters: z\n .record(z.string(), z.unknown())\n .describe(\"Parameter overrides as key→value pairs, e.g. { period: 4, amplitude: 0.5 }.\"),\n});\ntype UpdateTdNodeParametersArgs = z.infer<typeof updateTdNodeParametersSchema>;\n\nexport async function updateTdNodeParametersImpl(\n ctx: ToolContext,\n args: UpdateTdNodeParametersArgs,\n) {\n return guardTd(\n () => ctx.client.updateNodeParameters(args.path, args.parameters),\n (node) =>\n jsonResult(`Updated ${Object.keys(args.parameters).length} parameter(s) on ${node.path}.`, {\n node,\n }),\n );\n}\n\nexport const registerUpdateTdNodeParameters: ToolRegistrar = (server, ctx) => {\n server.registerTool(\n \"update_td_node_parameters\",\n {\n title: \"Update node parameters\",\n description: \"Set one or more parameters on an existing node.\",\n inputSchema: updateTdNodeParametersSchema.shape,\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n },\n (args) => updateTdNodeParametersImpl(ctx, args),\n );\n};\n","import { existsSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve, sep } from \"node:path\";\nimport { LlmClient } from \"../llm/client.js\";\nimport { buildToolContext } from \"../server/context.js\";\nimport { friendlyTdError } from \"../td-client/types.js\";\nimport type { ToolContext } from \"../tools/types.js\";\nimport { loadConfig, type TdmcpConfig, tdBaseUrl } from \"../utils/config.js\";\nimport { silentLogger } from \"../utils/logger.js\";\n\n/**\n * `tdmcp doctor` — a one-shot environment diagnostic for non-technical artists.\n *\n * It probes the things a fresh setup needs (the TouchDesigner bridge, the local\n * LLM copilot, the optional vault) and resolves the effective config, then prints\n * a plain-language pass/warn/fail report. The exit code is 0 unless a *critical*\n * check fails (the bridge or the config), so the optional copilot/vault never\n * blocks an otherwise-healthy setup.\n */\n\nexport type CheckStatus = \"pass\" | \"warn\" | \"fail\";\n\nexport interface DoctorCheck {\n /** Short stable id (machine-readable): \"bridge\" | \"config\" | \"llm\" | \"vault\". */\n id: string;\n /** Human label shown in the report. */\n title: string;\n status: CheckStatus;\n /** One-line explanation of the result. */\n detail: string;\n /** Whether a failure here is fatal (drives the exit code). */\n critical: boolean;\n /** Optional extra facts surfaced in the structured result (versions, urls, …). */\n data?: Record<string, unknown>;\n}\n\nexport interface DoctorReport {\n ok: boolean;\n checks: DoctorCheck[];\n /** Resolved configuration the checks ran against (handy for bug reports). */\n config: {\n tdBaseUrl: string;\n llmBaseUrl: string;\n llmModel: string;\n chatPort: number;\n vaultPath: string | null;\n };\n}\n\n/** Mirrors `CliResult` from agent.ts, plus the structured report for programmatic use. */\nexport interface DoctorResult {\n stdout: string;\n stderr: string;\n code: number;\n report: DoctorReport;\n}\n\nexport interface RunDoctorOptions {\n /** Inject a config (tests / callers that already loaded one); defaults to env. */\n config?: TdmcpConfig;\n /** Inject a context (tests); production builds one from the config. */\n makeCtx?: (config: TdmcpConfig) => ToolContext;\n /** Inject an LLM client (tests); defaults to a real `LlmClient` over the config. */\n makeLlmClient?: (config: TdmcpConfig) => Pick<LlmClient, \"health\">;\n /** Overridable filesystem probe for the vault check (tests); defaults to real fs. */\n vaultProbe?: (absPath: string) => { exists: boolean; isDir: boolean };\n}\n\nconst ICON: Record<CheckStatus, string> = { pass: \"✔\", warn: \"!\", fail: \"✖\" };\n\n/** Expands a leading `~/` the same way the Vault does, so the report matches reality. */\nfunction expandHome(p: string): string {\n if (p === \"~\") return homedir();\n if (p.startsWith(\"~/\") || p.startsWith(`~${sep}`)) return join(homedir(), p.slice(2));\n return p;\n}\n\nfunction defaultVaultProbe(absPath: string): { exists: boolean; isDir: boolean } {\n if (!existsSync(absPath)) return { exists: false, isDir: false };\n try {\n return { exists: true, isDir: statSync(absPath).isDirectory() };\n } catch {\n return { exists: true, isDir: false };\n }\n}\n\n/** TD bridge reachability + version. Critical: a failure here fails the whole doctor. */\nasync function checkBridge(ctx: ToolContext): Promise<DoctorCheck> {\n const base = { id: \"bridge\", title: \"TouchDesigner bridge\", critical: true } as const;\n try {\n const info = await ctx.client.getInfo();\n const version = info.td_version ?? \"unknown\";\n const bridge = info.bridge_version ? ` · bridge ${info.bridge_version}` : \"\";\n return {\n ...base,\n status: \"pass\",\n detail: `reachable at ${ctx.client.endpoint} (TD ${version}${bridge})`,\n data: { endpoint: ctx.client.endpoint, ...info },\n };\n } catch (err) {\n return {\n ...base,\n status: \"fail\",\n detail: `not reachable at ${ctx.client.endpoint}. Start TouchDesigner with the tdmcp bridge installed. (${friendlyTdError(\n err,\n )})`,\n data: { endpoint: ctx.client.endpoint },\n };\n }\n}\n\n/**\n * Local LLM (Ollama) copilot reachability + model availability. Optional feature, so\n * this never marks the doctor as failed — unreachable or model-not-pulled is a warn.\n */\nasync function checkLlm(\n config: TdmcpConfig,\n makeClient: (config: TdmcpConfig) => Pick<LlmClient, \"health\">,\n): Promise<DoctorCheck> {\n const base = { id: \"llm\", title: \"Local LLM copilot (Ollama)\", critical: false } as const;\n const data = { baseUrl: config.llmBaseUrl, model: config.llmModel };\n const health = await makeClient(config).health();\n if (!health.ok) {\n return {\n ...base,\n status: \"warn\",\n detail: `endpoint ${config.llmBaseUrl} not reachable — \\`tdmcp chat\\` is unavailable until a local LLM server is running (${health.detail}).`,\n data,\n };\n }\n if (!health.modelReady) {\n return {\n ...base,\n status: \"warn\",\n detail: `reachable, but ${health.detail}. Run \\`ollama pull ${config.llmModel}\\` to enable \\`tdmcp chat\\`.`,\n data,\n };\n }\n return {\n ...base,\n status: \"pass\",\n detail: `reachable at ${config.llmBaseUrl} — ${health.detail}.`,\n data,\n };\n}\n\n/**\n * Vault (Obsidian notes) configuration. Optional, so an unset path is a pass-with-note.\n * A configured-but-missing folder is a warn (real misconfiguration) but not fatal.\n */\nfunction checkVault(\n config: TdmcpConfig,\n probe: (absPath: string) => { exists: boolean; isDir: boolean },\n): DoctorCheck {\n const base = { id: \"vault\", title: \"Vault (optional)\", critical: false } as const;\n if (!config.vaultPath) {\n return {\n ...base,\n status: \"pass\",\n detail: \"not configured (TDMCP_VAULT_PATH unset) — vault tools are disabled, which is fine.\",\n data: { configured: false },\n };\n }\n const absPath = resolve(expandHome(config.vaultPath));\n const { exists, isDir } = probe(absPath);\n const data = { configured: true, path: absPath };\n if (!exists) {\n return {\n ...base,\n status: \"warn\",\n detail: `TDMCP_VAULT_PATH is set to \"${config.vaultPath}\" but that folder does not exist (${absPath}).`,\n data,\n };\n }\n if (!isDir) {\n return {\n ...base,\n status: \"warn\",\n detail: `TDMCP_VAULT_PATH \"${config.vaultPath}\" exists but is not a folder (${absPath}).`,\n data,\n };\n }\n return { ...base, status: \"pass\", detail: `folder found at ${absPath}.`, data };\n}\n\n/** Config sanity: surfaces the effective TD/LLM settings. Critical (anchors the exit code). */\nfunction checkConfig(config: TdmcpConfig): DoctorCheck {\n const td = tdBaseUrl(config);\n return {\n id: \"config\",\n title: \"Config\",\n status: \"pass\",\n critical: true,\n detail: `TD ${td} · LLM ${config.llmBaseUrl} (model ${config.llmModel}) · chat port ${config.chatPort}`,\n data: {\n tdBaseUrl: td,\n llmBaseUrl: config.llmBaseUrl,\n llmModel: config.llmModel,\n chatPort: config.chatPort,\n },\n };\n}\n\nfunction render(report: DoctorReport): string {\n const lines: string[] = [\"tdmcp doctor — environment check\", \"\"];\n for (const c of report.checks) {\n lines.push(` ${ICON[c.status]} ${c.title}: ${c.detail}`);\n }\n lines.push(\"\");\n const failed = report.checks.filter((c) => c.status === \"fail\");\n const warned = report.checks.filter((c) => c.status === \"warn\");\n if (report.ok && warned.length === 0) {\n lines.push(\"All good — TouchDesigner is reachable and your setup is ready.\");\n } else if (report.ok) {\n lines.push(`Ready, with ${warned.length} optional item(s) to look at (see the ! lines above).`);\n } else {\n lines.push(\n `Setup is not ready: ${failed.length} critical check(s) failed (see the ✖ lines above).`,\n );\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * Runs every diagnostic and returns a CliResult-shaped payload (plus the structured\n * report). Exit code is 0 unless a critical check (bridge or config) fails.\n */\nexport async function runDoctor(opts: RunDoctorOptions = {}): Promise<DoctorResult> {\n // Config first: if env is invalid, loadConfig throws — that is itself a fatal result.\n let config: TdmcpConfig;\n try {\n config = opts.config ?? loadConfig();\n } catch (err) {\n const report: DoctorReport = {\n ok: false,\n checks: [\n {\n id: \"config\",\n title: \"Config\",\n status: \"fail\",\n critical: true,\n detail: `invalid configuration: ${(err as Error).message}`,\n },\n ],\n config: {\n tdBaseUrl: \"(unresolved)\",\n llmBaseUrl: \"(unresolved)\",\n llmModel: \"(unresolved)\",\n chatPort: 0,\n vaultPath: null,\n },\n };\n return {\n stdout: `${render(report)}\\n`,\n stderr: \"Setup is not ready: invalid configuration.\\n\",\n code: 1,\n report,\n };\n }\n\n const ctx = opts.makeCtx\n ? opts.makeCtx(config)\n : buildToolContext(config, { logger: silentLogger });\n const makeLlmClient = opts.makeLlmClient ?? ((c: TdmcpConfig) => new LlmClient(c));\n const vaultProbe = opts.vaultProbe ?? defaultVaultProbe;\n\n const checks: DoctorCheck[] = [\n await checkBridge(ctx),\n checkConfig(config),\n await checkLlm(config, makeLlmClient),\n checkVault(config, vaultProbe),\n ];\n\n const ok = !checks.some((c) => c.critical && c.status === \"fail\");\n const report: DoctorReport = {\n ok,\n checks,\n config: {\n tdBaseUrl: tdBaseUrl(config),\n llmBaseUrl: config.llmBaseUrl,\n llmModel: config.llmModel,\n chatPort: config.chatPort,\n vaultPath: config.vaultPath ?? null,\n },\n };\n\n const summary = ok\n ? \"Setup is ready.\"\n : \"Setup is not ready: a critical check failed (run `tdmcp doctor` for details).\";\n return { stdout: `${render(report)}\\n`, stderr: `${summary}\\n`, code: ok ? 0 : 1, report };\n}\n","import type { TdmcpConfig } from \"../utils/config.js\";\n\n/** A single chat message in the OpenAI chat-completions shape. */\nexport interface ChatMessage {\n role: \"system\" | \"user\" | \"assistant\" | \"tool\";\n content: string | null;\n /** Present on assistant turns that request tool execution. */\n tool_calls?: ToolCall[];\n /** Present on `tool` messages — links the result back to its request. */\n tool_call_id?: string;\n /** Tool name (echoed on `tool` messages for readability). */\n name?: string;\n}\n\nexport interface ToolCall {\n id: string;\n type: \"function\";\n function: { name: string; arguments: string };\n}\n\n/** OpenAI-style function tool advertised to the model. */\nexport interface OpenAITool {\n type: \"function\";\n function: { name: string; description: string; parameters: unknown };\n}\n\nexport type LlmConfig = Pick<TdmcpConfig, \"llmBaseUrl\" | \"llmModel\" | \"llmApiKey\">;\n\n/** A partial settings update from the UI (only provided fields change). */\nexport interface SettingsPatch {\n model?: string;\n baseUrl?: string;\n apiKey?: string;\n}\n\n/**\n * Merge a UI settings patch onto the current config. `model`/`baseUrl` change only\n * when non-empty; `apiKey` clears on empty string, sets on non-empty, and is left\n * untouched when omitted. Pure, so it is unit-tested directly.\n */\nexport function applySettings(current: LlmConfig, patch: SettingsPatch): LlmConfig {\n const next: LlmConfig = { ...current };\n if (patch.model?.trim()) next.llmModel = patch.model.trim();\n if (patch.baseUrl?.trim()) next.llmBaseUrl = patch.baseUrl.trim();\n if (patch.apiKey !== undefined) {\n const key = patch.apiKey.trim();\n next.llmApiKey = key.length > 0 ? key : undefined;\n }\n return next;\n}\n\n/** One line of Ollama's native `/api/pull` progress stream. */\nexport interface PullProgress {\n status: string;\n total?: number;\n completed?: number;\n}\n\n/** A streamed completion chunk in OpenAI's delta shape. */\ninterface StreamChunk {\n choices?: Array<{\n delta?: {\n content?: string | null;\n tool_calls?: Array<{\n index?: number;\n id?: string;\n type?: \"function\";\n function?: { name?: string; arguments?: string };\n }>;\n };\n finish_reason?: string | null;\n }>;\n}\n\n/**\n * Merges streamed deltas into one assistant message. Text tokens are forwarded to\n * `onToken` as they arrive; tool-call fragments are accumulated by index until the\n * stream ends. Kept pure and standalone so the merge logic is unit-testable without\n * a live endpoint (streaming tool-call reassembly is the easiest thing to get wrong).\n */\nexport class ChatAccumulator {\n content = \"\";\n private readonly calls: Array<{ id: string; name: string; args: string }> = [];\n\n constructor(private readonly onToken?: (token: string) => void) {}\n\n push(chunk: StreamChunk): void {\n const delta = chunk.choices?.[0]?.delta;\n if (!delta) return;\n if (typeof delta.content === \"string\" && delta.content.length > 0) {\n this.content += delta.content;\n this.onToken?.(delta.content);\n }\n for (const part of delta.tool_calls ?? []) {\n const idx = part.index ?? 0;\n let slot = this.calls[idx];\n if (!slot) {\n slot = { id: \"\", name: \"\", args: \"\" };\n this.calls[idx] = slot;\n }\n if (part.id) slot.id = part.id;\n if (part.function?.name) slot.name = part.function.name;\n if (part.function?.arguments) slot.args += part.function.arguments;\n }\n }\n\n finish(): ChatMessage {\n const toolCalls = this.calls\n .filter((c) => c.name.length > 0)\n .map((c) => ({\n id: c.id || `call_${c.name}`,\n type: \"function\" as const,\n function: { name: c.name, arguments: c.args },\n }));\n return {\n role: \"assistant\",\n content: this.content || null,\n ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),\n };\n }\n}\n\nexport interface StreamOptions {\n signal?: AbortSignal;\n onToken?: (token: string) => void;\n}\n\n/** Read a byte stream line by line, trimming and skipping blanks. */\nasync function readLines(\n body: ReadableStream<Uint8Array>,\n onLine: (line: string) => void,\n): Promise<void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buf = \"\";\n for (;;) {\n const { value, done } = await reader.read();\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n let nl = buf.indexOf(\"\\n\");\n while (nl >= 0) {\n const line = buf.slice(0, nl).trim();\n buf = buf.slice(nl + 1);\n if (line) onLine(line);\n nl = buf.indexOf(\"\\n\");\n }\n }\n const tail = buf.trim();\n if (tail) onLine(tail);\n}\n\n/**\n * Thin client for any OpenAI-compatible `/chat/completions` endpoint. The default\n * target is a local Ollama server, but the same code talks to LM Studio, a cloud\n * GPU, or a paid API — the only knobs are base URL, model and an optional token.\n */\nexport class LlmClient {\n constructor(private readonly cfg: LlmConfig) {}\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { \"content-type\": \"application/json\" };\n if (this.cfg.llmApiKey) h.authorization = `Bearer ${this.cfg.llmApiKey}`;\n return h;\n }\n\n /** Ollama's native API lives at the root; derive it from the OpenAI base URL. */\n private nativeRoot(): string {\n return this.cfg.llmBaseUrl.replace(/\\/v1\\/?$/, \"\");\n }\n\n /** Reachability + model-availability probe used to show a friendly banner. */\n async health(): Promise<{ ok: boolean; modelReady: boolean; detail: string }> {\n try {\n const res = await fetch(`${this.cfg.llmBaseUrl}/models`, { headers: this.headers() });\n if (!res.ok)\n return { ok: false, modelReady: false, detail: `endpoint returned HTTP ${res.status}` };\n const data = (await res.json()) as { data?: Array<{ id: string }> };\n const models = (data.data ?? []).map((m) => m.id);\n const modelReady = models.includes(this.cfg.llmModel);\n const detail = modelReady\n ? `model '${this.cfg.llmModel}' is ready`\n : `model '${this.cfg.llmModel}' is not pulled (available: ${models.join(\", \") || \"none\"})`;\n return { ok: true, modelReady, detail };\n } catch (err) {\n return { ok: false, modelReady: false, detail: (err as Error).message };\n }\n }\n\n /** List the model ids the endpoint currently has available (empty on any failure). */\n async listModels(): Promise<string[]> {\n try {\n const res = await fetch(`${this.cfg.llmBaseUrl}/models`, { headers: this.headers() });\n if (!res.ok) return [];\n const data = (await res.json()) as { data?: Array<{ id: string }> };\n return (data.data ?? []).map((m) => m.id);\n } catch {\n return [];\n }\n }\n\n /** One streaming completion. Forwards text tokens via `onToken`; returns the assembled message. */\n async chatStream(\n messages: ChatMessage[],\n tools: OpenAITool[],\n opts: StreamOptions = {},\n ): Promise<ChatMessage> {\n const res = await fetch(`${this.cfg.llmBaseUrl}/chat/completions`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n model: this.cfg.llmModel,\n messages,\n tools,\n tool_choice: \"auto\",\n temperature: 0.4,\n stream: true,\n }),\n signal: opts.signal,\n });\n if (!res.ok) {\n const body = await res.text();\n throw new Error(`LLM endpoint returned HTTP ${res.status}: ${body.slice(0, 300)}`);\n }\n if (!res.body) throw new Error(\"LLM endpoint returned no response body\");\n\n const acc = new ChatAccumulator(opts.onToken);\n await readLines(res.body, (line) => {\n if (!line.startsWith(\"data:\")) return;\n const data = line.slice(5).trim();\n if (data === \"[DONE]\") return;\n try {\n acc.push(JSON.parse(data) as StreamChunk);\n } catch {\n // ignore keep-alives / non-JSON lines\n }\n });\n return acc.finish();\n }\n\n /** Pull the configured model via Ollama's native API, forwarding progress lines. */\n async pull(onProgress: (p: PullProgress) => void, signal?: AbortSignal): Promise<void> {\n const res = await fetch(`${this.nativeRoot()}/api/pull`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ name: this.cfg.llmModel, stream: true }),\n signal,\n });\n if (!res.ok)\n throw new Error(`pull failed (HTTP ${res.status}) — auto-pull needs a local Ollama server`);\n if (!res.body) return;\n await readLines(res.body, (line) => {\n try {\n onProgress(JSON.parse(line) as PullProgress);\n } catch {\n // ignore non-JSON lines\n }\n });\n }\n}\n"],"mappings":"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","names":["writeFileSync","resolve","z","existsSync","existsSync","q","existsSync","readdirSync","readFileSync","join","z","z","existsSync","readdirSync","readFileSync","join","r","existsSync","readdirSync","readFileSync","dirname","join","resolve","resolve","existsSync","readFileSync","dirname","readdirSync","join","z","resolve","z","z","q","parentPath","q","z","z","z","r","z","q","z","render","z","q","PRIMITIVE_SOP","z","render","z","q","z","z","q","z","z","z","z","q","z","z","q","z","buildSource","render","z","q","z","buildSource","z","q","z","z","q","r","z","z","q","z","builder","z","q","z","buildSource","z","q","z","render","z","q","z","buildSource","z","z","z","q","z","hexToRgb","z","z","z","q","z","render","z","q","z","buildSource","z","q","RESOLUTIONS","z","z","q","q2","z","render","z","z","z","q","z","z","q","z","z","z","buildSource","z","q","z","hexToRgb","z","q","z","ENGINE","z","q","z","z","RESOLUTIONS","hexToRgb","z","r","z","z","z","q","SHADERS","HEX_COLOR","parseHexColor","z","z","z","z","q","z","hexToRgb","buildSource","render","z","z","z","q","z","buildSource","z","z","buildSource","z","z","buildSource","z","z","z","q","z","render","z","z","r","z","z","z","q","RESOLUTIONS","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","RESOLUTIONS","q","z","z","z","z","z","q","z","z","z","z","z","z","q","z","z","z","z","z","z","z","z","z","z","z","z","z","r","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","parentOf","z","fetch","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","parentOf","z","z","existsSync","homedir","join","resolve","sep","expandHome","homedir","sep","join","existsSync","resolve","report","z","cmd","raw","parsed","resolve","ctx","writeFileSync"]}