let-them-talk 5.3.0 → 5.4.1
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 +346 -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 +864 -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 +141 -34
- 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 +9577 -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';
|
|
@@ -29,6 +31,11 @@ function getCityMods() {
|
|
|
29
31
|
function isDriving() { return _cityMods && _cityMods.vehicle && _cityMods.vehicle.isDriving(); }
|
|
30
32
|
function isConnected() { return false; }
|
|
31
33
|
|
|
34
|
+
function scopedOfficeApiUrl(path, options) {
|
|
35
|
+
if (typeof window.scopedApiUrl === 'function') return window.scopedApiUrl(path, null, options);
|
|
36
|
+
return path;
|
|
37
|
+
}
|
|
38
|
+
|
|
32
39
|
// Expose createCharacter + resolveAppearance for the character designer (Phase 3)
|
|
33
40
|
export { createCharacter } from './character.js';
|
|
34
41
|
export { resolveAppearance } from './appearance.js';
|
|
@@ -316,7 +323,7 @@ function executeCommand(agentName, action) {
|
|
|
316
323
|
showInputOverlay('Send message to ' + agentName + ':', 'Type your message...', function(msg) {
|
|
317
324
|
if (msg && msg.trim()) {
|
|
318
325
|
showBubble(agent, 'Message incoming...');
|
|
319
|
-
fetch('/api/inject'
|
|
326
|
+
fetch(scopedOfficeApiUrl('/api/inject'), {
|
|
320
327
|
method: 'POST',
|
|
321
328
|
headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
|
|
322
329
|
body: JSON.stringify({ to: agentName, content: msg.trim() })
|
|
@@ -329,7 +336,7 @@ function executeCommand(agentName, action) {
|
|
|
329
336
|
showInputOverlay('New task for ' + agentName + ':', 'Task title...', function(title) {
|
|
330
337
|
if (title && title.trim()) {
|
|
331
338
|
showBubble(agent, 'New task assigned!');
|
|
332
|
-
fetch('/api/tasks'
|
|
339
|
+
fetch(scopedOfficeApiUrl('/api/tasks'), {
|
|
333
340
|
method: 'POST',
|
|
334
341
|
headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
|
|
335
342
|
body: JSON.stringify({ title: title.trim(), assignee: agentName, status: 'pending' })
|
|
@@ -350,7 +357,7 @@ function executeCommand(agentName, action) {
|
|
|
350
357
|
|
|
351
358
|
case 'nudge':
|
|
352
359
|
showBubble(agent, 'Hey! Wake up!');
|
|
353
|
-
fetch('/api/inject'
|
|
360
|
+
fetch(scopedOfficeApiUrl('/api/inject'), {
|
|
354
361
|
method: 'POST',
|
|
355
362
|
headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
|
|
356
363
|
body: JSON.stringify({ to: agentName, content: 'Hey ' + agentName + ', the user is waiting for you. Please check for new messages and continue your work.' })
|
|
@@ -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,123 @@ 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
|
|
|
912
|
-
//
|
|
913
|
-
var
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
iframe.
|
|
917
|
-
|
|
956
|
+
// Iframe container
|
|
957
|
+
var iframeWrap = document.createElement('div');
|
|
958
|
+
iframeWrap.style.cssText = 'flex:1;position:relative;';
|
|
959
|
+
|
|
960
|
+
// Dashboard iframe. clipboard-write only — the iframe needs to copy agent
|
|
961
|
+
// prompts into the user's clipboard, it never needs to read from it.
|
|
962
|
+
var dashIframe = document.createElement('iframe');
|
|
963
|
+
dashIframe.id = 'mon-iframe-dashboard';
|
|
964
|
+
dashIframe.src = window.location.origin || 'http://localhost:3000';
|
|
965
|
+
dashIframe.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;border:none;background:#0d1117;';
|
|
966
|
+
dashIframe.allow = 'clipboard-write';
|
|
967
|
+
iframeWrap.appendChild(dashIframe);
|
|
968
|
+
|
|
969
|
+
// ComfyUI iframe (hidden initially). Same write-only clipboard scope.
|
|
970
|
+
var comfyIframe = document.createElement('iframe');
|
|
971
|
+
comfyIframe.id = 'mon-iframe-comfyui';
|
|
972
|
+
comfyIframe.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;border:none;background:#1a1a2e;display:none;';
|
|
973
|
+
comfyIframe.allow = 'clipboard-write';
|
|
974
|
+
// Don't load ComfyUI until tab is clicked (saves resources)
|
|
975
|
+
iframeWrap.appendChild(comfyIframe);
|
|
976
|
+
|
|
977
|
+
overlay.appendChild(iframeWrap);
|
|
978
|
+
document.body.appendChild(overlay);
|
|
979
|
+
_monitorOverlay = overlay;
|
|
980
|
+
_monitorActiveTab = 'dashboard';
|
|
981
|
+
|
|
982
|
+
// Tab switching
|
|
983
|
+
function switchTab(tab) {
|
|
984
|
+
_monitorActiveTab = tab;
|
|
985
|
+
var dIframe = document.getElementById('mon-iframe-dashboard');
|
|
986
|
+
var cIframe = document.getElementById('mon-iframe-comfyui');
|
|
987
|
+
var dTab = document.getElementById('mon-tab-dashboard');
|
|
988
|
+
var cTab = document.getElementById('mon-tab-comfyui');
|
|
989
|
+
|
|
990
|
+
if (tab === 'dashboard') {
|
|
991
|
+
if (dIframe) dIframe.style.display = 'block';
|
|
992
|
+
if (cIframe) cIframe.style.display = 'none';
|
|
993
|
+
if (dTab) { dTab.style.color = '#58a6ff'; dTab.style.borderBottomColor = '#58a6ff'; }
|
|
994
|
+
if (cTab) { cTab.style.color = '#8892b0'; cTab.style.borderBottomColor = 'transparent'; }
|
|
995
|
+
} else {
|
|
996
|
+
if (dIframe) dIframe.style.display = 'none';
|
|
997
|
+
if (cIframe) {
|
|
998
|
+
cIframe.style.display = 'block';
|
|
999
|
+
// Lazy-load ComfyUI on first switch. URL is configurable via
|
|
1000
|
+
// window.COMFYUI_URL (set it from the dashboard or page) so users
|
|
1001
|
+
// on non-default ports or remote ComfyUI hosts can override.
|
|
1002
|
+
if (!cIframe.src || cIframe.src === 'about:blank' || cIframe.src === '') {
|
|
1003
|
+
cIframe.src = (typeof window !== 'undefined' && window.COMFYUI_URL) || 'http://127.0.0.1:8188';
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
if (dTab) { dTab.style.color = '#8892b0'; dTab.style.borderBottomColor = 'transparent'; }
|
|
1007
|
+
if (cTab) { cTab.style.color = '#ff6b35'; cTab.style.borderBottomColor = '#ff6b35'; }
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
918
1010
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1011
|
+
overlay.querySelector('#mon-tab-dashboard').addEventListener('click', function() { switchTab('dashboard'); });
|
|
1012
|
+
overlay.querySelector('#mon-tab-comfyui').addEventListener('click', function() { switchTab('comfyui'); });
|
|
1013
|
+
|
|
1014
|
+
// Close button
|
|
1015
|
+
overlay.querySelector('#mon-close-btn').addEventListener('click', function() {
|
|
1016
|
+
if (typeof window.playerForceStand === 'function') window.playerForceStand();
|
|
1017
|
+
window.onPlayerStand();
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
// ESC key closes overlay
|
|
1021
|
+
overlay._escHandler = function(e) {
|
|
1022
|
+
if (e.code === 'Escape' && _monitorOverlay) {
|
|
1023
|
+
if (typeof window.playerForceStand === 'function') window.playerForceStand();
|
|
1024
|
+
window.onPlayerStand();
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
document.addEventListener('keydown', overlay._escHandler);
|
|
922
1028
|
|
|
923
|
-
// Focus iframe
|
|
924
|
-
|
|
1029
|
+
// Focus dashboard iframe
|
|
1030
|
+
dashIframe.addEventListener('load', function() { dashIframe.focus(); });
|
|
925
1031
|
};
|
|
926
1032
|
|
|
927
1033
|
window.onPlayerStand = function() {
|
|
928
|
-
if (
|
|
929
|
-
|
|
930
|
-
|
|
1034
|
+
if (_monitorOverlay) {
|
|
1035
|
+
if (_monitorOverlay._escHandler) document.removeEventListener('keydown', _monitorOverlay._escHandler);
|
|
1036
|
+
_monitorOverlay.remove();
|
|
1037
|
+
_monitorOverlay = null;
|
|
931
1038
|
}
|
|
932
1039
|
};
|
|
933
1040
|
|
package/office/navigation.js
CHANGED
|
@@ -5,163 +5,184 @@ import { S } from './state.js';
|
|
|
5
5
|
// Agents walk along connected waypoints to avoid walls/objects
|
|
6
6
|
// ============================================================
|
|
7
7
|
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// Left:
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
8
|
+
// Campus geometry reference (90W x 60D):
|
|
9
|
+
// Outer walls: X = ±45, Z = ±30
|
|
10
|
+
// Workspace: 5x4 desk grid at X=[-8,-4,0,4,8], Z=[6,10,14,18]
|
|
11
|
+
// Manager office at (30, 10), size 10x10:
|
|
12
|
+
// Left wall: X = 25, Right wall: X = 35
|
|
13
|
+
// Front wall: Z = 5 (door at center X=30)
|
|
14
|
+
// Back wall: Z = 15
|
|
15
|
+
// Path must approach from south (Z<5) and enter through door
|
|
16
|
+
// Main corridor: Z=0, runs full campus width (-2 to +2)
|
|
17
|
+
// Cross corridors: X=±20, connect north-south (3 units wide)
|
|
18
|
+
// Lobby/Entrance: Z=22-30, front wall gap at center
|
|
19
|
+
// Designer Studio: center (-28, 0), 12x10
|
|
20
|
+
// Bar & Café: center (-28, -18), 12x10
|
|
21
|
+
// Rec Center: center (0, -18), 12x10
|
|
22
|
+
// Gym: center (22, -18), 12x10
|
|
23
|
+
// Staircase: X=35, Z=-14 to -22, connects to mezzanine (Z=-18 to -30)
|
|
24
|
+
// Gallery Wing: inside campus at (-36, 10), 14x12, open east side at X=-29
|
|
16
25
|
|
|
17
26
|
var CAMPUS_WAYPOINTS = [
|
|
18
|
-
// === LOBBY / ENTRANCE ===
|
|
19
|
-
{ id: 'spawn', x: 0, z:
|
|
20
|
-
{ id: 'lobby', x: 0, z:
|
|
21
|
-
{ id: 'lobby_left', x: -
|
|
22
|
-
{ id: 'lobby_right', x:
|
|
23
|
-
|
|
24
|
-
// ===
|
|
25
|
-
{ id: '
|
|
26
|
-
{ id: '
|
|
27
|
-
{ id: '
|
|
28
|
-
{ id: '
|
|
29
|
-
{ id: '
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{ id: '
|
|
33
|
-
{ id: '
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
{ id: '
|
|
37
|
-
{ id: '
|
|
38
|
-
{ id: '
|
|
39
|
-
{ id: '
|
|
40
|
-
{ id: '
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
{ id: '
|
|
45
|
-
{ id: '
|
|
46
|
-
{ id: '
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
// Door at front wall center (
|
|
51
|
-
|
|
52
|
-
{ id: '
|
|
53
|
-
{ id: '
|
|
54
|
-
{ id: '
|
|
55
|
-
{ id: '
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
{ id: '
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
{ id: '
|
|
63
|
-
{ id: '
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
{ id: '
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
{ id: '
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
{ id: '
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
{ id: '
|
|
82
|
-
|
|
83
|
-
// === REST / DRESSING (right wing, for old office compat) ===
|
|
84
|
-
{ id: 'rest_entry', x: 7.5, z: -5.5 },
|
|
85
|
-
{ id: 'dress_entry', x: 7.5, z: -1.5 },
|
|
27
|
+
// === LOBBY / ENTRANCE (Z=22-30, front wall gap at center) ===
|
|
28
|
+
{ id: 'spawn', x: 0, z: 28 }, // entrance area (between door and reception)
|
|
29
|
+
{ id: 'lobby', x: 0, z: 24 }, // inside lobby center
|
|
30
|
+
{ id: 'lobby_left', x: -10, z: 24 }, // lobby left side
|
|
31
|
+
{ id: 'lobby_right', x: 10, z: 24 }, // lobby right side
|
|
32
|
+
|
|
33
|
+
// === WORKSPACE (5x4 desk grid, X=[-8,-4,0,4,8], Z=[6,10,14,18]) ===
|
|
34
|
+
{ id: 'work_N', x: 0, z: 18 }, // northernmost row center
|
|
35
|
+
{ id: 'work_NW', x: -8, z: 18 }, // north-west desk
|
|
36
|
+
{ id: 'work_NE', x: 8, z: 18 }, // north-east desk
|
|
37
|
+
{ id: 'work_W', x: -8, z: 14 }, // west mid desk
|
|
38
|
+
{ id: 'work_C', x: 0, z: 14 }, // center desk
|
|
39
|
+
{ id: 'work_E', x: 8, z: 14 }, // east mid desk
|
|
40
|
+
{ id: 'work_SW', x: -8, z: 10 }, // south-west desk
|
|
41
|
+
{ id: 'work_S', x: 0, z: 10 }, // south row center
|
|
42
|
+
{ id: 'work_SE', x: 8, z: 10 }, // south-east desk
|
|
43
|
+
|
|
44
|
+
// === MAIN CORRIDOR (Z=0, runs full width) ===
|
|
45
|
+
{ id: 'corr_L', x: -20, z: 0 }, // left end (at cross corridor)
|
|
46
|
+
{ id: 'corr_CL', x: -8, z: 0 }, // center-left
|
|
47
|
+
{ id: 'corr_C', x: 0, z: 0 }, // center
|
|
48
|
+
{ id: 'corr_CR', x: 8, z: 0 }, // center-right
|
|
49
|
+
{ id: 'corr_R', x: 20, z: 0 }, // right end (at cross corridor)
|
|
50
|
+
{ id: 'corr_RR', x: 30, z: 0 }, // far right (toward manager approach)
|
|
51
|
+
|
|
52
|
+
// === CROSS CORRIDORS (X=±20, connect north-south) ===
|
|
53
|
+
{ id: 'cross_NL', x: -20, z: 12 }, // north-left cross corridor
|
|
54
|
+
{ id: 'cross_SL', x: -20, z: -12 }, // south-left cross corridor
|
|
55
|
+
{ id: 'cross_NR', x: 20, z: 12 }, // north-right cross corridor
|
|
56
|
+
{ id: 'cross_SR', x: 20, z: -12 }, // south-right cross corridor
|
|
57
|
+
|
|
58
|
+
// === MANAGER OFFICE (center at (30,10), walls: left X=25, right X=35, front Z=5, back Z=15) ===
|
|
59
|
+
// Door at front wall center (X=30, Z=5). Path approaches from south (Z<5).
|
|
60
|
+
{ id: 'mgr_hallway', x: 30, z: 3 }, // south of office, in main corridor area
|
|
61
|
+
{ id: 'mgr_outside', x: 30, z: 4 }, // directly outside front wall
|
|
62
|
+
{ id: 'mgr_doorstep', x: 30, z: 5, triggerDoor: 'open' }, // at door threshold
|
|
63
|
+
{ id: 'mgr_entry', x: 30, z: 7 }, // just inside the door
|
|
64
|
+
{ id: 'mgr_desk', x: 30, z: 12 }, // at the manager desk
|
|
65
|
+
|
|
66
|
+
// === DESIGNER STUDIO (center (-28, 0), 12x10) ===
|
|
67
|
+
{ id: 'design_entry', x: -22, z: 0 }, // entry from cross corridor
|
|
68
|
+
{ id: 'design_center', x: -28, z: 0 }, // studio center
|
|
69
|
+
|
|
70
|
+
// === BAR & CAFÉ (center (-28, -18), 12x10) ===
|
|
71
|
+
{ id: 'bar_entry', x: -22, z: -14 }, // entry from south cross corridor
|
|
72
|
+
{ id: 'bar_center', x: -28, z: -18 }, // bar center
|
|
73
|
+
|
|
74
|
+
// === REC CENTER (center (0, -18), 12x10) ===
|
|
75
|
+
{ id: 'rec_entry', x: 0, z: -14 }, // entry from south corridor
|
|
76
|
+
{ id: 'rec_center', x: 0, z: -18 }, // rec center
|
|
77
|
+
|
|
78
|
+
// === GYM (center (22, -18), 12x10) ===
|
|
79
|
+
{ id: 'gym_entry', x: 14, z: -14 }, // entry from south cross corridor
|
|
80
|
+
{ id: 'gym_center', x: 22, z: -18 }, // gym center
|
|
81
|
+
|
|
82
|
+
// === STAIRCASE (X=35, Z=-14 to -22) ===
|
|
83
|
+
{ id: 'stairs_bot', x: 35, z: -14 }, // bottom of stairs
|
|
84
|
+
{ id: 'stairs_top', x: 35, z: -20 }, // top of stairs (mezzanine level)
|
|
85
|
+
|
|
86
|
+
// === MEZZANINE (Z=-18 to -30) ===
|
|
87
|
+
{ id: 'mezz_C', x: 0, z: -24 }, // mezzanine center
|
|
88
|
+
|
|
89
|
+
// === GALLERY WING (inside campus, center at -36, 10, entry from east at X=-29) ===
|
|
90
|
+
{ id: 'gallery_entry', x: -28, z: 10 }, // just outside east glass entrance
|
|
91
|
+
{ id: 'gallery_center',x: -36, z: 10 }, // gallery center
|
|
86
92
|
];
|
|
87
93
|
|
|
88
94
|
var CAMPUS_CONNECTIONS = [
|
|
89
|
-
//
|
|
90
|
-
['spawn',
|
|
91
|
-
['lobby',
|
|
92
|
-
['lobby',
|
|
93
|
-
['lobby',
|
|
94
|
-
['lobby_left',
|
|
95
|
-
['lobby_right',
|
|
96
|
-
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
['
|
|
100
|
-
['
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
['
|
|
105
|
-
|
|
106
|
-
['
|
|
107
|
-
|
|
108
|
-
//
|
|
109
|
-
['
|
|
110
|
-
['
|
|
111
|
-
['
|
|
112
|
-
|
|
113
|
-
['
|
|
114
|
-
['
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
['
|
|
118
|
-
['
|
|
119
|
-
['
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
['
|
|
124
|
-
['
|
|
125
|
-
['
|
|
126
|
-
['
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
['
|
|
132
|
-
['
|
|
133
|
-
['
|
|
134
|
-
|
|
135
|
-
['
|
|
136
|
-
['
|
|
137
|
-
['
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
//
|
|
144
|
-
['
|
|
145
|
-
['
|
|
146
|
-
['
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
//
|
|
150
|
-
['
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
['
|
|
155
|
-
['
|
|
156
|
-
|
|
157
|
-
//
|
|
158
|
-
['
|
|
159
|
-
['
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
['
|
|
164
|
-
|
|
95
|
+
// === LOBBY ===
|
|
96
|
+
['spawn', 'lobby'],
|
|
97
|
+
['lobby', 'lobby_left'],
|
|
98
|
+
['lobby', 'lobby_right'],
|
|
99
|
+
['lobby', 'work_N'], // lobby → northernmost workspace row
|
|
100
|
+
['lobby_left', 'work_NW'],
|
|
101
|
+
['lobby_right', 'work_NE'],
|
|
102
|
+
|
|
103
|
+
// === WORKSPACE GRID (rows N→S, Z: 18→10) ===
|
|
104
|
+
// North row (Z=18)
|
|
105
|
+
['work_N', 'work_NW'],
|
|
106
|
+
['work_N', 'work_NE'],
|
|
107
|
+
// Mid row (Z=14) — connected to north
|
|
108
|
+
['work_NW', 'work_W'],
|
|
109
|
+
['work_N', 'work_C'],
|
|
110
|
+
['work_NE', 'work_E'],
|
|
111
|
+
// Horizontal mid
|
|
112
|
+
['work_W', 'work_C'],
|
|
113
|
+
['work_C', 'work_E'],
|
|
114
|
+
// South row (Z=10) — connected to mid
|
|
115
|
+
['work_W', 'work_SW'],
|
|
116
|
+
['work_C', 'work_S'],
|
|
117
|
+
['work_E', 'work_SE'],
|
|
118
|
+
// Horizontal south
|
|
119
|
+
['work_SW', 'work_S'],
|
|
120
|
+
['work_S', 'work_SE'],
|
|
121
|
+
|
|
122
|
+
// === WORKSPACE → MAIN CORRIDOR (Z=0) ===
|
|
123
|
+
['work_SW', 'corr_CL'], // south-west desk down to corridor
|
|
124
|
+
['work_S', 'corr_C'], // south center down to corridor
|
|
125
|
+
['work_SE', 'corr_CR'], // south-east desk down to corridor
|
|
126
|
+
|
|
127
|
+
// === MAIN CORRIDOR (horizontal, Z=0) ===
|
|
128
|
+
['corr_L', 'corr_CL'],
|
|
129
|
+
['corr_CL', 'corr_C'],
|
|
130
|
+
['corr_C', 'corr_CR'],
|
|
131
|
+
['corr_CR', 'corr_R'],
|
|
132
|
+
['corr_R', 'corr_RR'], // extend east toward manager side
|
|
133
|
+
|
|
134
|
+
// === CROSS CORRIDORS (X=±20, north-south) ===
|
|
135
|
+
// Left cross corridor (X=-20): lobby-side north → main corridor → south zone
|
|
136
|
+
['cross_NL', 'work_NW'], // north end connects to workspace
|
|
137
|
+
['cross_NL', 'corr_L'], // meets main corridor
|
|
138
|
+
['corr_L', 'cross_SL'], // south through left cross corridor
|
|
139
|
+
['cross_SL', 'cross_NL'], // bidirectional shortcut label
|
|
140
|
+
// Right cross corridor (X=20): lobby-side north → main corridor → south zone
|
|
141
|
+
['cross_NR', 'work_NE'], // north end connects to workspace
|
|
142
|
+
['cross_NR', 'corr_R'], // meets main corridor
|
|
143
|
+
['corr_R', 'cross_SR'], // south through right cross corridor
|
|
144
|
+
['cross_SR', 'cross_NR'], // bidirectional shortcut label
|
|
145
|
+
|
|
146
|
+
// === MANAGER OFFICE ===
|
|
147
|
+
// Approach: corr_RR(30,0) → mgr_hallway(30,3) → mgr_outside(30,4) → door → inside
|
|
148
|
+
['corr_RR', 'mgr_hallway'], // walk north along X=30 toward office
|
|
149
|
+
['mgr_hallway', 'mgr_outside'], // step closer to front wall
|
|
150
|
+
['mgr_outside', 'mgr_doorstep'], // step to door threshold (triggers door open)
|
|
151
|
+
['mgr_doorstep', 'mgr_entry'], // walk through open door
|
|
152
|
+
['mgr_entry', 'mgr_desk'], // walk to manager desk
|
|
153
|
+
|
|
154
|
+
// === DESIGNER STUDIO (center -28, 0) — enter from left cross corridor ===
|
|
155
|
+
['corr_L', 'design_entry'], // branch off main corridor at X=-20 level
|
|
156
|
+
['design_entry', 'design_center'], // walk into studio
|
|
157
|
+
|
|
158
|
+
// === SOUTH ZONES — accessed via cross corridors reaching south ===
|
|
159
|
+
// Left south: cross_SL(-20,-12) → bar_entry(-22,-14) → bar_center(-28,-18)
|
|
160
|
+
['cross_SL', 'bar_entry'],
|
|
161
|
+
['bar_entry', 'bar_center'],
|
|
162
|
+
|
|
163
|
+
// Center south: corr_C(0,0) drops to rec via south cross node
|
|
164
|
+
['corr_C', 'rec_entry'], // direct south from main corridor center
|
|
165
|
+
['rec_entry', 'rec_center'],
|
|
166
|
+
|
|
167
|
+
// Right south: cross_SR(20,-12) → gym_entry(14,-14) → gym_center(22,-18)
|
|
168
|
+
['cross_SR', 'gym_entry'],
|
|
169
|
+
['gym_entry', 'gym_center'],
|
|
170
|
+
|
|
171
|
+
// Cross-south interconnect (bar ↔ rec ↔ gym at Z≈-14)
|
|
172
|
+
['bar_entry', 'rec_entry'],
|
|
173
|
+
['rec_entry', 'gym_entry'],
|
|
174
|
+
|
|
175
|
+
// === STAIRCASE & MEZZANINE ===
|
|
176
|
+
// Stairs bot at (35,-14): reachable from cross_SR and gym side
|
|
177
|
+
['cross_SR', 'stairs_bot'],
|
|
178
|
+
['gym_center', 'stairs_bot'],
|
|
179
|
+
['stairs_bot', 'stairs_top'],
|
|
180
|
+
['stairs_top', 'mezz_C'],
|
|
181
|
+
|
|
182
|
+
// === GALLERY WING (inside campus, upper-left area) ===
|
|
183
|
+
['cross_NL', 'gallery_entry'], // north from left cross corridor
|
|
184
|
+
['design_entry', 'gallery_entry'], // from designer studio area
|
|
185
|
+
['gallery_entry','gallery_center'], // enter gallery
|
|
165
186
|
];
|
|
166
187
|
|
|
167
188
|
// === BUILD GRAPH ===
|