Forge
pythondeeb25a2
1#!/usr/bin/env python3
2"""Fix intent-catalog.toml: restore melody_*, slash.args, append slashes at block end."""
3from __future__ import annotations
4
5import re
6from pathlib import Path
7
8ROOT = Path(__file__).resolve().parents[1] / "IntentMelody" / "intent-catalog.toml"
9
10MELODY: dict[str, list[str]] = {
11 "apply_edit": [
12 'melody_slug = "eld"',
13 'melody_shape = "parametric"',
14 'melody_tail_signature = "<start:ln>:<end:ln>"',
15 'melody_wire_class = "int_chain_colon_space"',
16 'melody_chord_commit = "enter"',
17 'melody_palette_usage_hint = "c:eld:<start>:<end> или одна строка c:eld:<line> (в аккорде c:eld;<start>;<end> / c:eld;<line> — «;» без Shift) — удалить строки"',
18 'melody_palette_usage_category = "Editor -> Line -> Delete"',
19 ],
20 "select": [
21 'melody_slug = "els"',
22 'melody_shape = "parametric"',
23 'melody_tail_signature = "<start:ln>:<end:ln>"',
24 'melody_wire_class = "int_chain_colon_space"',
25 'melody_chord_commit = "enter"',
26 'melody_palette_usage_hint = "c:els:<start>:<end> или одна строка c:els:<line> (в аккорде c:els;<start>;<end> / c:els;<line> — «;» без Shift) — выделить строки"',
27 'melody_palette_usage_category = "Editor -> Line -> Select"',
28 ],
29 "chat_export_readable": ['melody_slug = "cex"', 'melody_shape = "simple"'],
30 "chat_open_selected_thread": ['melody_slug = "ato"', 'melody_shape = "simple"'],
31 "chat_select_next_message": ['melody_slug = "amn"', 'melody_shape = "simple"'],
32 "chat_select_next_thread": ['melody_slug = "atn"', 'melody_shape = "simple"'],
33 "chat_select_prev_message": ['melody_slug = "amp"', 'melody_shape = "simple"'],
34 "chat_select_prev_thread": ['melody_slug = "atp"', 'melody_shape = "simple"'],
35 "chat_show_thread_overview": ['melody_slug = "atb"', 'melody_shape = "simple"'],
36 "chat_toggle_selected_thinking": ['melody_slug = "amt"', 'melody_shape = "simple"'],
37 "chat_toggle_show_thinking_in_history": ['melody_slug = "amh"', 'melody_shape = "simple"'],
38 "fork_chat_thread": ['melody_slug = "ctf"', 'melody_shape = "simple"'],
39 "send_chat": ['melody_slug = "cs"', 'melody_shape = "simple"'],
40 "show_chat_page": ['melody_slug = "cps"', 'melody_shape = "simple"'],
41 "build_solution_ui": ['melody_slug = "br"', 'melody_shape = "simple"'],
42 "build_structured": ['melody_slug = "bs"', 'melody_shape = "simple"'],
43 "run_tests": ['melody_slug = "bt"', 'melody_shape = "simple"'],
44 "debug_attach": ['melody_slug = "da"', 'melody_shape = "simple"'],
45 "debug_continue": ['melody_slug = "dc"', 'melody_shape = "simple"'],
46 "debug_launch": ['melody_slug = "dl"', 'melody_shape = "simple"'],
47 "debug_step_into": ['melody_slug = "di"', 'melody_shape = "simple"'],
48 "debug_step_out": ['melody_slug = "df"', 'melody_shape = "simple"'],
49 "debug_step_over": ['melody_slug = "dn"', 'melody_shape = "simple"'],
50 "debug_stop": ['melody_slug = "dx"', 'melody_shape = "simple"'],
51 "git_commit": ['melody_slug = "gc"', 'melody_shape = "simple"'],
52 "git_push": ['melody_slug = "gp"', 'melody_shape = "simple"'],
53 "git_status": ['melody_slug = "gs"', 'melody_shape = "simple"'],
54 "git_submodule": ['melody_slug = "gsu"', 'melody_shape = "simple"'],
55 "open_solution_dialog": ['melody_slug = "so"', 'melody_shape = "simple"'],
56 "toggle_workspace_splitters_lock": ['melody_slug = "tol"', 'melody_shape = "simple"'],
57 "show_environment_readiness_page": ['melody_slug = "ers"', 'melody_shape = "simple"'],
58 "show_hybrid_index_page": ['melody_slug = "his"', 'melody_shape = "simple"'],
59 "show_terminal_panel": ['melody_slug = "ts"', 'melody_shape = "simple"'],
60 "show_web_ai_portal_page": [
61 'melody_slug = "wai"',
62 'melody_shape = "parametric"',
63 "melody_show_usage_hint_if_bare_slug = false",
64 'melody_tail_signature = "<url:url>"',
65 'melody_wire_class = "url_remainder"',
66 'melody_chord_commit = "enter"',
67 'melody_palette_hint_slug = "wai-url"',
68 'melody_palette_usage_hint = "c:wai:<адрес> - веб-портал AI; адрес можно без схемы (или c:wai: для страницы по умолчанию)"',
69 'melody_palette_usage_category = "Web AI Portal"',
70 ],
71}
72
73ARGS_AFTER: dict[str, list[str]] = {
74 "/intercom show": ["", "[command.form.slash.args]", 'surface = "intercom"'],
75 "/editor show": ["", "[command.form.slash.args]", 'surface = "editor"'],
76 "/output show": ["", "[command.form.slash.args]", 'page = "Build"'],
77 "/tests show": ["", "[command.form.slash.args]", 'page = "Tests"'],
78 "/debug show": ["", "[command.form.slash.args]", 'page = "DebugStack"'],
79 "/repository show": ["", "[command.form.slash.args]", 'page = "Git"'],
80 "/editor panel": ["", "[command.form.slash.args]", 'page = "Editor"'],
81 "/terminal show": ["", "[command.form.slash.args]", 'page = "Terminal"'],
82 "/problems show": ["", "[command.form.slash.args]", 'page = "Problems"'],
83 "/events show": ["", "[command.form.slash.args]", 'page = "Events"'],
84 "/workspace show": ["", "[command.form.slash.args]", 'page = "WorkspaceHealth"'],
85 "/settings show": ["", "[command.form.slash.args]", 'page = "AiChatSettings"'],
86}
87
88
89def insert_melodies(lines: list[str]) -> list[str]:
90 out: list[str] = []
91 i = 0
92 while i < len(lines):
93 line = lines[i]
94 out.append(line)
95 m = re.match(r'^command_id = "([^"]*)"', line.strip())
96 if m:
97 cmd = m.group(1)
98 nxt = lines[i + 1].strip() if i + 1 < len(lines) else ""
99 if cmd in MELODY and not nxt.startswith("melody_"):
100 out.extend(MELODY[cmd])
101 i += 1
102 return out
103
104
105def insert_args(lines: list[str]) -> list[str]:
106 out: list[str] = []
107 i = 0
108 while i < len(lines):
109 line = lines[i]
110 out.append(line)
111 m = re.match(r'^path = "([^"]+)"', line.strip())
112 if m:
113 path = m.group(1)
114 if path in ARGS_AFTER:
115 j = i + 1
116 chunk = []
117 while j < len(lines):
118 s = lines[j].strip()
119 if s.startswith("group = ") or s.startswith("kind = "):
120 chunk.append(lines[j])
121 j += 1
122 continue
123 break
124 out.extend(chunk)
125 i = j - 1
126 tail = "\n".join(out[-6:])
127 if "[command.form.slash.args]" not in tail:
128 out.extend(ARGS_AFTER[path])
129 i += 1
130 return out
131
132
133def strip_trailing_garbage(lines: list[str]) -> list[str]:
134 while lines and lines[-1].strip().startswith("# =====") or (
135 lines and lines[-1].strip() == "[[command]]" and "Other" in (lines[-3] if len(lines) > 3 else "")
136 ):
137 lines.pop()
138 # remove duplicate empty help at end
139 text = "\n".join(lines)
140 marker = "# ==============================================================================\n# Other"
141 if marker in text:
142 text = text[: text.index(marker)].rstrip()
143 return text.splitlines()
144
145
146def main() -> None:
147 lines = ROOT.read_text(encoding="utf-8").splitlines()
148 lines = strip_trailing_garbage(lines)
149 lines = insert_melodies(lines)
150 lines = insert_args(lines)
151 # fix git commit help TOML
152 for i, ln in enumerate(lines):
153 if 'path = "/git commit"' in ln:
154 j = i + 1
155 if j < len(lines) and lines[j].startswith("help = "):
156 lines[j] = (
157 'help = "Коммит: хвост — сообщение (можно в кавычках: «feat: …»)."'
158 )
159 ROOT.write_text("\n".join(lines).rstrip() + "\n", encoding="utf-8")
160 print(f"Fixed {ROOT}")
161
162
163if __name__ == "__main__":
164 main()
165
View only · write via MCP/CIDE