Skip to content

Commit d0e9cd5

Browse files
v3.0.0-beta.2 — New Control Center, Guided Setup, and Read-only Project Review Panels (#114)
* chore: fix formatting and configure linter for v3.0.0b2 release * docs: replace embedded video elements with direct links for better compatibility * chore: bump project version to 3.0.0b2 * fix: update knowledge base parameter mapping keywords, action, and rationale to prevent silent corruption * docs: update documentation links from v3-alpha to beta
1 parent 7ca8bb5 commit d0e9cd5

34 files changed

Lines changed: 259 additions & 273 deletions

README.md

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# fls-pilot
22

3-
![version](https://img.shields.io/badge/version-3.0.0b1-blue)
3+
![version](https://img.shields.io/badge/version-3.0.0b2-blue)
44
![status](https://img.shields.io/badge/status-beta-yellow)
55
[![CI](https://github.com/thunderdew-dawn/fls-pilot/actions/workflows/ci.yml/badge.svg)](https://github.com/thunderdew-dawn/fls-pilot/actions/workflows/ci.yml)
66
![license](https://img.shields.io/badge/license-MIT-green)
@@ -10,7 +10,7 @@
1010
![macOS](https://img.shields.io/badge/macOS-12%2B-000000?logo=apple&logoColor=white)
1111
![FL Studio](https://img.shields.io/badge/FL%20Studio-2025%2B-orange)
1212

13-
[![Documentation Status](https://readthedocs.org/projects/fl-studio-pilot/badge/?version=v3-alpha)](https://fl-studio-pilot.readthedocs.io/en/v3-alpha/)
13+
[![Documentation Status](https://readthedocs.org/projects/fl-studio-pilot/badge/?version=beta)](https://fl-studio-pilot.readthedocs.io/en/beta/)
1414

1515
![fls-pilot](docs/assets/fls-pilot-logo-with-text.png)
1616

@@ -39,33 +39,23 @@ export-readiness checks.
3939

4040
### Mix Review & Gain Staging
4141

42-
<video controls muted playsinline preload="metadata" style="width: 100%; max-width: 960px;">
43-
<source src="docs/assets/ai-apply-gain-staging-example.mp4" type="video/mp4">
44-
</video>
42+
[▶️ Video: Mix Review & Gain Staging](https://github.com/thunderdew-dawn/fls-pilot/raw/main/docs/assets/ai-apply-gain-staging-example.mp4)
4543

4644
### Routing Audit
4745

48-
<video controls muted playsinline preload="metadata" style="width: 100%; max-width: 960px;">
49-
<source src="docs/assets/ai-based-mixer-routing-example.mp4" type="video/mp4">
50-
</video>
46+
[▶️ Video: Routing Audit](https://github.com/thunderdew-dawn/fls-pilot/raw/main/docs/assets/ai-based-mixer-routing-example.mp4)
5147

5248
### Project Organizer
5349

54-
<video controls muted playsinline preload="metadata" style="width: 100%; max-width: 960px;">
55-
<source src="docs/assets/ai-color-my-tracks-example.mp4" type="video/mp4">
56-
</video>
50+
[▶️ Video: Project Organizer](https://github.com/thunderdew-dawn/fls-pilot/raw/main/docs/assets/ai-color-my-tracks-example.mp4)
5751

5852
### Plugin & EQ Workflows
5953

60-
<video controls muted playsinline preload="metadata" style="width: 100%; max-width: 960px;">
61-
<source src="docs/assets/ai-set-highpass-on-eq-batch-example.mp4" type="video/mp4">
62-
</video>
54+
[▶️ Video: Plugin & EQ Workflows](https://github.com/thunderdew-dawn/fls-pilot/raw/main/docs/assets/ai-set-highpass-on-eq-batch-example.mp4)
6355

6456
### Composition
6557

66-
<video controls muted playsinline preload="metadata" style="width: 100%; max-width: 960px;">
67-
<source src="docs/assets/ai-generate-bassline-example.mp4" type="video/mp4">
68-
</video>
58+
[▶️ Video: Composition](https://github.com/thunderdew-dawn/fls-pilot/raw/main/docs/assets/ai-generate-bassline-example.mp4)
6959

7060
## Requirements
7161

@@ -154,7 +144,7 @@ part of the public ReadTheDocs site.
154144

155145
Public documentation:
156146

157-
<https://fl-studio-pilot.readthedocs.io/en/v3-alpha/>
147+
<https://fl-studio-pilot.readthedocs.io/en/beta/>
158148

159149
Useful local pages:
160150

docs/user-guide/workflows.md

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,7 @@ balance, routing, and low-end risks.
7878

7979
![Mix Review results](../assets/control-center-mix-review-2.png)
8080

81-
<video controls muted playsinline preload="metadata" style="width: 100%; max-width: 960px;">
82-
<source src="../../assets/ai-apply-gain-staging-example.mp4" type="video/mp4">
83-
</video>
81+
[▶️ Video: Mix Review](https://github.com/thunderdew-dawn/fls-pilot/raw/main/docs/assets/ai-apply-gain-staging-example.mp4)
8482

8583
Use prompts like:
8684

@@ -102,9 +100,7 @@ and fragile send/return layouts. Cleanup remains proposal-first.
102100

103101
![Routing Audit overview](../assets/control-center-routing-audit.png)
104102

105-
<video controls muted playsinline preload="metadata" style="width: 100%; max-width: 960px;">
106-
<source src="../../assets/ai-based-mixer-routing-example.mp4" type="video/mp4">
107-
</video>
103+
[▶️ Video: Routing Audit](https://github.com/thunderdew-dawn/fls-pilot/raw/main/docs/assets/ai-based-mixer-routing-example.mp4)
108104

109105
## Project Organizer
110106

@@ -113,28 +109,22 @@ candidates. It can propose one reversible cleanup step at a time.
113109

114110
![Project Organizer scan](../assets/control-center-project-organizer.png)
115111

116-
<video controls muted playsinline preload="metadata" style="width: 100%; max-width: 960px;">
117-
<source src="../../assets/ai-color-my-tracks-example.mp4" type="video/mp4">
118-
</video>
112+
[▶️ Video: Project Organizer](https://github.com/thunderdew-dawn/fls-pilot/raw/main/docs/assets/ai-color-my-tracks-example.mp4)
119113

120114
## Plugin and EQ Workflows
121115

122116
fls-pilot can inspect already-loaded plugins and configure supported parameters
123117
when parameter ranges are known. It cannot load or insert plugins.
124118

125-
<video controls muted playsinline preload="metadata" style="width: 100%; max-width: 960px;">
126-
<source src="../../assets/ai-set-highpass-on-eq-batch-example.mp4" type="video/mp4">
127-
</video>
119+
[▶️ Video: Plugin and EQ Workflows](https://github.com/thunderdew-dawn/fls-pilot/raw/main/docs/assets/ai-set-highpass-on-eq-batch-example.mp4)
128120

129121
## Composition
130122

131123
Composition tools can generate scale-aware melodies, chords, and patterns. The
132124
assistant should preview notes first and wait for approval before writing to
133125
the Piano Roll.
134126

135-
<video controls muted playsinline preload="metadata" style="width: 100%; max-width: 960px;">
136-
<source src="../../assets/ai-generate-bassline-example.mp4" type="video/mp4">
137-
</video>
127+
[▶️ Video: Composition](https://github.com/thunderdew-dawn/fls-pilot/raw/main/docs/assets/ai-generate-bassline-example.mp4)
138128

139129
## Project Health and Preflight
140130

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "fls-pilot"
7-
version = "3.0.0b1"
7+
version = "3.0.0b2"
88
description = "Control FL Studio with any MCP-compatible LLM: mixing, composition, and mix diagnosis through natural language."
99
readme = "README.md"
1010
license = { text = "MIT" }
@@ -139,7 +139,7 @@ select = ["E", "F", "I", "B", "UP", "SIM"]
139139

140140
[tool.ruff.lint.per-file-ignores]
141141
"scripts/**/*.py" = ["UP031"]
142-
"tests/**/*.py" = ["UP031"]
142+
"tests/**/*.py" = ["UP031", "E501"]
143143

144144
[tool.pytest.ini_options]
145145
addopts = """

scripts/check_github_project_fingerprint.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,15 @@ def main() -> int:
9494

9595
missing_from_project = sorted(source_numbers - set(by_number))
9696
if missing_from_project:
97-
errors.append(f"github-source-of-truth issues missing from Project #{PROJECT}: {missing_from_project}")
97+
errors.append(
98+
f"github-source-of-truth issues missing from Project #{PROJECT}: {missing_from_project}"
99+
)
98100

99101
missing_release_items = sorted(REQUIRED_RELEASE_ITEMS - set(by_number))
100102
if missing_release_items:
101-
errors.append(f"required 3.0 release-train issues missing from Project #{PROJECT}: {missing_release_items}")
103+
errors.append(
104+
f"required 3.0 release-train issues missing from Project #{PROJECT}: {missing_release_items}"
105+
)
102106

103107
for issue in source_issues:
104108
number = int(issue["number"])
@@ -113,14 +117,18 @@ def main() -> int:
113117

114118
if issue.get("state") == "CLOSED":
115119
if item.get("status") != "Done" or item.get("roadmap Lane") != "Done":
116-
errors.append(f"closed issue #{number} is not marked Done/Done in Project #{PROJECT}")
120+
errors.append(
121+
f"closed issue #{number} is not marked Done/Done in Project #{PROJECT}"
122+
)
117123

118124
if issue.get("state") == "OPEN" and "release-blocker" in labels:
119125
milestone = issue.get("milestone") or {}
120126
if not milestone.get("title"):
121127
errors.append(f"open release blocker #{number} has no milestone")
122128
if item.get("priority") != "P0":
123-
errors.append(f"open release blocker #{number} is not marked P0 in Project #{PROJECT}")
129+
errors.append(
130+
f"open release blocker #{number} is not marked P0 in Project #{PROJECT}"
131+
)
124132

125133
summary = {
126134
"project": PROJECT,

scripts/check_release_tag.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
import argparse
77
import re
88
import sys
9-
import tomllib
109
from pathlib import Path
1110

11+
import tomllib
1212

1313
TAG_RE = re.compile(
1414
r"^v(?P<base>\d+\.\d+\.\d+)(?:(?P<stable>-stable)|-(?P<phase>alpha|beta|rc)\.(?P<n>\d+))?$"

scripts/normalize_template_dump.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,7 @@ def _reserved_ranges(routing_rows: Iterable[Mapping[str, Any]]) -> list[dict[str
260260
current_signature: tuple[tuple[int, float | None], ...] | None = None
261261

262262
rows = sorted(
263-
(
264-
(_as_int(row.get("i", row.get("index", row.get("track")))), row)
265-
for row in routing_rows
266-
),
263+
((_as_int(row.get("i", row.get("index", row.get("track")))), row) for row in routing_rows),
267264
key=lambda pair: -1 if pair[0] is None else pair[0],
268265
)
269266
for index, row in rows:
@@ -514,7 +511,7 @@ def _plugins(detail: Mapping[str, Any], *, max_params_per_plugin: int) -> list[d
514511
"enabled": slot_data.get("enabled") if "enabled" in slot_data else None,
515512
"mix": _as_float(slot_data.get("mix")),
516513
"parameter_count": len(params),
517-
"parameter_signature": params[:max(0, max_params_per_plugin)],
514+
"parameter_signature": params[: max(0, max_params_per_plugin)],
518515
}
519516
)
520517
if out:

scripts/render_github_changelog.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,7 @@ def _display_url(url: str | None, repo: str, display_repo: str | None) -> str:
6868
def render(repo: str, token: str, display_repo: str | None = None) -> str:
6969
generated = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat()
7070
releases = _list(f"/repos/{repo}/releases", token)
71-
pulls = [
72-
pr
73-
for pr in _list(f"/repos/{repo}/pulls?state=closed", token)
74-
if pr.get("merged_at")
75-
]
71+
pulls = [pr for pr in _list(f"/repos/{repo}/pulls?state=closed", token) if pr.get("merged_at")]
7672
pulls.sort(key=lambda row: str(row.get("merged_at")), reverse=True)
7773

7874
lines = [

scripts/render_github_roadmap.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ def render(repo: str, token: str, display_repo: str | None = None) -> str:
9696
for milestone in sorted({_milestone(issue) for issue in open_issues}):
9797
group = [issue for issue in open_issues if _milestone(issue) == milestone]
9898
lines.extend([f"### {milestone}", ""])
99-
for issue in sorted(group, key=lambda item: (_priority(_labels(item)), int(item["number"]))):
99+
for issue in sorted(
100+
group, key=lambda item: (_priority(_labels(item)), int(item["number"]))
101+
):
100102
lines.append(_render_issue(issue, repo, display_repo))
101103
lines.append("")
102104

scripts/sync_github_labels.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import os
2-
import sys
3-
import subprocess
41
import json
2+
import subprocess
3+
import sys
54
from pathlib import Path
65

6+
77
def parse_labels(filepath):
88
"""
99
Parses the simple .github/labels.yml format.
@@ -12,9 +12,9 @@ def parse_labels(filepath):
1212
color: <color>
1313
description: <desc>
1414
"""
15-
with open(filepath, "r") as f:
15+
with open(filepath) as f:
1616
content = f.read()
17-
17+
1818
labels = []
1919
# match each block starting with `- name:`
2020
blocks = content.split("- name:")[1:]
@@ -28,15 +28,12 @@ def parse_labels(filepath):
2828
color = line.strip()[6:].strip().strip("'\"")
2929
elif line.strip().startswith("description:"):
3030
desc = line.strip()[12:].strip().strip("'\"")
31-
31+
3232
if name and name != "*":
33-
labels.append({
34-
"name": name,
35-
"color": color,
36-
"description": desc
37-
})
33+
labels.append({"name": name, "color": color, "description": desc})
3834
return labels
3935

36+
4037
def get_existing_labels():
4138
"""
4239
Uses gh cli to get existing labels.
@@ -46,7 +43,7 @@ def get_existing_labels():
4643
["gh", "label", "list", "--json", "name,color,description", "--limit", "500"],
4744
capture_output=True,
4845
text=True,
49-
check=True
46+
check=True,
5047
)
5148
return json.loads(result.stdout)
5249
except subprocess.CalledProcessError as e:
@@ -56,6 +53,7 @@ def get_existing_labels():
5653
print("Error: GitHub CLI (gh) is not installed or not in PATH.")
5754
sys.exit(1)
5855

56+
5957
def main():
6058
root_dir = Path(__file__).parent.parent
6159
labels_file = root_dir / ".github" / "labels.yml"
@@ -66,7 +64,7 @@ def main():
6664

6765
desired_labels = parse_labels(labels_file)
6866
existing_labels_list = get_existing_labels()
69-
67+
7068
existing_labels_map = {lbl["name"]: lbl for lbl in existing_labels_list}
7169

7270
print(f"Found {len(desired_labels)} desired labels in taxonomy.")
@@ -78,7 +76,7 @@ def main():
7876
name = desired["name"]
7977
color = desired.get("color", "ededed")
8078
desc = desired.get("description", "")
81-
79+
8280
if name in existing_labels_map:
8381
existing = existing_labels_map[name]
8482
# Check if color or description needs update
@@ -88,7 +86,7 @@ def main():
8886
subprocess.run(
8987
["gh", "label", "edit", name, "--color", color, "--description", desc],
9088
check=True,
91-
capture_output=True
89+
capture_output=True,
9290
)
9391
except subprocess.CalledProcessError as e:
9492
print(f"Failed to update label '{name}': {e}")
@@ -101,7 +99,7 @@ def main():
10199
subprocess.run(
102100
["gh", "label", "create", name, "--color", color, "--description", desc],
103101
check=True,
104-
capture_output=True
102+
capture_output=True,
105103
)
106104
except subprocess.CalledProcessError as e:
107105
print(f"Failed to create label '{name}': {e}")
@@ -113,5 +111,6 @@ def main():
113111

114112
print("Label sync complete.")
115113

114+
116115
if __name__ == "__main__":
117116
main()

0 commit comments

Comments
 (0)