copilotoffice 1.0.3 → 1.1.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.
@@ -140044,6 +140044,18 @@ var CopilotOffice = (() => {
140044
140044
  CORE_AGENT_IDS.clear();
140045
140045
  for (const a of AGENTS) CORE_AGENT_IDS.add(a.id);
140046
140046
  }
140047
+ function restoreSeatedReserveAgents(seatedAgents) {
140048
+ const valid = [];
140049
+ for (const seated of seatedAgents) {
140050
+ const reserveConfig = RESERVE_AGENTS[seated.deskId];
140051
+ if (!reserveConfig || reserveConfig.id !== seated.agentId) continue;
140052
+ valid.push(seated);
140053
+ if (!AGENTS.find((a) => a.id === seated.agentId)) {
140054
+ AGENTS.push(reserveConfig);
140055
+ }
140056
+ }
140057
+ return valid;
140058
+ }
140047
140059
  var FLEET_NAMES, FLEET_COLORS, FLEET_SEAT_POSITIONS, ARTHUR_FLEET_SEAT_INDEX, FLEET_AGENTS, RESERVE_AGENTS, SHOW_ARCHITECT_IN_DEFAULT_OFFICE, CORE_AGENT_IDS, RESERVE_AGENT_DESK, AGENTS, DEFAULT_AGENTS, DEFAULT_RESERVE_MAP, RANDOM_POOL_CONFIGS, RANDOM_SPRITE_COUNT, CORE_POSITIONS, RESERVE_DESK_IDS, RESERVE_POSITIONS, ROLE_TITLES;
140048
140060
  var init_agents = __esm({
140049
140061
  "src/config/agents.ts"() {
@@ -148603,10 +148615,17 @@ WARNING: This link could potentially be dangerous`)) {
148603
148615
  this.resizeHandler = null;
148604
148616
  this.resizeObserver = null;
148605
148617
  this.refitTimers = [];
148618
+ this.refitGeneration = 0;
148606
148619
  this.attachedOfficeId = null;
148607
148620
  this.isReadOnly = false;
148608
148621
  this.isReplaying = false;
148609
148622
  this.launchMode = "copilot";
148623
+ this.pendingInputLine = "";
148624
+ this.awaitingSessionIdRefresh = false;
148625
+ this.sessionRefreshCommandTimer = null;
148626
+ this.sessionRefreshExpiryTimer = null;
148627
+ this.currentSessionTitle = null;
148628
+ this.isEditingSessionTitle = false;
148610
148629
  this.scene = scene;
148611
148630
  this.inputManager = inputManager;
148612
148631
  this.getOfficeId = getOfficeId;
@@ -148635,6 +148654,11 @@ WARNING: This link could potentially be dangerous`)) {
148635
148654
  [Process exited with code ${exitCode}]`);
148636
148655
  }
148637
148656
  });
148657
+ window.copilotBridge.onSessionMetaUpdated((agentId, meta) => {
148658
+ if (agentId === this.currentAgentId) {
148659
+ this.updateSessionTitleDisplay(meta?.title || null);
148660
+ }
148661
+ });
148638
148662
  }
148639
148663
  }
148640
148664
  /**
@@ -148647,7 +148671,84 @@ WARNING: This link could potentially be dangerous`)) {
148647
148671
  this.setupTerminalListeners();
148648
148672
  console.log("[TerminalOverlay] Re-attached terminal IPC listeners");
148649
148673
  }
148650
- parseSessionId(_data) {
148674
+ clearSessionRefreshTimers() {
148675
+ if (this.sessionRefreshCommandTimer) {
148676
+ clearTimeout(this.sessionRefreshCommandTimer);
148677
+ this.sessionRefreshCommandTimer = null;
148678
+ }
148679
+ if (this.sessionRefreshExpiryTimer) {
148680
+ clearTimeout(this.sessionRefreshExpiryTimer);
148681
+ this.sessionRefreshExpiryTimer = null;
148682
+ }
148683
+ }
148684
+ scheduleSessionIdRefresh(agentId) {
148685
+ if (!window.copilotBridge) return;
148686
+ const officeId = this.getActiveOfficeId();
148687
+ this.awaitingSessionIdRefresh = true;
148688
+ this.clearSessionRefreshTimers();
148689
+ const el = this.spriteCardElement?.querySelector(".session-id-display");
148690
+ if (el) {
148691
+ el.textContent = "syncing...";
148692
+ }
148693
+ this.sessionRefreshCommandTimer = setTimeout(() => {
148694
+ this.sessionRefreshCommandTimer = null;
148695
+ void window.copilotBridge.terminalWrite(officeId, agentId, "/session\r").catch(() => {
148696
+ });
148697
+ }, 400);
148698
+ this.sessionRefreshExpiryTimer = setTimeout(() => {
148699
+ this.sessionRefreshExpiryTimer = null;
148700
+ this.awaitingSessionIdRefresh = false;
148701
+ this.updateSessionDisplay();
148702
+ }, 12e3);
148703
+ }
148704
+ parseSessionId(data) {
148705
+ if (!this.awaitingSessionIdRefresh || !this.currentAgentId || !window.copilotBridge) return;
148706
+ const match = data.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i);
148707
+ if (!match) return;
148708
+ const nextSessionId = match[0].toLowerCase();
148709
+ this.awaitingSessionIdRefresh = false;
148710
+ this.clearSessionRefreshTimers();
148711
+ this.sessionId = nextSessionId;
148712
+ this.updateSessionDisplay();
148713
+ const officeId = this.getActiveOfficeId();
148714
+ void window.copilotBridge.setSessionId(officeId, this.currentAgentId, nextSessionId).catch(() => {
148715
+ });
148716
+ }
148717
+ getActiveOfficeId() {
148718
+ return this.attachedOfficeId ?? this.getOfficeId();
148719
+ }
148720
+ clearRefitTimers() {
148721
+ for (const timer of this.refitTimers) {
148722
+ clearTimeout(timer);
148723
+ }
148724
+ this.refitTimers.length = 0;
148725
+ }
148726
+ resolveTerminalDimensions() {
148727
+ if (!this.terminal || !this.fitAddon) return null;
148728
+ this.fitAddon.fit();
148729
+ const proposed = this.fitAddon.proposeDimensions();
148730
+ const fallbackCols = this.terminal.cols || 80;
148731
+ const fallbackRows = this.terminal.rows || 24;
148732
+ const colsRaw = proposed?.cols ?? fallbackCols;
148733
+ const rowsRaw = proposed?.rows ?? fallbackRows;
148734
+ if (!Number.isFinite(colsRaw) || !Number.isFinite(rowsRaw)) return null;
148735
+ const cols = Math.max(2, Math.floor(colsRaw));
148736
+ const rows = Math.max(1, Math.floor(rowsRaw));
148737
+ return { cols, rows };
148738
+ }
148739
+ fitAndResizeTerminal(options) {
148740
+ if (!this.terminal || !this.fitAddon) return null;
148741
+ const dims = this.resolveTerminalDimensions();
148742
+ if (!dims) return null;
148743
+ const agentId = options?.agentId ?? this.currentAgentId;
148744
+ if (!agentId || !window.copilotBridge) return dims;
148745
+ const officeId = options?.officeId ?? this.getActiveOfficeId();
148746
+ void window.copilotBridge.terminalResize(officeId, agentId, dims.cols, dims.rows).catch(() => {
148747
+ });
148748
+ if (options?.refreshVisibleRows) {
148749
+ this.terminal.refresh(0, Math.max(0, dims.rows - 1));
148750
+ }
148751
+ return dims;
148651
148752
  }
148652
148753
  acknowledgeCompletedWork(officeId, agentId) {
148653
148754
  if (agentId === "pc-terminal") return;
@@ -148663,6 +148764,88 @@ WARNING: This link could potentially be dangerous`)) {
148663
148764
  el.onclick = () => this.copySessionId();
148664
148765
  }
148665
148766
  }
148767
+ updateSessionTitleDisplay(title) {
148768
+ this.currentSessionTitle = title && title.trim().length > 0 ? title : null;
148769
+ if (this.isEditingSessionTitle) return;
148770
+ const el = this.spriteCardElement?.querySelector(".session-title-display");
148771
+ if (!el) return;
148772
+ if (this.currentSessionTitle) {
148773
+ el.textContent = this.currentSessionTitle;
148774
+ el.title = this.currentSessionTitle;
148775
+ el.style.color = "#c8d4ff";
148776
+ return;
148777
+ }
148778
+ el.textContent = "Untitled session";
148779
+ el.title = "Click to set title";
148780
+ el.style.color = "#77839f";
148781
+ }
148782
+ async startSessionTitleEdit() {
148783
+ if (this.isReadOnly || !this.currentAgentId || this.isEditingSessionTitle || !this.spriteCardElement || !window.copilotBridge?.setSessionMeta) return;
148784
+ const titleEl = this.spriteCardElement.querySelector(".session-title-display");
148785
+ if (!titleEl) return;
148786
+ this.isEditingSessionTitle = true;
148787
+ const previousTitle = this.currentSessionTitle || "";
148788
+ const input = document.createElement("input");
148789
+ input.type = "text";
148790
+ input.value = previousTitle;
148791
+ input.maxLength = 120;
148792
+ input.className = "session-title-input";
148793
+ input.style.cssText = `
148794
+ width: min(520px, 52vw);
148795
+ max-width: 100%;
148796
+ background: #101629;
148797
+ color: #dbe6ff;
148798
+ border: 1px solid #3f5c92;
148799
+ border-radius: 6px;
148800
+ padding: 6px 10px;
148801
+ font-size: 15px;
148802
+ font-weight: 700;
148803
+ font-family: 'Cascadia Code', Consolas, monospace;
148804
+ line-height: 1.25;
148805
+ outline: none;
148806
+ `;
148807
+ titleEl.replaceWith(input);
148808
+ input.focus();
148809
+ input.select();
148810
+ const agentId = this.currentAgentId;
148811
+ let finalized = false;
148812
+ const finalize = async (save) => {
148813
+ if (finalized) return;
148814
+ finalized = true;
148815
+ const nextTitle = save ? input.value.trim() : previousTitle;
148816
+ if (save) {
148817
+ try {
148818
+ await withTimeout(
148819
+ window.copilotBridge.setSessionMeta(this.getActiveOfficeId(), agentId, { title: nextTitle }),
148820
+ IPC_TIMEOUT,
148821
+ "setSessionMeta"
148822
+ );
148823
+ } catch (error) {
148824
+ console.warn("[TerminalOverlay] Failed to save session title", error);
148825
+ }
148826
+ }
148827
+ this.isEditingSessionTitle = false;
148828
+ this.currentSessionTitle = nextTitle || null;
148829
+ if (!input.isConnected || !this.spriteCardElement) {
148830
+ this.updateSessionTitleDisplay(this.currentSessionTitle);
148831
+ return;
148832
+ }
148833
+ input.replaceWith(titleEl);
148834
+ this.updateSessionTitleDisplay(this.currentSessionTitle);
148835
+ };
148836
+ input.addEventListener("keydown", (event) => {
148837
+ if (event.key === "Enter") {
148838
+ event.preventDefault();
148839
+ void finalize(true);
148840
+ } else if (event.key === "Escape") {
148841
+ event.preventDefault();
148842
+ void finalize(false);
148843
+ }
148844
+ });
148845
+ input.addEventListener("blur", () => {
148846
+ void finalize(true);
148847
+ });
148848
+ }
148666
148849
  async show(agent, onClose, options) {
148667
148850
  const previousAgentId = this.currentAgentId;
148668
148851
  const previousOfficeId = this.attachedOfficeId ?? this.getOfficeId();
@@ -148674,24 +148857,26 @@ WARNING: This link could potentially be dangerous`)) {
148674
148857
  this.isReadOnly = options?.readOnly ?? false;
148675
148858
  this.launchMode = options?.launchMode ?? "copilot";
148676
148859
  this.attachedOfficeId = this.getOfficeId();
148860
+ const officeId = this.getActiveOfficeId();
148677
148861
  this.currentAgent = agent;
148678
148862
  if (!this.container) {
148679
148863
  this.createContainer();
148680
148864
  }
148681
148865
  const inceptionBadge = agent.id === "admin" ? " \u{1F3AD} INCEPTION MODE" : "";
148682
- let sessionTitleHtml = "";
148866
+ let sessionTitle = null;
148683
148867
  if (window.copilotBridge?.getSessionMeta) {
148684
148868
  try {
148685
- const meta = await window.copilotBridge.getSessionMeta(this.getOfficeId(), agent.id);
148869
+ const meta = await window.copilotBridge.getSessionMeta(officeId, agent.id);
148686
148870
  if (meta?.title) {
148687
- sessionTitleHtml = ` <span style="color: #aab; font-size: 15px;">\u2014 ${meta.title.replace(/</g, "&lt;")}</span>`;
148871
+ sessionTitle = meta.title;
148688
148872
  }
148689
148873
  } catch (_) {
148690
148874
  }
148691
148875
  }
148876
+ const sessionTitleHtml = sessionTitle ? ` <span style="color: #aab; font-size: 15px;">\u2014 ${sessionTitle.replace(/</g, "&lt;")}</span>` : "";
148692
148877
  if (this.headerElement) {
148693
148878
  const readOnlyBadge = this.isReadOnly ? ' <span style="color: #ffb86c; font-size: 12px; background: #332200; padding: 2px 8px; border-radius: 4px;">\u{1F512} READ-ONLY</span>' : "";
148694
- const shortcutsText = this.isReadOnly ? "[F10] Close [Ctrl+F] Fullscreen" : "[F10] Close [Ctrl+Shift+N] New Session [Ctrl+F] Fullscreen";
148879
+ const shortcutsText = this.isReadOnly ? "[F10] Close [Ctrl+F] Fullscreen" : "[F10] Close [/new or Ctrl+Shift+N] New Session [Ctrl+F] Fullscreen";
148695
148880
  const headerLabel = this.isReadOnly ? `\u{1F4DC} Meeting with ${agent.name}` : `\u{1F4AC} Talking to ${agent.name}`;
148696
148881
  this.headerElement.innerHTML = `
148697
148882
  <div style="display: flex; align-items: center; gap: 15px;">
@@ -148714,6 +148899,8 @@ WARNING: This link could potentially be dangerous`)) {
148714
148899
  if (this.container) {
148715
148900
  this.container.style.display = "flex";
148716
148901
  }
148902
+ this.awaitingSessionIdRefresh = false;
148903
+ this.clearSessionRefreshTimers();
148717
148904
  if (this.spriteCardElement) {
148718
148905
  this.spriteCardElement.style.display = "flex";
148719
148906
  }
@@ -148727,27 +148914,39 @@ WARNING: This link could potentially be dangerous`)) {
148727
148914
  agentNameDisplay.textContent = agent.name;
148728
148915
  agentNameDisplay.style.color = colorHex;
148729
148916
  }
148917
+ const agentDescriptionDisplay = this.spriteCardElement?.querySelector(".agent-description-display");
148918
+ if (agentDescriptionDisplay) {
148919
+ agentDescriptionDisplay.textContent = agent.description;
148920
+ }
148921
+ this.updateSessionTitleDisplay(sessionTitle);
148730
148922
  this.drawAgentSprite(agent);
148923
+ this.pendingInputLine = "";
148924
+ this.awaitingSessionIdRefresh = false;
148925
+ this.clearSessionRefreshTimers();
148926
+ this.clearRefitTimers();
148927
+ this.refitGeneration += 1;
148731
148928
  if (!this.terminal) {
148732
148929
  this.createTerminal();
148733
148930
  } else {
148734
148931
  this.isReplaying = true;
148932
+ this.terminal.reset();
148735
148933
  this.terminal.clear();
148736
148934
  }
148737
148935
  this.sessionId = null;
148738
148936
  if (window.copilotBridge) {
148739
148937
  try {
148740
148938
  const exists = await withTimeout(
148741
- window.copilotBridge.terminalExists(this.getOfficeId(), agent.id),
148939
+ window.copilotBridge.terminalExists(officeId, agent.id),
148742
148940
  IPC_TIMEOUT,
148743
148941
  "terminalExists"
148744
148942
  );
148745
148943
  if (!exists) {
148746
148944
  this.isReplaying = false;
148747
- await this.startNewSession(agent.id, agent.workingDir || officeManager.getCurrentWorkingDirectory());
148945
+ await this.startNewSession(agent.id, agent.workingDir || officeManager.getCurrentWorkingDirectory(), officeId);
148748
148946
  } else {
148947
+ this.fitAndResizeTerminal({ officeId, agentId: agent.id });
148749
148948
  const attachResult = await withTimeout(
148750
- window.copilotBridge.terminalAttach(this.getOfficeId(), agent.id),
148949
+ window.copilotBridge.terminalAttach(officeId, agent.id),
148751
148950
  IPC_TIMEOUT,
148752
148951
  "terminalAttach"
148753
148952
  );
@@ -148758,7 +148957,7 @@ WARNING: This link could potentially be dangerous`)) {
148758
148957
  this.isReplaying = false;
148759
148958
  this.scene.game.events.emit("agent:reattached", agent.id);
148760
148959
  const savedId = await withTimeout(
148761
- window.copilotBridge.getSessionId(this.getOfficeId(), agent.id),
148960
+ window.copilotBridge.getSessionId(officeId, agent.id),
148762
148961
  IPC_TIMEOUT,
148763
148962
  "getSessionId"
148764
148963
  );
@@ -148806,18 +149005,20 @@ WARNING: This link could potentially be dangerous`)) {
148806
149005
  }
148807
149006
  }, 50);
148808
149007
  }
148809
- async startNewSession(agentId, workingDir) {
149008
+ async startNewSession(agentId, workingDir, officeId) {
149009
+ this.awaitingSessionIdRefresh = false;
149010
+ this.clearSessionRefreshTimers();
148810
149011
  this.sessionId = null;
148811
149012
  this.updateSessionDisplay();
148812
149013
  const el = this.spriteCardElement?.querySelector(".session-id-display");
148813
149014
  if (el) {
148814
149015
  el.textContent = "starting...";
148815
149016
  }
148816
- this.fitAddon?.fit();
148817
- const dims = this.fitAddon?.proposeDimensions();
149017
+ const targetOfficeId = officeId ?? this.getActiveOfficeId();
149018
+ const dims = this.fitAndResizeTerminal({ officeId: targetOfficeId, agentId });
148818
149019
  const result = await withTimeout(
148819
149020
  this.launchMode === "shell" ? window.copilotBridge.terminalStart(
148820
- this.getOfficeId(),
149021
+ targetOfficeId,
148821
149022
  agentId,
148822
149023
  workingDir,
148823
149024
  dims?.cols,
@@ -148825,7 +149026,7 @@ WARNING: This link could potentially be dangerous`)) {
148825
149026
  void 0,
148826
149027
  "shell"
148827
149028
  ) : window.copilotBridge.terminalStart(
148828
- this.getOfficeId(),
149029
+ targetOfficeId,
148829
149030
  agentId,
148830
149031
  workingDir,
148831
149032
  dims?.cols,
@@ -148842,15 +149043,7 @@ WARNING: This link could potentially be dangerous`)) {
148842
149043
  }
148843
149044
  }
148844
149045
  fetchSessionId(agentId) {
148845
- if (window.copilotBridge && !this.sessionId) {
148846
- const el = this.spriteCardElement?.querySelector(".session-id-display");
148847
- if (el) {
148848
- el.textContent = "fetching...";
148849
- }
148850
- setTimeout(() => {
148851
- window.copilotBridge.terminalWrite(this.getOfficeId(), agentId, "/session\r");
148852
- }, 200);
148853
- }
149046
+ this.scheduleSessionIdRefresh(agentId);
148854
149047
  }
148855
149048
  createContainer() {
148856
149049
  this.container = document.createElement("div");
@@ -148925,8 +149118,8 @@ WARNING: This link could potentially be dangerous`)) {
148925
149118
  this.spriteCardElement.id = "sprite-card";
148926
149119
  this.spriteCardElement.style.cssText = `
148927
149120
  width: 100%;
148928
- background: #1a1a2e;
148929
- border-top: 1px solid #3a5a8a;
149121
+ background: #13131f;
149122
+ border-top: 1px solid #252540;
148930
149123
  font-family: 'Cascadia Code', Consolas, monospace;
148931
149124
  font-size: 14px;
148932
149125
  color: #888;
@@ -148934,7 +149127,7 @@ WARNING: This link could potentially be dangerous`)) {
148934
149127
  flex-shrink: 0;
148935
149128
  justify-content: space-between;
148936
149129
  align-items: center;
148937
- padding: 15px 30px;
149130
+ padding: 16px 24px;
148938
149131
  box-sizing: border-box;
148939
149132
  position: relative;
148940
149133
  z-index: 10001;
@@ -148947,13 +149140,32 @@ WARNING: This link could potentially be dangerous`)) {
148947
149140
  gap: 20px;
148948
149141
  `;
148949
149142
  agentDisplay.innerHTML = `
148950
- <canvas class="agent-sprite-canvas" width="32" height="34" style="image-rendering: pixelated; width: 160px; height: 170px; border-radius: 8px;"></canvas>
148951
- <div style="display: flex; flex-direction: column; gap: 5px;">
148952
- <span class="agent-name-display" style="font-weight: bold; font-size: 28px;"></span>
148953
- <span style="color: #666; font-size: 12px;">Session ID: <span class="session-id-display" style="color: #4a9eff; cursor: pointer;">--</span></span>
149143
+ <div style="width: 72px; background: #2a2a40; border: 1px solid #3a3a58; border-radius: 8px; display: flex; align-items: center; justify-content: center; overflow: hidden; flex-shrink: 0;">
149144
+ <canvas class="agent-sprite-canvas" width="32" height="34" style="image-rendering: pixelated; width: 64px; height: 68px; display: block;"></canvas>
149145
+ </div>
149146
+ <div style="display: flex; flex-direction: column; gap: 4px; min-width: 0;">
149147
+ <span class="agent-name-display" style="font-weight: 700; font-size: 18px; color: #dde;"></span>
149148
+ <span class="agent-description-display" style="color: #778; font-size: 13px; line-height: 1.25;"></span>
149149
+ <span class="session-title-display" style="color: #c8d4ff; font-size: 14px; font-weight: 700; line-height: 1.25; cursor: text; max-width: min(520px, 52vw); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">Untitled session</span>
149150
+ <span style="color: #666; font-size: 11px;">Session ID: <span class="session-id-display" style="color: #4a9eff; cursor: pointer;">--</span></span>
148954
149151
  </div>
148955
149152
  `;
148956
149153
  this.spriteCardElement.appendChild(agentDisplay);
149154
+ const sessionTitleDisplay = this.spriteCardElement.querySelector(".session-title-display");
149155
+ if (sessionTitleDisplay) {
149156
+ sessionTitleDisplay.onclick = () => {
149157
+ void this.startSessionTitleEdit();
149158
+ };
149159
+ sessionTitleDisplay.onkeydown = (event) => {
149160
+ if (event.key === "Enter" || event.key === " ") {
149161
+ event.preventDefault();
149162
+ void this.startSessionTitleEdit();
149163
+ }
149164
+ };
149165
+ sessionTitleDisplay.tabIndex = 0;
149166
+ sessionTitleDisplay.setAttribute("role", "button");
149167
+ sessionTitleDisplay.setAttribute("aria-label", "Edit session title");
149168
+ }
148957
149169
  const controlsColumn = document.createElement("div");
148958
149170
  controlsColumn.style.cssText = `
148959
149171
  display: flex;
@@ -148979,28 +149191,28 @@ WARNING: This link could potentially be dangerous`)) {
148979
149191
  white-space: nowrap;
148980
149192
  `;
148981
149193
  const historyBtn = document.createElement("button");
148982
- historyBtn.textContent = "\u{1F4DC} Session History";
149194
+ historyBtn.textContent = "Session History";
148983
149195
  historyBtn.style.cssText = btnStyle;
148984
149196
  historyBtn.onmouseover = () => historyBtn.style.background = "#3a4a5a";
148985
149197
  historyBtn.onmouseout = () => historyBtn.style.background = "#2a3a4a";
148986
149198
  historyBtn.onclick = () => this.toggleSessionHistory(historyBtn);
148987
149199
  buttonGrid.appendChild(historyBtn);
148988
149200
  const newSessionBtn = document.createElement("button");
148989
- newSessionBtn.textContent = "\u{1F504} New Session";
149201
+ newSessionBtn.textContent = "New Session";
148990
149202
  newSessionBtn.style.cssText = btnStyle;
148991
149203
  newSessionBtn.onmouseover = () => newSessionBtn.style.background = "#3a4a5a";
148992
149204
  newSessionBtn.onmouseout = () => newSessionBtn.style.background = "#2a3a4a";
148993
149205
  newSessionBtn.onclick = () => this.handleNewSession();
148994
149206
  buttonGrid.appendChild(newSessionBtn);
148995
149207
  const clearHistoryBtn = document.createElement("button");
148996
- clearHistoryBtn.textContent = "\u{1F5D1}\uFE0F Clear History";
149208
+ clearHistoryBtn.textContent = "Clear History";
148997
149209
  clearHistoryBtn.style.cssText = btnStyle;
148998
149210
  clearHistoryBtn.onmouseover = () => clearHistoryBtn.style.background = "#3a4a5a";
148999
149211
  clearHistoryBtn.onmouseout = () => clearHistoryBtn.style.background = "#2a3a4a";
149000
149212
  clearHistoryBtn.onclick = () => this.handleClearHistory();
149001
149213
  buttonGrid.appendChild(clearHistoryBtn);
149002
149214
  const closeSessionBtn = document.createElement("button");
149003
- closeSessionBtn.textContent = "\u23F9 Close Session";
149215
+ closeSessionBtn.textContent = "Close Session";
149004
149216
  closeSessionBtn.style.cssText = btnStyle + "color: #ff8888;";
149005
149217
  closeSessionBtn.onmouseover = () => {
149006
149218
  closeSessionBtn.style.background = "#4a2a2a";
@@ -149011,7 +149223,7 @@ WARNING: This link could potentially be dangerous`)) {
149011
149223
  closeSessionBtn.onclick = () => this.handleCloseSession();
149012
149224
  buttonGrid.appendChild(closeSessionBtn);
149013
149225
  this.fullscreenBtn = document.createElement("button");
149014
- this.fullscreenBtn.textContent = this.isFullWidth ? "\u26F6 Half" : "\u26F6 Fullscreen";
149226
+ this.fullscreenBtn.textContent = this.isFullWidth ? "Half Width" : "Full Width";
149015
149227
  this.fullscreenBtn.style.cssText = btnStyle + "color: #88ccff;";
149016
149228
  this.fullscreenBtn.onmouseover = () => {
149017
149229
  if (this.fullscreenBtn) this.fullscreenBtn.style.background = "#2a3a5a";
@@ -149023,7 +149235,7 @@ WARNING: This link could potentially be dangerous`)) {
149023
149235
  this.fullscreenBtn.title = "Toggle fullscreen (Ctrl+F)";
149024
149236
  buttonGrid.appendChild(this.fullscreenBtn);
149025
149237
  const refreshFocusBtn = document.createElement("button");
149026
- refreshFocusBtn.textContent = "\u{1F3AF} Refresh Focus";
149238
+ refreshFocusBtn.textContent = "Refresh Focus";
149027
149239
  refreshFocusBtn.style.cssText = btnStyle + "color: #88ffaa;";
149028
149240
  refreshFocusBtn.onmouseover = () => {
149029
149241
  refreshFocusBtn.style.background = "#2a4a3a";
@@ -149031,8 +149243,8 @@ WARNING: This link could potentially be dangerous`)) {
149031
149243
  refreshFocusBtn.onmouseout = () => {
149032
149244
  refreshFocusBtn.style.background = "#2a3a4a";
149033
149245
  };
149034
- refreshFocusBtn.onclick = () => this.focusTerminal();
149035
- refreshFocusBtn.title = "Re-focus terminal input when typing stops working";
149246
+ refreshFocusBtn.onclick = () => this.refreshFocusAndGeometry();
149247
+ refreshFocusBtn.title = "Re-focus terminal and force geometry self-heal";
149036
149248
  buttonGrid.appendChild(refreshFocusBtn);
149037
149249
  this.mobileKeyboardBtn = document.createElement("button");
149038
149250
  this.mobileKeyboardBtn.textContent = "\u2328 Open Keyboard";
@@ -149083,8 +149295,13 @@ WARNING: This link could potentially be dangerous`)) {
149083
149295
  }
149084
149296
  async handleNewSession() {
149085
149297
  if (!this.currentAgentId || !this.currentAgent || this.isReadOnly) return;
149298
+ this.awaitingSessionIdRefresh = false;
149299
+ this.clearSessionRefreshTimers();
149086
149300
  const officeId = this.attachedOfficeId ?? this.getOfficeId();
149087
149301
  console.log(`[TerminalOverlay] handleNewSession: agent=${this.currentAgentId}, office=${officeId}`);
149302
+ this.clearRefitTimers();
149303
+ this.refitGeneration += 1;
149304
+ this.pendingInputLine = "";
149088
149305
  this.terminal?.clear();
149089
149306
  this.terminal?.writeln("\x1B[33m[Starting new session...]\x1B[0m\r\n");
149090
149307
  await withTimeout(
@@ -149097,8 +149314,8 @@ WARNING: This link could potentially be dangerous`)) {
149097
149314
  if (el) el.textContent = "starting...";
149098
149315
  this.sessionId = null;
149099
149316
  this.updateSessionDisplay();
149100
- this.fitAddon?.fit();
149101
- const dims = this.fitAddon?.proposeDimensions();
149317
+ this.updateSessionTitleDisplay(null);
149318
+ const dims = this.fitAndResizeTerminal({ officeId, agentId: this.currentAgentId });
149102
149319
  const result = await withTimeout(
149103
149320
  this.launchMode === "shell" ? window.copilotBridge.terminalStart(
149104
149321
  officeId,
@@ -149138,6 +149355,7 @@ WARNING: This link could potentially be dangerous`)) {
149138
149355
  if (result.success && result.sessionId) {
149139
149356
  this.sessionId = result.sessionId;
149140
149357
  this.updateSessionDisplay();
149358
+ this.updateSessionTitleDisplay(null);
149141
149359
  }
149142
149360
  } catch {
149143
149361
  }
@@ -149240,9 +149458,6 @@ WARNING: This link could potentially be dangerous`)) {
149240
149458
  .xterm-viewport {
149241
149459
  background-color: #0a0a14 !important;
149242
149460
  }
149243
- .xterm-screen {
149244
- height: 100%;
149245
- }
149246
149461
  #terminal-container .xterm {
149247
149462
  height: 100%;
149248
149463
  }
@@ -149286,10 +149501,12 @@ WARNING: This link could potentially be dangerous`)) {
149286
149501
  this.fitAddon = new import_addon_fit.FitAddon();
149287
149502
  this.terminal.loadAddon(this.fitAddon);
149288
149503
  this.terminal.open(this.terminalDiv);
149289
- this.fitAddon.fit();
149504
+ this.fitAndResizeTerminal();
149290
149505
  this.terminal.attachCustomKeyEventHandler((event) => {
149291
- if ((event.ctrlKey || event.metaKey) && event.key === "v" && event.type === "keydown") {
149506
+ if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "v" && event.type === "keydown") {
149292
149507
  if (this.isReadOnly) return false;
149508
+ event.preventDefault();
149509
+ event.stopPropagation();
149293
149510
  navigator.clipboard.readText().then((text) => {
149294
149511
  if (text) this.terminal.paste(text);
149295
149512
  }).catch((err) => {
@@ -149301,8 +149518,34 @@ WARNING: This link could potentially be dangerous`)) {
149301
149518
  });
149302
149519
  this.terminal.onData((data) => {
149303
149520
  if (this.isReadOnly) return;
149304
- if (this.currentAgentId && window.copilotBridge) {
149305
- window.copilotBridge.terminalWrite(this.getOfficeId(), this.currentAgentId, data);
149521
+ if (!this.currentAgentId || !window.copilotBridge) return;
149522
+ let outbound = "";
149523
+ let shouldStartSlashNewSession = false;
149524
+ for (const ch of data) {
149525
+ if (ch === "\r" || ch === "\n") {
149526
+ const command = this.pendingInputLine.trim();
149527
+ this.pendingInputLine = "";
149528
+ if (command === "/new") {
149529
+ shouldStartSlashNewSession = true;
149530
+ }
149531
+ outbound += ch;
149532
+ continue;
149533
+ }
149534
+ if (ch === "\x7F") {
149535
+ this.pendingInputLine = this.pendingInputLine.slice(0, -1);
149536
+ outbound += ch;
149537
+ continue;
149538
+ }
149539
+ if (ch >= " ") {
149540
+ this.pendingInputLine += ch;
149541
+ }
149542
+ outbound += ch;
149543
+ }
149544
+ if (outbound.length > 0) {
149545
+ window.copilotBridge.terminalWrite(this.getOfficeId(), this.currentAgentId, outbound);
149546
+ }
149547
+ if (shouldStartSlashNewSession) {
149548
+ this.fetchSessionId(this.currentAgentId);
149306
149549
  }
149307
149550
  });
149308
149551
  this.resizeHandler = () => {
@@ -149370,18 +149613,27 @@ WARNING: This link could potentially be dangerous`)) {
149370
149613
  officePanel.style.width = "50%";
149371
149614
  terminalPanel.style.width = "50%";
149372
149615
  }
149616
+ refreshFocusAndGeometry() {
149617
+ this.clearRefitTimers();
149618
+ this.refitGeneration += 1;
149619
+ this.fitAndResizeTerminal({ refreshVisibleRows: true });
149620
+ this.focusTerminal();
149621
+ this.debouncedRefit();
149622
+ }
149373
149623
  /** Re-fit xterm after panel resize and notify PTY of new dimensions.
149374
149624
  * Multi-stage: immediate → 150ms → 350ms to catch late layout shifts. */
149375
149625
  debouncedRefit() {
149376
149626
  if (!this.fitAddon || !this.terminal || !this.currentAgentId) return;
149377
- for (const t of this.refitTimers) clearTimeout(t);
149378
- this.refitTimers.length = 0;
149627
+ const generation = ++this.refitGeneration;
149628
+ const agentId = this.currentAgentId;
149629
+ const officeId = this.getActiveOfficeId();
149630
+ this.clearRefitTimers();
149379
149631
  const doFit = () => {
149380
- this.fitAddon?.fit();
149381
- const dims = this.fitAddon?.proposeDimensions();
149382
- if (dims && window.copilotBridge && this.currentAgentId) {
149383
- window.copilotBridge.terminalResize(this.getOfficeId(), this.currentAgentId, dims.cols, dims.rows);
149384
- }
149632
+ if (!this.isVisible) return;
149633
+ if (generation !== this.refitGeneration) return;
149634
+ if (this.currentAgentId !== agentId) return;
149635
+ if (this.getActiveOfficeId() !== officeId) return;
149636
+ this.fitAndResizeTerminal({ officeId, agentId });
149385
149637
  };
149386
149638
  requestAnimationFrame(() => {
149387
149639
  doFit();
@@ -149405,14 +149657,8 @@ WARNING: This link could potentially be dangerous`)) {
149405
149657
  }
149406
149658
  applySpriteCardResponsiveStyles() {
149407
149659
  if (!this.spriteCardElement) return;
149408
- const isMobile = window.__copilotOfficeMobileModeActive?.() === true;
149409
- if (isMobile) {
149410
- this.spriteCardElement.style.minHeight = "416px";
149411
- this.spriteCardElement.style.padding = "39px";
149412
- return;
149413
- }
149414
149660
  this.spriteCardElement.style.minHeight = "";
149415
- this.spriteCardElement.style.padding = "15px 30px";
149661
+ this.spriteCardElement.style.padding = "16px 24px";
149416
149662
  }
149417
149663
  updateMobileKeyboardButtonVisibility() {
149418
149664
  if (!this.mobileKeyboardBtn) return;
@@ -149467,8 +149713,8 @@ WARNING: This link could potentially be dangerous`)) {
149467
149713
  setTerminalFocusVisual(focused) {
149468
149714
  this.isFocused = focused;
149469
149715
  if (this.spriteCardElement && this.spriteCardElement.style.display !== "none") {
149470
- this.spriteCardElement.style.background = focused ? "#1a1a2e" : "#111118";
149471
- this.spriteCardElement.style.borderTopColor = focused ? "#3a5a8a" : "#2a2a3a";
149716
+ this.spriteCardElement.style.background = focused ? "#13131f" : "#101019";
149717
+ this.spriteCardElement.style.borderTopColor = focused ? "#252540" : "#1c1c2f";
149472
149718
  }
149473
149719
  }
149474
149720
  setupKeyboardHandler() {
@@ -149483,6 +149729,9 @@ WARNING: This link could potentially be dangerous`)) {
149483
149729
  this.updateMobileKeyboardButtonVisibility();
149484
149730
  this.isVisible = false;
149485
149731
  this.isReadOnly = false;
149732
+ this.pendingInputLine = "";
149733
+ this.awaitingSessionIdRefresh = false;
149734
+ this.clearSessionRefreshTimers();
149486
149735
  this.closeHistoryPopover();
149487
149736
  this.restorePanelLayout();
149488
149737
  this.inputManager.deactivateTerminalF10();
@@ -149521,8 +149770,9 @@ WARNING: This link could potentially be dangerous`)) {
149521
149770
  return false;
149522
149771
  }
149523
149772
  destroy() {
149524
- for (const t of this.refitTimers) clearTimeout(t);
149525
- this.refitTimers.length = 0;
149773
+ this.clearRefitTimers();
149774
+ this.awaitingSessionIdRefresh = false;
149775
+ this.clearSessionRefreshTimers();
149526
149776
  if (this.resizeHandler) {
149527
149777
  window.removeEventListener("resize", this.resizeHandler);
149528
149778
  this.resizeHandler = null;
@@ -150477,8 +150727,11 @@ WARNING: This link could potentially be dangerous`)) {
150477
150727
  "use strict";
150478
150728
  DESKTOP_DASHBOARD_TYPOGRAPHY = {
150479
150729
  cardTitle: "15px",
150730
+ cardTitleLg: "18px",
150480
150731
  cardDescription: "11px",
150481
150732
  statusText: "11px",
150733
+ statusPanelText: "13px",
150734
+ statusPanelIcon: "26px",
150482
150735
  statusDot: "8px",
150483
150736
  elapsed: "10px",
150484
150737
  badge: "10px",
@@ -150489,14 +150742,18 @@ WARNING: This link could potentially be dangerous`)) {
150489
150742
  taskSummary: "10px",
150490
150743
  sessionLabel: "9px",
150491
150744
  sessionTitle: "13px",
150745
+ sessionTitleLg: "15px",
150492
150746
  sessionButton: "11px",
150493
150747
  emptyState: "11px",
150494
150748
  arthurHint: "10px"
150495
150749
  };
150496
150750
  MOBILE_DASHBOARD_TYPOGRAPHY = {
150497
150751
  cardTitle: "19px",
150752
+ cardTitleLg: "24px",
150498
150753
  cardDescription: "15px",
150499
150754
  statusText: "16px",
150755
+ statusPanelText: "18px",
150756
+ statusPanelIcon: "34px",
150500
150757
  statusDot: "11px",
150501
150758
  elapsed: "14px",
150502
150759
  badge: "13px",
@@ -150507,6 +150764,7 @@ WARNING: This link could potentially be dangerous`)) {
150507
150764
  taskSummary: "14px",
150508
150765
  sessionLabel: "13px",
150509
150766
  sessionTitle: "17px",
150767
+ sessionTitleLg: "20px",
150510
150768
  sessionButton: "14px",
150511
150769
  emptyState: "14px",
150512
150770
  arthurHint: "14px"
@@ -150538,6 +150796,7 @@ WARNING: This link could potentially be dangerous`)) {
150538
150796
  display: flex;
150539
150797
  align-items: center;
150540
150798
  gap: 12px;
150799
+ min-height: 108px;
150541
150800
  ">
150542
150801
  <div style="
150543
150802
  width: 64px;
@@ -150626,11 +150885,11 @@ WARNING: This link could potentially be dangerous`)) {
150626
150885
  padding: 0 4px;
150627
150886
  box-shadow: 0 1px 4px rgba(0,0,0,0.4);
150628
150887
  ">${unread}</div>` : "";
150629
- const elapsedHtml = elapsed ? `<span data-elapsed-agent="${agent.id}" style="color: #8a8; font-size: ${t.elapsed}; margin-left: 8px;">\u23F1 ${elapsed}</span>` : "";
150630
- const queueHtml = toolCount > 1 ? `<span style="
150888
+ const elapsedHtml = elapsed ? `<div data-elapsed-agent="${agent.id}" style="color: #8a8; font-size: ${t.elapsed}; margin-top: 4px;">\u23F1 ${elapsed}</div>` : "";
150889
+ const queueHtml = toolCount > 1 ? `<div style="
150631
150890
  background: #334; color: #aac; font-size: ${t.queue};
150632
- padding: 1px 6px; border-radius: 8px; margin-left: 6px;
150633
- ">${toolCount} tools</span>` : "";
150891
+ padding: 2px 8px; border-radius: 8px; margin-top: 4px;
150892
+ ">${toolCount} tools queued</div>` : "";
150634
150893
  let toolPipelineHtml = "";
150635
150894
  if (tools.length > 0) {
150636
150895
  const toolRows = tools.map((t2, i) => {
@@ -150686,12 +150945,19 @@ WARNING: This link could potentially be dangerous`)) {
150686
150945
  ">
150687
150946
  <div style="font-size: ${t.sessionLabel}; color: #3a3a5a; text-transform: uppercase; letter-spacing: 0.5px;">Session Info</div>
150688
150947
  <div class="session-title-display" data-agent="${agent.id}" style="
150689
- font-weight: bold; color: ${metaTitle ? "#ccd" : "#444"}; font-size: ${t.sessionTitle};
150948
+ font-weight: bold; color: ${metaTitle ? "#ccd" : "#444"}; font-size: ${t.sessionTitleLg};
150690
150949
  cursor: text; min-height: 18px; line-height: 1.4;
150691
150950
  overflow: hidden; text-overflow: ellipsis;
150692
150951
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
150693
150952
  " title="${metaTitle ? metaTitle.replace(/"/g, "&quot;") : "Click to set title"}">${metaTitle || "Untitled session"}</div>
150694
- <div style="display: flex; justify-content: flex-end; margin-top: 2px;">
150953
+ <button class="session-new-btn" data-agent="${agent.id}" style="
150954
+ margin-top: 2px;
150955
+ align-self: flex-start;
150956
+ background: #2a3a4a; border: 1px solid #4a5a6a; color: #a9cff7;
150957
+ font-size: ${t.sessionButton}; padding: 4px 10px; border-radius: 4px;
150958
+ cursor: pointer; transition: background 0.15s, border-color 0.15s;
150959
+ " title="Start a new session for this agent">\u{1F504} New Session</button>
150960
+ <div style="display: flex; justify-content: flex-end;">
150695
150961
  <button class="session-edit-btn" data-agent="${agent.id}" style="
150696
150962
  background: none; border: 1px solid #333; color: #667;
150697
150963
  font-size: ${t.sessionButton}; padding: 2px 8px; border-radius: 4px;
@@ -150725,46 +150991,60 @@ WARNING: This link could potentially be dangerous`)) {
150725
150991
  align-items: flex-start;
150726
150992
  gap: 14px;
150727
150993
  position: relative;
150728
- min-height: 200px;
150994
+ min-height: 236px;
150729
150995
  ">
150730
150996
  ${badgeHtml}
150731
- <div style="
150732
- flex-shrink: 0;
150733
- width: 72px;
150734
- background: ${colorHex}22;
150735
- border: 1px solid ${colorHex}44;
150736
- border-radius: 8px;
150737
- display: flex;
150738
- align-items: center;
150739
- justify-content: center;
150740
- overflow: hidden;
150741
- align-self: flex-start;
150742
- margin-top: 4px;
150743
- ">
150744
- <canvas
150745
- id="overview-sprite-${agent.id}"
150746
- width="32" height="34"
150747
- style="image-rendering: pixelated; width: 64px; height: 68px; display: block;"
150748
- ></canvas>
150997
+ <div style="flex-shrink: 0; width: 96px; display: flex; flex-direction: column; align-items: stretch; gap: 10px;">
150998
+ <div style="
150999
+ width: 96px;
151000
+ background: ${colorHex}22;
151001
+ border: 1px solid ${colorHex}44;
151002
+ border-radius: 10px;
151003
+ display: flex;
151004
+ align-items: center;
151005
+ justify-content: center;
151006
+ overflow: hidden;
151007
+ align-self: flex-start;
151008
+ padding: 6px 0;
151009
+ ">
151010
+ <canvas
151011
+ id="overview-sprite-${agent.id}"
151012
+ width="32" height="34"
151013
+ style="image-rendering: pixelated; width: 72px; height: 76px; display: block;"
151014
+ ></canvas>
151015
+ </div>
151016
+ <div style="
151017
+ border: 1px solid ${statusDot}66;
151018
+ background: ${statusDot}22;
151019
+ border-radius: 10px;
151020
+ padding: 8px 6px;
151021
+ display: flex;
151022
+ flex-direction: column;
151023
+ align-items: center;
151024
+ text-align: center;
151025
+ min-height: 96px;
151026
+ justify-content: center;
151027
+ ">
151028
+ <div style="font-size: ${t.statusPanelIcon}; line-height: 1;">${statusIcon}</div>
151029
+ <div style="
151030
+ margin-top: 6px;
151031
+ font-size: ${t.statusPanelText};
151032
+ color: ${statusDot};
151033
+ line-height: 1.15;
151034
+ font-weight: 700;
151035
+ white-space: normal;
151036
+ word-break: break-word;
151037
+ ">${statusLabel}</div>
151038
+ ${elapsedHtml}
151039
+ ${queueHtml}
151040
+ </div>
150749
151041
  </div>
150750
151042
  <div style="flex: 3; min-width: 0; display: flex; flex-direction: column; gap: 4px;">
150751
151043
  <div>
150752
- <div style="font-weight: bold; color: #dde; font-size: ${t.cardTitle};">${agent.name}</div>
151044
+ <div style="font-weight: bold; color: #dde; font-size: ${t.cardTitleLg};">${agent.name}</div>
150753
151045
  <div style="color: #778; font-size: ${t.cardDescription}; margin-top: 3px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;">${agent.description}</div>
150754
151046
  </div>
150755
151047
  <div>
150756
- <div style="display: flex; align-items: center; flex-wrap: wrap; margin-top: 4px;">
150757
- <div style="
150758
- font-size: ${t.statusText};
150759
- color: ${statusDot};
150760
- display: flex; align-items: center; gap: 4px;
150761
- ">
150762
- <span style="font-size: ${t.statusDot};">\u25CF</span>
150763
- <span>${statusIcon} ${statusLabel}</span>
150764
- </div>
150765
- ${elapsedHtml}
150766
- ${queueHtml}
150767
- </div>
150768
151048
  ${taskSummaryHtml}
150769
151049
  </div>
150770
151050
  ${toolPipelineHtml}
@@ -150795,6 +151075,10 @@ WARNING: This link could potentially be dangerous`)) {
150795
151075
  context.emitOpenTerminal(agentId);
150796
151076
  },
150797
151077
  handleMetaPanelClick(target, agentId, context) {
151078
+ if (target.closest(".session-new-btn")) {
151079
+ context.startNewSession(agentId);
151080
+ return;
151081
+ }
150798
151082
  if (target.closest(".session-edit-btn") || target.closest(".session-title-display")) {
150799
151083
  context.startSessionMetaEdit(agentId);
150800
151084
  }
@@ -150896,7 +151180,7 @@ WARNING: This link could potentially be dangerous`)) {
150896
151180
  background: ${bgColor};
150897
151181
  border: 1.5px solid ${borderColor};
150898
151182
  border-radius: 10px;
150899
- padding: 14px 16px;
151183
+ padding: 18px 16px;
150900
151184
  margin-bottom: 8px;
150901
151185
  cursor: ${cursor};
150902
151186
  transition: border-color 0.15s;
@@ -150904,6 +151188,7 @@ WARNING: This link could potentially be dangerous`)) {
150904
151188
  align-items: flex-start;
150905
151189
  gap: 12px;
150906
151190
  position: relative;
151191
+ min-height: 124px;
150907
151192
  ">
150908
151193
  <div style="
150909
151194
  flex-shrink: 0;
@@ -153555,12 +153840,8 @@ WARNING: This link could potentially be dangerous`)) {
153555
153840
  if (this.currentLayout === "default") {
153556
153841
  const officeId = officeManager.currentOfficeId;
153557
153842
  if (officeId) {
153558
- const seatedAgents = officeManager.getSeatedAgents(officeId);
153559
- for (const { deskId, agentId } of seatedAgents) {
153560
- const reserveConfig = RESERVE_AGENTS[deskId];
153561
- if (!reserveConfig || reserveConfig.id !== agentId) continue;
153562
- if (AGENTS.find((a) => a.id === agentId)) continue;
153563
- AGENTS.push(reserveConfig);
153843
+ const restoredSeatedAgents = restoreSeatedReserveAgents(officeManager.getSeatedAgents(officeId));
153844
+ for (const { deskId, agentId } of restoredSeatedAgents) {
153564
153845
  const desk = this.desks.find((d) => d.agentId === deskId);
153565
153846
  if (desk) {
153566
153847
  desk.agentId = agentId;
@@ -155443,165 +155724,1005 @@ WARNING: This link could potentially be dangerous`)) {
155443
155724
  }
155444
155725
  });
155445
155726
 
155446
- // src/main.ts
155447
- var require_main = __commonJS({
155448
- "src/main.ts"() {
155449
- var import_phaser10 = __toESM(require_phaser());
155450
- init_BootScene();
155451
- init_OfficeScene();
155452
- init_MeetingScene();
155453
- init_officeManager();
155454
- init_agents();
155455
- init_responsiveLayout();
155456
- init_layouts();
155457
- init_ToastNotification();
155458
- init_NotificationService();
155459
- init_SettingsPanel();
155460
- init_SpriteCustomizerPanel();
155461
- init_SpriteGenerator();
155462
- officeManager.ensureDefaultOffice();
155463
- function getCurrentLayout() {
155464
- return officeManager.currentOffice?.config.layout ?? "default";
155465
- }
155466
- function getCurrentAgents() {
155467
- return getLayout(getCurrentLayout()).agents;
155468
- }
155469
- function getCurrentAgentTools() {
155470
- return officeManager.currentOffice?.agentTools || /* @__PURE__ */ new Map();
155471
- }
155472
- function normalizeToolName(toolName) {
155473
- return (toolName ?? "").trim().toLowerCase().replace(/[\s-]+/g, "_");
155474
- }
155475
- function isAskUserTool(toolName, status) {
155476
- const normalized = normalizeToolName(toolName);
155477
- if (normalized === "ask_user" || normalized === "askuser") return true;
155478
- const statusText = (status ?? "").toLowerCase();
155479
- return statusText.includes("waiting for your answer") || statusText.includes("waiting on user input");
155480
- }
155481
- function isDonePendingAck(status) {
155482
- return !!status?.completionPendingAck;
155483
- }
155484
- var selectedAgentId = null;
155485
- var phaserGameRef;
155486
- var debugMode = false;
155487
- var currentZoom = parseFloat(localStorage.getItem("agencyOffice:zoomLevel") ?? "0.8");
155488
- currentZoom = isNaN(currentZoom) || currentZoom < 0.5 || currentZoom > 2 ? 0.8 : currentZoom;
155489
- var RESIZE_DEBOUNCE_MS = 200;
155490
- var agentPreloadStatus = /* @__PURE__ */ new Map();
155491
- var pendingStatusBarUpdate = false;
155492
- var pendingTerminalContentUpdate = false;
155493
- function scheduleUiUpdateWithFallback(callback) {
155494
- let done = false;
155495
- const runOnce = () => {
155496
- if (done) return;
155497
- done = true;
155498
- callback();
155499
- };
155500
- requestAnimationFrame(runOnce);
155501
- const fallbackDelayMs = document.hidden ? 80 : 200;
155502
- setTimeout(runOnce, fallbackDelayMs);
155503
- }
155504
- function scheduleStatusBarUpdate() {
155505
- if (pendingStatusBarUpdate) return;
155506
- pendingStatusBarUpdate = true;
155507
- scheduleUiUpdateWithFallback(() => {
155508
- pendingStatusBarUpdate = false;
155509
- updateStatusBarNow();
155510
- });
155511
- }
155512
- function scheduleTerminalContentUpdate() {
155513
- if (pendingTerminalContentUpdate) return;
155514
- pendingTerminalContentUpdate = true;
155515
- scheduleUiUpdateWithFallback(() => {
155516
- pendingTerminalContentUpdate = false;
155517
- updateTerminalContentNow();
155518
- });
155519
- }
155520
- var container = document.getElementById("game-container");
155521
- container.innerHTML = "";
155522
- container.style.cssText = "display: flex; flex-direction: column; width: 100%; height: calc(100% - 58px);";
155523
- var tabsBar = document.createElement("div");
155524
- tabsBar.id = "office-tabs";
155525
- tabsBar.style.cssText = `
155526
- display: flex;
155527
- align-items: center;
155528
- background: #1a1a2a;
155529
- border-bottom: 2px solid #333;
155530
- padding: 0 16px;
155531
- height: 72px;
155532
- flex-shrink: 0;
155533
- font-size: 22px;
155534
- `;
155535
- container.appendChild(tabsBar);
155536
- var mainContent = document.createElement("div");
155537
- mainContent.style.cssText = "display: flex; flex: 1; min-height: 0;";
155538
- container.appendChild(mainContent);
155539
- var officePanel = document.createElement("div");
155540
- officePanel.id = "office-panel";
155541
- officePanel.style.cssText = "width: 50%; height: 100%; position: relative;";
155542
- mainContent.appendChild(officePanel);
155543
- var terminalPanel = document.createElement("div");
155544
- terminalPanel.id = "terminal-panel";
155545
- terminalPanel.style.cssText = `
155546
- width: 50%;
155547
- height: 100%;
155548
- background: #1e1e2e;
155549
- border-left: 2px solid #333;
155550
- display: flex;
155551
- flex-direction: column;
155552
- position: relative;
155553
- `;
155554
- mainContent.appendChild(terminalPanel);
155555
- var currentResponsiveLayout = "default";
155556
- var resizeDebounceTimer = null;
155557
- function isMobileModeActive() {
155558
- return currentResponsiveLayout === "portrait-dashboard";
155559
- }
155560
- function applyMobileTopBarVisibility() {
155561
- const hidden = isMobileModeActive();
155562
- const ids = ["zoom-bar", "sprite-customizer-btn", "debug-toggle-btn"];
155563
- for (const id of ids) {
155564
- const el = document.getElementById(id);
155565
- if (!el) continue;
155566
- el.style.display = hidden ? "none" : "";
155567
- }
155568
- }
155569
- function applyResponsiveLayout(layoutKey) {
155570
- if (layoutKey === currentResponsiveLayout) return;
155571
- currentResponsiveLayout = layoutKey;
155572
- if (layoutKey === "portrait-dashboard") {
155573
- officePanel.style.display = "none";
155574
- terminalPanel.style.width = "100%";
155575
- terminalPanel.style.borderLeft = "none";
155576
- } else {
155577
- officePanel.style.display = "";
155578
- terminalPanel.style.width = "50%";
155579
- terminalPanel.style.borderLeft = "2px solid #333";
155580
- }
155581
- if (phaserGameRef) {
155582
- phaserGameRef.events.emit("layout:change", { layoutKey });
155583
- if (layoutKey === "default") {
155584
- const width = officePanel.clientWidth || window.innerWidth / 2;
155585
- const height = officePanel.clientHeight || window.innerHeight;
155586
- phaserGameRef.scale.resize(width, height);
155587
- }
155588
- }
155589
- applyMobileTopBarVisibility();
155590
- }
155591
- function onWindowResize() {
155592
- if (resizeDebounceTimer !== null) {
155593
- window.clearTimeout(resizeDebounceTimer);
155594
- }
155595
- resizeDebounceTimer = window.setTimeout(() => {
155727
+ // src/ui/SeriousTerminalController.ts
155728
+ var import_xterm2, import_addon_fit2, SeriousTerminalController;
155729
+ var init_SeriousTerminalController = __esm({
155730
+ "src/ui/SeriousTerminalController.ts"() {
155731
+ "use strict";
155732
+ import_xterm2 = __toESM(require_xterm());
155733
+ import_addon_fit2 = __toESM(require_addon_fit());
155734
+ SeriousTerminalController = class _SeriousTerminalController {
155735
+ constructor(host, options = {}) {
155736
+ this.historyPopover = null;
155737
+ this.terminal = null;
155738
+ this.fitAddon = null;
155739
+ this.resizeObserver = null;
155740
+ this.resizeHandler = null;
155741
+ this.refitTimers = [];
155742
+ this.activeOfficeId = null;
155743
+ this.activeAgentId = null;
155744
+ this.visible = false;
155745
+ this.openedAt = 0;
155746
+ this.sessionId = null;
155747
+ this.activeOptions = null;
155748
+ this.isFullWidth = false;
155749
+ this.host = host;
155750
+ this.onClose = options.onClose;
155751
+ this.isFullWidth = localStorage.getItem(_SeriousTerminalController.FULL_WIDTH_STORAGE_KEY) === "true";
155752
+ this.container = document.createElement("div");
155753
+ this.container.style.cssText = `
155754
+ display: none;
155755
+ flex-direction: column;
155756
+ flex: 1;
155757
+ min-height: 0;
155758
+ background: #11131c;
155759
+ color: #d7defa;
155760
+ border-left: 2px solid #2f3f62;
155761
+ font-family: 'Cascadia Code', Consolas, monospace;
155762
+ `;
155763
+ const header = document.createElement("div");
155764
+ header.style.cssText = `
155765
+ display: flex;
155766
+ align-items: center;
155767
+ justify-content: space-between;
155768
+ gap: 8px;
155769
+ padding: 12px 14px;
155770
+ border-bottom: 1px solid #27314e;
155771
+ background: #171b2a;
155772
+ flex-shrink: 0;
155773
+ `;
155774
+ const leftHeader = document.createElement("div");
155775
+ leftHeader.style.cssText = "min-width: 0;";
155776
+ this.titleEl = document.createElement("div");
155777
+ this.titleEl.style.cssText = "font-size: 14px; font-weight: 700; color: #9fc2ff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;";
155778
+ this.subtitleEl = document.createElement("div");
155779
+ this.subtitleEl.style.cssText = "font-size: 11px; color: #7f8bad; margin-top: 3px;";
155780
+ leftHeader.appendChild(this.titleEl);
155781
+ leftHeader.appendChild(this.subtitleEl);
155782
+ const rightHeader = document.createElement("div");
155783
+ rightHeader.style.cssText = "display: flex; align-items: center; gap: 6px;";
155784
+ this.statusEl = document.createElement("div");
155785
+ this.statusEl.style.cssText = "font-size: 11px; color: #8ca2db; margin-right: 4px;";
155786
+ const detachBtn = document.createElement("button");
155787
+ detachBtn.textContent = "Detach";
155788
+ detachBtn.style.cssText = this.buttonCss("#2f3754", "#6f8ed8");
155789
+ detachBtn.addEventListener("click", () => {
155790
+ void this.closeView({ detach: true });
155791
+ });
155792
+ const closeBtn = document.createElement("button");
155793
+ closeBtn.textContent = "Close";
155794
+ closeBtn.style.cssText = this.buttonCss("#3a2534", "#c98fbb");
155795
+ closeBtn.addEventListener("click", () => {
155796
+ void this.closeView({ detach: true });
155797
+ });
155798
+ rightHeader.appendChild(this.statusEl);
155799
+ rightHeader.appendChild(detachBtn);
155800
+ rightHeader.appendChild(closeBtn);
155801
+ header.appendChild(leftHeader);
155802
+ header.appendChild(rightHeader);
155803
+ this.terminalOuterEl = document.createElement("div");
155804
+ this.terminalOuterEl.style.cssText = `
155805
+ flex: 1;
155806
+ min-height: 0;
155807
+ overflow: hidden;
155808
+ background: #0d111b;
155809
+ padding: 10px;
155810
+ box-sizing: border-box;
155811
+ `;
155812
+ this.terminalDivEl = document.createElement("div");
155813
+ this.terminalDivEl.style.cssText = "width: 100%; height: 100%; overflow: hidden;";
155814
+ this.terminalOuterEl.appendChild(this.terminalDivEl);
155815
+ this.terminalOuterEl.addEventListener("mousedown", () => this.terminal?.focus());
155816
+ this.spriteCardEl = document.createElement("div");
155817
+ this.spriteCardEl.style.cssText = `
155818
+ width: 100%;
155819
+ background: #13131f;
155820
+ border-top: 1px solid #252540;
155821
+ font-family: 'Cascadia Code', Consolas, monospace;
155822
+ color: #c8d4ff;
155823
+ display: flex;
155824
+ flex-shrink: 0;
155825
+ justify-content: space-between;
155826
+ align-items: stretch;
155827
+ gap: 24px;
155828
+ min-height: 148px;
155829
+ padding: 16px 24px;
155830
+ box-sizing: border-box;
155831
+ `;
155832
+ const spriteCardLeft = document.createElement("div");
155833
+ spriteCardLeft.style.cssText = "display: flex; align-items: center; gap: 18px; min-width: 0; flex: 1;";
155834
+ const spriteFrame = document.createElement("div");
155835
+ spriteFrame.style.cssText = `
155836
+ width: 72px;
155837
+ background: #2a2a40;
155838
+ border: 1px solid #3a3a58;
155839
+ border-radius: 8px;
155840
+ display: flex;
155841
+ align-items: center;
155842
+ justify-content: center;
155843
+ overflow: hidden;
155844
+ flex-shrink: 0;
155845
+ `;
155846
+ this.spriteCanvasEl = document.createElement("canvas");
155847
+ this.spriteCanvasEl.width = 32;
155848
+ this.spriteCanvasEl.height = 34;
155849
+ this.spriteCanvasEl.style.cssText = `
155850
+ image-rendering: pixelated;
155851
+ width: 64px;
155852
+ height: 68px;
155853
+ display: block;
155854
+ `;
155855
+ spriteFrame.appendChild(this.spriteCanvasEl);
155856
+ const spriteCardText = document.createElement("div");
155857
+ spriteCardText.style.cssText = "display: flex; flex-direction: column; gap: 4px; min-width: 0;";
155858
+ this.spriteNameEl = document.createElement("span");
155859
+ this.spriteNameEl.style.cssText = "font-size: 18px; font-weight: 700; color: #dde; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;";
155860
+ this.spriteSubtitleEl = document.createElement("span");
155861
+ this.spriteSubtitleEl.style.cssText = "font-size: 13px; color: #778; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;";
155862
+ this.sessionTitleEl = document.createElement("span");
155863
+ this.sessionTitleEl.textContent = "Untitled session";
155864
+ this.sessionTitleEl.style.cssText = "font-size: 14px; font-weight: 700; color: #77839f; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;";
155865
+ spriteCardText.appendChild(this.spriteNameEl);
155866
+ spriteCardText.appendChild(this.spriteSubtitleEl);
155867
+ spriteCardText.appendChild(this.sessionTitleEl);
155868
+ spriteCardLeft.appendChild(spriteFrame);
155869
+ spriteCardLeft.appendChild(spriteCardText);
155870
+ const spriteCardRight = document.createElement("div");
155871
+ spriteCardRight.style.cssText = "display: flex; flex-direction: column; justify-content: center; align-items: flex-end; gap: 8px;";
155872
+ const sessionLabel = document.createElement("span");
155873
+ sessionLabel.textContent = "Session ID";
155874
+ sessionLabel.style.cssText = "font-size: 11px; color: #6f7fa9;";
155875
+ this.sessionIdEl = document.createElement("span");
155876
+ this.sessionIdEl.textContent = "--";
155877
+ this.sessionIdEl.style.cssText = "font-size: 12px; color: #8ec3ff; cursor: pointer;";
155878
+ this.sessionIdEl.title = "Copy session ID";
155879
+ this.sessionIdEl.onclick = () => this.copySessionId();
155880
+ spriteCardRight.appendChild(sessionLabel);
155881
+ spriteCardRight.appendChild(this.sessionIdEl);
155882
+ const buttonGrid = document.createElement("div");
155883
+ buttonGrid.style.cssText = `
155884
+ display: grid;
155885
+ grid-template-columns: repeat(2, max-content);
155886
+ gap: 6px;
155887
+ margin-top: 2px;
155888
+ `;
155889
+ const footerBtnCss = this.buttonCss("#2a3a4a", "#4a5a6a");
155890
+ const historyBtn = document.createElement("button");
155891
+ historyBtn.textContent = "Session History";
155892
+ historyBtn.style.cssText = footerBtnCss;
155893
+ historyBtn.onclick = () => {
155894
+ void this.toggleSessionHistory(historyBtn);
155895
+ };
155896
+ buttonGrid.appendChild(historyBtn);
155897
+ const newSessionBtn = document.createElement("button");
155898
+ newSessionBtn.textContent = "New Session";
155899
+ newSessionBtn.style.cssText = footerBtnCss;
155900
+ newSessionBtn.onclick = () => {
155901
+ void this.handleNewSession();
155902
+ };
155903
+ buttonGrid.appendChild(newSessionBtn);
155904
+ const clearHistoryBtn = document.createElement("button");
155905
+ clearHistoryBtn.textContent = "Clear History";
155906
+ clearHistoryBtn.style.cssText = footerBtnCss;
155907
+ clearHistoryBtn.onclick = () => {
155908
+ void this.handleClearHistory();
155909
+ };
155910
+ buttonGrid.appendChild(clearHistoryBtn);
155911
+ const closeSessionBtn = document.createElement("button");
155912
+ closeSessionBtn.textContent = "Close Session";
155913
+ closeSessionBtn.style.cssText = this.buttonCss("#3a2a2a", "#8f5d5d");
155914
+ closeSessionBtn.onclick = () => {
155915
+ void this.handleCloseSession();
155916
+ };
155917
+ buttonGrid.appendChild(closeSessionBtn);
155918
+ this.fullscreenBtn = document.createElement("button");
155919
+ this.fullscreenBtn.textContent = this.isFullWidth ? "Half Width" : "Full Width";
155920
+ this.fullscreenBtn.style.cssText = this.buttonCss("#2a2f4a", "#5a6aa0");
155921
+ this.fullscreenBtn.onclick = () => this.toggleFullWidth();
155922
+ buttonGrid.appendChild(this.fullscreenBtn);
155923
+ const refreshFocusBtn = document.createElement("button");
155924
+ refreshFocusBtn.textContent = "Refresh Focus";
155925
+ refreshFocusBtn.style.cssText = this.buttonCss("#2a3a2a", "#4f7b63");
155926
+ refreshFocusBtn.onclick = () => this.refreshFocusAndGeometry();
155927
+ buttonGrid.appendChild(refreshFocusBtn);
155928
+ spriteCardRight.appendChild(buttonGrid);
155929
+ this.spriteCardEl.appendChild(spriteCardLeft);
155930
+ this.spriteCardEl.appendChild(spriteCardRight);
155931
+ this.ensureXtermStyles();
155932
+ this.container.appendChild(header);
155933
+ this.container.appendChild(this.terminalOuterEl);
155934
+ this.container.appendChild(this.spriteCardEl);
155935
+ this.host.appendChild(this.container);
155936
+ this.createTerminal();
155937
+ if (window.copilotBridge) {
155938
+ window.copilotBridge.onTerminalData((agentId, data) => {
155939
+ if (!this.visible || this.activeAgentId !== agentId) return;
155940
+ this.terminal?.write(data);
155941
+ });
155942
+ window.copilotBridge.onTerminalExit((agentId, exitCode) => {
155943
+ if (!this.visible || this.activeAgentId !== agentId) return;
155944
+ this.terminal?.writeln(`\r
155945
+ [terminal exited with code ${exitCode}]`);
155946
+ this.setStatus("Exited");
155947
+ });
155948
+ window.copilotBridge.onSessionMetaUpdated((agentId) => {
155949
+ if (!this.visible || !this.activeOfficeId || this.activeAgentId !== agentId) return;
155950
+ void this.updateSessionTitle(this.activeOfficeId, agentId);
155951
+ });
155952
+ }
155953
+ }
155954
+ static {
155955
+ this.FULL_WIDTH_STORAGE_KEY = "agencyOffice:seriousTerminalFullWidth";
155956
+ }
155957
+ isVisible() {
155958
+ return this.visible;
155959
+ }
155960
+ refreshCardFromOverview() {
155961
+ if (!this.visible || !this.activeAgentId) return;
155962
+ this.renderExactOverviewCard(this.activeAgentId);
155963
+ }
155964
+ async openAgentTerminal(options) {
155965
+ if (!window.copilotBridge || !this.terminal) return;
155966
+ const switchingTarget = this.activeOfficeId !== options.officeId || this.activeAgentId !== options.agentId;
155967
+ if (switchingTarget) {
155968
+ await this.closeView({ detach: true, silent: true });
155969
+ }
155970
+ this.activeOfficeId = options.officeId;
155971
+ this.activeAgentId = options.agentId;
155972
+ this.activeOptions = { ...options };
155973
+ this.visible = true;
155974
+ this.openedAt = Date.now();
155975
+ this.sessionId = null;
155976
+ this.container.style.display = "flex";
155977
+ this.terminal.clear();
155978
+ this.titleEl.textContent = `${options.name} (${options.agentId})`;
155979
+ this.subtitleEl.textContent = options.description;
155980
+ this.updateSpriteCard(options);
155981
+ void this.updateSessionTitle(options.officeId, options.agentId);
155982
+ this.updateSessionIdDisplay();
155983
+ this.setStatus("Opening...");
155984
+ this.applyPanelLayout();
155985
+ this.refitAndResize(options.officeId, options.agentId);
155986
+ try {
155987
+ const exists = await window.copilotBridge.terminalExists(options.officeId, options.agentId);
155988
+ if (!exists) {
155989
+ const dims = this.fitAddon?.proposeDimensions();
155990
+ const startResult = await window.copilotBridge.terminalStart(
155991
+ options.officeId,
155992
+ options.agentId,
155993
+ options.workingDir,
155994
+ dims?.cols,
155995
+ dims?.rows,
155996
+ void 0,
155997
+ options.launchMode || "copilot"
155998
+ );
155999
+ if (!startResult.success) {
156000
+ this.terminal.writeln(`\r
156001
+ Failed to start terminal: ${startResult.error || "unknown error"}`);
156002
+ this.setStatus("Start failed");
156003
+ return;
156004
+ }
156005
+ if (startResult.sessionId) {
156006
+ this.sessionId = startResult.sessionId;
156007
+ this.updateSessionIdDisplay();
156008
+ }
156009
+ }
156010
+ const attachResult = await window.copilotBridge.terminalAttach(options.officeId, options.agentId);
156011
+ if (!attachResult.success) {
156012
+ this.terminal.writeln("\r\nFailed to attach terminal session.");
156013
+ this.setStatus("Attach failed");
156014
+ return;
156015
+ }
156016
+ if (attachResult.scrollback) {
156017
+ this.terminal.write(attachResult.scrollback);
156018
+ }
156019
+ const attachedSessionId = await window.copilotBridge.getSessionId(options.officeId, options.agentId);
156020
+ if (attachedSessionId) {
156021
+ this.sessionId = attachedSessionId;
156022
+ this.updateSessionIdDisplay();
156023
+ }
156024
+ this.setStatus(`Attached \xB7 ${this.formatElapsed(this.openedAt)}`);
156025
+ this.terminal.focus();
156026
+ this.debouncedRefit(options.officeId, options.agentId);
156027
+ this.refreshCardFromOverview();
156028
+ } catch (error) {
156029
+ this.terminal.writeln(`\r
156030
+ Terminal error: ${error?.message || String(error)}`);
156031
+ this.setStatus("Error");
156032
+ this.refreshCardFromOverview();
156033
+ }
156034
+ }
156035
+ async startNewSession(options) {
156036
+ if (!window.copilotBridge) return;
156037
+ try {
156038
+ await window.copilotBridge.resetSession(options.officeId, options.agentId);
156039
+ } catch {
156040
+ }
156041
+ const isCurrentView = this.visible && this.activeOfficeId === options.officeId && this.activeAgentId === options.agentId;
156042
+ if (isCurrentView) {
156043
+ await this.openAgentTerminal(options);
156044
+ return;
156045
+ }
156046
+ const startResult = await window.copilotBridge.terminalStart(
156047
+ options.officeId,
156048
+ options.agentId,
156049
+ options.workingDir,
156050
+ void 0,
156051
+ void 0,
156052
+ void 0,
156053
+ options.launchMode || "copilot"
156054
+ );
156055
+ if (!startResult.success) {
156056
+ console.warn(
156057
+ `[SeriousTerminalController] Failed to start new session for ${options.agentId}: ${startResult.error || "unknown error"}`
156058
+ );
156059
+ }
156060
+ }
156061
+ async closeView(options = {}) {
156062
+ const { detach = true, silent = false } = options;
156063
+ if (detach && this.activeOfficeId && this.activeAgentId && window.copilotBridge) {
156064
+ try {
156065
+ await window.copilotBridge.terminalDetach(this.activeOfficeId, this.activeAgentId);
156066
+ } catch {
156067
+ }
156068
+ }
156069
+ this.visible = false;
156070
+ this.container.style.display = "none";
156071
+ this.activeOfficeId = null;
156072
+ this.activeAgentId = null;
156073
+ this.activeOptions = null;
156074
+ this.sessionId = null;
156075
+ this.sessionTitleEl.textContent = "Untitled session";
156076
+ this.sessionTitleEl.style.color = "#77839f";
156077
+ this.updateSessionIdDisplay();
156078
+ this.setStatus("");
156079
+ this.clearRefitTimers();
156080
+ this.closeSessionHistoryPopover();
156081
+ this.applyPanelLayout();
156082
+ if (!silent) {
156083
+ this.onClose?.();
156084
+ }
156085
+ }
156086
+ setStatus(text) {
156087
+ this.statusEl.textContent = text;
156088
+ }
156089
+ updateSpriteCard(options) {
156090
+ this.spriteNameEl.textContent = options.name;
156091
+ this.spriteSubtitleEl.textContent = options.description;
156092
+ const colorHex = `#${(options.color ?? 7311064).toString(16).padStart(6, "0")}`;
156093
+ this.spriteNameEl.style.color = colorHex;
156094
+ this.renderAgentSprite(options.agentId, options.color ?? 7311064);
156095
+ }
156096
+ updateSessionIdDisplay() {
156097
+ this.sessionIdEl.textContent = this.sessionId || "--";
156098
+ }
156099
+ renderExactOverviewCard(agentId) {
156100
+ const sourceCard = document.querySelector(`#overview-content .agent-card[data-agent="${agentId}"]`);
156101
+ if (!sourceCard) return;
156102
+ const clonedCard = sourceCard.cloneNode(true);
156103
+ clonedCard.style.marginBottom = "0";
156104
+ clonedCard.style.cursor = "default";
156105
+ const sourceCanvases = sourceCard.querySelectorAll("canvas");
156106
+ const cloneCanvases = clonedCard.querySelectorAll("canvas");
156107
+ cloneCanvases.forEach((node, i) => {
156108
+ const canvas = node;
156109
+ canvas.removeAttribute("id");
156110
+ const src = sourceCanvases[i];
156111
+ const ctx = canvas.getContext("2d");
156112
+ if (!src || !ctx) return;
156113
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
156114
+ ctx.drawImage(src, 0, 0);
156115
+ });
156116
+ this.spriteCardEl.style.display = "block";
156117
+ this.spriteCardEl.style.padding = "10px 10px 12px";
156118
+ this.spriteCardEl.style.minHeight = "0";
156119
+ this.spriteCardEl.style.gap = "0";
156120
+ this.spriteCardEl.style.alignItems = "stretch";
156121
+ this.spriteCardEl.style.justifyContent = "stretch";
156122
+ this.spriteCardEl.innerHTML = "";
156123
+ this.spriteCardEl.appendChild(clonedCard);
156124
+ }
156125
+ async updateSessionTitle(officeId, agentId) {
156126
+ if (!window.copilotBridge?.getSessionMeta) {
156127
+ this.sessionTitleEl.textContent = "Untitled session";
156128
+ this.sessionTitleEl.style.color = "#77839f";
156129
+ return;
156130
+ }
156131
+ try {
156132
+ const meta = await window.copilotBridge.getSessionMeta(officeId, agentId);
156133
+ const title = meta?.title?.trim();
156134
+ if (title) {
156135
+ this.sessionTitleEl.textContent = title;
156136
+ this.sessionTitleEl.style.color = "#c8d4ff";
156137
+ } else {
156138
+ this.sessionTitleEl.textContent = "Untitled session";
156139
+ this.sessionTitleEl.style.color = "#77839f";
156140
+ }
156141
+ } catch {
156142
+ this.sessionTitleEl.textContent = "Untitled session";
156143
+ this.sessionTitleEl.style.color = "#77839f";
156144
+ }
156145
+ }
156146
+ async handleNewSession() {
156147
+ if (!this.activeOptions) return;
156148
+ await this.startNewSession(this.activeOptions);
156149
+ this.closeSessionHistoryPopover();
156150
+ }
156151
+ async handleClearHistory() {
156152
+ if (!window.copilotBridge || !this.activeOfficeId || !this.activeAgentId) return;
156153
+ try {
156154
+ await window.copilotBridge.clearSessionHistory(this.activeOfficeId, this.activeAgentId);
156155
+ this.terminal?.writeln("\r\n[session history cleared]");
156156
+ this.closeSessionHistoryPopover();
156157
+ } catch {
156158
+ this.terminal?.writeln("\r\n[failed to clear session history]");
156159
+ }
156160
+ }
156161
+ async handleCloseSession() {
156162
+ if (!window.copilotBridge || !this.activeOfficeId || !this.activeAgentId) return;
156163
+ try {
156164
+ await window.copilotBridge.resetSession(this.activeOfficeId, this.activeAgentId);
156165
+ this.terminal?.writeln("\r\n[session closed]");
156166
+ } catch {
156167
+ this.terminal?.writeln("\r\n[failed to close session]");
156168
+ }
156169
+ await this.closeView({ detach: true });
156170
+ }
156171
+ async toggleSessionHistory(anchor) {
156172
+ if (!window.copilotBridge || !this.activeOfficeId || !this.activeAgentId) return;
156173
+ if (this.historyPopover) {
156174
+ this.closeSessionHistoryPopover();
156175
+ return;
156176
+ }
156177
+ let history = [];
156178
+ try {
156179
+ history = await window.copilotBridge.getSessionHistory(this.activeOfficeId, this.activeAgentId);
156180
+ } catch {
156181
+ history = [];
156182
+ }
156183
+ const pop = document.createElement("div");
156184
+ pop.style.cssText = `
156185
+ position: absolute;
156186
+ right: 12px;
156187
+ bottom: calc(100% + 8px);
156188
+ width: min(620px, 88vw);
156189
+ max-height: 280px;
156190
+ overflow: auto;
156191
+ background: #101629;
156192
+ border: 1px solid #2f3f62;
156193
+ border-radius: 8px;
156194
+ box-shadow: 0 12px 28px rgba(0, 0, 0, 0.45);
156195
+ padding: 10px 12px;
156196
+ z-index: 10003;
156197
+ color: #c8d4ff;
156198
+ font-size: 12px;
156199
+ white-space: pre-wrap;
156200
+ line-height: 1.4;
156201
+ `;
156202
+ const title = document.createElement("div");
156203
+ title.textContent = `Session History (${history.length})`;
156204
+ title.style.cssText = "font-weight: 700; margin-bottom: 8px; color: #9fc2ff;";
156205
+ pop.appendChild(title);
156206
+ const body = document.createElement("div");
156207
+ if (history.length === 0) {
156208
+ body.textContent = "No history yet.";
156209
+ body.style.cssText = "color: #77839f; font-style: italic;";
156210
+ } else {
156211
+ body.textContent = history.join("\n");
156212
+ }
156213
+ pop.appendChild(body);
156214
+ const closeBtn = document.createElement("button");
156215
+ closeBtn.textContent = "Close";
156216
+ closeBtn.style.cssText = `${this.buttonCss("#2a2f4a", "#5a6aa0")} margin-top: 10px;`;
156217
+ closeBtn.onclick = () => this.closeSessionHistoryPopover();
156218
+ pop.appendChild(closeBtn);
156219
+ this.historyPopover = pop;
156220
+ this.spriteCardEl.style.position = "relative";
156221
+ this.spriteCardEl.appendChild(pop);
156222
+ anchor.blur();
156223
+ }
156224
+ closeSessionHistoryPopover() {
156225
+ if (this.historyPopover?.parentElement) {
156226
+ this.historyPopover.parentElement.removeChild(this.historyPopover);
156227
+ }
156228
+ this.historyPopover = null;
156229
+ }
156230
+ copySessionId() {
156231
+ if (!this.sessionId) return;
156232
+ navigator.clipboard.writeText(this.sessionId).then(() => {
156233
+ const original = this.sessionIdEl.textContent;
156234
+ this.sessionIdEl.textContent = "Copied!";
156235
+ this.sessionIdEl.style.color = "#61d394";
156236
+ setTimeout(() => {
156237
+ this.sessionIdEl.textContent = original;
156238
+ this.sessionIdEl.style.color = "#8ec3ff";
156239
+ }, 900);
156240
+ }).catch(() => {
156241
+ });
156242
+ }
156243
+ renderAgentSprite(seed, baseColor) {
156244
+ const ctx = this.spriteCanvasEl.getContext("2d");
156245
+ if (!ctx) return;
156246
+ ctx.clearRect(0, 0, 32, 34);
156247
+ ctx.imageSmoothingEnabled = false;
156248
+ const color = this.toHex(baseColor);
156249
+ const shade = this.toHex(this.scaleColor(baseColor, 0.72));
156250
+ const accent = this.toHex(this.scaleColor(baseColor, 1.22));
156251
+ const skin = "#f3cfa7";
156252
+ ctx.fillStyle = "#0f1425";
156253
+ ctx.fillRect(0, 0, 32, 34);
156254
+ ctx.fillStyle = shade;
156255
+ ctx.fillRect(8, 16, 16, 14);
156256
+ ctx.fillStyle = color;
156257
+ ctx.fillRect(9, 16, 14, 13);
156258
+ ctx.fillStyle = skin;
156259
+ ctx.fillRect(10, 8, 12, 9);
156260
+ ctx.fillStyle = accent;
156261
+ ctx.fillRect(10, 5, 12, 4);
156262
+ ctx.fillStyle = "#182033";
156263
+ ctx.fillRect(13, 11, 2, 2);
156264
+ ctx.fillRect(17, 11, 2, 2);
156265
+ const seedValue = [...seed].reduce((acc, ch) => acc + ch.charCodeAt(0), 0);
156266
+ const badgeX = seedValue % 2 === 0 ? 5 : 24;
156267
+ ctx.fillStyle = accent;
156268
+ ctx.fillRect(badgeX, 19, 3, 3);
156269
+ }
156270
+ toHex(color) {
156271
+ return `#${color.toString(16).padStart(6, "0")}`;
156272
+ }
156273
+ scaleColor(color, multiplier) {
156274
+ const r = Math.min(255, Math.max(0, Math.round((color >> 16 & 255) * multiplier)));
156275
+ const g = Math.min(255, Math.max(0, Math.round((color >> 8 & 255) * multiplier)));
156276
+ const b = Math.min(255, Math.max(0, Math.round((color & 255) * multiplier)));
156277
+ return r << 16 | g << 8 | b;
156278
+ }
156279
+ ensureXtermStyles() {
156280
+ if (document.getElementById("xterm-styles")) return;
156281
+ const style = document.createElement("style");
156282
+ style.id = "xterm-styles";
156283
+ style.textContent = `
156284
+ .xterm { height: 100%; }
156285
+ .xterm-viewport { overflow-y: auto !important; }
156286
+ #serious-terminal-container .xterm { height: 100%; }
156287
+ `;
156288
+ document.head.appendChild(style);
156289
+ }
156290
+ createTerminal() {
156291
+ this.terminal = new import_xterm2.Terminal({
156292
+ theme: {
156293
+ background: "#0d111b",
156294
+ foreground: "#e0e0e0",
156295
+ cursor: "#00ff88",
156296
+ cursorAccent: "#0d111b",
156297
+ selectionBackground: "#3a5a8a"
156298
+ },
156299
+ fontFamily: "Cascadia Code, Consolas, Monaco, monospace",
156300
+ fontSize: 16,
156301
+ lineHeight: 1.2,
156302
+ cursorBlink: true,
156303
+ cursorStyle: "block",
156304
+ scrollback: 1e4,
156305
+ allowProposedApi: true
156306
+ });
156307
+ this.fitAddon = new import_addon_fit2.FitAddon();
156308
+ this.terminal.loadAddon(this.fitAddon);
156309
+ this.terminalDivEl.id = "serious-terminal-container";
156310
+ this.terminal.open(this.terminalDivEl);
156311
+ this.terminal.attachCustomKeyEventHandler((event) => {
156312
+ if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "v" && event.type === "keydown") {
156313
+ event.preventDefault();
156314
+ event.stopPropagation();
156315
+ navigator.clipboard.readText().then((text) => {
156316
+ if (text) this.terminal?.paste(text);
156317
+ }).catch(() => {
156318
+ });
156319
+ return false;
156320
+ }
156321
+ return true;
156322
+ });
156323
+ this.terminal.onData((data) => {
156324
+ if (!window.copilotBridge || !this.activeOfficeId || !this.activeAgentId) return;
156325
+ void window.copilotBridge.terminalWrite(this.activeOfficeId, this.activeAgentId, data);
156326
+ });
156327
+ this.resizeHandler = () => {
156328
+ if (!this.visible || !this.activeOfficeId || !this.activeAgentId) return;
156329
+ this.debouncedRefit(this.activeOfficeId, this.activeAgentId);
156330
+ };
156331
+ window.addEventListener("resize", this.resizeHandler);
156332
+ this.resizeObserver = new ResizeObserver(() => {
156333
+ if (!this.visible || !this.activeOfficeId || !this.activeAgentId) return;
156334
+ this.debouncedRefit(this.activeOfficeId, this.activeAgentId);
156335
+ });
156336
+ this.resizeObserver.observe(this.terminalDivEl);
156337
+ }
156338
+ refitAndResize(officeId, agentId) {
156339
+ if (!this.fitAddon || !window.copilotBridge) return;
156340
+ this.fitAddon.fit();
156341
+ const dims = this.fitAddon.proposeDimensions();
156342
+ if (!dims) return;
156343
+ void window.copilotBridge.terminalResize(officeId, agentId, dims.cols, dims.rows);
156344
+ }
156345
+ debouncedRefit(officeId, agentId) {
156346
+ this.clearRefitTimers();
156347
+ requestAnimationFrame(() => {
156348
+ this.refitAndResize(officeId, agentId);
156349
+ this.refitTimers.push(setTimeout(() => {
156350
+ this.refitAndResize(officeId, agentId);
156351
+ this.refitTimers.push(setTimeout(() => this.refitAndResize(officeId, agentId), 200));
156352
+ }, 150));
156353
+ });
156354
+ }
156355
+ refreshFocusAndGeometry() {
156356
+ if (!this.visible || !this.activeOfficeId || !this.activeAgentId) return;
156357
+ this.terminal?.focus();
156358
+ this.debouncedRefit(this.activeOfficeId, this.activeAgentId);
156359
+ }
156360
+ toggleFullWidth() {
156361
+ this.isFullWidth = !this.isFullWidth;
156362
+ localStorage.setItem(_SeriousTerminalController.FULL_WIDTH_STORAGE_KEY, String(this.isFullWidth));
156363
+ this.fullscreenBtn.textContent = this.isFullWidth ? "Half Width" : "Full Width";
156364
+ this.applyPanelLayout();
156365
+ }
156366
+ applyPanelLayout() {
156367
+ const officePanel = document.getElementById("office-panel");
156368
+ const terminalPanel = document.getElementById("terminal-panel");
156369
+ const isMobile = window.__copilotOfficeMobileModeActive?.() === true;
156370
+ if (!officePanel || !terminalPanel || isMobile) return;
156371
+ const appMode = document.getElementById("game-container")?.dataset.appMode;
156372
+ if (appMode !== "serious" || !this.visible || !this.isFullWidth) {
156373
+ officePanel.style.display = "flex";
156374
+ officePanel.style.flexDirection = "column";
156375
+ terminalPanel.style.width = "50%";
156376
+ terminalPanel.style.borderLeft = "2px solid #333";
156377
+ return;
156378
+ }
156379
+ officePanel.style.display = "none";
156380
+ terminalPanel.style.width = "100%";
156381
+ terminalPanel.style.borderLeft = "none";
156382
+ }
156383
+ clearRefitTimers() {
156384
+ for (const timer of this.refitTimers) clearTimeout(timer);
156385
+ this.refitTimers.length = 0;
156386
+ }
156387
+ formatElapsed(startTime) {
156388
+ const seconds = Math.floor((Date.now() - startTime) / 1e3);
156389
+ if (seconds < 60) return `${seconds}s`;
156390
+ const mins = Math.floor(seconds / 60);
156391
+ const secs = seconds % 60;
156392
+ return `${mins}m ${secs}s`;
156393
+ }
156394
+ buttonCss(background, border) {
156395
+ return `
156396
+ background: ${background};
156397
+ border: 1px solid ${border};
156398
+ color: #d4dbf9;
156399
+ border-radius: 5px;
156400
+ padding: 6px 10px;
156401
+ font-family: inherit;
156402
+ font-size: 12px;
156403
+ cursor: pointer;
156404
+ white-space: nowrap;
156405
+ `;
156406
+ }
156407
+ };
156408
+ }
156409
+ });
156410
+
156411
+ // src/main.ts
156412
+ var require_main = __commonJS({
156413
+ "src/main.ts"() {
156414
+ var import_phaser10 = __toESM(require_phaser());
156415
+ init_BootScene();
156416
+ init_OfficeScene();
156417
+ init_MeetingScene();
156418
+ init_officeManager();
156419
+ init_agents();
156420
+ init_responsiveLayout();
156421
+ init_layouts();
156422
+ init_ToastNotification();
156423
+ init_NotificationService();
156424
+ init_SettingsPanel();
156425
+ init_SpriteCustomizerPanel();
156426
+ init_SeriousTerminalController();
156427
+ init_SpriteGenerator();
156428
+ officeManager.ensureDefaultOffice();
156429
+ function getCurrentLayout() {
156430
+ return officeManager.currentOffice?.config.layout ?? "default";
156431
+ }
156432
+ function getCurrentAgents() {
156433
+ return getLayout(getCurrentLayout()).agents;
156434
+ }
156435
+ function getCurrentAgentTools() {
156436
+ return officeManager.currentOffice?.agentTools || /* @__PURE__ */ new Map();
156437
+ }
156438
+ function syncActiveRosterForCurrentOffice() {
156439
+ const office = officeManager.currentOffice;
156440
+ if (!office) return;
156441
+ swapActiveAgents(office.config);
156442
+ if (office.config.layout === "default") {
156443
+ restoreSeatedReserveAgents(officeManager.getSeatedAgents(office.config.id));
156444
+ }
156445
+ }
156446
+ function normalizeToolName(toolName) {
156447
+ return (toolName ?? "").trim().toLowerCase().replace(/[\s-]+/g, "_");
156448
+ }
156449
+ function isAskUserTool(toolName, status) {
156450
+ const normalized = normalizeToolName(toolName);
156451
+ if (normalized === "ask_user" || normalized === "askuser") return true;
156452
+ const statusText = (status ?? "").toLowerCase();
156453
+ return statusText.includes("waiting for your answer") || statusText.includes("waiting on user input");
156454
+ }
156455
+ function isDonePendingAck(status) {
156456
+ return !!status?.completionPendingAck;
156457
+ }
156458
+ var selectedAgentId = null;
156459
+ var phaserGameRef;
156460
+ var debugMode = false;
156461
+ var currentZoom = parseFloat(localStorage.getItem("agencyOffice:zoomLevel") ?? "0.8");
156462
+ currentZoom = isNaN(currentZoom) || currentZoom < 0.5 || currentZoom > 2 ? 0.8 : currentZoom;
156463
+ var RESIZE_DEBOUNCE_MS = 200;
156464
+ var APP_MODE_STORAGE_KEY = "agencyOffice:appMode";
156465
+ var SESSION_META_CACHE_STORAGE_KEY = "agencyOffice:sessionMetaCacheByOffice";
156466
+ var OVERVIEW_SPRITE_CACHE_STORAGE_KEY = "agencyOffice:overviewSpriteCache";
156467
+ var PC_TERMINAL_ID2 = "pc-terminal";
156468
+ function sanitizeAppMode(value) {
156469
+ return value === "serious" ? "serious" : "game";
156470
+ }
156471
+ var appMode = sanitizeAppMode(localStorage.getItem(APP_MODE_STORAGE_KEY));
156472
+ function persistAppMode(mode) {
156473
+ try {
156474
+ localStorage.setItem(APP_MODE_STORAGE_KEY, mode);
156475
+ } catch {
156476
+ }
156477
+ }
156478
+ function loadSessionMetaCacheByOffice() {
156479
+ try {
156480
+ const raw = localStorage.getItem(SESSION_META_CACHE_STORAGE_KEY);
156481
+ if (!raw) return {};
156482
+ const parsed = JSON.parse(raw);
156483
+ return parsed && typeof parsed === "object" ? parsed : {};
156484
+ } catch {
156485
+ return {};
156486
+ }
156487
+ }
156488
+ function saveSessionMetaCacheByOffice(cache) {
156489
+ try {
156490
+ localStorage.setItem(SESSION_META_CACHE_STORAGE_KEY, JSON.stringify(cache));
156491
+ } catch {
156492
+ }
156493
+ }
156494
+ function getSessionMetaCacheForOffice(officeId) {
156495
+ const all = loadSessionMetaCacheByOffice();
156496
+ return all[officeId] || {};
156497
+ }
156498
+ function setSessionMetaCacheForOffice(officeId, meta) {
156499
+ const all = loadSessionMetaCacheByOffice();
156500
+ all[officeId] = meta;
156501
+ saveSessionMetaCacheByOffice(all);
156502
+ }
156503
+ function loadOverviewSpriteCache() {
156504
+ try {
156505
+ const raw = localStorage.getItem(OVERVIEW_SPRITE_CACHE_STORAGE_KEY);
156506
+ if (!raw) return {};
156507
+ const parsed = JSON.parse(raw);
156508
+ return parsed && typeof parsed === "object" ? parsed : {};
156509
+ } catch {
156510
+ return {};
156511
+ }
156512
+ }
156513
+ function saveOverviewSpriteCache(cache) {
156514
+ try {
156515
+ localStorage.setItem(OVERVIEW_SPRITE_CACHE_STORAGE_KEY, JSON.stringify(cache));
156516
+ } catch {
156517
+ }
156518
+ }
156519
+ var agentPreloadStatus = /* @__PURE__ */ new Map();
156520
+ var pendingStatusBarUpdate = false;
156521
+ var pendingTerminalContentUpdate = false;
156522
+ var OVERVIEW_SPRITE_MAX_RETRY_ATTEMPTS = 5;
156523
+ var OVERVIEW_SPRITE_RETRY_DELAY_MS = 120;
156524
+ var overviewSpriteRetryTimer = null;
156525
+ var overviewSpriteCache = loadOverviewSpriteCache();
156526
+ var overviewSpriteImageCache = /* @__PURE__ */ new Map();
156527
+ function scheduleUiUpdateWithFallback(callback) {
156528
+ let done = false;
156529
+ const runOnce = () => {
156530
+ if (done) return;
156531
+ done = true;
156532
+ callback();
156533
+ };
156534
+ requestAnimationFrame(runOnce);
156535
+ const fallbackDelayMs = document.hidden ? 80 : 200;
156536
+ setTimeout(runOnce, fallbackDelayMs);
156537
+ }
156538
+ function scheduleStatusBarUpdate() {
156539
+ if (pendingStatusBarUpdate) return;
156540
+ pendingStatusBarUpdate = true;
156541
+ scheduleUiUpdateWithFallback(() => {
156542
+ pendingStatusBarUpdate = false;
156543
+ updateStatusBarNow();
156544
+ });
156545
+ }
156546
+ function scheduleTerminalContentUpdate() {
156547
+ if (pendingTerminalContentUpdate) return;
156548
+ pendingTerminalContentUpdate = true;
156549
+ scheduleUiUpdateWithFallback(() => {
156550
+ pendingTerminalContentUpdate = false;
156551
+ updateTerminalContentNow();
156552
+ });
156553
+ }
156554
+ var container = document.getElementById("game-container");
156555
+ container.innerHTML = "";
156556
+ container.style.cssText = "display: flex; flex-direction: column; width: 100%; height: calc(100% - 58px);";
156557
+ var tabsBar = document.createElement("div");
156558
+ tabsBar.id = "office-tabs";
156559
+ tabsBar.style.cssText = `
156560
+ display: flex;
156561
+ align-items: center;
156562
+ background: #1a1a2a;
156563
+ border-bottom: 2px solid #333;
156564
+ padding: 0 16px;
156565
+ height: 72px;
156566
+ flex-shrink: 0;
156567
+ font-size: 22px;
156568
+ `;
156569
+ container.appendChild(tabsBar);
156570
+ var mainContent = document.createElement("div");
156571
+ mainContent.style.cssText = "display: flex; flex: 1; min-height: 0;";
156572
+ container.appendChild(mainContent);
156573
+ var officePanel = document.createElement("div");
156574
+ officePanel.id = "office-panel";
156575
+ officePanel.style.cssText = "width: 50%; height: 100%; position: relative;";
156576
+ mainContent.appendChild(officePanel);
156577
+ var terminalPanel = document.createElement("div");
156578
+ terminalPanel.id = "terminal-panel";
156579
+ terminalPanel.style.cssText = `
156580
+ width: 50%;
156581
+ height: 100%;
156582
+ background: #1e1e2e;
156583
+ border-left: 2px solid #333;
156584
+ display: flex;
156585
+ flex-direction: column;
156586
+ position: relative;
156587
+ `;
156588
+ mainContent.appendChild(terminalPanel);
156589
+ var overviewHost = document.createElement("div");
156590
+ overviewHost.id = "overview-host";
156591
+ overviewHost.style.cssText = `
156592
+ display: flex;
156593
+ flex-direction: column;
156594
+ flex: 1;
156595
+ min-height: 0;
156596
+ position: relative;
156597
+ `;
156598
+ terminalPanel.appendChild(overviewHost);
156599
+ var terminalHost = document.createElement("div");
156600
+ terminalHost.id = "terminal-host";
156601
+ terminalHost.style.cssText = "display: none; flex: 1; min-height: 0;";
156602
+ terminalPanel.appendChild(terminalHost);
156603
+ var seriousPlaceholder = document.createElement("div");
156604
+ seriousPlaceholder.id = "serious-terminal-placeholder";
156605
+ seriousPlaceholder.style.cssText = `
156606
+ display: none;
156607
+ flex: 1;
156608
+ min-height: 0;
156609
+ align-items: center;
156610
+ justify-content: center;
156611
+ padding: 24px;
156612
+ font-family: 'Cascadia Code', Consolas, monospace;
156613
+ text-align: center;
156614
+ color: #95a7d7;
156615
+ background: radial-gradient(circle at top, #222846 0%, #171c2f 50%, #13192a 100%);
156616
+ `;
156617
+ seriousPlaceholder.innerHTML = `
156618
+ <div style="max-width: 380px;">
156619
+ <div style="font-size: 34px; margin-bottom: 10px;">\u{1F4BB}</div>
156620
+ <div style="font-size: 18px; color: #c7d7ff; font-weight: 700; margin-bottom: 8px;">No terminal selected</div>
156621
+ <div style="font-size: 12px; line-height: 1.45; color: #8fa3d6;">
156622
+ Select an agent or office PC from the overview on the left to open a command line session.
156623
+ </div>
156624
+ </div>
156625
+ `;
156626
+ terminalHost.appendChild(seriousPlaceholder);
156627
+ var currentResponsiveLayout = "default";
156628
+ var resizeDebounceTimer = null;
156629
+ function isMobileModeActive() {
156630
+ return currentResponsiveLayout === "portrait-dashboard";
156631
+ }
156632
+ function applyMobileTopBarVisibility() {
156633
+ const hidden = isMobileModeActive();
156634
+ const ids = ["zoom-bar", "sprite-customizer-btn", "debug-toggle-btn"];
156635
+ for (const id of ids) {
156636
+ const el = document.getElementById(id);
156637
+ if (!el) continue;
156638
+ el.style.display = hidden ? "none" : "";
156639
+ }
156640
+ }
156641
+ function syncMainPanelLayout() {
156642
+ const hideOfficePanel = currentResponsiveLayout === "portrait-dashboard";
156643
+ if (hideOfficePanel) {
156644
+ officePanel.style.display = "none";
156645
+ officePanel.style.flexDirection = "";
156646
+ terminalPanel.style.width = "100%";
156647
+ terminalPanel.style.borderLeft = "none";
156648
+ return;
156649
+ }
156650
+ officePanel.style.display = appMode === "serious" ? "flex" : "";
156651
+ officePanel.style.flexDirection = appMode === "serious" ? "column" : "";
156652
+ terminalPanel.style.width = "50%";
156653
+ terminalPanel.style.borderLeft = "2px solid #333";
156654
+ }
156655
+ function applyResponsiveLayout(layoutKey) {
156656
+ if (layoutKey === currentResponsiveLayout) return;
156657
+ currentResponsiveLayout = layoutKey;
156658
+ syncMainPanelLayout();
156659
+ refreshRightPanelMode();
156660
+ if (phaserGameRef && appMode === "game") {
156661
+ phaserGameRef.events.emit("layout:change", { layoutKey });
156662
+ if (layoutKey === "default") {
156663
+ const width = officePanel.clientWidth || window.innerWidth / 2;
156664
+ const height = officePanel.clientHeight || window.innerHeight;
156665
+ phaserGameRef.scale.resize(width, height);
156666
+ }
156667
+ }
156668
+ applyMobileTopBarVisibility();
156669
+ }
156670
+ function onWindowResize() {
156671
+ if (resizeDebounceTimer !== null) {
156672
+ window.clearTimeout(resizeDebounceTimer);
156673
+ }
156674
+ resizeDebounceTimer = window.setTimeout(() => {
155596
156675
  const next = computeResponsiveLayout(window.innerWidth, window.innerHeight);
155597
156676
  applyResponsiveLayout(next);
155598
- if (phaserGameRef && currentResponsiveLayout === "default") {
156677
+ if (phaserGameRef && appMode === "game" && currentResponsiveLayout === "default") {
155599
156678
  const width = officePanel.clientWidth || window.innerWidth / 2;
155600
156679
  const height = officePanel.clientHeight || window.innerHeight;
155601
156680
  phaserGameRef.scale.resize(width, height);
155602
156681
  }
155603
156682
  }, RESIZE_DEBOUNCE_MS);
155604
156683
  }
156684
+ function applyAppMode(nextMode, options = {}) {
156685
+ const { persist = false, refreshTabs = true, force = false } = options;
156686
+ if (!force && nextMode === appMode) return;
156687
+ const previousMode = appMode;
156688
+ appMode = nextMode;
156689
+ const selectedAgentBeforeModeSwitch = selectedAgentId;
156690
+ if (previousMode === "serious" && appMode === "game") {
156691
+ void seriousTerminalController?.closeView({ detach: true, silent: true });
156692
+ }
156693
+ if (appMode === "serious") {
156694
+ prewarmOverviewSpriteCacheFromTextures();
156695
+ teardownPhaserGame();
156696
+ } else {
156697
+ ensurePhaserGame();
156698
+ }
156699
+ container.dataset.appMode = appMode;
156700
+ tabsBar.dataset.appMode = appMode;
156701
+ mainContent.dataset.appMode = appMode;
156702
+ officePanel.dataset.appMode = appMode;
156703
+ terminalPanel.dataset.appMode = appMode;
156704
+ overviewHost.dataset.appMode = appMode;
156705
+ terminalHost.dataset.appMode = appMode;
156706
+ syncMainPanelLayout();
156707
+ if (phaserGameRef && appMode === "game" && currentResponsiveLayout === "default") {
156708
+ const width = officePanel.clientWidth || window.innerWidth / 2;
156709
+ const height = officePanel.clientHeight || window.innerHeight;
156710
+ phaserGameRef.scale.resize(width, height);
156711
+ }
156712
+ if (persist) persistAppMode(appMode);
156713
+ if (refreshTabs) renderOfficeTabs();
156714
+ refreshRightPanelMode();
156715
+ updateTerminalContent();
156716
+ updateStatusBar();
156717
+ phaserGameRef?.events.emit("app:mode:changed", { mode: appMode, previousMode });
156718
+ if (appMode === "serious" && selectedAgentBeforeModeSwitch && getSeriousLaunchConfig(selectedAgentBeforeModeSwitch)) {
156719
+ void openAgentTerminal(selectedAgentBeforeModeSwitch);
156720
+ }
156721
+ }
156722
+ function toggleAppMode() {
156723
+ const nextMode = appMode === "game" ? "serious" : "game";
156724
+ applyAppMode(nextMode, { persist: true, refreshTabs: true });
156725
+ }
155605
156726
  applyResponsiveLayout(computeResponsiveLayout(window.innerWidth, window.innerHeight));
155606
156727
  window.addEventListener("resize", onWindowResize);
155607
156728
  if (typeof window !== "undefined") {
@@ -155651,6 +156772,21 @@ WARNING: This link could potentially be dangerous`)) {
155651
156772
  color: #4a4;
155652
156773
  ">+ New Office</div>
155653
156774
  <div style="flex: 1;"></div>
156775
+ <div id="app-mode-toggle-btn" style="
156776
+ padding: 8px 14px;
156777
+ background: ${appMode === "serious" ? "#2f2638" : "#252538"};
156778
+ border: 2px solid ${appMode === "serious" ? "#a66be0" : "#444"};
156779
+ border-radius: 6px;
156780
+ cursor: pointer;
156781
+ font-family: monospace;
156782
+ color: ${appMode === "serious" ? "#d4b6ff" : "#8fb7ff"};
156783
+ font-size: 14px;
156784
+ user-select: none;
156785
+ transition: all 0.2s;
156786
+ margin-right: 8px;
156787
+ " title="Toggle app mode (game/serious)">
156788
+ ${appMode === "serious" ? "\u{1F9E0} Serious Mode" : "\u{1F3AE} Game Mode"}
156789
+ </div>
155654
156790
  <div id="sprite-customizer-btn" style="
155655
156791
  padding: 8px 16px;
155656
156792
  background: #252538;
@@ -155749,12 +156885,16 @@ WARNING: This link could potentially be dangerous`)) {
155749
156885
  });
155750
156886
  });
155751
156887
  document.getElementById("new-office-btn")?.addEventListener("click", showNewOfficeDialog);
156888
+ document.getElementById("app-mode-toggle-btn")?.addEventListener("click", (e) => {
156889
+ e.stopPropagation();
156890
+ toggleAppMode();
156891
+ });
155752
156892
  document.getElementById("debug-toggle-btn")?.addEventListener("click", () => {
155753
156893
  debugMode = !debugMode;
155754
- phaserGame?.events.emit("debug:toggle", debugMode);
156894
+ phaserGameRef?.events.emit("debug:toggle", debugMode);
155755
156895
  renderOfficeTabs();
155756
156896
  if (!isMobileModeActive()) {
155757
- phaserGame?.events.emit("game:panel:clicked");
156897
+ phaserGameRef?.events.emit("game:panel:clicked");
155758
156898
  }
155759
156899
  console.log(`[Debug] Debug mode ${debugMode ? "ON" : "OFF"}`);
155760
156900
  });
@@ -155794,19 +156934,20 @@ WARNING: This link could potentially be dangerous`)) {
155794
156934
  applyMobileTopBarVisibility();
155795
156935
  }
155796
156936
  function switchToOffice(officeId) {
155797
- if (phaserGame?.registry.get("animating")) {
156937
+ if (phaserGameRef?.registry.get("animating")) {
155798
156938
  console.log("[Office] Blocked: animation in progress");
155799
156939
  return;
155800
156940
  }
155801
156941
  selectedAgentId = null;
156942
+ void seriousTerminalController?.closeView({ detach: true });
155802
156943
  officeManager.switchOffice(officeId);
155803
- const office = officeManager.currentOffice;
155804
- if (office) swapActiveAgents(office.config);
155805
- phaserGame?.events.emit("office:switch", officeId, officeManager.currentOffice?.config.workingDirectory);
156944
+ cachedSessionMeta = getSessionMetaCacheForOffice(officeId);
156945
+ syncActiveRosterForCurrentOffice();
156946
+ phaserGameRef?.events.emit("office:switch", officeId, officeManager.currentOffice?.config.workingDirectory);
155806
156947
  renderOfficeTabs();
155807
156948
  updateTerminalContent();
155808
156949
  updateStatusBar();
155809
- syncAgentStatuses();
156950
+ void reconnectAgentStatuses();
155810
156951
  fetchSessionMeta();
155811
156952
  console.log(`[Office] Switched to office: ${officeManager.currentOffice?.config.name}`);
155812
156953
  }
@@ -156001,8 +157142,8 @@ WARNING: This link could potentially be dangerous`)) {
156001
157142
  nameInput.select();
156002
157143
  }
156003
157144
  renderOfficeTabs();
156004
- var terminalHeader = document.createElement("div");
156005
- terminalHeader.style.cssText = `
157145
+ var overviewHeader = document.createElement("div");
157146
+ overviewHeader.style.cssText = `
156006
157147
  padding: 14px 20px;
156007
157148
  background: #141424;
156008
157149
  border-bottom: 2px solid #2a2a4a;
@@ -156012,7 +157153,7 @@ WARNING: This link could potentially be dangerous`)) {
156012
157153
  justify-content: space-between;
156013
157154
  align-items: center;
156014
157155
  `;
156015
- terminalHeader.innerHTML = `
157156
+ overviewHeader.innerHTML = `
156016
157157
  <div>
156017
157158
  <div id="terminal-title" style="font-size: 18px; font-weight: bold; color: #8af; margin-bottom: 4px;">\u{1F3E2} Office Overview</div>
156018
157159
  <div id="terminal-subtitle" style="font-size: 12px; color: #555;"></div>
@@ -156030,7 +157171,7 @@ WARNING: This link could potentially be dangerous`)) {
156030
157171
  white-space: nowrap;
156031
157172
  ">\u2715 Close Office</button>
156032
157173
  `;
156033
- terminalPanel.appendChild(terminalHeader);
157174
+ overviewHost.appendChild(overviewHeader);
156034
157175
  document.getElementById("close-office-btn").addEventListener("click", () => {
156035
157176
  const currentId = officeManager.currentOfficeId;
156036
157177
  const office = officeManager.currentOffice;
@@ -156040,9 +157181,9 @@ WARNING: This link could potentially be dangerous`)) {
156040
157181
  switchToOffice("office-0");
156041
157182
  }
156042
157183
  });
156043
- var terminalContent = document.createElement("div");
156044
- terminalContent.id = "terminal-content";
156045
- terminalContent.style.cssText = `
157184
+ var overviewContent = document.createElement("div");
157185
+ overviewContent.id = "terminal-content";
157186
+ overviewContent.style.cssText = `
156046
157187
  flex: 1;
156047
157188
  padding: 16px;
156048
157189
  overflow-y: auto;
@@ -156051,7 +157192,7 @@ WARNING: This link could potentially be dangerous`)) {
156051
157192
  color: #ccc;
156052
157193
  position: relative;
156053
157194
  `;
156054
- terminalPanel.appendChild(terminalContent);
157195
+ overviewHost.appendChild(overviewContent);
156055
157196
  var statusBar = document.createElement("div");
156056
157197
  statusBar.id = "status-bar";
156057
157198
  statusBar.style.cssText = `
@@ -156097,6 +157238,86 @@ WARNING: This link could potentially be dangerous`)) {
156097
157238
  function getAgentConfig(agentId) {
156098
157239
  return getCurrentAgents().find((a) => a.id === agentId) || AGENTS.find((a) => a.id === agentId);
156099
157240
  }
157241
+ var seriousTerminalController = null;
157242
+ function getSeriousLaunchConfig(agentId) {
157243
+ if (agentId === PC_TERMINAL_ID2) {
157244
+ return {
157245
+ name: "PC TERMINAL",
157246
+ description: "Local Shell",
157247
+ color: 7311064,
157248
+ workingDir: officeManager.getCurrentWorkingDirectory(),
157249
+ launchMode: "shell"
157250
+ };
157251
+ }
157252
+ const agent = getAgentConfig(agentId);
157253
+ if (!agent) return null;
157254
+ return {
157255
+ name: agent.name,
157256
+ description: agent.description,
157257
+ color: agent.color,
157258
+ workingDir: agent.workingDir || officeManager.getCurrentWorkingDirectory(),
157259
+ launchMode: "copilot"
157260
+ };
157261
+ }
157262
+ function refreshRightPanelMode() {
157263
+ const seriousDesktop = appMode === "serious" && currentResponsiveLayout === "default";
157264
+ const desiredOverviewParent = seriousDesktop ? officePanel : terminalPanel;
157265
+ if (overviewHost.parentElement !== desiredOverviewParent) {
157266
+ desiredOverviewParent.appendChild(overviewHost);
157267
+ }
157268
+ if (appMode === "serious") {
157269
+ const seriousVisible = !!seriousTerminalController?.isVisible();
157270
+ if (seriousDesktop) {
157271
+ overviewHost.style.display = "flex";
157272
+ terminalHost.style.display = "flex";
157273
+ seriousPlaceholder.style.display = seriousVisible ? "none" : "flex";
157274
+ return;
157275
+ }
157276
+ if (seriousVisible) {
157277
+ overviewHost.style.display = "none";
157278
+ terminalHost.style.display = "flex";
157279
+ seriousPlaceholder.style.display = "none";
157280
+ return;
157281
+ }
157282
+ overviewHost.style.display = "flex";
157283
+ terminalHost.style.display = "none";
157284
+ seriousPlaceholder.style.display = "none";
157285
+ return;
157286
+ }
157287
+ overviewHost.style.display = "flex";
157288
+ terminalHost.style.display = "none";
157289
+ seriousPlaceholder.style.display = "none";
157290
+ }
157291
+ async function openAgentTerminal(agentId) {
157292
+ if (appMode === "game") {
157293
+ phaserGameRef?.events.emit("open:agent:terminal", agentId);
157294
+ return;
157295
+ }
157296
+ const launchConfig = getSeriousLaunchConfig(agentId);
157297
+ if (!launchConfig || !window.copilotBridge) return;
157298
+ const officeId = officeManager.currentOfficeId || "office-0";
157299
+ const officeStatus = officeManager.getAgentStatus(officeId, agentId);
157300
+ if (officeStatus?.state === "slacking") {
157301
+ officeManager.setAgentStarting(officeId, agentId);
157302
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
157303
+ updateStatusBar();
157304
+ updateTerminalContent();
157305
+ }
157306
+ await seriousTerminalController?.openAgentTerminal({
157307
+ officeId,
157308
+ agentId,
157309
+ ...launchConfig
157310
+ });
157311
+ refreshRightPanelMode();
157312
+ }
157313
+ seriousTerminalController = new SeriousTerminalController(terminalHost, {
157314
+ onClose: () => {
157315
+ selectedAgentId = null;
157316
+ refreshRightPanelMode();
157317
+ updateStatusBar();
157318
+ updateTerminalContent();
157319
+ }
157320
+ });
156100
157321
  var notificationService = new NotificationService(
156101
157322
  toastManager,
156102
157323
  (agentId) => {
@@ -156109,7 +157330,7 @@ WARNING: This link could potentially be dangerous`)) {
156109
157330
  const oId = officeManager.currentOfficeId;
156110
157331
  if (oId) officeManager.clearUnread(oId, agentId);
156111
157332
  updateTerminalContent();
156112
- phaserGame?.events.emit("open:agent:terminal", agentId);
157333
+ void openAgentTerminal(agentId);
156113
157334
  }
156114
157335
  );
156115
157336
  function notifyAgent(agentId, eventType, context) {
@@ -156158,9 +157379,16 @@ WARNING: This link could potentially be dangerous`)) {
156158
157379
  var lastStatusBarHtml = "";
156159
157380
  var cachedSessionMeta = {};
156160
157381
  function fetchSessionMeta() {
157382
+ const officeId = officeManager.currentOfficeId || "office-0";
157383
+ const cached = getSessionMetaCacheForOffice(officeId);
157384
+ if (Object.keys(cached).length > 0) {
157385
+ cachedSessionMeta = cached;
157386
+ updateTerminalContent();
157387
+ }
156161
157388
  if (!window.copilotBridge?.getAllSessionMeta) return;
156162
- window.copilotBridge.getAllSessionMeta(officeManager.currentOfficeId || "office-0").then((meta) => {
157389
+ window.copilotBridge.getAllSessionMeta(officeId).then((meta) => {
156163
157390
  cachedSessionMeta = meta || {};
157391
+ setSessionMetaCacheForOffice(officeId, cachedSessionMeta);
156164
157392
  updateTerminalContent();
156165
157393
  }).catch(() => {
156166
157394
  });
@@ -156169,6 +157397,7 @@ WARNING: This link could potentially be dangerous`)) {
156169
157397
  scheduleTerminalContentUpdate();
156170
157398
  }
156171
157399
  function updateTerminalContentNow() {
157400
+ syncActiveRosterForCurrentOffice();
156172
157401
  const agentTools = getCurrentAgentTools();
156173
157402
  const office = officeManager.currentOffice;
156174
157403
  const closeBtn = document.getElementById("close-office-btn");
@@ -156193,47 +157422,135 @@ WARNING: This link could potentially be dangerous`)) {
156193
157422
  });
156194
157423
  if (html !== lastTerminalContentHtml) {
156195
157424
  lastTerminalContentHtml = html;
156196
- terminalContent.innerHTML = html;
156197
- drawOverviewSprites();
157425
+ overviewContent.innerHTML = html;
157426
+ }
157427
+ drawOverviewSprites();
157428
+ if (appMode === "serious") {
157429
+ seriousTerminalController?.refreshCardFromOverview();
156198
157430
  }
156199
157431
  }
156200
157432
  function updateStatusBar() {
156201
157433
  scheduleStatusBarUpdate();
156202
157434
  }
156203
- function drawOverviewSprites() {
156204
- setTimeout(() => {
156205
- if (!phaserGameRef) return;
157435
+ function clearOverviewSpriteRetry() {
157436
+ if (overviewSpriteRetryTimer) {
157437
+ clearTimeout(overviewSpriteRetryTimer);
157438
+ overviewSpriteRetryTimer = null;
157439
+ }
157440
+ }
157441
+ function drawCachedOverviewSprite(canvas, textureKey) {
157442
+ const dataUrl = overviewSpriteCache[textureKey];
157443
+ if (!dataUrl) return false;
157444
+ let img = overviewSpriteImageCache.get(textureKey);
157445
+ if (!img || img.src !== dataUrl) {
157446
+ img = new Image();
157447
+ img.src = dataUrl;
157448
+ overviewSpriteImageCache.set(textureKey, img);
157449
+ }
157450
+ const ctx = canvas.getContext("2d");
157451
+ if (!ctx) return true;
157452
+ const drawNow = () => {
157453
+ if (!img) return;
157454
+ ctx.imageSmoothingEnabled = false;
157455
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
157456
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
157457
+ };
157458
+ if (!img.complete || img.naturalWidth === 0) {
157459
+ img.onload = () => drawNow();
157460
+ return true;
157461
+ }
157462
+ drawNow();
157463
+ return true;
157464
+ }
157465
+ function updateOverviewSpriteCacheFromCanvas(canvas, textureKey) {
157466
+ try {
157467
+ const dataUrl = canvas.toDataURL("image/png");
157468
+ if (overviewSpriteCache[textureKey] !== dataUrl) {
157469
+ overviewSpriteCache = { ...overviewSpriteCache, [textureKey]: dataUrl };
157470
+ saveOverviewSpriteCache(overviewSpriteCache);
157471
+ const img = new Image();
157472
+ img.src = dataUrl;
157473
+ overviewSpriteImageCache.set(textureKey, img);
157474
+ }
157475
+ } catch {
157476
+ }
157477
+ }
157478
+ function drawTextureToOverviewCanvas(canvas, textureKey) {
157479
+ if (!phaserGameRef) {
157480
+ return drawCachedOverviewSprite(canvas, textureKey);
157481
+ }
157482
+ const texture = phaserGameRef.textures.get(textureKey);
157483
+ if (!texture || texture.key === "__MISSING") {
157484
+ return drawCachedOverviewSprite(canvas, textureKey);
157485
+ }
157486
+ const source = texture.getSourceImage();
157487
+ if (!source) {
157488
+ return drawCachedOverviewSprite(canvas, textureKey);
157489
+ }
157490
+ const ctx = canvas.getContext("2d");
157491
+ if (!ctx) return true;
157492
+ const sourceWidth = source instanceof HTMLImageElement ? source.naturalWidth || source.width : source.width;
157493
+ const sourceHeight = source instanceof HTMLImageElement ? source.naturalHeight || source.height : source.height;
157494
+ ctx.imageSmoothingEnabled = false;
157495
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
157496
+ if (sourceWidth > canvas.width || sourceHeight > canvas.height) {
157497
+ ctx.drawImage(source, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
157498
+ } else {
157499
+ ctx.drawImage(source, 0, 0);
157500
+ }
157501
+ updateOverviewSpriteCacheFromCanvas(canvas, textureKey);
157502
+ return true;
157503
+ }
157504
+ function prewarmOverviewSpriteCacheFromTextures() {
157505
+ if (!phaserGameRef) return;
157506
+ const textureKeys = getCurrentAgents().map((agent) => agent.sprite);
157507
+ if (!textureKeys.includes("desktop_pc")) textureKeys.push("desktop_pc");
157508
+ for (const textureKey of textureKeys) {
157509
+ const texture = phaserGameRef.textures.get(textureKey);
157510
+ if (!texture || texture.key === "__MISSING") continue;
157511
+ const source = texture.getSourceImage();
157512
+ if (!source) continue;
157513
+ const scratch = document.createElement("canvas");
157514
+ scratch.width = textureKey === "desktop_pc" ? 32 : 32;
157515
+ scratch.height = textureKey === "desktop_pc" ? 32 : 34;
157516
+ const ctx = scratch.getContext("2d");
157517
+ if (!ctx) continue;
157518
+ const sourceWidth = source instanceof HTMLImageElement ? source.naturalWidth || source.width : source.width;
157519
+ const sourceHeight = source instanceof HTMLImageElement ? source.naturalHeight || source.height : source.height;
157520
+ ctx.imageSmoothingEnabled = false;
157521
+ ctx.clearRect(0, 0, scratch.width, scratch.height);
157522
+ if (sourceWidth > scratch.width || sourceHeight > scratch.height) {
157523
+ ctx.drawImage(source, 0, 0, scratch.width, scratch.height, 0, 0, scratch.width, scratch.height);
157524
+ } else {
157525
+ ctx.drawImage(source, 0, 0);
157526
+ }
157527
+ updateOverviewSpriteCacheFromCanvas(scratch, textureKey);
157528
+ }
157529
+ }
157530
+ function drawOverviewSprites(attempt = 0) {
157531
+ clearOverviewSpriteRetry();
157532
+ requestAnimationFrame(() => {
157533
+ let missingTexture = false;
156206
157534
  for (const agent of getCurrentAgents()) {
156207
157535
  const canvas = document.getElementById(`overview-sprite-${agent.id}`);
156208
157536
  if (!canvas) continue;
156209
- const ctx = canvas.getContext("2d");
156210
- if (!ctx) continue;
156211
- const texture = phaserGameRef.textures.get(agent.sprite);
156212
- if (!texture || texture.key === "__MISSING") continue;
156213
- const source = texture.getSourceImage();
156214
- if (source) {
156215
- ctx.imageSmoothingEnabled = false;
156216
- ctx.clearRect(0, 0, canvas.width, canvas.height);
156217
- ctx.drawImage(source, 0, 0);
156218
- }
157537
+ const drawn = drawTextureToOverviewCanvas(canvas, agent.sprite);
157538
+ if (!drawn) missingTexture = true;
156219
157539
  }
156220
157540
  const pcCanvas = document.getElementById("overview-sprite-pc-terminal");
156221
157541
  if (pcCanvas) {
156222
- const ctx = pcCanvas.getContext("2d");
156223
- if (!ctx) return;
156224
- const texture = phaserGameRef.textures.get("desktop_pc");
156225
- if (!texture || texture.key === "__MISSING") return;
156226
- const source = texture.getSourceImage();
156227
- if (source) {
156228
- ctx.imageSmoothingEnabled = false;
156229
- ctx.clearRect(0, 0, pcCanvas.width, pcCanvas.height);
156230
- ctx.drawImage(source, 0, 0);
156231
- }
157542
+ const drawn = drawTextureToOverviewCanvas(pcCanvas, "desktop_pc");
157543
+ if (!drawn) missingTexture = true;
156232
157544
  }
156233
- }, 50);
157545
+ if (missingTexture && phaserGameRef && attempt < OVERVIEW_SPRITE_MAX_RETRY_ATTEMPTS) {
157546
+ overviewSpriteRetryTimer = setTimeout(() => {
157547
+ drawOverviewSprites(attempt + 1);
157548
+ }, OVERVIEW_SPRITE_RETRY_DELAY_MS);
157549
+ }
157550
+ });
156234
157551
  }
156235
157552
  function setupTerminalClickHandler() {
156236
- terminalContent.addEventListener("click", (e) => {
157553
+ overviewHost.addEventListener("click", (e) => {
156237
157554
  const target = e.target;
156238
157555
  const layout = getLayout(getCurrentLayout());
156239
157556
  const metaPanel = target.closest(".session-meta-panel");
@@ -156242,7 +157559,10 @@ WARNING: This link could potentially be dangerous`)) {
156242
157559
  const agentId = metaPanel.dataset.agent;
156243
157560
  if (!agentId) return;
156244
157561
  layout.clickHandler.handleMetaPanelClick(target, agentId, {
156245
- startSessionMetaEdit
157562
+ startSessionMetaEdit,
157563
+ startNewSession: (id) => {
157564
+ void startSessionFromOverview(id);
157565
+ }
156246
157566
  });
156247
157567
  return;
156248
157568
  }
@@ -156260,21 +157580,58 @@ WARNING: This link could potentially be dangerous`)) {
156260
157580
  },
156261
157581
  updateContent: updateTerminalContent,
156262
157582
  emitOpenTerminal: (id) => {
156263
- phaserGame?.events.emit("open:agent:terminal", id);
157583
+ void openAgentTerminal(id);
156264
157584
  }
156265
157585
  });
156266
157586
  }
156267
157587
  });
156268
157588
  }
157589
+ async function startSessionFromOverview(agentId) {
157590
+ if (!window.copilotBridge) return;
157591
+ const officeId = officeManager.currentOfficeId || "office-0";
157592
+ const launchConfig = getSeriousLaunchConfig(agentId);
157593
+ if (!launchConfig) return;
157594
+ cachedSessionMeta[agentId] = { title: "" };
157595
+ setSessionMetaCacheForOffice(officeId, cachedSessionMeta);
157596
+ updateTerminalContent();
157597
+ try {
157598
+ if (appMode === "serious" && seriousTerminalController) {
157599
+ await seriousTerminalController.startNewSession({
157600
+ officeId,
157601
+ agentId,
157602
+ ...launchConfig
157603
+ });
157604
+ } else {
157605
+ await window.copilotBridge.resetSession(officeId, agentId);
157606
+ await window.copilotBridge.terminalStart(
157607
+ officeId,
157608
+ agentId,
157609
+ launchConfig.workingDir,
157610
+ void 0,
157611
+ void 0,
157612
+ void 0,
157613
+ launchConfig.launchMode
157614
+ );
157615
+ }
157616
+ } catch (error) {
157617
+ console.warn(`[Office] Failed to start new session from overview for ${agentId}:`, error);
157618
+ }
157619
+ officeManager.setAgentStarting(officeId, agentId);
157620
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
157621
+ updateStatusBar();
157622
+ updateTerminalContent();
157623
+ }
156269
157624
  function startSessionMetaEdit(agentId) {
156270
- const panel = terminalContent.querySelector(`.session-meta-panel[data-agent="${agentId}"]`);
157625
+ const panel = overviewHost.querySelector(`.session-meta-panel[data-agent="${agentId}"]`);
156271
157626
  if (!panel) return;
156272
157627
  const meta = cachedSessionMeta[agentId] || { title: "" };
156273
157628
  const titleEl = panel.querySelector(".session-title-display");
156274
157629
  if (titleEl) {
156275
157630
  replaceWithInput(titleEl, meta.title, "Session title...", 80, async (value) => {
156276
- await window.copilotBridge.setSessionMeta(officeManager.currentOfficeId || "office-0", agentId, { title: value });
157631
+ const officeId = officeManager.currentOfficeId || "office-0";
157632
+ await window.copilotBridge.setSessionMeta(officeId, agentId, { title: value });
156277
157633
  cachedSessionMeta[agentId] = { title: value };
157634
+ setSessionMetaCacheForOffice(officeId, cachedSessionMeta);
156278
157635
  updateTerminalContent();
156279
157636
  });
156280
157637
  }
@@ -156347,7 +157704,7 @@ WARNING: This link could potentially be dangerous`)) {
156347
157704
  console.log(`[Office] Status: ${agentId} \u2192 thinking (${toolName})`);
156348
157705
  notifyAgent(agentId, "toolStart", { toolName });
156349
157706
  }
156350
- phaserGame?.events.emit("agent:tool:start", agentId, toolName, status);
157707
+ phaserGameRef?.events.emit("agent:tool:start", agentId, toolName, status);
156351
157708
  updateTerminalContent();
156352
157709
  updateStatusBar();
156353
157710
  });
@@ -156366,7 +157723,12 @@ WARNING: This link could potentially be dangerous`)) {
156366
157723
  officeManager.pushRecentAction(officeId, agentId, completedToolName, "completed");
156367
157724
  notifyAgent(agentId, "toolComplete", { toolName: completedToolName });
156368
157725
  if (remaining.length === 0) {
156369
- officeManager.setAgentReady(officeId, agentId);
157726
+ const currentStatus = officeManager.getAgentStatus(officeId, agentId);
157727
+ if (currentStatus?.subState === "thinking") {
157728
+ officeManager.setAgentThinking(officeId, agentId, currentStatus.thinkingDetail ?? "Processing...");
157729
+ } else {
157730
+ officeManager.setAgentReady(officeId, agentId);
157731
+ }
156370
157732
  } else if (remaining.some((t) => isAskUserTool(t.name, t.status))) {
156371
157733
  officeManager.setAgentWaiting(officeId, agentId);
156372
157734
  } else {
@@ -156374,7 +157736,7 @@ WARNING: This link could potentially be dangerous`)) {
156374
157736
  officeManager.setAgentThinking(officeId, agentId, `${last.name}`);
156375
157737
  }
156376
157738
  }
156377
- phaserGame?.events.emit("agent:status:changed", agentId);
157739
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
156378
157740
  updateTerminalContent();
156379
157741
  updateStatusBar();
156380
157742
  });
@@ -156396,7 +157758,7 @@ WARNING: This link could potentially be dangerous`)) {
156396
157758
  }
156397
157759
  notifyAgent(agentId, "turnEnd");
156398
157760
  }
156399
- phaserGame?.events.emit("agent:status:changed", agentId);
157761
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
156400
157762
  updateTerminalContent();
156401
157763
  updateStatusBar();
156402
157764
  });
@@ -156413,7 +157775,7 @@ WARNING: This link could potentially be dangerous`)) {
156413
157775
  officeManager.setAgentThinking(officeId, agentId, "Processing...");
156414
157776
  console.log(`[Office] Status: ${agentId} \u2192 thinking (turn start)`);
156415
157777
  notifyAgent(agentId, "turnStart");
156416
- phaserGame?.events.emit("agent:status:changed", agentId);
157778
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
156417
157779
  updateTerminalContent();
156418
157780
  updateStatusBar();
156419
157781
  });
@@ -156428,12 +157790,14 @@ WARNING: This link could potentially be dangerous`)) {
156428
157790
  }
156429
157791
  officeManager.setAgentThinking(officeId, agentId, "Processing...");
156430
157792
  console.log(`[Office] Status: ${agentId} \u2192 thinking (user message)`);
156431
- phaserGame?.events.emit("agent:status:changed", agentId);
157793
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
156432
157794
  updateTerminalContent();
156433
157795
  });
156434
157796
  window.copilotBridge.onSessionMetaUpdated((agentId, meta) => {
156435
157797
  console.log(`[Office] Session meta updated for ${agentId}: "${meta.title}"`);
157798
+ const officeId = officeManager.currentOfficeId || "office-0";
156436
157799
  cachedSessionMeta[agentId] = meta;
157800
+ setSessionMetaCacheForOffice(officeId, cachedSessionMeta);
156437
157801
  updateTerminalContent();
156438
157802
  });
156439
157803
  window.copilotBridge.onTerminalPreloadStatus((agentId, status) => {
@@ -156459,17 +157823,45 @@ WARNING: This link could potentially be dangerous`)) {
156459
157823
  notifyAgent(agentId, "sessionError");
156460
157824
  }
156461
157825
  }
156462
- phaserGame?.events.emit("agent:status:changed", agentId);
157826
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
156463
157827
  updateStatusBar();
156464
157828
  updateTerminalContent();
156465
157829
  });
156466
157830
  }
156467
157831
  var syncInProgress = false;
156468
- async function syncAgentStatuses() {
156469
- if (!window.copilotBridge || syncInProgress) return;
157832
+ var syncStartedAt = 0;
157833
+ var SYNC_LOCK_TIMEOUT_MS = 15e3;
157834
+ var STALE_IN_TURN_THINKING_TIMEOUT_MS = 9e4;
157835
+ var THINKING_TO_READY_GRACE_MS = 7e3;
157836
+ var SYNC_WAIT_POLL_MS = 50;
157837
+ async function waitForSyncIdle(timeoutMs = SYNC_LOCK_TIMEOUT_MS) {
157838
+ const startedAt = Date.now();
157839
+ while (syncInProgress && Date.now() - startedAt < timeoutMs) {
157840
+ await new Promise((resolve) => setTimeout(resolve, SYNC_WAIT_POLL_MS));
157841
+ }
157842
+ }
157843
+ async function syncAgentStatuses(force = false) {
157844
+ if (!window.copilotBridge) return;
157845
+ if (syncInProgress) {
157846
+ if (force) {
157847
+ await waitForSyncIdle();
157848
+ if (syncInProgress) {
157849
+ console.warn(`[Office] syncAgentStatuses lock held for >${SYNC_LOCK_TIMEOUT_MS / 1e3}s during forced sync \u2014 force-releasing`);
157850
+ syncInProgress = false;
157851
+ }
157852
+ } else {
157853
+ if (syncStartedAt && Date.now() - syncStartedAt > SYNC_LOCK_TIMEOUT_MS) {
157854
+ console.warn(`[Office] syncAgentStatuses lock held for >${SYNC_LOCK_TIMEOUT_MS / 1e3}s \u2014 force-releasing`);
157855
+ syncInProgress = false;
157856
+ } else {
157857
+ return;
157858
+ }
157859
+ }
157860
+ }
156470
157861
  const officeId = officeManager.currentOfficeId;
156471
157862
  if (!officeId) return;
156472
157863
  syncInProgress = true;
157864
+ syncStartedAt = Date.now();
156473
157865
  try {
156474
157866
  const statuses = await window.copilotBridge.queryAgentStatuses(officeId);
156475
157867
  let changed = false;
@@ -156480,6 +157872,11 @@ WARNING: This link could potentially be dangerous`)) {
156480
157872
  const current = officeManager.getAgentStatus(officeId, agent.id);
156481
157873
  const activeTools = getCurrentAgentTools().get(agent.id) || [];
156482
157874
  const waitingToolActive = activeTools.some((t) => isAskUserTool(t.name, t.status));
157875
+ const thinkingSince = current?.subState === "thinking" ? current.activityStartTime : null;
157876
+ const thinkingAgeMs = thinkingSince ? now - thinkingSince : null;
157877
+ const staleInTurnThinking = Boolean(
157878
+ current?.subState === "thinking" && thinkingSince && now - thinkingSince > STALE_IN_TURN_THINKING_TIMEOUT_MS && activeTools.length === 0
157879
+ );
156483
157880
  if (current?.subState === "starting" && current.activityStartTime && now - current.activityStartTime > STARTING_TIMEOUT_MS) {
156484
157881
  console.warn(`[Office] Agent ${agent.id} stuck in starting for >${STARTING_TIMEOUT_MS / 1e3}s \u2014 transitioning to error`);
156485
157882
  officeManager.setAgentError(officeId, agent.id, "Startup timed out");
@@ -156494,7 +157891,11 @@ WARNING: This link could potentially be dangerous`)) {
156494
157891
  changed = true;
156495
157892
  }
156496
157893
  } else if (serverStatus.inTurn) {
156497
- if (!current || current.subState !== "thinking" && current.subState !== "waiting") {
157894
+ if (staleInTurnThinking) {
157895
+ console.warn(`[Office] Agent ${agent.id} stale inTurn for >${STALE_IN_TURN_THINKING_TIMEOUT_MS / 1e3}s \u2014 resetting to ready`);
157896
+ officeManager.setAgentReady(officeId, agent.id);
157897
+ changed = true;
157898
+ } else if (!current || current.subState !== "thinking" && current.subState !== "waiting") {
156498
157899
  officeManager.setTaskSummary(officeId, agent.id, "Processing...");
156499
157900
  officeManager.setAgentThinking(officeId, agent.id, "Processing...");
156500
157901
  changed = true;
@@ -156506,6 +157907,9 @@ WARNING: This link could potentially be dangerous`)) {
156506
157907
  officeManager.setAgentReady(officeId, agent.id);
156507
157908
  changed = true;
156508
157909
  } else if (current.subState === "thinking" && !serverStatus.inTurn) {
157910
+ if (thinkingAgeMs !== null && thinkingAgeMs < THINKING_TO_READY_GRACE_MS) {
157911
+ continue;
157912
+ }
156509
157913
  console.warn(`[Office] Agent ${agent.id} stuck in thinking but server reports idle \u2014 resetting to ready`);
156510
157914
  const agentTools = getCurrentAgentTools();
156511
157915
  if (agentTools.has(agent.id)) {
@@ -156529,7 +157933,7 @@ WARNING: This link could potentially be dangerous`)) {
156529
157933
  }
156530
157934
  if (changed) {
156531
157935
  for (const agent of getCurrentAgents()) {
156532
- phaserGame?.events.emit("agent:status:changed", agent.id);
157936
+ phaserGameRef?.events.emit("agent:status:changed", agent.id);
156533
157937
  }
156534
157938
  updateTerminalContent();
156535
157939
  updateStatusBar();
@@ -156549,8 +157953,27 @@ WARNING: This link could potentially be dangerous`)) {
156549
157953
  pendingTerminalContentUpdate = false;
156550
157954
  updateStatusBarNow();
156551
157955
  updateTerminalContentNow();
157956
+ drawOverviewSprites();
156552
157957
  phaserGameRef?.events.emit("agent:status:changed");
156553
- void syncAgentStatuses();
157958
+ void reconnectAgentStatuses();
157959
+ }
157960
+ async function reconnectAgentStatuses() {
157961
+ if (!window.copilotBridge) return;
157962
+ const officeId = officeManager.currentOfficeId;
157963
+ if (!officeId) return;
157964
+ await waitForSyncIdle();
157965
+ try {
157966
+ const statuses = await window.copilotBridge.queryAgentStatuses(officeId);
157967
+ for (const [agentId, info] of Object.entries(statuses)) {
157968
+ if (info.alive) {
157969
+ await window.copilotBridge.terminalAttach(officeId, agentId).catch(() => {
157970
+ });
157971
+ }
157972
+ }
157973
+ } catch (e) {
157974
+ console.warn("[Office] Failed to reconnect agent viewers:", e);
157975
+ }
157976
+ await syncAgentStatuses(true);
156554
157977
  }
156555
157978
  var ELAPSED_TICK_MS = 1e3;
156556
157979
  setInterval(() => {
@@ -156579,6 +158002,7 @@ WARNING: This link could potentially be dangerous`)) {
156579
158002
  }
156580
158003
  }, ELAPSED_TICK_MS);
156581
158004
  function updateStatusBarNow() {
158005
+ syncActiveRosterForCurrentOffice();
156582
158006
  const office = officeManager.currentOffice;
156583
158007
  const agents = office ? Array.from(office.agents.values()) : [];
156584
158008
  const officeName = officeManager.currentOffice?.config.name || "No Office";
@@ -156610,6 +158034,17 @@ WARNING: This link could potentially be dangerous`)) {
156610
158034
  cursor: pointer;
156611
158035
  margin-right: 24px;
156612
158036
  ">\u27F3 Reset All Sessions</button>
158037
+ <button id="reconnect-statuses-btn" style="
158038
+ background: #1a2a2a;
158039
+ border: 1px solid #4a8;
158040
+ color: #8f8;
158041
+ font-family: monospace;
158042
+ font-size: 14px;
158043
+ padding: 4px 16px;
158044
+ border-radius: 4px;
158045
+ cursor: pointer;
158046
+ margin-right: 24px;
158047
+ ">\u{1F50C} Re-connect Statuses</button>
156613
158048
  <span style="color: #666; font-size: 10px;">WASD: Walk | Shift: Run | Space: Talk | F10: Close terminal</span>
156614
158049
  `;
156615
158050
  if (html !== lastStatusBarHtml) {
@@ -156629,60 +158064,37 @@ WARNING: This link could potentially be dangerous`)) {
156629
158064
  btn.textContent = "\u27F3 Reset All Sessions";
156630
158065
  }
156631
158066
  });
158067
+ document.getElementById("reconnect-statuses-btn")?.addEventListener("click", async () => {
158068
+ const btn = document.getElementById("reconnect-statuses-btn");
158069
+ if (btn) {
158070
+ btn.disabled = true;
158071
+ btn.textContent = "\u{1F50C} Reconnecting...";
158072
+ }
158073
+ await reconnectAgentStatuses();
158074
+ if (btn) {
158075
+ btn.disabled = false;
158076
+ btn.textContent = "\u{1F50C} Re-connect Statuses";
158077
+ }
158078
+ });
156632
158079
  }
156633
158080
  }
156634
- updateStatusBar();
156635
158081
  setupTerminalClickHandler();
156636
- updateTerminalContent();
156637
- fetchSessionMeta();
156638
- var phaserGame = new import_phaser10.default.Game({
156639
- type: import_phaser10.default.AUTO,
156640
- parent: officePanel,
156641
- width: officePanel.clientWidth || window.innerWidth / 2,
156642
- height: officePanel.clientHeight || window.innerHeight,
156643
- backgroundColor: "#1a1a2e",
156644
- physics: { default: "arcade", arcade: { debug: false } },
156645
- scene: [BootScene, OfficeScene, MeetingScene]
156646
- });
156647
- phaserGameRef = phaserGame;
156648
- officePanel.addEventListener("click", () => {
156649
- const canvas = officePanel.querySelector("canvas");
156650
- canvas?.focus();
156651
- });
156652
- officePanel.addEventListener("mousedown", () => {
156653
- if (isMobileModeActive()) return;
156654
- console.log("[main] game panel mousedown \u2014 emitting game:panel:clicked");
156655
- phaserGame?.events.emit("game:panel:clicked");
156656
- });
156657
- phaserGame.events.once("ready", () => {
156658
- drawOverviewSprites();
156659
- phaserGame.events.emit("layout:change", { layoutKey: currentResponsiveLayout });
156660
- });
156661
- window.addEventListener("focus", () => {
156662
- catchUpStatusViews("window focus");
156663
- });
156664
- document.addEventListener("visibilitychange", () => {
156665
- if (!document.hidden) {
156666
- catchUpStatusViews("document visible");
156667
- }
156668
- });
156669
- phaserGame.events.on("agent:session:closed", (agentId) => {
158082
+ function onAgentSessionClosed(agentId) {
156670
158083
  const officeId = officeManager.currentOfficeId;
156671
158084
  if (officeId) officeManager.setAgentSlacking(officeId, agentId);
156672
- phaserGame?.events.emit("agent:status:changed", agentId);
158085
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
156673
158086
  updateTerminalContent();
156674
158087
  updateStatusBar();
156675
- });
156676
- phaserGame.events.on("agent:status:changed", () => {
158088
+ }
158089
+ function onAgentStatusChanged() {
156677
158090
  updateTerminalContent();
156678
158091
  updateStatusBar();
156679
- });
156680
- phaserGame.events.on("agent:reattached", (agentId) => {
158092
+ }
158093
+ function onAgentReattached(agentId) {
156681
158094
  console.log(`[Office] Agent reattached: ${agentId}`);
156682
- syncAgentStatuses();
156683
- });
156684
- phaserGame.events.on("bgm:started", onBgmStarted);
156685
- phaserGame.events.on("fleet:office:created", async (officeId, sourceOfficeId) => {
158095
+ void syncAgentStatuses();
158096
+ }
158097
+ async function onFleetOfficeCreated(officeId, sourceOfficeId) {
156686
158098
  console.log(`[Office] Fleet V-Team office created: ${officeId} (source: ${sourceOfficeId ?? "none"})`);
156687
158099
  if (sourceOfficeId && window.copilotBridge?.transferSession) {
156688
158100
  try {
@@ -156693,11 +158105,11 @@ WARNING: This link could potentially be dangerous`)) {
156693
158105
  }
156694
158106
  }
156695
158107
  if (sourceOfficeId) {
156696
- phaserGame?.events.emit("fleet:source-office", { sourceOfficeId });
158108
+ phaserGameRef?.events.emit("fleet:source-office", { sourceOfficeId });
156697
158109
  }
156698
158110
  switchToOffice(officeId);
156699
- });
156700
- phaserGame.events.on("fleet:deploy-requested", async (data) => {
158111
+ }
158112
+ async function onFleetDeployRequested(data) {
156701
158113
  console.log(`[Fleet] Deploy requested: "${data.officeName}" from office ${data.sourceOfficeId}`);
156702
158114
  const fleetOffice = officeManager.createOffice(data.officeName, ".", "fleet-vteam");
156703
158115
  const officeId = fleetOffice.config.id;
@@ -156713,24 +158125,96 @@ WARNING: This link could potentially be dangerous`)) {
156713
158125
  console.warn("[Fleet] copilotBridge.transferSession not available");
156714
158126
  }
156715
158127
  data.resolve?.();
156716
- phaserGame?.events.emit("fleet:source-office", { sourceOfficeId: data.sourceOfficeId, prompt: data.prompt });
158128
+ phaserGameRef?.events.emit("fleet:source-office", { sourceOfficeId: data.sourceOfficeId, prompt: data.prompt });
156717
158129
  switchToOffice(officeId);
156718
- });
156719
- phaserGame.events.on("fleet:status", (status) => {
158130
+ }
158131
+ function onFleetStatus(status) {
156720
158132
  const subtitle = document.getElementById("terminal-subtitle");
156721
158133
  if (subtitle && officeManager.currentOffice?.config.layout === "fleet-vteam") {
156722
158134
  subtitle.textContent = `Fleet: ${status.active} active \xB7 ${status.completed} done \xB7 ${status.failed} failed / ${status.total} total`;
156723
158135
  }
156724
158136
  updateTerminalContent();
156725
- });
156726
- phaserGame.events.on("fleet:complete", () => {
158137
+ }
158138
+ function onFleetComplete() {
156727
158139
  console.log("[Fleet] All sub-agents complete");
156728
158140
  const subtitle = document.getElementById("terminal-subtitle");
156729
158141
  if (subtitle) {
156730
158142
  subtitle.textContent = "\u2705 Fleet complete!";
156731
158143
  }
156732
158144
  updateTerminalContent();
158145
+ }
158146
+ var officePanelListenersBound = false;
158147
+ function bindOfficePanelListeners() {
158148
+ if (officePanelListenersBound) return;
158149
+ officePanelListenersBound = true;
158150
+ officePanel.addEventListener("click", () => {
158151
+ const canvas = officePanel.querySelector("canvas");
158152
+ canvas?.focus();
158153
+ });
158154
+ officePanel.addEventListener("mousedown", () => {
158155
+ if (isMobileModeActive()) return;
158156
+ console.log("[main] game panel mousedown \u2014 emitting game:panel:clicked");
158157
+ phaserGameRef?.events.emit("game:panel:clicked");
158158
+ });
158159
+ }
158160
+ function getPhaserDimensions() {
158161
+ return {
158162
+ width: officePanel.clientWidth || window.innerWidth / 2,
158163
+ height: officePanel.clientHeight || window.innerHeight
158164
+ };
158165
+ }
158166
+ function bindPhaserEventListeners(game) {
158167
+ game.events.once("ready", () => {
158168
+ drawOverviewSprites();
158169
+ game.events.emit("layout:change", { layoutKey: currentResponsiveLayout });
158170
+ });
158171
+ game.events.on("agent:session:closed", onAgentSessionClosed);
158172
+ game.events.on("agent:status:changed", onAgentStatusChanged);
158173
+ game.events.on("agent:reattached", onAgentReattached);
158174
+ game.events.on("bgm:started", onBgmStarted);
158175
+ game.events.on("fleet:office:created", onFleetOfficeCreated);
158176
+ game.events.on("fleet:deploy-requested", onFleetDeployRequested);
158177
+ game.events.on("fleet:status", onFleetStatus);
158178
+ game.events.on("fleet:complete", onFleetComplete);
158179
+ }
158180
+ function ensurePhaserGame() {
158181
+ if (phaserGameRef) return;
158182
+ const { width, height } = getPhaserDimensions();
158183
+ const game = new import_phaser10.default.Game({
158184
+ type: import_phaser10.default.AUTO,
158185
+ parent: officePanel,
158186
+ width,
158187
+ height,
158188
+ backgroundColor: "#1a1a2e",
158189
+ physics: { default: "arcade", arcade: { debug: false } },
158190
+ scene: [BootScene, OfficeScene, MeetingScene]
158191
+ });
158192
+ phaserGameRef = game;
158193
+ bindPhaserEventListeners(game);
158194
+ }
158195
+ function teardownPhaserGame() {
158196
+ if (!phaserGameRef) return;
158197
+ const game = phaserGameRef;
158198
+ phaserGameRef = void 0;
158199
+ try {
158200
+ game.destroy(true);
158201
+ } catch (error) {
158202
+ console.warn("[main] Failed to destroy Phaser game cleanly:", error);
158203
+ }
158204
+ officePanel.innerHTML = "";
158205
+ }
158206
+ bindOfficePanelListeners();
158207
+ window.addEventListener("focus", () => {
158208
+ catchUpStatusViews("window focus");
158209
+ });
158210
+ document.addEventListener("visibilitychange", () => {
158211
+ if (!document.hidden) {
158212
+ catchUpStatusViews("document visible");
158213
+ }
156733
158214
  });
158215
+ syncActiveRosterForCurrentOffice();
158216
+ applyAppMode(appMode, { force: true, refreshTabs: false });
158217
+ fetchSessionMeta();
156734
158218
  }
156735
158219
  });
156736
158220
  return require_main();