Skip to content

Commit ca548fa

Browse files
dreamrecclaude
andauthored
v2.1.3 — security hardening + chat queue + path harmonization + model-tier override (#28)
* release: 2.1.3 — security hardening + chat queue + path harmonization + model-tier override Closes a CSRF / drive-by-RCE chain in tdpilot_API.tox, fixes a silent-message-drop on rapid /send, harmonizes chat-pipe storage under the dpsk4 variant root, and adds an explicit-intent override so "use pro model" / "use flash" in user text routes correctly. Security - Insecure-mode (TDPILOT_API_INSECURE=1) now bypasses ONLY the token check; origin allowlist + Sec-Fetch-Site checks always fire, so a malicious browser tab can't CSRF the chat-pipe even when insecure-mode is on for legitimate local tooling. - EXEC_MODE clamps to 'restricted' whenever insecure-mode is active unless TDPILOT_API_ALLOW_INSECURE_FULL_EXEC=1. Pre-2.1.3 the API tox unconditionally set EXEC_MODE=full at COMP load, so an unauthenticated POST chained into td_exec_python with full Python privileges. Live-confirmed restricted mode blocks os.system / __import__ / etc. - /send requires Content-Type: application/json from BROWSER callers (forces CORS preflight); local tooling without an Origin header keeps text/plain backwards compat. Chat HTML migrated to JSON envelope. - Loud textport banner when insecure-mode is active. Reliability - Rapid /send no longer drops messages: comp.par.Chatmessage.val is always cleared on read; messages that arrive while the worker is alive go through a FIFO inbox queue on comp.storage and drain one per EV_DONE. Reset clears the queue. - Chat HTML send button now gated on the runtime's turn-end signal (not on the /send fetch resolution, which returns 'queued' instantly). Path harmonization - New helper resolve_user_dir() returns ~/.tdpilot-dpsk4/api/<subdir> by default, falling back to ~/.tdpilot-api/<subdir> per-subdir if the legacy path has content. 9 modules (memory, knowledge, recipes, skills, snapshots, traces, macros, tools, history) and 17 tool-description strings updated to point at the new default. Path.home() is re-evaluated per call so test monkey-patches work. Model-tier override (user-reported regression) - _PRO_OVERRIDE_RE / _FLASH_OVERRIDE_RE in _resolve_model take precedence over both the configured tier and the auto heuristic. Recognizes 'use pro', 'use the pro model', 'switch to pro', 'force pro', 'with pro', 'via pro', 'run in pro', 'pro model', 'pro tier', 'pro mode', 'deepseek-v4-pro' (same set for flash, with word-boundary false-positive guards against 'professional', 'prompt', 'flashlight', etc.). Pro wins on ties. Tone - System prompt: agent no longer auto-saves feedback memories about its own behaviour uninvited. Saving requires user request OR a clearly-stated rule worth keeping. Tests + gates - 1680 passed (1674 base + 6 new override tests, 0 failures). - All 7 version manifests in sync at v2.1.3. - Both .tox source-hash gates pass (rebuilt in TD). See CHANGELOG.md for the full breakdown. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * style: ruff format pass on the two 2.1.3-edited API tox sources Mechanical formatter pass on tdpilot_api_extension.py (rewraps a multi-line `in (...)` tuple literal) and tdpilot_api_web_callbacks.py (swaps an escaped-double-quote string literal to single-quote outer) so the lint job's `ruff format --check` step passes. API .tox rebuilt to match the new source bytes — both freshness gates pass again. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 4b6bec2 commit ca548fa

39 files changed

Lines changed: 797 additions & 105 deletions

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
{
1111
"name": "tdpilot-dpsk4",
1212
"description": "AI copilot for TouchDesigner with live MCP control (DeepSeek v4 optimized) \u2014 103 tools, focus + locations, hint injection, component notes, POPx inspection, knowledge corpus, project lifecycle, custom parameter authoring, snapshots, undo-block safety, and typed patch sessions. Works with Claude Desktop, Claude Code (DeepSeek v4 backend), and any MCP-compatible client.",
13-
"version": "2.1.2",
13+
"version": "2.1.3",
1414
"author": {
1515
"name": "silviu"
1616
},

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tdpilot-dpsk4",
3-
"version": "2.1.2",
3+
"version": "2.1.3",
44
"description": "TDPilot DPSK4 \u2014 AI copilot for TouchDesigner (DeepSeek v4 optimized). 103 MCP tools for live node graph control, parameter management, diagnostics, safety, streaming, knowledge corpus, focus + locations, hint injection, component notes, technique memory, and typed patch sessions.",
55
"author": {
66
"name": "silviu"

CHANGELOG.md

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,150 @@
11
# Changelog
22

3+
## 2.1.3 - 2026-05-09
4+
5+
**Security hardening + chat-pipe queue + path harmonization for
6+
`tdpilot_API.tox`.** A fresh deep-debug audit of the chat-pipe found
7+
a CSRF / drive-by-RCE chain plus a silent-message-drop bug. Both
8+
closed in this release; storage is also unified under the dpsk4
9+
variant root.
10+
11+
### Security fixes
12+
13+
- **Bug #1`TDPILOT_API_INSECURE` no longer bypasses origin
14+
checks.** Pre-2.1.3 the insecure-mode env var bypassed BOTH the
15+
token AND the origin gate, leaving the chat-pipe wide open to
16+
cross-origin browser CSRF. Now insecure-mode bypasses **only** the
17+
token check; the origin allowlist + `Sec-Fetch-Site` checks always
18+
fire. Legitimate non-browser tooling (curl, Python `requests`)
19+
sends no `Origin` header so it still passes the same-origin gate.
20+
See `_check_auth` in `td_component/tdpilot_api_web_callbacks.py`.
21+
- **Bug #3`EXEC_MODE` clamps to `restricted` in insecure mode.**
22+
Pre-2.1.3 the API tox unconditionally set
23+
`TD_MCP_EXEC_MODE=full` at COMP load, so an unauthenticated POST
24+
to `/send` could chain into `td_exec_python` with full Python
25+
privileges. Now the clamp triggers whenever `TDPILOT_API_INSECURE`
26+
is truthy. Users who genuinely need full mode for trusted local
27+
scripting can opt back in by setting
28+
`TDPILOT_API_ALLOW_INSECURE_FULL_EXEC=1`. See
29+
`_build_runtime` in `td_component/tdpilot_api_extension.py`.
30+
- **`/send` now requires `Content-Type: application/json`.** The
31+
pre-2.1.3 plain-text body was a CORS "simple request" that
32+
bypassed preflight, letting cross-origin pages POST into the
33+
chat-pipe without the browser checking `Access-Control-Allow-
34+
Origin`. JSON triggers a preflight, which the origin gate
35+
rejects. The chat HTML's `send()` was migrated to the
36+
`{"message": "<text>"}` envelope.
37+
- **Loud startup banner when insecure-mode is active** — pre-2.1.3
38+
the bypass was a silent env toggle and the audit found it active
39+
on a real machine with no startup signal. The banner prints to
40+
textport on every COMP load and lists the secure-mode opt-in
41+
path.
42+
43+
### Reliability fixes
44+
45+
- **Bug #2 — rapid `/send` no longer drops messages.** Pre-2.1.3 a
46+
follow-up `/send` while the worker was still busy overwrote
47+
`comp.par.Chatmessage.val` before the prior message was consumed,
48+
so the prior message was silently dropped. New behaviour: the
49+
param is always cleared up front; messages that arrive while the
50+
worker is alive are appended to a FIFO inbox queue on
51+
`comp.storage` (`tdpilot_api_chat_inbox` key) and drained one at
52+
a time on each `EV_DONE`. The `/reset` path clears the queue.
53+
- **Chat HTML send-button gate.** The send button now stays
54+
disabled until the runtime emits a non-working agent state
55+
(`idle`, `ready`, `reset`, `error`, `send failed`) over the
56+
WebSocket, not just until the `/send` fetch resolves.
57+
Re-enabling on the fetch (which returns `queued` instantly)
58+
was the surface symptom of the queue-drop bug.
59+
60+
### Path harmonization
61+
62+
- **Chat-pipe storage moved under `~/.tdpilot-dpsk4/api/<subdir>`**
63+
with transparent legacy `~/.tdpilot-api/<subdir>` fallback. The
64+
dpsk4 fork now uses a single variant root for all its state
65+
(matching the MCP-side layout). New helper
66+
`tdpilot_api_config.resolve_user_dir(subdir)` returns the new
67+
location by default, falling back to the legacy path if it has
68+
content (per-subdir, not bulk-migrated). All 9 chat-pipe modules
69+
with hardcoded path constants (`memory`, `knowledge`, `recipes`,
70+
`skills`, `snapshots`, `traces`, `macros`, `tools`, `history`)
71+
now route through `resolve_user_dir`. Tool descriptions in
72+
`tdpilot_api_schema_defs.py` were swept to point at the new
73+
default — the LLM-facing copy and the runtime resolution are now
74+
consistent.
75+
- The legacy `~/.tdpilot-api/` is still used by users who have
76+
data there; no automatic migration runs on import. To move data,
77+
manually `mv ~/.tdpilot-api/* ~/.tdpilot-dpsk4/api/` after
78+
closing TD.
79+
80+
### Tone / politeness
81+
82+
- **Memory protocol updated.** The system prompt now instructs the
83+
agent NOT to save reflections about its own behaviour uninvited —
84+
only when the user explicitly asks ("remember this", "save a
85+
memory") or has just stated a clear rule / preference / fact
86+
worth keeping. Auto-saved meta-feedback memories were noise in
87+
the user's MEMORY.md index.
88+
89+
### Model routing
90+
91+
- **Bug — explicit "use pro" / "use flash" in user text was
92+
ignored.** Pre-2.1.3 the auto-tier heuristic was the only way to
93+
flip pro/flash on a per-turn basis. Users who set the COMP's
94+
`Modeltier` to `flash` (or left it at `auto` with a short
95+
prompt) and wrote "use pro model" in their message kept routing
96+
to flash because the heuristic scored 0 (no build-keyword, no
97+
code fence, no tool keywords, len < 300). Now `_resolve_model`
98+
checks `_PRO_OVERRIDE_RE` / `_FLASH_OVERRIDE_RE` against the
99+
user text BEFORE the tier-pin or auto heuristic. Phrases that
100+
trigger the override:
101+
- `use pro` / `use the pro model` / `switch to pro` / `force pro`
102+
- `with pro` / `via pro` / `run in pro` / `run with pro`
103+
- `pro model` / `pro tier` / `pro mode` / `in pro mode`
104+
- `deepseek-v4-pro` / `deepseekv4pro` / `deepseek_v4_pro`
105+
106+
Same pattern set applies to flash. Pro takes precedence on ties
107+
(since the motivating bug was "I asked for pro and got flash").
108+
The override is per-turn only — the next turn falls back to the
109+
configured tier.
110+
111+
False-positive guard via `\b…\b` word boundaries: the override
112+
does NOT trigger on `professional`, `professionally`, `prompt`,
113+
`production`, `process`, `flashlight`, `flashy`, `flashed`, or
114+
bare `pro` / `flash` mentions without a verb cue. Tests at
115+
`tests/test_tdpilot_api_agent.py::test_resolve_model_*_override_*`.
116+
117+
### Files touched
118+
119+
Source files (all in API tox source list — `.tox` rebuild required
120+
in TD; CI will reject this branch until `.tox-source-hash.json`
121+
is regenerated):
122+
123+
```
124+
td_component/tdpilot_api_web_callbacks.py # Bug #1 server side
125+
td_component/tdpilot_api_chat.html # Bug #1 client + Bug #2 client
126+
td_component/tdpilot_api_extension.py # Bug #3 + Bug #2 server + banner
127+
td_component/tdpilot_api_runtime.py # system-prompt politeness + path-string sweep
128+
td_component/tdpilot_api_config.py # resolve_user_dir
129+
td_component/tdpilot_api_memory.py # path constant
130+
td_component/tdpilot_api_knowledge.py # path constant
131+
td_component/tdpilot_api_recipes.py # path constant
132+
td_component/tdpilot_api_skills.py # path constant
133+
td_component/tdpilot_api_patches.py # path constant
134+
td_component/tdpilot_api_tracing.py # path constant
135+
td_component/tdpilot_api_user_tools.py # path constant
136+
td_component/tdpilot_api_macros.py # path constant
137+
td_component/tdpilot_api_compaction.py # path constant
138+
td_component/tdpilot_api_introspect.py # firstrun memory probe
139+
td_component/tdpilot_api_schema_defs.py # tool-description path sweep
140+
td_component/tdpilot_api_recovery.py # error-message path
141+
td_component/callbacks/_header.py # API_VERSION bump
142+
```
143+
144+
Tests `tests/test_standalone_csrf.py::test_insecure_mode_bypasses_token_and_origin`
145+
was renamed/updated to assert the new contract (insecure-mode
146+
bypasses token only, not origin).
147+
3148
## 2.1.2 - 2026-05-09
4149

5150
**Patch: opt-in MCP auth.** Pre-2.1.2 the dpsk4 COMP's

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝
88
```
99

10-
# TDPilot — DeepSeek v4 · v2.1.1
10+
# TDPilot — DeepSeek v4 · v2.1.3
1111

1212
[![CI](https://github.com/dreamrec/TDPilot_deepseekv4/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/dreamrec/TDPilot_deepseekv4/actions/workflows/ci.yml)
1313
[![npm](https://img.shields.io/npm/v/tdpilot-dpsk4?label=npm)](https://www.npmjs.com/package/tdpilot-dpsk4)
@@ -20,7 +20,7 @@
2020

2121
An AI assistant that lives inside TouchDesigner. It can inspect your network, build new operators, wire them up, debug errors, take screenshots, remember things between sessions, replay successful patterns, surface relevant memories before each turn, batch tool calls, recover from failures with actionable hints, and survive long conversations via context compaction.
2222

23-
> **v2.1.1 just shipped (May 9, 2026)**paused-TD UX trap fix (no more 60s tool-call timeouts when TD is paused), 4 new `recovery_hints` patterns (`td.Par.rawVal`, renderTOP attr typos, `tdu.Matrix.translation`, `ParCollection.children`), high-contrast red mark for user messages in chat, and a parallel CI freshness gate for `tdpilot_API.tox`. See [What's new since v1.5.x](#whats-new-since-v15x) below for the full timeline, or [CHANGELOG](CHANGELOG.md#211---2026-05-08) for the v2.1.1 details.
23+
> **v2.1.3 just shipped (May 9, 2026)**security hardening + chat-pipe queue + path harmonization. CSRF / drive-by RCE chain in `tdpilot_API.tox` closed (origin gate now enforced even in `TDPILOT_API_INSECURE` mode; `EXEC_MODE=full` clamped to `restricted` when insecure-mode is on; `/send` requires `application/json` to force CORS preflight). Rapid-`/send` message-drop bug fixed via FIFO inbox queue; chat HTML disables send button until the runtime emits turn-end. Storage moved under `~/.tdpilot-dpsk4/api/` with transparent legacy `~/.tdpilot-api/` fallback. See [What's new since v1.5.x](#whats-new-since-v15x) below for the full timeline, or [CHANGELOG](CHANGELOG.md#213---2026-05-09) for the v2.1.3 details.
2424
2525
There are two ways to run it. Pick whichever fits — they coexist in the same TD project if you want both.
2626

@@ -210,10 +210,12 @@ The standalone has 91 tools that cover the everyday inspect → build → wire
210210

211211
## What's new since v1.5.x
212212

213-
The line from v1.5.0 (Apr 25, 2026) to v2.1.1 (May 9, 2026) shipped in tight bursts. Most important updates, newest first:
213+
The line from v1.5.0 (Apr 25, 2026) to v2.1.3 (May 9, 2026) shipped in tight bursts. Most important updates, newest first:
214214

215215
| Version | Date | Headline |
216216
|---|---|---|
217+
| **v2.1.3** | May 9 | **Security hardening + chat-pipe queue + path harmonization.** Audit found a CSRF / drive-by RCE chain in `tdpilot_API.tox` (insecure-mode bypassed origin checks AND `EXEC_MODE=full` was hardcoded). Closed by always-on origin enforcement (insecure-mode bypasses only the token check), `EXEC_MODE` clamp to `restricted` whenever insecure-mode is active (opt back into full with `TDPILOT_API_ALLOW_INSECURE_FULL_EXEC=1`), `application/json` requirement on `/send` (forces CORS preflight for cross-origin POSTs), and a loud textport banner when insecure-mode is on. Rapid-`/send` message-drop bug fixed via FIFO inbox queue on `comp.storage` + chat HTML send-button gate on the runtime's turn-end signal (not on the fetch resolution). Chat-pipe storage namespaced under `~/.tdpilot-dpsk4/api/` with `~/.tdpilot-api/` legacy fallback in `resolve_user_dir`. |
218+
| **v2.1.2** | May 9 | **Opt-in MCP auth.** `autostart.onStart()` no longer wipes persistent secrets; `TDPILOT_DISABLE_AUTH_BYPASS=1` opts into the env-file-driven shared-secret flow. |
217219
| **v2.1.1** | May 9 | **Paused-TD UX trap + recovery hints + chat red mark.** `start_turn` now warns when `me.time.play=False` so a paused TD doesn't look like the agent is wedged on 60s tool-call timeouts. 4 new `recovery_hints` (`td.Par.rawVal`, renderTOP attr typos, `tdu.Matrix.translation`, `ParCollection.children`) harvested from a 184-message lighting-redesign turn. User messages in the chat now render with a high-contrast white-on-red `[USER]` stamp + thick red rule + red gradient. Parallel CI freshness gate added for `tdpilot_API.tox` so it can no longer silently go stale. |
218220
| **v2.1.0** | May 8 | **Chat UI rework.** Quiet-mode toggle (`Cmd/Ctrl + .`) hides tool-call surfaces for prompts-only scrollback. Smaller default fonts. Contextual ASCII flourishes appended to assistant turn-ends (9-bucket topic-keyword pool). Plus the v2.0.0 audit fixes (patch session lifecycle, recovery hints, info-textDAT red ❌). |
219221
| **v2.0.0** | May 8 | **Breaking + chat polish.** `is_tool_error_result()` requires the explicit `_tool_error` sentinel (legacy `"error"`-key fallback removed); `tdpilot_v1_3.tox` filename shim removed. New: small/large chat font-size toggle (`a` / `A`) at the far right of the status bar with `Cmd/Ctrl + +` / `-` shortcuts. Internal handlers unaffected — `recovery.attach_hint()` auto-stamps the sentinel; only external dispatcher integrations need to migrate. |

docs/MANUAL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# TDPilot v2.1.2 Manual
1+
# TDPilot v2.1.3 Manual
22

33
The full reference. Read the [README](../README.md) first if you haven't installed yet — this manual assumes you've got either the standalone .tox or the Claude Code plugin running.
44

mcp/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"schema_version": 1,
33
"name": "TDPilot DPSK4",
44
"slug": "tdpilot-dpsk4",
5-
"version": "2.1.2",
5+
"version": "2.1.3",
66
"repository": "https://github.com/dreamrec/TDPilot_deepseekv4",
77
"description": "MCP server for TouchDesigner (DeepSeek v4 optimized) with live graph control, diagnostics, safety, streaming, knowledge corpus, technique memory, and typed patch sessions.",
88
"entrypoints": {

npm/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# TDPilot v2.1.2
1+
# TDPilot v2.1.3
22

33
[![CI](https://github.com/dreamrec/TDPilot_deepseekv4/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/dreamrec/TDPilot_deepseekv4/actions/workflows/ci.yml)
44
[![npm](https://img.shields.io/npm/v/tdpilot-dpsk4?label=npm)](https://www.npmjs.com/package/tdpilot-dpsk4)

npm/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tdpilot-dpsk4",
3-
"version": "2.1.2",
3+
"version": "2.1.3",
44
"description": "AI copilot for TouchDesigner with live MCP control (DeepSeek v4 optimized) \u2014 103 tools, focus + locations, hint injection, component notes, POPx inspection, knowledge corpus, project lifecycle control, technique memory, typed patch sessions.",
55
"keywords": [
66
"touchdesigner",

plugin_README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# TDPilot v2.1.2 — TouchDesigner AI Assistant Plugin
1+
# TDPilot v2.1.3 — TouchDesigner AI Assistant Plugin
22

33
This plugin installs the **DPSK4 (Claude Code CLI) variant** of TDPilot.
44
Two variants ship in the same repo:
@@ -12,7 +12,7 @@ For the standalone .tox path, see the [main README](https://github.com/dreamrec/
1212

1313
---
1414

15-
TDPilot v2.1.2 provides 103 MCP tools for live control of TouchDesigner projects from Claude Code, optimized for DeepSeek v4. The bundled `.tox` includes a one-button installer (drag-drop into TD, click "Bootstrap All", done) — no manual setup script.
15+
TDPilot v2.1.3 provides 103 MCP tools for live control of TouchDesigner projects from Claude Code, optimized for DeepSeek v4. The bundled `.tox` includes a one-button installer (drag-drop into TD, click "Bootstrap All", done) — no manual setup script.
1616

1717
## Components
1818

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "tdpilot-dpsk4"
3-
version = "2.1.2"
3+
version = "2.1.3"
44
description = "MCP server for live control of TouchDesigner — create, inspect, connect, and manipulate nodes via AI agents"
55
readme = "README.md"
66
license = "MIT"

0 commit comments

Comments
 (0)