copilotoffice 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/electron/main.js +2307 -156
- package/dist/electron/terminal/ipc-relay.js +191 -6
- package/dist/electron/terminal/preload.js +33 -0
- package/dist/electron/terminal/server.js +213 -45
- package/dist/game.bundle.js +12478 -8446
- package/package.json +6 -4
|
@@ -3044,7 +3044,7 @@ var require_main = __commonJS({
|
|
|
3044
3044
|
exports2.createMessageConnection = exports2.createServerSocketTransport = exports2.createClientSocketTransport = exports2.createServerPipeTransport = exports2.createClientPipeTransport = exports2.generateRandomPipeName = exports2.StreamMessageWriter = exports2.StreamMessageReader = exports2.SocketMessageWriter = exports2.SocketMessageReader = exports2.PortMessageWriter = exports2.PortMessageReader = exports2.IPCMessageWriter = exports2.IPCMessageReader = void 0;
|
|
3045
3045
|
var ril_1 = require_ril();
|
|
3046
3046
|
ril_1.default.install();
|
|
3047
|
-
var
|
|
3047
|
+
var path5 = require("path");
|
|
3048
3048
|
var os4 = require("os");
|
|
3049
3049
|
var crypto_1 = require("crypto");
|
|
3050
3050
|
var net_1 = require("net");
|
|
@@ -3180,9 +3180,9 @@ var require_main = __commonJS({
|
|
|
3180
3180
|
}
|
|
3181
3181
|
let result;
|
|
3182
3182
|
if (XDG_RUNTIME_DIR) {
|
|
3183
|
-
result =
|
|
3183
|
+
result = path5.join(XDG_RUNTIME_DIR, `vscode-ipc-${randomSuffix}.sock`);
|
|
3184
3184
|
} else {
|
|
3185
|
-
result =
|
|
3185
|
+
result = path5.join(os4.tmpdir(), `vscode-${randomSuffix}.sock`);
|
|
3186
3186
|
}
|
|
3187
3187
|
const limit = safeIpcPathLengths.get(process.platform);
|
|
3188
3188
|
if (limit !== void 0 && result.length > limit) {
|
|
@@ -5067,10 +5067,10 @@ var init_dist = __esm({
|
|
|
5067
5067
|
});
|
|
5068
5068
|
|
|
5069
5069
|
// electron/terminal/server.ts
|
|
5070
|
-
var
|
|
5070
|
+
var path4 = __toESM(require("path"));
|
|
5071
5071
|
var os3 = __toESM(require("os"));
|
|
5072
|
-
var
|
|
5073
|
-
var
|
|
5072
|
+
var fs3 = __toESM(require("fs"));
|
|
5073
|
+
var crypto3 = __toESM(require("crypto"));
|
|
5074
5074
|
var import_child_process2 = require("child_process");
|
|
5075
5075
|
|
|
5076
5076
|
// electron/terminal/events-watcher.ts
|
|
@@ -5407,14 +5407,7 @@ var CopilotSdkProcess = class {
|
|
|
5407
5407
|
this.emitPrompt();
|
|
5408
5408
|
continue;
|
|
5409
5409
|
}
|
|
5410
|
-
this.
|
|
5411
|
-
this.queuedSend = this.queuedSend.then(async () => {
|
|
5412
|
-
await this.session.send({ prompt, mode: "enqueue" });
|
|
5413
|
-
}).catch((error) => {
|
|
5414
|
-
this.emitData(`\x1B[31m[SDK send failed: ${String(error)}]\x1B[0m\r
|
|
5415
|
-
`);
|
|
5416
|
-
this.emitPrompt();
|
|
5417
|
-
});
|
|
5410
|
+
this.enqueuePrompt(prompt);
|
|
5418
5411
|
continue;
|
|
5419
5412
|
}
|
|
5420
5413
|
if (ch === "\b" || ch === "\x7F") {
|
|
@@ -5428,6 +5421,34 @@ var CopilotSdkProcess = class {
|
|
|
5428
5421
|
this.emitData(ch);
|
|
5429
5422
|
}
|
|
5430
5423
|
}
|
|
5424
|
+
/**
|
|
5425
|
+
* Submit a complete prompt directly to the SDK session, bypassing the
|
|
5426
|
+
* line-editor. Handles multi-line prompts atomically (no premature submit on
|
|
5427
|
+
* embedded newlines) and echoes the prompt so it appears in the terminal as
|
|
5428
|
+
* if typed. This is the robust path used by programmatic drivers (e.g. Teams
|
|
5429
|
+
* remote dispatch) instead of racing keystrokes through `write()`.
|
|
5430
|
+
*/
|
|
5431
|
+
submitPrompt(text, label) {
|
|
5432
|
+
if (this.closed) return;
|
|
5433
|
+
const prompt = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trim();
|
|
5434
|
+
if (!prompt) return;
|
|
5435
|
+
this.lineBuffer = "";
|
|
5436
|
+
const tag = label ? `\x1B[2;36m[${label}]\x1B[0m ` : "";
|
|
5437
|
+
this.emitData(`${tag}${prompt.replace(/\n/g, "\r\n")}\r
|
|
5438
|
+
`);
|
|
5439
|
+
this.enqueuePrompt(prompt);
|
|
5440
|
+
}
|
|
5441
|
+
/** Queue a prompt for the SDK session, serialized after any in-flight send. */
|
|
5442
|
+
enqueuePrompt(prompt) {
|
|
5443
|
+
this.promptPending = true;
|
|
5444
|
+
this.queuedSend = this.queuedSend.then(async () => {
|
|
5445
|
+
await this.session.send({ prompt, mode: "enqueue" });
|
|
5446
|
+
}).catch((error) => {
|
|
5447
|
+
this.emitData(`\x1B[31m[SDK send failed: ${String(error)}]\x1B[0m\r
|
|
5448
|
+
`);
|
|
5449
|
+
this.emitPrompt();
|
|
5450
|
+
});
|
|
5451
|
+
}
|
|
5431
5452
|
resize(_cols, _rows) {
|
|
5432
5453
|
}
|
|
5433
5454
|
onData(callback) {
|
|
@@ -5649,27 +5670,73 @@ function repairDuplicateSessionIds(officeId, data, options = {}) {
|
|
|
5649
5670
|
return repaired;
|
|
5650
5671
|
}
|
|
5651
5672
|
|
|
5673
|
+
// electron/terminal/pty-registry.ts
|
|
5674
|
+
var crypto2 = __toESM(require("crypto"));
|
|
5675
|
+
var fs2 = __toESM(require("fs"));
|
|
5676
|
+
var path3 = __toESM(require("path"));
|
|
5677
|
+
var DEFAULT_REGISTRY_FILE = path3.join(process.cwd(), ".data", "pty-pids.json");
|
|
5678
|
+
function readPtyRegistry(file = DEFAULT_REGISTRY_FILE) {
|
|
5679
|
+
try {
|
|
5680
|
+
const raw = fs2.readFileSync(file, "utf8");
|
|
5681
|
+
const parsed = JSON.parse(raw);
|
|
5682
|
+
if (!Array.isArray(parsed)) return [];
|
|
5683
|
+
return parsed.filter(
|
|
5684
|
+
(r) => !!r && typeof r.pid === "number" && Number.isFinite(r.pid)
|
|
5685
|
+
);
|
|
5686
|
+
} catch {
|
|
5687
|
+
return [];
|
|
5688
|
+
}
|
|
5689
|
+
}
|
|
5690
|
+
function writePtyRegistry(records, file = DEFAULT_REGISTRY_FILE) {
|
|
5691
|
+
try {
|
|
5692
|
+
fs2.mkdirSync(path3.dirname(file), { recursive: true });
|
|
5693
|
+
const tmp = `${file}.${process.pid}.${crypto2.randomBytes(4).toString("hex")}.tmp`;
|
|
5694
|
+
fs2.writeFileSync(tmp, JSON.stringify(records, null, 2));
|
|
5695
|
+
fs2.renameSync(tmp, file);
|
|
5696
|
+
} catch {
|
|
5697
|
+
}
|
|
5698
|
+
}
|
|
5699
|
+
function registerPty(record, file = DEFAULT_REGISTRY_FILE) {
|
|
5700
|
+
const records = readPtyRegistry(file).filter((r) => r.pid !== record.pid);
|
|
5701
|
+
records.push(record);
|
|
5702
|
+
writePtyRegistry(records, file);
|
|
5703
|
+
}
|
|
5704
|
+
function unregisterPty(pid, file = DEFAULT_REGISTRY_FILE) {
|
|
5705
|
+
const records = readPtyRegistry(file);
|
|
5706
|
+
const next = records.filter((r) => r.pid !== pid);
|
|
5707
|
+
if (next.length !== records.length) {
|
|
5708
|
+
writePtyRegistry(next, file);
|
|
5709
|
+
}
|
|
5710
|
+
}
|
|
5711
|
+
|
|
5652
5712
|
// electron/terminal/server.ts
|
|
5653
5713
|
var ptyProcesses = /* @__PURE__ */ new Map();
|
|
5654
5714
|
var DEBUG_COLD_START = process.env.COPILOT_OFFICE_DEBUG_COLD_START === "1";
|
|
5655
5715
|
var agentToTerminal = /* @__PURE__ */ new Map();
|
|
5656
5716
|
var activeAgentViewers = /* @__PURE__ */ new Set();
|
|
5717
|
+
var agentForwardKeys = /* @__PURE__ */ new Set();
|
|
5718
|
+
var lastPtyDataAt = /* @__PURE__ */ new Map();
|
|
5657
5719
|
var viewerMaps = { activeAgentViewers, agentToTerminal };
|
|
5658
5720
|
var agentWatchers = /* @__PURE__ */ new Map();
|
|
5659
5721
|
var terminalBackend = null;
|
|
5660
5722
|
var eventSourceFactory = new FileWatcherEventSourceFactory();
|
|
5661
5723
|
var agentReadyState = /* @__PURE__ */ new Map();
|
|
5662
5724
|
var agentInTurn = /* @__PURE__ */ new Map();
|
|
5725
|
+
var userMessageSeq = /* @__PURE__ */ new Map();
|
|
5726
|
+
var lastUserMessageText = /* @__PURE__ */ new Map();
|
|
5727
|
+
function normalizePromptText(s) {
|
|
5728
|
+
return s.replace(/\s+/g, " ").trim();
|
|
5729
|
+
}
|
|
5663
5730
|
var MAX_BUFFER_BYTES = 512 * 1024;
|
|
5664
5731
|
var agentScrollbackBuffers = /* @__PURE__ */ new Map();
|
|
5665
5732
|
var agentScrollbackBytes = /* @__PURE__ */ new Map();
|
|
5666
|
-
var DATA_DIR =
|
|
5667
|
-
var OLD_SESSION_FILE =
|
|
5668
|
-
var OFFICES_FILE =
|
|
5733
|
+
var DATA_DIR = path4.join(process.cwd(), ".data");
|
|
5734
|
+
var OLD_SESSION_FILE = path4.join(DATA_DIR, "copilot-office-sessions.json");
|
|
5735
|
+
var OFFICES_FILE = path4.join(DATA_DIR, "copilot-offices.json");
|
|
5669
5736
|
var officeSessions = /* @__PURE__ */ new Map();
|
|
5670
5737
|
var hasAutoTitled = /* @__PURE__ */ new Set();
|
|
5671
5738
|
function getSessionFile(officeId) {
|
|
5672
|
-
return
|
|
5739
|
+
return path4.join(DATA_DIR, `${officeId}.sessions.json`);
|
|
5673
5740
|
}
|
|
5674
5741
|
function getOfficeSession(officeId) {
|
|
5675
5742
|
let data = officeSessions.get(officeId);
|
|
@@ -5707,9 +5774,9 @@ function appendToScrollback(agentId, data) {
|
|
|
5707
5774
|
}
|
|
5708
5775
|
async function loadOfficeSessionFile(officeId) {
|
|
5709
5776
|
try {
|
|
5710
|
-
await
|
|
5777
|
+
await fs3.promises.mkdir(DATA_DIR, { recursive: true });
|
|
5711
5778
|
const filePath = getSessionFile(officeId);
|
|
5712
|
-
const raw = await
|
|
5779
|
+
const raw = await fs3.promises.readFile(filePath, "utf8").catch(() => null);
|
|
5713
5780
|
const data = getOfficeSession(officeId);
|
|
5714
5781
|
if (raw) {
|
|
5715
5782
|
const parsed = JSON.parse(raw);
|
|
@@ -5739,27 +5806,27 @@ async function loadOfficeSessionFile(officeId) {
|
|
|
5739
5806
|
}
|
|
5740
5807
|
async function saveOfficeSessionFile(officeId) {
|
|
5741
5808
|
try {
|
|
5742
|
-
await
|
|
5809
|
+
await fs3.promises.mkdir(DATA_DIR, { recursive: true });
|
|
5743
5810
|
const data = getOfficeSession(officeId);
|
|
5744
5811
|
const json = {
|
|
5745
5812
|
current: Object.fromEntries(data.sessionIds),
|
|
5746
5813
|
history: Object.fromEntries(data.sessionHistory),
|
|
5747
5814
|
metadata: Object.fromEntries(data.sessionMeta)
|
|
5748
5815
|
};
|
|
5749
|
-
await
|
|
5816
|
+
await fs3.promises.writeFile(getSessionFile(officeId), JSON.stringify(json, null, 2));
|
|
5750
5817
|
} catch (e) {
|
|
5751
5818
|
console.error(`[TermServer] Failed to save sessions for ${officeId}:`, e);
|
|
5752
5819
|
}
|
|
5753
5820
|
}
|
|
5754
5821
|
async function createEmptySessionFile(officeId) {
|
|
5755
|
-
await
|
|
5822
|
+
await fs3.promises.mkdir(DATA_DIR, { recursive: true });
|
|
5756
5823
|
const filePath = getSessionFile(officeId);
|
|
5757
5824
|
try {
|
|
5758
|
-
await
|
|
5825
|
+
await fs3.promises.access(filePath, fs3.constants.F_OK);
|
|
5759
5826
|
await loadOfficeSessionFile(officeId);
|
|
5760
5827
|
} catch {
|
|
5761
5828
|
const empty = { current: {}, history: {}, metadata: {} };
|
|
5762
|
-
await
|
|
5829
|
+
await fs3.promises.writeFile(filePath, JSON.stringify(empty, null, 2));
|
|
5763
5830
|
getOfficeSession(officeId);
|
|
5764
5831
|
console.log(`[TermServer] Created empty session file for ${officeId}: ${filePath}`);
|
|
5765
5832
|
}
|
|
@@ -5779,19 +5846,19 @@ async function migrateGlobalSessionFile() {
|
|
|
5779
5846
|
try {
|
|
5780
5847
|
const migratedMarker = OLD_SESSION_FILE + ".migrated";
|
|
5781
5848
|
try {
|
|
5782
|
-
await
|
|
5849
|
+
await fs3.promises.access(migratedMarker, fs3.constants.F_OK);
|
|
5783
5850
|
return;
|
|
5784
5851
|
} catch {
|
|
5785
5852
|
}
|
|
5786
5853
|
let oldRaw = null;
|
|
5787
5854
|
try {
|
|
5788
|
-
oldRaw = await
|
|
5855
|
+
oldRaw = await fs3.promises.readFile(OLD_SESSION_FILE, "utf8");
|
|
5789
5856
|
} catch {
|
|
5790
5857
|
return;
|
|
5791
5858
|
}
|
|
5792
5859
|
let firstOfficeId = "office-0";
|
|
5793
5860
|
try {
|
|
5794
|
-
const officesRaw = await
|
|
5861
|
+
const officesRaw = await fs3.promises.readFile(OFFICES_FILE, "utf8");
|
|
5795
5862
|
const officesData = JSON.parse(officesRaw);
|
|
5796
5863
|
if (Array.isArray(officesData.offices) && officesData.offices.length > 0) {
|
|
5797
5864
|
firstOfficeId = officesData.offices[0].id || "office-0";
|
|
@@ -5800,22 +5867,22 @@ async function migrateGlobalSessionFile() {
|
|
|
5800
5867
|
}
|
|
5801
5868
|
const firstOfficeFile = getSessionFile(firstOfficeId);
|
|
5802
5869
|
try {
|
|
5803
|
-
await
|
|
5870
|
+
await fs3.promises.access(firstOfficeFile, fs3.constants.F_OK);
|
|
5804
5871
|
} catch {
|
|
5805
|
-
await
|
|
5872
|
+
await fs3.promises.writeFile(firstOfficeFile, oldRaw);
|
|
5806
5873
|
console.log(`[TermServer] Migrated global sessions to ${firstOfficeFile}`);
|
|
5807
5874
|
}
|
|
5808
|
-
await
|
|
5875
|
+
await fs3.promises.rename(OLD_SESSION_FILE, migratedMarker);
|
|
5809
5876
|
console.log(`[TermServer] Renamed old session file to ${migratedMarker}`);
|
|
5810
5877
|
} catch (e) {
|
|
5811
5878
|
console.error("[TermServer] Migration error:", e);
|
|
5812
5879
|
}
|
|
5813
5880
|
}
|
|
5814
5881
|
async function loadAllOfficeSessions() {
|
|
5815
|
-
await
|
|
5882
|
+
await fs3.promises.mkdir(DATA_DIR, { recursive: true });
|
|
5816
5883
|
await migrateGlobalSessionFile();
|
|
5817
5884
|
try {
|
|
5818
|
-
const files = await
|
|
5885
|
+
const files = await fs3.promises.readdir(DATA_DIR);
|
|
5819
5886
|
for (const file of files) {
|
|
5820
5887
|
const match = file.match(/^(.+)\.sessions\.json$/);
|
|
5821
5888
|
if (match) {
|
|
@@ -5833,6 +5900,46 @@ function getTerminalKey(officeId, agentId) {
|
|
|
5833
5900
|
if (ptyProcesses.has(ck)) return ck;
|
|
5834
5901
|
return null;
|
|
5835
5902
|
}
|
|
5903
|
+
function submitViaKeystrokes(proc, prompt, ck) {
|
|
5904
|
+
const text = prompt.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
5905
|
+
const safeWrite = (data) => {
|
|
5906
|
+
try {
|
|
5907
|
+
proc.write(data);
|
|
5908
|
+
} catch {
|
|
5909
|
+
}
|
|
5910
|
+
lastPtyDataAt.set(ck, Date.now());
|
|
5911
|
+
};
|
|
5912
|
+
const waitForIdle = (quietMs, capMs) => new Promise((resolve) => {
|
|
5913
|
+
const start = Date.now();
|
|
5914
|
+
const tick = () => {
|
|
5915
|
+
const last = lastPtyDataAt.get(ck) ?? 0;
|
|
5916
|
+
if (Date.now() - last >= quietMs || Date.now() - start >= capMs) resolve();
|
|
5917
|
+
else setTimeout(tick, 50);
|
|
5918
|
+
};
|
|
5919
|
+
tick();
|
|
5920
|
+
});
|
|
5921
|
+
void (async () => {
|
|
5922
|
+
await waitForIdle(300, 3e3);
|
|
5923
|
+
safeWrite("");
|
|
5924
|
+
safeWrite(`\x1B[200~${text}\x1B[201~`);
|
|
5925
|
+
await waitForIdle(250, 2e3);
|
|
5926
|
+
const delay = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
5927
|
+
const want = normalizePromptText(text);
|
|
5928
|
+
const baseline = userMessageSeq.get(ck) ?? 0;
|
|
5929
|
+
const accepted = () => (userMessageSeq.get(ck) ?? 0) > baseline && lastUserMessageText.get(ck) === want;
|
|
5930
|
+
const MAX_ATTEMPTS = 12;
|
|
5931
|
+
const POLL_MS = 500;
|
|
5932
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS && !accepted(); attempt++) {
|
|
5933
|
+
safeWrite("\r");
|
|
5934
|
+
for (let waited = 0; waited < POLL_MS && !accepted(); waited += 50) {
|
|
5935
|
+
await delay(50);
|
|
5936
|
+
}
|
|
5937
|
+
}
|
|
5938
|
+
if (!accepted()) {
|
|
5939
|
+
console.warn(`[TermServer] submitViaKeystrokes: prompt not confirmed accepted after ${MAX_ATTEMPTS} Enter attempts for ${ck} \u2014 it may not have submitted.`);
|
|
5940
|
+
}
|
|
5941
|
+
})();
|
|
5942
|
+
}
|
|
5836
5943
|
function killAllPtyProcesses() {
|
|
5837
5944
|
console.log(`[TermServer] Killing ${ptyProcesses.size} PTY processes`);
|
|
5838
5945
|
ptyProcesses.forEach((proc) => killPtyProcess(proc));
|
|
@@ -5843,7 +5950,10 @@ function killAllPtyProcesses() {
|
|
|
5843
5950
|
}
|
|
5844
5951
|
function killPtyProcess(proc) {
|
|
5845
5952
|
proc.process.kill();
|
|
5953
|
+
unregisterPty(proc.pid);
|
|
5846
5954
|
}
|
|
5955
|
+
var yoloEnabled = false;
|
|
5956
|
+
var additionalParams = "";
|
|
5847
5957
|
var pendingPreseededPrompts = /* @__PURE__ */ new Map();
|
|
5848
5958
|
async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows, preseededPrompt, launchMode = "copilot") {
|
|
5849
5959
|
if (process.env.COPILOT_E2E === "1") {
|
|
@@ -5865,7 +5975,7 @@ async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows,
|
|
|
5865
5975
|
const officeData = getOfficeSession(officeId);
|
|
5866
5976
|
let sessionId = officeData.sessionIds.get(agentId);
|
|
5867
5977
|
if (!sessionId) {
|
|
5868
|
-
sessionId =
|
|
5978
|
+
sessionId = crypto3.randomUUID();
|
|
5869
5979
|
officeData.sessionIds.set(agentId, sessionId);
|
|
5870
5980
|
await saveOfficeSessionFile(officeId);
|
|
5871
5981
|
console.log(`[TermServer] New session GUID for ${ck}: ${sessionId}`);
|
|
@@ -5876,9 +5986,9 @@ async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows,
|
|
|
5876
5986
|
const shell = os3.platform() === "win32" ? "powershell.exe" : "bash";
|
|
5877
5987
|
let cwd = process.cwd();
|
|
5878
5988
|
if (workingDir) {
|
|
5879
|
-
const customPath =
|
|
5989
|
+
const customPath = path4.isAbsolute(workingDir) ? workingDir : path4.join(process.cwd(), workingDir);
|
|
5880
5990
|
try {
|
|
5881
|
-
await
|
|
5991
|
+
await fs3.promises.access(customPath, fs3.constants.F_OK);
|
|
5882
5992
|
cwd = customPath;
|
|
5883
5993
|
} catch {
|
|
5884
5994
|
}
|
|
@@ -5906,6 +6016,9 @@ async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows,
|
|
|
5906
6016
|
workingDir
|
|
5907
6017
|
});
|
|
5908
6018
|
agentToTerminal.set(ck, terminalKey);
|
|
6019
|
+
if (terminalBackend.name === "node-pty") {
|
|
6020
|
+
registerPty({ pid: proc.pid, agentId, sessionId, startedAt: Date.now() });
|
|
6021
|
+
}
|
|
5909
6022
|
if (!shellOnlyMode) {
|
|
5910
6023
|
send({ type: "terminal-preload-status", agentId, status: "preloading" });
|
|
5911
6024
|
}
|
|
@@ -5964,8 +6077,16 @@ async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows,
|
|
|
5964
6077
|
console.log(`[TermServer] Forwarding turn_start for ${ck}`);
|
|
5965
6078
|
send({ type: "copilot-turn-start", agentId });
|
|
5966
6079
|
} else if (event.type === "user.message") {
|
|
6080
|
+
userMessageSeq.set(ck, (userMessageSeq.get(ck) ?? 0) + 1);
|
|
6081
|
+
let rawUserText = "";
|
|
6082
|
+
{
|
|
6083
|
+
const d = event.data ?? {};
|
|
6084
|
+
const raw = d.content || d.message || d.text || d.input || d.prompt || d.body || "";
|
|
6085
|
+
rawUserText = String(raw);
|
|
6086
|
+
lastUserMessageText.set(ck, normalizePromptText(rawUserText));
|
|
6087
|
+
}
|
|
5967
6088
|
console.log(`[TermServer] Forwarding user_message for ${ck}, data keys: ${JSON.stringify(Object.keys(event.data || {}))}`);
|
|
5968
|
-
send({ type: "copilot-user-message", agentId });
|
|
6089
|
+
send({ type: "copilot-user-message", agentId, text: rawUserText });
|
|
5969
6090
|
const existing = officeData.sessionMeta.get(agentId);
|
|
5970
6091
|
const existingTitle = typeof existing?.title === "string" ? existing.title.trim() : "";
|
|
5971
6092
|
if (existingTitle) {
|
|
@@ -6000,6 +6121,8 @@ async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows,
|
|
|
6000
6121
|
const isFleetCriticalEvent = event.type.startsWith("subagent.") || event.type === "system.notification" || event.type === "tool.execution_start" && event.data?.toolName === "task";
|
|
6001
6122
|
if (isFleetCriticalEvent || hasActiveViewer2(ck)) {
|
|
6002
6123
|
send({ type: "copilot-event", agentId, event });
|
|
6124
|
+
} else if (agentForwardKeys.has(ck)) {
|
|
6125
|
+
send({ type: "copilot-event", agentId, event, mainOnly: true });
|
|
6003
6126
|
} else {
|
|
6004
6127
|
console.warn(`[TermServer] Dropped copilot-event ${event.type} for ${ck} \u2014 no active viewer (viewers: [${[...activeAgentViewers].join(", ")}])`);
|
|
6005
6128
|
}
|
|
@@ -6017,6 +6140,7 @@ async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows,
|
|
|
6017
6140
|
pendingData = "";
|
|
6018
6141
|
};
|
|
6019
6142
|
proc.onData((data) => {
|
|
6143
|
+
lastPtyDataAt.set(ck, Date.now());
|
|
6020
6144
|
appendToScrollback(ck, data);
|
|
6021
6145
|
if (!shellOnlyMode && terminalBackend?.name === "node-pty" && !hasSignalledReady) {
|
|
6022
6146
|
const hasLegacyReadyMarker = data.includes("Environment loaded");
|
|
@@ -6037,12 +6161,16 @@ async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows,
|
|
|
6037
6161
|
});
|
|
6038
6162
|
proc.onExit(({ exitCode }) => {
|
|
6039
6163
|
send({ type: "terminal-exit", agentId, exitCode });
|
|
6164
|
+
unregisterPty(proc.pid);
|
|
6040
6165
|
ptyProcesses.delete(terminalKey);
|
|
6041
6166
|
activeAgentViewers.delete(ck);
|
|
6042
6167
|
agentScrollbackBuffers.delete(ck);
|
|
6043
6168
|
agentScrollbackBytes.delete(ck);
|
|
6044
6169
|
agentReadyState.delete(ck);
|
|
6045
6170
|
agentInTurn.delete(ck);
|
|
6171
|
+
lastPtyDataAt.delete(ck);
|
|
6172
|
+
userMessageSeq.delete(ck);
|
|
6173
|
+
lastUserMessageText.delete(ck);
|
|
6046
6174
|
const w = agentWatchers.get(ck);
|
|
6047
6175
|
if (w) {
|
|
6048
6176
|
w.stop();
|
|
@@ -6051,8 +6179,10 @@ async function startTerminalForAgent(officeId, agentId, workingDir, cols, rows,
|
|
|
6051
6179
|
});
|
|
6052
6180
|
if (!shellOnlyMode && terminalBackend.name === "node-pty") {
|
|
6053
6181
|
setTimeout(() => {
|
|
6054
|
-
|
|
6055
|
-
|
|
6182
|
+
const yoloFlag = yoloEnabled ? " --yolo" : "";
|
|
6183
|
+
const extraParams = additionalParams ? ` ${additionalParams}` : "";
|
|
6184
|
+
console.log(`[TermServer] Starting copilot --session-id for ${ck}: ${sessionId}${yoloEnabled ? " (yolo)" : ""}${additionalParams ? ` (params: ${additionalParams})` : ""}`);
|
|
6185
|
+
proc.write(`copilot --session-id=${sessionId}${yoloFlag}${extraParams}\r`);
|
|
6056
6186
|
}, 500);
|
|
6057
6187
|
}
|
|
6058
6188
|
return { success: true, pid: proc.pid, sessionId };
|
|
@@ -6083,12 +6213,47 @@ async function handleMessage(msg) {
|
|
|
6083
6213
|
}
|
|
6084
6214
|
break;
|
|
6085
6215
|
}
|
|
6216
|
+
case "submit-prompt": {
|
|
6217
|
+
const key = getTerminalKey(msg.officeId, msg.agentId);
|
|
6218
|
+
const proc = key ? ptyProcesses.get(key) : null;
|
|
6219
|
+
if (proc) {
|
|
6220
|
+
agentForwardKeys.add(compositeKey(msg.officeId, msg.agentId));
|
|
6221
|
+
const backendProc = proc.process;
|
|
6222
|
+
if (typeof backendProc.submitPrompt === "function") {
|
|
6223
|
+
backendProc.submitPrompt(msg.prompt, msg.label);
|
|
6224
|
+
} else {
|
|
6225
|
+
submitViaKeystrokes(backendProc, msg.prompt, key);
|
|
6226
|
+
}
|
|
6227
|
+
send({ type: "response", requestId: msg.requestId, result: { success: true } });
|
|
6228
|
+
} else {
|
|
6229
|
+
const ck = compositeKey(msg.officeId, msg.agentId);
|
|
6230
|
+
console.log(`[TermServer] SUBMIT-PROMPT FAILED \u2014 no PTY for ${ck}`);
|
|
6231
|
+
send({ type: "response", requestId: msg.requestId, result: { success: false, error: `No PTY for ${ck}` } });
|
|
6232
|
+
}
|
|
6233
|
+
break;
|
|
6234
|
+
}
|
|
6235
|
+
case "set-agent-forwarding": {
|
|
6236
|
+
const ck = compositeKey(msg.officeId, msg.agentId);
|
|
6237
|
+
if (msg.enabled) agentForwardKeys.add(ck);
|
|
6238
|
+
else agentForwardKeys.delete(ck);
|
|
6239
|
+
break;
|
|
6240
|
+
}
|
|
6086
6241
|
case "resize": {
|
|
6087
6242
|
const key = getTerminalKey(msg.officeId, msg.agentId);
|
|
6088
6243
|
const proc = key ? ptyProcesses.get(key) : null;
|
|
6089
6244
|
if (proc) proc.process.resize(msg.cols, msg.rows);
|
|
6090
6245
|
break;
|
|
6091
6246
|
}
|
|
6247
|
+
case "set-yolo": {
|
|
6248
|
+
yoloEnabled = msg.enabled;
|
|
6249
|
+
console.log(`[TermServer] YOLO mode ${yoloEnabled ? "ENABLED" : "disabled"}`);
|
|
6250
|
+
break;
|
|
6251
|
+
}
|
|
6252
|
+
case "set-additional-params": {
|
|
6253
|
+
additionalParams = (msg.params ?? "").trim();
|
|
6254
|
+
console.log(`[TermServer] Additional params ${additionalParams ? `set: ${additionalParams}` : "cleared"}`);
|
|
6255
|
+
break;
|
|
6256
|
+
}
|
|
6092
6257
|
case "kill": {
|
|
6093
6258
|
const ck = compositeKey(msg.officeId, msg.agentId);
|
|
6094
6259
|
const key = getTerminalKey(msg.officeId, msg.agentId);
|
|
@@ -6185,15 +6350,18 @@ async function handleMessage(msg) {
|
|
|
6185
6350
|
const ptyProc = termKey ? ptyProcesses.get(termKey) : null;
|
|
6186
6351
|
let cwd = process.cwd();
|
|
6187
6352
|
if (ptyProc?.workingDir) {
|
|
6188
|
-
const customPath =
|
|
6353
|
+
const customPath = path4.join(process.cwd(), ptyProc.workingDir);
|
|
6189
6354
|
try {
|
|
6190
|
-
await
|
|
6355
|
+
await fs3.promises.access(customPath, fs3.constants.F_OK);
|
|
6191
6356
|
cwd = customPath;
|
|
6192
6357
|
} catch {
|
|
6193
6358
|
}
|
|
6194
6359
|
}
|
|
6195
6360
|
try {
|
|
6196
|
-
|
|
6361
|
+
const wtArgs = ["-d", cwd, "copilot", "--session-id", sid];
|
|
6362
|
+
if (yoloEnabled) wtArgs.push("--yolo");
|
|
6363
|
+
if (additionalParams) wtArgs.push(...additionalParams.split(/\s+/).filter(Boolean));
|
|
6364
|
+
(0, import_child_process2.spawn)("wt", wtArgs, { detached: true, stdio: "ignore" }).unref();
|
|
6197
6365
|
send({ type: "response", requestId: msg.requestId, result: { success: true } });
|
|
6198
6366
|
} catch (error) {
|
|
6199
6367
|
send({ type: "response", requestId: msg.requestId, result: { success: false, error: String(error) } });
|
|
@@ -6225,7 +6393,7 @@ async function handleMessage(msg) {
|
|
|
6225
6393
|
hasAutoTitled.delete(ck);
|
|
6226
6394
|
send({ type: "session-meta-updated", agentId: msg.agentId, meta: { title: "" } });
|
|
6227
6395
|
archiveSessionId(msg.officeId, msg.agentId);
|
|
6228
|
-
const newSessionId =
|
|
6396
|
+
const newSessionId = crypto3.randomUUID();
|
|
6229
6397
|
officeDataReset.sessionIds.set(msg.agentId, newSessionId);
|
|
6230
6398
|
await saveOfficeSessionFile(msg.officeId);
|
|
6231
6399
|
console.log(`[TermServer] Reset session for ${ck}: new GUID ${newSessionId}`);
|
|
@@ -6276,7 +6444,7 @@ async function handleMessage(msg) {
|
|
|
6276
6444
|
}
|
|
6277
6445
|
officeData.sessionMeta.clear();
|
|
6278
6446
|
for (const agentId of officeData.sessionIds.keys()) {
|
|
6279
|
-
officeData.sessionIds.set(agentId,
|
|
6447
|
+
officeData.sessionIds.set(agentId, crypto3.randomUUID());
|
|
6280
6448
|
}
|
|
6281
6449
|
await saveOfficeSessionFile(officeId);
|
|
6282
6450
|
console.log(`[TermServer] All sessions reset for ${officeId}`);
|
|
@@ -6351,7 +6519,7 @@ async function handleMessage(msg) {
|
|
|
6351
6519
|
case "delete-office-session": {
|
|
6352
6520
|
const filePath = getSessionFile(msg.officeId);
|
|
6353
6521
|
try {
|
|
6354
|
-
await
|
|
6522
|
+
await fs3.promises.unlink(filePath);
|
|
6355
6523
|
officeSessions.delete(msg.officeId);
|
|
6356
6524
|
console.log(`[TermServer] Deleted session file for ${msg.officeId}`);
|
|
6357
6525
|
} catch {
|