aboutsummaryrefslogtreecommitdiff
path: root/downloads/floating-ui-designer.html
diff options
context:
space:
mode:
Diffstat (limited to 'downloads/floating-ui-designer.html')
-rw-r--r--downloads/floating-ui-designer.html932
1 files changed, 932 insertions, 0 deletions
diff --git a/downloads/floating-ui-designer.html b/downloads/floating-ui-designer.html
new file mode 100644
index 0000000..495bdc4
--- /dev/null
+++ b/downloads/floating-ui-designer.html
@@ -0,0 +1,932 @@
+<!DOCTYPE html>
+<html lang="en"><head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="description" content="Design floating buttons, menus and panels for the WebX11 newOS4 terminal β€” generate verified floating-add commands.">
+<title>🎨 Floating UI Designer v3 β€” WebX11 newOS4</title>
+<style>
+:root{--bg:#0d1117;--panel:#161b22;--panel2:#1c2230;--border:#30363d;--text:#e6edf3;--muted:#8b949e;--accent:#58a6ff;--green:#3fb950;--yellow:#d29922;--red:#f85149;--purple:#bc8cff}
+*{box-sizing:border-box;margin:0;padding:0}
+body{background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;padding:20px;max-width:1500px;margin:0 auto}
+h1{font-size:22px;margin-bottom:4px}
+h2{font-size:15px;margin-bottom:10px;color:var(--accent)}
+.sub{color:var(--muted);font-size:13px;margin-bottom:20px}
+.grid{display:grid;grid-template-columns:1fr 1fr;gap:20px;align-items:start}
+@media(max-width:1000px){.grid{grid-template-columns:1fr}}
+.card{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:16px;margin-bottom:20px}
+.tabs{display:flex;gap:6px;margin-bottom:16px}
+.tab{flex:1;padding:9px;border-radius:8px;border:1px solid var(--border);background:var(--panel2);color:var(--muted);cursor:pointer;font-size:14px}
+.tab.active{background:var(--accent);color:#fff;border-color:var(--accent);font-weight:600}
+label{display:block;font-size:12px;color:var(--muted);margin:10px 0 4px;text-transform:uppercase;letter-spacing:.5px}
+input[type=text],textarea,select{width:100%;background:var(--panel2);border:1px solid var(--border);border-radius:6px;color:var(--text);padding:9px;font-size:14px;font-family:inherit}
+input:focus,textarea:focus,select:focus{outline:none;border-color:var(--accent)}
+.row{display:flex;gap:8px;align-items:center}
+.row>*{flex:1}
+.emoji-chips{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}
+.emoji-chips button{background:var(--panel2);border:1px solid var(--border);border-radius:6px;padding:4px 7px;font-size:17px;cursor:pointer}
+.emoji-chips button:hover{border-color:var(--accent);background:#1f2a3a}
+.btn{padding:9px 16px;border-radius:8px;border:none;cursor:pointer;font-size:14px;font-weight:600}
+.btn-primary{background:var(--accent);color:#fff}
+.btn-green{background:var(--green);color:#fff}
+.btn-ghost{background:var(--panel2);color:var(--text);border:1px solid var(--border)}
+.btn-red{background:transparent;color:var(--red);border:1px solid var(--red);padding:4px 10px;font-size:12px}
+.btn-sm{padding:5px 10px;font-size:12px}
+.out{background:#0a0e14;border:1px solid var(--border);border-radius:8px;padding:12px;margin-top:12px;position:relative;word-break:break-all}
+.out code{font-family:'SF Mono',Consolas,monospace;font-size:13px;color:#7ee787;display:block;line-height:1.5}
+.out .copy-btn{position:absolute;top:8px;right:8px}
+.val{font-size:12px;margin-top:6px;min-height:16px}
+.val.ok{color:var(--green)}
+.val.warn{color:var(--yellow)}
+.val.err{color:var(--red)}
+/* preview */
+.term{background:#090c12;border:1px solid var(--border);border-radius:10px;overflow:hidden;height:460px;position:relative;display:flex;flex-direction:column}
+.term-bar{background:var(--panel2);padding:9px 14px;font-size:12px;color:var(--muted);display:flex;align-items:center;gap:8px;border-bottom:1px solid var(--border)}
+.term-bar .dots{display:flex;gap:5px}
+.term-bar .dots span{width:11px;height:11px;border-radius:50%;display:block}
+.term-body{flex:1;padding:14px;font-family:'SF Mono',Consolas,monospace;font-size:12.5px;color:#9aa7b8;overflow:hidden;line-height:1.7}
+.term-body .p{color:#3fb950}
+.term-body .c{color:#58a6ff}
+.float-layer{position:absolute;right:14px;bottom:14px;display:flex;flex-direction:column-reverse;align-items:flex-end;gap:10px}
+/* mock floating elements β€” styled like the real floating UI */
+.fbtn{width:46px;height:46px;border-radius:50%;background:linear-gradient(135deg,#58a6ff,#bc8cff);color:#fff;border:none;font-size:12px;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 14px rgba(0,0,0,.5);transition:transform .15s;padding:4px;text-align:center;line-height:1.1;overflow:hidden}
+.fbtn:hover{transform:scale(1.1)}
+.fbtn.draft{outline:2px dashed var(--yellow);outline-offset:3px}
+.fmenu{display:flex;flex-direction:column;align-items:flex-end}
+.fmenu-head{width:46px;height:46px;border-radius:50%;background:linear-gradient(135deg,#3fb950,#58a6ff);color:#fff;border:none;font-size:12px;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 14px rgba(0,0,0,.5);padding:4px;text-align:center;line-height:1.1;overflow:hidden}
+.fmenu-head:hover{transform:scale(1.1)}
+.fmenu-items{display:none;flex-direction:column;align-items:flex-end;gap:8px;margin-bottom:8px}
+.fmenu.open .fmenu-items{display:flex}
+.fsub{padding:8px 14px;border-radius:20px;background:#21262e;color:var(--text);border:1px solid var(--border);font-size:13px;cursor:pointer;white-space:nowrap}
+.fsub:hover{background:#2d333b;border-color:var(--accent)}
+.fpanel{background:#1c2230;border:1px solid var(--border);border-radius:10px;padding:12px 14px;min-width:180px;max-width:260px;box-shadow:0 4px 14px rgba(0,0,0,.5)}
+.fpanel b{display:block;font-size:13px;margin-bottom:6px;color:#e6edf3}
+.fpanel span{font-size:12px;color:var(--muted)}
+/* collection */
+.item{display:flex;gap:10px;align-items:center;padding:10px;border:1px solid var(--border);border-radius:8px;margin-bottom:8px;background:var(--panel2)}
+.item code{font-family:'SF Mono',Consolas,monospace;font-size:12.5px;color:#7ee787;flex:1;word-break:break-all}
+.item .tag{font-size:11px;padding:2px 8px;border-radius:10px;background:#2d333b;color:var(--accent);white-space:nowrap}
+/* palette */
+.pal-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:6px;max-height:320px;overflow-y:auto;padding:4px}
+.pal-cmd{background:var(--panel2);border:1px solid var(--border);border-radius:6px;padding:7px 10px;cursor:pointer;font-size:12.5px}
+.pal-cmd:hover{border-color:var(--accent);background:#1f2a3a}
+.pal-cmd code{font-family:'SF Mono',Consolas,monospace;color:#79c0ff}
+.pal-cmd small{display:block;color:var(--muted);font-size:11px;margin-top:2px}
+.pal-cmd .cat{float:right;font-size:10px;color:var(--purple);text-transform:uppercase;letter-spacing:.5px}
+.note{background:#2d2500;border:1px solid var(--yellow);border-radius:8px;padding:10px 14px;font-size:13px;margin-bottom:16px;line-height:1.5}
+.note b{color:var(--yellow)}
+.note-ok{background:#04260f;border:1px solid var(--green)}
+.note-ok b{color:var(--green)}
+#toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%) translateY(80px);background:var(--green);color:#fff;padding:10px 22px;border-radius:8px;font-size:14px;font-weight:600;transition:transform .25s;z-index:99}
+#toast.show{transform:translateX(-50%) translateY(0)}
+.menu-item-row{display:grid;grid-template-columns:1fr 1.4fr auto;gap:8px;margin-bottom:8px;align-items:center}
+.hint{font-size:11.5px;color:var(--muted);margin-top:6px;line-height:1.5}
+.grammar{background:#0a0e14;border:1px solid var(--border);border-radius:8px;padding:12px;font-family:'SF Mono',Consolas,monospace;font-size:12px;line-height:1.8;margin-bottom:14px}
+.grammar b{color:var(--accent);font-weight:600}
+.grammar em{color:var(--muted);font-style:normal}
+.preset{display:block;width:100%;text-align:left;background:var(--panel2);border:1px solid var(--border);border-radius:8px;padding:9px 12px;margin-bottom:6px;cursor:pointer;color:var(--text)}
+.preset:hover{border-color:var(--accent)}
+.preset b{font-size:13px}
+.preset small{display:block;color:var(--muted);font-size:11.5px;margin-top:2px;word-break:break-all}
+</style>
+</head>
+<body>
+
+<h1>🎨 Floating UI Designer <span style="color:var(--green);font-size:14px">v3 β€” quoting, import &amp; registry fixed</span></h1>
+<div class="sub">Design floating buttons, menus &amp; panels β†’ live preview β†’ copy validated <code style="color:#79c0ff">floating-add</code> commands for the WebX11 newOS4 terminal</div>
+
+<div class="note note-ok">
+ βœ… <b>Syntax verified against FloatingModule source code (2026-10-17):</b> menu items are <b>space-separated</b> and use <b>two colons</b> β€” <code>btn:Label:command</code>.<br>
+ Old pipe syntax (<code>btn:Label|cmd</code>) was <b>wrong</b> and silently produced broken menus. Multi-word labels/commands are auto-quoted here (<code>btn:"My Label":"cmd with args"</code>) β€” tested live in the real terminal and confirmed working.<br>
+ <b>v3 (2026-10-17):</b> auto-quoting, import/preset parsing, ID slugs and the full 344-command registry verified against the live terminal (v4.6.26).
+</div>
+
+<div class="grid">
+ <!-- ============ LEFT: BUILDER ============ -->
+ <div>
+ <div class="card">
+ <h2>1 Β· Real grammar (from the module's parser)</h2>
+ <div class="grammar">
+ <b>button:</b> floating-add btn &lt;id&gt; "<em>label</em>" &lt;command&gt; <em>[args...]</em><br>
+ <b>menu:</b>&nbsp;&nbsp; floating-add menu &lt;id&gt; "<em>label</em>" btn:Label:cmd btn:Label2:cmd2 ...<br>
+ <b>panel:</b>&nbsp;&nbsp; floating-add panel &lt;id&gt; "<em>title</em>" "<em>content</em>"<br>
+ <span style="color:var(--red)">⚠</span> an item with ONE colon (btn:Files) is dropped β†’ "No valid sub-buttons"<br>
+ <span style="color:var(--red)">⚠</span> menu items may NOT contain bare spaces β€” quote them: btn:"A B":ls
+ </div>
+
+ <h2>2 Β· Design your element</h2>
+ <div class="tabs" id="type-tabs">
+ <button class="tab active" data-type="btn">πŸ”˜ Button</button>
+ <button class="tab" data-type="menu">πŸ“‹ Menu</button>
+ <button class="tab" data-type="panel">πŸ“„ Panel</button>
+ </div>
+
+ <!-- BUTTON FORM -->
+ <div id="form-btn" style="">
+ <label for="btn-label">Label (pick an emoji or type)</label>
+ <input type="text" id="btn-label" placeholder="πŸ†• or πŸ†• New Session" value="πŸ†•">
+ <div class="emoji-chips" id="emoji-chips"><button>πŸ†•</button><button>βœ…</button><button>βš™οΈ</button><button>🌐</button><button>πŸ“‹</button><button>πŸ—‚οΈ</button><button>πŸ“</button><button>🧠</button><button>πŸ–₯️</button><button>πŸ“Š</button><button>πŸ”</button><button>πŸ”§</button><button>πŸš€</button><button>πŸ’Ύ</button><button>πŸ”</button><button>⚑</button><button>🎨</button><button>🧹</button><button>⏹️</button><button>❀️</button><button>πŸ€–</button><button>πŸ’¬</button><button>πŸ§ͺ</button><button>☁️</button></div>
+ <label for="btn-id">ID <span style="text-transform:none">(single word, no spaces)</span></label>
+ <input type="text" id="btn-id" placeholder="my-button" value="my-button">
+ <label for="btn-cmd">Command <span style="text-transform:none">(click a command in the palette below to insert)</span></label>
+ <input type="text" id="btn-cmd" placeholder="status (args allowed: ai-config confirm-timeout 0)" value="status">
+ </div>
+
+ <!-- MENU FORM -->
+ <div id="form-menu" style="display: none;">
+ <label for="menu-label">Menu label (header)</label>
+ <input type="text" id="menu-label" placeholder="πŸ—‚οΈ Files">
+ <div class="emoji-chips" id="emoji-chips2"><button>πŸ†•</button><button>βœ…</button><button>βš™οΈ</button><button>🌐</button><button>πŸ“‹</button><button>πŸ—‚οΈ</button><button>πŸ“</button><button>🧠</button><button>πŸ–₯️</button><button>πŸ“Š</button><button>πŸ”</button><button>πŸ”§</button><button>πŸš€</button><button>πŸ’Ύ</button><button>πŸ”</button><button>⚑</button><button>🎨</button><button>🧹</button><button>⏹️</button><button>❀️</button><button>πŸ€–</button><button>πŸ’¬</button><button>πŸ§ͺ</button><button>☁️</button></div>
+ <label for="menu-id">Menu ID</label>
+ <input type="text" id="menu-id" placeholder="files-menu">
+ <label>Items β€” each needs Label AND Command</label>
+ <div id="menu-items"><div class="menu-item-row"><input type="text" placeholder="Label"><input type="text" placeholder="Command (e.g. ls)"><button class="btn btn-red btn-sm">βœ•</button></div><div class="menu-item-row"><input type="text" placeholder="Label"><input type="text" placeholder="Command (e.g. ls)"><button class="btn btn-red btn-sm">βœ•</button></div></div>
+ <button class="btn btn-ghost btn-sm" id="menu-add-item">οΌ‹ Add item</button>
+ <div class="hint">Item labels/commands with spaces are auto-quoted β†’ btn:"My Label":"cmd with args" (verified working). Items with only one colon will be rejected here before you ever install them.</div>
+ </div>
+
+ <!-- PANEL FORM -->
+ <div id="form-panel" style="display: none;">
+ <label for="panel-label">Panel title</label>
+ <input type="text" id="panel-label" placeholder="πŸ“Š Status">
+ <label for="panel-id">Panel ID</label>
+ <input type="text" id="panel-id" placeholder="status-p">
+ <label for="panel-content">Content (markdown-lite: **bold** *italic* `code` [links](https://…)) β€” line breaks collapse to spaces</label>
+ <textarea id="panel-content" rows="3" placeholder="CPU: 2% | RAM: 45%"></textarea>
+ </div>
+ </div>
+
+ <div class="card">
+ <h2>3 Β· Presets (all commands verified real)</h2>
+ <div id="presets"><button class="preset"><b>πŸ—‚οΈ Files menu</b><small>list Β· trash Β· concept tree (this one is live in your UI)</small></button><button class="preset"><b>🧠 AI menu</b><small>ask Β· clear Β· context Β· debug</small></button><button class="preset"><b>πŸ–₯️ System menu</b><small>status Β· mem Β· logs Β· help</small></button><button class="preset"><b>🌐 Web menu</b><small>search Β· images Β· fetch Β· extract</small></button><button class="preset"><b>πŸ“Š Status panel</b><small>markdown-lite panel</small></button><button class="preset"><b>βš™οΈ Config button</b><small>button with arguments (user-verified)</small></button><button class="preset"><b>πŸ§ͺ Quoted items demo</b><small>multi-word label + multi-word command</small></button></div>
+ <button class="btn btn-ghost btn-sm" id="load-current">πŸ“₯ Import your current live setup (6 elements)</button>
+ </div>
+
+ <div class="card">
+ <h2>4 Β· Command palette</h2>
+ <input type="text" id="pal-search" placeholder="Search commands… (e.g. file, ai, web)">
+ <div class="pal-grid" id="pal-grid"><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>ai</code><small>Ask the AI assistant</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>ask</code><small>Ask the AI assistant</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>ai-clear</code><small>Clear AI context</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>ai-system</code><small>AI system prompt</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>ai-context</code><small>AI context info</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>ai-allow</code><small>Allow AI command</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>ai-deny</code><small>Deny AI command</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>ai-ignore</code><small>Ignore AI command</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>ai-config</code><small>AI configuration (user-verified)</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>chat</code><small>Open chat studio</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>debug</code><small>Open debug panel</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>debug-ai</code><small>AI debug panel</small></div><div class="pal-cmd"><span class="cat">agents</span>βœ“ <code>agent-list</code><small>List registered agents</small></div><div class="pal-cmd"><span class="cat">agents</span>βœ“ <code>agent-status</code><small>Agent status</small></div><div class="pal-cmd"><span class="cat">agents</span>βœ“ <code>agent-register</code><small>Register agent</small></div><div class="pal-cmd"><span class="cat">agents</span>βœ“ <code>agent-unregister</code><small>Unregister agent</small></div><div class="pal-cmd"><span class="cat">agents</span>βœ“ <code>contract-list</code><small>List A2A contracts</small></div><div class="pal-cmd"><span class="cat">agents</span>βœ“ <code>orchestrate</code><small>Run orchestrator</small></div><div class="pal-cmd"><span class="cat">agents</span>βœ“ <code>orchestrator-status</code><small>Orchestrator status</small></div><div class="pal-cmd"><span class="cat">agents</span>βœ“ <code>orchestrator-spawn</code><small>Spawn orchestrator</small></div><div class="pal-cmd"><span class="cat">agents</span>βœ“ <code>orchestrator-kill</code><small>Kill orchestrator</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>webxai</code><small>WebX AI alias</small></div><div class="pal-cmd"><span class="cat">ai</span>βœ“ <code>wx</code><small>WebX AI alias</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>ls</code><small>List current directory</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>cat</code><small>Read a file</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>put</code><small>Write a file</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>rm</code><small>Delete a file</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>trash</code><small>Trash a file</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>trash-dir</code><small>Trash a directory</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>ls-trash</code><small>List trash</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>empty-trash</code><small>Empty trash</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>nvfs-index</code><small>Build neural VFS index</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>nvfs-status</code><small>Neural VFS status</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>nvfs-resolve</code><small>Semantic file search</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>nvfs-tree</code><small>Concept tree</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>save</code><small>Save VFS snapshot</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>load</code><small>Load VFS snapshot</small></div><div class="pal-cmd"><span class="cat">files</span>βœ“ <code>import</code><small>Import VFS</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>help</code><small>Command reference</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>echo</code><small>Print text</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>mem</code><small>Memory usage</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>status</code><small>System status</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>preview</code><small>Preview a file</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>logs</code><small>System logs</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>clear</code><small>Clear terminal</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>cd</code><small>Change directory</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>modules</code><small>List modules</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>listmods</code><small>List modules</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>loadmod</code><small>Load a module</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>removemod</code><small>Remove a module</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>startup-modules</code><small>Manage startup modules</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>config</code><small>Config manager</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>config-list</code><small>List config</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>config-set</code><small>Set config key</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>config-export</code><small>Export config</small></div><div class="pal-cmd"><span class="cat">system</span>βœ“ <code>factory-reset</code><small>Full reset (destructive)</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>js</code><small>Run JavaScript</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>js-run</code><small>Run JavaScript</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>node</code><small>Run JavaScript</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>gui</code><small>Simple GUI</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>gui-button</code><small>GUI button</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>gui-input</code><small>GUI input</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>gui-text</code><small>GUI text</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>gui-clear</code><small>Clear GUI</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>gui-run</code><small>Run GUI actions</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>ollama</code><small>Ollama manager</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>ollamaconnect</code><small>Connect Ollama</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>ollamamodels</code><small>List Ollama models</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>ollamasetmodel</code><small>Set Ollama model</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>models</code><small>List LLM models</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>model-info</code><small>Model info</small></div><div class="pal-cmd"><span class="cat">tools</span>βœ“ <code>analyze</code><small>Media analyze</small></div><div class="pal-cmd"><span class="cat">agents</span>βœ“ <code>lease-list</code><small>List leases</small></div><div class="pal-cmd"><span class="cat">network</span>βœ“ <code>fetch</code><small>Fetch a URL</small></div><div class="pal-cmd"><span class="cat">network</span>βœ“ <code>web</code><small>Fetch a URL</small></div><div class="pal-cmd"><span class="cat">network</span>βœ“ <code>extract</code><small>Extract URL content</small></div><div class="pal-cmd"><span class="cat">network</span>βœ“ <code>search</code><small>Web search</small></div><div class="pal-cmd"><span class="cat">network</span>βœ“ <code>s</code><small>Web search (short)</small></div><div class="pal-cmd"><span class="cat">network</span>βœ“ <code>images</code><small>Image search</small></div><div class="pal-cmd"><span class="cat">network</span>βœ“ <code>videos</code><small>Video search</small></div><div class="pal-cmd"><span class="cat">network</span>βœ“ <code>server</code><small>Server monitor</small></div><div class="pal-cmd"><span class="cat">network</span>βœ“ <code>servers</code><small>List servers</small></div><div class="pal-cmd"><span class="cat">network</span>βœ“ <code>server-check</code><small>Check server</small></div><div class="pal-cmd"><span class="cat">network</span>βœ“ <code>monitor</code><small>Monitor system</small></div><div class="pal-cmd"><span class="cat">network</span>βœ“ <code>system-health</code><small>System health</small></div><div class="pal-cmd"><span class="cat">security</span>βœ“ <code>secret-list</code><small>List secrets</small></div><div class="pal-cmd"><span class="cat">security</span>βœ“ <code>secret-status</code><small>Secret vault status</small></div><div class="pal-cmd"><span class="cat">security</span>βœ“ <code>secret-set</code><small>Store a secret</small></div><div class="pal-cmd"><span class="cat">security</span>βœ“ <code>secret-get</code><small>Read a secret</small></div><div class="pal-cmd"><span class="cat">security</span>βœ“ <code>secret-lock</code><small>Lock vault</small></div><div class="pal-cmd"><span class="cat">security</span>βœ“ <code>secret-unlock</code><small>Unlock vault</small></div><div class="pal-cmd"><span class="cat">security</span>βœ“ <code>security</code><small>Security info</small></div><div class="pal-cmd"><span class="cat">security</span>βœ“ <code>security-level</code><small>Security level</small></div><div class="pal-cmd"><span class="cat">security</span>βœ“ <code>cmd-allow</code><small>Allow a command</small></div><div class="pal-cmd"><span class="cat">security</span>βœ“ <code>cmd-deny</code><small>Deny a command</small></div><div class="pal-cmd"><span class="cat">ui</span>βœ“ <code>floating-add</code><small>Add floating element</small></div><div class="pal-cmd"><span class="cat">ui</span>βœ“ <code>floating-remove</code><small>Remove element</small></div><div class="pal-cmd"><span class="cat">ui</span>βœ“ <code>floating-list</code><small>List elements</small></div><div class="pal-cmd"><span class="cat">ui</span>βœ“ <code>floating-pos</code><small>Position element</small></div><div class="pal-cmd"><span class="cat">ui</span>βœ“ <code>floating-toggle</code><small>Show/hide element</small></div><div class="pal-cmd"><span class="cat">ui</span>βœ“ <code>floating-clear</code><small>Remove ALL elements</small></div><div class="pal-cmd"><span class="cat">files</span>⚠ <code>files</code><small>File manager UI</small></div><div class="pal-cmd"><span class="cat">files</span>⚠ <code>edit</code><small>Open file editor</small></div><div class="pal-cmd"><span class="cat">files</span>⚠ <code>find</code><small>Find files</small></div><div class="pal-cmd"><span class="cat">ui</span>⚠ <code>theme</code><small>Change theme</small></div><div class="pal-cmd"><span class="cat">ui</span>⚠ <code>mindmap</code><small>Create mindmap</small></div><div class="pal-cmd"><span class="cat">ui</span>⚠ <code>svg</code><small>Render SVG</small></div><div class="pal-cmd"><span class="cat">tools</span>⚠ <code>calc</code><small>Calculator</small></div><div class="pal-cmd"><span class="cat">tools</span>⚠ <code>date</code><small>Show date</small></div><div class="pal-cmd"><span class="cat">tools</span>⚠ <code>env</code><small>Environment vars</small></div><div class="pal-cmd"><span class="cat">tools</span>⚠ <code>which</code><small>Locate command</small></div><div class="pal-cmd"><span class="cat">tools</span>⚠ <code>diff</code><small>Diff files</small></div><div class="pal-cmd"><span class="cat">tools</span>⚠ <code>gzip</code><small>Gzip file</small></div><div class="pal-cmd"><span class="cat">tools</span>⚠ <code>gunzip</code><small>Ungzip file</small></div><div class="pal-cmd"><span class="cat">tools</span>⚠ <code>encrypt</code><small>Encrypt file</small></div><div class="pal-cmd"><span class="cat">tools</span>⚠ <code>decrypt</code><small>Decrypt file</small></div><div class="pal-cmd"><span class="cat">network</span>⚠ <code>webdav-status</code><small>WebDAV status</small></div><div class="pal-cmd"><span class="cat">network</span>⚠ <code>webdav-ls</code><small>WebDAV listing</small></div><div class="pal-cmd"><span class="cat">network</span>⚠ <code>webdav-push</code><small>Push to WebDAV</small></div><div class="pal-cmd"><span class="cat">network</span>⚠ <code>webdav-pull</code><small>Pull from WebDAV</small></div><div class="pal-cmd"><span class="cat">system</span>⚠ <code>cron-list</code><small>List cron jobs</small></div><div class="pal-cmd"><span class="cat">system</span>⚠ <code>wpm</code><small>Package manager</small></div><div class="pal-cmd"><span class="cat">tools</span>⚠ <code>voice</code><small>Voice control</small></div><div class="pal-cmd"><span class="cat">system</span>⚠ <code>alias</code><small>Manage aliases</small></div></div>
+ <div class="hint">βœ“ = real terminal command (all default modules auto-load) Β· ⚠ = unknown, routes to the AI Β· click to insert into the form Β· search is case-insensitive.</div>
+ </div>
+
+ <div class="card">
+ <h2>5 Β· Import existing command</h2>
+ <textarea id="import-area" rows="3" placeholder="Paste floating-add lines here, e.g. floating-add menu files-menu &quot;πŸ—‚οΈ Files&quot; btn:List:ls"></textarea>
+ <div style="margin-top:8px"><button class="btn btn-primary btn-sm" id="import-btn">Parse &amp; load into builder</button></div>
+ </div>
+ </div>
+
+ <!-- ============ RIGHT: PREVIEW + OUTPUT ============ -->
+ <div>
+ <div class="card">
+ <h2>Live preview</h2>
+ <div class="term">
+ <div class="term-bar"><div class="dots"><span style="background:#f85149"></span><span style="background:#d29922"></span><span style="background:#3fb950"></span></div>newOS4 β€” mock terminal</div>
+ <div class="term-body">
+ <span class="p">webx11@newos4</span>:<span class="c">~</span>$ floating-list<br>
+ <span style="color:var(--muted)">… your draft renders bottom-right (dashed = draft) …</span>
+ </div>
+ <div class="float-layer" id="float-layer"><button class="fbtn draft">πŸ—‚οΈNew</button></div>
+ </div>
+ <div class="hint">Menus expand on click in the preview. The real UI also lets you drag elements by their header/button; position is saved automatically.</div>
+ </div>
+
+ <div class="card">
+ <h2>Generated command + validation</h2>
+ <div class="out">
+ <code id="out-code">floating-add btn my-button "πŸ†•" status</code>
+ <button class="btn btn-green btn-sm copy-btn" id="copy-main">πŸ“‹ Copy</button>
+ </div>
+ <div class="val ok" id="out-val" aria-live="polite">βœ“ "status" is a real terminal command</div>
+ <div style="margin-top:10px" class="row">
+ <button class="btn btn-primary" id="add-coll">βž• Add to collection</button>
+ <button class="btn btn-ghost" id="install-now">πŸš€ Copy &amp; run in terminal</button>
+ <a class="btn btn-ghost" href="https://webx11.duckdns.org/spaces/newos4/main.html" target="_blank" rel="noopener" style="text-align:center;text-decoration:none">πŸ–₯ Open newOS4 terminal β†—</a>
+ </div>
+ </div>
+
+ <div class="card">
+ <h2>Collection <span style="font-size:12px;color:var(--muted)" id="coll-count">(0)</span></h2>
+ <div id="coll-list"></div>
+ <div class="row" style="margin-top:10px">
+ <button class="btn btn-green" id="copy-all">πŸ“‹ Copy all</button>
+ <button class="btn btn-ghost" id="coll-clear">πŸ—‘ Clear</button>
+ </div>
+ <div class="hint">Paste the copied block into the newOS4 terminal to install everything at once.</div>
+ </div>
+ </div>
+</div>
+
+<div id="toast" class=""></div>
+
+<script>
+(function(){
+'use strict';
+var $ = function(id){ return document.getElementById(id); };
+
+/* ───────── Command registry β€” built from live list_available_modules (2026-10-17) ─────────
+ [command, description, category, auto] β€” auto=1 available immediately, auto=0 needs loadmod */
+var CMDS = [
+['a2a-ack','Acknowledge a message with result','agents',1],
+['a2a-list','Show pending A2A messages across all agents','agents',1],
+['a2a-poll','Poll for messages addressed to an agent (default: current or "user")','agents',1],
+['a2a-post','Post an A2A message','agents',1],
+['a2a-prune','Clean up expired and old completed messages','agents',1],
+['a2a-reject','Reject a message with error','agents',1],
+['a2a-send','Send an A2A message to an agent\u2019s inbox','agents',1],
+['a2a-status','Show scratchpad stats per agent','agents',1],
+['agent-list','Terminal command','agents',1],
+['agent-register','Terminal command','agents',1],
+['agent-status','Terminal command','agents',1],
+['agent-unregister','Terminal command','agents',1],
+['consensus','Start a consensus round: spawn 3 agents, debate the question, resolve by majority','agents',1],
+['consensus-history','Show past consensus rounds and their resolutions','agents',1],
+['consensus-status','Show current/active consensus round status','agents',1],
+['contract-list','Terminal command','agents',1],
+['contract-register','Terminal command','agents',1],
+['lease-create','Terminal command','agents',1],
+['lease-list','Terminal command','agents',1],
+['lease-renew','Terminal command','agents',1],
+['lease-revoke','Terminal command','agents',1],
+['memgraph-agent','Show namespaced nodes for an agent','agents',1],
+['memgraph-decay-config','Configure decay policy (default: 30d, 3 uses)','agents',1],
+['memgraph-export','Export graph as JSON','agents',1],
+['memgraph-learn','Add a fact to the memory graph','agents',1],
+['memgraph-prune','Remove stale low-weight edges (>30d, <3 accesses)','agents',1],
+['memgraph-search','Find nodes by label or type','agents',1],
+['memgraph-session','Show graph nodes for a session (default: today)','agents',1],
+['memgraph-stats','Most connected nodes, strongest edges, cluster info','agents',1],
+['memgraph-status','Show node/edge counts, last access','agents',1],
+['orchestrate','Delegate a task to an available agent (auto-spawns if needed)','agents',1],
+['orchestrate-decompose','Preview how a task would be decomposed into sub-tasks','agents',1],
+['orchestrate-parallel','Decompose and delegate sub-tasks in parallel (auto-splits on "and"/"then")','agents',1],
+['orchestrate-result','Show the last parallel batch results (stored in VFS)','agents',1],
+['orchestrator-config','Terminal command','agents',1],
+['orchestrator-kill','Terminate an agent and revoke leases','agents',1],
+['orchestrator-list','List all spawned agents with full details','agents',1],
+['orchestrator-purge','Remove dead agents (>60s since heartbeat)','agents',1],
+['orchestrator-restart-policy','Set per-agent restart policy','agents',1],
+['orchestrator-schedule','Schedule a recurring task delegation','agents',1],
+['orchestrator-schedules','List all active recurring schedules','agents',1],
+['orchestrator-sleep','Suspend agent to VFS','agents',1],
+['orchestrator-spawn','Manually spawn a new agent','agents',1],
+['orchestrator-status','Show agent pool status and config','agents',1],
+['orchestrator-unschedule','Remove a recurring schedule','agents',1],
+['orchestrator-wake','Restore agent from VFS sleep','agents',1],
+['pipeline','Autonomous CI/CD: test agents/queue/modules, deploy (test→auto-fix→verify), history (sh...','agents',1],
+['world-model','Show full world model as structured output','agents',1],
+['world-model-ask','Query the model (e.g. "what changed since yesterday")','agents',1],
+['world-model-config','Tune: refresh-interval, max-projects','agents',1],
+['world-model-refresh','Force re-synthesis from all subsystems','agents',1],
+['world-model-summary','One-line system self-awareness statement','agents',1],
+['agent-loops','Manage agent loop profiles','ai',1],
+['ai','Ask the AI assistant anything','ai',1],
+['ai-allow','Confirm pending AI action','ai',1],
+['ai-clear','Clear conversation context','ai',1],
+['ai-compress','Terminal command','ai',1],
+['ai-config','View or set AI loop config (max-turns, max-context, confirm-timeout(0=disabled))','ai',1],
+['ai-context','Show current conversation context','ai',1],
+['ai-deny','Deny pending AI action','ai',1],
+['ai-ignore','Suppress validator warnings for this session','ai',1],
+['ai-model','Show or set AI model','ai',1],
+['ai-stop','Cancel current AI operation','ai',1],
+['ai-system','Set system prompt','ai',1],
+['archive-list','Terminal command','ai',1],
+['archive-read','Terminal command','ai',1],
+['ask','Alias for ai command','ai',1],
+['bench','Run benchmark suite on a profile','ai',1],
+['bench-compare','Compare benchmark results of two profiles','ai',1],
+['chat','default','ai',1],
+['commit-approve','Terminal command','ai',1],
+['commit-deny','Terminal command','ai',1],
+['commit-status','Terminal command','ai',1],
+['context','Set or view current context profile','ai',1],
+['context-auto','Toggle auto-routing (detects intent from user input)','ai',1],
+['context-delete','Delete a context profile','ai',1],
+['context-new','Create a new context profile','ai',1],
+['contexts','List all available context profiles','ai',1],
+['debug','Toggle system debug console (logs, fetch, errors)','ai',1],
+['debug-ai','Toggle AI tool-call debug panel','ai',1],
+['debug-ai-last','Terminal command','ai',1],
+['debug-ai-log','Terminal command','ai',1],
+['debug-ai-send','Terminal command','ai',1],
+['guardrail','Terminal command','ai',1],
+['guardrail-add','Terminal command','ai',1],
+['guardrail-remove','Terminal command','ai',1],
+['mem-debug','Show memory breakdown by component','ai',1],
+['model-delete','Delete a model from local storage','ai',1],
+['model-info','Show details about a specific model','ai',1],
+['model-pull','Pull a model from Ollama registry','ai',1],
+['model-run','Run inference with a model','ai',1],
+['models','List all available Ollama models (table format)','ai',1],
+['ollama','Open the Ollama model manager UI','ai',1],
+['ollamaconnect','Connect to the Ollama server','ai',1],
+['ollamadisconnect','Disconnect from the Ollama server','ai',1],
+['ollamamodels','List all available models from Ollama','ai',1],
+['ollamasetmodel','Set the active Ollama model','ai',1],
+['ollamasetproxy','View or change the Ollama endpoint URL','ai',1],
+['reset-mem','Reset AI memory (logs, context, profile, guardrails) without losing VFS or config','ai',1],
+['shadow','Terminal command','ai',1],
+['shadow-commit','Terminal command','ai',1],
+['shadow-rollback','Terminal command','ai',1],
+['smart-ask','Ask a question using the active context','ai',1],
+['vaultmind-connect','Connect VaultMind wallet using hyperliquid_key from SecretVault','ai',1],
+['vaultmind-query','Query VaultMind API','ai',1],
+['vaultmind-status','Check VaultMind session status','ai',1],
+['wallet-lookup','Look up Hyperliquid wallet summary','ai',1],
+['webx','Alias for webxai','ai',1],
+['webxai','Send a question to the AI assistant','ai',1],
+['wx','Alias for webxai','ai',1],
+['base64','Base64 encode/decode','files',1],
+['basename','Strip directory from path','files',1],
+['cal','Display an ASCII calendar','files',1],
+['cat','Display file contents','files',1],
+['cd','Change current directory; cd / to go to root','files',1],
+['cp','Copy file or directory','files',1],
+['cut','Extract column from file','files',1],
+['date','Show current date/time (ISO, local, UTC, timestamp)','files',1],
+['decrypt','Decrypt a .enc file','files',1],
+['diff','Show differences between two VFS files or compare module source (usage: diff <file1> <f...','files',1],
+['dirname','Strip filename from path','files',1],
+['download','Download a file to your device','files',1],
+['du','Estimate file/directory size','files',1],
+['echo','Print text to the terminal','files',1],
+['edit','Open the code editor for a VFS file (usage: edit <path>)','files',1],
+['empty-trash','Permanently delete all trash items','files',1],
+['encrypt','AES-256-GCM encrypt a file','files',1],
+['env','List environment variables (webx11_ keys + user profile)','files',1],
+['expand','Toggle full-screen terminal output','files',1],
+['export','Set a shell variable','files',1],
+['files','Open the file manager overlay with VFS directory listing, preview, encrypt, zip','files',1],
+['find','Search files by name pattern','files',1],
+['grep','Search file content for pattern','files',1],
+['gunzip','Decompress a .gz file (binary-safe)','files',1],
+['gzip','Compress a VFS file to .gz','files',1],
+['head','Show first N lines (default: 10)','files',1],
+['hostname','Show host/user-agent info','files',1],
+['ls','List files and directories','files',1],
+['ls-trash','List items in trash','files',1],
+['mkdir','Create a directory; -p creates parent paths','files',1],
+['mv','Move file or directory','files',1],
+['nvfs-alias','Manage concept aliases','files',1],
+['nvfs-cancel','Cancel running index operation','files',1],
+['nvfs-config','View or set Neural VFS config (fuzzy-limit, tree-files, tree-concepts, resolve-files, d...','files',1],
+['nvfs-index','Scan VFS and build semantic concept index','files',1],
+['nvfs-index-graph','Terminal command','files',1],
+['nvfs-resolve','Find files related to a concept','files',1],
+['nvfs-save','Force-save current in-memory index to VFS (survives refresh)','files',1],
+['nvfs-status','Show semantic index stats and last scan time','files',1],
+['nvfs-sync','Incremental background sync (auto-sync dirty files)','files',1],
+['nvfs-tree','Show concept-to-file mapping as a tree','files',1],
+['preview','Render an HTML file from the VFS in a preview pane','files',1],
+['printf','Formatted print (%s, %d, %f, \u005Cn, \u005Ct)','files',1],
+['put','Create or overwrite a file','files',1],
+['pwd','Print current working directory','files',1],
+['rm','Remove a file (moved to trash); use -r/-rf for directories','files',1],
+['rmdir','Remove a directory','files',1],
+['script','Run a shell script from VFS','files',1],
+['sed','Stream editor; s/pat/rep/[g][i][p], /pat/d, Nd, $d; -i write in place; -n quiet mode','files',1],
+['seq','Generate sequence of numbers','files',1],
+['session-delete','Delete a saved session','files',1],
+['session-export','Terminal command','files',1],
+['session-import','Terminal command','files',1],
+['session-list','List all saved sessions','files',1],
+['session-load','Load a saved session','files',1],
+['session-new','Start a fresh session (auto-saves current, clears AI context)','files',1],
+['session-save','Save current session (path + terminal history)','files',1],
+['set','List all shell variables','files',1],
+['sh','script','files',1],
+['sleep','Delay execution with countdown','files',1],
+['sort','Sort lines of a file alphabetically','files',1],
+['tail','Show last N lines; -f follows live changes (Ctrl+C/Esc to stop)','files',1],
+['tar','Bundle a VFS directory into a tar archive (gzip if .gz)','files',1],
+['touch','Create empty file or update timestamp','files',1],
+['trash','Move a file to trash','files',1],
+['trash-dir','Move a directory to trash','files',1],
+['tree','Display directory structure as a tree','files',1],
+['uniq','Filter adjacent duplicate lines from a file','files',1],
+['unset','Remove a shell variable','files',1],
+['untar','Extract a tar archive into VFS (auto-detects gzip)','files',1],
+['upload','Upload a file from your device','files',1],
+['vfs-export','Export the entire virtual filesystem as JSON','files',1],
+['vfs-import','Import a previously exported VFS JSON file','files',1],
+['vfs-size','Terminal command','files',1],
+['wc','Count lines, words, and bytes','files',1],
+['wget','Download a URL and save to VFS','files',1],
+['which','Locate a command in the module registry','files',1],
+['whoami','Show current user name','files',1],
+['yes','no','files',1],
+['extract','Extract readable article content (title + body text) from a URL','network',1],
+['fetch','Fetch URL (raw HTML/text); --post enables POST with body, --type sets Content-Type, --r...','network',1],
+['images','Search for images','network',1],
+['s','No special action needed','network',1],
+['search','Terminal command','network',1],
+['videos','Search for videos','network',1],
+['webdav-backup','Backup entire VFS to WebDAV as a dated JSON snapshot','network',1],
+['webdav-backup-list','List available backup files on WebDAV','network',1],
+['webdav-browser','Modern WebDAV file-tree browser with bulk operations','network',1],
+['webdav-config','Configure WebDAV. No args = auto-detect from current page URL','network',1],
+['webdav-login','Open the login panel (Telegram or password) in THIS browser and configure WebDAV','network',1],
+['webdav-ls','List files/directories on the WebDAV remote','network',1],
+['webdav-mkdir','Create a remote directory','network',1],
+['webdav-move','Alias for webdav-rename','network',1],
+['webdav-pull','Download a WebDAV file to VFS','network',1],
+['webdav-push','Upload a VFS file to WebDAV','network',1],
+['webdav-rename','Rename or move a remote file/dir','network',1],
+['webdav-restore','Restore VFS from a WebDAV backup file','network',1],
+['webdav-rm','Delete a remote file or directory','network',1],
+['webdav-status','Show current WebDAV configuration status','network',1],
+['alias','List, set, or show aliases (usage: alias [name=value])','system',1],
+['bug-report','Generate a markdown bug report to /tmp/ for debugging','system',1],
+['checkpoint','Create a VFS snapshot (name defaults to ISO timestamp)','system',1],
+['checkpoint-del','Delete a VFS checkpoint','system',1],
+['checkpoint-list','List all VFS checkpoints','system',1],
+['clear','Terminal command','system',1],
+['cmd-allow','Terminal command','system',1],
+['cmd-deny','Terminal command','system',1],
+['config','Show all config or a specific key','system',1],
+['config-delete','Delete a configuration key','system',1],
+['config-export','Export all config as JSON','system',1],
+['config-list','List all configuration keys','system',1],
+['config-reset','Reset all configuration to defaults','system',1],
+['config-set','Set a configuration value','system',1],
+['cron-clear','Stop all cron jobs','system',1],
+['cron-every','Schedule a command to run every N seconds','system',1],
+['cron-list','List all active cron jobs','system',1],
+['cron-stop','Stop a specific cron job','system',1],
+['dashboard','Terminal command','system',1],
+['debug-analyze','Deep analysis of a specific error','system',1],
+['debug-fix','Suggest and optionally apply fix for an error','system',1],
+['debug-health','Check supervisor module health status','system',1],
+['debug-history','Show last N errors (default: 20)','system',1],
+['debug-stats','Show error summary (total, unique, clusters, top issues)','system',1],
+['debug-sync','Sync errors to backend API (or set sync URL)','system',1],
+['debug-sync-url','View or set the backend sync endpoint','system',1],
+['debug-trends','Error frequency over time (default: 7)','system',1],
+['doctor','Run all health checks, rank issues, show top 3 warnings','system',1],
+['errors','Show last n ERROR log entries (default: 20)','system',1],
+['factory-reset','Alias for reset all','system',1],
+['factory-reset-old','Terminal command','system',1],
+['font-size','Set terminal font size (persists across sessions)','system',1],
+['gui','Show the GUI builder overview','system',1],
+['gui-button','Add a clickable button','system',1],
+['gui-clear','Clear all GUI elements','system',1],
+['gui-input','Add a text input field','system',1],
+['gui-run','Run a terminal command from the GUI','system',1],
+['gui-text','Add a text element','system',1],
+['health-check','Audit VFS size, modules, logs, trash, skills, tool failures','system',1],
+['help','Show all commands or usage for a specific command','system',1],
+['history','Terminal command','system',1],
+['learn-skill','Reflect on topic, draft a skill from experience','system',1],
+['listmods','List all loaded modules with status','system',1],
+['load-local','Terminal command','system',1],
+['loadlocal','Terminal command','system',1],
+['loadmod','Load a module from a URL','system',1],
+['logrotate','Rotate current.log to a dated archive (auto-cleans old)','system',1],
+['logs','Show last n log entries (optionally filtered by level: INFO/WARN/ERROR)','system',1],
+['mem','Show memory usage (heap + localStorage + VFS)','system',1],
+['memory-map-export','Export memory index to /memory/reference.md (overwrites file)','system',1],
+['module-disable','Disable a module from auto-loading on refresh (persists)','system',1],
+['module-enable','Re-enable a previously disabled module','system',1],
+['module-info','Show module details: path, status, size, type, source, commands list','system',1],
+['module-list','List loaded modules grouped by category. Flags: --flat, --core, --ext, --foundation, --...','system',1],
+['module-load','Mark a lazy module as loaded','system',1],
+['module-reload','Unload then reload a module (shows diff)','system',1],
+['module-reset','Reset a module to a clean state (clears its state, keeps commands)','system',1],
+['module-stats','Show aggregate module statistics (loaded/unloaded/lazy/failed/disabled + total size)','system',1],
+['module-unload','Mark a module as unloaded','system',1],
+['modules','Open the module manager GUI','system',1],
+['modules-list','List all available modules from the module index','system',1],
+['monitor','Toggle auto-monitoring (checks every 60s)','system',1],
+['predict','Predict task duration, tool turns, and confidence','system',1],
+['predictor-config','Tune: confidence-threshold, min-data-points','system',1],
+['predictor-status','Model accuracy, data points, prediction count','system',1],
+['removemod','Remove a loaded module by name','system',1],
+['reset','Global reset command (default: mem)','system',1],
+['reset-vfs','Alias for reset vfs','system',1],
+['rollback','Restore VFS from a checkpoint','system',1],
+['sandbox-config','Tune: max-workers, min-workers, pool-timeout','system',1],
+['sandbox-run','Run a task in the sandbox (automatic routing)','system',1],
+['sandbox-status','Show sandbox pool health and task metrics','system',1],
+['secret-del','Remove a stored secret','system',1],
+['secret-get','Decrypt and display a secret value','system',1],
+['secret-list','List all stored secret names','system',1],
+['secret-lock','Lock the vault (clear derived key from memory)','system',1],
+['secret-set','Encrypt and store a secret','system',1],
+['secret-setpin','Set or change the vault PIN code','system',1],
+['secret-status','Show vault status (locked/unlocked/pin set/open mode)','system',1],
+['secret-unlock','Unlock the vault with a PIN code','system',1],
+['security','safe','system',1],
+['security-destructive','Terminal command','system',1],
+['security-flag','Terminal command','system',1],
+['security-level','Terminal command','system',1],
+['security-system','Terminal command','system',1],
+['security-whitelist','Terminal command','system',1],
+['server','Add a server to monitor','system',1],
+['server-check','Check a server status','system',1],
+['server-remove','Remove a server','system',1],
+['servers','List all monitored servers','system',1],
+['setfont','Alias for font-size','system',1],
+['skill-audit','Audit skills for stale, duplicate, and broken references','system',1],
+['skill-create','Create a new skill','system',1],
+['skill-delete','Delete a skill','system',1],
+['skill-export','Export a skill as JSON','system',1],
+['skill-import','Import a skill from JSON string','system',1],
+['skill-list','List all skills, optionally filtered by category','system',1],
+['skill-pack-core','Seed and manage built-in core skills (navigation, memory, search, modules, backup, agen...','system',1],
+['skill-patch','Replace a skill\u2019s full content','system',1],
+['skill-restore','Restore an archived skill','system',1],
+['skill-sync','Rebuild skills index from /skills/ directory','system',1],
+['skill-validate','Validate skill structure and get confidence score','system',1],
+['skill-view','View a skill\u2019s full content','system',1],
+['skill-webdav-sync','Push all skills to WebDAV as JSON files','system',1],
+['smart-prompt','Toggle context-aware prompt (shows name, skills, sessions, memory, edits)','system',1],
+['startup-modules','Terminal command','system',1],
+['status','Display system status (network, files, modules, Ollama)','system',1],
+['sysmsg','Toggle system/warning/error/info message visibility','system',1],
+['system-health','Show tool latency, module load times, VFS size, and error rates','system',1],
+['test-net','Check proxy API, Ollama, and internet connectivity','system',1],
+['unalias','Remove a user-defined alias (usage: unalias <name>)','system',1],
+['uptime','Show time since page load + last save time','system',1],
+['usage','Terminal command','system',1],
+['version','Show version, build date, and cache key','system',1],
+['vfs','Terminal command','system',1],
+['vfs-clean','Terminal command','system',1],
+['analyze','Analyze image/audio/video. Flags: --frames N, --spectrogram, --beats, --scene','tools',1],
+['calc','Evaluate expressions or convert between units','tools',1],
+['js','Evaluate JavaScript in page context','tools',1],
+['js-run','Load and execute a JS file from VFS','tools',1],
+['mindmap','Create, edit, visualize mindmaps. v4.5.44: multi-mindmap, find, move, undo, import, mer...','tools',1],
+['node','Alias for js-run (executes a JS file from VFS)','tools',1],
+['speak','Text-to-speech. No args = toggle auto-speak for AI responses','tools',1],
+['three','3D scene builder (Three.js). Run `three help` for full list.','tools',1],
+['tutorial','Interactive guided tour of newOS4 (6 quests)','tools',1],
+['voice','Start voice recording (Whisper STT), or type "voice stop" to cancel','tools',1],
+['wpm','Web Package Manager for installing and managing modules','tools',1],
+['floating-add','Add a floating UI element','ui',1],
+['floating-clear','Remove all floating elements','ui',1],
+['floating-list','Show all floating elements','ui',1],
+['floating-pos','Reposition a floating element','ui',1],
+['floating-remove','Remove a floating element','ui',1],
+['floating-toggle','Show/hide a floating element','ui',1],
+['kanban','Manage tasks on a kanban board (todo, doing, done columns)','ui',1],
+['theme','Manage and preview visual themes','ui',1],
+];
+var KNOWN = {}, AUTO = {};
+CMDS.forEach(function(c){ KNOWN[c[0]] = 1; AUTO[c[0]] = c[3]; });
+
+/* ───────── state ───────── */
+var state = { type:'btn', items:[{label:'List',command:'ls'},{label:'Trash',command:'ls-trash'}], collection:[] };
+
+/* ───────── helpers ───────── */
+function q(s){ return /\s/.test(s) ? '"'+s+'"' : s; }
+function slug(s){
+ var t = (s||'').toLowerCase().replace(/[^\w\s-]/g,'').trim().replace(/\s+/g,'-');
+ return t || '';
+}
+function typo(s){ return (s||'').replace(/"/g,'”').replace(/'/g,'’'); }
+function toast(msg){
+ var t = $('toast'); t.textContent = msg; t.classList.add('show');
+ clearTimeout(t._h); t._h = setTimeout(function(){ t.classList.remove('show'); }, 1800);
+}
+function copyText(text, msg){
+ var done = function(){ toast(msg || 'Copied!'); };
+ if (navigator.clipboard && navigator.clipboard.writeText) {
+ navigator.clipboard.writeText(text).then(done, function(){ fallback(); });
+ } else { fallback(); }
+ function fallback(){
+ var ta = document.createElement('textarea');
+ ta.value = text; ta.style.position='fixed'; ta.style.opacity='0';
+ document.body.appendChild(ta); ta.select();
+ try { document.execCommand('copy'); done(); } catch(e){ toast('Copy failed β€” select manually'); }
+ document.body.removeChild(ta);
+ }
+}
+function val(cls, msg){
+ var v = $('out-val'); v.className = 'val ' + cls; v.textContent = msg;
+}
+function fail(msg){
+ val('err', msg); $('out-code').textContent = 'β€”'; state.lastCmd = '';
+}
+
+/* ───────── builder ───────── */
+var EMOJIS = ['πŸ†•','βœ…','βš™οΈ','🌐','πŸ“‹','πŸ—‚οΈ','πŸ“','🧠','πŸ–₯️','πŸ“Š','πŸ”','πŸ”§','πŸš€','πŸ’Ύ','πŸ”','⚑','🎨','🧹','⏹️','❀️','πŸ€–','πŸ’¬','πŸ§ͺ','☁️'];
+
+function buildEmojiChips(){
+ ['emoji-chips','emoji-chips2'].forEach(function(cid){
+ var box = $(cid); box.innerHTML = '';
+ EMOJIS.forEach(function(e){
+ var b = document.createElement('button'); b.textContent = e;
+ b.onclick = function(){
+ var input = cid === 'emoji-chips' ? $('btn-label') : $('menu-label');
+ var v = input.value.trim();
+ var rest = v;
+ if (v && v.charCodeAt(0) >= 0x2190) rest = v.replace(/^[^\x00-\x7F]+[ \t]*/, '');
+ input.value = e + (rest ? ' ' + rest : '');
+ syncId(); generate();
+ };
+ box.appendChild(b);
+ });
+ });
+}
+
+function currentForm(){
+ if (state.type === 'btn') return { label:$('btn-label').value.trim(), id:$('btn-id').value.trim() };
+ if (state.type === 'menu') return { label:$('menu-label').value.trim(), id:$('menu-id').value.trim() };
+ return { label:$('panel-label').value.trim(), id:$('panel-id').value.trim() };
+}
+function syncId(){
+ var f = currentForm();
+ var idIn = state.type==='btn' ? $('btn-id') : state.type==='menu' ? $('menu-id') : $('panel-id');
+ var s = slug(f.label);
+ if (!idIn._dirty || !idIn.value) idIn.value = s ? s + (state.type==='menu' ? '-menu' : state.type==='panel' ? '-panel' : '') : '';
+}
+function markDirty(ev){ ev.target._dirty = true; }
+
+function itemRow(it, idx){
+ var row = document.createElement('div'); row.className = 'menu-item-row';
+ var l = document.createElement('input'); l.type='text'; l.placeholder='Label'; l.value = it.label;
+ var c = document.createElement('input'); c.type='text'; c.placeholder='Command (e.g. ls)'; c.value = it.command;
+ var x = document.createElement('button'); x.className='btn btn-red btn-sm'; x.textContent='βœ•';
+ l.oninput = function(){ it.label = l.value; generate(); };
+ c.oninput = function(){ it.command = c.value; generate(); };
+ l.onfocus = c.onfocus = function(){ state.focusItem = idx; };
+ x.onclick = function(){
+ state.items = state.items.filter(function(r){ return r !== it; });
+ renderItems(); generate();
+ };
+ row.appendChild(l); row.appendChild(c); row.appendChild(x);
+ return row;
+}
+function renderItems(){
+ var box = $('menu-items'); box.innerHTML = '';
+ state.items.forEach(function(it, i){ box.appendChild(itemRow(it, i)); });
+}
+$('menu-add-item').onclick = function(){
+ state.items.push({label:'', command:''});
+ state.focusItem = state.items.length - 1;
+ renderItems(); generate();
+ var rows = $('menu-items').querySelectorAll('.menu-item-row input');
+ if (rows.length) rows[rows.length-2].focus();
+};
+
+/* tabs */
+$('type-tabs').querySelectorAll('.tab').forEach(function(t){
+ t.onclick = function(){
+ $('type-tabs').querySelectorAll('.tab').forEach(function(x){ x.classList.remove('active'); });
+ t.classList.add('active');
+ state.type = t.dataset.type;
+ $('form-btn').style.display = state.type==='btn' ? '' : 'none';
+ $('form-menu').style.display = state.type==='menu' ? '' : 'none';
+ $('form-panel').style.display = state.type==='panel' ? '' : 'none';
+ syncId(); generate();
+ if (state.type === 'btn') $('btn-label').focus();
+ else if (state.type === 'menu') $('menu-label').focus();
+ else $('panel-label').focus();
+ };
+});
+
+/* ───────── generator + validation (mirrors FloatingModule._cmdAdd) ───────── */
+function validateCmd(cmd){
+ var w = (cmd || '').split(/\s+/)[0];
+ if (!w) return { level:'err', msg:'Command is empty' };
+ if (!KNOWN[w]) return { level:'warn', msg:'⚠ "'+w+'" is NOT a known terminal command β€” clicking will route it to the AI' };
+ return { level:'ok', msg:'βœ“ "'+w+'" is a real terminal command' };
+}
+function generate(){
+ var f = currentForm();
+ var cmd = '', notes = [];
+ if (!f.id || /[\s"']/.test(f.id)) { fail('βœ— ID is required and must be a single word β€” no spaces or quote characters'); return; }
+ if (!f.label) notes.push('label is empty');
+
+ if (state.type === 'btn') {
+ if (/["']/.test($('btn-cmd').value.trim())) { fail('βœ— Commands cannot contain quote characters (they break terminal tokenizing) β€” rephrase the command'); return; }
+ cmd = 'floating-add btn '+f.id+' "'+typo(f.label)+'" '+$('btn-cmd').value.trim();
+ var v = validateCmd($('btn-cmd').value.trim());
+ if (v.level==='err'){ fail('βœ— '+v.msg); return; }
+ if (v.level==='warn') notes.push(v.msg);
+ if (notes.length===0) val('ok', v.msg+' β€” ready to install');
+ else val('warn', notes.join(' Β· '));
+ }
+ else if (state.type === 'menu') {
+ if (state.items.length === 0){ fail('βœ— Menu needs at least one item'); return; }
+ var parts = [];
+ for (var i=0;i<state.items.length;i++){
+ var it = state.items[i];
+ if (!it.label || !it.command){ fail('βœ— Item '+(i+1)+': BOTH label and command are required (one-colon items get dropped by the parser)'); return; }
+ if (it.label.indexOf(':') !== -1){ fail('βœ— Item '+(i+1)+': label must not contain ":"'); return; }
+ if (/["']/.test(it.command)){ fail('βœ— Item '+(i+1)+': commands cannot contain quote characters β€” rephrase it'); return; }
+ parts.push('btn:'+q(typo(it.label))+':'+q(it.command));
+ var vc = validateCmd(it.command);
+ if (vc.level !== 'ok') notes.push('item "'+it.label+'": '+vc.msg);
+ }
+ cmd = 'floating-add menu '+f.id+' "'+typo(f.label)+'" '+parts.join(' ');
+ if (notes.length) val('warn', notes.join(' Β· '));
+ else val('ok','βœ“ all ' + state.items.length + ' item commands are real, auto-loaded commands β€” ready to install');
+ }
+ else {
+ cmd = 'floating-add panel '+f.id+' "'+typo(f.label)+'" "'+typo($('panel-content').value.trim().replace(/\s*\n\s*/g,' '))+'"';
+ if (notes.length) val('warn', notes.join(' Β· ')); else val('ok','βœ“ panel ready (markdown-lite supported)');
+ }
+ $('out-code').textContent = cmd;
+ state.lastCmd = cmd;
+ renderPreview();
+}
+
+/* ───────── preview ───────── */
+function renderPreview(){
+ var fl = $('float-layer'); fl.innerHTML = '';
+ var f = currentForm();
+ if (state.type === 'btn') {
+ var b = document.createElement('button'); b.className='fbtn draft'; b.textContent = f.label || '?';
+ b.onclick = function(){ toast('β†’ would run: '+$('btn-cmd').value.trim()); };
+ fl.appendChild(b);
+ } else if (state.type === 'menu') {
+ var m = document.createElement('div'); m.className = 'fmenu open';
+ var it = document.createElement('div'); it.className='fmenu-items';
+ state.items.forEach(function(s){
+ var sb = document.createElement('button'); sb.className='fsub'; sb.textContent = s.label || '?';
+ sb.onclick = function(ev){ ev.stopPropagation(); toast('β†’ would run: '+s.command); };
+ it.appendChild(sb);
+ });
+ var h = document.createElement('button'); h.className='fmenu-head draft'; h.textContent = f.label || '?';
+ h.onclick = function(){ m.classList.toggle('open'); };
+ m.appendChild(it); m.appendChild(h); fl.appendChild(m);
+ } else {
+ var p = document.createElement('div'); p.className='fpanel';
+ var t = document.createElement('b'); t.textContent = f.label || '?';
+ var c = document.createElement('span'); c.textContent = $('panel-content').value || '…';
+ p.appendChild(t); p.appendChild(c); fl.appendChild(p);
+ }
+}
+
+/* ───────── palette ───────── */
+function renderPalette(filter){
+ var g = $('pal-grid'); g.innerHTML = '';
+ CMDS.forEach(function(c){
+ if (filter && (c[0]+' '+c[1]+' '+c[2]).toLowerCase().indexOf(filter) === -1) return;
+ var d = document.createElement('div'); d.className='pal-cmd';
+ var auto = c[3] ? 'βœ“' : '⚠';
+ d.innerHTML = '<span class="cat">'+c[2]+'</span>'+auto+' <code>'+c[0]+'</code><small>'+c[1]+'</small>';
+ d.onclick = function(){
+ if (state.type === 'btn') { $('btn-cmd').value = c[0]; }
+ else if (state.type === 'menu' && state.items.length) {
+ var idx = (typeof state.focusItem === 'number' && state.focusItem < state.items.length) ? state.focusItem : state.items.length - 1;
+ state.items[idx].command = c[0]; renderItems();
+ }
+ else if (state.type === 'panel') { toast('Panels show text, not commands'); return; }
+ generate();
+ };
+ g.appendChild(d);
+ });
+ if (!g.children.length) g.innerHTML = '<div style="color:var(--muted);font-size:12px">No matching commands</div>';
+}
+$('pal-search').oninput = function(){ renderPalette($('pal-search').value.trim().toLowerCase()); };
+
+/* ───────── presets ───────── */
+var PRESETS = [
+ ['πŸ—‚οΈ Files menu','list Β· trash Β· concept tree (this one is live in your UI)','floating-add menu files-menu "πŸ—‚οΈ Files" btn:List:ls btn:Trash:ls-trash btn:Tree:nvfs-tree'],
+ ['🧠 AI menu','ask · clear · context · debug','floating-add menu ai-menu "🧠 AI" btn:Ask:ai btn:Clear:ai-clear btn:Context:ai-context btn:Debug:debug'],
+ ['πŸ–₯️ System menu','status Β· mem Β· logs Β· help','floating-add menu sys-menu "πŸ–₯️ System" btn:Status:status btn:Memory:mem btn:Logs:logs btn:Help:help'],
+ ['🌐 Web menu','search · images · fetch · extract','floating-add menu web-menu "🌐 Web" btn:Search:search btn:Images:images btn:Fetch:fetch btn:Extract:extract'],
+ ['πŸ“Š Status panel','markdown-lite panel','floating-add panel status-p "πŸ“Š Status" "newOS4 Β· **bold**, *italic* and `code` supported"'],
+ ['βš™οΈ Config button','button with arguments (user-verified)','floating-add btn cfg-timeout "βš™οΈ Timeout" ai-config confirm-timeout 0'],
+ ['πŸ§ͺ Quoted items demo','multi-word label + multi-word command','floating-add menu demo-q "πŸ§ͺ Demo" btn:"My Files":ls btn:Cfg:"ai-config confirm-timeout 0"']
+];
+var CURRENT_SETUP = [
+ 'floating-add btn config-timeout "βš™οΈtimeout" ai-config confirm-timeout 0',
+ 'floating-add btn ai-allow "βœ…Allow" ai-allow',
+ 'floating-add btn new-session "πŸ†•New" new-session',
+ 'floating-add btn webdav-btn "🌐" webdav-browser',
+ 'floating-add btn clipboard "πŸ“‹" clipboard-history',
+ 'floating-add menu files-menu "πŸ—‚οΈ Files" btn:List:ls btn:Trash:ls-trash btn:Tree:nvfs-tree'
+];
+function renderPresets(){
+ var box = $('presets'); box.innerHTML = '';
+ PRESETS.forEach(function(p){
+ var b = document.createElement('button'); b.className = 'preset';
+ b.innerHTML = '<b>'+p[0]+'</b><small>'+p[1]+'</small>';
+ b.title = p[2];
+ b.onclick = function(){ $('import-area').value = p[2]; parseImport(); };
+ box.appendChild(b);
+ });
+}
+$('load-current').onclick = function(){
+ $('import-area').value = CURRENT_SETUP.join('\n');
+ parseImport();
+ toast('Note: "new-session" and "clipboard-history" are not real commands β€” they route to the AI; consider "session-new" or "floating-list"');
+};
+
+/* ───────── import (mirrors the real parser) ───────── */
+function tokenize(line){
+ var toks=[], cur='', qq=null;
+ for (var i=0;i<line.length;i++){
+ var ch = line[i];
+ if (qq){ if (ch===qq){ qq=null; } else { cur += ch; } }
+ else if (ch==='"'||ch==="'"){ qq = ch; }
+ else if (/\s/.test(ch)){ if (cur){ toks.push(cur); cur=''; } }
+ else { cur += ch; }
+ }
+ if (cur) toks.push(cur);
+ return toks;
+}
+function parseFA(line){
+ var t = tokenize(line);
+ if (t.length < 4 || t[0] !== 'floating-add') return null;
+ var ty = t[1];
+ if (ty === 'btn' || ty === 'button') return { type:'btn', id:t[2], label:t[3], cmd:t.slice(4).join(' ') };
+ if (ty === 'menu'){
+ var items=[], buf='';
+ for (var i=4;i<t.length;i++){
+ buf = buf ? buf+' '+t[i] : t[i];
+ var f1 = buf.indexOf(':');
+ if (f1 === -1){ buf=''; continue; }
+ var f2 = buf.indexOf(':', f1+1);
+ if (f2 === -1) continue; // wait for command (exactly like the module)
+ if (buf.slice(0,f1) !== 'btn'){ buf=''; continue; }
+ var l = buf.slice(f1+1,f2), c = buf.slice(f2+1);
+ if (l && c) items.push({label:l, command:c});
+ buf = '';
+ }
+ return { type:'menu', id:t[2], label:t[3], items:items };
+ }
+ if (ty === 'panel') return { type:'panel', id:t[2], label:t[3], content:t.slice(4).join(' ') };
+ return null;
+}
+function parseImport(){
+ var lines = $('import-area').value.split('\n').filter(function(l){ return l.trim(); });
+ if (!lines.length){ toast('Nothing to parse'); return; }
+ var first = parseFA(lines[0].replace(/^[>$]\s+/, ''));
+ if (!first){ val('err','βœ— Not a valid floating-add line'); toast('Parse failed'); return; }
+ loadIntoBuilder(first);
+ // remaining lines go straight to collection
+ var added = 0;
+ for (var i=1;i<lines.length;i++){
+ var ln = lines[i].replace(/^[>$]\s+/, '');
+ var fa = parseFA(ln);
+ if (fa) { addToCollection(ln.trim(), false); added++; }
+ }
+ generate(); toast('Loaded into builder β€” ' + (1 + added) + ' of ' + lines.length + ' line(s)');
+}
+function loadIntoBuilder(fa){
+ var tab = document.querySelector('#type-tabs .tab[data-type="'+(fa.type==='btn'?'btn':fa.type==='menu'?'menu':'panel')+'"]');
+ if (tab) tab.click();
+ if (fa.type === 'btn'){ $('btn-label').value = fa.label; $('btn-id').value = fa.id; $('btn-id')._dirty = true; $('btn-cmd').value = fa.cmd; }
+ else if (fa.type === 'menu'){ $('menu-label').value = fa.label; $('menu-id').value = fa.id; $('menu-id')._dirty = true; state.items = fa.items.length ? fa.items : [{label:'',command:''}]; renderItems(); }
+ else { $('panel-label').value = fa.label; $('panel-id').value = fa.id; $('panel-id')._dirty = true; $('panel-content').value = fa.content; }
+}
+$('import-btn').onclick = parseImport;
+
+/* ───────── collection ───────── */
+function addToCollection(cmd, announce){
+ if (state.collection.indexOf(cmd) !== -1){ if (announce !== false) toast('Already in collection'); return; }
+ state.collection.push(cmd);
+ renderCollection();
+ if (announce !== false) toast('Added to collection ('+state.collection.length+')');
+}
+function renderCollection(){
+ var box = $('coll-list'); box.innerHTML = '';
+ $('coll-count').textContent = '(' + state.collection.length + ')';
+ if (!state.collection.length){ var e = document.createElement('div'); e.style.cssText = 'color:var(--muted);font-size:12px;padding:6px 2px'; e.textContent = 'Collection is empty β€” add commands from the form above'; box.appendChild(e); }
+ state.collection.forEach(function(cmd, idx){
+ var row = document.createElement('div'); row.className='item';
+ var c = document.createElement('code'); c.textContent = cmd;
+ var tag = document.createElement('span'); tag.className='tag'; var kind = (cmd.split(' ')[1]||''); tag.textContent = (kind==='menu'||kind==='panel')?kind:'btn';
+ var cp = document.createElement('button'); cp.className='btn btn-ghost btn-sm'; cp.textContent='πŸ“‹';
+ var rm = document.createElement('button'); rm.className='btn btn-red btn-sm'; rm.textContent='βœ•';
+ cp.setAttribute('aria-label', 'Copy command'); rm.setAttribute('aria-label', 'Remove command');
+ cp.onclick = function(){ copyText(cmd, 'Copied command'); };
+ rm.onclick = function(){ state.collection.splice(idx,1); renderCollection(); };
+ row.appendChild(c); row.appendChild(tag); row.appendChild(cp); row.appendChild(rm);
+ var mm = cmd.match(/^floating-add\s+\S+\s+\S+\s+"[^"]*"\s*([^\s]*)/);
+ if (mm && mm[1] && !KNOWN[mm[1]]) { var wn = document.createElement('span'); wn.textContent = '⚠'; wn.title = 'not a known terminal command β€” will route to the AI'; wn.style.color = 'var(--yellow)'; row.appendChild(wn); }
+ box.appendChild(row);
+ });
+}
+$('add-coll').onclick = function(){ if (state.lastCmd) addToCollection(state.lastCmd); else toast('Nothing to add yet'); };
+$('copy-all').onclick = function(){
+ if (!state.collection.length){ toast('Collection is empty'); return; }
+ copyText(state.collection.join('\n'), 'Copied ' + state.collection.length + ' commands');
+};
+$('coll-clear').onclick = function(){ state.collection = []; renderCollection(); };
+$('copy-main').onclick = function(){ var t = state.lastCmd; if (!t){ toast('Nothing to copy yet β€” complete the form'); return; } copyText(t, 'Command copied'); };
+$('install-now').onclick = function(){ var t = state.lastCmd; if (!t){ toast('Nothing to copy yet β€” complete the form'); return; } copyText(t, 'Copied β€” now paste it in the newOS4 terminal and press Enter'); };
+
+/* wire inputs */
+[['btn-label','btn-id'],['menu-label','menu-id'],['panel-label','panel-id']].forEach(function(pair){
+ $(pair[0]).oninput = function(){ syncId(); generate(); };
+ $(pair[1]).oninput = markDirty;
+});
+$('btn-cmd').oninput = generate;
+$('panel-content').oninput = generate;
+
+/* init */
+buildEmojiChips();
+renderItems();
+renderPresets();
+renderPalette('');
+renderCollection();
+generate();
+})();
+</script>
+
+</body></html> \ No newline at end of file