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.
- package/dist/electron/main.js +114 -56
- package/dist/electron/terminal/preload.js +12 -0
- package/dist/electron/terminal/server.js +102 -28
- package/dist/game.bundle.js +1907 -391
- package/package.json +3 -3
package/dist/game.bundle.js
CHANGED
|
@@ -121442,23 +121442,23 @@ var CopilotOffice = (() => {
|
|
|
121442
121442
|
* @return {Phaser.Textures.Frame} A clone of this Frame.
|
|
121443
121443
|
*/
|
|
121444
121444
|
clone: function() {
|
|
121445
|
-
var
|
|
121446
|
-
|
|
121447
|
-
|
|
121448
|
-
|
|
121449
|
-
|
|
121450
|
-
|
|
121451
|
-
|
|
121452
|
-
|
|
121453
|
-
|
|
121454
|
-
|
|
121455
|
-
|
|
121456
|
-
|
|
121457
|
-
|
|
121458
|
-
|
|
121459
|
-
|
|
121460
|
-
|
|
121461
|
-
return
|
|
121445
|
+
var clone2 = new Frame(this.texture, this.name, this.sourceIndex);
|
|
121446
|
+
clone2.cutX = this.cutX;
|
|
121447
|
+
clone2.cutY = this.cutY;
|
|
121448
|
+
clone2.cutWidth = this.cutWidth;
|
|
121449
|
+
clone2.cutHeight = this.cutHeight;
|
|
121450
|
+
clone2.x = this.x;
|
|
121451
|
+
clone2.y = this.y;
|
|
121452
|
+
clone2.width = this.width;
|
|
121453
|
+
clone2.height = this.height;
|
|
121454
|
+
clone2.halfWidth = this.halfWidth;
|
|
121455
|
+
clone2.halfHeight = this.halfHeight;
|
|
121456
|
+
clone2.centerX = this.centerX;
|
|
121457
|
+
clone2.centerY = this.centerY;
|
|
121458
|
+
clone2.rotated = this.rotated;
|
|
121459
|
+
clone2.data = Extend(true, clone2.data, this.data);
|
|
121460
|
+
clone2.updateUVs();
|
|
121461
|
+
return clone2;
|
|
121462
121462
|
},
|
|
121463
121463
|
/**
|
|
121464
121464
|
* Destroys this Frame by nulling its reference to the parent Texture and and data objects.
|
|
@@ -138673,15 +138673,15 @@ var CopilotOffice = (() => {
|
|
|
138673
138673
|
/***/
|
|
138674
138674
|
((module2) => {
|
|
138675
138675
|
var Clone = function(obj) {
|
|
138676
|
-
var
|
|
138676
|
+
var clone2 = {};
|
|
138677
138677
|
for (var key in obj) {
|
|
138678
138678
|
if (Array.isArray(obj[key])) {
|
|
138679
|
-
|
|
138679
|
+
clone2[key] = obj[key].slice(0);
|
|
138680
138680
|
} else {
|
|
138681
|
-
|
|
138681
|
+
clone2[key] = obj[key];
|
|
138682
138682
|
}
|
|
138683
138683
|
}
|
|
138684
|
-
return
|
|
138684
|
+
return clone2;
|
|
138685
138685
|
};
|
|
138686
138686
|
module2.exports = Clone;
|
|
138687
138687
|
})
|
|
@@ -138713,7 +138713,7 @@ var CopilotOffice = (() => {
|
|
|
138713
138713
|
((module2, __unused_webpack_exports, __webpack_require__2) => {
|
|
138714
138714
|
var IsPlainObject = __webpack_require__2(41212);
|
|
138715
138715
|
var Extend = function() {
|
|
138716
|
-
var options, name, src, copy, copyIsArray,
|
|
138716
|
+
var options, name, src, copy, copyIsArray, clone2, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false;
|
|
138717
138717
|
if (typeof target === "boolean") {
|
|
138718
138718
|
deep = target;
|
|
138719
138719
|
target = arguments[1] || {};
|
|
@@ -138734,11 +138734,11 @@ var CopilotOffice = (() => {
|
|
|
138734
138734
|
if (deep && copy && (IsPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
|
|
138735
138735
|
if (copyIsArray) {
|
|
138736
138736
|
copyIsArray = false;
|
|
138737
|
-
|
|
138737
|
+
clone2 = src && Array.isArray(src) ? src : [];
|
|
138738
138738
|
} else {
|
|
138739
|
-
|
|
138739
|
+
clone2 = src && IsPlainObject(src) ? src : {};
|
|
138740
138740
|
}
|
|
138741
|
-
target[name] = Extend(deep,
|
|
138741
|
+
target[name] = Extend(deep, clone2, copy);
|
|
138742
138742
|
} else if (copy !== void 0) {
|
|
138743
138743
|
target[name] = copy;
|
|
138744
138744
|
}
|
|
@@ -138922,13 +138922,13 @@ var CopilotOffice = (() => {
|
|
|
138922
138922
|
((module2, __unused_webpack_exports, __webpack_require__2) => {
|
|
138923
138923
|
var Clone = __webpack_require__2(41786);
|
|
138924
138924
|
var Merge = function(obj1, obj2) {
|
|
138925
|
-
var
|
|
138925
|
+
var clone2 = Clone(obj1);
|
|
138926
138926
|
for (var key in obj2) {
|
|
138927
|
-
if (!
|
|
138928
|
-
|
|
138927
|
+
if (!clone2.hasOwnProperty(key)) {
|
|
138928
|
+
clone2[key] = obj2[key];
|
|
138929
138929
|
}
|
|
138930
138930
|
}
|
|
138931
|
-
return
|
|
138931
|
+
return clone2;
|
|
138932
138932
|
};
|
|
138933
138933
|
module2.exports = Merge;
|
|
138934
138934
|
})
|
|
@@ -138939,13 +138939,13 @@ var CopilotOffice = (() => {
|
|
|
138939
138939
|
((module2, __unused_webpack_exports, __webpack_require__2) => {
|
|
138940
138940
|
var Clone = __webpack_require__2(41786);
|
|
138941
138941
|
var MergeRight = function(obj1, obj2) {
|
|
138942
|
-
var
|
|
138942
|
+
var clone2 = Clone(obj1);
|
|
138943
138943
|
for (var key in obj2) {
|
|
138944
|
-
if (
|
|
138945
|
-
|
|
138944
|
+
if (clone2.hasOwnProperty(key)) {
|
|
138945
|
+
clone2[key] = obj2[key];
|
|
138946
138946
|
}
|
|
138947
138947
|
}
|
|
138948
|
-
return
|
|
138948
|
+
return clone2;
|
|
138949
138949
|
};
|
|
138950
138950
|
module2.exports = MergeRight;
|
|
138951
138951
|
})
|
|
@@ -139192,6 +139192,22 @@ var CopilotOffice = (() => {
|
|
|
139192
139192
|
}
|
|
139193
139193
|
return vy < 0 ? 3 /* UP */ : 0 /* DOWN */;
|
|
139194
139194
|
}
|
|
139195
|
+
function nextWalkAction(spriteKey, vx, vy, current) {
|
|
139196
|
+
const newDir = directionFromVelocity(vx, vy);
|
|
139197
|
+
if (newDir === null) {
|
|
139198
|
+
return {
|
|
139199
|
+
kind: "idle",
|
|
139200
|
+
direction: current.direction,
|
|
139201
|
+
standFrame: getStandFrame(current.direction)
|
|
139202
|
+
};
|
|
139203
|
+
}
|
|
139204
|
+
return {
|
|
139205
|
+
kind: "play",
|
|
139206
|
+
direction: newDir,
|
|
139207
|
+
animKey: walkAnimKey(spriteKey, newDir),
|
|
139208
|
+
directionChanged: newDir !== current.direction
|
|
139209
|
+
};
|
|
139210
|
+
}
|
|
139195
139211
|
function registerWalkAnimations(anims, spriteKey) {
|
|
139196
139212
|
const directions = [0 /* DOWN */, 1 /* LEFT */, 2 /* RIGHT */, 3 /* UP */];
|
|
139197
139213
|
for (const dir of directions) {
|
|
@@ -140056,10 +140072,19 @@ var CopilotOffice = (() => {
|
|
|
140056
140072
|
}
|
|
140057
140073
|
return valid;
|
|
140058
140074
|
}
|
|
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;
|
|
140075
|
+
var ARCHITECT_AGENT_ID, GENERALIST_AGENT_ID, DEBUGGER_AGENT_ID, ADMIN_AGENT_ID, DEFAULT_PLAN_AGENT_IDS, 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;
|
|
140060
140076
|
var init_agents = __esm({
|
|
140061
140077
|
"src/config/agents.ts"() {
|
|
140062
140078
|
"use strict";
|
|
140079
|
+
ARCHITECT_AGENT_ID = "architect";
|
|
140080
|
+
GENERALIST_AGENT_ID = "generalist";
|
|
140081
|
+
DEBUGGER_AGENT_ID = "debugger";
|
|
140082
|
+
ADMIN_AGENT_ID = "admin";
|
|
140083
|
+
DEFAULT_PLAN_AGENT_IDS = [
|
|
140084
|
+
GENERALIST_AGENT_ID,
|
|
140085
|
+
DEBUGGER_AGENT_ID,
|
|
140086
|
+
ADMIN_AGENT_ID
|
|
140087
|
+
];
|
|
140063
140088
|
FLEET_NAMES = [
|
|
140064
140089
|
"Liam",
|
|
140065
140090
|
"Emma",
|
|
@@ -140216,7 +140241,7 @@ var CopilotOffice = (() => {
|
|
|
140216
140241
|
FLEET_AGENTS = FLEET_SEAT_POSITIONS.map((pos, i) => {
|
|
140217
140242
|
if (i === ARTHUR_FLEET_SEAT_INDEX) {
|
|
140218
140243
|
return {
|
|
140219
|
-
id:
|
|
140244
|
+
id: ARCHITECT_AGENT_ID,
|
|
140220
140245
|
name: "Arthur",
|
|
140221
140246
|
skill: "general",
|
|
140222
140247
|
sprite: "npc_architect",
|
|
@@ -140303,10 +140328,10 @@ var CopilotOffice = (() => {
|
|
|
140303
140328
|
};
|
|
140304
140329
|
SHOW_ARCHITECT_IN_DEFAULT_OFFICE = false;
|
|
140305
140330
|
CORE_AGENT_IDS = /* @__PURE__ */ new Set([
|
|
140306
|
-
|
|
140307
|
-
...SHOW_ARCHITECT_IN_DEFAULT_OFFICE ? [
|
|
140308
|
-
|
|
140309
|
-
|
|
140331
|
+
GENERALIST_AGENT_ID,
|
|
140332
|
+
...SHOW_ARCHITECT_IN_DEFAULT_OFFICE ? [ARCHITECT_AGENT_ID] : [],
|
|
140333
|
+
DEBUGGER_AGENT_ID,
|
|
140334
|
+
ADMIN_AGENT_ID
|
|
140310
140335
|
]);
|
|
140311
140336
|
RESERVE_AGENT_DESK = Object.fromEntries(
|
|
140312
140337
|
Object.entries(RESERVE_AGENTS).map(([deskId, config]) => [config.id, deskId])
|
|
@@ -140325,7 +140350,7 @@ var CopilotOffice = (() => {
|
|
|
140325
140350
|
description: "the Generalist"
|
|
140326
140351
|
},
|
|
140327
140352
|
...SHOW_ARCHITECT_IN_DEFAULT_OFFICE ? [{
|
|
140328
|
-
id:
|
|
140353
|
+
id: ARCHITECT_AGENT_ID,
|
|
140329
140354
|
name: "Arthur",
|
|
140330
140355
|
skill: "general",
|
|
140331
140356
|
sprite: "npc_architect",
|
|
@@ -141697,13 +141722,15 @@ var CopilotOffice = (() => {
|
|
|
141697
141722
|
if (vx !== 0 && vy !== 0) {
|
|
141698
141723
|
body.velocity.normalize().scale(currentSpeed);
|
|
141699
141724
|
}
|
|
141700
|
-
const
|
|
141701
|
-
|
|
141702
|
-
|
|
141703
|
-
|
|
141704
|
-
|
|
141725
|
+
const action = nextWalkAction("player", vx, vy, {
|
|
141726
|
+
direction: this.currentDirection,
|
|
141727
|
+
isWalking: this.isWalking
|
|
141728
|
+
});
|
|
141729
|
+
if (action.kind === "play") {
|
|
141730
|
+
this.currentDirection = action.direction;
|
|
141731
|
+
if (!this.isWalking || action.directionChanged) {
|
|
141705
141732
|
this.isWalking = true;
|
|
141706
|
-
this.anims.play(
|
|
141733
|
+
this.anims.play(action.animKey, true);
|
|
141707
141734
|
}
|
|
141708
141735
|
} else {
|
|
141709
141736
|
this.stopWalking();
|
|
@@ -148170,12 +148197,191 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148170
148197
|
}
|
|
148171
148198
|
});
|
|
148172
148199
|
|
|
148200
|
+
// src/config/zIndex.ts
|
|
148201
|
+
var ZIndex;
|
|
148202
|
+
var init_zIndex = __esm({
|
|
148203
|
+
"src/config/zIndex.ts"() {
|
|
148204
|
+
"use strict";
|
|
148205
|
+
ZIndex = {
|
|
148206
|
+
/** Status bar at the bottom of the app shell. */
|
|
148207
|
+
STATUS_BAR: 100,
|
|
148208
|
+
/** In-scene HTML overlay rendered by OfficeScene above the Phaser canvas
|
|
148209
|
+
* but below all modal surfaces (e.g. fleet-progress sticker). */
|
|
148210
|
+
OFFICE_SCENE_OVERLAY: 150,
|
|
148211
|
+
/** Transient toast notifications (auto-dismissed). */
|
|
148212
|
+
TOAST: 9e3,
|
|
148213
|
+
/** Terminal overlay panel host (xterm.js + tab strip). */
|
|
148214
|
+
TERMINAL_OVERLAY: 1e4,
|
|
148215
|
+
/** Sprite/session card that floats above the terminal overlay. */
|
|
148216
|
+
TERMINAL_SPRITE_CARD: 10001,
|
|
148217
|
+
/** Serious-mode terminal controller (full-pane mode). Sits above the
|
|
148218
|
+
* terminal overlay so its chrome (mode toggle, footer) stays on top. */
|
|
148219
|
+
SERIOUS_TERMINAL: 10003,
|
|
148220
|
+
/** Sprite customizer modal. Above terminal but below settings. */
|
|
148221
|
+
SPRITE_CUSTOMIZER: 15e3,
|
|
148222
|
+
/** Settings panel modal. */
|
|
148223
|
+
SETTINGS: 2e4,
|
|
148224
|
+
/** Notification settings modal. Shares SETTINGS' layer because the two
|
|
148225
|
+
* are never open simultaneously by app construction (both routed via
|
|
148226
|
+
* the same `settings:open` / `settings:close` bus). */
|
|
148227
|
+
NOTIFICATION_SETTINGS: 2e4,
|
|
148228
|
+
/** Generic blocking modal dialog (e.g. layout chooser, new office dialog).
|
|
148229
|
+
* Sits above everything except the absolute top-most modal layer. */
|
|
148230
|
+
MODAL_DIALOG: 99999,
|
|
148231
|
+
/** Reserved for the topmost modal layer (e.g. critical confirmation that
|
|
148232
|
+
* must sit above an already-open MODAL_DIALOG). */
|
|
148233
|
+
TOP_MODAL: 1e5
|
|
148234
|
+
};
|
|
148235
|
+
}
|
|
148236
|
+
});
|
|
148237
|
+
|
|
148238
|
+
// src/util/lifecycleLog.ts
|
|
148239
|
+
function logLifecycleTransition(t) {
|
|
148240
|
+
if (t.from === t.to) return;
|
|
148241
|
+
const full = { ...t, timestamp: Date.now() };
|
|
148242
|
+
const reasonStr = full.reason ? ` reason=${full.reason}` : "";
|
|
148243
|
+
const detailStr = full.detail ? ` detail=${JSON.stringify(full.detail)}` : "";
|
|
148244
|
+
console.log(
|
|
148245
|
+
`[lifecycle] agent=${full.agentId} office=${full.officeId} ${full.from}\u2192${full.to}${reasonStr}${detailStr}`
|
|
148246
|
+
);
|
|
148247
|
+
for (const fn of subscribers) {
|
|
148248
|
+
try {
|
|
148249
|
+
fn(full);
|
|
148250
|
+
} catch (err) {
|
|
148251
|
+
console.warn("[lifecycle] subscriber threw:", err);
|
|
148252
|
+
}
|
|
148253
|
+
}
|
|
148254
|
+
}
|
|
148255
|
+
var subscribers;
|
|
148256
|
+
var init_lifecycleLog = __esm({
|
|
148257
|
+
"src/util/lifecycleLog.ts"() {
|
|
148258
|
+
"use strict";
|
|
148259
|
+
subscribers = /* @__PURE__ */ new Set();
|
|
148260
|
+
}
|
|
148261
|
+
});
|
|
148262
|
+
|
|
148263
|
+
// src/office/officePersistence.ts
|
|
148264
|
+
function serializeOffices(state) {
|
|
148265
|
+
return JSON.stringify(
|
|
148266
|
+
{
|
|
148267
|
+
currentOfficeId: state.currentOfficeId,
|
|
148268
|
+
offices: state.offices
|
|
148269
|
+
},
|
|
148270
|
+
null,
|
|
148271
|
+
2
|
|
148272
|
+
);
|
|
148273
|
+
}
|
|
148274
|
+
function deserializeOffices(stored) {
|
|
148275
|
+
if (!stored) return { currentOfficeId: null, offices: [] };
|
|
148276
|
+
let data;
|
|
148277
|
+
try {
|
|
148278
|
+
data = JSON.parse(stored);
|
|
148279
|
+
} catch {
|
|
148280
|
+
return { currentOfficeId: null, offices: [] };
|
|
148281
|
+
}
|
|
148282
|
+
if (data === null || typeof data !== "object") {
|
|
148283
|
+
return { currentOfficeId: null, offices: [] };
|
|
148284
|
+
}
|
|
148285
|
+
const record = data;
|
|
148286
|
+
const rawOffices = Array.isArray(record.offices) ? record.offices : [];
|
|
148287
|
+
const offices = [];
|
|
148288
|
+
for (let i = 0; i < rawOffices.length; i++) {
|
|
148289
|
+
const raw = rawOffices[i];
|
|
148290
|
+
if (raw === null || typeof raw !== "object") continue;
|
|
148291
|
+
const cfg = raw;
|
|
148292
|
+
const name = typeof cfg.name === "string" ? cfg.name : `Office ${i}`;
|
|
148293
|
+
const workingDirectory = typeof cfg.workingDirectory === "string" ? cfg.workingDirectory : ".";
|
|
148294
|
+
const createdAt = typeof cfg.createdAt === "number" ? cfg.createdAt : Date.now();
|
|
148295
|
+
const layout = cfg.layout === "fleet-vteam" ? "fleet-vteam" : "default";
|
|
148296
|
+
const seatedAgents = Array.isArray(cfg.seatedAgents) ? cfg.seatedAgents.filter(
|
|
148297
|
+
(s) => !!s && typeof s === "object" && typeof s.deskId === "string" && typeof s.agentId === "string"
|
|
148298
|
+
) : [];
|
|
148299
|
+
const normalized = {
|
|
148300
|
+
// Reindex from array position — this replaces legacy UUID-style ids and
|
|
148301
|
+
// matches the prior inline loader behaviour exactly.
|
|
148302
|
+
id: `office-${i}`,
|
|
148303
|
+
name,
|
|
148304
|
+
workingDirectory,
|
|
148305
|
+
createdAt,
|
|
148306
|
+
layout,
|
|
148307
|
+
seatedAgents
|
|
148308
|
+
};
|
|
148309
|
+
if (cfg.customAgents !== void 0) {
|
|
148310
|
+
normalized.customAgents = cfg.customAgents;
|
|
148311
|
+
}
|
|
148312
|
+
if (cfg.customReserveAgents !== void 0) {
|
|
148313
|
+
normalized.customReserveAgents = cfg.customReserveAgents;
|
|
148314
|
+
}
|
|
148315
|
+
offices.push(normalized);
|
|
148316
|
+
}
|
|
148317
|
+
let currentOfficeId = null;
|
|
148318
|
+
if (record.currentOfficeId !== void 0 && record.currentOfficeId !== null) {
|
|
148319
|
+
currentOfficeId = String(record.currentOfficeId);
|
|
148320
|
+
}
|
|
148321
|
+
if (!currentOfficeId || !offices.some((o) => o.id === currentOfficeId)) {
|
|
148322
|
+
currentOfficeId = offices.length > 0 ? offices[0].id : null;
|
|
148323
|
+
}
|
|
148324
|
+
return { currentOfficeId, offices };
|
|
148325
|
+
}
|
|
148326
|
+
function createBridgePersistencePort() {
|
|
148327
|
+
const getBridge = () => typeof window !== "undefined" ? window.copilotBridge : void 0;
|
|
148328
|
+
return {
|
|
148329
|
+
async loadDurable() {
|
|
148330
|
+
const bridge = getBridge();
|
|
148331
|
+
if (!bridge?.loadOffices) return null;
|
|
148332
|
+
try {
|
|
148333
|
+
const result = await bridge.loadOffices();
|
|
148334
|
+
if (result?.success && typeof result.data === "string") {
|
|
148335
|
+
return result.data;
|
|
148336
|
+
}
|
|
148337
|
+
} catch (e) {
|
|
148338
|
+
console.warn("[OfficePersistence] loadOffices failed:", e);
|
|
148339
|
+
}
|
|
148340
|
+
return null;
|
|
148341
|
+
},
|
|
148342
|
+
async saveDurable(json) {
|
|
148343
|
+
const bridge = getBridge();
|
|
148344
|
+
if (!bridge?.saveOffices) return;
|
|
148345
|
+
try {
|
|
148346
|
+
await bridge.saveOffices(json);
|
|
148347
|
+
} catch (e) {
|
|
148348
|
+
console.warn("[OfficePersistence] saveOffices failed:", e);
|
|
148349
|
+
}
|
|
148350
|
+
},
|
|
148351
|
+
async createOfficeSession(officeId) {
|
|
148352
|
+
const bridge = getBridge();
|
|
148353
|
+
if (!bridge?.createOfficeSession) return;
|
|
148354
|
+
try {
|
|
148355
|
+
await bridge.createOfficeSession(officeId);
|
|
148356
|
+
} catch (e) {
|
|
148357
|
+
console.warn("[OfficePersistence] createOfficeSession failed:", e);
|
|
148358
|
+
}
|
|
148359
|
+
},
|
|
148360
|
+
async deleteOfficeSession(officeId) {
|
|
148361
|
+
const bridge = getBridge();
|
|
148362
|
+
if (!bridge?.deleteOfficeSession) return;
|
|
148363
|
+
try {
|
|
148364
|
+
await bridge.deleteOfficeSession(officeId);
|
|
148365
|
+
} catch (e) {
|
|
148366
|
+
console.warn("[OfficePersistence] deleteOfficeSession failed:", e);
|
|
148367
|
+
}
|
|
148368
|
+
}
|
|
148369
|
+
};
|
|
148370
|
+
}
|
|
148371
|
+
var init_officePersistence = __esm({
|
|
148372
|
+
"src/office/officePersistence.ts"() {
|
|
148373
|
+
"use strict";
|
|
148374
|
+
}
|
|
148375
|
+
});
|
|
148376
|
+
|
|
148173
148377
|
// src/office/officeManager.ts
|
|
148174
148378
|
var VALID_TRANSITIONS, MAX_RECENT_ACTIONS, OfficeManager, officeManager;
|
|
148175
148379
|
var init_officeManager = __esm({
|
|
148176
148380
|
"src/office/officeManager.ts"() {
|
|
148177
148381
|
"use strict";
|
|
148178
148382
|
init_agents();
|
|
148383
|
+
init_lifecycleLog();
|
|
148384
|
+
init_officePersistence();
|
|
148179
148385
|
VALID_TRANSITIONS = {
|
|
148180
148386
|
slacking: /* @__PURE__ */ new Set(["starting", "ready"]),
|
|
148181
148387
|
starting: /* @__PURE__ */ new Set(["ready", "error", "slacking"]),
|
|
@@ -148186,14 +148392,24 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148186
148392
|
};
|
|
148187
148393
|
MAX_RECENT_ACTIONS = 8;
|
|
148188
148394
|
OfficeManager = class {
|
|
148189
|
-
constructor() {
|
|
148395
|
+
constructor(persistence = createBridgePersistencePort()) {
|
|
148190
148396
|
this.offices = /* @__PURE__ */ new Map();
|
|
148191
148397
|
this.sessionToOffice = /* @__PURE__ */ new Map();
|
|
148192
148398
|
// sessionId → officeId
|
|
148193
148399
|
this._currentOfficeId = null;
|
|
148400
|
+
// Spec 008 (2026-06-12): durable load is async but renderer boot triggers
|
|
148401
|
+
// saves (status updates, agent registrations) almost immediately. Without
|
|
148402
|
+
// gating, those saves serialize the localStorage-only state and clobber
|
|
148403
|
+
// the multi-office file on disk before the durable load can hydrate. We
|
|
148404
|
+
// hold all durable writes until loadFromStorage's async path settles, then
|
|
148405
|
+
// flush whatever the most-recent state was. localStorage writes are NOT
|
|
148406
|
+
// gated — they're fast, synchronous, and only matter for next cold boot.
|
|
148407
|
+
this.durableLoadSettled = false;
|
|
148408
|
+
this.pendingDurableWrite = false;
|
|
148194
148409
|
// Callbacks for UI updates
|
|
148195
148410
|
this.onOfficeChanged = null;
|
|
148196
148411
|
this.onOfficesUpdated = null;
|
|
148412
|
+
this.persistence = persistence;
|
|
148197
148413
|
this.loadFromStorage();
|
|
148198
148414
|
}
|
|
148199
148415
|
get currentOfficeId() {
|
|
@@ -148237,11 +148453,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148237
148453
|
this._currentOfficeId = id;
|
|
148238
148454
|
}
|
|
148239
148455
|
this.saveToStorage();
|
|
148240
|
-
|
|
148241
|
-
window.copilotBridge.createOfficeSession(id).catch((e) => {
|
|
148242
|
-
console.warn("[OfficeManager] Failed to create session file:", e);
|
|
148243
|
-
});
|
|
148244
|
-
}
|
|
148456
|
+
void this.persistence.createOfficeSession(id);
|
|
148245
148457
|
this.onOfficesUpdated?.();
|
|
148246
148458
|
return data;
|
|
148247
148459
|
}
|
|
@@ -148259,11 +148471,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148259
148471
|
}
|
|
148260
148472
|
}
|
|
148261
148473
|
this.offices.delete(officeId);
|
|
148262
|
-
|
|
148263
|
-
window.copilotBridge.deleteOfficeSession(officeId).catch((e) => {
|
|
148264
|
-
console.warn("[OfficeManager] Failed to delete session file:", e);
|
|
148265
|
-
});
|
|
148266
|
-
}
|
|
148474
|
+
void this.persistence.deleteOfficeSession(officeId);
|
|
148267
148475
|
if (this._currentOfficeId === officeId) {
|
|
148268
148476
|
this._currentOfficeId = this.offices.has("office-0") ? "office-0" : this.offices.keys().next().value || null;
|
|
148269
148477
|
if (this._currentOfficeId) {
|
|
@@ -148335,70 +148543,63 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148335
148543
|
const office = this.offices.get(officeId);
|
|
148336
148544
|
return office?.config.seatedAgents ?? [];
|
|
148337
148545
|
}
|
|
148338
|
-
// Persistence — saves to both localStorage (fast) and .
|
|
148546
|
+
// Persistence — saves to both localStorage (fast) and durable file via port.
|
|
148339
148547
|
saveToStorage() {
|
|
148340
|
-
const
|
|
148548
|
+
const json = serializeOffices({
|
|
148341
148549
|
currentOfficeId: this._currentOfficeId,
|
|
148342
148550
|
offices: Array.from(this.offices.values()).map((o) => o.config)
|
|
148343
|
-
};
|
|
148344
|
-
const json = JSON.stringify(data, null, 2);
|
|
148551
|
+
});
|
|
148345
148552
|
try {
|
|
148346
148553
|
localStorage.setItem("copilot-offices", json);
|
|
148347
148554
|
} catch (e) {
|
|
148348
148555
|
console.warn("[OfficeManager] Failed to save to localStorage:", e);
|
|
148349
148556
|
}
|
|
148350
|
-
if (
|
|
148351
|
-
|
|
148352
|
-
|
|
148353
|
-
});
|
|
148557
|
+
if (!this.durableLoadSettled) {
|
|
148558
|
+
this.pendingDurableWrite = true;
|
|
148559
|
+
return;
|
|
148354
148560
|
}
|
|
148561
|
+
void this.persistence.saveDurable(json);
|
|
148562
|
+
}
|
|
148563
|
+
flushPendingDurableWrite() {
|
|
148564
|
+
if (!this.pendingDurableWrite) return;
|
|
148565
|
+
this.pendingDurableWrite = false;
|
|
148566
|
+
const json = serializeOffices({
|
|
148567
|
+
currentOfficeId: this._currentOfficeId,
|
|
148568
|
+
offices: Array.from(this.offices.values()).map((o) => o.config)
|
|
148569
|
+
});
|
|
148570
|
+
void this.persistence.saveDurable(json);
|
|
148355
148571
|
}
|
|
148356
148572
|
loadFromStorage() {
|
|
148357
|
-
this.
|
|
148358
|
-
|
|
148359
|
-
|
|
148360
|
-
|
|
148361
|
-
|
|
148362
|
-
|
|
148363
|
-
|
|
148364
|
-
|
|
148365
|
-
|
|
148366
|
-
|
|
148367
|
-
|
|
148368
|
-
|
|
148573
|
+
this.applyStoredState(localStorage.getItem("copilot-offices"));
|
|
148574
|
+
void this.persistence.loadDurable().then((data) => {
|
|
148575
|
+
if (data) {
|
|
148576
|
+
console.log("[OfficeManager] Loaded offices from durable persistence");
|
|
148577
|
+
this.applyStoredState(data);
|
|
148578
|
+
this.onOfficesUpdated?.();
|
|
148579
|
+
}
|
|
148580
|
+
}).catch((e) => {
|
|
148581
|
+
console.warn("[OfficeManager] Failed to load from durable persistence:", e);
|
|
148582
|
+
}).finally(() => {
|
|
148583
|
+
this.durableLoadSettled = true;
|
|
148584
|
+
this.flushPendingDurableWrite();
|
|
148585
|
+
});
|
|
148369
148586
|
}
|
|
148370
|
-
|
|
148371
|
-
|
|
148372
|
-
|
|
148373
|
-
|
|
148374
|
-
|
|
148375
|
-
|
|
148376
|
-
|
|
148377
|
-
|
|
148378
|
-
|
|
148379
|
-
|
|
148380
|
-
|
|
148381
|
-
|
|
148382
|
-
|
|
148383
|
-
|
|
148384
|
-
|
|
148385
|
-
|
|
148386
|
-
agentTools: existing?.agentTools ?? /* @__PURE__ */ new Map()
|
|
148387
|
-
};
|
|
148388
|
-
this.offices.set(id, officeData);
|
|
148389
|
-
}
|
|
148390
|
-
}
|
|
148391
|
-
let currentId = null;
|
|
148392
|
-
if (data.currentOfficeId !== void 0 && data.currentOfficeId !== null) {
|
|
148393
|
-
currentId = String(data.currentOfficeId);
|
|
148394
|
-
}
|
|
148395
|
-
if (currentId && this.offices.has(currentId)) {
|
|
148396
|
-
this._currentOfficeId = currentId;
|
|
148397
|
-
} else if (this.offices.size > 0) {
|
|
148398
|
-
this._currentOfficeId = this.offices.keys().next().value;
|
|
148399
|
-
}
|
|
148400
|
-
} catch (e) {
|
|
148401
|
-
console.warn("[OfficeManager] Failed to parse office data:", e);
|
|
148587
|
+
applyStoredState(stored) {
|
|
148588
|
+
const { currentOfficeId, offices } = deserializeOffices(stored);
|
|
148589
|
+
if (offices.length === 0 && currentOfficeId === null) return;
|
|
148590
|
+
for (const config of offices) {
|
|
148591
|
+
const existing = this.offices.get(config.id);
|
|
148592
|
+
const officeData = {
|
|
148593
|
+
config,
|
|
148594
|
+
agents: existing?.agents ?? /* @__PURE__ */ new Map(),
|
|
148595
|
+
agentTools: existing?.agentTools ?? /* @__PURE__ */ new Map()
|
|
148596
|
+
};
|
|
148597
|
+
this.offices.set(config.id, officeData);
|
|
148598
|
+
}
|
|
148599
|
+
if (currentOfficeId && this.offices.has(currentOfficeId)) {
|
|
148600
|
+
this._currentOfficeId = currentOfficeId;
|
|
148601
|
+
} else if (this.offices.size > 0) {
|
|
148602
|
+
this._currentOfficeId = this.offices.keys().next().value;
|
|
148402
148603
|
}
|
|
148403
148604
|
}
|
|
148404
148605
|
// Agent status helpers
|
|
@@ -148428,9 +148629,27 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148428
148629
|
console.warn(`[OfficeManager] Invalid transition: ${agentId} ${from} \u2192 ${target}`);
|
|
148429
148630
|
}
|
|
148430
148631
|
}
|
|
148431
|
-
|
|
148632
|
+
/**
|
|
148633
|
+
* Emit a structured lifecycle telemetry entry for a transition that has
|
|
148634
|
+
* already been applied to `status`. Callers pass the pre-mutation effective
|
|
148635
|
+
* state captured before mutating. Safe additive observability — never mutates
|
|
148636
|
+
* state and self-transitions are suppressed by the helper.
|
|
148637
|
+
*/
|
|
148638
|
+
emitLifecycleTransition(officeId, agentId, status, from, reason, detail) {
|
|
148639
|
+
const to = this.getEffectiveState(status);
|
|
148640
|
+
logLifecycleTransition({
|
|
148641
|
+
agentId,
|
|
148642
|
+
officeId,
|
|
148643
|
+
from,
|
|
148644
|
+
to,
|
|
148645
|
+
reason,
|
|
148646
|
+
detail
|
|
148647
|
+
});
|
|
148648
|
+
}
|
|
148649
|
+
setAgentSlacking(officeId, agentId, reason) {
|
|
148432
148650
|
const status = this.getOrCreateStatus(officeId, agentId);
|
|
148433
148651
|
if (!status) return;
|
|
148652
|
+
const from = this.getEffectiveState(status);
|
|
148434
148653
|
this.validateTransition(agentId, status, "slacking");
|
|
148435
148654
|
status.state = "slacking";
|
|
148436
148655
|
status.subState = null;
|
|
@@ -148440,11 +148659,13 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148440
148659
|
status.activityStartTime = null;
|
|
148441
148660
|
status.recentActions = [];
|
|
148442
148661
|
status.taskSummary = null;
|
|
148662
|
+
this.emitLifecycleTransition(officeId, agentId, status, from, reason);
|
|
148443
148663
|
}
|
|
148444
|
-
setAgentStarting(officeId, agentId) {
|
|
148664
|
+
setAgentStarting(officeId, agentId, reason) {
|
|
148445
148665
|
const status = this.getOrCreateStatus(officeId, agentId);
|
|
148446
148666
|
if (!status) return;
|
|
148447
148667
|
if (status.subState === "starting") return;
|
|
148668
|
+
const from = this.getEffectiveState(status);
|
|
148448
148669
|
this.validateTransition(agentId, status, "starting");
|
|
148449
148670
|
status.state = "active";
|
|
148450
148671
|
status.subState = "starting";
|
|
@@ -148452,10 +148673,12 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148452
148673
|
status.currentTool = null;
|
|
148453
148674
|
status.completionPendingAck = false;
|
|
148454
148675
|
status.activityStartTime = Date.now();
|
|
148676
|
+
this.emitLifecycleTransition(officeId, agentId, status, from, reason);
|
|
148455
148677
|
}
|
|
148456
|
-
setAgentReady(officeId, agentId) {
|
|
148678
|
+
setAgentReady(officeId, agentId, reason) {
|
|
148457
148679
|
const status = this.getOrCreateStatus(officeId, agentId);
|
|
148458
148680
|
if (!status) return;
|
|
148681
|
+
const from = this.getEffectiveState(status);
|
|
148459
148682
|
this.validateTransition(agentId, status, "ready");
|
|
148460
148683
|
status.state = "active";
|
|
148461
148684
|
status.subState = "ready";
|
|
@@ -148463,10 +148686,12 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148463
148686
|
status.currentTool = null;
|
|
148464
148687
|
status.completionPendingAck = false;
|
|
148465
148688
|
status.activityStartTime = null;
|
|
148689
|
+
this.emitLifecycleTransition(officeId, agentId, status, from, reason);
|
|
148466
148690
|
}
|
|
148467
|
-
setAgentDonePendingAck(officeId, agentId) {
|
|
148691
|
+
setAgentDonePendingAck(officeId, agentId, reason) {
|
|
148468
148692
|
const status = this.getOrCreateStatus(officeId, agentId);
|
|
148469
148693
|
if (!status) return;
|
|
148694
|
+
const from = this.getEffectiveState(status);
|
|
148470
148695
|
this.validateTransition(agentId, status, "ready");
|
|
148471
148696
|
status.state = "active";
|
|
148472
148697
|
status.subState = "ready";
|
|
@@ -148474,6 +148699,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148474
148699
|
status.currentTool = null;
|
|
148475
148700
|
status.completionPendingAck = true;
|
|
148476
148701
|
status.activityStartTime = null;
|
|
148702
|
+
this.emitLifecycleTransition(officeId, agentId, status, from, reason ?? "done_pending_ack");
|
|
148477
148703
|
}
|
|
148478
148704
|
acknowledgeAgentCompletion(officeId, agentId) {
|
|
148479
148705
|
const status = this.getOrCreateStatus(officeId, agentId);
|
|
@@ -148481,9 +148707,10 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148481
148707
|
status.completionPendingAck = false;
|
|
148482
148708
|
return true;
|
|
148483
148709
|
}
|
|
148484
|
-
setAgentWaiting(officeId, agentId) {
|
|
148710
|
+
setAgentWaiting(officeId, agentId, reason) {
|
|
148485
148711
|
const status = this.getOrCreateStatus(officeId, agentId);
|
|
148486
148712
|
if (!status) return;
|
|
148713
|
+
const from = this.getEffectiveState(status);
|
|
148487
148714
|
this.validateTransition(agentId, status, "waiting");
|
|
148488
148715
|
status.state = "active";
|
|
148489
148716
|
status.subState = "waiting";
|
|
@@ -148491,10 +148718,12 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148491
148718
|
status.currentTool = null;
|
|
148492
148719
|
status.completionPendingAck = false;
|
|
148493
148720
|
if (!status.activityStartTime) status.activityStartTime = Date.now();
|
|
148721
|
+
this.emitLifecycleTransition(officeId, agentId, status, from, reason);
|
|
148494
148722
|
}
|
|
148495
|
-
setAgentThinking(officeId, agentId, detail) {
|
|
148723
|
+
setAgentThinking(officeId, agentId, detail, reason) {
|
|
148496
148724
|
const status = this.getOrCreateStatus(officeId, agentId);
|
|
148497
148725
|
if (!status) return;
|
|
148726
|
+
const from = this.getEffectiveState(status);
|
|
148498
148727
|
this.validateTransition(agentId, status, "thinking");
|
|
148499
148728
|
status.state = "active";
|
|
148500
148729
|
status.subState = "thinking";
|
|
@@ -148504,6 +148733,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148504
148733
|
status.currentTool = tools?.length ? tools[tools.length - 1].name : null;
|
|
148505
148734
|
status.completionPendingAck = false;
|
|
148506
148735
|
if (!status.activityStartTime) status.activityStartTime = Date.now();
|
|
148736
|
+
this.emitLifecycleTransition(officeId, agentId, status, from, reason, detail ?? void 0);
|
|
148507
148737
|
}
|
|
148508
148738
|
clearAgentThinkingDetail(officeId, agentId) {
|
|
148509
148739
|
const status = this.getOrCreateStatus(officeId, agentId);
|
|
@@ -148524,9 +148754,10 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148524
148754
|
status.unreadCount = 0;
|
|
148525
148755
|
status.lastEvent = null;
|
|
148526
148756
|
}
|
|
148527
|
-
setAgentError(officeId, agentId, detail = null) {
|
|
148757
|
+
setAgentError(officeId, agentId, detail = null, reason) {
|
|
148528
148758
|
const status = this.getOrCreateStatus(officeId, agentId);
|
|
148529
148759
|
if (!status) return;
|
|
148760
|
+
const from = this.getEffectiveState(status);
|
|
148530
148761
|
this.validateTransition(agentId, status, "error");
|
|
148531
148762
|
status.state = "active";
|
|
148532
148763
|
status.subState = "error";
|
|
@@ -148534,6 +148765,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148534
148765
|
status.currentTool = null;
|
|
148535
148766
|
status.completionPendingAck = false;
|
|
148536
148767
|
status.activityStartTime = null;
|
|
148768
|
+
this.emitLifecycleTransition(officeId, agentId, status, from, reason, detail ?? void 0);
|
|
148537
148769
|
}
|
|
148538
148770
|
setLastCompletedAction(officeId, agentId, action) {
|
|
148539
148771
|
const status = this.getOrCreateStatus(officeId, agentId);
|
|
@@ -148569,6 +148801,271 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148569
148801
|
}
|
|
148570
148802
|
});
|
|
148571
148803
|
|
|
148804
|
+
// src/ui/clipboardToast.ts
|
|
148805
|
+
function ensureToastElement() {
|
|
148806
|
+
if (typeof document === "undefined") return null;
|
|
148807
|
+
let el = document.getElementById(TOAST_ID);
|
|
148808
|
+
if (el) return el;
|
|
148809
|
+
el = document.createElement("div");
|
|
148810
|
+
el.id = TOAST_ID;
|
|
148811
|
+
el.style.cssText = `
|
|
148812
|
+
position: fixed;
|
|
148813
|
+
top: 24px;
|
|
148814
|
+
left: 50%;
|
|
148815
|
+
transform: translateX(-50%);
|
|
148816
|
+
z-index: ${ZIndex.TERMINAL_SPRITE_CARD + 20};
|
|
148817
|
+
padding: 8px 16px;
|
|
148818
|
+
border-radius: 6px;
|
|
148819
|
+
font-family: 'Cascadia Code', Consolas, monospace;
|
|
148820
|
+
font-size: 13px;
|
|
148821
|
+
color: #ffffff;
|
|
148822
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
|
|
148823
|
+
pointer-events: none;
|
|
148824
|
+
opacity: 0;
|
|
148825
|
+
transition: opacity 120ms ease-out;
|
|
148826
|
+
max-width: 60vw;
|
|
148827
|
+
text-align: center;
|
|
148828
|
+
`;
|
|
148829
|
+
document.body.appendChild(el);
|
|
148830
|
+
return el;
|
|
148831
|
+
}
|
|
148832
|
+
function showClipboardToast(message, kind = "info") {
|
|
148833
|
+
const el = ensureToastElement();
|
|
148834
|
+
if (!el) return;
|
|
148835
|
+
el.textContent = message;
|
|
148836
|
+
el.style.background = KIND_BG[kind];
|
|
148837
|
+
el.style.opacity = "1";
|
|
148838
|
+
if (dismissTimer) clearTimeout(dismissTimer);
|
|
148839
|
+
dismissTimer = setTimeout(() => {
|
|
148840
|
+
el.style.opacity = "0";
|
|
148841
|
+
}, TOAST_DURATION_MS);
|
|
148842
|
+
}
|
|
148843
|
+
var TOAST_ID, TOAST_DURATION_MS, dismissTimer, KIND_BG;
|
|
148844
|
+
var init_clipboardToast = __esm({
|
|
148845
|
+
"src/ui/clipboardToast.ts"() {
|
|
148846
|
+
"use strict";
|
|
148847
|
+
init_zIndex();
|
|
148848
|
+
TOAST_ID = "copilot-office-clipboard-toast";
|
|
148849
|
+
TOAST_DURATION_MS = 1500;
|
|
148850
|
+
dismissTimer = null;
|
|
148851
|
+
KIND_BG = {
|
|
148852
|
+
success: "#1f6f3a",
|
|
148853
|
+
info: "#27355a",
|
|
148854
|
+
error: "#7a2230"
|
|
148855
|
+
};
|
|
148856
|
+
}
|
|
148857
|
+
});
|
|
148858
|
+
|
|
148859
|
+
// src/ui/xtermStyles.ts
|
|
148860
|
+
function ensureXtermStyles() {
|
|
148861
|
+
if (typeof document === "undefined") return;
|
|
148862
|
+
if (document.getElementById(STYLE_ID)) return;
|
|
148863
|
+
const style = document.createElement("style");
|
|
148864
|
+
style.id = STYLE_ID;
|
|
148865
|
+
style.textContent = `
|
|
148866
|
+
.xterm {
|
|
148867
|
+
height: 100%;
|
|
148868
|
+
}
|
|
148869
|
+
.xterm-viewport {
|
|
148870
|
+
overflow-y: scroll !important;
|
|
148871
|
+
background-color: #0a0a14 !important;
|
|
148872
|
+
scrollbar-width: none;
|
|
148873
|
+
scrollbar-gutter: auto;
|
|
148874
|
+
}
|
|
148875
|
+
.xterm-viewport::-webkit-scrollbar {
|
|
148876
|
+
width: 0 !important;
|
|
148877
|
+
height: 0 !important;
|
|
148878
|
+
display: none !important;
|
|
148879
|
+
}
|
|
148880
|
+
#terminal-container .xterm {
|
|
148881
|
+
height: 100%;
|
|
148882
|
+
}
|
|
148883
|
+
#serious-terminal-container .xterm {
|
|
148884
|
+
height: 100%;
|
|
148885
|
+
}
|
|
148886
|
+
`;
|
|
148887
|
+
document.head.appendChild(style);
|
|
148888
|
+
}
|
|
148889
|
+
var STYLE_ID;
|
|
148890
|
+
var init_xtermStyles = __esm({
|
|
148891
|
+
"src/ui/xtermStyles.ts"() {
|
|
148892
|
+
"use strict";
|
|
148893
|
+
STYLE_ID = "copilot-office-xterm-styles";
|
|
148894
|
+
}
|
|
148895
|
+
});
|
|
148896
|
+
|
|
148897
|
+
// src/ui/terminalWheel.ts
|
|
148898
|
+
function wheelToPtySequence(deltaY, opts = {}) {
|
|
148899
|
+
if (!deltaY) return "";
|
|
148900
|
+
const pages = Math.max(1, Math.round(opts.pagesPerNotch ?? 1));
|
|
148901
|
+
const key = deltaY < 0 ? PAGE_UP : PAGE_DOWN;
|
|
148902
|
+
return key.repeat(pages);
|
|
148903
|
+
}
|
|
148904
|
+
var PAGE_UP, PAGE_DOWN;
|
|
148905
|
+
var init_terminalWheel = __esm({
|
|
148906
|
+
"src/ui/terminalWheel.ts"() {
|
|
148907
|
+
"use strict";
|
|
148908
|
+
PAGE_UP = "\x1B[5~";
|
|
148909
|
+
PAGE_DOWN = "\x1B[6~";
|
|
148910
|
+
}
|
|
148911
|
+
});
|
|
148912
|
+
|
|
148913
|
+
// src/agents/AutoStartCoordinator.ts
|
|
148914
|
+
function readSessionStorage() {
|
|
148915
|
+
try {
|
|
148916
|
+
if (typeof sessionStorage !== "undefined") return sessionStorage;
|
|
148917
|
+
} catch {
|
|
148918
|
+
}
|
|
148919
|
+
return null;
|
|
148920
|
+
}
|
|
148921
|
+
function setAutoStartCoordinator(c) {
|
|
148922
|
+
_instance = c;
|
|
148923
|
+
}
|
|
148924
|
+
function getAutoStartCoordinator() {
|
|
148925
|
+
return _instance;
|
|
148926
|
+
}
|
|
148927
|
+
var WARMED_STORAGE_KEY, WarmedOfficeRegistry, AgentReplaceTracker, AutoStartCoordinator, _instance;
|
|
148928
|
+
var init_AutoStartCoordinator = __esm({
|
|
148929
|
+
"src/agents/AutoStartCoordinator.ts"() {
|
|
148930
|
+
"use strict";
|
|
148931
|
+
WARMED_STORAGE_KEY = "copilot-office-auto-start:warmed";
|
|
148932
|
+
WarmedOfficeRegistry = class {
|
|
148933
|
+
constructor() {
|
|
148934
|
+
const storage = readSessionStorage();
|
|
148935
|
+
let initial = [];
|
|
148936
|
+
if (storage) {
|
|
148937
|
+
try {
|
|
148938
|
+
const raw = storage.getItem(WARMED_STORAGE_KEY);
|
|
148939
|
+
if (raw) {
|
|
148940
|
+
const parsed = JSON.parse(raw);
|
|
148941
|
+
if (Array.isArray(parsed)) initial = parsed.filter((s) => typeof s === "string");
|
|
148942
|
+
}
|
|
148943
|
+
} catch {
|
|
148944
|
+
}
|
|
148945
|
+
}
|
|
148946
|
+
this.warmed = new Set(initial);
|
|
148947
|
+
}
|
|
148948
|
+
has(officeId) {
|
|
148949
|
+
return this.warmed.has(officeId);
|
|
148950
|
+
}
|
|
148951
|
+
mark(officeId) {
|
|
148952
|
+
this.warmed.add(officeId);
|
|
148953
|
+
const storage = readSessionStorage();
|
|
148954
|
+
if (!storage) return;
|
|
148955
|
+
try {
|
|
148956
|
+
storage.setItem(WARMED_STORAGE_KEY, JSON.stringify(Array.from(this.warmed)));
|
|
148957
|
+
} catch {
|
|
148958
|
+
}
|
|
148959
|
+
}
|
|
148960
|
+
/** @internal — test helper. */
|
|
148961
|
+
snapshot() {
|
|
148962
|
+
return Array.from(this.warmed);
|
|
148963
|
+
}
|
|
148964
|
+
/** @internal — e2e helper for spec 009 A4 (Settings OFF gate). */
|
|
148965
|
+
clearAll() {
|
|
148966
|
+
this.warmed.clear();
|
|
148967
|
+
const storage = readSessionStorage();
|
|
148968
|
+
if (storage) {
|
|
148969
|
+
try {
|
|
148970
|
+
storage.removeItem(WARMED_STORAGE_KEY);
|
|
148971
|
+
} catch {
|
|
148972
|
+
}
|
|
148973
|
+
}
|
|
148974
|
+
}
|
|
148975
|
+
};
|
|
148976
|
+
AgentReplaceTracker = class {
|
|
148977
|
+
constructor() {
|
|
148978
|
+
this.inFlight = /* @__PURE__ */ new Map();
|
|
148979
|
+
}
|
|
148980
|
+
has(agentId) {
|
|
148981
|
+
return this.inFlight.has(agentId);
|
|
148982
|
+
}
|
|
148983
|
+
get(agentId) {
|
|
148984
|
+
return this.inFlight.get(agentId);
|
|
148985
|
+
}
|
|
148986
|
+
set(agentId, p) {
|
|
148987
|
+
this.inFlight.set(agentId, p);
|
|
148988
|
+
}
|
|
148989
|
+
delete(agentId) {
|
|
148990
|
+
this.inFlight.delete(agentId);
|
|
148991
|
+
}
|
|
148992
|
+
};
|
|
148993
|
+
AutoStartCoordinator = class {
|
|
148994
|
+
constructor(deps) {
|
|
148995
|
+
this.deps = deps;
|
|
148996
|
+
this.warmedOffices = new WarmedOfficeRegistry();
|
|
148997
|
+
this.replaceTracker = new AgentReplaceTracker();
|
|
148998
|
+
}
|
|
148999
|
+
/** Rule #1 + #2 trigger. Idempotent: no-op if office already warmed or
|
|
149000
|
+
* setting is OFF. Returns the agents it kicked off (for testing). */
|
|
149001
|
+
async tryWarmCurrentOffice() {
|
|
149002
|
+
if (!this.deps.getSettings().autoStartKnownAgents) return [];
|
|
149003
|
+
const oid = this.deps.getCurrentOfficeId();
|
|
149004
|
+
if (!oid) return [];
|
|
149005
|
+
if (this.warmedOffices.has(oid)) return [];
|
|
149006
|
+
this.warmedOffices.mark(oid);
|
|
149007
|
+
let roster;
|
|
149008
|
+
try {
|
|
149009
|
+
roster = this.deps.getCanonicalAgentIds(oid) || [];
|
|
149010
|
+
} catch {
|
|
149011
|
+
roster = [];
|
|
149012
|
+
}
|
|
149013
|
+
let meta;
|
|
149014
|
+
try {
|
|
149015
|
+
meta = await this.deps.getSessionMeta(oid) || {};
|
|
149016
|
+
} catch {
|
|
149017
|
+
meta = {};
|
|
149018
|
+
}
|
|
149019
|
+
const titled = [];
|
|
149020
|
+
for (const id of roster) {
|
|
149021
|
+
const entry = meta[id];
|
|
149022
|
+
const title = entry && typeof entry.title === "string" ? entry.title.trim() : "";
|
|
149023
|
+
if (title) titled.push(id);
|
|
149024
|
+
}
|
|
149025
|
+
const sids = await Promise.all(
|
|
149026
|
+
titled.map(
|
|
149027
|
+
(id) => Promise.resolve().then(() => this.deps.getCurrentSessionId(oid, id)).catch(() => null)
|
|
149028
|
+
)
|
|
149029
|
+
);
|
|
149030
|
+
const qualifying = [];
|
|
149031
|
+
for (let i = 0; i < titled.length; i++) {
|
|
149032
|
+
if (sids[i]) qualifying.push(titled[i]);
|
|
149033
|
+
}
|
|
149034
|
+
for (const id of qualifying) {
|
|
149035
|
+
void Promise.resolve().then(() => this.deps.warmAgentSession(oid, id)).catch((err) => {
|
|
149036
|
+
try {
|
|
149037
|
+
console.warn(
|
|
149038
|
+
`[AutoStartCoordinator] warmAgentSession failed for ${oid}/${id}:`,
|
|
149039
|
+
err
|
|
149040
|
+
);
|
|
149041
|
+
} catch {
|
|
149042
|
+
}
|
|
149043
|
+
});
|
|
149044
|
+
}
|
|
149045
|
+
return qualifying;
|
|
149046
|
+
}
|
|
149047
|
+
/** Rule #3 trigger. Returns the in-flight promise for an existing replace,
|
|
149048
|
+
* otherwise starts and tracks a new one. Setting OFF short-circuits to
|
|
149049
|
+
* just resetSession (acts like Close Session, per FR-017). */
|
|
149050
|
+
replaceSession(officeId, agentId) {
|
|
149051
|
+
const existing = this.replaceTracker.get(agentId);
|
|
149052
|
+
if (existing) return existing;
|
|
149053
|
+
const p = (async () => {
|
|
149054
|
+
await this.deps.resetSession(officeId, agentId);
|
|
149055
|
+
if (this.deps.getSettings().autoStartKnownAgents) {
|
|
149056
|
+
await this.deps.warmAgentSession(officeId, agentId);
|
|
149057
|
+
}
|
|
149058
|
+
})().finally(() => {
|
|
149059
|
+
this.replaceTracker.delete(agentId);
|
|
149060
|
+
});
|
|
149061
|
+
this.replaceTracker.set(agentId, p);
|
|
149062
|
+
return p;
|
|
149063
|
+
}
|
|
149064
|
+
};
|
|
149065
|
+
_instance = null;
|
|
149066
|
+
}
|
|
149067
|
+
});
|
|
149068
|
+
|
|
148572
149069
|
// src/ui/TerminalOverlay.ts
|
|
148573
149070
|
function withTimeout(promise, ms, label) {
|
|
148574
149071
|
let timeoutId = null;
|
|
@@ -148584,14 +149081,22 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148584
149081
|
});
|
|
148585
149082
|
});
|
|
148586
149083
|
}
|
|
148587
|
-
var import_xterm, import_addon_fit, IPC_TIMEOUT, TerminalOverlay;
|
|
149084
|
+
var import_xterm, import_addon_fit, IPC_TIMEOUT, DEBUG_COLD_START, DEBUG_SPRITE_SERIOUS, TerminalOverlay;
|
|
148588
149085
|
var init_TerminalOverlay = __esm({
|
|
148589
149086
|
"src/ui/TerminalOverlay.ts"() {
|
|
148590
149087
|
"use strict";
|
|
148591
149088
|
import_xterm = __toESM(require_xterm());
|
|
148592
149089
|
import_addon_fit = __toESM(require_addon_fit());
|
|
149090
|
+
init_agents();
|
|
149091
|
+
init_zIndex();
|
|
148593
149092
|
init_officeManager();
|
|
149093
|
+
init_clipboardToast();
|
|
149094
|
+
init_xtermStyles();
|
|
149095
|
+
init_terminalWheel();
|
|
149096
|
+
init_AutoStartCoordinator();
|
|
148594
149097
|
IPC_TIMEOUT = 1e4;
|
|
149098
|
+
DEBUG_COLD_START = typeof window !== "undefined" && window.__COPILOT_OFFICE_DEBUG_COLD_START__ === true || false;
|
|
149099
|
+
DEBUG_SPRITE_SERIOUS = false;
|
|
148595
149100
|
TerminalOverlay = class _TerminalOverlay {
|
|
148596
149101
|
constructor(scene, inputManager, getOfficeId) {
|
|
148597
149102
|
this.container = null;
|
|
@@ -148613,6 +149118,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148613
149118
|
this.mobileKeyboardBtn = null;
|
|
148614
149119
|
this.isFocused = false;
|
|
148615
149120
|
this.resizeHandler = null;
|
|
149121
|
+
this.clipboardHandler = null;
|
|
148616
149122
|
this.resizeObserver = null;
|
|
148617
149123
|
this.refitTimers = [];
|
|
148618
149124
|
this.refitGeneration = 0;
|
|
@@ -148621,11 +149127,18 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148621
149127
|
this.isReplaying = false;
|
|
148622
149128
|
this.launchMode = "copilot";
|
|
148623
149129
|
this.pendingInputLine = "";
|
|
148624
|
-
|
|
148625
|
-
|
|
148626
|
-
this.sessionRefreshExpiryTimer = null;
|
|
149130
|
+
// Spec 007: awaitingSessionIdRefresh / sessionRefresh*Timer fields removed
|
|
149131
|
+
// along with the parseSessionId / scheduleSessionIdRefresh helpers.
|
|
148627
149132
|
this.currentSessionTitle = null;
|
|
148628
149133
|
this.isEditingSessionTitle = false;
|
|
149134
|
+
this.terminalContextMenu = null;
|
|
149135
|
+
this.terminalContextMenuDismiss = null;
|
|
149136
|
+
// Disposable returned by xterm.terminal.onData(...). Re-registered per show()
|
|
149137
|
+
// so the handler's closure captures the new agent id (feature 002, C3/V6).
|
|
149138
|
+
this.onDataDisposable = null;
|
|
149139
|
+
// Toggled while show() is awaiting detach/attach so onData cannot fire input
|
|
149140
|
+
// against a half-attached agent (feature 002, V5).
|
|
149141
|
+
this.isSwitchingAgent = false;
|
|
148629
149142
|
this.scene = scene;
|
|
148630
149143
|
this.inputManager = inputManager;
|
|
148631
149144
|
this.getOfficeId = getOfficeId;
|
|
@@ -148645,7 +149158,6 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148645
149158
|
if (this.isReplaying) return;
|
|
148646
149159
|
if (agentId === this.currentAgentId && this.terminal) {
|
|
148647
149160
|
this.terminal.write(data);
|
|
148648
|
-
this.parseSessionId(data);
|
|
148649
149161
|
}
|
|
148650
149162
|
});
|
|
148651
149163
|
window.copilotBridge.onTerminalExit((agentId, exitCode) => {
|
|
@@ -148671,49 +149183,12 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148671
149183
|
this.setupTerminalListeners();
|
|
148672
149184
|
console.log("[TerminalOverlay] Re-attached terminal IPC listeners");
|
|
148673
149185
|
}
|
|
148674
|
-
|
|
148675
|
-
|
|
148676
|
-
|
|
148677
|
-
|
|
148678
|
-
|
|
148679
|
-
|
|
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
|
-
}
|
|
149186
|
+
// Spec 007: parseSessionId / scheduleSessionIdRefresh / awaitingSessionIdRefresh
|
|
149187
|
+
// were removed. They greedily matched any UUID-shaped substring in PTY data
|
|
149188
|
+
// (which could be a constant install/trace/OAuth UUID emitted by Copilot CLI
|
|
149189
|
+
// before the real session UUID), then persisted that wrong value as the
|
|
149190
|
+
// agent's session id. The server is now the only source of truth for session
|
|
149191
|
+
// ids — see `bridge.resetSession` in the /new path below.
|
|
148717
149192
|
getActiveOfficeId() {
|
|
148718
149193
|
return this.attachedOfficeId ?? this.getOfficeId();
|
|
148719
149194
|
}
|
|
@@ -148723,6 +149198,75 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148723
149198
|
}
|
|
148724
149199
|
this.refitTimers.length = 0;
|
|
148725
149200
|
}
|
|
149201
|
+
// Spec 006: diagnostic toast prefix so multi-instance and channel issues
|
|
149202
|
+
// are visible in the UI (no DevTools required).
|
|
149203
|
+
tag() {
|
|
149204
|
+
return `[O${this.instanceId}]`;
|
|
149205
|
+
}
|
|
149206
|
+
// Spec 005 + 006: write text to OS clipboard via Electron main process.
|
|
149207
|
+
// Diagnostic toast on every outcome so we never have to guess again.
|
|
149208
|
+
async copyToClipboard(text, source = "live") {
|
|
149209
|
+
const t = this.tag();
|
|
149210
|
+
if (!text) {
|
|
149211
|
+
showClipboardToast(`${t} empty selection`, "info");
|
|
149212
|
+
return false;
|
|
149213
|
+
}
|
|
149214
|
+
const bridge = window.copilotBridge;
|
|
149215
|
+
if (!bridge?.clipboardWriteText) {
|
|
149216
|
+
try {
|
|
149217
|
+
await navigator.clipboard.writeText(text);
|
|
149218
|
+
showClipboardToast(`${t} OK ${text.length} (fallback)`, "success");
|
|
149219
|
+
return true;
|
|
149220
|
+
} catch {
|
|
149221
|
+
showClipboardToast(`${t} no-bridge`, "error");
|
|
149222
|
+
return false;
|
|
149223
|
+
}
|
|
149224
|
+
}
|
|
149225
|
+
try {
|
|
149226
|
+
const r = await bridge.clipboardWriteText(text);
|
|
149227
|
+
if (r?.success === true) {
|
|
149228
|
+
showClipboardToast(`${t} OK ${text.length} (verified)`, "success");
|
|
149229
|
+
return true;
|
|
149230
|
+
}
|
|
149231
|
+
if (r?.verified === false) {
|
|
149232
|
+
showClipboardToast(`${t} verify-fail (wrote=${text.length})`, "error");
|
|
149233
|
+
} else {
|
|
149234
|
+
showClipboardToast(`${t} bridge-err: ${r?.error || "unknown"}`, "error");
|
|
149235
|
+
}
|
|
149236
|
+
return false;
|
|
149237
|
+
} catch (e) {
|
|
149238
|
+
showClipboardToast(`${t} bridge-err: ${e?.message || "threw"}`, "error");
|
|
149239
|
+
return false;
|
|
149240
|
+
}
|
|
149241
|
+
}
|
|
149242
|
+
// Spec 005: read OS clipboard via Electron main, forward to PTY.
|
|
149243
|
+
async pasteFromClipboardToTerminal() {
|
|
149244
|
+
if (!this.currentAgentId || !window.copilotBridge) return;
|
|
149245
|
+
let text = "";
|
|
149246
|
+
try {
|
|
149247
|
+
const bridge = window.copilotBridge;
|
|
149248
|
+
if (bridge?.clipboardReadText) {
|
|
149249
|
+
const r = await bridge.clipboardReadText();
|
|
149250
|
+
if (r?.success) text = r.text || "";
|
|
149251
|
+
} else if (navigator.clipboard?.readText) {
|
|
149252
|
+
text = await navigator.clipboard.readText();
|
|
149253
|
+
}
|
|
149254
|
+
} catch (e) {
|
|
149255
|
+
showClipboardToast(`Paste failed: ${e?.message || "bridge threw"}`, "error");
|
|
149256
|
+
return;
|
|
149257
|
+
}
|
|
149258
|
+
if (!text) {
|
|
149259
|
+
showClipboardToast("Clipboard is empty", "info");
|
|
149260
|
+
return;
|
|
149261
|
+
}
|
|
149262
|
+
const officeId = this.attachedOfficeId ?? this.getOfficeId();
|
|
149263
|
+
try {
|
|
149264
|
+
await window.copilotBridge.terminalWrite(officeId, this.currentAgentId, text);
|
|
149265
|
+
showClipboardToast(`Pasted ${text.length} char${text.length === 1 ? "" : "s"}`, "success");
|
|
149266
|
+
} catch (e) {
|
|
149267
|
+
showClipboardToast(`Paste failed: ${e?.message || "terminalWrite threw"}`, "error");
|
|
149268
|
+
}
|
|
149269
|
+
}
|
|
148726
149270
|
resolveTerminalDimensions() {
|
|
148727
149271
|
if (!this.terminal || !this.fitAddon) return null;
|
|
148728
149272
|
this.fitAddon.fit();
|
|
@@ -148849,20 +149393,42 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148849
149393
|
async show(agent, onClose, options) {
|
|
148850
149394
|
const previousAgentId = this.currentAgentId;
|
|
148851
149395
|
const previousOfficeId = this.attachedOfficeId ?? this.getOfficeId();
|
|
149396
|
+
const nextOfficeId = this.getOfficeId();
|
|
149397
|
+
const isSwitchingAgent = previousAgentId !== null && (previousAgentId !== agent.id || previousOfficeId !== nextOfficeId);
|
|
148852
149398
|
if (previousAgentId && previousAgentId !== agent.id) {
|
|
148853
149399
|
this.acknowledgeCompletedWork(previousOfficeId, previousAgentId);
|
|
148854
149400
|
}
|
|
149401
|
+
if (isSwitchingAgent && previousAgentId && window.copilotBridge) {
|
|
149402
|
+
this.isSwitchingAgent = true;
|
|
149403
|
+
this.onDataDisposable?.dispose();
|
|
149404
|
+
this.onDataDisposable = null;
|
|
149405
|
+
try {
|
|
149406
|
+
const detachStartedAt = Date.now();
|
|
149407
|
+
await withTimeout(
|
|
149408
|
+
window.copilotBridge.terminalDetach(previousOfficeId, previousAgentId),
|
|
149409
|
+
IPC_TIMEOUT,
|
|
149410
|
+
"terminalDetach"
|
|
149411
|
+
);
|
|
149412
|
+
if (DEBUG_COLD_START) {
|
|
149413
|
+
console.log(
|
|
149414
|
+
`[TerminalOverlay] switch from=${previousAgentId} to=${agent.id} detachMs=${Date.now() - detachStartedAt}`
|
|
149415
|
+
);
|
|
149416
|
+
}
|
|
149417
|
+
} catch (e) {
|
|
149418
|
+
console.warn(`[TerminalOverlay] terminalDetach failed for ${previousAgentId}: ${String(e)}`);
|
|
149419
|
+
}
|
|
149420
|
+
}
|
|
148855
149421
|
this.currentAgentId = agent.id;
|
|
148856
149422
|
this.onCloseCallback = onClose;
|
|
148857
149423
|
this.isReadOnly = options?.readOnly ?? false;
|
|
148858
149424
|
this.launchMode = options?.launchMode ?? "copilot";
|
|
148859
|
-
this.attachedOfficeId =
|
|
149425
|
+
this.attachedOfficeId = nextOfficeId;
|
|
148860
149426
|
const officeId = this.getActiveOfficeId();
|
|
148861
149427
|
this.currentAgent = agent;
|
|
148862
149428
|
if (!this.container) {
|
|
148863
149429
|
this.createContainer();
|
|
148864
149430
|
}
|
|
148865
|
-
const inceptionBadge = agent.id ===
|
|
149431
|
+
const inceptionBadge = agent.id === ADMIN_AGENT_ID ? " \u{1F3AD} INCEPTION MODE" : "";
|
|
148866
149432
|
let sessionTitle = null;
|
|
148867
149433
|
if (window.copilotBridge?.getSessionMeta) {
|
|
148868
149434
|
try {
|
|
@@ -148899,8 +149465,6 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148899
149465
|
if (this.container) {
|
|
148900
149466
|
this.container.style.display = "flex";
|
|
148901
149467
|
}
|
|
148902
|
-
this.awaitingSessionIdRefresh = false;
|
|
148903
|
-
this.clearSessionRefreshTimers();
|
|
148904
149468
|
if (this.spriteCardElement) {
|
|
148905
149469
|
this.spriteCardElement.style.display = "flex";
|
|
148906
149470
|
}
|
|
@@ -148921,8 +149485,6 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148921
149485
|
this.updateSessionTitleDisplay(sessionTitle);
|
|
148922
149486
|
this.drawAgentSprite(agent);
|
|
148923
149487
|
this.pendingInputLine = "";
|
|
148924
|
-
this.awaitingSessionIdRefresh = false;
|
|
148925
|
-
this.clearSessionRefreshTimers();
|
|
148926
149488
|
this.clearRefitTimers();
|
|
148927
149489
|
this.refitGeneration += 1;
|
|
148928
149490
|
if (!this.terminal) {
|
|
@@ -148980,6 +149542,14 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
148980
149542
|
}
|
|
148981
149543
|
}
|
|
148982
149544
|
this.isVisible = true;
|
|
149545
|
+
const attachStartedAt = Date.now();
|
|
149546
|
+
this.isSwitchingAgent = false;
|
|
149547
|
+
this.registerOnDataHandler(agent.id, officeId);
|
|
149548
|
+
if (DEBUG_COLD_START && isSwitchingAgent) {
|
|
149549
|
+
console.log(
|
|
149550
|
+
`[TerminalOverlay] switch attach complete to=${agent.id} attachMs=${Date.now() - attachStartedAt}`
|
|
149551
|
+
);
|
|
149552
|
+
}
|
|
148983
149553
|
this.scene.game.events.emit("npc:highlight", agent.id);
|
|
148984
149554
|
const spriteCanvas = this.spriteCardElement?.querySelector(".agent-sprite-canvas");
|
|
148985
149555
|
if (spriteCanvas) {
|
|
@@ -149006,8 +149576,6 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149006
149576
|
}, 50);
|
|
149007
149577
|
}
|
|
149008
149578
|
async startNewSession(agentId, workingDir, officeId) {
|
|
149009
|
-
this.awaitingSessionIdRefresh = false;
|
|
149010
|
-
this.clearSessionRefreshTimers();
|
|
149011
149579
|
this.sessionId = null;
|
|
149012
149580
|
this.updateSessionDisplay();
|
|
149013
149581
|
const el = this.spriteCardElement?.querySelector(".session-id-display");
|
|
@@ -149042,8 +149610,19 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149042
149610
|
this.updateSessionDisplay();
|
|
149043
149611
|
}
|
|
149044
149612
|
}
|
|
149045
|
-
|
|
149046
|
-
|
|
149613
|
+
// Spec 007: after the user types /new in the PTY, ask the server to mint
|
|
149614
|
+
// a fresh per-agent session UUID. Authoritative — never parses CLI output.
|
|
149615
|
+
async fetchSessionId(agentId) {
|
|
149616
|
+
if (!window.copilotBridge) return;
|
|
149617
|
+
const officeId = this.getActiveOfficeId();
|
|
149618
|
+
try {
|
|
149619
|
+
const r = await window.copilotBridge.resetSession(officeId, agentId);
|
|
149620
|
+
if (r?.success && r.sessionId && agentId === this.currentAgentId) {
|
|
149621
|
+
this.sessionId = r.sessionId;
|
|
149622
|
+
this.updateSessionDisplay();
|
|
149623
|
+
}
|
|
149624
|
+
} catch {
|
|
149625
|
+
}
|
|
149047
149626
|
}
|
|
149048
149627
|
createContainer() {
|
|
149049
149628
|
this.container = document.createElement("div");
|
|
@@ -149059,7 +149638,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149059
149638
|
border-radius: 0;
|
|
149060
149639
|
display: none;
|
|
149061
149640
|
flex-direction: column;
|
|
149062
|
-
z-index:
|
|
149641
|
+
z-index: ${ZIndex.TERMINAL_OVERLAY};
|
|
149063
149642
|
`;
|
|
149064
149643
|
this.headerElement = document.createElement("div");
|
|
149065
149644
|
this.headerElement.style.cssText = `
|
|
@@ -149080,7 +149659,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149080
149659
|
terminalOuter.id = "terminal-container";
|
|
149081
149660
|
terminalOuter.style.cssText = `
|
|
149082
149661
|
flex: 1;
|
|
149083
|
-
overflow:
|
|
149662
|
+
overflow: auto;
|
|
149084
149663
|
min-height: 0;
|
|
149085
149664
|
padding: 10px;
|
|
149086
149665
|
box-sizing: border-box;
|
|
@@ -149089,13 +149668,18 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149089
149668
|
this.terminalDiv.style.cssText = `
|
|
149090
149669
|
width: 100%;
|
|
149091
149670
|
height: 100%;
|
|
149092
|
-
overflow: hidden;
|
|
149093
149671
|
`;
|
|
149094
149672
|
terminalOuter.appendChild(this.terminalDiv);
|
|
149095
149673
|
terminalOuter.addEventListener("mousedown", () => {
|
|
149096
149674
|
if (this.isVisible && !this.isFocused) {
|
|
149097
149675
|
this.focusTerminal();
|
|
149098
149676
|
}
|
|
149677
|
+
this.terminal?.focus();
|
|
149678
|
+
});
|
|
149679
|
+
terminalOuter.addEventListener("mouseup", () => {
|
|
149680
|
+
if (this.isVisible) {
|
|
149681
|
+
requestAnimationFrame(() => this.terminal?.focus());
|
|
149682
|
+
}
|
|
149099
149683
|
});
|
|
149100
149684
|
this.container.appendChild(terminalOuter);
|
|
149101
149685
|
const terminalPanel = document.getElementById("terminal-panel") || document.body;
|
|
@@ -149114,6 +149698,16 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149114
149698
|
}
|
|
149115
149699
|
/** Create the SpriteCard — a full-width bottom bar showing agent sprite, info, and controls. */
|
|
149116
149700
|
createSpriteCard() {
|
|
149701
|
+
const stale = document.getElementById("sprite-card");
|
|
149702
|
+
if (stale) {
|
|
149703
|
+
try {
|
|
149704
|
+
stale.remove();
|
|
149705
|
+
} catch {
|
|
149706
|
+
}
|
|
149707
|
+
if (DEBUG_SPRITE_SERIOUS) {
|
|
149708
|
+
console.log("[TerminalOverlay] createSpriteCard removed stale #sprite-card before append");
|
|
149709
|
+
}
|
|
149710
|
+
}
|
|
149117
149711
|
this.spriteCardElement = document.createElement("div");
|
|
149118
149712
|
this.spriteCardElement.id = "sprite-card";
|
|
149119
149713
|
this.spriteCardElement.style.cssText = `
|
|
@@ -149130,7 +149724,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149130
149724
|
padding: 16px 24px;
|
|
149131
149725
|
box-sizing: border-box;
|
|
149132
149726
|
position: relative;
|
|
149133
|
-
z-index:
|
|
149727
|
+
z-index: ${ZIndex.TERMINAL_SPRITE_CARD};
|
|
149134
149728
|
`;
|
|
149135
149729
|
const agentDisplay = document.createElement("div");
|
|
149136
149730
|
agentDisplay.className = "agent-display";
|
|
@@ -149277,49 +149871,65 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149277
149871
|
this.footerElement = this.spriteCardElement;
|
|
149278
149872
|
}
|
|
149279
149873
|
copySessionId() {
|
|
149280
|
-
if (this.sessionId)
|
|
149281
|
-
|
|
149874
|
+
if (!this.sessionId) return;
|
|
149875
|
+
void this.copyToClipboard(this.sessionId, "session").then((success) => {
|
|
149876
|
+
if (!this.sessionIdElement) return;
|
|
149877
|
+
const original = this.sessionIdElement.textContent;
|
|
149878
|
+
this.sessionIdElement.textContent = success ? "Copied!" : "Copy failed";
|
|
149879
|
+
this.sessionIdElement.style.color = success ? "#50fa7b" : "#ff6b6b";
|
|
149880
|
+
setTimeout(() => {
|
|
149282
149881
|
if (this.sessionIdElement) {
|
|
149283
|
-
|
|
149284
|
-
this.sessionIdElement.
|
|
149285
|
-
this.sessionIdElement.style.color = "#50fa7b";
|
|
149286
|
-
setTimeout(() => {
|
|
149287
|
-
if (this.sessionIdElement) {
|
|
149288
|
-
this.sessionIdElement.textContent = original;
|
|
149289
|
-
this.sessionIdElement.style.color = "#4a9eff";
|
|
149290
|
-
}
|
|
149291
|
-
}, 1e3);
|
|
149882
|
+
this.sessionIdElement.textContent = original;
|
|
149883
|
+
this.sessionIdElement.style.color = "#4a9eff";
|
|
149292
149884
|
}
|
|
149293
|
-
});
|
|
149294
|
-
}
|
|
149885
|
+
}, 1e3);
|
|
149886
|
+
});
|
|
149295
149887
|
}
|
|
149296
149888
|
async handleNewSession() {
|
|
149297
149889
|
if (!this.currentAgentId || !this.currentAgent || this.isReadOnly) return;
|
|
149298
|
-
this.awaitingSessionIdRefresh = false;
|
|
149299
|
-
this.clearSessionRefreshTimers();
|
|
149300
149890
|
const officeId = this.attachedOfficeId ?? this.getOfficeId();
|
|
149301
|
-
|
|
149891
|
+
const agentId = this.currentAgentId;
|
|
149892
|
+
console.log(`[TerminalOverlay] handleNewSession: agent=${agentId}, office=${officeId}`);
|
|
149302
149893
|
this.clearRefitTimers();
|
|
149303
149894
|
this.refitGeneration += 1;
|
|
149304
149895
|
this.pendingInputLine = "";
|
|
149305
149896
|
this.terminal?.clear();
|
|
149306
149897
|
this.terminal?.writeln("\x1B[33m[Starting new session...]\x1B[0m\r\n");
|
|
149307
|
-
await withTimeout(
|
|
149308
|
-
window.copilotBridge.resetSession(officeId, this.currentAgentId),
|
|
149309
|
-
IPC_TIMEOUT,
|
|
149310
|
-
"resetSession"
|
|
149311
|
-
).catch(() => {
|
|
149312
|
-
});
|
|
149313
149898
|
const el = this.spriteCardElement?.querySelector(".session-id-display");
|
|
149314
149899
|
if (el) el.textContent = "starting...";
|
|
149315
149900
|
this.sessionId = null;
|
|
149316
149901
|
this.updateSessionDisplay();
|
|
149317
149902
|
this.updateSessionTitleDisplay(null);
|
|
149318
|
-
const
|
|
149903
|
+
const coordinator = getAutoStartCoordinator();
|
|
149904
|
+
if (coordinator) {
|
|
149905
|
+
try {
|
|
149906
|
+
await coordinator.replaceSession(officeId, agentId);
|
|
149907
|
+
} catch (err) {
|
|
149908
|
+
this.terminal?.writeln(`Failed to start terminal: ${err?.message || String(err)}`);
|
|
149909
|
+
}
|
|
149910
|
+
try {
|
|
149911
|
+
if (window.copilotBridge?.getSessionId) {
|
|
149912
|
+
const sid = await window.copilotBridge.getSessionId(officeId, agentId);
|
|
149913
|
+
if (sid) {
|
|
149914
|
+
this.sessionId = sid;
|
|
149915
|
+
this.updateSessionDisplay();
|
|
149916
|
+
}
|
|
149917
|
+
}
|
|
149918
|
+
} catch {
|
|
149919
|
+
}
|
|
149920
|
+
return;
|
|
149921
|
+
}
|
|
149922
|
+
await withTimeout(
|
|
149923
|
+
window.copilotBridge.resetSession(officeId, agentId),
|
|
149924
|
+
IPC_TIMEOUT,
|
|
149925
|
+
"resetSession"
|
|
149926
|
+
).catch(() => {
|
|
149927
|
+
});
|
|
149928
|
+
const dims = this.fitAndResizeTerminal({ officeId, agentId });
|
|
149319
149929
|
const result = await withTimeout(
|
|
149320
149930
|
this.launchMode === "shell" ? window.copilotBridge.terminalStart(
|
|
149321
149931
|
officeId,
|
|
149322
|
-
|
|
149932
|
+
agentId,
|
|
149323
149933
|
this.currentAgent.workingDir || officeManager.getCurrentWorkingDirectory(),
|
|
149324
149934
|
dims?.cols,
|
|
149325
149935
|
dims?.rows,
|
|
@@ -149327,7 +149937,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149327
149937
|
"shell"
|
|
149328
149938
|
) : window.copilotBridge.terminalStart(
|
|
149329
149939
|
officeId,
|
|
149330
|
-
|
|
149940
|
+
agentId,
|
|
149331
149941
|
this.currentAgent.workingDir || officeManager.getCurrentWorkingDirectory(),
|
|
149332
149942
|
dims?.cols,
|
|
149333
149943
|
dims?.rows
|
|
@@ -149390,7 +150000,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149390
150000
|
min-width: 320px;
|
|
149391
150001
|
max-height: 250px;
|
|
149392
150002
|
overflow-y: auto;
|
|
149393
|
-
z-index:
|
|
150003
|
+
z-index: ${ZIndex.TERMINAL_SPRITE_CARD};
|
|
149394
150004
|
font-family: 'Cascadia Code', Consolas, monospace;
|
|
149395
150005
|
font-size: 12px;
|
|
149396
150006
|
box-shadow: 0 -4px 12px rgba(0,0,0,0.5);
|
|
@@ -149448,21 +150058,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149448
150058
|
this.closeHistoryPopover();
|
|
149449
150059
|
}
|
|
149450
150060
|
injectStyles() {
|
|
149451
|
-
|
|
149452
|
-
const style = document.createElement("style");
|
|
149453
|
-
style.id = "xterm-styles";
|
|
149454
|
-
style.textContent = `
|
|
149455
|
-
.xterm {
|
|
149456
|
-
height: 100%;
|
|
149457
|
-
}
|
|
149458
|
-
.xterm-viewport {
|
|
149459
|
-
background-color: #0a0a14 !important;
|
|
149460
|
-
}
|
|
149461
|
-
#terminal-container .xterm {
|
|
149462
|
-
height: 100%;
|
|
149463
|
-
}
|
|
149464
|
-
`;
|
|
149465
|
-
document.head.appendChild(style);
|
|
150061
|
+
ensureXtermStyles();
|
|
149466
150062
|
}
|
|
149467
150063
|
createTerminal() {
|
|
149468
150064
|
if (!this.terminalDiv) return;
|
|
@@ -149502,38 +150098,109 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149502
150098
|
this.terminal.loadAddon(this.fitAddon);
|
|
149503
150099
|
this.terminal.open(this.terminalDiv);
|
|
149504
150100
|
this.fitAndResizeTerminal();
|
|
150101
|
+
const MOUSE_MODES = /* @__PURE__ */ new Set([1e3, 1002, 1003, 1006]);
|
|
150102
|
+
this.terminal.parser.registerCsiHandler({ prefix: "?", final: "h" }, (params) => {
|
|
150103
|
+
for (const p of params) {
|
|
150104
|
+
if (typeof p === "number" && MOUSE_MODES.has(p)) return true;
|
|
150105
|
+
}
|
|
150106
|
+
return false;
|
|
150107
|
+
});
|
|
150108
|
+
this.terminal.attachCustomWheelEventHandler((event) => {
|
|
150109
|
+
const term = this.terminal;
|
|
150110
|
+
if (!term) return true;
|
|
150111
|
+
if (term.buffer.active.type !== "alternate") return true;
|
|
150112
|
+
const seq = wheelToPtySequence(event.deltaY);
|
|
150113
|
+
if (!seq) return true;
|
|
150114
|
+
const officeId = this.attachedOfficeId ?? this.getOfficeId();
|
|
150115
|
+
if (officeId && this.currentAgentId && window.copilotBridge) {
|
|
150116
|
+
void window.copilotBridge.terminalWrite(officeId, this.currentAgentId, seq);
|
|
150117
|
+
}
|
|
150118
|
+
return false;
|
|
150119
|
+
});
|
|
150120
|
+
this.installTerminalContextMenu();
|
|
149505
150121
|
this.terminal.attachCustomKeyEventHandler((event) => {
|
|
149506
150122
|
const isModifierPressed = event.ctrlKey || event.metaKey;
|
|
149507
150123
|
const key = event.key.toLowerCase();
|
|
149508
150124
|
if (event.type !== "keydown" || !isModifierPressed) return true;
|
|
149509
150125
|
if (key === "c") {
|
|
149510
|
-
const
|
|
149511
|
-
if (!
|
|
150126
|
+
const selection = this.terminal?.hasSelection() ? this.terminal.getSelection() ?? "" : "";
|
|
150127
|
+
if (!selection) {
|
|
149512
150128
|
return true;
|
|
149513
150129
|
}
|
|
149514
150130
|
event.preventDefault();
|
|
149515
150131
|
event.stopPropagation();
|
|
149516
|
-
|
|
149517
|
-
console.warn("[Terminal] Clipboard write failed:", err);
|
|
149518
|
-
});
|
|
150132
|
+
void this.copyToClipboard(selection, "live");
|
|
149519
150133
|
return false;
|
|
149520
150134
|
}
|
|
149521
150135
|
if (key === "v") {
|
|
149522
150136
|
if (this.isReadOnly) return false;
|
|
149523
150137
|
event.preventDefault();
|
|
149524
150138
|
event.stopPropagation();
|
|
149525
|
-
|
|
149526
|
-
if (text) this.terminal.paste(text);
|
|
149527
|
-
}).catch((err) => {
|
|
149528
|
-
console.warn("[Terminal] Clipboard read failed:", err);
|
|
149529
|
-
});
|
|
150139
|
+
void this.pasteFromClipboardToTerminal();
|
|
149530
150140
|
return false;
|
|
149531
150141
|
}
|
|
149532
150142
|
return true;
|
|
149533
150143
|
});
|
|
149534
|
-
this.
|
|
150144
|
+
if (this.clipboardHandler) {
|
|
150145
|
+
document.removeEventListener("keydown", this.clipboardHandler, true);
|
|
150146
|
+
}
|
|
150147
|
+
this.clipboardHandler = (event) => {
|
|
150148
|
+
if (!this.isVisible) return;
|
|
150149
|
+
if (this.isEditingSessionTitle) return;
|
|
150150
|
+
const active = document.activeElement;
|
|
150151
|
+
if (active && (active.tagName === "INPUT" || active.tagName === "TEXTAREA") && active !== this.terminal?.textarea) {
|
|
150152
|
+
return;
|
|
150153
|
+
}
|
|
150154
|
+
const isModifierPressed = event.ctrlKey || event.metaKey;
|
|
150155
|
+
if (!isModifierPressed || event.type !== "keydown") return;
|
|
150156
|
+
const key = event.key.toLowerCase();
|
|
150157
|
+
if (key === "c") {
|
|
150158
|
+
const selection = this.terminal?.hasSelection() ? this.terminal.getSelection() ?? "" : "";
|
|
150159
|
+
if (!selection) return;
|
|
150160
|
+
event.preventDefault();
|
|
150161
|
+
event.stopImmediatePropagation();
|
|
150162
|
+
void this.copyToClipboard(selection, "live");
|
|
150163
|
+
} else if (key === "v") {
|
|
150164
|
+
if (this.isReadOnly) return;
|
|
150165
|
+
event.preventDefault();
|
|
150166
|
+
event.stopImmediatePropagation();
|
|
150167
|
+
void this.pasteFromClipboardToTerminal();
|
|
150168
|
+
}
|
|
150169
|
+
};
|
|
150170
|
+
document.addEventListener("keydown", this.clipboardHandler, true);
|
|
150171
|
+
this.resizeHandler = () => {
|
|
150172
|
+
if (this.isVisible) {
|
|
150173
|
+
this.applySpriteCardResponsiveStyles();
|
|
150174
|
+
this.updateMobileKeyboardButtonVisibility();
|
|
150175
|
+
this.debouncedRefit();
|
|
150176
|
+
}
|
|
150177
|
+
};
|
|
150178
|
+
window.addEventListener("resize", this.resizeHandler);
|
|
150179
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
150180
|
+
if (this.isVisible) {
|
|
150181
|
+
this.applySpriteCardResponsiveStyles();
|
|
150182
|
+
this.updateMobileKeyboardButtonVisibility();
|
|
150183
|
+
this.debouncedRefit();
|
|
150184
|
+
}
|
|
150185
|
+
});
|
|
150186
|
+
if (this.terminalDiv) {
|
|
150187
|
+
this.resizeObserver.observe(this.terminalDiv);
|
|
150188
|
+
}
|
|
150189
|
+
}
|
|
150190
|
+
/**
|
|
150191
|
+
* Re-register the xterm `onData` handler with a fresh closure that captures
|
|
150192
|
+
* the bound `agentId` and `officeId` at registration time. Disposes any
|
|
150193
|
+
* previous registration so stale closures cannot send user keystrokes to
|
|
150194
|
+
* the wrong agent during an agent switch (feature 002, C3/V6).
|
|
150195
|
+
*/
|
|
150196
|
+
registerOnDataHandler(boundAgentId, boundOfficeId) {
|
|
150197
|
+
if (!this.terminal) return;
|
|
150198
|
+
this.onDataDisposable?.dispose();
|
|
150199
|
+
this.onDataDisposable = null;
|
|
150200
|
+
const result = this.terminal.onData((data) => {
|
|
149535
150201
|
if (this.isReadOnly) return;
|
|
149536
|
-
if (
|
|
150202
|
+
if (this.isSwitchingAgent) return;
|
|
150203
|
+
if (!window.copilotBridge) return;
|
|
149537
150204
|
let outbound = "";
|
|
149538
150205
|
let shouldStartSlashNewSession = false;
|
|
149539
150206
|
for (const ch of data) {
|
|
@@ -149557,30 +150224,98 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149557
150224
|
outbound += ch;
|
|
149558
150225
|
}
|
|
149559
150226
|
if (outbound.length > 0) {
|
|
149560
|
-
window.copilotBridge.terminalWrite(
|
|
150227
|
+
window.copilotBridge.terminalWrite(boundOfficeId, boundAgentId, outbound);
|
|
149561
150228
|
}
|
|
149562
150229
|
if (shouldStartSlashNewSession) {
|
|
149563
|
-
this.fetchSessionId(
|
|
150230
|
+
this.fetchSessionId(boundAgentId);
|
|
149564
150231
|
}
|
|
149565
150232
|
});
|
|
149566
|
-
this.
|
|
149567
|
-
|
|
149568
|
-
|
|
149569
|
-
|
|
149570
|
-
|
|
149571
|
-
|
|
150233
|
+
this.onDataDisposable = result && typeof result.dispose === "function" ? result : null;
|
|
150234
|
+
}
|
|
150235
|
+
/**
|
|
150236
|
+
* Spec 004: terminal right-click context menu with Copy (enabled iff
|
|
150237
|
+
* non-empty selection) and Paste (always enabled). Built once, reused
|
|
150238
|
+
* across selections; dismissed on any outside mousedown or Escape.
|
|
150239
|
+
*/
|
|
150240
|
+
installTerminalContextMenu() {
|
|
150241
|
+
if (!this.terminal || !this.terminalDiv) return;
|
|
150242
|
+
const menu = document.createElement("div");
|
|
150243
|
+
menu.id = "terminal-context-menu";
|
|
150244
|
+
menu.style.cssText = `
|
|
150245
|
+
position: fixed;
|
|
150246
|
+
display: none;
|
|
150247
|
+
z-index: ${ZIndex.TERMINAL_SPRITE_CARD + 10};
|
|
150248
|
+
min-width: 160px;
|
|
150249
|
+
background: #1c1c2a;
|
|
150250
|
+
border: 1px solid #3a3a55;
|
|
150251
|
+
border-radius: 6px;
|
|
150252
|
+
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.55);
|
|
150253
|
+
padding: 4px 0;
|
|
150254
|
+
font-family: 'Cascadia Code', Consolas, monospace;
|
|
150255
|
+
font-size: 13px;
|
|
150256
|
+
color: #cfd0e0;
|
|
150257
|
+
user-select: none;
|
|
150258
|
+
`;
|
|
150259
|
+
const makeItem = (label, onClick) => {
|
|
150260
|
+
const item = document.createElement("div");
|
|
150261
|
+
item.textContent = label;
|
|
150262
|
+
item.style.cssText = `
|
|
150263
|
+
padding: 6px 14px;
|
|
150264
|
+
cursor: pointer;
|
|
150265
|
+
`;
|
|
150266
|
+
item.dataset.enabled = "true";
|
|
150267
|
+
item.addEventListener("mouseenter", () => {
|
|
150268
|
+
if (item.dataset.enabled === "true") item.style.background = "#2a2a45";
|
|
150269
|
+
});
|
|
150270
|
+
item.addEventListener("mouseleave", () => {
|
|
150271
|
+
item.style.background = "";
|
|
150272
|
+
});
|
|
150273
|
+
item.addEventListener("mousedown", (e) => {
|
|
150274
|
+
e.preventDefault();
|
|
150275
|
+
e.stopPropagation();
|
|
150276
|
+
});
|
|
150277
|
+
item.addEventListener("click", (e) => {
|
|
150278
|
+
e.preventDefault();
|
|
150279
|
+
e.stopPropagation();
|
|
150280
|
+
if (item.dataset.enabled !== "true") return;
|
|
150281
|
+
this.hideTerminalContextMenu();
|
|
150282
|
+
onClick();
|
|
150283
|
+
});
|
|
150284
|
+
return item;
|
|
149572
150285
|
};
|
|
149573
|
-
|
|
149574
|
-
|
|
149575
|
-
|
|
149576
|
-
this.applySpriteCardResponsiveStyles();
|
|
149577
|
-
this.updateMobileKeyboardButtonVisibility();
|
|
149578
|
-
this.debouncedRefit();
|
|
149579
|
-
}
|
|
150286
|
+
const copyItem = makeItem("Copy", () => {
|
|
150287
|
+
const selection = this.terminal?.hasSelection() ? this.terminal.getSelection() ?? "" : "";
|
|
150288
|
+
void this.copyToClipboard(selection, "live");
|
|
149580
150289
|
});
|
|
149581
|
-
|
|
149582
|
-
this.
|
|
149583
|
-
}
|
|
150290
|
+
const pasteItem = makeItem("Paste", () => {
|
|
150291
|
+
void this.pasteFromClipboardToTerminal();
|
|
150292
|
+
});
|
|
150293
|
+
menu.appendChild(copyItem);
|
|
150294
|
+
menu.appendChild(pasteItem);
|
|
150295
|
+
document.body.appendChild(menu);
|
|
150296
|
+
this.terminalContextMenu = menu;
|
|
150297
|
+
this.terminalDiv.addEventListener("contextmenu", (event) => {
|
|
150298
|
+
if (!this.isVisible) return;
|
|
150299
|
+
event.preventDefault();
|
|
150300
|
+
const vw = window.innerWidth;
|
|
150301
|
+
const vh = window.innerHeight;
|
|
150302
|
+
menu.style.display = "block";
|
|
150303
|
+
const rect = menu.getBoundingClientRect();
|
|
150304
|
+
const left = Math.min(event.clientX, vw - rect.width - 4);
|
|
150305
|
+
const top = Math.min(event.clientY, vh - rect.height - 4);
|
|
150306
|
+
menu.style.left = `${Math.max(0, left)}px`;
|
|
150307
|
+
menu.style.top = `${Math.max(0, top)}px`;
|
|
150308
|
+
});
|
|
150309
|
+
this.terminalContextMenuDismiss = (e) => {
|
|
150310
|
+
if (!this.terminalContextMenu || this.terminalContextMenu.style.display === "none") return;
|
|
150311
|
+
if (e instanceof KeyboardEvent && e.key !== "Escape") return;
|
|
150312
|
+
this.hideTerminalContextMenu();
|
|
150313
|
+
};
|
|
150314
|
+
document.addEventListener("mousedown", this.terminalContextMenuDismiss, true);
|
|
150315
|
+
document.addEventListener("keydown", this.terminalContextMenuDismiss, true);
|
|
150316
|
+
}
|
|
150317
|
+
hideTerminalContextMenu() {
|
|
150318
|
+
if (this.terminalContextMenu) this.terminalContextMenu.style.display = "none";
|
|
149584
150319
|
}
|
|
149585
150320
|
/** Toggle between half-width and full-width terminal panel. */
|
|
149586
150321
|
toggleFullWidth() {
|
|
@@ -149681,15 +150416,12 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149681
150416
|
}
|
|
149682
150417
|
/** Give keyboard focus to the terminal. Safe to call when already focused. */
|
|
149683
150418
|
focusTerminal() {
|
|
149684
|
-
console.log("[TerminalOverlay] focusTerminal() \u2014 delegating to InputManager");
|
|
149685
150419
|
this.inputManager.switchToTerminal(
|
|
149686
150420
|
"TerminalOverlay.focusTerminal()",
|
|
149687
150421
|
() => this.handleNewSession(),
|
|
149688
150422
|
() => this.toggleFullWidth()
|
|
149689
150423
|
);
|
|
149690
|
-
|
|
149691
|
-
this.terminal?.focus();
|
|
149692
|
-
}
|
|
150424
|
+
this.terminal?.focus();
|
|
149693
150425
|
this.inputManager.focusTerminalXterm(this.terminal);
|
|
149694
150426
|
if (this.currentAgent) {
|
|
149695
150427
|
this.scene.game.events.emit("npc:highlight", this.currentAgent.id);
|
|
@@ -149704,7 +150436,6 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149704
150436
|
}
|
|
149705
150437
|
/** Give keyboard focus back to the game canvas. Safe to call when already blurred. */
|
|
149706
150438
|
blurTerminal() {
|
|
149707
|
-
console.log("[TerminalOverlay] blurTerminal() \u2014 delegating to InputManager");
|
|
149708
150439
|
const mobileLocked = window.__copilotOfficeMobileModeActive?.() === true;
|
|
149709
150440
|
if (mobileLocked) {
|
|
149710
150441
|
this.inputManager.switchToNone("TerminalOverlay.blurTerminal() mobile lock");
|
|
@@ -149734,7 +150465,12 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149734
150465
|
}
|
|
149735
150466
|
setupKeyboardHandler() {
|
|
149736
150467
|
}
|
|
150468
|
+
// Spec 008-smoke: expose state for the e2e debug hook.
|
|
150469
|
+
getActiveAgentId() {
|
|
150470
|
+
return this.currentAgentId;
|
|
150471
|
+
}
|
|
149737
150472
|
hide() {
|
|
150473
|
+
this.hideTerminalContextMenu();
|
|
149738
150474
|
if (this.container) {
|
|
149739
150475
|
this.container.style.display = "none";
|
|
149740
150476
|
}
|
|
@@ -149745,8 +150481,6 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149745
150481
|
this.isVisible = false;
|
|
149746
150482
|
this.isReadOnly = false;
|
|
149747
150483
|
this.pendingInputLine = "";
|
|
149748
|
-
this.awaitingSessionIdRefresh = false;
|
|
149749
|
-
this.clearSessionRefreshTimers();
|
|
149750
150484
|
this.closeHistoryPopover();
|
|
149751
150485
|
this.restorePanelLayout();
|
|
149752
150486
|
this.inputManager.deactivateTerminalF10();
|
|
@@ -149785,9 +150519,26 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149785
150519
|
return false;
|
|
149786
150520
|
}
|
|
149787
150521
|
destroy() {
|
|
150522
|
+
this.hideTerminalContextMenu();
|
|
150523
|
+
if (this.clipboardHandler) {
|
|
150524
|
+
document.removeEventListener("keydown", this.clipboardHandler, true);
|
|
150525
|
+
this.clipboardHandler = null;
|
|
150526
|
+
}
|
|
150527
|
+
if (this.terminalContextMenuDismiss) {
|
|
150528
|
+
document.removeEventListener("mousedown", this.terminalContextMenuDismiss, true);
|
|
150529
|
+
document.removeEventListener("keydown", this.terminalContextMenuDismiss, true);
|
|
150530
|
+
this.terminalContextMenuDismiss = null;
|
|
150531
|
+
}
|
|
150532
|
+
if (this.terminalContextMenu && this.terminalContextMenu.parentNode) {
|
|
150533
|
+
try {
|
|
150534
|
+
this.terminalContextMenu.parentNode.removeChild(this.terminalContextMenu);
|
|
150535
|
+
} catch {
|
|
150536
|
+
}
|
|
150537
|
+
}
|
|
150538
|
+
this.terminalContextMenu = null;
|
|
150539
|
+
this.onDataDisposable?.dispose();
|
|
150540
|
+
this.onDataDisposable = null;
|
|
149788
150541
|
this.clearRefitTimers();
|
|
149789
|
-
this.awaitingSessionIdRefresh = false;
|
|
149790
|
-
this.clearSessionRefreshTimers();
|
|
149791
150542
|
if (this.resizeHandler) {
|
|
149792
150543
|
window.removeEventListener("resize", this.resizeHandler);
|
|
149793
150544
|
this.resizeHandler = null;
|
|
@@ -149800,11 +150551,23 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
149800
150551
|
this.terminal.dispose();
|
|
149801
150552
|
}
|
|
149802
150553
|
if (this.container && this.container.parentNode) {
|
|
149803
|
-
|
|
150554
|
+
try {
|
|
150555
|
+
this.container.parentNode.removeChild(this.container);
|
|
150556
|
+
} catch {
|
|
150557
|
+
}
|
|
149804
150558
|
}
|
|
149805
|
-
|
|
149806
|
-
this.spriteCardElement
|
|
150559
|
+
try {
|
|
150560
|
+
if (this.spriteCardElement && this.spriteCardElement.parentNode) {
|
|
150561
|
+
this.spriteCardElement.parentNode.removeChild(this.spriteCardElement);
|
|
150562
|
+
}
|
|
150563
|
+
} catch {
|
|
149807
150564
|
}
|
|
150565
|
+
try {
|
|
150566
|
+
const fallback = document.getElementById("sprite-card");
|
|
150567
|
+
if (fallback) fallback.remove();
|
|
150568
|
+
} catch {
|
|
150569
|
+
}
|
|
150570
|
+
this.spriteCardElement = null;
|
|
149808
150571
|
if (window.copilotBridge) {
|
|
149809
150572
|
window.copilotBridge.removeTerminalListeners();
|
|
149810
150573
|
}
|
|
@@ -150949,6 +151712,16 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
150949
151712
|
const meta = cachedSessionMeta[agent.id];
|
|
150950
151713
|
const hasSession = liveStatus?.state === "active";
|
|
150951
151714
|
const metaTitle = meta?.title || "";
|
|
151715
|
+
const metaSessionId = meta?.sessionId || "";
|
|
151716
|
+
const sessionIdBadgeHtml = metaSessionId ? `<div class="session-id-badge" data-agent="${agent.id}" data-session-id="${metaSessionId}" title="Click to copy: ${metaSessionId}" style="
|
|
151717
|
+
display: inline-block; align-self: flex-start;
|
|
151718
|
+
font-family: ui-monospace, Menlo, Consolas, monospace;
|
|
151719
|
+
font-size: 10px; color: #8ec3ff;
|
|
151720
|
+
background: #1a2030; border: 1px solid #2a3550;
|
|
151721
|
+
padding: 1px 6px; border-radius: 3px;
|
|
151722
|
+
cursor: pointer; user-select: text;
|
|
151723
|
+
max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
151724
|
+
">${metaSessionId}</div>` : "";
|
|
150952
151725
|
const sessionPanelHtml = hasSession ? `
|
|
150953
151726
|
<div class="session-meta-panel" data-agent="${agent.id}" style="
|
|
150954
151727
|
flex: 2; min-width: 0;
|
|
@@ -150965,6 +151738,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
150965
151738
|
overflow: hidden; text-overflow: ellipsis;
|
|
150966
151739
|
display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
|
|
150967
151740
|
" title="${metaTitle ? metaTitle.replace(/"/g, """) : "Click to set title"}">${metaTitle || "Untitled session"}</div>
|
|
151741
|
+
${sessionIdBadgeHtml}
|
|
150968
151742
|
<button class="session-new-btn" data-agent="${agent.id}" style="
|
|
150969
151743
|
margin-top: 2px;
|
|
150970
151744
|
align-self: flex-start;
|
|
@@ -150972,6 +151746,12 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
150972
151746
|
font-size: ${t.sessionButton}; padding: 4px 10px; border-radius: 4px;
|
|
150973
151747
|
cursor: pointer; transition: background 0.15s, border-color 0.15s;
|
|
150974
151748
|
" title="Start a new session for this agent">\u{1F504} New Session</button>
|
|
151749
|
+
<button class="session-close-btn" data-agent="${agent.id}" style="
|
|
151750
|
+
align-self: flex-start;
|
|
151751
|
+
background: #3a2a2a; border: 1px solid #6a4a4a; color: #f7a9a9;
|
|
151752
|
+
font-size: ${t.sessionButton}; padding: 4px 10px; border-radius: 4px;
|
|
151753
|
+
cursor: pointer; transition: background 0.15s, border-color 0.15s;
|
|
151754
|
+
" title="Close this agent's session (agent returns to slacking)">\u2716 Close Session</button>
|
|
150975
151755
|
<div style="display: flex; justify-content: flex-end;">
|
|
150976
151756
|
<button class="session-edit-btn" data-agent="${agent.id}" style="
|
|
150977
151757
|
background: none; border: 1px solid #333; color: #667;
|
|
@@ -151090,6 +151870,10 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
151090
151870
|
context.emitOpenTerminal(agentId);
|
|
151091
151871
|
},
|
|
151092
151872
|
handleMetaPanelClick(target, agentId, context) {
|
|
151873
|
+
if (target.closest(".session-close-btn")) {
|
|
151874
|
+
context.closeSession(agentId);
|
|
151875
|
+
return;
|
|
151876
|
+
}
|
|
151093
151877
|
if (target.closest(".session-new-btn")) {
|
|
151094
151878
|
context.startNewSession(agentId);
|
|
151095
151879
|
return;
|
|
@@ -151108,6 +151892,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
151108
151892
|
"src/layouts/fleet/FleetDashboard.ts"() {
|
|
151109
151893
|
"use strict";
|
|
151110
151894
|
init_types();
|
|
151895
|
+
init_agents();
|
|
151111
151896
|
fleetDashboard = {
|
|
151112
151897
|
renderCards(ctx) {
|
|
151113
151898
|
const { agents, office, selectedAgentId, formatElapsed, formatRelativeTime } = ctx;
|
|
@@ -151157,7 +151942,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
151157
151942
|
}
|
|
151158
151943
|
const colorHex = "#" + agent.color.toString(16).padStart(6, "0");
|
|
151159
151944
|
const isSelected = agent.id === selectedAgentId;
|
|
151160
|
-
const isArthur = agent.id ===
|
|
151945
|
+
const isArthur = agent.id === ARCHITECT_AGENT_ID;
|
|
151161
151946
|
const borderColor = isSelected ? "#4a5a7a" : "#252540";
|
|
151162
151947
|
const bgColor = isSelected ? "#1a1e2e" : "#13131f";
|
|
151163
151948
|
const cursor = isArthur ? "pointer" : "default";
|
|
@@ -151260,9 +152045,10 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
151260
152045
|
var init_FleetClickHandler = __esm({
|
|
151261
152046
|
"src/layouts/fleet/FleetClickHandler.ts"() {
|
|
151262
152047
|
"use strict";
|
|
152048
|
+
init_agents();
|
|
151263
152049
|
fleetClickHandler = {
|
|
151264
152050
|
handleCardClick(agentId, context) {
|
|
151265
|
-
if (agentId ===
|
|
152051
|
+
if (agentId === ARCHITECT_AGENT_ID) {
|
|
151266
152052
|
context.setSelectedAgent(agentId);
|
|
151267
152053
|
context.emitOpenTerminal(agentId);
|
|
151268
152054
|
return;
|
|
@@ -151278,7 +152064,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
151278
152064
|
function getLayout(layout) {
|
|
151279
152065
|
return layouts[layout] ?? layouts["default"];
|
|
151280
152066
|
}
|
|
151281
|
-
var layouts;
|
|
152067
|
+
var defaultBehaviors, fleetBehaviors, layouts;
|
|
151282
152068
|
var init_layouts = __esm({
|
|
151283
152069
|
"src/layouts/index.ts"() {
|
|
151284
152070
|
"use strict";
|
|
@@ -151287,16 +152073,30 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
151287
152073
|
init_DefaultClickHandler();
|
|
151288
152074
|
init_FleetDashboard();
|
|
151289
152075
|
init_FleetClickHandler();
|
|
152076
|
+
defaultBehaviors = {
|
|
152077
|
+
supportsReserveAgents: true,
|
|
152078
|
+
restrictsInteractionToArchitect: false,
|
|
152079
|
+
hasPlayerPcTerminal: true,
|
|
152080
|
+
supportsFleetExecution: false
|
|
152081
|
+
};
|
|
152082
|
+
fleetBehaviors = {
|
|
152083
|
+
supportsReserveAgents: false,
|
|
152084
|
+
restrictsInteractionToArchitect: true,
|
|
152085
|
+
hasPlayerPcTerminal: false,
|
|
152086
|
+
supportsFleetExecution: true
|
|
152087
|
+
};
|
|
151290
152088
|
layouts = {
|
|
151291
152089
|
"default": {
|
|
151292
152090
|
agents: AGENTS,
|
|
151293
152091
|
dashboard: defaultDashboard,
|
|
151294
|
-
clickHandler: defaultClickHandler
|
|
152092
|
+
clickHandler: defaultClickHandler,
|
|
152093
|
+
behaviors: defaultBehaviors
|
|
151295
152094
|
},
|
|
151296
152095
|
"fleet-vteam": {
|
|
151297
152096
|
agents: FLEET_AGENTS,
|
|
151298
152097
|
dashboard: fleetDashboard,
|
|
151299
|
-
clickHandler: fleetClickHandler
|
|
152098
|
+
clickHandler: fleetClickHandler,
|
|
152099
|
+
behaviors: fleetBehaviors
|
|
151300
152100
|
}
|
|
151301
152101
|
};
|
|
151302
152102
|
}
|
|
@@ -151640,30 +152440,27 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
151640
152440
|
this.terminal.deactivateF10();
|
|
151641
152441
|
}
|
|
151642
152442
|
/**
|
|
151643
|
-
* Focus the xterm Terminal instance
|
|
151644
|
-
*
|
|
151645
|
-
*
|
|
152443
|
+
* Focus the xterm Terminal instance. Calls focus() synchronously for
|
|
152444
|
+
* immediate keyboard capture, then verifies after a short delay and retries
|
|
152445
|
+
* if the DOM wasn't ready (e.g. display transition still in flight).
|
|
151646
152446
|
*/
|
|
151647
152447
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
151648
152448
|
focusTerminalXterm(terminal) {
|
|
151649
|
-
|
|
151650
|
-
const
|
|
152449
|
+
terminal?.focus();
|
|
152450
|
+
const verify = (n, delay) => {
|
|
151651
152451
|
setTimeout(() => {
|
|
151652
|
-
terminal?.focus();
|
|
151653
|
-
console.log(`[InputManager] focusTerminalXterm() attempt ${n} executed | time: ${Date.now()}`);
|
|
151654
152452
|
const textarea = terminal?.textarea;
|
|
151655
|
-
if (textarea && document.activeElement !== textarea
|
|
151656
|
-
|
|
151657
|
-
|
|
152453
|
+
if (textarea && document.activeElement !== textarea) {
|
|
152454
|
+
terminal?.focus();
|
|
152455
|
+
if (n < 3) verify(n + 1, delay * 2);
|
|
151658
152456
|
}
|
|
151659
152457
|
}, delay);
|
|
151660
152458
|
};
|
|
151661
|
-
|
|
152459
|
+
verify(1, 50);
|
|
151662
152460
|
}
|
|
151663
152461
|
/** Blur the xterm Terminal instance (return DOM focus away from xterm). */
|
|
151664
152462
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
151665
152463
|
blurTerminalXterm(terminal) {
|
|
151666
|
-
console.log(`[InputManager] blurTerminalXterm() | time: ${Date.now()}`);
|
|
151667
152464
|
terminal?.blur();
|
|
151668
152465
|
}
|
|
151669
152466
|
/** Enable or disable verbose per-keydown logging in GlobalInputListener. */
|
|
@@ -152323,11 +153120,72 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
152323
153120
|
}
|
|
152324
153121
|
});
|
|
152325
153122
|
|
|
153123
|
+
// src/config/agentAutoStart.ts
|
|
153124
|
+
function clone() {
|
|
153125
|
+
return { ...DEFAULT_AGENT_AUTO_START_SETTINGS };
|
|
153126
|
+
}
|
|
153127
|
+
function readStorage() {
|
|
153128
|
+
try {
|
|
153129
|
+
if (typeof localStorage !== "undefined") return localStorage;
|
|
153130
|
+
} catch {
|
|
153131
|
+
}
|
|
153132
|
+
return null;
|
|
153133
|
+
}
|
|
153134
|
+
function getAgentAutoStartSettings() {
|
|
153135
|
+
const storage = readStorage();
|
|
153136
|
+
if (!storage) return clone();
|
|
153137
|
+
let raw;
|
|
153138
|
+
try {
|
|
153139
|
+
raw = storage.getItem(STORAGE_KEY2);
|
|
153140
|
+
} catch {
|
|
153141
|
+
return clone();
|
|
153142
|
+
}
|
|
153143
|
+
if (raw === null || raw === void 0) return clone();
|
|
153144
|
+
let parsed;
|
|
153145
|
+
try {
|
|
153146
|
+
parsed = JSON.parse(raw);
|
|
153147
|
+
} catch {
|
|
153148
|
+
try {
|
|
153149
|
+
storage.removeItem(STORAGE_KEY2);
|
|
153150
|
+
} catch {
|
|
153151
|
+
}
|
|
153152
|
+
return clone();
|
|
153153
|
+
}
|
|
153154
|
+
if (!parsed || typeof parsed !== "object") return clone();
|
|
153155
|
+
const candidate = parsed.autoStartKnownAgents;
|
|
153156
|
+
if (typeof candidate !== "boolean") return clone();
|
|
153157
|
+
return { autoStartKnownAgents: candidate };
|
|
153158
|
+
}
|
|
153159
|
+
function setAgentAutoStartSettings(next) {
|
|
153160
|
+
const storage = readStorage();
|
|
153161
|
+
if (!storage) return;
|
|
153162
|
+
try {
|
|
153163
|
+
storage.setItem(
|
|
153164
|
+
STORAGE_KEY2,
|
|
153165
|
+
JSON.stringify({ autoStartKnownAgents: !!next.autoStartKnownAgents })
|
|
153166
|
+
);
|
|
153167
|
+
} catch {
|
|
153168
|
+
}
|
|
153169
|
+
}
|
|
153170
|
+
function shouldAutoStart() {
|
|
153171
|
+
return getAgentAutoStartSettings().autoStartKnownAgents === true;
|
|
153172
|
+
}
|
|
153173
|
+
var DEFAULT_AGENT_AUTO_START_SETTINGS, STORAGE_KEY2;
|
|
153174
|
+
var init_agentAutoStart = __esm({
|
|
153175
|
+
"src/config/agentAutoStart.ts"() {
|
|
153176
|
+
"use strict";
|
|
153177
|
+
DEFAULT_AGENT_AUTO_START_SETTINGS = {
|
|
153178
|
+
autoStartKnownAgents: true
|
|
153179
|
+
};
|
|
153180
|
+
STORAGE_KEY2 = "copilot-office-agent-auto-start";
|
|
153181
|
+
}
|
|
153182
|
+
});
|
|
153183
|
+
|
|
152326
153184
|
// src/scenes/OfficeScene.ts
|
|
152327
153185
|
function debugLog(scene, ...args) {
|
|
152328
153186
|
if (scene.physics.world.drawDebug) console.log("[Debug]", ...args);
|
|
152329
153187
|
}
|
|
152330
|
-
var import_phaser8, ENABLE_DECORATIONS, ENABLE_BASKETBALL, ENABLE_GALAXIAN, ENABLE_ZOOM_BAR, PC_TERMINAL_ID, OfficeScene;
|
|
153188
|
+
var import_phaser8, DEBUG_COLD_START2, ENABLE_DECORATIONS, ENABLE_BASKETBALL, ENABLE_GALAXIAN, ENABLE_ZOOM_BAR, PC_TERMINAL_ID, OfficeScene;
|
|
152331
153189
|
var init_OfficeScene = __esm({
|
|
152332
153190
|
"src/scenes/OfficeScene.ts"() {
|
|
152333
153191
|
"use strict";
|
|
@@ -152340,12 +153198,15 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
152340
153198
|
init_agents();
|
|
152341
153199
|
init_layouts();
|
|
152342
153200
|
init_depths();
|
|
153201
|
+
init_zIndex();
|
|
152343
153202
|
init_InputManager();
|
|
152344
153203
|
init_officeManager();
|
|
152345
153204
|
init_fleetTracker();
|
|
152346
153205
|
init_fleetVisualizer();
|
|
152347
153206
|
init_DirectionalSprite();
|
|
152348
153207
|
init_CameraDragController();
|
|
153208
|
+
init_agentAutoStart();
|
|
153209
|
+
DEBUG_COLD_START2 = typeof window !== "undefined" && window.__COPILOT_OFFICE_DEBUG_COLD_START__ === true || false;
|
|
152349
153210
|
ENABLE_DECORATIONS = false;
|
|
152350
153211
|
ENABLE_BASKETBALL = false;
|
|
152351
153212
|
ENABLE_GALAXIAN = true;
|
|
@@ -152386,6 +153247,10 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
152386
153247
|
this.skipButton = null;
|
|
152387
153248
|
this.isPortraitDashboardMode = false;
|
|
152388
153249
|
}
|
|
153250
|
+
// Spec 008-smoke: accessor for the e2e debug hook in src/main.ts.
|
|
153251
|
+
getTerminalOverlay() {
|
|
153252
|
+
return this.terminalOverlay;
|
|
153253
|
+
}
|
|
152389
153254
|
setAnimating(value) {
|
|
152390
153255
|
this.animating = value;
|
|
152391
153256
|
this.game.registry.set("animating", value);
|
|
@@ -152471,13 +153336,13 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
152471
153336
|
} else {
|
|
152472
153337
|
this.triggerEntrance();
|
|
152473
153338
|
}
|
|
152474
|
-
const arthurNPC = this.npcs.find((n) => n.config.id ===
|
|
153339
|
+
const arthurNPC = this.npcs.find((n) => n.config.id === ARCHITECT_AGENT_ID);
|
|
152475
153340
|
if (arthurNPC) {
|
|
152476
153341
|
arthurNPC.updateAgentStatus(void 0);
|
|
152477
153342
|
}
|
|
152478
153343
|
const seatedNpcs = [];
|
|
152479
153344
|
for (const agent of AGENTS) {
|
|
152480
|
-
if (agent.id ===
|
|
153345
|
+
if (agent.id === ARCHITECT_AGENT_ID) continue;
|
|
152481
153346
|
const npc = this.npcs.find((n) => n.config.id === agent.id);
|
|
152482
153347
|
if (!npc) continue;
|
|
152483
153348
|
const deskX = npc.config.position.x * this.tileSize + this.tileSize / 2;
|
|
@@ -152491,7 +153356,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
152491
153356
|
const showAllBadges = () => {
|
|
152492
153357
|
seatedNpcs.forEach((n) => n.setBadgeVisible(true));
|
|
152493
153358
|
};
|
|
152494
|
-
this.triggerAgentWalkIn([
|
|
153359
|
+
this.triggerAgentWalkIn([ARCHITECT_AGENT_ID], showAllBadges);
|
|
152495
153360
|
}
|
|
152496
153361
|
});
|
|
152497
153362
|
this.basketballGame = new BasketballGame(this);
|
|
@@ -152592,7 +153457,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
152592
153457
|
this.openPlayerPcTerminal();
|
|
152593
153458
|
return;
|
|
152594
153459
|
}
|
|
152595
|
-
if (this.currentLayout
|
|
153460
|
+
if (getLayout(this.currentLayout).behaviors.restrictsInteractionToArchitect && agentId !== ARCHITECT_AGENT_ID) return;
|
|
152596
153461
|
const agents = getLayout(this.currentLayout).agents;
|
|
152597
153462
|
const agent = agents.find((a) => a.id === agentId);
|
|
152598
153463
|
if (agent) this.startConversation(agent);
|
|
@@ -152787,6 +153652,14 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
152787
153652
|
this.game.events.off("zoom:change");
|
|
152788
153653
|
this.cameraDrag?.destroy();
|
|
152789
153654
|
this.inputManager.destroy();
|
|
153655
|
+
if (DEBUG_SPRITE_SERIOUS) {
|
|
153656
|
+
console.log("[OfficeScene] shutdown destroying terminalOverlay");
|
|
153657
|
+
}
|
|
153658
|
+
try {
|
|
153659
|
+
this.terminalOverlay?.destroy();
|
|
153660
|
+
} catch (e) {
|
|
153661
|
+
console.warn("[OfficeScene] shutdown overlay destroy failed", e);
|
|
153662
|
+
}
|
|
152790
153663
|
}, this);
|
|
152791
153664
|
}
|
|
152792
153665
|
startBackgroundMusic() {
|
|
@@ -153682,7 +154555,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
153682
154555
|
font-family: 'Cascadia Code', Consolas, monospace;
|
|
153683
154556
|
font-size: 16px;
|
|
153684
154557
|
font-weight: bold;
|
|
153685
|
-
z-index:
|
|
154558
|
+
z-index: ${ZIndex.OFFICE_SCENE_OVERLAY};
|
|
153686
154559
|
transition: background 0.15s;
|
|
153687
154560
|
`;
|
|
153688
154561
|
btn.addEventListener("mouseenter", () => {
|
|
@@ -153808,7 +154681,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
153808
154681
|
const isReEntry = !this.fleetPrompt;
|
|
153809
154682
|
console.log(`[OfficeScene] initFleetPipeline: attachOfficeId=${attachOfficeId}, sourceOfficeId=${this.fleetSourceOfficeId}, currentOfficeId=${officeManager.currentOfficeId}, isReEntry=${isReEntry}`);
|
|
153810
154683
|
try {
|
|
153811
|
-
this.fleetTracker = new FleetTracker(
|
|
154684
|
+
this.fleetTracker = new FleetTracker(ARCHITECT_AGENT_ID, attachOfficeId);
|
|
153812
154685
|
await this.fleetTracker.startTracking();
|
|
153813
154686
|
this.fleetVisualizer = new FleetVisualizer(
|
|
153814
154687
|
this.fleetTracker,
|
|
@@ -153821,8 +154694,8 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
153821
154694
|
const fleetOfficeId = officeManager.currentOfficeId;
|
|
153822
154695
|
if (fleetOfficeId && window.copilotBridge?.terminalWrite) {
|
|
153823
154696
|
const fleetCmd = `/fleet ${this.fleetPrompt}\r`;
|
|
153824
|
-
console.log(`[OfficeScene] Sending /fleet to ${fleetOfficeId}
|
|
153825
|
-
const result = await window.copilotBridge.terminalWrite(fleetOfficeId,
|
|
154697
|
+
console.log(`[OfficeScene] Sending /fleet to ${fleetOfficeId}:${ARCHITECT_AGENT_ID} (${fleetCmd.length} chars)`);
|
|
154698
|
+
const result = await window.copilotBridge.terminalWrite(fleetOfficeId, ARCHITECT_AGENT_ID, fleetCmd);
|
|
153826
154699
|
console.log(`[OfficeScene] /fleet command result:`, result);
|
|
153827
154700
|
} else {
|
|
153828
154701
|
console.warn("[OfficeScene] Cannot send /fleet \u2014 no officeId or copilotBridge");
|
|
@@ -153872,23 +154745,49 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
153872
154745
|
});
|
|
153873
154746
|
}
|
|
153874
154747
|
async preStartAgentSessions() {
|
|
154748
|
+
if (!shouldAutoStart()) {
|
|
154749
|
+
if (DEBUG_COLD_START2) {
|
|
154750
|
+
console.log("[OfficeScene] preStart skipped (autoStartKnownAgents=false)");
|
|
154751
|
+
}
|
|
154752
|
+
return;
|
|
154753
|
+
}
|
|
153875
154754
|
if (typeof window !== "undefined" && window.copilotBridge) {
|
|
153876
154755
|
const oid = officeManager.currentOfficeId || "office-0";
|
|
153877
|
-
const startAgent = async (
|
|
153878
|
-
const
|
|
153879
|
-
const savedSessionId = await window.copilotBridge.getSessionId(oid,
|
|
154756
|
+
const startAgent = async (agentConfig, label) => {
|
|
154757
|
+
const startedAt = Date.now();
|
|
154758
|
+
const savedSessionId = await window.copilotBridge.getSessionId(oid, agentConfig.id);
|
|
153880
154759
|
if (savedSessionId) {
|
|
153881
154760
|
console.log(`[CopilotOffice] Resuming ${label} session: ${savedSessionId}`);
|
|
153882
154761
|
} else {
|
|
153883
154762
|
console.log(`[CopilotOffice] Starting new ${label} session (no saved session found)`);
|
|
153884
154763
|
}
|
|
153885
|
-
await window.copilotBridge.terminalStart(
|
|
154764
|
+
const result = await window.copilotBridge.terminalStart(
|
|
154765
|
+
oid,
|
|
154766
|
+
agentConfig.id,
|
|
154767
|
+
agentConfig.workingDir || officeManager.getCurrentWorkingDirectory()
|
|
154768
|
+
);
|
|
153886
154769
|
console.log(`[CopilotOffice] ${label} session ready`);
|
|
154770
|
+
if (DEBUG_COLD_START2) {
|
|
154771
|
+
const sessionId = (result && result.sessionId) ?? "unknown";
|
|
154772
|
+
const elapsedMs = Date.now() - startedAt;
|
|
154773
|
+
console.log(
|
|
154774
|
+
`[OfficeScene] preStart agent=${agentConfig.id} sessionId=${sessionId} elapsedMs=${elapsedMs}`
|
|
154775
|
+
);
|
|
154776
|
+
}
|
|
153887
154777
|
};
|
|
153888
|
-
const
|
|
153889
|
-
|
|
153890
|
-
|
|
154778
|
+
const roster = getLayout(this.currentLayout).agents;
|
|
154779
|
+
const agentsToStart = roster.length > 0 ? roster : AGENTS;
|
|
154780
|
+
const results = await Promise.allSettled(
|
|
154781
|
+
agentsToStart.map((a) => startAgent(a, `${a.name} (${a.description})`))
|
|
153891
154782
|
);
|
|
154783
|
+
for (let i = 0; i < results.length; i++) {
|
|
154784
|
+
const r = results[i];
|
|
154785
|
+
if (r.status === "rejected") {
|
|
154786
|
+
console.warn(
|
|
154787
|
+
`[CopilotOffice] preStart failed for ${agentsToStart[i].id}: ${String(r.reason)}`
|
|
154788
|
+
);
|
|
154789
|
+
}
|
|
154790
|
+
}
|
|
153892
154791
|
}
|
|
153893
154792
|
}
|
|
153894
154793
|
update() {
|
|
@@ -153941,7 +154840,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
153941
154840
|
}
|
|
153942
154841
|
}
|
|
153943
154842
|
}
|
|
153944
|
-
if (import_phaser8.default.Input.Keyboard.JustDown(this.dismissKey) && this.currentLayout
|
|
154843
|
+
if (import_phaser8.default.Input.Keyboard.JustDown(this.dismissKey) && getLayout(this.currentLayout).behaviors.supportsReserveAgents) {
|
|
153945
154844
|
const targetNPC = this.nearestNPC ?? (this.nearestDesk ? this.npcs.find((n) => n.config.id === this.nearestDesk.agentId) ?? null : null);
|
|
153946
154845
|
if (targetNPC && !CORE_AGENT_IDS.has(targetNPC.config.id) && RESERVE_AGENT_DESK[targetNPC.config.id]) {
|
|
153947
154846
|
this.dismissReserveAgent(targetNPC);
|
|
@@ -154129,7 +155028,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
154129
155028
|
}
|
|
154130
155029
|
startConversation(agent) {
|
|
154131
155030
|
if (this.currentLayout === "fleet-vteam") {
|
|
154132
|
-
if (agent.id !==
|
|
155031
|
+
if (agent.id !== ARCHITECT_AGENT_ID) return;
|
|
154133
155032
|
this.game.events.emit("agent:interact", agent.id);
|
|
154134
155033
|
this.terminalOverlay.show(
|
|
154135
155034
|
agent,
|
|
@@ -154139,7 +155038,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
154139
155038
|
);
|
|
154140
155039
|
return;
|
|
154141
155040
|
}
|
|
154142
|
-
if (agent.id ===
|
|
155041
|
+
if (agent.id === ARCHITECT_AGENT_ID) {
|
|
154143
155042
|
this.enterMeeting();
|
|
154144
155043
|
return;
|
|
154145
155044
|
}
|
|
@@ -154170,7 +155069,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
154170
155069
|
);
|
|
154171
155070
|
}
|
|
154172
155071
|
openPlayerPcTerminal() {
|
|
154173
|
-
if (this.currentLayout
|
|
155072
|
+
if (!getLayout(this.currentLayout).behaviors.hasPlayerPcTerminal) return;
|
|
154174
155073
|
const workingDir = officeManager.getCurrentWorkingDirectory();
|
|
154175
155074
|
const pcTerminalConfig = {
|
|
154176
155075
|
id: PC_TERMINAL_ID,
|
|
@@ -154494,7 +155393,8 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
154494
155393
|
var init_planParser = __esm({
|
|
154495
155394
|
"src/meeting/planParser.ts"() {
|
|
154496
155395
|
"use strict";
|
|
154497
|
-
|
|
155396
|
+
init_agents();
|
|
155397
|
+
DEFAULT_VALID_AGENT_IDS = DEFAULT_PLAN_AGENT_IDS;
|
|
154498
155398
|
}
|
|
154499
155399
|
});
|
|
154500
155400
|
|
|
@@ -154563,7 +155463,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
154563
155463
|
this.inputManager = new InputManager(this);
|
|
154564
155464
|
this.planApproval = new PlanApprovalOverlay();
|
|
154565
155465
|
this.terminalOverlay = new TerminalOverlay(this, this.inputManager, () => officeManager.currentOfficeId || "office-0");
|
|
154566
|
-
const arthur = AGENTS.find((a) => a.id ===
|
|
155466
|
+
const arthur = AGENTS.find((a) => a.id === ARCHITECT_AGENT_ID);
|
|
154567
155467
|
if (arthur) {
|
|
154568
155468
|
this.terminalOverlay.show(arthur, () => {
|
|
154569
155469
|
console.log("[MeetingScene] Terminal closed");
|
|
@@ -154720,7 +155620,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
154720
155620
|
if (typeof window === "undefined" || !window.copilotBridge) return;
|
|
154721
155621
|
const handler = (_agentId, data) => {
|
|
154722
155622
|
if (this.isExiting) return;
|
|
154723
|
-
if (_agentId !==
|
|
155623
|
+
if (_agentId !== ARCHITECT_AGENT_ID) return;
|
|
154724
155624
|
this.terminalOutputBuffer += data;
|
|
154725
155625
|
this.time.delayedCall(500, () => {
|
|
154726
155626
|
if (this.isExiting) return;
|
|
@@ -154746,7 +155646,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
154746
155646
|
onRevise: (feedback) => {
|
|
154747
155647
|
console.log("[MeetingScene] Revision requested:", feedback);
|
|
154748
155648
|
if (window.copilotBridge) {
|
|
154749
|
-
window.copilotBridge.terminalWrite(officeManager.currentOfficeId || "office-0",
|
|
155649
|
+
window.copilotBridge.terminalWrite(officeManager.currentOfficeId || "office-0", ARCHITECT_AGENT_ID, feedback + "\r");
|
|
154750
155650
|
}
|
|
154751
155651
|
this.meetingPlan = null;
|
|
154752
155652
|
this.terminalOutputBuffer = "";
|
|
@@ -154859,6 +155759,14 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
154859
155759
|
this.terminalOverlay?.hide();
|
|
154860
155760
|
}
|
|
154861
155761
|
this.inputManager?.destroy();
|
|
155762
|
+
if (DEBUG_SPRITE_SERIOUS) {
|
|
155763
|
+
console.log("[MeetingScene] shutdown destroying terminalOverlay");
|
|
155764
|
+
}
|
|
155765
|
+
try {
|
|
155766
|
+
this.terminalOverlay?.destroy();
|
|
155767
|
+
} catch (e) {
|
|
155768
|
+
console.warn("[MeetingScene] shutdown overlay destroy failed", e);
|
|
155769
|
+
}
|
|
154862
155770
|
this.meetingPlan = null;
|
|
154863
155771
|
this.terminalOutputBuffer = "";
|
|
154864
155772
|
this.isExiting = false;
|
|
@@ -154889,6 +155797,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
154889
155797
|
var init_ToastNotification = __esm({
|
|
154890
155798
|
"src/ui/ToastNotification.ts"() {
|
|
154891
155799
|
"use strict";
|
|
155800
|
+
init_zIndex();
|
|
154892
155801
|
MAX_VISIBLE = 3;
|
|
154893
155802
|
AUTO_DISMISS_MS = 5e3;
|
|
154894
155803
|
ANIMATION_MS = 300;
|
|
@@ -154905,7 +155814,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
154905
155814
|
top: 80px;
|
|
154906
155815
|
left: 16px;
|
|
154907
155816
|
width: calc(50% - 32px);
|
|
154908
|
-
z-index:
|
|
155817
|
+
z-index: ${ZIndex.TOAST};
|
|
154909
155818
|
pointer-events: none;
|
|
154910
155819
|
display: flex;
|
|
154911
155820
|
flex-direction: column;
|
|
@@ -155002,7 +155911,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155002
155911
|
// src/config/notifications.ts
|
|
155003
155912
|
function loadNotificationSettings() {
|
|
155004
155913
|
try {
|
|
155005
|
-
const raw = localStorage.getItem(
|
|
155914
|
+
const raw = localStorage.getItem(STORAGE_KEY3);
|
|
155006
155915
|
if (!raw) return structuredClone(DEFAULT_SETTINGS);
|
|
155007
155916
|
const parsed = JSON.parse(raw);
|
|
155008
155917
|
const merged = structuredClone(DEFAULT_SETTINGS);
|
|
@@ -155022,13 +155931,13 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155022
155931
|
}
|
|
155023
155932
|
}
|
|
155024
155933
|
function saveNotificationSettings(settings) {
|
|
155025
|
-
localStorage.setItem(
|
|
155934
|
+
localStorage.setItem(STORAGE_KEY3, JSON.stringify(settings));
|
|
155026
155935
|
}
|
|
155027
155936
|
function resetNotificationSettings() {
|
|
155028
|
-
localStorage.removeItem(
|
|
155937
|
+
localStorage.removeItem(STORAGE_KEY3);
|
|
155029
155938
|
return structuredClone(DEFAULT_SETTINGS);
|
|
155030
155939
|
}
|
|
155031
|
-
var NOTIFICATION_EVENT_LABELS, DEFAULT_SETTINGS,
|
|
155940
|
+
var NOTIFICATION_EVENT_LABELS, DEFAULT_SETTINGS, STORAGE_KEY3;
|
|
155032
155941
|
var init_notifications = __esm({
|
|
155033
155942
|
"src/config/notifications.ts"() {
|
|
155034
155943
|
"use strict";
|
|
@@ -155088,7 +155997,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155088
155997
|
}
|
|
155089
155998
|
}
|
|
155090
155999
|
};
|
|
155091
|
-
|
|
156000
|
+
STORAGE_KEY3 = "copilot-notification-settings";
|
|
155092
156001
|
}
|
|
155093
156002
|
});
|
|
155094
156003
|
|
|
@@ -155189,6 +156098,8 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155189
156098
|
"src/ui/SettingsPanel.ts"() {
|
|
155190
156099
|
"use strict";
|
|
155191
156100
|
init_notifications();
|
|
156101
|
+
init_agentAutoStart();
|
|
156102
|
+
init_zIndex();
|
|
155192
156103
|
ALL_EVENT_TYPES = [
|
|
155193
156104
|
"turnEnd",
|
|
155194
156105
|
"askUser",
|
|
@@ -155222,7 +156133,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155222
156133
|
position: fixed;
|
|
155223
156134
|
inset: 0;
|
|
155224
156135
|
background: rgba(0,0,0,0.6);
|
|
155225
|
-
z-index:
|
|
156136
|
+
z-index: ${ZIndex.SETTINGS};
|
|
155226
156137
|
display: flex;
|
|
155227
156138
|
align-items: center;
|
|
155228
156139
|
justify-content: center;
|
|
@@ -155273,8 +156184,31 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155273
156184
|
</div>
|
|
155274
156185
|
|
|
155275
156186
|
${this.renderAudioSection()}
|
|
156187
|
+
${this.renderAgentsSection()}
|
|
155276
156188
|
${this.renderNotificationsSection()}
|
|
155277
156189
|
${this.renderAboutSection()}
|
|
156190
|
+
`;
|
|
156191
|
+
}
|
|
156192
|
+
renderAgentsSection() {
|
|
156193
|
+
const settings = getAgentAutoStartSettings();
|
|
156194
|
+
return `
|
|
156195
|
+
<div class="settings-section" style="margin-bottom: 20px;">
|
|
156196
|
+
<h3 style="margin: 0 0 12px; font-size: 14px; color: #889; border-bottom: 1px solid #2a2a3e; padding-bottom: 8px;">
|
|
156197
|
+
\u{1F916} Agents
|
|
156198
|
+
</h3>
|
|
156199
|
+
<label style="display: flex; align-items: center; gap: 10px; padding: 8px 0; cursor: pointer;">
|
|
156200
|
+
<input
|
|
156201
|
+
type="checkbox"
|
|
156202
|
+
id="settings-agent-auto-start"
|
|
156203
|
+
${settings.autoStartKnownAgents ? "checked" : ""}
|
|
156204
|
+
style="cursor: pointer; width: 15px; height: 15px;"
|
|
156205
|
+
/>
|
|
156206
|
+
<span style="color: #aab; font-size: 13px;">Auto-start known agents</span>
|
|
156207
|
+
</label>
|
|
156208
|
+
<p style="margin: 4px 0 0 25px; font-size: 10px; color: #556;">
|
|
156209
|
+
When ON, agents with a saved session resume automatically on launch, office switch, and New Session.
|
|
156210
|
+
</p>
|
|
156211
|
+
</div>
|
|
155278
156212
|
`;
|
|
155279
156213
|
}
|
|
155280
156214
|
renderAudioSection() {
|
|
@@ -155423,8 +156357,16 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155423
156357
|
bindEvents(panel) {
|
|
155424
156358
|
panel.querySelector("#settings-close-btn")?.addEventListener("click", () => this.close());
|
|
155425
156359
|
this.bindAudioEvents(panel);
|
|
156360
|
+
this.bindAgentsEvents(panel);
|
|
155426
156361
|
this.bindNotificationEvents(panel);
|
|
155427
156362
|
}
|
|
156363
|
+
bindAgentsEvents(panel) {
|
|
156364
|
+
const cb = panel.querySelector("#settings-agent-auto-start");
|
|
156365
|
+
if (!cb) return;
|
|
156366
|
+
cb.addEventListener("change", () => {
|
|
156367
|
+
setAgentAutoStartSettings({ autoStartKnownAgents: cb.checked });
|
|
156368
|
+
});
|
|
156369
|
+
}
|
|
155428
156370
|
bindAudioEvents(panel) {
|
|
155429
156371
|
const muteBtn = panel.querySelector("#settings-bgm-mute-btn");
|
|
155430
156372
|
const slider = panel.querySelector("#settings-bgm-slider");
|
|
@@ -155463,7 +156405,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155463
156405
|
settings.events[eventType].enabled = checkbox.checked;
|
|
155464
156406
|
});
|
|
155465
156407
|
});
|
|
155466
|
-
panel.querySelectorAll('input[type="checkbox"]:not([data-field="enabled"])').forEach((checkbox) => {
|
|
156408
|
+
panel.querySelectorAll('input[type="checkbox"][data-event]:not([data-field="enabled"])').forEach((checkbox) => {
|
|
155467
156409
|
checkbox.addEventListener("change", () => {
|
|
155468
156410
|
const eventType = checkbox.dataset.event;
|
|
155469
156411
|
const field = checkbox.dataset.field;
|
|
@@ -155518,6 +156460,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155518
156460
|
"src/ui/SpriteCustomizerPanel.ts"() {
|
|
155519
156461
|
"use strict";
|
|
155520
156462
|
init_playerCustomization();
|
|
156463
|
+
init_zIndex();
|
|
155521
156464
|
COLOR_REGIONS = ["hair", "skin", "suit", "tie", "pants", "shoes"];
|
|
155522
156465
|
SpriteCustomizerPanel = class {
|
|
155523
156466
|
constructor(options) {
|
|
@@ -155526,15 +156469,18 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155526
156469
|
this.outsideClickHandler = null;
|
|
155527
156470
|
this.escapeHandler = null;
|
|
155528
156471
|
this.onColorsChanged = options.onColorsChanged;
|
|
156472
|
+
this.onOpenCallback = options.onOpen;
|
|
156473
|
+
this.onCloseCallback = options.onClose;
|
|
155529
156474
|
this.currentColors = loadPlayerColors();
|
|
155530
156475
|
}
|
|
155531
156476
|
show(anchorElement) {
|
|
156477
|
+
const wasOpen = this.container !== null;
|
|
155532
156478
|
if (this.container) this.hide();
|
|
155533
156479
|
this.currentColors = loadPlayerColors();
|
|
155534
156480
|
this.container = document.createElement("div");
|
|
155535
156481
|
this.container.style.cssText = `
|
|
155536
156482
|
position: fixed;
|
|
155537
|
-
z-index:
|
|
156483
|
+
z-index: ${ZIndex.SPRITE_CUSTOMIZER};
|
|
155538
156484
|
width: 320px;
|
|
155539
156485
|
background: #1a1a2e;
|
|
155540
156486
|
border: 2px solid #333;
|
|
@@ -155558,8 +156504,10 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155558
156504
|
}
|
|
155559
156505
|
this.previewImg = this.container.querySelector("#sprite-preview-img");
|
|
155560
156506
|
this.bindEvents();
|
|
156507
|
+
if (!wasOpen) this.onOpenCallback?.();
|
|
155561
156508
|
}
|
|
155562
156509
|
hide() {
|
|
156510
|
+
const wasOpen = this.container !== null;
|
|
155563
156511
|
if (this.outsideClickHandler) {
|
|
155564
156512
|
document.removeEventListener("mousedown", this.outsideClickHandler, true);
|
|
155565
156513
|
this.outsideClickHandler = null;
|
|
@@ -155573,6 +156521,7 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155573
156521
|
this.container = null;
|
|
155574
156522
|
}
|
|
155575
156523
|
this.previewImg = null;
|
|
156524
|
+
if (wasOpen) this.onCloseCallback?.();
|
|
155576
156525
|
}
|
|
155577
156526
|
toggle(anchorElement) {
|
|
155578
156527
|
if (this.container) {
|
|
@@ -155746,6 +156695,12 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155746
156695
|
"use strict";
|
|
155747
156696
|
import_xterm2 = __toESM(require_xterm());
|
|
155748
156697
|
import_addon_fit2 = __toESM(require_addon_fit());
|
|
156698
|
+
init_zIndex();
|
|
156699
|
+
init_TerminalOverlay();
|
|
156700
|
+
init_clipboardToast();
|
|
156701
|
+
init_xtermStyles();
|
|
156702
|
+
init_terminalWheel();
|
|
156703
|
+
init_AutoStartCoordinator();
|
|
155749
156704
|
SeriousTerminalController = class _SeriousTerminalController {
|
|
155750
156705
|
constructor(host, options = {}) {
|
|
155751
156706
|
this.historyPopover = null;
|
|
@@ -155761,6 +156716,15 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155761
156716
|
this.sessionId = null;
|
|
155762
156717
|
this.activeOptions = null;
|
|
155763
156718
|
this.isFullWidth = false;
|
|
156719
|
+
this.terminalContextMenu = null;
|
|
156720
|
+
this.terminalContextMenuDismiss = null;
|
|
156721
|
+
this.seriousInstanceId = String(_SeriousTerminalController.nextSeriousId++);
|
|
156722
|
+
// Spec 003 V13/V14: the onData callback registered on the xterm closes
|
|
156723
|
+
// over the office/agent ids captured at openAgentTerminal time, not the
|
|
156724
|
+
// live this.activeOfficeId/this.activeAgentId. Holding the disposable
|
|
156725
|
+
// here lets the next open() drop the previous binding before installing
|
|
156726
|
+
// a new one — exactly one live onData per controller at any moment.
|
|
156727
|
+
this.onDataDisposable = null;
|
|
155764
156728
|
this.host = host;
|
|
155765
156729
|
this.onClose = options.onClose;
|
|
155766
156730
|
this.isFullWidth = localStorage.getItem(_SeriousTerminalController.FULL_WIDTH_STORAGE_KEY) === "true";
|
|
@@ -155819,13 +156783,13 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155819
156783
|
this.terminalOuterEl.style.cssText = `
|
|
155820
156784
|
flex: 1;
|
|
155821
156785
|
min-height: 0;
|
|
155822
|
-
overflow:
|
|
156786
|
+
overflow: auto;
|
|
155823
156787
|
background: #0d111b;
|
|
155824
156788
|
padding: 10px;
|
|
155825
156789
|
box-sizing: border-box;
|
|
155826
156790
|
`;
|
|
155827
156791
|
this.terminalDivEl = document.createElement("div");
|
|
155828
|
-
this.terminalDivEl.style.cssText = "width: 100%; height: 100%;
|
|
156792
|
+
this.terminalDivEl.style.cssText = "width: 100%; height: 100%;";
|
|
155829
156793
|
this.terminalOuterEl.appendChild(this.terminalDivEl);
|
|
155830
156794
|
this.terminalOuterEl.addEventListener("mousedown", () => this.terminal?.focus());
|
|
155831
156795
|
this.spriteCardEl = document.createElement("div");
|
|
@@ -155969,9 +156933,29 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155969
156933
|
static {
|
|
155970
156934
|
this.FULL_WIDTH_STORAGE_KEY = "agencyOffice:seriousTerminalFullWidth";
|
|
155971
156935
|
}
|
|
156936
|
+
static {
|
|
156937
|
+
this.nextSeriousId = 0;
|
|
156938
|
+
}
|
|
155972
156939
|
isVisible() {
|
|
155973
156940
|
return this.visible;
|
|
155974
156941
|
}
|
|
156942
|
+
// Spec 008-smoke: expose active agent id for the e2e debug hook.
|
|
156943
|
+
getActiveAgentId() {
|
|
156944
|
+
return this.activeAgentId ?? null;
|
|
156945
|
+
}
|
|
156946
|
+
// Spec 008-smoke (T10): expose the visible sprite-card + session-id panel
|
|
156947
|
+
// text so e2e tests can assert what the operator actually sees after agent
|
|
156948
|
+
// switches. Used to repro the user-reported "locked to one agent" symptom.
|
|
156949
|
+
getPanelSnapshot() {
|
|
156950
|
+
return {
|
|
156951
|
+
activeAgentId: this.activeAgentId ?? null,
|
|
156952
|
+
titleText: this.titleEl.textContent ?? "",
|
|
156953
|
+
spriteName: this.spriteNameEl.textContent ?? "",
|
|
156954
|
+
spriteSubtitle: this.spriteSubtitleEl.textContent ?? "",
|
|
156955
|
+
sessionIdText: this.sessionIdEl.textContent ?? "",
|
|
156956
|
+
sessionIdField: this.sessionId ?? null
|
|
156957
|
+
};
|
|
156958
|
+
}
|
|
155975
156959
|
refreshCardFromOverview() {
|
|
155976
156960
|
if (!this.visible || !this.activeAgentId) return;
|
|
155977
156961
|
this.renderExactOverviewCard(this.activeAgentId);
|
|
@@ -155989,15 +156973,51 @@ WARNING: This link could potentially be dangerous`)) {
|
|
|
155989
156973
|
this.openedAt = Date.now();
|
|
155990
156974
|
this.sessionId = null;
|
|
155991
156975
|
this.container.style.display = "flex";
|
|
155992
|
-
|
|
155993
|
-
|
|
155994
|
-
|
|
155995
|
-
|
|
155996
|
-
|
|
155997
|
-
|
|
155998
|
-
|
|
155999
|
-
|
|
156000
|
-
|
|
156976
|
+
try {
|
|
156977
|
+
this.terminal.clear();
|
|
156978
|
+
this.titleEl.textContent = `${options.name} (${options.agentId})`;
|
|
156979
|
+
this.subtitleEl.textContent = options.description;
|
|
156980
|
+
this.updateSpriteCard(options);
|
|
156981
|
+
void this.updateSessionTitle(options.officeId, options.agentId);
|
|
156982
|
+
this.updateSessionIdDisplay();
|
|
156983
|
+
this.setStatus("Opening...");
|
|
156984
|
+
this.applyPanelLayout();
|
|
156985
|
+
this.refitAndResize(options.officeId, options.agentId);
|
|
156986
|
+
} catch (err) {
|
|
156987
|
+
const message = `serious-mode open failed during render: ${err?.message || String(err)}`;
|
|
156988
|
+
try {
|
|
156989
|
+
this.setStatus(message);
|
|
156990
|
+
} catch {
|
|
156991
|
+
}
|
|
156992
|
+
try {
|
|
156993
|
+
this.terminal.writeln(`\r
|
|
156994
|
+
[render error: ${message}]\r
|
|
156995
|
+
`);
|
|
156996
|
+
} catch {
|
|
156997
|
+
}
|
|
156998
|
+
if (DEBUG_SPRITE_SERIOUS) {
|
|
156999
|
+
console.log(
|
|
157000
|
+
`[SeriousTerminalController] openAgentTerminal render failure (officeId=${options.officeId} agentId=${options.agentId}): ${message}`
|
|
157001
|
+
);
|
|
157002
|
+
} else {
|
|
157003
|
+
console.warn("[SeriousTerminalController] openAgentTerminal render failure", err);
|
|
157004
|
+
}
|
|
157005
|
+
}
|
|
157006
|
+
const boundOfficeId = options.officeId;
|
|
157007
|
+
const boundAgentId = options.agentId;
|
|
157008
|
+
try {
|
|
157009
|
+
this.onDataDisposable?.dispose();
|
|
157010
|
+
} catch {
|
|
157011
|
+
}
|
|
157012
|
+
this.onDataDisposable = this.terminal.onData((data) => {
|
|
157013
|
+
if (!window.copilotBridge) return;
|
|
157014
|
+
void window.copilotBridge.terminalWrite(boundOfficeId, boundAgentId, data);
|
|
157015
|
+
});
|
|
157016
|
+
if (DEBUG_SPRITE_SERIOUS) {
|
|
157017
|
+
console.log(
|
|
157018
|
+
`[SeriousTerminalController] onData rebound officeId=${boundOfficeId} agentId=${boundAgentId}`
|
|
157019
|
+
);
|
|
157020
|
+
}
|
|
156001
157021
|
try {
|
|
156002
157022
|
const exists = await window.copilotBridge.terminalExists(options.officeId, options.agentId);
|
|
156003
157023
|
if (!exists) {
|
|
@@ -156049,6 +157069,21 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156049
157069
|
}
|
|
156050
157070
|
async startNewSession(options) {
|
|
156051
157071
|
if (!window.copilotBridge) return;
|
|
157072
|
+
const coordinator = getAutoStartCoordinator();
|
|
157073
|
+
if (coordinator) {
|
|
157074
|
+
try {
|
|
157075
|
+
await coordinator.replaceSession(options.officeId, options.agentId);
|
|
157076
|
+
} catch (err) {
|
|
157077
|
+
console.warn(
|
|
157078
|
+
`[SeriousTerminalController] replaceSession failed for ${options.agentId}: ${err?.message || String(err)}`
|
|
157079
|
+
);
|
|
157080
|
+
}
|
|
157081
|
+
const isCurrentView2 = this.visible && this.activeOfficeId === options.officeId && this.activeAgentId === options.agentId;
|
|
157082
|
+
if (isCurrentView2) {
|
|
157083
|
+
await this.openAgentTerminal(options);
|
|
157084
|
+
}
|
|
157085
|
+
return;
|
|
157086
|
+
}
|
|
156052
157087
|
try {
|
|
156053
157088
|
await window.copilotBridge.resetSession(options.officeId, options.agentId);
|
|
156054
157089
|
} catch {
|
|
@@ -156083,6 +157118,12 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156083
157118
|
}
|
|
156084
157119
|
this.visible = false;
|
|
156085
157120
|
this.container.style.display = "none";
|
|
157121
|
+
this.hideTerminalContextMenu();
|
|
157122
|
+
try {
|
|
157123
|
+
this.onDataDisposable?.dispose();
|
|
157124
|
+
} catch {
|
|
157125
|
+
}
|
|
157126
|
+
this.onDataDisposable = null;
|
|
156086
157127
|
this.activeOfficeId = null;
|
|
156087
157128
|
this.activeAgentId = null;
|
|
156088
157129
|
this.activeOptions = null;
|
|
@@ -156208,7 +157249,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156208
157249
|
border-radius: 8px;
|
|
156209
157250
|
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.45);
|
|
156210
157251
|
padding: 10px 12px;
|
|
156211
|
-
z-index:
|
|
157252
|
+
z-index: ${ZIndex.SERIOUS_TERMINAL};
|
|
156212
157253
|
color: #c8d4ff;
|
|
156213
157254
|
font-size: 12px;
|
|
156214
157255
|
white-space: pre-wrap;
|
|
@@ -156244,17 +157285,166 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156244
157285
|
}
|
|
156245
157286
|
copySessionId() {
|
|
156246
157287
|
if (!this.sessionId) return;
|
|
156247
|
-
|
|
157288
|
+
void this.copyToClipboard(this.sessionId, "session").then((success) => {
|
|
156248
157289
|
const original = this.sessionIdEl.textContent;
|
|
156249
|
-
this.sessionIdEl.textContent = "Copied!";
|
|
156250
|
-
this.sessionIdEl.style.color = "#61d394";
|
|
157290
|
+
this.sessionIdEl.textContent = success ? "Copied!" : "Copy failed";
|
|
157291
|
+
this.sessionIdEl.style.color = success ? "#61d394" : "#ff6b6b";
|
|
156251
157292
|
setTimeout(() => {
|
|
156252
157293
|
this.sessionIdEl.textContent = original;
|
|
156253
157294
|
this.sessionIdEl.style.color = "#8ec3ff";
|
|
156254
157295
|
}, 900);
|
|
156255
|
-
}).catch(() => {
|
|
156256
157296
|
});
|
|
156257
157297
|
}
|
|
157298
|
+
// Spec 006: diagnostic prefix so multi-instance and channel issues
|
|
157299
|
+
// are visible in the toast UI without opening DevTools.
|
|
157300
|
+
tag() {
|
|
157301
|
+
return `[S${this.seriousInstanceId}]`;
|
|
157302
|
+
}
|
|
157303
|
+
// Spec 005 + 006: single canonical clipboard write path via Electron main.
|
|
157304
|
+
// Diagnostic toast on every outcome.
|
|
157305
|
+
async copyToClipboard(text, source = "live") {
|
|
157306
|
+
const t = this.tag();
|
|
157307
|
+
if (!text) {
|
|
157308
|
+
showClipboardToast(`${t} empty selection`, "info");
|
|
157309
|
+
return false;
|
|
157310
|
+
}
|
|
157311
|
+
const bridge = window.copilotBridge;
|
|
157312
|
+
if (!bridge?.clipboardWriteText) {
|
|
157313
|
+
try {
|
|
157314
|
+
await navigator.clipboard.writeText(text);
|
|
157315
|
+
showClipboardToast(`${t} OK ${text.length} (fallback)`, "success");
|
|
157316
|
+
return true;
|
|
157317
|
+
} catch {
|
|
157318
|
+
showClipboardToast(`${t} no-bridge`, "error");
|
|
157319
|
+
return false;
|
|
157320
|
+
}
|
|
157321
|
+
}
|
|
157322
|
+
try {
|
|
157323
|
+
const r = await bridge.clipboardWriteText(text);
|
|
157324
|
+
if (r?.success === true) {
|
|
157325
|
+
showClipboardToast(`${t} OK ${text.length} (verified)`, "success");
|
|
157326
|
+
return true;
|
|
157327
|
+
}
|
|
157328
|
+
if (r?.verified === false) {
|
|
157329
|
+
showClipboardToast(`${t} verify-fail (wrote=${text.length})`, "error");
|
|
157330
|
+
} else {
|
|
157331
|
+
showClipboardToast(`${t} bridge-err: ${r?.error || "unknown"}`, "error");
|
|
157332
|
+
}
|
|
157333
|
+
return false;
|
|
157334
|
+
} catch (e) {
|
|
157335
|
+
showClipboardToast(`${t} bridge-err: ${e?.message || "threw"}`, "error");
|
|
157336
|
+
return false;
|
|
157337
|
+
}
|
|
157338
|
+
}
|
|
157339
|
+
// Spec 005: read OS clipboard via Electron main, forward to PTY.
|
|
157340
|
+
async pasteFromClipboardToTerminal() {
|
|
157341
|
+
if (!this.activeOfficeId || !this.activeAgentId || !window.copilotBridge) return;
|
|
157342
|
+
let text = "";
|
|
157343
|
+
try {
|
|
157344
|
+
const bridge = window.copilotBridge;
|
|
157345
|
+
if (bridge?.clipboardReadText) {
|
|
157346
|
+
const r = await bridge.clipboardReadText();
|
|
157347
|
+
if (r?.success) text = r.text || "";
|
|
157348
|
+
} else if (navigator.clipboard?.readText) {
|
|
157349
|
+
text = await navigator.clipboard.readText();
|
|
157350
|
+
}
|
|
157351
|
+
} catch (e) {
|
|
157352
|
+
showClipboardToast(`Paste failed: ${e?.message || "bridge threw"}`, "error");
|
|
157353
|
+
return;
|
|
157354
|
+
}
|
|
157355
|
+
if (!text) {
|
|
157356
|
+
showClipboardToast("Clipboard is empty", "info");
|
|
157357
|
+
return;
|
|
157358
|
+
}
|
|
157359
|
+
try {
|
|
157360
|
+
await window.copilotBridge.terminalWrite(this.activeOfficeId, this.activeAgentId, text);
|
|
157361
|
+
showClipboardToast(`Pasted ${text.length} char${text.length === 1 ? "" : "s"}`, "success");
|
|
157362
|
+
} catch (e) {
|
|
157363
|
+
showClipboardToast(`Paste failed: ${e?.message || "terminalWrite threw"}`, "error");
|
|
157364
|
+
}
|
|
157365
|
+
}
|
|
157366
|
+
/**
|
|
157367
|
+
* Spec 004: terminal right-click context menu (Copy / Paste). Built once
|
|
157368
|
+
* during attachTerminal, reused per right-click. Dismissed on outside
|
|
157369
|
+
* mousedown or Escape.
|
|
157370
|
+
*/
|
|
157371
|
+
installTerminalContextMenu() {
|
|
157372
|
+
if (!this.terminal || !this.terminalDivEl) return;
|
|
157373
|
+
const menu = document.createElement("div");
|
|
157374
|
+
menu.id = "serious-terminal-context-menu";
|
|
157375
|
+
menu.style.cssText = `
|
|
157376
|
+
position: fixed;
|
|
157377
|
+
display: none;
|
|
157378
|
+
z-index: ${ZIndex.TERMINAL_SPRITE_CARD + 10};
|
|
157379
|
+
min-width: 160px;
|
|
157380
|
+
background: #1c1c2a;
|
|
157381
|
+
border: 1px solid #3a3a55;
|
|
157382
|
+
border-radius: 6px;
|
|
157383
|
+
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.55);
|
|
157384
|
+
padding: 4px 0;
|
|
157385
|
+
font-family: 'Cascadia Code', Consolas, monospace;
|
|
157386
|
+
font-size: 13px;
|
|
157387
|
+
color: #cfd0e0;
|
|
157388
|
+
user-select: none;
|
|
157389
|
+
`;
|
|
157390
|
+
const makeItem = (label, onClick) => {
|
|
157391
|
+
const item = document.createElement("div");
|
|
157392
|
+
item.textContent = label;
|
|
157393
|
+
item.style.cssText = `padding: 6px 14px; cursor: pointer;`;
|
|
157394
|
+
item.dataset.enabled = "true";
|
|
157395
|
+
item.addEventListener("mouseenter", () => {
|
|
157396
|
+
if (item.dataset.enabled === "true") item.style.background = "#2a2a45";
|
|
157397
|
+
});
|
|
157398
|
+
item.addEventListener("mouseleave", () => {
|
|
157399
|
+
item.style.background = "";
|
|
157400
|
+
});
|
|
157401
|
+
item.addEventListener("mousedown", (e) => {
|
|
157402
|
+
e.preventDefault();
|
|
157403
|
+
e.stopPropagation();
|
|
157404
|
+
});
|
|
157405
|
+
item.addEventListener("click", (e) => {
|
|
157406
|
+
e.preventDefault();
|
|
157407
|
+
e.stopPropagation();
|
|
157408
|
+
if (item.dataset.enabled !== "true") return;
|
|
157409
|
+
this.hideTerminalContextMenu();
|
|
157410
|
+
onClick();
|
|
157411
|
+
});
|
|
157412
|
+
return item;
|
|
157413
|
+
};
|
|
157414
|
+
const copyItem = makeItem("Copy", () => {
|
|
157415
|
+
const selection = this.terminal?.hasSelection() ? this.terminal.getSelection() ?? "" : "";
|
|
157416
|
+
void this.copyToClipboard(selection, "live");
|
|
157417
|
+
});
|
|
157418
|
+
const pasteItem = makeItem("Paste", () => {
|
|
157419
|
+
void this.pasteFromClipboardToTerminal();
|
|
157420
|
+
});
|
|
157421
|
+
menu.appendChild(copyItem);
|
|
157422
|
+
menu.appendChild(pasteItem);
|
|
157423
|
+
document.body.appendChild(menu);
|
|
157424
|
+
this.terminalContextMenu = menu;
|
|
157425
|
+
this.terminalDivEl.addEventListener("contextmenu", (event) => {
|
|
157426
|
+
if (!this.visible) return;
|
|
157427
|
+
event.preventDefault();
|
|
157428
|
+
const vw = window.innerWidth;
|
|
157429
|
+
const vh = window.innerHeight;
|
|
157430
|
+
menu.style.display = "block";
|
|
157431
|
+
const rect = menu.getBoundingClientRect();
|
|
157432
|
+
const left = Math.min(event.clientX, vw - rect.width - 4);
|
|
157433
|
+
const top = Math.min(event.clientY, vh - rect.height - 4);
|
|
157434
|
+
menu.style.left = `${Math.max(0, left)}px`;
|
|
157435
|
+
menu.style.top = `${Math.max(0, top)}px`;
|
|
157436
|
+
});
|
|
157437
|
+
this.terminalContextMenuDismiss = (e) => {
|
|
157438
|
+
if (!this.terminalContextMenu || this.terminalContextMenu.style.display === "none") return;
|
|
157439
|
+
if (e instanceof KeyboardEvent && e.key !== "Escape") return;
|
|
157440
|
+
this.hideTerminalContextMenu();
|
|
157441
|
+
};
|
|
157442
|
+
document.addEventListener("mousedown", this.terminalContextMenuDismiss, true);
|
|
157443
|
+
document.addEventListener("keydown", this.terminalContextMenuDismiss, true);
|
|
157444
|
+
}
|
|
157445
|
+
hideTerminalContextMenu() {
|
|
157446
|
+
if (this.terminalContextMenu) this.terminalContextMenu.style.display = "none";
|
|
157447
|
+
}
|
|
156258
157448
|
renderAgentSprite(seed, baseColor) {
|
|
156259
157449
|
const ctx = this.spriteCanvasEl.getContext("2d");
|
|
156260
157450
|
if (!ctx) return;
|
|
@@ -156292,15 +157482,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156292
157482
|
return r << 16 | g << 8 | b;
|
|
156293
157483
|
}
|
|
156294
157484
|
ensureXtermStyles() {
|
|
156295
|
-
|
|
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);
|
|
157485
|
+
ensureXtermStyles();
|
|
156304
157486
|
}
|
|
156305
157487
|
createTerminal() {
|
|
156306
157488
|
this.terminal = new import_xterm2.Terminal({
|
|
@@ -156323,28 +157505,43 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156323
157505
|
this.terminal.loadAddon(this.fitAddon);
|
|
156324
157506
|
this.terminalDivEl.id = "serious-terminal-container";
|
|
156325
157507
|
this.terminal.open(this.terminalDivEl);
|
|
157508
|
+
const MOUSE_MODES = /* @__PURE__ */ new Set([1e3, 1002, 1003, 1006]);
|
|
157509
|
+
this.terminal.parser.registerCsiHandler({ prefix: "?", final: "h" }, (params) => {
|
|
157510
|
+
for (const p of params) {
|
|
157511
|
+
if (typeof p === "number" && MOUSE_MODES.has(p)) return true;
|
|
157512
|
+
}
|
|
157513
|
+
return false;
|
|
157514
|
+
});
|
|
157515
|
+
this.terminal.attachCustomWheelEventHandler((event) => {
|
|
157516
|
+
const term = this.terminal;
|
|
157517
|
+
if (!term) return true;
|
|
157518
|
+
if (term.buffer.active.type !== "alternate") return true;
|
|
157519
|
+
const seq = wheelToPtySequence(event.deltaY);
|
|
157520
|
+
if (!seq) return true;
|
|
157521
|
+
if (this.activeOfficeId && this.activeAgentId && window.copilotBridge) {
|
|
157522
|
+
void window.copilotBridge.terminalWrite(this.activeOfficeId, this.activeAgentId, seq);
|
|
157523
|
+
}
|
|
157524
|
+
return false;
|
|
157525
|
+
});
|
|
157526
|
+
this.installTerminalContextMenu();
|
|
156326
157527
|
this.terminal.attachCustomKeyEventHandler((event) => {
|
|
156327
157528
|
const isModifierPressed = event.ctrlKey || event.metaKey;
|
|
156328
157529
|
const key = event.key.toLowerCase();
|
|
156329
157530
|
if (event.type !== "keydown" || !isModifierPressed) return true;
|
|
156330
157531
|
if (key === "c") {
|
|
156331
|
-
const
|
|
156332
|
-
if (!
|
|
157532
|
+
const selection = this.terminal?.hasSelection() ? this.terminal.getSelection() ?? "" : "";
|
|
157533
|
+
if (!selection) {
|
|
156333
157534
|
return true;
|
|
156334
157535
|
}
|
|
156335
157536
|
event.preventDefault();
|
|
156336
157537
|
event.stopPropagation();
|
|
156337
|
-
|
|
156338
|
-
});
|
|
157538
|
+
void this.copyToClipboard(selection, "live");
|
|
156339
157539
|
return false;
|
|
156340
157540
|
}
|
|
156341
157541
|
if (key === "v") {
|
|
156342
157542
|
event.preventDefault();
|
|
156343
157543
|
event.stopPropagation();
|
|
156344
|
-
|
|
156345
|
-
if (text) this.terminal?.paste(text);
|
|
156346
|
-
}).catch(() => {
|
|
156347
|
-
});
|
|
157544
|
+
void this.pasteFromClipboardToTerminal();
|
|
156348
157545
|
return false;
|
|
156349
157546
|
}
|
|
156350
157547
|
if (key === "f") {
|
|
@@ -156355,9 +157552,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156355
157552
|
}
|
|
156356
157553
|
return true;
|
|
156357
157554
|
});
|
|
156358
|
-
this.terminal.onData((
|
|
156359
|
-
if (!window.copilotBridge || !this.activeOfficeId || !this.activeAgentId) return;
|
|
156360
|
-
void window.copilotBridge.terminalWrite(this.activeOfficeId, this.activeAgentId, data);
|
|
157555
|
+
this.terminal.onData((_data) => {
|
|
156361
157556
|
});
|
|
156362
157557
|
this.resizeHandler = () => {
|
|
156363
157558
|
if (!this.visible || !this.activeOfficeId || !this.activeAgentId) return;
|
|
@@ -156443,6 +157638,48 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156443
157638
|
}
|
|
156444
157639
|
});
|
|
156445
157640
|
|
|
157641
|
+
// src/util/toolStatus.ts
|
|
157642
|
+
function normalizeToolName(toolName) {
|
|
157643
|
+
return (toolName ?? "").trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
157644
|
+
}
|
|
157645
|
+
function isAskUserTool(toolName, status) {
|
|
157646
|
+
const normalized = normalizeToolName(toolName);
|
|
157647
|
+
if (normalized === "ask_user" || normalized === "askuser") return true;
|
|
157648
|
+
const statusText = (status ?? "").toLowerCase();
|
|
157649
|
+
return statusText.includes("waiting for your answer") || statusText.includes("waiting on user input");
|
|
157650
|
+
}
|
|
157651
|
+
function nextSubStateAfterToolComplete(remainingTools) {
|
|
157652
|
+
if (remainingTools.length === 0) return { kind: "idle" };
|
|
157653
|
+
if (remainingTools.some((t) => isAskUserTool(t.name, t.status))) {
|
|
157654
|
+
return { kind: "waiting" };
|
|
157655
|
+
}
|
|
157656
|
+
const last = remainingTools[remainingTools.length - 1];
|
|
157657
|
+
return { kind: "thinking", detail: String(last.name ?? "") };
|
|
157658
|
+
}
|
|
157659
|
+
var init_toolStatus = __esm({
|
|
157660
|
+
"src/util/toolStatus.ts"() {
|
|
157661
|
+
"use strict";
|
|
157662
|
+
}
|
|
157663
|
+
});
|
|
157664
|
+
|
|
157665
|
+
// src/util/startupTimeoutGuard.ts
|
|
157666
|
+
function decideStartupTimeoutTransition(inputs) {
|
|
157667
|
+
if (inputs.subState !== "starting") return { kind: "no-transition" };
|
|
157668
|
+
if (!inputs.activityStartTime) return { kind: "no-transition" };
|
|
157669
|
+
if (inputs.now - inputs.activityStartTime <= inputs.timeoutMs) {
|
|
157670
|
+
return { kind: "no-transition" };
|
|
157671
|
+
}
|
|
157672
|
+
if (inputs.serverAlive === true) {
|
|
157673
|
+
return { kind: "recover-to-ready" };
|
|
157674
|
+
}
|
|
157675
|
+
return { kind: "transition-to-error", reason: "Startup timed out" };
|
|
157676
|
+
}
|
|
157677
|
+
var init_startupTimeoutGuard = __esm({
|
|
157678
|
+
"src/util/startupTimeoutGuard.ts"() {
|
|
157679
|
+
"use strict";
|
|
157680
|
+
}
|
|
157681
|
+
});
|
|
157682
|
+
|
|
156446
157683
|
// src/main.ts
|
|
156447
157684
|
var require_main = __commonJS({
|
|
156448
157685
|
"src/main.ts"() {
|
|
@@ -156453,6 +157690,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156453
157690
|
init_officeManager();
|
|
156454
157691
|
init_agents();
|
|
156455
157692
|
init_responsiveLayout();
|
|
157693
|
+
init_zIndex();
|
|
156456
157694
|
init_layouts();
|
|
156457
157695
|
init_ToastNotification();
|
|
156458
157696
|
init_NotificationService();
|
|
@@ -156460,7 +157698,12 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156460
157698
|
init_SpriteCustomizerPanel();
|
|
156461
157699
|
init_SeriousTerminalController();
|
|
156462
157700
|
init_SpriteGenerator();
|
|
157701
|
+
init_toolStatus();
|
|
157702
|
+
init_startupTimeoutGuard();
|
|
157703
|
+
init_AutoStartCoordinator();
|
|
157704
|
+
init_agentAutoStart();
|
|
156463
157705
|
officeManager.ensureDefaultOffice();
|
|
157706
|
+
recordOfficeAccess(officeManager.currentOfficeId);
|
|
156464
157707
|
function getCurrentLayout() {
|
|
156465
157708
|
return officeManager.currentOffice?.config.layout ?? "default";
|
|
156466
157709
|
}
|
|
@@ -156478,15 +157721,6 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156478
157721
|
restoreSeatedReserveAgents(officeManager.getSeatedAgents(office.config.id));
|
|
156479
157722
|
}
|
|
156480
157723
|
}
|
|
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
157724
|
function isDonePendingAck(status) {
|
|
156491
157725
|
return !!status?.completionPendingAck;
|
|
156492
157726
|
}
|
|
@@ -156500,6 +157734,25 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156500
157734
|
var SESSION_META_CACHE_STORAGE_KEY = "agencyOffice:sessionMetaCacheByOffice";
|
|
156501
157735
|
var OVERVIEW_SPRITE_CACHE_STORAGE_KEY = "agencyOffice:overviewSpriteCache";
|
|
156502
157736
|
var PC_TERMINAL_ID2 = "pc-terminal";
|
|
157737
|
+
var OFFICE_SORT_STORAGE_KEY = "agencyOffice:officeSortMode";
|
|
157738
|
+
var OFFICE_ACCESS_TIMES_KEY = "agencyOffice:officeAccessTimes";
|
|
157739
|
+
var officeSortMode = localStorage.getItem(OFFICE_SORT_STORAGE_KEY) || "default";
|
|
157740
|
+
function getOfficeAccessTimes() {
|
|
157741
|
+
try {
|
|
157742
|
+
const raw = localStorage.getItem(OFFICE_ACCESS_TIMES_KEY);
|
|
157743
|
+
return raw ? JSON.parse(raw) : {};
|
|
157744
|
+
} catch {
|
|
157745
|
+
return {};
|
|
157746
|
+
}
|
|
157747
|
+
}
|
|
157748
|
+
function recordOfficeAccess(officeId) {
|
|
157749
|
+
const times = getOfficeAccessTimes();
|
|
157750
|
+
times[officeId] = Date.now();
|
|
157751
|
+
try {
|
|
157752
|
+
localStorage.setItem(OFFICE_ACCESS_TIMES_KEY, JSON.stringify(times));
|
|
157753
|
+
} catch {
|
|
157754
|
+
}
|
|
157755
|
+
}
|
|
156503
157756
|
function sanitizeAppMode(value) {
|
|
156504
157757
|
return value === "serious" ? "serious" : "game";
|
|
156505
157758
|
}
|
|
@@ -156725,6 +157978,17 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156725
157978
|
if (previousMode === "serious" && appMode === "game") {
|
|
156726
157979
|
void seriousTerminalController?.closeView({ detach: true, silent: true });
|
|
156727
157980
|
}
|
|
157981
|
+
if (previousMode === "game" && appMode === "serious") {
|
|
157982
|
+
try {
|
|
157983
|
+
const scene = phaserGameRef?.scene.getScene("OfficeScene");
|
|
157984
|
+
const overlay = scene?.getTerminalOverlay?.();
|
|
157985
|
+
if (overlay?.getIsVisible?.()) {
|
|
157986
|
+
overlay.hide?.();
|
|
157987
|
+
}
|
|
157988
|
+
} catch (err) {
|
|
157989
|
+
console.warn("[main] failed to hide game-mode terminal overlay on mode flip", err);
|
|
157990
|
+
}
|
|
157991
|
+
}
|
|
156728
157992
|
if (appMode === "serious") {
|
|
156729
157993
|
prewarmOverviewSpriteCacheFromTextures();
|
|
156730
157994
|
teardownPhaserGame();
|
|
@@ -156763,9 +158027,86 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156763
158027
|
if (typeof window !== "undefined") {
|
|
156764
158028
|
window.__copilotOfficeMobileModeActive = isMobileModeActive;
|
|
156765
158029
|
}
|
|
158030
|
+
if (typeof window !== "undefined" && window.__copilotOfficeE2E === true) {
|
|
158031
|
+
installE2eDebugHook();
|
|
158032
|
+
}
|
|
158033
|
+
function installE2eDebugHook() {
|
|
158034
|
+
const debugApi = {
|
|
158035
|
+
getActiveMode: () => appMode,
|
|
158036
|
+
setMode: (mode) => {
|
|
158037
|
+
if (mode === appMode) return;
|
|
158038
|
+
applyAppMode(mode, { persist: true, refreshTabs: true });
|
|
158039
|
+
},
|
|
158040
|
+
getCurrentOfficeId: () => officeManager.currentOfficeId,
|
|
158041
|
+
listAgents: () => {
|
|
158042
|
+
return getCurrentAgents().map((a) => ({
|
|
158043
|
+
id: a.id,
|
|
158044
|
+
name: a.name,
|
|
158045
|
+
tileX: a.tileX,
|
|
158046
|
+
tileY: a.tileY
|
|
158047
|
+
}));
|
|
158048
|
+
},
|
|
158049
|
+
getActiveTerminalAgentId: () => {
|
|
158050
|
+
if (appMode === "serious") {
|
|
158051
|
+
return seriousTerminalController?.getActiveAgentId?.() ?? null;
|
|
158052
|
+
}
|
|
158053
|
+
const scene = phaserGameRef?.scene.getScene("OfficeScene");
|
|
158054
|
+
const overlay = scene?.getTerminalOverlay?.();
|
|
158055
|
+
if (!overlay || !overlay.getIsVisible()) return null;
|
|
158056
|
+
return overlay.getActiveAgentId();
|
|
158057
|
+
},
|
|
158058
|
+
openAgentTerminal: async (agentId) => {
|
|
158059
|
+
await openAgentTerminal(agentId);
|
|
158060
|
+
},
|
|
158061
|
+
closeActiveTerminal: async () => {
|
|
158062
|
+
if (appMode === "serious") {
|
|
158063
|
+
await seriousTerminalController?.closeView({ detach: true });
|
|
158064
|
+
return;
|
|
158065
|
+
}
|
|
158066
|
+
const scene = phaserGameRef?.scene.getScene("OfficeScene");
|
|
158067
|
+
scene?.getTerminalOverlay?.()?.hide();
|
|
158068
|
+
},
|
|
158069
|
+
switchOffice: (officeId) => {
|
|
158070
|
+
switchToOffice(officeId);
|
|
158071
|
+
},
|
|
158072
|
+
getCachedSessionMetaForRender: () => {
|
|
158073
|
+
return { ...cachedSessionMeta };
|
|
158074
|
+
},
|
|
158075
|
+
getSeriousPanelSnapshot: () => {
|
|
158076
|
+
if (appMode !== "serious") return null;
|
|
158077
|
+
const snap = seriousTerminalController?.getPanelSnapshot?.();
|
|
158078
|
+
return snap ?? null;
|
|
158079
|
+
},
|
|
158080
|
+
getWarmedOfficeIds: () => autoStartCoordinator.warmedOffices.snapshot(),
|
|
158081
|
+
getAutoStartTerminalStartCount: () => autoStartTerminalStartCount,
|
|
158082
|
+
triggerAutoStartForCurrentOffice: () => autoStartCoordinator.tryWarmCurrentOffice(),
|
|
158083
|
+
replaceAgentSession: (officeId, agentId) => autoStartCoordinator.replaceSession(officeId, agentId),
|
|
158084
|
+
setAutoStartEnabled: (enabled) => {
|
|
158085
|
+
setAgentAutoStartSettings({ autoStartKnownAgents: enabled });
|
|
158086
|
+
},
|
|
158087
|
+
getAutoStartEnabled: () => getAgentAutoStartSettings().autoStartKnownAgents,
|
|
158088
|
+
clearWarmedOfficeRegistry: () => {
|
|
158089
|
+
autoStartCoordinator.warmedOffices.clearAll();
|
|
158090
|
+
},
|
|
158091
|
+
getCurrentSessionIdForAgent: async (officeId, agentId) => {
|
|
158092
|
+
if (!window.copilotBridge?.getSessionId) return null;
|
|
158093
|
+
try {
|
|
158094
|
+
return await window.copilotBridge.getSessionId(officeId, agentId);
|
|
158095
|
+
} catch {
|
|
158096
|
+
return null;
|
|
158097
|
+
}
|
|
158098
|
+
}
|
|
158099
|
+
};
|
|
158100
|
+
window.__copilotOfficeDebug = debugApi;
|
|
158101
|
+
console.log("[main] Spec 008-smoke: __copilotOfficeDebug installed");
|
|
158102
|
+
}
|
|
156766
158103
|
function renderOfficeTabs() {
|
|
156767
|
-
|
|
158104
|
+
let offices = officeManager.getAllOffices();
|
|
156768
158105
|
const currentId = officeManager.currentOfficeId;
|
|
158106
|
+
if (officeSortMode === "recent") {
|
|
158107
|
+
const accessTimes = getOfficeAccessTimes();
|
|
158108
|
+
offices = [...offices].sort((a, b) => (accessTimes[b.id] || 0) - (accessTimes[a.id] || 0));
|
|
158109
|
+
}
|
|
156769
158110
|
let html = "";
|
|
156770
158111
|
for (const office of offices) {
|
|
156771
158112
|
const isActive = office.id === currentId;
|
|
@@ -156976,6 +158317,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156976
158317
|
selectedAgentId = null;
|
|
156977
158318
|
void seriousTerminalController?.closeView({ detach: true });
|
|
156978
158319
|
officeManager.switchOffice(officeId);
|
|
158320
|
+
recordOfficeAccess(officeId);
|
|
156979
158321
|
cachedSessionMeta = getSessionMetaCacheForOffice(officeId);
|
|
156980
158322
|
syncActiveRosterForCurrentOffice();
|
|
156981
158323
|
phaserGameRef?.events.emit("office:switch", officeId, officeManager.currentOffice?.config.workingDirectory);
|
|
@@ -156984,6 +158326,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156984
158326
|
updateStatusBar();
|
|
156985
158327
|
void reconnectAgentStatuses();
|
|
156986
158328
|
fetchSessionMeta();
|
|
158329
|
+
void autoStartCoordinator.tryWarmCurrentOffice();
|
|
156987
158330
|
console.log(`[Office] Switched to office: ${officeManager.currentOffice?.config.name}`);
|
|
156988
158331
|
}
|
|
156989
158332
|
function showNewOfficeDialog() {
|
|
@@ -156991,7 +158334,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
156991
158334
|
const overlay = document.createElement("div");
|
|
156992
158335
|
overlay.style.cssText = `
|
|
156993
158336
|
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
|
156994
|
-
background: rgba(0,0,0,0.7); z-index:
|
|
158337
|
+
background: rgba(0,0,0,0.7); z-index: ${ZIndex.MODAL_DIALOG};
|
|
156995
158338
|
display: flex; align-items: center; justify-content: center;
|
|
156996
158339
|
`;
|
|
156997
158340
|
const dialog = document.createElement("div");
|
|
@@ -157104,7 +158447,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157104
158447
|
min-width: 280px;
|
|
157105
158448
|
font-family: 'Cascadia Code', Consolas, monospace;
|
|
157106
158449
|
color: #eee;
|
|
157107
|
-
z-index:
|
|
158450
|
+
z-index: ${ZIndex.TOP_MODAL};
|
|
157108
158451
|
box-shadow: 0 8px 24px rgba(0,0,0,0.5);
|
|
157109
158452
|
`;
|
|
157110
158453
|
const escapeHtml = (s) => s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
@@ -157193,20 +158536,49 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157193
158536
|
<div id="terminal-title" style="font-size: 18px; font-weight: bold; color: #8af; margin-bottom: 4px;">\u{1F3E2} Office Overview</div>
|
|
157194
158537
|
<div id="terminal-subtitle" style="font-size: 12px; color: #555;"></div>
|
|
157195
158538
|
</div>
|
|
157196
|
-
<
|
|
157197
|
-
|
|
157198
|
-
|
|
157199
|
-
|
|
157200
|
-
|
|
157201
|
-
|
|
157202
|
-
|
|
157203
|
-
|
|
157204
|
-
|
|
157205
|
-
|
|
157206
|
-
|
|
157207
|
-
|
|
158539
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
158540
|
+
<button id="office-sort-btn" style="
|
|
158541
|
+
padding: 6px 12px;
|
|
158542
|
+
background: ${officeSortMode === "recent" ? "#2a3a5a" : "#252538"};
|
|
158543
|
+
color: ${officeSortMode === "recent" ? "#8af" : "#666"};
|
|
158544
|
+
border: 1px solid ${officeSortMode === "recent" ? "#4488ff" : "#444"};
|
|
158545
|
+
border-radius: 4px;
|
|
158546
|
+
font-family: 'Cascadia Code', Consolas, monospace;
|
|
158547
|
+
font-size: 12px;
|
|
158548
|
+
cursor: pointer;
|
|
158549
|
+
white-space: nowrap;
|
|
158550
|
+
transition: all 0.2s;
|
|
158551
|
+
" title="Sort office tabs">\u21C5 ${officeSortMode === "recent" ? "Recent" : "Default"}</button>
|
|
158552
|
+
<button id="close-office-btn" style="
|
|
158553
|
+
display: none;
|
|
158554
|
+
padding: 6px 14px;
|
|
158555
|
+
background: #cc3344;
|
|
158556
|
+
color: #fff;
|
|
158557
|
+
border: none;
|
|
158558
|
+
border-radius: 4px;
|
|
158559
|
+
font-family: 'Cascadia Code', Consolas, monospace;
|
|
158560
|
+
font-size: 12px;
|
|
158561
|
+
cursor: pointer;
|
|
158562
|
+
white-space: nowrap;
|
|
158563
|
+
">\u2715 Close Office</button>
|
|
158564
|
+
</div>
|
|
157208
158565
|
`;
|
|
157209
158566
|
overviewHost.appendChild(overviewHeader);
|
|
158567
|
+
document.getElementById("office-sort-btn").addEventListener("click", () => {
|
|
158568
|
+
officeSortMode = officeSortMode === "default" ? "recent" : "default";
|
|
158569
|
+
try {
|
|
158570
|
+
localStorage.setItem(OFFICE_SORT_STORAGE_KEY, officeSortMode);
|
|
158571
|
+
} catch {
|
|
158572
|
+
}
|
|
158573
|
+
renderOfficeTabs();
|
|
158574
|
+
const sortBtn = document.getElementById("office-sort-btn");
|
|
158575
|
+
if (sortBtn) {
|
|
158576
|
+
sortBtn.textContent = `\u21C5 ${officeSortMode === "recent" ? "Recent" : "Default"}`;
|
|
158577
|
+
sortBtn.style.background = officeSortMode === "recent" ? "#2a3a5a" : "#252538";
|
|
158578
|
+
sortBtn.style.color = officeSortMode === "recent" ? "#8af" : "#666";
|
|
158579
|
+
sortBtn.style.borderColor = officeSortMode === "recent" ? "#4488ff" : "#444";
|
|
158580
|
+
}
|
|
158581
|
+
});
|
|
157210
158582
|
document.getElementById("close-office-btn").addEventListener("click", () => {
|
|
157211
158583
|
const currentId = officeManager.currentOfficeId;
|
|
157212
158584
|
const office = officeManager.currentOffice;
|
|
@@ -157244,7 +158616,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157244
158616
|
font-family: monospace;
|
|
157245
158617
|
font-size: 16px;
|
|
157246
158618
|
color: #888;
|
|
157247
|
-
z-index:
|
|
158619
|
+
z-index: ${ZIndex.STATUS_BAR};
|
|
157248
158620
|
`;
|
|
157249
158621
|
document.body.appendChild(statusBar);
|
|
157250
158622
|
var bgmMuted = localStorage.getItem("copilot-office-bgm-muted") !== "false";
|
|
@@ -157324,6 +158696,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157324
158696
|
seriousPlaceholder.style.display = "none";
|
|
157325
158697
|
}
|
|
157326
158698
|
async function openAgentTerminal(agentId) {
|
|
158699
|
+
selectedAgentId = agentId;
|
|
157327
158700
|
if (appMode === "game") {
|
|
157328
158701
|
phaserGameRef?.events.emit("open:agent:terminal", agentId);
|
|
157329
158702
|
return;
|
|
@@ -157353,6 +158726,80 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157353
158726
|
updateTerminalContent();
|
|
157354
158727
|
}
|
|
157355
158728
|
});
|
|
158729
|
+
var autoStartTerminalStartCount = 0;
|
|
158730
|
+
async function warmAgentSession(officeId, agentId) {
|
|
158731
|
+
if (!window.copilotBridge) return;
|
|
158732
|
+
const launchConfig = getSeriousLaunchConfig(agentId);
|
|
158733
|
+
if (!launchConfig) return;
|
|
158734
|
+
const workingDir = launchConfig.workingDir;
|
|
158735
|
+
const launchMode = launchConfig.launchMode;
|
|
158736
|
+
const officeStatus = officeManager.getAgentStatus(officeId, agentId);
|
|
158737
|
+
if (officeStatus?.state === "slacking") {
|
|
158738
|
+
officeManager.setAgentStarting(officeId, agentId);
|
|
158739
|
+
phaserGameRef?.events.emit("agent:status:changed", agentId);
|
|
158740
|
+
updateStatusBar();
|
|
158741
|
+
updateTerminalContent();
|
|
158742
|
+
}
|
|
158743
|
+
autoStartTerminalStartCount += 1;
|
|
158744
|
+
await window.copilotBridge.terminalStart(
|
|
158745
|
+
officeId,
|
|
158746
|
+
agentId,
|
|
158747
|
+
workingDir,
|
|
158748
|
+
void 0,
|
|
158749
|
+
void 0,
|
|
158750
|
+
void 0,
|
|
158751
|
+
launchMode
|
|
158752
|
+
);
|
|
158753
|
+
}
|
|
158754
|
+
function buildCanonicalAgentIdsForOffice(officeId) {
|
|
158755
|
+
const office = officeManager.currentOfficeId === officeId ? officeManager.currentOffice : null;
|
|
158756
|
+
if (office && officeManager.currentOfficeId === officeId) {
|
|
158757
|
+
return getCurrentAgents().map((a) => a.id);
|
|
158758
|
+
}
|
|
158759
|
+
const layoutKey = officeManager.currentOffice?.config.layout ?? "default";
|
|
158760
|
+
const layoutAgents = getLayout(layoutKey).agents.map((a) => a.id);
|
|
158761
|
+
const customIds = (officeManager.currentOffice?.config.customAgents ?? []).map(
|
|
158762
|
+
(a) => a.id
|
|
158763
|
+
);
|
|
158764
|
+
return Array.from(/* @__PURE__ */ new Set([...layoutAgents, ...customIds]));
|
|
158765
|
+
}
|
|
158766
|
+
var autoStartCoordinator = new AutoStartCoordinator({
|
|
158767
|
+
getCurrentOfficeId: () => officeManager.currentOfficeId,
|
|
158768
|
+
getCanonicalAgentIds: (oid) => buildCanonicalAgentIdsForOffice(oid),
|
|
158769
|
+
getSessionMeta: async (oid) => {
|
|
158770
|
+
if (!window.copilotBridge?.getAllSessionMeta) {
|
|
158771
|
+
return officeManager.currentOfficeId === oid ? cachedSessionMeta : getSessionMetaCacheForOffice(oid);
|
|
158772
|
+
}
|
|
158773
|
+
try {
|
|
158774
|
+
const fresh = await window.copilotBridge.getAllSessionMeta(oid);
|
|
158775
|
+
return fresh || {};
|
|
158776
|
+
} catch {
|
|
158777
|
+
return officeManager.currentOfficeId === oid ? cachedSessionMeta : getSessionMetaCacheForOffice(oid);
|
|
158778
|
+
}
|
|
158779
|
+
},
|
|
158780
|
+
getCurrentSessionId: async (oid, aid) => {
|
|
158781
|
+
if (!window.copilotBridge?.getSessionId) return null;
|
|
158782
|
+
try {
|
|
158783
|
+
return await window.copilotBridge.getSessionId(oid, aid);
|
|
158784
|
+
} catch {
|
|
158785
|
+
return null;
|
|
158786
|
+
}
|
|
158787
|
+
},
|
|
158788
|
+
getAgentLaunchConfig: (_oid, aid) => {
|
|
158789
|
+
const cfg = getSeriousLaunchConfig(aid);
|
|
158790
|
+
return {
|
|
158791
|
+
workingDir: cfg?.workingDir ?? officeManager.getCurrentWorkingDirectory(),
|
|
158792
|
+
launchMode: cfg?.launchMode ?? "copilot"
|
|
158793
|
+
};
|
|
158794
|
+
},
|
|
158795
|
+
resetSession: async (oid, aid) => {
|
|
158796
|
+
if (!window.copilotBridge) return;
|
|
158797
|
+
await window.copilotBridge.resetSession(oid, aid);
|
|
158798
|
+
},
|
|
158799
|
+
warmAgentSession: (oid, aid) => warmAgentSession(oid, aid),
|
|
158800
|
+
getSettings: () => getAgentAutoStartSettings()
|
|
158801
|
+
});
|
|
158802
|
+
setAutoStartCoordinator(autoStartCoordinator);
|
|
157356
158803
|
var notificationService = new NotificationService(
|
|
157357
158804
|
toastManager,
|
|
157358
158805
|
(agentId) => {
|
|
@@ -157408,6 +158855,14 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157408
158855
|
const base64 = scene.textures.getBase64("player");
|
|
157409
158856
|
spriteCustomizerPanel.updatePreview(base64);
|
|
157410
158857
|
}
|
|
158858
|
+
},
|
|
158859
|
+
// Route focus through InputManager: reuse the settings:open / settings:close
|
|
158860
|
+
// bus that OfficeScene already wires to suspendGameInput / resumeGameInput.
|
|
158861
|
+
onOpen: () => {
|
|
158862
|
+
phaserGameRef?.events.emit("settings:open");
|
|
158863
|
+
},
|
|
158864
|
+
onClose: () => {
|
|
158865
|
+
phaserGameRef?.events.emit("settings:close");
|
|
157411
158866
|
}
|
|
157412
158867
|
});
|
|
157413
158868
|
var lastTerminalContentHtml = "";
|
|
@@ -157593,10 +159048,27 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157593
159048
|
e.stopPropagation();
|
|
157594
159049
|
const agentId = metaPanel.dataset.agent;
|
|
157595
159050
|
if (!agentId) return;
|
|
159051
|
+
const idBadge = target.closest(".session-id-badge");
|
|
159052
|
+
if (idBadge) {
|
|
159053
|
+
const fullId = idBadge.dataset.sessionId ?? idBadge.textContent?.trim() ?? "";
|
|
159054
|
+
if (fullId) {
|
|
159055
|
+
void navigator.clipboard?.writeText(fullId).catch(() => {
|
|
159056
|
+
});
|
|
159057
|
+
const original = idBadge.textContent;
|
|
159058
|
+
idBadge.textContent = "\u2713 copied";
|
|
159059
|
+
setTimeout(() => {
|
|
159060
|
+
if (idBadge) idBadge.textContent = original;
|
|
159061
|
+
}, 700);
|
|
159062
|
+
}
|
|
159063
|
+
return;
|
|
159064
|
+
}
|
|
157596
159065
|
layout.clickHandler.handleMetaPanelClick(target, agentId, {
|
|
157597
159066
|
startSessionMetaEdit,
|
|
157598
159067
|
startNewSession: (id) => {
|
|
157599
159068
|
void startSessionFromOverview(id);
|
|
159069
|
+
},
|
|
159070
|
+
closeSession: (id) => {
|
|
159071
|
+
void closeSessionFromOverview(id);
|
|
157600
159072
|
}
|
|
157601
159073
|
});
|
|
157602
159074
|
return;
|
|
@@ -157656,6 +159128,25 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157656
159128
|
updateStatusBar();
|
|
157657
159129
|
updateTerminalContent();
|
|
157658
159130
|
}
|
|
159131
|
+
async function closeSessionFromOverview(agentId) {
|
|
159132
|
+
if (!window.copilotBridge) return;
|
|
159133
|
+
const officeId = officeManager.currentOfficeId || "office-0";
|
|
159134
|
+
try {
|
|
159135
|
+
await window.copilotBridge.resetSession(officeId, agentId);
|
|
159136
|
+
} catch (error) {
|
|
159137
|
+
console.warn(`[Office] Failed to close session from overview for ${agentId}:`, error);
|
|
159138
|
+
return;
|
|
159139
|
+
}
|
|
159140
|
+
const meta = cachedSessionMeta[agentId];
|
|
159141
|
+
if (meta) {
|
|
159142
|
+
cachedSessionMeta[agentId] = { ...meta, sessionId: void 0 };
|
|
159143
|
+
setSessionMetaCacheForOffice(officeId, cachedSessionMeta);
|
|
159144
|
+
}
|
|
159145
|
+
officeManager.setAgentSlacking(officeId, agentId);
|
|
159146
|
+
phaserGameRef?.events.emit("agent:status:changed", agentId);
|
|
159147
|
+
updateStatusBar();
|
|
159148
|
+
updateTerminalContent();
|
|
159149
|
+
}
|
|
157659
159150
|
function startSessionMetaEdit(agentId) {
|
|
157660
159151
|
const panel = overviewHost.querySelector(`.session-meta-panel[data-agent="${agentId}"]`);
|
|
157661
159152
|
if (!panel) return;
|
|
@@ -157731,11 +159222,11 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157731
159222
|
officeManager.setTaskSummary(officeId, agentId, status);
|
|
157732
159223
|
}
|
|
157733
159224
|
if (isAskUserTool(toolName, status)) {
|
|
157734
|
-
officeManager.setAgentWaiting(officeId, agentId);
|
|
159225
|
+
officeManager.setAgentWaiting(officeId, agentId, "ask_user");
|
|
157735
159226
|
console.log(`[Office] Status: ${agentId} \u2192 waiting (ask_user)`);
|
|
157736
159227
|
notifyAgent(agentId, "askUser");
|
|
157737
159228
|
} else {
|
|
157738
|
-
officeManager.setAgentThinking(officeId, agentId, `${toolName}
|
|
159229
|
+
officeManager.setAgentThinking(officeId, agentId, `${toolName}`, "tool_start");
|
|
157739
159230
|
console.log(`[Office] Status: ${agentId} \u2192 thinking (${toolName})`);
|
|
157740
159231
|
notifyAgent(agentId, "toolStart", { toolName });
|
|
157741
159232
|
}
|
|
@@ -157757,18 +159248,18 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157757
159248
|
officeManager.setLastCompletedAction(officeId, agentId, completedToolName);
|
|
157758
159249
|
officeManager.pushRecentAction(officeId, agentId, completedToolName, "completed");
|
|
157759
159250
|
notifyAgent(agentId, "toolComplete", { toolName: completedToolName });
|
|
157760
|
-
|
|
159251
|
+
const next = nextSubStateAfterToolComplete(remaining);
|
|
159252
|
+
if (next.kind === "idle") {
|
|
157761
159253
|
const currentStatus = officeManager.getAgentStatus(officeId, agentId);
|
|
157762
159254
|
if (currentStatus?.subState === "thinking") {
|
|
157763
|
-
officeManager.setAgentThinking(officeId, agentId, currentStatus.thinkingDetail ?? "Processing...");
|
|
159255
|
+
officeManager.setAgentThinking(officeId, agentId, currentStatus.thinkingDetail ?? "Processing...", "tool_complete_settling");
|
|
157764
159256
|
} else {
|
|
157765
|
-
officeManager.setAgentReady(officeId, agentId);
|
|
159257
|
+
officeManager.setAgentReady(officeId, agentId, "tool_complete");
|
|
157766
159258
|
}
|
|
157767
|
-
} else if (
|
|
157768
|
-
officeManager.setAgentWaiting(officeId, agentId);
|
|
159259
|
+
} else if (next.kind === "waiting") {
|
|
159260
|
+
officeManager.setAgentWaiting(officeId, agentId, "ask_user_race_guard");
|
|
157769
159261
|
} else {
|
|
157770
|
-
|
|
157771
|
-
officeManager.setAgentThinking(officeId, agentId, `${last.name}`);
|
|
159262
|
+
officeManager.setAgentThinking(officeId, agentId, next.detail, "tool_complete");
|
|
157772
159263
|
}
|
|
157773
159264
|
}
|
|
157774
159265
|
phaserGameRef?.events.emit("agent:status:changed", agentId);
|
|
@@ -157787,9 +159278,9 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157787
159278
|
agentTools.set(agentId, []);
|
|
157788
159279
|
}
|
|
157789
159280
|
if (waitingToolActive) {
|
|
157790
|
-
officeManager.setAgentWaiting(officeId, agentId);
|
|
159281
|
+
officeManager.setAgentWaiting(officeId, agentId, "turn_end_ask_user_active");
|
|
157791
159282
|
} else {
|
|
157792
|
-
officeManager.setAgentDonePendingAck(officeId, agentId);
|
|
159283
|
+
officeManager.setAgentDonePendingAck(officeId, agentId, "turn_end");
|
|
157793
159284
|
}
|
|
157794
159285
|
notifyAgent(agentId, "turnEnd");
|
|
157795
159286
|
}
|
|
@@ -157843,10 +159334,10 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157843
159334
|
const current = officeManager.getAgentStatus(officeId, agentId);
|
|
157844
159335
|
if (status === "preloading") {
|
|
157845
159336
|
if (!current || current.state === "slacking") {
|
|
157846
|
-
officeManager.setAgentStarting(officeId, agentId);
|
|
159337
|
+
officeManager.setAgentStarting(officeId, agentId, "preload");
|
|
157847
159338
|
}
|
|
157848
159339
|
} else if (status === "ready") {
|
|
157849
|
-
officeManager.setAgentReady(officeId, agentId);
|
|
159340
|
+
officeManager.setAgentReady(officeId, agentId, "preload_ready");
|
|
157850
159341
|
const agentTools = getCurrentAgentTools();
|
|
157851
159342
|
if (agentTools.has(agentId)) {
|
|
157852
159343
|
agentTools.set(agentId, []);
|
|
@@ -157854,7 +159345,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157854
159345
|
notifyAgent(agentId, "sessionReady");
|
|
157855
159346
|
} else if (status === "failed") {
|
|
157856
159347
|
console.warn(`[Office] Preload FAILED for ${agentId}`);
|
|
157857
|
-
officeManager.setAgentError(officeId, agentId, "Preload failed");
|
|
159348
|
+
officeManager.setAgentError(officeId, agentId, "Preload failed", "preload_failed");
|
|
157858
159349
|
notifyAgent(agentId, "sessionError");
|
|
157859
159350
|
}
|
|
157860
159351
|
}
|
|
@@ -157912,9 +159403,24 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
157912
159403
|
const staleInTurnThinking = Boolean(
|
|
157913
159404
|
current?.subState === "thinking" && thinkingSince && now - thinkingSince > STALE_IN_TURN_THINKING_TIMEOUT_MS && activeTools.length === 0
|
|
157914
159405
|
);
|
|
157915
|
-
|
|
159406
|
+
const decision = decideStartupTimeoutTransition({
|
|
159407
|
+
subState: current?.subState,
|
|
159408
|
+
activityStartTime: current?.activityStartTime,
|
|
159409
|
+
now,
|
|
159410
|
+
timeoutMs: STARTING_TIMEOUT_MS,
|
|
159411
|
+
serverAlive: serverStatus?.alive
|
|
159412
|
+
});
|
|
159413
|
+
if (decision.kind === "recover-to-ready") {
|
|
159414
|
+
console.warn(
|
|
159415
|
+
`[Office] Agent ${agent.id} stuck in starting past timeout but PTY alive \u2014 recovering to ready`
|
|
159416
|
+
);
|
|
159417
|
+
officeManager.setAgentReady(officeId, agent.id);
|
|
159418
|
+
changed = true;
|
|
159419
|
+
continue;
|
|
159420
|
+
}
|
|
159421
|
+
if (decision.kind === "transition-to-error") {
|
|
157916
159422
|
console.warn(`[Office] Agent ${agent.id} stuck in starting for >${STARTING_TIMEOUT_MS / 1e3}s \u2014 transitioning to error`);
|
|
157917
|
-
officeManager.setAgentError(officeId, agent.id,
|
|
159423
|
+
officeManager.setAgentError(officeId, agent.id, decision.reason);
|
|
157918
159424
|
changed = true;
|
|
157919
159425
|
continue;
|
|
157920
159426
|
}
|
|
@@ -158116,7 +159622,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
158116
159622
|
setupTerminalClickHandler();
|
|
158117
159623
|
function onAgentSessionClosed(agentId) {
|
|
158118
159624
|
const officeId = officeManager.currentOfficeId;
|
|
158119
|
-
if (officeId) officeManager.setAgentSlacking(officeId, agentId);
|
|
159625
|
+
if (officeId) officeManager.setAgentSlacking(officeId, agentId, "session_closed");
|
|
158120
159626
|
phaserGameRef?.events.emit("agent:status:changed", agentId);
|
|
158121
159627
|
updateTerminalContent();
|
|
158122
159628
|
updateStatusBar();
|
|
@@ -158133,7 +159639,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
158133
159639
|
console.log(`[Office] Fleet V-Team office created: ${officeId} (source: ${sourceOfficeId ?? "none"})`);
|
|
158134
159640
|
if (sourceOfficeId && window.copilotBridge?.transferSession) {
|
|
158135
159641
|
try {
|
|
158136
|
-
const result = await window.copilotBridge.transferSession(sourceOfficeId, officeId,
|
|
159642
|
+
const result = await window.copilotBridge.transferSession(sourceOfficeId, officeId, ARCHITECT_AGENT_ID);
|
|
158137
159643
|
console.log(`[Office] Arthur session transfer: ${result.success ? "OK" : result.error ?? "failed"}`);
|
|
158138
159644
|
} catch (e) {
|
|
158139
159645
|
console.warn("[Office] Failed to transfer Arthur session:", e);
|
|
@@ -158151,7 +159657,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
158151
159657
|
console.log(`[Fleet] Created fleet office: ${officeId}`);
|
|
158152
159658
|
if (window.copilotBridge?.transferSession) {
|
|
158153
159659
|
try {
|
|
158154
|
-
const result = await window.copilotBridge.transferSession(data.sourceOfficeId, officeId,
|
|
159660
|
+
const result = await window.copilotBridge.transferSession(data.sourceOfficeId, officeId, ARCHITECT_AGENT_ID);
|
|
158155
159661
|
console.log(`[Fleet] Arthur session transfer: ${result.success ? "OK" : "failed"}`, result);
|
|
158156
159662
|
} catch (e) {
|
|
158157
159663
|
console.warn("[Fleet] Failed to transfer Arthur session:", e);
|
|
@@ -158225,6 +159731,7 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
158225
159731
|
scene: [BootScene, OfficeScene, MeetingScene]
|
|
158226
159732
|
});
|
|
158227
159733
|
phaserGameRef = game;
|
|
159734
|
+
window.__phaserGame = game;
|
|
158228
159735
|
bindPhaserEventListeners(game);
|
|
158229
159736
|
}
|
|
158230
159737
|
function teardownPhaserGame() {
|
|
@@ -158236,9 +159743,18 @@ Terminal error: ${error?.message || String(error)}`);
|
|
|
158236
159743
|
} catch (error) {
|
|
158237
159744
|
console.warn("[main] Failed to destroy Phaser game cleanly:", error);
|
|
158238
159745
|
}
|
|
159746
|
+
delete window.__phaserGame;
|
|
158239
159747
|
officePanel.innerHTML = "";
|
|
158240
159748
|
}
|
|
158241
159749
|
bindOfficePanelListeners();
|
|
159750
|
+
officeManager.onOfficesUpdated = () => {
|
|
159751
|
+
syncActiveRosterForCurrentOffice();
|
|
159752
|
+
renderOfficeTabs();
|
|
159753
|
+
fetchSessionMeta();
|
|
159754
|
+
updateTerminalContent();
|
|
159755
|
+
updateStatusBar();
|
|
159756
|
+
void autoStartCoordinator.tryWarmCurrentOffice();
|
|
159757
|
+
};
|
|
158242
159758
|
window.addEventListener("focus", () => {
|
|
158243
159759
|
catchUpStatusViews("window focus");
|
|
158244
159760
|
});
|