copilotoffice 1.0.2 → 1.0.4
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/README.md +6 -4
- package/dist/electron/main.js +1 -1
- package/dist/electron/terminal/ipc-relay.js +1 -1
- package/dist/electron/terminal/preload.js +2 -2
- package/dist/electron/terminal/server.js +87 -79
- package/dist/game.bundle.js +438 -36
- package/package.json +1 -1
- package/dist/electron/events-watcher.js +0 -198
- package/dist/electron/preload.js +0 -90
- package/dist/electron/terminal-protocol.js +0 -18
- package/dist/electron/terminal-server.js +0 -485
|
@@ -1,485 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
-
for (let key of __getOwnPropNames(from))
|
|
11
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
-
}
|
|
14
|
-
return to;
|
|
15
|
-
};
|
|
16
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
-
mod
|
|
23
|
-
));
|
|
24
|
-
|
|
25
|
-
// electron/terminal-server.ts
|
|
26
|
-
var path2 = __toESM(require("path"));
|
|
27
|
-
var os2 = __toESM(require("os"));
|
|
28
|
-
var fs2 = __toESM(require("fs"));
|
|
29
|
-
var crypto = __toESM(require("crypto"));
|
|
30
|
-
var import_child_process = require("child_process");
|
|
31
|
-
|
|
32
|
-
// electron/events-watcher.ts
|
|
33
|
-
var fs = __toESM(require("fs"));
|
|
34
|
-
var path = __toESM(require("path"));
|
|
35
|
-
var os = __toESM(require("os"));
|
|
36
|
-
var EventsWatcher = class _EventsWatcher {
|
|
37
|
-
constructor(sessionId) {
|
|
38
|
-
this.fileOffset = 0;
|
|
39
|
-
this.lineBuffer = "";
|
|
40
|
-
this.watcher = null;
|
|
41
|
-
this.pollTimer = null;
|
|
42
|
-
this.fileExistsTimer = null;
|
|
43
|
-
this.callback = null;
|
|
44
|
-
this.stopped = false;
|
|
45
|
-
this.reading = false;
|
|
46
|
-
this.sessionId = sessionId;
|
|
47
|
-
this.filePath = path.join(
|
|
48
|
-
os.homedir(),
|
|
49
|
-
".copilot",
|
|
50
|
-
"session-state",
|
|
51
|
-
sessionId,
|
|
52
|
-
"events.jsonl"
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
static {
|
|
56
|
-
this.POLL_INTERVAL_MS = 500;
|
|
57
|
-
}
|
|
58
|
-
static {
|
|
59
|
-
this.FILE_CHECK_INTERVAL_MS = 200;
|
|
60
|
-
}
|
|
61
|
-
static {
|
|
62
|
-
this.MAX_FILE_WAIT_MS = 6e4;
|
|
63
|
-
}
|
|
64
|
-
getSessionId() {
|
|
65
|
-
return this.sessionId;
|
|
66
|
-
}
|
|
67
|
-
getFilePath() {
|
|
68
|
-
return this.filePath;
|
|
69
|
-
}
|
|
70
|
-
start(onEvent) {
|
|
71
|
-
this.callback = onEvent;
|
|
72
|
-
this.stopped = false;
|
|
73
|
-
fs.promises.access(this.filePath, fs.constants.F_OK).then(() => this.startWatching()).catch(() => {
|
|
74
|
-
console.log(`[EventsWatcher] Waiting for events.jsonl: ${this.filePath}`);
|
|
75
|
-
const startTime = Date.now();
|
|
76
|
-
this.fileExistsTimer = setInterval(() => {
|
|
77
|
-
if (this.stopped) {
|
|
78
|
-
if (this.fileExistsTimer) clearInterval(this.fileExistsTimer);
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
if (Date.now() - startTime > _EventsWatcher.MAX_FILE_WAIT_MS) {
|
|
82
|
-
console.warn(`[EventsWatcher] Timed out waiting for events.jsonl after ${_EventsWatcher.MAX_FILE_WAIT_MS / 1e3}s`);
|
|
83
|
-
if (this.fileExistsTimer) clearInterval(this.fileExistsTimer);
|
|
84
|
-
this.fileExistsTimer = null;
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
fs.promises.access(this.filePath, fs.constants.F_OK).then(() => {
|
|
88
|
-
console.log(`[EventsWatcher] Found events.jsonl`);
|
|
89
|
-
if (this.fileExistsTimer) clearInterval(this.fileExistsTimer);
|
|
90
|
-
this.fileExistsTimer = null;
|
|
91
|
-
this.startWatching();
|
|
92
|
-
}).catch(() => {
|
|
93
|
-
});
|
|
94
|
-
}, _EventsWatcher.FILE_CHECK_INTERVAL_MS);
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
startWatching() {
|
|
98
|
-
this.readNewLines();
|
|
99
|
-
try {
|
|
100
|
-
this.watcher = fs.watch(this.filePath, () => {
|
|
101
|
-
if (!this.stopped) this.readNewLines();
|
|
102
|
-
});
|
|
103
|
-
} catch (e) {
|
|
104
|
-
console.log(`[EventsWatcher] fs.watch failed: ${e}`);
|
|
105
|
-
}
|
|
106
|
-
this.pollTimer = setInterval(() => {
|
|
107
|
-
if (!this.stopped) this.readNewLines();
|
|
108
|
-
}, _EventsWatcher.POLL_INTERVAL_MS);
|
|
109
|
-
}
|
|
110
|
-
async readNewLines() {
|
|
111
|
-
if (this.reading) return;
|
|
112
|
-
this.reading = true;
|
|
113
|
-
try {
|
|
114
|
-
const stat = await fs.promises.stat(this.filePath);
|
|
115
|
-
if (stat.size <= this.fileOffset) return;
|
|
116
|
-
const handle = await fs.promises.open(this.filePath, "r");
|
|
117
|
-
try {
|
|
118
|
-
const buf = Buffer.alloc(stat.size - this.fileOffset);
|
|
119
|
-
await handle.read(buf, 0, buf.length, this.fileOffset);
|
|
120
|
-
this.fileOffset = stat.size;
|
|
121
|
-
const text = this.lineBuffer + buf.toString("utf-8");
|
|
122
|
-
const lines = text.split("\n");
|
|
123
|
-
this.lineBuffer = lines.pop() || "";
|
|
124
|
-
for (const line of lines) {
|
|
125
|
-
if (!line.trim()) continue;
|
|
126
|
-
try {
|
|
127
|
-
const event = JSON.parse(line);
|
|
128
|
-
if (this.callback) {
|
|
129
|
-
this.callback(event);
|
|
130
|
-
}
|
|
131
|
-
} catch (e) {
|
|
132
|
-
console.log(`[EventsWatcher] Failed to parse line: ${e}`);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
} finally {
|
|
136
|
-
await handle.close();
|
|
137
|
-
}
|
|
138
|
-
} catch (e) {
|
|
139
|
-
} finally {
|
|
140
|
-
this.reading = false;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
stop() {
|
|
144
|
-
this.stopped = true;
|
|
145
|
-
if (this.fileExistsTimer) {
|
|
146
|
-
clearInterval(this.fileExistsTimer);
|
|
147
|
-
this.fileExistsTimer = null;
|
|
148
|
-
}
|
|
149
|
-
if (this.watcher) {
|
|
150
|
-
this.watcher.close();
|
|
151
|
-
this.watcher = null;
|
|
152
|
-
}
|
|
153
|
-
if (this.pollTimer) {
|
|
154
|
-
clearInterval(this.pollTimer);
|
|
155
|
-
this.pollTimer = null;
|
|
156
|
-
}
|
|
157
|
-
this.callback = null;
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
function formatToolStatus(toolName, args) {
|
|
161
|
-
const base = (p) => typeof p === "string" ? path.basename(p) : "";
|
|
162
|
-
switch (toolName) {
|
|
163
|
-
case "view":
|
|
164
|
-
return `Reading ${base(args.path)}`;
|
|
165
|
-
case "edit":
|
|
166
|
-
return `Editing ${base(args.path)}`;
|
|
167
|
-
case "create":
|
|
168
|
-
return `Creating ${base(args.path)}`;
|
|
169
|
-
case "powershell":
|
|
170
|
-
const cmd = args.command || "";
|
|
171
|
-
return `Running: ${cmd.length > 40 ? cmd.slice(0, 40) + "\u2026" : cmd}`;
|
|
172
|
-
case "glob":
|
|
173
|
-
return `Finding files: ${args.pattern || ""}`;
|
|
174
|
-
case "grep":
|
|
175
|
-
return `Searching: ${args.pattern || ""}`;
|
|
176
|
-
case "web_fetch":
|
|
177
|
-
return `Fetching: ${args.url || ""}`;
|
|
178
|
-
case "task":
|
|
179
|
-
return `Subtask: ${args.description || "running"}`;
|
|
180
|
-
case "ask_user":
|
|
181
|
-
return "Waiting for your answer";
|
|
182
|
-
case "report_intent":
|
|
183
|
-
return `${args.intent || "Working"}`;
|
|
184
|
-
case "sql":
|
|
185
|
-
return `Query: ${args.description || "running"}`;
|
|
186
|
-
default:
|
|
187
|
-
return `Using ${toolName}`;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// electron/terminal-server.ts
|
|
192
|
-
var pty = null;
|
|
193
|
-
var ptyProcesses = /* @__PURE__ */ new Map();
|
|
194
|
-
var agentToTerminal = /* @__PURE__ */ new Map();
|
|
195
|
-
var activeAgentViewers = /* @__PURE__ */ new Set();
|
|
196
|
-
var agentWatchers = /* @__PURE__ */ new Map();
|
|
197
|
-
var MAX_BUFFER_LINES = 500;
|
|
198
|
-
var agentScrollbackBuffers = /* @__PURE__ */ new Map();
|
|
199
|
-
var SESSION_FILE = path2.join(process.cwd(), "copilot-office-sessions.json");
|
|
200
|
-
var agentSessionIds = /* @__PURE__ */ new Map();
|
|
201
|
-
function send(msg) {
|
|
202
|
-
if (process.send) {
|
|
203
|
-
process.send(msg);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
function appendToScrollback(agentId, data) {
|
|
207
|
-
let buf = agentScrollbackBuffers.get(agentId);
|
|
208
|
-
if (!buf) {
|
|
209
|
-
buf = [];
|
|
210
|
-
agentScrollbackBuffers.set(agentId, buf);
|
|
211
|
-
}
|
|
212
|
-
const lines = data.split("\n");
|
|
213
|
-
for (const line of lines) {
|
|
214
|
-
buf.push(line);
|
|
215
|
-
}
|
|
216
|
-
if (buf.length > MAX_BUFFER_LINES) {
|
|
217
|
-
buf.splice(0, buf.length - MAX_BUFFER_LINES);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
async function loadSessionIds() {
|
|
221
|
-
try {
|
|
222
|
-
const raw = await fs2.promises.readFile(SESSION_FILE, "utf8").catch(() => null);
|
|
223
|
-
if (raw) {
|
|
224
|
-
agentSessionIds = new Map(Object.entries(JSON.parse(raw)));
|
|
225
|
-
console.log("[TermServer] Loaded saved sessions:", agentSessionIds.size);
|
|
226
|
-
}
|
|
227
|
-
} catch (e) {
|
|
228
|
-
console.error("[TermServer] Failed to load session IDs:", e);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
async function saveSessionIds() {
|
|
232
|
-
try {
|
|
233
|
-
const data = Object.fromEntries(agentSessionIds);
|
|
234
|
-
await fs2.promises.writeFile(SESSION_FILE, JSON.stringify(data, null, 2));
|
|
235
|
-
} catch (e) {
|
|
236
|
-
console.error("[TermServer] Failed to save session IDs:", e);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
function getTerminalKey(agentId) {
|
|
240
|
-
const assignedKey = agentToTerminal.get(agentId);
|
|
241
|
-
if (assignedKey && ptyProcesses.has(assignedKey)) return assignedKey;
|
|
242
|
-
if (ptyProcesses.has(agentId)) return agentId;
|
|
243
|
-
return null;
|
|
244
|
-
}
|
|
245
|
-
function killAllPtyProcesses() {
|
|
246
|
-
console.log(`[TermServer] Killing ${ptyProcesses.size} PTY processes`);
|
|
247
|
-
ptyProcesses.forEach((proc, key) => {
|
|
248
|
-
try {
|
|
249
|
-
proc.process.kill();
|
|
250
|
-
} catch (e) {
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
ptyProcesses.clear();
|
|
254
|
-
agentToTerminal.clear();
|
|
255
|
-
agentWatchers.forEach((w) => w.stop());
|
|
256
|
-
agentWatchers.clear();
|
|
257
|
-
}
|
|
258
|
-
async function startTerminalForAgent(agentId, workingDir) {
|
|
259
|
-
if (!pty) {
|
|
260
|
-
return { success: false, error: "node-pty not available" };
|
|
261
|
-
}
|
|
262
|
-
const existingTerminalKey = agentToTerminal.get(agentId);
|
|
263
|
-
if (existingTerminalKey && ptyProcesses.has(existingTerminalKey)) {
|
|
264
|
-
const existing = ptyProcesses.get(existingTerminalKey);
|
|
265
|
-
return { success: true, pid: existing.pid, sessionId: existing.sessionId, reused: true };
|
|
266
|
-
}
|
|
267
|
-
let sessionId = agentSessionIds.get(agentId);
|
|
268
|
-
if (!sessionId) {
|
|
269
|
-
sessionId = crypto.randomUUID();
|
|
270
|
-
agentSessionIds.set(agentId, sessionId);
|
|
271
|
-
saveSessionIds();
|
|
272
|
-
console.log(`[TermServer] New session GUID for ${agentId}: ${sessionId}`);
|
|
273
|
-
} else {
|
|
274
|
-
console.log(`[TermServer] Reusing session GUID for ${agentId}: ${sessionId}`);
|
|
275
|
-
}
|
|
276
|
-
const terminalKey = agentId;
|
|
277
|
-
const shell = os2.platform() === "win32" ? "powershell.exe" : "bash";
|
|
278
|
-
let cwd = process.cwd();
|
|
279
|
-
if (workingDir) {
|
|
280
|
-
const customPath = path2.join(process.cwd(), workingDir);
|
|
281
|
-
try {
|
|
282
|
-
await fs2.promises.access(customPath, fs2.constants.F_OK);
|
|
283
|
-
cwd = customPath;
|
|
284
|
-
} catch {
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
const taggedEnv = {
|
|
288
|
-
...process.env,
|
|
289
|
-
AGENCY_OFFICE_PROCESS: "true",
|
|
290
|
-
AGENCY_OFFICE_AGENT: agentId
|
|
291
|
-
};
|
|
292
|
-
try {
|
|
293
|
-
const proc = pty.spawn(shell, [], {
|
|
294
|
-
name: "xterm-256color",
|
|
295
|
-
cols: 120,
|
|
296
|
-
rows: 30,
|
|
297
|
-
cwd,
|
|
298
|
-
env: taggedEnv
|
|
299
|
-
});
|
|
300
|
-
ptyProcesses.set(terminalKey, {
|
|
301
|
-
pid: proc.pid,
|
|
302
|
-
process: proc,
|
|
303
|
-
agentId: terminalKey,
|
|
304
|
-
sessionId,
|
|
305
|
-
workingDir
|
|
306
|
-
});
|
|
307
|
-
agentToTerminal.set(agentId, terminalKey);
|
|
308
|
-
agentSessionIds.set(agentId, sessionId);
|
|
309
|
-
saveSessionIds();
|
|
310
|
-
const watcher = new EventsWatcher(sessionId);
|
|
311
|
-
agentWatchers.set(agentId, watcher);
|
|
312
|
-
watcher.start((event) => {
|
|
313
|
-
if (!activeAgentViewers.has(agentId)) return;
|
|
314
|
-
send({ type: "copilot-event", agentId, event });
|
|
315
|
-
if (event.type === "tool.execution_start") {
|
|
316
|
-
const d = event.data;
|
|
317
|
-
send({ type: "copilot-tool-start", agentId, toolName: d.toolName, toolId: d.toolCallId, status: formatToolStatus(d.toolName, d.arguments) });
|
|
318
|
-
} else if (event.type === "tool.execution_complete") {
|
|
319
|
-
const d = event.data;
|
|
320
|
-
send({ type: "copilot-tool-complete", agentId, toolId: d.toolCallId, success: d.success });
|
|
321
|
-
} else if (event.type === "assistant.turn_end") {
|
|
322
|
-
send({ type: "copilot-turn-end", agentId });
|
|
323
|
-
} else if (event.type === "user.message") {
|
|
324
|
-
send({ type: "copilot-user-message", agentId });
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
const MAX_PENDING_BYTES = 65536;
|
|
328
|
-
let pendingData = "";
|
|
329
|
-
let flushTimer = null;
|
|
330
|
-
const flushData = () => {
|
|
331
|
-
flushTimer = null;
|
|
332
|
-
if (pendingData && activeAgentViewers.has(agentId)) {
|
|
333
|
-
send({ type: "terminal-data", agentId, data: pendingData });
|
|
334
|
-
}
|
|
335
|
-
pendingData = "";
|
|
336
|
-
};
|
|
337
|
-
proc.onData((data) => {
|
|
338
|
-
appendToScrollback(agentId, data);
|
|
339
|
-
if (!activeAgentViewers.has(agentId)) return;
|
|
340
|
-
pendingData += data;
|
|
341
|
-
if (pendingData.length >= MAX_PENDING_BYTES) {
|
|
342
|
-
if (flushTimer) clearTimeout(flushTimer);
|
|
343
|
-
flushData();
|
|
344
|
-
} else if (!flushTimer) {
|
|
345
|
-
flushTimer = setTimeout(flushData, 16);
|
|
346
|
-
}
|
|
347
|
-
});
|
|
348
|
-
proc.onExit(({ exitCode }) => {
|
|
349
|
-
send({ type: "terminal-exit", agentId, exitCode });
|
|
350
|
-
ptyProcesses.delete(terminalKey);
|
|
351
|
-
activeAgentViewers.delete(agentId);
|
|
352
|
-
agentScrollbackBuffers.delete(agentId);
|
|
353
|
-
const w = agentWatchers.get(agentId);
|
|
354
|
-
if (w) {
|
|
355
|
-
w.stop();
|
|
356
|
-
agentWatchers.delete(agentId);
|
|
357
|
-
}
|
|
358
|
-
});
|
|
359
|
-
setTimeout(() => {
|
|
360
|
-
console.log(`[TermServer] Starting copilot --resume for ${agentId}: ${sessionId}`);
|
|
361
|
-
proc.write(`copilot --resume ${sessionId}\r`);
|
|
362
|
-
}, 500);
|
|
363
|
-
return { success: true, pid: proc.pid, sessionId };
|
|
364
|
-
} catch (error) {
|
|
365
|
-
return { success: false, error: String(error) };
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
async function handleMessage(msg) {
|
|
369
|
-
switch (msg.type) {
|
|
370
|
-
case "start": {
|
|
371
|
-
activeAgentViewers.add(msg.agentId);
|
|
372
|
-
const result = await startTerminalForAgent(msg.agentId, msg.workingDir);
|
|
373
|
-
send({ type: "response", requestId: msg.requestId, result });
|
|
374
|
-
break;
|
|
375
|
-
}
|
|
376
|
-
case "write": {
|
|
377
|
-
const key = getTerminalKey(msg.agentId);
|
|
378
|
-
const proc = key ? ptyProcesses.get(key) : null;
|
|
379
|
-
if (proc) proc.process.write(msg.data);
|
|
380
|
-
break;
|
|
381
|
-
}
|
|
382
|
-
case "resize": {
|
|
383
|
-
const key = getTerminalKey(msg.agentId);
|
|
384
|
-
const proc = key ? ptyProcesses.get(key) : null;
|
|
385
|
-
if (proc) proc.process.resize(msg.cols, msg.rows);
|
|
386
|
-
break;
|
|
387
|
-
}
|
|
388
|
-
case "kill": {
|
|
389
|
-
const key = getTerminalKey(msg.agentId);
|
|
390
|
-
const proc = key ? ptyProcesses.get(key) : null;
|
|
391
|
-
if (proc) {
|
|
392
|
-
try {
|
|
393
|
-
proc.process.kill();
|
|
394
|
-
ptyProcesses.delete(key);
|
|
395
|
-
agentToTerminal.delete(msg.agentId);
|
|
396
|
-
send({ type: "response", requestId: msg.requestId, result: { success: true } });
|
|
397
|
-
} catch (error) {
|
|
398
|
-
send({ type: "response", requestId: msg.requestId, result: { success: false, error: String(error) } });
|
|
399
|
-
}
|
|
400
|
-
} else {
|
|
401
|
-
send({ type: "response", requestId: msg.requestId, result: { success: false, error: "No terminal for this agent" } });
|
|
402
|
-
}
|
|
403
|
-
break;
|
|
404
|
-
}
|
|
405
|
-
case "attach": {
|
|
406
|
-
console.log(`[TermServer] Attaching viewer for ${msg.agentId}`);
|
|
407
|
-
activeAgentViewers.add(msg.agentId);
|
|
408
|
-
const scrollback = agentScrollbackBuffers.get(msg.agentId) || [];
|
|
409
|
-
send({ type: "response", requestId: msg.requestId, result: { success: true, scrollback } });
|
|
410
|
-
break;
|
|
411
|
-
}
|
|
412
|
-
case "detach": {
|
|
413
|
-
console.log(`[TermServer] Detaching viewer for ${msg.agentId}`);
|
|
414
|
-
activeAgentViewers.delete(msg.agentId);
|
|
415
|
-
break;
|
|
416
|
-
}
|
|
417
|
-
case "exists": {
|
|
418
|
-
send({ type: "response", requestId: msg.requestId, result: getTerminalKey(msg.agentId) !== null });
|
|
419
|
-
break;
|
|
420
|
-
}
|
|
421
|
-
case "get-session-id": {
|
|
422
|
-
send({ type: "response", requestId: msg.requestId, result: agentSessionIds.get(msg.agentId) || null });
|
|
423
|
-
break;
|
|
424
|
-
}
|
|
425
|
-
case "save-session-id": {
|
|
426
|
-
agentSessionIds.set(msg.agentId, msg.sessionId);
|
|
427
|
-
saveSessionIds();
|
|
428
|
-
console.log(`[TermServer] Saved session for ${msg.agentId}: ${msg.sessionId}`);
|
|
429
|
-
send({ type: "response", requestId: msg.requestId, result: { success: true } });
|
|
430
|
-
break;
|
|
431
|
-
}
|
|
432
|
-
case "pop-out": {
|
|
433
|
-
const sid = agentSessionIds.get(msg.agentId);
|
|
434
|
-
if (!sid) {
|
|
435
|
-
send({ type: "response", requestId: msg.requestId, result: { success: false, error: "No session found for agent" } });
|
|
436
|
-
break;
|
|
437
|
-
}
|
|
438
|
-
const termKey = agentToTerminal.get(msg.agentId);
|
|
439
|
-
const ptyProc = termKey ? ptyProcesses.get(termKey) : null;
|
|
440
|
-
let cwd = process.cwd();
|
|
441
|
-
if (ptyProc?.workingDir) {
|
|
442
|
-
const customPath = path2.join(process.cwd(), ptyProc.workingDir);
|
|
443
|
-
try {
|
|
444
|
-
await fs2.promises.access(customPath, fs2.constants.F_OK);
|
|
445
|
-
cwd = customPath;
|
|
446
|
-
} catch {
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
try {
|
|
450
|
-
(0, import_child_process.spawn)("wt", ["-d", cwd, "copilot", "--resume", sid], { detached: true, stdio: "ignore" }).unref();
|
|
451
|
-
send({ type: "response", requestId: msg.requestId, result: { success: true } });
|
|
452
|
-
} catch (error) {
|
|
453
|
-
send({ type: "response", requestId: msg.requestId, result: { success: false, error: String(error) } });
|
|
454
|
-
}
|
|
455
|
-
break;
|
|
456
|
-
}
|
|
457
|
-
case "shutdown": {
|
|
458
|
-
console.log("[TermServer] Shutdown requested");
|
|
459
|
-
killAllPtyProcesses();
|
|
460
|
-
process.exit(0);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
async function main() {
|
|
465
|
-
console.log("[TermServer] Starting...");
|
|
466
|
-
try {
|
|
467
|
-
pty = require("node-pty");
|
|
468
|
-
console.log("[TermServer] node-pty loaded");
|
|
469
|
-
} catch (e) {
|
|
470
|
-
console.error("[TermServer] Failed to load node-pty:", e);
|
|
471
|
-
}
|
|
472
|
-
await loadSessionIds();
|
|
473
|
-
process.on("message", (msg) => {
|
|
474
|
-
handleMessage(msg).catch((e) => {
|
|
475
|
-
console.error("[TermServer] Unhandled error in message handler:", e);
|
|
476
|
-
});
|
|
477
|
-
});
|
|
478
|
-
process.on("SIGTERM", () => {
|
|
479
|
-
killAllPtyProcesses();
|
|
480
|
-
process.exit(0);
|
|
481
|
-
});
|
|
482
|
-
send({ type: "ready" });
|
|
483
|
-
console.log("[TermServer] Ready");
|
|
484
|
-
}
|
|
485
|
-
main();
|