let-them-talk 5.3.0 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -1
- package/README.md +158 -592
- package/SECURITY.md +3 -3
- package/USAGE.md +151 -0
- package/agent-contracts.js +447 -0
- package/api-agents.js +760 -0
- package/autonomy/decision-v2.js +380 -0
- package/autonomy/watchdog-policy.js +572 -0
- package/cli.js +454 -298
- package/conversation-templates/autonomous-feature.json +83 -22
- package/conversation-templates/code-review.json +69 -21
- package/conversation-templates/debug-squad.json +69 -21
- package/conversation-templates/feature-build.json +69 -21
- package/conversation-templates/research-write.json +69 -21
- package/dashboard.html +3148 -174
- package/dashboard.js +823 -786
- package/data-dir.js +58 -0
- package/docs/architecture/branch-semantics.md +157 -0
- package/docs/architecture/canonical-event-schema.md +88 -0
- package/docs/architecture/markdown-workspace.md +183 -0
- package/docs/architecture/runtime-contract.md +459 -0
- package/docs/architecture/runtime-migration-hardening.md +64 -0
- package/events/hooks.js +154 -0
- package/events/log.js +457 -0
- package/events/replay.js +33 -0
- package/events/schema.js +432 -0
- package/managed-team-integration.js +261 -0
- package/office/agents.js +704 -597
- package/office/animation.js +1 -1
- package/office/assets/arcade-cabinet.js +141 -0
- package/office/assets/archway.js +77 -0
- package/office/assets/bar-counter.js +91 -0
- package/office/assets/bar-stool.js +71 -0
- package/office/assets/beanbag.js +64 -0
- package/office/assets/bench.js +99 -0
- package/office/assets/bollard.js +87 -0
- package/office/assets/cactus.js +100 -0
- package/office/assets/carpet-tile.js +46 -0
- package/office/assets/chair.js +123 -0
- package/office/assets/chandelier.js +107 -0
- package/office/assets/coffee-machine.js +95 -0
- package/office/assets/coffee-table.js +81 -0
- package/office/assets/column.js +95 -0
- package/office/assets/desk-lamp.js +102 -0
- package/office/assets/desk.js +76 -0
- package/office/assets/dining-table.js +105 -0
- package/office/assets/door.js +70 -0
- package/office/assets/dual-monitor.js +72 -0
- package/office/assets/fence.js +76 -0
- package/office/assets/filing-cabinet.js +111 -0
- package/office/assets/floor-lamp.js +69 -0
- package/office/assets/floor-tile.js +54 -0
- package/office/assets/flower-pot.js +76 -0
- package/office/assets/foosball.js +95 -0
- package/office/assets/fridge.js +99 -0
- package/office/assets/gaming-chair.js +154 -0
- package/office/assets/gaming-desk.js +105 -0
- package/office/assets/glass-door.js +72 -0
- package/office/assets/glass-wall.js +64 -0
- package/office/assets/half-wall.js +49 -0
- package/office/assets/hanging-plant.js +112 -0
- package/office/assets/index.js +151 -0
- package/office/assets/indoor-tree.js +90 -0
- package/office/assets/l-sofa.js +153 -0
- package/office/assets/marble-floor.js +64 -0
- package/office/assets/materials.js +40 -0
- package/office/assets/meeting-table.js +88 -0
- package/office/assets/microwave.js +94 -0
- package/office/assets/monitor.js +67 -0
- package/office/assets/neon-strip.js +73 -0
- package/office/assets/painting.js +84 -0
- package/office/assets/palm-tree.js +108 -0
- package/office/assets/pc-tower.js +91 -0
- package/office/assets/pendant-light.js +67 -0
- package/office/assets/ping-pong.js +114 -0
- package/office/assets/plant.js +72 -0
- package/office/assets/planter-box.js +95 -0
- package/office/assets/pool-table.js +94 -0
- package/office/assets/printer.js +113 -0
- package/office/assets/reception-desk.js +133 -0
- package/office/assets/rug.js +78 -0
- package/office/assets/sculpture.js +85 -0
- package/office/assets/server-rack.js +98 -0
- package/office/assets/sink.js +109 -0
- package/office/assets/sofa.js +106 -0
- package/office/assets/speaker.js +83 -0
- package/office/assets/spotlight.js +83 -0
- package/office/assets/street-lamp.js +97 -0
- package/office/assets/trash-can.js +83 -0
- package/office/assets/treadmill.js +126 -0
- package/office/assets/trophy.js +89 -0
- package/office/assets/tv-screen.js +79 -0
- package/office/assets/vase.js +84 -0
- package/office/assets/wall-clock.js +84 -0
- package/office/assets/wall.js +53 -0
- package/office/assets/water-cooler.js +146 -0
- package/office/assets/whiteboard.js +115 -0
- package/office/assets.js +3 -431
- package/office/builder.js +791 -355
- package/office/campus-env.js +1012 -1119
- package/office/environment.js +2 -0
- package/office/gallery.js +997 -0
- package/office/index.js +165 -61
- package/office/navigation.js +173 -152
- package/office/player.js +178 -68
- package/office/robot-character.js +272 -0
- package/office/spectator-camera.js +33 -10
- package/office/state.js +2 -0
- package/office/world-save.js +35 -4
- package/package.json +57 -3
- package/providers/comfyui.js +383 -0
- package/providers/dalle.js +79 -0
- package/providers/gemini.js +181 -0
- package/providers/ollama.js +184 -0
- package/providers/replicate.js +115 -0
- package/providers/zai.js +183 -0
- package/runtime-descriptor.js +270 -0
- package/scripts/check-agent-contract-advisory.js +132 -0
- package/scripts/check-api-agent-parity.js +277 -0
- package/scripts/check-autonomy-v2-decision.js +207 -0
- package/scripts/check-autonomy-v2-execution.js +588 -0
- package/scripts/check-autonomy-v2-watchdog.js +224 -0
- package/scripts/check-branch-fork-snapshot.js +337 -0
- package/scripts/check-branch-isolation.js +787 -0
- package/scripts/check-branch-semantics.js +139 -0
- package/scripts/check-dashboard-control-plane.js +1304 -0
- package/scripts/check-docs-onboarding.js +490 -0
- package/scripts/check-event-schema.js +276 -0
- package/scripts/check-evidence-completion.js +239 -0
- package/scripts/check-invariants.js +992 -0
- package/scripts/check-lifecycle-hooks.js +525 -0
- package/scripts/check-managed-team-integration.js +166 -0
- package/scripts/check-markdown-workspace-export.js +548 -0
- package/scripts/check-markdown-workspace-safety.js +347 -0
- package/scripts/check-markdown-workspace.js +136 -0
- package/scripts/check-message-replay.js +429 -0
- package/scripts/check-migration-hardening.js +300 -0
- package/scripts/check-performance-indexing.js +272 -0
- package/scripts/check-provider-capabilities.js +316 -0
- package/scripts/check-runtime-contract.js +109 -0
- package/scripts/check-session-aware-context.js +172 -0
- package/scripts/check-session-lifecycle.js +210 -0
- package/scripts/export-markdown-workspace.js +84 -0
- package/scripts/fixtures/message-replay/clean.jsonl +2 -0
- package/scripts/fixtures/message-replay/corrupt-correction-payload.jsonl +1 -0
- package/scripts/fixtures/message-replay/corrupt-jsonl.jsonl +1 -0
- package/scripts/fixtures/message-replay/corrupt-payload.jsonl +1 -0
- package/scripts/fixtures/message-replay/out-of-order.jsonl +2 -0
- package/scripts/migrate-legacy-to-canonical.js +201 -0
- package/scripts/run-verification-suite.js +242 -0
- package/scripts/sync-packaged-docs.js +69 -0
- package/server.js +9546 -7216
- package/state/agents.js +161 -0
- package/state/canonical.js +3068 -0
- package/state/dashboard-queries.js +441 -0
- package/state/evidence.js +56 -0
- package/state/io.js +69 -0
- package/state/markdown-workspace.js +951 -0
- package/state/messages.js +669 -0
- package/state/sessions.js +683 -0
- package/state/tasks-workflows.js +92 -0
- package/templates/debate.json +2 -2
- package/templates/managed.json +4 -4
- package/templates/pair.json +2 -2
- package/templates/review.json +2 -2
- package/templates/team.json +3 -3
package/office/index.js
CHANGED
|
@@ -6,6 +6,8 @@ import { initScene } from './scene.js';
|
|
|
6
6
|
import { buildEnvironment, updateTVScreen } from './environment.js';
|
|
7
7
|
import { updateAgent } from './animation.js';
|
|
8
8
|
import { syncAgents, processMessages, walkTo, navigateTo, showBubble } from './agents.js';
|
|
9
|
+
import { tickGallery, updateGalleryScreens } from './gallery.js';
|
|
10
|
+
import { updateRobotAnimation } from './robot-character.js';
|
|
9
11
|
// Side-effect: registers window.officeGetAppearance
|
|
10
12
|
import './appearance.js';
|
|
11
13
|
import { spawnPlayer, despawnPlayer, isPlayerMode, updatePlayer, savePlayerAppearance, getPlayerAppearance, getPlayer, invalidateColliders } from './player.js';
|
|
@@ -26,8 +28,13 @@ function getCityMods() {
|
|
|
26
28
|
}).catch(function(e) { console.warn('City modules failed:', e); });
|
|
27
29
|
return _cityMods;
|
|
28
30
|
}
|
|
29
|
-
function isDriving() { return _cityMods && _cityMods.vehicle && _cityMods.vehicle.isDriving(); }
|
|
30
|
-
function isConnected() { return false; }
|
|
31
|
+
function isDriving() { return _cityMods && _cityMods.vehicle && _cityMods.vehicle.isDriving(); }
|
|
32
|
+
function isConnected() { return false; }
|
|
33
|
+
|
|
34
|
+
function scopedOfficeApiUrl(path, options) {
|
|
35
|
+
if (typeof window.scopedApiUrl === 'function') return window.scopedApiUrl(path, null, options);
|
|
36
|
+
return path;
|
|
37
|
+
}
|
|
31
38
|
|
|
32
39
|
// Expose createCharacter + resolveAppearance for the character designer (Phase 3)
|
|
33
40
|
export { createCharacter } from './character.js';
|
|
@@ -312,29 +319,29 @@ function executeCommand(agentName, action) {
|
|
|
312
319
|
});
|
|
313
320
|
break;
|
|
314
321
|
|
|
315
|
-
case 'send_message':
|
|
316
|
-
showInputOverlay('Send message to ' + agentName + ':', 'Type your message...', function(msg) {
|
|
317
|
-
if (msg && msg.trim()) {
|
|
318
|
-
showBubble(agent, 'Message incoming...');
|
|
319
|
-
fetch('/api/inject'
|
|
320
|
-
method: 'POST',
|
|
321
|
-
headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
|
|
322
|
-
body: JSON.stringify({ to: agentName, content: msg.trim() })
|
|
323
|
-
}).then(function() { showBubble(agent, 'Got it!'); });
|
|
324
|
-
}
|
|
322
|
+
case 'send_message':
|
|
323
|
+
showInputOverlay('Send message to ' + agentName + ':', 'Type your message...', function(msg) {
|
|
324
|
+
if (msg && msg.trim()) {
|
|
325
|
+
showBubble(agent, 'Message incoming...');
|
|
326
|
+
fetch(scopedOfficeApiUrl('/api/inject'), {
|
|
327
|
+
method: 'POST',
|
|
328
|
+
headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
|
|
329
|
+
body: JSON.stringify({ to: agentName, content: msg.trim() })
|
|
330
|
+
}).then(function() { showBubble(agent, 'Got it!'); });
|
|
331
|
+
}
|
|
325
332
|
});
|
|
326
333
|
break;
|
|
327
334
|
|
|
328
|
-
case 'assign_task':
|
|
329
|
-
showInputOverlay('New task for ' + agentName + ':', 'Task title...', function(title) {
|
|
330
|
-
if (title && title.trim()) {
|
|
331
|
-
showBubble(agent, 'New task assigned!');
|
|
332
|
-
fetch('/api/tasks'
|
|
333
|
-
method: 'POST',
|
|
334
|
-
headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
|
|
335
|
-
body: JSON.stringify({ title: title.trim(), assignee: agentName, status: 'pending' })
|
|
336
|
-
});
|
|
337
|
-
}
|
|
335
|
+
case 'assign_task':
|
|
336
|
+
showInputOverlay('New task for ' + agentName + ':', 'Task title...', function(title) {
|
|
337
|
+
if (title && title.trim()) {
|
|
338
|
+
showBubble(agent, 'New task assigned!');
|
|
339
|
+
fetch(scopedOfficeApiUrl('/api/tasks'), {
|
|
340
|
+
method: 'POST',
|
|
341
|
+
headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
|
|
342
|
+
body: JSON.stringify({ title: title.trim(), assignee: agentName, status: 'pending' })
|
|
343
|
+
});
|
|
344
|
+
}
|
|
338
345
|
});
|
|
339
346
|
break;
|
|
340
347
|
|
|
@@ -348,13 +355,13 @@ function executeCommand(agentName, action) {
|
|
|
348
355
|
}
|
|
349
356
|
break;
|
|
350
357
|
|
|
351
|
-
case 'nudge':
|
|
352
|
-
showBubble(agent, 'Hey! Wake up!');
|
|
353
|
-
fetch('/api/inject'
|
|
354
|
-
method: 'POST',
|
|
355
|
-
headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
|
|
356
|
-
body: JSON.stringify({ to: agentName, content: 'Hey ' + agentName + ', the user is waiting for you. Please check for new messages and continue your work.' })
|
|
357
|
-
});
|
|
358
|
+
case 'nudge':
|
|
359
|
+
showBubble(agent, 'Hey! Wake up!');
|
|
360
|
+
fetch(scopedOfficeApiUrl('/api/inject'), {
|
|
361
|
+
method: 'POST',
|
|
362
|
+
headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
|
|
363
|
+
body: JSON.stringify({ to: agentName, content: 'Hey ' + agentName + ', the user is waiting for you. Please check for new messages and continue your work.' })
|
|
364
|
+
});
|
|
358
365
|
break;
|
|
359
366
|
|
|
360
367
|
case 'edit_profile':
|
|
@@ -398,9 +405,15 @@ function animate() {
|
|
|
398
405
|
var time = S.clock.getElapsedTime();
|
|
399
406
|
|
|
400
407
|
for (var name in S.agents3d) {
|
|
401
|
-
|
|
408
|
+
var ag = S.agents3d[name];
|
|
409
|
+
if (!ag) continue;
|
|
410
|
+
updateAgent(ag, dt, time);
|
|
411
|
+
if (ag.isApiAgent && S.agents3d[name]) updateRobotAnimation(ag, dt, time);
|
|
402
412
|
}
|
|
403
413
|
|
|
414
|
+
// Gallery slideshow tick
|
|
415
|
+
if (S.currentEnv === 'campus') tickGallery(dt);
|
|
416
|
+
|
|
404
417
|
// Player avatar mode — skip when driving (vehicle takes over)
|
|
405
418
|
if (isPlayerMode() && S.controls && S.controls.keys && !isDriving()) {
|
|
406
419
|
updatePlayer(dt, time, S.controls.keys);
|
|
@@ -757,6 +770,13 @@ window.office3dStart = function() {
|
|
|
757
770
|
syncAgents();
|
|
758
771
|
processMessages();
|
|
759
772
|
updateTVScreen(S.clock.getElapsedTime());
|
|
773
|
+
// Fetch media for gallery screens
|
|
774
|
+
if (S.galleryScreens) {
|
|
775
|
+
var pq = window.currentProjectPath ? '?project=' + encodeURIComponent(window.currentProjectPath) : '';
|
|
776
|
+
fetch('/api/media' + pq).then(function(r) { return r.json(); }).then(function(media) {
|
|
777
|
+
if (Array.isArray(media) && media.length > 0) updateGalleryScreens(media);
|
|
778
|
+
}).catch(function() {});
|
|
779
|
+
}
|
|
760
780
|
}
|
|
761
781
|
}, 2000);
|
|
762
782
|
};
|
|
@@ -800,9 +820,19 @@ window.office3dSetEnvironment = function(env) {
|
|
|
800
820
|
// Load city modules on demand
|
|
801
821
|
if (env === 'city') getCityMods();
|
|
802
822
|
if (S.scene) {
|
|
803
|
-
// Remove all existing agents
|
|
823
|
+
// Remove all existing agents — including CSS2D label DOM elements
|
|
804
824
|
for (var name in S.agents3d) {
|
|
805
825
|
var agent = S.agents3d[name];
|
|
826
|
+
// Remove CSS2D label DOM elements explicitly
|
|
827
|
+
if (agent.parts.labelDiv && agent.parts.labelDiv.parentElement) agent.parts.labelDiv.remove();
|
|
828
|
+
if (agent.parts.bubbleDiv && agent.parts.bubbleDiv.parentElement) agent.parts.bubbleDiv.remove();
|
|
829
|
+
if (agent.parts.taskDiv && agent.parts.taskDiv.parentElement) agent.parts.taskDiv.remove();
|
|
830
|
+
// Remove all CSS2DObject DOM nodes from the group tree
|
|
831
|
+
agent.parts.group.traverse(function(child) {
|
|
832
|
+
if (child.isCSS2DObject && child.element && child.element.parentElement) {
|
|
833
|
+
child.element.remove();
|
|
834
|
+
}
|
|
835
|
+
});
|
|
806
836
|
S.scene.remove(agent.parts.group);
|
|
807
837
|
agent.parts.group.traverse(function(child) {
|
|
808
838
|
if (child.geometry) child.geometry.dispose();
|
|
@@ -813,6 +843,8 @@ window.office3dSetEnvironment = function(env) {
|
|
|
813
843
|
});
|
|
814
844
|
}
|
|
815
845
|
S.agents3d = {};
|
|
846
|
+
// Also release any claimed gallery seats
|
|
847
|
+
window._gallerySeatsReset = true;
|
|
816
848
|
S._tvScreen = null;
|
|
817
849
|
S._roofGroup = null;
|
|
818
850
|
S._managerDoor = null;
|
|
@@ -821,6 +853,7 @@ window.office3dSetEnvironment = function(env) {
|
|
|
821
853
|
S._managerOfficePos = null;
|
|
822
854
|
S._campusDeskPositions = null;
|
|
823
855
|
S.lastProcessedMsg = 0;
|
|
856
|
+
window._lastProcessedMsg = 0;
|
|
824
857
|
invalidateColliders();
|
|
825
858
|
buildEnvironment();
|
|
826
859
|
// syncAgents will recreate all agents with correct desk assignments
|
|
@@ -885,49 +918,120 @@ if (window.activeView === 'office') {
|
|
|
885
918
|
window.office3dStart();
|
|
886
919
|
}
|
|
887
920
|
|
|
888
|
-
// ===================== INTERACTIVE
|
|
889
|
-
var
|
|
921
|
+
// ===================== INTERACTIVE MONITOR — Dashboard + ComfyUI tabs =====================
|
|
922
|
+
var _monitorOverlay = null;
|
|
923
|
+
var _monitorActiveTab = 'dashboard';
|
|
890
924
|
|
|
891
925
|
window.onPlayerSit = function(deskIdx) {
|
|
892
|
-
if (
|
|
893
|
-
|
|
926
|
+
if (_monitorOverlay) return;
|
|
927
|
+
|
|
928
|
+
// Release pointer lock so mouse works in iframe
|
|
929
|
+
if (document.pointerLockElement) document.exitPointerLock();
|
|
930
|
+
|
|
931
|
+
// Use office-area as parent (it has proper positioning)
|
|
932
|
+
var container = document.getElementById('office-area');
|
|
933
|
+
if (!container) container = document.getElementById('office-3d-container');
|
|
894
934
|
if (!container) return;
|
|
895
935
|
|
|
896
|
-
//
|
|
936
|
+
// Overlay
|
|
897
937
|
var overlay = document.createElement('div');
|
|
898
|
-
overlay.id = 'office-
|
|
899
|
-
overlay.style.cssText = 'position:
|
|
938
|
+
overlay.id = 'office-monitor-overlay';
|
|
939
|
+
overlay.style.cssText = 'position:fixed;top:3%;left:5%;width:90%;height:92%;z-index:99999;background:#0a0c14;border-radius:10px;box-shadow:0 0 60px rgba(88,166,255,0.3),0 0 0 1px #30363d;overflow:hidden;display:flex;flex-direction:column;';
|
|
900
940
|
|
|
901
|
-
// Header bar
|
|
941
|
+
// Header bar with tabs + close
|
|
902
942
|
var header = document.createElement('div');
|
|
903
|
-
header.style.cssText = 'background:#
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
943
|
+
header.style.cssText = 'background:#141824;padding:0 12px;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;height:36px;border-bottom:1px solid #30363d;';
|
|
944
|
+
|
|
945
|
+
// Tab buttons
|
|
946
|
+
var tabsHtml = '<div style="display:flex;gap:0;">';
|
|
947
|
+
tabsHtml += '<button id="mon-tab-dashboard" style="padding:8px 16px;font-size:11px;font-family:monospace;border:none;cursor:pointer;border-bottom:2px solid #58a6ff;background:transparent;color:#58a6ff;">Dashboard</button>';
|
|
948
|
+
tabsHtml += '<button id="mon-tab-comfyui" style="padding:8px 16px;font-size:11px;font-family:monospace;border:none;cursor:pointer;border-bottom:2px solid transparent;background:transparent;color:#8892b0;">ComfyUI</button>';
|
|
949
|
+
tabsHtml += '</div>';
|
|
950
|
+
|
|
951
|
+
var closeHtml = '<button id="mon-close-btn" style="background:#ff5f57;color:#fff;border:none;border-radius:4px;padding:3px 14px;font-size:11px;font-weight:bold;cursor:pointer;font-family:monospace;">ESC to Leave</button>';
|
|
952
|
+
|
|
953
|
+
header.innerHTML = tabsHtml + closeHtml;
|
|
910
954
|
overlay.appendChild(header);
|
|
911
955
|
|
|
956
|
+
// Iframe container
|
|
957
|
+
var iframeWrap = document.createElement('div');
|
|
958
|
+
iframeWrap.style.cssText = 'flex:1;position:relative;';
|
|
959
|
+
|
|
912
960
|
// Dashboard iframe
|
|
913
|
-
var
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
961
|
+
var dashIframe = document.createElement('iframe');
|
|
962
|
+
dashIframe.id = 'mon-iframe-dashboard';
|
|
963
|
+
dashIframe.src = window.location.origin || 'http://localhost:3000';
|
|
964
|
+
dashIframe.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;border:none;background:#0d1117;';
|
|
965
|
+
dashIframe.allow = 'clipboard-read; clipboard-write';
|
|
966
|
+
iframeWrap.appendChild(dashIframe);
|
|
967
|
+
|
|
968
|
+
// ComfyUI iframe (hidden initially)
|
|
969
|
+
var comfyIframe = document.createElement('iframe');
|
|
970
|
+
comfyIframe.id = 'mon-iframe-comfyui';
|
|
971
|
+
comfyIframe.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;border:none;background:#1a1a2e;display:none;';
|
|
972
|
+
comfyIframe.allow = 'clipboard-read; clipboard-write';
|
|
973
|
+
// Don't load ComfyUI until tab is clicked (saves resources)
|
|
974
|
+
iframeWrap.appendChild(comfyIframe);
|
|
975
|
+
|
|
976
|
+
overlay.appendChild(iframeWrap);
|
|
977
|
+
document.body.appendChild(overlay);
|
|
978
|
+
_monitorOverlay = overlay;
|
|
979
|
+
_monitorActiveTab = 'dashboard';
|
|
980
|
+
|
|
981
|
+
// Tab switching
|
|
982
|
+
function switchTab(tab) {
|
|
983
|
+
_monitorActiveTab = tab;
|
|
984
|
+
var dIframe = document.getElementById('mon-iframe-dashboard');
|
|
985
|
+
var cIframe = document.getElementById('mon-iframe-comfyui');
|
|
986
|
+
var dTab = document.getElementById('mon-tab-dashboard');
|
|
987
|
+
var cTab = document.getElementById('mon-tab-comfyui');
|
|
988
|
+
|
|
989
|
+
if (tab === 'dashboard') {
|
|
990
|
+
if (dIframe) dIframe.style.display = 'block';
|
|
991
|
+
if (cIframe) cIframe.style.display = 'none';
|
|
992
|
+
if (dTab) { dTab.style.color = '#58a6ff'; dTab.style.borderBottomColor = '#58a6ff'; }
|
|
993
|
+
if (cTab) { cTab.style.color = '#8892b0'; cTab.style.borderBottomColor = 'transparent'; }
|
|
994
|
+
} else {
|
|
995
|
+
if (dIframe) dIframe.style.display = 'none';
|
|
996
|
+
if (cIframe) {
|
|
997
|
+
cIframe.style.display = 'block';
|
|
998
|
+
// Lazy-load ComfyUI on first switch
|
|
999
|
+
if (!cIframe.src || cIframe.src === 'about:blank' || cIframe.src === '') {
|
|
1000
|
+
cIframe.src = 'http://127.0.0.1:8188';
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
if (dTab) { dTab.style.color = '#8892b0'; dTab.style.borderBottomColor = 'transparent'; }
|
|
1004
|
+
if (cTab) { cTab.style.color = '#ff6b35'; cTab.style.borderBottomColor = '#ff6b35'; }
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
overlay.querySelector('#mon-tab-dashboard').addEventListener('click', function() { switchTab('dashboard'); });
|
|
1009
|
+
overlay.querySelector('#mon-tab-comfyui').addEventListener('click', function() { switchTab('comfyui'); });
|
|
1010
|
+
|
|
1011
|
+
// Close button
|
|
1012
|
+
overlay.querySelector('#mon-close-btn').addEventListener('click', function() {
|
|
1013
|
+
if (typeof window.playerForceStand === 'function') window.playerForceStand();
|
|
1014
|
+
window.onPlayerStand();
|
|
1015
|
+
});
|
|
1016
|
+
|
|
1017
|
+
// ESC key closes overlay
|
|
1018
|
+
overlay._escHandler = function(e) {
|
|
1019
|
+
if (e.code === 'Escape' && _monitorOverlay) {
|
|
1020
|
+
if (typeof window.playerForceStand === 'function') window.playerForceStand();
|
|
1021
|
+
window.onPlayerStand();
|
|
1022
|
+
}
|
|
1023
|
+
};
|
|
1024
|
+
document.addEventListener('keydown', overlay._escHandler);
|
|
1025
|
+
|
|
1026
|
+
// Focus dashboard iframe
|
|
1027
|
+
dashIframe.addEventListener('load', function() { dashIframe.focus(); });
|
|
925
1028
|
};
|
|
926
1029
|
|
|
927
1030
|
window.onPlayerStand = function() {
|
|
928
|
-
if (
|
|
929
|
-
|
|
930
|
-
|
|
1031
|
+
if (_monitorOverlay) {
|
|
1032
|
+
if (_monitorOverlay._escHandler) document.removeEventListener('keydown', _monitorOverlay._escHandler);
|
|
1033
|
+
_monitorOverlay.remove();
|
|
1034
|
+
_monitorOverlay = null;
|
|
931
1035
|
}
|
|
932
1036
|
};
|
|
933
1037
|
|