@dpantani/tdmcp 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -346
- package/dist/cli/agent.d.ts +139 -3
- package/dist/cli/agent.js +10236 -405
- package/dist/cli/agent.js.map +1 -1
- package/dist/index.js +13845 -2954
- package/dist/index.js.map +1 -1
- package/dist/knowledge/data/meta.json +1 -1
- package/dist/recipes/feedback_tunnel.json +4 -4
- package/dist/recipes/noise_landscape.json +102 -1
- package/dist/recipes/performable_feedback_tunnel.json +92 -0
- package/dist/recipes/webcam_glitch.json +5 -1
- package/package.json +21 -3
- package/recipes/feedback_tunnel.json +4 -4
- package/recipes/noise_landscape.json +102 -1
- package/recipes/performable_feedback_tunnel.json +92 -0
- package/recipes/webcam_glitch.json +5 -1
- package/td/README.md +1 -1
- package/td/modules/mcp/controllers/api_controller.py +70 -7
- package/td/modules/mcp/services/analysis_service.py +7 -2
- package/td/modules/mcp/services/api_service.py +25 -3
- package/td/modules/mcp/services/batch_service.py +36 -2
- package/td/modules/mcp/services/preview_service.py +89 -11
- package/td/modules/utils/version.py +1 -1
- package/td/tests/test_api_controller.py +67 -2
- package/td/tests/test_services.py +209 -0
package/dist/cli/agent.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ interface Logger {
|
|
|
7
7
|
error(message: string, meta?: Record<string, unknown>): void;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
interface TdEvent {
|
|
11
|
+
event: string;
|
|
12
|
+
data?: unknown;
|
|
13
|
+
}
|
|
14
|
+
type TdEventHandler = (event: TdEvent) => void;
|
|
15
|
+
|
|
10
16
|
interface OperatorParameter {
|
|
11
17
|
name: string;
|
|
12
18
|
label?: string;
|
|
@@ -201,6 +207,38 @@ declare class KnowledgeBase {
|
|
|
201
207
|
stats(): KnowledgeStats;
|
|
202
208
|
}
|
|
203
209
|
|
|
210
|
+
interface ParsedNote {
|
|
211
|
+
/** Parsed YAML frontmatter (empty object when the note has none). */
|
|
212
|
+
data: Record<string, unknown>;
|
|
213
|
+
/** Markdown body with the frontmatter stripped. */
|
|
214
|
+
body: string;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* A thin, safe wrapper over an Obsidian vault (a folder of markdown files on the
|
|
219
|
+
* local filesystem). Every path is resolved relative to the vault root and is
|
|
220
|
+
* refused if it escapes that root, so user-supplied note names cannot reach
|
|
221
|
+
* outside the vault.
|
|
222
|
+
*/
|
|
223
|
+
declare class Vault {
|
|
224
|
+
readonly root: string;
|
|
225
|
+
private readonly logger;
|
|
226
|
+
constructor(root: string, logger?: Logger);
|
|
227
|
+
/** Resolves a vault-relative path, throwing if it would escape the vault root. */
|
|
228
|
+
resolve(relPath: string): string;
|
|
229
|
+
exists(relPath: string): boolean;
|
|
230
|
+
read(relPath: string): string;
|
|
231
|
+
write(relPath: string, content: string): void;
|
|
232
|
+
writeBinary(relPath: string, data: Buffer): void;
|
|
233
|
+
ensureDir(relPath: string): void;
|
|
234
|
+
/** Lists file names directly inside `subdir`, optionally filtered by extension. */
|
|
235
|
+
list(subdir: string, ext?: string): string[];
|
|
236
|
+
/** Reads a markdown note and splits its frontmatter from its body. */
|
|
237
|
+
readNote(relPath: string): ParsedNote;
|
|
238
|
+
/** Writes a markdown note from frontmatter data + body. */
|
|
239
|
+
writeNote(relPath: string, data: Record<string, unknown>, body: string): void;
|
|
240
|
+
}
|
|
241
|
+
|
|
204
242
|
declare const RecipeSchema: z.ZodObject<{
|
|
205
243
|
id: z.ZodString;
|
|
206
244
|
name: z.ZodString;
|
|
@@ -252,6 +290,24 @@ declare const RecipeSchema: z.ZodObject<{
|
|
|
252
290
|
}, z.core.$strip>>>;
|
|
253
291
|
glsl_code: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
254
292
|
python_code: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
293
|
+
controls: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
294
|
+
name: z.ZodString;
|
|
295
|
+
type: z.ZodDefault<z.ZodEnum<{
|
|
296
|
+
string: "string";
|
|
297
|
+
int: "int";
|
|
298
|
+
float: "float";
|
|
299
|
+
toggle: "toggle";
|
|
300
|
+
menu: "menu";
|
|
301
|
+
rgb: "rgb";
|
|
302
|
+
pulse: "pulse";
|
|
303
|
+
}>>;
|
|
304
|
+
label: z.ZodOptional<z.ZodString>;
|
|
305
|
+
min: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
306
|
+
max: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
307
|
+
default: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodBoolean, z.ZodString]>>;
|
|
308
|
+
menu_items: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
309
|
+
bind_to: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
310
|
+
}, z.core.$strip>>>;
|
|
255
311
|
preview_description: z.ZodDefault<z.ZodString>;
|
|
256
312
|
}, z.core.$strip>;
|
|
257
313
|
type Recipe = z.infer<typeof RecipeSchema>;
|
|
@@ -266,11 +322,14 @@ interface RecipeSummary {
|
|
|
266
322
|
interface RecipeLibraryOptions {
|
|
267
323
|
dir?: string;
|
|
268
324
|
logger?: Logger;
|
|
325
|
+
/** Optional Obsidian vault; recipes in `<vault>/Recipes/*.md` are merged in (and override built-ins by id). */
|
|
326
|
+
vault?: Vault;
|
|
269
327
|
}
|
|
270
|
-
/** Loads and validates recipe JSON files from the recipes directory. */
|
|
328
|
+
/** Loads and validates recipe JSON files from the recipes directory, plus any vault recipes. */
|
|
271
329
|
declare class RecipeLibrary {
|
|
272
330
|
private readonly dir;
|
|
273
331
|
private readonly logger;
|
|
332
|
+
private readonly vault?;
|
|
274
333
|
private cache?;
|
|
275
334
|
constructor(options?: RecipeLibraryOptions);
|
|
276
335
|
private load;
|
|
@@ -320,6 +379,16 @@ interface TouchDesignerClientOptions {
|
|
|
320
379
|
token?: string;
|
|
321
380
|
/** Overridable for tests (defaults to global `fetch`). */
|
|
322
381
|
fetchImpl?: typeof fetch;
|
|
382
|
+
/**
|
|
383
|
+
* Extra attempts for a transient connection failure on an **idempotent** (GET)
|
|
384
|
+
* request — e.g. TD briefly stalls mid-build. Default 2 (so up to 3 tries).
|
|
385
|
+
* Only `TdConnectionError` is retried; timeouts and bridge errors are not (a
|
|
386
|
+
* timeout may mean the request was received, and non-GET methods aren't safe
|
|
387
|
+
* to repeat). Set 0 to disable.
|
|
388
|
+
*/
|
|
389
|
+
retries?: number;
|
|
390
|
+
/** Base backoff between retries, in ms (linear: delay × attempt). Default 150. */
|
|
391
|
+
retryDelayMs?: number;
|
|
323
392
|
}
|
|
324
393
|
/**
|
|
325
394
|
* HTTP client for the TouchDesigner REST bridge. Every method maps to one of the
|
|
@@ -332,9 +401,12 @@ declare class TouchDesignerClient {
|
|
|
332
401
|
private readonly logger;
|
|
333
402
|
private readonly token;
|
|
334
403
|
private readonly fetchImpl;
|
|
404
|
+
private readonly retries;
|
|
405
|
+
private readonly retryDelayMs;
|
|
335
406
|
constructor(options: TouchDesignerClientOptions);
|
|
336
407
|
get endpoint(): string;
|
|
337
408
|
private request;
|
|
409
|
+
private attemptRequest;
|
|
338
410
|
getInfo(): Promise<{
|
|
339
411
|
td_version?: string | undefined;
|
|
340
412
|
python_version?: string | undefined;
|
|
@@ -346,6 +418,7 @@ declare class TouchDesignerClient {
|
|
|
346
418
|
path: string;
|
|
347
419
|
type: string;
|
|
348
420
|
name: string;
|
|
421
|
+
parameter_warnings?: string[] | undefined;
|
|
349
422
|
}>;
|
|
350
423
|
deleteNode(path: string): Promise<{
|
|
351
424
|
deleted: string;
|
|
@@ -355,6 +428,7 @@ declare class TouchDesignerClient {
|
|
|
355
428
|
path: string;
|
|
356
429
|
type: string;
|
|
357
430
|
name: string;
|
|
431
|
+
parameter_warnings?: string[] | undefined;
|
|
358
432
|
}[];
|
|
359
433
|
}>;
|
|
360
434
|
getNode(path: string): Promise<{
|
|
@@ -362,6 +436,7 @@ declare class TouchDesignerClient {
|
|
|
362
436
|
type: string;
|
|
363
437
|
name: string;
|
|
364
438
|
parameters: Record<string, unknown>;
|
|
439
|
+
parameter_warnings?: string[] | undefined;
|
|
365
440
|
inputs?: string[] | undefined;
|
|
366
441
|
outputs?: string[] | undefined;
|
|
367
442
|
family?: string | undefined;
|
|
@@ -372,6 +447,7 @@ declare class TouchDesignerClient {
|
|
|
372
447
|
type: string;
|
|
373
448
|
name: string;
|
|
374
449
|
parameters: Record<string, unknown>;
|
|
450
|
+
parameter_warnings?: string[] | undefined;
|
|
375
451
|
inputs?: string[] | undefined;
|
|
376
452
|
outputs?: string[] | undefined;
|
|
377
453
|
family?: string | undefined;
|
|
@@ -420,6 +496,7 @@ declare class TouchDesignerClient {
|
|
|
420
496
|
path: string;
|
|
421
497
|
type: string;
|
|
422
498
|
name: string;
|
|
499
|
+
parameter_warnings?: string[] | undefined;
|
|
423
500
|
}[];
|
|
424
501
|
connections: {
|
|
425
502
|
source_path: string;
|
|
@@ -428,7 +505,7 @@ declare class TouchDesignerClient {
|
|
|
428
505
|
target_input: number;
|
|
429
506
|
}[];
|
|
430
507
|
}>;
|
|
431
|
-
getNetworkPerformance(path: string): Promise<{
|
|
508
|
+
getNetworkPerformance(path: string, recursive?: boolean): Promise<{
|
|
432
509
|
nodes: {
|
|
433
510
|
path: string;
|
|
434
511
|
cook_time_ms: number;
|
|
@@ -445,6 +522,8 @@ interface ToolContext {
|
|
|
445
522
|
knowledge: KnowledgeBase;
|
|
446
523
|
recipes: RecipeLibrary;
|
|
447
524
|
logger: Logger;
|
|
525
|
+
/** Optional Obsidian vault (set via TDMCP_VAULT_PATH); undefined when not configured. */
|
|
526
|
+
vault?: Vault;
|
|
448
527
|
/**
|
|
449
528
|
* Whether the raw Python escape-hatch tools may be registered. Undefined means
|
|
450
529
|
* allowed (the default); only an explicit `false` locks them out.
|
|
@@ -452,6 +531,39 @@ interface ToolContext {
|
|
|
452
531
|
allowRawPython?: boolean;
|
|
453
532
|
}
|
|
454
533
|
|
|
534
|
+
declare const ConfigSchema: z.ZodObject<{
|
|
535
|
+
tdHost: z.ZodDefault<z.ZodString>;
|
|
536
|
+
tdPort: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
537
|
+
transport: z.ZodDefault<z.ZodEnum<{
|
|
538
|
+
stdio: "stdio";
|
|
539
|
+
http: "http";
|
|
540
|
+
}>>;
|
|
541
|
+
logLevel: z.ZodDefault<z.ZodEnum<{
|
|
542
|
+
error: "error";
|
|
543
|
+
debug: "debug";
|
|
544
|
+
info: "info";
|
|
545
|
+
warn: "warn";
|
|
546
|
+
silent: "silent";
|
|
547
|
+
}>>;
|
|
548
|
+
requestTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
549
|
+
httpPort: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
550
|
+
events: z.ZodDefault<z.ZodEnum<{
|
|
551
|
+
on: "on";
|
|
552
|
+
off: "off";
|
|
553
|
+
}>>;
|
|
554
|
+
rawPython: z.ZodDefault<z.ZodEnum<{
|
|
555
|
+
on: "on";
|
|
556
|
+
off: "off";
|
|
557
|
+
}>>;
|
|
558
|
+
bridgeToken: z.ZodOptional<z.ZodString>;
|
|
559
|
+
llmBaseUrl: z.ZodDefault<z.ZodString>;
|
|
560
|
+
llmModel: z.ZodDefault<z.ZodString>;
|
|
561
|
+
llmApiKey: z.ZodOptional<z.ZodString>;
|
|
562
|
+
chatPort: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
563
|
+
vaultPath: z.ZodOptional<z.ZodString>;
|
|
564
|
+
}, z.core.$strip>;
|
|
565
|
+
type TdmcpConfig = z.infer<typeof ConfigSchema>;
|
|
566
|
+
|
|
455
567
|
interface CliResult {
|
|
456
568
|
stdout: string;
|
|
457
569
|
stderr: string;
|
|
@@ -462,5 +574,29 @@ interface RunCliOptions {
|
|
|
462
574
|
makeCtx?: () => ToolContext;
|
|
463
575
|
}
|
|
464
576
|
declare function runCli(argv: string[], opts?: RunCliOptions): Promise<CliResult>;
|
|
577
|
+
interface RunWatchOptions {
|
|
578
|
+
config?: TdmcpConfig;
|
|
579
|
+
includeHighFrequency?: boolean;
|
|
580
|
+
/** Where each event line goes; defaults to stdout. Overridable for tests. */
|
|
581
|
+
write?: (line: string) => void;
|
|
582
|
+
/** Inject a stream factory for tests; defaults to a real `TdEventStream`. */
|
|
583
|
+
makeStream?: (args: {
|
|
584
|
+
url: string;
|
|
585
|
+
onEvent: TdEventHandler;
|
|
586
|
+
includeHighFrequency: boolean;
|
|
587
|
+
}) => {
|
|
588
|
+
start: () => void;
|
|
589
|
+
close: () => void;
|
|
590
|
+
};
|
|
591
|
+
/** Resolve the returned promise when aborted; defaults to listening for SIGINT. */
|
|
592
|
+
signal?: AbortSignal;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Streams TouchDesigner bridge events to stdout as ndjson until interrupted.
|
|
596
|
+
* Runs outside `runCli` because it is a long-lived stream, not a request/response.
|
|
597
|
+
*/
|
|
598
|
+
declare function runWatch(opts?: RunWatchOptions): Promise<void>;
|
|
599
|
+
/** Interactive read-eval-print loop: each line is tokenized and run through runCli. */
|
|
600
|
+
declare function runRepl(opts?: RunCliOptions): Promise<void>;
|
|
465
601
|
|
|
466
|
-
export { type CliResult, type RunCliOptions, runCli };
|
|
602
|
+
export { type CliResult, type RunCliOptions, type RunWatchOptions, runCli, runRepl, runWatch };
|