@github/copilot-language-server 1.560.0 → 1.562.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/main.js +1020 -973
- package/dist/node_modules/@github/copilot-sdk/dist/cjs/cliVersion.js +1 -1
- package/dist/node_modules/@github/copilot-sdk/dist/cjs/client.js +165 -23
- package/dist/node_modules/@github/copilot-sdk/dist/cjs/copilotRequestHandler.js +17 -9
- package/dist/node_modules/@github/copilot-sdk/dist/cjs/ffiRuntimeHost.js +24 -0
- package/dist/node_modules/@github/copilot-sdk/dist/cjs/generated/rpc.js +1063 -258
- package/dist/node_modules/@github/copilot-sdk/dist/cjs/host.js +17 -1
- package/dist/node_modules/@github/copilot-sdk/dist/cjs/session.js +219 -29
- package/dist/node_modules/@github/copilot-sdk/dist/cjs/types.js +2 -2
- package/dist/node_modules/@github/copilot-sdk/package.json +28 -18
- package/package.json +20 -20
|
@@ -22,7 +22,7 @@ __export(cliVersion_exports, {
|
|
|
22
22
|
COPILOT_CLI_VERSION: () => COPILOT_CLI_VERSION
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(cliVersion_exports);
|
|
25
|
-
const COPILOT_CLI_VERSION = "1.0.
|
|
25
|
+
const COPILOT_CLI_VERSION = "1.0.103";
|
|
26
26
|
const COPILOT_CLI_USE_NPM_PACKAGE = false;
|
|
27
27
|
// Annotate the CommonJS export names for ESM import in node:
|
|
28
28
|
0 && (module.exports = {
|
|
@@ -293,6 +293,8 @@ class CopilotClient {
|
|
|
293
293
|
sessions = /* @__PURE__ */ new Map();
|
|
294
294
|
hostExitCallbacks = /* @__PURE__ */ new Map();
|
|
295
295
|
hostSessionFactories = /* @__PURE__ */ new Map();
|
|
296
|
+
hostAuthenticators = /* @__PURE__ */ new Map();
|
|
297
|
+
hostAuthentications = /* @__PURE__ */ new Map();
|
|
296
298
|
hostHandoffs = /* @__PURE__ */ new Map();
|
|
297
299
|
stderrBuffer = "";
|
|
298
300
|
// Captures CLI stderr for error messages
|
|
@@ -497,6 +499,7 @@ class CopilotClient {
|
|
|
497
499
|
const connArgs = conn.kind === "stdio" || conn.kind === "tcp" ? conn.args ?? [] : [];
|
|
498
500
|
this.connectionExtraArgs = [...connArgs];
|
|
499
501
|
this.options = {
|
|
502
|
+
entra: options.entra ? { ...options.entra } : void 0,
|
|
500
503
|
workingDirectory: options.workingDirectory ?? process.cwd(),
|
|
501
504
|
logLevel: options.logLevel,
|
|
502
505
|
gitHubToken: options.gitHubToken,
|
|
@@ -505,7 +508,6 @@ class CopilotClient {
|
|
|
505
508
|
telemetry: options.telemetry,
|
|
506
509
|
baseDirectory: options.baseDirectory,
|
|
507
510
|
sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0,
|
|
508
|
-
enableRemoteSessions: options.enableRemoteSessions ?? false,
|
|
509
511
|
mode: options.mode ?? "copilot-cli",
|
|
510
512
|
clientInfo: options.clientInfo
|
|
511
513
|
};
|
|
@@ -620,6 +622,16 @@ class CopilotClient {
|
|
|
620
622
|
handlers.gitHubToken = {
|
|
621
623
|
getToken: (params) => this.acquireGitHubToken(params)
|
|
622
624
|
};
|
|
625
|
+
handlers.uiThread = {
|
|
626
|
+
run: async ({ actionId }) => {
|
|
627
|
+
const connection = this.connectionConfig;
|
|
628
|
+
const host = this.ffiHost;
|
|
629
|
+
if (connection.kind !== "inprocess" || !connection.runOnUiThread || !host) {
|
|
630
|
+
throw new Error("No in-process runOnUiThread handler is configured.");
|
|
631
|
+
}
|
|
632
|
+
await connection.runOnUiThread(() => host.runUiAction(actionId));
|
|
633
|
+
}
|
|
634
|
+
};
|
|
623
635
|
this.clientGlobalHandlers = handlers;
|
|
624
636
|
}
|
|
625
637
|
async acquireGitHubToken(params) {
|
|
@@ -780,11 +792,19 @@ class CopilotClient {
|
|
|
780
792
|
const sessionId = session.sessionId;
|
|
781
793
|
let lastError = null;
|
|
782
794
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
795
|
+
if (this.connectionClosed) {
|
|
796
|
+
lastError = null;
|
|
797
|
+
break;
|
|
798
|
+
}
|
|
783
799
|
try {
|
|
784
800
|
await session.disconnect();
|
|
785
801
|
lastError = null;
|
|
786
802
|
break;
|
|
787
803
|
} catch (error) {
|
|
804
|
+
if (this.connectionClosed) {
|
|
805
|
+
lastError = null;
|
|
806
|
+
break;
|
|
807
|
+
}
|
|
788
808
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
789
809
|
if (attempt < 3) {
|
|
790
810
|
const delay = 100 * Math.pow(2, attempt - 1);
|
|
@@ -970,8 +990,10 @@ class CopilotClient {
|
|
|
970
990
|
* - Clears all sessions immediately without destroying them
|
|
971
991
|
* - Force closes the connection
|
|
972
992
|
* - Sends SIGKILL to the CLI process (if spawned by this client)
|
|
993
|
+
* - Waits for the spawned CLI process to exit
|
|
973
994
|
*
|
|
974
995
|
* @returns A promise that resolves when the force stop is complete
|
|
996
|
+
* @throws If the spawned CLI process cannot be terminated
|
|
975
997
|
*
|
|
976
998
|
* @example
|
|
977
999
|
* ```typescript
|
|
@@ -1018,13 +1040,6 @@ class CopilotClient {
|
|
|
1018
1040
|
}
|
|
1019
1041
|
this.socket = null;
|
|
1020
1042
|
}
|
|
1021
|
-
if (this.cliProcess && !this.isExternalServer) {
|
|
1022
|
-
try {
|
|
1023
|
-
this.cliProcess.kill("SIGKILL");
|
|
1024
|
-
} catch {
|
|
1025
|
-
}
|
|
1026
|
-
this.cliProcess = null;
|
|
1027
|
-
}
|
|
1028
1043
|
if (this.ffiHost) {
|
|
1029
1044
|
const host = this.ffiHost;
|
|
1030
1045
|
this.ffiHost = null;
|
|
@@ -1041,6 +1056,20 @@ class CopilotClient {
|
|
|
1041
1056
|
this.runtimePort = null;
|
|
1042
1057
|
this.stderrBuffer = "";
|
|
1043
1058
|
this.processExitPromise = null;
|
|
1059
|
+
if (this.cliProcess && !this.isExternalServer) {
|
|
1060
|
+
const child = this.cliProcess;
|
|
1061
|
+
if (child.exitCode == null && child.signalCode == null) {
|
|
1062
|
+
child.kill("SIGKILL");
|
|
1063
|
+
if (!await waitForChildExit(child, RUNTIME_SHUTDOWN_TIMEOUT_MS)) {
|
|
1064
|
+
throw new Error(
|
|
1065
|
+
`Timed out waiting for CLI process to exit after SIGKILL: ${RUNTIME_SHUTDOWN_TIMEOUT_MS}ms`
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
if (this.cliProcess === child) {
|
|
1070
|
+
this.cliProcess = null;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1044
1073
|
}
|
|
1045
1074
|
/**
|
|
1046
1075
|
* Creates a new conversation session with the Copilot CLI.
|
|
@@ -1299,6 +1328,7 @@ class CopilotClient {
|
|
|
1299
1328
|
model: config.model,
|
|
1300
1329
|
allowedModels: config.allowedModels,
|
|
1301
1330
|
sessionId: localSessionId,
|
|
1331
|
+
name: config.name,
|
|
1302
1332
|
clientName: config.clientName,
|
|
1303
1333
|
reasoningEffort: config.reasoningEffort,
|
|
1304
1334
|
reasoningSummary: config.reasoningSummary,
|
|
@@ -1312,7 +1342,8 @@ class CopilotClient {
|
|
|
1312
1342
|
skipPermission: tool.skipPermission,
|
|
1313
1343
|
defer: tool.defer,
|
|
1314
1344
|
metadata: tool.metadata,
|
|
1315
|
-
isTerminal: tool.isTerminal
|
|
1345
|
+
isTerminal: tool.isTerminal,
|
|
1346
|
+
namespace: tool.namespace
|
|
1316
1347
|
})),
|
|
1317
1348
|
toolSearch: config.toolSearch,
|
|
1318
1349
|
imageGeneration: config.imageGeneration,
|
|
@@ -1339,6 +1370,7 @@ class CopilotClient {
|
|
|
1339
1370
|
enableCitations: config.enableCitations,
|
|
1340
1371
|
enableFileChangeTracking: config.enableFileChangeTracking,
|
|
1341
1372
|
sessionLimits: config.sessionLimits,
|
|
1373
|
+
autopilot: config.autopilot,
|
|
1342
1374
|
modelCapabilities: config.modelCapabilities,
|
|
1343
1375
|
largeOutput: toWireLargeOutput(config.largeOutput),
|
|
1344
1376
|
requestPermission: !!config.onPermissionRequest,
|
|
@@ -1351,6 +1383,7 @@ class CopilotClient {
|
|
|
1351
1383
|
requestAutoModeSwitch: !!config.onAutoModeSwitchRequest,
|
|
1352
1384
|
hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)),
|
|
1353
1385
|
workingDirectory: config.workingDirectory,
|
|
1386
|
+
trustWorkingDirectory: config.trustWorkingDirectory,
|
|
1354
1387
|
additionalDirectories: config.additionalDirectories,
|
|
1355
1388
|
streaming: config.streaming,
|
|
1356
1389
|
includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true,
|
|
@@ -1377,20 +1410,23 @@ class CopilotClient {
|
|
|
1377
1410
|
enableSkills: config.enableSkills,
|
|
1378
1411
|
skillDirectories: config.skillDirectories,
|
|
1379
1412
|
...config.skillProvider ? { hasSkillProvider: true } : {},
|
|
1413
|
+
agentDirectories: config.agentDirectories,
|
|
1414
|
+
hookDirectories: config.hookDirectories,
|
|
1380
1415
|
pluginDirectories: config.pluginDirectories,
|
|
1381
1416
|
instructionDirectories: config.instructionDirectories,
|
|
1382
1417
|
disabledSkills: config.disabledSkills,
|
|
1383
1418
|
disabledMcpServers: config.disabledMcpServers,
|
|
1419
|
+
sandboxConfig: config.sandboxConfig,
|
|
1384
1420
|
infiniteSessions: config.infiniteSessions,
|
|
1385
1421
|
memory: config.memory,
|
|
1386
1422
|
gitHubToken: config.gitHubToken,
|
|
1387
1423
|
gitHubTokenProviderRegistrationId,
|
|
1388
|
-
remoteSession: config.remoteSession,
|
|
1389
1424
|
cloud: config.cloud,
|
|
1390
1425
|
featureFlags: config.featureFlags,
|
|
1391
1426
|
expAssignments: config.expAssignments,
|
|
1392
1427
|
enableManagedSettings: config.enableManagedSettings,
|
|
1393
1428
|
enforceManagedModelDefaults: config.enforceManagedModelDefaults,
|
|
1429
|
+
interactiveUser: config.interactiveUser,
|
|
1394
1430
|
managedSettings: config.managedSettings
|
|
1395
1431
|
});
|
|
1396
1432
|
const {
|
|
@@ -1581,6 +1617,7 @@ class CopilotClient {
|
|
|
1581
1617
|
enableCitations: config.enableCitations,
|
|
1582
1618
|
enableFileChangeTracking: config.enableFileChangeTracking,
|
|
1583
1619
|
sessionLimits: config.sessionLimits,
|
|
1620
|
+
autopilot: config.autopilot,
|
|
1584
1621
|
tools: config.tools?.map((tool) => ({
|
|
1585
1622
|
name: tool.name,
|
|
1586
1623
|
description: tool.description,
|
|
@@ -1589,7 +1626,8 @@ class CopilotClient {
|
|
|
1589
1626
|
skipPermission: tool.skipPermission,
|
|
1590
1627
|
defer: tool.defer,
|
|
1591
1628
|
metadata: tool.metadata,
|
|
1592
|
-
isTerminal: tool.isTerminal
|
|
1629
|
+
isTerminal: tool.isTerminal,
|
|
1630
|
+
namespace: tool.namespace
|
|
1593
1631
|
})),
|
|
1594
1632
|
toolSearch: config.toolSearch,
|
|
1595
1633
|
imageGeneration: config.imageGeneration,
|
|
@@ -1645,22 +1683,25 @@ class CopilotClient {
|
|
|
1645
1683
|
agent: config.agent,
|
|
1646
1684
|
skillDirectories: config.skillDirectories,
|
|
1647
1685
|
...config.skillProvider ? { hasSkillProvider: true } : {},
|
|
1686
|
+
agentDirectories: config.agentDirectories,
|
|
1687
|
+
hookDirectories: config.hookDirectories,
|
|
1648
1688
|
pluginDirectories: config.pluginDirectories,
|
|
1649
1689
|
instructionDirectories: config.instructionDirectories,
|
|
1650
1690
|
disabledSkills: config.disabledSkills,
|
|
1651
1691
|
disabledMcpServers: config.disabledMcpServers,
|
|
1692
|
+
sandboxConfig: config.sandboxConfig,
|
|
1652
1693
|
infiniteSessions: config.infiniteSessions,
|
|
1653
1694
|
memory: config.memory,
|
|
1654
1695
|
disableResume: config.suppressResumeEvent,
|
|
1655
1696
|
continuePendingWork: config.continuePendingWork,
|
|
1656
1697
|
gitHubToken: config.gitHubToken,
|
|
1657
1698
|
gitHubTokenProviderRegistrationId,
|
|
1658
|
-
remoteSession: config.remoteSession,
|
|
1659
1699
|
openCanvases: config.openCanvases,
|
|
1660
1700
|
featureFlags: config.featureFlags,
|
|
1661
1701
|
expAssignments: config.expAssignments,
|
|
1662
1702
|
enableManagedSettings: config.enableManagedSettings,
|
|
1663
1703
|
enforceManagedModelDefaults: config.enforceManagedModelDefaults,
|
|
1704
|
+
interactiveUser: config.interactiveUser,
|
|
1664
1705
|
managedSettings: config.managedSettings,
|
|
1665
1706
|
...extensionOptions?.requestedEnvironmentVariables ? {
|
|
1666
1707
|
requestedEnvironmentVariables: extensionOptions.requestedEnvironmentVariables
|
|
@@ -1724,6 +1765,18 @@ class CopilotClient {
|
|
|
1724
1765
|
* @experimental
|
|
1725
1766
|
*/
|
|
1726
1767
|
async startAhpHost(options) {
|
|
1768
|
+
const authentication = options?.authentication;
|
|
1769
|
+
if (!authentication || !["github", "none", "custom"].includes(authentication.mode)) {
|
|
1770
|
+
throw new Error("An explicit authentication mode is required");
|
|
1771
|
+
}
|
|
1772
|
+
if (authentication.mode === "custom" && (typeof authentication.requireIdentity !== "string" || !authentication.requireIdentity.trim() || typeof authentication.authenticate !== "function")) {
|
|
1773
|
+
throw new Error(
|
|
1774
|
+
"Custom authentication requires a nonempty requireIdentity and authenticate callback"
|
|
1775
|
+
);
|
|
1776
|
+
}
|
|
1777
|
+
if (authentication.mode !== "github" && options.githubEnvironment) {
|
|
1778
|
+
throw new Error("githubEnvironment requires github authentication");
|
|
1779
|
+
}
|
|
1727
1780
|
if (!options?.localServer && !options?.githubEnvironment) {
|
|
1728
1781
|
throw new Error("At least one of localServer or githubEnvironment is required");
|
|
1729
1782
|
}
|
|
@@ -1732,8 +1785,12 @@ class CopilotClient {
|
|
|
1732
1785
|
}
|
|
1733
1786
|
const rpc = this.rpc;
|
|
1734
1787
|
const hostId = (0, import_node_crypto.randomUUID)();
|
|
1788
|
+
if (authentication.mode === "custom") {
|
|
1789
|
+
this.hostAuthenticators.set(hostId, { ...authentication });
|
|
1790
|
+
}
|
|
1735
1791
|
const {
|
|
1736
1792
|
computeId,
|
|
1793
|
+
allowCreatingNewSessions,
|
|
1737
1794
|
localServer,
|
|
1738
1795
|
githubEnvironment,
|
|
1739
1796
|
onExit,
|
|
@@ -1745,7 +1802,11 @@ class CopilotClient {
|
|
|
1745
1802
|
this.hostSessionFactories.set(hostId, {
|
|
1746
1803
|
createSession,
|
|
1747
1804
|
resumeSession,
|
|
1748
|
-
onSessionReleased
|
|
1805
|
+
onSessionReleased,
|
|
1806
|
+
policy: {
|
|
1807
|
+
mode: authentication.mode,
|
|
1808
|
+
requireIdentity: authentication.mode === "custom" ? authentication.requireIdentity : void 0
|
|
1809
|
+
}
|
|
1749
1810
|
});
|
|
1750
1811
|
}
|
|
1751
1812
|
if (onExit) {
|
|
@@ -1754,11 +1815,13 @@ class CopilotClient {
|
|
|
1754
1815
|
try {
|
|
1755
1816
|
const info = await rpc.host.start({
|
|
1756
1817
|
hostId,
|
|
1818
|
+
authentication: authentication.mode === "custom" ? { mode: "custom", requireIdentity: authentication.requireIdentity } : { mode: authentication.mode },
|
|
1757
1819
|
computeId,
|
|
1758
1820
|
localServer,
|
|
1759
1821
|
githubEnvironment,
|
|
1760
1822
|
sessionFactory: createSession ? true : void 0,
|
|
1761
|
-
resumeFactory: resumeSession ? true : void 0
|
|
1823
|
+
resumeFactory: resumeSession ? true : void 0,
|
|
1824
|
+
allowCreatingNewSessions
|
|
1762
1825
|
});
|
|
1763
1826
|
return new import_host.AhpHost(
|
|
1764
1827
|
info,
|
|
@@ -1766,7 +1829,14 @@ class CopilotClient {
|
|
|
1766
1829
|
await rpc.host.dispose({ hostId });
|
|
1767
1830
|
},
|
|
1768
1831
|
(sessionId) => rpc.host.publishSession({ hostId, sessionId }),
|
|
1769
|
-
() => rpc.host.listSessions({ hostId })
|
|
1832
|
+
() => rpc.host.listSessions({ hostId }),
|
|
1833
|
+
(sessionId) => rpc.host.unpublishSession({ hostId, sessionId }),
|
|
1834
|
+
async (allowed) => {
|
|
1835
|
+
await rpc.host.setSessionCreationPolicy({
|
|
1836
|
+
hostId,
|
|
1837
|
+
allowCreatingNewSessions: allowed
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1770
1840
|
);
|
|
1771
1841
|
} catch (error) {
|
|
1772
1842
|
this.hostExitCallbacks.delete(hostId);
|
|
@@ -1792,7 +1862,8 @@ class CopilotClient {
|
|
|
1792
1862
|
disconnectHosts() {
|
|
1793
1863
|
for (const hostId of /* @__PURE__ */ new Set([
|
|
1794
1864
|
...this.hostExitCallbacks.keys(),
|
|
1795
|
-
...this.hostSessionFactories.keys()
|
|
1865
|
+
...this.hostSessionFactories.keys(),
|
|
1866
|
+
...this.hostAuthenticators.keys()
|
|
1796
1867
|
])) {
|
|
1797
1868
|
this.handleHostExit({
|
|
1798
1869
|
hostId,
|
|
@@ -1802,6 +1873,13 @@ class CopilotClient {
|
|
|
1802
1873
|
}
|
|
1803
1874
|
}
|
|
1804
1875
|
releaseHostSessions(hostId) {
|
|
1876
|
+
this.hostAuthenticators.delete(hostId);
|
|
1877
|
+
for (const [requestId, entry] of this.hostAuthentications) {
|
|
1878
|
+
if (entry.hostId === hostId) {
|
|
1879
|
+
this.hostAuthentications.delete(requestId);
|
|
1880
|
+
entry.controller.abort();
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1805
1883
|
this.hostSessionFactories.delete(hostId);
|
|
1806
1884
|
for (const [handoffId, entry] of this.hostHandoffs) {
|
|
1807
1885
|
if (entry.hostId === hostId) this.releaseHostSession(handoffId);
|
|
@@ -1830,10 +1908,19 @@ class CopilotClient {
|
|
|
1830
1908
|
}
|
|
1831
1909
|
}
|
|
1832
1910
|
async createHostSession(params) {
|
|
1911
|
+
const authentication = params.authentication;
|
|
1912
|
+
if (!authentication) {
|
|
1913
|
+
throw new Error("AHP session handoff authentication is required");
|
|
1914
|
+
}
|
|
1833
1915
|
const options = this.hostSessionFactories.get(params.hostId);
|
|
1834
1916
|
if (!(params.resume ? options?.resumeSession : options?.createSession) || this.hostHandoffs.has(params.handoffId)) {
|
|
1835
1917
|
throw new Error("AHP session factory is unavailable or handoff already exists");
|
|
1836
1918
|
}
|
|
1919
|
+
const policy = options.policy;
|
|
1920
|
+
const identity = authentication.identity;
|
|
1921
|
+
if (authentication.mode !== policy.mode || (authentication.mode === "none" ? identity !== void 0 : typeof identity !== "string" || !identity.trim()) || policy.mode === "custom" && identity !== policy.requireIdentity) {
|
|
1922
|
+
throw new Error("AHP trusted authentication does not match host policy");
|
|
1923
|
+
}
|
|
1837
1924
|
const entry = {
|
|
1838
1925
|
hostId: params.hostId,
|
|
1839
1926
|
requestedSessionId: params.config.sessionId,
|
|
@@ -1860,12 +1947,14 @@ class CopilotClient {
|
|
|
1860
1947
|
const { sessionId, ...resumeConfig } = config;
|
|
1861
1948
|
if (!sessionId) throw new Error("AHP resume requires sessionId");
|
|
1862
1949
|
return options.resumeSession({
|
|
1950
|
+
authentication,
|
|
1863
1951
|
sessionId,
|
|
1864
1952
|
config: resumeConfig,
|
|
1865
1953
|
signal: entry.controller.signal
|
|
1866
1954
|
});
|
|
1867
1955
|
}
|
|
1868
1956
|
return options.createSession({
|
|
1957
|
+
authentication,
|
|
1869
1958
|
config,
|
|
1870
1959
|
signal: entry.controller.signal
|
|
1871
1960
|
});
|
|
@@ -2012,6 +2101,7 @@ class CopilotClient {
|
|
|
2012
2101
|
let serverVersion;
|
|
2013
2102
|
try {
|
|
2014
2103
|
const connectParams = {
|
|
2104
|
+
entra: this.options.entra,
|
|
2015
2105
|
token: this.effectiveConnectionToken,
|
|
2016
2106
|
supportedTaskKinds: ["agent", "client", "shell"]
|
|
2017
2107
|
};
|
|
@@ -2026,6 +2116,9 @@ class CopilotClient {
|
|
|
2026
2116
|
serverVersion = result.protocolVersion;
|
|
2027
2117
|
} catch (err) {
|
|
2028
2118
|
if (err instanceof import_node.ResponseError && (err.code === import_node.ErrorCodes.MethodNotFound || err.message === "Unhandled method connect")) {
|
|
2119
|
+
if (this.options.entra) {
|
|
2120
|
+
throw new Error("This runtime does not support Entra client configuration.");
|
|
2121
|
+
}
|
|
2029
2122
|
serverVersion = (await raceAgainstExit(this.ping())).protocolVersion;
|
|
2030
2123
|
} else {
|
|
2031
2124
|
throw err;
|
|
@@ -2312,9 +2405,6 @@ class CopilotClient {
|
|
|
2312
2405
|
this.options.sessionIdleTimeoutSeconds.toString()
|
|
2313
2406
|
);
|
|
2314
2407
|
}
|
|
2315
|
-
if (this.options.enableRemoteSessions) {
|
|
2316
|
-
args.push("--remote");
|
|
2317
|
-
}
|
|
2318
2408
|
const envWithoutNodeDebug = this.buildRuntimeEnv();
|
|
2319
2409
|
if (!this.resolvedCliPath) {
|
|
2320
2410
|
throw new Error(
|
|
@@ -2426,7 +2516,13 @@ stderr: ${stderrOutput}`
|
|
|
2426
2516
|
this.cliStartTimeout = setTimeout(() => {
|
|
2427
2517
|
if (!resolved) {
|
|
2428
2518
|
resolved = true;
|
|
2429
|
-
reject(
|
|
2519
|
+
reject(
|
|
2520
|
+
new Error(
|
|
2521
|
+
`Timeout waiting for CLI server to start
|
|
2522
|
+
stdout: ${stdout.trim().slice(-8192) || "(empty)"}
|
|
2523
|
+
stderr: ${this.stderrBuffer.trim().slice(-8192) || "(empty)"}`
|
|
2524
|
+
)
|
|
2525
|
+
);
|
|
2430
2526
|
}
|
|
2431
2527
|
}, 3e4);
|
|
2432
2528
|
});
|
|
@@ -2494,9 +2590,6 @@ stderr: ${stderrOutput}`
|
|
|
2494
2590
|
if (this.options.sessionIdleTimeoutSeconds > 0) {
|
|
2495
2591
|
args.push("--session-idle-timeout", this.options.sessionIdleTimeoutSeconds.toString());
|
|
2496
2592
|
}
|
|
2497
|
-
if (this.options.enableRemoteSessions) {
|
|
2498
|
-
args.push("--remote");
|
|
2499
|
-
}
|
|
2500
2593
|
if (cliLoginSyncIntegrationId) {
|
|
2501
2594
|
args.push(`--cli-login-sync-integration-id=${cliLoginSyncIntegrationId}`);
|
|
2502
2595
|
}
|
|
@@ -2519,6 +2612,9 @@ stderr: ${stderrOutput}`
|
|
|
2519
2612
|
);
|
|
2520
2613
|
this.attachConnectionHandlers();
|
|
2521
2614
|
this.connection.listen();
|
|
2615
|
+
this.ffiHost.configureUiThread(
|
|
2616
|
+
this.connectionConfig.kind === "inprocess" && this.connectionConfig.runOnUiThread !== void 0
|
|
2617
|
+
);
|
|
2522
2618
|
}
|
|
2523
2619
|
static getNapiPrebuildsFolder(entrypoint) {
|
|
2524
2620
|
const arch = process.arch;
|
|
@@ -2561,6 +2657,9 @@ stderr: ${stderrOutput}`
|
|
|
2561
2657
|
stderr: ${stderrOutput}` : ""}`
|
|
2562
2658
|
);
|
|
2563
2659
|
this.logDebug(`stdin pipe error: ${reason}`);
|
|
2660
|
+
if (this.messageWriter) {
|
|
2661
|
+
this.messageWriter.suppressWriteErrors = true;
|
|
2662
|
+
}
|
|
2564
2663
|
try {
|
|
2565
2664
|
this.connection?.dispose();
|
|
2566
2665
|
} catch {
|
|
@@ -2666,6 +2765,49 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
2666
2765
|
"host.materializeSession",
|
|
2667
2766
|
(params) => this.createHostSession(params)
|
|
2668
2767
|
);
|
|
2768
|
+
this.connection.onRequest(
|
|
2769
|
+
"host.validateAuthentication",
|
|
2770
|
+
async (params) => {
|
|
2771
|
+
const authenticator = this.hostAuthenticators.get(params.hostId);
|
|
2772
|
+
if (!authenticator || this.hostAuthentications.has(params.requestId)) {
|
|
2773
|
+
throw new Error("AHP authenticator is unavailable or request already exists");
|
|
2774
|
+
}
|
|
2775
|
+
const entry = { hostId: params.hostId, controller: new AbortController() };
|
|
2776
|
+
this.hostAuthentications.set(params.requestId, entry);
|
|
2777
|
+
const signal = entry.controller.signal;
|
|
2778
|
+
const cancelled = new Promise((_resolve, reject) => {
|
|
2779
|
+
signal.addEventListener(
|
|
2780
|
+
"abort",
|
|
2781
|
+
() => reject(new Error("AHP authentication ended")),
|
|
2782
|
+
{ once: true }
|
|
2783
|
+
);
|
|
2784
|
+
});
|
|
2785
|
+
try {
|
|
2786
|
+
const result = await Promise.race([
|
|
2787
|
+
Promise.resolve().then(
|
|
2788
|
+
() => authenticator.authenticate({ token: params.token, signal })
|
|
2789
|
+
),
|
|
2790
|
+
cancelled
|
|
2791
|
+
]);
|
|
2792
|
+
if (signal.aborted || this.hostAuthenticators.get(params.hostId) !== authenticator) {
|
|
2793
|
+
throw new Error("AHP authentication ended");
|
|
2794
|
+
}
|
|
2795
|
+
return result;
|
|
2796
|
+
} finally {
|
|
2797
|
+
if (this.hostAuthentications.get(params.requestId) === entry) {
|
|
2798
|
+
this.hostAuthentications.delete(params.requestId);
|
|
2799
|
+
}
|
|
2800
|
+
entry.controller.abort();
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
);
|
|
2804
|
+
this.connection.onNotification(
|
|
2805
|
+
"host.authenticationCancelled",
|
|
2806
|
+
(params) => {
|
|
2807
|
+
const entry = this.hostAuthentications.get(params.requestId);
|
|
2808
|
+
if (entry?.hostId === params.hostId) entry.controller.abort();
|
|
2809
|
+
}
|
|
2810
|
+
);
|
|
2669
2811
|
this.connection.onNotification(
|
|
2670
2812
|
"host.sessionReleased",
|
|
2671
2813
|
(params) => {
|
|
@@ -98,7 +98,7 @@ class CopilotWebSocketForwarder extends CopilotWebSocketHandler {
|
|
|
98
98
|
constructor(context) {
|
|
99
99
|
super(context);
|
|
100
100
|
}
|
|
101
|
-
sendRequestMessage(data) {
|
|
101
|
+
sendRequestMessage(data, _ctx) {
|
|
102
102
|
if (this.#upstream?.readyState !== WebSocket.OPEN) {
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
@@ -182,6 +182,7 @@ class CopilotRequestHandler {
|
|
|
182
182
|
requestId: exchange.requestId,
|
|
183
183
|
sessionId: exchange.sessionId,
|
|
184
184
|
agentId: exchange.agentId,
|
|
185
|
+
agentInvocationId: exchange.agentInvocationId,
|
|
185
186
|
parentAgentId: exchange.parentAgentId,
|
|
186
187
|
interactionType: exchange.interactionType,
|
|
187
188
|
transport: exchange.transport,
|
|
@@ -209,7 +210,10 @@ class CopilotRequestHandler {
|
|
|
209
210
|
let cancelled;
|
|
210
211
|
const clientSettled = (async () => {
|
|
211
212
|
for await (const chunk of exchange.requestBody) {
|
|
212
|
-
await handler.sendRequestMessage(decodeFrame(chunk))
|
|
213
|
+
await handler.sendRequestMessage(decodeFrame(chunk.chunk ?? new Uint8Array()), {
|
|
214
|
+
...ctx,
|
|
215
|
+
agentInvocationId: chunk.agentInvocationId
|
|
216
|
+
});
|
|
213
217
|
}
|
|
214
218
|
return "client-complete";
|
|
215
219
|
})().catch((err) => {
|
|
@@ -309,7 +313,7 @@ function routeChunk(exchange, params) {
|
|
|
309
313
|
return;
|
|
310
314
|
}
|
|
311
315
|
if (params.data && params.data.length > 0) {
|
|
312
|
-
exchange.pushChunk(decodeChunkData(params.data, !!params.binary));
|
|
316
|
+
exchange.pushChunk(decodeChunkData(params.data, !!params.binary), params.agentInvocationId);
|
|
313
317
|
}
|
|
314
318
|
if (params.end) {
|
|
315
319
|
exchange.pushEnd();
|
|
@@ -319,6 +323,7 @@ class CopilotRequestExchange {
|
|
|
319
323
|
requestId;
|
|
320
324
|
sessionId;
|
|
321
325
|
agentId;
|
|
326
|
+
agentInvocationId;
|
|
322
327
|
parentAgentId;
|
|
323
328
|
interactionType;
|
|
324
329
|
method = "GET";
|
|
@@ -341,6 +346,7 @@ class CopilotRequestExchange {
|
|
|
341
346
|
setContext(params) {
|
|
342
347
|
this.sessionId = params.sessionId;
|
|
343
348
|
this.agentId = params.agentId;
|
|
349
|
+
this.agentInvocationId = params.agentInvocationId;
|
|
344
350
|
this.parentAgentId = params.parentAgentId;
|
|
345
351
|
this.interactionType = params.interactionType;
|
|
346
352
|
this.method = params.method;
|
|
@@ -361,8 +367,8 @@ class CopilotRequestExchange {
|
|
|
361
367
|
return this.#cancelled;
|
|
362
368
|
}
|
|
363
369
|
// --- Request body feed (driven by the adapter as chunk frames arrive) ---
|
|
364
|
-
pushChunk(chunk) {
|
|
365
|
-
this.#push({ chunk });
|
|
370
|
+
pushChunk(chunk, agentInvocationId) {
|
|
371
|
+
this.#push({ chunk, agentInvocationId });
|
|
366
372
|
}
|
|
367
373
|
pushEnd() {
|
|
368
374
|
this.#push({ end: true });
|
|
@@ -405,7 +411,7 @@ class CopilotRequestExchange {
|
|
|
405
411
|
this.#drained = true;
|
|
406
412
|
return { value: void 0, done: true };
|
|
407
413
|
}
|
|
408
|
-
return { value: item
|
|
414
|
+
return { value: item, done: false };
|
|
409
415
|
}
|
|
410
416
|
})
|
|
411
417
|
};
|
|
@@ -517,9 +523,11 @@ async function buildFetchRequest(exchange) {
|
|
|
517
523
|
async function drainAsync(stream) {
|
|
518
524
|
const parts = [];
|
|
519
525
|
let total = 0;
|
|
520
|
-
for await (const
|
|
521
|
-
|
|
522
|
-
|
|
526
|
+
for await (const item of stream) {
|
|
527
|
+
if (item.chunk) {
|
|
528
|
+
parts.push(item.chunk);
|
|
529
|
+
total += item.chunk.byteLength;
|
|
530
|
+
}
|
|
523
531
|
}
|
|
524
532
|
if (parts.length === 0) {
|
|
525
533
|
return new Uint8Array(0);
|
|
@@ -80,6 +80,15 @@ function loadLibrary(libraryPath) {
|
|
|
80
80
|
"size_t"
|
|
81
81
|
]),
|
|
82
82
|
connectionClose: lib.func(`${SYMBOL_PREFIX}connection_close`, "bool", ["uint32"]),
|
|
83
|
+
connectionSetUiThreadHandler: lib.func(
|
|
84
|
+
`${SYMBOL_PREFIX}connection_set_ui_thread_handler`,
|
|
85
|
+
"bool",
|
|
86
|
+
["uint32", "bool"]
|
|
87
|
+
),
|
|
88
|
+
connectionRunUiAction: lib.func(`${SYMBOL_PREFIX}connection_run_ui_action`, "bool", [
|
|
89
|
+
"uint32",
|
|
90
|
+
"uint32"
|
|
91
|
+
]),
|
|
83
92
|
outboundCallbackType
|
|
84
93
|
};
|
|
85
94
|
loadedLibraryPath = libraryPath;
|
|
@@ -230,6 +239,21 @@ class FfiRuntimeHost {
|
|
|
230
239
|
throw new Error("Failed to write a frame to the in-process runtime connection.");
|
|
231
240
|
}
|
|
232
241
|
}
|
|
242
|
+
configureUiThread(enabled) {
|
|
243
|
+
if (this.disposed || !this.lib.connectionSetUiThreadHandler(this.connectionId, enabled)) {
|
|
244
|
+
throw new Error("Failed to configure the in-process UI dispatcher.");
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
runUiAction(actionId) {
|
|
248
|
+
if (!Number.isInteger(actionId) || actionId < 0 || actionId > 4294967295) {
|
|
249
|
+
throw new RangeError("UI action ID must be an unsigned 32-bit integer.");
|
|
250
|
+
}
|
|
251
|
+
if (this.disposed || !this.lib.connectionRunUiAction(this.connectionId, actionId)) {
|
|
252
|
+
throw new Error(
|
|
253
|
+
"Native UI action is retired, already executed, or not running on the process main thread."
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
233
257
|
/**
|
|
234
258
|
* Native outbound (server→client) callback. koffi delivers it on the JS event loop
|
|
235
259
|
* via a threadsafe function, so the frame is decoded and written straight to
|