1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
#!/usr/bin/env python3
"""gen-floating-designer-registry.py — Task 4 of the v2->v3 repair plan. (v2)
Rebuilds the floating-ui-designer CMDS registry from ground truth:
* union of `commands['X']` registrations in modules/core + modules/ext
(bundle/worker files skipped), and
* terminal.js dispatch builtins (`cmd === 'x'`).
Emits /tmp/fui_cmds_snippet.txt with one JS line per command:
['name','desc','cat',1],
Descriptions are re-escaped safely: apostrophes -> \u2019, backslashes -> \u005C
(no raw backslash pairs ever enter the page). Prints acceptance diagnostics.
"""
import os, re
from collections import Counter
BASE = '/var/www/webx11.duckdns.org/spaces/newos4'
OUT = '/tmp/fui_cmds_snippet.txt'
files = []
for d in ('modules/core', 'modules/ext'):
dd = os.path.join(BASE, d)
for f in sorted(os.listdir(dd)):
if not f.endswith('.js'):
continue
if 'bundle' in f or 'worker' in f:
continue
files.append(os.path.join(d, f))
texts = {}
for rel in files:
try:
texts[rel] = open(os.path.join(BASE, rel), encoding='utf-8', errors='replace').read()
except Exception as e:
print('skip', rel, e)
cmd_re = re.compile(r"commands\['([^']+)'\]\s*=")
src_of = {}
for rel, txt in texts.items():
for name in cmd_re.findall(txt):
src_of.setdefault(name, set()).add(rel)
disp = set()
t = texts.get('modules/core/terminal.js', '')
for m in re.finditer(r"cmd === '([a-z0-9-]+)'", t):
disp.add(m.group(1))
for n in disp:
src_of.setdefault(n, set()).add('modules/core/terminal.js')
ALL = sorted(src_of.keys())
def cat_for(rels):
joined = ' '.join(rels)
rules = [
(('aiassist', 'aiasm', 'smartctx', 'chatstudio', 'ollama'), 'ai'),
(('agent-registry', 'orchestrator', 'leases', 'memory-graph', 'world-model'), 'agents'),
(('module-fs', 'busybox', 'shell', 'filemgr', 'editor', 'finder', 'diff', 'neural-vfs', 'cryptogzip'), 'files'),
(('searxng', 'fetcher', 'webdav'), 'network'),
(('calc', 'mindmap', 'three', 'media', 'voice', 'wpm', 'tutorial', 'console'), 'tools'),
(('floating', 'theme', 'kanban'), 'ui'),
(('system', 'config', 'modmgr', 'debug-supervisor', 'predictor', 'servermon', 'sandbox', 'secret-vault', 'terminal'), 'system'),
]
for keys, cat in rules:
if any(k in joined for k in keys):
return cat
return 'system'
DESC_FALLBACK = 'Terminal command'
def desc_for(name):
pat = re.compile(r"'" + re.escape(name) + r"'\s*:\s*'((?:[^'\\]|\\.){1,200})'")
for rel in sorted(texts.keys()):
m = pat.search(texts[rel])
if not m:
continue
raw = m.group(1)
# unescape source-level escaping: \\ -> placeholder, \' and \" -> quote
raw = raw.replace('\\\\', '\x01')
raw = raw.replace("\\'", "'").replace('\\"', '"')
raw = raw.replace('\x01', '\\')
# strip control chars
raw = ''.join(' ' if ord(c) < 32 else c for c in raw)
if '\u2014' in raw:
raw = raw.split('\u2014', 1)[1].strip()
if not raw or raw.lower() == name:
continue
if len(raw) > 90:
raw = raw[:87].rstrip() + '...'
return raw
return DESC_FALLBACK
entries = []
for n in ALL:
d = desc_for(n)
d = d.replace('\\', '\\u005C').replace("'", '\\u2019')
entries.append((cat_for(src_of[n]), n, d))
entries.sort(key=lambda e: (e[0], e[1]))
cnt = Counter(c for c, _, _ in entries)
print('total=%d' % len(entries))
for k in sorted(cnt):
print(' %-8s %d' % (k, cnt[k]))
want = ['session-new', 'health-check', 'doctor', 'uptime', 'ai-stop', 'kanban', 'webdav-browser', 'vfs-export', 'fetch']
bad = ['new-session', 'clipboard-history', 'web', 'save', 'load', 'import', 'svg']
have = set(e[1] for e in entries)
print('missing:', [w for w in want if w not in have])
print('excluded-present:', [b for b in bad if b in have])
print('no-desc fallback count:', sum(1 for _, _, d in entries if d == DESC_FALLBACK))
assert len(entries) >= 330, 'TOO FEW COMMANDS: %d' % len(entries)
with open(OUT, 'w', encoding='utf-8') as f:
for cat, n, d in entries:
f.write("['%s','%s','%s',1],\n" % (n, d, cat))
print('WROTE', OUT)
|