touchdesigner-mcp-server 1.4.0 → 1.4.2
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.ja.md +5 -1
- package/README.md +5 -4
- package/dist/core/compatibility.js +13 -9
- package/dist/features/tools/handlers/tdTools.js +25 -96
- package/dist/gen/endpoints/TouchDesignerAPI.js +1 -1
- package/dist/gen/mcp/touchDesignerAPI.zod.js +1 -1
- package/dist/tdClient/touchDesignerClient.js +68 -7
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -18,6 +18,8 @@ TouchDesigner MCPは、AIモデルとTouchDesigner WebServer DAT 間のブリッ
|
|
|
18
18
|
|
|
19
19
|
**[インストールガイド](docs/installation.ja.md)** を参照してください。
|
|
20
20
|
|
|
21
|
+
アップデートする場合は **[最新リリース](https://github.com/8beeeaaat/touchdesigner-mcp/releases/latest#for-updates-from-previous-versions)** の手順を参照してください。
|
|
22
|
+
|
|
21
23
|
## MCPサーバーの機能
|
|
22
24
|
|
|
23
25
|
このサーバーは、Model Context Protocol (MCP) を通じてTouchDesigner への操作、および各種実装ドキュメントへの参照を可能にします。
|
|
@@ -87,9 +89,11 @@ TouchDesigner MCPは、AIモデルとTouchDesigner WebServer DAT 間のブリッ
|
|
|
87
89
|
|
|
88
90
|
- **開発者向け:** ローカルで開発している場合は、`package.json` を編集した後に `npm run version` を実行してください(または単に `npm version ...` を使用してください)。これにより、Python API(`pyproject.toml` + `td/modules/utils/version.py`)、MCPバンドルマニフェスト、およびレジストリメタデータが同期され、ランタイム互換性チェックが成功するようになります。
|
|
89
91
|
|
|
92
|
+
互換性チェックの内部動作については [Version Compatibility Verification](docs/architecture.md#version-compatibility-verification) も参照してください。
|
|
93
|
+
|
|
90
94
|
### 接続エラーのトラブルシューティング
|
|
91
95
|
|
|
92
|
-
- `TouchDesignerClient` は接続に失敗した互換性チェック結果を **最大
|
|
96
|
+
- `TouchDesignerClient` は接続に失敗した互換性チェック結果を **最大60秒間キャッシュ**し、その間のツール呼び出しでは同じエラーを再利用して TouchDesigner への無駄な負荷を避けます。TTL が切れると自動的に再試行します。
|
|
93
97
|
- MCP サーバーが TouchDesigner に接続できない場合は、次のようなガイド付きメッセージが表示されます:
|
|
94
98
|
- `ECONNREFUSED` / "connect refused": TouchDesigner を起動し、`mcp_webserver_base.tox` からインポートした WebServer DAT がアクティブか、ポート設定(デフォルト `9981`)が正しいか確認してください。
|
|
95
99
|
- `ETIMEDOUT` / "timeout": TouchDesigner の応答が遅い、またはネットワークが詰まっています。TouchDesigner/ WebServer DAT の再起動やネットワーク状況の確認を行ってください。
|
package/README.md
CHANGED
|
@@ -16,10 +16,9 @@ TouchDesigner MCP acts as a bridge between AI models and the TouchDesigner WebSe
|
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Please refer to the **[Installation Guide](docs/installation.md)**.
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
troubleshooting tips.
|
|
21
|
+
If you are updating, please refer to the procedure in the **[Latest Release](https://github.com/8beeeaaat/touchdesigner-mcp/releases/latest#for-updates-from-previous-versions)**.
|
|
23
22
|
|
|
24
23
|
## MCP Server Features
|
|
25
24
|
|
|
@@ -91,9 +90,11 @@ The MCP server uses **semantic versioning** for flexible compatibility checks
|
|
|
91
90
|
|
|
92
91
|
- **For developers:** When developing locally, run `npm run version` after editing `package.json` (or simply use `npm version ...`). This keeps the Python API (`pyproject.toml` + `td/modules/utils/version.py`), MCP bundle manifest, and registry metadata in sync so that the runtime compatibility check succeeds.
|
|
93
92
|
|
|
93
|
+
For a deeper look at how the MCP server enforces these rules, see [Version Compatibility Verification](docs/architecture.md#version-compatibility-verification).
|
|
94
|
+
|
|
94
95
|
### Troubleshooting connection errors
|
|
95
96
|
|
|
96
|
-
- `TouchDesignerClient` caches failed connection checks for **
|
|
97
|
+
- `TouchDesignerClient` caches failed connection checks for **60 seconds**. Subsequent tool calls reuse the cached error to avoid spamming TouchDesigner and automatically retry after the TTL expires.
|
|
97
98
|
- When the MCP server cannot reach TouchDesigner, you now get guided error messages with concrete fixes:
|
|
98
99
|
- `ECONNREFUSED` / "connect refused": start TouchDesigner, ensure the WebServer DAT from `mcp_webserver_base.tox` is running, and confirm the configured port (default `9981`).
|
|
99
100
|
- `ETIMEDOUT` / "timeout": TouchDesigner is responding slowly or the network is blocked. Restart TouchDesigner/WebServer DAT or check your network connection.
|
|
@@ -65,11 +65,11 @@ const COMPATIBILITY_POLICY = {
|
|
|
65
65
|
},
|
|
66
66
|
/**
|
|
67
67
|
* Behavior when PATCH versions differ
|
|
68
|
-
* - '
|
|
68
|
+
* - 'allow': Allow without logging
|
|
69
69
|
*/
|
|
70
70
|
[COMPATIBILITY_POLICY_TYPES.PATCH_DIFF]: {
|
|
71
71
|
compatible: true,
|
|
72
|
-
level: COMPATIBILITY_POLICY_ERROR_LEVELS.
|
|
72
|
+
level: COMPATIBILITY_POLICY_ERROR_LEVELS.ALLOW,
|
|
73
73
|
message: generatePatchDiffMessage,
|
|
74
74
|
},
|
|
75
75
|
/**
|
|
@@ -112,14 +112,15 @@ export const getCompatibilityPolicy = (type) => {
|
|
|
112
112
|
* Update guide template
|
|
113
113
|
*/
|
|
114
114
|
const updateGuide = `
|
|
115
|
-
Update Guide:
|
|
116
|
-
1. Download the latest release
|
|
115
|
+
Update Guide: https://github.com/8beeeaaat/touchdesigner-mcp/releases/latest#for-updates-from-previous-versions
|
|
116
|
+
1. Download the latest release files from the releases page
|
|
117
117
|
2. Replace TouchDesigner components:
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
1. Delete the existing touchdesigner-mcp-td folder from your system
|
|
119
|
+
2. Delete old mcp_webserver_base node from your TouchDesigner project
|
|
120
|
+
3. Extract and import the new mcp_webserver_base.tox to your TouchDesigner project
|
|
120
121
|
3. Restart TouchDesigner and the MCP client (e.g., Claude Desktop)
|
|
121
122
|
|
|
122
|
-
For more details, see: https://github.com/8beeeaaat/touchdesigner-mcp#troubleshooting-version-compatibility
|
|
123
|
+
For more details on compatibility, see: https://github.com/8beeeaaat/touchdesigner-mcp#troubleshooting-version-compatibility
|
|
123
124
|
`.trim();
|
|
124
125
|
/**
|
|
125
126
|
* Generate error message for unknown version information
|
|
@@ -131,8 +132,11 @@ export function generateNoVersionMessage(args) {
|
|
|
131
132
|
MCP Server: ${args.mcpVersion || "Unknown"}
|
|
132
133
|
API Server: ${args.apiVersion || "Unknown"}
|
|
133
134
|
|
|
135
|
+
${args.apiVersion ? "" : "You might be using an old tox file from before v1.3.0 released on December 1, 2025, or the TouchDesigner setup might not be done correctly."}
|
|
136
|
+
${args.mcpVersion ? "" : "The MCP server version could not be determined. You might be using an outdated MCP server."}
|
|
137
|
+
|
|
134
138
|
Version information is required to ensure compatibility between the MCP server and TouchDesigner components.
|
|
135
|
-
Please ensure both components are updated to
|
|
139
|
+
Please ensure both components are updated to latest versions.
|
|
136
140
|
|
|
137
141
|
${updateGuide}
|
|
138
142
|
`.trim();
|
|
@@ -148,7 +152,7 @@ MCP Server: ${args.mcpVersion}
|
|
|
148
152
|
API Server: ${args.apiVersion}
|
|
149
153
|
|
|
150
154
|
MAJOR version mismatch indicates breaking changes.
|
|
151
|
-
|
|
155
|
+
Please ensure both components are updated to compatible versions.
|
|
152
156
|
|
|
153
157
|
${updateGuide}
|
|
154
158
|
`.trim();
|
|
@@ -75,14 +75,7 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
75
75
|
detailLevel: detailLevel ?? "summary",
|
|
76
76
|
responseFormat,
|
|
77
77
|
});
|
|
78
|
-
return
|
|
79
|
-
content: [
|
|
80
|
-
{
|
|
81
|
-
text: formattedText,
|
|
82
|
-
type: "text",
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
};
|
|
78
|
+
return createToolResult(tdClient, formattedText);
|
|
86
79
|
}
|
|
87
80
|
catch (error) {
|
|
88
81
|
return handleToolError(error, logger, TOOL_NAMES.GET_TD_INFO);
|
|
@@ -104,14 +97,7 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
104
97
|
detailLevel: detailLevel ?? "summary",
|
|
105
98
|
responseFormat,
|
|
106
99
|
});
|
|
107
|
-
return
|
|
108
|
-
content: [
|
|
109
|
-
{
|
|
110
|
-
text: formattedText,
|
|
111
|
-
type: "text",
|
|
112
|
-
},
|
|
113
|
-
],
|
|
114
|
-
};
|
|
100
|
+
return createToolResult(tdClient, formattedText);
|
|
115
101
|
}
|
|
116
102
|
catch (error) {
|
|
117
103
|
return handleToolError(error, logger, TOOL_NAMES.EXECUTE_PYTHON_SCRIPT);
|
|
@@ -128,14 +114,7 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
128
114
|
detailLevel: detailLevel ?? "summary",
|
|
129
115
|
responseFormat,
|
|
130
116
|
});
|
|
131
|
-
return
|
|
132
|
-
content: [
|
|
133
|
-
{
|
|
134
|
-
text: formattedText,
|
|
135
|
-
type: "text",
|
|
136
|
-
},
|
|
137
|
-
],
|
|
138
|
-
};
|
|
117
|
+
return createToolResult(tdClient, formattedText);
|
|
139
118
|
}
|
|
140
119
|
catch (error) {
|
|
141
120
|
return handleToolError(error, logger, TOOL_NAMES.CREATE_TD_NODE, REFERENCE_COMMENT);
|
|
@@ -152,14 +131,7 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
152
131
|
detailLevel: detailLevel ?? "summary",
|
|
153
132
|
responseFormat,
|
|
154
133
|
});
|
|
155
|
-
return
|
|
156
|
-
content: [
|
|
157
|
-
{
|
|
158
|
-
text: formattedText,
|
|
159
|
-
type: "text",
|
|
160
|
-
},
|
|
161
|
-
],
|
|
162
|
-
};
|
|
134
|
+
return createToolResult(tdClient, formattedText);
|
|
163
135
|
}
|
|
164
136
|
catch (error) {
|
|
165
137
|
return handleToolError(error, logger, TOOL_NAMES.DELETE_TD_NODE, REFERENCE_COMMENT);
|
|
@@ -181,14 +153,7 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
181
153
|
limit,
|
|
182
154
|
responseFormat,
|
|
183
155
|
});
|
|
184
|
-
return
|
|
185
|
-
content: [
|
|
186
|
-
{
|
|
187
|
-
text: formattedText,
|
|
188
|
-
type: "text",
|
|
189
|
-
},
|
|
190
|
-
],
|
|
191
|
-
};
|
|
156
|
+
return createToolResult(tdClient, formattedText);
|
|
192
157
|
}
|
|
193
158
|
catch (error) {
|
|
194
159
|
return handleToolError(error, logger, TOOL_NAMES.GET_TD_NODES, REFERENCE_COMMENT);
|
|
@@ -207,14 +172,7 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
207
172
|
limit,
|
|
208
173
|
responseFormat,
|
|
209
174
|
});
|
|
210
|
-
return
|
|
211
|
-
content: [
|
|
212
|
-
{
|
|
213
|
-
text: formattedText,
|
|
214
|
-
type: "text",
|
|
215
|
-
},
|
|
216
|
-
],
|
|
217
|
-
};
|
|
175
|
+
return createToolResult(tdClient, formattedText);
|
|
218
176
|
}
|
|
219
177
|
catch (error) {
|
|
220
178
|
return handleToolError(error, logger, TOOL_NAMES.GET_TD_NODE_PARAMETERS, REFERENCE_COMMENT);
|
|
@@ -232,14 +190,7 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
232
190
|
limit,
|
|
233
191
|
responseFormat,
|
|
234
192
|
});
|
|
235
|
-
return
|
|
236
|
-
content: [
|
|
237
|
-
{
|
|
238
|
-
text: formattedText,
|
|
239
|
-
type: "text",
|
|
240
|
-
},
|
|
241
|
-
],
|
|
242
|
-
};
|
|
193
|
+
return createToolResult(tdClient, formattedText);
|
|
243
194
|
}
|
|
244
195
|
catch (error) {
|
|
245
196
|
return handleToolError(error, logger, TOOL_NAMES.GET_TD_NODE_ERRORS, REFERENCE_COMMENT);
|
|
@@ -256,14 +207,7 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
256
207
|
detailLevel: detailLevel ?? "summary",
|
|
257
208
|
responseFormat,
|
|
258
209
|
});
|
|
259
|
-
return
|
|
260
|
-
content: [
|
|
261
|
-
{
|
|
262
|
-
text: formattedText,
|
|
263
|
-
type: "text",
|
|
264
|
-
},
|
|
265
|
-
],
|
|
266
|
-
};
|
|
210
|
+
return createToolResult(tdClient, formattedText);
|
|
267
211
|
}
|
|
268
212
|
catch (error) {
|
|
269
213
|
return handleToolError(error, logger, TOOL_NAMES.UPDATE_TD_NODE_PARAMETERS, REFERENCE_COMMENT);
|
|
@@ -278,14 +222,7 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
278
222
|
throw result.error;
|
|
279
223
|
}
|
|
280
224
|
const formattedText = formatExecNodeMethodResult(result.data, { args, kwargs, method, nodePath }, { detailLevel: detailLevel ?? "summary", responseFormat });
|
|
281
|
-
return
|
|
282
|
-
content: [
|
|
283
|
-
{
|
|
284
|
-
text: formattedText,
|
|
285
|
-
type: "text",
|
|
286
|
-
},
|
|
287
|
-
],
|
|
288
|
-
};
|
|
225
|
+
return createToolResult(tdClient, formattedText);
|
|
289
226
|
}
|
|
290
227
|
catch (error) {
|
|
291
228
|
logger.sendLog({
|
|
@@ -307,14 +244,7 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
307
244
|
limit: params.limit ?? 50,
|
|
308
245
|
responseFormat: params.responseFormat,
|
|
309
246
|
});
|
|
310
|
-
return
|
|
311
|
-
content: [
|
|
312
|
-
{
|
|
313
|
-
text: formattedText,
|
|
314
|
-
type: "text",
|
|
315
|
-
},
|
|
316
|
-
],
|
|
317
|
-
};
|
|
247
|
+
return createToolResult(tdClient, formattedText);
|
|
318
248
|
}
|
|
319
249
|
catch (error) {
|
|
320
250
|
return handleToolError(error, logger, TOOL_NAMES.GET_TD_CLASSES, REFERENCE_COMMENT);
|
|
@@ -333,14 +263,7 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
333
263
|
limit: limit ?? 30,
|
|
334
264
|
responseFormat,
|
|
335
265
|
});
|
|
336
|
-
return
|
|
337
|
-
content: [
|
|
338
|
-
{
|
|
339
|
-
text: formattedText,
|
|
340
|
-
type: "text",
|
|
341
|
-
},
|
|
342
|
-
],
|
|
343
|
-
};
|
|
266
|
+
return createToolResult(tdClient, formattedText);
|
|
344
267
|
}
|
|
345
268
|
catch (error) {
|
|
346
269
|
return handleToolError(error, logger, TOOL_NAMES.GET_TD_CLASS_DETAILS, REFERENCE_COMMENT);
|
|
@@ -357,20 +280,26 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
357
280
|
detailLevel: detailLevel ?? "summary",
|
|
358
281
|
responseFormat,
|
|
359
282
|
});
|
|
360
|
-
return
|
|
361
|
-
content: [
|
|
362
|
-
{
|
|
363
|
-
text: formattedText,
|
|
364
|
-
type: "text",
|
|
365
|
-
},
|
|
366
|
-
],
|
|
367
|
-
};
|
|
283
|
+
return createToolResult(tdClient, formattedText);
|
|
368
284
|
}
|
|
369
285
|
catch (error) {
|
|
370
286
|
return handleToolError(error, logger, TOOL_NAMES.GET_TD_MODULE_HELP);
|
|
371
287
|
}
|
|
372
288
|
});
|
|
373
289
|
}
|
|
290
|
+
const createToolResult = (tdClient, text) => {
|
|
291
|
+
const content = [
|
|
292
|
+
{
|
|
293
|
+
text,
|
|
294
|
+
type: "text",
|
|
295
|
+
},
|
|
296
|
+
];
|
|
297
|
+
const additionalContents = tdClient.getAdditionalToolResultContents();
|
|
298
|
+
if (additionalContents) {
|
|
299
|
+
content.push(...additionalContents);
|
|
300
|
+
}
|
|
301
|
+
return { content };
|
|
302
|
+
};
|
|
374
303
|
function matchesMetadataFilter(entry, keyword) {
|
|
375
304
|
const normalizedKeyword = keyword.toLowerCase();
|
|
376
305
|
const haystacks = [
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Do not edit manually.
|
|
4
4
|
* TouchDesigner API
|
|
5
5
|
* OpenAPI schema for generating TouchDesigner API client code
|
|
6
|
-
* OpenAPI spec version: 1.
|
|
6
|
+
* OpenAPI spec version: 1.4.1
|
|
7
7
|
*/
|
|
8
8
|
import { customInstance } from '../../api/customInstance.js';
|
|
9
9
|
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
@@ -20,7 +20,8 @@ const defaultApiClient = {
|
|
|
20
20
|
getTdPythonClasses: apiGetTdPythonClasses,
|
|
21
21
|
updateNode: apiUpdateNode,
|
|
22
22
|
};
|
|
23
|
-
export const ERROR_CACHE_TTL_MS =
|
|
23
|
+
export const ERROR_CACHE_TTL_MS = 60 * 1000; // 60 seconds
|
|
24
|
+
export const SUCCESS_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
24
25
|
/**
|
|
25
26
|
* Null logger implementation that discards all logs
|
|
26
27
|
*/
|
|
@@ -57,16 +58,14 @@ function handleApiResponse(response) {
|
|
|
57
58
|
}
|
|
58
59
|
return { data, success: true };
|
|
59
60
|
}
|
|
60
|
-
/**
|
|
61
|
-
* TouchDesigner client implementation with dependency injection
|
|
62
|
-
* for better testability and separation of concerns
|
|
63
|
-
*/
|
|
64
61
|
export class TouchDesignerClient {
|
|
65
62
|
logger;
|
|
66
63
|
api;
|
|
67
64
|
verifiedCompatibilityError;
|
|
68
65
|
cachedCompatibilityCheck;
|
|
69
66
|
errorCacheTimestamp;
|
|
67
|
+
successCacheTimestamp;
|
|
68
|
+
compatibilityNotice;
|
|
70
69
|
/**
|
|
71
70
|
* Initialize TouchDesigner client with optional dependencies
|
|
72
71
|
*/
|
|
@@ -76,6 +75,8 @@ export class TouchDesignerClient {
|
|
|
76
75
|
this.verifiedCompatibilityError = null;
|
|
77
76
|
this.cachedCompatibilityCheck = false;
|
|
78
77
|
this.errorCacheTimestamp = null;
|
|
78
|
+
this.successCacheTimestamp = null;
|
|
79
|
+
this.compatibilityNotice = null;
|
|
79
80
|
}
|
|
80
81
|
/**
|
|
81
82
|
* Log debug message
|
|
@@ -98,13 +99,56 @@ export class TouchDesignerClient {
|
|
|
98
99
|
const now = Date.now();
|
|
99
100
|
return now - this.errorCacheTimestamp >= ERROR_CACHE_TTL_MS;
|
|
100
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Check whether the cached successful compatibility check is still valid
|
|
104
|
+
*/
|
|
105
|
+
hasValidSuccessCache() {
|
|
106
|
+
if (!this.cachedCompatibilityCheck || !this.successCacheTimestamp) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
const now = Date.now();
|
|
110
|
+
return now - this.successCacheTimestamp < SUCCESS_CACHE_TTL_MS;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Force the next API call to re-run compatibility verification.
|
|
114
|
+
* Useful when the user explicitly requests version information.
|
|
115
|
+
*/
|
|
116
|
+
invalidateCompatibilityCache(reason) {
|
|
117
|
+
if (this.cachedCompatibilityCheck) {
|
|
118
|
+
this.logDebug("Invalidating cached compatibility check", { reason });
|
|
119
|
+
}
|
|
120
|
+
this.cachedCompatibilityCheck = false;
|
|
121
|
+
this.successCacheTimestamp = null;
|
|
122
|
+
this.verifiedCompatibilityError = null;
|
|
123
|
+
this.errorCacheTimestamp = null;
|
|
124
|
+
this.compatibilityNotice = null;
|
|
125
|
+
}
|
|
126
|
+
getAdditionalToolResultContents() {
|
|
127
|
+
if (!this.compatibilityNotice) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
return [
|
|
131
|
+
{
|
|
132
|
+
annotations: {
|
|
133
|
+
audience: ["user", "assistant"],
|
|
134
|
+
priority: this.compatibilityNotice.level === "warning" ? 0.2 : 0.1,
|
|
135
|
+
},
|
|
136
|
+
text: this.compatibilityNotice.message,
|
|
137
|
+
type: "text",
|
|
138
|
+
},
|
|
139
|
+
];
|
|
140
|
+
}
|
|
101
141
|
/**
|
|
102
142
|
* Verify compatibility with the TouchDesigner server
|
|
103
143
|
*/
|
|
104
144
|
async verifyCompatibility() {
|
|
105
145
|
// If we've already verified compatibility successfully, skip re-verification
|
|
106
146
|
if (this.cachedCompatibilityCheck && !this.verifiedCompatibilityError) {
|
|
107
|
-
|
|
147
|
+
if (this.hasValidSuccessCache()) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
this.logDebug("Compatibility cache expired, re-verifying...");
|
|
151
|
+
this.invalidateCompatibilityCache("success cache expired");
|
|
108
152
|
}
|
|
109
153
|
// Clear cached error if TTL has expired
|
|
110
154
|
if (this.verifiedCompatibilityError && this.shouldClearErrorCache()) {
|
|
@@ -129,9 +173,20 @@ export class TouchDesignerClient {
|
|
|
129
173
|
}
|
|
130
174
|
const result = await this.verifyVersionCompatibility();
|
|
131
175
|
if (result.success) {
|
|
176
|
+
const compatibilityInfo = result.data;
|
|
132
177
|
this.verifiedCompatibilityError = null;
|
|
133
178
|
this.errorCacheTimestamp = null;
|
|
134
179
|
this.cachedCompatibilityCheck = true;
|
|
180
|
+
this.successCacheTimestamp = Date.now();
|
|
181
|
+
if (compatibilityInfo.level === "warning" && compatibilityInfo.message) {
|
|
182
|
+
this.compatibilityNotice = {
|
|
183
|
+
level: compatibilityInfo.level,
|
|
184
|
+
message: compatibilityInfo.message,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
this.compatibilityNotice = null;
|
|
189
|
+
}
|
|
135
190
|
this.logDebug("Compatibility verified successfully");
|
|
136
191
|
return;
|
|
137
192
|
}
|
|
@@ -142,6 +197,8 @@ export class TouchDesignerClient {
|
|
|
142
197
|
this.verifiedCompatibilityError = result.error;
|
|
143
198
|
this.errorCacheTimestamp = Date.now();
|
|
144
199
|
this.cachedCompatibilityCheck = false;
|
|
200
|
+
this.successCacheTimestamp = null;
|
|
201
|
+
this.compatibilityNotice = null;
|
|
145
202
|
throw result.error;
|
|
146
203
|
}
|
|
147
204
|
/**
|
|
@@ -173,6 +230,7 @@ export class TouchDesignerClient {
|
|
|
173
230
|
* Get TouchDesigner server information
|
|
174
231
|
*/
|
|
175
232
|
async getTdInfo() {
|
|
233
|
+
this.invalidateCompatibilityCache("tdInfo request");
|
|
176
234
|
return this.apiCall("Getting server info", () => this.api.getTdInfo());
|
|
177
235
|
}
|
|
178
236
|
/**
|
|
@@ -295,7 +353,10 @@ export class TouchDesignerClient {
|
|
|
295
353
|
if (result.level === "error") {
|
|
296
354
|
return createErrorResult(new Error(result.message));
|
|
297
355
|
}
|
|
298
|
-
return createSuccessResult(
|
|
356
|
+
return createSuccessResult({
|
|
357
|
+
level: result.level,
|
|
358
|
+
message: result.message,
|
|
359
|
+
});
|
|
299
360
|
}
|
|
300
361
|
/**
|
|
301
362
|
* Format connection errors with helpful messages
|