copilotoffice 1.0.4 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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;
@@ -148659,10 +148760,92 @@ WARNING: This link could potentially be dangerous`)) {
148659
148760
  const el = this.spriteCardElement?.querySelector(".session-id-display");
148660
148761
  if (el && this.sessionId) {
148661
148762
  el.textContent = this.sessionId;
148662
- el.title = `Click to copy. Resume with: copilot --resume ${this.sessionId}`;
148763
+ el.title = `Click to copy. Resume with: copilot --session-id ${this.sessionId}`;
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,27 @@ 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
+ const isModifierPressed = event.ctrlKey || event.metaKey;
149507
+ const key = event.key.toLowerCase();
149508
+ if (event.type !== "keydown" || !isModifierPressed) return true;
149509
+ if (key === "c") {
149510
+ const selectedText = this.terminal?.hasSelection() ? this.terminal.getSelection() : "";
149511
+ if (!selectedText) {
149512
+ return true;
149513
+ }
149514
+ event.preventDefault();
149515
+ event.stopPropagation();
149516
+ navigator.clipboard.writeText(selectedText).catch((err) => {
149517
+ console.warn("[Terminal] Clipboard write failed:", err);
149518
+ });
149519
+ return false;
149520
+ }
149521
+ if (key === "v") {
149292
149522
  if (this.isReadOnly) return false;
149523
+ event.preventDefault();
149524
+ event.stopPropagation();
149293
149525
  navigator.clipboard.readText().then((text) => {
149294
149526
  if (text) this.terminal.paste(text);
149295
149527
  }).catch((err) => {
@@ -149301,8 +149533,34 @@ WARNING: This link could potentially be dangerous`)) {
149301
149533
  });
149302
149534
  this.terminal.onData((data) => {
149303
149535
  if (this.isReadOnly) return;
149304
- if (this.currentAgentId && window.copilotBridge) {
149305
- window.copilotBridge.terminalWrite(this.getOfficeId(), this.currentAgentId, data);
149536
+ if (!this.currentAgentId || !window.copilotBridge) return;
149537
+ let outbound = "";
149538
+ let shouldStartSlashNewSession = false;
149539
+ for (const ch of data) {
149540
+ if (ch === "\r" || ch === "\n") {
149541
+ const command = this.pendingInputLine.trim();
149542
+ this.pendingInputLine = "";
149543
+ if (command === "/new") {
149544
+ shouldStartSlashNewSession = true;
149545
+ }
149546
+ outbound += ch;
149547
+ continue;
149548
+ }
149549
+ if (ch === "\x7F") {
149550
+ this.pendingInputLine = this.pendingInputLine.slice(0, -1);
149551
+ outbound += ch;
149552
+ continue;
149553
+ }
149554
+ if (ch >= " ") {
149555
+ this.pendingInputLine += ch;
149556
+ }
149557
+ outbound += ch;
149558
+ }
149559
+ if (outbound.length > 0) {
149560
+ window.copilotBridge.terminalWrite(this.getOfficeId(), this.currentAgentId, outbound);
149561
+ }
149562
+ if (shouldStartSlashNewSession) {
149563
+ this.fetchSessionId(this.currentAgentId);
149306
149564
  }
149307
149565
  });
149308
149566
  this.resizeHandler = () => {
@@ -149370,18 +149628,27 @@ WARNING: This link could potentially be dangerous`)) {
149370
149628
  officePanel.style.width = "50%";
149371
149629
  terminalPanel.style.width = "50%";
149372
149630
  }
149631
+ refreshFocusAndGeometry() {
149632
+ this.clearRefitTimers();
149633
+ this.refitGeneration += 1;
149634
+ this.fitAndResizeTerminal({ refreshVisibleRows: true });
149635
+ this.focusTerminal();
149636
+ this.debouncedRefit();
149637
+ }
149373
149638
  /** Re-fit xterm after panel resize and notify PTY of new dimensions.
149374
149639
  * Multi-stage: immediate → 150ms → 350ms to catch late layout shifts. */
149375
149640
  debouncedRefit() {
149376
149641
  if (!this.fitAddon || !this.terminal || !this.currentAgentId) return;
149377
- for (const t of this.refitTimers) clearTimeout(t);
149378
- this.refitTimers.length = 0;
149642
+ const generation = ++this.refitGeneration;
149643
+ const agentId = this.currentAgentId;
149644
+ const officeId = this.getActiveOfficeId();
149645
+ this.clearRefitTimers();
149379
149646
  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
- }
149647
+ if (!this.isVisible) return;
149648
+ if (generation !== this.refitGeneration) return;
149649
+ if (this.currentAgentId !== agentId) return;
149650
+ if (this.getActiveOfficeId() !== officeId) return;
149651
+ this.fitAndResizeTerminal({ officeId, agentId });
149385
149652
  };
149386
149653
  requestAnimationFrame(() => {
149387
149654
  doFit();
@@ -149405,14 +149672,8 @@ WARNING: This link could potentially be dangerous`)) {
149405
149672
  }
149406
149673
  applySpriteCardResponsiveStyles() {
149407
149674
  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
149675
  this.spriteCardElement.style.minHeight = "";
149415
- this.spriteCardElement.style.padding = "15px 30px";
149676
+ this.spriteCardElement.style.padding = "16px 24px";
149416
149677
  }
149417
149678
  updateMobileKeyboardButtonVisibility() {
149418
149679
  if (!this.mobileKeyboardBtn) return;
@@ -149467,8 +149728,8 @@ WARNING: This link could potentially be dangerous`)) {
149467
149728
  setTerminalFocusVisual(focused) {
149468
149729
  this.isFocused = focused;
149469
149730
  if (this.spriteCardElement && this.spriteCardElement.style.display !== "none") {
149470
- this.spriteCardElement.style.background = focused ? "#1a1a2e" : "#111118";
149471
- this.spriteCardElement.style.borderTopColor = focused ? "#3a5a8a" : "#2a2a3a";
149731
+ this.spriteCardElement.style.background = focused ? "#13131f" : "#101019";
149732
+ this.spriteCardElement.style.borderTopColor = focused ? "#252540" : "#1c1c2f";
149472
149733
  }
149473
149734
  }
149474
149735
  setupKeyboardHandler() {
@@ -149483,6 +149744,9 @@ WARNING: This link could potentially be dangerous`)) {
149483
149744
  this.updateMobileKeyboardButtonVisibility();
149484
149745
  this.isVisible = false;
149485
149746
  this.isReadOnly = false;
149747
+ this.pendingInputLine = "";
149748
+ this.awaitingSessionIdRefresh = false;
149749
+ this.clearSessionRefreshTimers();
149486
149750
  this.closeHistoryPopover();
149487
149751
  this.restorePanelLayout();
149488
149752
  this.inputManager.deactivateTerminalF10();
@@ -149521,8 +149785,9 @@ WARNING: This link could potentially be dangerous`)) {
149521
149785
  return false;
149522
149786
  }
149523
149787
  destroy() {
149524
- for (const t of this.refitTimers) clearTimeout(t);
149525
- this.refitTimers.length = 0;
149788
+ this.clearRefitTimers();
149789
+ this.awaitingSessionIdRefresh = false;
149790
+ this.clearSessionRefreshTimers();
149526
149791
  if (this.resizeHandler) {
149527
149792
  window.removeEventListener("resize", this.resizeHandler);
149528
149793
  this.resizeHandler = null;
@@ -150477,8 +150742,11 @@ WARNING: This link could potentially be dangerous`)) {
150477
150742
  "use strict";
150478
150743
  DESKTOP_DASHBOARD_TYPOGRAPHY = {
150479
150744
  cardTitle: "15px",
150745
+ cardTitleLg: "18px",
150480
150746
  cardDescription: "11px",
150481
150747
  statusText: "11px",
150748
+ statusPanelText: "13px",
150749
+ statusPanelIcon: "26px",
150482
150750
  statusDot: "8px",
150483
150751
  elapsed: "10px",
150484
150752
  badge: "10px",
@@ -150489,14 +150757,18 @@ WARNING: This link could potentially be dangerous`)) {
150489
150757
  taskSummary: "10px",
150490
150758
  sessionLabel: "9px",
150491
150759
  sessionTitle: "13px",
150760
+ sessionTitleLg: "15px",
150492
150761
  sessionButton: "11px",
150493
150762
  emptyState: "11px",
150494
150763
  arthurHint: "10px"
150495
150764
  };
150496
150765
  MOBILE_DASHBOARD_TYPOGRAPHY = {
150497
150766
  cardTitle: "19px",
150767
+ cardTitleLg: "24px",
150498
150768
  cardDescription: "15px",
150499
150769
  statusText: "16px",
150770
+ statusPanelText: "18px",
150771
+ statusPanelIcon: "34px",
150500
150772
  statusDot: "11px",
150501
150773
  elapsed: "14px",
150502
150774
  badge: "13px",
@@ -150507,6 +150779,7 @@ WARNING: This link could potentially be dangerous`)) {
150507
150779
  taskSummary: "14px",
150508
150780
  sessionLabel: "13px",
150509
150781
  sessionTitle: "17px",
150782
+ sessionTitleLg: "20px",
150510
150783
  sessionButton: "14px",
150511
150784
  emptyState: "14px",
150512
150785
  arthurHint: "14px"
@@ -150538,6 +150811,7 @@ WARNING: This link could potentially be dangerous`)) {
150538
150811
  display: flex;
150539
150812
  align-items: center;
150540
150813
  gap: 12px;
150814
+ min-height: 108px;
150541
150815
  ">
150542
150816
  <div style="
150543
150817
  width: 64px;
@@ -150626,11 +150900,11 @@ WARNING: This link could potentially be dangerous`)) {
150626
150900
  padding: 0 4px;
150627
150901
  box-shadow: 0 1px 4px rgba(0,0,0,0.4);
150628
150902
  ">${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="
150903
+ const elapsedHtml = elapsed ? `<div data-elapsed-agent="${agent.id}" style="color: #8a8; font-size: ${t.elapsed}; margin-top: 4px;">\u23F1 ${elapsed}</div>` : "";
150904
+ const queueHtml = toolCount > 1 ? `<div style="
150631
150905
  background: #334; color: #aac; font-size: ${t.queue};
150632
- padding: 1px 6px; border-radius: 8px; margin-left: 6px;
150633
- ">${toolCount} tools</span>` : "";
150906
+ padding: 2px 8px; border-radius: 8px; margin-top: 4px;
150907
+ ">${toolCount} tools queued</div>` : "";
150634
150908
  let toolPipelineHtml = "";
150635
150909
  if (tools.length > 0) {
150636
150910
  const toolRows = tools.map((t2, i) => {
@@ -150686,12 +150960,19 @@ WARNING: This link could potentially be dangerous`)) {
150686
150960
  ">
150687
150961
  <div style="font-size: ${t.sessionLabel}; color: #3a3a5a; text-transform: uppercase; letter-spacing: 0.5px;">Session Info</div>
150688
150962
  <div class="session-title-display" data-agent="${agent.id}" style="
150689
- font-weight: bold; color: ${metaTitle ? "#ccd" : "#444"}; font-size: ${t.sessionTitle};
150963
+ font-weight: bold; color: ${metaTitle ? "#ccd" : "#444"}; font-size: ${t.sessionTitleLg};
150690
150964
  cursor: text; min-height: 18px; line-height: 1.4;
150691
150965
  overflow: hidden; text-overflow: ellipsis;
150692
150966
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
150693
150967
  " 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;">
150968
+ <button class="session-new-btn" data-agent="${agent.id}" style="
150969
+ margin-top: 2px;
150970
+ align-self: flex-start;
150971
+ background: #2a3a4a; border: 1px solid #4a5a6a; color: #a9cff7;
150972
+ font-size: ${t.sessionButton}; padding: 4px 10px; border-radius: 4px;
150973
+ cursor: pointer; transition: background 0.15s, border-color 0.15s;
150974
+ " title="Start a new session for this agent">\u{1F504} New Session</button>
150975
+ <div style="display: flex; justify-content: flex-end;">
150695
150976
  <button class="session-edit-btn" data-agent="${agent.id}" style="
150696
150977
  background: none; border: 1px solid #333; color: #667;
150697
150978
  font-size: ${t.sessionButton}; padding: 2px 8px; border-radius: 4px;
@@ -150725,46 +151006,60 @@ WARNING: This link could potentially be dangerous`)) {
150725
151006
  align-items: flex-start;
150726
151007
  gap: 14px;
150727
151008
  position: relative;
150728
- min-height: 200px;
151009
+ min-height: 236px;
150729
151010
  ">
150730
151011
  ${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>
151012
+ <div style="flex-shrink: 0; width: 96px; display: flex; flex-direction: column; align-items: stretch; gap: 10px;">
151013
+ <div style="
151014
+ width: 96px;
151015
+ background: ${colorHex}22;
151016
+ border: 1px solid ${colorHex}44;
151017
+ border-radius: 10px;
151018
+ display: flex;
151019
+ align-items: center;
151020
+ justify-content: center;
151021
+ overflow: hidden;
151022
+ align-self: flex-start;
151023
+ padding: 6px 0;
151024
+ ">
151025
+ <canvas
151026
+ id="overview-sprite-${agent.id}"
151027
+ width="32" height="34"
151028
+ style="image-rendering: pixelated; width: 72px; height: 76px; display: block;"
151029
+ ></canvas>
151030
+ </div>
151031
+ <div style="
151032
+ border: 1px solid ${statusDot}66;
151033
+ background: ${statusDot}22;
151034
+ border-radius: 10px;
151035
+ padding: 8px 6px;
151036
+ display: flex;
151037
+ flex-direction: column;
151038
+ align-items: center;
151039
+ text-align: center;
151040
+ min-height: 96px;
151041
+ justify-content: center;
151042
+ ">
151043
+ <div style="font-size: ${t.statusPanelIcon}; line-height: 1;">${statusIcon}</div>
151044
+ <div style="
151045
+ margin-top: 6px;
151046
+ font-size: ${t.statusPanelText};
151047
+ color: ${statusDot};
151048
+ line-height: 1.15;
151049
+ font-weight: 700;
151050
+ white-space: normal;
151051
+ word-break: break-word;
151052
+ ">${statusLabel}</div>
151053
+ ${elapsedHtml}
151054
+ ${queueHtml}
151055
+ </div>
150749
151056
  </div>
150750
151057
  <div style="flex: 3; min-width: 0; display: flex; flex-direction: column; gap: 4px;">
150751
151058
  <div>
150752
- <div style="font-weight: bold; color: #dde; font-size: ${t.cardTitle};">${agent.name}</div>
151059
+ <div style="font-weight: bold; color: #dde; font-size: ${t.cardTitleLg};">${agent.name}</div>
150753
151060
  <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
151061
  </div>
150755
151062
  <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
151063
  ${taskSummaryHtml}
150769
151064
  </div>
150770
151065
  ${toolPipelineHtml}
@@ -150795,6 +151090,10 @@ WARNING: This link could potentially be dangerous`)) {
150795
151090
  context.emitOpenTerminal(agentId);
150796
151091
  },
150797
151092
  handleMetaPanelClick(target, agentId, context) {
151093
+ if (target.closest(".session-new-btn")) {
151094
+ context.startNewSession(agentId);
151095
+ return;
151096
+ }
150798
151097
  if (target.closest(".session-edit-btn") || target.closest(".session-title-display")) {
150799
151098
  context.startSessionMetaEdit(agentId);
150800
151099
  }
@@ -150896,7 +151195,7 @@ WARNING: This link could potentially be dangerous`)) {
150896
151195
  background: ${bgColor};
150897
151196
  border: 1.5px solid ${borderColor};
150898
151197
  border-radius: 10px;
150899
- padding: 14px 16px;
151198
+ padding: 18px 16px;
150900
151199
  margin-bottom: 8px;
150901
151200
  cursor: ${cursor};
150902
151201
  transition: border-color 0.15s;
@@ -150904,6 +151203,7 @@ WARNING: This link could potentially be dangerous`)) {
150904
151203
  align-items: flex-start;
150905
151204
  gap: 12px;
150906
151205
  position: relative;
151206
+ min-height: 124px;
150907
151207
  ">
150908
151208
  <div style="
150909
151209
  flex-shrink: 0;
@@ -153555,12 +153855,8 @@ WARNING: This link could potentially be dangerous`)) {
153555
153855
  if (this.currentLayout === "default") {
153556
153856
  const officeId = officeManager.currentOfficeId;
153557
153857
  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);
153858
+ const restoredSeatedAgents = restoreSeatedReserveAgents(officeManager.getSeatedAgents(officeId));
153859
+ for (const { deskId, agentId } of restoredSeatedAgents) {
153564
153860
  const desk = this.desks.find((d) => d.agentId === deskId);
153565
153861
  if (desk) {
153566
153862
  desk.agentId = agentId;
@@ -155443,151 +155739,969 @@ WARNING: This link could potentially be dangerous`)) {
155443
155739
  }
155444
155740
  });
155445
155741
 
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
- }
155742
+ // src/ui/SeriousTerminalController.ts
155743
+ var import_xterm2, import_addon_fit2, SeriousTerminalController;
155744
+ var init_SeriousTerminalController = __esm({
155745
+ "src/ui/SeriousTerminalController.ts"() {
155746
+ "use strict";
155747
+ import_xterm2 = __toESM(require_xterm());
155748
+ import_addon_fit2 = __toESM(require_addon_fit());
155749
+ SeriousTerminalController = class _SeriousTerminalController {
155750
+ constructor(host, options = {}) {
155751
+ this.historyPopover = null;
155752
+ this.terminal = null;
155753
+ this.fitAddon = null;
155754
+ this.resizeObserver = null;
155755
+ this.resizeHandler = null;
155756
+ this.refitTimers = [];
155757
+ this.activeOfficeId = null;
155758
+ this.activeAgentId = null;
155759
+ this.visible = false;
155760
+ this.openedAt = 0;
155761
+ this.sessionId = null;
155762
+ this.activeOptions = null;
155763
+ this.isFullWidth = false;
155764
+ this.host = host;
155765
+ this.onClose = options.onClose;
155766
+ this.isFullWidth = localStorage.getItem(_SeriousTerminalController.FULL_WIDTH_STORAGE_KEY) === "true";
155767
+ this.container = document.createElement("div");
155768
+ this.container.style.cssText = `
155769
+ display: none;
155770
+ flex-direction: column;
155771
+ flex: 1;
155772
+ min-height: 0;
155773
+ background: #11131c;
155774
+ color: #d7defa;
155775
+ border-left: 2px solid #2f3f62;
155776
+ font-family: 'Cascadia Code', Consolas, monospace;
155777
+ `;
155778
+ const header = document.createElement("div");
155779
+ header.style.cssText = `
155780
+ display: flex;
155781
+ align-items: center;
155782
+ justify-content: space-between;
155783
+ gap: 8px;
155784
+ padding: 12px 14px;
155785
+ border-bottom: 1px solid #27314e;
155786
+ background: #171b2a;
155787
+ flex-shrink: 0;
155788
+ `;
155789
+ const leftHeader = document.createElement("div");
155790
+ leftHeader.style.cssText = "min-width: 0;";
155791
+ this.titleEl = document.createElement("div");
155792
+ this.titleEl.style.cssText = "font-size: 14px; font-weight: 700; color: #9fc2ff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;";
155793
+ this.subtitleEl = document.createElement("div");
155794
+ this.subtitleEl.style.cssText = "font-size: 11px; color: #7f8bad; margin-top: 3px;";
155795
+ leftHeader.appendChild(this.titleEl);
155796
+ leftHeader.appendChild(this.subtitleEl);
155797
+ const rightHeader = document.createElement("div");
155798
+ rightHeader.style.cssText = "display: flex; align-items: center; gap: 6px;";
155799
+ this.statusEl = document.createElement("div");
155800
+ this.statusEl.style.cssText = "font-size: 11px; color: #8ca2db; margin-right: 4px;";
155801
+ const detachBtn = document.createElement("button");
155802
+ detachBtn.textContent = "Detach";
155803
+ detachBtn.style.cssText = this.buttonCss("#2f3754", "#6f8ed8");
155804
+ detachBtn.addEventListener("click", () => {
155805
+ void this.closeView({ detach: true });
155806
+ });
155807
+ const closeBtn = document.createElement("button");
155808
+ closeBtn.textContent = "Close";
155809
+ closeBtn.style.cssText = this.buttonCss("#3a2534", "#c98fbb");
155810
+ closeBtn.addEventListener("click", () => {
155811
+ void this.closeView({ detach: true });
155812
+ });
155813
+ rightHeader.appendChild(this.statusEl);
155814
+ rightHeader.appendChild(detachBtn);
155815
+ rightHeader.appendChild(closeBtn);
155816
+ header.appendChild(leftHeader);
155817
+ header.appendChild(rightHeader);
155818
+ this.terminalOuterEl = document.createElement("div");
155819
+ this.terminalOuterEl.style.cssText = `
155820
+ flex: 1;
155821
+ min-height: 0;
155822
+ overflow: hidden;
155823
+ background: #0d111b;
155824
+ padding: 10px;
155825
+ box-sizing: border-box;
155826
+ `;
155827
+ this.terminalDivEl = document.createElement("div");
155828
+ this.terminalDivEl.style.cssText = "width: 100%; height: 100%; overflow: hidden;";
155829
+ this.terminalOuterEl.appendChild(this.terminalDivEl);
155830
+ this.terminalOuterEl.addEventListener("mousedown", () => this.terminal?.focus());
155831
+ this.spriteCardEl = document.createElement("div");
155832
+ this.spriteCardEl.style.cssText = `
155833
+ width: 100%;
155834
+ background: #13131f;
155835
+ border-top: 1px solid #252540;
155836
+ font-family: 'Cascadia Code', Consolas, monospace;
155837
+ color: #c8d4ff;
155838
+ display: flex;
155839
+ flex-shrink: 0;
155840
+ justify-content: space-between;
155841
+ align-items: stretch;
155842
+ gap: 24px;
155843
+ min-height: 148px;
155844
+ padding: 16px 24px;
155845
+ box-sizing: border-box;
155846
+ `;
155847
+ const spriteCardLeft = document.createElement("div");
155848
+ spriteCardLeft.style.cssText = "display: flex; align-items: center; gap: 18px; min-width: 0; flex: 1;";
155849
+ const spriteFrame = document.createElement("div");
155850
+ spriteFrame.style.cssText = `
155851
+ width: 72px;
155852
+ background: #2a2a40;
155853
+ border: 1px solid #3a3a58;
155854
+ border-radius: 8px;
155855
+ display: flex;
155856
+ align-items: center;
155857
+ justify-content: center;
155858
+ overflow: hidden;
155859
+ flex-shrink: 0;
155860
+ `;
155861
+ this.spriteCanvasEl = document.createElement("canvas");
155862
+ this.spriteCanvasEl.width = 32;
155863
+ this.spriteCanvasEl.height = 34;
155864
+ this.spriteCanvasEl.style.cssText = `
155865
+ image-rendering: pixelated;
155866
+ width: 64px;
155867
+ height: 68px;
155868
+ display: block;
155869
+ `;
155870
+ spriteFrame.appendChild(this.spriteCanvasEl);
155871
+ const spriteCardText = document.createElement("div");
155872
+ spriteCardText.style.cssText = "display: flex; flex-direction: column; gap: 4px; min-width: 0;";
155873
+ this.spriteNameEl = document.createElement("span");
155874
+ this.spriteNameEl.style.cssText = "font-size: 18px; font-weight: 700; color: #dde; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;";
155875
+ this.spriteSubtitleEl = document.createElement("span");
155876
+ this.spriteSubtitleEl.style.cssText = "font-size: 13px; color: #778; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;";
155877
+ this.sessionTitleEl = document.createElement("span");
155878
+ this.sessionTitleEl.textContent = "Untitled session";
155879
+ this.sessionTitleEl.style.cssText = "font-size: 14px; font-weight: 700; color: #77839f; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;";
155880
+ spriteCardText.appendChild(this.spriteNameEl);
155881
+ spriteCardText.appendChild(this.spriteSubtitleEl);
155882
+ spriteCardText.appendChild(this.sessionTitleEl);
155883
+ spriteCardLeft.appendChild(spriteFrame);
155884
+ spriteCardLeft.appendChild(spriteCardText);
155885
+ const spriteCardRight = document.createElement("div");
155886
+ spriteCardRight.style.cssText = "display: flex; flex-direction: column; justify-content: center; align-items: flex-end; gap: 8px;";
155887
+ const sessionLabel = document.createElement("span");
155888
+ sessionLabel.textContent = "Session ID";
155889
+ sessionLabel.style.cssText = "font-size: 11px; color: #6f7fa9;";
155890
+ this.sessionIdEl = document.createElement("span");
155891
+ this.sessionIdEl.textContent = "--";
155892
+ this.sessionIdEl.style.cssText = "font-size: 12px; color: #8ec3ff; cursor: pointer;";
155893
+ this.sessionIdEl.title = "Copy session ID";
155894
+ this.sessionIdEl.onclick = () => this.copySessionId();
155895
+ spriteCardRight.appendChild(sessionLabel);
155896
+ spriteCardRight.appendChild(this.sessionIdEl);
155897
+ const buttonGrid = document.createElement("div");
155898
+ buttonGrid.style.cssText = `
155899
+ display: grid;
155900
+ grid-template-columns: repeat(2, max-content);
155901
+ gap: 6px;
155902
+ margin-top: 2px;
155903
+ `;
155904
+ const footerBtnCss = this.buttonCss("#2a3a4a", "#4a5a6a");
155905
+ const historyBtn = document.createElement("button");
155906
+ historyBtn.textContent = "Session History";
155907
+ historyBtn.style.cssText = footerBtnCss;
155908
+ historyBtn.onclick = () => {
155909
+ void this.toggleSessionHistory(historyBtn);
155910
+ };
155911
+ buttonGrid.appendChild(historyBtn);
155912
+ const newSessionBtn = document.createElement("button");
155913
+ newSessionBtn.textContent = "New Session";
155914
+ newSessionBtn.style.cssText = footerBtnCss;
155915
+ newSessionBtn.onclick = () => {
155916
+ void this.handleNewSession();
155917
+ };
155918
+ buttonGrid.appendChild(newSessionBtn);
155919
+ const clearHistoryBtn = document.createElement("button");
155920
+ clearHistoryBtn.textContent = "Clear History";
155921
+ clearHistoryBtn.style.cssText = footerBtnCss;
155922
+ clearHistoryBtn.onclick = () => {
155923
+ void this.handleClearHistory();
155924
+ };
155925
+ buttonGrid.appendChild(clearHistoryBtn);
155926
+ const closeSessionBtn = document.createElement("button");
155927
+ closeSessionBtn.textContent = "Close Session";
155928
+ closeSessionBtn.style.cssText = this.buttonCss("#3a2a2a", "#8f5d5d");
155929
+ closeSessionBtn.onclick = () => {
155930
+ void this.handleCloseSession();
155931
+ };
155932
+ buttonGrid.appendChild(closeSessionBtn);
155933
+ this.fullscreenBtn = document.createElement("button");
155934
+ this.fullscreenBtn.textContent = this.isFullWidth ? "Half Width" : "Full Width";
155935
+ this.fullscreenBtn.style.cssText = this.buttonCss("#2a2f4a", "#5a6aa0");
155936
+ this.fullscreenBtn.onclick = () => this.toggleFullWidth();
155937
+ buttonGrid.appendChild(this.fullscreenBtn);
155938
+ const refreshFocusBtn = document.createElement("button");
155939
+ refreshFocusBtn.textContent = "Refresh Focus";
155940
+ refreshFocusBtn.style.cssText = this.buttonCss("#2a3a2a", "#4f7b63");
155941
+ refreshFocusBtn.onclick = () => this.refreshFocusAndGeometry();
155942
+ buttonGrid.appendChild(refreshFocusBtn);
155943
+ spriteCardRight.appendChild(buttonGrid);
155944
+ this.spriteCardEl.appendChild(spriteCardLeft);
155945
+ this.spriteCardEl.appendChild(spriteCardRight);
155946
+ this.ensureXtermStyles();
155947
+ this.container.appendChild(header);
155948
+ this.container.appendChild(this.terminalOuterEl);
155949
+ this.container.appendChild(this.spriteCardEl);
155950
+ this.host.appendChild(this.container);
155951
+ this.createTerminal();
155952
+ if (window.copilotBridge) {
155953
+ window.copilotBridge.onTerminalData((agentId, data) => {
155954
+ if (!this.visible || this.activeAgentId !== agentId) return;
155955
+ this.terminal?.write(data);
155956
+ });
155957
+ window.copilotBridge.onTerminalExit((agentId, exitCode) => {
155958
+ if (!this.visible || this.activeAgentId !== agentId) return;
155959
+ this.terminal?.writeln(`\r
155960
+ [terminal exited with code ${exitCode}]`);
155961
+ this.setStatus("Exited");
155962
+ });
155963
+ window.copilotBridge.onSessionMetaUpdated((agentId) => {
155964
+ if (!this.visible || !this.activeOfficeId || this.activeAgentId !== agentId) return;
155965
+ void this.updateSessionTitle(this.activeOfficeId, agentId);
155966
+ });
155967
+ }
155968
+ }
155969
+ static {
155970
+ this.FULL_WIDTH_STORAGE_KEY = "agencyOffice:seriousTerminalFullWidth";
155971
+ }
155972
+ isVisible() {
155973
+ return this.visible;
155974
+ }
155975
+ refreshCardFromOverview() {
155976
+ if (!this.visible || !this.activeAgentId) return;
155977
+ this.renderExactOverviewCard(this.activeAgentId);
155978
+ }
155979
+ async openAgentTerminal(options) {
155980
+ if (!window.copilotBridge || !this.terminal) return;
155981
+ const switchingTarget = this.activeOfficeId !== options.officeId || this.activeAgentId !== options.agentId;
155982
+ if (switchingTarget) {
155983
+ await this.closeView({ detach: true, silent: true });
155984
+ }
155985
+ this.activeOfficeId = options.officeId;
155986
+ this.activeAgentId = options.agentId;
155987
+ this.activeOptions = { ...options };
155988
+ this.visible = true;
155989
+ this.openedAt = Date.now();
155990
+ this.sessionId = null;
155991
+ this.container.style.display = "flex";
155992
+ this.terminal.clear();
155993
+ this.titleEl.textContent = `${options.name} (${options.agentId})`;
155994
+ this.subtitleEl.textContent = options.description;
155995
+ this.updateSpriteCard(options);
155996
+ void this.updateSessionTitle(options.officeId, options.agentId);
155997
+ this.updateSessionIdDisplay();
155998
+ this.setStatus("Opening...");
155999
+ this.applyPanelLayout();
156000
+ this.refitAndResize(options.officeId, options.agentId);
156001
+ try {
156002
+ const exists = await window.copilotBridge.terminalExists(options.officeId, options.agentId);
156003
+ if (!exists) {
156004
+ const dims = this.fitAddon?.proposeDimensions();
156005
+ const startResult = await window.copilotBridge.terminalStart(
156006
+ options.officeId,
156007
+ options.agentId,
156008
+ options.workingDir,
156009
+ dims?.cols,
156010
+ dims?.rows,
156011
+ void 0,
156012
+ options.launchMode || "copilot"
156013
+ );
156014
+ if (!startResult.success) {
156015
+ this.terminal.writeln(`\r
156016
+ Failed to start terminal: ${startResult.error || "unknown error"}`);
156017
+ this.setStatus("Start failed");
156018
+ return;
156019
+ }
156020
+ if (startResult.sessionId) {
156021
+ this.sessionId = startResult.sessionId;
156022
+ this.updateSessionIdDisplay();
156023
+ }
156024
+ }
156025
+ const attachResult = await window.copilotBridge.terminalAttach(options.officeId, options.agentId);
156026
+ if (!attachResult.success) {
156027
+ this.terminal.writeln("\r\nFailed to attach terminal session.");
156028
+ this.setStatus("Attach failed");
156029
+ return;
156030
+ }
156031
+ if (attachResult.scrollback) {
156032
+ this.terminal.write(attachResult.scrollback);
156033
+ }
156034
+ const attachedSessionId = await window.copilotBridge.getSessionId(options.officeId, options.agentId);
156035
+ if (attachedSessionId) {
156036
+ this.sessionId = attachedSessionId;
156037
+ this.updateSessionIdDisplay();
156038
+ }
156039
+ this.setStatus(`Attached \xB7 ${this.formatElapsed(this.openedAt)}`);
156040
+ this.terminal.focus();
156041
+ this.debouncedRefit(options.officeId, options.agentId);
156042
+ this.refreshCardFromOverview();
156043
+ } catch (error) {
156044
+ this.terminal.writeln(`\r
156045
+ Terminal error: ${error?.message || String(error)}`);
156046
+ this.setStatus("Error");
156047
+ this.refreshCardFromOverview();
156048
+ }
156049
+ }
156050
+ async startNewSession(options) {
156051
+ if (!window.copilotBridge) return;
156052
+ try {
156053
+ await window.copilotBridge.resetSession(options.officeId, options.agentId);
156054
+ } catch {
156055
+ }
156056
+ const isCurrentView = this.visible && this.activeOfficeId === options.officeId && this.activeAgentId === options.agentId;
156057
+ if (isCurrentView) {
156058
+ await this.openAgentTerminal(options);
156059
+ return;
156060
+ }
156061
+ const startResult = await window.copilotBridge.terminalStart(
156062
+ options.officeId,
156063
+ options.agentId,
156064
+ options.workingDir,
156065
+ void 0,
156066
+ void 0,
156067
+ void 0,
156068
+ options.launchMode || "copilot"
156069
+ );
156070
+ if (!startResult.success) {
156071
+ console.warn(
156072
+ `[SeriousTerminalController] Failed to start new session for ${options.agentId}: ${startResult.error || "unknown error"}`
156073
+ );
156074
+ }
156075
+ }
156076
+ async closeView(options = {}) {
156077
+ const { detach = true, silent = false } = options;
156078
+ if (detach && this.activeOfficeId && this.activeAgentId && window.copilotBridge) {
156079
+ try {
156080
+ await window.copilotBridge.terminalDetach(this.activeOfficeId, this.activeAgentId);
156081
+ } catch {
156082
+ }
156083
+ }
156084
+ this.visible = false;
156085
+ this.container.style.display = "none";
156086
+ this.activeOfficeId = null;
156087
+ this.activeAgentId = null;
156088
+ this.activeOptions = null;
156089
+ this.sessionId = null;
156090
+ this.sessionTitleEl.textContent = "Untitled session";
156091
+ this.sessionTitleEl.style.color = "#77839f";
156092
+ this.updateSessionIdDisplay();
156093
+ this.setStatus("");
156094
+ this.clearRefitTimers();
156095
+ this.closeSessionHistoryPopover();
156096
+ this.applyPanelLayout();
156097
+ if (!silent) {
156098
+ this.onClose?.();
156099
+ }
156100
+ }
156101
+ setStatus(text) {
156102
+ this.statusEl.textContent = text;
156103
+ }
156104
+ updateSpriteCard(options) {
156105
+ this.spriteNameEl.textContent = options.name;
156106
+ this.spriteSubtitleEl.textContent = options.description;
156107
+ const colorHex = `#${(options.color ?? 7311064).toString(16).padStart(6, "0")}`;
156108
+ this.spriteNameEl.style.color = colorHex;
156109
+ this.renderAgentSprite(options.agentId, options.color ?? 7311064);
156110
+ }
156111
+ updateSessionIdDisplay() {
156112
+ this.sessionIdEl.textContent = this.sessionId || "--";
156113
+ }
156114
+ renderExactOverviewCard(agentId) {
156115
+ const sourceCard = document.querySelector(`#overview-content .agent-card[data-agent="${agentId}"]`);
156116
+ if (!sourceCard) return;
156117
+ const clonedCard = sourceCard.cloneNode(true);
156118
+ clonedCard.style.marginBottom = "0";
156119
+ clonedCard.style.cursor = "default";
156120
+ const sourceCanvases = sourceCard.querySelectorAll("canvas");
156121
+ const cloneCanvases = clonedCard.querySelectorAll("canvas");
156122
+ cloneCanvases.forEach((node, i) => {
156123
+ const canvas = node;
156124
+ canvas.removeAttribute("id");
156125
+ const src = sourceCanvases[i];
156126
+ const ctx = canvas.getContext("2d");
156127
+ if (!src || !ctx) return;
156128
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
156129
+ ctx.drawImage(src, 0, 0);
156130
+ });
156131
+ this.spriteCardEl.style.display = "block";
156132
+ this.spriteCardEl.style.padding = "10px 10px 12px";
156133
+ this.spriteCardEl.style.minHeight = "0";
156134
+ this.spriteCardEl.style.gap = "0";
156135
+ this.spriteCardEl.style.alignItems = "stretch";
156136
+ this.spriteCardEl.style.justifyContent = "stretch";
156137
+ this.spriteCardEl.innerHTML = "";
156138
+ this.spriteCardEl.appendChild(clonedCard);
156139
+ }
156140
+ async updateSessionTitle(officeId, agentId) {
156141
+ if (!window.copilotBridge?.getSessionMeta) {
156142
+ this.sessionTitleEl.textContent = "Untitled session";
156143
+ this.sessionTitleEl.style.color = "#77839f";
156144
+ return;
156145
+ }
156146
+ try {
156147
+ const meta = await window.copilotBridge.getSessionMeta(officeId, agentId);
156148
+ const title = meta?.title?.trim();
156149
+ if (title) {
156150
+ this.sessionTitleEl.textContent = title;
156151
+ this.sessionTitleEl.style.color = "#c8d4ff";
156152
+ } else {
156153
+ this.sessionTitleEl.textContent = "Untitled session";
156154
+ this.sessionTitleEl.style.color = "#77839f";
156155
+ }
156156
+ } catch {
156157
+ this.sessionTitleEl.textContent = "Untitled session";
156158
+ this.sessionTitleEl.style.color = "#77839f";
156159
+ }
156160
+ }
156161
+ async handleNewSession() {
156162
+ if (!this.activeOptions) return;
156163
+ await this.startNewSession(this.activeOptions);
156164
+ this.closeSessionHistoryPopover();
156165
+ }
156166
+ async handleClearHistory() {
156167
+ if (!window.copilotBridge || !this.activeOfficeId || !this.activeAgentId) return;
156168
+ try {
156169
+ await window.copilotBridge.clearSessionHistory(this.activeOfficeId, this.activeAgentId);
156170
+ this.terminal?.writeln("\r\n[session history cleared]");
156171
+ this.closeSessionHistoryPopover();
156172
+ } catch {
156173
+ this.terminal?.writeln("\r\n[failed to clear session history]");
156174
+ }
156175
+ }
156176
+ async handleCloseSession() {
156177
+ if (!window.copilotBridge || !this.activeOfficeId || !this.activeAgentId) return;
156178
+ try {
156179
+ await window.copilotBridge.resetSession(this.activeOfficeId, this.activeAgentId);
156180
+ this.terminal?.writeln("\r\n[session closed]");
156181
+ } catch {
156182
+ this.terminal?.writeln("\r\n[failed to close session]");
156183
+ }
156184
+ await this.closeView({ detach: true });
156185
+ }
156186
+ async toggleSessionHistory(anchor) {
156187
+ if (!window.copilotBridge || !this.activeOfficeId || !this.activeAgentId) return;
156188
+ if (this.historyPopover) {
156189
+ this.closeSessionHistoryPopover();
156190
+ return;
156191
+ }
156192
+ let history = [];
156193
+ try {
156194
+ history = await window.copilotBridge.getSessionHistory(this.activeOfficeId, this.activeAgentId);
156195
+ } catch {
156196
+ history = [];
156197
+ }
156198
+ const pop = document.createElement("div");
156199
+ pop.style.cssText = `
156200
+ position: absolute;
156201
+ right: 12px;
156202
+ bottom: calc(100% + 8px);
156203
+ width: min(620px, 88vw);
156204
+ max-height: 280px;
156205
+ overflow: auto;
156206
+ background: #101629;
156207
+ border: 1px solid #2f3f62;
156208
+ border-radius: 8px;
156209
+ box-shadow: 0 12px 28px rgba(0, 0, 0, 0.45);
156210
+ padding: 10px 12px;
156211
+ z-index: 10003;
156212
+ color: #c8d4ff;
156213
+ font-size: 12px;
156214
+ white-space: pre-wrap;
156215
+ line-height: 1.4;
156216
+ `;
156217
+ const title = document.createElement("div");
156218
+ title.textContent = `Session History (${history.length})`;
156219
+ title.style.cssText = "font-weight: 700; margin-bottom: 8px; color: #9fc2ff;";
156220
+ pop.appendChild(title);
156221
+ const body = document.createElement("div");
156222
+ if (history.length === 0) {
156223
+ body.textContent = "No history yet.";
156224
+ body.style.cssText = "color: #77839f; font-style: italic;";
156225
+ } else {
156226
+ body.textContent = history.join("\n");
156227
+ }
156228
+ pop.appendChild(body);
156229
+ const closeBtn = document.createElement("button");
156230
+ closeBtn.textContent = "Close";
156231
+ closeBtn.style.cssText = `${this.buttonCss("#2a2f4a", "#5a6aa0")} margin-top: 10px;`;
156232
+ closeBtn.onclick = () => this.closeSessionHistoryPopover();
156233
+ pop.appendChild(closeBtn);
156234
+ this.historyPopover = pop;
156235
+ this.spriteCardEl.style.position = "relative";
156236
+ this.spriteCardEl.appendChild(pop);
156237
+ anchor.blur();
156238
+ }
156239
+ closeSessionHistoryPopover() {
156240
+ if (this.historyPopover?.parentElement) {
156241
+ this.historyPopover.parentElement.removeChild(this.historyPopover);
156242
+ }
156243
+ this.historyPopover = null;
156244
+ }
156245
+ copySessionId() {
156246
+ if (!this.sessionId) return;
156247
+ navigator.clipboard.writeText(this.sessionId).then(() => {
156248
+ const original = this.sessionIdEl.textContent;
156249
+ this.sessionIdEl.textContent = "Copied!";
156250
+ this.sessionIdEl.style.color = "#61d394";
156251
+ setTimeout(() => {
156252
+ this.sessionIdEl.textContent = original;
156253
+ this.sessionIdEl.style.color = "#8ec3ff";
156254
+ }, 900);
156255
+ }).catch(() => {
156256
+ });
156257
+ }
156258
+ renderAgentSprite(seed, baseColor) {
156259
+ const ctx = this.spriteCanvasEl.getContext("2d");
156260
+ if (!ctx) return;
156261
+ ctx.clearRect(0, 0, 32, 34);
156262
+ ctx.imageSmoothingEnabled = false;
156263
+ const color = this.toHex(baseColor);
156264
+ const shade = this.toHex(this.scaleColor(baseColor, 0.72));
156265
+ const accent = this.toHex(this.scaleColor(baseColor, 1.22));
156266
+ const skin = "#f3cfa7";
156267
+ ctx.fillStyle = "#0f1425";
156268
+ ctx.fillRect(0, 0, 32, 34);
156269
+ ctx.fillStyle = shade;
156270
+ ctx.fillRect(8, 16, 16, 14);
156271
+ ctx.fillStyle = color;
156272
+ ctx.fillRect(9, 16, 14, 13);
156273
+ ctx.fillStyle = skin;
156274
+ ctx.fillRect(10, 8, 12, 9);
156275
+ ctx.fillStyle = accent;
156276
+ ctx.fillRect(10, 5, 12, 4);
156277
+ ctx.fillStyle = "#182033";
156278
+ ctx.fillRect(13, 11, 2, 2);
156279
+ ctx.fillRect(17, 11, 2, 2);
156280
+ const seedValue = [...seed].reduce((acc, ch) => acc + ch.charCodeAt(0), 0);
156281
+ const badgeX = seedValue % 2 === 0 ? 5 : 24;
156282
+ ctx.fillStyle = accent;
156283
+ ctx.fillRect(badgeX, 19, 3, 3);
156284
+ }
156285
+ toHex(color) {
156286
+ return `#${color.toString(16).padStart(6, "0")}`;
156287
+ }
156288
+ scaleColor(color, multiplier) {
156289
+ const r = Math.min(255, Math.max(0, Math.round((color >> 16 & 255) * multiplier)));
156290
+ const g = Math.min(255, Math.max(0, Math.round((color >> 8 & 255) * multiplier)));
156291
+ const b = Math.min(255, Math.max(0, Math.round((color & 255) * multiplier)));
156292
+ return r << 16 | g << 8 | b;
156293
+ }
156294
+ ensureXtermStyles() {
156295
+ if (document.getElementById("xterm-styles")) return;
156296
+ const style = document.createElement("style");
156297
+ style.id = "xterm-styles";
156298
+ style.textContent = `
156299
+ .xterm { height: 100%; }
156300
+ .xterm-viewport { overflow-y: auto !important; }
156301
+ #serious-terminal-container .xterm { height: 100%; }
156302
+ `;
156303
+ document.head.appendChild(style);
156304
+ }
156305
+ createTerminal() {
156306
+ this.terminal = new import_xterm2.Terminal({
156307
+ theme: {
156308
+ background: "#0d111b",
156309
+ foreground: "#e0e0e0",
156310
+ cursor: "#00ff88",
156311
+ cursorAccent: "#0d111b",
156312
+ selectionBackground: "#3a5a8a"
156313
+ },
156314
+ fontFamily: "Cascadia Code, Consolas, Monaco, monospace",
156315
+ fontSize: 16,
156316
+ lineHeight: 1.2,
156317
+ cursorBlink: true,
156318
+ cursorStyle: "block",
156319
+ scrollback: 1e4,
156320
+ allowProposedApi: true
156321
+ });
156322
+ this.fitAddon = new import_addon_fit2.FitAddon();
156323
+ this.terminal.loadAddon(this.fitAddon);
156324
+ this.terminalDivEl.id = "serious-terminal-container";
156325
+ this.terminal.open(this.terminalDivEl);
156326
+ this.terminal.attachCustomKeyEventHandler((event) => {
156327
+ const isModifierPressed = event.ctrlKey || event.metaKey;
156328
+ const key = event.key.toLowerCase();
156329
+ if (event.type !== "keydown" || !isModifierPressed) return true;
156330
+ if (key === "c") {
156331
+ const selectedText = this.terminal?.hasSelection() ? this.terminal.getSelection() : "";
156332
+ if (!selectedText) {
156333
+ return true;
156334
+ }
156335
+ event.preventDefault();
156336
+ event.stopPropagation();
156337
+ navigator.clipboard.writeText(selectedText).catch(() => {
156338
+ });
156339
+ return false;
156340
+ }
156341
+ if (key === "v") {
156342
+ event.preventDefault();
156343
+ event.stopPropagation();
156344
+ navigator.clipboard.readText().then((text) => {
156345
+ if (text) this.terminal?.paste(text);
156346
+ }).catch(() => {
156347
+ });
156348
+ return false;
156349
+ }
156350
+ if (key === "f") {
156351
+ event.preventDefault();
156352
+ event.stopPropagation();
156353
+ this.toggleFullWidth();
156354
+ return false;
156355
+ }
156356
+ return true;
156357
+ });
156358
+ this.terminal.onData((data) => {
156359
+ if (!window.copilotBridge || !this.activeOfficeId || !this.activeAgentId) return;
156360
+ void window.copilotBridge.terminalWrite(this.activeOfficeId, this.activeAgentId, data);
156361
+ });
156362
+ this.resizeHandler = () => {
156363
+ if (!this.visible || !this.activeOfficeId || !this.activeAgentId) return;
156364
+ this.debouncedRefit(this.activeOfficeId, this.activeAgentId);
156365
+ };
156366
+ window.addEventListener("resize", this.resizeHandler);
156367
+ this.resizeObserver = new ResizeObserver(() => {
156368
+ if (!this.visible || !this.activeOfficeId || !this.activeAgentId) return;
156369
+ this.debouncedRefit(this.activeOfficeId, this.activeAgentId);
156370
+ });
156371
+ this.resizeObserver.observe(this.terminalDivEl);
156372
+ }
156373
+ refitAndResize(officeId, agentId) {
156374
+ if (!this.fitAddon || !window.copilotBridge) return;
156375
+ this.fitAddon.fit();
156376
+ const dims = this.fitAddon.proposeDimensions();
156377
+ if (!dims) return;
156378
+ void window.copilotBridge.terminalResize(officeId, agentId, dims.cols, dims.rows);
156379
+ }
156380
+ debouncedRefit(officeId, agentId) {
156381
+ this.clearRefitTimers();
156382
+ requestAnimationFrame(() => {
156383
+ this.refitAndResize(officeId, agentId);
156384
+ this.refitTimers.push(setTimeout(() => {
156385
+ this.refitAndResize(officeId, agentId);
156386
+ this.refitTimers.push(setTimeout(() => this.refitAndResize(officeId, agentId), 200));
156387
+ }, 150));
156388
+ });
156389
+ }
156390
+ refreshFocusAndGeometry() {
156391
+ if (!this.visible || !this.activeOfficeId || !this.activeAgentId) return;
156392
+ this.terminal?.focus();
156393
+ this.debouncedRefit(this.activeOfficeId, this.activeAgentId);
156394
+ }
156395
+ toggleFullWidth() {
156396
+ this.isFullWidth = !this.isFullWidth;
156397
+ localStorage.setItem(_SeriousTerminalController.FULL_WIDTH_STORAGE_KEY, String(this.isFullWidth));
156398
+ this.fullscreenBtn.textContent = this.isFullWidth ? "Half Width" : "Full Width";
156399
+ this.applyPanelLayout();
156400
+ }
156401
+ applyPanelLayout() {
156402
+ const officePanel = document.getElementById("office-panel");
156403
+ const terminalPanel = document.getElementById("terminal-panel");
156404
+ const isMobile = window.__copilotOfficeMobileModeActive?.() === true;
156405
+ if (!officePanel || !terminalPanel || isMobile) return;
156406
+ const appMode = document.getElementById("game-container")?.dataset.appMode;
156407
+ if (appMode !== "serious" || !this.visible || !this.isFullWidth) {
156408
+ officePanel.style.display = "flex";
156409
+ officePanel.style.flexDirection = "column";
156410
+ terminalPanel.style.width = "50%";
156411
+ terminalPanel.style.borderLeft = "2px solid #333";
156412
+ return;
156413
+ }
156414
+ officePanel.style.display = "none";
156415
+ terminalPanel.style.width = "100%";
156416
+ terminalPanel.style.borderLeft = "none";
156417
+ }
156418
+ clearRefitTimers() {
156419
+ for (const timer of this.refitTimers) clearTimeout(timer);
156420
+ this.refitTimers.length = 0;
156421
+ }
156422
+ formatElapsed(startTime) {
156423
+ const seconds = Math.floor((Date.now() - startTime) / 1e3);
156424
+ if (seconds < 60) return `${seconds}s`;
156425
+ const mins = Math.floor(seconds / 60);
156426
+ const secs = seconds % 60;
156427
+ return `${mins}m ${secs}s`;
156428
+ }
156429
+ buttonCss(background, border) {
156430
+ return `
156431
+ background: ${background};
156432
+ border: 1px solid ${border};
156433
+ color: #d4dbf9;
156434
+ border-radius: 5px;
156435
+ padding: 6px 10px;
156436
+ font-family: inherit;
156437
+ font-size: 12px;
156438
+ cursor: pointer;
156439
+ white-space: nowrap;
156440
+ `;
156441
+ }
156442
+ };
156443
+ }
156444
+ });
156445
+
156446
+ // src/main.ts
156447
+ var require_main = __commonJS({
156448
+ "src/main.ts"() {
156449
+ var import_phaser10 = __toESM(require_phaser());
156450
+ init_BootScene();
156451
+ init_OfficeScene();
156452
+ init_MeetingScene();
156453
+ init_officeManager();
156454
+ init_agents();
156455
+ init_responsiveLayout();
156456
+ init_layouts();
156457
+ init_ToastNotification();
156458
+ init_NotificationService();
156459
+ init_SettingsPanel();
156460
+ init_SpriteCustomizerPanel();
156461
+ init_SeriousTerminalController();
156462
+ init_SpriteGenerator();
156463
+ officeManager.ensureDefaultOffice();
156464
+ function getCurrentLayout() {
156465
+ return officeManager.currentOffice?.config.layout ?? "default";
156466
+ }
156467
+ function getCurrentAgents() {
156468
+ return getLayout(getCurrentLayout()).agents;
156469
+ }
156470
+ function getCurrentAgentTools() {
156471
+ return officeManager.currentOffice?.agentTools || /* @__PURE__ */ new Map();
156472
+ }
156473
+ function syncActiveRosterForCurrentOffice() {
156474
+ const office = officeManager.currentOffice;
156475
+ if (!office) return;
156476
+ swapActiveAgents(office.config);
156477
+ if (office.config.layout === "default") {
156478
+ restoreSeatedReserveAgents(officeManager.getSeatedAgents(office.config.id));
156479
+ }
156480
+ }
156481
+ function normalizeToolName(toolName) {
156482
+ return (toolName ?? "").trim().toLowerCase().replace(/[\s-]+/g, "_");
156483
+ }
156484
+ function isAskUserTool(toolName, status) {
156485
+ const normalized = normalizeToolName(toolName);
156486
+ if (normalized === "ask_user" || normalized === "askuser") return true;
156487
+ const statusText = (status ?? "").toLowerCase();
156488
+ return statusText.includes("waiting for your answer") || statusText.includes("waiting on user input");
156489
+ }
156490
+ function isDonePendingAck(status) {
156491
+ return !!status?.completionPendingAck;
156492
+ }
156493
+ var selectedAgentId = null;
156494
+ var phaserGameRef;
156495
+ var debugMode = false;
156496
+ var currentZoom = parseFloat(localStorage.getItem("agencyOffice:zoomLevel") ?? "0.8");
156497
+ currentZoom = isNaN(currentZoom) || currentZoom < 0.5 || currentZoom > 2 ? 0.8 : currentZoom;
156498
+ var RESIZE_DEBOUNCE_MS = 200;
156499
+ var APP_MODE_STORAGE_KEY = "agencyOffice:appMode";
156500
+ var SESSION_META_CACHE_STORAGE_KEY = "agencyOffice:sessionMetaCacheByOffice";
156501
+ var OVERVIEW_SPRITE_CACHE_STORAGE_KEY = "agencyOffice:overviewSpriteCache";
156502
+ var PC_TERMINAL_ID2 = "pc-terminal";
156503
+ function sanitizeAppMode(value) {
156504
+ return value === "serious" ? "serious" : "game";
156505
+ }
156506
+ var appMode = sanitizeAppMode(localStorage.getItem(APP_MODE_STORAGE_KEY));
156507
+ function persistAppMode(mode) {
156508
+ try {
156509
+ localStorage.setItem(APP_MODE_STORAGE_KEY, mode);
156510
+ } catch {
156511
+ }
156512
+ }
156513
+ function loadSessionMetaCacheByOffice() {
156514
+ try {
156515
+ const raw = localStorage.getItem(SESSION_META_CACHE_STORAGE_KEY);
156516
+ if (!raw) return {};
156517
+ const parsed = JSON.parse(raw);
156518
+ return parsed && typeof parsed === "object" ? parsed : {};
156519
+ } catch {
156520
+ return {};
156521
+ }
156522
+ }
156523
+ function saveSessionMetaCacheByOffice(cache) {
156524
+ try {
156525
+ localStorage.setItem(SESSION_META_CACHE_STORAGE_KEY, JSON.stringify(cache));
156526
+ } catch {
156527
+ }
156528
+ }
156529
+ function getSessionMetaCacheForOffice(officeId) {
156530
+ const all = loadSessionMetaCacheByOffice();
156531
+ return all[officeId] || {};
156532
+ }
156533
+ function setSessionMetaCacheForOffice(officeId, meta) {
156534
+ const all = loadSessionMetaCacheByOffice();
156535
+ all[officeId] = meta;
156536
+ saveSessionMetaCacheByOffice(all);
156537
+ }
156538
+ function loadOverviewSpriteCache() {
156539
+ try {
156540
+ const raw = localStorage.getItem(OVERVIEW_SPRITE_CACHE_STORAGE_KEY);
156541
+ if (!raw) return {};
156542
+ const parsed = JSON.parse(raw);
156543
+ return parsed && typeof parsed === "object" ? parsed : {};
156544
+ } catch {
156545
+ return {};
156546
+ }
156547
+ }
156548
+ function saveOverviewSpriteCache(cache) {
156549
+ try {
156550
+ localStorage.setItem(OVERVIEW_SPRITE_CACHE_STORAGE_KEY, JSON.stringify(cache));
156551
+ } catch {
156552
+ }
156553
+ }
156554
+ var agentPreloadStatus = /* @__PURE__ */ new Map();
156555
+ var pendingStatusBarUpdate = false;
156556
+ var pendingTerminalContentUpdate = false;
156557
+ var OVERVIEW_SPRITE_MAX_RETRY_ATTEMPTS = 5;
156558
+ var OVERVIEW_SPRITE_RETRY_DELAY_MS = 120;
156559
+ var overviewSpriteRetryTimer = null;
156560
+ var overviewSpriteCache = loadOverviewSpriteCache();
156561
+ var overviewSpriteImageCache = /* @__PURE__ */ new Map();
156562
+ function scheduleUiUpdateWithFallback(callback) {
156563
+ let done = false;
156564
+ const runOnce = () => {
156565
+ if (done) return;
156566
+ done = true;
156567
+ callback();
156568
+ };
156569
+ requestAnimationFrame(runOnce);
156570
+ const fallbackDelayMs = document.hidden ? 80 : 200;
156571
+ setTimeout(runOnce, fallbackDelayMs);
156572
+ }
156573
+ function scheduleStatusBarUpdate() {
156574
+ if (pendingStatusBarUpdate) return;
156575
+ pendingStatusBarUpdate = true;
156576
+ scheduleUiUpdateWithFallback(() => {
156577
+ pendingStatusBarUpdate = false;
156578
+ updateStatusBarNow();
156579
+ });
156580
+ }
156581
+ function scheduleTerminalContentUpdate() {
156582
+ if (pendingTerminalContentUpdate) return;
156583
+ pendingTerminalContentUpdate = true;
156584
+ scheduleUiUpdateWithFallback(() => {
156585
+ pendingTerminalContentUpdate = false;
156586
+ updateTerminalContentNow();
156587
+ });
156588
+ }
156589
+ var container = document.getElementById("game-container");
156590
+ container.innerHTML = "";
156591
+ container.style.cssText = "display: flex; flex-direction: column; width: 100%; height: calc(100% - 58px);";
156592
+ var tabsBar = document.createElement("div");
156593
+ tabsBar.id = "office-tabs";
156594
+ tabsBar.style.cssText = `
156595
+ display: flex;
156596
+ align-items: center;
156597
+ background: #1a1a2a;
156598
+ border-bottom: 2px solid #333;
156599
+ padding: 0 16px;
156600
+ height: 72px;
156601
+ flex-shrink: 0;
156602
+ font-size: 22px;
156603
+ `;
156604
+ container.appendChild(tabsBar);
156605
+ var mainContent = document.createElement("div");
156606
+ mainContent.style.cssText = "display: flex; flex: 1; min-height: 0;";
156607
+ container.appendChild(mainContent);
156608
+ var officePanel = document.createElement("div");
156609
+ officePanel.id = "office-panel";
156610
+ officePanel.style.cssText = "width: 50%; height: 100%; position: relative;";
156611
+ mainContent.appendChild(officePanel);
156612
+ var terminalPanel = document.createElement("div");
156613
+ terminalPanel.id = "terminal-panel";
156614
+ terminalPanel.style.cssText = `
156615
+ width: 50%;
156616
+ height: 100%;
156617
+ background: #1e1e2e;
156618
+ border-left: 2px solid #333;
156619
+ display: flex;
156620
+ flex-direction: column;
156621
+ position: relative;
156622
+ `;
156623
+ mainContent.appendChild(terminalPanel);
156624
+ var overviewHost = document.createElement("div");
156625
+ overviewHost.id = "overview-host";
156626
+ overviewHost.style.cssText = `
156627
+ display: flex;
156628
+ flex-direction: column;
156629
+ flex: 1;
156630
+ min-height: 0;
156631
+ position: relative;
156632
+ `;
156633
+ terminalPanel.appendChild(overviewHost);
156634
+ var terminalHost = document.createElement("div");
156635
+ terminalHost.id = "terminal-host";
156636
+ terminalHost.style.cssText = "display: none; flex: 1; min-height: 0;";
156637
+ terminalPanel.appendChild(terminalHost);
156638
+ var seriousPlaceholder = document.createElement("div");
156639
+ seriousPlaceholder.id = "serious-terminal-placeholder";
156640
+ seriousPlaceholder.style.cssText = `
156641
+ display: none;
156642
+ flex: 1;
156643
+ min-height: 0;
156644
+ align-items: center;
156645
+ justify-content: center;
156646
+ padding: 24px;
156647
+ font-family: 'Cascadia Code', Consolas, monospace;
156648
+ text-align: center;
156649
+ color: #95a7d7;
156650
+ background: radial-gradient(circle at top, #222846 0%, #171c2f 50%, #13192a 100%);
156651
+ `;
156652
+ seriousPlaceholder.innerHTML = `
156653
+ <div style="max-width: 380px;">
156654
+ <div style="font-size: 34px; margin-bottom: 10px;">\u{1F4BB}</div>
156655
+ <div style="font-size: 18px; color: #c7d7ff; font-weight: 700; margin-bottom: 8px;">No terminal selected</div>
156656
+ <div style="font-size: 12px; line-height: 1.45; color: #8fa3d6;">
156657
+ Select an agent or office PC from the overview on the left to open a command line session.
156658
+ </div>
156659
+ </div>
156660
+ `;
156661
+ terminalHost.appendChild(seriousPlaceholder);
156662
+ var currentResponsiveLayout = "default";
156663
+ var resizeDebounceTimer = null;
156664
+ function isMobileModeActive() {
156665
+ return currentResponsiveLayout === "portrait-dashboard";
156666
+ }
156667
+ function applyMobileTopBarVisibility() {
156668
+ const hidden = isMobileModeActive();
156669
+ const ids = ["zoom-bar", "sprite-customizer-btn", "debug-toggle-btn"];
156670
+ for (const id of ids) {
156671
+ const el = document.getElementById(id);
156672
+ if (!el) continue;
156673
+ el.style.display = hidden ? "none" : "";
156674
+ }
156675
+ }
156676
+ function syncMainPanelLayout() {
156677
+ const hideOfficePanel = currentResponsiveLayout === "portrait-dashboard";
156678
+ if (hideOfficePanel) {
156679
+ officePanel.style.display = "none";
156680
+ officePanel.style.flexDirection = "";
156681
+ terminalPanel.style.width = "100%";
156682
+ terminalPanel.style.borderLeft = "none";
156683
+ return;
156684
+ }
156685
+ officePanel.style.display = appMode === "serious" ? "flex" : "";
156686
+ officePanel.style.flexDirection = appMode === "serious" ? "column" : "";
156687
+ terminalPanel.style.width = "50%";
156688
+ terminalPanel.style.borderLeft = "2px solid #333";
156689
+ }
156690
+ function applyResponsiveLayout(layoutKey) {
156691
+ if (layoutKey === currentResponsiveLayout) return;
156692
+ currentResponsiveLayout = layoutKey;
156693
+ syncMainPanelLayout();
156694
+ refreshRightPanelMode();
156695
+ if (phaserGameRef && appMode === "game") {
156696
+ phaserGameRef.events.emit("layout:change", { layoutKey });
156697
+ if (layoutKey === "default") {
156698
+ const width = officePanel.clientWidth || window.innerWidth / 2;
156699
+ const height = officePanel.clientHeight || window.innerHeight;
156700
+ phaserGameRef.scale.resize(width, height);
156701
+ }
156702
+ }
156703
+ applyMobileTopBarVisibility();
156704
+ }
155591
156705
  function onWindowResize() {
155592
156706
  if (resizeDebounceTimer !== null) {
155593
156707
  window.clearTimeout(resizeDebounceTimer);
@@ -155595,13 +156709,55 @@ WARNING: This link could potentially be dangerous`)) {
155595
156709
  resizeDebounceTimer = window.setTimeout(() => {
155596
156710
  const next = computeResponsiveLayout(window.innerWidth, window.innerHeight);
155597
156711
  applyResponsiveLayout(next);
155598
- if (phaserGameRef && currentResponsiveLayout === "default") {
156712
+ if (phaserGameRef && appMode === "game" && currentResponsiveLayout === "default") {
155599
156713
  const width = officePanel.clientWidth || window.innerWidth / 2;
155600
156714
  const height = officePanel.clientHeight || window.innerHeight;
155601
156715
  phaserGameRef.scale.resize(width, height);
155602
156716
  }
155603
156717
  }, RESIZE_DEBOUNCE_MS);
155604
156718
  }
156719
+ function applyAppMode(nextMode, options = {}) {
156720
+ const { persist = false, refreshTabs = true, force = false } = options;
156721
+ if (!force && nextMode === appMode) return;
156722
+ const previousMode = appMode;
156723
+ appMode = nextMode;
156724
+ const selectedAgentBeforeModeSwitch = selectedAgentId;
156725
+ if (previousMode === "serious" && appMode === "game") {
156726
+ void seriousTerminalController?.closeView({ detach: true, silent: true });
156727
+ }
156728
+ if (appMode === "serious") {
156729
+ prewarmOverviewSpriteCacheFromTextures();
156730
+ teardownPhaserGame();
156731
+ } else {
156732
+ ensurePhaserGame();
156733
+ }
156734
+ container.dataset.appMode = appMode;
156735
+ tabsBar.dataset.appMode = appMode;
156736
+ mainContent.dataset.appMode = appMode;
156737
+ officePanel.dataset.appMode = appMode;
156738
+ terminalPanel.dataset.appMode = appMode;
156739
+ overviewHost.dataset.appMode = appMode;
156740
+ terminalHost.dataset.appMode = appMode;
156741
+ syncMainPanelLayout();
156742
+ if (phaserGameRef && appMode === "game" && currentResponsiveLayout === "default") {
156743
+ const width = officePanel.clientWidth || window.innerWidth / 2;
156744
+ const height = officePanel.clientHeight || window.innerHeight;
156745
+ phaserGameRef.scale.resize(width, height);
156746
+ }
156747
+ if (persist) persistAppMode(appMode);
156748
+ if (refreshTabs) renderOfficeTabs();
156749
+ refreshRightPanelMode();
156750
+ updateTerminalContent();
156751
+ updateStatusBar();
156752
+ phaserGameRef?.events.emit("app:mode:changed", { mode: appMode, previousMode });
156753
+ if (appMode === "serious" && selectedAgentBeforeModeSwitch && getSeriousLaunchConfig(selectedAgentBeforeModeSwitch)) {
156754
+ void openAgentTerminal(selectedAgentBeforeModeSwitch);
156755
+ }
156756
+ }
156757
+ function toggleAppMode() {
156758
+ const nextMode = appMode === "game" ? "serious" : "game";
156759
+ applyAppMode(nextMode, { persist: true, refreshTabs: true });
156760
+ }
155605
156761
  applyResponsiveLayout(computeResponsiveLayout(window.innerWidth, window.innerHeight));
155606
156762
  window.addEventListener("resize", onWindowResize);
155607
156763
  if (typeof window !== "undefined") {
@@ -155651,6 +156807,21 @@ WARNING: This link could potentially be dangerous`)) {
155651
156807
  color: #4a4;
155652
156808
  ">+ New Office</div>
155653
156809
  <div style="flex: 1;"></div>
156810
+ <div id="app-mode-toggle-btn" style="
156811
+ padding: 8px 14px;
156812
+ background: ${appMode === "serious" ? "#2f2638" : "#252538"};
156813
+ border: 2px solid ${appMode === "serious" ? "#a66be0" : "#444"};
156814
+ border-radius: 6px;
156815
+ cursor: pointer;
156816
+ font-family: monospace;
156817
+ color: ${appMode === "serious" ? "#d4b6ff" : "#8fb7ff"};
156818
+ font-size: 14px;
156819
+ user-select: none;
156820
+ transition: all 0.2s;
156821
+ margin-right: 8px;
156822
+ " title="Toggle app mode (game/serious)">
156823
+ ${appMode === "serious" ? "\u{1F9E0} Serious Mode" : "\u{1F3AE} Game Mode"}
156824
+ </div>
155654
156825
  <div id="sprite-customizer-btn" style="
155655
156826
  padding: 8px 16px;
155656
156827
  background: #252538;
@@ -155749,12 +156920,16 @@ WARNING: This link could potentially be dangerous`)) {
155749
156920
  });
155750
156921
  });
155751
156922
  document.getElementById("new-office-btn")?.addEventListener("click", showNewOfficeDialog);
156923
+ document.getElementById("app-mode-toggle-btn")?.addEventListener("click", (e) => {
156924
+ e.stopPropagation();
156925
+ toggleAppMode();
156926
+ });
155752
156927
  document.getElementById("debug-toggle-btn")?.addEventListener("click", () => {
155753
156928
  debugMode = !debugMode;
155754
- phaserGame?.events.emit("debug:toggle", debugMode);
156929
+ phaserGameRef?.events.emit("debug:toggle", debugMode);
155755
156930
  renderOfficeTabs();
155756
156931
  if (!isMobileModeActive()) {
155757
- phaserGame?.events.emit("game:panel:clicked");
156932
+ phaserGameRef?.events.emit("game:panel:clicked");
155758
156933
  }
155759
156934
  console.log(`[Debug] Debug mode ${debugMode ? "ON" : "OFF"}`);
155760
156935
  });
@@ -155794,19 +156969,20 @@ WARNING: This link could potentially be dangerous`)) {
155794
156969
  applyMobileTopBarVisibility();
155795
156970
  }
155796
156971
  function switchToOffice(officeId) {
155797
- if (phaserGame?.registry.get("animating")) {
156972
+ if (phaserGameRef?.registry.get("animating")) {
155798
156973
  console.log("[Office] Blocked: animation in progress");
155799
156974
  return;
155800
156975
  }
155801
156976
  selectedAgentId = null;
156977
+ void seriousTerminalController?.closeView({ detach: true });
155802
156978
  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);
156979
+ cachedSessionMeta = getSessionMetaCacheForOffice(officeId);
156980
+ syncActiveRosterForCurrentOffice();
156981
+ phaserGameRef?.events.emit("office:switch", officeId, officeManager.currentOffice?.config.workingDirectory);
155806
156982
  renderOfficeTabs();
155807
156983
  updateTerminalContent();
155808
156984
  updateStatusBar();
155809
- syncAgentStatuses();
156985
+ void reconnectAgentStatuses();
155810
156986
  fetchSessionMeta();
155811
156987
  console.log(`[Office] Switched to office: ${officeManager.currentOffice?.config.name}`);
155812
156988
  }
@@ -156001,8 +157177,8 @@ WARNING: This link could potentially be dangerous`)) {
156001
157177
  nameInput.select();
156002
157178
  }
156003
157179
  renderOfficeTabs();
156004
- var terminalHeader = document.createElement("div");
156005
- terminalHeader.style.cssText = `
157180
+ var overviewHeader = document.createElement("div");
157181
+ overviewHeader.style.cssText = `
156006
157182
  padding: 14px 20px;
156007
157183
  background: #141424;
156008
157184
  border-bottom: 2px solid #2a2a4a;
@@ -156012,7 +157188,7 @@ WARNING: This link could potentially be dangerous`)) {
156012
157188
  justify-content: space-between;
156013
157189
  align-items: center;
156014
157190
  `;
156015
- terminalHeader.innerHTML = `
157191
+ overviewHeader.innerHTML = `
156016
157192
  <div>
156017
157193
  <div id="terminal-title" style="font-size: 18px; font-weight: bold; color: #8af; margin-bottom: 4px;">\u{1F3E2} Office Overview</div>
156018
157194
  <div id="terminal-subtitle" style="font-size: 12px; color: #555;"></div>
@@ -156030,7 +157206,7 @@ WARNING: This link could potentially be dangerous`)) {
156030
157206
  white-space: nowrap;
156031
157207
  ">\u2715 Close Office</button>
156032
157208
  `;
156033
- terminalPanel.appendChild(terminalHeader);
157209
+ overviewHost.appendChild(overviewHeader);
156034
157210
  document.getElementById("close-office-btn").addEventListener("click", () => {
156035
157211
  const currentId = officeManager.currentOfficeId;
156036
157212
  const office = officeManager.currentOffice;
@@ -156040,9 +157216,9 @@ WARNING: This link could potentially be dangerous`)) {
156040
157216
  switchToOffice("office-0");
156041
157217
  }
156042
157218
  });
156043
- var terminalContent = document.createElement("div");
156044
- terminalContent.id = "terminal-content";
156045
- terminalContent.style.cssText = `
157219
+ var overviewContent = document.createElement("div");
157220
+ overviewContent.id = "terminal-content";
157221
+ overviewContent.style.cssText = `
156046
157222
  flex: 1;
156047
157223
  padding: 16px;
156048
157224
  overflow-y: auto;
@@ -156051,7 +157227,7 @@ WARNING: This link could potentially be dangerous`)) {
156051
157227
  color: #ccc;
156052
157228
  position: relative;
156053
157229
  `;
156054
- terminalPanel.appendChild(terminalContent);
157230
+ overviewHost.appendChild(overviewContent);
156055
157231
  var statusBar = document.createElement("div");
156056
157232
  statusBar.id = "status-bar";
156057
157233
  statusBar.style.cssText = `
@@ -156097,6 +157273,86 @@ WARNING: This link could potentially be dangerous`)) {
156097
157273
  function getAgentConfig(agentId) {
156098
157274
  return getCurrentAgents().find((a) => a.id === agentId) || AGENTS.find((a) => a.id === agentId);
156099
157275
  }
157276
+ var seriousTerminalController = null;
157277
+ function getSeriousLaunchConfig(agentId) {
157278
+ if (agentId === PC_TERMINAL_ID2) {
157279
+ return {
157280
+ name: "PC TERMINAL",
157281
+ description: "Local Shell",
157282
+ color: 7311064,
157283
+ workingDir: officeManager.getCurrentWorkingDirectory(),
157284
+ launchMode: "shell"
157285
+ };
157286
+ }
157287
+ const agent = getAgentConfig(agentId);
157288
+ if (!agent) return null;
157289
+ return {
157290
+ name: agent.name,
157291
+ description: agent.description,
157292
+ color: agent.color,
157293
+ workingDir: agent.workingDir || officeManager.getCurrentWorkingDirectory(),
157294
+ launchMode: "copilot"
157295
+ };
157296
+ }
157297
+ function refreshRightPanelMode() {
157298
+ const seriousDesktop = appMode === "serious" && currentResponsiveLayout === "default";
157299
+ const desiredOverviewParent = seriousDesktop ? officePanel : terminalPanel;
157300
+ if (overviewHost.parentElement !== desiredOverviewParent) {
157301
+ desiredOverviewParent.appendChild(overviewHost);
157302
+ }
157303
+ if (appMode === "serious") {
157304
+ const seriousVisible = !!seriousTerminalController?.isVisible();
157305
+ if (seriousDesktop) {
157306
+ overviewHost.style.display = "flex";
157307
+ terminalHost.style.display = "flex";
157308
+ seriousPlaceholder.style.display = seriousVisible ? "none" : "flex";
157309
+ return;
157310
+ }
157311
+ if (seriousVisible) {
157312
+ overviewHost.style.display = "none";
157313
+ terminalHost.style.display = "flex";
157314
+ seriousPlaceholder.style.display = "none";
157315
+ return;
157316
+ }
157317
+ overviewHost.style.display = "flex";
157318
+ terminalHost.style.display = "none";
157319
+ seriousPlaceholder.style.display = "none";
157320
+ return;
157321
+ }
157322
+ overviewHost.style.display = "flex";
157323
+ terminalHost.style.display = "none";
157324
+ seriousPlaceholder.style.display = "none";
157325
+ }
157326
+ async function openAgentTerminal(agentId) {
157327
+ if (appMode === "game") {
157328
+ phaserGameRef?.events.emit("open:agent:terminal", agentId);
157329
+ return;
157330
+ }
157331
+ const launchConfig = getSeriousLaunchConfig(agentId);
157332
+ if (!launchConfig || !window.copilotBridge) return;
157333
+ const officeId = officeManager.currentOfficeId || "office-0";
157334
+ const officeStatus = officeManager.getAgentStatus(officeId, agentId);
157335
+ if (officeStatus?.state === "slacking") {
157336
+ officeManager.setAgentStarting(officeId, agentId);
157337
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
157338
+ updateStatusBar();
157339
+ updateTerminalContent();
157340
+ }
157341
+ await seriousTerminalController?.openAgentTerminal({
157342
+ officeId,
157343
+ agentId,
157344
+ ...launchConfig
157345
+ });
157346
+ refreshRightPanelMode();
157347
+ }
157348
+ seriousTerminalController = new SeriousTerminalController(terminalHost, {
157349
+ onClose: () => {
157350
+ selectedAgentId = null;
157351
+ refreshRightPanelMode();
157352
+ updateStatusBar();
157353
+ updateTerminalContent();
157354
+ }
157355
+ });
156100
157356
  var notificationService = new NotificationService(
156101
157357
  toastManager,
156102
157358
  (agentId) => {
@@ -156109,7 +157365,7 @@ WARNING: This link could potentially be dangerous`)) {
156109
157365
  const oId = officeManager.currentOfficeId;
156110
157366
  if (oId) officeManager.clearUnread(oId, agentId);
156111
157367
  updateTerminalContent();
156112
- phaserGame?.events.emit("open:agent:terminal", agentId);
157368
+ void openAgentTerminal(agentId);
156113
157369
  }
156114
157370
  );
156115
157371
  function notifyAgent(agentId, eventType, context) {
@@ -156158,9 +157414,16 @@ WARNING: This link could potentially be dangerous`)) {
156158
157414
  var lastStatusBarHtml = "";
156159
157415
  var cachedSessionMeta = {};
156160
157416
  function fetchSessionMeta() {
157417
+ const officeId = officeManager.currentOfficeId || "office-0";
157418
+ const cached = getSessionMetaCacheForOffice(officeId);
157419
+ if (Object.keys(cached).length > 0) {
157420
+ cachedSessionMeta = cached;
157421
+ updateTerminalContent();
157422
+ }
156161
157423
  if (!window.copilotBridge?.getAllSessionMeta) return;
156162
- window.copilotBridge.getAllSessionMeta(officeManager.currentOfficeId || "office-0").then((meta) => {
157424
+ window.copilotBridge.getAllSessionMeta(officeId).then((meta) => {
156163
157425
  cachedSessionMeta = meta || {};
157426
+ setSessionMetaCacheForOffice(officeId, cachedSessionMeta);
156164
157427
  updateTerminalContent();
156165
157428
  }).catch(() => {
156166
157429
  });
@@ -156169,6 +157432,7 @@ WARNING: This link could potentially be dangerous`)) {
156169
157432
  scheduleTerminalContentUpdate();
156170
157433
  }
156171
157434
  function updateTerminalContentNow() {
157435
+ syncActiveRosterForCurrentOffice();
156172
157436
  const agentTools = getCurrentAgentTools();
156173
157437
  const office = officeManager.currentOffice;
156174
157438
  const closeBtn = document.getElementById("close-office-btn");
@@ -156193,47 +157457,135 @@ WARNING: This link could potentially be dangerous`)) {
156193
157457
  });
156194
157458
  if (html !== lastTerminalContentHtml) {
156195
157459
  lastTerminalContentHtml = html;
156196
- terminalContent.innerHTML = html;
156197
- drawOverviewSprites();
157460
+ overviewContent.innerHTML = html;
157461
+ }
157462
+ drawOverviewSprites();
157463
+ if (appMode === "serious") {
157464
+ seriousTerminalController?.refreshCardFromOverview();
156198
157465
  }
156199
157466
  }
156200
157467
  function updateStatusBar() {
156201
157468
  scheduleStatusBarUpdate();
156202
157469
  }
156203
- function drawOverviewSprites() {
156204
- setTimeout(() => {
156205
- if (!phaserGameRef) return;
157470
+ function clearOverviewSpriteRetry() {
157471
+ if (overviewSpriteRetryTimer) {
157472
+ clearTimeout(overviewSpriteRetryTimer);
157473
+ overviewSpriteRetryTimer = null;
157474
+ }
157475
+ }
157476
+ function drawCachedOverviewSprite(canvas, textureKey) {
157477
+ const dataUrl = overviewSpriteCache[textureKey];
157478
+ if (!dataUrl) return false;
157479
+ let img = overviewSpriteImageCache.get(textureKey);
157480
+ if (!img || img.src !== dataUrl) {
157481
+ img = new Image();
157482
+ img.src = dataUrl;
157483
+ overviewSpriteImageCache.set(textureKey, img);
157484
+ }
157485
+ const ctx = canvas.getContext("2d");
157486
+ if (!ctx) return true;
157487
+ const drawNow = () => {
157488
+ if (!img) return;
157489
+ ctx.imageSmoothingEnabled = false;
157490
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
157491
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
157492
+ };
157493
+ if (!img.complete || img.naturalWidth === 0) {
157494
+ img.onload = () => drawNow();
157495
+ return true;
157496
+ }
157497
+ drawNow();
157498
+ return true;
157499
+ }
157500
+ function updateOverviewSpriteCacheFromCanvas(canvas, textureKey) {
157501
+ try {
157502
+ const dataUrl = canvas.toDataURL("image/png");
157503
+ if (overviewSpriteCache[textureKey] !== dataUrl) {
157504
+ overviewSpriteCache = { ...overviewSpriteCache, [textureKey]: dataUrl };
157505
+ saveOverviewSpriteCache(overviewSpriteCache);
157506
+ const img = new Image();
157507
+ img.src = dataUrl;
157508
+ overviewSpriteImageCache.set(textureKey, img);
157509
+ }
157510
+ } catch {
157511
+ }
157512
+ }
157513
+ function drawTextureToOverviewCanvas(canvas, textureKey) {
157514
+ if (!phaserGameRef) {
157515
+ return drawCachedOverviewSprite(canvas, textureKey);
157516
+ }
157517
+ const texture = phaserGameRef.textures.get(textureKey);
157518
+ if (!texture || texture.key === "__MISSING") {
157519
+ return drawCachedOverviewSprite(canvas, textureKey);
157520
+ }
157521
+ const source = texture.getSourceImage();
157522
+ if (!source) {
157523
+ return drawCachedOverviewSprite(canvas, textureKey);
157524
+ }
157525
+ const ctx = canvas.getContext("2d");
157526
+ if (!ctx) return true;
157527
+ const sourceWidth = source instanceof HTMLImageElement ? source.naturalWidth || source.width : source.width;
157528
+ const sourceHeight = source instanceof HTMLImageElement ? source.naturalHeight || source.height : source.height;
157529
+ ctx.imageSmoothingEnabled = false;
157530
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
157531
+ if (sourceWidth > canvas.width || sourceHeight > canvas.height) {
157532
+ ctx.drawImage(source, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
157533
+ } else {
157534
+ ctx.drawImage(source, 0, 0);
157535
+ }
157536
+ updateOverviewSpriteCacheFromCanvas(canvas, textureKey);
157537
+ return true;
157538
+ }
157539
+ function prewarmOverviewSpriteCacheFromTextures() {
157540
+ if (!phaserGameRef) return;
157541
+ const textureKeys = getCurrentAgents().map((agent) => agent.sprite);
157542
+ if (!textureKeys.includes("desktop_pc")) textureKeys.push("desktop_pc");
157543
+ for (const textureKey of textureKeys) {
157544
+ const texture = phaserGameRef.textures.get(textureKey);
157545
+ if (!texture || texture.key === "__MISSING") continue;
157546
+ const source = texture.getSourceImage();
157547
+ if (!source) continue;
157548
+ const scratch = document.createElement("canvas");
157549
+ scratch.width = textureKey === "desktop_pc" ? 32 : 32;
157550
+ scratch.height = textureKey === "desktop_pc" ? 32 : 34;
157551
+ const ctx = scratch.getContext("2d");
157552
+ if (!ctx) continue;
157553
+ const sourceWidth = source instanceof HTMLImageElement ? source.naturalWidth || source.width : source.width;
157554
+ const sourceHeight = source instanceof HTMLImageElement ? source.naturalHeight || source.height : source.height;
157555
+ ctx.imageSmoothingEnabled = false;
157556
+ ctx.clearRect(0, 0, scratch.width, scratch.height);
157557
+ if (sourceWidth > scratch.width || sourceHeight > scratch.height) {
157558
+ ctx.drawImage(source, 0, 0, scratch.width, scratch.height, 0, 0, scratch.width, scratch.height);
157559
+ } else {
157560
+ ctx.drawImage(source, 0, 0);
157561
+ }
157562
+ updateOverviewSpriteCacheFromCanvas(scratch, textureKey);
157563
+ }
157564
+ }
157565
+ function drawOverviewSprites(attempt = 0) {
157566
+ clearOverviewSpriteRetry();
157567
+ requestAnimationFrame(() => {
157568
+ let missingTexture = false;
156206
157569
  for (const agent of getCurrentAgents()) {
156207
157570
  const canvas = document.getElementById(`overview-sprite-${agent.id}`);
156208
157571
  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
- }
157572
+ const drawn = drawTextureToOverviewCanvas(canvas, agent.sprite);
157573
+ if (!drawn) missingTexture = true;
156219
157574
  }
156220
157575
  const pcCanvas = document.getElementById("overview-sprite-pc-terminal");
156221
157576
  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
- }
157577
+ const drawn = drawTextureToOverviewCanvas(pcCanvas, "desktop_pc");
157578
+ if (!drawn) missingTexture = true;
156232
157579
  }
156233
- }, 50);
157580
+ if (missingTexture && phaserGameRef && attempt < OVERVIEW_SPRITE_MAX_RETRY_ATTEMPTS) {
157581
+ overviewSpriteRetryTimer = setTimeout(() => {
157582
+ drawOverviewSprites(attempt + 1);
157583
+ }, OVERVIEW_SPRITE_RETRY_DELAY_MS);
157584
+ }
157585
+ });
156234
157586
  }
156235
157587
  function setupTerminalClickHandler() {
156236
- terminalContent.addEventListener("click", (e) => {
157588
+ overviewHost.addEventListener("click", (e) => {
156237
157589
  const target = e.target;
156238
157590
  const layout = getLayout(getCurrentLayout());
156239
157591
  const metaPanel = target.closest(".session-meta-panel");
@@ -156242,7 +157594,10 @@ WARNING: This link could potentially be dangerous`)) {
156242
157594
  const agentId = metaPanel.dataset.agent;
156243
157595
  if (!agentId) return;
156244
157596
  layout.clickHandler.handleMetaPanelClick(target, agentId, {
156245
- startSessionMetaEdit
157597
+ startSessionMetaEdit,
157598
+ startNewSession: (id) => {
157599
+ void startSessionFromOverview(id);
157600
+ }
156246
157601
  });
156247
157602
  return;
156248
157603
  }
@@ -156260,21 +157615,58 @@ WARNING: This link could potentially be dangerous`)) {
156260
157615
  },
156261
157616
  updateContent: updateTerminalContent,
156262
157617
  emitOpenTerminal: (id) => {
156263
- phaserGame?.events.emit("open:agent:terminal", id);
157618
+ void openAgentTerminal(id);
156264
157619
  }
156265
157620
  });
156266
157621
  }
156267
157622
  });
156268
157623
  }
157624
+ async function startSessionFromOverview(agentId) {
157625
+ if (!window.copilotBridge) return;
157626
+ const officeId = officeManager.currentOfficeId || "office-0";
157627
+ const launchConfig = getSeriousLaunchConfig(agentId);
157628
+ if (!launchConfig) return;
157629
+ cachedSessionMeta[agentId] = { title: "" };
157630
+ setSessionMetaCacheForOffice(officeId, cachedSessionMeta);
157631
+ updateTerminalContent();
157632
+ try {
157633
+ if (appMode === "serious" && seriousTerminalController) {
157634
+ await seriousTerminalController.startNewSession({
157635
+ officeId,
157636
+ agentId,
157637
+ ...launchConfig
157638
+ });
157639
+ } else {
157640
+ await window.copilotBridge.resetSession(officeId, agentId);
157641
+ await window.copilotBridge.terminalStart(
157642
+ officeId,
157643
+ agentId,
157644
+ launchConfig.workingDir,
157645
+ void 0,
157646
+ void 0,
157647
+ void 0,
157648
+ launchConfig.launchMode
157649
+ );
157650
+ }
157651
+ } catch (error) {
157652
+ console.warn(`[Office] Failed to start new session from overview for ${agentId}:`, error);
157653
+ }
157654
+ officeManager.setAgentStarting(officeId, agentId);
157655
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
157656
+ updateStatusBar();
157657
+ updateTerminalContent();
157658
+ }
156269
157659
  function startSessionMetaEdit(agentId) {
156270
- const panel = terminalContent.querySelector(`.session-meta-panel[data-agent="${agentId}"]`);
157660
+ const panel = overviewHost.querySelector(`.session-meta-panel[data-agent="${agentId}"]`);
156271
157661
  if (!panel) return;
156272
157662
  const meta = cachedSessionMeta[agentId] || { title: "" };
156273
157663
  const titleEl = panel.querySelector(".session-title-display");
156274
157664
  if (titleEl) {
156275
157665
  replaceWithInput(titleEl, meta.title, "Session title...", 80, async (value) => {
156276
- await window.copilotBridge.setSessionMeta(officeManager.currentOfficeId || "office-0", agentId, { title: value });
157666
+ const officeId = officeManager.currentOfficeId || "office-0";
157667
+ await window.copilotBridge.setSessionMeta(officeId, agentId, { title: value });
156277
157668
  cachedSessionMeta[agentId] = { title: value };
157669
+ setSessionMetaCacheForOffice(officeId, cachedSessionMeta);
156278
157670
  updateTerminalContent();
156279
157671
  });
156280
157672
  }
@@ -156347,7 +157739,7 @@ WARNING: This link could potentially be dangerous`)) {
156347
157739
  console.log(`[Office] Status: ${agentId} \u2192 thinking (${toolName})`);
156348
157740
  notifyAgent(agentId, "toolStart", { toolName });
156349
157741
  }
156350
- phaserGame?.events.emit("agent:tool:start", agentId, toolName, status);
157742
+ phaserGameRef?.events.emit("agent:tool:start", agentId, toolName, status);
156351
157743
  updateTerminalContent();
156352
157744
  updateStatusBar();
156353
157745
  });
@@ -156366,7 +157758,12 @@ WARNING: This link could potentially be dangerous`)) {
156366
157758
  officeManager.pushRecentAction(officeId, agentId, completedToolName, "completed");
156367
157759
  notifyAgent(agentId, "toolComplete", { toolName: completedToolName });
156368
157760
  if (remaining.length === 0) {
156369
- officeManager.setAgentReady(officeId, agentId);
157761
+ const currentStatus = officeManager.getAgentStatus(officeId, agentId);
157762
+ if (currentStatus?.subState === "thinking") {
157763
+ officeManager.setAgentThinking(officeId, agentId, currentStatus.thinkingDetail ?? "Processing...");
157764
+ } else {
157765
+ officeManager.setAgentReady(officeId, agentId);
157766
+ }
156370
157767
  } else if (remaining.some((t) => isAskUserTool(t.name, t.status))) {
156371
157768
  officeManager.setAgentWaiting(officeId, agentId);
156372
157769
  } else {
@@ -156374,7 +157771,7 @@ WARNING: This link could potentially be dangerous`)) {
156374
157771
  officeManager.setAgentThinking(officeId, agentId, `${last.name}`);
156375
157772
  }
156376
157773
  }
156377
- phaserGame?.events.emit("agent:status:changed", agentId);
157774
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
156378
157775
  updateTerminalContent();
156379
157776
  updateStatusBar();
156380
157777
  });
@@ -156396,7 +157793,7 @@ WARNING: This link could potentially be dangerous`)) {
156396
157793
  }
156397
157794
  notifyAgent(agentId, "turnEnd");
156398
157795
  }
156399
- phaserGame?.events.emit("agent:status:changed", agentId);
157796
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
156400
157797
  updateTerminalContent();
156401
157798
  updateStatusBar();
156402
157799
  });
@@ -156413,7 +157810,7 @@ WARNING: This link could potentially be dangerous`)) {
156413
157810
  officeManager.setAgentThinking(officeId, agentId, "Processing...");
156414
157811
  console.log(`[Office] Status: ${agentId} \u2192 thinking (turn start)`);
156415
157812
  notifyAgent(agentId, "turnStart");
156416
- phaserGame?.events.emit("agent:status:changed", agentId);
157813
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
156417
157814
  updateTerminalContent();
156418
157815
  updateStatusBar();
156419
157816
  });
@@ -156428,12 +157825,14 @@ WARNING: This link could potentially be dangerous`)) {
156428
157825
  }
156429
157826
  officeManager.setAgentThinking(officeId, agentId, "Processing...");
156430
157827
  console.log(`[Office] Status: ${agentId} \u2192 thinking (user message)`);
156431
- phaserGame?.events.emit("agent:status:changed", agentId);
157828
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
156432
157829
  updateTerminalContent();
156433
157830
  });
156434
157831
  window.copilotBridge.onSessionMetaUpdated((agentId, meta) => {
156435
157832
  console.log(`[Office] Session meta updated for ${agentId}: "${meta.title}"`);
157833
+ const officeId = officeManager.currentOfficeId || "office-0";
156436
157834
  cachedSessionMeta[agentId] = meta;
157835
+ setSessionMetaCacheForOffice(officeId, cachedSessionMeta);
156437
157836
  updateTerminalContent();
156438
157837
  });
156439
157838
  window.copilotBridge.onTerminalPreloadStatus((agentId, status) => {
@@ -156459,17 +157858,45 @@ WARNING: This link could potentially be dangerous`)) {
156459
157858
  notifyAgent(agentId, "sessionError");
156460
157859
  }
156461
157860
  }
156462
- phaserGame?.events.emit("agent:status:changed", agentId);
157861
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
156463
157862
  updateStatusBar();
156464
157863
  updateTerminalContent();
156465
157864
  });
156466
157865
  }
156467
157866
  var syncInProgress = false;
156468
- async function syncAgentStatuses() {
156469
- if (!window.copilotBridge || syncInProgress) return;
157867
+ var syncStartedAt = 0;
157868
+ var SYNC_LOCK_TIMEOUT_MS = 15e3;
157869
+ var STALE_IN_TURN_THINKING_TIMEOUT_MS = 9e4;
157870
+ var THINKING_TO_READY_GRACE_MS = 7e3;
157871
+ var SYNC_WAIT_POLL_MS = 50;
157872
+ async function waitForSyncIdle(timeoutMs = SYNC_LOCK_TIMEOUT_MS) {
157873
+ const startedAt = Date.now();
157874
+ while (syncInProgress && Date.now() - startedAt < timeoutMs) {
157875
+ await new Promise((resolve) => setTimeout(resolve, SYNC_WAIT_POLL_MS));
157876
+ }
157877
+ }
157878
+ async function syncAgentStatuses(force = false) {
157879
+ if (!window.copilotBridge) return;
157880
+ if (syncInProgress) {
157881
+ if (force) {
157882
+ await waitForSyncIdle();
157883
+ if (syncInProgress) {
157884
+ console.warn(`[Office] syncAgentStatuses lock held for >${SYNC_LOCK_TIMEOUT_MS / 1e3}s during forced sync \u2014 force-releasing`);
157885
+ syncInProgress = false;
157886
+ }
157887
+ } else {
157888
+ if (syncStartedAt && Date.now() - syncStartedAt > SYNC_LOCK_TIMEOUT_MS) {
157889
+ console.warn(`[Office] syncAgentStatuses lock held for >${SYNC_LOCK_TIMEOUT_MS / 1e3}s \u2014 force-releasing`);
157890
+ syncInProgress = false;
157891
+ } else {
157892
+ return;
157893
+ }
157894
+ }
157895
+ }
156470
157896
  const officeId = officeManager.currentOfficeId;
156471
157897
  if (!officeId) return;
156472
157898
  syncInProgress = true;
157899
+ syncStartedAt = Date.now();
156473
157900
  try {
156474
157901
  const statuses = await window.copilotBridge.queryAgentStatuses(officeId);
156475
157902
  let changed = false;
@@ -156480,6 +157907,11 @@ WARNING: This link could potentially be dangerous`)) {
156480
157907
  const current = officeManager.getAgentStatus(officeId, agent.id);
156481
157908
  const activeTools = getCurrentAgentTools().get(agent.id) || [];
156482
157909
  const waitingToolActive = activeTools.some((t) => isAskUserTool(t.name, t.status));
157910
+ const thinkingSince = current?.subState === "thinking" ? current.activityStartTime : null;
157911
+ const thinkingAgeMs = thinkingSince ? now - thinkingSince : null;
157912
+ const staleInTurnThinking = Boolean(
157913
+ current?.subState === "thinking" && thinkingSince && now - thinkingSince > STALE_IN_TURN_THINKING_TIMEOUT_MS && activeTools.length === 0
157914
+ );
156483
157915
  if (current?.subState === "starting" && current.activityStartTime && now - current.activityStartTime > STARTING_TIMEOUT_MS) {
156484
157916
  console.warn(`[Office] Agent ${agent.id} stuck in starting for >${STARTING_TIMEOUT_MS / 1e3}s \u2014 transitioning to error`);
156485
157917
  officeManager.setAgentError(officeId, agent.id, "Startup timed out");
@@ -156494,7 +157926,11 @@ WARNING: This link could potentially be dangerous`)) {
156494
157926
  changed = true;
156495
157927
  }
156496
157928
  } else if (serverStatus.inTurn) {
156497
- if (!current || current.subState !== "thinking" && current.subState !== "waiting") {
157929
+ if (staleInTurnThinking) {
157930
+ console.warn(`[Office] Agent ${agent.id} stale inTurn for >${STALE_IN_TURN_THINKING_TIMEOUT_MS / 1e3}s \u2014 resetting to ready`);
157931
+ officeManager.setAgentReady(officeId, agent.id);
157932
+ changed = true;
157933
+ } else if (!current || current.subState !== "thinking" && current.subState !== "waiting") {
156498
157934
  officeManager.setTaskSummary(officeId, agent.id, "Processing...");
156499
157935
  officeManager.setAgentThinking(officeId, agent.id, "Processing...");
156500
157936
  changed = true;
@@ -156506,6 +157942,9 @@ WARNING: This link could potentially be dangerous`)) {
156506
157942
  officeManager.setAgentReady(officeId, agent.id);
156507
157943
  changed = true;
156508
157944
  } else if (current.subState === "thinking" && !serverStatus.inTurn) {
157945
+ if (thinkingAgeMs !== null && thinkingAgeMs < THINKING_TO_READY_GRACE_MS) {
157946
+ continue;
157947
+ }
156509
157948
  console.warn(`[Office] Agent ${agent.id} stuck in thinking but server reports idle \u2014 resetting to ready`);
156510
157949
  const agentTools = getCurrentAgentTools();
156511
157950
  if (agentTools.has(agent.id)) {
@@ -156529,7 +157968,7 @@ WARNING: This link could potentially be dangerous`)) {
156529
157968
  }
156530
157969
  if (changed) {
156531
157970
  for (const agent of getCurrentAgents()) {
156532
- phaserGame?.events.emit("agent:status:changed", agent.id);
157971
+ phaserGameRef?.events.emit("agent:status:changed", agent.id);
156533
157972
  }
156534
157973
  updateTerminalContent();
156535
157974
  updateStatusBar();
@@ -156549,8 +157988,27 @@ WARNING: This link could potentially be dangerous`)) {
156549
157988
  pendingTerminalContentUpdate = false;
156550
157989
  updateStatusBarNow();
156551
157990
  updateTerminalContentNow();
157991
+ drawOverviewSprites();
156552
157992
  phaserGameRef?.events.emit("agent:status:changed");
156553
- void syncAgentStatuses();
157993
+ void reconnectAgentStatuses();
157994
+ }
157995
+ async function reconnectAgentStatuses() {
157996
+ if (!window.copilotBridge) return;
157997
+ const officeId = officeManager.currentOfficeId;
157998
+ if (!officeId) return;
157999
+ await waitForSyncIdle();
158000
+ try {
158001
+ const statuses = await window.copilotBridge.queryAgentStatuses(officeId);
158002
+ for (const [agentId, info] of Object.entries(statuses)) {
158003
+ if (info.alive) {
158004
+ await window.copilotBridge.terminalAttach(officeId, agentId).catch(() => {
158005
+ });
158006
+ }
158007
+ }
158008
+ } catch (e) {
158009
+ console.warn("[Office] Failed to reconnect agent viewers:", e);
158010
+ }
158011
+ await syncAgentStatuses(true);
156554
158012
  }
156555
158013
  var ELAPSED_TICK_MS = 1e3;
156556
158014
  setInterval(() => {
@@ -156579,6 +158037,7 @@ WARNING: This link could potentially be dangerous`)) {
156579
158037
  }
156580
158038
  }, ELAPSED_TICK_MS);
156581
158039
  function updateStatusBarNow() {
158040
+ syncActiveRosterForCurrentOffice();
156582
158041
  const office = officeManager.currentOffice;
156583
158042
  const agents = office ? Array.from(office.agents.values()) : [];
156584
158043
  const officeName = officeManager.currentOffice?.config.name || "No Office";
@@ -156610,6 +158069,17 @@ WARNING: This link could potentially be dangerous`)) {
156610
158069
  cursor: pointer;
156611
158070
  margin-right: 24px;
156612
158071
  ">\u27F3 Reset All Sessions</button>
158072
+ <button id="reconnect-statuses-btn" style="
158073
+ background: #1a2a2a;
158074
+ border: 1px solid #4a8;
158075
+ color: #8f8;
158076
+ font-family: monospace;
158077
+ font-size: 14px;
158078
+ padding: 4px 16px;
158079
+ border-radius: 4px;
158080
+ cursor: pointer;
158081
+ margin-right: 24px;
158082
+ ">\u{1F50C} Re-connect Statuses</button>
156613
158083
  <span style="color: #666; font-size: 10px;">WASD: Walk | Shift: Run | Space: Talk | F10: Close terminal</span>
156614
158084
  `;
156615
158085
  if (html !== lastStatusBarHtml) {
@@ -156629,60 +158099,37 @@ WARNING: This link could potentially be dangerous`)) {
156629
158099
  btn.textContent = "\u27F3 Reset All Sessions";
156630
158100
  }
156631
158101
  });
158102
+ document.getElementById("reconnect-statuses-btn")?.addEventListener("click", async () => {
158103
+ const btn = document.getElementById("reconnect-statuses-btn");
158104
+ if (btn) {
158105
+ btn.disabled = true;
158106
+ btn.textContent = "\u{1F50C} Reconnecting...";
158107
+ }
158108
+ await reconnectAgentStatuses();
158109
+ if (btn) {
158110
+ btn.disabled = false;
158111
+ btn.textContent = "\u{1F50C} Re-connect Statuses";
158112
+ }
158113
+ });
156632
158114
  }
156633
158115
  }
156634
- updateStatusBar();
156635
158116
  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) => {
158117
+ function onAgentSessionClosed(agentId) {
156670
158118
  const officeId = officeManager.currentOfficeId;
156671
158119
  if (officeId) officeManager.setAgentSlacking(officeId, agentId);
156672
- phaserGame?.events.emit("agent:status:changed", agentId);
158120
+ phaserGameRef?.events.emit("agent:status:changed", agentId);
156673
158121
  updateTerminalContent();
156674
158122
  updateStatusBar();
156675
- });
156676
- phaserGame.events.on("agent:status:changed", () => {
158123
+ }
158124
+ function onAgentStatusChanged() {
156677
158125
  updateTerminalContent();
156678
158126
  updateStatusBar();
156679
- });
156680
- phaserGame.events.on("agent:reattached", (agentId) => {
158127
+ }
158128
+ function onAgentReattached(agentId) {
156681
158129
  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) => {
158130
+ void syncAgentStatuses();
158131
+ }
158132
+ async function onFleetOfficeCreated(officeId, sourceOfficeId) {
156686
158133
  console.log(`[Office] Fleet V-Team office created: ${officeId} (source: ${sourceOfficeId ?? "none"})`);
156687
158134
  if (sourceOfficeId && window.copilotBridge?.transferSession) {
156688
158135
  try {
@@ -156693,11 +158140,11 @@ WARNING: This link could potentially be dangerous`)) {
156693
158140
  }
156694
158141
  }
156695
158142
  if (sourceOfficeId) {
156696
- phaserGame?.events.emit("fleet:source-office", { sourceOfficeId });
158143
+ phaserGameRef?.events.emit("fleet:source-office", { sourceOfficeId });
156697
158144
  }
156698
158145
  switchToOffice(officeId);
156699
- });
156700
- phaserGame.events.on("fleet:deploy-requested", async (data) => {
158146
+ }
158147
+ async function onFleetDeployRequested(data) {
156701
158148
  console.log(`[Fleet] Deploy requested: "${data.officeName}" from office ${data.sourceOfficeId}`);
156702
158149
  const fleetOffice = officeManager.createOffice(data.officeName, ".", "fleet-vteam");
156703
158150
  const officeId = fleetOffice.config.id;
@@ -156713,24 +158160,96 @@ WARNING: This link could potentially be dangerous`)) {
156713
158160
  console.warn("[Fleet] copilotBridge.transferSession not available");
156714
158161
  }
156715
158162
  data.resolve?.();
156716
- phaserGame?.events.emit("fleet:source-office", { sourceOfficeId: data.sourceOfficeId, prompt: data.prompt });
158163
+ phaserGameRef?.events.emit("fleet:source-office", { sourceOfficeId: data.sourceOfficeId, prompt: data.prompt });
156717
158164
  switchToOffice(officeId);
156718
- });
156719
- phaserGame.events.on("fleet:status", (status) => {
158165
+ }
158166
+ function onFleetStatus(status) {
156720
158167
  const subtitle = document.getElementById("terminal-subtitle");
156721
158168
  if (subtitle && officeManager.currentOffice?.config.layout === "fleet-vteam") {
156722
158169
  subtitle.textContent = `Fleet: ${status.active} active \xB7 ${status.completed} done \xB7 ${status.failed} failed / ${status.total} total`;
156723
158170
  }
156724
158171
  updateTerminalContent();
156725
- });
156726
- phaserGame.events.on("fleet:complete", () => {
158172
+ }
158173
+ function onFleetComplete() {
156727
158174
  console.log("[Fleet] All sub-agents complete");
156728
158175
  const subtitle = document.getElementById("terminal-subtitle");
156729
158176
  if (subtitle) {
156730
158177
  subtitle.textContent = "\u2705 Fleet complete!";
156731
158178
  }
156732
158179
  updateTerminalContent();
158180
+ }
158181
+ var officePanelListenersBound = false;
158182
+ function bindOfficePanelListeners() {
158183
+ if (officePanelListenersBound) return;
158184
+ officePanelListenersBound = true;
158185
+ officePanel.addEventListener("click", () => {
158186
+ const canvas = officePanel.querySelector("canvas");
158187
+ canvas?.focus();
158188
+ });
158189
+ officePanel.addEventListener("mousedown", () => {
158190
+ if (isMobileModeActive()) return;
158191
+ console.log("[main] game panel mousedown \u2014 emitting game:panel:clicked");
158192
+ phaserGameRef?.events.emit("game:panel:clicked");
158193
+ });
158194
+ }
158195
+ function getPhaserDimensions() {
158196
+ return {
158197
+ width: officePanel.clientWidth || window.innerWidth / 2,
158198
+ height: officePanel.clientHeight || window.innerHeight
158199
+ };
158200
+ }
158201
+ function bindPhaserEventListeners(game) {
158202
+ game.events.once("ready", () => {
158203
+ drawOverviewSprites();
158204
+ game.events.emit("layout:change", { layoutKey: currentResponsiveLayout });
158205
+ });
158206
+ game.events.on("agent:session:closed", onAgentSessionClosed);
158207
+ game.events.on("agent:status:changed", onAgentStatusChanged);
158208
+ game.events.on("agent:reattached", onAgentReattached);
158209
+ game.events.on("bgm:started", onBgmStarted);
158210
+ game.events.on("fleet:office:created", onFleetOfficeCreated);
158211
+ game.events.on("fleet:deploy-requested", onFleetDeployRequested);
158212
+ game.events.on("fleet:status", onFleetStatus);
158213
+ game.events.on("fleet:complete", onFleetComplete);
158214
+ }
158215
+ function ensurePhaserGame() {
158216
+ if (phaserGameRef) return;
158217
+ const { width, height } = getPhaserDimensions();
158218
+ const game = new import_phaser10.default.Game({
158219
+ type: import_phaser10.default.AUTO,
158220
+ parent: officePanel,
158221
+ width,
158222
+ height,
158223
+ backgroundColor: "#1a1a2e",
158224
+ physics: { default: "arcade", arcade: { debug: false } },
158225
+ scene: [BootScene, OfficeScene, MeetingScene]
158226
+ });
158227
+ phaserGameRef = game;
158228
+ bindPhaserEventListeners(game);
158229
+ }
158230
+ function teardownPhaserGame() {
158231
+ if (!phaserGameRef) return;
158232
+ const game = phaserGameRef;
158233
+ phaserGameRef = void 0;
158234
+ try {
158235
+ game.destroy(true);
158236
+ } catch (error) {
158237
+ console.warn("[main] Failed to destroy Phaser game cleanly:", error);
158238
+ }
158239
+ officePanel.innerHTML = "";
158240
+ }
158241
+ bindOfficePanelListeners();
158242
+ window.addEventListener("focus", () => {
158243
+ catchUpStatusViews("window focus");
158244
+ });
158245
+ document.addEventListener("visibilitychange", () => {
158246
+ if (!document.hidden) {
158247
+ catchUpStatusViews("document visible");
158248
+ }
156733
158249
  });
158250
+ syncActiveRosterForCurrentOffice();
158251
+ applyAppMode(appMode, { force: true, refreshTabs: false });
158252
+ fetchSessionMeta();
156734
158253
  }
156735
158254
  });
156736
158255
  return require_main();