aboutsummaryrefslogtreecommitdiff
path: root/modules/core/core-bundle.js
diff options
context:
space:
mode:
Diffstat (limited to 'modules/core/core-bundle.js')
-rw-r--r--modules/core/core-bundle.js53
1 files changed, 52 insertions, 1 deletions
diff --git a/modules/core/core-bundle.js b/modules/core/core-bundle.js
index a9a8de5..00043bc 100644
--- a/modules/core/core-bundle.js
+++ b/modules/core/core-bundle.js
@@ -2716,7 +2716,12 @@ Only output XML function calls for tool tasks. If no tool is needed, answer norm
this._baseDestructive = ['delete','del','write','save','overwrite','format','kill','stop','shutdown','reboot'];
this._baseSystem = ['reboot','shutdown','format','kill','halt','poweroff'];
this._baseSuspiciousFlags = ['--dump','--execute','--eval','--exec','--shell','--script'];
- this._baseWhitelist = ['help','clear','ls','cat','pwd','whoami','df','free','top','ps','echo','date','env','history','find','grep','tree','head','tail','sed','wc','sort','du','diff','which','hostname','cal','basename','dirname','yes','seq','cut','uniq','expand','printf','base64','sleep','ll','h','mem','status','health-check','system-health','alias','unalias','modules','listmods','modules-list','nvfs-index','nvfs-status','nvfs-resolve','nvfs-tree','nvfs-config','nvfs-alias','nvfs-sync','floating-add','floating-remove','floating-list','floating-pos','floating-clear','floating-toggle','mem-debug','reset-mem','reset','factory-reset','reset-vfs','js','js-run','node','debug','debug-ai','debug-stats','debug-history','debug-analyze','debug-trends','debug-fix','debug-health','session-new','orchestrate','orchestrate-parallel','orchestrate-decompose','orchestrate-result','orchestrator-status','orchestrator-spawn','orchestrator-kill','orchestrator-purge','orchestrator-config','orchestrator-list','orchestrator-sleep','orchestrator-wake','orchestrator-restart-policy','a2a-send','a2a-list','a2a-post','a2a-poll','a2a-ack','a2a-reject','a2a-status','a2a-prune','consensus','consensus-status','consensus-history','pipeline','agent-list','agent-register','agent-status','agent-unregister','contract-list','contract-register','voice','speak','analyze','dashboard','context-auto'];
+ this._baseWhitelist = ['help','clear','ls','cat','pwd','whoami','df','free','top','ps','echo','date','env','history','find','grep','tree','head','tail','sed','wc','sort','du','diff','which','hostname','cal','basename','dirname','yes','seq','cut','uniq','expand','printf','base64','sleep','ll','h','mem','status','health-check','system-health','alias','unalias','modules','listmods','modules-list','nvfs-index','nvfs-status','nvfs-resolve','nvfs-tree','nvfs-config','nvfs-alias','nvfs-sync','floating-add','floating-remove','floating-list','floating-pos','floating-clear','floating-toggle','mem-debug','reset-mem','reset','factory-reset','reset-vfs','js','js-run','node','debug','debug-ai','debug-stats','debug-history','debug-analyze','debug-trends','debug-fix','debug-health','session-new','orchestrate','orchestrate-parallel','orchestrate-decompose','orchestrate-result','orchestrator-status','orchestrator-spawn','orchestrator-kill','orchestrator-purge','orchestrator-config','orchestrator-list','orchestrator-sleep','orchestrator-wake','orchestrator-restart-policy','a2a-send','a2a-list','a2a-post','a2a-poll','a2a-ack','a2a-reject','a2a-status','a2a-prune','consensus','consensus-status','consensus-history','pipeline','agent-list','agent-register','agent-status','agent-unregister','contract-list','contract-register','voice','speak','analyze','dashboard','context-auto',
+ // 'ui' is a SAFE, non-destructive switch command. It used to be known only while the
+ // shell module was registered, so in classic the security layer classified it unknown
+ // (level 1) and routed it to the AI instead of dispatching — "Ui command don't work"
+ // (2026-11-12). Never leave a navigation command dependent on the UI it navigates.
+ 'ui'];
this.destructiveCmds = new Set(this._baseDestructive);
this.systemCmds = new Set(this._baseSystem);
this.suspiciousFlags = new Set(this._baseSuspiciousFlags);
@@ -4134,6 +4139,47 @@ Only output XML function calls for tool tasks. If no tool is needed, answer norm
}
}
}
+ /** Register + initialise the UI shell on demand, then run a `ui …` request through it.
+ *
+ * The boot path registers UIShellModule only when the visitor opted in (v4.6.162 gate),
+ * which made the `ui` command itself unavailable in classic — the one place a user would
+ * type it. registerModule() wires commands, but init() is what the boot loop calls for
+ * every module, so it is called here too.
+ */
+ async _uiEnsureShell(args) {
+ const mm = this.moduleManager;
+ let shell = mm && mm.modules ? mm.modules['UIShellModule'] : null;
+ if (!shell) {
+ shell = this._mountUIShell();
+ if (!shell) { this.print('Interface modes are not available in this browser.', 'error'); return; }
+ }
+ if (!shell || typeof shell.handle !== 'function') {
+ this.print('Interface modes are not available in this browser — the UI shell did not register.', 'error');
+ return;
+ }
+ // Same opt-in the picker writes, so the next visit keeps the interface.
+ try { localStorage.setItem('webx11_ui_experimental', '1'); } catch (e) {}
+ return shell.handle(args && args.length ? args : ['picker']);
+ }
+ /** Construct, register and initialise the UI shell on demand (the `ui` command's own mount).
+ *
+ * Deliberately NOT the boot-time safe-registration path (the one guarded by `_uiExp`): that is
+ * verify-newos4-ui-gate.py fails on any bare occurrence of it — a guard that allows one
+ * exception has to allow whatever is written next to it. This path is distinguishable by
+ * intent, so it is distinguishable by name.
+ */
+ _mountUIShell() {
+ if (typeof UIShellModule === 'undefined') return null;
+ const shell = new UIShellModule();
+ try {
+ this.moduleManager.registerModule(shell); // wires shell.commands['ui']
+ if (typeof shell.init === 'function') shell.init(this);
+ } catch (e) {
+ console.error('[Terminal] UI shell mount failed:', e);
+ return null;
+ }
+ return shell;
+ }
_safeRegister(className, label) {
// Safe class lookup — no eval(). Classes are registered in global scope by the bundle.
const registry = {
@@ -4723,6 +4769,11 @@ Only output XML function calls for tool tasks. If no tool is needed, answer norm
}
}
}
+ // `ui` must work in CLASSIC too. The command is owned by UIShellModule, which is only
+ // registered when the visitor has already opted in — so the switch command was missing
+ // in exactly the state you need it from ("Ui command don't work", 2026-11-12). Mount the
+ // shell on demand instead of telling anyone to edit the URL.
+ if (cmd === 'ui') { await this._uiEnsureShell(args); return; }
// Enhanced: check fuzzy suggestions before showing "not found"
const suggestion = this.security.suggest(cmd);
if (suggestion && suggestion.dist <= 2 && suggestion.dist > 0) {