copilotoffice 1.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,9 +23,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  ));
24
24
 
25
25
  // electron/main.ts
26
- var import_electron2 = require("electron");
27
- var path2 = __toESM(require("path"));
28
- var fs = __toESM(require("fs"));
26
+ var import_electron3 = require("electron");
27
+ var path3 = __toESM(require("path"));
28
+ var fs2 = __toESM(require("fs"));
29
29
  var import_child_process2 = require("child_process");
30
30
 
31
31
  // electron/terminal/ipc-relay.ts
@@ -313,6 +313,96 @@ var TerminalRelay = class _TerminalRelay {
313
313
  }
314
314
  };
315
315
 
316
+ // electron/officeFileStore.ts
317
+ var fs = __toESM(require("fs"));
318
+ var path2 = __toESM(require("path"));
319
+ var DEFAULT_DATA_SUBDIR = ".data";
320
+ var DEFAULT_FILE_NAME = "copilot-offices.json";
321
+ function createOfficeFileStore(options = {}) {
322
+ const cwd = options.cwd ?? process.cwd();
323
+ const dataSubdir = options.dataSubdir ?? DEFAULT_DATA_SUBDIR;
324
+ const fileName = options.fileName ?? DEFAULT_FILE_NAME;
325
+ const dataDir = path2.join(cwd, dataSubdir);
326
+ const filePath = path2.join(dataDir, fileName);
327
+ return {
328
+ filePath,
329
+ load() {
330
+ try {
331
+ if (!fs.existsSync(filePath)) return { success: true, data: null };
332
+ const data = fs.readFileSync(filePath, "utf8");
333
+ return { success: true, data };
334
+ } catch (e) {
335
+ return { success: false, data: null, error: String(e) };
336
+ }
337
+ },
338
+ save(data) {
339
+ try {
340
+ fs.mkdirSync(dataDir, { recursive: true });
341
+ fs.writeFileSync(filePath, data, "utf8");
342
+ return { success: true };
343
+ } catch (e) {
344
+ return { success: false, error: String(e) };
345
+ }
346
+ }
347
+ };
348
+ }
349
+
350
+ // electron/nonTerminalIpc.ts
351
+ var import_electron2 = require("electron");
352
+ function registerNonTerminalIpc(hooks) {
353
+ import_electron2.ipcMain.handle("request-hard-reload", () => {
354
+ console.log("[Main] Hard reload requested by renderer");
355
+ hooks.onHardReloadRequested();
356
+ return { success: true };
357
+ });
358
+ import_electron2.ipcMain.handle("show-native-notification", (_event, title, body) => {
359
+ if (!import_electron2.Notification.isSupported()) return { success: false };
360
+ const notification = new import_electron2.Notification({ title, body });
361
+ notification.on("click", () => {
362
+ const win = hooks.getMainWindow();
363
+ if (win) {
364
+ if (win.isMinimized()) win.restore();
365
+ win.focus();
366
+ }
367
+ });
368
+ notification.show();
369
+ return { success: true };
370
+ });
371
+ import_electron2.ipcMain.handle("save-offices", (_event, data) => {
372
+ return hooks.officeStore.save(data);
373
+ });
374
+ import_electron2.ipcMain.handle("load-offices", () => {
375
+ return hooks.officeStore.load();
376
+ });
377
+ import_electron2.ipcMain.handle("clipboard-write-text", (_event, text) => {
378
+ try {
379
+ if (typeof text !== "string") {
380
+ return { success: false, verified: false, error: "text must be a string" };
381
+ }
382
+ import_electron2.clipboard.writeText(text);
383
+ const verify = import_electron2.clipboard.readText();
384
+ const matched = verify === text;
385
+ if (!matched) {
386
+ console.warn(`[Main/Clipboard] writeText verify mismatch len=${text.length}`);
387
+ return { success: false, verified: false, error: "clipboard verification failed" };
388
+ }
389
+ return { success: true, verified: true };
390
+ } catch (e) {
391
+ console.warn("[Main/Clipboard] writeText threw", e);
392
+ return { success: false, verified: false, error: e?.message || String(e) };
393
+ }
394
+ });
395
+ import_electron2.ipcMain.handle("clipboard-read-text", () => {
396
+ try {
397
+ const text = import_electron2.clipboard.readText();
398
+ return { success: true, text };
399
+ } catch (e) {
400
+ console.warn("[Main/Clipboard] readText threw", e);
401
+ return { success: false, text: "", error: e?.message || String(e) };
402
+ }
403
+ });
404
+ }
405
+
316
406
  // electron/main.ts
317
407
  var OPEN_DEVTOOLS_ON_START = process.env.COPILOT_OFFICE_OPEN_DEVTOOLS !== "0";
318
408
  var ENABLE_FILE_WATCHER = process.env.COPILOT_OFFICE_ENABLE_WATCHER !== "0";
@@ -357,9 +447,9 @@ var watcherProcess = null;
357
447
  var relay = new TerminalRelay(() => mainWindow);
358
448
  var pendingHardReload = false;
359
449
  function startFileWatcher() {
360
- const copilotOfficePath = path2.join(process.cwd(), "CopilotOffice");
361
- if (!fs.existsSync(path2.join(copilotOfficePath, "package.json"))) {
362
- if (fs.existsSync(path2.join(process.cwd(), "src", "main.ts"))) {
450
+ const copilotOfficePath = path3.join(process.cwd(), "CopilotOffice");
451
+ if (!fs2.existsSync(path3.join(copilotOfficePath, "package.json"))) {
452
+ if (fs2.existsSync(path3.join(process.cwd(), "src", "main.ts"))) {
363
453
  watcherProcess = (0, import_child_process2.spawn)("npx", ["esbuild", "src/main.ts", "--bundle", "--outfile=dist/game.bundle.js", "--platform=browser", "--format=iife", "--global-name=CopilotOffice", "--watch"], {
364
454
  cwd: process.cwd(),
365
455
  shell: true,
@@ -390,19 +480,19 @@ function startFileWatcher() {
390
480
  }
391
481
  }
392
482
  function createWindow() {
393
- mainWindow = new import_electron2.BrowserWindow({
483
+ mainWindow = new import_electron3.BrowserWindow({
394
484
  width: 2560,
395
485
  height: 1440,
396
486
  title: "Copilot Office",
397
487
  webPreferences: {
398
- preload: path2.join(__dirname, "terminal", "preload.js"),
488
+ preload: path3.join(__dirname, "terminal", "preload.js"),
399
489
  contextIsolation: true,
400
490
  nodeIntegration: false,
401
491
  backgroundThrottling: false
402
492
  }
403
493
  });
404
494
  mainWindow.maximize();
405
- mainWindow.loadFile(path2.join(__dirname, "../../src/index.html"));
495
+ mainWindow.loadFile(path3.join(__dirname, "../../src/index.html"));
406
496
  if (OPEN_DEVTOOLS_ON_START) {
407
497
  mainWindow.webContents.openDevTools({ mode: "detach" });
408
498
  }
@@ -427,49 +517,17 @@ function createWindow() {
427
517
  mainWindow = null;
428
518
  });
429
519
  }
430
- import_electron2.app.whenReady().then(async () => {
431
- import_electron2.Menu.setApplicationMenu(null);
520
+ import_electron3.app.whenReady().then(async () => {
521
+ import_electron3.Menu.setApplicationMenu(null);
432
522
  killOrphanedProcesses();
433
523
  relay.registerIpc();
434
- import_electron2.ipcMain.handle("request-hard-reload", () => {
435
- console.log("[Main] Hard reload requested by renderer");
436
- pendingHardReload = true;
437
- return { success: true };
438
- });
439
- import_electron2.ipcMain.handle("show-native-notification", (_event, title, body) => {
440
- if (!import_electron2.Notification.isSupported()) return { success: false };
441
- const notification = new import_electron2.Notification({ title, body });
442
- notification.on("click", () => {
443
- if (mainWindow) {
444
- if (mainWindow.isMinimized()) mainWindow.restore();
445
- mainWindow.focus();
446
- }
447
- });
448
- notification.show();
449
- return { success: true };
450
- });
451
- const dataDir = path2.join(process.cwd(), ".data");
452
- fs.mkdirSync(dataDir, { recursive: true });
453
- const officesFilePath = path2.join(dataDir, "copilot-offices.json");
454
- import_electron2.ipcMain.handle("save-offices", (_event, data) => {
455
- try {
456
- fs.mkdirSync(dataDir, { recursive: true });
457
- fs.writeFileSync(officesFilePath, data, "utf8");
458
- return { success: true };
459
- } catch (e) {
460
- console.warn("[Main] Failed to save offices:", e);
461
- return { success: false, error: String(e) };
462
- }
463
- });
464
- import_electron2.ipcMain.handle("load-offices", () => {
465
- try {
466
- if (!fs.existsSync(officesFilePath)) return { success: true, data: null };
467
- const data = fs.readFileSync(officesFilePath, "utf8");
468
- return { success: true, data };
469
- } catch (e) {
470
- console.warn("[Main] Failed to load offices:", e);
471
- return { success: false, error: String(e), data: null };
472
- }
524
+ const officeStore = createOfficeFileStore();
525
+ registerNonTerminalIpc({
526
+ getMainWindow: () => mainWindow,
527
+ onHardReloadRequested: () => {
528
+ pendingHardReload = true;
529
+ },
530
+ officeStore
473
531
  });
474
532
  await relay.spawnServer(__dirname);
475
533
  if (ENABLE_FILE_WATCHER) {
@@ -478,22 +536,22 @@ import_electron2.app.whenReady().then(async () => {
478
536
  console.log("[Main] File watcher disabled");
479
537
  }
480
538
  createWindow();
481
- import_electron2.app.on("activate", () => {
482
- if (import_electron2.BrowserWindow.getAllWindows().length === 0) createWindow();
539
+ import_electron3.app.on("activate", () => {
540
+ if (import_electron3.BrowserWindow.getAllWindows().length === 0) createWindow();
483
541
  });
484
542
  });
485
- import_electron2.app.on("window-all-closed", () => {
543
+ import_electron3.app.on("window-all-closed", () => {
486
544
  if (watcherProcess) watcherProcess.kill();
487
- if (process.platform !== "darwin") import_electron2.app.quit();
545
+ if (process.platform !== "darwin") import_electron3.app.quit();
488
546
  });
489
547
  var isShuttingDown = false;
490
- import_electron2.app.on("before-quit", (event) => {
548
+ import_electron3.app.on("before-quit", (event) => {
491
549
  if (isShuttingDown) return;
492
550
  isShuttingDown = true;
493
551
  event.preventDefault();
494
552
  console.log("[Main] Awaiting relay shutdown before quit\u2026");
495
553
  relay.shutdown().finally(() => {
496
554
  console.log("[Main] Relay shutdown complete \u2014 quitting");
497
- import_electron2.app.quit();
555
+ import_electron3.app.quit();
498
556
  });
499
557
  });
@@ -17,6 +17,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
17
17
  var preload_exports = {};
18
18
  module.exports = __toCommonJS(preload_exports);
19
19
  var import_electron = require("electron");
20
+ import_electron.contextBridge.exposeInMainWorld("__copilotOfficeE2E", process.env.COPILOT_E2E === "1");
20
21
  import_electron.contextBridge.exposeInMainWorld("copilotBridge", {
21
22
  // Terminal management
22
23
  terminalStart: (officeId, agentId, workingDir, cols, rows, preseededPrompt, launchMode) => {
@@ -148,5 +149,16 @@ import_electron.contextBridge.exposeInMainWorld("copilotBridge", {
148
149
  // Native OS notifications
149
150
  showNativeNotification: (title, body) => {
150
151
  return import_electron.ipcRenderer.invoke("show-native-notification", title, body);
152
+ },
153
+ // Spec 003 follow-up: write to OS clipboard via Electron main process.
154
+ // Bypasses Permissions API + focus restrictions that make
155
+ // navigator.clipboard.writeText unreliable in xterm-focused contexts.
156
+ clipboardWriteText: (text) => {
157
+ return import_electron.ipcRenderer.invoke("clipboard-write-text", text);
158
+ },
159
+ // Spec 004: read OS clipboard via Electron main. Renderer pairs this with
160
+ // terminalWrite to implement Paste in the terminal context menu.
161
+ clipboardReadText: () => {
162
+ return import_electron.ipcRenderer.invoke("clipboard-read-text");
151
163
  }
152
164
  });
@@ -5070,7 +5070,7 @@ var init_dist = __esm({
5070
5070
  var path3 = __toESM(require("path"));
5071
5071
  var os3 = __toESM(require("os"));
5072
5072
  var fs2 = __toESM(require("fs"));
5073
- var crypto = __toESM(require("crypto"));
5073
+ var crypto2 = __toESM(require("crypto"));
5074
5074
  var import_child_process2 = require("child_process");
5075
5075
 
5076
5076
  // electron/terminal/events-watcher.ts
@@ -5595,10 +5595,66 @@ function createSdkCliLaunchConfig(cliPath) {
5595
5595
  return { cliPath, cliArgs: [] };
5596
5596
  }
5597
5597
 
5598
+ // electron/terminal/agent-viewers.ts
5599
+ function addAgentViewer(ck, maps) {
5600
+ maps.activeAgentViewers.add(ck);
5601
+ const termKey = maps.agentToTerminal.get(ck);
5602
+ if (termKey && termKey !== ck) {
5603
+ maps.activeAgentViewers.add(termKey);
5604
+ return { aliasKey: termKey };
5605
+ }
5606
+ return { aliasKey: null };
5607
+ }
5608
+ function removeAgentViewer(ck, maps) {
5609
+ maps.activeAgentViewers.delete(ck);
5610
+ const termKey = maps.agentToTerminal.get(ck);
5611
+ if (termKey && termKey !== ck) {
5612
+ maps.activeAgentViewers.delete(termKey);
5613
+ return { aliasKey: termKey };
5614
+ }
5615
+ return { aliasKey: null };
5616
+ }
5617
+ function hasActiveViewer(ck, maps) {
5618
+ if (maps.activeAgentViewers.has(ck)) return true;
5619
+ for (const [alias, termKey] of maps.agentToTerminal) {
5620
+ if (termKey === ck && maps.activeAgentViewers.has(alias)) return true;
5621
+ }
5622
+ return false;
5623
+ }
5624
+
5625
+ // electron/terminal/session-repair.ts
5626
+ var crypto = __toESM(require("crypto"));
5627
+ function repairDuplicateSessionIds(officeId, data, options = {}) {
5628
+ const logger = options.logger ?? { warn: (msg) => console.warn(msg) };
5629
+ const mintId = options.mintId ?? (() => crypto.randomUUID());
5630
+ const seen = /* @__PURE__ */ new Map();
5631
+ let repaired = false;
5632
+ for (const [agentId, sessionId] of data.sessionIds.entries()) {
5633
+ const firstAgent = seen.get(sessionId);
5634
+ if (firstAgent === void 0) {
5635
+ seen.set(sessionId, agentId);
5636
+ continue;
5637
+ }
5638
+ let fresh = mintId();
5639
+ while (seen.has(fresh) || data.sessionIds.get(agentId) === fresh) {
5640
+ fresh = mintId();
5641
+ }
5642
+ data.sessionIds.set(agentId, fresh);
5643
+ seen.set(fresh, agentId);
5644
+ logger.warn(
5645
+ `[TermServer] Repaired duplicate sessionId for officeId=${officeId} agentId=${agentId} from=${sessionId} to=${fresh}`
5646
+ );
5647
+ repaired = true;
5648
+ }
5649
+ return repaired;
5650
+ }
5651
+
5598
5652
  // electron/terminal/server.ts
5599
5653
  var ptyProcesses = /* @__PURE__ */ new Map();
5654
+ var DEBUG_COLD_START = process.env.COPILOT_OFFICE_DEBUG_COLD_START === "1";
5600
5655
  var agentToTerminal = /* @__PURE__ */ new Map();
5601
5656
  var activeAgentViewers = /* @__PURE__ */ new Set();
5657
+ var viewerMaps = { activeAgentViewers, agentToTerminal };
5602
5658
  var agentWatchers = /* @__PURE__ */ new Map();
5603
5659
  var terminalBackend = null;
5604
5660
  var eventSourceFactory = new FileWatcherEventSourceFactory();
@@ -5626,12 +5682,8 @@ function getOfficeSession(officeId) {
5626
5682
  function compositeKey(officeId, agentId) {
5627
5683
  return `${officeId}:${agentId}`;
5628
5684
  }
5629
- function hasActiveViewer(ck) {
5630
- if (activeAgentViewers.has(ck)) return true;
5631
- for (const [alias, termKey] of agentToTerminal) {
5632
- if (termKey === ck && activeAgentViewers.has(alias)) return true;
5633
- }
5634
- return false;
5685
+ function hasActiveViewer2(ck) {
5686
+ return hasActiveViewer(ck, viewerMaps);
5635
5687
  }
5636
5688
  function send(msg) {
5637
5689
  if (process.send) {
@@ -5675,6 +5727,10 @@ async function loadOfficeSessionFile(officeId) {
5675
5727
  data.sessionMeta = /* @__PURE__ */ new Map();
5676
5728
  await saveOfficeSessionFile(officeId);
5677
5729
  }
5730
+ const repaired = repairDuplicateSessionIds(officeId, data);
5731
+ if (repaired) {
5732
+ await saveOfficeSessionFile(officeId);
5733
+ }
5678
5734
  console.log(`[TermServer] Loaded sessions for ${officeId}: ${data.sessionIds.size} current, ${data.sessionHistory.size} history`);
5679
5735
  }
5680
5736
  } catch (e) {
@@ -5790,6 +5846,9 @@ function killPtyProcess(proc) {
5790
5846
  }
5791
5847
  var pendingPreseededPrompts = /* @__PURE__ */ new Map();
5792
5848
  async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows, preseededPrompt, launchMode = "copilot") {
5849
+ if (process.env.COPILOT_E2E === "1") {
5850
+ launchMode = "shell";
5851
+ }
5793
5852
  if (!terminalBackend || !terminalBackend.isAvailable()) {
5794
5853
  return { success: false, error: "terminal backend not available" };
5795
5854
  }
@@ -5806,7 +5865,7 @@ async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows,
5806
5865
  const officeData = getOfficeSession(officeId);
5807
5866
  let sessionId = officeData.sessionIds.get(agentId);
5808
5867
  if (!sessionId) {
5809
- sessionId = crypto.randomUUID();
5868
+ sessionId = crypto2.randomUUID();
5810
5869
  officeData.sessionIds.set(agentId, sessionId);
5811
5870
  await saveOfficeSessionFile(officeId);
5812
5871
  console.log(`[TermServer] New session GUID for ${ck}: ${sessionId}`);
@@ -5939,7 +5998,7 @@ async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows,
5939
5998
  console.log(`[TermServer] Subagent FAILED for ${ck}: ${d.agentName ?? "unknown"} (toolCallId: ${d.toolCallId ?? "?"}, error: ${d.error ?? "unknown"})`);
5940
5999
  }
5941
6000
  const isFleetCriticalEvent = event.type.startsWith("subagent.") || event.type === "system.notification" || event.type === "tool.execution_start" && event.data?.toolName === "task";
5942
- if (isFleetCriticalEvent || hasActiveViewer(ck)) {
6001
+ if (isFleetCriticalEvent || hasActiveViewer2(ck)) {
5943
6002
  send({ type: "copilot-event", agentId, event });
5944
6003
  } else {
5945
6004
  console.warn(`[TermServer] Dropped copilot-event ${event.type} for ${ck} \u2014 no active viewer (viewers: [${[...activeAgentViewers].join(", ")}])`);
@@ -5952,18 +6011,22 @@ async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows,
5952
6011
  let flushTimer = null;
5953
6012
  const flushData = () => {
5954
6013
  flushTimer = null;
5955
- if (pendingData && hasActiveViewer(ck)) {
6014
+ if (pendingData && hasActiveViewer2(ck)) {
5956
6015
  send({ type: "terminal-data", agentId, data: pendingData });
5957
6016
  }
5958
6017
  pendingData = "";
5959
6018
  };
5960
6019
  proc.onData((data) => {
5961
6020
  appendToScrollback(ck, data);
5962
- if (!shellOnlyMode && terminalBackend?.name === "node-pty" && !hasSignalledReady && data.includes("Environment loaded")) {
5963
- console.log(`[TermServer] Primary ready signal for ${ck}: "Environment loaded" detected`);
5964
- signalReady();
6021
+ if (!shellOnlyMode && terminalBackend?.name === "node-pty" && !hasSignalledReady) {
6022
+ const hasLegacyReadyMarker = data.includes("Environment loaded");
6023
+ const hasInteractiveFooter = data.includes("/ commands") || data.includes("? help");
6024
+ if (hasLegacyReadyMarker || hasInteractiveFooter) {
6025
+ console.log(`[TermServer] Ready signal for ${ck}: PTY marker detected`);
6026
+ signalReady();
6027
+ }
5965
6028
  }
5966
- if (!hasActiveViewer(ck)) return;
6029
+ if (!hasActiveViewer2(ck)) return;
5967
6030
  pendingData += data;
5968
6031
  if (pendingData.length >= MAX_PENDING_BYTES) {
5969
6032
  if (flushTimer) clearTimeout(flushTimer);
@@ -5989,7 +6052,7 @@ async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows,
5989
6052
  if (!shellOnlyMode && terminalBackend.name === "node-pty") {
5990
6053
  setTimeout(() => {
5991
6054
  console.log(`[TermServer] Starting copilot --session-id for ${ck}: ${sessionId}`);
5992
- proc.write(`copilot --session-id ${sessionId}\r`);
6055
+ proc.write(`copilot --session-id=${sessionId}\r`);
5993
6056
  }, 500);
5994
6057
  }
5995
6058
  return { success: true, pid: proc.pid, sessionId };
@@ -6058,11 +6121,9 @@ async function handleMessage(msg) {
6058
6121
  case "attach": {
6059
6122
  const ck = compositeKey(msg.officeId, msg.agentId);
6060
6123
  console.log(`[TermServer] Attaching viewer for ${ck}`);
6061
- activeAgentViewers.add(ck);
6062
- const termKey = agentToTerminal.get(ck);
6063
- if (termKey && termKey !== ck) {
6064
- activeAgentViewers.add(termKey);
6065
- console.log(`[TermServer] Also marking original key ${termKey} as active viewer (transferred session)`);
6124
+ const { aliasKey } = addAgentViewer(ck, viewerMaps);
6125
+ if (aliasKey) {
6126
+ console.log(`[TermServer] Also marking original key ${aliasKey} as active viewer (transferred session)`);
6066
6127
  }
6067
6128
  const chunks = agentScrollbackBuffers.get(ck) || [];
6068
6129
  const rawScrollback = chunks.join("");
@@ -6072,11 +6133,7 @@ async function handleMessage(msg) {
6072
6133
  case "detach": {
6073
6134
  const ck = compositeKey(msg.officeId, msg.agentId);
6074
6135
  console.log(`[TermServer] Detaching viewer for ${ck}`);
6075
- activeAgentViewers.delete(ck);
6076
- const termKey = agentToTerminal.get(ck);
6077
- if (termKey && termKey !== ck) {
6078
- activeAgentViewers.delete(termKey);
6079
- }
6136
+ removeAgentViewer(ck, viewerMaps);
6080
6137
  break;
6081
6138
  }
6082
6139
  case "exists": {
@@ -6093,6 +6150,15 @@ async function handleMessage(msg) {
6093
6150
  const officeData = getOfficeSession(msg.officeId);
6094
6151
  const current = officeData.sessionIds.get(msg.agentId);
6095
6152
  const changed = !!normalized && current !== normalized;
6153
+ if (changed && normalized) {
6154
+ for (const [otherAgent, otherSid] of officeData.sessionIds) {
6155
+ if (otherAgent !== msg.agentId && otherSid === normalized) {
6156
+ console.warn(`[TermServer] Rejected set-session-id ${normalized} for ${compositeKey(msg.officeId, msg.agentId)} \u2014 already in use by ${otherAgent}`);
6157
+ send({ type: "response", requestId: msg.requestId, result: { success: false, error: "sessionId already in use by another agent in this office" } });
6158
+ return;
6159
+ }
6160
+ }
6161
+ }
6096
6162
  if (changed) {
6097
6163
  archiveSessionId(msg.officeId, msg.agentId);
6098
6164
  officeData.sessionIds.set(msg.agentId, normalized);
@@ -6159,7 +6225,7 @@ async function handleMessage(msg) {
6159
6225
  hasAutoTitled.delete(ck);
6160
6226
  send({ type: "session-meta-updated", agentId: msg.agentId, meta: { title: "" } });
6161
6227
  archiveSessionId(msg.officeId, msg.agentId);
6162
- const newSessionId = crypto.randomUUID();
6228
+ const newSessionId = crypto2.randomUUID();
6163
6229
  officeDataReset.sessionIds.set(msg.agentId, newSessionId);
6164
6230
  await saveOfficeSessionFile(msg.officeId);
6165
6231
  console.log(`[TermServer] Reset session for ${ck}: new GUID ${newSessionId}`);
@@ -6210,7 +6276,7 @@ async function handleMessage(msg) {
6210
6276
  }
6211
6277
  officeData.sessionMeta.clear();
6212
6278
  for (const agentId of officeData.sessionIds.keys()) {
6213
- officeData.sessionIds.set(agentId, crypto.randomUUID());
6279
+ officeData.sessionIds.set(agentId, crypto2.randomUUID());
6214
6280
  }
6215
6281
  await saveOfficeSessionFile(officeId);
6216
6282
  console.log(`[TermServer] All sessions reset for ${officeId}`);
@@ -6266,7 +6332,15 @@ async function handleMessage(msg) {
6266
6332
  }
6267
6333
  case "get-all-session-meta": {
6268
6334
  const officeData = getOfficeSession(msg.officeId);
6269
- send({ type: "response", requestId: msg.requestId, result: Object.fromEntries(officeData.sessionMeta) });
6335
+ const merged = {};
6336
+ for (const [agentId, meta] of officeData.sessionMeta.entries()) {
6337
+ const sessionId = officeData.sessionIds.get(agentId);
6338
+ merged[agentId] = sessionId ? { ...meta, sessionId } : { ...meta };
6339
+ }
6340
+ for (const [agentId, sessionId] of officeData.sessionIds.entries()) {
6341
+ if (!merged[agentId]) merged[agentId] = { title: "", sessionId };
6342
+ }
6343
+ send({ type: "response", requestId: msg.requestId, result: merged });
6270
6344
  break;
6271
6345
  }
6272
6346
  case "create-office-session": {